diff --git a/.gitignore b/.gitignore index 189b414f0..9263a0c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /build /CMakeLists.txt.user +/.idea +/src/backend/opencl/cl/cn/cryptonight_gen.cl diff --git a/CHANGELOG.md b/CHANGELOG.md index 501679771..a56048220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# v3.1.1 +- [#1133](https://github.com/xmrig/xmrig/issues/1133) Fixed syslog regression. +- [#1138](https://github.com/xmrig/xmrig/issues/1138) Fixed multiple network bugs. +- [#1141](https://github.com/xmrig/xmrig/issues/1141) Fixed log in background mode. +- [#1142](https://github.com/xmrig/xmrig/pull/1142) RandomX hashrate improved by 0.5-1.5% depending on variant and CPU. +- [#1146](https://github.com/xmrig/xmrig/pull/1146) Fixed race condition in RandomX thread init. +- [#1148](https://github.com/xmrig/xmrig/pull/1148) Fixed, on Linux linker marking entire executable as having an executable stack. +- Fixed, for Argon2 algorithms command line options like `--threads` was ignored. +- Fixed command line options for single pool, free order allowed again. + +# v3.1.0 +- [#1107](https://github.com/xmrig/xmrig/issues/1107#issuecomment-522235892) Added Argon2 algorithm family: `argon2/chukwa` and `argon2/wrkz`. + # v3.0.0 - **[#1111](https://github.com/xmrig/xmrig/pull/1111) Added RandomX (`rx/test`) algorithm for testing and benchmarking.** - **[#1036](https://github.com/xmrig/xmrig/pull/1036) Added RandomWOW (`rx/wow`) algorithm for [Wownero](http://wownero.org/).** diff --git a/CMakeLists.txt b/CMakeLists.txt index 152883198..07654d040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,22 @@ cmake_minimum_required(VERSION 2.8) project(xmrig) -option(WITH_LIBCPUID "Use Libcpuid" ON) -option(WITH_HWLOC "Use hwloc" ON) -option(WITH_CN_LITE "CryptoNight-Lite support" ON) -option(WITH_CN_HEAVY "CryptoNight-Heavy support" ON) -option(WITH_CN_PICO "CryptoNight-Pico support" ON) -option(WITH_CN_GPU "CryptoNight-GPU support" ON) -option(WITH_RANDOMX "RandomX support" ON) -option(WITH_HTTP "HTTP protocol support (client/server)" ON) +option(WITH_LIBCPUID "Enable libcpuid support" ON) +option(WITH_HWLOC "Enable hwloc support" ON) +option(WITH_CN_LITE "Enable CryptoNight-Lite algorithms family" ON) +option(WITH_CN_HEAVY "Enable CryptoNight-Heavy algorithms family" ON) +option(WITH_CN_PICO "Enable CryptoNight-Pico algorithm" ON) +option(WITH_CN_GPU "Enable CryptoNight-GPU algorithm" ON) +option(WITH_RANDOMX "Enable RandomX algorithms family" ON) +option(WITH_ARGON2 "Enable Argon2 algorithms family" ON) +option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON) option(WITH_DEBUG_LOG "Enable debug log output" OFF) option(WITH_TLS "Enable OpenSSL support" ON) option(WITH_ASM "Enable ASM PoW implementations" ON) option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF) +option(WITH_OPENCL "Enable OpenCL backend" ON) +option(WITH_STRICT_CACHE "Enable strict checks for OpenCL cache" ON) +option(WITH_INTERLEAVE_DEBUG_LOG "Enable debug log for threads interleave" OFF) option(BUILD_STATIC "Build static binary" OFF) option(ARM_TARGET "Force use specific ARM target 8 or 7" 0) @@ -151,66 +155,9 @@ add_definitions(/DUNICODE) find_package(UV REQUIRED) -if (WITH_RANDOMX) - include_directories(src/crypto/randomx) - add_definitions(/DXMRIG_ALGO_RANDOMX) - set(SOURCES_CRYPTO - "${SOURCES_CRYPTO}" - src/crypto/randomx/aes_hash.cpp - src/crypto/randomx/allocator.cpp - src/crypto/randomx/argon2_core.c - src/crypto/randomx/argon2_ref.c - src/crypto/randomx/blake2_generator.cpp - src/crypto/randomx/blake2/blake2b.c - src/crypto/randomx/bytecode_machine.cpp - src/crypto/randomx/dataset.cpp - src/crypto/randomx/instructions_portable.cpp - src/crypto/randomx/randomx.cpp - src/crypto/randomx/reciprocal.c - src/crypto/randomx/soft_aes.cpp - src/crypto/randomx/superscalar.cpp - src/crypto/randomx/virtual_machine.cpp - src/crypto/randomx/virtual_memory.cpp - src/crypto/randomx/vm_compiled_light.cpp - src/crypto/randomx/vm_compiled.cpp - src/crypto/randomx/vm_interpreted_light.cpp - src/crypto/randomx/vm_interpreted.cpp - src/crypto/rx/Rx.cpp - src/crypto/rx/Rx.h - src/crypto/rx/RxAlgo.cpp - src/crypto/rx/RxAlgo.h - src/crypto/rx/RxCache.cpp - src/crypto/rx/RxCache.h - src/crypto/rx/RxConfig.cpp - src/crypto/rx/RxConfig.h - src/crypto/rx/RxDataset.cpp - src/crypto/rx/RxDataset.h - src/crypto/rx/RxVm.cpp - src/crypto/rx/RxVm.h - ) - if (NOT ARCH_ID) - set(ARCH_ID ${CMAKE_HOST_SYSTEM_PROCESSOR}) - endif() - if (CMAKE_C_COMPILER_ID MATCHES MSVC) - enable_language(ASM_MASM) - list(APPEND SOURCES_CRYPTO - src/crypto/randomx/jit_compiler_x86_static.asm - src/crypto/randomx/jit_compiler_x86.cpp - ) - elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) - list(APPEND SOURCES_CRYPTO - src/crypto/randomx/jit_compiler_x86_static.S - src/crypto/randomx/jit_compiler_x86.cpp - ) - # cheat because cmake and ccache hate each other - set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C) - endif() -else() - remove_definitions(/DXMRIG_ALGO_RANDOMX) -endif() - include(cmake/flags.cmake) - +include(cmake/randomx.cmake) +include(cmake/argon2.cmake) include(cmake/OpenSSL.cmake) include(cmake/asm.cmake) include(cmake/cn-gpu.cmake) @@ -244,4 +191,4 @@ if (WITH_DEBUG_LOG) endif() add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES} ${CN_GPU_SOURCES}) -target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB}) +target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB} ${ARGON2_LIBRARY}) diff --git a/cmake/argon2.cmake b/cmake/argon2.cmake new file mode 100644 index 000000000..e82cd3899 --- /dev/null +++ b/cmake/argon2.cmake @@ -0,0 +1,18 @@ +if (WITH_ARGON2) + add_definitions(/DXMRIG_ALGO_ARGON2) + + list(APPEND HEADERS_CRYPTO + src/crypto/argon2/Hash.h + src/crypto/argon2/Impl.h + ) + + list(APPEND SOURCES_CRYPTO + src/crypto/argon2/Impl.cpp + ) + + add_subdirectory(src/3rdparty/argon2) + set(ARGON2_LIBRARY argon2) +else() + remove_definitions(/DXMRIG_ALGO_ARGON2) + set(ARGON2_LIBRARY "") +endif() diff --git a/cmake/randomx.cmake b/cmake/randomx.cmake new file mode 100644 index 000000000..d0d892b96 --- /dev/null +++ b/cmake/randomx.cmake @@ -0,0 +1,61 @@ +if (WITH_RANDOMX) + add_definitions(/DXMRIG_ALGO_RANDOMX) + + list(APPEND HEADERS_CRYPTO + src/crypto/rx/Rx.h + src/crypto/rx/RxAlgo.h + src/crypto/rx/RxCache.h + src/crypto/rx/RxConfig.h + src/crypto/rx/RxDataset.h + src/crypto/rx/RxVm.h + ) + + list(APPEND SOURCES_CRYPTO + src/crypto/randomx/aes_hash.cpp + src/crypto/randomx/allocator.cpp + src/crypto/randomx/argon2_core.c + src/crypto/randomx/argon2_ref.c + src/crypto/randomx/blake2_generator.cpp + src/crypto/randomx/blake2/blake2b.c + src/crypto/randomx/bytecode_machine.cpp + src/crypto/randomx/dataset.cpp + src/crypto/randomx/instructions_portable.cpp + src/crypto/randomx/randomx.cpp + src/crypto/randomx/reciprocal.c + src/crypto/randomx/soft_aes.cpp + src/crypto/randomx/superscalar.cpp + src/crypto/randomx/virtual_machine.cpp + src/crypto/randomx/virtual_memory.cpp + src/crypto/randomx/vm_compiled_light.cpp + src/crypto/randomx/vm_compiled.cpp + src/crypto/randomx/vm_interpreted_light.cpp + src/crypto/randomx/vm_interpreted.cpp + src/crypto/rx/Rx.cpp + src/crypto/rx/RxAlgo.cpp + src/crypto/rx/RxCache.cpp + src/crypto/rx/RxConfig.cpp + src/crypto/rx/RxDataset.cpp + src/crypto/rx/RxVm.cpp + ) + + if (CMAKE_C_COMPILER_ID MATCHES MSVC) + enable_language(ASM_MASM) + list(APPEND SOURCES_CRYPTO + src/crypto/randomx/jit_compiler_x86_static.asm + src/crypto/randomx/jit_compiler_x86.cpp + ) + elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND SOURCES_CRYPTO + src/crypto/randomx/jit_compiler_x86_static.S + src/crypto/randomx/jit_compiler_x86.cpp + ) + # cheat because cmake and ccache hate each other + set_property(SOURCE src/crypto/randomx/jit_compiler_x86_static.S PROPERTY LANGUAGE C) + endif() + + if (CMAKE_CXX_COMPILER_ID MATCHES Clang) + set_source_files_properties(src/crypto/randomx/jit_compiler_x86.cpp PROPERTIES COMPILE_FLAGS -Wno-unused-const-variable) + endif() +else() + remove_definitions(/DXMRIG_ALGO_RANDOMX) +endif() diff --git a/doc/ALGORITHMS.md b/doc/ALGORITHMS.md index ab55bb743..aff8b3bf8 100644 --- a/doc/ALGORITHMS.md +++ b/doc/ALGORITHMS.md @@ -23,4 +23,30 @@ Since version 3 mining [algorithm](#algorithm-names) should specified for each p ## Algorithm names -* https://xmrig.com/docs/algorithms +| Name | Memory | Version | Notes | +|------|--------|---------|-------| +| `argon2/chukwa` | 512 KB | 3.1.0+ | Argon2id (Chukwa). | +| `argon2/wrkz` | 256 KB | 3.1.0+ | Argon2id (WRKZ) | +| `rx/test` | 2 MB | 3.0.0+ | RandomX (reference configuration). | +| `rx/0` | 2 MB | 3.0.0+ | RandomX (reference configuration), reserved for future use. | +| `rx/wow` | 1 MB | 3.0.0+ | RandomWOW. | +| `rx/loki` | 2 MB | 3.0.0+ | RandomXL. | +| `cn/fast` | 2 MB | 3.0.0+ | CryptoNight variant 1 with half iterations. | +| `cn/rwz` | 2 MB | 2.14.0+ | CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation. | +| `cn/zls` | 2 MB | 2.14.0+ | CryptoNight variant 2 with 3/4 iterations. | +| `cn/double` | 2 MB | 2.14.0+ | CryptoNight variant 2 with double iterations. | +| `cn/r` | 2 MB | 2.13.0+ | CryptoNightR (Monero's variant 4). | +| `cn/wow` | 2 MB | 2.12.0+ | CryptoNightR (Wownero). | +| `cn/gpu` | 2 MB | 2.11.0+ | CryptoNight-GPU. | +| `cn-pico` | 256 KB | 2.10.0+ | CryptoNight-Pico. | +| `cn/half` | 2 MB | 2.9.0+ | CryptoNight variant 2 with half iterations. | +| `cn/2` | 2 MB | 2.8.0+ | CryptoNight variant 2. | +| `cn/xao` | 2 MB | 2.6.4+ | CryptoNight variant 0 (modified). | +| `cn/rto` | 2 MB | 2.6.4+ | CryptoNight variant 1 (modified). | +| `cn-heavy/tube` | 4 MB | 2.6.4+ | CryptoNight-Heavy (modified). | +| `cn-heavy/xhv` | 4 MB | 2.6.3+ | CryptoNight-Heavy (modified). | +| `cn-heavy/0` | 4 MB | 2.6.0+ | CryptoNight-Heavy. | +| `cn/1` | 2 MB | 2.5.0+ | CryptoNight variant 1. | +| `cn-lite/1` | 1 MB | 2.5.0+ | CryptoNight-Lite variant 1. | +| `cn-lite/0` | 1 MB | 0.8.0+ | CryptoNight-Lite variant 0. | +| `cn/0` | 2 MB | 0.5.0+ | CryptoNight (original). | diff --git a/doc/CHANGELOG_OLD.md b/doc/CHANGELOG_OLD.md index 15ae35a9c..58be062b2 100644 --- a/doc/CHANGELOG_OLD.md +++ b/doc/CHANGELOG_OLD.md @@ -1,3 +1,9 @@ +# v2.99.6-beta +- Added commands `pause` and `resume` via JSON RPC 2.0 API (`POST /json_rpc`). +- Fixed autoconfig regression (since 2.99.5), mostly `rx/wow` was affected by this bug. +- Fixed user job recovery after donation round. +- Information about AVX2 CPU feature how hidden in miner summary. + # v2.99.5-beta - [#1066](https://github.com/xmrig/xmrig/issues/1066#issuecomment-518080529) Fixed crash and added error message if pool not ready for RandomX. - [#1092](https://github.com/xmrig/xmrig/issues/1092) Fixed crash if wrong CPU affinity used. diff --git a/doc/CPU.md b/doc/CPU.md index 756d3a0ca..4d1f08588 100644 --- a/doc/CPU.md +++ b/doc/CPU.md @@ -1,7 +1,5 @@ # CPU backend -**Information in this document actual to version 2.99.5+** - All CPU related settings contains in one `cpu` object in config file, CPU backend allow specify multiple profiles and allow switch between them without restrictions by pool request or config change. Default auto-configuration create reasonable minimum of profiles which cover all supported algorithms. ### Example @@ -93,3 +91,6 @@ Mining threads priority, value from `1` (lowest priority) to `5` (highest possib #### `asm` Enable/configure or disable ASM optimizations. Possible values: `true`, `false`, `"intel"`, `"ryzen"`, `"bulldozer"`. + +#### `argon2-impl` (since v3.1.0) +Allow override automatically detected Argon2 implementation, this option added mostly for debug purposes, default value `null` means autodetect. Other possible values: `"x86_64"`, `"SSE2"`, `"SSSE3"`, `"XOP"`, `"AVX2"`, `"AVX-512F"`. Manual selection has no safe guards, if you CPU not support required instuctions, miner will crash. diff --git a/doc/PERSISTENT_OPTIONS.md b/doc/PERSISTENT_OPTIONS.md new file mode 100644 index 000000000..7f845c1b5 --- /dev/null +++ b/doc/PERSISTENT_OPTIONS.md @@ -0,0 +1,9 @@ +# Persistent options + +Options in list below can't changed in runtime by watching config file or via API. + +* `background` +* `donate-level` +* `cpu/argon2-impl` +* `opencl/loader` +* `opencl/platform` diff --git a/doc/data/algorithms.json b/doc/data/algorithms.json deleted file mode 100644 index b42fa82f3..000000000 --- a/doc/data/algorithms.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "current": [ - ["rx/test", "2 MB", "2.99.5+", "RandomX (reference configuration)."], - ["rx/0", "2 MB", "2.99.0+", "RandomX (reference configuration), reserved for future use."], - ["rx/wow", "1 MB", "2.99.0+", "RandomWOW."], - ["rx/loki", "2 MB", "2.99.0+", "RandomXL."], - ["cn/fast", "2 MB", "2.99.0+", "CryptoNight variant 1 with half iterations."], - ["cn/rwz", "2 MB", "2.14.0+", "CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation."], - ["cn/zls", "2 MB", "2.14.0+", "CryptoNight variant 2 with 3/4 iterations."], - ["cn/double", "2 MB", "2.14.0+", "CryptoNight variant 2 with double iterations."], - ["cn/r", "2 MB", "2.13.0+", "CryptoNightR (Monero's variant 4)."], - ["cn/wow", "2 MB", "2.12.0+", "CryptoNightR (Wownero)."], - ["cn/gpu", "2 MB", "2.11.0+", "CryptoNight-GPU."], - ["cn-pico", "256 KB", "2.10.0+", "CryptoNight-Pico."], - ["cn/half", "2 MB", "2.9.0+", "CryptoNight variant 2 with half iterations."], - ["cn/2", "2 MB", "2.8.0+", "CryptoNight variant 2."], - ["cn/xao", "2 MB", "2.6.4+", "CryptoNight variant 0 (modified)."], - ["cn/rto", "2 MB", "2.6.4+", "CryptoNight variant 1 (modified)."], - ["cn-heavy/tube", "4 MB", "2.6.4+", "CryptoNight-Heavy (modified)."], - ["cn-heavy/xhv", "4 MB", "2.6.3+", "CryptoNight-Heavy (modified)."], - ["cn-heavy/0", "4 MB", "2.6.0+", "CryptoNight-Heavy."], - ["cn/1", "2 MB", "2.5.0+", "CryptoNight variant 1."], - ["cn-lite/1", "1 MB", "2.5.0+", "CryptoNight-Lite variant 1."], - ["cn-lite/0", "1 MB", "0.8.0+", "CryptoNight-Lite variant 0."], - ["cn/0", "2 MB", "0.5.0+", "CryptoNight (original)."] - ], - "removed": [ - ["cn/msr", "2 MB", "2.6.3+", "Renamed to cn/fast, still supported as alias."], - ["cn/xtl", "2 MB", "2.6.1-2.16.0", "Coin forked to cn/half."], - ["cn-lite/ipbc", "1 MB", "2.6.1-2.6.3", "Coin forked to cn-heavy/tube."] - ] -} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 000000000..80cad8a1c --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "xmrig", + "version": "3.0.0", + "description": "RandomX, CryptoNight and Argon2 miner", + "main": "index.js", + "directories": { + "doc": "doc" + }, + "scripts": { + "build": "node scripts/generate_cl.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/xmrig/xmrig.git" + }, + "keywords": [], + "author": "", + "license": "GPLv3", + "bugs": { + "url": "https://github.com/xmrig/xmrig/issues" + }, + "homepage": "https://github.com/xmrig/xmrig#readme" +} diff --git a/scripts/generate_cl.js b/scripts/generate_cl.js new file mode 100644 index 000000000..910b752bd --- /dev/null +++ b/scripts/generate_cl.js @@ -0,0 +1,86 @@ +#!/usr/bin/env node + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { text2h, text2h_bundle, addIncludes } = require('./js/opencl'); +const { opencl_minify } = require('./js/opencl_minify'); +const cwd = process.cwd(); + + +function cn() +{ + const cn = opencl_minify(addIncludes('cryptonight.cl', [ + 'algorithm.cl', + 'wolf-aes.cl', + 'wolf-skein.cl', + 'jh.cl', + 'blake256.cl', + 'groestl256.cl', + 'fast_int_math_v2.cl', + 'fast_div_heavy.cl', + 'keccak.cl' + ])); + + // fs.writeFileSync('cryptonight_gen.cl', cn); + fs.writeFileSync('cryptonight_cl.h', text2h(cn, 'xmrig', 'cryptonight_cl')); +} + + +function cn_r() +{ + const items = {}; + + items.cryptonight_r_defines_cl = opencl_minify(addIncludes('cryptonight_r_defines.cl', [ 'wolf-aes.cl' ])); + items.cryptonight_r_cl = opencl_minify(fs.readFileSync('cryptonight_r.cl', 'utf8')); + + // for (let key in items) { + // fs.writeFileSync(key + '_gen.cl', items[key]); + // } + + fs.writeFileSync('cryptonight_r_cl.h', text2h_bundle('xmrig', items)); +} + + +function cn_gpu() +{ + const cn_gpu = opencl_minify(addIncludes('cryptonight_gpu.cl', [ 'wolf-aes.cl', 'keccak.cl' ])); + + // fs.writeFileSync('cryptonight_gpu_gen.cl', cn_gpu); + fs.writeFileSync('cryptonight_gpu_cl.h', text2h(cn_gpu, 'xmrig', 'cryptonight_gpu_cl')); +} + + +function rx() +{ + let rx = addIncludes('randomx.cl', [ + '../cn/algorithm.cl', + 'randomx_constants_monero.h', + 'randomx_constants_wow.h', + 'randomx_constants_loki.h', + 'aes.cl', + 'blake2b.cl', + 'randomx_vm.cl', + 'randomx_jit.cl' + ]); + + rx = rx.replace(/(\t| )*#include "fillAes1Rx4.cl"/g, fs.readFileSync('fillAes1Rx4.cl', 'utf8')); + rx = rx.replace(/(\t| )*#include "blake2b_double_block.cl"/g, fs.readFileSync('blake2b_double_block.cl', 'utf8')); + rx = opencl_minify(rx); + + //fs.writeFileSync('randomx_gen.cl', rx); + fs.writeFileSync('randomx_cl.h', text2h(rx, 'xmrig', 'randomx_cl')); +} + + +process.chdir(path.resolve('src/backend/opencl/cl/cn')); + +cn(); +cn_r(); +cn_gpu(); + +process.chdir(cwd); +process.chdir(path.resolve('src/backend/opencl/cl/rx')); + +rx(); \ No newline at end of file diff --git a/scripts/js/opencl.js b/scripts/js/opencl.js new file mode 100644 index 000000000..878aa44b4 --- /dev/null +++ b/scripts/js/opencl.js @@ -0,0 +1,91 @@ +'use strict'; + +const fs = require('fs'); + + +function bin2h(buf, namespace, name) +{ + const size = buf.byteLength; + let out = `#pragma once\n\nnamespace ${namespace} {\n\nstatic unsigned char ${name}[${size}] = {\n `; + + let b = 32; + for (let i = 0; i < size; i++) { + out += `0x${buf.readUInt8(i).toString(16).padStart(2, '0')}${size - i > 1 ? ',' : ''}`; + + if (--b === 0) { + b = 32; + out += '\n '; + } + } + + out += `\n};\n\n} // namespace ${namespace}\n`; + + return out; +} + + +function text2h_internal(text, name) +{ + const buf = Buffer.from(text); + const size = buf.byteLength; + let out = `\nstatic char ${name}[${size + 1}] = {\n `; + + let b = 32; + for (let i = 0; i < size; i++) { + out += `0x${buf.readUInt8(i).toString(16).padStart(2, '0')},`; + + if (--b === 0) { + b = 32; + out += '\n '; + } + } + + out += '0x00'; + + out += '\n};\n'; + + return out; +} + + +function text2h(text, namespace, name) +{ + return `#pragma once\n\nnamespace ${namespace} {\n` + text2h_internal(text, name) + `\n} // namespace ${namespace}\n`; +} + + +function text2h_bundle(namespace, items) +{ + let out = `#pragma once\n\nnamespace ${namespace} {\n`; + + for (let key in items) { + out += text2h_internal(items[key], key); + } + + return out + `\n} // namespace ${namespace}\n`; +} + + +function addInclude(input, name) +{ + return input.replace(`#include "${name}"`, fs.readFileSync(name, 'utf8')); +} + + +function addIncludes(inputFileName, names) +{ + let data = fs.readFileSync(inputFileName, 'utf8'); + + for (let name of names) { + data = addInclude(data, name); + } + + return data; +} + + +module.exports.bin2h = bin2h; +module.exports.text2h = text2h; +module.exports.text2h_bundle = text2h_bundle; +module.exports.addInclude = addInclude; +module.exports.addIncludes = addIncludes; \ No newline at end of file diff --git a/scripts/js/opencl_minify.js b/scripts/js/opencl_minify.js new file mode 100644 index 000000000..503fa486c --- /dev/null +++ b/scripts/js/opencl_minify.js @@ -0,0 +1,50 @@ +'use strict'; + +function opencl_minify(input) +{ + let out = input.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, ''); // comments + out = out.replace(/^#\s+/gm, '#'); // macros with spaces + out = out.replace(/\n{2,}/g, '\n'); // empty lines + out = out.replace(/^\s+/gm, ''); // leading whitespace + out = out.replace(/ {2,}/g, ' '); // extra whitespace + + let array = out.split('\n').map(line => { + if (line[0] === '#') { + return line + } + + line = line.replace(/, /g, ','); + line = line.replace(/ \? /g, '?'); + line = line.replace(/ : /g, ':'); + line = line.replace(/ = /g, '='); + line = line.replace(/ != /g, '!='); + line = line.replace(/ >= /g, '>='); + line = line.replace(/ <= /g, '<='); + line = line.replace(/ == /g, '=='); + line = line.replace(/ \+= /g, '+='); + line = line.replace(/ -= /g, '-='); + line = line.replace(/ \|= /g, '|='); + line = line.replace(/ \| /g, '|'); + line = line.replace(/ \|\| /g, '||'); + line = line.replace(/ & /g, '&'); + line = line.replace(/ && /g, '&&'); + line = line.replace(/ > /g, '>'); + line = line.replace(/ < /g, '<'); + line = line.replace(/ \+ /g, '+'); + line = line.replace(/ - /g, '-'); + line = line.replace(/ \* /g, '*'); + line = line.replace(/ \^ /g, '^'); + line = line.replace(/ & /g, '&'); + line = line.replace(/ \/ /g, '/'); + line = line.replace(/ << /g, '<<'); + line = line.replace(/ >> /g, '>>'); + line = line.replace(/if \(/g, 'if('); + + return line; + }); + + return array.join('\n'); +} + + +module.exports.opencl_minify = opencl_minify; \ No newline at end of file diff --git a/src/3rdparty/CL/LICENSE b/src/3rdparty/CL/LICENSE new file mode 100644 index 000000000..020ce65fc --- /dev/null +++ b/src/3rdparty/CL/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2008-2015 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are 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 Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + https://www.khronos.org/registry/ + +THE MATERIALS ARE 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 +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/src/3rdparty/CL/README.md b/src/3rdparty/CL/README.md new file mode 100644 index 000000000..757e56e15 --- /dev/null +++ b/src/3rdparty/CL/README.md @@ -0,0 +1,50 @@ +# OpenCLTM API Headers + +This repository contains C language headers for the OpenCL API. + +The authoritative public repository for these headers is located at: + +https://github.com/KhronosGroup/OpenCL-Headers + +Issues, proposed fixes for issues, and other suggested changes should be +created using Github. + +## Branch Structure + +The OpenCL API headers in this repository are Unified headers and are designed +to work with all released OpenCL versions. This differs from previous OpenCL +API headers, where version-specific API headers either existed in separate +branches, or in separate folders in a branch. + +## Compiling for a Specific OpenCL Version + +By default, the OpenCL API headers in this repository are for the latest +OpenCL version (currently OpenCL 2.2). To use these API headers to target +a different OpenCL version, an application may `#define` the preprocessor +value `CL_TARGET_OPENCL_VERSION` before including the OpenCL API headers. +The `CL_TARGET_OPENCL_VERSION` is a three digit decimal value representing +the OpenCL API version. + +For example, to enforce usage of no more than the OpenCL 1.2 APIs, you may +include the OpenCL API headers as follows: + +``` +#define CL_TARGET_OPENCL_VERSION 120 +#include +``` + +## Directory Structure + +``` +README.md This file +LICENSE Source license for the OpenCL API headers +CL/ Unified OpenCL API headers tree +``` + +## License + +See [LICENSE](LICENSE). + +--- + +OpenCL and the OpenCL logo are trademarks of Apple Inc. used by permission by Khronos. diff --git a/src/3rdparty/CL/cl.h b/src/3rdparty/CL/cl.h new file mode 100644 index 000000000..32ae73fc5 --- /dev/null +++ b/src/3rdparty/CL/cl.h @@ -0,0 +1,1804 @@ +/******************************************************************************* + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#ifndef __OPENCL_CL_H +#define __OPENCL_CL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ + +typedef struct _cl_platform_id * cl_platform_id; +typedef struct _cl_device_id * cl_device_id; +typedef struct _cl_context * cl_context; +typedef struct _cl_command_queue * cl_command_queue; +typedef struct _cl_mem * cl_mem; +typedef struct _cl_program * cl_program; +typedef struct _cl_kernel * cl_kernel; +typedef struct _cl_event * cl_event; +typedef struct _cl_sampler * cl_sampler; + +typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ +typedef cl_ulong cl_bitfield; +typedef cl_bitfield cl_device_type; +typedef cl_uint cl_platform_info; +typedef cl_uint cl_device_info; +typedef cl_bitfield cl_device_fp_config; +typedef cl_uint cl_device_mem_cache_type; +typedef cl_uint cl_device_local_mem_type; +typedef cl_bitfield cl_device_exec_capabilities; +#ifdef CL_VERSION_2_0 +typedef cl_bitfield cl_device_svm_capabilities; +#endif +typedef cl_bitfield cl_command_queue_properties; +#ifdef CL_VERSION_1_2 +typedef intptr_t cl_device_partition_property; +typedef cl_bitfield cl_device_affinity_domain; +#endif + +typedef intptr_t cl_context_properties; +typedef cl_uint cl_context_info; +#ifdef CL_VERSION_2_0 +typedef cl_bitfield cl_queue_properties; +#endif +typedef cl_uint cl_command_queue_info; +typedef cl_uint cl_channel_order; +typedef cl_uint cl_channel_type; +typedef cl_bitfield cl_mem_flags; +#ifdef CL_VERSION_2_0 +typedef cl_bitfield cl_svm_mem_flags; +#endif +typedef cl_uint cl_mem_object_type; +typedef cl_uint cl_mem_info; +#ifdef CL_VERSION_1_2 +typedef cl_bitfield cl_mem_migration_flags; +#endif +typedef cl_uint cl_image_info; +#ifdef CL_VERSION_1_1 +typedef cl_uint cl_buffer_create_type; +#endif +typedef cl_uint cl_addressing_mode; +typedef cl_uint cl_filter_mode; +typedef cl_uint cl_sampler_info; +typedef cl_bitfield cl_map_flags; +#ifdef CL_VERSION_2_0 +typedef intptr_t cl_pipe_properties; +typedef cl_uint cl_pipe_info; +#endif +typedef cl_uint cl_program_info; +typedef cl_uint cl_program_build_info; +#ifdef CL_VERSION_1_2 +typedef cl_uint cl_program_binary_type; +#endif +typedef cl_int cl_build_status; +typedef cl_uint cl_kernel_info; +#ifdef CL_VERSION_1_2 +typedef cl_uint cl_kernel_arg_info; +typedef cl_uint cl_kernel_arg_address_qualifier; +typedef cl_uint cl_kernel_arg_access_qualifier; +typedef cl_bitfield cl_kernel_arg_type_qualifier; +#endif +typedef cl_uint cl_kernel_work_group_info; +#ifdef CL_VERSION_2_1 +typedef cl_uint cl_kernel_sub_group_info; +#endif +typedef cl_uint cl_event_info; +typedef cl_uint cl_command_type; +typedef cl_uint cl_profiling_info; +#ifdef CL_VERSION_2_0 +typedef cl_bitfield cl_sampler_properties; +typedef cl_uint cl_kernel_exec_info; +#endif + +typedef struct _cl_image_format { + cl_channel_order image_channel_order; + cl_channel_type image_channel_data_type; +} cl_image_format; + +#ifdef CL_VERSION_1_2 + +typedef struct _cl_image_desc { + cl_mem_object_type image_type; + size_t image_width; + size_t image_height; + size_t image_depth; + size_t image_array_size; + size_t image_row_pitch; + size_t image_slice_pitch; + cl_uint num_mip_levels; + cl_uint num_samples; +#ifdef CL_VERSION_2_0 +#ifdef __GNUC__ + __extension__ /* Prevents warnings about anonymous union in -pedantic builds */ +#endif +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4201 ) /* Prevents warning about nameless struct/union in /W4 /Za builds */ +#endif + union { +#endif + cl_mem buffer; +#ifdef CL_VERSION_2_0 + cl_mem mem_object; + }; +#ifdef _MSC_VER +#pragma warning( pop ) +#endif +#endif +} cl_image_desc; + +#endif + +#ifdef CL_VERSION_1_1 + +typedef struct _cl_buffer_region { + size_t origin; + size_t size; +} cl_buffer_region; + +#endif + +/******************************************************************************/ + +/* Error Codes */ +#define CL_SUCCESS 0 +#define CL_DEVICE_NOT_FOUND -1 +#define CL_DEVICE_NOT_AVAILABLE -2 +#define CL_COMPILER_NOT_AVAILABLE -3 +#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 +#define CL_OUT_OF_RESOURCES -5 +#define CL_OUT_OF_HOST_MEMORY -6 +#define CL_PROFILING_INFO_NOT_AVAILABLE -7 +#define CL_MEM_COPY_OVERLAP -8 +#define CL_IMAGE_FORMAT_MISMATCH -9 +#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 +#define CL_BUILD_PROGRAM_FAILURE -11 +#define CL_MAP_FAILURE -12 +#ifdef CL_VERSION_1_1 +#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 +#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 +#endif +#ifdef CL_VERSION_1_2 +#define CL_COMPILE_PROGRAM_FAILURE -15 +#define CL_LINKER_NOT_AVAILABLE -16 +#define CL_LINK_PROGRAM_FAILURE -17 +#define CL_DEVICE_PARTITION_FAILED -18 +#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 +#endif + +#define CL_INVALID_VALUE -30 +#define CL_INVALID_DEVICE_TYPE -31 +#define CL_INVALID_PLATFORM -32 +#define CL_INVALID_DEVICE -33 +#define CL_INVALID_CONTEXT -34 +#define CL_INVALID_QUEUE_PROPERTIES -35 +#define CL_INVALID_COMMAND_QUEUE -36 +#define CL_INVALID_HOST_PTR -37 +#define CL_INVALID_MEM_OBJECT -38 +#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 +#define CL_INVALID_IMAGE_SIZE -40 +#define CL_INVALID_SAMPLER -41 +#define CL_INVALID_BINARY -42 +#define CL_INVALID_BUILD_OPTIONS -43 +#define CL_INVALID_PROGRAM -44 +#define CL_INVALID_PROGRAM_EXECUTABLE -45 +#define CL_INVALID_KERNEL_NAME -46 +#define CL_INVALID_KERNEL_DEFINITION -47 +#define CL_INVALID_KERNEL -48 +#define CL_INVALID_ARG_INDEX -49 +#define CL_INVALID_ARG_VALUE -50 +#define CL_INVALID_ARG_SIZE -51 +#define CL_INVALID_KERNEL_ARGS -52 +#define CL_INVALID_WORK_DIMENSION -53 +#define CL_INVALID_WORK_GROUP_SIZE -54 +#define CL_INVALID_WORK_ITEM_SIZE -55 +#define CL_INVALID_GLOBAL_OFFSET -56 +#define CL_INVALID_EVENT_WAIT_LIST -57 +#define CL_INVALID_EVENT -58 +#define CL_INVALID_OPERATION -59 +#define CL_INVALID_GL_OBJECT -60 +#define CL_INVALID_BUFFER_SIZE -61 +#define CL_INVALID_MIP_LEVEL -62 +#define CL_INVALID_GLOBAL_WORK_SIZE -63 +#ifdef CL_VERSION_1_1 +#define CL_INVALID_PROPERTY -64 +#endif +#ifdef CL_VERSION_1_2 +#define CL_INVALID_IMAGE_DESCRIPTOR -65 +#define CL_INVALID_COMPILER_OPTIONS -66 +#define CL_INVALID_LINKER_OPTIONS -67 +#define CL_INVALID_DEVICE_PARTITION_COUNT -68 +#endif +#ifdef CL_VERSION_2_0 +#define CL_INVALID_PIPE_SIZE -69 +#define CL_INVALID_DEVICE_QUEUE -70 +#endif +#ifdef CL_VERSION_2_2 +#define CL_INVALID_SPEC_ID -71 +#define CL_MAX_SIZE_RESTRICTION_EXCEEDED -72 +#endif + + +/* cl_bool */ +#define CL_FALSE 0 +#define CL_TRUE 1 +#ifdef CL_VERSION_1_2 +#define CL_BLOCKING CL_TRUE +#define CL_NON_BLOCKING CL_FALSE +#endif + +/* cl_platform_info */ +#define CL_PLATFORM_PROFILE 0x0900 +#define CL_PLATFORM_VERSION 0x0901 +#define CL_PLATFORM_NAME 0x0902 +#define CL_PLATFORM_VENDOR 0x0903 +#define CL_PLATFORM_EXTENSIONS 0x0904 +#ifdef CL_VERSION_2_1 +#define CL_PLATFORM_HOST_TIMER_RESOLUTION 0x0905 +#endif + +/* cl_device_type - bitfield */ +#define CL_DEVICE_TYPE_DEFAULT (1 << 0) +#define CL_DEVICE_TYPE_CPU (1 << 1) +#define CL_DEVICE_TYPE_GPU (1 << 2) +#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) +#ifdef CL_VERSION_1_2 +#define CL_DEVICE_TYPE_CUSTOM (1 << 4) +#endif +#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF + +/* cl_device_info */ +#define CL_DEVICE_TYPE 0x1000 +#define CL_DEVICE_VENDOR_ID 0x1001 +#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 +#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 +#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 +#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B +#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C +#define CL_DEVICE_ADDRESS_BITS 0x100D +#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E +#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F +#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 +#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 +#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 +#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 +#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 +#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 +#define CL_DEVICE_IMAGE_SUPPORT 0x1016 +#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 +#define CL_DEVICE_MAX_SAMPLERS 0x1018 +#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 +#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A +#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B +#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C +#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D +#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E +#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F +#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 +#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 +#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 +#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 +#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 +#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 +#define CL_DEVICE_ENDIAN_LITTLE 0x1026 +#define CL_DEVICE_AVAILABLE 0x1027 +#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 +#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 +#define CL_DEVICE_QUEUE_PROPERTIES 0x102A /* deprecated */ +#ifdef CL_VERSION_2_0 +#define CL_DEVICE_QUEUE_ON_HOST_PROPERTIES 0x102A +#endif +#define CL_DEVICE_NAME 0x102B +#define CL_DEVICE_VENDOR 0x102C +#define CL_DRIVER_VERSION 0x102D +#define CL_DEVICE_PROFILE 0x102E +#define CL_DEVICE_VERSION 0x102F +#define CL_DEVICE_EXTENSIONS 0x1030 +#define CL_DEVICE_PLATFORM 0x1031 +#ifdef CL_VERSION_1_2 +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +#endif +/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG which is already defined in "cl_ext.h" */ +#ifdef CL_VERSION_1_1 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 +#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 /* deprecated */ +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C +#define CL_DEVICE_OPENCL_C_VERSION 0x103D +#endif +#ifdef CL_VERSION_1_2 +#define CL_DEVICE_LINKER_AVAILABLE 0x103E +#define CL_DEVICE_BUILT_IN_KERNELS 0x103F +#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 +#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 +#define CL_DEVICE_PARENT_DEVICE 0x1042 +#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 +#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 +#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 +#define CL_DEVICE_PARTITION_TYPE 0x1046 +#define CL_DEVICE_REFERENCE_COUNT 0x1047 +#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 +#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 +#endif +#ifdef CL_VERSION_2_0 +#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A +#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B +#define CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS 0x104C +#define CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE 0x104D +#define CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES 0x104E +#define CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE 0x104F +#define CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE 0x1050 +#define CL_DEVICE_MAX_ON_DEVICE_QUEUES 0x1051 +#define CL_DEVICE_MAX_ON_DEVICE_EVENTS 0x1052 +#define CL_DEVICE_SVM_CAPABILITIES 0x1053 +#define CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE 0x1054 +#define CL_DEVICE_MAX_PIPE_ARGS 0x1055 +#define CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS 0x1056 +#define CL_DEVICE_PIPE_MAX_PACKET_SIZE 0x1057 +#define CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT 0x1058 +#define CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT 0x1059 +#define CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT 0x105A +#endif +#ifdef CL_VERSION_2_1 +#define CL_DEVICE_IL_VERSION 0x105B +#define CL_DEVICE_MAX_NUM_SUB_GROUPS 0x105C +#define CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS 0x105D +#endif + +/* cl_device_fp_config - bitfield */ +#define CL_FP_DENORM (1 << 0) +#define CL_FP_INF_NAN (1 << 1) +#define CL_FP_ROUND_TO_NEAREST (1 << 2) +#define CL_FP_ROUND_TO_ZERO (1 << 3) +#define CL_FP_ROUND_TO_INF (1 << 4) +#define CL_FP_FMA (1 << 5) +#ifdef CL_VERSION_1_1 +#define CL_FP_SOFT_FLOAT (1 << 6) +#endif +#ifdef CL_VERSION_1_2 +#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) +#endif + +/* cl_device_mem_cache_type */ +#define CL_NONE 0x0 +#define CL_READ_ONLY_CACHE 0x1 +#define CL_READ_WRITE_CACHE 0x2 + +/* cl_device_local_mem_type */ +#define CL_LOCAL 0x1 +#define CL_GLOBAL 0x2 + +/* cl_device_exec_capabilities - bitfield */ +#define CL_EXEC_KERNEL (1 << 0) +#define CL_EXEC_NATIVE_KERNEL (1 << 1) + +/* cl_command_queue_properties - bitfield */ +#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) +#define CL_QUEUE_PROFILING_ENABLE (1 << 1) +#ifdef CL_VERSION_2_0 +#define CL_QUEUE_ON_DEVICE (1 << 2) +#define CL_QUEUE_ON_DEVICE_DEFAULT (1 << 3) +#endif + +/* cl_context_info */ +#define CL_CONTEXT_REFERENCE_COUNT 0x1080 +#define CL_CONTEXT_DEVICES 0x1081 +#define CL_CONTEXT_PROPERTIES 0x1082 +#ifdef CL_VERSION_1_1 +#define CL_CONTEXT_NUM_DEVICES 0x1083 +#endif + +/* cl_context_properties */ +#define CL_CONTEXT_PLATFORM 0x1084 +#ifdef CL_VERSION_1_2 +#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_device_partition_property */ +#define CL_DEVICE_PARTITION_EQUALLY 0x1086 +#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 +#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 +#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 + +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_device_affinity_domain */ +#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) +#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) +#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) +#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) +#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) +#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) + +#endif + +#ifdef CL_VERSION_2_0 + +/* cl_device_svm_capabilities */ +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM (1 << 2) +#define CL_DEVICE_SVM_ATOMICS (1 << 3) + +#endif + +/* cl_command_queue_info */ +#define CL_QUEUE_CONTEXT 0x1090 +#define CL_QUEUE_DEVICE 0x1091 +#define CL_QUEUE_REFERENCE_COUNT 0x1092 +#define CL_QUEUE_PROPERTIES 0x1093 +#ifdef CL_VERSION_2_0 +#define CL_QUEUE_SIZE 0x1094 +#endif +#ifdef CL_VERSION_2_1 +#define CL_QUEUE_DEVICE_DEFAULT 0x1095 +#endif + +/* cl_mem_flags and cl_svm_mem_flags - bitfield */ +#define CL_MEM_READ_WRITE (1 << 0) +#define CL_MEM_WRITE_ONLY (1 << 1) +#define CL_MEM_READ_ONLY (1 << 2) +#define CL_MEM_USE_HOST_PTR (1 << 3) +#define CL_MEM_ALLOC_HOST_PTR (1 << 4) +#define CL_MEM_COPY_HOST_PTR (1 << 5) +/* reserved (1 << 6) */ +#ifdef CL_VERSION_1_2 +#define CL_MEM_HOST_WRITE_ONLY (1 << 7) +#define CL_MEM_HOST_READ_ONLY (1 << 8) +#define CL_MEM_HOST_NO_ACCESS (1 << 9) +#endif +#ifdef CL_VERSION_2_0 +#define CL_MEM_SVM_FINE_GRAIN_BUFFER (1 << 10) /* used by cl_svm_mem_flags only */ +#define CL_MEM_SVM_ATOMICS (1 << 11) /* used by cl_svm_mem_flags only */ +#define CL_MEM_KERNEL_READ_AND_WRITE (1 << 12) +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_mem_migration_flags - bitfield */ +#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) +#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) + +#endif + +/* cl_channel_order */ +#define CL_R 0x10B0 +#define CL_A 0x10B1 +#define CL_RG 0x10B2 +#define CL_RA 0x10B3 +#define CL_RGB 0x10B4 +#define CL_RGBA 0x10B5 +#define CL_BGRA 0x10B6 +#define CL_ARGB 0x10B7 +#define CL_INTENSITY 0x10B8 +#define CL_LUMINANCE 0x10B9 +#ifdef CL_VERSION_1_1 +#define CL_Rx 0x10BA +#define CL_RGx 0x10BB +#define CL_RGBx 0x10BC +#endif +#ifdef CL_VERSION_1_2 +#define CL_DEPTH 0x10BD +#define CL_DEPTH_STENCIL 0x10BE +#endif +#ifdef CL_VERSION_2_0 +#define CL_sRGB 0x10BF +#define CL_sRGBx 0x10C0 +#define CL_sRGBA 0x10C1 +#define CL_sBGRA 0x10C2 +#define CL_ABGR 0x10C3 +#endif + +/* cl_channel_type */ +#define CL_SNORM_INT8 0x10D0 +#define CL_SNORM_INT16 0x10D1 +#define CL_UNORM_INT8 0x10D2 +#define CL_UNORM_INT16 0x10D3 +#define CL_UNORM_SHORT_565 0x10D4 +#define CL_UNORM_SHORT_555 0x10D5 +#define CL_UNORM_INT_101010 0x10D6 +#define CL_SIGNED_INT8 0x10D7 +#define CL_SIGNED_INT16 0x10D8 +#define CL_SIGNED_INT32 0x10D9 +#define CL_UNSIGNED_INT8 0x10DA +#define CL_UNSIGNED_INT16 0x10DB +#define CL_UNSIGNED_INT32 0x10DC +#define CL_HALF_FLOAT 0x10DD +#define CL_FLOAT 0x10DE +#ifdef CL_VERSION_1_2 +#define CL_UNORM_INT24 0x10DF +#endif +#ifdef CL_VERSION_2_1 +#define CL_UNORM_INT_101010_2 0x10E0 +#endif + +/* cl_mem_object_type */ +#define CL_MEM_OBJECT_BUFFER 0x10F0 +#define CL_MEM_OBJECT_IMAGE2D 0x10F1 +#define CL_MEM_OBJECT_IMAGE3D 0x10F2 +#ifdef CL_VERSION_1_2 +#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 +#define CL_MEM_OBJECT_IMAGE1D 0x10F4 +#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 +#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 +#endif +#ifdef CL_VERSION_2_0 +#define CL_MEM_OBJECT_PIPE 0x10F7 +#endif + +/* cl_mem_info */ +#define CL_MEM_TYPE 0x1100 +#define CL_MEM_FLAGS 0x1101 +#define CL_MEM_SIZE 0x1102 +#define CL_MEM_HOST_PTR 0x1103 +#define CL_MEM_MAP_COUNT 0x1104 +#define CL_MEM_REFERENCE_COUNT 0x1105 +#define CL_MEM_CONTEXT 0x1106 +#ifdef CL_VERSION_1_1 +#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 +#define CL_MEM_OFFSET 0x1108 +#endif +#ifdef CL_VERSION_2_0 +#define CL_MEM_USES_SVM_POINTER 0x1109 +#endif + +/* cl_image_info */ +#define CL_IMAGE_FORMAT 0x1110 +#define CL_IMAGE_ELEMENT_SIZE 0x1111 +#define CL_IMAGE_ROW_PITCH 0x1112 +#define CL_IMAGE_SLICE_PITCH 0x1113 +#define CL_IMAGE_WIDTH 0x1114 +#define CL_IMAGE_HEIGHT 0x1115 +#define CL_IMAGE_DEPTH 0x1116 +#ifdef CL_VERSION_1_2 +#define CL_IMAGE_ARRAY_SIZE 0x1117 +#define CL_IMAGE_BUFFER 0x1118 +#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 +#define CL_IMAGE_NUM_SAMPLES 0x111A +#endif + +#ifdef CL_VERSION_2_0 + +/* cl_pipe_info */ +#define CL_PIPE_PACKET_SIZE 0x1120 +#define CL_PIPE_MAX_PACKETS 0x1121 + +#endif + +/* cl_addressing_mode */ +#define CL_ADDRESS_NONE 0x1130 +#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 +#define CL_ADDRESS_CLAMP 0x1132 +#define CL_ADDRESS_REPEAT 0x1133 +#ifdef CL_VERSION_1_1 +#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 +#endif + +/* cl_filter_mode */ +#define CL_FILTER_NEAREST 0x1140 +#define CL_FILTER_LINEAR 0x1141 + +/* cl_sampler_info */ +#define CL_SAMPLER_REFERENCE_COUNT 0x1150 +#define CL_SAMPLER_CONTEXT 0x1151 +#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 +#define CL_SAMPLER_ADDRESSING_MODE 0x1153 +#define CL_SAMPLER_FILTER_MODE 0x1154 +#ifdef CL_VERSION_2_0 +/* These enumerants are for the cl_khr_mipmap_image extension. + They have since been added to cl_ext.h with an appropriate + KHR suffix, but are left here for backwards compatibility. */ +#define CL_SAMPLER_MIP_FILTER_MODE 0x1155 +#define CL_SAMPLER_LOD_MIN 0x1156 +#define CL_SAMPLER_LOD_MAX 0x1157 +#endif + +/* cl_map_flags - bitfield */ +#define CL_MAP_READ (1 << 0) +#define CL_MAP_WRITE (1 << 1) +#ifdef CL_VERSION_1_2 +#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) +#endif + +/* cl_program_info */ +#define CL_PROGRAM_REFERENCE_COUNT 0x1160 +#define CL_PROGRAM_CONTEXT 0x1161 +#define CL_PROGRAM_NUM_DEVICES 0x1162 +#define CL_PROGRAM_DEVICES 0x1163 +#define CL_PROGRAM_SOURCE 0x1164 +#define CL_PROGRAM_BINARY_SIZES 0x1165 +#define CL_PROGRAM_BINARIES 0x1166 +#ifdef CL_VERSION_1_2 +#define CL_PROGRAM_NUM_KERNELS 0x1167 +#define CL_PROGRAM_KERNEL_NAMES 0x1168 +#endif +#ifdef CL_VERSION_2_1 +#define CL_PROGRAM_IL 0x1169 +#endif +#ifdef CL_VERSION_2_2 +#define CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT 0x116A +#define CL_PROGRAM_SCOPE_GLOBAL_DTORS_PRESENT 0x116B +#endif + +/* cl_program_build_info */ +#define CL_PROGRAM_BUILD_STATUS 0x1181 +#define CL_PROGRAM_BUILD_OPTIONS 0x1182 +#define CL_PROGRAM_BUILD_LOG 0x1183 +#ifdef CL_VERSION_1_2 +#define CL_PROGRAM_BINARY_TYPE 0x1184 +#endif +#ifdef CL_VERSION_2_0 +#define CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE 0x1185 +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_program_binary_type */ +#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 +#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 +#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 +#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 + +#endif + +/* cl_build_status */ +#define CL_BUILD_SUCCESS 0 +#define CL_BUILD_NONE -1 +#define CL_BUILD_ERROR -2 +#define CL_BUILD_IN_PROGRESS -3 + +/* cl_kernel_info */ +#define CL_KERNEL_FUNCTION_NAME 0x1190 +#define CL_KERNEL_NUM_ARGS 0x1191 +#define CL_KERNEL_REFERENCE_COUNT 0x1192 +#define CL_KERNEL_CONTEXT 0x1193 +#define CL_KERNEL_PROGRAM 0x1194 +#ifdef CL_VERSION_1_2 +#define CL_KERNEL_ATTRIBUTES 0x1195 +#endif +#ifdef CL_VERSION_2_1 +#define CL_KERNEL_MAX_NUM_SUB_GROUPS 0x11B9 +#define CL_KERNEL_COMPILE_NUM_SUB_GROUPS 0x11BA +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_kernel_arg_info */ +#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 +#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 +#define CL_KERNEL_ARG_TYPE_NAME 0x1198 +#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 +#define CL_KERNEL_ARG_NAME 0x119A + +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_kernel_arg_address_qualifier */ +#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B +#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C +#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D +#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E + +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_kernel_arg_access_qualifier */ +#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 +#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 +#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 +#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 + +#endif + +#ifdef CL_VERSION_1_2 + +/* cl_kernel_arg_type_qualifier */ +#define CL_KERNEL_ARG_TYPE_NONE 0 +#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) +#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) +#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) +#ifdef CL_VERSION_2_0 +#define CL_KERNEL_ARG_TYPE_PIPE (1 << 3) +#endif + +#endif + +/* cl_kernel_work_group_info */ +#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 +#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 +#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 +#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 +#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 +#ifdef CL_VERSION_1_2 +#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 +#endif + +#ifdef CL_VERSION_2_1 + +/* cl_kernel_sub_group_info */ +#define CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE 0x2033 +#define CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE 0x2034 +#define CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT 0x11B8 + +#endif + +#ifdef CL_VERSION_2_0 + +/* cl_kernel_exec_info */ +#define CL_KERNEL_EXEC_INFO_SVM_PTRS 0x11B6 +#define CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM 0x11B7 + +#endif + +/* cl_event_info */ +#define CL_EVENT_COMMAND_QUEUE 0x11D0 +#define CL_EVENT_COMMAND_TYPE 0x11D1 +#define CL_EVENT_REFERENCE_COUNT 0x11D2 +#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 +#ifdef CL_VERSION_1_1 +#define CL_EVENT_CONTEXT 0x11D4 +#endif + +/* cl_command_type */ +#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 +#define CL_COMMAND_TASK 0x11F1 +#define CL_COMMAND_NATIVE_KERNEL 0x11F2 +#define CL_COMMAND_READ_BUFFER 0x11F3 +#define CL_COMMAND_WRITE_BUFFER 0x11F4 +#define CL_COMMAND_COPY_BUFFER 0x11F5 +#define CL_COMMAND_READ_IMAGE 0x11F6 +#define CL_COMMAND_WRITE_IMAGE 0x11F7 +#define CL_COMMAND_COPY_IMAGE 0x11F8 +#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 +#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA +#define CL_COMMAND_MAP_BUFFER 0x11FB +#define CL_COMMAND_MAP_IMAGE 0x11FC +#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD +#define CL_COMMAND_MARKER 0x11FE +#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF +#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 +#ifdef CL_VERSION_1_1 +#define CL_COMMAND_READ_BUFFER_RECT 0x1201 +#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 +#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 +#define CL_COMMAND_USER 0x1204 +#endif +#ifdef CL_VERSION_1_2 +#define CL_COMMAND_BARRIER 0x1205 +#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 +#define CL_COMMAND_FILL_BUFFER 0x1207 +#define CL_COMMAND_FILL_IMAGE 0x1208 +#endif +#ifdef CL_VERSION_2_0 +#define CL_COMMAND_SVM_FREE 0x1209 +#define CL_COMMAND_SVM_MEMCPY 0x120A +#define CL_COMMAND_SVM_MEMFILL 0x120B +#define CL_COMMAND_SVM_MAP 0x120C +#define CL_COMMAND_SVM_UNMAP 0x120D +#endif + +/* command execution status */ +#define CL_COMPLETE 0x0 +#define CL_RUNNING 0x1 +#define CL_SUBMITTED 0x2 +#define CL_QUEUED 0x3 + +#ifdef CL_VERSION_1_1 + +/* cl_buffer_create_type */ +#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 + +#endif + +/* cl_profiling_info */ +#define CL_PROFILING_COMMAND_QUEUED 0x1280 +#define CL_PROFILING_COMMAND_SUBMIT 0x1281 +#define CL_PROFILING_COMMAND_START 0x1282 +#define CL_PROFILING_COMMAND_END 0x1283 +#ifdef CL_VERSION_2_0 +#define CL_PROFILING_COMMAND_COMPLETE 0x1284 +#endif + +/********************************************************************************************************/ + +/* Platform API */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetPlatformIDs(cl_uint num_entries, + cl_platform_id * platforms, + cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetPlatformInfo(cl_platform_id platform, + cl_platform_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Device APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceIDs(cl_platform_id platform, + cl_device_type device_type, + cl_uint num_entries, + cl_device_id * devices, + cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceInfo(cl_device_id device, + cl_device_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clCreateSubDevices(cl_device_id in_device, + const cl_device_partition_property * properties, + cl_uint num_devices, + cl_device_id * out_devices, + cl_uint * num_devices_ret) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainDevice(cl_device_id device) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseDevice(cl_device_id device) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_VERSION_2_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetDefaultDeviceCommandQueue(cl_context context, + cl_device_id device, + cl_command_queue command_queue) CL_API_SUFFIX__VERSION_2_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceAndHostTimer(cl_device_id device, + cl_ulong* device_timestamp, + cl_ulong* host_timestamp) CL_API_SUFFIX__VERSION_2_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetHostTimer(cl_device_id device, + cl_ulong * host_timestamp) CL_API_SUFFIX__VERSION_2_1; + +#endif + +/* Context APIs */ +extern CL_API_ENTRY cl_context CL_API_CALL +clCreateContext(const cl_context_properties * properties, + cl_uint num_devices, + const cl_device_id * devices, + void (CL_CALLBACK * pfn_notify)(const char * errinfo, + const void * private_info, + size_t cb, + void * user_data), + void * user_data, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_context CL_API_CALL +clCreateContextFromType(const cl_context_properties * properties, + cl_device_type device_type, + void (CL_CALLBACK * pfn_notify)(const char * errinfo, + const void * private_info, + size_t cb, + void * user_data), + void * user_data, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainContext(cl_context context) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseContext(cl_context context) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetContextInfo(cl_context context, + cl_context_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Command Queue APIs */ + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_command_queue CL_API_CALL +clCreateCommandQueueWithProperties(cl_context context, + cl_device_id device, + const cl_queue_properties * properties, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_2_0; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainCommandQueue(cl_command_queue command_queue) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseCommandQueue(cl_command_queue command_queue) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetCommandQueueInfo(cl_command_queue command_queue, + cl_command_queue_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Memory Object APIs */ +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateBuffer(cl_context context, + cl_mem_flags flags, + size_t size, + void * host_ptr, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateSubBuffer(cl_mem buffer, + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_1; + +#endif + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateImage(cl_context context, + cl_mem_flags flags, + const cl_image_format * image_format, + const cl_image_desc * image_desc, + void * host_ptr, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreatePipe(cl_context context, + cl_mem_flags flags, + cl_uint pipe_packet_size, + cl_uint pipe_max_packets, + const cl_pipe_properties * properties, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_2_0; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainMemObject(cl_mem memobj) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseMemObject(cl_mem memobj) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetSupportedImageFormats(cl_context context, + cl_mem_flags flags, + cl_mem_object_type image_type, + cl_uint num_entries, + cl_image_format * image_formats, + cl_uint * num_image_formats) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetMemObjectInfo(cl_mem memobj, + cl_mem_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetImageInfo(cl_mem image, + cl_image_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetPipeInfo(cl_mem pipe, + cl_pipe_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_2_0; + +#endif + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetMemObjectDestructorCallback(cl_mem memobj, + void (CL_CALLBACK * pfn_notify)(cl_mem memobj, + void * user_data), + void * user_data) CL_API_SUFFIX__VERSION_1_1; + +#endif + +/* SVM Allocation APIs */ + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY void * CL_API_CALL +clSVMAlloc(cl_context context, + cl_svm_mem_flags flags, + size_t size, + cl_uint alignment) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY void CL_API_CALL +clSVMFree(cl_context context, + void * svm_pointer) CL_API_SUFFIX__VERSION_2_0; + +#endif + +/* Sampler APIs */ + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_sampler CL_API_CALL +clCreateSamplerWithProperties(cl_context context, + const cl_sampler_properties * sampler_properties, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_2_0; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainSampler(cl_sampler sampler) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseSampler(cl_sampler sampler) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetSamplerInfo(cl_sampler sampler, + cl_sampler_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Program Object APIs */ +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithSource(cl_context context, + cl_uint count, + const char ** strings, + const size_t * lengths, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithBinary(cl_context context, + cl_uint num_devices, + const cl_device_id * device_list, + const size_t * lengths, + const unsigned char ** binaries, + cl_int * binary_status, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithBuiltInKernels(cl_context context, + cl_uint num_devices, + const cl_device_id * device_list, + const char * kernel_names, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_VERSION_2_1 + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithIL(cl_context context, + const void* il, + size_t length, + cl_int* errcode_ret) CL_API_SUFFIX__VERSION_2_1; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainProgram(cl_program program) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseProgram(cl_program program) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clBuildProgram(cl_program program, + cl_uint num_devices, + const cl_device_id * device_list, + const char * options, + void (CL_CALLBACK * pfn_notify)(cl_program program, + void * user_data), + void * user_data) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clCompileProgram(cl_program program, + cl_uint num_devices, + const cl_device_id * device_list, + const char * options, + cl_uint num_input_headers, + const cl_program * input_headers, + const char ** header_include_names, + void (CL_CALLBACK * pfn_notify)(cl_program program, + void * user_data), + void * user_data) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_program CL_API_CALL +clLinkProgram(cl_context context, + cl_uint num_devices, + const cl_device_id * device_list, + const char * options, + cl_uint num_input_programs, + const cl_program * input_programs, + void (CL_CALLBACK * pfn_notify)(cl_program program, + void * user_data), + void * user_data, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_VERSION_2_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetProgramReleaseCallback(cl_program program, + void (CL_CALLBACK * pfn_notify)(cl_program program, + void * user_data), + void * user_data) CL_API_SUFFIX__VERSION_2_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetProgramSpecializationConstant(cl_program program, + cl_uint spec_id, + size_t spec_size, + const void* spec_value) CL_API_SUFFIX__VERSION_2_2; + +#endif + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clUnloadPlatformCompiler(cl_platform_id platform) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetProgramInfo(cl_program program, + cl_program_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetProgramBuildInfo(cl_program program, + cl_device_id device, + cl_program_build_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Kernel Object APIs */ +extern CL_API_ENTRY cl_kernel CL_API_CALL +clCreateKernel(cl_program program, + const char * kernel_name, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clCreateKernelsInProgram(cl_program program, + cl_uint num_kernels, + cl_kernel * kernels, + cl_uint * num_kernels_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_2_1 + +extern CL_API_ENTRY cl_kernel CL_API_CALL +clCloneKernel(cl_kernel source_kernel, + cl_int* errcode_ret) CL_API_SUFFIX__VERSION_2_1; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainKernel(cl_kernel kernel) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseKernel(cl_kernel kernel) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelArg(cl_kernel kernel, + cl_uint arg_index, + size_t arg_size, + const void * arg_value) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelArgSVMPointer(cl_kernel kernel, + cl_uint arg_index, + const void * arg_value) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelExecInfo(cl_kernel kernel, + cl_kernel_exec_info param_name, + size_t param_value_size, + const void * param_value) CL_API_SUFFIX__VERSION_2_0; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelInfo(cl_kernel kernel, + cl_kernel_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelArgInfo(cl_kernel kernel, + cl_uint arg_indx, + cl_kernel_arg_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelWorkGroupInfo(cl_kernel kernel, + cl_device_id device, + cl_kernel_work_group_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_2_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelSubGroupInfo(cl_kernel kernel, + cl_device_id device, + cl_kernel_sub_group_info param_name, + size_t input_value_size, + const void* input_value, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret) CL_API_SUFFIX__VERSION_2_1; + +#endif + +/* Event Object APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clWaitForEvents(cl_uint num_events, + const cl_event * event_list) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetEventInfo(cl_event event, + cl_event_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_event CL_API_CALL +clCreateUserEvent(cl_context context, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_1; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainEvent(cl_event event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseEvent(cl_event event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetUserEventStatus(cl_event event, + cl_int execution_status) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetEventCallback(cl_event event, + cl_int command_exec_callback_type, + void (CL_CALLBACK * pfn_notify)(cl_event event, + cl_int event_command_status, + void * user_data), + void * user_data) CL_API_SUFFIX__VERSION_1_1; + +#endif + +/* Profiling APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetEventProfilingInfo(cl_event event, + cl_profiling_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +/* Flush and Finish APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clFlush(cl_command_queue command_queue) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clFinish(cl_command_queue command_queue) CL_API_SUFFIX__VERSION_1_0; + +/* Enqueued Commands APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadBuffer(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_read, + size_t offset, + size_t size, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadBufferRect(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_read, + const size_t * buffer_offset, + const size_t * host_offset, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_1; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteBuffer(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_write, + size_t offset, + size_t size, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteBufferRect(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_write, + const size_t * buffer_offset, + const size_t * host_offset, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_1; + +#endif + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueFillBuffer(cl_command_queue command_queue, + cl_mem buffer, + const void * pattern, + size_t pattern_size, + size_t offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBuffer(cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_buffer, + size_t src_offset, + size_t dst_offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBufferRect(cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_buffer, + const size_t * src_origin, + const size_t * dst_origin, + const size_t * region, + size_t src_row_pitch, + size_t src_slice_pitch, + size_t dst_row_pitch, + size_t dst_slice_pitch, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_1; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadImage(cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_read, + const size_t * origin, + const size_t * region, + size_t row_pitch, + size_t slice_pitch, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteImage(cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_write, + const size_t * origin, + const size_t * region, + size_t input_row_pitch, + size_t input_slice_pitch, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueFillImage(cl_command_queue command_queue, + cl_mem image, + const void * fill_color, + const size_t * origin, + const size_t * region, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyImage(cl_command_queue command_queue, + cl_mem src_image, + cl_mem dst_image, + const size_t * src_origin, + const size_t * dst_origin, + const size_t * region, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyImageToBuffer(cl_command_queue command_queue, + cl_mem src_image, + cl_mem dst_buffer, + const size_t * src_origin, + const size_t * region, + size_t dst_offset, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBufferToImage(cl_command_queue command_queue, + cl_mem src_buffer, + cl_mem dst_image, + size_t src_offset, + const size_t * dst_origin, + const size_t * region, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY void * CL_API_CALL +clEnqueueMapBuffer(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_map, + cl_map_flags map_flags, + size_t offset, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY void * CL_API_CALL +clEnqueueMapImage(cl_command_queue command_queue, + cl_mem image, + cl_bool blocking_map, + cl_map_flags map_flags, + const size_t * origin, + const size_t * region, + size_t * image_row_pitch, + size_t * image_slice_pitch, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueUnmapMemObject(cl_command_queue command_queue, + cl_mem memobj, + void * mapped_ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueMigrateMemObjects(cl_command_queue command_queue, + cl_uint num_mem_objects, + const cl_mem * mem_objects, + cl_mem_migration_flags flags, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueNDRangeKernel(cl_command_queue command_queue, + cl_kernel kernel, + cl_uint work_dim, + const size_t * global_work_offset, + const size_t * global_work_size, + const size_t * local_work_size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueNativeKernel(cl_command_queue command_queue, + void (CL_CALLBACK * user_func)(void *), + void * args, + size_t cb_args, + cl_uint num_mem_objects, + const cl_mem * mem_list, + const void ** args_mem_loc, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueMarkerWithWaitList(cl_command_queue command_queue, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueBarrierWithWaitList(cl_command_queue command_queue, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_VERSION_2_0 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMFree(cl_command_queue command_queue, + cl_uint num_svm_pointers, + void * svm_pointers[], + void (CL_CALLBACK * pfn_free_func)(cl_command_queue queue, + cl_uint num_svm_pointers, + void * svm_pointers[], + void * user_data), + void * user_data, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMemcpy(cl_command_queue command_queue, + cl_bool blocking_copy, + void * dst_ptr, + const void * src_ptr, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMemFill(cl_command_queue command_queue, + void * svm_ptr, + const void * pattern, + size_t pattern_size, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMap(cl_command_queue command_queue, + cl_bool blocking_map, + cl_map_flags flags, + void * svm_ptr, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMUnmap(cl_command_queue command_queue, + void * svm_ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_0; + +#endif + +#ifdef CL_VERSION_2_1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMigrateMem(cl_command_queue command_queue, + cl_uint num_svm_pointers, + const void ** svm_pointers, + const size_t * sizes, + cl_mem_migration_flags flags, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_2_1; + +#endif + +#ifdef CL_VERSION_1_2 + +/* Extension function access + * + * Returns the extension function address for the given function name, + * or NULL if a valid function can not be found. The client must + * check to make sure the address is not NULL, before using or + * calling the returned function address. + */ +extern CL_API_ENTRY void * CL_API_CALL +clGetExtensionFunctionAddressForPlatform(cl_platform_id platform, + const char * func_name) CL_API_SUFFIX__VERSION_1_2; + +#endif + +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS + /* + * WARNING: + * This API introduces mutable state into the OpenCL implementation. It has been REMOVED + * to better facilitate thread safety. The 1.0 API is not thread safe. It is not tested by the + * OpenCL 1.1 conformance test, and consequently may not work or may not work dependably. + * It is likely to be non-performant. Use of this API is not advised. Use at your own risk. + * + * Software developers previously relying on this API are instructed to set the command queue + * properties when creating the queue, instead. + */ + extern CL_API_ENTRY cl_int CL_API_CALL + clSetCommandQueueProperty(cl_command_queue command_queue, + cl_command_queue_properties properties, + cl_bool enable, + cl_command_queue_properties * old_properties) CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED; +#endif /* CL_USE_DEPRECATED_OPENCL_1_0_APIS */ + +/* Deprecated OpenCL 1.1 APIs */ +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateImage2D(cl_context context, + cl_mem_flags flags, + const cl_image_format * image_format, + size_t image_width, + size_t image_height, + size_t image_row_pitch, + void * host_ptr, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateImage3D(cl_context context, + cl_mem_flags flags, + const cl_image_format * image_format, + size_t image_width, + size_t image_height, + size_t image_depth, + size_t image_row_pitch, + size_t image_slice_pitch, + void * host_ptr, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueMarker(cl_command_queue command_queue, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueWaitForEvents(cl_command_queue command_queue, + cl_uint num_events, + const cl_event * event_list) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueBarrier(cl_command_queue command_queue) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clUnloadCompiler(void) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED void * CL_API_CALL +clGetExtensionFunctionAddress(const char * func_name) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +/* Deprecated OpenCL 2.0 APIs */ +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_2_DEPRECATED cl_command_queue CL_API_CALL +clCreateCommandQueue(cl_context context, + cl_device_id device, + cl_command_queue_properties properties, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_2_DEPRECATED cl_sampler CL_API_CALL +clCreateSampler(cl_context context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_2_DEPRECATED cl_int CL_API_CALL +clEnqueueTask(cl_command_queue command_queue, + cl_kernel kernel, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_H */ diff --git a/src/3rdparty/CL/cl_d3d10.h b/src/3rdparty/CL/cl_d3d10.h new file mode 100644 index 000000000..d5960a43f --- /dev/null +++ b/src/3rdparty/CL/cl_d3d10.h @@ -0,0 +1,131 @@ +/********************************************************************************** + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ + +#ifndef __OPENCL_CL_D3D10_H +#define __OPENCL_CL_D3D10_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * cl_khr_d3d10_sharing */ +#define cl_khr_d3d10_sharing 1 + +typedef cl_uint cl_d3d10_device_source_khr; +typedef cl_uint cl_d3d10_device_set_khr; + +/******************************************************************************/ + +/* Error Codes */ +#define CL_INVALID_D3D10_DEVICE_KHR -1002 +#define CL_INVALID_D3D10_RESOURCE_KHR -1003 +#define CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR -1004 +#define CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR -1005 + +/* cl_d3d10_device_source_nv */ +#define CL_D3D10_DEVICE_KHR 0x4010 +#define CL_D3D10_DXGI_ADAPTER_KHR 0x4011 + +/* cl_d3d10_device_set_nv */ +#define CL_PREFERRED_DEVICES_FOR_D3D10_KHR 0x4012 +#define CL_ALL_DEVICES_FOR_D3D10_KHR 0x4013 + +/* cl_context_info */ +#define CL_CONTEXT_D3D10_DEVICE_KHR 0x4014 +#define CL_CONTEXT_D3D10_PREFER_SHARED_RESOURCES_KHR 0x402C + +/* cl_mem_info */ +#define CL_MEM_D3D10_RESOURCE_KHR 0x4015 + +/* cl_image_info */ +#define CL_IMAGE_D3D10_SUBRESOURCE_KHR 0x4016 + +/* cl_command_type */ +#define CL_COMMAND_ACQUIRE_D3D10_OBJECTS_KHR 0x4017 +#define CL_COMMAND_RELEASE_D3D10_OBJECTS_KHR 0x4018 + +/******************************************************************************/ + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromD3D10KHR_fn)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10BufferKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D10Buffer * resource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10Texture2DKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D10Texture2D * resource, + UINT subresource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D10Texture3DKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D10Texture3D * resource, + UINT subresource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireD3D10ObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseD3D10ObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_D3D10_H */ + diff --git a/src/3rdparty/CL/cl_d3d11.h b/src/3rdparty/CL/cl_d3d11.h new file mode 100644 index 000000000..39f907239 --- /dev/null +++ b/src/3rdparty/CL/cl_d3d11.h @@ -0,0 +1,131 @@ +/********************************************************************************** + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ + +#ifndef __OPENCL_CL_D3D11_H +#define __OPENCL_CL_D3D11_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * cl_khr_d3d11_sharing */ +#define cl_khr_d3d11_sharing 1 + +typedef cl_uint cl_d3d11_device_source_khr; +typedef cl_uint cl_d3d11_device_set_khr; + +/******************************************************************************/ + +/* Error Codes */ +#define CL_INVALID_D3D11_DEVICE_KHR -1006 +#define CL_INVALID_D3D11_RESOURCE_KHR -1007 +#define CL_D3D11_RESOURCE_ALREADY_ACQUIRED_KHR -1008 +#define CL_D3D11_RESOURCE_NOT_ACQUIRED_KHR -1009 + +/* cl_d3d11_device_source */ +#define CL_D3D11_DEVICE_KHR 0x4019 +#define CL_D3D11_DXGI_ADAPTER_KHR 0x401A + +/* cl_d3d11_device_set */ +#define CL_PREFERRED_DEVICES_FOR_D3D11_KHR 0x401B +#define CL_ALL_DEVICES_FOR_D3D11_KHR 0x401C + +/* cl_context_info */ +#define CL_CONTEXT_D3D11_DEVICE_KHR 0x401D +#define CL_CONTEXT_D3D11_PREFER_SHARED_RESOURCES_KHR 0x402D + +/* cl_mem_info */ +#define CL_MEM_D3D11_RESOURCE_KHR 0x401E + +/* cl_image_info */ +#define CL_IMAGE_D3D11_SUBRESOURCE_KHR 0x401F + +/* cl_command_type */ +#define CL_COMMAND_ACQUIRE_D3D11_OBJECTS_KHR 0x4020 +#define CL_COMMAND_RELEASE_D3D11_OBJECTS_KHR 0x4021 + +/******************************************************************************/ + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromD3D11KHR_fn)( + cl_platform_id platform, + cl_d3d11_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d11_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11BufferKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D11Buffer * resource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11Texture2DKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D11Texture2D * resource, + UINT subresource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromD3D11Texture3DKHR_fn)( + cl_context context, + cl_mem_flags flags, + ID3D11Texture3D * resource, + UINT subresource, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireD3D11ObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseD3D11ObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_D3D11_H */ + diff --git a/src/3rdparty/CL/cl_dx9_media_sharing.h b/src/3rdparty/CL/cl_dx9_media_sharing.h new file mode 100644 index 000000000..2729e8b9e --- /dev/null +++ b/src/3rdparty/CL/cl_dx9_media_sharing.h @@ -0,0 +1,132 @@ +/********************************************************************************** + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ + +#ifndef __OPENCL_CL_DX9_MEDIA_SHARING_H +#define __OPENCL_CL_DX9_MEDIA_SHARING_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ +/* cl_khr_dx9_media_sharing */ +#define cl_khr_dx9_media_sharing 1 + +typedef cl_uint cl_dx9_media_adapter_type_khr; +typedef cl_uint cl_dx9_media_adapter_set_khr; + +#if defined(_WIN32) +#include +typedef struct _cl_dx9_surface_info_khr +{ + IDirect3DSurface9 *resource; + HANDLE shared_handle; +} cl_dx9_surface_info_khr; +#endif + + +/******************************************************************************/ + +/* Error Codes */ +#define CL_INVALID_DX9_MEDIA_ADAPTER_KHR -1010 +#define CL_INVALID_DX9_MEDIA_SURFACE_KHR -1011 +#define CL_DX9_MEDIA_SURFACE_ALREADY_ACQUIRED_KHR -1012 +#define CL_DX9_MEDIA_SURFACE_NOT_ACQUIRED_KHR -1013 + +/* cl_media_adapter_type_khr */ +#define CL_ADAPTER_D3D9_KHR 0x2020 +#define CL_ADAPTER_D3D9EX_KHR 0x2021 +#define CL_ADAPTER_DXVA_KHR 0x2022 + +/* cl_media_adapter_set_khr */ +#define CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR 0x2023 +#define CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR 0x2024 + +/* cl_context_info */ +#define CL_CONTEXT_ADAPTER_D3D9_KHR 0x2025 +#define CL_CONTEXT_ADAPTER_D3D9EX_KHR 0x2026 +#define CL_CONTEXT_ADAPTER_DXVA_KHR 0x2027 + +/* cl_mem_info */ +#define CL_MEM_DX9_MEDIA_ADAPTER_TYPE_KHR 0x2028 +#define CL_MEM_DX9_MEDIA_SURFACE_INFO_KHR 0x2029 + +/* cl_image_info */ +#define CL_IMAGE_DX9_MEDIA_PLANE_KHR 0x202A + +/* cl_command_type */ +#define CL_COMMAND_ACQUIRE_DX9_MEDIA_SURFACES_KHR 0x202B +#define CL_COMMAND_RELEASE_DX9_MEDIA_SURFACES_KHR 0x202C + +/******************************************************************************/ + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetDeviceIDsFromDX9MediaAdapterKHR_fn)( + cl_platform_id platform, + cl_uint num_media_adapters, + cl_dx9_media_adapter_type_khr * media_adapter_type, + void * media_adapters, + cl_dx9_media_adapter_set_khr media_adapter_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint * num_devices) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromDX9MediaSurfaceKHR_fn)( + cl_context context, + cl_mem_flags flags, + cl_dx9_media_adapter_type_khr adapter_type, + void * surface_info, + cl_uint plane, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireDX9MediaSurfacesKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseDX9MediaSurfacesKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_2; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_DX9_MEDIA_SHARING_H */ + diff --git a/src/3rdparty/CL/cl_dx9_media_sharing_intel.h b/src/3rdparty/CL/cl_dx9_media_sharing_intel.h new file mode 100644 index 000000000..737e68564 --- /dev/null +++ b/src/3rdparty/CL/cl_dx9_media_sharing_intel.h @@ -0,0 +1,182 @@ +/********************************************************************************** + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ +/*****************************************************************************\ + +Copyright (c) 2013-2019 Intel Corporation All Rights Reserved. + +THESE MATERIALS ARE PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE +MATERIALS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +File Name: cl_dx9_media_sharing_intel.h + +Abstract: + +Notes: + +\*****************************************************************************/ + +#ifndef __OPENCL_CL_DX9_MEDIA_SHARING_INTEL_H +#define __OPENCL_CL_DX9_MEDIA_SHARING_INTEL_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************** +* cl_intel_dx9_media_sharing extension * +****************************************/ + +#define cl_intel_dx9_media_sharing 1 + +typedef cl_uint cl_dx9_device_source_intel; +typedef cl_uint cl_dx9_device_set_intel; + +/* error codes */ +#define CL_INVALID_DX9_DEVICE_INTEL -1010 +#define CL_INVALID_DX9_RESOURCE_INTEL -1011 +#define CL_DX9_RESOURCE_ALREADY_ACQUIRED_INTEL -1012 +#define CL_DX9_RESOURCE_NOT_ACQUIRED_INTEL -1013 + +/* cl_dx9_device_source_intel */ +#define CL_D3D9_DEVICE_INTEL 0x4022 +#define CL_D3D9EX_DEVICE_INTEL 0x4070 +#define CL_DXVA_DEVICE_INTEL 0x4071 + +/* cl_dx9_device_set_intel */ +#define CL_PREFERRED_DEVICES_FOR_DX9_INTEL 0x4024 +#define CL_ALL_DEVICES_FOR_DX9_INTEL 0x4025 + +/* cl_context_info */ +#define CL_CONTEXT_D3D9_DEVICE_INTEL 0x4026 +#define CL_CONTEXT_D3D9EX_DEVICE_INTEL 0x4072 +#define CL_CONTEXT_DXVA_DEVICE_INTEL 0x4073 + +/* cl_mem_info */ +#define CL_MEM_DX9_RESOURCE_INTEL 0x4027 +#define CL_MEM_DX9_SHARED_HANDLE_INTEL 0x4074 + +/* cl_image_info */ +#define CL_IMAGE_DX9_PLANE_INTEL 0x4075 + +/* cl_command_type */ +#define CL_COMMAND_ACQUIRE_DX9_OBJECTS_INTEL 0x402A +#define CL_COMMAND_RELEASE_DX9_OBJECTS_INTEL 0x402B +/******************************************************************************/ + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceIDsFromDX9INTEL( + cl_platform_id platform, + cl_dx9_device_source_intel dx9_device_source, + void* dx9_object, + cl_dx9_device_set_intel dx9_device_set, + cl_uint num_entries, + cl_device_id* devices, + cl_uint* num_devices) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL* clGetDeviceIDsFromDX9INTEL_fn)( + cl_platform_id platform, + cl_dx9_device_source_intel dx9_device_source, + void* dx9_object, + cl_dx9_device_set_intel dx9_device_set, + cl_uint num_entries, + cl_device_id* devices, + cl_uint* num_devices) CL_EXT_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromDX9MediaSurfaceINTEL( + cl_context context, + cl_mem_flags flags, + IDirect3DSurface9* resource, + HANDLE sharedHandle, + UINT plane, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromDX9MediaSurfaceINTEL_fn)( + cl_context context, + cl_mem_flags flags, + IDirect3DSurface9* resource, + HANDLE sharedHandle, + UINT plane, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireDX9ObjectsINTEL( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireDX9ObjectsINTEL_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseDX9ObjectsINTEL( + cl_command_queue command_queue, + cl_uint num_objects, + cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseDX9ObjectsINTEL_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_1; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_DX9_MEDIA_SHARING_INTEL_H */ + diff --git a/src/3rdparty/CL/cl_egl.h b/src/3rdparty/CL/cl_egl.h new file mode 100644 index 000000000..bc4d998eb --- /dev/null +++ b/src/3rdparty/CL/cl_egl.h @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#ifndef __OPENCL_CL_EGL_H +#define __OPENCL_CL_EGL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Command type for events created with clEnqueueAcquireEGLObjectsKHR */ +#define CL_COMMAND_EGL_FENCE_SYNC_OBJECT_KHR 0x202F +#define CL_COMMAND_ACQUIRE_EGL_OBJECTS_KHR 0x202D +#define CL_COMMAND_RELEASE_EGL_OBJECTS_KHR 0x202E + +/* Error type for clCreateFromEGLImageKHR */ +#define CL_INVALID_EGL_OBJECT_KHR -1093 +#define CL_EGL_RESOURCE_NOT_ACQUIRED_KHR -1092 + +/* CLeglImageKHR is an opaque handle to an EGLImage */ +typedef void* CLeglImageKHR; + +/* CLeglDisplayKHR is an opaque handle to an EGLDisplay */ +typedef void* CLeglDisplayKHR; + +/* CLeglSyncKHR is an opaque handle to an EGLSync object */ +typedef void* CLeglSyncKHR; + +/* properties passed to clCreateFromEGLImageKHR */ +typedef intptr_t cl_egl_image_properties_khr; + + +#define cl_khr_egl_image 1 + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromEGLImageKHR(cl_context context, + CLeglDisplayKHR egldisplay, + CLeglImageKHR eglimage, + cl_mem_flags flags, + const cl_egl_image_properties_khr * properties, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL *clCreateFromEGLImageKHR_fn)( + cl_context context, + CLeglDisplayKHR egldisplay, + CLeglImageKHR eglimage, + cl_mem_flags flags, + const cl_egl_image_properties_khr * properties, + cl_int * errcode_ret); + + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireEGLObjectsKHR(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireEGLObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event); + + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseEGLObjectsKHR(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseEGLObjectsKHR_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event); + + +#define cl_khr_egl_event 1 + +extern CL_API_ENTRY cl_event CL_API_CALL +clCreateEventFromEGLSyncKHR(cl_context context, + CLeglSyncKHR sync, + CLeglDisplayKHR display, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_event (CL_API_CALL *clCreateEventFromEGLSyncKHR_fn)( + cl_context context, + CLeglSyncKHR sync, + CLeglDisplayKHR display, + cl_int * errcode_ret); + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_EGL_H */ diff --git a/src/3rdparty/CL/cl_ext.h b/src/3rdparty/CL/cl_ext.h new file mode 100644 index 000000000..5c185915c --- /dev/null +++ b/src/3rdparty/CL/cl_ext.h @@ -0,0 +1,762 @@ +/******************************************************************************* + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/* cl_ext.h contains OpenCL extensions which don't have external */ +/* (OpenGL, D3D) dependencies. */ + +#ifndef __CL_EXT_H +#define __CL_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* cl_khr_fp64 extension - no extension #define since it has no functions */ +/* CL_DEVICE_DOUBLE_FP_CONFIG is defined in CL.h for OpenCL >= 120 */ + +#if CL_TARGET_OPENCL_VERSION <= 110 +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +#endif + +/* cl_khr_fp16 extension - no extension #define since it has no functions */ +#define CL_DEVICE_HALF_FP_CONFIG 0x1033 + +/* Memory object destruction + * + * Apple extension for use to manage externally allocated buffers used with cl_mem objects with CL_MEM_USE_HOST_PTR + * + * Registers a user callback function that will be called when the memory object is deleted and its resources + * freed. Each call to clSetMemObjectCallbackFn registers the specified user callback function on a callback + * stack associated with memobj. The registered user callback functions are called in the reverse order in + * which they were registered. The user callback functions are called and then the memory object is deleted + * and its resources freed. This provides a mechanism for the application (and libraries) using memobj to be + * notified when the memory referenced by host_ptr, specified when the memory object is created and used as + * the storage bits for the memory object, can be reused or freed. + * + * The application may not call CL api's with the cl_mem object passed to the pfn_notify. + * + * Please check for the "cl_APPLE_SetMemObjectDestructor" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) + * before using. + */ +#define cl_APPLE_SetMemObjectDestructor 1 +cl_int CL_API_ENTRY clSetMemObjectDestructorAPPLE( cl_mem memobj, + void (* pfn_notify)(cl_mem memobj, void * user_data), + void * user_data) CL_EXT_SUFFIX__VERSION_1_0; + + +/* Context Logging Functions + * + * The next three convenience functions are intended to be used as the pfn_notify parameter to clCreateContext(). + * Please check for the "cl_APPLE_ContextLoggingFunctions" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) + * before using. + * + * clLogMessagesToSystemLog forwards on all log messages to the Apple System Logger + */ +#define cl_APPLE_ContextLoggingFunctions 1 +extern void CL_API_ENTRY clLogMessagesToSystemLogAPPLE( const char * errstr, + const void * private_info, + size_t cb, + void * user_data) CL_EXT_SUFFIX__VERSION_1_0; + +/* clLogMessagesToStdout sends all log messages to the file descriptor stdout */ +extern void CL_API_ENTRY clLogMessagesToStdoutAPPLE( const char * errstr, + const void * private_info, + size_t cb, + void * user_data) CL_EXT_SUFFIX__VERSION_1_0; + +/* clLogMessagesToStderr sends all log messages to the file descriptor stderr */ +extern void CL_API_ENTRY clLogMessagesToStderrAPPLE( const char * errstr, + const void * private_info, + size_t cb, + void * user_data) CL_EXT_SUFFIX__VERSION_1_0; + + +/************************ +* cl_khr_icd extension * +************************/ +#define cl_khr_icd 1 + +/* cl_platform_info */ +#define CL_PLATFORM_ICD_SUFFIX_KHR 0x0920 + +/* Additional Error Codes */ +#define CL_PLATFORM_NOT_FOUND_KHR -1001 + +extern CL_API_ENTRY cl_int CL_API_CALL +clIcdGetPlatformIDsKHR(cl_uint num_entries, + cl_platform_id * platforms, + cl_uint * num_platforms); + +typedef CL_API_ENTRY cl_int +(CL_API_CALL *clIcdGetPlatformIDsKHR_fn)(cl_uint num_entries, + cl_platform_id * platforms, + cl_uint * num_platforms); + + +/******************************* + * cl_khr_il_program extension * + *******************************/ +#define cl_khr_il_program 1 + +/* New property to clGetDeviceInfo for retrieving supported intermediate + * languages + */ +#define CL_DEVICE_IL_VERSION_KHR 0x105B + +/* New property to clGetProgramInfo for retrieving for retrieving the IL of a + * program + */ +#define CL_PROGRAM_IL_KHR 0x1169 + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithILKHR(cl_context context, + const void * il, + size_t length, + cl_int * errcode_ret); + +typedef CL_API_ENTRY cl_program +(CL_API_CALL *clCreateProgramWithILKHR_fn)(cl_context context, + const void * il, + size_t length, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +/* Extension: cl_khr_image2d_from_buffer + * + * This extension allows a 2D image to be created from a cl_mem buffer without + * a copy. The type associated with a 2D image created from a buffer in an + * OpenCL program is image2d_t. Both the sampler and sampler-less read_image + * built-in functions are supported for 2D images and 2D images created from + * a buffer. Similarly, the write_image built-ins are also supported for 2D + * images created from a buffer. + * + * When the 2D image from buffer is created, the client must specify the + * width, height, image format (i.e. channel order and channel data type) + * and optionally the row pitch. + * + * The pitch specified must be a multiple of + * CL_DEVICE_IMAGE_PITCH_ALIGNMENT_KHR pixels. + * The base address of the buffer must be aligned to + * CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT_KHR pixels. + */ + +#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT_KHR 0x104A +#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT_KHR 0x104B + + +/************************************** + * cl_khr_initialize_memory extension * + **************************************/ + +#define CL_CONTEXT_MEMORY_INITIALIZE_KHR 0x2030 + + +/************************************** + * cl_khr_terminate_context extension * + **************************************/ + +#define CL_DEVICE_TERMINATE_CAPABILITY_KHR 0x2031 +#define CL_CONTEXT_TERMINATE_KHR 0x2032 + +#define cl_khr_terminate_context 1 +extern CL_API_ENTRY cl_int CL_API_CALL +clTerminateContextKHR(cl_context context) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL *clTerminateContextKHR_fn)(cl_context context) CL_EXT_SUFFIX__VERSION_1_2; + + +/* + * Extension: cl_khr_spir + * + * This extension adds support to create an OpenCL program object from a + * Standard Portable Intermediate Representation (SPIR) instance + */ + +#define CL_DEVICE_SPIR_VERSIONS 0x40E0 +#define CL_PROGRAM_BINARY_TYPE_INTERMEDIATE 0x40E1 + + +/***************************************** + * cl_khr_create_command_queue extension * + *****************************************/ +#define cl_khr_create_command_queue 1 + +typedef cl_bitfield cl_queue_properties_khr; + +extern CL_API_ENTRY cl_command_queue CL_API_CALL +clCreateCommandQueueWithPropertiesKHR(cl_context context, + cl_device_id device, + const cl_queue_properties_khr* properties, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_command_queue +(CL_API_CALL *clCreateCommandQueueWithPropertiesKHR_fn)(cl_context context, + cl_device_id device, + const cl_queue_properties_khr* properties, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + + +/****************************************** +* cl_nv_device_attribute_query extension * +******************************************/ + +/* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ +#define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 +#define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 +#define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 +#define CL_DEVICE_WARP_SIZE_NV 0x4003 +#define CL_DEVICE_GPU_OVERLAP_NV 0x4004 +#define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 +#define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 + + +/********************************* +* cl_amd_device_attribute_query * +*********************************/ + +#define CL_DEVICE_PROFILING_TIMER_OFFSET_AMD 0x4036 + + +/********************************* +* cl_arm_printf extension +*********************************/ + +#define CL_PRINTF_CALLBACK_ARM 0x40B0 +#define CL_PRINTF_BUFFERSIZE_ARM 0x40B1 + + +/*********************************** +* cl_ext_device_fission extension +***********************************/ +#define cl_ext_device_fission 1 + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseDeviceEXT(cl_device_id device) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL *clReleaseDeviceEXT_fn)(cl_device_id device) CL_EXT_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainDeviceEXT(cl_device_id device) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL *clRetainDeviceEXT_fn)(cl_device_id device) CL_EXT_SUFFIX__VERSION_1_1; + +typedef cl_ulong cl_device_partition_property_ext; +extern CL_API_ENTRY cl_int CL_API_CALL +clCreateSubDevicesEXT(cl_device_id in_device, + const cl_device_partition_property_ext * properties, + cl_uint num_entries, + cl_device_id * out_devices, + cl_uint * num_devices) CL_EXT_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clCreateSubDevicesEXT_fn)(cl_device_id in_device, + const cl_device_partition_property_ext * properties, + cl_uint num_entries, + cl_device_id * out_devices, + cl_uint * num_devices) CL_EXT_SUFFIX__VERSION_1_1; + +/* cl_device_partition_property_ext */ +#define CL_DEVICE_PARTITION_EQUALLY_EXT 0x4050 +#define CL_DEVICE_PARTITION_BY_COUNTS_EXT 0x4051 +#define CL_DEVICE_PARTITION_BY_NAMES_EXT 0x4052 +#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT 0x4053 + +/* clDeviceGetInfo selectors */ +#define CL_DEVICE_PARENT_DEVICE_EXT 0x4054 +#define CL_DEVICE_PARTITION_TYPES_EXT 0x4055 +#define CL_DEVICE_AFFINITY_DOMAINS_EXT 0x4056 +#define CL_DEVICE_REFERENCE_COUNT_EXT 0x4057 +#define CL_DEVICE_PARTITION_STYLE_EXT 0x4058 + +/* error codes */ +#define CL_DEVICE_PARTITION_FAILED_EXT -1057 +#define CL_INVALID_PARTITION_COUNT_EXT -1058 +#define CL_INVALID_PARTITION_NAME_EXT -1059 + +/* CL_AFFINITY_DOMAINs */ +#define CL_AFFINITY_DOMAIN_L1_CACHE_EXT 0x1 +#define CL_AFFINITY_DOMAIN_L2_CACHE_EXT 0x2 +#define CL_AFFINITY_DOMAIN_L3_CACHE_EXT 0x3 +#define CL_AFFINITY_DOMAIN_L4_CACHE_EXT 0x4 +#define CL_AFFINITY_DOMAIN_NUMA_EXT 0x10 +#define CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT 0x100 + +/* cl_device_partition_property_ext list terminators */ +#define CL_PROPERTIES_LIST_END_EXT ((cl_device_partition_property_ext) 0) +#define CL_PARTITION_BY_COUNTS_LIST_END_EXT ((cl_device_partition_property_ext) 0) +#define CL_PARTITION_BY_NAMES_LIST_END_EXT ((cl_device_partition_property_ext) 0 - 1) + + +/*********************************** + * cl_ext_migrate_memobject extension definitions + ***********************************/ +#define cl_ext_migrate_memobject 1 + +typedef cl_bitfield cl_mem_migration_flags_ext; + +#define CL_MIGRATE_MEM_OBJECT_HOST_EXT 0x1 + +#define CL_COMMAND_MIGRATE_MEM_OBJECT_EXT 0x4040 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueMigrateMemObjectEXT(cl_command_queue command_queue, + cl_uint num_mem_objects, + const cl_mem * mem_objects, + cl_mem_migration_flags_ext flags, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event); + +typedef CL_API_ENTRY cl_int +(CL_API_CALL *clEnqueueMigrateMemObjectEXT_fn)(cl_command_queue command_queue, + cl_uint num_mem_objects, + const cl_mem * mem_objects, + cl_mem_migration_flags_ext flags, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event); + + +/********************************* +* cl_qcom_ext_host_ptr extension +*********************************/ +#define cl_qcom_ext_host_ptr 1 + +#define CL_MEM_EXT_HOST_PTR_QCOM (1 << 29) + +#define CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM 0x40A0 +#define CL_DEVICE_PAGE_SIZE_QCOM 0x40A1 +#define CL_IMAGE_ROW_ALIGNMENT_QCOM 0x40A2 +#define CL_IMAGE_SLICE_ALIGNMENT_QCOM 0x40A3 +#define CL_MEM_HOST_UNCACHED_QCOM 0x40A4 +#define CL_MEM_HOST_WRITEBACK_QCOM 0x40A5 +#define CL_MEM_HOST_WRITETHROUGH_QCOM 0x40A6 +#define CL_MEM_HOST_WRITE_COMBINING_QCOM 0x40A7 + +typedef cl_uint cl_image_pitch_info_qcom; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceImageInfoQCOM(cl_device_id device, + size_t image_width, + size_t image_height, + const cl_image_format *image_format, + cl_image_pitch_info_qcom param_name, + size_t param_value_size, + void *param_value, + size_t *param_value_size_ret); + +typedef struct _cl_mem_ext_host_ptr +{ + /* Type of external memory allocation. */ + /* Legal values will be defined in layered extensions. */ + cl_uint allocation_type; + + /* Host cache policy for this external memory allocation. */ + cl_uint host_cache_policy; + +} cl_mem_ext_host_ptr; + + +/******************************************* +* cl_qcom_ext_host_ptr_iocoherent extension +********************************************/ + +/* Cache policy specifying io-coherence */ +#define CL_MEM_HOST_IOCOHERENT_QCOM 0x40A9 + + +/********************************* +* cl_qcom_ion_host_ptr extension +*********************************/ + +#define CL_MEM_ION_HOST_PTR_QCOM 0x40A8 + +typedef struct _cl_mem_ion_host_ptr +{ + /* Type of external memory allocation. */ + /* Must be CL_MEM_ION_HOST_PTR_QCOM for ION allocations. */ + cl_mem_ext_host_ptr ext_host_ptr; + + /* ION file descriptor */ + int ion_filedesc; + + /* Host pointer to the ION allocated memory */ + void* ion_hostptr; + +} cl_mem_ion_host_ptr; + + +/********************************* +* cl_qcom_android_native_buffer_host_ptr extension +*********************************/ + +#define CL_MEM_ANDROID_NATIVE_BUFFER_HOST_PTR_QCOM 0x40C6 + +typedef struct _cl_mem_android_native_buffer_host_ptr +{ + /* Type of external memory allocation. */ + /* Must be CL_MEM_ANDROID_NATIVE_BUFFER_HOST_PTR_QCOM for Android native buffers. */ + cl_mem_ext_host_ptr ext_host_ptr; + + /* Virtual pointer to the android native buffer */ + void* anb_ptr; + +} cl_mem_android_native_buffer_host_ptr; + + +/****************************************** + * cl_img_yuv_image extension * + ******************************************/ + +/* Image formats used in clCreateImage */ +#define CL_NV21_IMG 0x40D0 +#define CL_YV12_IMG 0x40D1 + + +/****************************************** + * cl_img_cached_allocations extension * + ******************************************/ + +/* Flag values used by clCreateBuffer */ +#define CL_MEM_USE_UNCACHED_CPU_MEMORY_IMG (1 << 26) +#define CL_MEM_USE_CACHED_CPU_MEMORY_IMG (1 << 27) + + +/****************************************** + * cl_img_use_gralloc_ptr extension * + ******************************************/ +#define cl_img_use_gralloc_ptr 1 + +/* Flag values used by clCreateBuffer */ +#define CL_MEM_USE_GRALLOC_PTR_IMG (1 << 28) + +/* To be used by clGetEventInfo: */ +#define CL_COMMAND_ACQUIRE_GRALLOC_OBJECTS_IMG 0x40D2 +#define CL_COMMAND_RELEASE_GRALLOC_OBJECTS_IMG 0x40D3 + +/* Error code from clEnqueueReleaseGrallocObjectsIMG */ +#define CL_GRALLOC_RESOURCE_NOT_ACQUIRED_IMG 0x40D4 + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireGrallocObjectsIMG(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseGrallocObjectsIMG(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + + +/********************************* +* cl_khr_subgroups extension +*********************************/ +#define cl_khr_subgroups 1 + +#if !defined(CL_VERSION_2_1) +/* For OpenCL 2.1 and newer, cl_kernel_sub_group_info is declared in CL.h. + In hindsight, there should have been a khr suffix on this type for + the extension, but keeping it un-suffixed to maintain backwards + compatibility. */ +typedef cl_uint cl_kernel_sub_group_info; +#endif + +/* cl_kernel_sub_group_info */ +#define CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE_KHR 0x2033 +#define CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR 0x2034 + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelSubGroupInfoKHR(cl_kernel in_kernel, + cl_device_id in_device, + cl_kernel_sub_group_info param_name, + size_t input_value_size, + const void * input_value, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_EXT_SUFFIX__VERSION_2_0_DEPRECATED; + +typedef CL_API_ENTRY cl_int +(CL_API_CALL * clGetKernelSubGroupInfoKHR_fn)(cl_kernel in_kernel, + cl_device_id in_device, + cl_kernel_sub_group_info param_name, + size_t input_value_size, + const void * input_value, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_EXT_SUFFIX__VERSION_2_0_DEPRECATED; + + +/********************************* +* cl_khr_mipmap_image extension +*********************************/ + +/* cl_sampler_properties */ +#define CL_SAMPLER_MIP_FILTER_MODE_KHR 0x1155 +#define CL_SAMPLER_LOD_MIN_KHR 0x1156 +#define CL_SAMPLER_LOD_MAX_KHR 0x1157 + + +/********************************* +* cl_khr_priority_hints extension +*********************************/ +/* This extension define is for backwards compatibility. + It shouldn't be required since this extension has no new functions. */ +#define cl_khr_priority_hints 1 + +typedef cl_uint cl_queue_priority_khr; + +/* cl_command_queue_properties */ +#define CL_QUEUE_PRIORITY_KHR 0x1096 + +/* cl_queue_priority_khr */ +#define CL_QUEUE_PRIORITY_HIGH_KHR (1<<0) +#define CL_QUEUE_PRIORITY_MED_KHR (1<<1) +#define CL_QUEUE_PRIORITY_LOW_KHR (1<<2) + + +/********************************* +* cl_khr_throttle_hints extension +*********************************/ +/* This extension define is for backwards compatibility. + It shouldn't be required since this extension has no new functions. */ +#define cl_khr_throttle_hints 1 + +typedef cl_uint cl_queue_throttle_khr; + +/* cl_command_queue_properties */ +#define CL_QUEUE_THROTTLE_KHR 0x1097 + +/* cl_queue_throttle_khr */ +#define CL_QUEUE_THROTTLE_HIGH_KHR (1<<0) +#define CL_QUEUE_THROTTLE_MED_KHR (1<<1) +#define CL_QUEUE_THROTTLE_LOW_KHR (1<<2) + + +/********************************* +* cl_khr_subgroup_named_barrier +*********************************/ +/* This extension define is for backwards compatibility. + It shouldn't be required since this extension has no new functions. */ +#define cl_khr_subgroup_named_barrier 1 + +/* cl_device_info */ +#define CL_DEVICE_MAX_NAMED_BARRIER_COUNT_KHR 0x2035 + + +/********************************** + * cl_arm_import_memory extension * + **********************************/ +#define cl_arm_import_memory 1 + +typedef intptr_t cl_import_properties_arm; + +/* Default and valid proporties name for cl_arm_import_memory */ +#define CL_IMPORT_TYPE_ARM 0x40B2 + +/* Host process memory type default value for CL_IMPORT_TYPE_ARM property */ +#define CL_IMPORT_TYPE_HOST_ARM 0x40B3 + +/* DMA BUF memory type value for CL_IMPORT_TYPE_ARM property */ +#define CL_IMPORT_TYPE_DMA_BUF_ARM 0x40B4 + +/* Protected DMA BUF memory type value for CL_IMPORT_TYPE_ARM property */ +#define CL_IMPORT_TYPE_PROTECTED_ARM 0x40B5 + +/* This extension adds a new function that allows for direct memory import into + * OpenCL via the clImportMemoryARM function. + * + * Memory imported through this interface will be mapped into the device's page + * tables directly, providing zero copy access. It will never fall back to copy + * operations and aliased buffers. + * + * Types of memory supported for import are specified as additional extension + * strings. + * + * This extension produces cl_mem allocations which are compatible with all other + * users of cl_mem in the standard API. + * + * This extension maps pages with the same properties as the normal buffer creation + * function clCreateBuffer. + */ +extern CL_API_ENTRY cl_mem CL_API_CALL +clImportMemoryARM( cl_context context, + cl_mem_flags flags, + const cl_import_properties_arm *properties, + void *memory, + size_t size, + cl_int *errcode_ret) CL_EXT_SUFFIX__VERSION_1_0; + + +/****************************************** + * cl_arm_shared_virtual_memory extension * + ******************************************/ +#define cl_arm_shared_virtual_memory 1 + +/* Used by clGetDeviceInfo */ +#define CL_DEVICE_SVM_CAPABILITIES_ARM 0x40B6 + +/* Used by clGetMemObjectInfo */ +#define CL_MEM_USES_SVM_POINTER_ARM 0x40B7 + +/* Used by clSetKernelExecInfoARM: */ +#define CL_KERNEL_EXEC_INFO_SVM_PTRS_ARM 0x40B8 +#define CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM_ARM 0x40B9 + +/* To be used by clGetEventInfo: */ +#define CL_COMMAND_SVM_FREE_ARM 0x40BA +#define CL_COMMAND_SVM_MEMCPY_ARM 0x40BB +#define CL_COMMAND_SVM_MEMFILL_ARM 0x40BC +#define CL_COMMAND_SVM_MAP_ARM 0x40BD +#define CL_COMMAND_SVM_UNMAP_ARM 0x40BE + +/* Flag values returned by clGetDeviceInfo with CL_DEVICE_SVM_CAPABILITIES_ARM as the param_name. */ +#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER_ARM (1 << 0) +#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER_ARM (1 << 1) +#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM_ARM (1 << 2) +#define CL_DEVICE_SVM_ATOMICS_ARM (1 << 3) + +/* Flag values used by clSVMAllocARM: */ +#define CL_MEM_SVM_FINE_GRAIN_BUFFER_ARM (1 << 10) +#define CL_MEM_SVM_ATOMICS_ARM (1 << 11) + +typedef cl_bitfield cl_svm_mem_flags_arm; +typedef cl_uint cl_kernel_exec_info_arm; +typedef cl_bitfield cl_device_svm_capabilities_arm; + +extern CL_API_ENTRY void * CL_API_CALL +clSVMAllocARM(cl_context context, + cl_svm_mem_flags_arm flags, + size_t size, + cl_uint alignment) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY void CL_API_CALL +clSVMFreeARM(cl_context context, + void * svm_pointer) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMFreeARM(cl_command_queue command_queue, + cl_uint num_svm_pointers, + void * svm_pointers[], + void (CL_CALLBACK * pfn_free_func)(cl_command_queue queue, + cl_uint num_svm_pointers, + void * svm_pointers[], + void * user_data), + void * user_data, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMemcpyARM(cl_command_queue command_queue, + cl_bool blocking_copy, + void * dst_ptr, + const void * src_ptr, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMemFillARM(cl_command_queue command_queue, + void * svm_ptr, + const void * pattern, + size_t pattern_size, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMMapARM(cl_command_queue command_queue, + cl_bool blocking_map, + cl_map_flags flags, + void * svm_ptr, + size_t size, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueSVMUnmapARM(cl_command_queue command_queue, + void * svm_ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelArgSVMPointerARM(cl_kernel kernel, + cl_uint arg_index, + const void * arg_value) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelExecInfoARM(cl_kernel kernel, + cl_kernel_exec_info_arm param_name, + size_t param_value_size, + const void * param_value) CL_EXT_SUFFIX__VERSION_1_2; + +/******************************** + * cl_arm_get_core_id extension * + ********************************/ + +#ifdef CL_VERSION_1_2 + +#define cl_arm_get_core_id 1 + +/* Device info property for bitfield of cores present */ +#define CL_DEVICE_COMPUTE_UNITS_BITFIELD_ARM 0x40BF + +#endif /* CL_VERSION_1_2 */ + +/********************************* +* cl_arm_job_slot_selection +*********************************/ + +#define cl_arm_job_slot_selection 1 + +/* cl_device_info */ +#define CL_DEVICE_JOB_SLOTS_ARM 0x41E0 + +/* cl_command_queue_properties */ +#define CL_QUEUE_JOB_SLOT_ARM 0x41E1 + +#ifdef __cplusplus +} +#endif + + +#endif /* __CL_EXT_H */ diff --git a/src/3rdparty/CL/cl_ext_intel.h b/src/3rdparty/CL/cl_ext_intel.h new file mode 100644 index 000000000..9d1e4b587 --- /dev/null +++ b/src/3rdparty/CL/cl_ext_intel.h @@ -0,0 +1,423 @@ +/******************************************************************************* + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ +/*****************************************************************************\ + +Copyright (c) 2013-2019 Intel Corporation All Rights Reserved. + +THESE MATERIALS ARE PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE +MATERIALS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +File Name: cl_ext_intel.h + +Abstract: + +Notes: + +\*****************************************************************************/ + +#ifndef __CL_EXT_INTEL_H +#define __CL_EXT_INTEL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************** +* cl_intel_thread_local_exec extension * +****************************************/ + +#define cl_intel_thread_local_exec 1 + +#define CL_QUEUE_THREAD_LOCAL_EXEC_ENABLE_INTEL (((cl_bitfield)1) << 31) + +/*********************************************** +* cl_intel_device_partition_by_names extension * +************************************************/ + +#define cl_intel_device_partition_by_names 1 + +#define CL_DEVICE_PARTITION_BY_NAMES_INTEL 0x4052 +#define CL_PARTITION_BY_NAMES_LIST_END_INTEL -1 + +/************************************************ +* cl_intel_accelerator extension * +* cl_intel_motion_estimation extension * +* cl_intel_advanced_motion_estimation extension * +*************************************************/ + +#define cl_intel_accelerator 1 +#define cl_intel_motion_estimation 1 +#define cl_intel_advanced_motion_estimation 1 + +typedef struct _cl_accelerator_intel* cl_accelerator_intel; +typedef cl_uint cl_accelerator_type_intel; +typedef cl_uint cl_accelerator_info_intel; + +typedef struct _cl_motion_estimation_desc_intel { + cl_uint mb_block_type; + cl_uint subpixel_mode; + cl_uint sad_adjust_mode; + cl_uint search_path_type; +} cl_motion_estimation_desc_intel; + +/* error codes */ +#define CL_INVALID_ACCELERATOR_INTEL -1094 +#define CL_INVALID_ACCELERATOR_TYPE_INTEL -1095 +#define CL_INVALID_ACCELERATOR_DESCRIPTOR_INTEL -1096 +#define CL_ACCELERATOR_TYPE_NOT_SUPPORTED_INTEL -1097 + +/* cl_accelerator_type_intel */ +#define CL_ACCELERATOR_TYPE_MOTION_ESTIMATION_INTEL 0x0 + +/* cl_accelerator_info_intel */ +#define CL_ACCELERATOR_DESCRIPTOR_INTEL 0x4090 +#define CL_ACCELERATOR_REFERENCE_COUNT_INTEL 0x4091 +#define CL_ACCELERATOR_CONTEXT_INTEL 0x4092 +#define CL_ACCELERATOR_TYPE_INTEL 0x4093 + +/* cl_motion_detect_desc_intel flags */ +#define CL_ME_MB_TYPE_16x16_INTEL 0x0 +#define CL_ME_MB_TYPE_8x8_INTEL 0x1 +#define CL_ME_MB_TYPE_4x4_INTEL 0x2 + +#define CL_ME_SUBPIXEL_MODE_INTEGER_INTEL 0x0 +#define CL_ME_SUBPIXEL_MODE_HPEL_INTEL 0x1 +#define CL_ME_SUBPIXEL_MODE_QPEL_INTEL 0x2 + +#define CL_ME_SAD_ADJUST_MODE_NONE_INTEL 0x0 +#define CL_ME_SAD_ADJUST_MODE_HAAR_INTEL 0x1 + +#define CL_ME_SEARCH_PATH_RADIUS_2_2_INTEL 0x0 +#define CL_ME_SEARCH_PATH_RADIUS_4_4_INTEL 0x1 +#define CL_ME_SEARCH_PATH_RADIUS_16_12_INTEL 0x5 + +#define CL_ME_SKIP_BLOCK_TYPE_16x16_INTEL 0x0 +#define CL_ME_CHROMA_INTRA_PREDICT_ENABLED_INTEL 0x1 +#define CL_ME_LUMA_INTRA_PREDICT_ENABLED_INTEL 0x2 +#define CL_ME_SKIP_BLOCK_TYPE_8x8_INTEL 0x4 + +#define CL_ME_FORWARD_INPUT_MODE_INTEL 0x1 +#define CL_ME_BACKWARD_INPUT_MODE_INTEL 0x2 +#define CL_ME_BIDIRECTION_INPUT_MODE_INTEL 0x3 + +#define CL_ME_BIDIR_WEIGHT_QUARTER_INTEL 16 +#define CL_ME_BIDIR_WEIGHT_THIRD_INTEL 21 +#define CL_ME_BIDIR_WEIGHT_HALF_INTEL 32 +#define CL_ME_BIDIR_WEIGHT_TWO_THIRD_INTEL 43 +#define CL_ME_BIDIR_WEIGHT_THREE_QUARTER_INTEL 48 + +#define CL_ME_COST_PENALTY_NONE_INTEL 0x0 +#define CL_ME_COST_PENALTY_LOW_INTEL 0x1 +#define CL_ME_COST_PENALTY_NORMAL_INTEL 0x2 +#define CL_ME_COST_PENALTY_HIGH_INTEL 0x3 + +#define CL_ME_COST_PRECISION_QPEL_INTEL 0x0 +#define CL_ME_COST_PRECISION_HPEL_INTEL 0x1 +#define CL_ME_COST_PRECISION_PEL_INTEL 0x2 +#define CL_ME_COST_PRECISION_DPEL_INTEL 0x3 + +#define CL_ME_LUMA_PREDICTOR_MODE_VERTICAL_INTEL 0x0 +#define CL_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_INTEL 0x1 +#define CL_ME_LUMA_PREDICTOR_MODE_DC_INTEL 0x2 +#define CL_ME_LUMA_PREDICTOR_MODE_DIAGONAL_DOWN_LEFT_INTEL 0x3 + +#define CL_ME_LUMA_PREDICTOR_MODE_DIAGONAL_DOWN_RIGHT_INTEL 0x4 +#define CL_ME_LUMA_PREDICTOR_MODE_PLANE_INTEL 0x4 +#define CL_ME_LUMA_PREDICTOR_MODE_VERTICAL_RIGHT_INTEL 0x5 +#define CL_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_DOWN_INTEL 0x6 +#define CL_ME_LUMA_PREDICTOR_MODE_VERTICAL_LEFT_INTEL 0x7 +#define CL_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_UP_INTEL 0x8 + +#define CL_ME_CHROMA_PREDICTOR_MODE_DC_INTEL 0x0 +#define CL_ME_CHROMA_PREDICTOR_MODE_HORIZONTAL_INTEL 0x1 +#define CL_ME_CHROMA_PREDICTOR_MODE_VERTICAL_INTEL 0x2 +#define CL_ME_CHROMA_PREDICTOR_MODE_PLANE_INTEL 0x3 + +/* cl_device_info */ +#define CL_DEVICE_ME_VERSION_INTEL 0x407E + +#define CL_ME_VERSION_LEGACY_INTEL 0x0 +#define CL_ME_VERSION_ADVANCED_VER_1_INTEL 0x1 +#define CL_ME_VERSION_ADVANCED_VER_2_INTEL 0x2 + +extern CL_API_ENTRY cl_accelerator_intel CL_API_CALL +clCreateAcceleratorINTEL( + cl_context context, + cl_accelerator_type_intel accelerator_type, + size_t descriptor_size, + const void* descriptor, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_accelerator_intel (CL_API_CALL *clCreateAcceleratorINTEL_fn)( + cl_context context, + cl_accelerator_type_intel accelerator_type, + size_t descriptor_size, + const void* descriptor, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetAcceleratorInfoINTEL( + cl_accelerator_intel accelerator, + cl_accelerator_info_intel param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetAcceleratorInfoINTEL_fn)( + cl_accelerator_intel accelerator, + cl_accelerator_info_intel param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainAcceleratorINTEL( + cl_accelerator_intel accelerator) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clRetainAcceleratorINTEL_fn)( + cl_accelerator_intel accelerator) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseAcceleratorINTEL( + cl_accelerator_intel accelerator) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clReleaseAcceleratorINTEL_fn)( + cl_accelerator_intel accelerator) CL_EXT_SUFFIX__VERSION_1_2; + +/****************************************** +* cl_intel_simultaneous_sharing extension * +*******************************************/ + +#define cl_intel_simultaneous_sharing 1 + +#define CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL 0x4104 +#define CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL 0x4105 + +/*********************************** +* cl_intel_egl_image_yuv extension * +************************************/ + +#define cl_intel_egl_image_yuv 1 + +#define CL_EGL_YUV_PLANE_INTEL 0x4107 + +/******************************** +* cl_intel_packed_yuv extension * +*********************************/ + +#define cl_intel_packed_yuv 1 + +#define CL_YUYV_INTEL 0x4076 +#define CL_UYVY_INTEL 0x4077 +#define CL_YVYU_INTEL 0x4078 +#define CL_VYUY_INTEL 0x4079 + +/******************************************** +* cl_intel_required_subgroup_size extension * +*********************************************/ + +#define cl_intel_required_subgroup_size 1 + +#define CL_DEVICE_SUB_GROUP_SIZES_INTEL 0x4108 +#define CL_KERNEL_SPILL_MEM_SIZE_INTEL 0x4109 +#define CL_KERNEL_COMPILE_SUB_GROUP_SIZE_INTEL 0x410A + +/**************************************** +* cl_intel_driver_diagnostics extension * +*****************************************/ + +#define cl_intel_driver_diagnostics 1 + +typedef cl_uint cl_diagnostics_verbose_level; + +#define CL_CONTEXT_SHOW_DIAGNOSTICS_INTEL 0x4106 + +#define CL_CONTEXT_DIAGNOSTICS_LEVEL_ALL_INTEL ( 0xff ) +#define CL_CONTEXT_DIAGNOSTICS_LEVEL_GOOD_INTEL ( 1 ) +#define CL_CONTEXT_DIAGNOSTICS_LEVEL_BAD_INTEL ( 1 << 1 ) +#define CL_CONTEXT_DIAGNOSTICS_LEVEL_NEUTRAL_INTEL ( 1 << 2 ) + +/******************************** +* cl_intel_planar_yuv extension * +*********************************/ + +#define CL_NV12_INTEL 0x410E + +#define CL_MEM_NO_ACCESS_INTEL ( 1 << 24 ) +#define CL_MEM_ACCESS_FLAGS_UNRESTRICTED_INTEL ( 1 << 25 ) + +#define CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL 0x417E +#define CL_DEVICE_PLANAR_YUV_MAX_HEIGHT_INTEL 0x417F + +/******************************************************* +* cl_intel_device_side_avc_motion_estimation extension * +********************************************************/ + +#define CL_DEVICE_AVC_ME_VERSION_INTEL 0x410B +#define CL_DEVICE_AVC_ME_SUPPORTS_TEXTURE_SAMPLER_USE_INTEL 0x410C +#define CL_DEVICE_AVC_ME_SUPPORTS_PREEMPTION_INTEL 0x410D + +#define CL_AVC_ME_VERSION_0_INTEL 0x0; // No support. +#define CL_AVC_ME_VERSION_1_INTEL 0x1; // First supported version. + +#define CL_AVC_ME_MAJOR_16x16_INTEL 0x0 +#define CL_AVC_ME_MAJOR_16x8_INTEL 0x1 +#define CL_AVC_ME_MAJOR_8x16_INTEL 0x2 +#define CL_AVC_ME_MAJOR_8x8_INTEL 0x3 + +#define CL_AVC_ME_MINOR_8x8_INTEL 0x0 +#define CL_AVC_ME_MINOR_8x4_INTEL 0x1 +#define CL_AVC_ME_MINOR_4x8_INTEL 0x2 +#define CL_AVC_ME_MINOR_4x4_INTEL 0x3 + +#define CL_AVC_ME_MAJOR_FORWARD_INTEL 0x0 +#define CL_AVC_ME_MAJOR_BACKWARD_INTEL 0x1 +#define CL_AVC_ME_MAJOR_BIDIRECTIONAL_INTEL 0x2 + +#define CL_AVC_ME_PARTITION_MASK_ALL_INTEL 0x0 +#define CL_AVC_ME_PARTITION_MASK_16x16_INTEL 0x7E +#define CL_AVC_ME_PARTITION_MASK_16x8_INTEL 0x7D +#define CL_AVC_ME_PARTITION_MASK_8x16_INTEL 0x7B +#define CL_AVC_ME_PARTITION_MASK_8x8_INTEL 0x77 +#define CL_AVC_ME_PARTITION_MASK_8x4_INTEL 0x6F +#define CL_AVC_ME_PARTITION_MASK_4x8_INTEL 0x5F +#define CL_AVC_ME_PARTITION_MASK_4x4_INTEL 0x3F + +#define CL_AVC_ME_SEARCH_WINDOW_EXHAUSTIVE_INTEL 0x0 +#define CL_AVC_ME_SEARCH_WINDOW_SMALL_INTEL 0x1 +#define CL_AVC_ME_SEARCH_WINDOW_TINY_INTEL 0x2 +#define CL_AVC_ME_SEARCH_WINDOW_EXTRA_TINY_INTEL 0x3 +#define CL_AVC_ME_SEARCH_WINDOW_DIAMOND_INTEL 0x4 +#define CL_AVC_ME_SEARCH_WINDOW_LARGE_DIAMOND_INTEL 0x5 +#define CL_AVC_ME_SEARCH_WINDOW_RESERVED0_INTEL 0x6 +#define CL_AVC_ME_SEARCH_WINDOW_RESERVED1_INTEL 0x7 +#define CL_AVC_ME_SEARCH_WINDOW_CUSTOM_INTEL 0x8 +#define CL_AVC_ME_SEARCH_WINDOW_16x12_RADIUS_INTEL 0x9 +#define CL_AVC_ME_SEARCH_WINDOW_4x4_RADIUS_INTEL 0x2 +#define CL_AVC_ME_SEARCH_WINDOW_2x2_RADIUS_INTEL 0xa + +#define CL_AVC_ME_SAD_ADJUST_MODE_NONE_INTEL 0x0 +#define CL_AVC_ME_SAD_ADJUST_MODE_HAAR_INTEL 0x2 + +#define CL_AVC_ME_SUBPIXEL_MODE_INTEGER_INTEL 0x0 +#define CL_AVC_ME_SUBPIXEL_MODE_HPEL_INTEL 0x1 +#define CL_AVC_ME_SUBPIXEL_MODE_QPEL_INTEL 0x3 + +#define CL_AVC_ME_COST_PRECISION_QPEL_INTEL 0x0 +#define CL_AVC_ME_COST_PRECISION_HPEL_INTEL 0x1 +#define CL_AVC_ME_COST_PRECISION_PEL_INTEL 0x2 +#define CL_AVC_ME_COST_PRECISION_DPEL_INTEL 0x3 + +#define CL_AVC_ME_BIDIR_WEIGHT_QUARTER_INTEL 0x10 +#define CL_AVC_ME_BIDIR_WEIGHT_THIRD_INTEL 0x15 +#define CL_AVC_ME_BIDIR_WEIGHT_HALF_INTEL 0x20 +#define CL_AVC_ME_BIDIR_WEIGHT_TWO_THIRD_INTEL 0x2B +#define CL_AVC_ME_BIDIR_WEIGHT_THREE_QUARTER_INTEL 0x30 + +#define CL_AVC_ME_BORDER_REACHED_LEFT_INTEL 0x0 +#define CL_AVC_ME_BORDER_REACHED_RIGHT_INTEL 0x2 +#define CL_AVC_ME_BORDER_REACHED_TOP_INTEL 0x4 +#define CL_AVC_ME_BORDER_REACHED_BOTTOM_INTEL 0x8 + +#define CL_AVC_ME_SKIP_BLOCK_PARTITION_16x16_INTEL 0x0 +#define CL_AVC_ME_SKIP_BLOCK_PARTITION_8x8_INTEL 0x4000 + +#define CL_AVC_ME_SKIP_BLOCK_16x16_FORWARD_ENABLE_INTEL ( 0x1 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_16x16_BACKWARD_ENABLE_INTEL ( 0x2 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_16x16_DUAL_ENABLE_INTEL ( 0x3 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_FORWARD_ENABLE_INTEL ( 0x55 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_BACKWARD_ENABLE_INTEL ( 0xAA << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_DUAL_ENABLE_INTEL ( 0xFF << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_0_FORWARD_ENABLE_INTEL ( 0x1 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_0_BACKWARD_ENABLE_INTEL ( 0x2 << 24 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_1_FORWARD_ENABLE_INTEL ( 0x1 << 26 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_1_BACKWARD_ENABLE_INTEL ( 0x2 << 26 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_2_FORWARD_ENABLE_INTEL ( 0x1 << 28 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_2_BACKWARD_ENABLE_INTEL ( 0x2 << 28 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_3_FORWARD_ENABLE_INTEL ( 0x1 << 30 ) +#define CL_AVC_ME_SKIP_BLOCK_8x8_3_BACKWARD_ENABLE_INTEL ( 0x2 << 30 ) + +#define CL_AVC_ME_BLOCK_BASED_SKIP_4x4_INTEL 0x00 +#define CL_AVC_ME_BLOCK_BASED_SKIP_8x8_INTEL 0x80 + +#define CL_AVC_ME_INTRA_16x16_INTEL 0x0 +#define CL_AVC_ME_INTRA_8x8_INTEL 0x1 +#define CL_AVC_ME_INTRA_4x4_INTEL 0x2 + +#define CL_AVC_ME_INTRA_LUMA_PARTITION_MASK_16x16_INTEL 0x6 +#define CL_AVC_ME_INTRA_LUMA_PARTITION_MASK_8x8_INTEL 0x5 +#define CL_AVC_ME_INTRA_LUMA_PARTITION_MASK_4x4_INTEL 0x3 + +#define CL_AVC_ME_INTRA_NEIGHBOR_LEFT_MASK_ENABLE_INTEL 0x60 +#define CL_AVC_ME_INTRA_NEIGHBOR_UPPER_MASK_ENABLE_INTEL 0x10 +#define CL_AVC_ME_INTRA_NEIGHBOR_UPPER_RIGHT_MASK_ENABLE_INTEL 0x8 +#define CL_AVC_ME_INTRA_NEIGHBOR_UPPER_LEFT_MASK_ENABLE_INTEL 0x4 + +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_VERTICAL_INTEL 0x0 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_INTEL 0x1 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_DC_INTEL 0x2 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_DIAGONAL_DOWN_LEFT_INTEL 0x3 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_DIAGONAL_DOWN_RIGHT_INTEL 0x4 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_PLANE_INTEL 0x4 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_VERTICAL_RIGHT_INTEL 0x5 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_DOWN_INTEL 0x6 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_VERTICAL_LEFT_INTEL 0x7 +#define CL_AVC_ME_LUMA_PREDICTOR_MODE_HORIZONTAL_UP_INTEL 0x8 +#define CL_AVC_ME_CHROMA_PREDICTOR_MODE_DC_INTEL 0x0 +#define CL_AVC_ME_CHROMA_PREDICTOR_MODE_HORIZONTAL_INTEL 0x1 +#define CL_AVC_ME_CHROMA_PREDICTOR_MODE_VERTICAL_INTEL 0x2 +#define CL_AVC_ME_CHROMA_PREDICTOR_MODE_PLANE_INTEL 0x3 + +#define CL_AVC_ME_FRAME_FORWARD_INTEL 0x1 +#define CL_AVC_ME_FRAME_BACKWARD_INTEL 0x2 +#define CL_AVC_ME_FRAME_DUAL_INTEL 0x3 + +#define CL_AVC_ME_SLICE_TYPE_PRED_INTEL 0x0 +#define CL_AVC_ME_SLICE_TYPE_BPRED_INTEL 0x1 +#define CL_AVC_ME_SLICE_TYPE_INTRA_INTEL 0x2 + +#define CL_AVC_ME_INTERLACED_SCAN_TOP_FIELD_INTEL 0x0 +#define CL_AVC_ME_INTERLACED_SCAN_BOTTOM_FIELD_INTEL 0x1 + +#ifdef __cplusplus +} +#endif + +#endif /* __CL_EXT_INTEL_H */ diff --git a/src/3rdparty/CL/cl_gl.h b/src/3rdparty/CL/cl_gl.h new file mode 100644 index 000000000..fbdaf6297 --- /dev/null +++ b/src/3rdparty/CL/cl_gl.h @@ -0,0 +1,171 @@ +/********************************************************************************** + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +#ifndef __OPENCL_CL_GL_H +#define __OPENCL_CL_GL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef cl_uint cl_gl_object_type; +typedef cl_uint cl_gl_texture_info; +typedef cl_uint cl_gl_platform_info; +typedef struct __GLsync *cl_GLsync; + +/* cl_gl_object_type = 0x2000 - 0x200F enum values are currently taken */ +#define CL_GL_OBJECT_BUFFER 0x2000 +#define CL_GL_OBJECT_TEXTURE2D 0x2001 +#define CL_GL_OBJECT_TEXTURE3D 0x2002 +#define CL_GL_OBJECT_RENDERBUFFER 0x2003 +#ifdef CL_VERSION_1_2 +#define CL_GL_OBJECT_TEXTURE2D_ARRAY 0x200E +#define CL_GL_OBJECT_TEXTURE1D 0x200F +#define CL_GL_OBJECT_TEXTURE1D_ARRAY 0x2010 +#define CL_GL_OBJECT_TEXTURE_BUFFER 0x2011 +#endif + +/* cl_gl_texture_info */ +#define CL_GL_TEXTURE_TARGET 0x2004 +#define CL_GL_MIPMAP_LEVEL 0x2005 +#ifdef CL_VERSION_1_2 +#define CL_GL_NUM_SAMPLES 0x2012 +#endif + + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLBuffer(cl_context context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_VERSION_1_2 + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLTexture(cl_context context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texture, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_2; + +#endif + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLRenderbuffer(cl_context context, + cl_mem_flags flags, + cl_GLuint renderbuffer, + cl_int * errcode_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLObjectInfo(cl_mem memobj, + cl_gl_object_type * gl_object_type, + cl_GLuint * gl_object_name) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLTextureInfo(cl_mem memobj, + cl_gl_texture_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireGLObjects(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseGLObjects(cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem * mem_objects, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) CL_API_SUFFIX__VERSION_1_0; + + +/* Deprecated OpenCL 1.1 APIs */ +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateFromGLTexture2D(cl_context context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texture, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateFromGLTexture3D(cl_context context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texture, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +/* cl_khr_gl_sharing extension */ + +#define cl_khr_gl_sharing 1 + +typedef cl_uint cl_gl_context_info; + +/* Additional Error Codes */ +#define CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR -1000 + +/* cl_gl_context_info */ +#define CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR 0x2006 +#define CL_DEVICES_FOR_GL_CONTEXT_KHR 0x2007 + +/* Additional cl_context_properties */ +#define CL_GL_CONTEXT_KHR 0x2008 +#define CL_EGL_DISPLAY_KHR 0x2009 +#define CL_GLX_DISPLAY_KHR 0x200A +#define CL_WGL_HDC_KHR 0x200B +#define CL_CGL_SHAREGROUP_KHR 0x200C + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLContextInfoKHR(const cl_context_properties * properties, + cl_gl_context_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetGLContextInfoKHR_fn)( + const cl_context_properties * properties, + cl_gl_context_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret); + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_GL_H */ diff --git a/src/3rdparty/CL/cl_gl_ext.h b/src/3rdparty/CL/cl_gl_ext.h new file mode 100644 index 000000000..c26d31abe --- /dev/null +++ b/src/3rdparty/CL/cl_gl_ext.h @@ -0,0 +1,52 @@ +/********************************************************************************** + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +#ifndef __OPENCL_CL_GL_EXT_H +#define __OPENCL_CL_GL_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * cl_khr_gl_event extension + */ +#define CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR 0x200D + +extern CL_API_ENTRY cl_event CL_API_CALL +clCreateEventFromGLsyncKHR(cl_context context, + cl_GLsync cl_GLsync, + cl_int * errcode_ret) CL_EXT_SUFFIX__VERSION_1_1; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_GL_EXT_H */ diff --git a/src/3rdparty/CL/cl_platform.h b/src/3rdparty/CL/cl_platform.h new file mode 100644 index 000000000..7f4ddea5b --- /dev/null +++ b/src/3rdparty/CL/cl_platform.h @@ -0,0 +1,1384 @@ +/********************************************************************************** + * Copyright (c) 2008-2018 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +#ifndef __CL_PLATFORM_H +#define __CL_PLATFORM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) + #define CL_API_ENTRY + #define CL_API_CALL __stdcall + #define CL_CALLBACK __stdcall +#else + #define CL_API_ENTRY + #define CL_API_CALL + #define CL_CALLBACK +#endif + +/* + * Deprecation flags refer to the last version of the header in which the + * feature was not deprecated. + * + * E.g. VERSION_1_1_DEPRECATED means the feature is present in 1.1 without + * deprecation but is deprecated in versions later than 1.1. + */ + +#define CL_EXTENSION_WEAK_LINK +#define CL_API_SUFFIX__VERSION_1_0 +#define CL_EXT_SUFFIX__VERSION_1_0 +#define CL_API_SUFFIX__VERSION_1_1 +#define CL_EXT_SUFFIX__VERSION_1_1 +#define CL_API_SUFFIX__VERSION_1_2 +#define CL_EXT_SUFFIX__VERSION_1_2 +#define CL_API_SUFFIX__VERSION_2_0 +#define CL_EXT_SUFFIX__VERSION_2_0 +#define CL_API_SUFFIX__VERSION_2_1 +#define CL_EXT_SUFFIX__VERSION_2_1 +#define CL_API_SUFFIX__VERSION_2_2 +#define CL_EXT_SUFFIX__VERSION_2_2 + + +#ifdef __GNUC__ + #define CL_EXT_SUFFIX_DEPRECATED __attribute__((deprecated)) + #define CL_EXT_PREFIX_DEPRECATED +#elif defined(_WIN32) + #define CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX_DEPRECATED __declspec(deprecated) +#else + #define CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX_DEPRECATED +#endif + +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED +#else + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED CL_EXT_PREFIX_DEPRECATED +#endif + +#ifdef CL_USE_DEPRECATED_OPENCL_1_1_APIS + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED +#else + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED CL_EXT_PREFIX_DEPRECATED +#endif + +#ifdef CL_USE_DEPRECATED_OPENCL_1_2_APIS + #define CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_2_DEPRECATED +#else + #define CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_2_DEPRECATED CL_EXT_PREFIX_DEPRECATED + #endif + +#ifdef CL_USE_DEPRECATED_OPENCL_2_0_APIS + #define CL_EXT_SUFFIX__VERSION_2_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_2_0_DEPRECATED +#else + #define CL_EXT_SUFFIX__VERSION_2_0_DEPRECATED CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX__VERSION_2_0_DEPRECATED CL_EXT_PREFIX_DEPRECATED +#endif + +#ifdef CL_USE_DEPRECATED_OPENCL_2_1_APIS + #define CL_EXT_SUFFIX__VERSION_2_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_2_1_DEPRECATED +#else + #define CL_EXT_SUFFIX__VERSION_2_1_DEPRECATED CL_EXT_SUFFIX_DEPRECATED + #define CL_EXT_PREFIX__VERSION_2_1_DEPRECATED CL_EXT_PREFIX_DEPRECATED +#endif + +#if (defined (_WIN32) && defined(_MSC_VER)) + +/* scalar types */ +typedef signed __int8 cl_char; +typedef unsigned __int8 cl_uchar; +typedef signed __int16 cl_short; +typedef unsigned __int16 cl_ushort; +typedef signed __int32 cl_int; +typedef unsigned __int32 cl_uint; +typedef signed __int64 cl_long; +typedef unsigned __int64 cl_ulong; + +typedef unsigned __int16 cl_half; +typedef float cl_float; +typedef double cl_double; + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 340282346638528859811704183484516925440.0f +#define CL_FLT_MIN 1.175494350822287507969e-38f +#define CL_FLT_EPSILON 1.1920928955078125e-7f + +#define CL_HALF_DIG 3 +#define CL_HALF_MANT_DIG 11 +#define CL_HALF_MAX_10_EXP +4 +#define CL_HALF_MAX_EXP +16 +#define CL_HALF_MIN_10_EXP -4 +#define CL_HALF_MIN_EXP -13 +#define CL_HALF_RADIX 2 +#define CL_HALF_MAX 65504.0f +#define CL_HALF_MIN 6.103515625e-05f +#define CL_HALF_EPSILON 9.765625e-04f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 1.7976931348623158e+308 +#define CL_DBL_MIN 2.225073858507201383090e-308 +#define CL_DBL_EPSILON 2.220446049250313080847e-16 + +#define CL_M_E 2.7182818284590452354 +#define CL_M_LOG2E 1.4426950408889634074 +#define CL_M_LOG10E 0.43429448190325182765 +#define CL_M_LN2 0.69314718055994530942 +#define CL_M_LN10 2.30258509299404568402 +#define CL_M_PI 3.14159265358979323846 +#define CL_M_PI_2 1.57079632679489661923 +#define CL_M_PI_4 0.78539816339744830962 +#define CL_M_1_PI 0.31830988618379067154 +#define CL_M_2_PI 0.63661977236758134308 +#define CL_M_2_SQRTPI 1.12837916709551257390 +#define CL_M_SQRT2 1.41421356237309504880 +#define CL_M_SQRT1_2 0.70710678118654752440 + +#define CL_M_E_F 2.718281828f +#define CL_M_LOG2E_F 1.442695041f +#define CL_M_LOG10E_F 0.434294482f +#define CL_M_LN2_F 0.693147181f +#define CL_M_LN10_F 2.302585093f +#define CL_M_PI_F 3.141592654f +#define CL_M_PI_2_F 1.570796327f +#define CL_M_PI_4_F 0.785398163f +#define CL_M_1_PI_F 0.318309886f +#define CL_M_2_PI_F 0.636619772f +#define CL_M_2_SQRTPI_F 1.128379167f +#define CL_M_SQRT2_F 1.414213562f +#define CL_M_SQRT1_2_F 0.707106781f + +#define CL_NAN (CL_INFINITY - CL_INFINITY) +#define CL_HUGE_VALF ((cl_float) 1e50) +#define CL_HUGE_VAL ((cl_double) 1e500) +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#else + +#include + +/* scalar types */ +typedef int8_t cl_char; +typedef uint8_t cl_uchar; +typedef int16_t cl_short; +typedef uint16_t cl_ushort; +typedef int32_t cl_int; +typedef uint32_t cl_uint; +typedef int64_t cl_long; +typedef uint64_t cl_ulong; + +typedef uint16_t cl_half; +typedef float cl_float; +typedef double cl_double; + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 340282346638528859811704183484516925440.0f +#define CL_FLT_MIN 1.175494350822287507969e-38f +#define CL_FLT_EPSILON 1.1920928955078125e-7f + +#define CL_HALF_DIG 3 +#define CL_HALF_MANT_DIG 11 +#define CL_HALF_MAX_10_EXP +4 +#define CL_HALF_MAX_EXP +16 +#define CL_HALF_MIN_10_EXP -4 +#define CL_HALF_MIN_EXP -13 +#define CL_HALF_RADIX 2 +#define CL_HALF_MAX 65504.0f +#define CL_HALF_MIN 6.103515625e-05f +#define CL_HALF_EPSILON 9.765625e-04f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 +#define CL_DBL_MIN 2.225073858507201383090e-308 +#define CL_DBL_EPSILON 2.220446049250313080847e-16 + +#define CL_M_E 2.7182818284590452354 +#define CL_M_LOG2E 1.4426950408889634074 +#define CL_M_LOG10E 0.43429448190325182765 +#define CL_M_LN2 0.69314718055994530942 +#define CL_M_LN10 2.30258509299404568402 +#define CL_M_PI 3.14159265358979323846 +#define CL_M_PI_2 1.57079632679489661923 +#define CL_M_PI_4 0.78539816339744830962 +#define CL_M_1_PI 0.31830988618379067154 +#define CL_M_2_PI 0.63661977236758134308 +#define CL_M_2_SQRTPI 1.12837916709551257390 +#define CL_M_SQRT2 1.41421356237309504880 +#define CL_M_SQRT1_2 0.70710678118654752440 + +#define CL_M_E_F 2.718281828f +#define CL_M_LOG2E_F 1.442695041f +#define CL_M_LOG10E_F 0.434294482f +#define CL_M_LN2_F 0.693147181f +#define CL_M_LN10_F 2.302585093f +#define CL_M_PI_F 3.141592654f +#define CL_M_PI_2_F 1.570796327f +#define CL_M_PI_4_F 0.785398163f +#define CL_M_1_PI_F 0.318309886f +#define CL_M_2_PI_F 0.636619772f +#define CL_M_2_SQRTPI_F 1.128379167f +#define CL_M_SQRT2_F 1.414213562f +#define CL_M_SQRT1_2_F 0.707106781f + +#if defined( __GNUC__ ) + #define CL_HUGE_VALF __builtin_huge_valf() + #define CL_HUGE_VAL __builtin_huge_val() + #define CL_NAN __builtin_nanf( "" ) +#else + #define CL_HUGE_VALF ((cl_float) 1e50) + #define CL_HUGE_VAL ((cl_double) 1e500) + float nanf( const char * ); + #define CL_NAN nanf( "" ) +#endif +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#endif + +#include + +/* Mirror types to GL types. Mirror types allow us to avoid deciding which 87s to load based on whether we are using GL or GLES here. */ +typedef unsigned int cl_GLuint; +typedef int cl_GLint; +typedef unsigned int cl_GLenum; + +/* + * Vector types + * + * Note: OpenCL requires that all types be naturally aligned. + * This means that vector types must be naturally aligned. + * For example, a vector of four floats must be aligned to + * a 16 byte boundary (calculated as 4 * the natural 4-byte + * alignment of the float). The alignment qualifiers here + * will only function properly if your compiler supports them + * and if you don't actively work to defeat them. For example, + * in order for a cl_float4 to be 16 byte aligned in a struct, + * the start of the struct must itself be 16-byte aligned. + * + * Maintaining proper alignment is the user's responsibility. + */ + +/* Define basic vector types */ +#if defined( __VEC__ ) + #include /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ + typedef __vector unsigned char __cl_uchar16; + typedef __vector signed char __cl_char16; + typedef __vector unsigned short __cl_ushort8; + typedef __vector signed short __cl_short8; + typedef __vector unsigned int __cl_uint4; + typedef __vector signed int __cl_int4; + typedef __vector float __cl_float4; + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_UINT4__ 1 + #define __CL_INT4__ 1 + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef float __cl_float4 __attribute__((vector_size(16))); + #else + typedef __m128 __cl_float4; + #endif + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE2__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef cl_uchar __cl_uchar16 __attribute__((vector_size(16))); + typedef cl_char __cl_char16 __attribute__((vector_size(16))); + typedef cl_ushort __cl_ushort8 __attribute__((vector_size(16))); + typedef cl_short __cl_short8 __attribute__((vector_size(16))); + typedef cl_uint __cl_uint4 __attribute__((vector_size(16))); + typedef cl_int __cl_int4 __attribute__((vector_size(16))); + typedef cl_ulong __cl_ulong2 __attribute__((vector_size(16))); + typedef cl_long __cl_long2 __attribute__((vector_size(16))); + typedef cl_double __cl_double2 __attribute__((vector_size(16))); + #else + typedef __m128i __cl_uchar16; + typedef __m128i __cl_char16; + typedef __m128i __cl_ushort8; + typedef __m128i __cl_short8; + typedef __m128i __cl_uint4; + typedef __m128i __cl_int4; + typedef __m128i __cl_ulong2; + typedef __m128i __cl_long2; + typedef __m128d __cl_double2; + #endif + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_INT4__ 1 + #define __CL_UINT4__ 1 + #define __CL_ULONG2__ 1 + #define __CL_LONG2__ 1 + #define __CL_DOUBLE2__ 1 +#endif + +#if defined( __MMX__ ) + #include + #if defined( __GNUC__ ) + typedef cl_uchar __cl_uchar8 __attribute__((vector_size(8))); + typedef cl_char __cl_char8 __attribute__((vector_size(8))); + typedef cl_ushort __cl_ushort4 __attribute__((vector_size(8))); + typedef cl_short __cl_short4 __attribute__((vector_size(8))); + typedef cl_uint __cl_uint2 __attribute__((vector_size(8))); + typedef cl_int __cl_int2 __attribute__((vector_size(8))); + typedef cl_ulong __cl_ulong1 __attribute__((vector_size(8))); + typedef cl_long __cl_long1 __attribute__((vector_size(8))); + typedef cl_float __cl_float2 __attribute__((vector_size(8))); + #else + typedef __m64 __cl_uchar8; + typedef __m64 __cl_char8; + typedef __m64 __cl_ushort4; + typedef __m64 __cl_short4; + typedef __m64 __cl_uint2; + typedef __m64 __cl_int2; + typedef __m64 __cl_ulong1; + typedef __m64 __cl_long1; + typedef __m64 __cl_float2; + #endif + #define __CL_UCHAR8__ 1 + #define __CL_CHAR8__ 1 + #define __CL_USHORT4__ 1 + #define __CL_SHORT4__ 1 + #define __CL_INT2__ 1 + #define __CL_UINT2__ 1 + #define __CL_ULONG1__ 1 + #define __CL_LONG1__ 1 + #define __CL_FLOAT2__ 1 +#endif + +#if defined( __AVX__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef cl_float __cl_float8 __attribute__((vector_size(32))); + typedef cl_double __cl_double4 __attribute__((vector_size(32))); + #else + typedef __m256 __cl_float8; + typedef __m256d __cl_double4; + #endif + #define __CL_FLOAT8__ 1 + #define __CL_DOUBLE4__ 1 +#endif + +/* Define capabilities for anonymous struct members. */ +#if !defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define __CL_HAS_ANON_STRUCT__ 1 +#define __CL_ANON_STRUCT__ +#elif defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) +#define __CL_HAS_ANON_STRUCT__ 1 +#define __CL_ANON_STRUCT__ __extension__ +#elif defined( _WIN32) && defined(_MSC_VER) + #if _MSC_VER >= 1500 + /* Microsoft Developer Studio 2008 supports anonymous structs, but + * complains by default. */ + #define __CL_HAS_ANON_STRUCT__ 1 + #define __CL_ANON_STRUCT__ + /* Disable warning C4201: nonstandard extension used : nameless + * struct/union */ + #pragma warning( push ) + #pragma warning( disable : 4201 ) + #endif +#else +#define __CL_HAS_ANON_STRUCT__ 0 +#define __CL_ANON_STRUCT__ +#endif + +/* Define alignment keys */ +#if defined( __GNUC__ ) + #define CL_ALIGNED(_x) __attribute__ ((aligned(_x))) +#elif defined( _WIN32) && (_MSC_VER) + /* Alignment keys neutered on windows because MSVC can't swallow function arguments with alignment requirements */ + /* http://msdn.microsoft.com/en-us/library/373ak2y1%28VS.71%29.aspx */ + /* #include */ + /* #define CL_ALIGNED(_x) _CRT_ALIGN(_x) */ + #define CL_ALIGNED(_x) +#else + #warning Need to implement some method to align data here + #define CL_ALIGNED(_x) +#endif + +/* Indicate whether .xyzw, .s0123 and .hi.lo are supported */ +#if __CL_HAS_ANON_STRUCT__ + /* .xyzw and .s0123...{f|F} are supported */ + #define CL_HAS_NAMED_VECTOR_FIELDS 1 + /* .hi and .lo are supported */ + #define CL_HAS_HI_LO_VECTOR_FIELDS 1 +#endif + +/* Define cl_vector types */ + +/* ---- cl_charn ---- */ +typedef union +{ + cl_char CL_ALIGNED(2) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_char lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2; +#endif +}cl_char2; + +typedef union +{ + cl_char CL_ALIGNED(4) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_char2 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[2]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4; +#endif +}cl_char4; + +/* cl_char3 is identical in size, alignment and behavior to cl_char4. See section 6.1.5. */ +typedef cl_char4 cl_char3; + +typedef union +{ + cl_char CL_ALIGNED(8) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_char4 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[4]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[2]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8; +#endif +}cl_char8; + +typedef union +{ + cl_char CL_ALIGNED(16) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_char8 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[8]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[4]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8[2]; +#endif +#if defined( __CL_CHAR16__ ) + __cl_char16 v16; +#endif +}cl_char16; + + +/* ---- cl_ucharn ---- */ +typedef union +{ + cl_uchar CL_ALIGNED(2) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_uchar lo, hi; }; +#endif +#if defined( __cl_uchar2__) + __cl_uchar2 v2; +#endif +}cl_uchar2; + +typedef union +{ + cl_uchar CL_ALIGNED(4) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_uchar2 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[2]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4; +#endif +}cl_uchar4; + +/* cl_uchar3 is identical in size, alignment and behavior to cl_uchar4. See section 6.1.5. */ +typedef cl_uchar4 cl_uchar3; + +typedef union +{ + cl_uchar CL_ALIGNED(8) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_uchar4 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[4]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[2]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8; +#endif +}cl_uchar8; + +typedef union +{ + cl_uchar CL_ALIGNED(16) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_uchar8 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[8]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[4]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8[2]; +#endif +#if defined( __CL_UCHAR16__ ) + __cl_uchar16 v16; +#endif +}cl_uchar16; + + +/* ---- cl_shortn ---- */ +typedef union +{ + cl_short CL_ALIGNED(4) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_short lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2; +#endif +}cl_short2; + +typedef union +{ + cl_short CL_ALIGNED(8) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_short2 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[2]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4; +#endif +}cl_short4; + +/* cl_short3 is identical in size, alignment and behavior to cl_short4. See section 6.1.5. */ +typedef cl_short4 cl_short3; + +typedef union +{ + cl_short CL_ALIGNED(16) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_short4 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[4]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[2]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8; +#endif +}cl_short8; + +typedef union +{ + cl_short CL_ALIGNED(32) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_short8 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[8]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[4]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8[2]; +#endif +#if defined( __CL_SHORT16__ ) + __cl_short16 v16; +#endif +}cl_short16; + + +/* ---- cl_ushortn ---- */ +typedef union +{ + cl_ushort CL_ALIGNED(4) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_ushort lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2; +#endif +}cl_ushort2; + +typedef union +{ + cl_ushort CL_ALIGNED(8) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_ushort2 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[2]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4; +#endif +}cl_ushort4; + +/* cl_ushort3 is identical in size, alignment and behavior to cl_ushort4. See section 6.1.5. */ +typedef cl_ushort4 cl_ushort3; + +typedef union +{ + cl_ushort CL_ALIGNED(16) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_ushort4 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[4]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[2]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8; +#endif +}cl_ushort8; + +typedef union +{ + cl_ushort CL_ALIGNED(32) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_ushort8 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[8]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[4]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8[2]; +#endif +#if defined( __CL_USHORT16__ ) + __cl_ushort16 v16; +#endif +}cl_ushort16; + + +/* ---- cl_halfn ---- */ +typedef union +{ + cl_half CL_ALIGNED(4) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_half x, y; }; + __CL_ANON_STRUCT__ struct{ cl_half s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_half lo, hi; }; +#endif +#if defined( __CL_HALF2__) + __cl_half2 v2; +#endif +}cl_half2; + +typedef union +{ + cl_half CL_ALIGNED(8) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_half x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_half s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_half2 lo, hi; }; +#endif +#if defined( __CL_HALF2__) + __cl_half2 v2[2]; +#endif +#if defined( __CL_HALF4__) + __cl_half4 v4; +#endif +}cl_half4; + +/* cl_half3 is identical in size, alignment and behavior to cl_half4. See section 6.1.5. */ +typedef cl_half4 cl_half3; + +typedef union +{ + cl_half CL_ALIGNED(16) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_half x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_half s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_half4 lo, hi; }; +#endif +#if defined( __CL_HALF2__) + __cl_half2 v2[4]; +#endif +#if defined( __CL_HALF4__) + __cl_half4 v4[2]; +#endif +#if defined( __CL_HALF8__ ) + __cl_half8 v8; +#endif +}cl_half8; + +typedef union +{ + cl_half CL_ALIGNED(32) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_half x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_half s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_half8 lo, hi; }; +#endif +#if defined( __CL_HALF2__) + __cl_half2 v2[8]; +#endif +#if defined( __CL_HALF4__) + __cl_half4 v4[4]; +#endif +#if defined( __CL_HALF8__ ) + __cl_half8 v8[2]; +#endif +#if defined( __CL_HALF16__ ) + __cl_half16 v16; +#endif +}cl_half16; + +/* ---- cl_intn ---- */ +typedef union +{ + cl_int CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_int lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2; +#endif +}cl_int2; + +typedef union +{ + cl_int CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_int2 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[2]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4; +#endif +}cl_int4; + +/* cl_int3 is identical in size, alignment and behavior to cl_int4. See section 6.1.5. */ +typedef cl_int4 cl_int3; + +typedef union +{ + cl_int CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_int4 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[4]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[2]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8; +#endif +}cl_int8; + +typedef union +{ + cl_int CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_int8 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[8]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[4]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8[2]; +#endif +#if defined( __CL_INT16__ ) + __cl_int16 v16; +#endif +}cl_int16; + + +/* ---- cl_uintn ---- */ +typedef union +{ + cl_uint CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_uint lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2; +#endif +}cl_uint2; + +typedef union +{ + cl_uint CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_uint2 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[2]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4; +#endif +}cl_uint4; + +/* cl_uint3 is identical in size, alignment and behavior to cl_uint4. See section 6.1.5. */ +typedef cl_uint4 cl_uint3; + +typedef union +{ + cl_uint CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_uint4 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[4]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[2]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8; +#endif +}cl_uint8; + +typedef union +{ + cl_uint CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_uint8 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[8]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[4]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8[2]; +#endif +#if defined( __CL_UINT16__ ) + __cl_uint16 v16; +#endif +}cl_uint16; + +/* ---- cl_longn ---- */ +typedef union +{ + cl_long CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_long lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2; +#endif +}cl_long2; + +typedef union +{ + cl_long CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_long2 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[2]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4; +#endif +}cl_long4; + +/* cl_long3 is identical in size, alignment and behavior to cl_long4. See section 6.1.5. */ +typedef cl_long4 cl_long3; + +typedef union +{ + cl_long CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_long4 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[4]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[2]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8; +#endif +}cl_long8; + +typedef union +{ + cl_long CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_long8 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[8]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[4]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8[2]; +#endif +#if defined( __CL_LONG16__ ) + __cl_long16 v16; +#endif +}cl_long16; + + +/* ---- cl_ulongn ---- */ +typedef union +{ + cl_ulong CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_ulong lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2; +#endif +}cl_ulong2; + +typedef union +{ + cl_ulong CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_ulong2 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[2]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4; +#endif +}cl_ulong4; + +/* cl_ulong3 is identical in size, alignment and behavior to cl_ulong4. See section 6.1.5. */ +typedef cl_ulong4 cl_ulong3; + +typedef union +{ + cl_ulong CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_ulong4 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[4]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[2]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8; +#endif +}cl_ulong8; + +typedef union +{ + cl_ulong CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_ulong8 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[8]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[4]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8[2]; +#endif +#if defined( __CL_ULONG16__ ) + __cl_ulong16 v16; +#endif +}cl_ulong16; + + +/* --- cl_floatn ---- */ + +typedef union +{ + cl_float CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_float lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2; +#endif +}cl_float2; + +typedef union +{ + cl_float CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_float2 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[2]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4; +#endif +}cl_float4; + +/* cl_float3 is identical in size, alignment and behavior to cl_float4. See section 6.1.5. */ +typedef cl_float4 cl_float3; + +typedef union +{ + cl_float CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_float4 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[4]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[2]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8; +#endif +}cl_float8; + +typedef union +{ + cl_float CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_float8 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[8]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[4]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8[2]; +#endif +#if defined( __CL_FLOAT16__ ) + __cl_float16 v16; +#endif +}cl_float16; + +/* --- cl_doublen ---- */ + +typedef union +{ + cl_double CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_double lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2; +#endif +}cl_double2; + +typedef union +{ + cl_double CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_double2 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[2]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4; +#endif +}cl_double4; + +/* cl_double3 is identical in size, alignment and behavior to cl_double4. See section 6.1.5. */ +typedef cl_double4 cl_double3; + +typedef union +{ + cl_double CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_double4 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[4]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[2]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8; +#endif +}cl_double8; + +typedef union +{ + cl_double CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_double8 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[8]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[4]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8[2]; +#endif +#if defined( __CL_DOUBLE16__ ) + __cl_double16 v16; +#endif +}cl_double16; + +/* Macro to facilitate debugging + * Usage: + * Place CL_PROGRAM_STRING_DEBUG_INFO on the line before the first line of your source. + * The first line ends with: CL_PROGRAM_STRING_DEBUG_INFO \" + * Each line thereafter of OpenCL C source must end with: \n\ + * The last line ends in "; + * + * Example: + * + * const char *my_program = CL_PROGRAM_STRING_DEBUG_INFO "\ + * kernel void foo( int a, float * b ) \n\ + * { \n\ + * // my comment \n\ + * *b[ get_global_id(0)] = a; \n\ + * } \n\ + * "; + * + * This should correctly set up the line, (column) and file information for your source + * string so you can do source level debugging. + */ +#define __CL_STRINGIFY( _x ) # _x +#define _CL_STRINGIFY( _x ) __CL_STRINGIFY( _x ) +#define CL_PROGRAM_STRING_DEBUG_INFO "#line " _CL_STRINGIFY(__LINE__) " \"" __FILE__ "\" \n\n" + +#ifdef __cplusplus +} +#endif + +#undef __CL_HAS_ANON_STRUCT__ +#undef __CL_ANON_STRUCT__ +#if defined( _WIN32) && defined(_MSC_VER) + #if _MSC_VER >=1500 + #pragma warning( pop ) + #endif +#endif + +#endif /* __CL_PLATFORM_H */ diff --git a/src/3rdparty/CL/cl_va_api_media_sharing_intel.h b/src/3rdparty/CL/cl_va_api_media_sharing_intel.h new file mode 100644 index 000000000..934f3f52a --- /dev/null +++ b/src/3rdparty/CL/cl_va_api_media_sharing_intel.h @@ -0,0 +1,172 @@ +/********************************************************************************** + * Copyright (c) 2008-2019 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ +/*****************************************************************************\ + +Copyright (c) 2013-2019 Intel Corporation All Rights Reserved. + +THESE MATERIALS ARE PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE +MATERIALS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +File Name: cl_va_api_media_sharing_intel.h + +Abstract: + +Notes: + +\*****************************************************************************/ + + +#ifndef __OPENCL_CL_VA_API_MEDIA_SHARING_INTEL_H +#define __OPENCL_CL_VA_API_MEDIA_SHARING_INTEL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************** +* cl_intel_va_api_media_sharing extension * +*******************************************/ + +#define cl_intel_va_api_media_sharing 1 + +/* error codes */ +#define CL_INVALID_VA_API_MEDIA_ADAPTER_INTEL -1098 +#define CL_INVALID_VA_API_MEDIA_SURFACE_INTEL -1099 +#define CL_VA_API_MEDIA_SURFACE_ALREADY_ACQUIRED_INTEL -1100 +#define CL_VA_API_MEDIA_SURFACE_NOT_ACQUIRED_INTEL -1101 + +/* cl_va_api_device_source_intel */ +#define CL_VA_API_DISPLAY_INTEL 0x4094 + +/* cl_va_api_device_set_intel */ +#define CL_PREFERRED_DEVICES_FOR_VA_API_INTEL 0x4095 +#define CL_ALL_DEVICES_FOR_VA_API_INTEL 0x4096 + +/* cl_context_info */ +#define CL_CONTEXT_VA_API_DISPLAY_INTEL 0x4097 + +/* cl_mem_info */ +#define CL_MEM_VA_API_MEDIA_SURFACE_INTEL 0x4098 + +/* cl_image_info */ +#define CL_IMAGE_VA_API_PLANE_INTEL 0x4099 + +/* cl_command_type */ +#define CL_COMMAND_ACQUIRE_VA_API_MEDIA_SURFACES_INTEL 0x409A +#define CL_COMMAND_RELEASE_VA_API_MEDIA_SURFACES_INTEL 0x409B + +typedef cl_uint cl_va_api_device_source_intel; +typedef cl_uint cl_va_api_device_set_intel; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceIDsFromVA_APIMediaAdapterINTEL( + cl_platform_id platform, + cl_va_api_device_source_intel media_adapter_type, + void* media_adapter, + cl_va_api_device_set_intel media_adapter_set, + cl_uint num_entries, + cl_device_id* devices, + cl_uint* num_devices) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn)( + cl_platform_id platform, + cl_va_api_device_source_intel media_adapter_type, + void* media_adapter, + cl_va_api_device_set_intel media_adapter_set, + cl_uint num_entries, + cl_device_id* devices, + cl_uint* num_devices) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromVA_APIMediaSurfaceINTEL( + cl_context context, + cl_mem_flags flags, + VASurfaceID* surface, + cl_uint plane, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL * clCreateFromVA_APIMediaSurfaceINTEL_fn)( + cl_context context, + cl_mem_flags flags, + VASurfaceID* surface, + cl_uint plane, + cl_int* errcode_ret) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireVA_APIMediaSurfacesINTEL( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseVA_APIMediaSurfacesINTEL( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)( + cl_command_queue command_queue, + cl_uint num_objects, + const cl_mem* mem_objects, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event) CL_EXT_SUFFIX__VERSION_1_2; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_VA_API_MEDIA_SHARING_INTEL_H */ + diff --git a/src/3rdparty/CL/cl_version.h b/src/3rdparty/CL/cl_version.h new file mode 100644 index 000000000..bb766cb9b --- /dev/null +++ b/src/3rdparty/CL/cl_version.h @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2018 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#ifndef __CL_VERSION_H +#define __CL_VERSION_H + +/* Detect which version to target */ +#if !defined(CL_TARGET_OPENCL_VERSION) +#pragma message("cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 220 (OpenCL 2.2)") +#define CL_TARGET_OPENCL_VERSION 220 +#endif +#if CL_TARGET_OPENCL_VERSION != 100 && \ + CL_TARGET_OPENCL_VERSION != 110 && \ + CL_TARGET_OPENCL_VERSION != 120 && \ + CL_TARGET_OPENCL_VERSION != 200 && \ + CL_TARGET_OPENCL_VERSION != 210 && \ + CL_TARGET_OPENCL_VERSION != 220 +#pragma message("cl_version: CL_TARGET_OPENCL_VERSION is not a valid value (100, 110, 120, 200, 210, 220). Defaulting to 220 (OpenCL 2.2)") +#undef CL_TARGET_OPENCL_VERSION +#define CL_TARGET_OPENCL_VERSION 220 +#endif + + +/* OpenCL Version */ +#if CL_TARGET_OPENCL_VERSION >= 220 && !defined(CL_VERSION_2_2) +#define CL_VERSION_2_2 1 +#endif +#if CL_TARGET_OPENCL_VERSION >= 210 && !defined(CL_VERSION_2_1) +#define CL_VERSION_2_1 1 +#endif +#if CL_TARGET_OPENCL_VERSION >= 200 && !defined(CL_VERSION_2_0) +#define CL_VERSION_2_0 1 +#endif +#if CL_TARGET_OPENCL_VERSION >= 120 && !defined(CL_VERSION_1_2) +#define CL_VERSION_1_2 1 +#endif +#if CL_TARGET_OPENCL_VERSION >= 110 && !defined(CL_VERSION_1_1) +#define CL_VERSION_1_1 1 +#endif +#if CL_TARGET_OPENCL_VERSION >= 100 && !defined(CL_VERSION_1_0) +#define CL_VERSION_1_0 1 +#endif + +/* Allow deprecated APIs for older OpenCL versions. */ +#if CL_TARGET_OPENCL_VERSION <= 210 && !defined(CL_USE_DEPRECATED_OPENCL_2_1_APIS) +#define CL_USE_DEPRECATED_OPENCL_2_1_APIS +#endif +#if CL_TARGET_OPENCL_VERSION <= 200 && !defined(CL_USE_DEPRECATED_OPENCL_2_0_APIS) +#define CL_USE_DEPRECATED_OPENCL_2_0_APIS +#endif +#if CL_TARGET_OPENCL_VERSION <= 120 && !defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS) +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS +#endif +#if CL_TARGET_OPENCL_VERSION <= 110 && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define CL_USE_DEPRECATED_OPENCL_1_1_APIS +#endif +#if CL_TARGET_OPENCL_VERSION <= 100 && !defined(CL_USE_DEPRECATED_OPENCL_1_0_APIS) +#define CL_USE_DEPRECATED_OPENCL_1_0_APIS +#endif + +#endif /* __CL_VERSION_H */ diff --git a/src/3rdparty/CL/opencl.h b/src/3rdparty/CL/opencl.h new file mode 100644 index 000000000..143d1d2dc --- /dev/null +++ b/src/3rdparty/CL/opencl.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are 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 Materials. + * + * MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS + * KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS + * SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + * https://www.khronos.org/registry/ + * + * THE MATERIALS ARE 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 + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ + +#ifndef __OPENCL_H +#define __OPENCL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_H */ diff --git a/src/3rdparty/argon2.h b/src/3rdparty/argon2.h new file mode 100644 index 000000000..6d5f2e694 --- /dev/null +++ b/src/3rdparty/argon2.h @@ -0,0 +1,33 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef XMRIG_3RDPARTY_ARGON2_H +#define XMRIG_3RDPARTY_ARGON2_H + + +#include "3rdparty/argon2/include/argon2.h" + + +#endif /* XMRIG_3RDPARTY_ARGON2_H */ diff --git a/src/3rdparty/argon2/CMakeLists.txt b/src/3rdparty/argon2/CMakeLists.txt new file mode 100644 index 000000000..30900b0bc --- /dev/null +++ b/src/3rdparty/argon2/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required(VERSION 2.6) + +project(Argon2 C) +set(ARGON2_VERSION 1.0) +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) + +include(CheckCSourceCompiles) + +add_library(argon2 STATIC + lib/argon2.c + lib/core.c + lib/encoding.c + lib/genkat.c + lib/impl-select.c + lib/blake2/blake2.c +) + +target_include_directories(argon2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(argon2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +if (CMAKE_C_COMPILER_ID MATCHES MSVC) + function(add_feature_impl FEATURE MSVC_FLAG DEF) + add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c) + target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) + target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib) + set_target_properties(argon2-${FEATURE} PROPERTIES POSITION_INDEPENDENT_CODE True) + + target_compile_options(argon2-${FEATURE} PRIVATE ${MSVC_FLAG}) + target_compile_definitions(argon2-${FEATURE} PRIVATE ${DEF}) + target_link_libraries(argon2 PUBLIC argon2-${FEATURE}) + endfunction() + + add_feature_impl(sse2 "" HAVE_SSE2) + add_feature_impl(ssse3 "/arch:SSSE3" HAVE_SSSE3) + add_feature_impl(xop "" HAVE_XOP) + add_feature_impl(avx2 "/arch:AVX2" HAVE_AVX2) + add_feature_impl(avx512f "/arch:AVX512F" HAVE_AVX512F) + + target_sources(argon2 PRIVATE arch/x86_64/lib/argon2-arch.c arch/x86_64/lib/cpu-flags.c) +elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8) + function(add_feature_impl FEATURE GCC_FLAG DEF) + add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c) + target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) + target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib) + set_target_properties(argon2-${FEATURE} PROPERTIES POSITION_INDEPENDENT_CODE True) + + message("-- argon2: detecting feature '${FEATURE}'...") + file(READ arch/x86_64/src/test-feature-${FEATURE}.c SOURCE_CODE) + + # try without flag: + check_c_source_compiles("${SOURCE_CODE}" FEATURE_${FEATURE}_NOFLAG) + set(HAS_FEATURE ${FEATURE_${FEATURE}_NOFLAG}) + if (NOT "${HAS_FEATURE}") + # try with -m flag: + set(CMAKE_REQUIRED_FLAGS ${GCC_FLAG}) + check_c_source_compiles("${SOURCE_CODE}" FEATURE_${FEATURE}_FLAG) + set(CMAKE_REQUIRED_FLAGS "") + + set(HAS_FEATURE ${FEATURE_${FEATURE}_FLAG}) + if (${HAS_FEATURE}) + target_compile_options(argon2-${FEATURE} PRIVATE ${GCC_FLAG}) + endif() + endif() + + if (${HAS_FEATURE}) + message("-- argon2: feature '${FEATURE}' detected!") + target_compile_definitions(argon2-${FEATURE} PRIVATE ${DEF}) + endif() + + target_link_libraries(argon2 PUBLIC argon2-${FEATURE}) + endfunction() + + add_feature_impl(sse2 -msse2 HAVE_SSE2) + add_feature_impl(ssse3 -mssse3 HAVE_SSSE3) + add_feature_impl(xop -mxop HAVE_XOP) + add_feature_impl(avx2 -mavx2 HAVE_AVX2) + add_feature_impl(avx512f -mavx512f HAVE_AVX512F) + + target_sources(argon2 PRIVATE arch/x86_64/lib/argon2-arch.c arch/x86_64/lib/cpu-flags.c) +else() + target_sources(argon2 PRIVATE arch/generic/lib/argon2-arch.c) +endif() diff --git a/src/3rdparty/argon2/LICENSE b/src/3rdparty/argon2/LICENSE new file mode 100644 index 000000000..f9b00035c --- /dev/null +++ b/src/3rdparty/argon2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Ondrej Mosnáček + +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/src/3rdparty/argon2/README.md b/src/3rdparty/argon2/README.md new file mode 100644 index 000000000..254e26dad --- /dev/null +++ b/src/3rdparty/argon2/README.md @@ -0,0 +1,58 @@ +# Argon2 [![Build Status](https://travis-ci.org/WOnder93/argon2.svg?branch=master)](https://travis-ci.org/WOnder93/argon2) +A multi-arch library implementing the Argon2 password hashing algorithm. + +This project is based on the [original source code](https://github.com/P-H-C/phc-winner-argon2) by the Argon2 authors. The goal of this project is to provide efficient Argon2 implementations for various HW architectures (x86, SSE, ARM, PowerPC, ...). + +For the x86_64 architecture, the library implements a simple CPU dispatch which automatically selects the best implementation based on CPU flags and quick benchmarks. + +# Building +## Using GNU autotools + +To prepare the build environment, run: +```bash +autoreconf -i +./configure +``` + +After that, just run `make` to build the library. + +### Running tests +After configuring the build environment, run `make check` to run the tests. + +### Architecture options +You can specify the target architecture by passing the `--host=...` flag to `./configure`. + +Supported architectures: + * `x86_64` – 64-bit x86 architecture + * `generic` – use generic C impementation + +## Using CMake + +To prepare the build environment, run: +```bash +cmake -DCMAKE_BUILD_TYPE=Release . +``` + +Then you can run `make` to build the library. + +## Using QMake/Qt Creator +A [QMake](http://doc.qt.io/qt-4.8/qmake-manual.html) project is also available in the `qmake` directory. You can open it in the [Qt Creator IDE](http://wiki.qt.io/Category:Tools::QtCreator) or build it from terminal: +```bash +cd qmake +# see table below for the list of possible ARCH and CONFIG values +qmake ARCH=... CONFIG+=... +make +``` + +### Architecture options +For QMake builds you can configure support for different architectures. Use the `ARCH` variable to choose the architecture and the `CONFIG` variable to set additional options. + +Supported architectures: + * `x86_64` – 64-bit x86 architecture + * QMake config flags: + * `USE_SSE2` – use SSE2 instructions + * `USE_SSSE3` – use SSSE3 instructions + * `USE_XOP` – use XOP instructions + * `USE_AVX2` – use AVX2 instructions + * `USE_AVX512F` – use AVX-512F instructions + * `generic` – use generic C impementation diff --git a/src/3rdparty/argon2/arch/generic/lib/argon2-arch.c b/src/3rdparty/argon2/arch/generic/lib/argon2-arch.c new file mode 100644 index 000000000..39abadeeb --- /dev/null +++ b/src/3rdparty/argon2/arch/generic/lib/argon2-arch.c @@ -0,0 +1,20 @@ +#include +#include +#include + +#include "impl-select.h" + +#define rotr64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) + +#include "argon2-template-64.h" + +void fill_segment_default(const argon2_instance_t *instance, + argon2_position_t position) +{ + fill_segment_64(instance, position); +} + +void argon2_get_impl_list(argon2_impl_list *list) +{ + list->count = 0; +} diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-arch.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-arch.c new file mode 100644 index 000000000..4486e3951 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-arch.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "impl-select.h" + +#include "cpu-flags.h" +#include "argon2-sse2.h" +#include "argon2-ssse3.h" +#include "argon2-xop.h" +#include "argon2-avx2.h" +#include "argon2-avx512f.h" + +/* NOTE: there is no portable intrinsic for 64-bit rotate, but any + * sane compiler should be able to compile this into a ROR instruction: */ +#define rotr64(x, n) ((x) >> (n)) | ((x) << (64 - (n))) + +#include "argon2-template-64.h" + +void fill_segment_default(const argon2_instance_t *instance, + argon2_position_t position) +{ + fill_segment_64(instance, position); +} + +void argon2_get_impl_list(argon2_impl_list *list) +{ + static const argon2_impl IMPLS[] = { + { "x86_64", NULL, fill_segment_default }, + { "SSE2", check_sse2, fill_segment_sse2 }, + { "SSSE3", check_ssse3, fill_segment_ssse3 }, + { "XOP", check_xop, fill_segment_xop }, + { "AVX2", check_avx2, fill_segment_avx2 }, + { "AVX-512F", check_avx512f, fill_segment_avx512f }, + }; + + cpu_flags_get(); + + list->count = sizeof(IMPLS) / sizeof(IMPLS[0]); + list->entries = IMPLS; +} diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.c new file mode 100644 index 000000000..09ef421a6 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.c @@ -0,0 +1,347 @@ +#include "argon2-avx2.h" + +#ifdef HAVE_AVX2 +#include + +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "cpu-flags.h" + +#define r16 (_mm256_setr_epi8( \ + 2, 3, 4, 5, 6, 7, 0, 1, \ + 10, 11, 12, 13, 14, 15, 8, 9, \ + 18, 19, 20, 21, 22, 23, 16, 17, \ + 26, 27, 28, 29, 30, 31, 24, 25)) + +#define r24 (_mm256_setr_epi8( \ + 3, 4, 5, 6, 7, 0, 1, 2, \ + 11, 12, 13, 14, 15, 8, 9, 10, \ + 19, 20, 21, 22, 23, 16, 17, 18, \ + 27, 28, 29, 30, 31, 24, 25, 26)) + +#define ror64_16(x) _mm256_shuffle_epi8((x), r16) +#define ror64_24(x) _mm256_shuffle_epi8((x), r24) +#define ror64_32(x) _mm256_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) +#define ror64_63(x) \ + _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x))) + +static __m256i f(__m256i x, __m256i y) +{ + __m256i z = _mm256_mul_epu32(x, y); + return _mm256_add_epi64(_mm256_add_epi64(x, y), _mm256_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm256_xor_si256(D0, A0); \ + D1 = _mm256_xor_si256(D1, A1); \ +\ + D0 = ror64_32(D0); \ + D1 = ror64_32(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm256_xor_si256(B0, C0); \ + B1 = _mm256_xor_si256(B1, C1); \ +\ + B0 = ror64_24(B0); \ + B1 = ror64_24(B1); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm256_xor_si256(D0, A0); \ + D1 = _mm256_xor_si256(D1, A1); \ +\ + D0 = ror64_16(D0); \ + D1 = ror64_16(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm256_xor_si256(B0, C0); \ + B1 = _mm256_xor_si256(B1, C1); \ +\ + B0 = ror64_63(B0); \ + B1 = ror64_63(B1); \ + } while ((void)0, 0) + +#define DIAGONALIZE1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \ + B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \ +\ + C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ +\ + D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \ + D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \ + B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \ +\ + C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ +\ + D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \ + D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \ + } while ((void)0, 0) + +#define DIAGONALIZE2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m256i tmp1, tmp2; \ + tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \ + tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \ + B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ +\ + tmp1 = C0; \ + C0 = C1; \ + C1 = tmp1; \ +\ + tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \ + tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \ + D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m256i tmp1, tmp2; \ + tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \ + tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \ + B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ +\ + tmp1 = C0; \ + C0 = C1; \ + C1 = tmp1; \ +\ + tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \ + tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \ + D1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + D0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE1(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + UNDIAGONALIZE1(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + UNDIAGONALIZE2(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +enum { + ARGON2_HWORDS_IN_BLOCK = ARGON2_OWORDS_IN_BLOCK / 2, +}; + +static void fill_block(__m256i *s, const block *ref_block, block *next_block, + int with_xor) +{ + __m256i block_XY[ARGON2_HWORDS_IN_BLOCK]; + unsigned int i; + + if (with_xor) { + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + s[i] =_mm256_xor_si256( + s[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i)); + block_XY[i] = _mm256_xor_si256( + s[i], _mm256_loadu_si256((const __m256i *)next_block->v + i)); + } + + } else { + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + block_XY[i] = s[i] =_mm256_xor_si256( + s[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i)); + } + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND1( + s[8 * i + 0], s[8 * i + 1], s[8 * i + 2], s[8 * i + 3], + s[8 * i + 4], s[8 * i + 5], s[8 * i + 6], s[8 * i + 7]); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND2( + s[4 * 0 + i], s[4 * 1 + i], s[4 * 2 + i], s[4 * 3 + i], + s[4 * 4 + i], s[4 * 5 + i], s[4 * 6 + i], s[4 * 7 + i]); + } + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + s[i] = _mm256_xor_si256(s[i], block_XY[i]); + _mm256_storeu_si256((__m256i *)next_block->v + i, s[i]); + } +} + +static void next_addresses(block *address_block, block *input_block) +{ + /*Temporary zero-initialized blocks*/ + __m256i zero_block[ARGON2_HWORDS_IN_BLOCK]; + __m256i zero2_block[ARGON2_HWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + + /*Increasing index counter*/ + input_block->v[6]++; + + /*First iteration of G*/ + fill_block(zero_block, input_block, address_block, 0); + + /*Second iteration of G*/ + fill_block(zero2_block, address_block, address_block, 0); +} + +void fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m256i state[ARGON2_HWORDS_IN_BLOCK]; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + + /* version 1.2.1 and earlier: overwrite, not XOR */ + if (0 == position.pass || ARGON2_VERSION_10 == instance->version) { + fill_block(state, ref_block, curr_block, 0); + } else { + fill_block(state, ref_block, curr_block, 1); + } + } +} + +int check_avx2(void) +{ + return cpu_flags_have_avx2(); +} + +#else + +void fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position) +{ +} + +int check_avx2(void) +{ + return 0; +} + +#endif diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.h new file mode 100644 index 000000000..8abdb8a53 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx2.h @@ -0,0 +1,11 @@ +#ifndef ARGON2_AVX2_H +#define ARGON2_AVX2_H + +#include "core.h" + +void fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position); + +int check_avx2(void); + +#endif // ARGON2_AVX2_H diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.c new file mode 100644 index 000000000..79fd2ddaf --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.c @@ -0,0 +1,332 @@ +#include "argon2-avx512f.h" + +#ifdef HAVE_AVX512F +#include +#include + +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "cpu-flags.h" + +#define ror64(x, n) _mm512_ror_epi64((x), (n)) + +static __m512i f(__m512i x, __m512i y) +{ + __m512i z = _mm512_mul_epu32(x, y); + return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm512_xor_si512(D0, A0); \ + D1 = _mm512_xor_si512(D1, A1); \ +\ + D0 = ror64(D0, 32); \ + D1 = ror64(D1, 32); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm512_xor_si512(B0, C0); \ + B1 = _mm512_xor_si512(B1, C1); \ +\ + B0 = ror64(B0, 24); \ + B1 = ror64(B1, 24); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm512_xor_si512(D0, A0); \ + D1 = _mm512_xor_si512(D1, A1); \ +\ + D0 = ror64(D0, 16); \ + D1 = ror64(D1, 16); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm512_xor_si512(B0, C0); \ + B1 = _mm512_xor_si512(B1, C1); \ +\ + B0 = ror64(B0, 63); \ + B1 = ror64(B1, 63); \ + } while ((void)0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \ + B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \ +\ + C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ +\ + D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \ + D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \ + B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \ +\ + C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ +\ + D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \ + D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#define SWAP_HALVES(A0, A1) \ + do { \ + __m512i t0, t1; \ + t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \ + t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \ + A0 = t0; \ + A1 = t1; \ + } while((void)0, 0) + +#define SWAP_QUARTERS(A0, A1) \ + do { \ + SWAP_HALVES(A0, A1); \ + A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \ + A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \ + } while((void)0, 0) + +#define UNSWAP_QUARTERS(A0, A1) \ + do { \ + A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \ + A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \ + SWAP_HALVES(A0, A1); \ + } while((void)0, 0) + +#define BLAKE2_ROUND1(A0, C0, B0, D0, A1, C1, B1, D1) \ + do { \ + SWAP_HALVES(A0, B0); \ + SWAP_HALVES(C0, D0); \ + SWAP_HALVES(A1, B1); \ + SWAP_HALVES(C1, D1); \ + BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \ + SWAP_HALVES(A0, B0); \ + SWAP_HALVES(C0, D0); \ + SWAP_HALVES(A1, B1); \ + SWAP_HALVES(C1, D1); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + SWAP_QUARTERS(A0, A1); \ + SWAP_QUARTERS(B0, B1); \ + SWAP_QUARTERS(C0, C1); \ + SWAP_QUARTERS(D0, D1); \ + BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \ + UNSWAP_QUARTERS(A0, A1); \ + UNSWAP_QUARTERS(B0, B1); \ + UNSWAP_QUARTERS(C0, C1); \ + UNSWAP_QUARTERS(D0, D1); \ + } while ((void)0, 0) + +enum { + ARGON2_VECS_IN_BLOCK = ARGON2_OWORDS_IN_BLOCK / 4, +}; + +static void fill_block(__m512i *s, const block *ref_block, block *next_block, + int with_xor) +{ + __m512i block_XY[ARGON2_VECS_IN_BLOCK]; + unsigned int i; + + if (with_xor) { + for (i = 0; i < ARGON2_VECS_IN_BLOCK; i++) { + s[i] =_mm512_xor_si512( + s[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i)); + block_XY[i] = _mm512_xor_si512( + s[i], _mm512_loadu_si512((const __m512i *)next_block->v + i)); + } + + } else { + for (i = 0; i < ARGON2_VECS_IN_BLOCK; i++) { + block_XY[i] = s[i] =_mm512_xor_si512( + s[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i)); + } + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND1( + s[8 * i + 0], s[8 * i + 1], s[8 * i + 2], s[8 * i + 3], + s[8 * i + 4], s[8 * i + 5], s[8 * i + 6], s[8 * i + 7]); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND2( + s[2 * 0 + i], s[2 * 1 + i], s[2 * 2 + i], s[2 * 3 + i], + s[2 * 4 + i], s[2 * 5 + i], s[2 * 6 + i], s[2 * 7 + i]); + } + + for (i = 0; i < ARGON2_VECS_IN_BLOCK; i++) { + s[i] = _mm512_xor_si512(s[i], block_XY[i]); + _mm512_storeu_si512((__m512i *)next_block->v + i, s[i]); + } +} + +static void next_addresses(block *address_block, block *input_block) +{ + /*Temporary zero-initialized blocks*/ + __m512i zero_block[ARGON2_VECS_IN_BLOCK]; + __m512i zero2_block[ARGON2_VECS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + + /*Increasing index counter*/ + input_block->v[6]++; + + /*First iteration of G*/ + fill_block(zero_block, input_block, address_block, 0); + + /*Second iteration of G*/ + fill_block(zero2_block, address_block, address_block, 0); +} + +void fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m512i state[ARGON2_VECS_IN_BLOCK]; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + + /* version 1.2.1 and earlier: overwrite, not XOR */ + if (0 == position.pass || ARGON2_VERSION_10 == instance->version) { + fill_block(state, ref_block, curr_block, 0); + } else { + fill_block(state, ref_block, curr_block, 1); + } + } +} + +int check_avx512f(void) +{ + return cpu_flags_have_avx512f(); +} + +#else + +void fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position) +{ +} + +int check_avx512f(void) +{ + return 0; +} + +#endif diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.h new file mode 100644 index 000000000..ba4311142 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-avx512f.h @@ -0,0 +1,11 @@ +#ifndef ARGON2_AVX512F_H +#define ARGON2_AVX512F_H + +#include "core.h" + +void fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position); + +int check_avx512f(void); + +#endif // ARGON2_AVX512F_H diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.c new file mode 100644 index 000000000..5eccdf07e --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.c @@ -0,0 +1,128 @@ +#include "argon2-sse2.h" + +#ifdef HAVE_SSE2 +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "cpu-flags.h" + +#define ror64_16(x) \ + _mm_shufflehi_epi16( \ + _mm_shufflelo_epi16((x), _MM_SHUFFLE(0, 3, 2, 1)), \ + _MM_SHUFFLE(0, 3, 2, 1)) +#define ror64_24(x) \ + _mm_xor_si128(_mm_srli_epi64((x), 24), _mm_slli_epi64((x), 40)) +#define ror64_32(x) _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) +#define ror64_63(x) \ + _mm_xor_si128(_mm_srli_epi64((x), 63), _mm_add_epi64((x), (x))) + +static __m128i f(__m128i x, __m128i y) +{ + __m128i z = _mm_mul_epu32(x, y); + return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64_32(D0); \ + D1 = ror64_32(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64_24(B0); \ + B1 = ror64_24(B1); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64_16(D0); \ + D1 = ror64_16(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64_63(B0); \ + B1 = ror64_63(B1); \ + } while ((void)0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = D0; \ + __m128i t1 = B0; \ + D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \ + D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \ + B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \ + B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = B0; \ + __m128i t1 = D0; \ + B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \ + B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \ + D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \ + D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C1, D0, A1, B1, C0, D1); \ + G2(A0, B0, C1, D0, A1, B1, C0, D1); \ +\ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#include "argon2-template-128.h" + +void fill_segment_sse2(const argon2_instance_t *instance, + argon2_position_t position) +{ + fill_segment_128(instance, position); +} + +int check_sse2(void) +{ + return cpu_flags_have_sse2(); +} + +#else + +void fill_segment_sse2(const argon2_instance_t *instance, + argon2_position_t position) +{ +} + +int check_sse2(void) +{ + return 0; +} + +#endif diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.h new file mode 100644 index 000000000..024d503d3 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-sse2.h @@ -0,0 +1,11 @@ +#ifndef ARGON2_SSE2_H +#define ARGON2_SSE2_H + +#include "core.h" + +void fill_segment_sse2(const argon2_instance_t *instance, + argon2_position_t position); + +int check_sse2(void); + +#endif // ARGON2_SSE2_H diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.c new file mode 100644 index 000000000..86e9b3c90 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.c @@ -0,0 +1,140 @@ +#include "argon2-ssse3.h" + +#ifdef HAVE_SSSE3 +#include + +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "cpu-flags.h" + +#define r16 (_mm_setr_epi8( \ + 2, 3, 4, 5, 6, 7, 0, 1, \ + 10, 11, 12, 13, 14, 15, 8, 9)) + +#define r24 (_mm_setr_epi8( \ + 3, 4, 5, 6, 7, 0, 1, 2, \ + 11, 12, 13, 14, 15, 8, 9, 10)) + +#define ror64_16(x) _mm_shuffle_epi8((x), r16) +#define ror64_24(x) _mm_shuffle_epi8((x), r24) +#define ror64_32(x) _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) +#define ror64_63(x) \ + _mm_xor_si128(_mm_srli_epi64((x), 63), _mm_add_epi64((x), (x))) + +static __m128i f(__m128i x, __m128i y) +{ + __m128i z = _mm_mul_epu32(x, y); + return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64_32(D0); \ + D1 = ror64_32(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64_24(B0); \ + B1 = ror64_24(B1); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64_16(D0); \ + D1 = ror64_16(D1); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64_63(B0); \ + B1 = ror64_63(B1); \ + } while ((void)0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B1, B0, 8); \ + __m128i t1 = _mm_alignr_epi8(B0, B1, 8); \ + B0 = t0; \ + B1 = t1; \ +\ + t0 = _mm_alignr_epi8(D1, D0, 8); \ + t1 = _mm_alignr_epi8(D0, D1, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B0, B1, 8); \ + __m128i t1 = _mm_alignr_epi8(B1, B0, 8); \ + B0 = t0; \ + B1 = t1; \ +\ + t0 = _mm_alignr_epi8(D0, D1, 8); \ + t1 = _mm_alignr_epi8(D1, D0, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C1, D0, A1, B1, C0, D1); \ + G2(A0, B0, C1, D0, A1, B1, C0, D1); \ +\ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#include "argon2-template-128.h" + +void fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position) +{ + fill_segment_128(instance, position); +} + +int check_ssse3(void) +{ + return cpu_flags_have_ssse3(); +} + +#else + +void fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position) +{ +} + +int check_ssse3(void) +{ + return 0; +} + +#endif diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.h new file mode 100644 index 000000000..139fdacca --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-ssse3.h @@ -0,0 +1,11 @@ +#ifndef ARGON2_SSSE3_H +#define ARGON2_SSSE3_H + +#include "core.h" + +void fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position); + +int check_ssse3(void); + +#endif // ARGON2_SSSE3_H diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-template-128.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-template-128.h new file mode 100644 index 000000000..4fb04c1fe --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-template-128.h @@ -0,0 +1,168 @@ +#include + +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "core.h" + +static void fill_block(__m128i *s, const block *ref_block, block *next_block, + int with_xor) +{ + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + unsigned int i; + + if (with_xor) { + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + s[i] = _mm_xor_si128( + s[i], _mm_loadu_si128((const __m128i *)ref_block->v + i)); + block_XY[i] = _mm_xor_si128( + s[i], _mm_loadu_si128((const __m128i *)next_block->v + i)); + } + } else { + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + block_XY[i] = s[i] = _mm_xor_si128( + s[i], _mm_loadu_si128((const __m128i *)ref_block->v + i)); + } + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND( + s[8 * i + 0], s[8 * i + 1], s[8 * i + 2], s[8 * i + 3], + s[8 * i + 4], s[8 * i + 5], s[8 * i + 6], s[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND( + s[8 * 0 + i], s[8 * 1 + i], s[8 * 2 + i], s[8 * 3 + i], + s[8 * 4 + i], s[8 * 5 + i], s[8 * 6 + i], s[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + s[i] = _mm_xor_si128(s[i], block_XY[i]); + _mm_storeu_si128((__m128i *)next_block->v + i, s[i]); + } +} + +static void next_addresses(block *address_block, block *input_block) +{ + /*Temporary zero-initialized blocks*/ + __m128i zero_block[ARGON2_OWORDS_IN_BLOCK]; + __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + + /*Increasing index counter*/ + input_block->v[6]++; + + /*First iteration of G*/ + fill_block(zero_block, input_block, address_block, 0); + + /*Second iteration of G*/ + fill_block(zero2_block, address_block, address_block, 0); +} + +static void fill_segment_128(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m128i state[ARGON2_OWORDS_IN_BLOCK]; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + + /* version 1.2.1 and earlier: overwrite, not XOR */ + if (0 == position.pass || ARGON2_VERSION_10 == instance->version) { + fill_block(state, ref_block, curr_block, 0); + } else { + fill_block(state, ref_block, curr_block, 1); + } + } +} diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.c b/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.c new file mode 100644 index 000000000..0e877bce0 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.c @@ -0,0 +1,128 @@ +#include "argon2-xop.h" + +#ifdef HAVE_XOP +#include + +#ifdef __GNUC__ +# include +#else +# include +#endif + +#include "cpu-flags.h" + +#define ror64(x, c) _mm_roti_epi64((x), -(c)) + +static __m128i f(__m128i x, __m128i y) +{ + __m128i z = _mm_mul_epu32(x, y); + return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64(D0, 32); \ + D1 = ror64(D1, 32); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64(B0, 24); \ + B1 = ror64(B1, 24); \ + } while ((void)0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = f(A0, B0); \ + A1 = f(A1, B1); \ +\ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ +\ + D0 = ror64(D0, 16); \ + D1 = ror64(D1, 16); \ +\ + C0 = f(C0, D0); \ + C1 = f(C1, D1); \ +\ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ +\ + B0 = ror64(B0, 63); \ + B1 = ror64(B1, 63); \ + } while ((void)0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B1, B0, 8); \ + __m128i t1 = _mm_alignr_epi8(B0, B1, 8); \ + B0 = t0; \ + B1 = t1; \ +\ + t0 = _mm_alignr_epi8(D1, D0, 8); \ + t1 = _mm_alignr_epi8(D0, D1, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B0, B1, 8); \ + __m128i t1 = _mm_alignr_epi8(B1, B0, 8); \ + B0 = t0; \ + B1 = t1; \ +\ + t0 = _mm_alignr_epi8(D0, D1, 8); \ + t1 = _mm_alignr_epi8(D1, D0, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void)0, 0) + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ +\ + G1(A0, B0, C1, D0, A1, B1, C0, D1); \ + G2(A0, B0, C1, D0, A1, B1, C0, D1); \ +\ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#include "argon2-template-128.h" + +void fill_segment_xop(const argon2_instance_t *instance, + argon2_position_t position) +{ + fill_segment_128(instance, position); +} + +int check_xop(void) +{ + return cpu_flags_have_xop(); +} + +#else + +void fill_segment_xop(const argon2_instance_t *instance, + argon2_position_t position) +{ +} + +int check_xop(void) +{ + return 0; +} + +#endif diff --git a/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.h b/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.h new file mode 100644 index 000000000..1474a11c0 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/argon2-xop.h @@ -0,0 +1,11 @@ +#ifndef ARGON2_XOP_H +#define ARGON2_XOP_H + +#include "core.h" + +void fill_segment_xop(const argon2_instance_t *instance, + argon2_position_t position); + +int check_xop(void); + +#endif // ARGON2_XOP_H diff --git a/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.c b/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.c new file mode 100644 index 000000000..cd13cb015 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.c @@ -0,0 +1,129 @@ +#include +#include + + +#include "cpu-flags.h" + +#include + +#ifdef _MSC_VER +# include +#else +# include +#endif + +#ifndef bit_OSXSAVE +# define bit_OSXSAVE (1 << 27) +#endif + +#ifndef bit_SSE2 +# define bit_SSE2 (1 << 26) +#endif + +#ifndef bit_SSSE3 +# define bit_SSSE3 (1 << 9) +#endif + +#ifndef bit_AVX2 +# define bit_AVX2 (1 << 5) +#endif + +#ifndef bit_AVX512F +# define bit_AVX512F (1 << 16) +#endif + +#ifndef bit_XOP +# define bit_XOP (1 << 11) +#endif + +#define PROCESSOR_INFO (1) +#define EXTENDED_FEATURES (7) + +#define EAX_Reg (0) +#define EBX_Reg (1) +#define ECX_Reg (2) +#define EDX_Reg (3) + + +enum { + X86_64_FEATURE_SSE2 = (1 << 0), + X86_64_FEATURE_SSSE3 = (1 << 1), + X86_64_FEATURE_XOP = (1 << 2), + X86_64_FEATURE_AVX2 = (1 << 3), + X86_64_FEATURE_AVX512F = (1 << 4), +}; + +static unsigned int cpu_flags; + + +static inline void cpuid(uint32_t level, int32_t output[4]) +{ +# ifdef _MSC_VER + __cpuid(output, (int) level); +# else + __cpuid_count(level, 0, output[0], output[1], output[2], output[3]); +# endif +} + + +static bool has_feature(uint32_t level, uint32_t reg, int32_t bit) +{ + int32_t cpu_info[4] = { 0 }; + cpuid(level, cpu_info); + + return (cpu_info[reg] & bit) != 0; +} + + +void cpu_flags_get(void) +{ + if (has_feature(PROCESSOR_INFO, EDX_Reg, bit_SSE2)) { + cpu_flags |= X86_64_FEATURE_SSE2; + } + + if (has_feature(PROCESSOR_INFO, ECX_Reg, bit_SSSE3)) { + cpu_flags |= X86_64_FEATURE_SSSE3; + } + + if (!has_feature(PROCESSOR_INFO, ECX_Reg, bit_OSXSAVE)) { + return; + } + + if (has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX2)) { + cpu_flags |= X86_64_FEATURE_AVX2; + } + + if (has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX512F)) { + cpu_flags |= X86_64_FEATURE_AVX512F; + } + + if (has_feature(0x80000001, ECX_Reg, bit_XOP)) { + cpu_flags |= X86_64_FEATURE_XOP; + } +} + +int cpu_flags_have_sse2(void) +{ + return cpu_flags & X86_64_FEATURE_SSE2; +} + +int cpu_flags_have_ssse3(void) +{ + return cpu_flags & X86_64_FEATURE_SSSE3; +} + +int cpu_flags_have_xop(void) +{ + return cpu_flags & X86_64_FEATURE_XOP; +} + +int cpu_flags_have_avx2(void) +{ + return cpu_flags & X86_64_FEATURE_AVX2; +} + +int cpu_flags_have_avx512f(void) +{ + return cpu_flags & X86_64_FEATURE_AVX512F; +} + diff --git a/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.h b/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.h new file mode 100644 index 000000000..b546a8ba1 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/lib/cpu-flags.h @@ -0,0 +1,12 @@ +#ifndef ARGON2_CPU_FLAGS_H +#define ARGON2_CPU_FLAGS_H + +void cpu_flags_get(void); + +int cpu_flags_have_sse2(void); +int cpu_flags_have_ssse3(void); +int cpu_flags_have_xop(void); +int cpu_flags_have_avx2(void); +int cpu_flags_have_avx512f(void); + +#endif // ARGON2_CPU_FLAGS_H diff --git a/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx2.c b/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx2.c new file mode 100644 index 000000000..01e5b156d --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx2.c @@ -0,0 +1,8 @@ +#include + +void function_avx2(__m256i *dst, const __m256i *a, const __m256i *b) +{ + *dst = _mm256_xor_si256(*a, *b); +} + +int main(void) { return 0; } diff --git a/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx512f.c b/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx512f.c new file mode 100644 index 000000000..372eb2561 --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/src/test-feature-avx512f.c @@ -0,0 +1,8 @@ +#include + +void function_avx512f(__m512i *dst, const __m512i *a) +{ + *dst = _mm512_ror_epi64(*a, 57); +} + +int main(void) { return 0; } diff --git a/src/3rdparty/argon2/arch/x86_64/src/test-feature-sse2.c b/src/3rdparty/argon2/arch/x86_64/src/test-feature-sse2.c new file mode 100644 index 000000000..4a3b70fda --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/src/test-feature-sse2.c @@ -0,0 +1,8 @@ +#include + +void function_sse2(__m128i *dst, const __m128i *a, const __m128i *b) +{ + *dst = _mm_xor_si128(*a, *b); +} + +int main(void) { return 0; } diff --git a/src/3rdparty/argon2/arch/x86_64/src/test-feature-ssse3.c b/src/3rdparty/argon2/arch/x86_64/src/test-feature-ssse3.c new file mode 100644 index 000000000..db2b3551a --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/src/test-feature-ssse3.c @@ -0,0 +1,8 @@ +#include + +void function_ssse3(__m128i *dst, const __m128i *a, const __m128i *b) +{ + *dst = _mm_shuffle_epi8(*a, *b); +} + +int main(void) { return 0; } diff --git a/src/3rdparty/argon2/arch/x86_64/src/test-feature-xop.c b/src/3rdparty/argon2/arch/x86_64/src/test-feature-xop.c new file mode 100644 index 000000000..5897fe14d --- /dev/null +++ b/src/3rdparty/argon2/arch/x86_64/src/test-feature-xop.c @@ -0,0 +1,8 @@ +#include + +void function_xop(__m128i *dst, const __m128i *a, int b) +{ + *dst = _mm_roti_epi64(*a, b); +} + +int main(void) { return 0; } diff --git a/src/3rdparty/argon2/include/argon2.h b/src/3rdparty/argon2/include/argon2.h new file mode 100644 index 000000000..7759a8857 --- /dev/null +++ b/src/3rdparty/argon2/include/argon2.h @@ -0,0 +1,465 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef ARGON2_H +#define ARGON2_H + +#include +#include +#include +#include + +/* Symbols visibility control */ +#define ARGON2_PUBLIC + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Argon2 input parameter restrictions + */ + +/* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(4) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +/* Flags to determine which fields are securely wiped (default = no wipe). */ +#define ARGON2_DEFAULT_FLAGS UINT32_C(0) +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) +#define ARGON2_FLAG_GENKAT (UINT32_C(1) << 3) + +/* Global flag to determine if we are wiping internal memory buffers. This flag + * is defined in core.c and deafults to 1 (wipe internal memory). */ +extern int FLAG_clear_internal_memory; + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Memory allocator types --- for external allocation */ +typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); +typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); + +/* Argon2 external data structures */ + +/* + ***** + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with + * 4 parallel lanes. + * You want to erase the password, but you're OK with last pass not being + * erased. You want to use the default memory allocator. + * Then you initialize: + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t version; /* version number */ + + allocate_fptr allocate_cbk; /* pointer to memory allocator */ + deallocate_fptr free_cbk; /* pointer to memory deallocator */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { + Argon2_d = 0, + Argon2_i = 1, + Argon2_id = 2 +} argon2_type; + +/* Version of the algorithm */ +typedef enum Argon2_version { + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13, + ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 +} argon2_version; + +/* + * Function that gives the string representation of an argon2_type. + * @param type The argon2_type that we want the string for + * @param uppercase Whether the string should have the first letter uppercase + * @return NULL if invalid type, otherwise the string representation. + */ +ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase); + +/* + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type); + +/** + * Hashes a password with Argon2i, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +/** + * Hashes a password with Argon2i, producing a raw hash by allocating memory at + * @hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash - updated by the function + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2id_hash_raw_ex(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen, + void *memory); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd, + const size_t pwdlen, argon2_type type); + +/** + * Argon2d: Version of Argon2 that picks memory blocks depending + * on the password and salt. Only for side-channel-free + * environment!! + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_ctx(argon2_context *context); + +/** + * Argon2i: Version of Argon2 that picks memory blocks + * independent on the password and salt. Good for side-channels, + * but worse w.r.t. tradeoff attacks if only one pass is used. + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_ctx(argon2_context *context); + +/** + * Argon2id: Version of Argon2 where the first half-pass over memory is + * password-independent, the rest are password-dependent (on the password and + * salt). OK against side channels (they reduce to 1/2-pass Argon2i), and + * better with w.r.t. tradeoff attacks (similar to Argon2d). + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_ctx(argon2_context *context); + +/** + * Verify if a given password is correct for Argon2d hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2i hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2id hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context, + const char *hash); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type); + +/** + * Get the associated error message for given error code + * @return The error message associated with the given error code + */ +ARGON2_PUBLIC const char *argon2_error_message(int error_code); + +/** + * Returns the encoded hash length for the given input parameters + * @param t_cost Number of iterations + * @param m_cost Memory usage in kibibytes + * @param parallelism Number of threads; used to compute lanes + * @param saltlen Salt size in bytes + * @param hashlen Hash size in bytes + * @param type The argon2_type that we want the encoded length for + * @return The encoded hash length in bytes + */ +ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, + uint32_t parallelism, uint32_t saltlen, + uint32_t hashlen, argon2_type type); + +/* signals availability of argon2_select_impl: */ +#define ARGON2_SELECTABLE_IMPL + +/** + * Selects the fastest available optimized implementation. + * @param out The file for debug output (e. g. stderr; pass NULL for no + * debug output) + * @param prefix What to print before each line; NULL is equivalent to empty + * string + */ +ARGON2_PUBLIC void argon2_select_impl(); +ARGON2_PUBLIC const char *argon2_get_impl_name(); +ARGON2_PUBLIC int argon2_select_impl_by_name(const char *name); + +/* signals support for passing preallocated memory: */ +#define ARGON2_PREALLOCATED_MEMORY + +ARGON2_PUBLIC size_t argon2_memory_size(uint32_t m_cost, uint32_t parallelism); + +/** + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @param type The Argon2 type + * @param memory Preallocated memory for blocks (or NULL) + * @param memory_size The size of preallocated memory + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +ARGON2_PUBLIC int argon2_ctx_mem(argon2_context *context, argon2_type type, + void *memory, size_t memory_size); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/3rdparty/argon2/lib/argon2-template-64.h b/src/3rdparty/argon2/lib/argon2-template-64.h new file mode 100644 index 000000000..16ddbd35e --- /dev/null +++ b/src/3rdparty/argon2/lib/argon2-template-64.h @@ -0,0 +1,193 @@ +#include + +#include "core.h" + +#define MASK_32 UINT64_C(0xFFFFFFFF) + +#define F(x, y) ((x) + (y) + 2 * ((x) & MASK_32) * ((y) & MASK_32)) + +#define G(a, b, c, d) \ + do { \ + a = F(a, b); \ + d = rotr64(d ^ a, 32); \ + c = F(c, d); \ + b = rotr64(b ^ c, 24); \ + a = F(a, b); \ + d = rotr64(d ^ a, 16); \ + c = F(c, d); \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, \ + v8, v9, v10, v11, v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG1(v) \ + BLAKE2_ROUND_NOMSG( \ + (v)[ 0], (v)[ 1], (v)[ 2], (v)[ 3], \ + (v)[ 4], (v)[ 5], (v)[ 6], (v)[ 7], \ + (v)[ 8], (v)[ 9], (v)[10], (v)[11], \ + (v)[12], (v)[13], (v)[14], (v)[15]) + +#define BLAKE2_ROUND_NOMSG2(v) \ + BLAKE2_ROUND_NOMSG( \ + (v)[ 0], (v)[ 1], (v)[ 16], (v)[ 17], \ + (v)[ 32], (v)[ 33], (v)[ 48], (v)[ 49], \ + (v)[ 64], (v)[ 65], (v)[ 80], (v)[ 81], \ + (v)[ 96], (v)[ 97], (v)[112], (v)[113]) + +static void fill_block(const block *prev_block, const block *ref_block, + block *next_block, int with_xor) +{ + block blockR, block_tmp; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + if (with_xor) { + xor_block(&block_tmp, next_block); + } + + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + BLAKE2_ROUND_NOMSG1(blockR.v + 0 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 1 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 2 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 3 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 4 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 5 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 6 * 16); + BLAKE2_ROUND_NOMSG1(blockR.v + 7 * 16); + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + BLAKE2_ROUND_NOMSG2(blockR.v + 0 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 1 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 2 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 3 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 4 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 5 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 6 * 2); + BLAKE2_ROUND_NOMSG2(blockR.v + 7 * 2); + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +static void next_addresses(block *address_block, block *input_block, + const block *zero_block) +{ + input_block->v[6]++; + fill_block(zero_block, input_block, address_block, 0); + fill_block(zero_block, address_block, address_block, 0); +} + +static void fill_segment_64(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block, *curr_block, *prev_block; + block address_block, input_block, zero_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + init_block_value(&zero_block, 0); + init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + next_addresses(&address_block, &input_block, &zero_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + next_addresses(&address_block, &input_block, &zero_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + prev_block = instance->memory + prev_offset; + + /* version 1.2.1 and earlier: overwrite, not XOR */ + if (0 == position.pass || ARGON2_VERSION_10 == instance->version) { + fill_block(prev_block, ref_block, curr_block, 0); + } else { + fill_block(prev_block, ref_block, curr_block, 1); + } + } +} diff --git a/src/3rdparty/argon2/lib/argon2.c b/src/3rdparty/argon2/lib/argon2.c new file mode 100644 index 000000000..d4d038a97 --- /dev/null +++ b/src/3rdparty/argon2/lib/argon2.c @@ -0,0 +1,504 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2.h" +#include "encoding.h" +#include "core.h" + +const char *argon2_type2string(argon2_type type, int uppercase) { + switch (type) { + case Argon2_d: + return uppercase ? "Argon2d" : "argon2d"; + case Argon2_i: + return uppercase ? "Argon2i" : "argon2i"; + case Argon2_id: + return uppercase ? "Argon2id" : "argon2id"; + } + + return NULL; +} + +static void argon2_compute_memory_blocks(uint32_t *memory_blocks, + uint32_t *segment_length, + uint32_t m_cost, uint32_t lanes) +{ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + *memory_blocks = m_cost; + if (*memory_blocks < 2 * ARGON2_SYNC_POINTS * lanes) { + *memory_blocks = 2 * ARGON2_SYNC_POINTS * lanes; + } + + *segment_length = *memory_blocks / (lanes * ARGON2_SYNC_POINTS); + /* Ensure that all segments have equal length */ + *memory_blocks = *segment_length * (lanes * ARGON2_SYNC_POINTS); +} + +size_t argon2_memory_size(uint32_t m_cost, uint32_t parallelism) { + uint32_t memory_blocks, segment_length; + argon2_compute_memory_blocks(&memory_blocks, &segment_length, m_cost, + parallelism); + return memory_blocks * ARGON2_BLOCK_SIZE; +} + +int argon2_ctx_mem(argon2_context *context, argon2_type type, void *memory, + size_t memory_size) { + /* 1. Validate all inputs */ + int result = validate_inputs(context); + uint32_t memory_blocks, segment_length; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (Argon2_d != type && Argon2_i != type && Argon2_id != type) { + return ARGON2_INCORRECT_TYPE; + } + + /* 2. Align memory size */ + argon2_compute_memory_blocks(&memory_blocks, &segment_length, + context->m_cost, context->lanes); + + /* check for sufficient memory size: */ + if (memory != NULL && (memory_size % ARGON2_BLOCK_SIZE != 0 || + memory_size / ARGON2_BLOCK_SIZE < memory_blocks)) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + instance.version = context->version; + instance.memory = (block *)memory; + instance.passes = context->t_cost; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + instance.print_internals = !!(context->flags & ARGON2_FLAG_GENKAT); + instance.keep_memory = memory != NULL; + + if (instance.threads > instance.lanes) { + instance.threads = instance.lanes; + } + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + result = fill_memory_blocks(&instance); + + if (ARGON2_OK != result) { + return result; + } + /* 5. Finalization */ + finalize(context, &instance); + + return ARGON2_OK; +} + +int argon2_ctx(argon2_context *context, argon2_type type) { + return argon2_ctx_mem(context, type, NULL, 0); +} + +int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version){ + + argon2_context context; + int result; + uint8_t *out; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (saltlen > ARGON2_MAX_SALT_LENGTH) { + return ARGON2_SALT_TOO_LONG; + } + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (hashlen < ARGON2_MIN_OUTLEN) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + out = malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *)out; + context.outlen = (uint32_t)hashlen; + context.pwd = CONST_CAST(uint8_t *)pwd; + context.pwdlen = (uint32_t)pwdlen; + context.salt = CONST_CAST(uint8_t *)salt; + context.saltlen = (uint32_t)saltlen; + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = t_cost; + context.m_cost = m_cost; + context.lanes = parallelism; + context.threads = parallelism; + context.allocate_cbk = NULL; + context.free_cbk = NULL; + context.flags = ARGON2_DEFAULT_FLAGS; + context.version = version; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + clear_internal_memory(out, hashlen); + free(out); + return result; + } + + /* if raw hash requested, write it */ + if (hash) { + memcpy(hash, out, hashlen); + } + + /* if encoding requested, write it */ + if (encoded && encodedlen) { + if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { + clear_internal_memory(out, hashlen); /* wipe buffers if error */ + clear_internal_memory(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + clear_internal_memory(out, hashlen); + free(out); + + return ARGON2_OK; +} + +int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_i, + ARGON2_VERSION_NUMBER); +} + +int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_d, + ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_raw_ex(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen, void *memory) { + argon2_context context; + + context.out = (uint8_t *)hash; + context.outlen = (uint32_t)hashlen; + context.pwd = CONST_CAST(uint8_t *)pwd; + context.pwdlen = (uint32_t)pwdlen; + context.salt = CONST_CAST(uint8_t *)salt; + context.saltlen = (uint32_t)saltlen; + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = t_cost; + context.m_cost = m_cost; + context.lanes = parallelism; + context.threads = parallelism; + context.allocate_cbk = NULL; + context.free_cbk = NULL; + context.flags = ARGON2_DEFAULT_FLAGS; + context.version = ARGON2_VERSION_NUMBER; + + return argon2_ctx_mem(&context, Argon2_id, memory, m_cost * 1024); +} + +static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { + size_t i; + uint8_t d = 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int)((1 & ((d - 1) >> 8)) - 1); +} + +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) { + + argon2_context ctx; + uint8_t *desired_result = NULL; + + int ret = ARGON2_OK; + + size_t encoded_len; + uint32_t max_field_len; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (encoded == NULL) { + return ARGON2_DECODING_FAIL; + } + + encoded_len = strlen(encoded); + if (encoded_len > UINT32_MAX) { + return ARGON2_DECODING_FAIL; + } + + /* No field can be longer than the encoded length */ + max_field_len = (uint32_t)encoded_len; + + ctx.saltlen = max_field_len; + ctx.outlen = max_field_len; + + ctx.salt = malloc(ctx.saltlen); + ctx.out = malloc(ctx.outlen); + if (!ctx.salt || !ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ctx.pwd = (uint8_t *)pwd; + ctx.pwdlen = (uint32_t)pwdlen; + + ret = decode_string(&ctx, encoded, type); + if (ret != ARGON2_OK) { + goto fail; + } + + /* Set aside the desired result, and get a new buffer. */ + desired_result = ctx.out; + ctx.out = malloc(ctx.outlen); + if (!ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ret = argon2_verify_ctx(&ctx, (char *)desired_result, type); + if (ret != ARGON2_OK) { + goto fail; + } + +fail: + free(ctx.salt); + free(ctx.out); + free(desired_result); + + return ret; +} + +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_d); +} + +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_id); +} + +int argon2d_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_d); +} + +int argon2i_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_i); +} + +int argon2id_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_id); +} + +int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type) { + int ret = argon2_ctx(context, type); + if (ret != ARGON2_OK) { + return ret; + } + + if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) { + return ARGON2_VERIFY_MISMATCH; + } + + return ARGON2_OK; +} + +int argon2d_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_d); +} + +int argon2i_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_i); +} + +int argon2id_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_id); +} + +const char *argon2_error_message(int error_code) { + switch (error_code) { + case ARGON2_OK: + return "OK"; + case ARGON2_OUTPUT_PTR_NULL: + return "Output pointer is NULL"; + case ARGON2_OUTPUT_TOO_SHORT: + return "Output is too short"; + case ARGON2_OUTPUT_TOO_LONG: + return "Output is too long"; + case ARGON2_PWD_TOO_SHORT: + return "Password is too short"; + case ARGON2_PWD_TOO_LONG: + return "Password is too long"; + case ARGON2_SALT_TOO_SHORT: + return "Salt is too short"; + case ARGON2_SALT_TOO_LONG: + return "Salt is too long"; + case ARGON2_AD_TOO_SHORT: + return "Associated data is too short"; + case ARGON2_AD_TOO_LONG: + return "Associated data is too long"; + case ARGON2_SECRET_TOO_SHORT: + return "Secret is too short"; + case ARGON2_SECRET_TOO_LONG: + return "Secret is too long"; + case ARGON2_TIME_TOO_SMALL: + return "Time cost is too small"; + case ARGON2_TIME_TOO_LARGE: + return "Time cost is too large"; + case ARGON2_MEMORY_TOO_LITTLE: + return "Memory cost is too small"; + case ARGON2_MEMORY_TOO_MUCH: + return "Memory cost is too large"; + case ARGON2_LANES_TOO_FEW: + return "Too few lanes"; + case ARGON2_LANES_TOO_MANY: + return "Too many lanes"; + case ARGON2_PWD_PTR_MISMATCH: + return "Password pointer is NULL, but password length is not 0"; + case ARGON2_SALT_PTR_MISMATCH: + return "Salt pointer is NULL, but salt length is not 0"; + case ARGON2_SECRET_PTR_MISMATCH: + return "Secret pointer is NULL, but secret length is not 0"; + case ARGON2_AD_PTR_MISMATCH: + return "Associated data pointer is NULL, but ad length is not 0"; + case ARGON2_MEMORY_ALLOCATION_ERROR: + return "Memory allocation error"; + case ARGON2_FREE_MEMORY_CBK_NULL: + return "The free memory callback is NULL"; + case ARGON2_ALLOCATE_MEMORY_CBK_NULL: + return "The allocate memory callback is NULL"; + case ARGON2_INCORRECT_PARAMETER: + return "Argon2_Context context is NULL"; + case ARGON2_INCORRECT_TYPE: + return "There is no such version of Argon2"; + case ARGON2_OUT_PTR_MISMATCH: + return "Output pointer mismatch"; + case ARGON2_THREADS_TOO_FEW: + return "Not enough threads"; + case ARGON2_THREADS_TOO_MANY: + return "Too many threads"; + case ARGON2_MISSING_ARGS: + return "Missing arguments"; + case ARGON2_ENCODING_FAIL: + return "Encoding failed"; + case ARGON2_DECODING_FAIL: + return "Decoding failed"; + case ARGON2_THREAD_FAIL: + return "Threading failure"; + case ARGON2_DECODING_LENGTH_FAIL: + return "Some of encoded parameters are too long or too short"; + case ARGON2_VERIFY_MISMATCH: + return "The password does not match the supplied hash"; + default: + return "Unknown error code"; + } +} + +size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, + uint32_t saltlen, uint32_t hashlen, argon2_type type) { + return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) + + numlen(t_cost) + numlen(m_cost) + numlen(parallelism) + + b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + + 1; +} diff --git a/src/3rdparty/argon2/lib/blake2/blake2-impl.h b/src/3rdparty/argon2/lib/blake2/blake2-impl.h new file mode 100644 index 000000000..e6cdf7c4e --- /dev/null +++ b/src/3rdparty/argon2/lib/blake2/blake2-impl.h @@ -0,0 +1,90 @@ +#ifndef ARGON2_BLAKE2_IMPL_H +#define ARGON2_BLAKE2_IMPL_H + +#include + +/* Argon2 Team - Begin Code */ +/* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. +*/ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif +/* Argon2 Team - End Code */ + +static inline uint32_t load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + return *(const uint32_t *)src; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static inline uint64_t load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + return *(const uint64_t *)src; +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static inline void store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + *(uint32_t *)dst = w; +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static inline void store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + *(uint64_t *)dst = w; +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +#endif // ARGON2_BLAKE2_IMPL_H diff --git a/src/3rdparty/argon2/lib/blake2/blake2.c b/src/3rdparty/argon2/lib/blake2/blake2.c new file mode 100644 index 000000000..d32028ed5 --- /dev/null +++ b/src/3rdparty/argon2/lib/blake2/blake2.c @@ -0,0 +1,225 @@ +#include + +#include "blake2/blake2.h" +#include "blake2/blake2-impl.h" + +#include "core.h" + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179) +}; + +#define rotr64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +#define G(m, r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(m, v, r) \ + do { \ + G(m, r, 0, v[0], v[4], v[ 8], v[12]); \ + G(m, r, 1, v[1], v[5], v[ 9], v[13]); \ + G(m, r, 2, v[2], v[6], v[10], v[14]); \ + G(m, r, 3, v[3], v[7], v[11], v[15]); \ + G(m, r, 4, v[0], v[5], v[10], v[15]); \ + G(m, r, 5, v[1], v[6], v[11], v[12]); \ + G(m, r, 6, v[2], v[7], v[ 8], v[13]); \ + G(m, r, 7, v[3], v[4], v[ 9], v[14]); \ + } while ((void)0, 0) + +void blake2b_compress(blake2b_state *S, const void *block, uint64_t f0) +{ + uint64_t m[16]; + uint64_t v[16]; + + m[ 0] = load64((const uint64_t *)block + 0); + m[ 1] = load64((const uint64_t *)block + 1); + m[ 2] = load64((const uint64_t *)block + 2); + m[ 3] = load64((const uint64_t *)block + 3); + m[ 4] = load64((const uint64_t *)block + 4); + m[ 5] = load64((const uint64_t *)block + 5); + m[ 6] = load64((const uint64_t *)block + 6); + m[ 7] = load64((const uint64_t *)block + 7); + m[ 8] = load64((const uint64_t *)block + 8); + m[ 9] = load64((const uint64_t *)block + 9); + m[10] = load64((const uint64_t *)block + 10); + m[11] = load64((const uint64_t *)block + 11); + m[12] = load64((const uint64_t *)block + 12); + m[13] = load64((const uint64_t *)block + 13); + m[14] = load64((const uint64_t *)block + 14); + m[15] = load64((const uint64_t *)block + 15); + + v[ 0] = S->h[0]; + v[ 1] = S->h[1]; + v[ 2] = S->h[2]; + v[ 3] = S->h[3]; + v[ 4] = S->h[4]; + v[ 5] = S->h[5]; + v[ 6] = S->h[6]; + v[ 7] = S->h[7]; + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ f0; + v[15] = blake2b_IV[7]; + + ROUND(m, v, 0); + ROUND(m, v, 1); + ROUND(m, v, 2); + ROUND(m, v, 3); + ROUND(m, v, 4); + ROUND(m, v, 5); + ROUND(m, v, 6); + ROUND(m, v, 7); + ROUND(m, v, 8); + ROUND(m, v, 9); + ROUND(m, v, 10); + ROUND(m, v, 11); + + S->h[0] ^= v[0] ^ v[ 8]; + S->h[1] ^= v[1] ^ v[ 9]; + S->h[2] ^= v[2] ^ v[10]; + S->h[3] ^= v[3] ^ v[11]; + S->h[4] ^= v[4] ^ v[12]; + S->h[5] ^= v[5] ^ v[13]; + S->h[6] ^= v[6] ^ v[14]; + S->h[7] ^= v[7] ^ v[15]; +} + +static void blake2b_increment_counter(blake2b_state *S, uint64_t inc) +{ + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static void blake2b_init_state(blake2b_state *S) +{ + memcpy(S->h, blake2b_IV, sizeof(S->h)); + S->t[1] = S->t[0] = 0; + S->buflen = 0; +} + +void blake2b_init(blake2b_state *S, size_t outlen) +{ + blake2b_init_state(S); + /* XOR initial state with param block: */ + S->h[0] ^= (uint64_t)outlen | (UINT64_C(1) << 16) | (UINT64_C(1) << 24); +} + +void blake2b_update(blake2b_state *S, const void *in, size_t inlen) +{ + const uint8_t *pin = (const uint8_t *)in; + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf, 0); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin, 0); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += inlen; +} + +void blake2b_final(blake2b_state *S, void *out, size_t outlen) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + unsigned int i; + + blake2b_increment_counter(S, S->buflen); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf, UINT64_C(0xFFFFFFFFFFFFFFFF)); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + i * sizeof(uint64_t), S->h[i]); + } + + memcpy(out, buffer, outlen); + clear_internal_memory(buffer, sizeof(buffer)); + clear_internal_memory(S->buf, sizeof(S->buf)); + clear_internal_memory(S->h, sizeof(S->h)); +} + +void blake2b_long(void *out, size_t outlen, const void *in, size_t inlen) +{ + uint8_t *pout = (uint8_t *)out; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = {0}; + + store32(outlen_bytes, (uint32_t)outlen); + if (outlen <= BLAKE2B_OUTBYTES) { + blake2b_init(&blake_state, outlen); + blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)); + blake2b_update(&blake_state, in, inlen); + blake2b_final(&blake_state, pout, outlen); + } else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + + blake2b_init(&blake_state, BLAKE2B_OUTBYTES); + blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)); + blake2b_update(&blake_state, in, inlen); + blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + + memcpy(pout, out_buffer, BLAKE2B_OUTBYTES / 2); + pout += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + blake2b_init(&blake_state, BLAKE2B_OUTBYTES); + blake2b_update(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + + memcpy(pout, out_buffer, BLAKE2B_OUTBYTES / 2); + pout += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + blake2b_init(&blake_state, toproduce); + blake2b_update(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + blake2b_final(&blake_state, out_buffer, toproduce); + + memcpy(pout, out_buffer, toproduce); + + clear_internal_memory(out_buffer, sizeof(out_buffer)); + } +} diff --git a/src/3rdparty/argon2/lib/blake2/blake2.h b/src/3rdparty/argon2/lib/blake2/blake2.h new file mode 100644 index 000000000..7deeaa1fa --- /dev/null +++ b/src/3rdparty/argon2/lib/blake2/blake2.h @@ -0,0 +1,30 @@ +#ifndef ARGON2_BLAKE2_H +#define ARGON2_BLAKE2_H + +#include +#include + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; +} blake2b_state; + +/* Streaming API */ +void blake2b_init(blake2b_state *S, size_t outlen); +void blake2b_update(blake2b_state *S, const void *in, size_t inlen); +void blake2b_final(blake2b_state *S, void *out, size_t outlen); + +void blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); + +#endif // ARGON2_BLAKE2_H + diff --git a/src/3rdparty/argon2/lib/core.c b/src/3rdparty/argon2/lib/core.c new file mode 100644 index 000000000..5d130c04a --- /dev/null +++ b/src/3rdparty/argon2/lib/core.c @@ -0,0 +1,539 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +/*For memory wiping*/ +#ifdef _MSC_VER +#include +#include /* For SecureZeroMemory */ +#endif +#if defined __STDC_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#define VC_GE_2005(version) (version >= 1400) + +#include +#include +#include +#include + +#include "core.h" +#include "blake2/blake2.h" +#include "blake2/blake2-impl.h" + +#include "genkat.h" + +#if defined(__clang__) +#if __has_attribute(optnone) +#define NOT_OPTIMIZED __attribute__((optnone)) +#endif +#elif defined(__GNUC__) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40400 +#define NOT_OPTIMIZED __attribute__((optimize("O0"))) +#endif +#endif +#ifndef NOT_OPTIMIZED +#define NOT_OPTIMIZED +#endif + +/***************Instance and Position constructors**********/ +void init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } + +void copy_block(block *dst, const block *src) { + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +void xor_block(block *dst, const block *src) { + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +static void load_block(block *dst, const void *input) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = load64((const uint8_t *)input + i * sizeof(dst->v[i])); + } +} + +static void store_block(void *output, const block *src) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory functions*****************/ + +int allocate_memory(const argon2_context *context, + argon2_instance_t *instance) { + size_t blocks = instance->memory_blocks; + size_t memory_size = blocks * ARGON2_BLOCK_SIZE; + + /* 0. Check for memory supplied by user: */ + /* NOTE: Sufficient memory size is already checked in argon2_ctx_mem() */ + if (instance->memory != NULL) { + return ARGON2_OK; + } + + /* 1. Check for multiplication overflow */ + if (blocks != 0 && memory_size / ARGON2_BLOCK_SIZE != blocks) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 2. Try to allocate with appropriate allocator */ + if (context->allocate_cbk) { + (context->allocate_cbk)((uint8_t **)&instance->memory, memory_size); + } else { + instance->memory = malloc(memory_size); + } + + if (instance->memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + return ARGON2_OK; +} + +void free_memory(const argon2_context *context, + const argon2_instance_t *instance) { + size_t memory_size = instance->memory_blocks * ARGON2_BLOCK_SIZE; + + clear_internal_memory(instance->memory, memory_size); + + if (instance->keep_memory) { + /* user-supplied memory -- do not free */ + return; + } + + if (context->free_cbk) { + (context->free_cbk)((uint8_t *)instance->memory, memory_size); + } else { + free(instance->memory); + } +} + +void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) { +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) + SecureZeroMemory(v, n); +#elif defined memset_s + memset_s(v, n, 0, n); +#elif defined(__OpenBSD__) + explicit_bzero(v, n); +#else + static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; + memset_sec(v, 0, n); +#endif +} + +/* Memory clear flag defaults to true. */ +int FLAG_clear_internal_memory = 0; +void clear_internal_memory(void *v, size_t n) { + if (FLAG_clear_internal_memory && v) { + secure_wipe_memory(v, n); + } +} + +void finalize(const argon2_context *context, argon2_instance_t *instance) { + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + copy_block(&blockhash, instance->memory + instance->lane_length - 1); + + /* XOR the last blocks */ + for (l = 1; l < instance->lanes; ++l) { + uint32_t last_block_in_lane = + l * instance->lane_length + (instance->lane_length - 1); + xor_block(&blockhash, instance->memory + last_block_in_lane); + } + + /* Hash the result */ + { + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + store_block(blockhash_bytes, &blockhash); + blake2b_long(context->out, context->outlen, blockhash_bytes, + ARGON2_BLOCK_SIZE); + /* clear blockhash and blockhash_bytes */ + clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE); + clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); + } + + if (instance->print_internals) { + print_tag(context->out, context->outlen); + } + + free_memory(context, instance); + } +} + +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) { + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (0 == position->pass) { + /* First pass */ + if (0 == position->slice) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (0 != position->pass) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +/* Single-threaded version for p=1 case */ +static int fill_memory_blocks_st(argon2_instance_t *instance) { + uint32_t r, s, l; + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position = { r, l, (uint8_t)s, 0 }; + fill_segment(instance, position); + } + } + + if (instance->print_internals) { + internal_kat(instance, r); /* Print all memory blocks */ + } + } + return ARGON2_OK; +} + +int fill_memory_blocks(argon2_instance_t *instance) { + if (instance == NULL || instance->lanes == 0) { + return ARGON2_INCORRECT_PARAMETER; + } + + return fill_memory_blocks_st(instance); +} + +int validate_inputs(const argon2_context *context) { + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password (required param) */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + + /* Validate salt (required param) */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + + /* Validate secret (optional param) */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data (optional param) */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + + if (NULL != context->allocate_cbk && NULL == context->free_cbk) { + return ARGON2_FREE_MEMORY_CBK_NULL; + } + + if (NULL == context->allocate_cbk && NULL != context->free_cbk) { + return ARGON2_ALLOCATE_MEMORY_CBK_NULL; + } + + return ARGON2_OK; +} + +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { + uint32_t l; + /* Make the first and second block in each lane as G(H0||0||i) or + G(H0||1||i) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 0], + blockhash_bytes); + + store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type) { + blake2b_state BlakeHash; + uint8_t value[sizeof(uint32_t)]; + + if (NULL == context || NULL == blockhash) { + return; + } + + blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + + store32(&value, context->lanes); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->outlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->m_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->t_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->version); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, (uint32_t)type); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + store32(&value, context->pwdlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->pwd != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + secure_wipe_memory(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + } + + store32(&value, context->saltlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->salt != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->salt, + context->saltlen); + } + + store32(&value, context->secretlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->secret != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + secure_wipe_memory(context->secret, context->secretlen); + context->secretlen = 0; + } + } + + store32(&value, context->adlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->ad != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + context->adlen); + } + + blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); +} + +int initialize(argon2_instance_t *instance, argon2_context *context) { + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) + return ARGON2_INCORRECT_PARAMETER; + instance->context_ptr = context; + + /* 1. Memory allocation */ + + result = allocate_memory(context, instance); + if (result != ARGON2_OK) { + return result; + } + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - + ARGON2_PREHASH_DIGEST_LENGTH); + + if (instance->print_internals) { + initial_kat(blockhash, context, instance->type); + } + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} diff --git a/src/3rdparty/argon2/lib/core.h b/src/3rdparty/argon2/lib/core.h new file mode 100644 index 000000000..5c67fa364 --- /dev/null +++ b/src/3rdparty/argon2/lib/core.h @@ -0,0 +1,226 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef ARGON2_CORE_H +#define ARGON2_CORE_H + +#include "argon2.h" + +#if defined(_MSC_VER) +#define ALIGN(n) __declspec(align(16)) +#elif defined(__GNUC__) || defined(__clang) +#define ALIGN(x) __attribute__((__aligned__(x))) +#else +#define ALIGN(x) +#endif + +#define CONST_CAST(x) (x)(uintptr_t) + +/**********************Argon2 internal constants*******************************/ + +enum argon2_core_constants { + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data types***********************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +void init_block_value(block *b, uint8_t in); + +/* Copy block @src to block @dst */ +void copy_block(block *dst, const block *src); + +/* XOR @src onto @dst bytewise */ +void xor_block(block *dst, const block *src); + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block *memory; /* Memory pointer */ + uint32_t version; + uint32_t passes; /* Number of passes */ + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ + int keep_memory; + argon2_context *context_ptr; /* points back to original context */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core functions********************************/ + +/* Allocates memory to the given pointer, uses the appropriate allocator as + * specified in the context. Total allocated memory is num*size. + * @param context argon2_context which specifies the allocator + * @param instance the Argon2 instance + * @return ARGON2_OK if memory is allocated successfully + */ +int allocate_memory(const argon2_context *context, + argon2_instance_t *instance); + +/* + * Frees memory at the given pointer, uses the appropriate deallocator as + * specified in the context. Also cleans the memory using clear_internal_memory. + * @param context argon2_context which specifies the deallocator + * @param instance the Argon2 instance + */ +void free_memory(const argon2_context *context, + const argon2_instance_t *instance); + +/* Function that securely cleans the memory. This ignores any flags set + * regarding clearing memory. Usually one just calls clear_internal_memory. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +void secure_wipe_memory(void *v, size_t n); + +/* Function that securely clears the memory if FLAG_clear_internal_memory is + * set. If the flag isn't set, this function does nothing. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +ARGON2_PUBLIC void clear_internal_memory(void *v, size_t n); + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane); + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +int validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +int initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +void fill_segment(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return ARGON2_OK if successful, @context->state + */ +int fill_memory_blocks(argon2_instance_t *instance); + +#endif diff --git a/src/3rdparty/argon2/lib/encoding.c b/src/3rdparty/argon2/lib/encoding.c new file mode 100644 index 000000000..af56e4477 --- /dev/null +++ b/src/3rdparty/argon2/lib/encoding.c @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include "encoding.h" +#include "core.h" + +/* + * Example code for a decoder and encoder of "hash strings", with Argon2 + * parameters. + * + * This code comprises three sections: + * + * -- The first section contains generic Base64 encoding and decoding + * functions. It is conceptually applicable to any hash function + * implementation that uses Base64 to encode and decode parameters, + * salts and outputs. It could be made into a library, provided that + * the relevant functions are made public (non-static) and be given + * reasonable names to avoid collisions with other functions. + * + * -- The second section is specific to Argon2. It encodes and decodes + * the parameters, salts and outputs. It does not compute the hash + * itself. + * + * The code was originally written by Thomas Pornin , + * to whom comments and remarks may be sent. It is released under what + * should amount to Public Domain or its closest equivalent; the + * following mantra is supposed to incarnate that fact with all the + * proper legal rituals: + * + * --------------------------------------------------------------------- + * This file is provided under the terms of Creative Commons CC0 1.0 + * Public Domain Dedication. To the extent possible under law, the + * author (Thomas Pornin) has waived all copyright and related or + * neighboring rights to this file. This work is published from: Canada. + * --------------------------------------------------------------------- + * + * Copyright (c) 2015 Thomas Pornin + */ + +/* ==================================================================== */ +/* + * Common code; could be shared between different hash functions. + * + * Note: the Base64 functions below assume that uppercase letters (resp. + * lowercase letters) have consecutive numerical codes, that fit on 8 + * bits. All modern systems use ASCII-compatible charsets, where these + * properties are true. If you are stuck with a dinosaur of a system + * that still defaults to EBCDIC then you already have much bigger + * interoperability issues to deal with. + */ + +/* + * Some macros for constant-time comparisons. These work over values in + * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". + */ +#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF) +#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF) +#define GE(x, y) (GT(y, x) ^ 0xFF) +#define LT(x, y) GT(y, x) +#define LE(x, y) GE(y, x) + +/* + * Convert value x (0..63) to corresponding Base64 character. + */ +static int b64_byte_to_char(unsigned x) { + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | + (EQ(x, 63) & '/'); +} + +/* + * Convert character c to the corresponding 6-bit value. If character c + * is not a Base64 character, then 0xFF (255) is returned. + */ +static unsigned b64_char_to_byte(int c) { + unsigned x; + + x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | + (EQ(c, '/') & 63); + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + +/* + * Convert some bytes to Base64. 'dst_len' is the length (in characters) + * of the output buffer 'dst'; if that buffer is not large enough to + * receive the result (including the terminating 0), then (size_t)-1 + * is returned. Otherwise, the zero-terminated Base64 string is written + * in the buffer, and the output length (counted WITHOUT the terminating + * zero) is returned. + */ +static size_t to_base64(char *dst, size_t dst_len, const void *src, + size_t src_len) { + size_t olen; + const unsigned char *buf; + unsigned acc, acc_len; + + olen = (src_len / 3) << 2; + switch (src_len % 3) { + case 2: + olen++; + /* fall through */ + case 1: + olen += 2; + break; + } + if (dst_len <= olen) { + return (size_t)-1; + } + acc = 0; + acc_len = 0; + buf = (const unsigned char *)src; + while (src_len-- > 0) { + acc = (acc << 8) + (*buf++); + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + *dst++ = (char)b64_byte_to_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + *dst++ = (char)b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); + } + *dst++ = 0; + return olen; +} + +/* + * Decode Base64 chars into bytes. The '*dst_len' value must initially + * contain the length of the output buffer '*dst'; when the decoding + * ends, the actual number of decoded bytes is written back in + * '*dst_len'. + * + * Decoding stops when a non-Base64 character is encountered, or when + * the output buffer capacity is exceeded. If an error occurred (output + * buffer is too small, invalid last characters leading to unprocessed + * buffered bits), then NULL is returned; otherwise, the returned value + * points to the first non-Base64 character in the source stream, which + * may be the terminating zero. + */ +static const char *from_base64(void *dst, size_t *dst_len, const char *src) { + size_t len; + unsigned char *buf; + unsigned acc, acc_len; + + buf = (unsigned char *)dst; + len = 0; + acc = 0; + acc_len = 0; + for (;;) { + unsigned d; + + d = b64_char_to_byte(*src); + if (d == 0xFF) { + break; + } + src++; + acc = (acc << 6) + d; + acc_len += 6; + if (acc_len >= 8) { + acc_len -= 8; + if ((len++) >= *dst_len) { + return NULL; + } + *buf++ = (acc >> acc_len) & 0xFF; + } + } + + /* + * If the input length is equal to 1 modulo 4 (which is + * invalid), then there will remain 6 unprocessed bits; + * otherwise, only 0, 2 or 4 bits are buffered. The buffered + * bits must also all be zero. + */ + if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) { + return NULL; + } + *dst_len = len; + return src; +} + +/* + * Decode decimal integer from 'str'; the value is written in '*v'. + * Returned value is a pointer to the next non-decimal character in the + * string. If there is no digit at all, or the value encoding is not + * minimal (extra leading zeros), or the value does not fit in an + * 'unsigned long', then NULL is returned. + */ +static const char *decode_decimal(const char *str, unsigned long *v) { + const char *orig; + unsigned long acc; + + acc = 0; + for (orig = str;; str++) { + int c; + + c = *str; + if (c < '0' || c > '9') { + break; + } + c -= '0'; + if (acc > (ULONG_MAX / 10)) { + return NULL; + } + acc *= 10; + if ((unsigned long)c > (ULONG_MAX - acc)) { + return NULL; + } + acc += (unsigned long)c; + } + if (str == orig || (*orig == '0' && str != (orig + 1))) { + return NULL; + } + *v = acc; + return str; +} + +/* ==================================================================== */ +/* + * Code specific to Argon2. + * + * The code below applies the following format: + * + * $argon2[$v=]$m=,t=,p=$$ + * + * where is either 'd', 'id', or 'i', is a decimal integer (positive, + * fits in an 'unsigned long'), and is Base64-encoded data (no '=' padding + * characters, no newline or whitespace). + * + * The last two binary chunks (encoded in Base64) are, in that order, + * the salt and the output. Both are required. The binary salt length and the + * output length must be in the allowed ranges defined in argon2.h. + * + * The ctx struct must contain buffers large enough to hold the salt and pwd + * when it is fed into decode_string. + */ + +int decode_string(argon2_context *ctx, const char *str, argon2_type type) { + +/* check for prefix */ +#define CC(prefix) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) != 0) { \ + return ARGON2_DECODING_FAIL; \ + } \ + str += cc_len; \ + } while ((void)0, 0) + +/* optional prefix checking with supplied code */ +#define CC_opt(prefix, code) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) == 0) { \ + str += cc_len; \ + { code; } \ + } \ + } while ((void)0, 0) + +/* Decoding prefix into uint32_t decimal */ +#define DECIMAL_U32(x) \ + do { \ + unsigned long dec_x; \ + str = decode_decimal(str, &dec_x); \ + if (str == NULL || dec_x > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = (uint32_t)dec_x; \ + } while ((void)0, 0) + +/* Decoding base64 into a binary buffer */ +#define BIN(buf, max_len, len) \ + do { \ + size_t bin_len = (max_len); \ + str = from_base64(buf, &bin_len, str); \ + if (str == NULL || bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t)bin_len; \ + } while ((void)0, 0) + + size_t maxsaltlen = ctx->saltlen; + size_t maxoutlen = ctx->outlen; + int validation_result; + const char* type_string; + + /* We should start with the argon2_type we are using */ + type_string = argon2_type2string(type, 0); + if (!type_string) { + return ARGON2_INCORRECT_TYPE; + } + + CC("$"); + CC(type_string); + + /* Reading the version number if the default is suppressed */ + ctx->version = ARGON2_VERSION_10; + CC_opt("$v=", DECIMAL_U32(ctx->version)); + + CC("$m="); + DECIMAL_U32(ctx->m_cost); + CC(",t="); + DECIMAL_U32(ctx->t_cost); + CC(",p="); + DECIMAL_U32(ctx->lanes); + ctx->threads = ctx->lanes; + + CC("$"); + BIN(ctx->salt, maxsaltlen, ctx->saltlen); + CC("$"); + BIN(ctx->out, maxoutlen, ctx->outlen); + + /* The rest of the fields get the default values */ + ctx->secret = NULL; + ctx->secretlen = 0; + ctx->ad = NULL; + ctx->adlen = 0; + ctx->allocate_cbk = NULL; + ctx->free_cbk = NULL; + ctx->flags = ARGON2_DEFAULT_FLAGS; + + /* On return, must have valid context */ + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + + /* Can't have any additional characters */ + if (*str == 0) { + return ARGON2_OK; + } else { + return ARGON2_DECODING_FAIL; + } +#undef CC +#undef CC_opt +#undef DECIMAL_U32 +#undef BIN +} + +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type) { +#define SS(str) \ + do { \ + size_t pp_len = strlen(str); \ + if (pp_len >= dst_len) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + memcpy(dst, str, pp_len + 1); \ + dst += pp_len; \ + dst_len -= pp_len; \ + } while ((void)0, 0) + +#define SX(x) \ + do { \ + char tmp[30]; \ + sprintf(tmp, "%lu", (unsigned long)(x)); \ + SS(tmp); \ + } while ((void)0, 0) + +#define SB(buf, len) \ + do { \ + size_t sb_len = to_base64(dst, dst_len, buf, len); \ + if (sb_len == (size_t)-1) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + dst += sb_len; \ + dst_len -= sb_len; \ + } while ((void)0, 0) + + const char* type_string = argon2_type2string(type, 0); + int validation_result = validate_inputs(ctx); + + if (!type_string) { + return ARGON2_ENCODING_FAIL; + } + + if (validation_result != ARGON2_OK) { + return validation_result; + } + + SS("$"); + SS(type_string); + + SS("$v="); + SX(ctx->version); + + SS("$m="); + SX(ctx->m_cost); + SS(",t="); + SX(ctx->t_cost); + SS(",p="); + SX(ctx->lanes); + + SS("$"); + SB(ctx->salt, ctx->saltlen); + + SS("$"); + SB(ctx->out, ctx->outlen); + return ARGON2_OK; + +#undef SS +#undef SX +#undef SB +} + +size_t b64len(uint32_t len) { + size_t olen = ((size_t)len / 3) << 2; + + switch (len % 3) { + case 2: + olen++; + /* fall through */ + case 1: + olen += 2; + break; + } + + return olen; +} + +size_t numlen(uint32_t num) { + size_t len = 1; + while (num >= 10) { + ++len; + num = num / 10; + } + return len; +} + diff --git a/src/3rdparty/argon2/lib/encoding.h b/src/3rdparty/argon2/lib/encoding.h new file mode 100644 index 000000000..e7834e4f5 --- /dev/null +++ b/src/3rdparty/argon2/lib/encoding.h @@ -0,0 +1,40 @@ +#ifndef ENCODING_H +#define ENCODING_H +#include "argon2.h" + +#define ARGON2_MAX_DECODED_LANES UINT32_C(255) +#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8) +#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12) + +/* +* encode an Argon2 hash string into the provided buffer. 'dst_len' +* contains the size, in characters, of the 'dst' buffer; if 'dst_len' +* is less than the number of required characters (including the +* terminating 0), then this function returns ARGON2_ENCODING_ERROR. +* +* on success, ARGON2_OK is returned. +*/ +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type); + +/* +* Decodes an Argon2 hash string into the provided structure 'ctx'. +* The only fields that must be set prior to this call are ctx.saltlen and +* ctx.outlen (which must be the maximal salt and out length values that are +* allowed), ctx.salt and ctx.out (which must be buffers of the specified +* length), and ctx.pwd and ctx.pwdlen which must hold a valid password. +* +* Invalid input string causes an error. On success, the ctx is valid and all +* fields have been initialized. +* +* Returned value is ARGON2_OK on success, other ARGON2_ codes on error. +*/ +int decode_string(argon2_context *ctx, const char *str, argon2_type type); + +/* Returns the length of the encoded byte stream with length len */ +size_t b64len(uint32_t len); + +/* Returns the length of the encoded number num */ +size_t numlen(uint32_t num); + +#endif diff --git a/src/3rdparty/argon2/lib/genkat.c b/src/3rdparty/argon2/lib/genkat.c new file mode 100644 index 000000000..fd5663bfb --- /dev/null +++ b/src/3rdparty/argon2/lib/genkat.c @@ -0,0 +1,117 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include + +#include "genkat.h" + +void initial_kat(const uint8_t *blockhash, const argon2_context *context, + argon2_type type) { + unsigned i; + + if (blockhash != NULL && context != NULL) { + printf("=======================================\n"); + + printf("%s version number %d\n", argon2_type2string(type, 1), + context->version); + + printf("=======================================\n"); + + + printf("Memory: %u KiB, Iterations: %u, Parallelism: %u lanes, Tag " + "length: %u bytes\n", + context->m_cost, context->t_cost, context->lanes, + context->outlen); + + printf("Password[%u]: ", context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + printf("CLEARED\n"); + } else { + for (i = 0; i < context->pwdlen; ++i) { + printf("%2.2x ", ((unsigned char *)context->pwd)[i]); + } + + printf("\n"); + } + + printf("Salt[%u]: ", context->saltlen); + + for (i = 0; i < context->saltlen; ++i) { + printf("%2.2x ", ((unsigned char *)context->salt)[i]); + } + + printf("\n"); + + printf("Secret[%u]: ", context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + printf("CLEARED\n"); + } else { + for (i = 0; i < context->secretlen; ++i) { + printf("%2.2x ", ((unsigned char *)context->secret)[i]); + } + + printf("\n"); + } + + printf("Associated data[%u]: ", context->adlen); + + for (i = 0; i < context->adlen; ++i) { + printf("%2.2x ", ((unsigned char *)context->ad)[i]); + } + + printf("\n"); + + printf("Pre-hashing digest: "); + + for (i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; ++i) { + printf("%2.2x ", ((unsigned char *)blockhash)[i]); + } + + printf("\n"); + } +} + +void print_tag(const void *out, uint32_t outlen) { + unsigned i; + if (out != NULL) { + printf("Tag: "); + + for (i = 0; i < outlen; ++i) { + printf("%2.2x ", ((uint8_t *)out)[i]); + } + + printf("\n"); + } +} + +void internal_kat(const argon2_instance_t *instance, uint32_t pass) { + + if (instance != NULL) { + uint32_t i, j; + printf("\n After pass %u:\n", pass); + + for (i = 0; i < instance->memory_blocks; ++i) { + uint32_t how_many_words = + (instance->memory_blocks > ARGON2_QWORDS_IN_BLOCK) + ? 1 + : ARGON2_QWORDS_IN_BLOCK; + + for (j = 0; j < how_many_words; ++j) + printf("Block %.4u [%3u]: %016" PRIx64 "\n", i, j, + instance->memory[i].v[j]); + } + } +} diff --git a/src/3rdparty/argon2/lib/genkat.h b/src/3rdparty/argon2/lib/genkat.h new file mode 100644 index 000000000..815c09b50 --- /dev/null +++ b/src/3rdparty/argon2/lib/genkat.h @@ -0,0 +1,47 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef ARGON2_KAT_H +#define ARGON2_KAT_H + +#include "core.h" + +/* + * Initial KAT function that prints the inputs to the file + * @param blockhash Array that contains pre-hashing digest + * @param context Holds inputs + * @param type Argon2 type + * @pre blockhash must point to INPUT_INITIAL_HASH_LENGTH bytes + * @pre context member pointers must point to allocated memory of size according + * to the length values + */ +void initial_kat(const uint8_t *blockhash, const argon2_context *context, + argon2_type type); + +/* + * Function that prints the output tag + * @param out output array pointer + * @param outlen digest length + * @pre out must point to @a outlen bytes + **/ +void print_tag(const void *out, uint32_t outlen); + +/* + * Function that prints the internal state at given moment + * @param instance pointer to the current instance + * @param pass current pass number + * @pre instance must have necessary memory allocated + **/ +void internal_kat(const argon2_instance_t *instance, uint32_t pass); + +#endif diff --git a/src/3rdparty/argon2/lib/impl-select.c b/src/3rdparty/argon2/lib/impl-select.c new file mode 100644 index 000000000..d618010ca --- /dev/null +++ b/src/3rdparty/argon2/lib/impl-select.c @@ -0,0 +1,115 @@ +#include +#include + +#include "impl-select.h" + +#include "argon2.h" + +#define BENCH_SAMPLES 1024 +#define BENCH_MEM_BLOCKS 512 + +static argon2_impl selected_argon_impl = { + "default", NULL, fill_segment_default +}; + +/* the benchmark routine is not thread-safe, so we can use a global var here: */ +static block memory[BENCH_MEM_BLOCKS]; + +static uint64_t benchmark_impl(const argon2_impl *impl) { + clock_t time; + unsigned int i; + uint64_t bench; + argon2_instance_t instance; + argon2_position_t pos; + + memset(memory, 0, sizeof(memory)); + + instance.version = ARGON2_VERSION_NUMBER; + instance.memory = memory; + instance.passes = 1; + instance.memory_blocks = BENCH_MEM_BLOCKS; + instance.segment_length = BENCH_MEM_BLOCKS / ARGON2_SYNC_POINTS; + instance.lane_length = instance.segment_length * ARGON2_SYNC_POINTS; + instance.lanes = 1; + instance.threads = 1; + instance.type = Argon2_i; + + pos.lane = 0; + pos.pass = 0; + pos.slice = 0; + pos.index = 0; + + /* warm-up cache: */ + impl->fill_segment(&instance, pos); + + /* OK, now measure: */ + bench = 0; + time = clock(); + for (i = 0; i < BENCH_SAMPLES; i++) { + impl->fill_segment(&instance, pos); + } + time = clock() - time; + bench = (uint64_t)time; + return bench; +} + +void argon2_select_impl() +{ + argon2_impl_list impls; + unsigned int i; + const argon2_impl *best_impl = NULL; + uint64_t best_bench = UINT_MAX; + + argon2_get_impl_list(&impls); + + for (i = 0; i < impls.count; i++) { + const argon2_impl *impl = &impls.entries[i]; + uint64_t bench; + + if (impl->check != NULL && !impl->check()) { + continue; + } + + bench = benchmark_impl(impl); + + if (bench < best_bench) { + best_bench = bench; + best_impl = impl; + } + } + + if (best_impl != NULL) { + selected_argon_impl = *best_impl; + } +} + +void fill_segment(const argon2_instance_t *instance, argon2_position_t position) +{ + selected_argon_impl.fill_segment(instance, position); +} + +const char *argon2_get_impl_name() +{ + return selected_argon_impl.name; +} + + +int argon2_select_impl_by_name(const char *name) +{ + argon2_impl_list impls; + unsigned int i; + + argon2_get_impl_list(&impls); + + for (i = 0; i < impls.count; i++) { + const argon2_impl *impl = &impls.entries[i]; + + if (strcmp(impl->name, name) == 0) { + selected_argon_impl = *impl; + + return 1; + } + } + + return 0; +} diff --git a/src/3rdparty/argon2/lib/impl-select.h b/src/3rdparty/argon2/lib/impl-select.h new file mode 100644 index 000000000..e4acbd1fe --- /dev/null +++ b/src/3rdparty/argon2/lib/impl-select.h @@ -0,0 +1,23 @@ +#ifndef ARGON2_IMPL_SELECT_H +#define ARGON2_IMPL_SELECT_H + +#include "core.h" + +typedef struct Argon2_impl { + const char *name; + int (*check)(void); + void (*fill_segment)(const argon2_instance_t *instance, + argon2_position_t position); +} argon2_impl; + +typedef struct Argon2_impl_list { + const argon2_impl *entries; + size_t count; +} argon2_impl_list; + +void argon2_get_impl_list(argon2_impl_list *list); +void fill_segment_default(const argon2_instance_t *instance, + argon2_position_t position); + +#endif // ARGON2_IMPL_SELECT_H + diff --git a/src/3rdparty/base32/base32.h b/src/3rdparty/base32/base32.h new file mode 100644 index 000000000..7b8187f0f --- /dev/null +++ b/src/3rdparty/base32/base32.h @@ -0,0 +1,68 @@ +// Base32 implementation +// +// Copyright 2010 Google Inc. +// Author: Markus Gutschke +// +// 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. +// +// Encode and decode from base32 encoding using the following alphabet: +// ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 +// This alphabet is documented in RFC 4648/3548 +// +// We allow white-space and hyphens, but all other characters are considered +// invalid. +// +// All functions return the number of output bytes or -1 on error. If the +// output buffer is too small, the result will silently be truncated. + +#ifndef XMRIG_BASE32_H +#define XMRIG_BASE32_H + + +#include + + +int base32_encode(const uint8_t *data, int length, uint8_t *result, int bufSize) { + if (length < 0 || length > (1 << 28)) { + return -1; + } + int count = 0; + if (length > 0) { + int buffer = data[0]; + int next = 1; + int bitsLeft = 8; + while (count < bufSize && (bitsLeft > 0 || next < length)) { + if (bitsLeft < 5) { + if (next < length) { + buffer <<= 8; + buffer |= data[next++] & 0xFF; + bitsLeft += 8; + } else { + int pad = 5 - bitsLeft; + buffer <<= pad; + bitsLeft += pad; + } + } + int index = 0x1F & (buffer >> (bitsLeft - 5)); + bitsLeft -= 5; + result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index]; + } + } + if (count < bufSize) { + result[count] = '\000'; + } + return count; +} + + +#endif /* XMRIG_BASE32_H */ diff --git a/src/3rdparty/cl.h b/src/3rdparty/cl.h new file mode 100644 index 000000000..bd9a46d06 --- /dev/null +++ b/src/3rdparty/cl.h @@ -0,0 +1,36 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CL_H +#define XMRIG_CL_H + + +#if defined(__APPLE__) +# include +#else +# include "3rdparty/CL/cl.h" +#endif + + +#endif /* XMRIG_CL_H */ diff --git a/src/Summary.cpp b/src/Summary.cpp index ab6b7b1ec..227fdcc80 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -71,13 +71,12 @@ static void print_cpu(Config *) { const ICpuInfo *info = Cpu::info(); - Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s (%zu)") " %sx64 %sAES %sAVX2", + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s (%zu)") " %sx64 %sAES", "CPU", info->brand(), info->packages(), info->isX64() ? GREEN_BOLD_S : RED_BOLD_S "-", - info->hasAES() ? GREEN_BOLD_S : RED_BOLD_S "-", - info->hasAVX2() ? GREEN_BOLD_S : RED_BOLD_S "-" + info->hasAES() ? GREEN_BOLD_S : RED_BOLD_S "-" ); # if defined(XMRIG_FEATURE_LIBCPUID) || defined (XMRIG_FEATURE_HWLOC) Log::print(WHITE_BOLD(" %-13s") BLACK_BOLD("L2:") WHITE_BOLD("%.1f MB") BLACK_BOLD(" L3:") WHITE_BOLD("%.1f MB") diff --git a/src/backend/backend.cmake b/src/backend/backend.cmake index c37cf262a..14f0ab9c6 100644 --- a/src/backend/backend.cmake +++ b/src/backend/backend.cmake @@ -1,13 +1,16 @@ include (src/backend/cpu/cpu.cmake) +include (src/backend/opencl/opencl.cmake) include (src/backend/common/common.cmake) set(HEADERS_BACKEND "${HEADERS_BACKEND_COMMON}" "${HEADERS_BACKEND_CPU}" + "${HEADERS_BACKEND_OPENCL}" ) set(SOURCES_BACKEND "${SOURCES_BACKEND_COMMON}" "${SOURCES_BACKEND_CPU}" + "${SOURCES_BACKEND_OPENCL}" ) diff --git a/src/backend/common/Tags.h b/src/backend/common/Tags.h new file mode 100644 index 000000000..938a1bc49 --- /dev/null +++ b/src/backend/common/Tags.h @@ -0,0 +1,44 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_TAGS_H +#define XMRIG_TAGS_H + + +namespace xmrig { + + +const char *cpu_tag(); + + +#ifdef XMRIG_FEATURE_OPENCL +const char *ocl_tag(); +#endif + + +} // namespace xmrig + + +#endif /* XMRIG_TAGS_H */ diff --git a/src/backend/common/Thread.h b/src/backend/common/Thread.h index b71659151..3bef53194 100644 --- a/src/backend/common/Thread.h +++ b/src/backend/common/Thread.h @@ -42,18 +42,18 @@ template class Thread { public: - inline Thread(IBackend *backend, size_t index, const T &config) : m_index(index), m_config(config), m_backend(backend) {} + inline Thread(IBackend *backend, size_t id, const T &config) : m_id(id), m_config(config), m_backend(backend) {} inline ~Thread() { m_thread.join(); delete m_worker; } inline const T &config() const { return m_config; } inline IBackend *backend() const { return m_backend; } inline IWorker *worker() const { return m_worker; } - inline size_t index() const { return m_index; } + inline size_t id() const { return m_id; } inline void setWorker(IWorker *worker) { m_worker = worker; } inline void start(void (*callback) (void *)) { m_thread = std::thread(callback, this); } private: - const size_t m_index = 0; + const size_t m_id = 0; const T m_config; IBackend *m_backend; IWorker *m_worker = nullptr; diff --git a/src/backend/common/Threads.cpp b/src/backend/common/Threads.cpp index 17fc29511..bb9e440f6 100644 --- a/src/backend/common/Threads.cpp +++ b/src/backend/common/Threads.cpp @@ -25,13 +25,20 @@ #include "backend/common/Threads.h" #include "backend/cpu/CpuThreads.h" +#include "crypto/cn/CnAlgo.h" #include "rapidjson/document.h" +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/OclThreads.h" +#endif + + namespace xmrig { static const char *kAsterisk = "*"; +static const char *kCn2 = "cn/2"; } // namespace xmrig @@ -61,7 +68,11 @@ size_t xmrig::Threads::read(const rapidjson::Value &value) if (!threads.isEmpty()) { move(member.name.GetString(), std::move(threads)); } + } + } + for (auto &member : value.GetObject()) { + if (member.value.IsArray() || member.value.IsObject()) { continue; } @@ -109,6 +120,10 @@ xmrig::String xmrig::Threads::profileName(const Algorithm &algorithm, bool st return String(); } + if (algorithm.family() == Algorithm::CN && CnAlgo<>::base(algorithm) == Algorithm::CN_2 && has(kCn2)) { + return kCn2; + } + if (name.contains("/")) { const String base = name.split('/').at(0); if (has(base)) { @@ -148,4 +163,8 @@ namespace xmrig { template class Threads; +#ifdef XMRIG_FEATURE_OPENCL +template class Threads; +#endif + } // namespace xmrig diff --git a/src/backend/common/Threads.h b/src/backend/common/Threads.h index 2cb333d6f..afae184cb 100644 --- a/src/backend/common/Threads.h +++ b/src/backend/common/Threads.h @@ -47,7 +47,13 @@ public: inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); } inline const T &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); } inline void disable(const Algorithm &algo) { m_disabled.insert(algo); } - inline void move(const char *profile, T &&threads) { m_profiles.insert({ profile, threads }); } + + inline void move(const char *profile, T &&threads) + { + if (!threads.isEmpty()) { + m_profiles.insert({ profile, std::move(threads) }); + } + } const T &get(const String &profileName) const; size_t read(const rapidjson::Value &value); diff --git a/src/backend/common/Worker.h b/src/backend/common/Worker.h index 5f5df9250..f55ec8aac 100644 --- a/src/backend/common/Worker.h +++ b/src/backend/common/Worker.h @@ -28,7 +28,7 @@ #include -#include +#include #include "backend/common/interfaces/IWorker.h" diff --git a/src/backend/common/WorkerJob.h b/src/backend/common/WorkerJob.h index c9a3d55ca..6e31a7015 100644 --- a/src/backend/common/WorkerJob.h +++ b/src/backend/common/WorkerJob.h @@ -56,6 +56,7 @@ public: } if (index() == 1 && job.index() == 0 && job == m_jobs[0]) { + m_index = 0; return; } @@ -63,18 +64,18 @@ public: } - inline void nextRound(uint32_t reserveCount) + inline void nextRound(uint32_t rounds, uint32_t roundSize) { m_rounds[index()]++; - if ((m_rounds[index()] % reserveCount) == 0) { + if ((m_rounds[index()] % rounds) == 0) { for (size_t i = 0; i < N; ++i) { - *nonce(i) = Nonce::next(index(), *nonce(i), reserveCount, currentJob().isNicehash()); + *nonce(i) = Nonce::next(index(), *nonce(i), rounds * roundSize, currentJob().isNicehash()); } } else { for (size_t i = 0; i < N; ++i) { - *nonce(i) += 1; + *nonce(i) += roundSize; } } } @@ -111,15 +112,15 @@ inline uint32_t *xmrig::WorkerJob<1>::nonce(size_t) template<> -inline void xmrig::WorkerJob<1>::nextRound(uint32_t reserveCount) +inline void xmrig::WorkerJob<1>::nextRound(uint32_t rounds, uint32_t roundSize) { m_rounds[index()]++; - if ((m_rounds[index()] % reserveCount) == 0) { - *nonce() = Nonce::next(index(), *nonce(), reserveCount, currentJob().isNicehash()); + if ((m_rounds[index()] % rounds) == 0) { + *nonce() = Nonce::next(index(), *nonce(), rounds * roundSize, currentJob().isNicehash()); } else { - *nonce() += 1; + *nonce() += roundSize; } } diff --git a/src/backend/common/Workers.cpp b/src/backend/common/Workers.cpp index 036bc8b66..7ed9bd8e5 100644 --- a/src/backend/common/Workers.cpp +++ b/src/backend/common/Workers.cpp @@ -31,6 +31,11 @@ #include "base/io/log/Log.h" +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/OclWorker.h" +#endif + + namespace xmrig { @@ -129,7 +134,7 @@ void xmrig::Workers::tick(uint64_t) return; } - d_ptr->hashrate->add(handle->index(), handle->worker()->hashCount(), handle->worker()->timestamp()); + d_ptr->hashrate->add(handle->id(), handle->worker()->hashCount(), handle->worker()->timestamp()); } d_ptr->hashrate->updateHighest(); @@ -137,7 +142,7 @@ void xmrig::Workers::tick(uint64_t) template -xmrig::IWorker *xmrig::Workers::create(Thread *) +xmrig::IWorker *xmrig::Workers::create(Thread *) { return nullptr; } @@ -146,15 +151,18 @@ xmrig::IWorker *xmrig::Workers::create(Thread *) template void xmrig::Workers::onReady(void *arg) { - Thread *handle = static_cast* >(arg); + auto handle = static_cast* >(arg); IWorker *worker = create(handle); if (!worker || !worker->selfTest()) { LOG_ERR("thread %zu error: \"hash self-test failed\".", worker->id()); + delete worker; return; } + assert(handle->backend() != nullptr); + handle->setWorker(worker); handle->backend()->start(worker); } @@ -166,32 +174,21 @@ namespace xmrig { template<> xmrig::IWorker *xmrig::Workers::create(Thread *handle) { - const int intensity = handle->config().intensity; - -# if defined(XMRIG_ALGO_RANDOMX) || defined(XMRIG_ALGO_CN_GPU) - if (intensity > handle->config().algorithm.maxIntensity()) { - LOG_WARN("CPU thread %zu warning: \"intensity %d not supported for %s algorithm\".", handle->index(), handle->config().intensity, handle->config().algorithm.shortName()); - - return new CpuWorker<1>(handle->index(), handle->config()); - } -# endif - - - switch (intensity) { + switch (handle->config().intensity) { case 1: - return new CpuWorker<1>(handle->index(), handle->config()); + return new CpuWorker<1>(handle->id(), handle->config()); case 2: - return new CpuWorker<2>(handle->index(), handle->config()); + return new CpuWorker<2>(handle->id(), handle->config()); case 3: - return new CpuWorker<3>(handle->index(), handle->config()); + return new CpuWorker<3>(handle->id(), handle->config()); case 4: - return new CpuWorker<4>(handle->index(), handle->config()); + return new CpuWorker<4>(handle->id(), handle->config()); case 5: - return new CpuWorker<5>(handle->index(), handle->config()); + return new CpuWorker<5>(handle->id(), handle->config()); } return nullptr; @@ -201,4 +198,16 @@ xmrig::IWorker *xmrig::Workers::create(Thread *han template class Workers; +#ifdef XMRIG_FEATURE_OPENCL +template<> +xmrig::IWorker *xmrig::Workers::create(Thread *handle) +{ + return new OclWorker(handle->id(), handle->config()); +} + + +template class Workers; +#endif + + } // namespace xmrig diff --git a/src/backend/common/Workers.h b/src/backend/common/Workers.h index 77dd434c2..bb35157a4 100644 --- a/src/backend/common/Workers.h +++ b/src/backend/common/Workers.h @@ -31,6 +31,11 @@ #include "backend/cpu/CpuLaunchData.h" +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/OclLaunchData.h" +#endif + + namespace xmrig { @@ -52,7 +57,7 @@ public: void tick(uint64_t ticks); private: - static IWorker *create(Thread *handle); + static IWorker *create(Thread *handle); static void onReady(void *arg); std::vector *> m_workers; @@ -62,11 +67,16 @@ private: template<> IWorker *Workers::create(Thread *handle); - - extern template class Workers; +#ifdef XMRIG_FEATURE_OPENCL +template<> +IWorker *Workers::create(Thread *handle); +extern template class Workers; +#endif + + } // namespace xmrig diff --git a/src/backend/common/common.cmake b/src/backend/common/common.cmake index c470ea507..cddd40014 100644 --- a/src/backend/common/common.cmake +++ b/src/backend/common/common.cmake @@ -1,13 +1,16 @@ set(HEADERS_BACKEND_COMMON + src/backend/common/Hashrate.h + src/backend/common/Tags.h src/backend/common/interfaces/IBackend.h + src/backend/common/interfaces/IRxListener.h src/backend/common/interfaces/IThread.h src/backend/common/interfaces/IWorker.h - src/backend/common/Hashrate.h + src/backend/common/misc/PciTopology.h src/backend/common/Thread.h src/backend/common/Threads.h src/backend/common/Worker.h - src/backend/common/Workers.h src/backend/common/WorkerJob.h + src/backend/common/Workers.h ) set(SOURCES_BACKEND_COMMON diff --git a/src/backend/common/interfaces/IBackend.h b/src/backend/common/interfaces/IBackend.h index 2ec8bf045..91f3e6343 100644 --- a/src/backend/common/interfaces/IBackend.h +++ b/src/backend/common/interfaces/IBackend.h @@ -37,6 +37,7 @@ namespace xmrig { class Algorithm; class Hashrate; +class IApiRequest; class IWorker; class Job; class String; @@ -61,6 +62,7 @@ public: # ifdef XMRIG_FEATURE_API virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0; + virtual void handleRequest(IApiRequest &request) = 0; # endif }; diff --git a/src/backend/common/interfaces/IRxListener.h b/src/backend/common/interfaces/IRxListener.h new file mode 100644 index 000000000..b4dde9e5a --- /dev/null +++ b/src/backend/common/interfaces/IRxListener.h @@ -0,0 +1,44 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2016-2018 XMRig + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_IRXLISTENER_H +#define XMRIG_IRXLISTENER_H + + +namespace xmrig { + + +class IRxListener +{ +public: + virtual ~IRxListener() = default; + +# ifdef XMRIG_ALGO_RANDOMX + virtual void onDatasetReady() = 0; +# endif +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_IRXLISTENER_H diff --git a/src/backend/common/misc/PciTopology.h b/src/backend/common/misc/PciTopology.h new file mode 100644 index 000000000..dcfacb201 --- /dev/null +++ b/src/backend/common/misc/PciTopology.h @@ -0,0 +1,62 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_PCITOPOLOGY_H +#define XMRIG_PCITOPOLOGY_H + + +#include + + +#include "base/tools/String.h" + + +namespace xmrig { + + +class PciTopology +{ +public: + PciTopology() = default; + PciTopology(uint32_t bus, uint32_t device, uint32_t function) : bus(bus), device(device), function(function) {} + + uint32_t bus = 0; + uint32_t device = 0; + uint32_t function = 0; + + String toString() const + { + char *buf = new char[8](); + snprintf(buf, 8, "%02x:%02x.%01x", bus, device, function); + + return buf; + } +}; + + +} // namespace xmrig + + +#endif /* XMRIG_PCITOPOLOGY_H */ diff --git a/src/backend/cpu/CpuBackend.cpp b/src/backend/cpu/CpuBackend.cpp index 77baeaf60..22ae63d87 100644 --- a/src/backend/cpu/CpuBackend.cpp +++ b/src/backend/cpu/CpuBackend.cpp @@ -28,6 +28,7 @@ #include "backend/common/Hashrate.h" #include "backend/common/interfaces/IWorker.h" +#include "backend/common/Tags.h" #include "backend/common/Workers.h" #include "backend/cpu/Cpu.h" #include "backend/cpu/CpuBackend.h" @@ -43,6 +44,16 @@ #include "rapidjson/document.h" +#ifdef XMRIG_FEATURE_API +# include "base/api/interfaces/IApiRequest.h" +#endif + + +#ifdef XMRIG_ALGO_ARGON2 +# include "crypto/argon2/Impl.h" +#endif + + namespace xmrig { @@ -51,29 +62,63 @@ extern template class Threads; static const char *tag = CYAN_BG_BOLD(" cpu "); static const String kType = "cpu"; +static std::mutex mutex; -struct LaunchStatus +struct CpuLaunchStatus { public: - inline void reset() + inline size_t hugePages() const { return m_hugePages; } + inline size_t memory() const { return m_ways * m_memory; } + inline size_t pages() const { return m_pages; } + inline size_t threads() const { return m_threads; } + inline size_t ways() const { return m_ways; } + + inline void start(const std::vector &threads, size_t memory) { - hugePages = 0; - memory = 0; - pages = 0; - started = 0; - threads = 0; - ways = 0; - ts = Chrono::steadyMSecs(); + m_hugePages = 0; + m_memory = memory; + m_pages = 0; + m_started = 0; + m_threads = threads.size(); + m_ways = 0; + m_ts = Chrono::steadyMSecs(); + + for (const CpuLaunchData &data : threads) { + m_ways += data.intensity; + } } - size_t hugePages = 0; - size_t memory = 0; - size_t pages = 0; - size_t started = 0; - size_t threads = 0; - size_t ways = 0; - uint64_t ts = 0; + inline bool started(const std::pair &hugePages) + { + m_started++; + m_hugePages += hugePages.first; + m_pages += hugePages.second; + + return m_started == m_threads; + } + + inline void print() const + { + LOG_INFO("%s" GREEN_BOLD(" READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"), + tag, + m_threads, m_ways, + (m_hugePages == m_pages ? GREEN_BOLD_S : (m_hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), + m_hugePages, m_pages, + m_hugePages == 0 ? 0.0 : static_cast(m_hugePages) / m_pages * 100.0, + m_ways * m_memory / 1024, + Chrono::steadyMSecs() - m_ts + ); + } + +private: + size_t m_hugePages = 0; + size_t m_memory = 0; + size_t m_pages = 0; + size_t m_started = 0; + size_t m_threads = 0; + size_t m_ways = 0; + uint64_t m_ts = 0; }; @@ -95,16 +140,7 @@ public: algo.l3() / 1024 ); - workers.stop(); - - status.reset(); - status.memory = algo.l3(); - status.threads = threads.size(); - - for (const CpuLaunchData &data : threads) { - status.ways += static_cast(data.intensity); - } - + status.start(threads, algo.l3()); workers.start(threads); } @@ -113,14 +149,45 @@ public: { std::lock_guard lock(mutex); - return status.ways; + return status.ways(); + } + + + rapidjson::Value hugePages(int version, rapidjson::Document &doc) + { + std::pair pages(0, 0); + + # ifdef XMRIG_ALGO_RANDOMX + if (algo.family() == Algorithm::RANDOM_X) { + pages = Rx::hugePages(); + } + # endif + + mutex.lock(); + + pages.first += status.hugePages(); + pages.second += status.pages(); + + mutex.unlock(); + + rapidjson::Value hugepages; + + if (version > 1) { + hugepages.SetArray(); + hugepages.PushBack(pages.first, doc.GetAllocator()); + hugepages.PushBack(pages.second, doc.GetAllocator()); + } + else { + hugepages = pages.first == pages.second; + } + + return hugepages; } Algorithm algo; Controller *controller; - LaunchStatus status; - std::mutex mutex; + CpuLaunchStatus status; std::vector threads; String profileName; Workers workers; @@ -130,6 +197,12 @@ public: } // namespace xmrig +const char *xmrig::cpu_tag() +{ + return tag; +} + + xmrig::CpuBackend::CpuBackend(Controller *controller) : d_ptr(new CpuBackendPrivate(controller)) { @@ -143,25 +216,6 @@ xmrig::CpuBackend::~CpuBackend() } -std::pair xmrig::CpuBackend::hugePages() const -{ - std::pair pages(0, 0); - -# ifdef XMRIG_ALGO_RANDOMX - if (d_ptr->algo.family() == Algorithm::RANDOM_X) { - pages = Rx::hugePages(); - } -# endif - - std::lock_guard lock(d_ptr->mutex); - - pages.first += d_ptr->status.hugePages; - pages.second += d_ptr->status.pages; - - return pages; -} - - bool xmrig::CpuBackend::isEnabled() const { return d_ptr->controller->config()->cpu().isEnabled(); @@ -192,8 +246,17 @@ const xmrig::String &xmrig::CpuBackend::type() const } -void xmrig::CpuBackend::prepare(const Job &) +void xmrig::CpuBackend::prepare(const Job &nextJob) { +# ifdef XMRIG_ALGO_ARGON2 + if (nextJob.algorithm().family() == Algorithm::ARGON2 && argon2::Impl::select(d_ptr->controller->config()->cpu().argon2Impl())) { + LOG_INFO("%s use " WHITE_BOLD("argon2") " implementation " CSI "1;%dm" "%s", + tag, + argon2::Impl::name() == "default" ? 33 : 32, + argon2::Impl::name().data() + ); + } +# endif } @@ -205,11 +268,11 @@ void xmrig::CpuBackend::printHashrate(bool details) char num[8 * 3] = { 0 }; - Log::print(WHITE_BOLD_S "| CPU THREAD | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); + Log::print(WHITE_BOLD_S "| CPU # | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); size_t i = 0; for (const CpuLaunchData &data : d_ptr->threads) { - Log::print("| %13zu | %8" PRId64 " | %7s | %7s | %7s |", + Log::print("| %8zu | %8" PRId64 " | %7s | %7s | %7s |", i, data.affinity, Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), @@ -219,6 +282,14 @@ void xmrig::CpuBackend::printHashrate(bool details) i++; } + +# ifdef XMRIG_FEATURE_OPENCL + Log::print(WHITE_BOLD_S "| - | - | %7s | %7s | %7s |", + Hashrate::format(hashrate()->calc(Hashrate::ShortInterval), num, sizeof num / 3), + Hashrate::format(hashrate()->calc(Hashrate::MediumInterval), num + 8, sizeof num / 3), + Hashrate::format(hashrate()->calc(Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3) + ); +# endif } @@ -231,7 +302,7 @@ void xmrig::CpuBackend::setJob(const Job &job) const CpuConfig &cpu = d_ptr->controller->config()->cpu(); std::vector threads = cpu.get(d_ptr->controller->miner(), job.algorithm()); - if (d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { + if (!d_ptr->threads.empty() && d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { return; } @@ -239,13 +310,13 @@ void xmrig::CpuBackend::setJob(const Job &job) d_ptr->profileName = cpu.threads().profileName(job.algorithm()); if (d_ptr->profileName.isNull() || threads.empty()) { - d_ptr->workers.stop(); + LOG_WARN("%s " RED_BOLD("disabled") YELLOW(" (no suitable configuration found)"), tag); - LOG_WARN(YELLOW_BOLD_S "CPU disabled, no suitable configuration for algo %s", job.algorithm().shortName()); - - return; + return stop(); } + stop(); + d_ptr->threads = std::move(threads); d_ptr->start(); } @@ -253,28 +324,13 @@ void xmrig::CpuBackend::setJob(const Job &job) void xmrig::CpuBackend::start(IWorker *worker) { - d_ptr->mutex.lock(); + mutex.lock(); - const auto pages = worker->memory()->hugePages(); - - d_ptr->status.started++; - d_ptr->status.hugePages += pages.first; - d_ptr->status.pages += pages.second; - - if (d_ptr->status.started == d_ptr->status.threads) { - const double percent = d_ptr->status.hugePages == 0 ? 0.0 : static_cast(d_ptr->status.hugePages) / d_ptr->status.pages * 100.0; - const size_t memory = d_ptr->status.ways * d_ptr->status.memory / 1024; - - LOG_INFO("%s" GREEN_BOLD(" READY") " threads " CYAN_BOLD("%zu(%zu)") " huge pages %s%zu/%zu %1.0f%%\x1B[0m memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"), - tag, - d_ptr->status.threads, d_ptr->status.ways, - (d_ptr->status.hugePages == d_ptr->status.pages ? GREEN_BOLD_S : (d_ptr->status.hugePages == 0 ? RED_BOLD_S : YELLOW_BOLD_S)), - d_ptr->status.hugePages, d_ptr->status.pages, percent, memory, - Chrono::steadyMSecs() - d_ptr->status.ts - ); + if (d_ptr->status.started(worker->memory()->hugePages())) { + d_ptr->status.print(); } - d_ptr->mutex.unlock(); + mutex.unlock(); worker->start(); } @@ -282,6 +338,10 @@ void xmrig::CpuBackend::start(IWorker *worker) void xmrig::CpuBackend::stop() { + if (d_ptr->threads.empty()) { + return; + } + const uint64_t ts = Chrono::steadyMSecs(); d_ptr->workers.stop(); @@ -319,13 +379,11 @@ rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const out.AddMember("asm", false, allocator); # endif - const auto pages = hugePages(); +# ifdef XMRIG_ALGO_ARGON2 + out.AddMember("argon2-impl", argon2::Impl::name().toJSON(), allocator); +# endif - rapidjson::Value hugepages(rapidjson::kArrayType); - hugepages.PushBack(pages.first, allocator); - hugepages.PushBack(pages.second, allocator); - - out.AddMember("hugepages", hugepages, allocator); + out.AddMember("hugepages", d_ptr->hugePages(2, doc), allocator); out.AddMember("memory", static_cast(d_ptr->algo.isValid() ? (d_ptr->ways() * d_ptr->algo.l3()) : 0), allocator); if (d_ptr->threads.empty() || !hashrate()) { @@ -357,4 +415,12 @@ rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const return out; } + + +void xmrig::CpuBackend::handleRequest(IApiRequest &request) +{ + if (request.type() == IApiRequest::REQ_SUMMARY) { + request.reply().AddMember("hugepages", d_ptr->hugePages(request.version(), request.doc()), request.doc().GetAllocator()); + } +} #endif diff --git a/src/backend/cpu/CpuBackend.h b/src/backend/cpu/CpuBackend.h index 2b907840f..9d6d85ac4 100644 --- a/src/backend/cpu/CpuBackend.h +++ b/src/backend/cpu/CpuBackend.h @@ -46,8 +46,6 @@ public: CpuBackend(Controller *controller); ~CpuBackend() override; - std::pair hugePages() const; - protected: bool isEnabled() const override; bool isEnabled(const Algorithm &algorithm) const override; @@ -63,6 +61,7 @@ protected: # ifdef XMRIG_FEATURE_API rapidjson::Value toJSON(rapidjson::Document &doc) const override; + void handleRequest(IApiRequest &request) override; # endif private: diff --git a/src/backend/cpu/CpuConfig.cpp b/src/backend/cpu/CpuConfig.cpp index 5905b7b4b..7ea6a38b7 100644 --- a/src/backend/cpu/CpuConfig.cpp +++ b/src/backend/cpu/CpuConfig.cpp @@ -62,6 +62,11 @@ static const char *kRx = "rx"; static const char *kRxWOW = "rx/wow"; #endif +#ifdef XMRIG_ALGO_ARGON2 +static const char *kArgon2 = "argon2"; +static const char *kArgon2Impl = "argon2-impl"; +#endif + extern template class Threads; } @@ -94,6 +99,10 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const obj.AddMember(StringRef(kAsm), m_assembly.toJSON(), allocator); # endif +# ifdef XMRIG_ALGO_ARGON2 + obj.AddMember(StringRef(kArgon2Impl), m_argon2Impl.toJSON(), allocator); +# endif + m_threads.toJSON(obj, doc); return obj; @@ -112,14 +121,14 @@ std::vector xmrig::CpuConfig::get(const Miner *miner, cons out.reserve(threads.count()); for (const CpuThread &thread : threads.data()) { - out.push_back(CpuLaunchData(miner, algorithm, *this, thread)); + out.emplace_back(miner, algorithm, *this, thread); } return out; } -void xmrig::CpuConfig::read(const rapidjson::Value &value) +void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version) { if (value.IsObject()) { m_enabled = Json::getBool(value, kEnabled, m_enabled); @@ -132,9 +141,17 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value) m_assembly = Json::getValue(value, kAsm); # endif +# ifdef XMRIG_ALGO_ARGON2 + m_argon2Impl = Json::getString(value, kArgon2Impl); +# endif + if (!m_threads.read(value)) { generate(); } + + if (version == 0) { + generateArgon2(); + } } else if (value.IsBool() && value.IsFalse()) { m_enabled = false; @@ -174,6 +191,16 @@ void xmrig::CpuConfig::generate() m_threads.move(kRx, cpu->threads(Algorithm::RX_0)); m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW)); # endif + + generateArgon2(); +} + + +void xmrig::CpuConfig::generateArgon2() +{ +# ifdef XMRIG_ALGO_ARGON2 + m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA)); +# endif } diff --git a/src/backend/cpu/CpuConfig.h b/src/backend/cpu/CpuConfig.h index 5aca51884..67010eea8 100644 --- a/src/backend/cpu/CpuConfig.h +++ b/src/backend/cpu/CpuConfig.h @@ -49,17 +49,19 @@ public: bool isHwAES() const; rapidjson::Value toJSON(rapidjson::Document &doc) const; std::vector get(const Miner *miner, const Algorithm &algorithm) const; - void read(const rapidjson::Value &value); + void read(const rapidjson::Value &value, uint32_t version); inline bool isEnabled() const { return m_enabled; } inline bool isHugePages() const { return m_hugePages; } inline bool isShouldSave() const { return m_shouldSave; } inline const Assembly &assembly() const { return m_assembly; } + inline const String &argon2Impl() const { return m_argon2Impl; } inline const Threads &threads() const { return m_threads; } inline int priority() const { return m_priority; } private: void generate(); + void generateArgon2(); void setAesMode(const rapidjson::Value &aesMode); inline void setPriority(int priority) { m_priority = (priority >= -1 && priority <= 5) ? priority : -1; } @@ -70,6 +72,7 @@ private: bool m_hugePages = true; bool m_shouldSave = false; int m_priority = -1; + String m_argon2Impl; Threads m_threads; }; diff --git a/src/backend/cpu/CpuLaunchData.cpp b/src/backend/cpu/CpuLaunchData.cpp index a01f22a6a..3916e7d2e 100644 --- a/src/backend/cpu/CpuLaunchData.cpp +++ b/src/backend/cpu/CpuLaunchData.cpp @@ -24,6 +24,9 @@ */ +#include + + #include "backend/cpu/CpuLaunchData.h" #include "backend/cpu/CpuConfig.h" @@ -33,10 +36,10 @@ xmrig::CpuLaunchData::CpuLaunchData(const Miner *miner, const Algorithm &algorit assembly(config.assembly()), hugePages(config.isHugePages()), hwAES(config.isHwAES()), - intensity(thread.intensity()), priority(config.priority()), affinity(thread.affinity()), - miner(miner) + miner(miner), + intensity(std::min(thread.intensity(), algorithm.maxIntensity())) { } diff --git a/src/backend/cpu/CpuLaunchData.h b/src/backend/cpu/CpuLaunchData.h index bb18816a5..92636bcab 100644 --- a/src/backend/cpu/CpuLaunchData.h +++ b/src/backend/cpu/CpuLaunchData.h @@ -58,10 +58,10 @@ public: const Assembly assembly; const bool hugePages; const bool hwAES; - const int intensity; const int priority; const int64_t affinity; const Miner *miner; + const uint32_t intensity; }; diff --git a/src/backend/cpu/CpuThread.cpp b/src/backend/cpu/CpuThread.cpp index 7d7a9e855..660107fa6 100644 --- a/src/backend/cpu/CpuThread.cpp +++ b/src/backend/cpu/CpuThread.cpp @@ -31,11 +31,11 @@ xmrig::CpuThread::CpuThread(const rapidjson::Value &value) { if (value.IsArray() && value.Size() >= 2) { - m_intensity = value[0].GetInt(); + m_intensity = value[0].GetUint(); m_affinity = value[1].GetInt(); } else if (value.IsInt()) { - m_intensity = -1; + m_intensity = 0; m_affinity = value.GetInt(); } } @@ -44,7 +44,7 @@ xmrig::CpuThread::CpuThread(const rapidjson::Value &value) rapidjson::Value xmrig::CpuThread::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; - if (m_intensity == -1) { + if (m_intensity == 0) { return Value(m_affinity); } diff --git a/src/backend/cpu/CpuThread.h b/src/backend/cpu/CpuThread.h index 691ee1146..91d63a1c9 100644 --- a/src/backend/cpu/CpuThread.h +++ b/src/backend/cpu/CpuThread.h @@ -35,15 +35,15 @@ namespace xmrig { class CpuThread { public: - inline constexpr CpuThread() {} - inline constexpr CpuThread(int64_t affinity, int intensity) : m_intensity(intensity), m_affinity(affinity) {} + inline constexpr CpuThread() = default; + inline constexpr CpuThread(int64_t affinity, uint32_t intensity) : m_affinity(affinity), m_intensity(intensity) {} CpuThread(const rapidjson::Value &value); inline bool isEqual(const CpuThread &other) const { return other.m_affinity == m_affinity && other.m_intensity == m_intensity; } - inline bool isValid() const { return m_intensity == -1 || (m_intensity >= 1 && m_intensity <= 5); } - inline int intensity() const { return m_intensity == -1 ? 1 : m_intensity; } + inline bool isValid() const { return m_intensity <= 5; } inline int64_t affinity() const { return m_affinity; } + inline uint32_t intensity() const { return m_intensity == 0 ? 1 : m_intensity; } inline bool operator!=(const CpuThread &other) const { return !isEqual(other); } inline bool operator==(const CpuThread &other) const { return isEqual(other); } @@ -51,8 +51,8 @@ public: rapidjson::Value toJSON(rapidjson::Document &doc) const; private: - int m_intensity = -1; - int64_t m_affinity = -1; + int64_t m_affinity = -1; + uint32_t m_intensity = 0; }; diff --git a/src/backend/cpu/CpuThreads.cpp b/src/backend/cpu/CpuThreads.cpp index 07e8ca33f..5bd9cca97 100644 --- a/src/backend/cpu/CpuThreads.cpp +++ b/src/backend/cpu/CpuThreads.cpp @@ -94,7 +94,7 @@ xmrig::CpuThreads::CpuThreads(const rapidjson::Value &value) } } else if (value.IsObject()) { - int intensity = Json::getInt(value, kIntensity, 1); + uint32_t intensity = Json::getUint(value, kIntensity, 1); const size_t threads = std::min(Json::getUint(value, kThreads), 1024); m_affinity = getAffinityMask(Json::getValue(value, kAffinity)); m_format = ObjectFormat; @@ -110,7 +110,7 @@ xmrig::CpuThreads::CpuThreads(const rapidjson::Value &value) } -xmrig::CpuThreads::CpuThreads(size_t count, int intensity) +xmrig::CpuThreads::CpuThreads(size_t count, uint32_t intensity) { m_data.reserve(count); diff --git a/src/backend/cpu/CpuThreads.h b/src/backend/cpu/CpuThreads.h index f8ad64308..13cd725ff 100644 --- a/src/backend/cpu/CpuThreads.h +++ b/src/backend/cpu/CpuThreads.h @@ -42,13 +42,13 @@ public: inline CpuThreads(size_t count) : m_data(count) {} CpuThreads(const rapidjson::Value &value); - CpuThreads(size_t count, int intensity); + CpuThreads(size_t count, uint32_t intensity); inline bool isEmpty() const { return m_data.empty(); } inline const std::vector &data() const { return m_data; } inline size_t count() const { return m_data.size(); } inline void add(CpuThread &&thread) { m_data.push_back(thread); } - inline void add(int64_t affinity, int intensity) { add(CpuThread(affinity, intensity)); } + inline void add(int64_t affinity, uint32_t intensity) { add(CpuThread(affinity, intensity)); } inline void reserve(size_t capacity) { m_data.reserve(capacity); } rapidjson::Value toJSON(rapidjson::Document &doc) const; diff --git a/src/backend/cpu/CpuWorker.cpp b/src/backend/cpu/CpuWorker.cpp index 14ef1797e..a98027c0f 100644 --- a/src/backend/cpu/CpuWorker.cpp +++ b/src/backend/cpu/CpuWorker.cpp @@ -24,7 +24,7 @@ */ -#include +#include #include @@ -46,15 +46,15 @@ namespace xmrig { -static constexpr uint32_t kReserveCount = 4096; +static constexpr uint32_t kReserveCount = 32768; } // namespace xmrig template -xmrig::CpuWorker::CpuWorker(size_t index, const CpuLaunchData &data) : - Worker(index, data.affinity, data.priority), +xmrig::CpuWorker::CpuWorker(size_t id, const CpuLaunchData &data) : + Worker(id, data.affinity, data.priority), m_algorithm(data.algorithm), m_assembly(data.assembly), m_hwAES(data.hwAES), @@ -90,6 +90,8 @@ void xmrig::CpuWorker::allocateRandomX_VM() if (Nonce::sequence(Nonce::CPU) == 0) { return; } + + dataset = Rx::dataset(m_job.currentJob(), m_node); } if (!m_vm) { @@ -118,7 +120,6 @@ bool xmrig::CpuWorker::selfTest() verify(Algorithm::CN_XAO, test_output_xao) && verify(Algorithm::CN_RTO, test_output_rto) && verify(Algorithm::CN_HALF, test_output_half) && - verify2(Algorithm::CN_WOW, test_output_wow) && verify2(Algorithm::CN_R, test_output_r) && verify(Algorithm::CN_RWZ, test_output_rwz) && verify(Algorithm::CN_ZLS, test_output_zls) && @@ -156,6 +157,13 @@ bool xmrig::CpuWorker::selfTest() } # endif +# ifdef XMRIG_ALGO_ARGON2 + if (m_algorithm.family() == Algorithm::ARGON2) { + return verify(Algorithm::AR2_CHUKWA, argon2_chukwa_test_out) && + verify(Algorithm::AR2_WRKZ, argon2_wrkz_test_out); + } +# endif + return false; } @@ -200,11 +208,11 @@ void xmrig::CpuWorker::start() for (size_t i = 0; i < N; ++i) { if (*reinterpret_cast(m_hash + (i * 32) + 24) < job.target()) { - JobResults::submit(JobResult(job, *m_job.nonce(i), m_hash + (i * 32))); + JobResults::submit(job, *m_job.nonce(i), m_hash + (i * 32)); } } - m_job.nextRound(kReserveCount); + m_job.nextRound(kReserveCount, 1); m_count += N; std::this_thread::yield(); @@ -291,6 +299,10 @@ void xmrig::CpuWorker::allocateCnCtx() template void xmrig::CpuWorker::consumeJob() { + if (Nonce::sequence(Nonce::CPU) == 0) { + return; + } + m_job.add(m_miner->job(), Nonce::sequence(Nonce::CPU), kReserveCount); # ifdef XMRIG_ALGO_RANDOMX diff --git a/src/backend/cpu/CpuWorker.h b/src/backend/cpu/CpuWorker.h index 4cdd10f8f..02ce0826c 100644 --- a/src/backend/cpu/CpuWorker.h +++ b/src/backend/cpu/CpuWorker.h @@ -30,7 +30,7 @@ #include "backend/common/Worker.h" #include "backend/common/WorkerJob.h" #include "backend/cpu/CpuLaunchData.h" -#include "base/net/stratum/Job.h" +#include "base/tools/Object.h" #include "net/JobResult.h" @@ -44,7 +44,9 @@ template class CpuWorker : public Worker { public: - CpuWorker(size_t index, const CpuLaunchData &data); + XMRIG_DISABLE_COPY_MOVE_DEFAULT(CpuWorker) + + CpuWorker(size_t id, const CpuLaunchData &data); ~CpuWorker() override; protected: @@ -71,7 +73,7 @@ private: const CnHash::AlgoVariant m_av; const Miner *m_miner; cryptonight_ctx *m_ctx[N]; - uint8_t m_hash[N * 32]; + uint8_t m_hash[N * 32]{ 0 }; VirtualMemory *m_memory = nullptr; WorkerJob m_job; diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp index de8ff2721..267988952 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -145,7 +145,7 @@ xmrig::CpuThreads xmrig::AdvancedCpuInfo::threads(const Algorithm &algorithm) co count = threads() / 2; } - int intensity = algorithm.maxIntensity() == 1 ? -1 : 1; + uint32_t intensity = algorithm.maxIntensity() == 1 ? 0 : 1; # ifdef XMRIG_ALGO_CN_PICO if (algorithm == Algorithm::CN_PICO_0 && (count / cores()) >= 2) { diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp index 2f3177d2e..15ac8f402 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -52,7 +52,6 @@ #define VENDOR_ID (0) #define PROCESSOR_INFO (1) -#define CACHE_TLB_DESCRIPTOR (2) #define EXTENDED_FEATURES (7) #define PROCESSOR_BRAND_STRING_1 (0x80000002) #define PROCESSOR_BRAND_STRING_2 (0x80000003) @@ -222,5 +221,11 @@ xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm) const } # endif +# ifdef XMRIG_ALGO_ARGON2 + if (algorithm.family() == Algorithm::ARGON2) { + return count; + } +# endif + return CpuThreads(std::max(count / 2, 1), 1); } diff --git a/src/backend/cpu/platform/HwlocCpuInfo.cpp b/src/backend/cpu/platform/HwlocCpuInfo.cpp index 7da997872..9e5037424 100644 --- a/src/backend/cpu/platform/HwlocCpuInfo.cpp +++ b/src/backend/cpu/platform/HwlocCpuInfo.cpp @@ -251,7 +251,7 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith int L2_associativity = 0; size_t extra = 0; const size_t scratchpad = algorithm.l3(); - int intensity = algorithm.maxIntensity() == 1 ? -1 : 1; + uint32_t intensity = algorithm.maxIntensity() == 1 ? 0 : 1; if (cache->attr->cache.depth == 3) { for (size_t i = 0; i < cache->arity; ++i) { diff --git a/src/backend/opencl/OclBackend.cpp b/src/backend/opencl/OclBackend.cpp new file mode 100644 index 000000000..b9f5d35a5 --- /dev/null +++ b/src/backend/opencl/OclBackend.cpp @@ -0,0 +1,403 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "backend/common/Hashrate.h" +#include "backend/common/interfaces/IWorker.h" +#include "backend/common/Tags.h" +#include "backend/common/Workers.h" +#include "backend/opencl/OclBackend.h" +#include "backend/opencl/OclConfig.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/OclWorker.h" +#include "backend/opencl/wrappers/OclContext.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Chrono.h" +#include "base/tools/String.h" +#include "core/config/Config.h" +#include "core/Controller.h" +#include "rapidjson/document.h" + + +#ifdef XMRIG_FEATURE_API +# include "base/api/interfaces/IApiRequest.h" +#endif + + +namespace xmrig { + + +extern template class Threads; + + +constexpr const size_t oneMiB = 1024u * 1024u; +static const char *tag = MAGENTA_BG_BOLD(WHITE_BOLD_S " ocl "); +static const String kType = "opencl"; +static std::mutex mutex; + + +static void printDisabled(const char *reason) +{ + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") RED_BOLD("disabled") "%s", "OPENCL", reason); +} + + +struct OclLaunchStatus +{ +public: + inline bool started() { m_started++; return m_started == m_threads; } + inline size_t threads() const { return m_threads; } + + inline void start(size_t threads) + { + m_started = 0; + m_threads = threads; + m_ts = Chrono::steadyMSecs(); + OclWorker::ready = false; + } + + inline void print() const + { + LOG_INFO("%s" GREEN_BOLD(" READY") " threads " CYAN_BOLD("%zu") BLACK_BOLD(" (%" PRIu64 " ms)"), + tag, + m_threads, + Chrono::steadyMSecs() - m_ts + ); + } + +private: + size_t m_started = 0; + size_t m_threads = 0; + uint64_t m_ts = 0; +}; + + +class OclBackendPrivate +{ +public: + inline OclBackendPrivate(Controller *controller) : + controller(controller) + { + init(controller->config()->cl()); + } + + + void init(const OclConfig &cl) + { + if (!cl.isEnabled()) { + return printDisabled(""); + } + + if (!OclLib::init(cl.loader())) { + return printDisabled(RED_S " (failed to load OpenCL runtime)"); + } + + platform = cl.platform(); + if (!platform.isValid()) { + return printDisabled(RED_S " (selected OpenCL platform NOT found)"); + } + + devices = platform.devices(); + if (devices.empty()) { + return printDisabled(RED_S " (no devices)"); + } + + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("#%zu ") WHITE_BOLD("%s") "/" WHITE_BOLD("%s"), "OPENCL", platform.index(), platform.name().data(), platform.version().data()); + + for (const OclDevice &device : devices) { + Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("#%zu") YELLOW(" %s") " %s " WHITE_BOLD("%uMHz") " cu:" WHITE_BOLD("%u") " mem:" CYAN("%zu/%zu") " MB", "OPENCL GPU", + device.index(), + device.hasTopology() ? device.topology().toString().data() : "n/a", + device.printableName().data(), + device.clock(), + device.computeUnits(), + device.freeMemSize() / oneMiB, + device.globalMemSize() / oneMiB); + } + } + + + inline void start() + { + LOG_INFO("%s use profile " BLUE_BG(WHITE_BOLD_S " %s ") WHITE_BOLD_S " (" CYAN_BOLD("%zu") WHITE_BOLD(" threads)") " scratchpad " CYAN_BOLD("%zu KB"), + tag, + profileName.data(), + threads.size(), + algo.l3() / 1024 + ); + + Log::print(WHITE_BOLD("| # | GPU | BUS ID | I | W | SI | MC | U | MEM | NAME")); + + size_t i = 0; + for (const auto &data : threads) { + Log::print("|" CYAN_BOLD("%3zu") " |" CYAN_BOLD("%4u") " |" YELLOW(" %7s") " |" CYAN_BOLD("%5u") " |" CYAN_BOLD("%3u") " |" + CYAN_BOLD("%3u") " |" CYAN_BOLD("%3s") " |" CYAN_BOLD("%3u") " |" CYAN("%5zu") " | %s", + i, + data.thread.index(), + data.device.hasTopology() ? data.device.topology().toString().data() : "n/a", + data.thread.intensity(), + data.thread.worksize(), + data.thread.stridedIndex(), + data.thread.stridedIndex() == 2 ? std::to_string(data.thread.memChunk()).c_str() : "-", + data.thread.unrollFactor(), + data.thread.intensity() * algo.l3() / oneMiB, + data.device.printableName().data() + ); + + i++; + } + + status.start(threads.size()); + workers.start(threads); + } + + + Algorithm algo; + Controller *controller; + OclContext context; + OclLaunchStatus status; + OclPlatform platform; + std::vector devices; + std::vector threads; + String profileName; + Workers workers; +}; + + +} // namespace xmrig + + +const char *xmrig::ocl_tag() +{ + return tag; +} + + +xmrig::OclBackend::OclBackend(Controller *controller) : + d_ptr(new OclBackendPrivate(controller)) +{ + d_ptr->workers.setBackend(this); +} + + +xmrig::OclBackend::~OclBackend() +{ + delete d_ptr; + + OclLib::close(); +} + + +bool xmrig::OclBackend::isEnabled() const +{ + return d_ptr->controller->config()->cl().isEnabled() && OclLib::isInitialized() && d_ptr->platform.isValid() && !d_ptr->devices.empty(); +} + + +bool xmrig::OclBackend::isEnabled(const Algorithm &algorithm) const +{ + return !d_ptr->controller->config()->cl().threads().get(algorithm).isEmpty(); +} + + +const xmrig::Hashrate *xmrig::OclBackend::hashrate() const +{ + return d_ptr->workers.hashrate(); +} + + +const xmrig::String &xmrig::OclBackend::profileName() const +{ + return d_ptr->profileName; +} + + +const xmrig::String &xmrig::OclBackend::type() const +{ + return kType; +} + + +void xmrig::OclBackend::prepare(const Job &) +{ +} + + +void xmrig::OclBackend::printHashrate(bool details) +{ + if (!details || !hashrate()) { + return; + } + + char num[8 * 3] = { 0 }; + + Log::print(WHITE_BOLD_S "| OPENCL # | AFFINITY | 10s H/s | 60s H/s | 15m H/s |"); + + size_t i = 0; + for (const OclLaunchData &data : d_ptr->threads) { + Log::print("| %8zu | %8" PRId64 " | %7s | %7s | %7s |" CYAN_BOLD(" #%u") YELLOW(" %s") " %s", + i, + data.affinity, + Hashrate::format(hashrate()->calc(i, Hashrate::ShortInterval), num, sizeof num / 3), + Hashrate::format(hashrate()->calc(i, Hashrate::MediumInterval), num + 8, sizeof num / 3), + Hashrate::format(hashrate()->calc(i, Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3), + data.device.index(), + data.device.hasTopology() ? data.device.topology().toString().data() : "n/a", + data.device.printableName().data() + ); + + i++; + } + + Log::print(WHITE_BOLD_S "| - | - | %7s | %7s | %7s |", + Hashrate::format(hashrate()->calc(Hashrate::ShortInterval), num, sizeof num / 3), + Hashrate::format(hashrate()->calc(Hashrate::MediumInterval), num + 8, sizeof num / 3), + Hashrate::format(hashrate()->calc(Hashrate::LargeInterval), num + 8 * 2, sizeof num / 3) + ); +} + + +void xmrig::OclBackend::setJob(const Job &job) +{ + if (!isEnabled()) { + return stop(); + } + + const OclConfig &cl = d_ptr->controller->config()->cl(); + + std::vector threads = cl.get(d_ptr->controller->miner(), job.algorithm(), d_ptr->platform, d_ptr->devices, tag); + if (!d_ptr->threads.empty() && d_ptr->threads.size() == threads.size() && std::equal(d_ptr->threads.begin(), d_ptr->threads.end(), threads.begin())) { + return; + } + + d_ptr->algo = job.algorithm(); + d_ptr->profileName = cl.threads().profileName(job.algorithm()); + + if (d_ptr->profileName.isNull() || threads.empty()) { + LOG_WARN("%s " RED_BOLD("disabled") YELLOW(" (no suitable configuration found)"), tag); + + return stop(); + } + + if (!d_ptr->context.init(d_ptr->devices, threads, job)) { + LOG_WARN("%s " RED_BOLD("disabled") YELLOW(" (OpenCL context unavailable)"), tag); + + return stop(); + } + + stop(); + + d_ptr->threads = std::move(threads); + d_ptr->start(); +} + + +void xmrig::OclBackend::start(IWorker *worker) +{ + mutex.lock(); + + if (d_ptr->status.started()) { + d_ptr->status.print(); + + OclWorker::ready = true; + } + + mutex.unlock(); + + worker->start(); +} + + +void xmrig::OclBackend::stop() +{ + if (d_ptr->threads.empty()) { + return; + } + + const uint64_t ts = Chrono::steadyMSecs(); + + d_ptr->workers.stop(); + d_ptr->threads.clear(); + + LOG_INFO("%s" YELLOW(" stopped") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); +} + + +void xmrig::OclBackend::tick(uint64_t ticks) +{ + d_ptr->workers.tick(ticks); +} + + +#ifdef XMRIG_FEATURE_API +rapidjson::Value xmrig::OclBackend::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value out(kObjectType); + out.AddMember("type", type().toJSON(), allocator); + out.AddMember("enabled", isEnabled(), allocator); + out.AddMember("algo", d_ptr->algo.toJSON(), allocator); + out.AddMember("profile", profileName().toJSON(), allocator); + out.AddMember("platform", d_ptr->platform.toJSON(doc), allocator); + + if (d_ptr->threads.empty() || !hashrate()) { + return out; + } + + Value threads(kArrayType); + const Hashrate *hr = hashrate(); + + size_t i = 0; + for (const OclLaunchData &data : d_ptr->threads) { + Value thread = data.thread.toJSON(doc); + thread.AddMember("affinity", data.affinity, allocator); + + Value hashrate(kArrayType); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::ShortInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::MediumInterval)), allocator); + hashrate.PushBack(Hashrate::normalize(hr->calc(i, Hashrate::LargeInterval)), allocator); + + i++; + + thread.AddMember("hashrate", hashrate, allocator); + threads.PushBack(thread, allocator); + } + + out.AddMember("threads", threads, allocator); + + return out; +} + + +void xmrig::OclBackend::handleRequest(IApiRequest &) +{ +} +#endif diff --git a/src/backend/opencl/OclBackend.h b/src/backend/opencl/OclBackend.h new file mode 100644 index 000000000..e6ba092ee --- /dev/null +++ b/src/backend/opencl/OclBackend.h @@ -0,0 +1,82 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLBACKEND_H +#define XMRIG_OCLBACKEND_H + + +#include + + +#include "backend/common/interfaces/IBackend.h" + + +namespace xmrig { + + +class Controller; +class OclBackendPrivate; +class Miner; + + +class OclBackend : public IBackend +{ +public: + OclBackend() = delete; + OclBackend(const OclBackend &other) = delete; + OclBackend(Controller *controller); + OclBackend(OclBackend &&other) = delete; + + ~OclBackend() override; + + OclBackend &operator=(const OclBackend &other) = delete; + OclBackend &operator=(OclBackend &&other) = delete; + +protected: + bool isEnabled() const override; + bool isEnabled(const Algorithm &algorithm) const override; + const Hashrate *hashrate() const override; + const String &profileName() const override; + const String &type() const override; + void prepare(const Job &nextJob) override; + void printHashrate(bool details) override; + void setJob(const Job &job) override; + void start(IWorker *worker) override; + void stop() override; + void tick(uint64_t ticks) override; + +# ifdef XMRIG_FEATURE_API + rapidjson::Value toJSON(rapidjson::Document &doc) const override; + void handleRequest(IApiRequest &request) override; +# endif + +private: + OclBackendPrivate *d_ptr; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLBACKEND_H */ diff --git a/src/backend/opencl/OclCache.cpp b/src/backend/opencl/OclCache.cpp new file mode 100644 index 000000000..7e5504c08 --- /dev/null +++ b/src/backend/opencl/OclCache.cpp @@ -0,0 +1,184 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include + + +#include "3rdparty/base32/base32.h" +#include "backend/common/Tags.h" +#include "backend/opencl/interfaces/IOclRunner.h" +#include "backend/opencl/OclCache.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/tools/Chrono.h" +#include "crypto/common/keccak.h" + + +namespace xmrig { + + +static std::mutex mutex; + + +static cl_program createFromSource(const IOclRunner *runner) +{ + LOG_INFO("%s GPU " WHITE_BOLD("#%zu") " " YELLOW_BOLD("compiling..."), ocl_tag(), runner->data().device.index()); + + cl_int ret; + cl_device_id device = runner->data().device.id(); + const char *source = runner->source(); + const uint64_t ts = Chrono::steadyMSecs(); + + cl_program program = OclLib::createProgramWithSource(runner->ctx(), 1, &source, nullptr, &ret); + if (ret != CL_SUCCESS) { + return nullptr; + } + + if (OclLib::buildProgram(program, 1, &device, runner->buildOptions()) != CL_SUCCESS) { + printf("BUILD LOG:\n%s\n", OclLib::getProgramBuildLog(program, device).data()); + + OclLib::release(program); + return nullptr; + } + + LOG_INFO("%s GPU " WHITE_BOLD("#%zu") " " GREEN_BOLD("compilation completed") BLACK_BOLD(" (%" PRIu64 " ms)"), + ocl_tag(), runner->data().device.index(), Chrono::steadyMSecs() - ts); + + return program; +} + + +static cl_program createFromBinary(const IOclRunner *runner, const std::string &fileName) +{ + std::ifstream file(fileName, std::ofstream::in | std::ofstream::binary); + if (!file.good()) { + return nullptr; + } + + std::ostringstream ss; + ss << file.rdbuf(); + + const std::string s = ss.str(); + const size_t bin_size = s.size(); + auto data_ptr = s.data(); + cl_device_id device = runner->data().device.id(); + + cl_int clStatus; + cl_int ret; + cl_program program = OclLib::createProgramWithBinary(runner->ctx(), 1, &device, &bin_size, reinterpret_cast(&data_ptr), &clStatus, &ret); + if (ret != CL_SUCCESS) { + return nullptr; + } + + if (OclLib::buildProgram(program, 1, &device) != CL_SUCCESS) { + OclLib::release(program); + return nullptr; + } + + return program; +} + + +} // namespace xmrig + + +cl_program xmrig::OclCache::build(const IOclRunner *runner) +{ + std::lock_guard lock(mutex); + + if (Nonce::sequence(Nonce::OPENCL) == 0) { + return nullptr; + } + + std::string fileName; + if (runner->data().cache) { +# ifdef _WIN32 + fileName = prefix() + "\\xmrig\\.cache\\" + cacheKey(runner) + ".bin"; +# else + fileName = prefix() + "/.cache/" + cacheKey(runner) + ".bin"; +# endif + + cl_program program = createFromBinary(runner, fileName); + if (program) { + return program; + } + } + + cl_program program = createFromSource(runner); + if (runner->data().cache && program) { + save(program, fileName); + } + + return program; +} + + +std::string xmrig::OclCache::cacheKey(const char *deviceKey, const char *options, const char *source) +{ + std::string in(source); + in += options; + in += deviceKey; + + uint8_t hash[200]; + keccak(in.c_str(), in.size(), hash); + + uint8_t result[32] = { 0 }; + base32_encode(hash, 12, result, sizeof(result)); + + return reinterpret_cast(result); +} + + +std::string xmrig::OclCache::cacheKey(const IOclRunner *runner) +{ + return cacheKey(runner->deviceKey(), runner->buildOptions(), runner->source()); +} + + +void xmrig::OclCache::save(cl_program program, const std::string &fileName) +{ + size_t size = 0; + if (OclLib::getProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size), &size) != CL_SUCCESS) { + return; + } + + std::vector binary(size); + + char *data = binary.data(); + if (OclLib::getProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(char *), &data) != CL_SUCCESS) { + return; + } + + createDirectory(); + + std::ofstream file_stream; + file_stream.open(fileName, std::ofstream::out | std::ofstream::binary); + file_stream.write(binary.data(), static_cast(binary.size())); + file_stream.close(); +} diff --git a/src/backend/opencl/OclCache.h b/src/backend/opencl/OclCache.h new file mode 100644 index 000000000..e3eea5c3f --- /dev/null +++ b/src/backend/opencl/OclCache.h @@ -0,0 +1,58 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLCACHE_H +#define XMRIG_OCLCACHE_H + + +#include + + +using cl_program = struct _cl_program *; + + +namespace xmrig { + + +class IOclRunner; + + +class OclCache +{ +public: + static cl_program build(const IOclRunner *runner); + static std::string cacheKey(const char *deviceKey, const char *options, const char *source); + static std::string cacheKey(const IOclRunner *runner); + +private: + static std::string prefix(); + static void createDirectory(); + static void save(cl_program program, const std::string &fileName); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLCACHE_H */ diff --git a/src/backend/opencl/OclCache_unix.cpp b/src/backend/opencl/OclCache_unix.cpp new file mode 100644 index 000000000..563a5b853 --- /dev/null +++ b/src/backend/opencl/OclCache_unix.cpp @@ -0,0 +1,42 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + + +#include "backend/opencl/OclCache.h" + + +void xmrig::OclCache::createDirectory() +{ + std::string path = prefix() + "/.cache"; + mkdir(path.c_str(), 0744); +} + + +std::string xmrig::OclCache::prefix() +{ + return "."; +} diff --git a/src/backend/opencl/OclCache_win.cpp b/src/backend/opencl/OclCache_win.cpp new file mode 100644 index 000000000..c6da323cd --- /dev/null +++ b/src/backend/opencl/OclCache_win.cpp @@ -0,0 +1,52 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include + + +#include "backend/opencl/OclCache.h" + + +void xmrig::OclCache::createDirectory() +{ + std::string path = prefix() + "/xmrig"; + _mkdir(path.c_str()); + + path += "/.cache"; + _mkdir(path.c_str()); +} + + +std::string xmrig::OclCache::prefix() +{ + char path[MAX_PATH + 1]; + if (SHGetSpecialFolderPathA(HWND_DESKTOP, path, CSIDL_LOCAL_APPDATA, FALSE)) { + return path; + } + + return "."; +} diff --git a/src/backend/opencl/OclConfig.cpp b/src/backend/opencl/OclConfig.cpp new file mode 100644 index 000000000..cdb38ccb8 --- /dev/null +++ b/src/backend/opencl/OclConfig.cpp @@ -0,0 +1,293 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclConfig.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/json/Json.h" +#include "base/io/log/Log.h" +#include "rapidjson/document.h" + + +namespace xmrig { + +static const char *kAMD = "AMD"; +static const char *kCache = "cache"; +static const char *kCn = "cn"; +static const char *kCn2 = "cn/2"; +static const char *kEnabled = "enabled"; +static const char *kINTEL = "INTEL"; +static const char *kLoader = "loader"; +static const char *kNVIDIA = "NVIDIA"; +static const char *kPlatform = "platform"; + + +#ifdef XMRIG_ALGO_CN_GPU +static const char *kCnGPU = "cn/gpu"; +#endif + +#ifdef XMRIG_ALGO_CN_LITE +static const char *kCnLite = "cn-lite"; +#endif + +#ifdef XMRIG_ALGO_CN_HEAVY +static const char *kCnHeavy = "cn-heavy"; +#endif + +#ifdef XMRIG_ALGO_CN_PICO +static const char *kCnPico = "cn-pico"; +#endif + +#ifdef XMRIG_ALGO_RANDOMX +static const char *kRx = "rx"; +static const char *kRxWOW = "rx/wow"; +#endif + +#ifdef XMRIG_ALGO_ARGON2 +//static const char *kArgon2 = "argon2"; +#endif + + +extern template class Threads; + + +static size_t generate(const char *key, Threads &threads, const Algorithm &algorithm, const std::vector &devices) +{ + if (threads.has(key) || threads.isExist(algorithm)) { + return 0; + } + + OclThreads profile; + for (const OclDevice &device : devices) { + device.generate(algorithm, profile); + } + + const size_t count = profile.count(); + threads.move(key, std::move(profile)); + + return count; +} + + +} + + +xmrig::OclConfig::OclConfig() : + m_platformVendor(kAMD) +{ +} + + +xmrig::OclPlatform xmrig::OclConfig::platform() const +{ + const auto platforms = OclPlatform::get(); + if (platforms.empty()) { + return {}; + } + + if (!m_platformVendor.isEmpty()) { + String search; + String vendor = m_platformVendor; + vendor.toUpper(); + + if (vendor == kAMD) { + search = "Advanced Micro Devices"; + } + else if (vendor == kNVIDIA) { + search = kNVIDIA; + } + else if (vendor == kINTEL) { + search = "Intel"; + } + else { + search = m_platformVendor; + } + + for (const auto &platform : platforms) { + if (platform.vendor().contains(search)) { + return platform; + } + } + } + else if (m_platformIndex < platforms.size()) { + return platforms[m_platformIndex]; + } + + return {}; +} + + +rapidjson::Value xmrig::OclConfig::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value obj(kObjectType); + + obj.AddMember(StringRef(kEnabled), m_enabled, allocator); + obj.AddMember(StringRef(kCache), m_cache, allocator); + obj.AddMember(StringRef(kLoader), m_loader.toJSON(), allocator); + obj.AddMember(StringRef(kPlatform), m_platformVendor.isEmpty() ? Value(m_platformIndex) : m_platformVendor.toJSON(), allocator); + + m_threads.toJSON(obj, doc); + + return obj; +} + + +std::vector xmrig::OclConfig::get(const Miner *miner, const Algorithm &algorithm, const OclPlatform &platform, const std::vector &devices, const char *tag) const +{ + std::vector out; + const OclThreads &threads = m_threads.get(algorithm); + + if (threads.isEmpty()) { + return out; + } + + out.reserve(threads.count() * 2); + + for (const OclThread &thread : threads.data()) { + if (thread.index() >= devices.size()) { + LOG_INFO("%s" YELLOW(" skip non-existing device with index ") YELLOW_BOLD("%u"), tag, thread.index()); + continue; + } + +# ifdef XMRIG_ALGO_RANDOMX + auto dataset = algorithm.family() == Algorithm::RANDOM_X ? std::make_shared() : nullptr; +# endif + + if (thread.threads().size() > 1) { + auto interleave = std::make_shared(thread.threads().size()); + + for (int64_t affinity : thread.threads()) { + OclLaunchData data(miner, algorithm, *this, platform, thread, devices[thread.index()], affinity); + data.interleave = interleave; + +# ifdef XMRIG_ALGO_RANDOMX + data.dataset = dataset; +# endif + + out.emplace_back(std::move(data)); + } + } + else { + OclLaunchData data(miner, algorithm, *this, platform, thread, devices[thread.index()], thread.threads().front()); + +# ifdef XMRIG_ALGO_RANDOMX + data.dataset = dataset; +# endif + + out.emplace_back(std::move(data)); + } + } + + return out; +} + + +void xmrig::OclConfig::read(const rapidjson::Value &value) +{ + if (value.IsObject()) { + m_enabled = Json::getBool(value, kEnabled, m_enabled); + m_cache = Json::getBool(value, kCache, m_cache); + m_loader = Json::getString(value, kLoader); + + setPlatform(Json::getValue(value, kPlatform)); + + if (isEnabled()) { + m_threads.read(value); + + generate(); + } + } + else if (value.IsBool() && value.IsFalse()) { + m_enabled = false; + } + else { + generate(); + } +} + + +void xmrig::OclConfig::generate() +{ + if (!OclLib::init(loader())) { + return; + } + + const auto devices = platform().devices(); + if (devices.empty()) { + return; + } + + size_t count = 0; + + count += xmrig::generate(kCn, m_threads, Algorithm::CN_0, devices); + count += xmrig::generate(kCn2, m_threads, Algorithm::CN_2, devices); + + if (!m_threads.isExist(Algorithm::CN_0)) { + m_threads.disable(Algorithm::CN_0); + count++; + } + +# ifdef XMRIG_ALGO_CN_GPU + count += xmrig::generate(kCnGPU, m_threads, Algorithm::CN_GPU, devices); +# endif + +# ifdef XMRIG_ALGO_CN_LITE + count += xmrig::generate(kCnLite, m_threads, Algorithm::CN_LITE_1, devices); + + if (!m_threads.isExist(Algorithm::CN_LITE_0)) { + m_threads.disable(Algorithm::CN_LITE_0); + count++; + } +# endif + +# ifdef XMRIG_ALGO_CN_HEAVY + count += xmrig::generate(kCnHeavy, m_threads, Algorithm::CN_HEAVY_0, devices); +# endif + +# ifdef XMRIG_ALGO_CN_PICO + count += xmrig::generate(kCnPico, m_threads, Algorithm::CN_PICO_0, devices); +# endif + +# ifdef XMRIG_ALGO_RANDOMX + count += xmrig::generate(kRx, m_threads, Algorithm::RX_0, devices); + count += xmrig::generate(kRxWOW, m_threads, Algorithm::RX_WOW, devices); +# endif + + m_shouldSave = count > 0; +} + + +void xmrig::OclConfig::setPlatform(const rapidjson::Value &platform) +{ + if (platform.IsString()) { + m_platformVendor = platform.GetString(); + } + else if (platform.IsUint()) { + m_platformVendor = nullptr; + m_platformIndex = platform.GetUint(); + } +} diff --git a/src/backend/opencl/OclConfig.h b/src/backend/opencl/OclConfig.h new file mode 100644 index 000000000..22d1378ea --- /dev/null +++ b/src/backend/opencl/OclConfig.h @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLCONFIG_H +#define XMRIG_OCLCONFIG_H + + +#include "backend/common/Threads.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclPlatform.h" + + +namespace xmrig { + + +class OclConfig +{ +public: + OclConfig(); + + OclPlatform platform() const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + std::vector get(const Miner *miner, const Algorithm &algorithm, const OclPlatform &platform, const std::vector &devices, const char *tag) const; + void read(const rapidjson::Value &value); + + inline bool isCacheEnabled() const { return m_cache; } + inline bool isEnabled() const { return m_enabled; } + inline bool isShouldSave() const { return m_shouldSave; } + inline const String &loader() const { return m_loader; } + inline const Threads &threads() const { return m_threads; } + +private: + void generate(); + void setPlatform(const rapidjson::Value &platform); + + bool m_cache = true; + bool m_enabled = true; + bool m_shouldSave = false; + String m_loader; + String m_platformVendor; + Threads m_threads; + uint32_t m_platformIndex = 0; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLCONFIG_H */ diff --git a/src/backend/opencl/OclGenerator.h b/src/backend/opencl/OclGenerator.h new file mode 100644 index 000000000..9a04a0597 --- /dev/null +++ b/src/backend/opencl/OclGenerator.h @@ -0,0 +1,43 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLGENERATOR_H +#define XMRIG_OCLGENERATOR_H + + +namespace xmrig { + + +class Algorithm; +class OclDevice; +class OclThreads; + + +using ocl_gen_config_fun = bool (*)(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); + + +} // namespace xmrig + + +#endif /* XMRIG_OCLGENERATOR_H */ diff --git a/src/backend/opencl/OclInterleave.cpp b/src/backend/opencl/OclInterleave.cpp new file mode 100644 index 000000000..d7226f416 --- /dev/null +++ b/src/backend/opencl/OclInterleave.cpp @@ -0,0 +1,118 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclInterleave.h" +#include "base/io/log/Log.h" +#include "base/tools/Chrono.h" + + +#include +#include + + +uint64_t xmrig::OclInterleave::adjustDelay(size_t id) +{ + const uint64_t t0 = Chrono::steadyMSecs(); + uint64_t delay = 0; + + { + std::lock_guard lock(m_mutex); + + const uint64_t dt = t0 - m_timestamp; + m_timestamp = t0; + + // The perfect interleaving is when N threads on the same GPU start with T/N interval between each other + // If a thread starts earlier than 0.75*T/N ms after the previous thread, delay it to restore perfect interleaving + if ((dt > 0) && (dt < m_threshold * (m_averageRunTime / m_threads))) { + delay = static_cast(m_averageRunTime / m_threads - dt); + m_threshold = 0.75; + } + } + + if (delay == 0) { + return 0; + } + + if (delay >= 400) { + delay = 200; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(delay)); + +# ifdef XMRIG_INTERLEAVE_DEBUG + LOG_WARN("Thread #%zu was paused for %" PRIu64 " ms to adjust interleaving", id, delay); +# endif + + return delay; +} + + +uint64_t xmrig::OclInterleave::resumeDelay(size_t id) +{ + uint64_t delay = 0; + + { + constexpr const double firstThreadSpeedupCoeff = 1.25; + + std::lock_guard lock(m_mutex); + delay = static_cast(m_resumeCounter * m_averageRunTime / m_threads / firstThreadSpeedupCoeff); + ++m_resumeCounter; + } + + if (delay == 0) { + return 0; + } + + if (delay > 1000) { + delay = 1000; + } + +# ifdef XMRIG_INTERLEAVE_DEBUG + LOG_WARN("Thread #%zu will be paused for %" PRIu64 " ms to before resuming", id, delay); +# endif + + std::this_thread::sleep_for(std::chrono::milliseconds(delay)); + + return delay; +} + + +void xmrig::OclInterleave::setResumeCounter(uint32_t value) +{ + std::lock_guard lock(m_mutex); + m_resumeCounter = value; +} + + +void xmrig::OclInterleave::setRunTime(uint64_t time) +{ + // averagingBias = 1.0 - only the last delta time is taken into account + // averagingBias = 0.5 - the last delta time has the same weight as all the previous ones combined + // averagingBias = 0.1 - the last delta time has 10% weight of all the previous ones combined + constexpr double averagingBias = 0.1; + + std::lock_guard lock(m_mutex); + m_averageRunTime = m_averageRunTime * (1.0 - averagingBias) + time * averagingBias; +} diff --git a/src/backend/opencl/OclInterleave.h b/src/backend/opencl/OclInterleave.h new file mode 100644 index 000000000..663272955 --- /dev/null +++ b/src/backend/opencl/OclInterleave.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLINTERLEAVE_H +#define XMRIG_OCLINTERLEAVE_H + + +#include +#include + + +namespace xmrig { + + +class OclInterleave +{ +public: + OclInterleave() = delete; + inline OclInterleave(size_t threads) : m_threads(threads) {} + + uint64_t adjustDelay(size_t id); + uint64_t resumeDelay(size_t id); + void setResumeCounter(uint32_t value); + void setRunTime(uint64_t time); + +private: + const size_t m_threads; + double m_averageRunTime = 0.0; + double m_threshold = 0.95; + std::mutex m_mutex; + uint32_t m_resumeCounter = 0; + uint64_t m_timestamp = 0; +}; + + +using OclInterleavePtr = std::shared_ptr; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLINTERLEAVE_H */ diff --git a/src/backend/opencl/OclLaunchData.cpp b/src/backend/opencl/OclLaunchData.cpp new file mode 100644 index 000000000..f09e7b195 --- /dev/null +++ b/src/backend/opencl/OclLaunchData.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/OclConfig.h" + + +xmrig::OclLaunchData::OclLaunchData(const Miner *miner, const Algorithm &algorithm, const OclConfig &config, const OclPlatform &platform, const OclThread &thread, const OclDevice &device, int64_t affinity) : + algorithm(algorithm), + cache(config.isCacheEnabled()), + affinity(affinity), + miner(miner), + device(device), + platform(platform), + thread(thread) +{ +} + + +bool xmrig::OclLaunchData::isEqual(const OclLaunchData &other) const +{ + return (other.algorithm == algorithm && + other.thread == thread); +} diff --git a/src/backend/opencl/OclLaunchData.h b/src/backend/opencl/OclLaunchData.h new file mode 100644 index 000000000..66c2aaf0f --- /dev/null +++ b/src/backend/opencl/OclLaunchData.h @@ -0,0 +1,84 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLLAUNCHDATA_H +#define XMRIG_OCLLAUNCHDATA_H + + +#include "backend/opencl/OclInterleave.h" +#include "backend/opencl/OclThread.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "backend/opencl/wrappers/OclPlatform.h" +#include "crypto/common/Algorithm.h" +#include "crypto/common/Nonce.h" + + +#ifdef XMRIG_ALGO_RANDOMX +# include "backend/opencl/runners/tools/OclRxDataset.h" +#endif + + +using cl_context = struct _cl_context *; + + +namespace xmrig { + + +class OclConfig; +class Miner; + + +class OclLaunchData +{ +public: + OclLaunchData(const Miner *miner, const Algorithm &algorithm, const OclConfig &config, const OclPlatform &platform, const OclThread &thread, const OclDevice &device, int64_t affinity); + + bool isEqual(const OclLaunchData &other) const; + + inline constexpr static Nonce::Backend backend() { return Nonce::OPENCL; } + + inline bool operator!=(const OclLaunchData &other) const { return !isEqual(other); } + inline bool operator==(const OclLaunchData &other) const { return isEqual(other); } + + cl_context ctx = nullptr; + const Algorithm algorithm; + const bool cache; + const int64_t affinity; + const Miner *miner; + const OclDevice device; + const OclPlatform platform; + const OclThread thread; + OclInterleavePtr interleave; + +# ifdef XMRIG_ALGO_RANDOMX + OclRxDatasetPtr dataset; +# endif +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLLAUNCHDATA_H */ diff --git a/src/backend/opencl/OclThread.cpp b/src/backend/opencl/OclThread.cpp new file mode 100644 index 000000000..02ef5f3b2 --- /dev/null +++ b/src/backend/opencl/OclThread.cpp @@ -0,0 +1,154 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclThread.h" + +#include "base/io/json/Json.h" +#include "rapidjson/document.h" + + +#include + + +namespace xmrig { + +static const char *kIndex = "index"; +static const char *kIntensity = "intensity"; +static const char *kStridedIndex = "strided_index"; +static const char *kThreads = "threads"; +static const char *kUnroll = "unroll"; +static const char *kWorksize = "worksize"; + +#ifdef XMRIG_ALGO_RANDOMX +static const char *kBFactor = "bfactor"; +static const char *kGCNAsm = "gcn_asm"; +static const char* kDatasetHost = "dataset_host"; +#endif + +} // namespace xmrig + + +xmrig::OclThread::OclThread(const rapidjson::Value &value) +{ + m_index = Json::getUint(value, kIndex); + m_worksize = std::max(std::min(Json::getUint(value, kWorksize), 128u), 1u); + m_unrollFactor = std::max(std::min(Json::getUint(value, kUnroll, m_unrollFactor), 128u), 1u); + + setIntensity(Json::getUint(value, kIntensity)); + + const auto &si = Json::getArray(value, kStridedIndex); + if (si.IsArray() && si.Size() >= 2) { + m_stridedIndex = std::min(si[0].GetUint(), 2u); + m_memChunk = std::min(si[1].GetUint(), 18u); + } + else { + m_stridedIndex = 0; + m_memChunk = 0; + m_fields.set(STRIDED_INDEX_FIELD, false); + } + + const auto &threads = Json::getArray(value, kThreads); + if (threads.IsArray()) { + m_threads.reserve(threads.Size()); + + for (const auto &affinity : threads.GetArray()) { + m_threads.emplace_back(affinity.GetInt64()); + } + } + + if (m_threads.empty()) { + m_threads.emplace_back(-1); + } + +# ifdef XMRIG_ALGO_RANDOMX + const auto &gcnAsm = Json::getValue(value, kGCNAsm); + if (gcnAsm.IsBool()) { + m_fields.set(RANDOMX_FIELDS, true); + + m_gcnAsm = gcnAsm.GetBool(); + m_bfactor = Json::getUint(value, kBFactor, m_bfactor); + m_datasetHost = Json::getBool(value, kDatasetHost, m_datasetHost); + } +# endif +} + + +bool xmrig::OclThread::isEqual(const OclThread &other) const +{ + return other.m_threads.size() == m_threads.size() && + std::equal(m_threads.begin(), m_threads.end(), other.m_threads.begin()) && + other.m_bfactor == m_bfactor && + other.m_datasetHost == m_datasetHost && + other.m_gcnAsm == m_gcnAsm && + other.m_index == m_index && + other.m_intensity == m_intensity && + other.m_memChunk == m_memChunk && + other.m_stridedIndex == m_stridedIndex && + other.m_unrollFactor == m_unrollFactor && + other.m_worksize == m_worksize; +} + + +rapidjson::Value xmrig::OclThread::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value out(kObjectType); + + out.AddMember(StringRef(kIndex), index(), allocator); + out.AddMember(StringRef(kIntensity), intensity(), allocator); + out.AddMember(StringRef(kWorksize), worksize(), allocator); + + if (m_fields.test(STRIDED_INDEX_FIELD)) { + Value si(kArrayType); + si.Reserve(2, allocator); + si.PushBack(stridedIndex(), allocator); + si.PushBack(memChunk(), allocator); + out.AddMember(StringRef(kStridedIndex), si, allocator); + } + + Value threads(kArrayType); + threads.Reserve(m_threads.size(), allocator); + + for (auto thread : m_threads) { + threads.PushBack(thread, allocator); + } + + out.AddMember(StringRef(kThreads), threads, allocator); + + if (m_fields.test(RANDOMX_FIELDS)) { +# ifdef XMRIG_ALGO_RANDOMX + out.AddMember(StringRef(kBFactor), bfactor(), allocator); + out.AddMember(StringRef(kGCNAsm), isAsm(), allocator); + out.AddMember(StringRef(kDatasetHost), isDatasetHost(), allocator); +# endif + } + else { + out.AddMember(StringRef(kUnroll), unrollFactor(), allocator); + } + + return out; +} diff --git a/src/backend/opencl/OclThread.h b/src/backend/opencl/OclThread.h new file mode 100644 index 000000000..1882abf7a --- /dev/null +++ b/src/backend/opencl/OclThread.h @@ -0,0 +1,131 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLTHREAD_H +#define XMRIG_OCLTHREAD_H + + +#include "crypto/common/Algorithm.h" +#include "rapidjson/fwd.h" + + +#include +#include + + +namespace xmrig { + + +class OclThread +{ +public: + OclThread() = delete; + OclThread(uint32_t index, uint32_t intensity, uint32_t worksize, uint32_t stridedIndex, uint32_t memChunk, uint32_t threads, uint32_t unrollFactor) : + m_threads(threads, -1), + m_index(index), + m_memChunk(memChunk), + m_stridedIndex(stridedIndex), + m_unrollFactor(unrollFactor), + m_worksize(worksize) + { + setIntensity(intensity); + } + +# ifdef XMRIG_ALGO_CN_GPU + OclThread(uint32_t index, uint32_t intensity, uint32_t worksize, uint32_t threads, uint32_t unrollFactor) : + m_fields(0), + m_threads(threads, -1), + m_index(index), + m_memChunk(0), + m_stridedIndex(0), + m_unrollFactor(unrollFactor), + m_worksize(worksize) + { + setIntensity(intensity); + } +# endif + +# ifdef XMRIG_ALGO_RANDOMX + OclThread(uint32_t index, uint32_t intensity, uint32_t worksize, uint32_t threads, bool gcnAsm, bool datasetHost, uint32_t bfactor) : + m_datasetHost(datasetHost), + m_gcnAsm(gcnAsm), + m_fields(2), + m_threads(threads, -1), + m_bfactor(bfactor), + m_index(index), + m_memChunk(0), + m_stridedIndex(0), + m_worksize(worksize) + { + setIntensity(intensity); + } +# endif + + OclThread(const rapidjson::Value &value); + + inline bool isAsm() const { return m_gcnAsm; } + inline bool isDatasetHost() const { return m_datasetHost; } + inline bool isValid() const { return m_intensity > 0; } + inline const std::vector &threads() const { return m_threads; } + inline uint32_t bfactor() const { return m_bfactor; } + inline uint32_t index() const { return m_index; } + inline uint32_t intensity() const { return m_intensity; } + inline uint32_t memChunk() const { return m_memChunk; } + inline uint32_t stridedIndex() const { return m_stridedIndex; } + inline uint32_t unrollFactor() const { return m_unrollFactor; } + inline uint32_t worksize() const { return m_worksize; } + + inline bool operator!=(const OclThread &other) const { return !isEqual(other); } + inline bool operator==(const OclThread &other) const { return isEqual(other); } + + bool isEqual(const OclThread &other) const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +private: + enum Fields { + STRIDED_INDEX_FIELD, + RANDOMX_FIELDS, + FIELD_MAX + }; + + inline void setIntensity(uint32_t intensity) { m_intensity = intensity / m_worksize * m_worksize; } + + bool m_datasetHost = false; + bool m_gcnAsm = true; + std::bitset m_fields = 1; + std::vector m_threads; + uint32_t m_bfactor = 6; + uint32_t m_index = 0; + uint32_t m_intensity = 0; + uint32_t m_memChunk = 2; + uint32_t m_stridedIndex = 2; + uint32_t m_unrollFactor = 8; + uint32_t m_worksize = 0; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLTHREAD_H */ diff --git a/src/backend/opencl/OclThreads.cpp b/src/backend/opencl/OclThreads.cpp new file mode 100644 index 000000000..03cd3936a --- /dev/null +++ b/src/backend/opencl/OclThreads.cpp @@ -0,0 +1,61 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "backend/opencl/OclThreads.h" +#include "base/io/json/Json.h" +#include "rapidjson/document.h" + + +xmrig::OclThreads::OclThreads(const rapidjson::Value &value) +{ + if (value.IsArray()) { + for (auto &v : value.GetArray()) { + OclThread thread(v); + if (thread.isValid()) { + add(std::move(thread)); + } + } + } +} + + +rapidjson::Value xmrig::OclThreads::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + Value out(kArrayType); + + out.SetArray(); + + for (const OclThread &thread : m_data) { + out.PushBack(thread.toJSON(doc), allocator); + } + + return out; +} diff --git a/src/backend/opencl/OclThreads.h b/src/backend/opencl/OclThreads.h new file mode 100644 index 000000000..1ca4c70a1 --- /dev/null +++ b/src/backend/opencl/OclThreads.h @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLTHREADS_H +#define XMRIG_OCLTHREADS_H + + +#include + + +#include "backend/opencl/OclThread.h" + + +namespace xmrig { + + +class OclThreads +{ +public: + OclThreads() = default; + OclThreads(const rapidjson::Value &value); + + inline bool isEmpty() const { return m_data.empty(); } + inline const std::vector &data() const { return m_data; } + inline size_t count() const { return m_data.size(); } + inline void add(OclThread &&thread) { m_data.push_back(thread); } + inline void reserve(size_t capacity) { m_data.reserve(capacity); } + + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +private: + std::vector m_data; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLTHREADS_H */ diff --git a/src/backend/opencl/OclWorker.cpp b/src/backend/opencl/OclWorker.cpp new file mode 100644 index 000000000..4247fb786 --- /dev/null +++ b/src/backend/opencl/OclWorker.cpp @@ -0,0 +1,235 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclWorker.h" + +#include "backend/common/Tags.h" +#include "backend/opencl/runners/OclCnRunner.h" +#include "base/io/log/Log.h" +#include "base/tools/Chrono.h" +#include "core/Miner.h" +#include "crypto/common/Nonce.h" +#include "net/JobResults.h" + + +#ifdef XMRIG_ALGO_RANDOMX +# include "backend/opencl/runners/OclRxJitRunner.h" +# include "backend/opencl/runners/OclRxVmRunner.h" +#endif + +#ifdef XMRIG_ALGO_CN_GPU +# include "backend/opencl/runners/OclRyoRunner.h" +#endif + + +#include +#include + + +namespace xmrig { + + +static constexpr uint32_t kReserveCount = 32768; +std::atomic OclWorker::ready; + + +static inline bool isReady() { return !Nonce::isPaused() && OclWorker::ready; } +static inline uint32_t roundSize(uint32_t intensity) { return kReserveCount / intensity + 1; } + + +static inline void printError(size_t id, const char *error) +{ + LOG_ERR("%s" RED_S " thread " RED_BOLD("#%zu") RED_S " failed with error " RED_BOLD("%s"), ocl_tag(), id, error); +} + + +} // namespace xmrig + + + +xmrig::OclWorker::OclWorker(size_t id, const OclLaunchData &data) : + Worker(id, data.affinity, -1), + m_algorithm(data.algorithm), + m_miner(data.miner), + m_intensity(data.thread.intensity()), + m_interleave(data.interleave) +{ + switch (m_algorithm.family()) { + case Algorithm::RANDOM_X: +# ifdef XMRIG_ALGO_RANDOMX + if (data.thread.isAsm() && data.device.vendorId() == OCL_VENDOR_AMD) { + m_runner = new OclRxJitRunner(id, data); + } + else { + m_runner = new OclRxVmRunner(id, data); + } +# endif + break; + + case Algorithm::ARGON2: +# ifdef XMRIG_ALGO_ARGON2 + m_runner = nullptr; // TODO OclArgon2Runner +# endif + break; + + default: +# ifdef XMRIG_ALGO_CN_GPU + if (m_algorithm == Algorithm::CN_GPU) { + m_runner = new OclRyoRunner(id, data); + } + else +# endif + { + m_runner = new OclCnRunner(id, data); + } + break; + } + + if (!m_runner) { + return; + } + + try { + m_runner->init(); + m_runner->build(); + } + catch (std::exception &ex) { + printError(id, ex.what()); + + delete m_runner; + m_runner = nullptr; + } +} + + +xmrig::OclWorker::~OclWorker() +{ + delete m_runner; +} + + +bool xmrig::OclWorker::selfTest() +{ + return m_runner != nullptr; +} + + +void xmrig::OclWorker::start() +{ + cl_uint results[0x100]; + + while (Nonce::sequence(Nonce::OPENCL) > 0) { + if (!isReady()) { + if (m_interleave) { + m_interleave->setResumeCounter(0); + } + + do { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + while (!isReady() && Nonce::sequence(Nonce::OPENCL) > 0); + + if (Nonce::sequence(Nonce::OPENCL) == 0) { + break; + } + + if (m_interleave) { + m_interleave->resumeDelay(m_id); + } + + if (!consumeJob()) { + return; + } + } + + while (!Nonce::isOutdated(Nonce::OPENCL, m_job.sequence())) { + if (m_interleave) { + m_interleave->adjustDelay(m_id); + } + + const uint64_t t = Chrono::steadyMSecs(); + + try { + m_runner->run(*m_job.nonce(), results); + } + catch (std::exception &ex) { + printError(id(), ex.what()); + + return; + } + + if (results[0xFF] > 0) { + JobResults::submit(m_job.currentJob(), results, results[0xFF]); + } + + m_job.nextRound(roundSize(m_intensity), m_intensity); + + storeStats(t); + std::this_thread::yield(); + } + + if (!consumeJob()) { + return; + } + } +} + + +bool xmrig::OclWorker::consumeJob() +{ + if (Nonce::sequence(Nonce::OPENCL) == 0) { + return false; + } + + m_job.add(m_miner->job(), Nonce::sequence(Nonce::OPENCL), roundSize(m_intensity) * m_intensity); + + try { + m_runner->set(m_job.currentJob(), m_job.blob()); + } + catch (std::exception &ex) { + printError(id(), ex.what()); + + return false; + } + + return true; +} + + +void xmrig::OclWorker::storeStats(uint64_t t) +{ + if (!isReady()) { + return; + } + + m_count += m_intensity; + + if (m_interleave) { + m_interleave->setRunTime(Chrono::steadyMSecs() - t); + } + + Worker::storeStats(); +} diff --git a/src/backend/opencl/OclWorker.h b/src/backend/opencl/OclWorker.h new file mode 100644 index 000000000..e28c784dc --- /dev/null +++ b/src/backend/opencl/OclWorker.h @@ -0,0 +1,77 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLWORKER_H +#define XMRIG_OCLWORKER_H + + +#include "backend/common/Worker.h" +#include "backend/common/WorkerJob.h" +#include "backend/opencl/OclLaunchData.h" +#include "net/JobResult.h" + + +namespace xmrig { + + +class IOclRunner; + + +class OclWorker : public Worker +{ +public: + OclWorker() = delete; + OclWorker(const OclWorker &other) = delete; + OclWorker(OclWorker &&other) = delete; + OclWorker(size_t id, const OclLaunchData &data); + + ~OclWorker() override; + + OclWorker &operator=(const OclWorker &other) = delete; + OclWorker &operator=(OclWorker &&other) = delete; + + static std::atomic ready; + +protected: + bool selfTest() override; + void start() override; + +private: + bool consumeJob(); + void storeStats(uint64_t ts); + + const Algorithm m_algorithm; + const Miner *m_miner; + const uint32_t m_intensity; + IOclRunner *m_runner = nullptr; + OclInterleavePtr m_interleave; + WorkerJob<1> m_job; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLWORKER_H */ diff --git a/src/backend/opencl/cl/OclSource.cpp b/src/backend/opencl/cl/OclSource.cpp new file mode 100644 index 000000000..5f569d496 --- /dev/null +++ b/src/backend/opencl/cl/OclSource.cpp @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/cl/OclSource.h" + +#include "backend/opencl/cl/cn/cryptonight_cl.h" +#include "crypto/common/Algorithm.h" + + +#ifdef XMRIG_ALGO_CN_GPU +# include "backend/opencl/cl/cn/cryptonight_gpu_cl.h" +#endif + +#ifdef XMRIG_ALGO_RANDOMX +# include "backend/opencl/cl/rx/randomx_cl.h" +#endif + + +const char *xmrig::OclSource::get(const Algorithm &algorithm) +{ +# ifdef XMRIG_ALGO_RANDOMX + if (algorithm.family() == Algorithm::RANDOM_X) { + return randomx_cl; + } +# endif + +# ifdef XMRIG_ALGO_CN_GPU + if (algorithm == Algorithm::CN_GPU) { + return cryptonight_gpu_cl; + } +# endif + + return cryptonight_cl; +} diff --git a/src/backend/opencl/cl/OclSource.h b/src/backend/opencl/cl/OclSource.h new file mode 100644 index 000000000..40b70810a --- /dev/null +++ b/src/backend/opencl/cl/OclSource.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLSOURCE_H +#define XMRIG_OCLSOURCE_H + + +namespace xmrig { + + +class Algorithm; + + +class OclSource +{ +public: + static const char *get(const Algorithm &algorithm); + static void init(); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLSOURCE_H */ diff --git a/src/backend/opencl/cl/cn/algorithm.cl b/src/backend/opencl/cl/cn/algorithm.cl new file mode 100644 index 000000000..af7730121 --- /dev/null +++ b/src/backend/opencl/cl/cn/algorithm.cl @@ -0,0 +1,31 @@ +#define ALGO_CN_0 0 +#define ALGO_CN_1 1 +#define ALGO_CN_2 2 +#define ALGO_CN_R 3 +#define ALGO_CN_FAST 4 +#define ALGO_CN_HALF 5 +#define ALGO_CN_XAO 6 +#define ALGO_CN_RTO 7 +#define ALGO_CN_RWZ 8 +#define ALGO_CN_ZLS 9 +#define ALGO_CN_DOUBLE 10 +#define ALGO_CN_GPU 11 +#define ALGO_CN_LITE_0 12 +#define ALGO_CN_LITE_1 13 +#define ALGO_CN_HEAVY_0 14 +#define ALGO_CN_HEAVY_TUBE 15 +#define ALGO_CN_HEAVY_XHV 16 +#define ALGO_CN_PICO_0 17 +#define ALGO_RX_0 18 +#define ALGO_RX_WOW 19 +#define ALGO_RX_LOKI 20 +#define ALGO_AR2_CHUKWA 21 +#define ALGO_AR2_WRKZ 22 + +#define FAMILY_UNKNOWN 0 +#define FAMILY_CN 1 +#define FAMILY_CN_LITE 2 +#define FAMILY_CN_HEAVY 3 +#define FAMILY_CN_PICO 4 +#define FAMILY_RANDOM_X 5 +#define FAMILY_ARGON2 6 diff --git a/src/backend/opencl/cl/cn/blake256.cl b/src/backend/opencl/cl/cn/blake256.cl new file mode 100644 index 000000000..72d0ac3d4 --- /dev/null +++ b/src/backend/opencl/cl/cn/blake256.cl @@ -0,0 +1,91 @@ +/* +* blake256 kernel implementation. +* +* ==========================(LICENSE BEGIN)============================ +* Copyright (c) 2014 djm34 +* Copyright (c) 2014 tpruvot +* 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. +* +* ===========================(LICENSE END)============================= +* +* @author djm34 +*/ +__constant static const int sigma[16][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } +}; + + +__constant static const sph_u32 c_IV256[8] = { + 0x6A09E667, 0xBB67AE85, + 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, + 0x1F83D9AB, 0x5BE0CD19 +}; + +/* Second part (64-80) msg never change, store it */ +__constant static const sph_u32 c_Padding[16] = { + 0, 0, 0, 0, + 0x80000000, 0, 0, 0, + 0, 0, 0, 0, + 0, 1, 0, 640, +}; +__constant static const sph_u32 c_u256[16] = { + 0x243F6A88, 0x85A308D3, + 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, + 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, + 0x3F84D5B5, 0xB5470917 +}; + +#define GS(a,b,c,d,x) { \ + const sph_u32 idx1 = sigma[r][x]; \ + const sph_u32 idx2 = sigma[r][x+1]; \ + v[a] += (m[idx1] ^ c_u256[idx2]) + v[b]; \ + v[d] ^= v[a]; \ + v[d] = rotate(v[d], 16U); \ + v[c] += v[d]; \ + v[b] ^= v[c]; \ + v[b] = rotate(v[b], 20U); \ +\ + v[a] += (m[idx2] ^ c_u256[idx1]) + v[b]; \ + v[d] ^= v[a]; \ + v[d] = rotate(v[d], 24U); \ + v[c] += v[d]; \ + v[b] ^= v[c]; \ + v[b] = rotate(v[b], 25U); \ +} diff --git a/src/backend/opencl/cl/cn/cryptonight.cl b/src/backend/opencl/cl/cn/cryptonight.cl new file mode 100644 index 000000000..f5f976b62 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight.cl @@ -0,0 +1,1068 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* For Mesa clover support */ +#ifdef cl_clang_storage_class_specifiers +# pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable +#endif + + +#include "algorithm.cl" +#include "wolf-aes.cl" +#include "wolf-skein.cl" +#include "jh.cl" +#include "blake256.cl" +#include "groestl256.cl" +#include "fast_int_math_v2.cl" +#include "fast_div_heavy.cl" +#include "keccak.cl" + + +#if defined(__NV_CL_C_VERSION) && STRIDED_INDEX != 0 +# undef STRIDED_INDEX +# define STRIDED_INDEX 0 +#endif + + +#define MEM_CHUNK (1 << MEM_CHUNK_EXPONENT) + + +#if (STRIDED_INDEX == 0) +# define IDX(x) (x) +#elif (STRIDED_INDEX == 1) +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) +# define IDX(x) ((x) * WORKSIZE) +# else +# define IDX(x) mul24((x), Threads) +# endif +#elif (STRIDED_INDEX == 2) +# define IDX(x) (((x) % MEM_CHUNK) + ((x) / MEM_CHUNK) * WORKSIZE * MEM_CHUNK) +#endif + + +inline ulong getIdx() +{ + return get_global_id(0) - get_global_offset(0); +} + + +#define mix_and_propagate(xin) (xin)[(get_local_id(1)) % 8][get_local_id(0)] ^ (xin)[(get_local_id(1) + 1) % 8][get_local_id(0)] + + +__attribute__((reqd_work_group_size(8, 8, 1))) +__kernel void cn0(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +{ + uint ExpandedKey1[40]; + __local uint AES0[256], AES1[256], AES2[256], AES3[256]; + uint4 text; + + const uint gIdx = getIdx(); + + for (int i = get_local_id(1) * 8 + get_local_id(0); i < 256; i += 8 * 8) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + AES2[i] = rotate(tmp, 16U); + AES3[i] = rotate(tmp, 24U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + __local ulong State_buf[8 * 25]; + + { + states += 25 * gIdx; + +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + Scratchpad += (gIdx / WORKSIZE) * (MEMORY >> 4) * WORKSIZE + (gIdx % WORKSIZE); +# else + Scratchpad += gIdx; +# endif +# elif (STRIDED_INDEX == 2) + Scratchpad += (gIdx / WORKSIZE) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * (gIdx % WORKSIZE); +# endif + + if (get_local_id(1) == 0) { + __local ulong* State = State_buf + get_local_id(0) * 25; + + ((__local ulong8 *)State)[0] = vload8(0, input); + State[8] = input[8]; + State[9] = input[9]; + State[10] = input[10]; + State[11] = input[11]; + State[12] = input[12]; + State[13] = input[13]; + State[14] = input[14]; + State[15] = input[15]; + + ((__local uint *)State)[9] &= 0x00FFFFFFU; + ((__local uint *)State)[9] |= (((uint)get_global_id(0)) & 0xFF) << 24; + ((__local uint *)State)[10] &= 0xFF000000U; + /* explicit cast to `uint` is required because some OpenCL implementations (e.g. NVIDIA) + * handle get_global_id and get_global_offset as signed long long int and add + * 0xFFFFFFFF... to `get_global_id` if we set on host side a 32bit offset where the first bit is `1` + * (even if it is correct casted to unsigned on the host) + */ + ((__local uint *)State)[10] |= (((uint)get_global_id(0) >> 8)); + + // Last bit of padding + State[16] = 0x8000000000000000UL; + + for (int i = 17; i < 25; ++i) { + State[i] = 0x00UL; + } + + keccakf1600_2(State); + + #pragma unroll 1 + for (int i = 0; i < 25; ++i) { + states[i] = State[i]; + } + } + } + + barrier(CLK_GLOBAL_MEM_FENCE); + + { + text = vload4(get_local_id(1) + 4, (__global uint *)(states)); + + #pragma unroll + for (int i = 0; i < 4; ++i) { + ((ulong *)ExpandedKey1)[i] = states[i]; + } + + AESExpandKey256(ExpandedKey1); + } + + mem_fence(CLK_LOCAL_MEM_FENCE); + +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + __local uint4 xin[8][8]; + + /* Also left over threads perform this loop. + * The left over thread results will be ignored + */ + #pragma unroll 16 + for (size_t i = 0; i < 16; i++) { + #pragma unroll 10 + for (int j = 0; j < 10; ++j) { + uint4 t = ((uint4 *)ExpandedKey1)[j]; + t.s0 ^= AES0[BYTE(text.s0, 0)] ^ AES1[BYTE(text.s1, 1)] ^ AES2[BYTE(text.s2, 2)] ^ AES3[BYTE(text.s3, 3)]; + t.s1 ^= AES0[BYTE(text.s1, 0)] ^ AES1[BYTE(text.s2, 1)] ^ AES2[BYTE(text.s3, 2)] ^ AES3[BYTE(text.s0, 3)]; + t.s2 ^= AES0[BYTE(text.s2, 0)] ^ AES1[BYTE(text.s3, 1)] ^ AES2[BYTE(text.s0, 2)] ^ AES3[BYTE(text.s1, 3)]; + t.s3 ^= AES0[BYTE(text.s3, 0)] ^ AES1[BYTE(text.s0, 1)] ^ AES2[BYTE(text.s1, 2)] ^ AES3[BYTE(text.s2, 3)]; + text = t; + } + + barrier(CLK_LOCAL_MEM_FENCE); + xin[get_local_id(1)][get_local_id(0)] = text; + barrier(CLK_LOCAL_MEM_FENCE); + text = mix_and_propagate(xin); + } +# endif + + { + const uint local_id1 = get_local_id(1); + #pragma unroll 2 + for(uint i = 0; i < (MEMORY >> 4); i += 8) { + #pragma unroll 10 + for (uint j = 0; j < 10; ++j) { + uint4 t = ((uint4 *)ExpandedKey1)[j]; + t.s0 ^= AES0[BYTE(text.s0, 0)] ^ AES1[BYTE(text.s1, 1)] ^ AES2[BYTE(text.s2, 2)] ^ AES3[BYTE(text.s3, 3)]; + t.s1 ^= AES0[BYTE(text.s1, 0)] ^ AES1[BYTE(text.s2, 1)] ^ AES2[BYTE(text.s3, 2)] ^ AES3[BYTE(text.s0, 3)]; + t.s2 ^= AES0[BYTE(text.s2, 0)] ^ AES1[BYTE(text.s3, 1)] ^ AES2[BYTE(text.s0, 2)] ^ AES3[BYTE(text.s1, 3)]; + t.s3 ^= AES0[BYTE(text.s3, 0)] ^ AES1[BYTE(text.s0, 1)] ^ AES2[BYTE(text.s1, 2)] ^ AES3[BYTE(text.s2, 3)]; + text = t; + } + + Scratchpad[IDX(i + local_id1)] = text; + } + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} + + +#if (ALGO_BASE == ALGO_CN_0) +__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) +__kernel void cn1(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +{ + ulong a[2], b[2]; + __local uint AES0[256], AES1[256]; + + const ulong gIdx = getIdx(); + + for (int i = get_local_id(0); i < 256; i += WORKSIZE) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + uint4 b_x; + + { + states += 25 * gIdx; +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + get_local_id(0); +# else + Scratchpad += gIdx; +# endif +# elif (STRIDED_INDEX == 2) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * get_local_id(0); +# endif + + a[0] = states[0] ^ states[4]; + b[0] = states[2] ^ states[6]; + a[1] = states[1] ^ states[5]; + b[1] = states[3] ^ states[7]; + + b_x = ((uint4 *)b)[0]; + } + + mem_fence(CLK_LOCAL_MEM_FENCE); + + { + uint idx0 = a[0]; + + #pragma unroll CN_UNROLL + for (int i = 0; i < ITERATIONS; ++i) { + ulong c[2]; + + ((uint4 *)c)[0] = Scratchpad[IDX((idx0 & MASK) >> 4)]; + ((uint4 *)c)[0] = AES_Round_Two_Tables(AES0, AES1, ((uint4 *)c)[0], ((uint4 *)a)[0]); + + Scratchpad[IDX((idx0 & MASK) >> 4)] = b_x ^ ((uint4 *)c)[0]; + + uint4 tmp; + tmp = Scratchpad[IDX((as_uint2(c[0]).s0 & MASK) >> 4)]; + + a[1] += c[0] * as_ulong2(tmp).s0; + a[0] += mul_hi(c[0], as_ulong2(tmp).s0); + + Scratchpad[IDX((as_uint2(c[0]).s0 & MASK) >> 4)] = ((uint4 *)a)[0]; + + ((uint4 *)a)[0] ^= tmp; + idx0 = a[0]; + + b_x = ((uint4 *)c)[0]; + +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + { + const long2 n = *((__global long2*)(Scratchpad + (IDX((idx0 & MASK) >> 4)))); + long q = fast_div_heavy(n.s0, as_int4(n).s2 | 0x5); + *((__global long*)(Scratchpad + (IDX((idx0 & MASK) >> 4)))) = n.s0 ^ q; + +# if (ALGO == ALGO_CN_HEAVY_XHV) + idx0 = (~as_int4(n).s2) ^ q; +# else + idx0 = as_int4(n).s2 ^ q; +# endif + } +# endif + } + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} +#elif (ALGO_BASE == ALGO_CN_1) +#define VARIANT1_1(p) \ + uint table = 0x75310U; \ + uint index = (((p).s2 >> 26) & 12) | (((p).s2 >> 23) & 2); \ + (p).s2 ^= ((table >> index) & 0x30U) << 24 + + +#define VARIANT1_2(p) ((uint2 *)&(p))[0] ^= tweak1_2_0 + + +#define VARIANT1_INIT() \ + tweak1_2 = as_uint2(input[4]); \ + tweak1_2.s0 >>= 24; \ + tweak1_2.s0 |= tweak1_2.s1 << 8; \ + tweak1_2.s1 = (uint) get_global_id(0); \ + tweak1_2 ^= as_uint2(states[24]) + + +__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) +__kernel void cn1(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +{ + ulong a[2], b[2]; + __local uint AES0[256], AES1[256]; + + const ulong gIdx = getIdx(); + + for (int i = get_local_id(0); i < 256; i += WORKSIZE) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + uint2 tweak1_2; + uint4 b_x; + + { + states += 25 * gIdx; +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + get_local_id(0); +# else + Scratchpad += gIdx; +# endif +# elif (STRIDED_INDEX == 2) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * get_local_id(0); +# endif + + a[0] = states[0] ^ states[4]; + b[0] = states[2] ^ states[6]; + a[1] = states[1] ^ states[5]; + b[1] = states[3] ^ states[7]; + + b_x = ((uint4 *)b)[0]; + VARIANT1_INIT(); + } + + mem_fence(CLK_LOCAL_MEM_FENCE); + + { +# if (ALGO == ALGO_CN_HEAVY_TUBE) + uint idx0 = a[0]; +# define IDX_0 idx0 +# else +# define IDX_0 as_uint2(a[0]).s0 +# endif + + #pragma unroll CN_UNROLL + for (int i = 0; i < ITERATIONS; ++i) { + ulong c[2]; + + ((uint4 *)c)[0] = Scratchpad[IDX((IDX_0 & MASK) >> 4)]; + +# if (ALGO == ALGO_CN_HEAVY_TUBE) + ((uint4 *)c)[0] = AES_Round_bittube2(AES0, AES1, ((uint4 *)c)[0], ((uint4 *)a)[0]); +# else + ((uint4 *)c)[0] = AES_Round_Two_Tables(AES0, AES1, ((uint4 *)c)[0], ((uint4 *)a)[0]); +# endif + + b_x ^= ((uint4 *)c)[0]; + VARIANT1_1(b_x); + + Scratchpad[IDX((IDX_0 & MASK) >> 4)] = b_x; + + uint4 tmp; + tmp = Scratchpad[IDX((as_uint2(c[0]).s0 & MASK) >> 4)]; + + a[1] += c[0] * as_ulong2(tmp).s0; + a[0] += mul_hi(c[0], as_ulong2(tmp).s0); + + uint2 tweak1_2_0 = tweak1_2; +# if (ALGO == ALGO_CN_RTO || ALGO == ALGO_CN_HEAVY_TUBE) + tweak1_2_0 ^= ((uint2 *)&(a[0]))[0]; +# endif + + VARIANT1_2(a[1]); + Scratchpad[IDX((as_uint2(c[0]).s0 & MASK) >> 4)] = ((uint4 *)a)[0]; + VARIANT1_2(a[1]); + + ((uint4 *)a)[0] ^= tmp; + +# if (ALGO == ALGO_CN_HEAVY_TUBE) + idx0 = a[0]; +# endif + + b_x = ((uint4 *)c)[0]; + +# if (ALGO == ALGO_CN_HEAVY_TUBE) + { + const long2 n = *((__global long2*)(Scratchpad + (IDX((idx0 & MASK) >> 4)))); + long q = fast_div_heavy(n.s0, as_int4(n).s2 | 0x5); + *((__global long*)(Scratchpad + (IDX((idx0 & MASK) >> 4)))) = n.s0 ^ q; + idx0 = as_int4(n).s2 ^ q; + } +# endif + } + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} + +#undef IDX_0 +#elif (ALGO_BASE == ALGO_CN_2) +__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) +__kernel void cn1(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +{ + ulong a[2], b[4]; + __local uint AES0[256], AES1[256], AES2[256], AES3[256]; + + const ulong gIdx = getIdx(); + + for(int i = get_local_id(0); i < 256; i += WORKSIZE) + { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + AES2[i] = rotate(tmp, 16U); + AES3[i] = rotate(tmp, 24U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + states += 25 * gIdx; + +# if defined(__NV_CL_C_VERSION) + Scratchpad += gIdx * (ITERATIONS >> 2); +# else +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) + Scratchpad += gIdx; +# elif (STRIDED_INDEX == 2) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * get_local_id(0); +# endif +# endif + + a[0] = states[0] ^ states[4]; + a[1] = states[1] ^ states[5]; + + b[0] = states[2] ^ states[6]; + b[1] = states[3] ^ states[7]; + b[2] = states[8] ^ states[10]; + b[3] = states[9] ^ states[11]; + } + + ulong2 bx0 = ((ulong2 *)b)[0]; + ulong2 bx1 = ((ulong2 *)b)[1]; + + mem_fence(CLK_LOCAL_MEM_FENCE); + +# ifdef __NV_CL_C_VERSION + __local uint16 scratchpad_line_buf[WORKSIZE]; + __local uint16* scratchpad_line = scratchpad_line_buf + get_local_id(0); +# define SCRATCHPAD_CHUNK(N) (*(__local uint4*)((__local uchar*)(scratchpad_line) + (idx1 ^ (N << 4)))) +# else +# if (STRIDED_INDEX == 0) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + (idx ^ (N << 4)))) +# elif (STRIDED_INDEX == 1) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + mul24(as_uint(idx ^ (N << 4)), Threads))) +# elif (STRIDED_INDEX == 2) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + (((idx ^ (N << 4)) % (MEM_CHUNK << 4)) + ((idx ^ (N << 4)) / (MEM_CHUNK << 4)) * WORKSIZE * (MEM_CHUNK << 4)))) +# endif +# endif + + { + uint2 division_result = as_uint2(states[12]); + uint sqrt_result = as_uint2(states[13]).s0; + + #pragma unroll CN_UNROLL + for (int i = 0; i < ITERATIONS; ++i) { +# ifdef __NV_CL_C_VERSION + uint idx = a[0] & 0x1FFFC0; + uint idx1 = a[0] & 0x30; + + *scratchpad_line = *(__global uint16*)((__global uchar*)(Scratchpad) + idx); +# else + uint idx = a[0] & MASK; +# endif + + uint4 c = SCRATCHPAD_CHUNK(0); + c = AES_Round(AES0, AES1, AES2, AES3, c, ((uint4 *)a)[0]); + + { +# if (ALGO == ALGO_CN_RWZ) + const ulong2 chunk1 = as_ulong2(SCRATCHPAD_CHUNK(3)); + const ulong2 chunk2 = as_ulong2(SCRATCHPAD_CHUNK(2)); + const ulong2 chunk3 = as_ulong2(SCRATCHPAD_CHUNK(1)); +# else + const ulong2 chunk1 = as_ulong2(SCRATCHPAD_CHUNK(1)); + const ulong2 chunk2 = as_ulong2(SCRATCHPAD_CHUNK(2)); + const ulong2 chunk3 = as_ulong2(SCRATCHPAD_CHUNK(3)); +# endif + + SCRATCHPAD_CHUNK(1) = as_uint4(chunk3 + bx1); + SCRATCHPAD_CHUNK(2) = as_uint4(chunk1 + bx0); + SCRATCHPAD_CHUNK(3) = as_uint4(chunk2 + ((ulong2 *)a)[0]); + } + + SCRATCHPAD_CHUNK(0) = as_uint4(bx0) ^ c; + +# ifdef __NV_CL_C_VERSION + *(__global uint16*)((__global uchar*)(Scratchpad) + idx) = *scratchpad_line; + + idx = as_ulong2(c).s0 & 0x1FFFC0; + idx1 = as_ulong2(c).s0 & 0x30; + + *scratchpad_line = *(__global uint16*)((__global uchar*)(Scratchpad) + idx); +# else + idx = as_ulong2(c).s0 & MASK; +# endif + + uint4 tmp = SCRATCHPAD_CHUNK(0); + + { + tmp.s0 ^= division_result.s0; + tmp.s1 ^= division_result.s1 ^ sqrt_result; + + division_result = fast_div_v2(as_ulong2(c).s1, (c.s0 + (sqrt_result << 1)) | 0x80000001UL); + sqrt_result = fast_sqrt_v2(as_ulong2(c).s0 + as_ulong(division_result)); + } + + ulong2 t; + t.s0 = mul_hi(as_ulong2(c).s0, as_ulong2(tmp).s0); + t.s1 = as_ulong2(c).s0 * as_ulong2(tmp).s0; + { + const ulong2 chunk1 = as_ulong2(SCRATCHPAD_CHUNK(1)) ^ t; + const ulong2 chunk2 = as_ulong2(SCRATCHPAD_CHUNK(2)); + t ^= chunk2; + const ulong2 chunk3 = as_ulong2(SCRATCHPAD_CHUNK(3)); + +# if (ALGO == ALGO_CN_RWZ) + SCRATCHPAD_CHUNK(1) = as_uint4(chunk1 + bx1); + SCRATCHPAD_CHUNK(2) = as_uint4(chunk3 + bx0); + SCRATCHPAD_CHUNK(3) = as_uint4(chunk2 + ((ulong2 *)a)[0]); +# else + SCRATCHPAD_CHUNK(1) = as_uint4(chunk3 + bx1); + SCRATCHPAD_CHUNK(2) = as_uint4(chunk1 + bx0); + SCRATCHPAD_CHUNK(3) = as_uint4(chunk2 + ((ulong2 *)a)[0]); +# endif + } + + a[1] += t.s1; + a[0] += t.s0; + + SCRATCHPAD_CHUNK(0) = ((uint4 *)a)[0]; + +# ifdef __NV_CL_C_VERSION + *(__global uint16*)((__global uchar*)(Scratchpad) + idx) = *scratchpad_line; +# endif + + ((uint4 *)a)[0] ^= tmp; + bx1 = bx0; + bx0 = as_ulong2(c); + } + +# undef SCRATCHPAD_CHUNK + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} +#endif + + +__attribute__((reqd_work_group_size(8, 8, 1))) +__kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3, uint Threads) +{ + __local uint AES0[256], AES1[256], AES2[256], AES3[256]; + uint ExpandedKey2[40]; + uint4 text; + + const ulong gIdx = getIdx(); + + for (int i = get_local_id(1) * 8 + get_local_id(0); i < 256; i += 8 * 8) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + AES2[i] = rotate(tmp, 16U); + AES3[i] = rotate(tmp, 24U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + states += 25 * gIdx; +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + Scratchpad += (gIdx / WORKSIZE) * (MEMORY >> 4) * WORKSIZE + (gIdx % WORKSIZE); +# else + Scratchpad += gIdx; +# endif +# elif (STRIDED_INDEX == 2) + Scratchpad += (gIdx / WORKSIZE) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * (gIdx % WORKSIZE); +# endif + + #if defined(__Tahiti__) || defined(__Pitcairn__) + + for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = states[i + 4]; + text = vload4(get_local_id(1) + 4, (__global uint *)states); + + #else + + text = vload4(get_local_id(1) + 4, (__global uint *)states); + ((uint8 *)ExpandedKey2)[0] = vload8(1, (__global uint *)states); + + #endif + + AESExpandKey256(ExpandedKey2); + } + + barrier(CLK_LOCAL_MEM_FENCE); + +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + __local uint4 xin1[8][8]; + __local uint4 xin2[8][8]; + __local uint4* xin1_store = &xin1[get_local_id(1)][get_local_id(0)]; + __local uint4* xin1_load = &xin1[(get_local_id(1) + 1) % 8][get_local_id(0)]; + __local uint4* xin2_store = &xin2[get_local_id(1)][get_local_id(0)]; + __local uint4* xin2_load = &xin2[(get_local_id(1) + 1) % 8][get_local_id(0)]; + *xin2_store = (uint4)(0, 0, 0, 0); +# endif + + { +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + #pragma unroll 2 + for(int i = 0, i1 = get_local_id(1); i < (MEMORY >> 7); ++i, i1 = (i1 + 16) % (MEMORY >> 4)) + { + text ^= Scratchpad[IDX(i1)]; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin2_load; + + #pragma unroll 10 + for(int j = 0; j < 10; ++j) + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + + *xin1_store = text; + + text ^= Scratchpad[IDX(i1 + 8)]; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin1_load; + + #pragma unroll 10 + for(int j = 0; j < 10; ++j) + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + + *xin2_store = text; + } + + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin2_load; + +# else + const uint local_id1 = get_local_id(1); + #pragma unroll 2 + for (uint i = 0; i < (MEMORY >> 7); ++i) { + text ^= Scratchpad[IDX((i << 3) + local_id1)]; + + #pragma unroll 10 + for(uint j = 0; j < 10; ++j) + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + } +# endif + } + +# if (ALGO_FAMILY == FAMILY_CN_HEAVY) + /* Also left over threads performe this loop. + * The left over thread results will be ignored + */ + #pragma unroll 16 + for(size_t i = 0; i < 16; i++) + { + #pragma unroll 10 + for (int j = 0; j < 10; ++j) { + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + } + + barrier(CLK_LOCAL_MEM_FENCE); + *xin1_store = text; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin1_load; + } +# endif + + { + vstore2(as_ulong2(text), get_local_id(1) + 4, states); + } + + barrier(CLK_GLOBAL_MEM_FENCE); + + __local ulong State_buf[8 * 25]; + + { + if(!get_local_id(1)) + { + __local ulong* State = State_buf + get_local_id(0) * 25; + + for(int i = 0; i < 25; ++i) State[i] = states[i]; + + keccakf1600_2(State); + + for(int i = 0; i < 25; ++i) states[i] = State[i]; + + uint StateSwitch = State[0] & 3; + __global uint *destinationBranch1 = StateSwitch == 0 ? Branch0 : Branch1; + __global uint *destinationBranch2 = StateSwitch == 2 ? Branch2 : Branch3; + __global uint *destinationBranch = StateSwitch < 2 ? destinationBranch1 : destinationBranch2; + destinationBranch[atomic_inc(destinationBranch + Threads)] = gIdx; + } + } + mem_fence(CLK_GLOBAL_MEM_FENCE); +} + + +#define VSWAP8(x) (((x) >> 56) | (((x) >> 40) & 0x000000000000FF00UL) | (((x) >> 24) & 0x0000000000FF0000UL) \ + | (((x) >> 8) & 0x00000000FF000000UL) | (((x) << 8) & 0x000000FF00000000UL) \ + | (((x) << 24) & 0x0000FF0000000000UL) | (((x) << 40) & 0x00FF000000000000UL) | (((x) << 56) & 0xFF00000000000000UL)) + + +#define VSWAP4(x) ((((x) >> 24) & 0xFFU) | (((x) >> 8) & 0xFF00U) | (((x) << 8) & 0xFF0000U) | (((x) << 24) & 0xFF000000U)) + + +__kernel void Skein(__global ulong *states, __global uint *BranchBuf, __global uint *output, ulong Target, uint Threads) +{ + const uint idx = get_global_id(0) - get_global_offset(0); + + // do not use early return here + if(idx < BranchBuf[Threads]) { + states += 25 * BranchBuf[idx]; + + // skein + ulong8 h = vload8(0, SKEIN512_256_IV); + + // Type field begins with final bit, first bit, then six bits of type; the last 96 + // bits are input processed (including in the block to be processed with that tweak) + // The output transform is only one run of UBI, since we need only 256 bits of output + // The tweak for the output transform is Type = Output with the Final bit set + // T[0] for the output is 8, and I don't know why - should be message size... + ulong t[3] = { 0x00UL, 0x7000000000000000UL, 0x00UL }; + ulong8 p, m; + + #pragma unroll 1 + for (uint i = 0; i < 4; ++i) + { + t[0] += i < 3 ? 0x40UL : 0x08UL; + + t[2] = t[0] ^ t[1]; + + m = (i < 3) ? vload8(i, states) : (ulong8)(states[24], 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); + const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY; + p = Skein512Block(m, h, h8, t); + + h = m ^ p; + + t[1] = i < 2 ? 0x3000000000000000UL : 0xB000000000000000UL; + } + + t[0] = 0x08UL; + t[1] = 0xFF00000000000000UL; + t[2] = t[0] ^ t[1]; + + p = (ulong8)(0); + const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY; + + p = Skein512Block(p, h, h8, t); + + // Note that comparison is equivalent to subtraction - we can't just compare 8 32-bit values + // and expect an accurate result for target > 32-bit without implementing carries + if (p.s3 <= Target) { + ulong outIdx = atomic_inc(output + 0xFF); + if (outIdx < 0xFF) { + output[outIdx] = BranchBuf[idx] + (uint) get_global_offset(0); + } + } + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} + + +#define SWAP8(x) as_ulong(as_uchar8(x).s76543210) + + +#define JHXOR \ + h0h ^= input[0]; \ + h0l ^= input[1]; \ + h1h ^= input[2]; \ + h1l ^= input[3]; \ + h2h ^= input[4]; \ + h2l ^= input[5]; \ + h3h ^= input[6]; \ + h3l ^= input[7]; \ +\ + E8; \ +\ + h4h ^= input[0]; \ + h4l ^= input[1]; \ + h5h ^= input[2]; \ + h5l ^= input[3]; \ + h6h ^= input[4]; \ + h6l ^= input[5]; \ + h7h ^= input[6]; \ + h7l ^= input[7] + + +__kernel void JH(__global ulong *states, __global uint *BranchBuf, __global uint *output, ulong Target, uint Threads) +{ + const uint idx = get_global_id(0) - get_global_offset(0); + + // do not use early return here + if (idx < BranchBuf[Threads]) { + states += 25 * BranchBuf[idx]; + + sph_u64 h0h = 0xEBD3202C41A398EBUL, h0l = 0xC145B29C7BBECD92UL, h1h = 0xFAC7D4609151931CUL, h1l = 0x038A507ED6820026UL, h2h = 0x45B92677269E23A4UL, h2l = 0x77941AD4481AFBE0UL, h3h = 0x7A176B0226ABB5CDUL, h3l = 0xA82FFF0F4224F056UL; + sph_u64 h4h = 0x754D2E7F8996A371UL, h4l = 0x62E27DF70849141DUL, h5h = 0x948F2476F7957627UL, h5l = 0x6C29804757B6D587UL, h6h = 0x6C0D8EAC2D275E5CUL, h6l = 0x0F7A0557C6508451UL, h7h = 0xEA12247067D3E47BUL, h7l = 0x69D71CD313ABE389UL; + sph_u64 tmp; + + for (uint i = 0; i < 3; ++i) { + ulong input[8]; + + const int shifted = i << 3; + for (uint x = 0; x < 8; ++x) { + input[x] = (states[shifted + x]); + } + + JHXOR; + } + + { + ulong input[8] = { (states[24]), 0x80UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL }; + JHXOR; + } + + { + ulong input[8] = { 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x00UL, 0x4006000000000000UL }; + JHXOR; + } + + // Note that comparison is equivalent to subtraction - we can't just compare 8 32-bit values + // and expect an accurate result for target > 32-bit without implementing carries + if (h7l <= Target) { + ulong outIdx = atomic_inc(output + 0xFF); + if (outIdx < 0xFF) { + output[outIdx] = BranchBuf[idx] + (uint) get_global_offset(0); + } + } + } +} + + +#define SWAP4(x) as_uint(as_uchar4(x).s3210) + + +__kernel void Blake(__global ulong *states, __global uint *BranchBuf, __global uint *output, ulong Target, uint Threads) +{ + const uint idx = get_global_id(0) - get_global_offset(0); + + // do not use early return here + if (idx < BranchBuf[Threads]) { + states += 25 * BranchBuf[idx]; + + unsigned int m[16]; + unsigned int v[16]; + uint h[8]; + uint bitlen = 0; + + ((uint8 *)h)[0] = vload8(0U, c_IV256); + + for (uint i = 0; i < 3; ++i) { + ((uint16 *)m)[0] = vload16(i, (__global uint *)states); + for (uint x = 0; x < 16; ++x) { + m[x] = SWAP4(m[x]); + } + + bitlen += 512; + + ((uint16 *)v)[0].lo = ((uint8 *)h)[0]; + ((uint16 *)v)[0].hi = vload8(0U, c_u256); + + v[12] ^= bitlen; + v[13] ^= bitlen; + + for (uint r = 0; r < 14; r++) { + GS(0, 4, 0x8, 0xC, 0x0); + GS(1, 5, 0x9, 0xD, 0x2); + GS(2, 6, 0xA, 0xE, 0x4); + GS(3, 7, 0xB, 0xF, 0x6); + GS(0, 5, 0xA, 0xF, 0x8); + GS(1, 6, 0xB, 0xC, 0xA); + GS(2, 7, 0x8, 0xD, 0xC); + GS(3, 4, 0x9, 0xE, 0xE); + } + + ((uint8 *)h)[0] ^= ((uint8 *)v)[0] ^ ((uint8 *)v)[1]; + } + + m[0] = SWAP4(((__global uint *)states)[48]); + m[1] = SWAP4(((__global uint *)states)[49]); + m[2] = 0x80000000U; + m[3] = 0x00U; + m[4] = 0x00U; + m[5] = 0x00U; + m[6] = 0x00U; + m[7] = 0x00U; + m[8] = 0x00U; + m[9] = 0x00U; + m[10] = 0x00U; + m[11] = 0x00U; + m[12] = 0x00U; + m[13] = 1U; + m[14] = 0U; + m[15] = 0x640; + + bitlen += 64; + + ((uint16 *)v)[0].lo = ((uint8 *)h)[0]; + ((uint16 *)v)[0].hi = vload8(0U, c_u256); + + v[12] ^= bitlen; + v[13] ^= bitlen; + + for (uint r = 0; r < 14; r++) { + GS(0, 4, 0x8, 0xC, 0x0); + GS(1, 5, 0x9, 0xD, 0x2); + GS(2, 6, 0xA, 0xE, 0x4); + GS(3, 7, 0xB, 0xF, 0x6); + GS(0, 5, 0xA, 0xF, 0x8); + GS(1, 6, 0xB, 0xC, 0xA); + GS(2, 7, 0x8, 0xD, 0xC); + GS(3, 4, 0x9, 0xE, 0xE); + } + + ((uint8 *)h)[0] ^= ((uint8 *)v)[0] ^ ((uint8 *)v)[1]; + + for (uint i = 0; i < 8; ++i) { + h[i] = SWAP4(h[i]); + } + + // Note that comparison is equivalent to subtraction - we can't just compare 8 32-bit values + // and expect an accurate result for target > 32-bit without implementing carries + uint2 t = (uint2)(h[6],h[7]); + if (as_ulong(t) <= Target) { + ulong outIdx = atomic_inc(output + 0xFF); + if (outIdx < 0xFF) { + output[outIdx] = BranchBuf[idx] + (uint) get_global_offset(0); + } + } + } +} + + +#undef SWAP4 + + +__kernel void Groestl(__global ulong *states, __global uint *BranchBuf, __global uint *output, ulong Target, uint Threads) +{ + const uint idx = get_global_id(0) - get_global_offset(0); + + // do not use early return here + if (idx < BranchBuf[Threads]) { + states += 25 * BranchBuf[idx]; + + ulong State[8] = { 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0x0001000000000000UL }; + ulong H[8], M[8]; + + // BUG: AMD driver 19.7.X crashs if this is written as loop + // Thx AMD for so bad software + { + ((ulong8 *)M)[0] = vload8(0, states); + + for (uint x = 0; x < 8; ++x) { + H[x] = M[x] ^ State[x]; + } + + PERM_SMALL_P(H); + PERM_SMALL_Q(M); + + for (uint x = 0; x < 8; ++x) { + State[x] ^= H[x] ^ M[x]; + } + } + + { + ((ulong8 *)M)[0] = vload8(1, states); + + for (uint x = 0; x < 8; ++x) { + H[x] = M[x] ^ State[x]; + } + + PERM_SMALL_P(H); + PERM_SMALL_Q(M); + + for (uint x = 0; x < 8; ++x) { + State[x] ^= H[x] ^ M[x]; + } + } + + { + ((ulong8 *)M)[0] = vload8(2, states); + + for (uint x = 0; x < 8; ++x) { + H[x] = M[x] ^ State[x]; + } + + PERM_SMALL_P(H); + PERM_SMALL_Q(M); + + for (uint x = 0; x < 8; ++x) { + State[x] ^= H[x] ^ M[x]; + } + } + + M[0] = states[24]; + M[1] = 0x80UL; + M[2] = 0UL; + M[3] = 0UL; + M[4] = 0UL; + M[5] = 0UL; + M[6] = 0UL; + M[7] = 0x0400000000000000UL; + + for (uint x = 0; x < 8; ++x) { + H[x] = M[x] ^ State[x]; + } + + PERM_SMALL_P(H); + PERM_SMALL_Q(M); + + ulong tmp[8]; + for (uint i = 0; i < 8; ++i) { + tmp[i] = State[i] ^= H[i] ^ M[i]; + } + + PERM_SMALL_P(State); + + for (uint i = 0; i < 8; ++i) { + State[i] ^= tmp[i]; + } + + // Note that comparison is equivalent to subtraction - we can't just compare 8 32-bit values + // and expect an accurate result for target > 32-bit without implementing carries + if (State[7] <= Target) { + ulong outIdx = atomic_inc(output + 0xFF); + if (outIdx < 0xFF) { + output[outIdx] = BranchBuf[idx] + (uint) get_global_offset(0); + } + } + } +} diff --git a/src/backend/opencl/cl/cn/cryptonight_cl.h b/src/backend/opencl/cl/cn/cryptonight_cl.h new file mode 100644 index 000000000..a0eac01e5 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_cl.h @@ -0,0 +1,1895 @@ +#pragma once + +namespace xmrig { + +static char cryptonight_cl[60367] = { + 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x63,0x6c,0x61,0x6e,0x67,0x5f,0x73,0x74,0x6f,0x72,0x61,0x67,0x65,0x5f,0x63,0x6c,0x61,0x73,0x73,0x5f,0x73,0x70, + 0x65,0x63,0x69,0x66,0x69,0x65,0x72,0x73,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f, + 0x4e,0x20,0x63,0x6c,0x5f,0x63,0x6c,0x61,0x6e,0x67,0x5f,0x73,0x74,0x6f,0x72,0x61,0x67,0x65,0x5f,0x63,0x6c,0x61,0x73,0x73,0x5f,0x73,0x70,0x65,0x63,0x69,0x66,0x69, + 0x65,0x72,0x73,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x43,0x4e,0x5f,0x30,0x20,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x31,0x20,0x31,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x32,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f, + 0x52,0x20,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x46,0x41,0x53,0x54,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x41,0x4c,0x46,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43, + 0x4e,0x5f,0x58,0x41,0x4f,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x54,0x4f,0x20,0x37,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x57,0x5a,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x43,0x4e,0x5f,0x5a,0x4c,0x53,0x20,0x39,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x44,0x4f,0x55,0x42,0x4c,0x45, + 0x20,0x31,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x47,0x50,0x55,0x20,0x31,0x31,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x4c,0x49,0x54,0x45,0x5f,0x30,0x20,0x31,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47, + 0x4f,0x5f,0x43,0x4e,0x5f,0x4c,0x49,0x54,0x45,0x5f,0x31,0x20,0x31,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48, + 0x45,0x41,0x56,0x59,0x5f,0x30,0x20,0x31,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f, + 0x54,0x55,0x42,0x45,0x20,0x31,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x58,0x48, + 0x56,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x50,0x49,0x43,0x4f,0x5f,0x30,0x20,0x31,0x37,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x30,0x20,0x31,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x52,0x58,0x5f,0x57,0x4f,0x57,0x20,0x31,0x39,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x4c,0x4f,0x4b,0x49,0x20, + 0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x41,0x52,0x32,0x5f,0x43,0x48,0x55,0x4b,0x57,0x41,0x20,0x32,0x31,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x41,0x52,0x32,0x5f,0x57,0x52,0x4b,0x5a,0x20,0x32,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46, + 0x41,0x4d,0x49,0x4c,0x59,0x5f,0x55,0x4e,0x4b,0x4e,0x4f,0x57,0x4e,0x20,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43, + 0x4e,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x4c,0x49,0x54,0x45,0x20,0x32,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x20,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46, + 0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x50,0x49,0x43,0x4f,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x5f,0x58,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x41,0x52,0x47,0x4f,0x4e,0x32,0x20, + 0x36,0x0a,0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x57,0x4f,0x4c,0x46,0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x4f, + 0x4c,0x46,0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70, + 0x73,0x32,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x61, + 0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x78, + 0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x20,0x61, + 0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69, + 0x6e,0x6c,0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x20,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x73,0x72,0x63,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x77,0x69,0x64,0x74,0x68,0x29,0x3c, + 0x33,0x32,0x75,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x73,0x72,0x63,0x30,0x3c,0x3c,0x28,0x33,0x32,0x75,0x2d,0x6f,0x66,0x66,0x73,0x65,0x74, + 0x2d,0x77,0x69,0x64,0x74,0x68,0x29,0x29,0x3e,0x3e,0x28,0x33,0x32,0x75,0x2d,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, + 0x73,0x72,0x63,0x30,0x3e,0x3e,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x32,0x35,0x36,0x5d,0x20, + 0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x41,0x35,0x36,0x33,0x36,0x33,0x43,0x36,0x55,0x2c,0x30,0x78,0x38,0x34,0x37,0x43,0x37,0x43,0x46,0x38,0x55,0x2c,0x30,0x78,0x39,0x39, + 0x37,0x37,0x37,0x37,0x45,0x45,0x55,0x2c,0x30,0x78,0x38,0x44,0x37,0x42,0x37,0x42,0x46,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x44,0x46,0x32,0x46,0x32,0x46,0x46,0x55, + 0x2c,0x30,0x78,0x42,0x44,0x36,0x42,0x36,0x42,0x44,0x36,0x55,0x2c,0x30,0x78,0x42,0x31,0x36,0x46,0x36,0x46,0x44,0x45,0x55,0x2c,0x30,0x78,0x35,0x34,0x43,0x35,0x43, + 0x35,0x39,0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x55,0x2c,0x30,0x78, + 0x41,0x39,0x36,0x37,0x36,0x37,0x43,0x45,0x55,0x2c,0x30,0x78,0x37,0x44,0x32,0x42,0x32,0x42,0x35,0x36,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x46,0x45,0x46,0x45,0x45, + 0x37,0x55,0x2c,0x30,0x78,0x36,0x32,0x44,0x37,0x44,0x37,0x42,0x35,0x55,0x2c,0x30,0x78,0x45,0x36,0x41,0x42,0x41,0x42,0x34,0x44,0x55,0x2c,0x30,0x78,0x39,0x41,0x37, + 0x36,0x37,0x36,0x45,0x43,0x55,0x2c,0x0a,0x30,0x78,0x34,0x35,0x43,0x41,0x43,0x41,0x38,0x46,0x55,0x2c,0x30,0x78,0x39,0x44,0x38,0x32,0x38,0x32,0x31,0x46,0x55,0x2c, + 0x30,0x78,0x34,0x30,0x43,0x39,0x43,0x39,0x38,0x39,0x55,0x2c,0x30,0x78,0x38,0x37,0x37,0x44,0x37,0x44,0x46,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x35,0x46,0x41,0x46, + 0x41,0x45,0x46,0x55,0x2c,0x30,0x78,0x45,0x42,0x35,0x39,0x35,0x39,0x42,0x32,0x55,0x2c,0x30,0x78,0x43,0x39,0x34,0x37,0x34,0x37,0x38,0x45,0x55,0x2c,0x30,0x78,0x30, + 0x42,0x46,0x30,0x46,0x30,0x46,0x42,0x55,0x2c,0x0a,0x30,0x78,0x45,0x43,0x41,0x44,0x41,0x44,0x34,0x31,0x55,0x2c,0x30,0x78,0x36,0x37,0x44,0x34,0x44,0x34,0x42,0x33, + 0x55,0x2c,0x30,0x78,0x46,0x44,0x41,0x32,0x41,0x32,0x35,0x46,0x55,0x2c,0x30,0x78,0x45,0x41,0x41,0x46,0x41,0x46,0x34,0x35,0x55,0x2c,0x0a,0x30,0x78,0x42,0x46,0x39, + 0x43,0x39,0x43,0x32,0x33,0x55,0x2c,0x30,0x78,0x46,0x37,0x41,0x34,0x41,0x34,0x35,0x33,0x55,0x2c,0x30,0x78,0x39,0x36,0x37,0x32,0x37,0x32,0x45,0x34,0x55,0x2c,0x30, + 0x78,0x35,0x42,0x43,0x30,0x43,0x30,0x39,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x32,0x42,0x37,0x42,0x37,0x37,0x35,0x55,0x2c,0x30,0x78,0x31,0x43,0x46,0x44,0x46,0x44, + 0x45,0x31,0x55,0x2c,0x30,0x78,0x41,0x45,0x39,0x33,0x39,0x33,0x33,0x44,0x55,0x2c,0x30,0x78,0x36,0x41,0x32,0x36,0x32,0x36,0x34,0x43,0x55,0x2c,0x0a,0x30,0x78,0x35, + 0x41,0x33,0x36,0x33,0x36,0x36,0x43,0x55,0x2c,0x30,0x78,0x34,0x31,0x33,0x46,0x33,0x46,0x37,0x45,0x55,0x2c,0x30,0x78,0x30,0x32,0x46,0x37,0x46,0x37,0x46,0x35,0x55, + 0x2c,0x30,0x78,0x34,0x46,0x43,0x43,0x43,0x43,0x38,0x33,0x55,0x2c,0x0a,0x30,0x78,0x35,0x43,0x33,0x34,0x33,0x34,0x36,0x38,0x55,0x2c,0x30,0x78,0x46,0x34,0x41,0x35, + 0x41,0x35,0x35,0x31,0x55,0x2c,0x30,0x78,0x33,0x34,0x45,0x35,0x45,0x35,0x44,0x31,0x55,0x2c,0x30,0x78,0x30,0x38,0x46,0x31,0x46,0x31,0x46,0x39,0x55,0x2c,0x0a,0x30, + 0x78,0x39,0x33,0x37,0x31,0x37,0x31,0x45,0x32,0x55,0x2c,0x30,0x78,0x37,0x33,0x44,0x38,0x44,0x38,0x41,0x42,0x55,0x2c,0x30,0x78,0x35,0x33,0x33,0x31,0x33,0x31,0x36, + 0x32,0x55,0x2c,0x30,0x78,0x33,0x46,0x31,0x35,0x31,0x35,0x32,0x41,0x55,0x2c,0x0a,0x30,0x78,0x30,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x55,0x2c,0x30,0x78,0x35,0x32, + 0x43,0x37,0x43,0x37,0x39,0x35,0x55,0x2c,0x30,0x78,0x36,0x35,0x32,0x33,0x32,0x33,0x34,0x36,0x55,0x2c,0x30,0x78,0x35,0x45,0x43,0x33,0x43,0x33,0x39,0x44,0x55,0x2c, + 0x0a,0x30,0x78,0x32,0x38,0x31,0x38,0x31,0x38,0x33,0x30,0x55,0x2c,0x30,0x78,0x41,0x31,0x39,0x36,0x39,0x36,0x33,0x37,0x55,0x2c,0x30,0x78,0x30,0x46,0x30,0x35,0x30, + 0x35,0x30,0x41,0x55,0x2c,0x30,0x78,0x42,0x35,0x39,0x41,0x39,0x41,0x32,0x46,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x55,0x2c,0x30,0x78, + 0x33,0x36,0x31,0x32,0x31,0x32,0x32,0x34,0x55,0x2c,0x30,0x78,0x39,0x42,0x38,0x30,0x38,0x30,0x31,0x42,0x55,0x2c,0x30,0x78,0x33,0x44,0x45,0x32,0x45,0x32,0x44,0x46, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x36,0x45,0x42,0x45,0x42,0x43,0x44,0x55,0x2c,0x30,0x78,0x36,0x39,0x32,0x37,0x32,0x37,0x34,0x45,0x55,0x2c,0x30,0x78,0x43,0x44,0x42, + 0x32,0x42,0x32,0x37,0x46,0x55,0x2c,0x30,0x78,0x39,0x46,0x37,0x35,0x37,0x35,0x45,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x42,0x30,0x39,0x30,0x39,0x31,0x32,0x55,0x2c, + 0x30,0x78,0x39,0x45,0x38,0x33,0x38,0x33,0x31,0x44,0x55,0x2c,0x30,0x78,0x37,0x34,0x32,0x43,0x32,0x43,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x45,0x31,0x41,0x31,0x41, + 0x33,0x34,0x55,0x2c,0x0a,0x30,0x78,0x32,0x44,0x31,0x42,0x31,0x42,0x33,0x36,0x55,0x2c,0x30,0x78,0x42,0x32,0x36,0x45,0x36,0x45,0x44,0x43,0x55,0x2c,0x30,0x78,0x45, + 0x45,0x35,0x41,0x35,0x41,0x42,0x34,0x55,0x2c,0x30,0x78,0x46,0x42,0x41,0x30,0x41,0x30,0x35,0x42,0x55,0x2c,0x0a,0x30,0x78,0x46,0x36,0x35,0x32,0x35,0x32,0x41,0x34, + 0x55,0x2c,0x30,0x78,0x34,0x44,0x33,0x42,0x33,0x42,0x37,0x36,0x55,0x2c,0x30,0x78,0x36,0x31,0x44,0x36,0x44,0x36,0x42,0x37,0x55,0x2c,0x30,0x78,0x43,0x45,0x42,0x33, + 0x42,0x33,0x37,0x44,0x55,0x2c,0x0a,0x30,0x78,0x37,0x42,0x32,0x39,0x32,0x39,0x35,0x32,0x55,0x2c,0x30,0x78,0x33,0x45,0x45,0x33,0x45,0x33,0x44,0x44,0x55,0x2c,0x30, + 0x78,0x37,0x31,0x32,0x46,0x32,0x46,0x35,0x45,0x55,0x2c,0x30,0x78,0x39,0x37,0x38,0x34,0x38,0x34,0x31,0x33,0x55,0x2c,0x0a,0x30,0x78,0x46,0x35,0x35,0x33,0x35,0x33, + 0x41,0x36,0x55,0x2c,0x30,0x78,0x36,0x38,0x44,0x31,0x44,0x31,0x42,0x39,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x32,0x43, + 0x45,0x44,0x45,0x44,0x43,0x31,0x55,0x2c,0x0a,0x30,0x78,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x31,0x46,0x46,0x43,0x46,0x43,0x45,0x33,0x55, + 0x2c,0x30,0x78,0x43,0x38,0x42,0x31,0x42,0x31,0x37,0x39,0x55,0x2c,0x30,0x78,0x45,0x44,0x35,0x42,0x35,0x42,0x42,0x36,0x55,0x2c,0x0a,0x30,0x78,0x42,0x45,0x36,0x41, + 0x36,0x41,0x44,0x34,0x55,0x2c,0x30,0x78,0x34,0x36,0x43,0x42,0x43,0x42,0x38,0x44,0x55,0x2c,0x30,0x78,0x44,0x39,0x42,0x45,0x42,0x45,0x36,0x37,0x55,0x2c,0x30,0x78, + 0x34,0x42,0x33,0x39,0x33,0x39,0x37,0x32,0x55,0x2c,0x0a,0x30,0x78,0x44,0x45,0x34,0x41,0x34,0x41,0x39,0x34,0x55,0x2c,0x30,0x78,0x44,0x34,0x34,0x43,0x34,0x43,0x39, + 0x38,0x55,0x2c,0x30,0x78,0x45,0x38,0x35,0x38,0x35,0x38,0x42,0x30,0x55,0x2c,0x30,0x78,0x34,0x41,0x43,0x46,0x43,0x46,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x42, + 0x44,0x30,0x44,0x30,0x42,0x42,0x55,0x2c,0x30,0x78,0x32,0x41,0x45,0x46,0x45,0x46,0x43,0x35,0x55,0x2c,0x30,0x78,0x45,0x35,0x41,0x41,0x41,0x41,0x34,0x46,0x55,0x2c, + 0x30,0x78,0x31,0x36,0x46,0x42,0x46,0x42,0x45,0x44,0x55,0x2c,0x0a,0x30,0x78,0x43,0x35,0x34,0x33,0x34,0x33,0x38,0x36,0x55,0x2c,0x30,0x78,0x44,0x37,0x34,0x44,0x34, + 0x44,0x39,0x41,0x55,0x2c,0x30,0x78,0x35,0x35,0x33,0x33,0x33,0x33,0x36,0x36,0x55,0x2c,0x30,0x78,0x39,0x34,0x38,0x35,0x38,0x35,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78, + 0x43,0x46,0x34,0x35,0x34,0x35,0x38,0x41,0x55,0x2c,0x30,0x78,0x31,0x30,0x46,0x39,0x46,0x39,0x45,0x39,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x32,0x30,0x32,0x30,0x34, + 0x55,0x2c,0x30,0x78,0x38,0x31,0x37,0x46,0x37,0x46,0x46,0x45,0x55,0x2c,0x0a,0x30,0x78,0x46,0x30,0x35,0x30,0x35,0x30,0x41,0x30,0x55,0x2c,0x30,0x78,0x34,0x34,0x33, + 0x43,0x33,0x43,0x37,0x38,0x55,0x2c,0x30,0x78,0x42,0x41,0x39,0x46,0x39,0x46,0x32,0x35,0x55,0x2c,0x30,0x78,0x45,0x33,0x41,0x38,0x41,0x38,0x34,0x42,0x55,0x2c,0x0a, + 0x30,0x78,0x46,0x33,0x35,0x31,0x35,0x31,0x41,0x32,0x55,0x2c,0x30,0x78,0x46,0x45,0x41,0x33,0x41,0x33,0x35,0x44,0x55,0x2c,0x30,0x78,0x43,0x30,0x34,0x30,0x34,0x30, + 0x38,0x30,0x55,0x2c,0x30,0x78,0x38,0x41,0x38,0x46,0x38,0x46,0x30,0x35,0x55,0x2c,0x0a,0x30,0x78,0x41,0x44,0x39,0x32,0x39,0x32,0x33,0x46,0x55,0x2c,0x30,0x78,0x42, + 0x43,0x39,0x44,0x39,0x44,0x32,0x31,0x55,0x2c,0x30,0x78,0x34,0x38,0x33,0x38,0x33,0x38,0x37,0x30,0x55,0x2c,0x30,0x78,0x30,0x34,0x46,0x35,0x46,0x35,0x46,0x31,0x55, + 0x2c,0x0a,0x30,0x78,0x44,0x46,0x42,0x43,0x42,0x43,0x36,0x33,0x55,0x2c,0x30,0x78,0x43,0x31,0x42,0x36,0x42,0x36,0x37,0x37,0x55,0x2c,0x30,0x78,0x37,0x35,0x44,0x41, + 0x44,0x41,0x41,0x46,0x55,0x2c,0x30,0x78,0x36,0x33,0x32,0x31,0x32,0x31,0x34,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x55,0x2c,0x30, + 0x78,0x31,0x41,0x46,0x46,0x46,0x46,0x45,0x35,0x55,0x2c,0x30,0x78,0x30,0x45,0x46,0x33,0x46,0x33,0x46,0x44,0x55,0x2c,0x30,0x78,0x36,0x44,0x44,0x32,0x44,0x32,0x42, + 0x46,0x55,0x2c,0x0a,0x30,0x78,0x34,0x43,0x43,0x44,0x43,0x44,0x38,0x31,0x55,0x2c,0x30,0x78,0x31,0x34,0x30,0x43,0x30,0x43,0x31,0x38,0x55,0x2c,0x30,0x78,0x33,0x35, + 0x31,0x33,0x31,0x33,0x32,0x36,0x55,0x2c,0x30,0x78,0x32,0x46,0x45,0x43,0x45,0x43,0x43,0x33,0x55,0x2c,0x0a,0x30,0x78,0x45,0x31,0x35,0x46,0x35,0x46,0x42,0x45,0x55, + 0x2c,0x30,0x78,0x41,0x32,0x39,0x37,0x39,0x37,0x33,0x35,0x55,0x2c,0x30,0x78,0x43,0x43,0x34,0x34,0x34,0x34,0x38,0x38,0x55,0x2c,0x30,0x78,0x33,0x39,0x31,0x37,0x31, + 0x37,0x32,0x45,0x55,0x2c,0x0a,0x30,0x78,0x35,0x37,0x43,0x34,0x43,0x34,0x39,0x33,0x55,0x2c,0x30,0x78,0x46,0x32,0x41,0x37,0x41,0x37,0x35,0x35,0x55,0x2c,0x30,0x78, + 0x38,0x32,0x37,0x45,0x37,0x45,0x46,0x43,0x55,0x2c,0x30,0x78,0x34,0x37,0x33,0x44,0x33,0x44,0x37,0x41,0x55,0x2c,0x0a,0x30,0x78,0x41,0x43,0x36,0x34,0x36,0x34,0x43, + 0x38,0x55,0x2c,0x30,0x78,0x45,0x37,0x35,0x44,0x35,0x44,0x42,0x41,0x55,0x2c,0x30,0x78,0x32,0x42,0x31,0x39,0x31,0x39,0x33,0x32,0x55,0x2c,0x30,0x78,0x39,0x35,0x37, + 0x33,0x37,0x33,0x45,0x36,0x55,0x2c,0x0a,0x30,0x78,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x30,0x55,0x2c,0x30,0x78,0x39,0x38,0x38,0x31,0x38,0x31,0x31,0x39,0x55,0x2c, + 0x30,0x78,0x44,0x31,0x34,0x46,0x34,0x46,0x39,0x45,0x55,0x2c,0x30,0x78,0x37,0x46,0x44,0x43,0x44,0x43,0x41,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x36,0x32,0x32,0x32, + 0x32,0x34,0x34,0x55,0x2c,0x30,0x78,0x37,0x45,0x32,0x41,0x32,0x41,0x35,0x34,0x55,0x2c,0x30,0x78,0x41,0x42,0x39,0x30,0x39,0x30,0x33,0x42,0x55,0x2c,0x30,0x78,0x38, + 0x33,0x38,0x38,0x38,0x38,0x30,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x41,0x34,0x36,0x34,0x36,0x38,0x43,0x55,0x2c,0x30,0x78,0x32,0x39,0x45,0x45,0x45,0x45,0x43,0x37, + 0x55,0x2c,0x30,0x78,0x44,0x33,0x42,0x38,0x42,0x38,0x36,0x42,0x55,0x2c,0x30,0x78,0x33,0x43,0x31,0x34,0x31,0x34,0x32,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x39,0x44, + 0x45,0x44,0x45,0x41,0x37,0x55,0x2c,0x30,0x78,0x45,0x32,0x35,0x45,0x35,0x45,0x42,0x43,0x55,0x2c,0x30,0x78,0x31,0x44,0x30,0x42,0x30,0x42,0x31,0x36,0x55,0x2c,0x30, + 0x78,0x37,0x36,0x44,0x42,0x44,0x42,0x41,0x44,0x55,0x2c,0x0a,0x30,0x78,0x33,0x42,0x45,0x30,0x45,0x30,0x44,0x42,0x55,0x2c,0x30,0x78,0x35,0x36,0x33,0x32,0x33,0x32, + 0x36,0x34,0x55,0x2c,0x30,0x78,0x34,0x45,0x33,0x41,0x33,0x41,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x45,0x30,0x41,0x30,0x41,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x44, + 0x42,0x34,0x39,0x34,0x39,0x39,0x32,0x55,0x2c,0x30,0x78,0x30,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x55,0x2c,0x30,0x78,0x36,0x43,0x32,0x34,0x32,0x34,0x34,0x38,0x55, + 0x2c,0x30,0x78,0x45,0x34,0x35,0x43,0x35,0x43,0x42,0x38,0x55,0x2c,0x0a,0x30,0x78,0x35,0x44,0x43,0x32,0x43,0x32,0x39,0x46,0x55,0x2c,0x30,0x78,0x36,0x45,0x44,0x33, + 0x44,0x33,0x42,0x44,0x55,0x2c,0x30,0x78,0x45,0x46,0x41,0x43,0x41,0x43,0x34,0x33,0x55,0x2c,0x30,0x78,0x41,0x36,0x36,0x32,0x36,0x32,0x43,0x34,0x55,0x2c,0x0a,0x30, + 0x78,0x41,0x38,0x39,0x31,0x39,0x31,0x33,0x39,0x55,0x2c,0x30,0x78,0x41,0x34,0x39,0x35,0x39,0x35,0x33,0x31,0x55,0x2c,0x30,0x78,0x33,0x37,0x45,0x34,0x45,0x34,0x44, + 0x33,0x55,0x2c,0x30,0x78,0x38,0x42,0x37,0x39,0x37,0x39,0x46,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x32,0x45,0x37,0x45,0x37,0x44,0x35,0x55,0x2c,0x30,0x78,0x34,0x33, + 0x43,0x38,0x43,0x38,0x38,0x42,0x55,0x2c,0x30,0x78,0x35,0x39,0x33,0x37,0x33,0x37,0x36,0x45,0x55,0x2c,0x30,0x78,0x42,0x37,0x36,0x44,0x36,0x44,0x44,0x41,0x55,0x2c, + 0x0a,0x30,0x78,0x38,0x43,0x38,0x44,0x38,0x44,0x30,0x31,0x55,0x2c,0x30,0x78,0x36,0x34,0x44,0x35,0x44,0x35,0x42,0x31,0x55,0x2c,0x30,0x78,0x44,0x32,0x34,0x45,0x34, + 0x45,0x39,0x43,0x55,0x2c,0x30,0x78,0x45,0x30,0x41,0x39,0x41,0x39,0x34,0x39,0x55,0x2c,0x0a,0x30,0x78,0x42,0x34,0x36,0x43,0x36,0x43,0x44,0x38,0x55,0x2c,0x30,0x78, + 0x46,0x41,0x35,0x36,0x35,0x36,0x41,0x43,0x55,0x2c,0x30,0x78,0x30,0x37,0x46,0x34,0x46,0x34,0x46,0x33,0x55,0x2c,0x30,0x78,0x32,0x35,0x45,0x41,0x45,0x41,0x43,0x46, + 0x55,0x2c,0x0a,0x30,0x78,0x41,0x46,0x36,0x35,0x36,0x35,0x43,0x41,0x55,0x2c,0x30,0x78,0x38,0x45,0x37,0x41,0x37,0x41,0x46,0x34,0x55,0x2c,0x30,0x78,0x45,0x39,0x41, + 0x45,0x41,0x45,0x34,0x37,0x55,0x2c,0x30,0x78,0x31,0x38,0x30,0x38,0x30,0x38,0x31,0x30,0x55,0x2c,0x0a,0x30,0x78,0x44,0x35,0x42,0x41,0x42,0x41,0x36,0x46,0x55,0x2c, + 0x30,0x78,0x38,0x38,0x37,0x38,0x37,0x38,0x46,0x30,0x55,0x2c,0x30,0x78,0x36,0x46,0x32,0x35,0x32,0x35,0x34,0x41,0x55,0x2c,0x30,0x78,0x37,0x32,0x32,0x45,0x32,0x45, + 0x35,0x43,0x55,0x2c,0x0a,0x30,0x78,0x32,0x34,0x31,0x43,0x31,0x43,0x33,0x38,0x55,0x2c,0x30,0x78,0x46,0x31,0x41,0x36,0x41,0x36,0x35,0x37,0x55,0x2c,0x30,0x78,0x43, + 0x37,0x42,0x34,0x42,0x34,0x37,0x33,0x55,0x2c,0x30,0x78,0x35,0x31,0x43,0x36,0x43,0x36,0x39,0x37,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x45,0x38,0x45,0x38,0x43,0x42, + 0x55,0x2c,0x30,0x78,0x37,0x43,0x44,0x44,0x44,0x44,0x41,0x31,0x55,0x2c,0x30,0x78,0x39,0x43,0x37,0x34,0x37,0x34,0x45,0x38,0x55,0x2c,0x30,0x78,0x32,0x31,0x31,0x46, + 0x31,0x46,0x33,0x45,0x55,0x2c,0x0a,0x30,0x78,0x44,0x44,0x34,0x42,0x34,0x42,0x39,0x36,0x55,0x2c,0x30,0x78,0x44,0x43,0x42,0x44,0x42,0x44,0x36,0x31,0x55,0x2c,0x30, + 0x78,0x38,0x36,0x38,0x42,0x38,0x42,0x30,0x44,0x55,0x2c,0x30,0x78,0x38,0x35,0x38,0x41,0x38,0x41,0x30,0x46,0x55,0x2c,0x0a,0x30,0x78,0x39,0x30,0x37,0x30,0x37,0x30, + 0x45,0x30,0x55,0x2c,0x30,0x78,0x34,0x32,0x33,0x45,0x33,0x45,0x37,0x43,0x55,0x2c,0x30,0x78,0x43,0x34,0x42,0x35,0x42,0x35,0x37,0x31,0x55,0x2c,0x30,0x78,0x41,0x41, + 0x36,0x36,0x36,0x36,0x43,0x43,0x55,0x2c,0x0a,0x30,0x78,0x44,0x38,0x34,0x38,0x34,0x38,0x39,0x30,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x55, + 0x2c,0x30,0x78,0x30,0x31,0x46,0x36,0x46,0x36,0x46,0x37,0x55,0x2c,0x30,0x78,0x31,0x32,0x30,0x45,0x30,0x45,0x31,0x43,0x55,0x2c,0x0a,0x30,0x78,0x41,0x33,0x36,0x31, + 0x36,0x31,0x43,0x32,0x55,0x2c,0x30,0x78,0x35,0x46,0x33,0x35,0x33,0x35,0x36,0x41,0x55,0x2c,0x30,0x78,0x46,0x39,0x35,0x37,0x35,0x37,0x41,0x45,0x55,0x2c,0x30,0x78, + 0x44,0x30,0x42,0x39,0x42,0x39,0x36,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39,0x31,0x38,0x36,0x38,0x36,0x31,0x37,0x55,0x2c,0x30,0x78,0x35,0x38,0x43,0x31,0x43,0x31,0x39, + 0x39,0x55,0x2c,0x30,0x78,0x32,0x37,0x31,0x44,0x31,0x44,0x33,0x41,0x55,0x2c,0x30,0x78,0x42,0x39,0x39,0x45,0x39,0x45,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x38, + 0x45,0x31,0x45,0x31,0x44,0x39,0x55,0x2c,0x30,0x78,0x31,0x33,0x46,0x38,0x46,0x38,0x45,0x42,0x55,0x2c,0x30,0x78,0x42,0x33,0x39,0x38,0x39,0x38,0x32,0x42,0x55,0x2c, + 0x30,0x78,0x33,0x33,0x31,0x31,0x31,0x31,0x32,0x32,0x55,0x2c,0x0a,0x30,0x78,0x42,0x42,0x36,0x39,0x36,0x39,0x44,0x32,0x55,0x2c,0x30,0x78,0x37,0x30,0x44,0x39,0x44, + 0x39,0x41,0x39,0x55,0x2c,0x30,0x78,0x38,0x39,0x38,0x45,0x38,0x45,0x30,0x37,0x55,0x2c,0x30,0x78,0x41,0x37,0x39,0x34,0x39,0x34,0x33,0x33,0x55,0x2c,0x0a,0x30,0x78, + 0x42,0x36,0x39,0x42,0x39,0x42,0x32,0x44,0x55,0x2c,0x30,0x78,0x32,0x32,0x31,0x45,0x31,0x45,0x33,0x43,0x55,0x2c,0x30,0x78,0x39,0x32,0x38,0x37,0x38,0x37,0x31,0x35, + 0x55,0x2c,0x30,0x78,0x32,0x30,0x45,0x39,0x45,0x39,0x43,0x39,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x43,0x45,0x43,0x45,0x38,0x37,0x55,0x2c,0x30,0x78,0x46,0x46,0x35, + 0x35,0x35,0x35,0x41,0x41,0x55,0x2c,0x30,0x78,0x37,0x38,0x32,0x38,0x32,0x38,0x35,0x30,0x55,0x2c,0x30,0x78,0x37,0x41,0x44,0x46,0x44,0x46,0x41,0x35,0x55,0x2c,0x0a, + 0x30,0x78,0x38,0x46,0x38,0x43,0x38,0x43,0x30,0x33,0x55,0x2c,0x30,0x78,0x46,0x38,0x41,0x31,0x41,0x31,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x30,0x38,0x39,0x38,0x39, + 0x30,0x39,0x55,0x2c,0x30,0x78,0x31,0x37,0x30,0x44,0x30,0x44,0x31,0x41,0x55,0x2c,0x0a,0x30,0x78,0x44,0x41,0x42,0x46,0x42,0x46,0x36,0x35,0x55,0x2c,0x30,0x78,0x33, + 0x31,0x45,0x36,0x45,0x36,0x44,0x37,0x55,0x2c,0x30,0x78,0x43,0x36,0x34,0x32,0x34,0x32,0x38,0x34,0x55,0x2c,0x30,0x78,0x42,0x38,0x36,0x38,0x36,0x38,0x44,0x30,0x55, + 0x2c,0x0a,0x30,0x78,0x43,0x33,0x34,0x31,0x34,0x31,0x38,0x32,0x55,0x2c,0x30,0x78,0x42,0x30,0x39,0x39,0x39,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x37,0x37,0x32,0x44, + 0x32,0x44,0x35,0x41,0x55,0x2c,0x30,0x78,0x31,0x31,0x30,0x46,0x30,0x46,0x31,0x45,0x55,0x2c,0x0a,0x30,0x78,0x43,0x42,0x42,0x30,0x42,0x30,0x37,0x42,0x55,0x2c,0x30, + 0x78,0x46,0x43,0x35,0x34,0x35,0x34,0x41,0x38,0x55,0x2c,0x30,0x78,0x44,0x36,0x42,0x42,0x42,0x42,0x36,0x44,0x55,0x2c,0x30,0x78,0x33,0x41,0x31,0x36,0x31,0x36,0x32, + 0x43,0x55,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x59,0x54,0x45,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x28,0x78,0x6d,0x72,0x69,0x67,0x5f, + 0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x28,0x78,0x29,0x2c,0x20,0x28,0x79,0x29,0x20,0x3c,0x3c,0x20,0x33,0x55,0x2c,0x20,0x38,0x55,0x29,0x29,0x0a,0x23,0x69,0x66, + 0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x69,0x6e, + 0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x62,0x69,0x74,0x74,0x75,0x62,0x65,0x32,0x28,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x29, + 0x0a,0x7b,0x0a,0x78,0x3d,0x7e,0x78,0x3b,0x0a,0x6b,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c, + 0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45, + 0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c, + 0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x30,0x3b,0x0a,0x6b,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20, + 0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73, + 0x32,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x31,0x20,0x5e,0x3d, + 0x20,0x6b,0x2e,0x73,0x31,0x3b,0x0a,0x6b,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x30,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x33,0x29, + 0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x32,0x3b,0x0a,0x6b,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45, + 0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c, + 0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x3b, + 0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a, + 0x41,0x45,0x53,0x32,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x33,0x2c,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20, + 0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x58,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42, + 0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73, + 0x30,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c, + 0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45, + 0x28,0x58,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65, + 0x79,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b, + 0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d, + 0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b, + 0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x54,0x77,0x6f,0x5f,0x54,0x61,0x62,0x6c,0x65,0x73,0x28,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58, + 0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74, + 0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58, + 0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54, + 0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f, + 0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54, + 0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b, + 0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d, + 0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b, + 0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45, + 0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c, + 0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65, + 0x79,0x3b,0x0a,0x7d,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68, + 0x61,0x72,0x20,0x72,0x63,0x6f,0x6e,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x30,0x78,0x38,0x64,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x30,0x32,0x2c,0x30,0x78,0x30,0x34, + 0x2c,0x30,0x78,0x30,0x38,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x34,0x30,0x20,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68,0x61,0x72,0x20,0x73,0x62,0x6f,0x78,0x5b,0x32,0x35,0x36,0x5d,0x20, + 0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x36,0x33,0x2c,0x30,0x78,0x37,0x43,0x2c,0x30,0x78,0x37,0x37,0x2c,0x30,0x78,0x37,0x42,0x2c,0x30,0x78,0x46,0x32,0x2c,0x30,0x78,0x36, + 0x42,0x2c,0x30,0x78,0x36,0x46,0x2c,0x30,0x78,0x43,0x35,0x2c,0x30,0x78,0x33,0x30,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x36,0x37,0x2c,0x30,0x78,0x32,0x42,0x2c, + 0x30,0x78,0x46,0x45,0x2c,0x30,0x78,0x44,0x37,0x2c,0x30,0x78,0x41,0x42,0x2c,0x30,0x78,0x37,0x36,0x2c,0x0a,0x30,0x78,0x43,0x41,0x2c,0x30,0x78,0x38,0x32,0x2c,0x30, + 0x78,0x43,0x39,0x2c,0x30,0x78,0x37,0x44,0x2c,0x30,0x78,0x46,0x41,0x2c,0x30,0x78,0x35,0x39,0x2c,0x30,0x78,0x34,0x37,0x2c,0x30,0x78,0x46,0x30,0x2c,0x30,0x78,0x41, + 0x44,0x2c,0x30,0x78,0x44,0x34,0x2c,0x30,0x78,0x41,0x32,0x2c,0x30,0x78,0x41,0x46,0x2c,0x30,0x78,0x39,0x43,0x2c,0x30,0x78,0x41,0x34,0x2c,0x30,0x78,0x37,0x32,0x2c, + 0x30,0x78,0x43,0x30,0x2c,0x0a,0x30,0x78,0x42,0x37,0x2c,0x30,0x78,0x46,0x44,0x2c,0x30,0x78,0x39,0x33,0x2c,0x30,0x78,0x32,0x36,0x2c,0x30,0x78,0x33,0x36,0x2c,0x30, + 0x78,0x33,0x46,0x2c,0x30,0x78,0x46,0x37,0x2c,0x30,0x78,0x43,0x43,0x2c,0x30,0x78,0x33,0x34,0x2c,0x30,0x78,0x41,0x35,0x2c,0x30,0x78,0x45,0x35,0x2c,0x30,0x78,0x46, + 0x31,0x2c,0x30,0x78,0x37,0x31,0x2c,0x30,0x78,0x44,0x38,0x2c,0x30,0x78,0x33,0x31,0x2c,0x30,0x78,0x31,0x35,0x2c,0x0a,0x30,0x78,0x30,0x34,0x2c,0x30,0x78,0x43,0x37, + 0x2c,0x30,0x78,0x32,0x33,0x2c,0x30,0x78,0x43,0x33,0x2c,0x30,0x78,0x31,0x38,0x2c,0x30,0x78,0x39,0x36,0x2c,0x30,0x78,0x30,0x35,0x2c,0x30,0x78,0x39,0x41,0x2c,0x30, + 0x78,0x30,0x37,0x2c,0x30,0x78,0x31,0x32,0x2c,0x30,0x78,0x38,0x30,0x2c,0x30,0x78,0x45,0x32,0x2c,0x30,0x78,0x45,0x42,0x2c,0x30,0x78,0x32,0x37,0x2c,0x30,0x78,0x42, + 0x32,0x2c,0x30,0x78,0x37,0x35,0x2c,0x0a,0x30,0x78,0x30,0x39,0x2c,0x30,0x78,0x38,0x33,0x2c,0x30,0x78,0x32,0x43,0x2c,0x30,0x78,0x31,0x41,0x2c,0x30,0x78,0x31,0x42, + 0x2c,0x30,0x78,0x36,0x45,0x2c,0x30,0x78,0x35,0x41,0x2c,0x30,0x78,0x41,0x30,0x2c,0x30,0x78,0x35,0x32,0x2c,0x30,0x78,0x33,0x42,0x2c,0x30,0x78,0x44,0x36,0x2c,0x30, + 0x78,0x42,0x33,0x2c,0x30,0x78,0x32,0x39,0x2c,0x30,0x78,0x45,0x33,0x2c,0x30,0x78,0x32,0x46,0x2c,0x30,0x78,0x38,0x34,0x2c,0x0a,0x30,0x78,0x35,0x33,0x2c,0x30,0x78, + 0x44,0x31,0x2c,0x30,0x78,0x30,0x30,0x2c,0x30,0x78,0x45,0x44,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x46,0x43,0x2c,0x30,0x78,0x42,0x31,0x2c,0x30,0x78,0x35,0x42, + 0x2c,0x30,0x78,0x36,0x41,0x2c,0x30,0x78,0x43,0x42,0x2c,0x30,0x78,0x42,0x45,0x2c,0x30,0x78,0x33,0x39,0x2c,0x30,0x78,0x34,0x41,0x2c,0x30,0x78,0x34,0x43,0x2c,0x30, + 0x78,0x35,0x38,0x2c,0x30,0x78,0x43,0x46,0x2c,0x0a,0x30,0x78,0x44,0x30,0x2c,0x30,0x78,0x45,0x46,0x2c,0x30,0x78,0x41,0x41,0x2c,0x30,0x78,0x46,0x42,0x2c,0x30,0x78, + 0x34,0x33,0x2c,0x30,0x78,0x34,0x44,0x2c,0x30,0x78,0x33,0x33,0x2c,0x30,0x78,0x38,0x35,0x2c,0x30,0x78,0x34,0x35,0x2c,0x30,0x78,0x46,0x39,0x2c,0x30,0x78,0x30,0x32, + 0x2c,0x30,0x78,0x37,0x46,0x2c,0x30,0x78,0x35,0x30,0x2c,0x30,0x78,0x33,0x43,0x2c,0x30,0x78,0x39,0x46,0x2c,0x30,0x78,0x41,0x38,0x2c,0x0a,0x30,0x78,0x35,0x31,0x2c, + 0x30,0x78,0x41,0x33,0x2c,0x30,0x78,0x34,0x30,0x2c,0x30,0x78,0x38,0x46,0x2c,0x30,0x78,0x39,0x32,0x2c,0x30,0x78,0x39,0x44,0x2c,0x30,0x78,0x33,0x38,0x2c,0x30,0x78, + 0x46,0x35,0x2c,0x30,0x78,0x42,0x43,0x2c,0x30,0x78,0x42,0x36,0x2c,0x30,0x78,0x44,0x41,0x2c,0x30,0x78,0x32,0x31,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x46,0x46, + 0x2c,0x30,0x78,0x46,0x33,0x2c,0x30,0x78,0x44,0x32,0x2c,0x0a,0x30,0x78,0x43,0x44,0x2c,0x30,0x78,0x30,0x43,0x2c,0x30,0x78,0x31,0x33,0x2c,0x30,0x78,0x45,0x43,0x2c, + 0x30,0x78,0x35,0x46,0x2c,0x30,0x78,0x39,0x37,0x2c,0x30,0x78,0x34,0x34,0x2c,0x30,0x78,0x31,0x37,0x2c,0x30,0x78,0x43,0x34,0x2c,0x30,0x78,0x41,0x37,0x2c,0x30,0x78, + 0x37,0x45,0x2c,0x30,0x78,0x33,0x44,0x2c,0x30,0x78,0x36,0x34,0x2c,0x30,0x78,0x35,0x44,0x2c,0x30,0x78,0x31,0x39,0x2c,0x30,0x78,0x37,0x33,0x2c,0x0a,0x30,0x78,0x36, + 0x30,0x2c,0x30,0x78,0x38,0x31,0x2c,0x30,0x78,0x34,0x46,0x2c,0x30,0x78,0x44,0x43,0x2c,0x30,0x78,0x32,0x32,0x2c,0x30,0x78,0x32,0x41,0x2c,0x30,0x78,0x39,0x30,0x2c, + 0x30,0x78,0x38,0x38,0x2c,0x30,0x78,0x34,0x36,0x2c,0x30,0x78,0x45,0x45,0x2c,0x30,0x78,0x42,0x38,0x2c,0x30,0x78,0x31,0x34,0x2c,0x30,0x78,0x44,0x45,0x2c,0x30,0x78, + 0x35,0x45,0x2c,0x30,0x78,0x30,0x42,0x2c,0x30,0x78,0x44,0x42,0x2c,0x0a,0x30,0x78,0x45,0x30,0x2c,0x30,0x78,0x33,0x32,0x2c,0x30,0x78,0x33,0x41,0x2c,0x30,0x78,0x30, + 0x41,0x2c,0x30,0x78,0x34,0x39,0x2c,0x30,0x78,0x30,0x36,0x2c,0x30,0x78,0x32,0x34,0x2c,0x30,0x78,0x35,0x43,0x2c,0x30,0x78,0x43,0x32,0x2c,0x30,0x78,0x44,0x33,0x2c, + 0x30,0x78,0x41,0x43,0x2c,0x30,0x78,0x36,0x32,0x2c,0x30,0x78,0x39,0x31,0x2c,0x30,0x78,0x39,0x35,0x2c,0x30,0x78,0x45,0x34,0x2c,0x30,0x78,0x37,0x39,0x2c,0x0a,0x30, + 0x78,0x45,0x37,0x2c,0x30,0x78,0x43,0x38,0x2c,0x30,0x78,0x33,0x37,0x2c,0x30,0x78,0x36,0x44,0x2c,0x30,0x78,0x38,0x44,0x2c,0x30,0x78,0x44,0x35,0x2c,0x30,0x78,0x34, + 0x45,0x2c,0x30,0x78,0x41,0x39,0x2c,0x30,0x78,0x36,0x43,0x2c,0x30,0x78,0x35,0x36,0x2c,0x30,0x78,0x46,0x34,0x2c,0x30,0x78,0x45,0x41,0x2c,0x30,0x78,0x36,0x35,0x2c, + 0x30,0x78,0x37,0x41,0x2c,0x30,0x78,0x41,0x45,0x2c,0x30,0x78,0x30,0x38,0x2c,0x0a,0x30,0x78,0x42,0x41,0x2c,0x30,0x78,0x37,0x38,0x2c,0x30,0x78,0x32,0x35,0x2c,0x30, + 0x78,0x32,0x45,0x2c,0x30,0x78,0x31,0x43,0x2c,0x30,0x78,0x41,0x36,0x2c,0x30,0x78,0x42,0x34,0x2c,0x30,0x78,0x43,0x36,0x2c,0x30,0x78,0x45,0x38,0x2c,0x30,0x78,0x44, + 0x44,0x2c,0x30,0x78,0x37,0x34,0x2c,0x30,0x78,0x31,0x46,0x2c,0x30,0x78,0x34,0x42,0x2c,0x30,0x78,0x42,0x44,0x2c,0x30,0x78,0x38,0x42,0x2c,0x30,0x78,0x38,0x41,0x2c, + 0x0a,0x30,0x78,0x37,0x30,0x2c,0x30,0x78,0x33,0x45,0x2c,0x30,0x78,0x42,0x35,0x2c,0x30,0x78,0x36,0x36,0x2c,0x30,0x78,0x34,0x38,0x2c,0x30,0x78,0x30,0x33,0x2c,0x30, + 0x78,0x46,0x36,0x2c,0x30,0x78,0x30,0x45,0x2c,0x30,0x78,0x36,0x31,0x2c,0x30,0x78,0x33,0x35,0x2c,0x30,0x78,0x35,0x37,0x2c,0x30,0x78,0x42,0x39,0x2c,0x30,0x78,0x38, + 0x36,0x2c,0x30,0x78,0x43,0x31,0x2c,0x30,0x78,0x31,0x44,0x2c,0x30,0x78,0x39,0x45,0x2c,0x0a,0x30,0x78,0x45,0x31,0x2c,0x30,0x78,0x46,0x38,0x2c,0x30,0x78,0x39,0x38, + 0x2c,0x30,0x78,0x31,0x31,0x2c,0x30,0x78,0x36,0x39,0x2c,0x30,0x78,0x44,0x39,0x2c,0x30,0x78,0x38,0x45,0x2c,0x30,0x78,0x39,0x34,0x2c,0x30,0x78,0x39,0x42,0x2c,0x30, + 0x78,0x31,0x45,0x2c,0x30,0x78,0x38,0x37,0x2c,0x30,0x78,0x45,0x39,0x2c,0x30,0x78,0x43,0x45,0x2c,0x30,0x78,0x35,0x35,0x2c,0x30,0x78,0x32,0x38,0x2c,0x30,0x78,0x44, + 0x46,0x2c,0x0a,0x30,0x78,0x38,0x43,0x2c,0x30,0x78,0x41,0x31,0x2c,0x30,0x78,0x38,0x39,0x2c,0x30,0x78,0x30,0x44,0x2c,0x30,0x78,0x42,0x46,0x2c,0x30,0x78,0x45,0x36, + 0x2c,0x30,0x78,0x34,0x32,0x2c,0x30,0x78,0x36,0x38,0x2c,0x30,0x78,0x34,0x31,0x2c,0x30,0x78,0x39,0x39,0x2c,0x30,0x78,0x32,0x44,0x2c,0x30,0x78,0x30,0x46,0x2c,0x30, + 0x78,0x42,0x30,0x2c,0x30,0x78,0x35,0x34,0x2c,0x30,0x78,0x42,0x42,0x2c,0x30,0x78,0x31,0x36,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x75, + 0x62,0x57,0x6f,0x72,0x64,0x28,0x69,0x6e,0x77,0x29,0x20,0x28,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x33,0x29,0x5d,0x20, + 0x3c,0x3c,0x20,0x32,0x34,0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x32,0x29,0x5d,0x20,0x3c,0x3c,0x20, + 0x31,0x36,0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x31,0x29,0x5d,0x20,0x3c,0x3c,0x20,0x38,0x29,0x20, + 0x7c,0x20,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x30,0x29,0x5d,0x29,0x0a,0x76,0x6f,0x69,0x64,0x20,0x41,0x45,0x53,0x45,0x78, + 0x70,0x61,0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6b,0x65,0x79,0x62,0x75,0x66,0x29,0x0a,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x75,0x69,0x6e,0x74,0x20,0x63,0x3d,0x38,0x2c,0x69,0x3d,0x31,0x3b,0x20,0x63,0x3c,0x34,0x30,0x3b,0x20,0x2b,0x2b,0x63,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20, + 0x74,0x3d,0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x7c,0x7c,0x28,0x28,0x63,0x26,0x37,0x29,0x3d,0x3d,0x34,0x29,0x29,0x3f,0x53,0x75,0x62,0x57,0x6f,0x72,0x64, + 0x28,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x29,0x3a,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x62,0x75, + 0x66,0x5b,0x63,0x5d,0x3d,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x38,0x5d,0x5e,0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x3f,0x72,0x6f,0x74,0x61,0x74, + 0x65,0x28,0x74,0x2c,0x32,0x34,0x55,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x28,0x75,0x63,0x68,0x61,0x72,0x34,0x29,0x28,0x72,0x63,0x6f,0x6e,0x5b,0x69, + 0x2b,0x2b,0x5d,0x2c,0x30,0x55,0x2c,0x30,0x55,0x2c,0x30,0x55,0x29,0x29,0x3a,0x74,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69, + 0x66,0x6e,0x64,0x65,0x66,0x20,0x57,0x4f,0x4c,0x46,0x5f,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x43,0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x4f,0x4c,0x46, + 0x5f,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x43,0x4c,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70, + 0x73,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x61,0x6d, + 0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x78,0x6d,0x72, + 0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x69,0x74,0x61,0x6c,0x69,0x67,0x6e,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32, + 0x29,0x20,0x61,0x6d,0x64,0x5f,0x62,0x69,0x74,0x61,0x6c,0x69,0x67,0x6e,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29, + 0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x69, + 0x74,0x61,0x6c,0x69,0x67,0x6e,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x73,0x72,0x63,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x32,0x20,0x73,0x72,0x63,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x32,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74, + 0x32,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x73,0x30,0x3d,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x28,0x28,0x28,0x28,0x28, + 0x6c,0x6f,0x6e,0x67,0x29,0x73,0x72,0x63,0x30,0x2e,0x73,0x30,0x29,0x3c,0x3c,0x33,0x32,0x29,0x7c,0x28,0x6c,0x6f,0x6e,0x67,0x29,0x73,0x72,0x63,0x31,0x2e,0x73,0x30, + 0x29,0x3e,0x3e,0x28,0x73,0x72,0x63,0x32,0x29,0x29,0x3b,0x0a,0x72,0x65,0x73,0x75,0x6c,0x74,0x2e,0x73,0x31,0x3d,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x28,0x28,0x28, + 0x28,0x28,0x6c,0x6f,0x6e,0x67,0x29,0x73,0x72,0x63,0x30,0x2e,0x73,0x31,0x29,0x3c,0x3c,0x33,0x32,0x29,0x7c,0x28,0x6c,0x6f,0x6e,0x67,0x29,0x73,0x72,0x63,0x31,0x2e, + 0x73,0x31,0x29,0x3e,0x3e,0x28,0x73,0x72,0x63,0x32,0x29,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x23, + 0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x4b,0x53,0x5f,0x50,0x41,0x52,0x49,0x54,0x59,0x20,0x30,0x78, + 0x31,0x42,0x44,0x31,0x31,0x42,0x44,0x41,0x41,0x39,0x46,0x43,0x31,0x41,0x32,0x32,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f, + 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x4b,0x45,0x49,0x4e,0x32,0x35,0x36,0x5f,0x49,0x56,0x5b,0x38,0x5d,0x20,0x3d,0x0a, + 0x7b,0x0a,0x30,0x78,0x43,0x43,0x44,0x30,0x34,0x34,0x41,0x31,0x32,0x46,0x44,0x42,0x33,0x45,0x31,0x33,0x55,0x4c,0x2c,0x30,0x78,0x45,0x38,0x33,0x35,0x39,0x30,0x33, + 0x30,0x31,0x41,0x37,0x39,0x41,0x39,0x45,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x35,0x41,0x45,0x41,0x30,0x36,0x31,0x34,0x46,0x38,0x31,0x36,0x45,0x36,0x46,0x55, + 0x4c,0x2c,0x30,0x78,0x32,0x41,0x32,0x37,0x36,0x37,0x41,0x34,0x41,0x45,0x39,0x42,0x39,0x34,0x44,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x45,0x43,0x30,0x36,0x30,0x32, + 0x35,0x45,0x37,0x34,0x44,0x44,0x37,0x36,0x38,0x33,0x55,0x4c,0x2c,0x30,0x78,0x45,0x37,0x41,0x34,0x33,0x36,0x43,0x44,0x43,0x34,0x37,0x34,0x36,0x32,0x35,0x31,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x43,0x33,0x36,0x46,0x42,0x41,0x46,0x39,0x33,0x39,0x33,0x41,0x44,0x31,0x38,0x35,0x55,0x4c,0x2c,0x30,0x78,0x33,0x45,0x45,0x44,0x42,0x41, + 0x31,0x38,0x33,0x33,0x45,0x44,0x46,0x43,0x31,0x33,0x55,0x4c,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63, + 0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x4b,0x45,0x49,0x4e,0x35,0x31,0x32,0x5f,0x32,0x35,0x36,0x5f,0x49,0x56,0x5b,0x38,0x5d, + 0x20,0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x43,0x43,0x44,0x30,0x34,0x34,0x41,0x31,0x32,0x46,0x44,0x42,0x33,0x45,0x31,0x33,0x55,0x4c,0x2c,0x30,0x78,0x45,0x38,0x33,0x35, + 0x39,0x30,0x33,0x30,0x31,0x41,0x37,0x39,0x41,0x39,0x45,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x35,0x41,0x45,0x41,0x30,0x36,0x31,0x34,0x46,0x38,0x31,0x36,0x45, + 0x36,0x46,0x55,0x4c,0x2c,0x30,0x78,0x32,0x41,0x32,0x37,0x36,0x37,0x41,0x34,0x41,0x45,0x39,0x42,0x39,0x34,0x44,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x45,0x43,0x30, + 0x36,0x30,0x32,0x35,0x45,0x37,0x34,0x44,0x44,0x37,0x36,0x38,0x33,0x55,0x4c,0x2c,0x30,0x78,0x45,0x37,0x41,0x34,0x33,0x36,0x43,0x44,0x43,0x34,0x37,0x34,0x36,0x32, + 0x35,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x33,0x36,0x46,0x42,0x41,0x46,0x39,0x33,0x39,0x33,0x41,0x44,0x31,0x38,0x35,0x55,0x4c,0x2c,0x30,0x78,0x33,0x45,0x45, + 0x44,0x42,0x41,0x31,0x38,0x33,0x33,0x45,0x44,0x46,0x43,0x31,0x33,0x55,0x4c,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x4b,0x45,0x49,0x4e, + 0x5f,0x49,0x4e,0x4a,0x45,0x43,0x54,0x5f,0x4b,0x45,0x59,0x28,0x70,0x2c,0x20,0x73,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x70,0x2b,0x3d,0x68,0x3b,0x20,0x5c, + 0x0a,0x70,0x2e,0x73,0x35,0x2b,0x3d,0x74,0x5b,0x73,0x20,0x25,0x20,0x33,0x5d,0x3b,0x20,0x5c,0x0a,0x70,0x2e,0x73,0x36,0x2b,0x3d,0x74,0x5b,0x28,0x73,0x2b,0x31,0x29, + 0x20,0x25,0x20,0x33,0x5d,0x3b,0x20,0x5c,0x0a,0x70,0x2e,0x73,0x37,0x2b,0x3d,0x73,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x28,0x30,0x29,0x0a,0x75, + 0x6c,0x6f,0x6e,0x67,0x20,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x52,0x4f,0x54,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x78,0x2c,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x79,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x79,0x3c,0x33,0x32,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x28,0x61, + 0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x69,0x74,0x61,0x6c,0x69,0x67,0x6e,0x28,0x78,0x2c,0x78,0x2e,0x73, + 0x31,0x30,0x2c,0x33,0x32,0x2d,0x79,0x29,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x28,0x61,0x73,0x5f,0x75, + 0x6c,0x6f,0x6e,0x67,0x28,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x69,0x74,0x61,0x6c,0x69,0x67,0x6e,0x28,0x78,0x2e,0x73,0x31,0x30,0x2c,0x78,0x2c, + 0x33,0x32,0x2d,0x28,0x79,0x2d,0x33,0x32,0x29,0x29,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x76,0x6f,0x69,0x64,0x20,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38, + 0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x20,0x2a,0x70,0x76,0x30,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x20,0x2a,0x70,0x76,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x72,0x63,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x63,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x20,0x72,0x63,0x32,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x63,0x33,0x29,0x0a,0x7b,0x0a,0x2a,0x70,0x76,0x30,0x2b,0x3d,0x2a,0x70, + 0x76,0x31,0x3b,0x0a,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x30,0x3d,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x52,0x4f,0x54,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32, + 0x28,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x30,0x29,0x2c,0x72,0x63,0x30,0x29,0x3b,0x0a,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x31,0x3d,0x53,0x4b,0x45,0x49, + 0x4e,0x5f,0x52,0x4f,0x54,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x31,0x29,0x2c,0x72,0x63,0x31,0x29,0x3b,0x0a, + 0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x32,0x3d,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x52,0x4f,0x54,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x28,0x2a,0x70, + 0x76,0x31,0x29,0x2e,0x73,0x32,0x29,0x2c,0x72,0x63,0x32,0x29,0x3b,0x0a,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x33,0x3d,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x52,0x4f, + 0x54,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x28,0x2a,0x70,0x76,0x31,0x29,0x2e,0x73,0x33,0x29,0x2c,0x72,0x63,0x33,0x29,0x3b,0x0a,0x2a,0x70,0x76,0x31, + 0x20,0x5e,0x3d,0x20,0x2a,0x70,0x76,0x30,0x3b,0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x53,0x6b,0x65,0x69,0x6e,0x45,0x76,0x65,0x6e,0x52,0x6f,0x75,0x6e, + 0x64,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x70,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x68,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x74,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x29,0x0a,0x7b,0x0a,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x49, + 0x4e,0x4a,0x45,0x43,0x54,0x5f,0x4b,0x45,0x59,0x28,0x70,0x2c,0x73,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x20,0x70,0x76,0x30,0x3d,0x70,0x2e,0x65,0x76,0x65, + 0x6e,0x2c,0x70,0x76,0x31,0x3d,0x70,0x2e,0x6f,0x64,0x64,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31, + 0x2c,0x34,0x36,0x2c,0x33,0x36,0x2c,0x31,0x39,0x2c,0x33,0x37,0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28, + 0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70, + 0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38, + 0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x33,0x33,0x2c,0x32,0x37,0x2c,0x31,0x34,0x2c,0x34,0x32,0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75, + 0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31, + 0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b, + 0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x31,0x37,0x2c,0x34,0x39,0x2c,0x33,0x36,0x2c,0x33,0x39, + 0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c,0x32,0x2c, + 0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28, + 0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x34, + 0x34,0x2c,0x39,0x2c,0x35,0x34,0x2c,0x35,0x36,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x28,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x32,0x28,0x70,0x76,0x30,0x2c, + 0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x29,0x28,0x31,0x2c,0x34,0x2c,0x32,0x2c,0x37,0x2c,0x33,0x2c,0x36,0x2c,0x30,0x2c,0x35,0x29,0x29,0x29,0x3b, + 0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x53,0x6b,0x65,0x69,0x6e,0x4f,0x64,0x64,0x52,0x6f,0x75,0x6e,0x64,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x70, + 0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x68,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x74,0x2c,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x29,0x0a,0x7b,0x0a,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x49,0x4e,0x4a,0x45,0x43,0x54,0x5f,0x4b,0x45,0x59,0x28, + 0x70,0x2c,0x73,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x20,0x70,0x76,0x30,0x3d,0x70,0x2e,0x65,0x76,0x65,0x6e,0x2c,0x70,0x76,0x31,0x3d,0x70,0x2e,0x6f,0x64, + 0x64,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x33,0x39,0x2c,0x33,0x30,0x2c,0x33,0x34,0x2c, + 0x32,0x34,0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c, + 0x32,0x2c,0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34, + 0x29,0x28,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31, + 0x2c,0x31,0x33,0x2c,0x35,0x30,0x2c,0x31,0x30,0x2c,0x31,0x37,0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28, + 0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70, + 0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b,0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38, + 0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x32,0x35,0x2c,0x32,0x39,0x2c,0x33,0x39,0x2c,0x34,0x33,0x29,0x3b,0x0a,0x70,0x76,0x30,0x3d,0x73,0x68,0x75, + 0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x30,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x70,0x76,0x31, + 0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x34,0x29,0x28,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x29,0x29,0x3b, + 0x0a,0x53,0x6b,0x65,0x69,0x6e,0x4d,0x69,0x78,0x38,0x28,0x26,0x70,0x76,0x30,0x2c,0x26,0x70,0x76,0x31,0x2c,0x38,0x2c,0x33,0x35,0x2c,0x35,0x36,0x2c,0x32,0x32,0x29, + 0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x28,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x32,0x28,0x70,0x76,0x30,0x2c,0x70,0x76,0x31,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67, + 0x38,0x29,0x28,0x31,0x2c,0x34,0x2c,0x32,0x2c,0x37,0x2c,0x33,0x2c,0x36,0x2c,0x30,0x2c,0x35,0x29,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20, + 0x53,0x6b,0x65,0x69,0x6e,0x35,0x31,0x32,0x42,0x6c,0x6f,0x63,0x6b,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x70,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x68,0x2c, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x38,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x74,0x29,0x0a,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67, + 0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x31,0x38,0x3b,0x20,0x2b,0x2b,0x69, + 0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x53,0x6b,0x65,0x69,0x6e,0x45,0x76,0x65,0x6e,0x52,0x6f,0x75,0x6e,0x64,0x28,0x70,0x2c,0x68,0x2c,0x74,0x2c,0x69,0x29,0x3b,0x0a,0x2b, + 0x2b,0x69,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d,0x70,0x3d,0x68,0x2e,0x73,0x30,0x3b,0x0a,0x68,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x68,0x2c, + 0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x68,0x2e,0x73,0x37, + 0x3d,0x68,0x38,0x3b,0x0a,0x68,0x38,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x70,0x3d,0x53,0x6b,0x65,0x69,0x6e,0x4f,0x64,0x64,0x52,0x6f,0x75,0x6e,0x64,0x28,0x70,0x2c,0x68, + 0x2c,0x74,0x2c,0x69,0x29,0x3b,0x0a,0x74,0x6d,0x70,0x3d,0x68,0x2e,0x73,0x30,0x3b,0x0a,0x68,0x3d,0x73,0x68,0x75,0x66,0x66,0x6c,0x65,0x28,0x68,0x2c,0x28,0x75,0x6c, + 0x6f,0x6e,0x67,0x38,0x29,0x28,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x29,0x29,0x3b,0x0a,0x68,0x2e,0x73,0x37,0x3d,0x68,0x38, + 0x3b,0x0a,0x68,0x38,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x7d,0x0a,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x49,0x4e,0x4a,0x45,0x43,0x54,0x5f,0x4b,0x45,0x59,0x28,0x70,0x2c,0x31, + 0x38,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x28,0x70,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x53,0x50,0x48,0x5f,0x4a,0x48,0x5f,0x36,0x34,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x50,0x48,0x5f,0x4c,0x49,0x54,0x54,0x4c,0x45,0x5f,0x45, + 0x4e,0x44,0x49,0x41,0x4e,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x09,0x78,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x09,0x78,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x69,0x6e,0x74,0x20,0x73, + 0x70,0x68,0x5f,0x75,0x33,0x32,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x3b,0x0a,0x23, + 0x69,0x66,0x20,0x53,0x50,0x48,0x5f,0x4c,0x49,0x54,0x54,0x4c,0x45,0x5f,0x45,0x4e,0x44,0x49,0x41,0x4e,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x33,0x32, + 0x65,0x28,0x78,0x29,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x32,0x34,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53, + 0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x3e,0x3e,0x38,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30, + 0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x3c,0x3c,0x38,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28, + 0x30,0x78,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x3c,0x3c,0x32, + 0x34,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x64,0x65,0x63,0x33,0x32,0x65,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x65,0x64,0x20,0x73,0x70,0x68,0x5f,0x64,0x65,0x63,0x33,0x32,0x6c,0x65,0x5f,0x61,0x6c,0x69,0x67, + 0x6e,0x65,0x64,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x6e,0x63,0x33,0x32,0x65,0x20,0x73,0x70,0x68,0x5f,0x65,0x6e,0x63,0x33,0x32,0x6c,0x65,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x36,0x34,0x65,0x28,0x78,0x29,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x35, + 0x36,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3e,0x3e,0x34,0x30,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34, + 0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f, + 0x43,0x36,0x34,0x28,0x78,0x29,0x3e,0x3e,0x32,0x34,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x46,0x46,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3e,0x3e,0x38,0x29,0x26,0x53,0x50, + 0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28, + 0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x38,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30, + 0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x32, + 0x34,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20, + 0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x34,0x30,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78, + 0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34, + 0x28,0x78,0x29,0x3c,0x3c,0x35,0x36,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x29,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x65,0x63,0x36,0x34,0x65,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x65,0x64,0x20,0x73,0x70, + 0x68,0x5f,0x64,0x65,0x63,0x36,0x34,0x6c,0x65,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x65,0x64,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x6e,0x63,0x36,0x34,0x65, + 0x20,0x73,0x70,0x68,0x5f,0x65,0x6e,0x63,0x36,0x34,0x6c,0x65,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x33,0x32,0x65,0x28, + 0x78,0x29,0x20,0x53,0x50,0x48,0x5f,0x43,0x33,0x32,0x28,0x78,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x65,0x63,0x33,0x32,0x65,0x5f,0x61,0x6c,0x69, + 0x67,0x6e,0x65,0x64,0x20,0x73,0x70,0x68,0x5f,0x64,0x65,0x63,0x33,0x32,0x62,0x65,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x65,0x64,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x65,0x6e,0x63,0x33,0x32,0x65,0x20,0x73,0x70,0x68,0x5f,0x65,0x6e,0x63,0x33,0x32,0x62,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x36,0x34,0x65, + 0x28,0x78,0x29,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x65,0x63,0x36,0x34,0x65,0x5f,0x61,0x6c, + 0x69,0x67,0x6e,0x65,0x64,0x20,0x73,0x70,0x68,0x5f,0x64,0x65,0x63,0x36,0x34,0x62,0x65,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x65,0x64,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x65,0x6e,0x63,0x36,0x34,0x65,0x20,0x73,0x70,0x68,0x5f,0x65,0x6e,0x63,0x36,0x34,0x62,0x65,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x53,0x62,0x28,0x78,0x30,0x2c,0x20,0x78,0x31,0x2c,0x20,0x78,0x32,0x2c,0x20,0x78,0x33,0x2c,0x20,0x63,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c, + 0x0a,0x78,0x33,0x3d,0x7e,0x78,0x33,0x3b,0x20,0x5c,0x0a,0x78,0x30,0x20,0x5e,0x3d,0x20,0x28,0x63,0x29,0x26,0x7e,0x78,0x32,0x3b,0x20,0x5c,0x0a,0x74,0x6d,0x70,0x3d, + 0x28,0x63,0x29,0x5e,0x28,0x78,0x30,0x26,0x78,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x78,0x30,0x20,0x5e,0x3d,0x20,0x78,0x32,0x26,0x78,0x33,0x3b,0x20,0x5c,0x0a,0x78,0x33, + 0x20,0x5e,0x3d,0x20,0x7e,0x78,0x31,0x26,0x78,0x32,0x3b,0x20,0x5c,0x0a,0x78,0x31,0x20,0x5e,0x3d,0x20,0x78,0x30,0x26,0x78,0x32,0x3b,0x20,0x5c,0x0a,0x78,0x32,0x20, + 0x5e,0x3d,0x20,0x78,0x30,0x26,0x7e,0x78,0x33,0x3b,0x20,0x5c,0x0a,0x78,0x30,0x20,0x5e,0x3d,0x20,0x78,0x31,0x7c,0x78,0x33,0x3b,0x20,0x5c,0x0a,0x78,0x33,0x20,0x5e, + 0x3d,0x20,0x78,0x31,0x26,0x78,0x32,0x3b,0x20,0x5c,0x0a,0x78,0x31,0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x26,0x78,0x30,0x3b,0x20,0x5c,0x0a,0x78,0x32,0x20,0x5e,0x3d, + 0x20,0x74,0x6d,0x70,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x62,0x28,0x78, + 0x30,0x2c,0x20,0x78,0x31,0x2c,0x20,0x78,0x32,0x2c,0x20,0x78,0x33,0x2c,0x20,0x78,0x34,0x2c,0x20,0x78,0x35,0x2c,0x20,0x78,0x36,0x2c,0x20,0x78,0x37,0x29,0x20,0x64, + 0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x78,0x34,0x20,0x5e,0x3d,0x20,0x78,0x31,0x3b,0x20,0x5c,0x0a,0x78,0x35,0x20,0x5e,0x3d,0x20,0x78,0x32,0x3b,0x20,0x5c,0x0a,0x78,0x36, + 0x20,0x5e,0x3d,0x20,0x78,0x33,0x5e,0x78,0x30,0x3b,0x20,0x5c,0x0a,0x78,0x37,0x20,0x5e,0x3d,0x20,0x78,0x30,0x3b,0x20,0x5c,0x0a,0x78,0x30,0x20,0x5e,0x3d,0x20,0x78, + 0x35,0x3b,0x20,0x5c,0x0a,0x78,0x31,0x20,0x5e,0x3d,0x20,0x78,0x36,0x3b,0x20,0x5c,0x0a,0x78,0x32,0x20,0x5e,0x3d,0x20,0x78,0x37,0x5e,0x78,0x34,0x3b,0x20,0x5c,0x0a, + 0x78,0x33,0x20,0x5e,0x3d,0x20,0x78,0x34,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x43,0x5b,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x30,0x78, + 0x36,0x37,0x46,0x38,0x31,0x35,0x44,0x46,0x41,0x32,0x44,0x45,0x44,0x35,0x37,0x32,0x55,0x4c,0x2c,0x30,0x78,0x35,0x37,0x31,0x35,0x32,0x33,0x42,0x37,0x30,0x41,0x31, + 0x35,0x38,0x34,0x37,0x42,0x55,0x4c,0x2c,0x30,0x78,0x46,0x36,0x38,0x37,0x35,0x41,0x34,0x44,0x39,0x30,0x44,0x36,0x41,0x42,0x38,0x31,0x55,0x4c,0x2c,0x30,0x78,0x34, + 0x30,0x32,0x42,0x44,0x31,0x43,0x33,0x43,0x35,0x34,0x46,0x39,0x46,0x34,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x43,0x46,0x41,0x34,0x35,0x35,0x43,0x45,0x30,0x33, + 0x41,0x39,0x38,0x45,0x41,0x55,0x4c,0x2c,0x30,0x78,0x39,0x41,0x39,0x39,0x42,0x32,0x36,0x36,0x39,0x39,0x44,0x32,0x43,0x35,0x30,0x33,0x55,0x4c,0x2c,0x30,0x78,0x38, + 0x41,0x35,0x33,0x42,0x42,0x46,0x32,0x42,0x34,0x39,0x36,0x30,0x32,0x36,0x36,0x55,0x4c,0x2c,0x30,0x78,0x33,0x31,0x41,0x32,0x44,0x42,0x38,0x38,0x31,0x41,0x31,0x34, + 0x35,0x36,0x42,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x42,0x30,0x45,0x31,0x39,0x39,0x41,0x35,0x43,0x35,0x41,0x41,0x33,0x30,0x33,0x55,0x4c,0x2c,0x30,0x78,0x31, + 0x30,0x34,0x34,0x43,0x31,0x38,0x37,0x30,0x41,0x42,0x32,0x33,0x46,0x34,0x30,0x55,0x4c,0x2c,0x30,0x78,0x31,0x44,0x39,0x35,0x39,0x45,0x38,0x34,0x38,0x30,0x31,0x39, + 0x30,0x35,0x31,0x43,0x55,0x4c,0x2c,0x30,0x78,0x44,0x43,0x43,0x44,0x45,0x37,0x35,0x45,0x41,0x44,0x45,0x42,0x33,0x33,0x36,0x46,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x34, + 0x31,0x36,0x42,0x42,0x46,0x30,0x32,0x39,0x32,0x31,0x33,0x42,0x41,0x31,0x30,0x55,0x4c,0x2c,0x30,0x78,0x44,0x30,0x32,0x37,0x42,0x42,0x46,0x37,0x31,0x35,0x36,0x35, + 0x37,0x38,0x44,0x43,0x55,0x4c,0x2c,0x30,0x78,0x35,0x30,0x37,0x38,0x41,0x41,0x33,0x37,0x33,0x39,0x38,0x31,0x32,0x43,0x30,0x41,0x55,0x4c,0x2c,0x30,0x78,0x44,0x33, + 0x39,0x31,0x30,0x30,0x34,0x31,0x44,0x32,0x42,0x46,0x31,0x41,0x33,0x46,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x30,0x37,0x45,0x43,0x43,0x46,0x36,0x30,0x44,0x35,0x41, + 0x32,0x44,0x34,0x32,0x55,0x4c,0x2c,0x30,0x78,0x43,0x45,0x39,0x37,0x43,0x30,0x39,0x32,0x39,0x43,0x39,0x46,0x36,0x32,0x44,0x44,0x55,0x4c,0x2c,0x30,0x78,0x41,0x43, + 0x34,0x34,0x32,0x42,0x43,0x37,0x30,0x42,0x41,0x37,0x35,0x43,0x31,0x38,0x55,0x4c,0x2c,0x30,0x78,0x32,0x33,0x46,0x43,0x43,0x36,0x36,0x33,0x44,0x36,0x36,0x35,0x44, + 0x46,0x44,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x41,0x42,0x38,0x45,0x30,0x39,0x45,0x30,0x33,0x36,0x43,0x36,0x45,0x39,0x37,0x55,0x4c,0x2c,0x30,0x78,0x41,0x38, + 0x45,0x43,0x36,0x43,0x34,0x34,0x37,0x45,0x34,0x35,0x30,0x35,0x32,0x31,0x55,0x4c,0x2c,0x30,0x78,0x46,0x41,0x36,0x31,0x38,0x45,0x35,0x44,0x42,0x42,0x30,0x33,0x46, + 0x31,0x45,0x45,0x55,0x4c,0x2c,0x30,0x78,0x39,0x37,0x38,0x31,0x38,0x33,0x39,0x34,0x42,0x32,0x39,0x37,0x39,0x36,0x46,0x44,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x46, + 0x33,0x30,0x30,0x33,0x44,0x42,0x33,0x37,0x38,0x35,0x38,0x45,0x34,0x41,0x55,0x4c,0x2c,0x30,0x78,0x39,0x35,0x36,0x41,0x39,0x46,0x46,0x42,0x32,0x44,0x38,0x44,0x36, + 0x37,0x32,0x41,0x55,0x4c,0x2c,0x30,0x78,0x36,0x43,0x36,0x39,0x42,0x38,0x46,0x38,0x38,0x31,0x37,0x33,0x46,0x45,0x38,0x41,0x55,0x4c,0x2c,0x30,0x78,0x31,0x34,0x34, + 0x32,0x37,0x46,0x43,0x30,0x34,0x36,0x37,0x32,0x43,0x37,0x38,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x34,0x35,0x45,0x43,0x37,0x42,0x44,0x38,0x46,0x31,0x35,0x46, + 0x34,0x43,0x35,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x42,0x42,0x31,0x31,0x38,0x46,0x41,0x37,0x36,0x46,0x34,0x34,0x37,0x35,0x55,0x4c,0x2c,0x30,0x78,0x42,0x43,0x38, + 0x38,0x45,0x34,0x41,0x45,0x42,0x37,0x37,0x35,0x44,0x45,0x35,0x32,0x55,0x4c,0x2c,0x30,0x78,0x46,0x34,0x41,0x33,0x41,0x36,0x39,0x38,0x31,0x45,0x30,0x30,0x42,0x38, + 0x38,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x35,0x36,0x33,0x41,0x33,0x41,0x39,0x33,0x33,0x38,0x46,0x46,0x34,0x38,0x45,0x55,0x4c,0x2c,0x30,0x78,0x38,0x39,0x46, + 0x39,0x42,0x37,0x44,0x35,0x32,0x34,0x35,0x36,0x35,0x46,0x41,0x41,0x55,0x4c,0x2c,0x30,0x78,0x46,0x44,0x45,0x30,0x35,0x41,0x37,0x43,0x32,0x30,0x45,0x44,0x46,0x31, + 0x42,0x36,0x55,0x4c,0x2c,0x30,0x78,0x33,0x36,0x32,0x43,0x34,0x32,0x30,0x36,0x35,0x41,0x45,0x39,0x43,0x41,0x33,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x44,0x39, + 0x38,0x46,0x45,0x34,0x45,0x34,0x33,0x33,0x35,0x32,0x39,0x43,0x45,0x55,0x4c,0x2c,0x30,0x78,0x41,0x37,0x34,0x42,0x39,0x41,0x37,0x33,0x37,0x34,0x46,0x39,0x33,0x41, + 0x35,0x33,0x55,0x4c,0x2c,0x30,0x78,0x38,0x36,0x38,0x31,0x34,0x45,0x36,0x46,0x35,0x39,0x31,0x46,0x46,0x35,0x44,0x30,0x55,0x4c,0x2c,0x30,0x78,0x39,0x46,0x35,0x41, + 0x44,0x38,0x41,0x46,0x38,0x31,0x41,0x44,0x39,0x44,0x30,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x41,0x36,0x32,0x33,0x34,0x45,0x45,0x36,0x37,0x30,0x36,0x30,0x35, + 0x41,0x37,0x55,0x4c,0x2c,0x30,0x78,0x32,0x37,0x31,0x37,0x42,0x39,0x36,0x45,0x42,0x45,0x32,0x38,0x30,0x42,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x33,0x46,0x31,0x30, + 0x38,0x30,0x43,0x36,0x32,0x36,0x30,0x37,0x37,0x34,0x34,0x37,0x55,0x4c,0x2c,0x30,0x78,0x37,0x42,0x34,0x38,0x37,0x45,0x43,0x36,0x36,0x46,0x37,0x45,0x41,0x30,0x45, + 0x30,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x30,0x41,0x34,0x46,0x38,0x34,0x41,0x41,0x35,0x30,0x41,0x35,0x35,0x30,0x44,0x55,0x4c,0x2c,0x30,0x78,0x39,0x45,0x46,0x31, + 0x38,0x45,0x39,0x37,0x39,0x46,0x45,0x37,0x45,0x33,0x39,0x31,0x55,0x4c,0x2c,0x30,0x78,0x44,0x34,0x38,0x44,0x36,0x30,0x35,0x30,0x38,0x31,0x37,0x32,0x37,0x36,0x38, + 0x36,0x55,0x4c,0x2c,0x30,0x78,0x36,0x32,0x42,0x30,0x45,0x35,0x46,0x33,0x34,0x31,0x35,0x41,0x39,0x45,0x37,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x41,0x32,0x30, + 0x35,0x34,0x34,0x30,0x45,0x43,0x31,0x46,0x39,0x46,0x46,0x43,0x55,0x4c,0x2c,0x30,0x78,0x38,0x34,0x43,0x39,0x46,0x34,0x43,0x45,0x30,0x30,0x31,0x41,0x45,0x34,0x45, + 0x33,0x55,0x4c,0x2c,0x30,0x78,0x44,0x38,0x39,0x35,0x46,0x41,0x39,0x44,0x46,0x35,0x39,0x34,0x44,0x37,0x34,0x46,0x55,0x4c,0x2c,0x30,0x78,0x41,0x35,0x35,0x34,0x43, + 0x33,0x32,0x34,0x31,0x31,0x37,0x45,0x32,0x45,0x35,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x38,0x36,0x45,0x46,0x45,0x42,0x44,0x32,0x38,0x37,0x32,0x44,0x46,0x35, + 0x42,0x55,0x4c,0x2c,0x30,0x78,0x42,0x32,0x43,0x34,0x41,0x35,0x30,0x46,0x45,0x32,0x37,0x46,0x46,0x35,0x37,0x38,0x55,0x4c,0x2c,0x30,0x78,0x32,0x45,0x44,0x33,0x34, + 0x39,0x45,0x45,0x45,0x46,0x37,0x43,0x38,0x39,0x30,0x35,0x55,0x4c,0x2c,0x30,0x78,0x37,0x46,0x35,0x39,0x32,0x38,0x45,0x42,0x38,0x35,0x39,0x33,0x37,0x45,0x34,0x34, + 0x55,0x4c,0x2c,0x0a,0x30,0x78,0x34,0x41,0x33,0x31,0x32,0x34,0x42,0x33,0x33,0x37,0x36,0x39,0x35,0x46,0x37,0x30,0x55,0x4c,0x2c,0x30,0x78,0x36,0x35,0x45,0x34,0x44, + 0x36,0x31,0x44,0x46,0x31,0x32,0x38,0x38,0x36,0x35,0x45,0x55,0x4c,0x2c,0x30,0x78,0x45,0x37,0x32,0x30,0x42,0x39,0x35,0x31,0x30,0x34,0x37,0x37,0x31,0x42,0x43,0x37, + 0x55,0x4c,0x2c,0x30,0x78,0x38,0x41,0x38,0x37,0x44,0x34,0x32,0x33,0x45,0x38,0x34,0x33,0x46,0x45,0x37,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x32,0x39,0x34,0x37, + 0x36,0x39,0x32,0x41,0x33,0x45,0x38,0x32,0x39,0x37,0x44,0x55,0x4c,0x2c,0x30,0x78,0x43,0x31,0x44,0x39,0x33,0x30,0x39,0x42,0x30,0x39,0x37,0x41,0x43,0x42,0x44,0x44, + 0x55,0x4c,0x2c,0x30,0x78,0x45,0x30,0x31,0x42,0x44,0x43,0x35,0x42,0x46,0x42,0x33,0x30,0x31,0x42,0x31,0x44,0x55,0x4c,0x2c,0x30,0x78,0x42,0x46,0x38,0x32,0x39,0x43, + 0x46,0x32,0x34,0x46,0x34,0x39,0x32,0x34,0x44,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x46,0x42,0x46,0x37,0x30,0x42,0x34,0x33,0x31,0x42,0x41,0x45,0x37,0x41,0x34, + 0x55,0x4c,0x2c,0x30,0x78,0x34,0x38,0x42,0x43,0x46,0x38,0x44,0x45,0x30,0x35,0x34,0x34,0x33,0x32,0x30,0x44,0x55,0x4c,0x2c,0x30,0x78,0x33,0x39,0x44,0x33,0x42,0x42, + 0x35,0x33,0x33,0x32,0x46,0x43,0x41,0x45,0x33,0x42,0x55,0x4c,0x2c,0x30,0x78,0x41,0x30,0x38,0x42,0x32,0x39,0x45,0x30,0x43,0x31,0x43,0x33,0x39,0x46,0x34,0x35,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x30,0x46,0x30,0x39,0x41,0x45,0x46,0x37,0x46,0x44,0x30,0x35,0x43,0x39,0x45,0x35,0x55,0x4c,0x2c,0x30,0x78,0x33,0x34,0x46,0x31,0x39,0x30, + 0x34,0x32,0x31,0x32,0x33,0x34,0x37,0x30,0x39,0x34,0x55,0x4c,0x2c,0x30,0x78,0x39,0x35,0x45,0x44,0x34,0x34,0x45,0x33,0x30,0x31,0x42,0x37,0x37,0x31,0x41,0x32,0x55, + 0x4c,0x2c,0x30,0x78,0x34,0x41,0x39,0x38,0x32,0x46,0x34,0x46,0x33,0x36,0x38,0x45,0x33,0x42,0x45,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x35,0x46,0x36,0x36,0x43, + 0x41,0x30,0x36,0x33,0x31,0x44,0x34,0x30,0x38,0x38,0x55,0x4c,0x2c,0x30,0x78,0x46,0x46,0x41,0x46,0x35,0x32,0x38,0x37,0x34,0x42,0x34,0x34,0x43,0x31,0x34,0x37,0x55, + 0x4c,0x2c,0x30,0x78,0x33,0x30,0x43,0x36,0x30,0x41,0x45,0x32,0x46,0x31,0x34,0x41,0x42,0x42,0x37,0x45,0x55,0x4c,0x2c,0x30,0x78,0x45,0x36,0x38,0x43,0x36,0x45,0x43, + 0x43,0x43,0x35,0x42,0x36,0x37,0x30,0x34,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x30,0x43,0x41,0x34,0x46,0x42,0x44,0x35,0x36,0x41,0x34,0x44,0x35,0x41,0x34,0x55, + 0x4c,0x2c,0x30,0x78,0x41,0x45,0x31,0x38,0x33,0x45,0x43,0x38,0x34,0x42,0x38,0x34,0x39,0x44,0x44,0x41,0x55,0x4c,0x2c,0x30,0x78,0x41,0x44,0x44,0x31,0x36,0x34,0x33, + 0x30,0x34,0x35,0x43,0x45,0x35,0x37,0x37,0x33,0x55,0x4c,0x2c,0x30,0x78,0x36,0x37,0x32,0x35,0x35,0x43,0x31,0x34,0x36,0x38,0x43,0x45,0x41,0x36,0x45,0x38,0x55,0x4c, + 0x2c,0x0a,0x30,0x78,0x31,0x36,0x45,0x31,0x30,0x45,0x43,0x42,0x46,0x32,0x38,0x43,0x44,0x41,0x41,0x33,0x55,0x4c,0x2c,0x30,0x78,0x39,0x41,0x39,0x39,0x39,0x34,0x39, + 0x41,0x35,0x38,0x30,0x36,0x45,0x39,0x33,0x33,0x55,0x4c,0x2c,0x30,0x78,0x37,0x42,0x38,0x34,0x36,0x46,0x43,0x32,0x32,0x30,0x42,0x32,0x36,0x30,0x31,0x46,0x55,0x4c, + 0x2c,0x30,0x78,0x31,0x38,0x38,0x35,0x44,0x31,0x41,0x30,0x37,0x46,0x41,0x43,0x43,0x45,0x44,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x33,0x31,0x39,0x44,0x44,0x38, + 0x44,0x41,0x31,0x35,0x42,0x35,0x39,0x33,0x32,0x55,0x4c,0x2c,0x30,0x78,0x34,0x36,0x42,0x34,0x41,0x35,0x41,0x41,0x43,0x30,0x31,0x43,0x39,0x41,0x35,0x30,0x55,0x4c, + 0x2c,0x30,0x78,0x42,0x41,0x36,0x42,0x30,0x34,0x45,0x34,0x36,0x37,0x36,0x33,0x33,0x44,0x39,0x46,0x55,0x4c,0x2c,0x30,0x78,0x37,0x45,0x45,0x45,0x35,0x36,0x30,0x42, + 0x41,0x42,0x31,0x39,0x43,0x41,0x46,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x34,0x32,0x31,0x32,0x38,0x41,0x39,0x45,0x41,0x37,0x39,0x42,0x31,0x31,0x46,0x55,0x4c, + 0x2c,0x30,0x78,0x45,0x45,0x35,0x31,0x33,0x36,0x33,0x42,0x33,0x35,0x46,0x37,0x42,0x44,0x45,0x39,0x55,0x4c,0x2c,0x30,0x78,0x37,0x36,0x44,0x33,0x35,0x30,0x37,0x35, + 0x35,0x41,0x41,0x43,0x35,0x37,0x31,0x44,0x55,0x4c,0x2c,0x30,0x78,0x30,0x31,0x37,0x30,0x37,0x44,0x41,0x33,0x46,0x45,0x43,0x32,0x34,0x36,0x33,0x41,0x55,0x4c,0x2c, + 0x0a,0x30,0x78,0x34,0x32,0x44,0x38,0x41,0x34,0x39,0x38,0x41,0x46,0x43,0x31,0x33,0x35,0x46,0x37,0x55,0x4c,0x2c,0x30,0x78,0x37,0x39,0x36,0x37,0x36,0x42,0x39,0x45, + 0x32,0x30,0x45,0x43,0x45,0x44,0x37,0x38,0x55,0x4c,0x2c,0x30,0x78,0x41,0x38,0x44,0x42,0x33,0x41,0x45,0x41,0x31,0x35,0x36,0x33,0x38,0x33,0x34,0x31,0x55,0x4c,0x2c, + 0x30,0x78,0x38,0x33,0x32,0x43,0x38,0x33,0x33,0x32,0x34,0x44,0x33,0x42,0x43,0x33,0x46,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x33,0x34,0x37,0x32,0x37,0x31,0x43, + 0x31,0x46,0x33,0x42,0x34,0x30,0x41,0x37,0x55,0x4c,0x2c,0x30,0x78,0x39,0x41,0x37,0x36,0x32,0x44,0x42,0x37,0x33,0x34,0x46,0x30,0x34,0x30,0x35,0x39,0x55,0x4c,0x2c, + 0x30,0x78,0x46,0x44,0x34,0x46,0x32,0x31,0x44,0x32,0x36,0x43,0x34,0x45,0x33,0x45,0x45,0x37,0x55,0x4c,0x2c,0x30,0x78,0x45,0x46,0x35,0x39,0x35,0x37,0x44,0x43,0x33, + 0x39,0x38,0x44,0x46,0x44,0x42,0x38,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x41,0x45,0x42,0x34,0x39,0x32,0x42,0x34,0x39,0x30,0x43,0x39,0x42,0x38,0x44,0x55,0x4c,0x2c, + 0x30,0x78,0x30,0x44,0x37,0x30,0x46,0x33,0x36,0x38,0x34,0x39,0x44,0x37,0x41,0x32,0x35,0x42,0x55,0x4c,0x2c,0x30,0x78,0x38,0x34,0x35,0x35,0x38,0x44,0x37,0x41,0x44, + 0x30,0x41,0x45,0x33,0x42,0x37,0x44,0x55,0x4c,0x2c,0x30,0x78,0x36,0x35,0x38,0x45,0x46,0x38,0x45,0x34,0x46,0x30,0x45,0x39,0x41,0x35,0x46,0x35,0x55,0x4c,0x2c,0x0a, + 0x30,0x78,0x35,0x33,0x33,0x42,0x31,0x30,0x33,0x36,0x46,0x34,0x41,0x32,0x42,0x38,0x41,0x30,0x55,0x4c,0x2c,0x30,0x78,0x35,0x41,0x45,0x43,0x33,0x45,0x37,0x35,0x39, + 0x45,0x30,0x37,0x41,0x38,0x30,0x43,0x55,0x4c,0x2c,0x30,0x78,0x34,0x46,0x38,0x38,0x45,0x38,0x35,0x36,0x39,0x32,0x39,0x34,0x36,0x38,0x39,0x31,0x55,0x4c,0x2c,0x30, + 0x78,0x34,0x43,0x42,0x43,0x42,0x41,0x46,0x38,0x35,0x35,0x35,0x43,0x42,0x30,0x35,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x42,0x39,0x34,0x38,0x37,0x46,0x33,0x39, + 0x39,0x33,0x42,0x42,0x42,0x45,0x33,0x55,0x4c,0x2c,0x30,0x78,0x35,0x44,0x31,0x43,0x36,0x42,0x37,0x32,0x44,0x36,0x46,0x34,0x44,0x41,0x37,0x35,0x55,0x4c,0x2c,0x30, + 0x78,0x36,0x44,0x42,0x33,0x33,0x34,0x44,0x43,0x32,0x38,0x41,0x43,0x41,0x45,0x36,0x34,0x55,0x4c,0x2c,0x30,0x78,0x37,0x31,0x44,0x42,0x32,0x38,0x42,0x38,0x35,0x30, + 0x41,0x35,0x33,0x34,0x36,0x43,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x41,0x35,0x31,0x38,0x44,0x31,0x30,0x46,0x32,0x45,0x32,0x36,0x31,0x46,0x38,0x55,0x4c,0x2c,0x30, + 0x78,0x46,0x43,0x37,0x35,0x44,0x44,0x35,0x39,0x33,0x33,0x36,0x34,0x44,0x42,0x45,0x33,0x55,0x4c,0x2c,0x30,0x78,0x41,0x32,0x33,0x46,0x43,0x45,0x34,0x33,0x46,0x31, + 0x42,0x43,0x41,0x43,0x31,0x43,0x55,0x4c,0x2c,0x30,0x78,0x42,0x30,0x34,0x33,0x45,0x38,0x30,0x32,0x33,0x43,0x44,0x31,0x42,0x42,0x36,0x37,0x55,0x4c,0x2c,0x0a,0x30, + 0x78,0x37,0x35,0x41,0x31,0x32,0x39,0x38,0x38,0x43,0x41,0x35,0x42,0x30,0x41,0x33,0x33,0x55,0x4c,0x2c,0x30,0x78,0x35,0x43,0x35,0x33,0x31,0x36,0x42,0x34,0x34,0x44, + 0x31,0x39,0x33,0x34,0x37,0x46,0x55,0x4c,0x2c,0x30,0x78,0x31,0x45,0x34,0x44,0x37,0x39,0x30,0x45,0x43,0x33,0x39,0x34,0x33,0x42,0x39,0x32,0x55,0x4c,0x2c,0x30,0x78, + 0x33,0x46,0x41,0x46,0x45,0x45,0x42,0x36,0x44,0x37,0x37,0x35,0x37,0x34,0x37,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x31,0x33,0x39,0x31,0x41,0x42,0x45,0x46,0x37, + 0x44,0x34,0x41,0x38,0x45,0x41,0x55,0x4c,0x2c,0x30,0x78,0x35,0x31,0x32,0x37,0x32,0x33,0x34,0x43,0x30,0x39,0x37,0x45,0x46,0x34,0x35,0x43,0x55,0x4c,0x2c,0x30,0x78, + 0x44,0x32,0x33,0x43,0x33,0x32,0x42,0x41,0x35,0x33,0x32,0x34,0x41,0x33,0x32,0x36,0x55,0x4c,0x2c,0x30,0x78,0x41,0x44,0x44,0x35,0x41,0x36,0x36,0x44,0x34,0x41,0x31, + 0x37,0x41,0x33,0x34,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x38,0x43,0x39,0x46,0x32,0x41,0x46,0x41,0x36,0x33,0x45,0x31,0x44,0x42,0x35,0x55,0x4c,0x2c,0x30,0x78, + 0x35,0x36,0x33,0x43,0x36,0x42,0x39,0x31,0x39,0x38,0x33,0x44,0x35,0x39,0x38,0x33,0x55,0x4c,0x2c,0x30,0x78,0x34,0x44,0x36,0x30,0x38,0x36,0x37,0x32,0x41,0x31,0x37, + 0x43,0x46,0x38,0x34,0x43,0x55,0x4c,0x2c,0x30,0x78,0x46,0x36,0x43,0x37,0x36,0x45,0x30,0x38,0x43,0x43,0x33,0x45,0x45,0x32,0x34,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78, + 0x35,0x45,0x37,0x36,0x42,0x43,0x42,0x31,0x42,0x33,0x33,0x33,0x39,0x38,0x32,0x46,0x55,0x4c,0x2c,0x30,0x78,0x32,0x41,0x45,0x36,0x43,0x34,0x45,0x46,0x41,0x35,0x36, + 0x36,0x44,0x36,0x32,0x42,0x55,0x4c,0x2c,0x30,0x78,0x33,0x36,0x44,0x34,0x43,0x31,0x42,0x45,0x45,0x38,0x42,0x36,0x46,0x34,0x30,0x36,0x55,0x4c,0x2c,0x30,0x78,0x36, + 0x33,0x32,0x31,0x45,0x46,0x42,0x43,0x31,0x35,0x38,0x32,0x45,0x45,0x37,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x39,0x43,0x39,0x35,0x33,0x46,0x34,0x30,0x44,0x34, + 0x45,0x43,0x31,0x46,0x44,0x55,0x4c,0x2c,0x30,0x78,0x32,0x36,0x35,0x38,0x35,0x38,0x30,0x36,0x43,0x34,0x35,0x41,0x37,0x44,0x41,0x37,0x55,0x4c,0x2c,0x30,0x78,0x31, + 0x36,0x46,0x41,0x45,0x30,0x30,0x36,0x31,0x36,0x31,0x34,0x43,0x31,0x37,0x45,0x55,0x4c,0x2c,0x30,0x78,0x33,0x46,0x39,0x44,0x36,0x33,0x32,0x38,0x33,0x44,0x41,0x46, + 0x39,0x30,0x37,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x43,0x44,0x32,0x39,0x42,0x30,0x30,0x45,0x33,0x46,0x32,0x43,0x39,0x44,0x32,0x55,0x4c,0x2c,0x30,0x78,0x33, + 0x30,0x30,0x43,0x44,0x34,0x42,0x37,0x33,0x30,0x43,0x45,0x41,0x41,0x35,0x46,0x55,0x4c,0x2c,0x30,0x78,0x39,0x38,0x33,0x32,0x45,0x30,0x46,0x32,0x31,0x36,0x35,0x31, + 0x32,0x41,0x37,0x34,0x55,0x4c,0x2c,0x30,0x78,0x39,0x41,0x46,0x38,0x43,0x45,0x45,0x33,0x44,0x38,0x33,0x30,0x45,0x42,0x30,0x44,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39, + 0x32,0x37,0x39,0x46,0x31,0x42,0x35,0x37,0x42,0x39,0x45,0x43,0x35,0x34,0x42,0x55,0x4c,0x2c,0x30,0x78,0x44,0x33,0x36,0x38,0x38,0x36,0x30,0x34,0x36,0x45,0x45,0x36, + 0x35,0x31,0x46,0x46,0x55,0x4c,0x2c,0x30,0x78,0x33,0x31,0x36,0x37,0x39,0x36,0x45,0x36,0x35,0x37,0x34,0x44,0x32,0x33,0x39,0x42,0x55,0x4c,0x2c,0x30,0x78,0x30,0x35, + 0x37,0x35,0x30,0x41,0x31,0x37,0x46,0x33,0x41,0x36,0x45,0x36,0x43,0x43,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x45,0x36,0x43,0x33,0x32,0x31,0x33,0x44,0x39,0x38,0x31, + 0x37,0x36,0x42,0x31,0x55,0x4c,0x2c,0x30,0x78,0x36,0x32,0x41,0x32,0x30,0x35,0x46,0x38,0x38,0x34,0x35,0x32,0x31,0x37,0x33,0x43,0x55,0x4c,0x2c,0x30,0x78,0x34,0x37, + 0x31,0x35,0x34,0x37,0x37,0x38,0x42,0x33,0x43,0x42,0x32,0x42,0x46,0x34,0x55,0x4c,0x2c,0x30,0x78,0x34,0x38,0x36,0x41,0x39,0x33,0x32,0x33,0x38,0x32,0x35,0x34,0x34, + 0x36,0x46,0x46,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x35,0x36,0x35,0x35,0x45,0x34,0x45,0x30,0x37,0x35,0x38,0x44,0x46,0x33,0x38,0x55,0x4c,0x2c,0x30,0x78,0x38,0x45, + 0x35,0x30,0x38,0x36,0x46,0x43,0x38,0x39,0x37,0x43,0x46,0x43,0x46,0x32,0x55,0x4c,0x2c,0x30,0x78,0x38,0x36,0x43,0x41,0x30,0x42,0x44,0x30,0x34,0x34,0x32,0x45,0x37, + 0x30,0x33,0x31,0x55,0x4c,0x2c,0x30,0x78,0x34,0x45,0x34,0x37,0x37,0x38,0x33,0x30,0x41,0x32,0x30,0x39,0x34,0x30,0x46,0x30,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x33, + 0x33,0x38,0x46,0x37,0x44,0x31,0x33,0x39,0x45,0x45,0x41,0x30,0x36,0x35,0x55,0x4c,0x2c,0x30,0x78,0x42,0x44,0x33,0x41,0x32,0x43,0x45,0x34,0x33,0x37,0x45,0x39,0x35, + 0x45,0x46,0x37,0x55,0x4c,0x2c,0x30,0x78,0x36,0x46,0x46,0x38,0x31,0x33,0x30,0x31,0x32,0x36,0x42,0x32,0x39,0x37,0x32,0x31,0x55,0x4c,0x2c,0x30,0x78,0x45,0x37,0x44, + 0x45,0x39,0x46,0x45,0x46,0x44,0x31,0x45,0x44,0x34,0x34,0x41,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x39,0x39,0x32,0x32,0x35,0x37,0x36,0x31,0x35,0x44,0x46,0x41, + 0x30,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x42,0x45,0x34,0x32,0x44,0x43,0x31,0x32,0x46,0x36,0x46,0x37,0x38,0x35,0x33,0x43,0x55,0x4c,0x2c,0x30,0x78,0x37,0x45,0x42, + 0x30,0x32,0x37,0x41,0x42,0x37,0x43,0x45,0x43,0x41,0x37,0x44,0x38,0x55,0x4c,0x2c,0x30,0x78,0x44,0x45,0x41,0x38,0x33,0x45,0x41,0x41,0x44,0x41,0x37,0x44,0x38,0x44, + 0x35,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x38,0x36,0x39,0x30,0x32,0x42,0x44,0x39,0x33,0x43,0x45,0x32,0x35,0x41,0x41,0x55,0x4c,0x2c,0x30,0x78,0x46,0x39,0x30, + 0x38,0x37,0x33,0x31,0x41,0x46,0x44,0x34,0x33,0x46,0x36,0x35,0x41,0x55,0x4c,0x2c,0x30,0x78,0x41,0x35,0x31,0x39,0x34,0x41,0x31,0x37,0x44,0x41,0x45,0x46,0x35,0x46, + 0x43,0x30,0x55,0x4c,0x2c,0x30,0x78,0x36,0x41,0x32,0x31,0x46,0x44,0x34,0x43,0x33,0x33,0x36,0x36,0x34,0x44,0x39,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x30,0x31, + 0x35,0x34,0x31,0x44,0x42,0x33,0x31,0x39,0x38,0x42,0x34,0x33,0x35,0x55,0x4c,0x2c,0x30,0x78,0x39,0x42,0x35,0x34,0x43,0x44,0x45,0x44,0x42,0x42,0x30,0x46,0x31,0x45, + 0x45,0x41,0x55,0x4c,0x2c,0x30,0x78,0x37,0x32,0x34,0x30,0x39,0x37,0x35,0x31,0x41,0x31,0x36,0x33,0x44,0x30,0x39,0x41,0x55,0x4c,0x2c,0x30,0x78,0x45,0x32,0x36,0x46, + 0x34,0x37,0x39,0x31,0x42,0x46,0x39,0x44,0x37,0x35,0x46,0x36,0x55,0x4c,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x65,0x76,0x65,0x6e,0x5f, + 0x68,0x69,0x28,0x72,0x29,0x20,0x28,0x43,0x5b,0x28,0x28,0x72,0x29,0x20,0x3c,0x3c,0x20,0x32,0x29,0x20,0x2b,0x20,0x30,0x5d,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x43,0x65,0x76,0x65,0x6e,0x5f,0x6c,0x6f,0x28,0x72,0x29,0x20,0x28,0x43,0x5b,0x28,0x28,0x72,0x29,0x20,0x3c,0x3c,0x20,0x32,0x29,0x20,0x2b,0x20,0x31,0x5d, + 0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x6f,0x64,0x64,0x5f,0x68,0x69,0x28,0x72,0x29,0x20,0x28,0x43,0x5b,0x28,0x28,0x72,0x29,0x20,0x3c,0x3c,0x20, + 0x32,0x29,0x20,0x2b,0x20,0x32,0x5d,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x6f,0x64,0x64,0x5f,0x6c,0x6f,0x28,0x72,0x29,0x20,0x28,0x43,0x5b,0x28, + 0x28,0x72,0x29,0x20,0x3c,0x3c,0x20,0x32,0x29,0x20,0x2b,0x20,0x33,0x5d,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x28,0x78,0x30,0x2c,0x20,0x78,0x31, + 0x2c,0x20,0x78,0x32,0x2c,0x20,0x78,0x33,0x2c,0x20,0x63,0x62,0x2c,0x20,0x72,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x53,0x62,0x28,0x78,0x30,0x20,0x23,0x23, + 0x20,0x68,0x2c,0x78,0x31,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x32,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x33,0x20,0x23,0x23,0x20,0x68,0x2c,0x63,0x62,0x20,0x23,0x23, + 0x20,0x68,0x69,0x28,0x72,0x29,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x62,0x28,0x78,0x30,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x31,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x32, + 0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x33,0x20,0x23,0x23,0x20,0x6c,0x2c,0x63,0x62,0x20,0x23,0x23,0x20,0x6c,0x6f,0x28,0x72,0x29,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20, + 0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x28,0x78,0x30,0x2c,0x20,0x78,0x31,0x2c,0x20,0x78,0x32,0x2c,0x20, + 0x78,0x33,0x2c,0x20,0x78,0x34,0x2c,0x20,0x78,0x35,0x2c,0x20,0x78,0x36,0x2c,0x20,0x78,0x37,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x4c,0x62,0x28,0x78,0x30, + 0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x31,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x32,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x33,0x20,0x23,0x23,0x20,0x68,0x2c,0x5c,0x0a, + 0x78,0x34,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x35,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x36,0x20,0x23,0x23,0x20,0x68,0x2c,0x78,0x37,0x20,0x23,0x23,0x20,0x68,0x29, + 0x3b,0x20,0x5c,0x0a,0x4c,0x62,0x28,0x78,0x30,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x31,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x32,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78, + 0x33,0x20,0x23,0x23,0x20,0x6c,0x2c,0x5c,0x0a,0x78,0x34,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x35,0x20,0x23,0x23,0x20,0x6c,0x2c,0x78,0x36,0x20,0x23,0x23,0x20,0x6c, + 0x2c,0x78,0x37,0x20,0x23,0x23,0x20,0x6c,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x63,0x2c,0x20,0x6e,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x20,0x74,0x3d,0x28,0x78, + 0x20,0x23,0x23,0x20,0x68,0x26,0x28,0x63,0x29,0x29,0x3c,0x3c,0x28,0x6e,0x29,0x3b,0x20,0x5c,0x0a,0x78,0x20,0x23,0x23,0x20,0x68,0x3d,0x28,0x28,0x78,0x20,0x23,0x23, + 0x20,0x68,0x3e,0x3e,0x28,0x6e,0x29,0x29,0x26,0x28,0x63,0x29,0x29,0x7c,0x74,0x3b,0x20,0x5c,0x0a,0x74,0x3d,0x28,0x78,0x20,0x23,0x23,0x20,0x6c,0x26,0x28,0x63,0x29, + 0x29,0x3c,0x3c,0x28,0x6e,0x29,0x3b,0x20,0x5c,0x0a,0x78,0x20,0x23,0x23,0x20,0x6c,0x3d,0x28,0x28,0x78,0x20,0x23,0x23,0x20,0x6c,0x3e,0x3e,0x28,0x6e,0x29,0x29,0x26, + 0x28,0x63,0x29,0x29,0x7c,0x74,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x30, + 0x28,0x78,0x29,0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, + 0x35,0x35,0x35,0x35,0x29,0x2c,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x31,0x28,0x78,0x29,0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50, + 0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x29,0x2c,0x20,0x32,0x29,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x32,0x28,0x78,0x29,0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x46,0x30,0x46, + 0x30,0x46,0x30,0x46,0x30,0x46,0x30,0x46,0x30,0x46,0x30,0x46,0x29,0x2c,0x20,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x33,0x28,0x78,0x29,0x20, + 0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x46,0x46,0x30,0x30,0x46,0x46,0x30,0x30,0x46,0x46,0x30,0x30,0x46,0x46, + 0x29,0x2c,0x20,0x38,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x34,0x28,0x78,0x29,0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50,0x48,0x5f,0x43,0x36, + 0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x46,0x46,0x46,0x46,0x30,0x30,0x30,0x30,0x46,0x46,0x46,0x46,0x29,0x2c,0x20,0x31,0x36,0x29,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x57,0x35,0x28,0x78,0x29,0x20,0x57,0x7a,0x28,0x78,0x2c,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x29,0x2c,0x20,0x33,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x36,0x28,0x78,0x29,0x20,0x64,0x6f, + 0x20,0x7b,0x20,0x5c,0x0a,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x20,0x74,0x3d,0x78,0x20,0x23,0x23,0x20,0x68,0x3b,0x20,0x5c,0x0a,0x78,0x20,0x23,0x23,0x20,0x68,0x3d, + 0x78,0x20,0x23,0x23,0x20,0x6c,0x3b,0x20,0x5c,0x0a,0x78,0x20,0x23,0x23,0x20,0x6c,0x3d,0x74,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30, + 0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x4c,0x28,0x72,0x6f,0x29,0x20,0x53,0x4c,0x75,0x28,0x72,0x20,0x2b,0x20,0x72,0x6f,0x2c,0x20,0x72,0x6f,0x29, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x4c,0x75,0x28,0x72,0x2c,0x20,0x72,0x6f,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x53,0x28,0x68,0x30,0x2c, + 0x68,0x32,0x2c,0x68,0x34,0x2c,0x68,0x36,0x2c,0x43,0x65,0x76,0x65,0x6e,0x5f,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x28,0x68,0x31,0x2c,0x68,0x33,0x2c,0x68,0x35, + 0x2c,0x68,0x37,0x2c,0x43,0x6f,0x64,0x64,0x5f,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x4c,0x28,0x68,0x30,0x2c,0x68,0x32,0x2c,0x68,0x34,0x2c,0x68,0x36,0x2c,0x68,0x31, + 0x2c,0x68,0x33,0x2c,0x68,0x35,0x2c,0x68,0x37,0x29,0x3b,0x20,0x5c,0x0a,0x57,0x20,0x23,0x23,0x20,0x72,0x6f,0x28,0x68,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x57,0x20,0x23, + 0x23,0x20,0x72,0x6f,0x28,0x68,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x57,0x20,0x23,0x23,0x20,0x72,0x6f,0x28,0x68,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x57,0x20,0x23,0x23,0x20, + 0x72,0x6f,0x28,0x68,0x37,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x69,0x66,0x20,0x53,0x50,0x48,0x5f,0x53,0x4d, + 0x41,0x4c,0x4c,0x5f,0x46,0x4f,0x4f,0x54,0x50,0x52,0x49,0x4e,0x54,0x5f,0x4a,0x48,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x38,0x20,0x64,0x6f,0x20,0x7b, + 0x20,0x5c,0x0a,0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,0x20,0x72,0x3b,0x20,0x5c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c,0x34,0x32,0x3b, + 0x20,0x72,0x2b,0x3d,0x37,0x29,0x20,0x7b,0x20,0x5c,0x0a,0x53,0x4c,0x28,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x28,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x28, + 0x32,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x28,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x28,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x28,0x35,0x29,0x3b,0x20,0x5c, + 0x0a,0x53,0x4c,0x28,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x38,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x30,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53, + 0x4c,0x75,0x28,0x20,0x31,0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x32,0x2c,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x33,0x2c, + 0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x34,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x35,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a, + 0x53,0x4c,0x75,0x28,0x20,0x36,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x37,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x38, + 0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x20,0x39,0x2c,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x30,0x2c,0x33,0x29,0x3b,0x20,0x5c, + 0x0a,0x53,0x4c,0x75,0x28,0x31,0x31,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x32,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31, + 0x33,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x34,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x35,0x2c,0x31,0x29,0x3b,0x20, + 0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x36,0x2c,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x37,0x2c,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28, + 0x31,0x38,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x31,0x39,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x30,0x2c,0x36,0x29,0x3b, + 0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x31,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x32,0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75, + 0x28,0x32,0x33,0x2c,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x34,0x2c,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x35,0x2c,0x34,0x29, + 0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x36,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x37,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c, + 0x75,0x28,0x32,0x38,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x32,0x39,0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x30,0x2c,0x32, + 0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x31,0x2c,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x32,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53, + 0x4c,0x75,0x28,0x33,0x33,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x34,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x35,0x2c, + 0x30,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x36,0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x37,0x2c,0x32,0x29,0x3b,0x20,0x5c,0x0a, + 0x53,0x4c,0x75,0x28,0x33,0x38,0x2c,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x33,0x39,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x34,0x30, + 0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x53,0x4c,0x75,0x28,0x34,0x31,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a, + 0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69, + 0x6e,0x74,0x20,0x73,0x69,0x67,0x6d,0x61,0x5b,0x31,0x36,0x5d,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x7b,0x20,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35, + 0x2c,0x36,0x2c,0x37,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x30,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c,0x31,0x33,0x2c,0x31,0x34,0x2c,0x31,0x35,0x20,0x7d,0x2c,0x0a,0x7b,0x20, + 0x31,0x34,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x36,0x2c,0x31,0x2c,0x31,0x32,0x2c,0x30,0x2c,0x32,0x2c,0x31,0x31,0x2c, + 0x37,0x2c,0x35,0x2c,0x33,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x31,0x31,0x2c,0x38,0x2c,0x31,0x32,0x2c,0x30,0x2c,0x35,0x2c,0x32,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x31, + 0x30,0x2c,0x31,0x34,0x2c,0x33,0x2c,0x36,0x2c,0x37,0x2c,0x31,0x2c,0x39,0x2c,0x34,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x37,0x2c,0x39,0x2c,0x33,0x2c,0x31,0x2c,0x31,0x33, + 0x2c,0x31,0x32,0x2c,0x31,0x31,0x2c,0x31,0x34,0x2c,0x32,0x2c,0x36,0x2c,0x35,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x30,0x2c,0x31,0x35,0x2c,0x38,0x20,0x7d,0x2c,0x0a,0x7b, + 0x20,0x39,0x2c,0x30,0x2c,0x35,0x2c,0x37,0x2c,0x32,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x31,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c,0x36,0x2c, + 0x38,0x2c,0x33,0x2c,0x31,0x33,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x32,0x2c,0x31,0x32,0x2c,0x36,0x2c,0x31,0x30,0x2c,0x30,0x2c,0x31,0x31,0x2c,0x38,0x2c,0x33,0x2c,0x34, + 0x2c,0x31,0x33,0x2c,0x37,0x2c,0x35,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x31,0x2c,0x39,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x31,0x32,0x2c,0x35,0x2c,0x31,0x2c,0x31,0x35, + 0x2c,0x31,0x34,0x2c,0x31,0x33,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x30,0x2c,0x37,0x2c,0x36,0x2c,0x33,0x2c,0x39,0x2c,0x32,0x2c,0x38,0x2c,0x31,0x31,0x20,0x7d,0x2c,0x0a, + 0x7b,0x20,0x31,0x33,0x2c,0x31,0x31,0x2c,0x37,0x2c,0x31,0x34,0x2c,0x31,0x32,0x2c,0x31,0x2c,0x33,0x2c,0x39,0x2c,0x35,0x2c,0x30,0x2c,0x31,0x35,0x2c,0x34,0x2c,0x38, + 0x2c,0x36,0x2c,0x32,0x2c,0x31,0x30,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x36,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x39,0x2c,0x31,0x31,0x2c,0x33,0x2c,0x30,0x2c,0x38,0x2c, + 0x31,0x32,0x2c,0x32,0x2c,0x31,0x33,0x2c,0x37,0x2c,0x31,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x35,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x31,0x30,0x2c,0x32,0x2c,0x38,0x2c,0x34, + 0x2c,0x37,0x2c,0x36,0x2c,0x31,0x2c,0x35,0x2c,0x31,0x35,0x2c,0x31,0x31,0x2c,0x39,0x2c,0x31,0x34,0x2c,0x33,0x2c,0x31,0x32,0x2c,0x31,0x33,0x2c,0x30,0x20,0x7d,0x2c, + 0x0a,0x7b,0x20,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x30,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c, + 0x31,0x33,0x2c,0x31,0x34,0x2c,0x31,0x35,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x31,0x34,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c, + 0x36,0x2c,0x31,0x2c,0x31,0x32,0x2c,0x30,0x2c,0x32,0x2c,0x31,0x31,0x2c,0x37,0x2c,0x35,0x2c,0x33,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x31,0x31,0x2c,0x38,0x2c,0x31,0x32, + 0x2c,0x30,0x2c,0x35,0x2c,0x32,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x31,0x30,0x2c,0x31,0x34,0x2c,0x33,0x2c,0x36,0x2c,0x37,0x2c,0x31,0x2c,0x39,0x2c,0x34,0x20,0x7d, + 0x2c,0x0a,0x7b,0x20,0x37,0x2c,0x39,0x2c,0x33,0x2c,0x31,0x2c,0x31,0x33,0x2c,0x31,0x32,0x2c,0x31,0x31,0x2c,0x31,0x34,0x2c,0x32,0x2c,0x36,0x2c,0x35,0x2c,0x31,0x30, + 0x2c,0x34,0x2c,0x30,0x2c,0x31,0x35,0x2c,0x38,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x39,0x2c,0x30,0x2c,0x35,0x2c,0x37,0x2c,0x32,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x31,0x35, + 0x2c,0x31,0x34,0x2c,0x31,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c,0x36,0x2c,0x38,0x2c,0x33,0x2c,0x31,0x33,0x20,0x7d,0x2c,0x0a,0x7b,0x20,0x32,0x2c,0x31,0x32,0x2c,0x36, + 0x2c,0x31,0x30,0x2c,0x30,0x2c,0x31,0x31,0x2c,0x38,0x2c,0x33,0x2c,0x34,0x2c,0x31,0x33,0x2c,0x37,0x2c,0x35,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x31,0x2c,0x39,0x20, + 0x7d,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x73,0x70,0x68, + 0x5f,0x75,0x33,0x32,0x20,0x63,0x5f,0x49,0x56,0x32,0x35,0x36,0x5b,0x38,0x5d,0x3d,0x7b,0x0a,0x30,0x78,0x36,0x41,0x30,0x39,0x45,0x36,0x36,0x37,0x2c,0x30,0x78,0x42, + 0x42,0x36,0x37,0x41,0x45,0x38,0x35,0x2c,0x0a,0x30,0x78,0x33,0x43,0x36,0x45,0x46,0x33,0x37,0x32,0x2c,0x30,0x78,0x41,0x35,0x34,0x46,0x46,0x35,0x33,0x41,0x2c,0x0a, + 0x30,0x78,0x35,0x31,0x30,0x45,0x35,0x32,0x37,0x46,0x2c,0x30,0x78,0x39,0x42,0x30,0x35,0x36,0x38,0x38,0x43,0x2c,0x0a,0x30,0x78,0x31,0x46,0x38,0x33,0x44,0x39,0x41, + 0x42,0x2c,0x30,0x78,0x35,0x42,0x45,0x30,0x43,0x44,0x31,0x39,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69, + 0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x73,0x70,0x68,0x5f,0x75,0x33,0x32,0x20,0x63,0x5f,0x50,0x61,0x64,0x64,0x69,0x6e,0x67,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a, + 0x30,0x2c,0x30,0x2c,0x30,0x2c,0x30,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x2c,0x30,0x2c,0x30,0x2c,0x30,0x2c,0x0a,0x30,0x2c,0x30,0x2c,0x30, + 0x2c,0x30,0x2c,0x0a,0x30,0x2c,0x31,0x2c,0x30,0x2c,0x36,0x34,0x30,0x2c,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61, + 0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x73,0x70,0x68,0x5f,0x75,0x33,0x32,0x20,0x63,0x5f,0x75,0x32,0x35,0x36,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x30, + 0x78,0x32,0x34,0x33,0x46,0x36,0x41,0x38,0x38,0x2c,0x30,0x78,0x38,0x35,0x41,0x33,0x30,0x38,0x44,0x33,0x2c,0x0a,0x30,0x78,0x31,0x33,0x31,0x39,0x38,0x41,0x32,0x45, + 0x2c,0x30,0x78,0x30,0x33,0x37,0x30,0x37,0x33,0x34,0x34,0x2c,0x0a,0x30,0x78,0x41,0x34,0x30,0x39,0x33,0x38,0x32,0x32,0x2c,0x30,0x78,0x32,0x39,0x39,0x46,0x33,0x31, + 0x44,0x30,0x2c,0x0a,0x30,0x78,0x30,0x38,0x32,0x45,0x46,0x41,0x39,0x38,0x2c,0x30,0x78,0x45,0x43,0x34,0x45,0x36,0x43,0x38,0x39,0x2c,0x0a,0x30,0x78,0x34,0x35,0x32, + 0x38,0x32,0x31,0x45,0x36,0x2c,0x30,0x78,0x33,0x38,0x44,0x30,0x31,0x33,0x37,0x37,0x2c,0x0a,0x30,0x78,0x42,0x45,0x35,0x34,0x36,0x36,0x43,0x46,0x2c,0x30,0x78,0x33, + 0x34,0x45,0x39,0x30,0x43,0x36,0x43,0x2c,0x0a,0x30,0x78,0x43,0x30,0x41,0x43,0x32,0x39,0x42,0x37,0x2c,0x30,0x78,0x43,0x39,0x37,0x43,0x35,0x30,0x44,0x44,0x2c,0x0a, + 0x30,0x78,0x33,0x46,0x38,0x34,0x44,0x35,0x42,0x35,0x2c,0x30,0x78,0x42,0x35,0x34,0x37,0x30,0x39,0x31,0x37,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x47,0x53,0x28,0x61,0x2c,0x62,0x2c,0x63,0x2c,0x64,0x2c,0x78,0x29,0x20,0x7b,0x20,0x5c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x73,0x70,0x68,0x5f,0x75,0x33,0x32, + 0x20,0x69,0x64,0x78,0x31,0x3d,0x73,0x69,0x67,0x6d,0x61,0x5b,0x72,0x5d,0x5b,0x78,0x5d,0x3b,0x20,0x5c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x73,0x70,0x68,0x5f,0x75, + 0x33,0x32,0x20,0x69,0x64,0x78,0x32,0x3d,0x73,0x69,0x67,0x6d,0x61,0x5b,0x72,0x5d,0x5b,0x78,0x2b,0x31,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x61,0x5d,0x2b,0x3d,0x28, + 0x6d,0x5b,0x69,0x64,0x78,0x31,0x5d,0x5e,0x63,0x5f,0x75,0x32,0x35,0x36,0x5b,0x69,0x64,0x78,0x32,0x5d,0x29,0x2b,0x76,0x5b,0x62,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b, + 0x64,0x5d,0x20,0x5e,0x3d,0x20,0x76,0x5b,0x61,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x64,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x76,0x5b,0x64,0x5d,0x2c,0x31, + 0x36,0x55,0x29,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x63,0x5d,0x2b,0x3d,0x76,0x5b,0x64,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x62,0x5d,0x20,0x5e,0x3d,0x20,0x76,0x5b,0x63, + 0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x62,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x76,0x5b,0x62,0x5d,0x2c,0x32,0x30,0x55,0x29,0x3b,0x20,0x5c,0x0a,0x5c,0x0a, + 0x76,0x5b,0x61,0x5d,0x2b,0x3d,0x28,0x6d,0x5b,0x69,0x64,0x78,0x32,0x5d,0x5e,0x63,0x5f,0x75,0x32,0x35,0x36,0x5b,0x69,0x64,0x78,0x31,0x5d,0x29,0x2b,0x76,0x5b,0x62, + 0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x64,0x5d,0x20,0x5e,0x3d,0x20,0x76,0x5b,0x61,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x64,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65, + 0x28,0x76,0x5b,0x64,0x5d,0x2c,0x32,0x34,0x55,0x29,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x63,0x5d,0x2b,0x3d,0x76,0x5b,0x64,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x62,0x5d, + 0x20,0x5e,0x3d,0x20,0x76,0x5b,0x63,0x5d,0x3b,0x20,0x5c,0x0a,0x76,0x5b,0x62,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x76,0x5b,0x62,0x5d,0x2c,0x32,0x35,0x55, + 0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x09,0x78,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x53,0x50,0x48,0x5f,0x52,0x4f,0x54,0x4c,0x36,0x34,0x28,0x78,0x2c,0x20,0x79,0x29,0x09,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x28,0x78,0x29,0x2c, + 0x20,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x79,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x36,0x34,0x65,0x28,0x78,0x29,0x20,0x28,0x28,0x53, + 0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x35,0x36,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78, + 0x29,0x3e,0x3e,0x34,0x30,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30, + 0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3e,0x3e,0x32,0x34,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36, + 0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48, + 0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3e,0x3e,0x38,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46, + 0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x38,0x29,0x26,0x53,0x50, + 0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28, + 0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x32,0x34,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x30,0x30,0x46, + 0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c, + 0x34,0x30,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29, + 0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x78,0x29,0x3c,0x3c,0x35,0x36,0x29,0x26,0x53,0x50,0x48,0x5f,0x43,0x36,0x34,0x28,0x30, + 0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34, + 0x5f,0x30,0x28,0x78,0x29,0x20,0x28,0x28,0x78,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34,0x5f,0x31, + 0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x38,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x42,0x36,0x34,0x5f,0x32,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x31,0x36,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34,0x5f,0x33,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x32,0x34,0x29,0x20,0x26,0x20,0x30,0x78, + 0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34,0x5f,0x34,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x33,0x32, + 0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34,0x5f,0x35,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29, + 0x20,0x3e,0x3e,0x20,0x34,0x30,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36,0x34,0x5f,0x36,0x28,0x78,0x29, + 0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x34,0x38,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x36, + 0x34,0x5f,0x37,0x28,0x78,0x29,0x20,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x35,0x36,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x36,0x34,0x20,0x53, + 0x50,0x48,0x5f,0x52,0x4f,0x54,0x4c,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x50,0x43,0x36,0x34,0x28,0x6a,0x2c,0x20,0x72,0x29,0x20,0x28,0x28,0x73, + 0x70,0x68,0x5f,0x75,0x36,0x34,0x29,0x28,0x28,0x6a,0x29,0x20,0x2b,0x20,0x28,0x72,0x29,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x51,0x43,0x36,0x34, + 0x28,0x6a,0x2c,0x20,0x72,0x29,0x20,0x28,0x28,0x28,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x29,0x28,0x72,0x29,0x20,0x3c,0x3c,0x20,0x35,0x36,0x29,0x20,0x5e,0x20,0x28, + 0x7e,0x28,0x28,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x29,0x28,0x6a,0x29,0x20,0x3c,0x3c,0x20,0x35,0x36,0x29,0x29,0x29,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x54,0x30,0x5f,0x47,0x5b,0x5d,0x20,0x3d,0x0a,0x7b, + 0x0a,0x30,0x78,0x63,0x36,0x61,0x35,0x39,0x37,0x66,0x34,0x61,0x35,0x66,0x34,0x33,0x32,0x63,0x36,0x55,0x4c,0x2c,0x30,0x78,0x66,0x38,0x38,0x34,0x65,0x62,0x39,0x37, + 0x38,0x34,0x39,0x37,0x36,0x66,0x66,0x38,0x55,0x4c,0x2c,0x30,0x78,0x65,0x65,0x39,0x39,0x63,0x37,0x62,0x30,0x39,0x39,0x62,0x30,0x35,0x65,0x65,0x65,0x55,0x4c,0x2c, + 0x30,0x78,0x66,0x36,0x38,0x64,0x66,0x37,0x38,0x63,0x38,0x64,0x38,0x63,0x37,0x61,0x66,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x66,0x66,0x30,0x64,0x65,0x35,0x31,0x37, + 0x30,0x64,0x31,0x37,0x65,0x38,0x66,0x66,0x55,0x4c,0x2c,0x30,0x78,0x64,0x36,0x62,0x64,0x62,0x37,0x64,0x63,0x62,0x64,0x64,0x63,0x30,0x61,0x64,0x36,0x55,0x4c,0x2c, + 0x30,0x78,0x64,0x65,0x62,0x31,0x61,0x37,0x63,0x38,0x62,0x31,0x63,0x38,0x31,0x36,0x64,0x65,0x55,0x4c,0x2c,0x30,0x78,0x39,0x31,0x35,0x34,0x33,0x39,0x66,0x63,0x35, + 0x34,0x66,0x63,0x36,0x64,0x39,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x30,0x35,0x30,0x63,0x30,0x66,0x30,0x35,0x30,0x66,0x30,0x39,0x30,0x36,0x30,0x55,0x4c,0x2c, + 0x30,0x78,0x30,0x32,0x30,0x33,0x30,0x34,0x30,0x35,0x30,0x33,0x30,0x35,0x30,0x37,0x30,0x32,0x55,0x4c,0x2c,0x30,0x78,0x63,0x65,0x61,0x39,0x38,0x37,0x65,0x30,0x61, + 0x39,0x65,0x30,0x32,0x65,0x63,0x65,0x55,0x4c,0x2c,0x30,0x78,0x35,0x36,0x37,0x64,0x61,0x63,0x38,0x37,0x37,0x64,0x38,0x37,0x64,0x31,0x35,0x36,0x55,0x4c,0x2c,0x0a, + 0x30,0x78,0x65,0x37,0x31,0x39,0x64,0x35,0x32,0x62,0x31,0x39,0x32,0x62,0x63,0x63,0x65,0x37,0x55,0x4c,0x2c,0x30,0x78,0x62,0x35,0x36,0x32,0x37,0x31,0x61,0x36,0x36, + 0x32,0x61,0x36,0x31,0x33,0x62,0x35,0x55,0x4c,0x2c,0x30,0x78,0x34,0x64,0x65,0x36,0x39,0x61,0x33,0x31,0x65,0x36,0x33,0x31,0x37,0x63,0x34,0x64,0x55,0x4c,0x2c,0x30, + 0x78,0x65,0x63,0x39,0x61,0x63,0x33,0x62,0x35,0x39,0x61,0x62,0x35,0x35,0x39,0x65,0x63,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x66,0x34,0x35,0x30,0x35,0x63,0x66,0x34, + 0x35,0x63,0x66,0x34,0x30,0x38,0x66,0x55,0x4c,0x2c,0x30,0x78,0x31,0x66,0x39,0x64,0x33,0x65,0x62,0x63,0x39,0x64,0x62,0x63,0x61,0x33,0x31,0x66,0x55,0x4c,0x2c,0x30, + 0x78,0x38,0x39,0x34,0x30,0x30,0x39,0x63,0x30,0x34,0x30,0x63,0x30,0x34,0x39,0x38,0x39,0x55,0x4c,0x2c,0x30,0x78,0x66,0x61,0x38,0x37,0x65,0x66,0x39,0x32,0x38,0x37, + 0x39,0x32,0x36,0x38,0x66,0x61,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x65,0x66,0x31,0x35,0x63,0x35,0x33,0x66,0x31,0x35,0x33,0x66,0x64,0x30,0x65,0x66,0x55,0x4c,0x2c,0x30, + 0x78,0x62,0x32,0x65,0x62,0x37,0x66,0x32,0x36,0x65,0x62,0x32,0x36,0x39,0x34,0x62,0x32,0x55,0x4c,0x2c,0x30,0x78,0x38,0x65,0x63,0x39,0x30,0x37,0x34,0x30,0x63,0x39, + 0x34,0x30,0x63,0x65,0x38,0x65,0x55,0x4c,0x2c,0x30,0x78,0x66,0x62,0x30,0x62,0x65,0x64,0x31,0x64,0x30,0x62,0x31,0x64,0x65,0x36,0x66,0x62,0x55,0x4c,0x2c,0x0a,0x30, + 0x78,0x34,0x31,0x65,0x63,0x38,0x32,0x32,0x66,0x65,0x63,0x32,0x66,0x36,0x65,0x34,0x31,0x55,0x4c,0x2c,0x30,0x78,0x62,0x33,0x36,0x37,0x37,0x64,0x61,0x39,0x36,0x37, + 0x61,0x39,0x31,0x61,0x62,0x33,0x55,0x4c,0x2c,0x30,0x78,0x35,0x66,0x66,0x64,0x62,0x65,0x31,0x63,0x66,0x64,0x31,0x63,0x34,0x33,0x35,0x66,0x55,0x4c,0x2c,0x30,0x78, + 0x34,0x35,0x65,0x61,0x38,0x61,0x32,0x35,0x65,0x61,0x32,0x35,0x36,0x30,0x34,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x33,0x62,0x66,0x34,0x36,0x64,0x61,0x62,0x66, + 0x64,0x61,0x66,0x39,0x32,0x33,0x55,0x4c,0x2c,0x30,0x78,0x35,0x33,0x66,0x37,0x61,0x36,0x30,0x32,0x66,0x37,0x30,0x32,0x35,0x31,0x35,0x33,0x55,0x4c,0x2c,0x30,0x78, + 0x65,0x34,0x39,0x36,0x64,0x33,0x61,0x31,0x39,0x36,0x61,0x31,0x34,0x35,0x65,0x34,0x55,0x4c,0x2c,0x30,0x78,0x39,0x62,0x35,0x62,0x32,0x64,0x65,0x64,0x35,0x62,0x65, + 0x64,0x37,0x36,0x39,0x62,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x35,0x63,0x32,0x65,0x61,0x35,0x64,0x63,0x32,0x35,0x64,0x32,0x38,0x37,0x35,0x55,0x4c,0x2c,0x30,0x78, + 0x65,0x31,0x31,0x63,0x64,0x39,0x32,0x34,0x31,0x63,0x32,0x34,0x63,0x35,0x65,0x31,0x55,0x4c,0x2c,0x30,0x78,0x33,0x64,0x61,0x65,0x37,0x61,0x65,0x39,0x61,0x65,0x65, + 0x39,0x64,0x34,0x33,0x64,0x55,0x4c,0x2c,0x30,0x78,0x34,0x63,0x36,0x61,0x39,0x38,0x62,0x65,0x36,0x61,0x62,0x65,0x66,0x32,0x34,0x63,0x55,0x4c,0x2c,0x0a,0x30,0x78, + 0x36,0x63,0x35,0x61,0x64,0x38,0x65,0x65,0x35,0x61,0x65,0x65,0x38,0x32,0x36,0x63,0x55,0x4c,0x2c,0x30,0x78,0x37,0x65,0x34,0x31,0x66,0x63,0x63,0x33,0x34,0x31,0x63, + 0x33,0x62,0x64,0x37,0x65,0x55,0x4c,0x2c,0x30,0x78,0x66,0x35,0x30,0x32,0x66,0x31,0x30,0x36,0x30,0x32,0x30,0x36,0x66,0x33,0x66,0x35,0x55,0x4c,0x2c,0x30,0x78,0x38, + 0x33,0x34,0x66,0x31,0x64,0x64,0x31,0x34,0x66,0x64,0x31,0x35,0x32,0x38,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x38,0x35,0x63,0x64,0x30,0x65,0x34,0x35,0x63,0x65, + 0x34,0x38,0x63,0x36,0x38,0x55,0x4c,0x2c,0x30,0x78,0x35,0x31,0x66,0x34,0x61,0x32,0x30,0x37,0x66,0x34,0x30,0x37,0x35,0x36,0x35,0x31,0x55,0x4c,0x2c,0x30,0x78,0x64, + 0x31,0x33,0x34,0x62,0x39,0x35,0x63,0x33,0x34,0x35,0x63,0x38,0x64,0x64,0x31,0x55,0x4c,0x2c,0x30,0x78,0x66,0x39,0x30,0x38,0x65,0x39,0x31,0x38,0x30,0x38,0x31,0x38, + 0x65,0x31,0x66,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x65,0x32,0x39,0x33,0x64,0x66,0x61,0x65,0x39,0x33,0x61,0x65,0x34,0x63,0x65,0x32,0x55,0x4c,0x2c,0x30,0x78,0x61, + 0x62,0x37,0x33,0x34,0x64,0x39,0x35,0x37,0x33,0x39,0x35,0x33,0x65,0x61,0x62,0x55,0x4c,0x2c,0x30,0x78,0x36,0x32,0x35,0x33,0x63,0x34,0x66,0x35,0x35,0x33,0x66,0x35, + 0x39,0x37,0x36,0x32,0x55,0x4c,0x2c,0x30,0x78,0x32,0x61,0x33,0x66,0x35,0x34,0x34,0x31,0x33,0x66,0x34,0x31,0x36,0x62,0x32,0x61,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30, + 0x38,0x30,0x63,0x31,0x30,0x31,0x34,0x30,0x63,0x31,0x34,0x31,0x63,0x30,0x38,0x55,0x4c,0x2c,0x30,0x78,0x39,0x35,0x35,0x32,0x33,0x31,0x66,0x36,0x35,0x32,0x66,0x36, + 0x36,0x33,0x39,0x35,0x55,0x4c,0x2c,0x30,0x78,0x34,0x36,0x36,0x35,0x38,0x63,0x61,0x66,0x36,0x35,0x61,0x66,0x65,0x39,0x34,0x36,0x55,0x4c,0x2c,0x30,0x78,0x39,0x64, + 0x35,0x65,0x32,0x31,0x65,0x32,0x35,0x65,0x65,0x32,0x37,0x66,0x39,0x64,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x30,0x32,0x38,0x36,0x30,0x37,0x38,0x32,0x38,0x37,0x38, + 0x34,0x38,0x33,0x30,0x55,0x4c,0x2c,0x30,0x78,0x33,0x37,0x61,0x31,0x36,0x65,0x66,0x38,0x61,0x31,0x66,0x38,0x63,0x66,0x33,0x37,0x55,0x4c,0x2c,0x30,0x78,0x30,0x61, + 0x30,0x66,0x31,0x34,0x31,0x31,0x30,0x66,0x31,0x31,0x31,0x62,0x30,0x61,0x55,0x4c,0x2c,0x30,0x78,0x32,0x66,0x62,0x35,0x35,0x65,0x63,0x34,0x62,0x35,0x63,0x34,0x65, + 0x62,0x32,0x66,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x65,0x30,0x39,0x31,0x63,0x31,0x62,0x30,0x39,0x31,0x62,0x31,0x35,0x30,0x65,0x55,0x4c,0x2c,0x30,0x78,0x32,0x34, + 0x33,0x36,0x34,0x38,0x35,0x61,0x33,0x36,0x35,0x61,0x37,0x65,0x32,0x34,0x55,0x4c,0x2c,0x30,0x78,0x31,0x62,0x39,0x62,0x33,0x36,0x62,0x36,0x39,0x62,0x62,0x36,0x61, + 0x64,0x31,0x62,0x55,0x4c,0x2c,0x30,0x78,0x64,0x66,0x33,0x64,0x61,0x35,0x34,0x37,0x33,0x64,0x34,0x37,0x39,0x38,0x64,0x66,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x63,0x64, + 0x32,0x36,0x38,0x31,0x36,0x61,0x32,0x36,0x36,0x61,0x61,0x37,0x63,0x64,0x55,0x4c,0x2c,0x30,0x78,0x34,0x65,0x36,0x39,0x39,0x63,0x62,0x62,0x36,0x39,0x62,0x62,0x66, + 0x35,0x34,0x65,0x55,0x4c,0x2c,0x30,0x78,0x37,0x66,0x63,0x64,0x66,0x65,0x34,0x63,0x63,0x64,0x34,0x63,0x33,0x33,0x37,0x66,0x55,0x4c,0x2c,0x30,0x78,0x65,0x61,0x39, + 0x66,0x63,0x66,0x62,0x61,0x39,0x66,0x62,0x61,0x35,0x30,0x65,0x61,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x32,0x31,0x62,0x32,0x34,0x32,0x64,0x31,0x62,0x32,0x64,0x33, + 0x66,0x31,0x32,0x55,0x4c,0x2c,0x30,0x78,0x31,0x64,0x39,0x65,0x33,0x61,0x62,0x39,0x39,0x65,0x62,0x39,0x61,0x34,0x31,0x64,0x55,0x4c,0x2c,0x30,0x78,0x35,0x38,0x37, + 0x34,0x62,0x30,0x39,0x63,0x37,0x34,0x39,0x63,0x63,0x34,0x35,0x38,0x55,0x4c,0x2c,0x30,0x78,0x33,0x34,0x32,0x65,0x36,0x38,0x37,0x32,0x32,0x65,0x37,0x32,0x34,0x36, + 0x33,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x36,0x32,0x64,0x36,0x63,0x37,0x37,0x32,0x64,0x37,0x37,0x34,0x31,0x33,0x36,0x55,0x4c,0x2c,0x30,0x78,0x64,0x63,0x62, + 0x32,0x61,0x33,0x63,0x64,0x62,0x32,0x63,0x64,0x31,0x31,0x64,0x63,0x55,0x4c,0x2c,0x30,0x78,0x62,0x34,0x65,0x65,0x37,0x33,0x32,0x39,0x65,0x65,0x32,0x39,0x39,0x64, + 0x62,0x34,0x55,0x4c,0x2c,0x30,0x78,0x35,0x62,0x66,0x62,0x62,0x36,0x31,0x36,0x66,0x62,0x31,0x36,0x34,0x64,0x35,0x62,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x61,0x34,0x66, + 0x36,0x35,0x33,0x30,0x31,0x66,0x36,0x30,0x31,0x61,0x35,0x61,0x34,0x55,0x4c,0x2c,0x30,0x78,0x37,0x36,0x34,0x64,0x65,0x63,0x64,0x37,0x34,0x64,0x64,0x37,0x61,0x31, + 0x37,0x36,0x55,0x4c,0x2c,0x30,0x78,0x62,0x37,0x36,0x31,0x37,0x35,0x61,0x33,0x36,0x31,0x61,0x33,0x31,0x34,0x62,0x37,0x55,0x4c,0x2c,0x30,0x78,0x37,0x64,0x63,0x65, + 0x66,0x61,0x34,0x39,0x63,0x65,0x34,0x39,0x33,0x34,0x37,0x64,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x32,0x37,0x62,0x61,0x34,0x38,0x64,0x37,0x62,0x38,0x64,0x64,0x66, + 0x35,0x32,0x55,0x4c,0x2c,0x30,0x78,0x64,0x64,0x33,0x65,0x61,0x31,0x34,0x32,0x33,0x65,0x34,0x32,0x39,0x66,0x64,0x64,0x55,0x4c,0x2c,0x30,0x78,0x35,0x65,0x37,0x31, + 0x62,0x63,0x39,0x33,0x37,0x31,0x39,0x33,0x63,0x64,0x35,0x65,0x55,0x4c,0x2c,0x30,0x78,0x31,0x33,0x39,0x37,0x32,0x36,0x61,0x32,0x39,0x37,0x61,0x32,0x62,0x31,0x31, + 0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x61,0x36,0x66,0x35,0x35,0x37,0x30,0x34,0x66,0x35,0x30,0x34,0x61,0x32,0x61,0x36,0x55,0x4c,0x2c,0x30,0x78,0x62,0x39,0x36,0x38, + 0x36,0x39,0x62,0x38,0x36,0x38,0x62,0x38,0x30,0x31,0x62,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x55,0x4c,0x2c,0x30,0x78,0x63,0x31,0x32,0x63,0x39,0x39,0x37,0x34,0x32,0x63,0x37,0x34,0x62,0x35,0x63,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x34,0x30,0x36,0x30, + 0x38,0x30,0x61,0x30,0x36,0x30,0x61,0x30,0x65,0x30,0x34,0x30,0x55,0x4c,0x2c,0x30,0x78,0x65,0x33,0x31,0x66,0x64,0x64,0x32,0x31,0x31,0x66,0x32,0x31,0x63,0x32,0x65, + 0x33,0x55,0x4c,0x2c,0x30,0x78,0x37,0x39,0x63,0x38,0x66,0x32,0x34,0x33,0x63,0x38,0x34,0x33,0x33,0x61,0x37,0x39,0x55,0x4c,0x2c,0x30,0x78,0x62,0x36,0x65,0x64,0x37, + 0x37,0x32,0x63,0x65,0x64,0x32,0x63,0x39,0x61,0x62,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64,0x34,0x62,0x65,0x62,0x33,0x64,0x39,0x62,0x65,0x64,0x39,0x30,0x64,0x64, + 0x34,0x55,0x4c,0x2c,0x30,0x78,0x38,0x64,0x34,0x36,0x30,0x31,0x63,0x61,0x34,0x36,0x63,0x61,0x34,0x37,0x38,0x64,0x55,0x4c,0x2c,0x30,0x78,0x36,0x37,0x64,0x39,0x63, + 0x65,0x37,0x30,0x64,0x39,0x37,0x30,0x31,0x37,0x36,0x37,0x55,0x4c,0x2c,0x30,0x78,0x37,0x32,0x34,0x62,0x65,0x34,0x64,0x64,0x34,0x62,0x64,0x64,0x61,0x66,0x37,0x32, + 0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x34,0x64,0x65,0x33,0x33,0x37,0x39,0x64,0x65,0x37,0x39,0x65,0x64,0x39,0x34,0x55,0x4c,0x2c,0x30,0x78,0x39,0x38,0x64,0x34,0x32, + 0x62,0x36,0x37,0x64,0x34,0x36,0x37,0x66,0x66,0x39,0x38,0x55,0x4c,0x2c,0x30,0x78,0x62,0x30,0x65,0x38,0x37,0x62,0x32,0x33,0x65,0x38,0x32,0x33,0x39,0x33,0x62,0x30, + 0x55,0x4c,0x2c,0x30,0x78,0x38,0x35,0x34,0x61,0x31,0x31,0x64,0x65,0x34,0x61,0x64,0x65,0x35,0x62,0x38,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x62,0x62,0x36,0x62,0x36, + 0x64,0x62,0x64,0x36,0x62,0x62,0x64,0x30,0x36,0x62,0x62,0x55,0x4c,0x2c,0x30,0x78,0x63,0x35,0x32,0x61,0x39,0x31,0x37,0x65,0x32,0x61,0x37,0x65,0x62,0x62,0x63,0x35, + 0x55,0x4c,0x2c,0x30,0x78,0x34,0x66,0x65,0x35,0x39,0x65,0x33,0x34,0x65,0x35,0x33,0x34,0x37,0x62,0x34,0x66,0x55,0x4c,0x2c,0x30,0x78,0x65,0x64,0x31,0x36,0x63,0x31, + 0x33,0x61,0x31,0x36,0x33,0x61,0x64,0x37,0x65,0x64,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x36,0x63,0x35,0x31,0x37,0x35,0x34,0x63,0x35,0x35,0x34,0x64,0x32,0x38,0x36, + 0x55,0x4c,0x2c,0x30,0x78,0x39,0x61,0x64,0x37,0x32,0x66,0x36,0x32,0x64,0x37,0x36,0x32,0x66,0x38,0x39,0x61,0x55,0x4c,0x2c,0x30,0x78,0x36,0x36,0x35,0x35,0x63,0x63, + 0x66,0x66,0x35,0x35,0x66,0x66,0x39,0x39,0x36,0x36,0x55,0x4c,0x2c,0x30,0x78,0x31,0x31,0x39,0x34,0x32,0x32,0x61,0x37,0x39,0x34,0x61,0x37,0x62,0x36,0x31,0x31,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x38,0x61,0x63,0x66,0x30,0x66,0x34,0x61,0x63,0x66,0x34,0x61,0x63,0x30,0x38,0x61,0x55,0x4c,0x2c,0x30,0x78,0x65,0x39,0x31,0x30,0x63,0x39, + 0x33,0x30,0x31,0x30,0x33,0x30,0x64,0x39,0x65,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,0x34,0x30,0x36,0x30,0x38,0x30,0x61,0x30,0x36,0x30,0x61,0x30,0x65,0x30,0x34,0x55, + 0x4c,0x2c,0x30,0x78,0x66,0x65,0x38,0x31,0x65,0x37,0x39,0x38,0x38,0x31,0x39,0x38,0x36,0x36,0x66,0x65,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x61,0x30,0x66,0x30,0x35,0x62, + 0x30,0x62,0x66,0x30,0x30,0x62,0x61,0x62,0x61,0x30,0x55,0x4c,0x2c,0x30,0x78,0x37,0x38,0x34,0x34,0x66,0x30,0x63,0x63,0x34,0x34,0x63,0x63,0x62,0x34,0x37,0x38,0x55, + 0x4c,0x2c,0x30,0x78,0x32,0x35,0x62,0x61,0x34,0x61,0x64,0x35,0x62,0x61,0x64,0x35,0x66,0x30,0x32,0x35,0x55,0x4c,0x2c,0x30,0x78,0x34,0x62,0x65,0x33,0x39,0x36,0x33, + 0x65,0x65,0x33,0x33,0x65,0x37,0x35,0x34,0x62,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x61,0x32,0x66,0x33,0x35,0x66,0x30,0x65,0x66,0x33,0x30,0x65,0x61,0x63,0x61,0x32,0x55, + 0x4c,0x2c,0x30,0x78,0x35,0x64,0x66,0x65,0x62,0x61,0x31,0x39,0x66,0x65,0x31,0x39,0x34,0x34,0x35,0x64,0x55,0x4c,0x2c,0x30,0x78,0x38,0x30,0x63,0x30,0x31,0x62,0x35, + 0x62,0x63,0x30,0x35,0x62,0x64,0x62,0x38,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x35,0x38,0x61,0x30,0x61,0x38,0x35,0x38,0x61,0x38,0x35,0x38,0x30,0x30,0x35,0x55,0x4c, + 0x2c,0x0a,0x30,0x78,0x33,0x66,0x61,0x64,0x37,0x65,0x65,0x63,0x61,0x64,0x65,0x63,0x64,0x33,0x33,0x66,0x55,0x4c,0x2c,0x30,0x78,0x32,0x31,0x62,0x63,0x34,0x32,0x64, + 0x66,0x62,0x63,0x64,0x66,0x66,0x65,0x32,0x31,0x55,0x4c,0x2c,0x30,0x78,0x37,0x30,0x34,0x38,0x65,0x30,0x64,0x38,0x34,0x38,0x64,0x38,0x61,0x38,0x37,0x30,0x55,0x4c, + 0x2c,0x30,0x78,0x66,0x31,0x30,0x34,0x66,0x39,0x30,0x63,0x30,0x34,0x30,0x63,0x66,0x64,0x66,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x33,0x64,0x66,0x63,0x36,0x37, + 0x61,0x64,0x66,0x37,0x61,0x31,0x39,0x36,0x33,0x55,0x4c,0x2c,0x30,0x78,0x37,0x37,0x63,0x31,0x65,0x65,0x35,0x38,0x63,0x31,0x35,0x38,0x32,0x66,0x37,0x37,0x55,0x4c, + 0x2c,0x30,0x78,0x61,0x66,0x37,0x35,0x34,0x35,0x39,0x66,0x37,0x35,0x39,0x66,0x33,0x30,0x61,0x66,0x55,0x4c,0x2c,0x30,0x78,0x34,0x32,0x36,0x33,0x38,0x34,0x61,0x35, + 0x36,0x33,0x61,0x35,0x65,0x37,0x34,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x30,0x33,0x30,0x34,0x30,0x35,0x30,0x33,0x30,0x35,0x30,0x37,0x30,0x32,0x30,0x55,0x4c, + 0x2c,0x30,0x78,0x65,0x35,0x31,0x61,0x64,0x31,0x32,0x65,0x31,0x61,0x32,0x65,0x63,0x62,0x65,0x35,0x55,0x4c,0x2c,0x30,0x78,0x66,0x64,0x30,0x65,0x65,0x31,0x31,0x32, + 0x30,0x65,0x31,0x32,0x65,0x66,0x66,0x64,0x55,0x4c,0x2c,0x30,0x78,0x62,0x66,0x36,0x64,0x36,0x35,0x62,0x37,0x36,0x64,0x62,0x37,0x30,0x38,0x62,0x66,0x55,0x4c,0x2c, + 0x0a,0x30,0x78,0x38,0x31,0x34,0x63,0x31,0x39,0x64,0x34,0x34,0x63,0x64,0x34,0x35,0x35,0x38,0x31,0x55,0x4c,0x2c,0x30,0x78,0x31,0x38,0x31,0x34,0x33,0x30,0x33,0x63, + 0x31,0x34,0x33,0x63,0x32,0x34,0x31,0x38,0x55,0x4c,0x2c,0x30,0x78,0x32,0x36,0x33,0x35,0x34,0x63,0x35,0x66,0x33,0x35,0x35,0x66,0x37,0x39,0x32,0x36,0x55,0x4c,0x2c, + 0x30,0x78,0x63,0x33,0x32,0x66,0x39,0x64,0x37,0x31,0x32,0x66,0x37,0x31,0x62,0x32,0x63,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x62,0x65,0x65,0x31,0x36,0x37,0x33,0x38, + 0x65,0x31,0x33,0x38,0x38,0x36,0x62,0x65,0x55,0x4c,0x2c,0x30,0x78,0x33,0x35,0x61,0x32,0x36,0x61,0x66,0x64,0x61,0x32,0x66,0x64,0x63,0x38,0x33,0x35,0x55,0x4c,0x2c, + 0x30,0x78,0x38,0x38,0x63,0x63,0x30,0x62,0x34,0x66,0x63,0x63,0x34,0x66,0x63,0x37,0x38,0x38,0x55,0x4c,0x2c,0x30,0x78,0x32,0x65,0x33,0x39,0x35,0x63,0x34,0x62,0x33, + 0x39,0x34,0x62,0x36,0x35,0x32,0x65,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x33,0x35,0x37,0x33,0x64,0x66,0x39,0x35,0x37,0x66,0x39,0x36,0x61,0x39,0x33,0x55,0x4c,0x2c, + 0x30,0x78,0x35,0x35,0x66,0x32,0x61,0x61,0x30,0x64,0x66,0x32,0x30,0x64,0x35,0x38,0x35,0x35,0x55,0x4c,0x2c,0x30,0x78,0x66,0x63,0x38,0x32,0x65,0x33,0x39,0x64,0x38, + 0x32,0x39,0x64,0x36,0x31,0x66,0x63,0x55,0x4c,0x2c,0x30,0x78,0x37,0x61,0x34,0x37,0x66,0x34,0x63,0x39,0x34,0x37,0x63,0x39,0x62,0x33,0x37,0x61,0x55,0x4c,0x2c,0x0a, + 0x30,0x78,0x63,0x38,0x61,0x63,0x38,0x62,0x65,0x66,0x61,0x63,0x65,0x66,0x32,0x37,0x63,0x38,0x55,0x4c,0x2c,0x30,0x78,0x62,0x61,0x65,0x37,0x36,0x66,0x33,0x32,0x65, + 0x37,0x33,0x32,0x38,0x38,0x62,0x61,0x55,0x4c,0x2c,0x30,0x78,0x33,0x32,0x32,0x62,0x36,0x34,0x37,0x64,0x32,0x62,0x37,0x64,0x34,0x66,0x33,0x32,0x55,0x4c,0x2c,0x30, + 0x78,0x65,0x36,0x39,0x35,0x64,0x37,0x61,0x34,0x39,0x35,0x61,0x34,0x34,0x32,0x65,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x63,0x30,0x61,0x30,0x39,0x62,0x66,0x62,0x61, + 0x30,0x66,0x62,0x33,0x62,0x63,0x30,0x55,0x4c,0x2c,0x30,0x78,0x31,0x39,0x39,0x38,0x33,0x32,0x62,0x33,0x39,0x38,0x62,0x33,0x61,0x61,0x31,0x39,0x55,0x4c,0x2c,0x30, + 0x78,0x39,0x65,0x64,0x31,0x32,0x37,0x36,0x38,0x64,0x31,0x36,0x38,0x66,0x36,0x39,0x65,0x55,0x4c,0x2c,0x30,0x78,0x61,0x33,0x37,0x66,0x35,0x64,0x38,0x31,0x37,0x66, + 0x38,0x31,0x32,0x32,0x61,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x34,0x34,0x36,0x36,0x38,0x38,0x61,0x61,0x36,0x36,0x61,0x61,0x65,0x65,0x34,0x34,0x55,0x4c,0x2c,0x30, + 0x78,0x35,0x34,0x37,0x65,0x61,0x38,0x38,0x32,0x37,0x65,0x38,0x32,0x64,0x36,0x35,0x34,0x55,0x4c,0x2c,0x30,0x78,0x33,0x62,0x61,0x62,0x37,0x36,0x65,0x36,0x61,0x62, + 0x65,0x36,0x64,0x64,0x33,0x62,0x55,0x4c,0x2c,0x30,0x78,0x30,0x62,0x38,0x33,0x31,0x36,0x39,0x65,0x38,0x33,0x39,0x65,0x39,0x35,0x30,0x62,0x55,0x4c,0x2c,0x0a,0x30, + 0x78,0x38,0x63,0x63,0x61,0x30,0x33,0x34,0x35,0x63,0x61,0x34,0x35,0x63,0x39,0x38,0x63,0x55,0x4c,0x2c,0x30,0x78,0x63,0x37,0x32,0x39,0x39,0x35,0x37,0x62,0x32,0x39, + 0x37,0x62,0x62,0x63,0x63,0x37,0x55,0x4c,0x2c,0x30,0x78,0x36,0x62,0x64,0x33,0x64,0x36,0x36,0x65,0x64,0x33,0x36,0x65,0x30,0x35,0x36,0x62,0x55,0x4c,0x2c,0x30,0x78, + 0x32,0x38,0x33,0x63,0x35,0x30,0x34,0x34,0x33,0x63,0x34,0x34,0x36,0x63,0x32,0x38,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x61,0x37,0x37,0x39,0x35,0x35,0x38,0x62,0x37,0x39, + 0x38,0x62,0x32,0x63,0x61,0x37,0x55,0x4c,0x2c,0x30,0x78,0x62,0x63,0x65,0x32,0x36,0x33,0x33,0x64,0x65,0x32,0x33,0x64,0x38,0x31,0x62,0x63,0x55,0x4c,0x2c,0x30,0x78, + 0x31,0x36,0x31,0x64,0x32,0x63,0x32,0x37,0x31,0x64,0x32,0x37,0x33,0x31,0x31,0x36,0x55,0x4c,0x2c,0x30,0x78,0x61,0x64,0x37,0x36,0x34,0x31,0x39,0x61,0x37,0x36,0x39, + 0x61,0x33,0x37,0x61,0x64,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64,0x62,0x33,0x62,0x61,0x64,0x34,0x64,0x33,0x62,0x34,0x64,0x39,0x36,0x64,0x62,0x55,0x4c,0x2c,0x30,0x78, + 0x36,0x34,0x35,0x36,0x63,0x38,0x66,0x61,0x35,0x36,0x66,0x61,0x39,0x65,0x36,0x34,0x55,0x4c,0x2c,0x30,0x78,0x37,0x34,0x34,0x65,0x65,0x38,0x64,0x32,0x34,0x65,0x64, + 0x32,0x61,0x36,0x37,0x34,0x55,0x4c,0x2c,0x30,0x78,0x31,0x34,0x31,0x65,0x32,0x38,0x32,0x32,0x31,0x65,0x32,0x32,0x33,0x36,0x31,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78, + 0x39,0x32,0x64,0x62,0x33,0x66,0x37,0x36,0x64,0x62,0x37,0x36,0x65,0x34,0x39,0x32,0x55,0x4c,0x2c,0x30,0x78,0x30,0x63,0x30,0x61,0x31,0x38,0x31,0x65,0x30,0x61,0x31, + 0x65,0x31,0x32,0x30,0x63,0x55,0x4c,0x2c,0x30,0x78,0x34,0x38,0x36,0x63,0x39,0x30,0x62,0x34,0x36,0x63,0x62,0x34,0x66,0x63,0x34,0x38,0x55,0x4c,0x2c,0x30,0x78,0x62, + 0x38,0x65,0x34,0x36,0x62,0x33,0x37,0x65,0x34,0x33,0x37,0x38,0x66,0x62,0x38,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x66,0x35,0x64,0x32,0x35,0x65,0x37,0x35,0x64,0x65, + 0x37,0x37,0x38,0x39,0x66,0x55,0x4c,0x2c,0x30,0x78,0x62,0x64,0x36,0x65,0x36,0x31,0x62,0x32,0x36,0x65,0x62,0x32,0x30,0x66,0x62,0x64,0x55,0x4c,0x2c,0x30,0x78,0x34, + 0x33,0x65,0x66,0x38,0x36,0x32,0x61,0x65,0x66,0x32,0x61,0x36,0x39,0x34,0x33,0x55,0x4c,0x2c,0x30,0x78,0x63,0x34,0x61,0x36,0x39,0x33,0x66,0x31,0x61,0x36,0x66,0x31, + 0x33,0x35,0x63,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x39,0x61,0x38,0x37,0x32,0x65,0x33,0x61,0x38,0x65,0x33,0x64,0x61,0x33,0x39,0x55,0x4c,0x2c,0x30,0x78,0x33, + 0x31,0x61,0x34,0x36,0x32,0x66,0x37,0x61,0x34,0x66,0x37,0x63,0x36,0x33,0x31,0x55,0x4c,0x2c,0x30,0x78,0x64,0x33,0x33,0x37,0x62,0x64,0x35,0x39,0x33,0x37,0x35,0x39, + 0x38,0x61,0x64,0x33,0x55,0x4c,0x2c,0x30,0x78,0x66,0x32,0x38,0x62,0x66,0x66,0x38,0x36,0x38,0x62,0x38,0x36,0x37,0x34,0x66,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64, + 0x35,0x33,0x32,0x62,0x31,0x35,0x36,0x33,0x32,0x35,0x36,0x38,0x33,0x64,0x35,0x55,0x4c,0x2c,0x30,0x78,0x38,0x62,0x34,0x33,0x30,0x64,0x63,0x35,0x34,0x33,0x63,0x35, + 0x34,0x65,0x38,0x62,0x55,0x4c,0x2c,0x30,0x78,0x36,0x65,0x35,0x39,0x64,0x63,0x65,0x62,0x35,0x39,0x65,0x62,0x38,0x35,0x36,0x65,0x55,0x4c,0x2c,0x30,0x78,0x64,0x61, + 0x62,0x37,0x61,0x66,0x63,0x32,0x62,0x37,0x63,0x32,0x31,0x38,0x64,0x61,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x31,0x38,0x63,0x30,0x32,0x38,0x66,0x38,0x63,0x38,0x66, + 0x38,0x65,0x30,0x31,0x55,0x4c,0x2c,0x30,0x78,0x62,0x31,0x36,0x34,0x37,0x39,0x61,0x63,0x36,0x34,0x61,0x63,0x31,0x64,0x62,0x31,0x55,0x4c,0x2c,0x30,0x78,0x39,0x63, + 0x64,0x32,0x32,0x33,0x36,0x64,0x64,0x32,0x36,0x64,0x66,0x31,0x39,0x63,0x55,0x4c,0x2c,0x30,0x78,0x34,0x39,0x65,0x30,0x39,0x32,0x33,0x62,0x65,0x30,0x33,0x62,0x37, + 0x32,0x34,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64,0x38,0x62,0x34,0x61,0x62,0x63,0x37,0x62,0x34,0x63,0x37,0x31,0x66,0x64,0x38,0x55,0x4c,0x2c,0x30,0x78,0x61,0x63, + 0x66,0x61,0x34,0x33,0x31,0x35,0x66,0x61,0x31,0x35,0x62,0x39,0x61,0x63,0x55,0x4c,0x2c,0x30,0x78,0x66,0x33,0x30,0x37,0x66,0x64,0x30,0x39,0x30,0x37,0x30,0x39,0x66, + 0x61,0x66,0x33,0x55,0x4c,0x2c,0x30,0x78,0x63,0x66,0x32,0x35,0x38,0x35,0x36,0x66,0x32,0x35,0x36,0x66,0x61,0x30,0x63,0x66,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x63,0x61, + 0x61,0x66,0x38,0x66,0x65,0x61,0x61,0x66,0x65,0x61,0x32,0x30,0x63,0x61,0x55,0x4c,0x2c,0x30,0x78,0x66,0x34,0x38,0x65,0x66,0x33,0x38,0x39,0x38,0x65,0x38,0x39,0x37, + 0x64,0x66,0x34,0x55,0x4c,0x2c,0x30,0x78,0x34,0x37,0x65,0x39,0x38,0x65,0x32,0x30,0x65,0x39,0x32,0x30,0x36,0x37,0x34,0x37,0x55,0x4c,0x2c,0x30,0x78,0x31,0x30,0x31, + 0x38,0x32,0x30,0x32,0x38,0x31,0x38,0x32,0x38,0x33,0x38,0x31,0x30,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x66,0x64,0x35,0x64,0x65,0x36,0x34,0x64,0x35,0x36,0x34,0x30, + 0x62,0x36,0x66,0x55,0x4c,0x2c,0x30,0x78,0x66,0x30,0x38,0x38,0x66,0x62,0x38,0x33,0x38,0x38,0x38,0x33,0x37,0x33,0x66,0x30,0x55,0x4c,0x2c,0x30,0x78,0x34,0x61,0x36, + 0x66,0x39,0x34,0x62,0x31,0x36,0x66,0x62,0x31,0x66,0x62,0x34,0x61,0x55,0x4c,0x2c,0x30,0x78,0x35,0x63,0x37,0x32,0x62,0x38,0x39,0x36,0x37,0x32,0x39,0x36,0x63,0x61, + 0x35,0x63,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x38,0x32,0x34,0x37,0x30,0x36,0x63,0x32,0x34,0x36,0x63,0x35,0x34,0x33,0x38,0x55,0x4c,0x2c,0x30,0x78,0x35,0x37,0x66, + 0x31,0x61,0x65,0x30,0x38,0x66,0x31,0x30,0x38,0x35,0x66,0x35,0x37,0x55,0x4c,0x2c,0x30,0x78,0x37,0x33,0x63,0x37,0x65,0x36,0x35,0x32,0x63,0x37,0x35,0x32,0x32,0x31, + 0x37,0x33,0x55,0x4c,0x2c,0x30,0x78,0x39,0x37,0x35,0x31,0x33,0x35,0x66,0x33,0x35,0x31,0x66,0x33,0x36,0x34,0x39,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x63,0x62,0x32, + 0x33,0x38,0x64,0x36,0x35,0x32,0x33,0x36,0x35,0x61,0x65,0x63,0x62,0x55,0x4c,0x2c,0x30,0x78,0x61,0x31,0x37,0x63,0x35,0x39,0x38,0x34,0x37,0x63,0x38,0x34,0x32,0x35, + 0x61,0x31,0x55,0x4c,0x2c,0x30,0x78,0x65,0x38,0x39,0x63,0x63,0x62,0x62,0x66,0x39,0x63,0x62,0x66,0x35,0x37,0x65,0x38,0x55,0x4c,0x2c,0x30,0x78,0x33,0x65,0x32,0x31, + 0x37,0x63,0x36,0x33,0x32,0x31,0x36,0x33,0x35,0x64,0x33,0x65,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x36,0x64,0x64,0x33,0x37,0x37,0x63,0x64,0x64,0x37,0x63,0x65,0x61, + 0x39,0x36,0x55,0x4c,0x2c,0x30,0x78,0x36,0x31,0x64,0x63,0x63,0x32,0x37,0x66,0x64,0x63,0x37,0x66,0x31,0x65,0x36,0x31,0x55,0x4c,0x2c,0x30,0x78,0x30,0x64,0x38,0x36, + 0x31,0x61,0x39,0x31,0x38,0x36,0x39,0x31,0x39,0x63,0x30,0x64,0x55,0x4c,0x2c,0x30,0x78,0x30,0x66,0x38,0x35,0x31,0x65,0x39,0x34,0x38,0x35,0x39,0x34,0x39,0x62,0x30, + 0x66,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x65,0x30,0x39,0x30,0x64,0x62,0x61,0x62,0x39,0x30,0x61,0x62,0x34,0x62,0x65,0x30,0x55,0x4c,0x2c,0x30,0x78,0x37,0x63,0x34,0x32, + 0x66,0x38,0x63,0x36,0x34,0x32,0x63,0x36,0x62,0x61,0x37,0x63,0x55,0x4c,0x2c,0x30,0x78,0x37,0x31,0x63,0x34,0x65,0x32,0x35,0x37,0x63,0x34,0x35,0x37,0x32,0x36,0x37, + 0x31,0x55,0x4c,0x2c,0x30,0x78,0x63,0x63,0x61,0x61,0x38,0x33,0x65,0x35,0x61,0x61,0x65,0x35,0x32,0x39,0x63,0x63,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x30,0x64,0x38, + 0x33,0x62,0x37,0x33,0x64,0x38,0x37,0x33,0x65,0x33,0x39,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x36,0x30,0x35,0x30,0x63,0x30,0x66,0x30,0x35,0x30,0x66,0x30,0x39,0x30, + 0x36,0x55,0x4c,0x2c,0x30,0x78,0x66,0x37,0x30,0x31,0x66,0x35,0x30,0x33,0x30,0x31,0x30,0x33,0x66,0x34,0x66,0x37,0x55,0x4c,0x2c,0x30,0x78,0x31,0x63,0x31,0x32,0x33, + 0x38,0x33,0x36,0x31,0x32,0x33,0x36,0x32,0x61,0x31,0x63,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x63,0x32,0x61,0x33,0x39,0x66,0x66,0x65,0x61,0x33,0x66,0x65,0x33,0x63,0x63, + 0x32,0x55,0x4c,0x2c,0x30,0x78,0x36,0x61,0x35,0x66,0x64,0x34,0x65,0x31,0x35,0x66,0x65,0x31,0x38,0x62,0x36,0x61,0x55,0x4c,0x2c,0x30,0x78,0x61,0x65,0x66,0x39,0x34, + 0x37,0x31,0x30,0x66,0x39,0x31,0x30,0x62,0x65,0x61,0x65,0x55,0x4c,0x2c,0x30,0x78,0x36,0x39,0x64,0x30,0x64,0x32,0x36,0x62,0x64,0x30,0x36,0x62,0x30,0x32,0x36,0x39, + 0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x37,0x39,0x31,0x32,0x65,0x61,0x38,0x39,0x31,0x61,0x38,0x62,0x66,0x31,0x37,0x55,0x4c,0x2c,0x30,0x78,0x39,0x39,0x35,0x38,0x32, + 0x39,0x65,0x38,0x35,0x38,0x65,0x38,0x37,0x31,0x39,0x39,0x55,0x4c,0x2c,0x30,0x78,0x33,0x61,0x32,0x37,0x37,0x34,0x36,0x39,0x32,0x37,0x36,0x39,0x35,0x33,0x33,0x61, + 0x55,0x4c,0x2c,0x30,0x78,0x32,0x37,0x62,0x39,0x34,0x65,0x64,0x30,0x62,0x39,0x64,0x30,0x66,0x37,0x32,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64,0x39,0x33,0x38,0x61, + 0x39,0x34,0x38,0x33,0x38,0x34,0x38,0x39,0x31,0x64,0x39,0x55,0x4c,0x2c,0x30,0x78,0x65,0x62,0x31,0x33,0x63,0x64,0x33,0x35,0x31,0x33,0x33,0x35,0x64,0x65,0x65,0x62, + 0x55,0x4c,0x2c,0x30,0x78,0x32,0x62,0x62,0x33,0x35,0x36,0x63,0x65,0x62,0x33,0x63,0x65,0x65,0x35,0x32,0x62,0x55,0x4c,0x2c,0x30,0x78,0x32,0x32,0x33,0x33,0x34,0x34, + 0x35,0x35,0x33,0x33,0x35,0x35,0x37,0x37,0x32,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x64,0x32,0x62,0x62,0x62,0x66,0x64,0x36,0x62,0x62,0x64,0x36,0x30,0x34,0x64,0x32, + 0x55,0x4c,0x2c,0x30,0x78,0x61,0x39,0x37,0x30,0x34,0x39,0x39,0x30,0x37,0x30,0x39,0x30,0x33,0x39,0x61,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,0x37,0x38,0x39,0x30,0x65, + 0x38,0x30,0x38,0x39,0x38,0x30,0x38,0x37,0x30,0x37,0x55,0x4c,0x2c,0x30,0x78,0x33,0x33,0x61,0x37,0x36,0x36,0x66,0x32,0x61,0x37,0x66,0x32,0x63,0x31,0x33,0x33,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x32,0x64,0x62,0x36,0x35,0x61,0x63,0x31,0x62,0x36,0x63,0x31,0x65,0x63,0x32,0x64,0x55,0x4c,0x2c,0x30,0x78,0x33,0x63,0x32,0x32,0x37,0x38, + 0x36,0x36,0x32,0x32,0x36,0x36,0x35,0x61,0x33,0x63,0x55,0x4c,0x2c,0x30,0x78,0x31,0x35,0x39,0x32,0x32,0x61,0x61,0x64,0x39,0x32,0x61,0x64,0x62,0x38,0x31,0x35,0x55, + 0x4c,0x2c,0x30,0x78,0x63,0x39,0x32,0x30,0x38,0x39,0x36,0x30,0x32,0x30,0x36,0x30,0x61,0x39,0x63,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x37,0x34,0x39,0x31,0x35, + 0x64,0x62,0x34,0x39,0x64,0x62,0x35,0x63,0x38,0x37,0x55,0x4c,0x2c,0x30,0x78,0x61,0x61,0x66,0x66,0x34,0x66,0x31,0x61,0x66,0x66,0x31,0x61,0x62,0x30,0x61,0x61,0x55, + 0x4c,0x2c,0x30,0x78,0x35,0x30,0x37,0x38,0x61,0x30,0x38,0x38,0x37,0x38,0x38,0x38,0x64,0x38,0x35,0x30,0x55,0x4c,0x2c,0x30,0x78,0x61,0x35,0x37,0x61,0x35,0x31,0x38, + 0x65,0x37,0x61,0x38,0x65,0x32,0x62,0x61,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x33,0x38,0x66,0x30,0x36,0x38,0x61,0x38,0x66,0x38,0x61,0x38,0x39,0x30,0x33,0x55, + 0x4c,0x2c,0x30,0x78,0x35,0x39,0x66,0x38,0x62,0x32,0x31,0x33,0x66,0x38,0x31,0x33,0x34,0x61,0x35,0x39,0x55,0x4c,0x2c,0x30,0x78,0x30,0x39,0x38,0x30,0x31,0x32,0x39, + 0x62,0x38,0x30,0x39,0x62,0x39,0x32,0x30,0x39,0x55,0x4c,0x2c,0x30,0x78,0x31,0x61,0x31,0x37,0x33,0x34,0x33,0x39,0x31,0x37,0x33,0x39,0x32,0x33,0x31,0x61,0x55,0x4c, + 0x2c,0x0a,0x30,0x78,0x36,0x35,0x64,0x61,0x63,0x61,0x37,0x35,0x64,0x61,0x37,0x35,0x31,0x30,0x36,0x35,0x55,0x4c,0x2c,0x30,0x78,0x64,0x37,0x33,0x31,0x62,0x35,0x35, + 0x33,0x33,0x31,0x35,0x33,0x38,0x34,0x64,0x37,0x55,0x4c,0x2c,0x30,0x78,0x38,0x34,0x63,0x36,0x31,0x33,0x35,0x31,0x63,0x36,0x35,0x31,0x64,0x35,0x38,0x34,0x55,0x4c, + 0x2c,0x30,0x78,0x64,0x30,0x62,0x38,0x62,0x62,0x64,0x33,0x62,0x38,0x64,0x33,0x30,0x33,0x64,0x30,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x32,0x63,0x33,0x31,0x66,0x35, + 0x65,0x63,0x33,0x35,0x65,0x64,0x63,0x38,0x32,0x55,0x4c,0x2c,0x30,0x78,0x32,0x39,0x62,0x30,0x35,0x32,0x63,0x62,0x62,0x30,0x63,0x62,0x65,0x32,0x32,0x39,0x55,0x4c, + 0x2c,0x30,0x78,0x35,0x61,0x37,0x37,0x62,0x34,0x39,0x39,0x37,0x37,0x39,0x39,0x63,0x33,0x35,0x61,0x55,0x4c,0x2c,0x30,0x78,0x31,0x65,0x31,0x31,0x33,0x63,0x33,0x33, + 0x31,0x31,0x33,0x33,0x32,0x64,0x31,0x65,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x62,0x63,0x62,0x66,0x36,0x34,0x36,0x63,0x62,0x34,0x36,0x33,0x64,0x37,0x62,0x55,0x4c, + 0x2c,0x30,0x78,0x61,0x38,0x66,0x63,0x34,0x62,0x31,0x66,0x66,0x63,0x31,0x66,0x62,0x37,0x61,0x38,0x55,0x4c,0x2c,0x30,0x78,0x36,0x64,0x64,0x36,0x64,0x61,0x36,0x31, + 0x64,0x36,0x36,0x31,0x30,0x63,0x36,0x64,0x55,0x4c,0x2c,0x30,0x78,0x32,0x63,0x33,0x61,0x35,0x38,0x34,0x65,0x33,0x61,0x34,0x65,0x36,0x32,0x32,0x63,0x55,0x4c,0x0a, + 0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x54,0x34,0x5f,0x47,0x5b,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x41,0x35,0x46,0x34,0x33,0x32,0x43,0x36,0x43,0x36,0x41,0x35,0x39,0x37,0x46,0x34,0x55,0x4c, + 0x2c,0x30,0x78,0x38,0x34,0x39,0x37,0x36,0x46,0x46,0x38,0x46,0x38,0x38,0x34,0x45,0x42,0x39,0x37,0x55,0x4c,0x2c,0x30,0x78,0x39,0x39,0x42,0x30,0x35,0x45,0x45,0x45, + 0x45,0x45,0x39,0x39,0x43,0x37,0x42,0x30,0x55,0x4c,0x2c,0x30,0x78,0x38,0x44,0x38,0x43,0x37,0x41,0x46,0x36,0x46,0x36,0x38,0x44,0x46,0x37,0x38,0x43,0x55,0x4c,0x2c, + 0x0a,0x30,0x78,0x30,0x44,0x31,0x37,0x45,0x38,0x46,0x46,0x46,0x46,0x30,0x44,0x45,0x35,0x31,0x37,0x55,0x4c,0x2c,0x30,0x78,0x42,0x44,0x44,0x43,0x30,0x41,0x44,0x36, + 0x44,0x36,0x42,0x44,0x42,0x37,0x44,0x43,0x55,0x4c,0x2c,0x30,0x78,0x42,0x31,0x43,0x38,0x31,0x36,0x44,0x45,0x44,0x45,0x42,0x31,0x41,0x37,0x43,0x38,0x55,0x4c,0x2c, + 0x30,0x78,0x35,0x34,0x46,0x43,0x36,0x44,0x39,0x31,0x39,0x31,0x35,0x34,0x33,0x39,0x46,0x43,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x30,0x46,0x30,0x39,0x30,0x36,0x30, + 0x36,0x30,0x35,0x30,0x43,0x30,0x46,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x33,0x30,0x35,0x30,0x37,0x30,0x32,0x30,0x32,0x30,0x33,0x30,0x34,0x30,0x35,0x55,0x4c,0x2c, + 0x30,0x78,0x41,0x39,0x45,0x30,0x32,0x45,0x43,0x45,0x43,0x45,0x41,0x39,0x38,0x37,0x45,0x30,0x55,0x4c,0x2c,0x30,0x78,0x37,0x44,0x38,0x37,0x44,0x31,0x35,0x36,0x35, + 0x36,0x37,0x44,0x41,0x43,0x38,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x39,0x32,0x42,0x43,0x43,0x45,0x37,0x45,0x37,0x31,0x39,0x44,0x35,0x32,0x42,0x55,0x4c,0x2c, + 0x30,0x78,0x36,0x32,0x41,0x36,0x31,0x33,0x42,0x35,0x42,0x35,0x36,0x32,0x37,0x31,0x41,0x36,0x55,0x4c,0x2c,0x30,0x78,0x45,0x36,0x33,0x31,0x37,0x43,0x34,0x44,0x34, + 0x44,0x45,0x36,0x39,0x41,0x33,0x31,0x55,0x4c,0x2c,0x30,0x78,0x39,0x41,0x42,0x35,0x35,0x39,0x45,0x43,0x45,0x43,0x39,0x41,0x43,0x33,0x42,0x35,0x55,0x4c,0x2c,0x0a, + 0x30,0x78,0x34,0x35,0x43,0x46,0x34,0x30,0x38,0x46,0x38,0x46,0x34,0x35,0x30,0x35,0x43,0x46,0x55,0x4c,0x2c,0x30,0x78,0x39,0x44,0x42,0x43,0x41,0x33,0x31,0x46,0x31, + 0x46,0x39,0x44,0x33,0x45,0x42,0x43,0x55,0x4c,0x2c,0x30,0x78,0x34,0x30,0x43,0x30,0x34,0x39,0x38,0x39,0x38,0x39,0x34,0x30,0x30,0x39,0x43,0x30,0x55,0x4c,0x2c,0x30, + 0x78,0x38,0x37,0x39,0x32,0x36,0x38,0x46,0x41,0x46,0x41,0x38,0x37,0x45,0x46,0x39,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x35,0x33,0x46,0x44,0x30,0x45,0x46,0x45, + 0x46,0x31,0x35,0x43,0x35,0x33,0x46,0x55,0x4c,0x2c,0x30,0x78,0x45,0x42,0x32,0x36,0x39,0x34,0x42,0x32,0x42,0x32,0x45,0x42,0x37,0x46,0x32,0x36,0x55,0x4c,0x2c,0x30, + 0x78,0x43,0x39,0x34,0x30,0x43,0x45,0x38,0x45,0x38,0x45,0x43,0x39,0x30,0x37,0x34,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x42,0x31,0x44,0x45,0x36,0x46,0x42,0x46,0x42, + 0x30,0x42,0x45,0x44,0x31,0x44,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x45,0x43,0x32,0x46,0x36,0x45,0x34,0x31,0x34,0x31,0x45,0x43,0x38,0x32,0x32,0x46,0x55,0x4c,0x2c,0x30, + 0x78,0x36,0x37,0x41,0x39,0x31,0x41,0x42,0x33,0x42,0x33,0x36,0x37,0x37,0x44,0x41,0x39,0x55,0x4c,0x2c,0x30,0x78,0x46,0x44,0x31,0x43,0x34,0x33,0x35,0x46,0x35,0x46, + 0x46,0x44,0x42,0x45,0x31,0x43,0x55,0x4c,0x2c,0x30,0x78,0x45,0x41,0x32,0x35,0x36,0x30,0x34,0x35,0x34,0x35,0x45,0x41,0x38,0x41,0x32,0x35,0x55,0x4c,0x2c,0x0a,0x30, + 0x78,0x42,0x46,0x44,0x41,0x46,0x39,0x32,0x33,0x32,0x33,0x42,0x46,0x34,0x36,0x44,0x41,0x55,0x4c,0x2c,0x30,0x78,0x46,0x37,0x30,0x32,0x35,0x31,0x35,0x33,0x35,0x33, + 0x46,0x37,0x41,0x36,0x30,0x32,0x55,0x4c,0x2c,0x30,0x78,0x39,0x36,0x41,0x31,0x34,0x35,0x45,0x34,0x45,0x34,0x39,0x36,0x44,0x33,0x41,0x31,0x55,0x4c,0x2c,0x30,0x78, + 0x35,0x42,0x45,0x44,0x37,0x36,0x39,0x42,0x39,0x42,0x35,0x42,0x32,0x44,0x45,0x44,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x32,0x35,0x44,0x32,0x38,0x37,0x35,0x37,0x35, + 0x43,0x32,0x45,0x41,0x35,0x44,0x55,0x4c,0x2c,0x30,0x78,0x31,0x43,0x32,0x34,0x43,0x35,0x45,0x31,0x45,0x31,0x31,0x43,0x44,0x39,0x32,0x34,0x55,0x4c,0x2c,0x30,0x78, + 0x41,0x45,0x45,0x39,0x44,0x34,0x33,0x44,0x33,0x44,0x41,0x45,0x37,0x41,0x45,0x39,0x55,0x4c,0x2c,0x30,0x78,0x36,0x41,0x42,0x45,0x46,0x32,0x34,0x43,0x34,0x43,0x36, + 0x41,0x39,0x38,0x42,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x41,0x45,0x45,0x38,0x32,0x36,0x43,0x36,0x43,0x35,0x41,0x44,0x38,0x45,0x45,0x55,0x4c,0x2c,0x30,0x78, + 0x34,0x31,0x43,0x33,0x42,0x44,0x37,0x45,0x37,0x45,0x34,0x31,0x46,0x43,0x43,0x33,0x55,0x4c,0x2c,0x30,0x78,0x30,0x32,0x30,0x36,0x46,0x33,0x46,0x35,0x46,0x35,0x30, + 0x32,0x46,0x31,0x30,0x36,0x55,0x4c,0x2c,0x30,0x78,0x34,0x46,0x44,0x31,0x35,0x32,0x38,0x33,0x38,0x33,0x34,0x46,0x31,0x44,0x44,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78, + 0x35,0x43,0x45,0x34,0x38,0x43,0x36,0x38,0x36,0x38,0x35,0x43,0x44,0x30,0x45,0x34,0x55,0x4c,0x2c,0x30,0x78,0x46,0x34,0x30,0x37,0x35,0x36,0x35,0x31,0x35,0x31,0x46, + 0x34,0x41,0x32,0x30,0x37,0x55,0x4c,0x2c,0x30,0x78,0x33,0x34,0x35,0x43,0x38,0x44,0x44,0x31,0x44,0x31,0x33,0x34,0x42,0x39,0x35,0x43,0x55,0x4c,0x2c,0x30,0x78,0x30, + 0x38,0x31,0x38,0x45,0x31,0x46,0x39,0x46,0x39,0x30,0x38,0x45,0x39,0x31,0x38,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x33,0x41,0x45,0x34,0x43,0x45,0x32,0x45,0x32,0x39, + 0x33,0x44,0x46,0x41,0x45,0x55,0x4c,0x2c,0x30,0x78,0x37,0x33,0x39,0x35,0x33,0x45,0x41,0x42,0x41,0x42,0x37,0x33,0x34,0x44,0x39,0x35,0x55,0x4c,0x2c,0x30,0x78,0x35, + 0x33,0x46,0x35,0x39,0x37,0x36,0x32,0x36,0x32,0x35,0x33,0x43,0x34,0x46,0x35,0x55,0x4c,0x2c,0x30,0x78,0x33,0x46,0x34,0x31,0x36,0x42,0x32,0x41,0x32,0x41,0x33,0x46, + 0x35,0x34,0x34,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x43,0x31,0x34,0x31,0x43,0x30,0x38,0x30,0x38,0x30,0x43,0x31,0x30,0x31,0x34,0x55,0x4c,0x2c,0x30,0x78,0x35, + 0x32,0x46,0x36,0x36,0x33,0x39,0x35,0x39,0x35,0x35,0x32,0x33,0x31,0x46,0x36,0x55,0x4c,0x2c,0x30,0x78,0x36,0x35,0x41,0x46,0x45,0x39,0x34,0x36,0x34,0x36,0x36,0x35, + 0x38,0x43,0x41,0x46,0x55,0x4c,0x2c,0x30,0x78,0x35,0x45,0x45,0x32,0x37,0x46,0x39,0x44,0x39,0x44,0x35,0x45,0x32,0x31,0x45,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32, + 0x38,0x37,0x38,0x34,0x38,0x33,0x30,0x33,0x30,0x32,0x38,0x36,0x30,0x37,0x38,0x55,0x4c,0x2c,0x30,0x78,0x41,0x31,0x46,0x38,0x43,0x46,0x33,0x37,0x33,0x37,0x41,0x31, + 0x36,0x45,0x46,0x38,0x55,0x4c,0x2c,0x30,0x78,0x30,0x46,0x31,0x31,0x31,0x42,0x30,0x41,0x30,0x41,0x30,0x46,0x31,0x34,0x31,0x31,0x55,0x4c,0x2c,0x30,0x78,0x42,0x35, + 0x43,0x34,0x45,0x42,0x32,0x46,0x32,0x46,0x42,0x35,0x35,0x45,0x43,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x30,0x39,0x31,0x42,0x31,0x35,0x30,0x45,0x30,0x45,0x30,0x39, + 0x31,0x43,0x31,0x42,0x55,0x4c,0x2c,0x30,0x78,0x33,0x36,0x35,0x41,0x37,0x45,0x32,0x34,0x32,0x34,0x33,0x36,0x34,0x38,0x35,0x41,0x55,0x4c,0x2c,0x30,0x78,0x39,0x42, + 0x42,0x36,0x41,0x44,0x31,0x42,0x31,0x42,0x39,0x42,0x33,0x36,0x42,0x36,0x55,0x4c,0x2c,0x30,0x78,0x33,0x44,0x34,0x37,0x39,0x38,0x44,0x46,0x44,0x46,0x33,0x44,0x41, + 0x35,0x34,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x36,0x36,0x41,0x41,0x37,0x43,0x44,0x43,0x44,0x32,0x36,0x38,0x31,0x36,0x41,0x55,0x4c,0x2c,0x30,0x78,0x36,0x39, + 0x42,0x42,0x46,0x35,0x34,0x45,0x34,0x45,0x36,0x39,0x39,0x43,0x42,0x42,0x55,0x4c,0x2c,0x30,0x78,0x43,0x44,0x34,0x43,0x33,0x33,0x37,0x46,0x37,0x46,0x43,0x44,0x46, + 0x45,0x34,0x43,0x55,0x4c,0x2c,0x30,0x78,0x39,0x46,0x42,0x41,0x35,0x30,0x45,0x41,0x45,0x41,0x39,0x46,0x43,0x46,0x42,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x31,0x42, + 0x32,0x44,0x33,0x46,0x31,0x32,0x31,0x32,0x31,0x42,0x32,0x34,0x32,0x44,0x55,0x4c,0x2c,0x30,0x78,0x39,0x45,0x42,0x39,0x41,0x34,0x31,0x44,0x31,0x44,0x39,0x45,0x33, + 0x41,0x42,0x39,0x55,0x4c,0x2c,0x30,0x78,0x37,0x34,0x39,0x43,0x43,0x34,0x35,0x38,0x35,0x38,0x37,0x34,0x42,0x30,0x39,0x43,0x55,0x4c,0x2c,0x30,0x78,0x32,0x45,0x37, + 0x32,0x34,0x36,0x33,0x34,0x33,0x34,0x32,0x45,0x36,0x38,0x37,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x44,0x37,0x37,0x34,0x31,0x33,0x36,0x33,0x36,0x32,0x44,0x36, + 0x43,0x37,0x37,0x55,0x4c,0x2c,0x30,0x78,0x42,0x32,0x43,0x44,0x31,0x31,0x44,0x43,0x44,0x43,0x42,0x32,0x41,0x33,0x43,0x44,0x55,0x4c,0x2c,0x30,0x78,0x45,0x45,0x32, + 0x39,0x39,0x44,0x42,0x34,0x42,0x34,0x45,0x45,0x37,0x33,0x32,0x39,0x55,0x4c,0x2c,0x30,0x78,0x46,0x42,0x31,0x36,0x34,0x44,0x35,0x42,0x35,0x42,0x46,0x42,0x42,0x36, + 0x31,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x36,0x30,0x31,0x41,0x35,0x41,0x34,0x41,0x34,0x46,0x36,0x35,0x33,0x30,0x31,0x55,0x4c,0x2c,0x30,0x78,0x34,0x44,0x44, + 0x37,0x41,0x31,0x37,0x36,0x37,0x36,0x34,0x44,0x45,0x43,0x44,0x37,0x55,0x4c,0x2c,0x30,0x78,0x36,0x31,0x41,0x33,0x31,0x34,0x42,0x37,0x42,0x37,0x36,0x31,0x37,0x35, + 0x41,0x33,0x55,0x4c,0x2c,0x30,0x78,0x43,0x45,0x34,0x39,0x33,0x34,0x37,0x44,0x37,0x44,0x43,0x45,0x46,0x41,0x34,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x37,0x42,0x38, + 0x44,0x44,0x46,0x35,0x32,0x35,0x32,0x37,0x42,0x41,0x34,0x38,0x44,0x55,0x4c,0x2c,0x30,0x78,0x33,0x45,0x34,0x32,0x39,0x46,0x44,0x44,0x44,0x44,0x33,0x45,0x41,0x31, + 0x34,0x32,0x55,0x4c,0x2c,0x30,0x78,0x37,0x31,0x39,0x33,0x43,0x44,0x35,0x45,0x35,0x45,0x37,0x31,0x42,0x43,0x39,0x33,0x55,0x4c,0x2c,0x30,0x78,0x39,0x37,0x41,0x32, + 0x42,0x31,0x31,0x33,0x31,0x33,0x39,0x37,0x32,0x36,0x41,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x35,0x30,0x34,0x41,0x32,0x41,0x36,0x41,0x36,0x46,0x35,0x35,0x37, + 0x30,0x34,0x55,0x4c,0x2c,0x30,0x78,0x36,0x38,0x42,0x38,0x30,0x31,0x42,0x39,0x42,0x39,0x36,0x38,0x36,0x39,0x42,0x38,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x32,0x43,0x37,0x34,0x42,0x35,0x43,0x31,0x43,0x31,0x32,0x43,0x39,0x39,0x37, + 0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x30,0x41,0x30,0x45,0x30,0x34,0x30,0x34,0x30,0x36,0x30,0x38,0x30,0x41,0x30,0x55,0x4c,0x2c,0x30,0x78,0x31,0x46,0x32,0x31, + 0x43,0x32,0x45,0x33,0x45,0x33,0x31,0x46,0x44,0x44,0x32,0x31,0x55,0x4c,0x2c,0x30,0x78,0x43,0x38,0x34,0x33,0x33,0x41,0x37,0x39,0x37,0x39,0x43,0x38,0x46,0x32,0x34, + 0x33,0x55,0x4c,0x2c,0x30,0x78,0x45,0x44,0x32,0x43,0x39,0x41,0x42,0x36,0x42,0x36,0x45,0x44,0x37,0x37,0x32,0x43,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x42,0x45,0x44,0x39, + 0x30,0x44,0x44,0x34,0x44,0x34,0x42,0x45,0x42,0x33,0x44,0x39,0x55,0x4c,0x2c,0x30,0x78,0x34,0x36,0x43,0x41,0x34,0x37,0x38,0x44,0x38,0x44,0x34,0x36,0x30,0x31,0x43, + 0x41,0x55,0x4c,0x2c,0x30,0x78,0x44,0x39,0x37,0x30,0x31,0x37,0x36,0x37,0x36,0x37,0x44,0x39,0x43,0x45,0x37,0x30,0x55,0x4c,0x2c,0x30,0x78,0x34,0x42,0x44,0x44,0x41, + 0x46,0x37,0x32,0x37,0x32,0x34,0x42,0x45,0x34,0x44,0x44,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x45,0x37,0x39,0x45,0x44,0x39,0x34,0x39,0x34,0x44,0x45,0x33,0x33,0x37, + 0x39,0x55,0x4c,0x2c,0x30,0x78,0x44,0x34,0x36,0x37,0x46,0x46,0x39,0x38,0x39,0x38,0x44,0x34,0x32,0x42,0x36,0x37,0x55,0x4c,0x2c,0x30,0x78,0x45,0x38,0x32,0x33,0x39, + 0x33,0x42,0x30,0x42,0x30,0x45,0x38,0x37,0x42,0x32,0x33,0x55,0x4c,0x2c,0x30,0x78,0x34,0x41,0x44,0x45,0x35,0x42,0x38,0x35,0x38,0x35,0x34,0x41,0x31,0x31,0x44,0x45, + 0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x42,0x42,0x44,0x30,0x36,0x42,0x42,0x42,0x42,0x36,0x42,0x36,0x44,0x42,0x44,0x55,0x4c,0x2c,0x30,0x78,0x32,0x41,0x37,0x45,0x42, + 0x42,0x43,0x35,0x43,0x35,0x32,0x41,0x39,0x31,0x37,0x45,0x55,0x4c,0x2c,0x30,0x78,0x45,0x35,0x33,0x34,0x37,0x42,0x34,0x46,0x34,0x46,0x45,0x35,0x39,0x45,0x33,0x34, + 0x55,0x4c,0x2c,0x30,0x78,0x31,0x36,0x33,0x41,0x44,0x37,0x45,0x44,0x45,0x44,0x31,0x36,0x43,0x31,0x33,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x35,0x35,0x34,0x44, + 0x32,0x38,0x36,0x38,0x36,0x43,0x35,0x31,0x37,0x35,0x34,0x55,0x4c,0x2c,0x30,0x78,0x44,0x37,0x36,0x32,0x46,0x38,0x39,0x41,0x39,0x41,0x44,0x37,0x32,0x46,0x36,0x32, + 0x55,0x4c,0x2c,0x30,0x78,0x35,0x35,0x46,0x46,0x39,0x39,0x36,0x36,0x36,0x36,0x35,0x35,0x43,0x43,0x46,0x46,0x55,0x4c,0x2c,0x30,0x78,0x39,0x34,0x41,0x37,0x42,0x36, + 0x31,0x31,0x31,0x31,0x39,0x34,0x32,0x32,0x41,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x46,0x34,0x41,0x43,0x30,0x38,0x41,0x38,0x41,0x43,0x46,0x30,0x46,0x34,0x41, + 0x55,0x4c,0x2c,0x30,0x78,0x31,0x30,0x33,0x30,0x44,0x39,0x45,0x39,0x45,0x39,0x31,0x30,0x43,0x39,0x33,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x36,0x30,0x41,0x30,0x45, + 0x30,0x34,0x30,0x34,0x30,0x36,0x30,0x38,0x30,0x41,0x55,0x4c,0x2c,0x30,0x78,0x38,0x31,0x39,0x38,0x36,0x36,0x46,0x45,0x46,0x45,0x38,0x31,0x45,0x37,0x39,0x38,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x46,0x30,0x30,0x42,0x41,0x42,0x41,0x30,0x41,0x30,0x46,0x30,0x35,0x42,0x30,0x42,0x55,0x4c,0x2c,0x30,0x78,0x34,0x34,0x43,0x43,0x42,0x34, + 0x37,0x38,0x37,0x38,0x34,0x34,0x46,0x30,0x43,0x43,0x55,0x4c,0x2c,0x30,0x78,0x42,0x41,0x44,0x35,0x46,0x30,0x32,0x35,0x32,0x35,0x42,0x41,0x34,0x41,0x44,0x35,0x55, + 0x4c,0x2c,0x30,0x78,0x45,0x33,0x33,0x45,0x37,0x35,0x34,0x42,0x34,0x42,0x45,0x33,0x39,0x36,0x33,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x46,0x33,0x30,0x45,0x41,0x43, + 0x41,0x32,0x41,0x32,0x46,0x33,0x35,0x46,0x30,0x45,0x55,0x4c,0x2c,0x30,0x78,0x46,0x45,0x31,0x39,0x34,0x34,0x35,0x44,0x35,0x44,0x46,0x45,0x42,0x41,0x31,0x39,0x55, + 0x4c,0x2c,0x30,0x78,0x43,0x30,0x35,0x42,0x44,0x42,0x38,0x30,0x38,0x30,0x43,0x30,0x31,0x42,0x35,0x42,0x55,0x4c,0x2c,0x30,0x78,0x38,0x41,0x38,0x35,0x38,0x30,0x30, + 0x35,0x30,0x35,0x38,0x41,0x30,0x41,0x38,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x41,0x44,0x45,0x43,0x44,0x33,0x33,0x46,0x33,0x46,0x41,0x44,0x37,0x45,0x45,0x43,0x55, + 0x4c,0x2c,0x30,0x78,0x42,0x43,0x44,0x46,0x46,0x45,0x32,0x31,0x32,0x31,0x42,0x43,0x34,0x32,0x44,0x46,0x55,0x4c,0x2c,0x30,0x78,0x34,0x38,0x44,0x38,0x41,0x38,0x37, + 0x30,0x37,0x30,0x34,0x38,0x45,0x30,0x44,0x38,0x55,0x4c,0x2c,0x30,0x78,0x30,0x34,0x30,0x43,0x46,0x44,0x46,0x31,0x46,0x31,0x30,0x34,0x46,0x39,0x30,0x43,0x55,0x4c, + 0x2c,0x0a,0x30,0x78,0x44,0x46,0x37,0x41,0x31,0x39,0x36,0x33,0x36,0x33,0x44,0x46,0x43,0x36,0x37,0x41,0x55,0x4c,0x2c,0x30,0x78,0x43,0x31,0x35,0x38,0x32,0x46,0x37, + 0x37,0x37,0x37,0x43,0x31,0x45,0x45,0x35,0x38,0x55,0x4c,0x2c,0x30,0x78,0x37,0x35,0x39,0x46,0x33,0x30,0x41,0x46,0x41,0x46,0x37,0x35,0x34,0x35,0x39,0x46,0x55,0x4c, + 0x2c,0x30,0x78,0x36,0x33,0x41,0x35,0x45,0x37,0x34,0x32,0x34,0x32,0x36,0x33,0x38,0x34,0x41,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x30,0x35,0x30,0x37,0x30,0x32, + 0x30,0x32,0x30,0x33,0x30,0x34,0x30,0x35,0x30,0x55,0x4c,0x2c,0x30,0x78,0x31,0x41,0x32,0x45,0x43,0x42,0x45,0x35,0x45,0x35,0x31,0x41,0x44,0x31,0x32,0x45,0x55,0x4c, + 0x2c,0x30,0x78,0x30,0x45,0x31,0x32,0x45,0x46,0x46,0x44,0x46,0x44,0x30,0x45,0x45,0x31,0x31,0x32,0x55,0x4c,0x2c,0x30,0x78,0x36,0x44,0x42,0x37,0x30,0x38,0x42,0x46, + 0x42,0x46,0x36,0x44,0x36,0x35,0x42,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x34,0x43,0x44,0x34,0x35,0x35,0x38,0x31,0x38,0x31,0x34,0x43,0x31,0x39,0x44,0x34,0x55,0x4c, + 0x2c,0x30,0x78,0x31,0x34,0x33,0x43,0x32,0x34,0x31,0x38,0x31,0x38,0x31,0x34,0x33,0x30,0x33,0x43,0x55,0x4c,0x2c,0x30,0x78,0x33,0x35,0x35,0x46,0x37,0x39,0x32,0x36, + 0x32,0x36,0x33,0x35,0x34,0x43,0x35,0x46,0x55,0x4c,0x2c,0x30,0x78,0x32,0x46,0x37,0x31,0x42,0x32,0x43,0x33,0x43,0x33,0x32,0x46,0x39,0x44,0x37,0x31,0x55,0x4c,0x2c, + 0x0a,0x30,0x78,0x45,0x31,0x33,0x38,0x38,0x36,0x42,0x45,0x42,0x45,0x45,0x31,0x36,0x37,0x33,0x38,0x55,0x4c,0x2c,0x30,0x78,0x41,0x32,0x46,0x44,0x43,0x38,0x33,0x35, + 0x33,0x35,0x41,0x32,0x36,0x41,0x46,0x44,0x55,0x4c,0x2c,0x30,0x78,0x43,0x43,0x34,0x46,0x43,0x37,0x38,0x38,0x38,0x38,0x43,0x43,0x30,0x42,0x34,0x46,0x55,0x4c,0x2c, + 0x30,0x78,0x33,0x39,0x34,0x42,0x36,0x35,0x32,0x45,0x32,0x45,0x33,0x39,0x35,0x43,0x34,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x35,0x37,0x46,0x39,0x36,0x41,0x39,0x33, + 0x39,0x33,0x35,0x37,0x33,0x44,0x46,0x39,0x55,0x4c,0x2c,0x30,0x78,0x46,0x32,0x30,0x44,0x35,0x38,0x35,0x35,0x35,0x35,0x46,0x32,0x41,0x41,0x30,0x44,0x55,0x4c,0x2c, + 0x30,0x78,0x38,0x32,0x39,0x44,0x36,0x31,0x46,0x43,0x46,0x43,0x38,0x32,0x45,0x33,0x39,0x44,0x55,0x4c,0x2c,0x30,0x78,0x34,0x37,0x43,0x39,0x42,0x33,0x37,0x41,0x37, + 0x41,0x34,0x37,0x46,0x34,0x43,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x41,0x43,0x45,0x46,0x32,0x37,0x43,0x38,0x43,0x38,0x41,0x43,0x38,0x42,0x45,0x46,0x55,0x4c,0x2c, + 0x30,0x78,0x45,0x37,0x33,0x32,0x38,0x38,0x42,0x41,0x42,0x41,0x45,0x37,0x36,0x46,0x33,0x32,0x55,0x4c,0x2c,0x30,0x78,0x32,0x42,0x37,0x44,0x34,0x46,0x33,0x32,0x33, + 0x32,0x32,0x42,0x36,0x34,0x37,0x44,0x55,0x4c,0x2c,0x30,0x78,0x39,0x35,0x41,0x34,0x34,0x32,0x45,0x36,0x45,0x36,0x39,0x35,0x44,0x37,0x41,0x34,0x55,0x4c,0x2c,0x0a, + 0x30,0x78,0x41,0x30,0x46,0x42,0x33,0x42,0x43,0x30,0x43,0x30,0x41,0x30,0x39,0x42,0x46,0x42,0x55,0x4c,0x2c,0x30,0x78,0x39,0x38,0x42,0x33,0x41,0x41,0x31,0x39,0x31, + 0x39,0x39,0x38,0x33,0x32,0x42,0x33,0x55,0x4c,0x2c,0x30,0x78,0x44,0x31,0x36,0x38,0x46,0x36,0x39,0x45,0x39,0x45,0x44,0x31,0x32,0x37,0x36,0x38,0x55,0x4c,0x2c,0x30, + 0x78,0x37,0x46,0x38,0x31,0x32,0x32,0x41,0x33,0x41,0x33,0x37,0x46,0x35,0x44,0x38,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x36,0x36,0x41,0x41,0x45,0x45,0x34,0x34,0x34, + 0x34,0x36,0x36,0x38,0x38,0x41,0x41,0x55,0x4c,0x2c,0x30,0x78,0x37,0x45,0x38,0x32,0x44,0x36,0x35,0x34,0x35,0x34,0x37,0x45,0x41,0x38,0x38,0x32,0x55,0x4c,0x2c,0x30, + 0x78,0x41,0x42,0x45,0x36,0x44,0x44,0x33,0x42,0x33,0x42,0x41,0x42,0x37,0x36,0x45,0x36,0x55,0x4c,0x2c,0x30,0x78,0x38,0x33,0x39,0x45,0x39,0x35,0x30,0x42,0x30,0x42, + 0x38,0x33,0x31,0x36,0x39,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x41,0x34,0x35,0x43,0x39,0x38,0x43,0x38,0x43,0x43,0x41,0x30,0x33,0x34,0x35,0x55,0x4c,0x2c,0x30, + 0x78,0x32,0x39,0x37,0x42,0x42,0x43,0x43,0x37,0x43,0x37,0x32,0x39,0x39,0x35,0x37,0x42,0x55,0x4c,0x2c,0x30,0x78,0x44,0x33,0x36,0x45,0x30,0x35,0x36,0x42,0x36,0x42, + 0x44,0x33,0x44,0x36,0x36,0x45,0x55,0x4c,0x2c,0x30,0x78,0x33,0x43,0x34,0x34,0x36,0x43,0x32,0x38,0x32,0x38,0x33,0x43,0x35,0x30,0x34,0x34,0x55,0x4c,0x2c,0x0a,0x30, + 0x78,0x37,0x39,0x38,0x42,0x32,0x43,0x41,0x37,0x41,0x37,0x37,0x39,0x35,0x35,0x38,0x42,0x55,0x4c,0x2c,0x30,0x78,0x45,0x32,0x33,0x44,0x38,0x31,0x42,0x43,0x42,0x43, + 0x45,0x32,0x36,0x33,0x33,0x44,0x55,0x4c,0x2c,0x30,0x78,0x31,0x44,0x32,0x37,0x33,0x31,0x31,0x36,0x31,0x36,0x31,0x44,0x32,0x43,0x32,0x37,0x55,0x4c,0x2c,0x30,0x78, + 0x37,0x36,0x39,0x41,0x33,0x37,0x41,0x44,0x41,0x44,0x37,0x36,0x34,0x31,0x39,0x41,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x42,0x34,0x44,0x39,0x36,0x44,0x42,0x44,0x42, + 0x33,0x42,0x41,0x44,0x34,0x44,0x55,0x4c,0x2c,0x30,0x78,0x35,0x36,0x46,0x41,0x39,0x45,0x36,0x34,0x36,0x34,0x35,0x36,0x43,0x38,0x46,0x41,0x55,0x4c,0x2c,0x30,0x78, + 0x34,0x45,0x44,0x32,0x41,0x36,0x37,0x34,0x37,0x34,0x34,0x45,0x45,0x38,0x44,0x32,0x55,0x4c,0x2c,0x30,0x78,0x31,0x45,0x32,0x32,0x33,0x36,0x31,0x34,0x31,0x34,0x31, + 0x45,0x32,0x38,0x32,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x42,0x37,0x36,0x45,0x34,0x39,0x32,0x39,0x32,0x44,0x42,0x33,0x46,0x37,0x36,0x55,0x4c,0x2c,0x30,0x78, + 0x30,0x41,0x31,0x45,0x31,0x32,0x30,0x43,0x30,0x43,0x30,0x41,0x31,0x38,0x31,0x45,0x55,0x4c,0x2c,0x30,0x78,0x36,0x43,0x42,0x34,0x46,0x43,0x34,0x38,0x34,0x38,0x36, + 0x43,0x39,0x30,0x42,0x34,0x55,0x4c,0x2c,0x30,0x78,0x45,0x34,0x33,0x37,0x38,0x46,0x42,0x38,0x42,0x38,0x45,0x34,0x36,0x42,0x33,0x37,0x55,0x4c,0x2c,0x0a,0x30,0x78, + 0x35,0x44,0x45,0x37,0x37,0x38,0x39,0x46,0x39,0x46,0x35,0x44,0x32,0x35,0x45,0x37,0x55,0x4c,0x2c,0x30,0x78,0x36,0x45,0x42,0x32,0x30,0x46,0x42,0x44,0x42,0x44,0x36, + 0x45,0x36,0x31,0x42,0x32,0x55,0x4c,0x2c,0x30,0x78,0x45,0x46,0x32,0x41,0x36,0x39,0x34,0x33,0x34,0x33,0x45,0x46,0x38,0x36,0x32,0x41,0x55,0x4c,0x2c,0x30,0x78,0x41, + 0x36,0x46,0x31,0x33,0x35,0x43,0x34,0x43,0x34,0x41,0x36,0x39,0x33,0x46,0x31,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x41,0x38,0x45,0x33,0x44,0x41,0x33,0x39,0x33,0x39,0x41, + 0x38,0x37,0x32,0x45,0x33,0x55,0x4c,0x2c,0x30,0x78,0x41,0x34,0x46,0x37,0x43,0x36,0x33,0x31,0x33,0x31,0x41,0x34,0x36,0x32,0x46,0x37,0x55,0x4c,0x2c,0x30,0x78,0x33, + 0x37,0x35,0x39,0x38,0x41,0x44,0x33,0x44,0x33,0x33,0x37,0x42,0x44,0x35,0x39,0x55,0x4c,0x2c,0x30,0x78,0x38,0x42,0x38,0x36,0x37,0x34,0x46,0x32,0x46,0x32,0x38,0x42, + 0x46,0x46,0x38,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x32,0x35,0x36,0x38,0x33,0x44,0x35,0x44,0x35,0x33,0x32,0x42,0x31,0x35,0x36,0x55,0x4c,0x2c,0x30,0x78,0x34, + 0x33,0x43,0x35,0x34,0x45,0x38,0x42,0x38,0x42,0x34,0x33,0x30,0x44,0x43,0x35,0x55,0x4c,0x2c,0x30,0x78,0x35,0x39,0x45,0x42,0x38,0x35,0x36,0x45,0x36,0x45,0x35,0x39, + 0x44,0x43,0x45,0x42,0x55,0x4c,0x2c,0x30,0x78,0x42,0x37,0x43,0x32,0x31,0x38,0x44,0x41,0x44,0x41,0x42,0x37,0x41,0x46,0x43,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38, + 0x43,0x38,0x46,0x38,0x45,0x30,0x31,0x30,0x31,0x38,0x43,0x30,0x32,0x38,0x46,0x55,0x4c,0x2c,0x30,0x78,0x36,0x34,0x41,0x43,0x31,0x44,0x42,0x31,0x42,0x31,0x36,0x34, + 0x37,0x39,0x41,0x43,0x55,0x4c,0x2c,0x30,0x78,0x44,0x32,0x36,0x44,0x46,0x31,0x39,0x43,0x39,0x43,0x44,0x32,0x32,0x33,0x36,0x44,0x55,0x4c,0x2c,0x30,0x78,0x45,0x30, + 0x33,0x42,0x37,0x32,0x34,0x39,0x34,0x39,0x45,0x30,0x39,0x32,0x33,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x42,0x34,0x43,0x37,0x31,0x46,0x44,0x38,0x44,0x38,0x42,0x34, + 0x41,0x42,0x43,0x37,0x55,0x4c,0x2c,0x30,0x78,0x46,0x41,0x31,0x35,0x42,0x39,0x41,0x43,0x41,0x43,0x46,0x41,0x34,0x33,0x31,0x35,0x55,0x4c,0x2c,0x30,0x78,0x30,0x37, + 0x30,0x39,0x46,0x41,0x46,0x33,0x46,0x33,0x30,0x37,0x46,0x44,0x30,0x39,0x55,0x4c,0x2c,0x30,0x78,0x32,0x35,0x36,0x46,0x41,0x30,0x43,0x46,0x43,0x46,0x32,0x35,0x38, + 0x35,0x36,0x46,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x41,0x46,0x45,0x41,0x32,0x30,0x43,0x41,0x43,0x41,0x41,0x46,0x38,0x46,0x45,0x41,0x55,0x4c,0x2c,0x30,0x78,0x38,0x45, + 0x38,0x39,0x37,0x44,0x46,0x34,0x46,0x34,0x38,0x45,0x46,0x33,0x38,0x39,0x55,0x4c,0x2c,0x30,0x78,0x45,0x39,0x32,0x30,0x36,0x37,0x34,0x37,0x34,0x37,0x45,0x39,0x38, + 0x45,0x32,0x30,0x55,0x4c,0x2c,0x30,0x78,0x31,0x38,0x32,0x38,0x33,0x38,0x31,0x30,0x31,0x30,0x31,0x38,0x32,0x30,0x32,0x38,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x35, + 0x36,0x34,0x30,0x42,0x36,0x46,0x36,0x46,0x44,0x35,0x44,0x45,0x36,0x34,0x55,0x4c,0x2c,0x30,0x78,0x38,0x38,0x38,0x33,0x37,0x33,0x46,0x30,0x46,0x30,0x38,0x38,0x46, + 0x42,0x38,0x33,0x55,0x4c,0x2c,0x30,0x78,0x36,0x46,0x42,0x31,0x46,0x42,0x34,0x41,0x34,0x41,0x36,0x46,0x39,0x34,0x42,0x31,0x55,0x4c,0x2c,0x30,0x78,0x37,0x32,0x39, + 0x36,0x43,0x41,0x35,0x43,0x35,0x43,0x37,0x32,0x42,0x38,0x39,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x34,0x36,0x43,0x35,0x34,0x33,0x38,0x33,0x38,0x32,0x34,0x37, + 0x30,0x36,0x43,0x55,0x4c,0x2c,0x30,0x78,0x46,0x31,0x30,0x38,0x35,0x46,0x35,0x37,0x35,0x37,0x46,0x31,0x41,0x45,0x30,0x38,0x55,0x4c,0x2c,0x30,0x78,0x43,0x37,0x35, + 0x32,0x32,0x31,0x37,0x33,0x37,0x33,0x43,0x37,0x45,0x36,0x35,0x32,0x55,0x4c,0x2c,0x30,0x78,0x35,0x31,0x46,0x33,0x36,0x34,0x39,0x37,0x39,0x37,0x35,0x31,0x33,0x35, + 0x46,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x32,0x33,0x36,0x35,0x41,0x45,0x43,0x42,0x43,0x42,0x32,0x33,0x38,0x44,0x36,0x35,0x55,0x4c,0x2c,0x30,0x78,0x37,0x43,0x38, + 0x34,0x32,0x35,0x41,0x31,0x41,0x31,0x37,0x43,0x35,0x39,0x38,0x34,0x55,0x4c,0x2c,0x30,0x78,0x39,0x43,0x42,0x46,0x35,0x37,0x45,0x38,0x45,0x38,0x39,0x43,0x43,0x42, + 0x42,0x46,0x55,0x4c,0x2c,0x30,0x78,0x32,0x31,0x36,0x33,0x35,0x44,0x33,0x45,0x33,0x45,0x32,0x31,0x37,0x43,0x36,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x44,0x37, + 0x43,0x45,0x41,0x39,0x36,0x39,0x36,0x44,0x44,0x33,0x37,0x37,0x43,0x55,0x4c,0x2c,0x30,0x78,0x44,0x43,0x37,0x46,0x31,0x45,0x36,0x31,0x36,0x31,0x44,0x43,0x43,0x32, + 0x37,0x46,0x55,0x4c,0x2c,0x30,0x78,0x38,0x36,0x39,0x31,0x39,0x43,0x30,0x44,0x30,0x44,0x38,0x36,0x31,0x41,0x39,0x31,0x55,0x4c,0x2c,0x30,0x78,0x38,0x35,0x39,0x34, + 0x39,0x42,0x30,0x46,0x30,0x46,0x38,0x35,0x31,0x45,0x39,0x34,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x30,0x41,0x42,0x34,0x42,0x45,0x30,0x45,0x30,0x39,0x30,0x44,0x42, + 0x41,0x42,0x55,0x4c,0x2c,0x30,0x78,0x34,0x32,0x43,0x36,0x42,0x41,0x37,0x43,0x37,0x43,0x34,0x32,0x46,0x38,0x43,0x36,0x55,0x4c,0x2c,0x30,0x78,0x43,0x34,0x35,0x37, + 0x32,0x36,0x37,0x31,0x37,0x31,0x43,0x34,0x45,0x32,0x35,0x37,0x55,0x4c,0x2c,0x30,0x78,0x41,0x41,0x45,0x35,0x32,0x39,0x43,0x43,0x43,0x43,0x41,0x41,0x38,0x33,0x45, + 0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x38,0x37,0x33,0x45,0x33,0x39,0x30,0x39,0x30,0x44,0x38,0x33,0x42,0x37,0x33,0x55,0x4c,0x2c,0x30,0x78,0x30,0x35,0x30,0x46, + 0x30,0x39,0x30,0x36,0x30,0x36,0x30,0x35,0x30,0x43,0x30,0x46,0x55,0x4c,0x2c,0x30,0x78,0x30,0x31,0x30,0x33,0x46,0x34,0x46,0x37,0x46,0x37,0x30,0x31,0x46,0x35,0x30, + 0x33,0x55,0x4c,0x2c,0x30,0x78,0x31,0x32,0x33,0x36,0x32,0x41,0x31,0x43,0x31,0x43,0x31,0x32,0x33,0x38,0x33,0x36,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x41,0x33,0x46,0x45, + 0x33,0x43,0x43,0x32,0x43,0x32,0x41,0x33,0x39,0x46,0x46,0x45,0x55,0x4c,0x2c,0x30,0x78,0x35,0x46,0x45,0x31,0x38,0x42,0x36,0x41,0x36,0x41,0x35,0x46,0x44,0x34,0x45, + 0x31,0x55,0x4c,0x2c,0x30,0x78,0x46,0x39,0x31,0x30,0x42,0x45,0x41,0x45,0x41,0x45,0x46,0x39,0x34,0x37,0x31,0x30,0x55,0x4c,0x2c,0x30,0x78,0x44,0x30,0x36,0x42,0x30, + 0x32,0x36,0x39,0x36,0x39,0x44,0x30,0x44,0x32,0x36,0x42,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x39,0x31,0x41,0x38,0x42,0x46,0x31,0x37,0x31,0x37,0x39,0x31,0x32,0x45,0x41, + 0x38,0x55,0x4c,0x2c,0x30,0x78,0x35,0x38,0x45,0x38,0x37,0x31,0x39,0x39,0x39,0x39,0x35,0x38,0x32,0x39,0x45,0x38,0x55,0x4c,0x2c,0x30,0x78,0x32,0x37,0x36,0x39,0x35, + 0x33,0x33,0x41,0x33,0x41,0x32,0x37,0x37,0x34,0x36,0x39,0x55,0x4c,0x2c,0x30,0x78,0x42,0x39,0x44,0x30,0x46,0x37,0x32,0x37,0x32,0x37,0x42,0x39,0x34,0x45,0x44,0x30, + 0x55,0x4c,0x2c,0x0a,0x30,0x78,0x33,0x38,0x34,0x38,0x39,0x31,0x44,0x39,0x44,0x39,0x33,0x38,0x41,0x39,0x34,0x38,0x55,0x4c,0x2c,0x30,0x78,0x31,0x33,0x33,0x35,0x44, + 0x45,0x45,0x42,0x45,0x42,0x31,0x33,0x43,0x44,0x33,0x35,0x55,0x4c,0x2c,0x30,0x78,0x42,0x33,0x43,0x45,0x45,0x35,0x32,0x42,0x32,0x42,0x42,0x33,0x35,0x36,0x43,0x45, + 0x55,0x4c,0x2c,0x30,0x78,0x33,0x33,0x35,0x35,0x37,0x37,0x32,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,0x35,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x42,0x42,0x44,0x36,0x30, + 0x34,0x44,0x32,0x44,0x32,0x42,0x42,0x42,0x46,0x44,0x36,0x55,0x4c,0x2c,0x30,0x78,0x37,0x30,0x39,0x30,0x33,0x39,0x41,0x39,0x41,0x39,0x37,0x30,0x34,0x39,0x39,0x30, + 0x55,0x4c,0x2c,0x30,0x78,0x38,0x39,0x38,0x30,0x38,0x37,0x30,0x37,0x30,0x37,0x38,0x39,0x30,0x45,0x38,0x30,0x55,0x4c,0x2c,0x30,0x78,0x41,0x37,0x46,0x32,0x43,0x31, + 0x33,0x33,0x33,0x33,0x41,0x37,0x36,0x36,0x46,0x32,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x42,0x36,0x43,0x31,0x45,0x43,0x32,0x44,0x32,0x44,0x42,0x36,0x35,0x41,0x43,0x31, + 0x55,0x4c,0x2c,0x30,0x78,0x32,0x32,0x36,0x36,0x35,0x41,0x33,0x43,0x33,0x43,0x32,0x32,0x37,0x38,0x36,0x36,0x55,0x4c,0x2c,0x30,0x78,0x39,0x32,0x41,0x44,0x42,0x38, + 0x31,0x35,0x31,0x35,0x39,0x32,0x32,0x41,0x41,0x44,0x55,0x4c,0x2c,0x30,0x78,0x32,0x30,0x36,0x30,0x41,0x39,0x43,0x39,0x43,0x39,0x32,0x30,0x38,0x39,0x36,0x30,0x55, + 0x4c,0x2c,0x0a,0x30,0x78,0x34,0x39,0x44,0x42,0x35,0x43,0x38,0x37,0x38,0x37,0x34,0x39,0x31,0x35,0x44,0x42,0x55,0x4c,0x2c,0x30,0x78,0x46,0x46,0x31,0x41,0x42,0x30, + 0x41,0x41,0x41,0x41,0x46,0x46,0x34,0x46,0x31,0x41,0x55,0x4c,0x2c,0x30,0x78,0x37,0x38,0x38,0x38,0x44,0x38,0x35,0x30,0x35,0x30,0x37,0x38,0x41,0x30,0x38,0x38,0x55, + 0x4c,0x2c,0x30,0x78,0x37,0x41,0x38,0x45,0x32,0x42,0x41,0x35,0x41,0x35,0x37,0x41,0x35,0x31,0x38,0x45,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x38,0x46,0x38,0x41,0x38,0x39, + 0x30,0x33,0x30,0x33,0x38,0x46,0x30,0x36,0x38,0x41,0x55,0x4c,0x2c,0x30,0x78,0x46,0x38,0x31,0x33,0x34,0x41,0x35,0x39,0x35,0x39,0x46,0x38,0x42,0x32,0x31,0x33,0x55, + 0x4c,0x2c,0x30,0x78,0x38,0x30,0x39,0x42,0x39,0x32,0x30,0x39,0x30,0x39,0x38,0x30,0x31,0x32,0x39,0x42,0x55,0x4c,0x2c,0x30,0x78,0x31,0x37,0x33,0x39,0x32,0x33,0x31, + 0x41,0x31,0x41,0x31,0x37,0x33,0x34,0x33,0x39,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x44,0x41,0x37,0x35,0x31,0x30,0x36,0x35,0x36,0x35,0x44,0x41,0x43,0x41,0x37,0x35,0x55, + 0x4c,0x2c,0x30,0x78,0x33,0x31,0x35,0x33,0x38,0x34,0x44,0x37,0x44,0x37,0x33,0x31,0x42,0x35,0x35,0x33,0x55,0x4c,0x2c,0x30,0x78,0x43,0x36,0x35,0x31,0x44,0x35,0x38, + 0x34,0x38,0x34,0x43,0x36,0x31,0x33,0x35,0x31,0x55,0x4c,0x2c,0x30,0x78,0x42,0x38,0x44,0x33,0x30,0x33,0x44,0x30,0x44,0x30,0x42,0x38,0x42,0x42,0x44,0x33,0x55,0x4c, + 0x2c,0x0a,0x30,0x78,0x43,0x33,0x35,0x45,0x44,0x43,0x38,0x32,0x38,0x32,0x43,0x33,0x31,0x46,0x35,0x45,0x55,0x4c,0x2c,0x30,0x78,0x42,0x30,0x43,0x42,0x45,0x32,0x32, + 0x39,0x32,0x39,0x42,0x30,0x35,0x32,0x43,0x42,0x55,0x4c,0x2c,0x30,0x78,0x37,0x37,0x39,0x39,0x43,0x33,0x35,0x41,0x35,0x41,0x37,0x37,0x42,0x34,0x39,0x39,0x55,0x4c, + 0x2c,0x30,0x78,0x31,0x31,0x33,0x33,0x32,0x44,0x31,0x45,0x31,0x45,0x31,0x31,0x33,0x43,0x33,0x33,0x55,0x4c,0x2c,0x0a,0x30,0x78,0x43,0x42,0x34,0x36,0x33,0x44,0x37, + 0x42,0x37,0x42,0x43,0x42,0x46,0x36,0x34,0x36,0x55,0x4c,0x2c,0x30,0x78,0x46,0x43,0x31,0x46,0x42,0x37,0x41,0x38,0x41,0x38,0x46,0x43,0x34,0x42,0x31,0x46,0x55,0x4c, + 0x2c,0x30,0x78,0x44,0x36,0x36,0x31,0x30,0x43,0x36,0x44,0x36,0x44,0x44,0x36,0x44,0x41,0x36,0x31,0x55,0x4c,0x2c,0x30,0x78,0x33,0x41,0x34,0x45,0x36,0x32,0x32,0x43, + 0x32,0x43,0x33,0x41,0x35,0x38,0x34,0x45,0x55,0x4c,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x53,0x54,0x54,0x28,0x64,0x2c,0x20,0x61,0x2c, + 0x20,0x62,0x30,0x2c,0x20,0x62,0x31,0x2c,0x20,0x62,0x32,0x2c,0x20,0x62,0x33,0x2c,0x20,0x62,0x34,0x2c,0x20,0x62,0x35,0x2c,0x20,0x62,0x36,0x2c,0x20,0x62,0x37,0x29, + 0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x74,0x5b,0x64,0x5d,0x3d,0x54,0x30,0x5f,0x47,0x5b,0x42,0x36,0x34,0x5f,0x30,0x28,0x61,0x5b,0x62,0x30,0x5d,0x29,0x5d,0x20, + 0x5c,0x0a,0x5e,0x20,0x52,0x36,0x34,0x28,0x54,0x30,0x5f,0x47,0x5b,0x42,0x36,0x34,0x5f,0x31,0x28,0x61,0x5b,0x62,0x31,0x5d,0x29,0x5d,0x2c,0x38,0x29,0x20,0x5c,0x0a, + 0x5e,0x20,0x52,0x36,0x34,0x28,0x54,0x30,0x5f,0x47,0x5b,0x42,0x36,0x34,0x5f,0x32,0x28,0x61,0x5b,0x62,0x32,0x5d,0x29,0x5d,0x2c,0x31,0x36,0x29,0x20,0x5c,0x0a,0x5e, + 0x20,0x52,0x36,0x34,0x28,0x54,0x30,0x5f,0x47,0x5b,0x42,0x36,0x34,0x5f,0x33,0x28,0x61,0x5b,0x62,0x33,0x5d,0x29,0x5d,0x2c,0x32,0x34,0x29,0x20,0x5c,0x0a,0x5e,0x20, + 0x54,0x34,0x5f,0x47,0x5b,0x42,0x36,0x34,0x5f,0x34,0x28,0x61,0x5b,0x62,0x34,0x5d,0x29,0x5d,0x20,0x5c,0x0a,0x5e,0x20,0x52,0x36,0x34,0x28,0x54,0x34,0x5f,0x47,0x5b, + 0x42,0x36,0x34,0x5f,0x35,0x28,0x61,0x5b,0x62,0x35,0x5d,0x29,0x5d,0x2c,0x38,0x29,0x20,0x5c,0x0a,0x5e,0x20,0x52,0x36,0x34,0x28,0x54,0x34,0x5f,0x47,0x5b,0x42,0x36, + 0x34,0x5f,0x36,0x28,0x61,0x5b,0x62,0x36,0x5d,0x29,0x5d,0x2c,0x31,0x36,0x29,0x20,0x5c,0x0a,0x5e,0x20,0x52,0x36,0x34,0x28,0x54,0x34,0x5f,0x47,0x5b,0x42,0x36,0x34, + 0x5f,0x37,0x28,0x61,0x5b,0x62,0x37,0x5d,0x29,0x5d,0x2c,0x32,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x61,0x2c,0x20,0x72,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c, + 0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x5b,0x38,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30, + 0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x31,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61, + 0x5b,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x32,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x50, + 0x43,0x36,0x34,0x28,0x30,0x78,0x33,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x34,0x30, + 0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x35,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61, + 0x5b,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x36,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37,0x5d,0x20,0x5e,0x3d,0x20,0x50, + 0x43,0x36,0x34,0x28,0x30,0x78,0x37,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x30,0x2c,0x61,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c, + 0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x31,0x2c,0x61,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36, + 0x2c,0x37,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x32,0x2c,0x61,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x2c, + 0x31,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x33,0x2c,0x61,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x29,0x3b, + 0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x34,0x2c,0x61,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x29,0x3b,0x20,0x5c,0x0a, + 0x52,0x53,0x54,0x54,0x28,0x35,0x2c,0x61,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54, + 0x54,0x28,0x36,0x2c,0x61,0x2c,0x36,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x37, + 0x2c,0x61,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x30,0x5d,0x3d,0x74,0x5b,0x30,0x5d, + 0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x74,0x5b,0x31,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x32,0x5d,0x3d,0x74,0x5b,0x32,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b, + 0x33,0x5d,0x3d,0x74,0x5b,0x33,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x34,0x5d,0x3d,0x74,0x5b,0x34,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x35,0x5d,0x3d,0x74,0x5b,0x35, + 0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x36,0x5d,0x3d,0x74,0x5b,0x36,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37,0x5d,0x3d,0x74,0x5b,0x37,0x5d,0x3b,0x20,0x5c,0x0a,0x7d, + 0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50, + 0x66,0x28,0x61,0x2c,0x72,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x61,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x30,0x30,0x2c, + 0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x31,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b, + 0x32,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x32,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43, + 0x36,0x34,0x28,0x30,0x78,0x33,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x34,0x30,0x2c, + 0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x35,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b, + 0x36,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43,0x36,0x34,0x28,0x30,0x78,0x36,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37,0x5d,0x20,0x5e,0x3d,0x20,0x50,0x43, + 0x36,0x34,0x28,0x30,0x78,0x37,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x37,0x2c,0x61,0x2c,0x37,0x2c,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33, + 0x2c,0x34,0x2c,0x35,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37,0x5d,0x3d,0x74,0x5b,0x37,0x5d,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20, + 0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x61,0x2c,0x20,0x72,0x29,0x20, + 0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x5b,0x38,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36, + 0x34,0x28,0x30,0x78,0x30,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x31,0x30,0x2c,0x72, + 0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x32,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x33, + 0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x33,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36, + 0x34,0x28,0x30,0x78,0x34,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x35,0x30,0x2c,0x72, + 0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x36,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37, + 0x5d,0x20,0x5e,0x3d,0x20,0x51,0x43,0x36,0x34,0x28,0x30,0x78,0x37,0x30,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x30,0x2c,0x61,0x2c,0x31,0x2c, + 0x33,0x2c,0x35,0x2c,0x37,0x2c,0x30,0x2c,0x32,0x2c,0x34,0x2c,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x31,0x2c,0x61,0x2c,0x32,0x2c,0x34,0x2c,0x36, + 0x2c,0x30,0x2c,0x31,0x2c,0x33,0x2c,0x35,0x2c,0x37,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x32,0x2c,0x61,0x2c,0x33,0x2c,0x35,0x2c,0x37,0x2c,0x31,0x2c, + 0x32,0x2c,0x34,0x2c,0x36,0x2c,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x33,0x2c,0x61,0x2c,0x34,0x2c,0x36,0x2c,0x30,0x2c,0x32,0x2c,0x33,0x2c,0x35, + 0x2c,0x37,0x2c,0x31,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x34,0x2c,0x61,0x2c,0x35,0x2c,0x37,0x2c,0x31,0x2c,0x33,0x2c,0x34,0x2c,0x36,0x2c,0x30,0x2c, + 0x32,0x29,0x3b,0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x35,0x2c,0x61,0x2c,0x36,0x2c,0x30,0x2c,0x32,0x2c,0x34,0x2c,0x35,0x2c,0x37,0x2c,0x31,0x2c,0x33,0x29,0x3b, + 0x20,0x5c,0x0a,0x52,0x53,0x54,0x54,0x28,0x36,0x2c,0x61,0x2c,0x37,0x2c,0x31,0x2c,0x33,0x2c,0x35,0x2c,0x36,0x2c,0x30,0x2c,0x32,0x2c,0x34,0x29,0x3b,0x20,0x5c,0x0a, + 0x52,0x53,0x54,0x54,0x28,0x37,0x2c,0x61,0x2c,0x30,0x2c,0x32,0x2c,0x34,0x2c,0x36,0x2c,0x37,0x2c,0x31,0x2c,0x33,0x2c,0x35,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x30, + 0x5d,0x3d,0x74,0x5b,0x30,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x74,0x5b,0x31,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x32,0x5d,0x3d,0x74,0x5b,0x32,0x5d, + 0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x33,0x5d,0x3d,0x74,0x5b,0x33,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x34,0x5d,0x3d,0x74,0x5b,0x34,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b, + 0x35,0x5d,0x3d,0x74,0x5b,0x35,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x36,0x5d,0x3d,0x74,0x5b,0x36,0x5d,0x3b,0x20,0x5c,0x0a,0x61,0x5b,0x37,0x5d,0x3d,0x74,0x5b,0x37, + 0x5d,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d, + 0x41,0x4c,0x4c,0x5f,0x50,0x28,0x61,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c, + 0x31,0x30,0x3b,0x20,0x72,0x20,0x2b,0x2b,0x29,0x20,0x5c,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x61,0x2c,0x72,0x29,0x3b,0x20, + 0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c, + 0x5f,0x50,0x66,0x28,0x61,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c,0x39,0x3b, + 0x20,0x72,0x20,0x2b,0x2b,0x29,0x20,0x7b,0x20,0x5c,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x61,0x2c,0x72,0x29,0x3b,0x7d,0x20, + 0x5c,0x0a,0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x66,0x28,0x61,0x2c,0x39,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65, + 0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x61,0x29,0x20,0x64,0x6f,0x20, + 0x7b,0x20,0x5c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c,0x31,0x30,0x3b,0x20,0x72,0x20,0x2b,0x2b,0x29,0x20,0x5c,0x0a, + 0x52,0x4f,0x55,0x4e,0x44,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x61,0x2c,0x72,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30, + 0x29,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x42,0x41,0x53,0x45,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x32,0x29,0x0a,0x69, + 0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x65,0x74,0x5f,0x72,0x65,0x63,0x69,0x70,0x72,0x6f,0x63,0x61,0x6c,0x28,0x75,0x69,0x6e,0x74,0x20,0x61, + 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x61,0x5f,0x68,0x69,0x3d,0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x28,0x28,0x61, + 0x3e,0x3e,0x38,0x29,0x2b,0x28,0x28,0x31,0x32,0x36,0x55,0x2b,0x33,0x31,0x55,0x29,0x3c,0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x20,0x61,0x5f,0x6c,0x6f,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65,0x28,0x61,0x26,0x30,0x78,0x46, + 0x46,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x72,0x3d,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x72,0x65,0x63,0x69,0x70,0x28,0x61, + 0x5f,0x68,0x69,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x72,0x5f,0x73,0x63,0x61,0x6c,0x65,0x64,0x3d,0x61,0x73,0x5f,0x66,0x6c, + 0x6f,0x61,0x74,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x72,0x29,0x2b,0x28,0x36,0x34,0x55,0x3c,0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x68,0x3d,0x66,0x6d,0x61,0x28,0x61,0x5f,0x6c,0x6f,0x2c,0x72,0x2c,0x66,0x6d,0x61,0x28,0x61,0x5f,0x68,0x69,0x2c,0x72,0x2c,0x2d, + 0x31,0x2e,0x30,0x66,0x29,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x72,0x29,0x3c,0x3c,0x39,0x29,0x2d,0x63, + 0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x69,0x6e,0x74,0x5f,0x72,0x74,0x65,0x28,0x68,0x2a,0x72,0x5f,0x73,0x63,0x61,0x6c,0x65,0x64,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e, + 0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x66,0x61,0x73,0x74,0x5f,0x64,0x69,0x76,0x5f,0x76,0x32,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x2c,0x75, + 0x69,0x6e,0x74,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x3d,0x67,0x65,0x74,0x5f,0x72,0x65,0x63,0x69,0x70,0x72, + 0x6f,0x63,0x61,0x6c,0x28,0x62,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6b,0x3d,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x61,0x73, + 0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x73,0x30,0x2c,0x72,0x29,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x72,0x29,0x2a,0x61,0x73,0x5f,0x75, + 0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x73,0x31,0x29,0x2b,0x61,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x71,0x3d,0x61,0x73,0x5f,0x75, + 0x69,0x6e,0x74,0x32,0x28,0x6b,0x29,0x2e,0x73,0x31,0x3b,0x0a,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d,0x70,0x3d,0x61,0x2d,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28, + 0x71,0x29,0x2a,0x62,0x29,0x3b,0x0a,0x28,0x28,0x69,0x6e,0x74,0x2a,0x29,0x26,0x74,0x6d,0x70,0x29,0x5b,0x31,0x5d,0x2d,0x3d,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74, + 0x32,0x28,0x6b,0x29,0x2e,0x73,0x31,0x3c,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x73,0x31,0x29,0x3f,0x62,0x3a,0x30,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x6f,0x76,0x65,0x72,0x73,0x68,0x6f,0x6f,0x74,0x3d,0x28,0x28,0x69,0x6e,0x74,0x2a,0x29,0x26,0x74,0x6d,0x70,0x29,0x5b,0x31,0x5d, + 0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x75,0x6e,0x64,0x65,0x72,0x73,0x68,0x6f,0x6f,0x74,0x3d,0x61,0x73,0x5f,0x69,0x6e, + 0x74,0x32,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x62,0x2d,0x31,0x29,0x2d,0x74,0x6d,0x70,0x29,0x2e,0x73,0x31,0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x72,0x65,0x74, + 0x75,0x72,0x6e,0x20,0x28,0x75,0x69,0x6e,0x74,0x32,0x29,0x28,0x71,0x2b,0x6f,0x76,0x65,0x72,0x73,0x68,0x6f,0x6f,0x74,0x2d,0x75,0x6e,0x64,0x65,0x72,0x73,0x68,0x6f, + 0x6f,0x74,0x2c,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x2b,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x6f,0x76,0x65, + 0x72,0x73,0x68,0x6f,0x6f,0x74,0x29,0x26,0x62,0x29,0x2d,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x75,0x6e,0x64,0x65,0x72,0x73,0x68,0x6f,0x6f,0x74,0x29,0x26, + 0x62,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x20,0x66,0x61,0x73,0x74,0x5f,0x73,0x71,0x72,0x74,0x5f,0x76,0x32,0x28, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6e,0x31,0x29,0x0a,0x7b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x3d,0x61,0x73,0x5f,0x66,0x6c,0x6f, + 0x61,0x74,0x28,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x6e,0x31,0x29,0x2e,0x73,0x31,0x3e,0x3e,0x39,0x29,0x2b,0x28,0x28,0x36,0x34,0x55,0x2b,0x31,0x32, + 0x37,0x55,0x29,0x3c,0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x31,0x3d,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x72,0x73,0x71,0x72,0x74, + 0x28,0x78,0x29,0x3b,0x0a,0x78,0x3d,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x73,0x71,0x72,0x74,0x28,0x78,0x29,0x3b,0x0a,0x78,0x31,0x3d,0x61,0x73,0x5f,0x66,0x6c,0x6f, + 0x61,0x74,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x78,0x31,0x29,0x2b,0x28,0x33,0x32,0x55,0x3c,0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x20,0x78,0x30,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x78,0x29,0x2d,0x28,0x31,0x35,0x38,0x55,0x3c,0x3c,0x32,0x33,0x29,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x64,0x65,0x6c,0x74,0x61,0x30,0x3d,0x6e,0x31,0x2d,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x28, + 0x75,0x69,0x6e,0x74,0x32,0x29,0x28,0x6d,0x75,0x6c,0x32,0x34,0x28,0x78,0x30,0x2c,0x78,0x30,0x29,0x2c,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x78,0x30,0x2c,0x78,0x30, + 0x29,0x29,0x29,0x3c,0x3c,0x31,0x38,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x64,0x65,0x6c,0x74,0x61,0x3d,0x63,0x6f,0x6e,0x76, + 0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x32,0x28,0x64,0x65,0x6c,0x74,0x61,0x30,0x29,0x2e,0x73,0x31, + 0x29,0x2a,0x78,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x28,0x78,0x30,0x3c,0x3c,0x31,0x30,0x29,0x2b,0x63,0x6f,0x6e,0x76,0x65, + 0x72,0x74,0x5f,0x69,0x6e,0x74,0x5f,0x72,0x74,0x65,0x28,0x64,0x65,0x6c,0x74,0x61,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x3d, + 0x72,0x65,0x73,0x75,0x6c,0x74,0x3e,0x3e,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x62,0x3d,0x72,0x65,0x73,0x75,0x6c,0x74,0x26,0x31, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x78,0x32,0x3d,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x73,0x29,0x2a,0x28,0x73,0x2b,0x62, + 0x29,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x72,0x65,0x73,0x75,0x6c,0x74,0x29,0x3c,0x3c,0x33,0x32,0x29,0x2d,0x6e,0x31,0x3b,0x0a,0x69,0x66,0x28,0x28, + 0x6c,0x6f,0x6e,0x67,0x29,0x28,0x78,0x32,0x2b,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x62,0x2d,0x31,0x29,0x29,0x3e,0x3d,0x30,0x29,0x20,0x2d,0x2d,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x3b,0x0a,0x69,0x66,0x28,0x28,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x78,0x32,0x2b,0x30,0x78,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x2b,0x73, + 0x29,0x3c,0x30,0x29,0x20,0x2b,0x2b,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a, + 0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x46,0x41,0x53,0x54,0x5f,0x44,0x49,0x56,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x43,0x4c, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x53,0x54,0x5f,0x44,0x49,0x56,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x43,0x4c,0x0a,0x23,0x69,0x66,0x20,0x28, + 0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x29,0x0a, + 0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x66,0x61,0x73,0x74,0x5f,0x64,0x69,0x76,0x5f,0x68,0x65,0x61,0x76,0x79,0x28,0x6c,0x6f,0x6e,0x67,0x20, + 0x5f,0x61,0x2c,0x69,0x6e,0x74,0x20,0x5f,0x62,0x29,0x0a,0x7b,0x0a,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x3d,0x61,0x62,0x73,0x28,0x5f,0x61,0x29,0x3b,0x0a,0x69,0x6e,0x74, + 0x20,0x62,0x3d,0x61,0x62,0x73,0x28,0x5f,0x62,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x72,0x63,0x70,0x3d,0x6e,0x61,0x74,0x69,0x76,0x65,0x5f,0x72,0x65,0x63, + 0x69,0x70,0x28,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65,0x28,0x62,0x29,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20, + 0x72,0x63,0x70,0x32,0x3d,0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x72,0x63,0x70,0x29,0x2b,0x28,0x33,0x32,0x55,0x3c, + 0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x71,0x31,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x63,0x6f, + 0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x73,0x31,0x29,0x2a,0x72, + 0x63,0x70,0x32,0x29,0x3b,0x0a,0x61,0x2d,0x3d,0x71,0x31,0x2a,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x62,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x71,0x32, + 0x66,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x32,0x28,0x61,0x3e,0x3e,0x31, + 0x32,0x29,0x2e,0x73,0x30,0x29,0x2a,0x72,0x63,0x70,0x3b,0x0a,0x71,0x32,0x66,0x3d,0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74, + 0x28,0x71,0x32,0x66,0x29,0x2b,0x28,0x31,0x32,0x55,0x3c,0x3c,0x32,0x33,0x29,0x29,0x3b,0x0a,0x6c,0x6f,0x6e,0x67,0x20,0x71,0x32,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72, + 0x74,0x5f,0x6c,0x6f,0x6e,0x67,0x5f,0x72,0x74,0x65,0x28,0x71,0x32,0x66,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x61,0x32,0x3d,0x61,0x73,0x5f,0x69,0x6e,0x74,0x32,0x28, + 0x61,0x29,0x2e,0x73,0x30,0x2d,0x61,0x73,0x5f,0x69,0x6e,0x74,0x32,0x28,0x71,0x32,0x29,0x2e,0x73,0x30,0x2a,0x62,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x71,0x33,0x3d,0x63, + 0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x69,0x6e,0x74,0x5f,0x72,0x74,0x65,0x28,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x5f,0x72,0x74,0x65, + 0x28,0x61,0x32,0x29,0x2a,0x72,0x63,0x70,0x29,0x3b,0x0a,0x71,0x33,0x2b,0x3d,0x28,0x61,0x32,0x2d,0x71,0x33,0x2a,0x62,0x29,0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x71,0x3d,0x71,0x31,0x2b,0x71,0x32,0x2b,0x71,0x33,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x28,0x61,0x73, + 0x5f,0x69,0x6e,0x74,0x32,0x28,0x5f,0x61,0x29,0x2e,0x73,0x31,0x5e,0x5f,0x62,0x29,0x3c,0x30,0x29,0x3f,0x2d,0x71,0x3a,0x71,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x58,0x4d,0x52,0x49,0x47,0x5f,0x4b,0x45,0x43,0x43,0x41,0x4b,0x5f,0x43, + 0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x58,0x4d,0x52,0x49,0x47,0x5f,0x4b,0x45,0x43,0x43,0x41,0x4b,0x5f,0x43,0x4c,0x0a,0x73,0x74,0x61,0x74,0x69,0x63, + 0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f, + 0x72,0x6e,0x64,0x63,0x5b,0x32,0x34,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c, + 0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x32,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x38,0x30,0x38,0x61,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x2c,0x30,0x78,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x62,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c, + 0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x38,0x30,0x30,0x39,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x61,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x38,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x39, + 0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x61,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38, + 0x30,0x30,0x30,0x38,0x30,0x38,0x62,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x62,0x2c,0x30,0x78,0x38,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x39,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30, + 0x33,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x32,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x61,0x2c,0x30,0x78,0x38,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x61,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38, + 0x31,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x30,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x38,0x0a,0x7d,0x3b,0x0a,0x73, + 0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x65,0x63,0x63, + 0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x32,0x34,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x31,0x2c,0x33,0x2c,0x36,0x2c,0x31,0x30,0x2c,0x31,0x35,0x2c,0x32,0x31,0x2c, + 0x32,0x38,0x2c,0x33,0x36,0x2c,0x34,0x35,0x2c,0x35,0x35,0x2c,0x32,0x2c,0x31,0x34,0x2c,0x0a,0x32,0x37,0x2c,0x34,0x31,0x2c,0x35,0x36,0x2c,0x38,0x2c,0x32,0x35,0x2c, + 0x34,0x33,0x2c,0x36,0x32,0x2c,0x31,0x38,0x2c,0x33,0x39,0x2c,0x36,0x31,0x2c,0x32,0x30,0x2c,0x34,0x34,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c, + 0x6e,0x5b,0x32,0x34,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x31,0x30,0x2c,0x37,0x2c,0x31,0x31,0x2c,0x31,0x37,0x2c,0x31,0x38,0x2c,0x33,0x2c,0x35,0x2c,0x31,0x36,0x2c,0x38, + 0x2c,0x32,0x31,0x2c,0x32,0x34,0x2c,0x34,0x2c,0x0a,0x31,0x35,0x2c,0x32,0x33,0x2c,0x31,0x39,0x2c,0x31,0x33,0x2c,0x31,0x32,0x2c,0x32,0x2c,0x32,0x30,0x2c,0x31,0x34, + 0x2c,0x32,0x32,0x2c,0x39,0x2c,0x36,0x2c,0x31,0x0a,0x7d,0x3b,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30,0x5f,0x31,0x28, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x20,0x69,0x2c,0x72,0x6f,0x75,0x6e,0x64,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20, + 0x74,0x2c,0x62,0x63,0x5b,0x35,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x72, + 0x6f,0x75,0x6e,0x64,0x3d,0x30,0x3b,0x20,0x72,0x6f,0x75,0x6e,0x64,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x72,0x6f,0x75,0x6e,0x64,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b, + 0x30,0x5d,0x3d,0x73,0x74,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b, + 0x32,0x30,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x31,0x5d,0x5e,0x73,0x74, + 0x5b,0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x31,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x37,0x5d,0x5e,0x73, + 0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x32,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x33,0x5d,0x3d,0x73,0x74,0x5b,0x33,0x5d, + 0x5e,0x73,0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x3b,0x0a,0x62,0x63,0x5b, + 0x34,0x5d,0x3d,0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b, + 0x32,0x34,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x3d,0x30,0x3b,0x20, + 0x69,0x3c,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x74,0x3d,0x62,0x63,0x5b,0x28,0x69,0x2b,0x34,0x29,0x20,0x25,0x20,0x35,0x5d,0x5e,0x72,0x6f,0x74,0x61, + 0x74,0x65,0x28,0x62,0x63,0x5b,0x28,0x69,0x2b,0x31,0x29,0x20,0x25,0x20,0x35,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x20,0x5d,0x20,0x5e,0x3d, + 0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b, + 0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x32,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x7d, + 0x0a,0x74,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61, + 0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d, + 0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x69,0x5d, + 0x29,0x3b,0x0a,0x74,0x3d,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66, + 0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x69,0x2b,0x3d,0x35,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x74,0x6d,0x70,0x5b,0x35,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69, + 0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x35,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x74,0x6d,0x70,0x5b,0x78,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65, + 0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x78,0x5d,0x5e,0x73,0x74,0x5b,0x69,0x2b,0x28,0x28,0x78,0x2b,0x32,0x29,0x20,0x25,0x20,0x35,0x29,0x5d,0x2c,0x73, + 0x74,0x5b,0x69,0x2b,0x78,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x28,0x28,0x78,0x2b,0x31,0x29,0x20,0x25,0x20,0x35,0x29,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72, + 0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x35,0x3b, + 0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x78,0x5d,0x3d,0x74,0x6d,0x70,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x73,0x74,0x5b,0x30, + 0x5d,0x20,0x5e,0x3d,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6e,0x64,0x63,0x5b,0x72,0x6f,0x75,0x6e,0x64,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x76,0x6f, + 0x69,0x64,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30,0x5f,0x32,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a, + 0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x20,0x69,0x2c,0x72,0x6f,0x75,0x6e,0x64,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x2c,0x62,0x63,0x5b,0x35,0x5d, + 0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x30,0x3b, + 0x20,0x72,0x6f,0x75,0x6e,0x64,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x72,0x6f,0x75,0x6e,0x64,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x30, + 0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x30,0x5d,0x5e,0x72,0x6f,0x74, + 0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e,0x73,0x74, + 0x5b,0x32,0x32,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b, + 0x31,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x31,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x33,0x5d,0x5e,0x73, + 0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a, + 0x62,0x63,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e, + 0x73,0x74,0x5b,0x32,0x32,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x34,0x5d, + 0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x34,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x33,0x5d,0x3d,0x73,0x74,0x5b,0x33,0x5d, + 0x5e,0x73,0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x5e,0x72,0x6f,0x74,0x61, + 0x74,0x65,0x28,0x73,0x74,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b, + 0x32,0x30,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x34,0x5d,0x3d,0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x31, + 0x34,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x34,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x31,0x5d,0x5e,0x73,0x74, + 0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x31,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x73, + 0x74,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73, + 0x74,0x5b,0x31,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b, + 0x0a,0x73,0x74,0x5b,0x32,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d, + 0x3b,0x0a,0x73,0x74,0x5b,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30, + 0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63, + 0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x37,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63, + 0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x37,0x5d,0x20,0x5e,0x3d,0x20, + 0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x33,0x5d,0x20,0x5e,0x3d, + 0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x38,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x33,0x5d,0x20,0x5e, + 0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x38,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x33,0x5d, + 0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x39,0x5d, + 0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31, + 0x39,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x74,0x3d, + 0x73,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x3d,0x30, + 0x3b,0x20,0x69,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f, + 0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3d,0x72,0x6f, + 0x74,0x61,0x74,0x65,0x28,0x74,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x69,0x5d,0x29,0x3b,0x0a, + 0x74,0x3d,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20, + 0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x69,0x2b,0x3d,0x35,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d, + 0x70,0x31,0x3d,0x73,0x74,0x5b,0x69,0x5d,0x2c,0x74,0x6d,0x70,0x32,0x3d,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x5d,0x3d,0x62,0x69,0x74, + 0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x5d,0x5e,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b, + 0x31,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x5e,0x73, + 0x74,0x5b,0x69,0x2b,0x33,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d, + 0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b, + 0x32,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73, + 0x74,0x5b,0x69,0x2b,0x33,0x5d,0x5e,0x74,0x6d,0x70,0x31,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x29,0x3b,0x0a,0x73,0x74, + 0x5b,0x69,0x2b,0x34,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x5e,0x74,0x6d,0x70,0x32,0x2c,0x73,0x74,0x5b, + 0x69,0x2b,0x34,0x5d,0x2c,0x74,0x6d,0x70,0x31,0x29,0x3b,0x0a,0x7d,0x0a,0x73,0x74,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72, + 0x6e,0x64,0x63,0x5b,0x72,0x6f,0x75,0x6e,0x64,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69,0x66,0x20,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x64,0x28,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x29,0x20,0x26,0x26,0x20,0x53,0x54,0x52,0x49,0x44,0x45,0x44, + 0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x21,0x3d,0x20,0x30,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x30,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20,0x28,0x31,0x20,0x3c,0x3c,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e, + 0x4b,0x5f,0x45,0x58,0x50,0x4f,0x4e,0x45,0x4e,0x54,0x29,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d, + 0x3d,0x20,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x28,0x78,0x29,0x20,0x28,0x78,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53, + 0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d, + 0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x49,0x44,0x58,0x28,0x78,0x29,0x20,0x28,0x28,0x78,0x29,0x20,0x2a,0x20,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x28,0x78,0x29,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x28,0x78,0x29,0x2c,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20, + 0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x25,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48, + 0x55,0x4e,0x4b,0x29,0x20,0x2b,0x20,0x28,0x28,0x78,0x29,0x20,0x2f,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x29,0x20,0x2a,0x20,0x57,0x4f,0x52,0x4b,0x53, + 0x49,0x5a,0x45,0x20,0x2a,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x29,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75, + 0x6c,0x6f,0x6e,0x67,0x20,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6d,0x69,0x78,0x5f,0x61,0x6e,0x64,0x5f,0x70,0x72,0x6f,0x70,0x61,0x67,0x61,0x74,0x65,0x28,0x78,0x69,0x6e,0x29,0x20,0x28, + 0x78,0x69,0x6e,0x29,0x5b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x29,0x20,0x25,0x20,0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x20,0x5e,0x20,0x28,0x78,0x69,0x6e,0x29,0x5b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x31,0x29,0x20,0x2b,0x20,0x31,0x29,0x20,0x25,0x20,0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d, + 0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f, + 0x73,0x69,0x7a,0x65,0x28,0x38,0x2c,0x38,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x30,0x28, + 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20, + 0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x45,0x78,0x70, + 0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x31,0x5b,0x34,0x30,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x32,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32, + 0x35,0x36,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x65,0x78,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x49,0x64,0x78, + 0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x31,0x29,0x2a,0x38,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x36,0x3b,0x20, + 0x69,0x2b,0x3d,0x38,0x2a,0x38,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b, + 0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x31,0x36,0x55,0x29, + 0x3b,0x0a,0x41,0x45,0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x32,0x34,0x55,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72, + 0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x5b,0x38,0x2a,0x32,0x35,0x5d,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74, + 0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20, + 0x3d,0x3d,0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e, + 0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23, + 0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41, + 0x56,0x59,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x28,0x67,0x49,0x64,0x78,0x2f,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x2a, + 0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x28,0x67,0x49,0x64,0x78,0x20,0x25,0x20,0x57,0x4f,0x52, + 0x4b,0x53,0x49,0x5a,0x45,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0a, + 0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32, + 0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x28,0x67,0x49,0x64,0x78,0x2f,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x2a,0x28,0x4d, + 0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x28,0x67,0x49, + 0x64,0x78,0x20,0x25,0x20,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3d,0x3d,0x30,0x29,0x20,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x53, + 0x74,0x61,0x74,0x65,0x3d,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x32, + 0x35,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x30,0x5d,0x3d, + 0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30,0x2c,0x69,0x6e,0x70,0x75,0x74,0x29,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x38,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b, + 0x38,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x39,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x39,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x30,0x5d, + 0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x31,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x31,0x5d,0x3b, + 0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x32,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x32,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x33,0x5d,0x3d, + 0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x33,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x34,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x34,0x5d,0x3b,0x0a, + 0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x35,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x35,0x5d,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x39,0x5d,0x20,0x26,0x3d,0x20,0x30,0x78,0x30,0x30,0x46,0x46,0x46,0x46,0x46,0x46,0x55,0x3b,0x0a, + 0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x39,0x5d,0x7c,0x3d,0x28,0x28,0x28,0x75, + 0x69,0x6e,0x74,0x29,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x3c,0x3c,0x32,0x34,0x3b, + 0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x31,0x30,0x5d,0x20,0x26,0x3d,0x20, + 0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74, + 0x61,0x74,0x65,0x29,0x5b,0x31,0x30,0x5d,0x7c,0x3d,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x29,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28, + 0x30,0x29,0x3e,0x3e,0x38,0x29,0x29,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x36,0x5d,0x3d,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x37,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b,0x2b, + 0x69,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31, + 0x36,0x30,0x30,0x5f,0x32,0x28,0x53,0x74,0x61,0x74,0x65,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66, + 0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73, + 0x5b,0x69,0x5d,0x3d,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f, + 0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x34, + 0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x34,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e, + 0x74,0x20,0x2a,0x29,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x0a,0x66,0x6f, + 0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20, + 0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x31,0x29,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a, + 0x41,0x45,0x53,0x45,0x78,0x70,0x61,0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x31,0x29,0x3b,0x0a,0x7d, + 0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b, + 0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48, + 0x45,0x41,0x56,0x59,0x29,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x69,0x6e,0x5b,0x38,0x5d,0x5b,0x38,0x5d,0x3b,0x0a,0x23, + 0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x36,0x0a,0x66,0x6f,0x72,0x20,0x28,0x73,0x69,0x7a,0x65,0x5f,0x74,0x20,0x69,0x3d,0x30, + 0x3b,0x20,0x69,0x3c,0x31,0x36,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x20,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30, + 0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74, + 0x34,0x20,0x74,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x31,0x29,0x5b,0x6a,0x5d,0x3b,0x0a, + 0x74,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65, + 0x78,0x74,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x3b, + 0x0a,0x74,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41, + 0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74, + 0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d, + 0x3b,0x0a,0x74,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x33,0x29, + 0x5d,0x3b,0x0a,0x74,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d, + 0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45, + 0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x33, + 0x29,0x5d,0x3b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x74,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f, + 0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x78,0x69,0x6e,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x5d, + 0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28, + 0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x6d,0x69,0x78,0x5f,0x61, + 0x6e,0x64,0x5f,0x70,0x72,0x6f,0x70,0x61,0x67,0x61,0x74,0x65,0x28,0x78,0x69,0x6e,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x31,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28, + 0x31,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x32,0x0a,0x66,0x6f,0x72,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d, + 0x30,0x3b,0x20,0x69,0x3c,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x3b,0x20,0x69,0x2b,0x3d,0x38,0x29,0x20,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d, + 0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b, + 0x20,0x2b,0x2b,0x6a,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64, + 0x65,0x64,0x4b,0x65,0x79,0x31,0x29,0x5b,0x6a,0x5d,0x3b,0x0a,0x74,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65, + 0x78,0x74,0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x74,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x74, + 0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d, + 0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45, + 0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x74,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x31,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54, + 0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x74,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45, + 0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x30,0x2c,0x31, + 0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x74,0x65,0x78,0x74,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x74,0x3b,0x0a,0x7d,0x0a,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x69,0x2b,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x31,0x29,0x5d,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x7d,0x0a,0x7d, + 0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29, + 0x3b,0x0a,0x7d,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x42,0x41,0x53,0x45,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x30,0x29, + 0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f, + 0x73,0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f, + 0x69,0x64,0x20,0x63,0x6e,0x31,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x75, + 0x6c,0x6f,0x6e,0x67,0x20,0x61,0x5b,0x32,0x5d,0x2c,0x62,0x5b,0x32,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53, + 0x30,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x67,0x49, + 0x64,0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x36,0x3b,0x20,0x69,0x2b,0x3d,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d, + 0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x7d,0x0a, + 0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x62,0x5f,0x78,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20, + 0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b, + 0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45, + 0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d, + 0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67, + 0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53, + 0x49,0x5a,0x45,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x53,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44, + 0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x65,0x74,0x5f,0x67, + 0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b, + 0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69, + 0x66,0x0a,0x61,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x62,0x5b,0x30,0x5d, + 0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x36,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65, + 0x73,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x35,0x5d,0x3b,0x0a,0x62,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x33,0x5d,0x5e,0x73, + 0x74,0x61,0x74,0x65,0x73,0x5b,0x37,0x5d,0x3b,0x0a,0x62,0x5f,0x78,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x62,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x7d, + 0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b, + 0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x30,0x3d,0x61,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c, + 0x6c,0x20,0x43,0x4e,0x5f,0x55,0x4e,0x52,0x4f,0x4c,0x4c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x49,0x54,0x45,0x52, + 0x41,0x54,0x49,0x4f,0x4e,0x53,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e, + 0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3d,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26, + 0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3d,0x41,0x45,0x53,0x5f, + 0x52,0x6f,0x75,0x6e,0x64,0x5f,0x54,0x77,0x6f,0x5f,0x54,0x61,0x62,0x6c,0x65,0x73,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x28,0x28,0x75,0x69,0x6e, + 0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x53,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3d,0x62,0x5f,0x78, + 0x5e,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x74,0x6d,0x70, + 0x3d,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x5b,0x30,0x5d,0x29,0x2e, + 0x73,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x2b,0x3d,0x63,0x5b,0x30,0x5d,0x2a,0x61,0x73,0x5f,0x75,0x6c,0x6f, + 0x6e,0x67,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x3b,0x0a,0x61,0x5b,0x30,0x5d,0x2b,0x3d,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x63,0x5b,0x30,0x5d,0x2c,0x61, + 0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x29,0x3b,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44, + 0x58,0x28,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3d, + 0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d, + 0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x69,0x64,0x78,0x30,0x3d,0x61,0x5b,0x30,0x5d,0x3b,0x0a,0x62,0x5f,0x78,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20, + 0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d, + 0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x6e,0x3d,0x2a,0x28, + 0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x6c,0x6f,0x6e,0x67,0x32,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x28,0x49,0x44, + 0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x29,0x29,0x29,0x3b,0x0a,0x6c,0x6f,0x6e,0x67,0x20,0x71,0x3d,0x66,0x61,0x73, + 0x74,0x5f,0x64,0x69,0x76,0x5f,0x68,0x65,0x61,0x76,0x79,0x28,0x6e,0x2e,0x73,0x30,0x2c,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x6e,0x29,0x2e,0x73,0x32,0x7c,0x30, + 0x78,0x35,0x29,0x3b,0x0a,0x2a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70, + 0x61,0x64,0x2b,0x28,0x49,0x44,0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x29,0x29,0x29,0x3d,0x6e,0x2e,0x73,0x30,0x5e, + 0x71,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x58,0x48, + 0x56,0x29,0x0a,0x69,0x64,0x78,0x30,0x3d,0x28,0x7e,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x6e,0x29,0x2e,0x73,0x32,0x29,0x5e,0x71,0x3b,0x0a,0x23,0x65,0x6c,0x73, + 0x65,0x0a,0x69,0x64,0x78,0x30,0x3d,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x6e,0x29,0x2e,0x73,0x32,0x5e,0x71,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c, + 0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x42,0x41,0x53,0x45,0x20, + 0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x41,0x52,0x49,0x41,0x4e,0x54,0x31,0x5f,0x31, + 0x28,0x70,0x29,0x20,0x5c,0x0a,0x75,0x69,0x6e,0x74,0x20,0x74,0x61,0x62,0x6c,0x65,0x3d,0x30,0x78,0x37,0x35,0x33,0x31,0x30,0x55,0x3b,0x20,0x5c,0x0a,0x75,0x69,0x6e, + 0x74,0x20,0x69,0x6e,0x64,0x65,0x78,0x3d,0x28,0x28,0x28,0x70,0x29,0x2e,0x73,0x32,0x3e,0x3e,0x32,0x36,0x29,0x26,0x31,0x32,0x29,0x7c,0x28,0x28,0x28,0x70,0x29,0x2e, + 0x73,0x32,0x3e,0x3e,0x32,0x33,0x29,0x26,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x28,0x70,0x29,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x28,0x28,0x74,0x61,0x62,0x6c,0x65,0x3e, + 0x3e,0x69,0x6e,0x64,0x65,0x78,0x29,0x26,0x30,0x78,0x33,0x30,0x55,0x29,0x3c,0x3c,0x32,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x41,0x52,0x49,0x41, + 0x4e,0x54,0x31,0x5f,0x32,0x28,0x70,0x29,0x20,0x28,0x28,0x75,0x69,0x6e,0x74,0x32,0x20,0x2a,0x29,0x26,0x28,0x70,0x29,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74, + 0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x5f,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x41,0x52,0x49,0x41,0x4e,0x54,0x31,0x5f,0x49,0x4e,0x49,0x54,0x28, + 0x29,0x20,0x5c,0x0a,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x69,0x6e,0x70,0x75,0x74,0x5b,0x34,0x5d,0x29,0x3b, + 0x20,0x5c,0x0a,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x2e,0x73,0x30,0x20,0x3e,0x3e,0x3d,0x20,0x32,0x34,0x3b,0x20,0x5c,0x0a,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f, + 0x32,0x2e,0x73,0x30,0x7c,0x3d,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x2e,0x73,0x31,0x3c,0x3c,0x38,0x3b,0x20,0x5c,0x0a,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32, + 0x2e,0x73,0x31,0x3d,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x5c,0x0a,0x74, + 0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x20,0x5e,0x3d,0x20,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x34,0x5d,0x29,0x0a, + 0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73, + 0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69, + 0x64,0x20,0x63,0x6e,0x31,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x75,0x6c, + 0x6f,0x6e,0x67,0x20,0x61,0x5b,0x32,0x5d,0x2c,0x62,0x5b,0x32,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x67,0x49,0x64, + 0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x36,0x3b,0x20,0x69,0x2b,0x3d,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d, + 0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x7d,0x0a,0x62, + 0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x75,0x69,0x6e, + 0x74,0x32,0x20,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x62,0x5f,0x78,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73, + 0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d, + 0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29, + 0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23,0x69,0x66, + 0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59, + 0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d, + 0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28, + 0x30,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a,0x53,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52, + 0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x61,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x30,0x5d,0x5e, + 0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x62,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73, + 0x5b,0x36,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x35,0x5d,0x3b,0x0a,0x62, + 0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x37,0x5d,0x3b,0x0a,0x62,0x5f,0x78,0x3d,0x28,0x28,0x75, + 0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x62,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x56,0x41,0x52,0x49,0x41,0x4e,0x54,0x31,0x5f,0x49,0x4e,0x49,0x54,0x28,0x29,0x3b,0x0a,0x7d, + 0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b, + 0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55, + 0x42,0x45,0x29,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x30,0x3d,0x61,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x5f, + 0x30,0x20,0x69,0x64,0x78,0x30,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x5f,0x30,0x20,0x61,0x73,0x5f,0x75,0x69, + 0x6e,0x74,0x32,0x28,0x61,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x30,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f, + 0x6c,0x6c,0x20,0x43,0x4e,0x5f,0x55,0x4e,0x52,0x4f,0x4c,0x4c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x49,0x54,0x45, + 0x52,0x41,0x54,0x49,0x4f,0x4e,0x53,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x28,0x28,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3d,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x49,0x44,0x58,0x5f, + 0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f, + 0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3d,0x41, + 0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x62,0x69,0x74,0x74,0x75,0x62,0x65,0x32,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x28,0x28,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x23,0x65, + 0x6c,0x73,0x65,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x54,0x77, + 0x6f,0x5f,0x54,0x61,0x62,0x6c,0x65,0x73,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b, + 0x30,0x5d,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x62,0x5f,0x78,0x20, + 0x5e,0x3d,0x20,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x56,0x41,0x52,0x49,0x41,0x4e,0x54,0x31,0x5f,0x31,0x28,0x62, + 0x5f,0x78,0x29,0x3b,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x49,0x44,0x58,0x5f,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29, + 0x3e,0x3e,0x34,0x29,0x5d,0x3d,0x62,0x5f,0x78,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x74,0x6d,0x70,0x3d,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x30,0x26,0x4d,0x41,0x53,0x4b, + 0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x2b,0x3d,0x63,0x5b,0x30,0x5d,0x2a,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70, + 0x29,0x2e,0x73,0x30,0x3b,0x0a,0x61,0x5b,0x30,0x5d,0x2b,0x3d,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x63,0x5b,0x30,0x5d,0x2c,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67, + 0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x74,0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x5f,0x30,0x3d,0x74,0x77,0x65, + 0x61,0x6b,0x31,0x5f,0x32,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x54,0x4f,0x20, + 0x7c,0x7c,0x20,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x74, + 0x77,0x65,0x61,0x6b,0x31,0x5f,0x32,0x5f,0x30,0x20,0x5e,0x3d,0x20,0x28,0x28,0x75,0x69,0x6e,0x74,0x32,0x20,0x2a,0x29,0x26,0x28,0x61,0x5b,0x30,0x5d,0x29,0x29,0x5b, + 0x30,0x5d,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x56,0x41,0x52,0x49,0x41,0x4e,0x54,0x31,0x5f,0x32,0x28,0x61,0x5b,0x31,0x5d,0x29,0x3b,0x0a,0x53,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x30,0x26,0x4d, + 0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x5d,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x56,0x41,0x52,0x49,0x41, + 0x4e,0x54,0x31,0x5f,0x32,0x28,0x61,0x5b,0x31,0x5d,0x29,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20, + 0x74,0x6d,0x70,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f, + 0x54,0x55,0x42,0x45,0x29,0x0a,0x69,0x64,0x78,0x30,0x3d,0x61,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x62,0x5f,0x78,0x3d,0x28,0x28,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x2a,0x29,0x63,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43, + 0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x6e,0x3d,0x2a,0x28, + 0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x6c,0x6f,0x6e,0x67,0x32,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x28,0x49,0x44, + 0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x29,0x29,0x29,0x3b,0x0a,0x6c,0x6f,0x6e,0x67,0x20,0x71,0x3d,0x66,0x61,0x73, + 0x74,0x5f,0x64,0x69,0x76,0x5f,0x68,0x65,0x61,0x76,0x79,0x28,0x6e,0x2e,0x73,0x30,0x2c,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x6e,0x29,0x2e,0x73,0x32,0x7c,0x30, + 0x78,0x35,0x29,0x3b,0x0a,0x2a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70, + 0x61,0x64,0x2b,0x28,0x49,0x44,0x58,0x28,0x28,0x69,0x64,0x78,0x30,0x26,0x4d,0x41,0x53,0x4b,0x29,0x3e,0x3e,0x34,0x29,0x29,0x29,0x29,0x3d,0x6e,0x2e,0x73,0x30,0x5e, + 0x71,0x3b,0x0a,0x69,0x64,0x78,0x30,0x3d,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x6e,0x29,0x2e,0x73,0x32,0x5e,0x71,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69, + 0x66,0x0a,0x7d,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46, + 0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x49,0x44,0x58,0x5f,0x30,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x41,0x4c,0x47, + 0x4f,0x5f,0x42,0x41,0x53,0x45,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x32,0x29,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65, + 0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a, + 0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x31,0x28,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e,0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20, + 0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74, + 0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x5b,0x32,0x5d,0x2c,0x62,0x5b, + 0x34,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b, + 0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x32,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x67,0x49,0x64,0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67, + 0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x36,0x3b,0x20,0x69,0x2b,0x3d,0x57,0x4f,0x52,0x4b,0x53,0x49, + 0x5a,0x45,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x69,0x5d,0x3b,0x0a, + 0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c, + 0x38,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x41,0x45, + 0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x32,0x34,0x55,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72, + 0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b, + 0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x64,0x65,0x66,0x69,0x6e,0x65,0x64,0x28,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f, + 0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x49,0x54,0x45,0x52,0x41, + 0x54,0x49,0x4f,0x4e,0x53,0x3e,0x3e,0x32,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e, + 0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f, + 0x52,0x59,0x3e,0x3e,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20, + 0x31,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49, + 0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x65,0x74,0x5f, + 0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45, + 0x2b,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x61,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b, + 0x34,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x35,0x5d,0x3b,0x0a,0x62,0x5b, + 0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x36,0x5d,0x3b,0x0a,0x62,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61, + 0x74,0x65,0x73,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x37,0x5d,0x3b,0x0a,0x62,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x38,0x5d, + 0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x62,0x5b,0x33,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x61,0x74, + 0x65,0x73,0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x62,0x78,0x30,0x3d,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29, + 0x62,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x62,0x78,0x31,0x3d,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x62,0x29,0x5b, + 0x31,0x5d,0x3b,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43, + 0x45,0x29,0x3b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x20,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x5f,0x62,0x75,0x66,0x5b, + 0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x20,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3d,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67, + 0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50, + 0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x29, + 0x20,0x2b,0x20,0x28,0x69,0x64,0x78,0x31,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x69,0x66, + 0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43, + 0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70, + 0x61,0x64,0x29,0x20,0x2b,0x20,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28, + 0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41, + 0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x29,0x20,0x2b,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29, + 0x29,0x2c,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x29,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44, + 0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e, + 0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x20,0x2b,0x20,0x28,0x28,0x28,0x69,0x64,0x78,0x20, + 0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x25,0x20,0x28,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20, + 0x2b,0x20,0x28,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x2f,0x20,0x28,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b, + 0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x2a,0x20,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x28,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20, + 0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x64, + 0x69,0x76,0x69,0x73,0x69,0x6f,0x6e,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31, + 0x32,0x5d,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73,0x71,0x72,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73, + 0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x33,0x5d,0x29,0x2e,0x73,0x30,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x43,0x4e, + 0x5f,0x55,0x4e,0x52,0x4f,0x4c,0x4c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x49,0x54,0x45,0x52,0x41,0x54,0x49,0x4f, + 0x4e,0x53,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53, + 0x49,0x4f,0x4e,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x30,0x78,0x31,0x46,0x46,0x46,0x43,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74, + 0x20,0x69,0x64,0x78,0x31,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x30,0x78,0x33,0x30,0x3b,0x0a,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e, + 0x65,0x3d,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a, + 0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x4d,0x41,0x53,0x4b,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34, + 0x20,0x63,0x3d,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3b,0x0a,0x63,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f, + 0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x63,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74, + 0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f, + 0x43,0x4e,0x5f,0x52,0x57,0x5a,0x29,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x31,0x3d,0x61,0x73,0x5f,0x75, + 0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x32,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75, + 0x6e,0x6b,0x33,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31, + 0x29,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x31,0x3d,0x61,0x73, + 0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x29,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x32,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41, + 0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63, + 0x68,0x75,0x6e,0x6b,0x33,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b, + 0x28,0x33,0x29,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29, + 0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x33,0x2b,0x62,0x78,0x31,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41, + 0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x2b,0x62,0x78,0x30,0x29,0x3b, + 0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68, + 0x75,0x6e,0x6b,0x32,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x62,0x78,0x30,0x29,0x5e,0x63,0x3b,0x0a,0x23, + 0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3d,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3b, + 0x0a,0x69,0x64,0x78,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x30,0x78,0x31,0x46,0x46,0x46,0x43,0x30,0x3b,0x0a,0x69, + 0x64,0x78,0x31,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x30,0x78,0x33,0x30,0x3b,0x0a,0x2a,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3d,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28, + 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78, + 0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x64,0x78,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x4d,0x41,0x53, + 0x4b,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x6d,0x70,0x3d,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43, + 0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3b,0x0a,0x7b,0x0a,0x74,0x6d,0x70,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x64,0x69,0x76,0x69,0x73,0x69,0x6f,0x6e,0x5f,0x72,0x65, + 0x73,0x75,0x6c,0x74,0x2e,0x73,0x30,0x3b,0x0a,0x74,0x6d,0x70,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x64,0x69,0x76,0x69,0x73,0x69,0x6f,0x6e,0x5f,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x2e,0x73,0x31,0x5e,0x73,0x71,0x72,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x64,0x69,0x76,0x69,0x73,0x69,0x6f,0x6e,0x5f,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x3d,0x66,0x61,0x73,0x74,0x5f,0x64,0x69,0x76,0x5f,0x76,0x32,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x31,0x2c,0x28, + 0x63,0x2e,0x73,0x30,0x2b,0x28,0x73,0x71,0x72,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3c,0x3c,0x31,0x29,0x29,0x7c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30, + 0x31,0x55,0x4c,0x29,0x3b,0x0a,0x73,0x71,0x72,0x74,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x66,0x61,0x73,0x74,0x5f,0x73,0x71,0x72,0x74,0x5f,0x76,0x32,0x28,0x61, + 0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x2b,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x64,0x69,0x76,0x69,0x73,0x69,0x6f,0x6e, + 0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x74,0x3b,0x0a,0x74,0x2e,0x73,0x30,0x3d,0x6d,0x75,0x6c,0x5f, + 0x68,0x69,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x2c,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70, + 0x29,0x2e,0x73,0x30,0x29,0x3b,0x0a,0x74,0x2e,0x73,0x31,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x2a,0x61,0x73,0x5f,0x75, + 0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x3b,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68, + 0x75,0x6e,0x6b,0x31,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28, + 0x31,0x29,0x29,0x5e,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x32,0x3d,0x61,0x73,0x5f,0x75,0x6c, + 0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x29,0x3b,0x0a,0x74,0x20,0x5e,0x3d,0x20, + 0x63,0x68,0x75,0x6e,0x6b,0x32,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x33,0x3d,0x61,0x73,0x5f,0x75, + 0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20, + 0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x57,0x5a,0x29,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44, + 0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x2b,0x62,0x78,0x31,0x29,0x3b,0x0a, + 0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75, + 0x6e,0x6b,0x33,0x2b,0x62,0x78,0x30,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x3d,0x61,0x73, + 0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x32,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b, + 0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69, + 0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x33,0x2b,0x62,0x78,0x31,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e, + 0x4b,0x28,0x32,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x2b,0x62,0x78,0x30,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54, + 0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x32,0x2b,0x28, + 0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x61,0x5b,0x31,0x5d,0x2b, + 0x3d,0x74,0x2e,0x73,0x31,0x3b,0x0a,0x61,0x5b,0x30,0x5d,0x2b,0x3d,0x74,0x2e,0x73,0x30,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48, + 0x55,0x4e,0x4b,0x28,0x30,0x29,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f, + 0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3d,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66, + 0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x62,0x78,0x31,0x3d,0x62,0x78,0x30, + 0x3b,0x0a,0x62,0x78,0x30,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x53,0x43,0x52, + 0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c, + 0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72, + 0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x38,0x2c, + 0x38,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x32,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f, + 0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68, + 0x30,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x31,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x32,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42, + 0x72,0x61,0x6e,0x63,0x68,0x33,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x32,0x5b,0x32,0x35,0x36, + 0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x5b,0x34, + 0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x65,0x78,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x67,0x49,0x64,0x78, + 0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x31,0x29,0x2a,0x38,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x36,0x3b,0x20, + 0x69,0x2b,0x3d,0x38,0x2a,0x38,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b, + 0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x31,0x36,0x55,0x29, + 0x3b,0x0a,0x41,0x45,0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x32,0x34,0x55,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72, + 0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61, + 0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58, + 0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e, + 0x3e,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a, + 0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45, + 0x41,0x56,0x59,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x28,0x67,0x49,0x64,0x78,0x2f,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29, + 0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x28,0x67,0x49,0x64,0x78,0x20,0x25,0x20,0x57,0x4f, + 0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20, + 0x32,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x28,0x67,0x49,0x64,0x78,0x2f,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x2a,0x28, + 0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x28,0x67, + 0x49,0x64,0x78,0x20,0x25,0x20,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69,0x66,0x20,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x64,0x28,0x5f,0x5f,0x54,0x61,0x68,0x69,0x74,0x69,0x5f,0x5f,0x29,0x20,0x7c,0x7c,0x20,0x64,0x65,0x66,0x69,0x6e,0x65,0x64,0x28,0x5f,0x5f,0x50,0x69,0x74, + 0x63,0x61,0x69,0x72,0x6e,0x5f,0x5f,0x29,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20, + 0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65, + 0x73,0x5b,0x69,0x2b,0x34,0x5d,0x3b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64, + 0x28,0x31,0x29,0x2b,0x34,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a, + 0x23,0x65,0x6c,0x73,0x65,0x0a,0x74,0x65,0x78,0x74,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31, + 0x29,0x2b,0x34,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x28,0x28, + 0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28, + 0x31,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x41,0x45,0x53,0x45,0x78,0x70,0x61,0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29, + 0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29, + 0x3b,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f, + 0x48,0x45,0x41,0x56,0x59,0x29,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x69,0x6e,0x31,0x5b,0x38,0x5d,0x5b,0x38,0x5d,0x3b, + 0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x69,0x6e,0x32,0x5b,0x38,0x5d,0x5b,0x38,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x26,0x78,0x69,0x6e,0x31,0x5b,0x67,0x65,0x74,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64,0x3d,0x26,0x78,0x69,0x6e,0x31,0x5b,0x28,0x67,0x65, + 0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x31,0x29,0x20,0x25,0x20,0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x32,0x5f,0x73,0x74,0x6f,0x72, + 0x65,0x3d,0x26,0x78,0x69,0x6e,0x32,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x32,0x5f,0x6c, + 0x6f,0x61,0x64,0x3d,0x26,0x78,0x69,0x6e,0x32,0x5b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x31,0x29,0x20,0x25,0x20, + 0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x73,0x74,0x6f,0x72,0x65, + 0x3d,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x28,0x30,0x2c,0x30,0x2c,0x30,0x2c,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20, + 0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x29, + 0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x32,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x2c,0x69,0x31, + 0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0x20,0x69,0x3c,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x37,0x29,0x3b, + 0x20,0x2b,0x2b,0x69,0x2c,0x69,0x31,0x3d,0x28,0x69,0x31,0x2b,0x31,0x36,0x29,0x20,0x25,0x20,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x29,0x0a,0x7b, + 0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x69,0x31,0x29,0x5d,0x3b,0x0a,0x62,0x61, + 0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74, + 0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31, + 0x30,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x74,0x65,0x78,0x74,0x3d,0x41, + 0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x74,0x65,0x78, + 0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x6a,0x5d,0x29,0x3b,0x0a,0x2a, + 0x78,0x69,0x6e,0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x69,0x31,0x2b,0x38,0x29,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41, + 0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69,0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64, + 0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b, + 0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c, + 0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78, + 0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x6a,0x5d,0x29,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78, + 0x74,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45, + 0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x31,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31, + 0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x32,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d, + 0x30,0x3b,0x20,0x69,0x3c,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x37,0x29,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d, + 0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x49,0x44,0x58,0x28,0x28,0x69,0x3c,0x3c,0x33,0x29,0x2b,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x31, + 0x29,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x28,0x75,0x69,0x6e,0x74,0x20,0x6a, + 0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45, + 0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a, + 0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x6a,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x23, + 0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x5f,0x46,0x41,0x4d,0x49,0x4c,0x59,0x20,0x3d,0x3d,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41, + 0x56,0x59,0x29,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x36,0x0a,0x66,0x6f,0x72,0x28,0x73,0x69,0x7a,0x65,0x5f,0x74, + 0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x31,0x36,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x0a,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c, + 0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x20,0x7b,0x0a, + 0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45, + 0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b, + 0x6a,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e, + 0x43,0x45,0x29,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43, + 0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69, + 0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7b,0x0a,0x76,0x73,0x74,0x6f,0x72,0x65,0x32,0x28,0x61,0x73,0x5f,0x75, + 0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x65,0x78,0x74,0x29,0x2c,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x34,0x2c,0x73,0x74, + 0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f, + 0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x5b, + 0x38,0x2a,0x32,0x35,0x5d,0x3b,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x21,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x29,0x0a,0x7b,0x0a, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x53,0x74,0x61,0x74,0x65,0x3d,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67, + 0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x32,0x35,0x3b,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20, + 0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x6b, + 0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30,0x5f,0x32,0x28,0x53,0x74,0x61,0x74,0x65,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30, + 0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x69,0x5d,0x3d,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3b, + 0x0a,0x75,0x69,0x6e,0x74,0x20,0x53,0x74,0x61,0x74,0x65,0x53,0x77,0x69,0x74,0x63,0x68,0x3d,0x53,0x74,0x61,0x74,0x65,0x5b,0x30,0x5d,0x26,0x33,0x3b,0x0a,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e,0x63,0x68,0x31,0x3d, + 0x53,0x74,0x61,0x74,0x65,0x53,0x77,0x69,0x74,0x63,0x68,0x3d,0x3d,0x30,0x3f,0x42,0x72,0x61,0x6e,0x63,0x68,0x30,0x3a,0x42,0x72,0x61,0x6e,0x63,0x68,0x31,0x3b,0x0a, + 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e,0x63,0x68, + 0x32,0x3d,0x53,0x74,0x61,0x74,0x65,0x53,0x77,0x69,0x74,0x63,0x68,0x3d,0x3d,0x32,0x3f,0x42,0x72,0x61,0x6e,0x63,0x68,0x32,0x3a,0x42,0x72,0x61,0x6e,0x63,0x68,0x33, + 0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e, + 0x63,0x68,0x3d,0x53,0x74,0x61,0x74,0x65,0x53,0x77,0x69,0x74,0x63,0x68,0x3c,0x32,0x3f,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e, + 0x63,0x68,0x31,0x3a,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e,0x63,0x68,0x32,0x3b,0x0a,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74, + 0x69,0x6f,0x6e,0x42,0x72,0x61,0x6e,0x63,0x68,0x5b,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x64,0x65,0x73,0x74,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e, + 0x42,0x72,0x61,0x6e,0x63,0x68,0x2b,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x5d,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66, + 0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x53,0x57,0x41,0x50,0x38,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x35,0x36,0x29,0x20,0x7c,0x20,0x28, + 0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x34,0x30,0x29,0x20,0x26,0x20,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30, + 0x55,0x4c,0x29,0x20,0x7c,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x32,0x34,0x29,0x20,0x26,0x20,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x28,0x78,0x29,0x3e,0x3e,0x38,0x29,0x26,0x30,0x78,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x7c,0x28,0x28,0x28,0x78,0x29,0x3c,0x3c,0x38,0x29,0x26,0x30,0x78,0x30,0x30,0x30,0x30,0x30, + 0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x20,0x5c,0x0a,0x7c,0x20,0x28,0x28,0x28,0x78,0x29,0x3c,0x3c,0x32,0x34,0x29,0x26,0x30,0x78, + 0x30,0x30,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x7c,0x28,0x28,0x28,0x78,0x29,0x3c,0x3c,0x34,0x30,0x29,0x26,0x30, + 0x78,0x30,0x30,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x7c,0x28,0x28,0x28,0x78,0x29,0x3c,0x3c,0x35,0x36,0x29,0x26, + 0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56, + 0x53,0x57,0x41,0x50,0x34,0x28,0x78,0x29,0x20,0x28,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x32,0x34,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x55,0x29,0x20, + 0x7c,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3e,0x3e,0x20,0x38,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x30,0x30,0x55,0x29,0x20,0x7c,0x20,0x28,0x28,0x28,0x78,0x29, + 0x20,0x3c,0x3c,0x20,0x38,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x55,0x29,0x20,0x7c,0x20,0x28,0x28,0x28,0x78,0x29,0x20,0x3c,0x3c,0x20,0x32, + 0x34,0x29,0x20,0x26,0x20,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64, + 0x20,0x53,0x6b,0x65,0x69,0x6e,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54, + 0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a, + 0x69,0x66,0x28,0x69,0x64,0x78,0x3c,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x5d,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61, + 0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x68, + 0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30,0x2c,0x53,0x4b,0x45,0x49,0x4e,0x35,0x31,0x32,0x5f,0x32,0x35,0x36,0x5f,0x49,0x56,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e, + 0x67,0x20,0x74,0x5b,0x33,0x5d,0x3d,0x7b,0x20,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x37,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x20,0x7d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x70,0x2c,0x6d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67, + 0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x34,0x3b,0x20, + 0x2b,0x2b,0x69,0x29,0x0a,0x7b,0x0a,0x74,0x5b,0x30,0x5d,0x2b,0x3d,0x69,0x3c,0x33,0x3f,0x30,0x78,0x34,0x30,0x55,0x4c,0x3a,0x30,0x78,0x30,0x38,0x55,0x4c,0x3b,0x0a, + 0x74,0x5b,0x32,0x5d,0x3d,0x74,0x5b,0x30,0x5d,0x5e,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x6d,0x3d,0x28,0x69,0x3c,0x33,0x29,0x3f,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x69, + 0x2c,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3a,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x29,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x34,0x5d,0x2c,0x30,0x55,0x4c, + 0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x38,0x3d,0x68,0x2e,0x73,0x30,0x5e,0x68,0x2e,0x73,0x31,0x5e,0x68,0x2e,0x73,0x32,0x5e,0x68,0x2e,0x73,0x33,0x5e,0x68,0x2e, + 0x73,0x34,0x5e,0x68,0x2e,0x73,0x35,0x5e,0x68,0x2e,0x73,0x36,0x5e,0x68,0x2e,0x73,0x37,0x5e,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x4b,0x53,0x5f,0x50,0x41,0x52,0x49,0x54, + 0x59,0x3b,0x0a,0x70,0x3d,0x53,0x6b,0x65,0x69,0x6e,0x35,0x31,0x32,0x42,0x6c,0x6f,0x63,0x6b,0x28,0x6d,0x2c,0x68,0x2c,0x68,0x38,0x2c,0x74,0x29,0x3b,0x0a,0x68,0x3d, + 0x6d,0x5e,0x70,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x69,0x3c,0x32,0x3f,0x30,0x78,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x55,0x4c,0x3a,0x30,0x78,0x42,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x74,0x5b,0x30,0x5d,0x3d, + 0x30,0x78,0x30,0x38,0x55,0x4c,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55, + 0x4c,0x3b,0x0a,0x74,0x5b,0x32,0x5d,0x3d,0x74,0x5b,0x30,0x5d,0x5e,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x70,0x3d,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x29,0x28,0x30,0x29, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x38,0x3d,0x68,0x2e,0x73,0x30,0x5e,0x68,0x2e,0x73,0x31,0x5e,0x68,0x2e,0x73,0x32,0x5e, + 0x68,0x2e,0x73,0x33,0x5e,0x68,0x2e,0x73,0x34,0x5e,0x68,0x2e,0x73,0x35,0x5e,0x68,0x2e,0x73,0x36,0x5e,0x68,0x2e,0x73,0x37,0x5e,0x53,0x4b,0x45,0x49,0x4e,0x5f,0x4b, + 0x53,0x5f,0x50,0x41,0x52,0x49,0x54,0x59,0x3b,0x0a,0x70,0x3d,0x53,0x6b,0x65,0x69,0x6e,0x35,0x31,0x32,0x42,0x6c,0x6f,0x63,0x6b,0x28,0x70,0x2c,0x68,0x2c,0x68,0x38, + 0x2c,0x74,0x29,0x3b,0x0a,0x69,0x66,0x28,0x70,0x2e,0x73,0x33,0x3c,0x3d,0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6f,0x75, + 0x74,0x49,0x64,0x78,0x3d,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x30,0x78,0x46,0x46,0x29,0x3b,0x0a,0x69,0x66, + 0x28,0x6f,0x75,0x74,0x49,0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x20,0x7b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x49,0x64,0x78,0x5d,0x3d,0x42, + 0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x2b,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f, + 0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47, + 0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x57,0x41,0x50, + 0x38,0x28,0x78,0x29,0x20,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61,0x73,0x5f,0x75,0x63,0x68,0x61,0x72,0x38,0x28,0x78,0x29,0x2e,0x73,0x37,0x36,0x35,0x34, + 0x33,0x32,0x31,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4a,0x48,0x58,0x4f,0x52,0x20,0x5c,0x0a,0x68,0x30,0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70, + 0x75,0x74,0x5b,0x30,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x30,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x31,0x68,0x20, + 0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x32,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x31,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x33,0x5d,0x3b,0x20, + 0x5c,0x0a,0x68,0x32,0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x34,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x32,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75, + 0x74,0x5b,0x35,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x33,0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x36,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x33,0x6c,0x20,0x5e, + 0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x37,0x5d,0x3b,0x20,0x5c,0x0a,0x5c,0x0a,0x45,0x38,0x3b,0x20,0x5c,0x0a,0x5c,0x0a,0x68,0x34,0x68,0x20,0x5e,0x3d,0x20,0x69, + 0x6e,0x70,0x75,0x74,0x5b,0x30,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x34,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x35, + 0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x32,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x35,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x33,0x5d, + 0x3b,0x20,0x5c,0x0a,0x68,0x36,0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x34,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x36,0x6c,0x20,0x5e,0x3d,0x20,0x69,0x6e, + 0x70,0x75,0x74,0x5b,0x35,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x37,0x68,0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x36,0x5d,0x3b,0x20,0x5c,0x0a,0x68,0x37,0x6c, + 0x20,0x5e,0x3d,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x37,0x5d,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x4a,0x48,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6f,0x75,0x74, + 0x70,0x75,0x74,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29, + 0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x64,0x78,0x3c,0x42,0x72, + 0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x5d,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x42, + 0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x3b,0x0a,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x20,0x68,0x30,0x68,0x3d,0x30,0x78,0x45,0x42,0x44, + 0x33,0x32,0x30,0x32,0x43,0x34,0x31,0x41,0x33,0x39,0x38,0x45,0x42,0x55,0x4c,0x2c,0x68,0x30,0x6c,0x3d,0x30,0x78,0x43,0x31,0x34,0x35,0x42,0x32,0x39,0x43,0x37,0x42, + 0x42,0x45,0x43,0x44,0x39,0x32,0x55,0x4c,0x2c,0x68,0x31,0x68,0x3d,0x30,0x78,0x46,0x41,0x43,0x37,0x44,0x34,0x36,0x30,0x39,0x31,0x35,0x31,0x39,0x33,0x31,0x43,0x55, + 0x4c,0x2c,0x68,0x31,0x6c,0x3d,0x30,0x78,0x30,0x33,0x38,0x41,0x35,0x30,0x37,0x45,0x44,0x36,0x38,0x32,0x30,0x30,0x32,0x36,0x55,0x4c,0x2c,0x68,0x32,0x68,0x3d,0x30, + 0x78,0x34,0x35,0x42,0x39,0x32,0x36,0x37,0x37,0x32,0x36,0x39,0x45,0x32,0x33,0x41,0x34,0x55,0x4c,0x2c,0x68,0x32,0x6c,0x3d,0x30,0x78,0x37,0x37,0x39,0x34,0x31,0x41, + 0x44,0x34,0x34,0x38,0x31,0x41,0x46,0x42,0x45,0x30,0x55,0x4c,0x2c,0x68,0x33,0x68,0x3d,0x30,0x78,0x37,0x41,0x31,0x37,0x36,0x42,0x30,0x32,0x32,0x36,0x41,0x42,0x42, + 0x35,0x43,0x44,0x55,0x4c,0x2c,0x68,0x33,0x6c,0x3d,0x30,0x78,0x41,0x38,0x32,0x46,0x46,0x46,0x30,0x46,0x34,0x32,0x32,0x34,0x46,0x30,0x35,0x36,0x55,0x4c,0x3b,0x0a, + 0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x20,0x68,0x34,0x68,0x3d,0x30,0x78,0x37,0x35,0x34,0x44,0x32,0x45,0x37,0x46,0x38,0x39,0x39,0x36,0x41,0x33,0x37,0x31,0x55,0x4c, + 0x2c,0x68,0x34,0x6c,0x3d,0x30,0x78,0x36,0x32,0x45,0x32,0x37,0x44,0x46,0x37,0x30,0x38,0x34,0x39,0x31,0x34,0x31,0x44,0x55,0x4c,0x2c,0x68,0x35,0x68,0x3d,0x30,0x78, + 0x39,0x34,0x38,0x46,0x32,0x34,0x37,0x36,0x46,0x37,0x39,0x35,0x37,0x36,0x32,0x37,0x55,0x4c,0x2c,0x68,0x35,0x6c,0x3d,0x30,0x78,0x36,0x43,0x32,0x39,0x38,0x30,0x34, + 0x37,0x35,0x37,0x42,0x36,0x44,0x35,0x38,0x37,0x55,0x4c,0x2c,0x68,0x36,0x68,0x3d,0x30,0x78,0x36,0x43,0x30,0x44,0x38,0x45,0x41,0x43,0x32,0x44,0x32,0x37,0x35,0x45, + 0x35,0x43,0x55,0x4c,0x2c,0x68,0x36,0x6c,0x3d,0x30,0x78,0x30,0x46,0x37,0x41,0x30,0x35,0x35,0x37,0x43,0x36,0x35,0x30,0x38,0x34,0x35,0x31,0x55,0x4c,0x2c,0x68,0x37, + 0x68,0x3d,0x30,0x78,0x45,0x41,0x31,0x32,0x32,0x34,0x37,0x30,0x36,0x37,0x44,0x33,0x45,0x34,0x37,0x42,0x55,0x4c,0x2c,0x68,0x37,0x6c,0x3d,0x30,0x78,0x36,0x39,0x44, + 0x37,0x31,0x43,0x44,0x33,0x31,0x33,0x41,0x42,0x45,0x33,0x38,0x39,0x55,0x4c,0x3b,0x0a,0x73,0x70,0x68,0x5f,0x75,0x36,0x34,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x66,0x6f, + 0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x33,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x69, + 0x6e,0x70,0x75,0x74,0x5b,0x38,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x65,0x64,0x3d,0x69,0x3c,0x3c,0x33,0x3b, + 0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x69,0x6e,0x70,0x75, + 0x74,0x5b,0x78,0x5d,0x3d,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x73,0x68,0x69,0x66,0x74,0x65,0x64,0x2b,0x78,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x4a,0x48,0x58,0x4f, + 0x52,0x3b,0x0a,0x7d,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x28,0x73,0x74,0x61,0x74,0x65,0x73,0x5b, + 0x32,0x34,0x5d,0x29,0x2c,0x30,0x78,0x38,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c, + 0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x20,0x7d,0x3b,0x0a,0x4a,0x48,0x58,0x4f,0x52,0x3b,0x0a, + 0x7d,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x69,0x6e,0x70,0x75,0x74,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30, + 0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30,0x55,0x4c,0x2c,0x30, + 0x78,0x30,0x30,0x55,0x4c,0x2c,0x30,0x78,0x34,0x30,0x30,0x36,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x20,0x7d,0x3b,0x0a,0x4a,0x48, + 0x58,0x4f,0x52,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x68,0x37,0x6c,0x3c,0x3d,0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6f, + 0x75,0x74,0x49,0x64,0x78,0x3d,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x30,0x78,0x46,0x46,0x29,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x75,0x74,0x49,0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x20,0x7b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x49,0x64,0x78,0x5d,0x3d, + 0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x2b,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x57,0x41,0x50, + 0x34,0x28,0x78,0x29,0x20,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x61,0x73,0x5f,0x75,0x63,0x68,0x61,0x72,0x34,0x28,0x78,0x29,0x2e,0x73,0x33,0x32,0x31,0x30,0x29, + 0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x42,0x6c,0x61,0x6b,0x65,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c, + 0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x42,0x75,0x66,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x64,0x78,0x3c,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x54, + 0x68,0x72,0x65,0x61,0x64,0x73,0x5d,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b, + 0x69,0x64,0x78,0x5d,0x3b,0x0a,0x75,0x6e,0x73,0x69,0x67,0x6e,0x65,0x64,0x20,0x69,0x6e,0x74,0x20,0x6d,0x5b,0x31,0x36,0x5d,0x3b,0x0a,0x75,0x6e,0x73,0x69,0x67,0x6e, + 0x65,0x64,0x20,0x69,0x6e,0x74,0x20,0x76,0x5b,0x31,0x36,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x68,0x5b,0x38,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x62,0x69, + 0x74,0x6c,0x65,0x6e,0x3d,0x30,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x68,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30, + 0x55,0x2c,0x63,0x5f,0x49,0x56,0x32,0x35,0x36,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x33,0x3b,0x20, + 0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x31,0x36,0x20,0x2a,0x29,0x6d,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x31,0x36,0x28, + 0x69,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20, + 0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x31,0x36,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x6d,0x5b,0x78,0x5d,0x3d,0x53,0x57,0x41, + 0x50,0x34,0x28,0x6d,0x5b,0x78,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x69,0x74,0x6c,0x65,0x6e,0x2b,0x3d,0x35,0x31,0x32,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x31, + 0x36,0x20,0x2a,0x29,0x76,0x29,0x5b,0x30,0x5d,0x2e,0x6c,0x6f,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x68,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x28,0x28, + 0x75,0x69,0x6e,0x74,0x31,0x36,0x20,0x2a,0x29,0x76,0x29,0x5b,0x30,0x5d,0x2e,0x68,0x69,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30,0x55,0x2c,0x63,0x5f,0x75,0x32, + 0x35,0x36,0x29,0x3b,0x0a,0x76,0x5b,0x31,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x69,0x74,0x6c,0x65,0x6e,0x3b,0x0a,0x76,0x5b,0x31,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x62, + 0x69,0x74,0x6c,0x65,0x6e,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c,0x31,0x34,0x3b,0x20,0x72,0x2b,0x2b,0x29, + 0x20,0x7b,0x0a,0x47,0x53,0x28,0x30,0x2c,0x34,0x2c,0x30,0x78,0x38,0x2c,0x30,0x78,0x43,0x2c,0x30,0x78,0x30,0x29,0x3b,0x0a,0x47,0x53,0x28,0x31,0x2c,0x35,0x2c,0x30, + 0x78,0x39,0x2c,0x30,0x78,0x44,0x2c,0x30,0x78,0x32,0x29,0x3b,0x0a,0x47,0x53,0x28,0x32,0x2c,0x36,0x2c,0x30,0x78,0x41,0x2c,0x30,0x78,0x45,0x2c,0x30,0x78,0x34,0x29, + 0x3b,0x0a,0x47,0x53,0x28,0x33,0x2c,0x37,0x2c,0x30,0x78,0x42,0x2c,0x30,0x78,0x46,0x2c,0x30,0x78,0x36,0x29,0x3b,0x0a,0x47,0x53,0x28,0x30,0x2c,0x35,0x2c,0x30,0x78, + 0x41,0x2c,0x30,0x78,0x46,0x2c,0x30,0x78,0x38,0x29,0x3b,0x0a,0x47,0x53,0x28,0x31,0x2c,0x36,0x2c,0x30,0x78,0x42,0x2c,0x30,0x78,0x43,0x2c,0x30,0x78,0x41,0x29,0x3b, + 0x0a,0x47,0x53,0x28,0x32,0x2c,0x37,0x2c,0x30,0x78,0x38,0x2c,0x30,0x78,0x44,0x2c,0x30,0x78,0x43,0x29,0x3b,0x0a,0x47,0x53,0x28,0x33,0x2c,0x34,0x2c,0x30,0x78,0x39, + 0x2c,0x30,0x78,0x45,0x2c,0x30,0x78,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x68,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20, + 0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x76,0x29,0x5b,0x30,0x5d,0x5e,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x76,0x29,0x5b,0x31,0x5d,0x3b, + 0x0a,0x7d,0x0a,0x6d,0x5b,0x30,0x5d,0x3d,0x53,0x57,0x41,0x50,0x34,0x28,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29, + 0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x5b,0x34,0x38,0x5d,0x29,0x3b,0x0a,0x6d,0x5b,0x31,0x5d,0x3d,0x53,0x57,0x41,0x50,0x34,0x28,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x5b,0x34,0x39,0x5d,0x29,0x3b,0x0a,0x6d,0x5b,0x32,0x5d,0x3d,0x30,0x78, + 0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x33,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x34,0x5d,0x3d,0x30,0x78,0x30,0x30, + 0x55,0x3b,0x0a,0x6d,0x5b,0x35,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x36,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x37,0x5d,0x3d, + 0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x38,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x39,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d, + 0x5b,0x31,0x30,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x31,0x31,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x31,0x32,0x5d,0x3d,0x30, + 0x78,0x30,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x31,0x33,0x5d,0x3d,0x31,0x55,0x3b,0x0a,0x6d,0x5b,0x31,0x34,0x5d,0x3d,0x30,0x55,0x3b,0x0a,0x6d,0x5b,0x31,0x35,0x5d,0x3d, + 0x30,0x78,0x36,0x34,0x30,0x3b,0x0a,0x62,0x69,0x74,0x6c,0x65,0x6e,0x2b,0x3d,0x36,0x34,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x31,0x36,0x20,0x2a,0x29,0x76,0x29, + 0x5b,0x30,0x5d,0x2e,0x6c,0x6f,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x68,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x31,0x36, + 0x20,0x2a,0x29,0x76,0x29,0x5b,0x30,0x5d,0x2e,0x68,0x69,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30,0x55,0x2c,0x63,0x5f,0x75,0x32,0x35,0x36,0x29,0x3b,0x0a,0x76, + 0x5b,0x31,0x32,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x69,0x74,0x6c,0x65,0x6e,0x3b,0x0a,0x76,0x5b,0x31,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x69,0x74,0x6c,0x65,0x6e,0x3b, + 0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x72,0x3d,0x30,0x3b,0x20,0x72,0x3c,0x31,0x34,0x3b,0x20,0x72,0x2b,0x2b,0x29,0x20,0x7b,0x0a,0x47,0x53,0x28, + 0x30,0x2c,0x34,0x2c,0x30,0x78,0x38,0x2c,0x30,0x78,0x43,0x2c,0x30,0x78,0x30,0x29,0x3b,0x0a,0x47,0x53,0x28,0x31,0x2c,0x35,0x2c,0x30,0x78,0x39,0x2c,0x30,0x78,0x44, + 0x2c,0x30,0x78,0x32,0x29,0x3b,0x0a,0x47,0x53,0x28,0x32,0x2c,0x36,0x2c,0x30,0x78,0x41,0x2c,0x30,0x78,0x45,0x2c,0x30,0x78,0x34,0x29,0x3b,0x0a,0x47,0x53,0x28,0x33, + 0x2c,0x37,0x2c,0x30,0x78,0x42,0x2c,0x30,0x78,0x46,0x2c,0x30,0x78,0x36,0x29,0x3b,0x0a,0x47,0x53,0x28,0x30,0x2c,0x35,0x2c,0x30,0x78,0x41,0x2c,0x30,0x78,0x46,0x2c, + 0x30,0x78,0x38,0x29,0x3b,0x0a,0x47,0x53,0x28,0x31,0x2c,0x36,0x2c,0x30,0x78,0x42,0x2c,0x30,0x78,0x43,0x2c,0x30,0x78,0x41,0x29,0x3b,0x0a,0x47,0x53,0x28,0x32,0x2c, + 0x37,0x2c,0x30,0x78,0x38,0x2c,0x30,0x78,0x44,0x2c,0x30,0x78,0x43,0x29,0x3b,0x0a,0x47,0x53,0x28,0x33,0x2c,0x34,0x2c,0x30,0x78,0x39,0x2c,0x30,0x78,0x45,0x2c,0x30, + 0x78,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x68,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x28,0x28,0x75,0x69,0x6e,0x74, + 0x38,0x20,0x2a,0x29,0x76,0x29,0x5b,0x30,0x5d,0x5e,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x76,0x29,0x5b,0x31,0x5d,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x68,0x5b,0x69,0x5d,0x3d,0x53,0x57,0x41,0x50,0x34, + 0x28,0x68,0x5b,0x69,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x74,0x3d,0x28,0x75,0x69,0x6e,0x74,0x32,0x29,0x28,0x68,0x5b,0x36,0x5d,0x2c,0x68, + 0x5b,0x37,0x5d,0x29,0x3b,0x0a,0x69,0x66,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x74,0x29,0x3c,0x3d,0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a, + 0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6f,0x75,0x74,0x49,0x64,0x78,0x3d,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x30, + 0x78,0x46,0x46,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x49,0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x20,0x7b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f, + 0x75,0x74,0x49,0x64,0x78,0x5d,0x3d,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x2b,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x67,0x65,0x74, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65, + 0x66,0x20,0x53,0x57,0x41,0x50,0x34,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x47,0x72,0x6f,0x65,0x73,0x74,0x6c,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x2a,0x42,0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6f,0x75,0x74, + 0x70,0x75,0x74,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29, + 0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x64,0x78,0x3c,0x42,0x72, + 0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x5d,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x42, + 0x72,0x61,0x6e,0x63,0x68,0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5b,0x38,0x5d,0x3d,0x7b,0x20, + 0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x55,0x4c,0x2c,0x30,0x78,0x30,0x30, + 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x20,0x7d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x48,0x5b,0x38,0x5d,0x2c,0x4d, + 0x5b,0x38,0x5d,0x3b,0x0a,0x7b,0x0a,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x2a,0x29,0x4d,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30, + 0x2c,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b, + 0x78,0x29,0x20,0x7b,0x0a,0x48,0x5b,0x78,0x5d,0x3d,0x4d,0x5b,0x78,0x5d,0x5e,0x53,0x74,0x61,0x74,0x65,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x50,0x45,0x52,0x4d,0x5f, + 0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x48,0x29,0x3b,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x4d,0x29,0x3b,0x0a,0x66,0x6f,0x72, + 0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x78,0x5d, + 0x20,0x5e,0x3d,0x20,0x48,0x5b,0x78,0x5d,0x5e,0x4d,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7b,0x0a,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x2a,0x29, + 0x4d,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x31,0x2c,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e, + 0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x48,0x5b,0x78,0x5d,0x3d,0x4d,0x5b,0x78,0x5d,0x5e,0x53,0x74,0x61, + 0x74,0x65,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x48,0x29,0x3b,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53, + 0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x4d,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b, + 0x2b,0x78,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x78,0x5d,0x20,0x5e,0x3d,0x20,0x48,0x5b,0x78,0x5d,0x5e,0x4d,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d, + 0x0a,0x7b,0x0a,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x2a,0x29,0x4d,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x32,0x2c,0x73,0x74,0x61, + 0x74,0x65,0x73,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b, + 0x0a,0x48,0x5b,0x78,0x5d,0x3d,0x4d,0x5b,0x78,0x5d,0x5e,0x53,0x74,0x61,0x74,0x65,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c, + 0x4c,0x5f,0x50,0x28,0x48,0x29,0x3b,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x4d,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69, + 0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x78,0x5d,0x20,0x5e,0x3d,0x20, + 0x48,0x5b,0x78,0x5d,0x5e,0x4d,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x4d,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x34,0x5d,0x3b,0x0a, + 0x4d,0x5b,0x31,0x5d,0x3d,0x30,0x78,0x38,0x30,0x55,0x4c,0x3b,0x0a,0x4d,0x5b,0x32,0x5d,0x3d,0x30,0x55,0x4c,0x3b,0x0a,0x4d,0x5b,0x33,0x5d,0x3d,0x30,0x55,0x4c,0x3b, + 0x0a,0x4d,0x5b,0x34,0x5d,0x3d,0x30,0x55,0x4c,0x3b,0x0a,0x4d,0x5b,0x35,0x5d,0x3d,0x30,0x55,0x4c,0x3b,0x0a,0x4d,0x5b,0x36,0x5d,0x3d,0x30,0x55,0x4c,0x3b,0x0a,0x4d, + 0x5b,0x37,0x5d,0x3d,0x30,0x78,0x30,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75, + 0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x48,0x5b,0x78,0x5d,0x3d,0x4d,0x5b,0x78,0x5d,0x5e,0x53, + 0x74,0x61,0x74,0x65,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x50,0x28,0x48,0x29,0x3b,0x0a,0x50,0x45,0x52,0x4d, + 0x5f,0x53,0x4d,0x41,0x4c,0x4c,0x5f,0x51,0x28,0x4d,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d,0x70,0x5b,0x38,0x5d,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x74,0x6d,0x70,0x5b,0x69,0x5d,0x3d,0x53,0x74,0x61, + 0x74,0x65,0x5b,0x69,0x5d,0x20,0x5e,0x3d,0x20,0x48,0x5b,0x69,0x5d,0x5e,0x4d,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x50,0x45,0x52,0x4d,0x5f,0x53,0x4d,0x41,0x4c,0x4c, + 0x5f,0x50,0x28,0x53,0x74,0x61,0x74,0x65,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x38,0x3b,0x20,0x2b, + 0x2b,0x69,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x53, + 0x74,0x61,0x74,0x65,0x5b,0x37,0x5d,0x3c,0x3d,0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6f,0x75,0x74,0x49,0x64,0x78,0x3d, + 0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x2b,0x30,0x78,0x46,0x46,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x49, + 0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x20,0x7b,0x0a,0x6f,0x75,0x74,0x70,0x75,0x74,0x5b,0x6f,0x75,0x74,0x49,0x64,0x78,0x5d,0x3d,0x42,0x72,0x61,0x6e,0x63,0x68, + 0x42,0x75,0x66,0x5b,0x69,0x64,0x78,0x5d,0x2b,0x28,0x75,0x69,0x6e,0x74,0x29,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65, + 0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x00 +}; + +} // namespace xmrig diff --git a/src/backend/opencl/cl/cn/cryptonight_gpu.cl b/src/backend/opencl/cl/cn/cryptonight_gpu.cl new file mode 100644 index 000000000..d7a313f5a --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_gpu.cl @@ -0,0 +1,520 @@ +#include "wolf-aes.cl" +#include "keccak.cl" + + +inline uint getIdx() +{ + return get_global_id(0) - get_global_offset(0); +} + + +#define IDX(x) (x) + + +inline float4 _mm_add_ps(float4 a, float4 b) +{ + return a + b; +} + + +inline float4 _mm_sub_ps(float4 a, float4 b) +{ + return a - b; +} + + +inline float4 _mm_mul_ps(float4 a, float4 b) +{ + return a * b; +} + + +inline float4 _mm_div_ps(float4 a, float4 b) +{ + return a / b; +} + + +inline float4 _mm_and_ps(float4 a, int b) +{ + return as_float4(as_int4(a) & (int4)(b)); +} + + +inline float4 _mm_or_ps(float4 a, int b) +{ + return as_float4(as_int4(a) | (int4)(b)); +} + + +inline float4 _mm_fmod_ps(float4 v, float dc) +{ + float4 d = (float4)(dc); + float4 c = _mm_div_ps(v, d); + c = trunc(c); + c = _mm_mul_ps(c, d); + return _mm_sub_ps(v, c); +} + + +inline int4 _mm_xor_si128(int4 a, int4 b) +{ + return a ^ b; +} + + +inline float4 _mm_xor_ps(float4 a, int b) +{ + return as_float4(as_int4(a) ^ (int4)(b)); +} + + +inline int4 _mm_alignr_epi8(int4 a, const uint rot) +{ + const uint right = 8 * rot; + const uint left = (32 - 8 * rot); + return (int4)( + ((uint)a.x >> right) | ( a.y << left ), + ((uint)a.y >> right) | ( a.z << left ), + ((uint)a.z >> right) | ( a.w << left ), + ((uint)a.w >> right) | ( a.x << left ) + ); +} + + +inline global int4* scratchpad_ptr(uint idx, uint n, __global int *lpad) { return (__global int4*)((__global char*)lpad + (idx & MASK) + n * 16); } + + +inline float4 fma_break(float4 x) +{ + // Break the dependency chain by setitng the exp to ?????01 + x = _mm_and_ps(x, 0xFEFFFFFF); + return _mm_or_ps(x, 0x00800000); +} + + +inline void sub_round(float4 n0, float4 n1, float4 n2, float4 n3, float4 rnd_c, float4* n, float4* d, float4* c) +{ + n1 = _mm_add_ps(n1, *c); + float4 nn = _mm_mul_ps(n0, *c); + nn = _mm_mul_ps(n1, _mm_mul_ps(nn,nn)); + nn = fma_break(nn); + *n = _mm_add_ps(*n, nn); + + n3 = _mm_sub_ps(n3, *c); + float4 dd = _mm_mul_ps(n2, *c); + dd = _mm_mul_ps(n3, _mm_mul_ps(dd,dd)); + dd = fma_break(dd); + *d = _mm_add_ps(*d, dd); + + //Constant feedback + *c = _mm_add_ps(*c, rnd_c); + *c = _mm_add_ps(*c, (float4)(0.734375f)); + float4 r = _mm_add_ps(nn, dd); + r = _mm_and_ps(r, 0x807FFFFF); + r = _mm_or_ps(r, 0x40000000); + *c = _mm_add_ps(*c, r); + +} + + +// 9*8 + 2 = 74 +inline void round_compute(float4 n0, float4 n1, float4 n2, float4 n3, float4 rnd_c, float4* c, float4* r) +{ + float4 n = (float4)(0.0f); + float4 d = (float4)(0.0f); + + sub_round(n0, n1, n2, n3, rnd_c, &n, &d, c); + sub_round(n1, n2, n3, n0, rnd_c, &n, &d, c); + sub_round(n2, n3, n0, n1, rnd_c, &n, &d, c); + sub_round(n3, n0, n1, n2, rnd_c, &n, &d, c); + sub_round(n3, n2, n1, n0, rnd_c, &n, &d, c); + sub_round(n2, n1, n0, n3, rnd_c, &n, &d, c); + sub_round(n1, n0, n3, n2, rnd_c, &n, &d, c); + sub_round(n0, n3, n2, n1, rnd_c, &n, &d, c); + + // Make sure abs(d) > 2.0 - this prevents division by zero and accidental overflows by division by < 1.0 + d = _mm_and_ps(d, 0xFF7FFFFF); + d = _mm_or_ps(d, 0x40000000); + *r =_mm_add_ps(*r, _mm_div_ps(n,d)); +} + + +inline int4 single_comupte(float4 n0, float4 n1, float4 n2, float4 n3, float cnt, float4 rnd_c, __local float4* sum) +{ + float4 c= (float4)(cnt); + // 35 maths calls follow (140 FLOPS) + float4 r = (float4)(0.0f); + + for (int i = 0; i < 4; ++i) { + round_compute(n0, n1, n2, n3, rnd_c, &c, &r); + } + + // do a quick fmod by setting exp to 2 + r = _mm_and_ps(r, 0x807FFFFF); + r = _mm_or_ps(r, 0x40000000); + *sum = r; // 34 + float4 x = (float4)(536870880.0f); + r = _mm_mul_ps(r, x); // 35 + return convert_int4_rte(r); +} + + +inline void single_comupte_wrap(const uint rot, int4 v0, int4 v1, int4 v2, int4 v3, float cnt, float4 rnd_c, __local float4* sum, __local int4* out) +{ + float4 n0 = convert_float4_rte(v0); + float4 n1 = convert_float4_rte(v1); + float4 n2 = convert_float4_rte(v2); + float4 n3 = convert_float4_rte(v3); + + int4 r = single_comupte(n0, n1, n2, n3, cnt, rnd_c, sum); + *out = rot == 0 ? r : _mm_alignr_epi8(r, rot); +} + + +static const __constant uint look[16][4] = { + {0, 1, 2, 3}, + {0, 2, 3, 1}, + {0, 3, 1, 2}, + {0, 3, 2, 1}, + + {1, 0, 2, 3}, + {1, 2, 3, 0}, + {1, 3, 0, 2}, + {1, 3, 2, 0}, + + {2, 1, 0, 3}, + {2, 0, 3, 1}, + {2, 3, 1, 0}, + {2, 3, 0, 1}, + + {3, 1, 2, 0}, + {3, 2, 0, 1}, + {3, 0, 1, 2}, + {3, 0, 2, 1} +}; + + +static const __constant float ccnt[16] = { + 1.34375f, + 1.28125f, + 1.359375f, + 1.3671875f, + + 1.4296875f, + 1.3984375f, + 1.3828125f, + 1.3046875f, + + 1.4140625f, + 1.2734375f, + 1.2578125f, + 1.2890625f, + + 1.3203125f, + 1.3515625f, + 1.3359375f, + 1.4609375f +}; + + +struct SharedMemChunk +{ + int4 out[16]; + float4 va[16]; +}; + + +__attribute__((reqd_work_group_size(WORKSIZE * 16, 1, 1))) +__kernel void cn1(__global int *lpad_in, __global int *spad, uint numThreads) +{ + const uint gIdx = getIdx(); + uint chunk = get_local_id(0) / 16; + + __global int* lpad = (__global int*)((__global char*)lpad_in + MEMORY * (gIdx/16)); + + __local struct SharedMemChunk smem_in[WORKSIZE]; + __local struct SharedMemChunk* smem = smem_in + chunk; + + uint tid = get_local_id(0) % 16; + + uint idxHash = gIdx/16; + uint s = ((__global uint*)spad)[idxHash * 50] >> 8; + float4 vs = (float4)(0); + + // tid divided + const uint tidd = tid / 4; + // tid modulo + const uint tidm = tid % 4; + const uint block = tidd * 16 + tidm; + + #pragma unroll CN_UNROLL + for (uint i = 0; i < ITERATIONS; i++) { + mem_fence(CLK_LOCAL_MEM_FENCE); + int tmp = ((__global int*)scratchpad_ptr(s, tidd, lpad))[tidm]; + ((__local int*)(smem->out))[tid] = tmp; + mem_fence(CLK_LOCAL_MEM_FENCE); + + { + single_comupte_wrap( + tidm, + *(smem->out + look[tid][0]), + *(smem->out + look[tid][1]), + *(smem->out + look[tid][2]), + *(smem->out + look[tid][3]), + ccnt[tid], vs, smem->va + tid, + smem->out + tid + ); + } + mem_fence(CLK_LOCAL_MEM_FENCE); + + int outXor = ((__local int*)smem->out)[block]; + for (uint dd = block + 4; dd < (tidd + 1) * 16; dd += 4) { + outXor ^= ((__local int*)smem->out)[dd]; + } + + ((__global int*)scratchpad_ptr(s, tidd, lpad))[tidm] = outXor ^ tmp; + ((__local int*)smem->out)[tid] = outXor; + + float va_tmp1 = ((__local float*)smem->va)[block] + ((__local float*)smem->va)[block + 4]; + float va_tmp2 = ((__local float*)smem->va)[block+ 8] + ((__local float*)smem->va)[block + 12]; + ((__local float*)smem->va)[tid] = va_tmp1 + va_tmp2; + + mem_fence(CLK_LOCAL_MEM_FENCE); + + int out2 = ((__local int*)smem->out)[tid] ^ ((__local int*)smem->out)[tid + 4 ] ^ ((__local int*)smem->out)[tid + 8] ^ ((__local int*)smem->out)[tid + 12]; + va_tmp1 = ((__local float*)smem->va)[block] + ((__local float*)smem->va)[block + 4]; + va_tmp2 = ((__local float*)smem->va)[block + 8] + ((__local float*)smem->va)[block + 12]; + va_tmp1 = va_tmp1 + va_tmp2; + va_tmp1 = fabs(va_tmp1); + + float xx = va_tmp1 * 16777216.0f; + int xx_int = (int)xx; + ((__local int*)smem->out)[tid] = out2 ^ xx_int; + ((__local float*)smem->va)[tid] = va_tmp1 / 64.0f; + + mem_fence(CLK_LOCAL_MEM_FENCE); + + vs = smem->va[0]; + s = smem->out[0].x ^ smem->out[0].y ^ smem->out[0].z ^ smem->out[0].w; + } +} + + +static const __constant uint skip[3] = { + 20,22,22 +}; + + +inline void generate_512(uint idx, __local ulong* in, __global ulong* out) +{ + ulong hash[25]; + + hash[0] = in[0] ^ idx; + for (int i = 1; i < 25; ++i) { + hash[i] = in[i]; + } + + for (int a = 0; a < 3; ++a) { + keccakf1600_1(hash); + for (int i = 0; i < skip[a]; ++i) { + out[i] = hash[i]; + } + + out += skip[a]; + } +} + + +__attribute__((reqd_work_group_size(8, 8, 1))) +__kernel void cn0(__global ulong *input, __global int *Scratchpad, __global ulong *states, uint Threads) +{ + const uint gIdx = getIdx(); + __local ulong State_buf[8 * 25]; + __local ulong* State = State_buf + get_local_id(0) * 25; + + { + states += 25 * gIdx; + + Scratchpad = (__global int*)((__global char*)Scratchpad + MEMORY * gIdx); + + if (get_local_id(1) == 0) { + +# ifdef __NV_CL_C_VERSION + for(uint i = 0; i < 8; ++i) + State[i] = input[i]; +# else + ((__local ulong8 *)State)[0] = vload8(0, input); +# endif + + State[8] = input[8]; + State[9] = input[9]; + State[10] = input[10]; + + ((__local uint *)State)[9] &= 0x00FFFFFFU; + ((__local uint *)State)[9] |= (((uint)get_global_id(0)) & 0xFF) << 24; + ((__local uint *)State)[10] &= 0xFF000000U; + /* explicit cast to `uint` is required because some OpenCL implementations (e.g. NVIDIA) + * handle get_global_id and get_global_offset as signed long long int and add + * 0xFFFFFFFF... to `get_global_id` if we set on host side a 32bit offset where the first bit is `1` + * (even if it is correct casted to unsigned on the host) + */ + ((__local uint *)State)[10] |= (((uint)get_global_id(0) >> 8)); + + for (int i = 11; i < 25; ++i) { + State[i] = 0x00UL; + } + + // Last bit of padding + State[16] = 0x8000000000000000UL; + + keccakf1600_2(State); + + #pragma unroll + for (int i = 0; i < 25; ++i) { + states[i] = State[i]; + } + } + } +} + + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void cn00(__global int *Scratchpad, __global ulong *states) +{ + const uint gIdx = getIdx() / 64; + __local ulong State[25]; + + states += 25 * gIdx; + + Scratchpad = (__global int*)((__global char*)Scratchpad + MEMORY * gIdx); + + for (int i = get_local_id(0); i < 25; i += get_local_size(0)) { + State[i] = states[i]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for (uint i = get_local_id(0); i < MEMORY / 512; i += get_local_size(0)) { + generate_512(i, State, (__global ulong*)((__global uchar*)Scratchpad + i * 512)); + } +} + + +__attribute__((reqd_work_group_size(8, 8, 1))) +__kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *output, ulong Target, uint Threads) +{ + __local uint AES0[256], AES1[256], AES2[256], AES3[256]; + uint ExpandedKey2[40]; + uint4 text; + + const uint gIdx = getIdx(); + + for (int i = get_local_id(1) * 8 + get_local_id(0); i < 256; i += 8 * 8) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + AES2[i] = rotate(tmp, 16U); + AES3[i] = rotate(tmp, 24U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + __local uint4 xin1[8][8]; + __local uint4 xin2[8][8]; + + { + states += 25 * gIdx; + Scratchpad += gIdx * (MEMORY >> 4); + + #if defined(__Tahiti__) || defined(__Pitcairn__) + for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = states[i + 4]; + text = vload4(get_local_id(1) + 4, (__global uint *)states); + #else + text = vload4(get_local_id(1) + 4, (__global uint *)states); + ((uint8 *)ExpandedKey2)[0] = vload8(1, (__global uint *)states); + #endif + + AESExpandKey256(ExpandedKey2); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + __local uint4* xin1_store = &xin1[get_local_id(1)][get_local_id(0)]; + __local uint4* xin1_load = &xin1[(get_local_id(1) + 1) % 8][get_local_id(0)]; + __local uint4* xin2_store = &xin2[get_local_id(1)][get_local_id(0)]; + __local uint4* xin2_load = &xin2[(get_local_id(1) + 1) % 8][get_local_id(0)]; + *xin2_store = (uint4)(0, 0, 0, 0); + + { + + #pragma unroll 2 + for (int i = 0, i1 = get_local_id(1); i < (MEMORY >> 7); ++i, i1 = (i1 + 16) % (MEMORY >> 4)) { + text ^= Scratchpad[(uint)i1]; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin2_load; + + #pragma unroll 10 + for(int j = 0; j < 10; ++j) + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + + *xin1_store = text; + + text ^= Scratchpad[(uint)i1 + 8u]; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin1_load; + + #pragma unroll 10 + for(int j = 0; j < 10; ++j) + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + + *xin2_store = text; + } + + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin2_load; + } + + /* Also left over threads performe this loop. + * The left over thread results will be ignored + */ + #pragma unroll 16 + for(size_t i = 0; i < 16; i++) + { + #pragma unroll 10 + for (int j = 0; j < 10; ++j) { + text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]); + } + + barrier(CLK_LOCAL_MEM_FENCE); + *xin1_store = text; + barrier(CLK_LOCAL_MEM_FENCE); + text ^= *xin1_load; + } + + __local ulong State_buf[8 * 25]; + { + vstore2(as_ulong2(text), get_local_id(1) + 4, states); + } + + barrier(CLK_GLOBAL_MEM_FENCE); + + { + if(!get_local_id(1)) + { + __local ulong* State = State_buf + get_local_id(0) * 25; + + for(int i = 0; i < 25; ++i) State[i] = states[i]; + + keccakf1600_2(State); + + if(State[3] <= Target) + { + ulong outIdx = atomic_inc(output + 0xFF); + if(outIdx < 0xFF) + output[outIdx] = get_global_id(0); + } + } + } + mem_fence(CLK_GLOBAL_MEM_FENCE); +} diff --git a/src/backend/opencl/cl/cn/cryptonight_gpu_cl.h b/src/backend/opencl/cl/cn/cryptonight_gpu_cl.h new file mode 100644 index 000000000..8838e2a96 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_gpu_cl.h @@ -0,0 +1,639 @@ +#pragma once + +namespace xmrig { + +static char cryptonight_gpu_cl[20166] = { + 0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x57,0x4f,0x4c,0x46,0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x4f,0x4c,0x46, + 0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32, + 0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64, + 0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x78,0x6d,0x72, + 0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x20,0x61,0x6d,0x64, + 0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x6c, + 0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x20,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x73,0x72,0x63,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x77,0x69,0x64,0x74,0x68,0x29,0x3c,0x33,0x32, + 0x75,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x73,0x72,0x63,0x30,0x3c,0x3c,0x28,0x33,0x32,0x75,0x2d,0x6f,0x66,0x66,0x73,0x65,0x74,0x2d,0x77, + 0x69,0x64,0x74,0x68,0x29,0x29,0x3e,0x3e,0x28,0x33,0x32,0x75,0x2d,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x73,0x72, + 0x63,0x30,0x3e,0x3e,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x32,0x35,0x36,0x5d,0x20,0x3d,0x0a, + 0x7b,0x0a,0x30,0x78,0x41,0x35,0x36,0x33,0x36,0x33,0x43,0x36,0x55,0x2c,0x30,0x78,0x38,0x34,0x37,0x43,0x37,0x43,0x46,0x38,0x55,0x2c,0x30,0x78,0x39,0x39,0x37,0x37, + 0x37,0x37,0x45,0x45,0x55,0x2c,0x30,0x78,0x38,0x44,0x37,0x42,0x37,0x42,0x46,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x44,0x46,0x32,0x46,0x32,0x46,0x46,0x55,0x2c,0x30, + 0x78,0x42,0x44,0x36,0x42,0x36,0x42,0x44,0x36,0x55,0x2c,0x30,0x78,0x42,0x31,0x36,0x46,0x36,0x46,0x44,0x45,0x55,0x2c,0x30,0x78,0x35,0x34,0x43,0x35,0x43,0x35,0x39, + 0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x55,0x2c,0x30,0x78,0x41,0x39, + 0x36,0x37,0x36,0x37,0x43,0x45,0x55,0x2c,0x30,0x78,0x37,0x44,0x32,0x42,0x32,0x42,0x35,0x36,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x46,0x45,0x46,0x45,0x45,0x37,0x55, + 0x2c,0x30,0x78,0x36,0x32,0x44,0x37,0x44,0x37,0x42,0x35,0x55,0x2c,0x30,0x78,0x45,0x36,0x41,0x42,0x41,0x42,0x34,0x44,0x55,0x2c,0x30,0x78,0x39,0x41,0x37,0x36,0x37, + 0x36,0x45,0x43,0x55,0x2c,0x0a,0x30,0x78,0x34,0x35,0x43,0x41,0x43,0x41,0x38,0x46,0x55,0x2c,0x30,0x78,0x39,0x44,0x38,0x32,0x38,0x32,0x31,0x46,0x55,0x2c,0x30,0x78, + 0x34,0x30,0x43,0x39,0x43,0x39,0x38,0x39,0x55,0x2c,0x30,0x78,0x38,0x37,0x37,0x44,0x37,0x44,0x46,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x35,0x46,0x41,0x46,0x41,0x45, + 0x46,0x55,0x2c,0x30,0x78,0x45,0x42,0x35,0x39,0x35,0x39,0x42,0x32,0x55,0x2c,0x30,0x78,0x43,0x39,0x34,0x37,0x34,0x37,0x38,0x45,0x55,0x2c,0x30,0x78,0x30,0x42,0x46, + 0x30,0x46,0x30,0x46,0x42,0x55,0x2c,0x0a,0x30,0x78,0x45,0x43,0x41,0x44,0x41,0x44,0x34,0x31,0x55,0x2c,0x30,0x78,0x36,0x37,0x44,0x34,0x44,0x34,0x42,0x33,0x55,0x2c, + 0x30,0x78,0x46,0x44,0x41,0x32,0x41,0x32,0x35,0x46,0x55,0x2c,0x30,0x78,0x45,0x41,0x41,0x46,0x41,0x46,0x34,0x35,0x55,0x2c,0x0a,0x30,0x78,0x42,0x46,0x39,0x43,0x39, + 0x43,0x32,0x33,0x55,0x2c,0x30,0x78,0x46,0x37,0x41,0x34,0x41,0x34,0x35,0x33,0x55,0x2c,0x30,0x78,0x39,0x36,0x37,0x32,0x37,0x32,0x45,0x34,0x55,0x2c,0x30,0x78,0x35, + 0x42,0x43,0x30,0x43,0x30,0x39,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x32,0x42,0x37,0x42,0x37,0x37,0x35,0x55,0x2c,0x30,0x78,0x31,0x43,0x46,0x44,0x46,0x44,0x45,0x31, + 0x55,0x2c,0x30,0x78,0x41,0x45,0x39,0x33,0x39,0x33,0x33,0x44,0x55,0x2c,0x30,0x78,0x36,0x41,0x32,0x36,0x32,0x36,0x34,0x43,0x55,0x2c,0x0a,0x30,0x78,0x35,0x41,0x33, + 0x36,0x33,0x36,0x36,0x43,0x55,0x2c,0x30,0x78,0x34,0x31,0x33,0x46,0x33,0x46,0x37,0x45,0x55,0x2c,0x30,0x78,0x30,0x32,0x46,0x37,0x46,0x37,0x46,0x35,0x55,0x2c,0x30, + 0x78,0x34,0x46,0x43,0x43,0x43,0x43,0x38,0x33,0x55,0x2c,0x0a,0x30,0x78,0x35,0x43,0x33,0x34,0x33,0x34,0x36,0x38,0x55,0x2c,0x30,0x78,0x46,0x34,0x41,0x35,0x41,0x35, + 0x35,0x31,0x55,0x2c,0x30,0x78,0x33,0x34,0x45,0x35,0x45,0x35,0x44,0x31,0x55,0x2c,0x30,0x78,0x30,0x38,0x46,0x31,0x46,0x31,0x46,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39, + 0x33,0x37,0x31,0x37,0x31,0x45,0x32,0x55,0x2c,0x30,0x78,0x37,0x33,0x44,0x38,0x44,0x38,0x41,0x42,0x55,0x2c,0x30,0x78,0x35,0x33,0x33,0x31,0x33,0x31,0x36,0x32,0x55, + 0x2c,0x30,0x78,0x33,0x46,0x31,0x35,0x31,0x35,0x32,0x41,0x55,0x2c,0x0a,0x30,0x78,0x30,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x55,0x2c,0x30,0x78,0x35,0x32,0x43,0x37, + 0x43,0x37,0x39,0x35,0x55,0x2c,0x30,0x78,0x36,0x35,0x32,0x33,0x32,0x33,0x34,0x36,0x55,0x2c,0x30,0x78,0x35,0x45,0x43,0x33,0x43,0x33,0x39,0x44,0x55,0x2c,0x0a,0x30, + 0x78,0x32,0x38,0x31,0x38,0x31,0x38,0x33,0x30,0x55,0x2c,0x30,0x78,0x41,0x31,0x39,0x36,0x39,0x36,0x33,0x37,0x55,0x2c,0x30,0x78,0x30,0x46,0x30,0x35,0x30,0x35,0x30, + 0x41,0x55,0x2c,0x30,0x78,0x42,0x35,0x39,0x41,0x39,0x41,0x32,0x46,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x55,0x2c,0x30,0x78,0x33,0x36, + 0x31,0x32,0x31,0x32,0x32,0x34,0x55,0x2c,0x30,0x78,0x39,0x42,0x38,0x30,0x38,0x30,0x31,0x42,0x55,0x2c,0x30,0x78,0x33,0x44,0x45,0x32,0x45,0x32,0x44,0x46,0x55,0x2c, + 0x0a,0x30,0x78,0x32,0x36,0x45,0x42,0x45,0x42,0x43,0x44,0x55,0x2c,0x30,0x78,0x36,0x39,0x32,0x37,0x32,0x37,0x34,0x45,0x55,0x2c,0x30,0x78,0x43,0x44,0x42,0x32,0x42, + 0x32,0x37,0x46,0x55,0x2c,0x30,0x78,0x39,0x46,0x37,0x35,0x37,0x35,0x45,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x42,0x30,0x39,0x30,0x39,0x31,0x32,0x55,0x2c,0x30,0x78, + 0x39,0x45,0x38,0x33,0x38,0x33,0x31,0x44,0x55,0x2c,0x30,0x78,0x37,0x34,0x32,0x43,0x32,0x43,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x45,0x31,0x41,0x31,0x41,0x33,0x34, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x44,0x31,0x42,0x31,0x42,0x33,0x36,0x55,0x2c,0x30,0x78,0x42,0x32,0x36,0x45,0x36,0x45,0x44,0x43,0x55,0x2c,0x30,0x78,0x45,0x45,0x35, + 0x41,0x35,0x41,0x42,0x34,0x55,0x2c,0x30,0x78,0x46,0x42,0x41,0x30,0x41,0x30,0x35,0x42,0x55,0x2c,0x0a,0x30,0x78,0x46,0x36,0x35,0x32,0x35,0x32,0x41,0x34,0x55,0x2c, + 0x30,0x78,0x34,0x44,0x33,0x42,0x33,0x42,0x37,0x36,0x55,0x2c,0x30,0x78,0x36,0x31,0x44,0x36,0x44,0x36,0x42,0x37,0x55,0x2c,0x30,0x78,0x43,0x45,0x42,0x33,0x42,0x33, + 0x37,0x44,0x55,0x2c,0x0a,0x30,0x78,0x37,0x42,0x32,0x39,0x32,0x39,0x35,0x32,0x55,0x2c,0x30,0x78,0x33,0x45,0x45,0x33,0x45,0x33,0x44,0x44,0x55,0x2c,0x30,0x78,0x37, + 0x31,0x32,0x46,0x32,0x46,0x35,0x45,0x55,0x2c,0x30,0x78,0x39,0x37,0x38,0x34,0x38,0x34,0x31,0x33,0x55,0x2c,0x0a,0x30,0x78,0x46,0x35,0x35,0x33,0x35,0x33,0x41,0x36, + 0x55,0x2c,0x30,0x78,0x36,0x38,0x44,0x31,0x44,0x31,0x42,0x39,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x32,0x43,0x45,0x44, + 0x45,0x44,0x43,0x31,0x55,0x2c,0x0a,0x30,0x78,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x31,0x46,0x46,0x43,0x46,0x43,0x45,0x33,0x55,0x2c,0x30, + 0x78,0x43,0x38,0x42,0x31,0x42,0x31,0x37,0x39,0x55,0x2c,0x30,0x78,0x45,0x44,0x35,0x42,0x35,0x42,0x42,0x36,0x55,0x2c,0x0a,0x30,0x78,0x42,0x45,0x36,0x41,0x36,0x41, + 0x44,0x34,0x55,0x2c,0x30,0x78,0x34,0x36,0x43,0x42,0x43,0x42,0x38,0x44,0x55,0x2c,0x30,0x78,0x44,0x39,0x42,0x45,0x42,0x45,0x36,0x37,0x55,0x2c,0x30,0x78,0x34,0x42, + 0x33,0x39,0x33,0x39,0x37,0x32,0x55,0x2c,0x0a,0x30,0x78,0x44,0x45,0x34,0x41,0x34,0x41,0x39,0x34,0x55,0x2c,0x30,0x78,0x44,0x34,0x34,0x43,0x34,0x43,0x39,0x38,0x55, + 0x2c,0x30,0x78,0x45,0x38,0x35,0x38,0x35,0x38,0x42,0x30,0x55,0x2c,0x30,0x78,0x34,0x41,0x43,0x46,0x43,0x46,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x42,0x44,0x30, + 0x44,0x30,0x42,0x42,0x55,0x2c,0x30,0x78,0x32,0x41,0x45,0x46,0x45,0x46,0x43,0x35,0x55,0x2c,0x30,0x78,0x45,0x35,0x41,0x41,0x41,0x41,0x34,0x46,0x55,0x2c,0x30,0x78, + 0x31,0x36,0x46,0x42,0x46,0x42,0x45,0x44,0x55,0x2c,0x0a,0x30,0x78,0x43,0x35,0x34,0x33,0x34,0x33,0x38,0x36,0x55,0x2c,0x30,0x78,0x44,0x37,0x34,0x44,0x34,0x44,0x39, + 0x41,0x55,0x2c,0x30,0x78,0x35,0x35,0x33,0x33,0x33,0x33,0x36,0x36,0x55,0x2c,0x30,0x78,0x39,0x34,0x38,0x35,0x38,0x35,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78,0x43,0x46, + 0x34,0x35,0x34,0x35,0x38,0x41,0x55,0x2c,0x30,0x78,0x31,0x30,0x46,0x39,0x46,0x39,0x45,0x39,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x55,0x2c, + 0x30,0x78,0x38,0x31,0x37,0x46,0x37,0x46,0x46,0x45,0x55,0x2c,0x0a,0x30,0x78,0x46,0x30,0x35,0x30,0x35,0x30,0x41,0x30,0x55,0x2c,0x30,0x78,0x34,0x34,0x33,0x43,0x33, + 0x43,0x37,0x38,0x55,0x2c,0x30,0x78,0x42,0x41,0x39,0x46,0x39,0x46,0x32,0x35,0x55,0x2c,0x30,0x78,0x45,0x33,0x41,0x38,0x41,0x38,0x34,0x42,0x55,0x2c,0x0a,0x30,0x78, + 0x46,0x33,0x35,0x31,0x35,0x31,0x41,0x32,0x55,0x2c,0x30,0x78,0x46,0x45,0x41,0x33,0x41,0x33,0x35,0x44,0x55,0x2c,0x30,0x78,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x30, + 0x55,0x2c,0x30,0x78,0x38,0x41,0x38,0x46,0x38,0x46,0x30,0x35,0x55,0x2c,0x0a,0x30,0x78,0x41,0x44,0x39,0x32,0x39,0x32,0x33,0x46,0x55,0x2c,0x30,0x78,0x42,0x43,0x39, + 0x44,0x39,0x44,0x32,0x31,0x55,0x2c,0x30,0x78,0x34,0x38,0x33,0x38,0x33,0x38,0x37,0x30,0x55,0x2c,0x30,0x78,0x30,0x34,0x46,0x35,0x46,0x35,0x46,0x31,0x55,0x2c,0x0a, + 0x30,0x78,0x44,0x46,0x42,0x43,0x42,0x43,0x36,0x33,0x55,0x2c,0x30,0x78,0x43,0x31,0x42,0x36,0x42,0x36,0x37,0x37,0x55,0x2c,0x30,0x78,0x37,0x35,0x44,0x41,0x44,0x41, + 0x41,0x46,0x55,0x2c,0x30,0x78,0x36,0x33,0x32,0x31,0x32,0x31,0x34,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x31, + 0x41,0x46,0x46,0x46,0x46,0x45,0x35,0x55,0x2c,0x30,0x78,0x30,0x45,0x46,0x33,0x46,0x33,0x46,0x44,0x55,0x2c,0x30,0x78,0x36,0x44,0x44,0x32,0x44,0x32,0x42,0x46,0x55, + 0x2c,0x0a,0x30,0x78,0x34,0x43,0x43,0x44,0x43,0x44,0x38,0x31,0x55,0x2c,0x30,0x78,0x31,0x34,0x30,0x43,0x30,0x43,0x31,0x38,0x55,0x2c,0x30,0x78,0x33,0x35,0x31,0x33, + 0x31,0x33,0x32,0x36,0x55,0x2c,0x30,0x78,0x32,0x46,0x45,0x43,0x45,0x43,0x43,0x33,0x55,0x2c,0x0a,0x30,0x78,0x45,0x31,0x35,0x46,0x35,0x46,0x42,0x45,0x55,0x2c,0x30, + 0x78,0x41,0x32,0x39,0x37,0x39,0x37,0x33,0x35,0x55,0x2c,0x30,0x78,0x43,0x43,0x34,0x34,0x34,0x34,0x38,0x38,0x55,0x2c,0x30,0x78,0x33,0x39,0x31,0x37,0x31,0x37,0x32, + 0x45,0x55,0x2c,0x0a,0x30,0x78,0x35,0x37,0x43,0x34,0x43,0x34,0x39,0x33,0x55,0x2c,0x30,0x78,0x46,0x32,0x41,0x37,0x41,0x37,0x35,0x35,0x55,0x2c,0x30,0x78,0x38,0x32, + 0x37,0x45,0x37,0x45,0x46,0x43,0x55,0x2c,0x30,0x78,0x34,0x37,0x33,0x44,0x33,0x44,0x37,0x41,0x55,0x2c,0x0a,0x30,0x78,0x41,0x43,0x36,0x34,0x36,0x34,0x43,0x38,0x55, + 0x2c,0x30,0x78,0x45,0x37,0x35,0x44,0x35,0x44,0x42,0x41,0x55,0x2c,0x30,0x78,0x32,0x42,0x31,0x39,0x31,0x39,0x33,0x32,0x55,0x2c,0x30,0x78,0x39,0x35,0x37,0x33,0x37, + 0x33,0x45,0x36,0x55,0x2c,0x0a,0x30,0x78,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x30,0x55,0x2c,0x30,0x78,0x39,0x38,0x38,0x31,0x38,0x31,0x31,0x39,0x55,0x2c,0x30,0x78, + 0x44,0x31,0x34,0x46,0x34,0x46,0x39,0x45,0x55,0x2c,0x30,0x78,0x37,0x46,0x44,0x43,0x44,0x43,0x41,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x36,0x32,0x32,0x32,0x32,0x34, + 0x34,0x55,0x2c,0x30,0x78,0x37,0x45,0x32,0x41,0x32,0x41,0x35,0x34,0x55,0x2c,0x30,0x78,0x41,0x42,0x39,0x30,0x39,0x30,0x33,0x42,0x55,0x2c,0x30,0x78,0x38,0x33,0x38, + 0x38,0x38,0x38,0x30,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x41,0x34,0x36,0x34,0x36,0x38,0x43,0x55,0x2c,0x30,0x78,0x32,0x39,0x45,0x45,0x45,0x45,0x43,0x37,0x55,0x2c, + 0x30,0x78,0x44,0x33,0x42,0x38,0x42,0x38,0x36,0x42,0x55,0x2c,0x30,0x78,0x33,0x43,0x31,0x34,0x31,0x34,0x32,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x39,0x44,0x45,0x44, + 0x45,0x41,0x37,0x55,0x2c,0x30,0x78,0x45,0x32,0x35,0x45,0x35,0x45,0x42,0x43,0x55,0x2c,0x30,0x78,0x31,0x44,0x30,0x42,0x30,0x42,0x31,0x36,0x55,0x2c,0x30,0x78,0x37, + 0x36,0x44,0x42,0x44,0x42,0x41,0x44,0x55,0x2c,0x0a,0x30,0x78,0x33,0x42,0x45,0x30,0x45,0x30,0x44,0x42,0x55,0x2c,0x30,0x78,0x35,0x36,0x33,0x32,0x33,0x32,0x36,0x34, + 0x55,0x2c,0x30,0x78,0x34,0x45,0x33,0x41,0x33,0x41,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x45,0x30,0x41,0x30,0x41,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x44,0x42,0x34, + 0x39,0x34,0x39,0x39,0x32,0x55,0x2c,0x30,0x78,0x30,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x55,0x2c,0x30,0x78,0x36,0x43,0x32,0x34,0x32,0x34,0x34,0x38,0x55,0x2c,0x30, + 0x78,0x45,0x34,0x35,0x43,0x35,0x43,0x42,0x38,0x55,0x2c,0x0a,0x30,0x78,0x35,0x44,0x43,0x32,0x43,0x32,0x39,0x46,0x55,0x2c,0x30,0x78,0x36,0x45,0x44,0x33,0x44,0x33, + 0x42,0x44,0x55,0x2c,0x30,0x78,0x45,0x46,0x41,0x43,0x41,0x43,0x34,0x33,0x55,0x2c,0x30,0x78,0x41,0x36,0x36,0x32,0x36,0x32,0x43,0x34,0x55,0x2c,0x0a,0x30,0x78,0x41, + 0x38,0x39,0x31,0x39,0x31,0x33,0x39,0x55,0x2c,0x30,0x78,0x41,0x34,0x39,0x35,0x39,0x35,0x33,0x31,0x55,0x2c,0x30,0x78,0x33,0x37,0x45,0x34,0x45,0x34,0x44,0x33,0x55, + 0x2c,0x30,0x78,0x38,0x42,0x37,0x39,0x37,0x39,0x46,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x32,0x45,0x37,0x45,0x37,0x44,0x35,0x55,0x2c,0x30,0x78,0x34,0x33,0x43,0x38, + 0x43,0x38,0x38,0x42,0x55,0x2c,0x30,0x78,0x35,0x39,0x33,0x37,0x33,0x37,0x36,0x45,0x55,0x2c,0x30,0x78,0x42,0x37,0x36,0x44,0x36,0x44,0x44,0x41,0x55,0x2c,0x0a,0x30, + 0x78,0x38,0x43,0x38,0x44,0x38,0x44,0x30,0x31,0x55,0x2c,0x30,0x78,0x36,0x34,0x44,0x35,0x44,0x35,0x42,0x31,0x55,0x2c,0x30,0x78,0x44,0x32,0x34,0x45,0x34,0x45,0x39, + 0x43,0x55,0x2c,0x30,0x78,0x45,0x30,0x41,0x39,0x41,0x39,0x34,0x39,0x55,0x2c,0x0a,0x30,0x78,0x42,0x34,0x36,0x43,0x36,0x43,0x44,0x38,0x55,0x2c,0x30,0x78,0x46,0x41, + 0x35,0x36,0x35,0x36,0x41,0x43,0x55,0x2c,0x30,0x78,0x30,0x37,0x46,0x34,0x46,0x34,0x46,0x33,0x55,0x2c,0x30,0x78,0x32,0x35,0x45,0x41,0x45,0x41,0x43,0x46,0x55,0x2c, + 0x0a,0x30,0x78,0x41,0x46,0x36,0x35,0x36,0x35,0x43,0x41,0x55,0x2c,0x30,0x78,0x38,0x45,0x37,0x41,0x37,0x41,0x46,0x34,0x55,0x2c,0x30,0x78,0x45,0x39,0x41,0x45,0x41, + 0x45,0x34,0x37,0x55,0x2c,0x30,0x78,0x31,0x38,0x30,0x38,0x30,0x38,0x31,0x30,0x55,0x2c,0x0a,0x30,0x78,0x44,0x35,0x42,0x41,0x42,0x41,0x36,0x46,0x55,0x2c,0x30,0x78, + 0x38,0x38,0x37,0x38,0x37,0x38,0x46,0x30,0x55,0x2c,0x30,0x78,0x36,0x46,0x32,0x35,0x32,0x35,0x34,0x41,0x55,0x2c,0x30,0x78,0x37,0x32,0x32,0x45,0x32,0x45,0x35,0x43, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x34,0x31,0x43,0x31,0x43,0x33,0x38,0x55,0x2c,0x30,0x78,0x46,0x31,0x41,0x36,0x41,0x36,0x35,0x37,0x55,0x2c,0x30,0x78,0x43,0x37,0x42, + 0x34,0x42,0x34,0x37,0x33,0x55,0x2c,0x30,0x78,0x35,0x31,0x43,0x36,0x43,0x36,0x39,0x37,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x45,0x38,0x45,0x38,0x43,0x42,0x55,0x2c, + 0x30,0x78,0x37,0x43,0x44,0x44,0x44,0x44,0x41,0x31,0x55,0x2c,0x30,0x78,0x39,0x43,0x37,0x34,0x37,0x34,0x45,0x38,0x55,0x2c,0x30,0x78,0x32,0x31,0x31,0x46,0x31,0x46, + 0x33,0x45,0x55,0x2c,0x0a,0x30,0x78,0x44,0x44,0x34,0x42,0x34,0x42,0x39,0x36,0x55,0x2c,0x30,0x78,0x44,0x43,0x42,0x44,0x42,0x44,0x36,0x31,0x55,0x2c,0x30,0x78,0x38, + 0x36,0x38,0x42,0x38,0x42,0x30,0x44,0x55,0x2c,0x30,0x78,0x38,0x35,0x38,0x41,0x38,0x41,0x30,0x46,0x55,0x2c,0x0a,0x30,0x78,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x30, + 0x55,0x2c,0x30,0x78,0x34,0x32,0x33,0x45,0x33,0x45,0x37,0x43,0x55,0x2c,0x30,0x78,0x43,0x34,0x42,0x35,0x42,0x35,0x37,0x31,0x55,0x2c,0x30,0x78,0x41,0x41,0x36,0x36, + 0x36,0x36,0x43,0x43,0x55,0x2c,0x0a,0x30,0x78,0x44,0x38,0x34,0x38,0x34,0x38,0x39,0x30,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x55,0x2c,0x30, + 0x78,0x30,0x31,0x46,0x36,0x46,0x36,0x46,0x37,0x55,0x2c,0x30,0x78,0x31,0x32,0x30,0x45,0x30,0x45,0x31,0x43,0x55,0x2c,0x0a,0x30,0x78,0x41,0x33,0x36,0x31,0x36,0x31, + 0x43,0x32,0x55,0x2c,0x30,0x78,0x35,0x46,0x33,0x35,0x33,0x35,0x36,0x41,0x55,0x2c,0x30,0x78,0x46,0x39,0x35,0x37,0x35,0x37,0x41,0x45,0x55,0x2c,0x30,0x78,0x44,0x30, + 0x42,0x39,0x42,0x39,0x36,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39,0x31,0x38,0x36,0x38,0x36,0x31,0x37,0x55,0x2c,0x30,0x78,0x35,0x38,0x43,0x31,0x43,0x31,0x39,0x39,0x55, + 0x2c,0x30,0x78,0x32,0x37,0x31,0x44,0x31,0x44,0x33,0x41,0x55,0x2c,0x30,0x78,0x42,0x39,0x39,0x45,0x39,0x45,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x38,0x45,0x31, + 0x45,0x31,0x44,0x39,0x55,0x2c,0x30,0x78,0x31,0x33,0x46,0x38,0x46,0x38,0x45,0x42,0x55,0x2c,0x30,0x78,0x42,0x33,0x39,0x38,0x39,0x38,0x32,0x42,0x55,0x2c,0x30,0x78, + 0x33,0x33,0x31,0x31,0x31,0x31,0x32,0x32,0x55,0x2c,0x0a,0x30,0x78,0x42,0x42,0x36,0x39,0x36,0x39,0x44,0x32,0x55,0x2c,0x30,0x78,0x37,0x30,0x44,0x39,0x44,0x39,0x41, + 0x39,0x55,0x2c,0x30,0x78,0x38,0x39,0x38,0x45,0x38,0x45,0x30,0x37,0x55,0x2c,0x30,0x78,0x41,0x37,0x39,0x34,0x39,0x34,0x33,0x33,0x55,0x2c,0x0a,0x30,0x78,0x42,0x36, + 0x39,0x42,0x39,0x42,0x32,0x44,0x55,0x2c,0x30,0x78,0x32,0x32,0x31,0x45,0x31,0x45,0x33,0x43,0x55,0x2c,0x30,0x78,0x39,0x32,0x38,0x37,0x38,0x37,0x31,0x35,0x55,0x2c, + 0x30,0x78,0x32,0x30,0x45,0x39,0x45,0x39,0x43,0x39,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x43,0x45,0x43,0x45,0x38,0x37,0x55,0x2c,0x30,0x78,0x46,0x46,0x35,0x35,0x35, + 0x35,0x41,0x41,0x55,0x2c,0x30,0x78,0x37,0x38,0x32,0x38,0x32,0x38,0x35,0x30,0x55,0x2c,0x30,0x78,0x37,0x41,0x44,0x46,0x44,0x46,0x41,0x35,0x55,0x2c,0x0a,0x30,0x78, + 0x38,0x46,0x38,0x43,0x38,0x43,0x30,0x33,0x55,0x2c,0x30,0x78,0x46,0x38,0x41,0x31,0x41,0x31,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x30,0x38,0x39,0x38,0x39,0x30,0x39, + 0x55,0x2c,0x30,0x78,0x31,0x37,0x30,0x44,0x30,0x44,0x31,0x41,0x55,0x2c,0x0a,0x30,0x78,0x44,0x41,0x42,0x46,0x42,0x46,0x36,0x35,0x55,0x2c,0x30,0x78,0x33,0x31,0x45, + 0x36,0x45,0x36,0x44,0x37,0x55,0x2c,0x30,0x78,0x43,0x36,0x34,0x32,0x34,0x32,0x38,0x34,0x55,0x2c,0x30,0x78,0x42,0x38,0x36,0x38,0x36,0x38,0x44,0x30,0x55,0x2c,0x0a, + 0x30,0x78,0x43,0x33,0x34,0x31,0x34,0x31,0x38,0x32,0x55,0x2c,0x30,0x78,0x42,0x30,0x39,0x39,0x39,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x37,0x37,0x32,0x44,0x32,0x44, + 0x35,0x41,0x55,0x2c,0x30,0x78,0x31,0x31,0x30,0x46,0x30,0x46,0x31,0x45,0x55,0x2c,0x0a,0x30,0x78,0x43,0x42,0x42,0x30,0x42,0x30,0x37,0x42,0x55,0x2c,0x30,0x78,0x46, + 0x43,0x35,0x34,0x35,0x34,0x41,0x38,0x55,0x2c,0x30,0x78,0x44,0x36,0x42,0x42,0x42,0x42,0x36,0x44,0x55,0x2c,0x30,0x78,0x33,0x41,0x31,0x36,0x31,0x36,0x32,0x43,0x55, + 0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x59,0x54,0x45,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x28,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d, + 0x64,0x5f,0x62,0x66,0x65,0x28,0x28,0x78,0x29,0x2c,0x20,0x28,0x79,0x29,0x20,0x3c,0x3c,0x20,0x33,0x55,0x2c,0x20,0x38,0x55,0x29,0x29,0x0a,0x23,0x69,0x66,0x20,0x28, + 0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x69,0x6e,0x6c,0x69, + 0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x62,0x69,0x74,0x74,0x75,0x62,0x65,0x32,0x28,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x29,0x0a,0x7b, + 0x0a,0x78,0x3d,0x7e,0x78,0x3b,0x0a,0x6b,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x30,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x33,0x29, + 0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x30,0x3b,0x0a,0x6b,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45, + 0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c, + 0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x6b, + 0x2e,0x73,0x31,0x3b,0x0a,0x6b,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42, + 0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x2c, + 0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x32,0x3b,0x0a,0x6b,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x31,0x29, + 0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x3b,0x0a,0x7d, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45, + 0x53,0x32,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x33,0x2c,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20,0x5e,0x3d, + 0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e, + 0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42, + 0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54, + 0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c, + 0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x30,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58, + 0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e, + 0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41, + 0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b,0x0a,0x7d, + 0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x54,0x77,0x6f,0x5f,0x54,0x61,0x62,0x6c,0x65,0x73,0x28,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69,0x6e,0x74, + 0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73, + 0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73, + 0x33,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61, + 0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x58,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x72, + 0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x31,0x29, + 0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b, + 0x0a,0x7d,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68,0x61,0x72, + 0x20,0x72,0x63,0x6f,0x6e,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x30,0x78,0x38,0x64,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x30,0x32,0x2c,0x30,0x78,0x30,0x34,0x2c,0x30, + 0x78,0x30,0x38,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x34,0x30,0x20,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68,0x61,0x72,0x20,0x73,0x62,0x6f,0x78,0x5b,0x32,0x35,0x36,0x5d,0x20,0x3d,0x0a, + 0x7b,0x0a,0x30,0x78,0x36,0x33,0x2c,0x30,0x78,0x37,0x43,0x2c,0x30,0x78,0x37,0x37,0x2c,0x30,0x78,0x37,0x42,0x2c,0x30,0x78,0x46,0x32,0x2c,0x30,0x78,0x36,0x42,0x2c, + 0x30,0x78,0x36,0x46,0x2c,0x30,0x78,0x43,0x35,0x2c,0x30,0x78,0x33,0x30,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x36,0x37,0x2c,0x30,0x78,0x32,0x42,0x2c,0x30,0x78, + 0x46,0x45,0x2c,0x30,0x78,0x44,0x37,0x2c,0x30,0x78,0x41,0x42,0x2c,0x30,0x78,0x37,0x36,0x2c,0x0a,0x30,0x78,0x43,0x41,0x2c,0x30,0x78,0x38,0x32,0x2c,0x30,0x78,0x43, + 0x39,0x2c,0x30,0x78,0x37,0x44,0x2c,0x30,0x78,0x46,0x41,0x2c,0x30,0x78,0x35,0x39,0x2c,0x30,0x78,0x34,0x37,0x2c,0x30,0x78,0x46,0x30,0x2c,0x30,0x78,0x41,0x44,0x2c, + 0x30,0x78,0x44,0x34,0x2c,0x30,0x78,0x41,0x32,0x2c,0x30,0x78,0x41,0x46,0x2c,0x30,0x78,0x39,0x43,0x2c,0x30,0x78,0x41,0x34,0x2c,0x30,0x78,0x37,0x32,0x2c,0x30,0x78, + 0x43,0x30,0x2c,0x0a,0x30,0x78,0x42,0x37,0x2c,0x30,0x78,0x46,0x44,0x2c,0x30,0x78,0x39,0x33,0x2c,0x30,0x78,0x32,0x36,0x2c,0x30,0x78,0x33,0x36,0x2c,0x30,0x78,0x33, + 0x46,0x2c,0x30,0x78,0x46,0x37,0x2c,0x30,0x78,0x43,0x43,0x2c,0x30,0x78,0x33,0x34,0x2c,0x30,0x78,0x41,0x35,0x2c,0x30,0x78,0x45,0x35,0x2c,0x30,0x78,0x46,0x31,0x2c, + 0x30,0x78,0x37,0x31,0x2c,0x30,0x78,0x44,0x38,0x2c,0x30,0x78,0x33,0x31,0x2c,0x30,0x78,0x31,0x35,0x2c,0x0a,0x30,0x78,0x30,0x34,0x2c,0x30,0x78,0x43,0x37,0x2c,0x30, + 0x78,0x32,0x33,0x2c,0x30,0x78,0x43,0x33,0x2c,0x30,0x78,0x31,0x38,0x2c,0x30,0x78,0x39,0x36,0x2c,0x30,0x78,0x30,0x35,0x2c,0x30,0x78,0x39,0x41,0x2c,0x30,0x78,0x30, + 0x37,0x2c,0x30,0x78,0x31,0x32,0x2c,0x30,0x78,0x38,0x30,0x2c,0x30,0x78,0x45,0x32,0x2c,0x30,0x78,0x45,0x42,0x2c,0x30,0x78,0x32,0x37,0x2c,0x30,0x78,0x42,0x32,0x2c, + 0x30,0x78,0x37,0x35,0x2c,0x0a,0x30,0x78,0x30,0x39,0x2c,0x30,0x78,0x38,0x33,0x2c,0x30,0x78,0x32,0x43,0x2c,0x30,0x78,0x31,0x41,0x2c,0x30,0x78,0x31,0x42,0x2c,0x30, + 0x78,0x36,0x45,0x2c,0x30,0x78,0x35,0x41,0x2c,0x30,0x78,0x41,0x30,0x2c,0x30,0x78,0x35,0x32,0x2c,0x30,0x78,0x33,0x42,0x2c,0x30,0x78,0x44,0x36,0x2c,0x30,0x78,0x42, + 0x33,0x2c,0x30,0x78,0x32,0x39,0x2c,0x30,0x78,0x45,0x33,0x2c,0x30,0x78,0x32,0x46,0x2c,0x30,0x78,0x38,0x34,0x2c,0x0a,0x30,0x78,0x35,0x33,0x2c,0x30,0x78,0x44,0x31, + 0x2c,0x30,0x78,0x30,0x30,0x2c,0x30,0x78,0x45,0x44,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x46,0x43,0x2c,0x30,0x78,0x42,0x31,0x2c,0x30,0x78,0x35,0x42,0x2c,0x30, + 0x78,0x36,0x41,0x2c,0x30,0x78,0x43,0x42,0x2c,0x30,0x78,0x42,0x45,0x2c,0x30,0x78,0x33,0x39,0x2c,0x30,0x78,0x34,0x41,0x2c,0x30,0x78,0x34,0x43,0x2c,0x30,0x78,0x35, + 0x38,0x2c,0x30,0x78,0x43,0x46,0x2c,0x0a,0x30,0x78,0x44,0x30,0x2c,0x30,0x78,0x45,0x46,0x2c,0x30,0x78,0x41,0x41,0x2c,0x30,0x78,0x46,0x42,0x2c,0x30,0x78,0x34,0x33, + 0x2c,0x30,0x78,0x34,0x44,0x2c,0x30,0x78,0x33,0x33,0x2c,0x30,0x78,0x38,0x35,0x2c,0x30,0x78,0x34,0x35,0x2c,0x30,0x78,0x46,0x39,0x2c,0x30,0x78,0x30,0x32,0x2c,0x30, + 0x78,0x37,0x46,0x2c,0x30,0x78,0x35,0x30,0x2c,0x30,0x78,0x33,0x43,0x2c,0x30,0x78,0x39,0x46,0x2c,0x30,0x78,0x41,0x38,0x2c,0x0a,0x30,0x78,0x35,0x31,0x2c,0x30,0x78, + 0x41,0x33,0x2c,0x30,0x78,0x34,0x30,0x2c,0x30,0x78,0x38,0x46,0x2c,0x30,0x78,0x39,0x32,0x2c,0x30,0x78,0x39,0x44,0x2c,0x30,0x78,0x33,0x38,0x2c,0x30,0x78,0x46,0x35, + 0x2c,0x30,0x78,0x42,0x43,0x2c,0x30,0x78,0x42,0x36,0x2c,0x30,0x78,0x44,0x41,0x2c,0x30,0x78,0x32,0x31,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x46,0x46,0x2c,0x30, + 0x78,0x46,0x33,0x2c,0x30,0x78,0x44,0x32,0x2c,0x0a,0x30,0x78,0x43,0x44,0x2c,0x30,0x78,0x30,0x43,0x2c,0x30,0x78,0x31,0x33,0x2c,0x30,0x78,0x45,0x43,0x2c,0x30,0x78, + 0x35,0x46,0x2c,0x30,0x78,0x39,0x37,0x2c,0x30,0x78,0x34,0x34,0x2c,0x30,0x78,0x31,0x37,0x2c,0x30,0x78,0x43,0x34,0x2c,0x30,0x78,0x41,0x37,0x2c,0x30,0x78,0x37,0x45, + 0x2c,0x30,0x78,0x33,0x44,0x2c,0x30,0x78,0x36,0x34,0x2c,0x30,0x78,0x35,0x44,0x2c,0x30,0x78,0x31,0x39,0x2c,0x30,0x78,0x37,0x33,0x2c,0x0a,0x30,0x78,0x36,0x30,0x2c, + 0x30,0x78,0x38,0x31,0x2c,0x30,0x78,0x34,0x46,0x2c,0x30,0x78,0x44,0x43,0x2c,0x30,0x78,0x32,0x32,0x2c,0x30,0x78,0x32,0x41,0x2c,0x30,0x78,0x39,0x30,0x2c,0x30,0x78, + 0x38,0x38,0x2c,0x30,0x78,0x34,0x36,0x2c,0x30,0x78,0x45,0x45,0x2c,0x30,0x78,0x42,0x38,0x2c,0x30,0x78,0x31,0x34,0x2c,0x30,0x78,0x44,0x45,0x2c,0x30,0x78,0x35,0x45, + 0x2c,0x30,0x78,0x30,0x42,0x2c,0x30,0x78,0x44,0x42,0x2c,0x0a,0x30,0x78,0x45,0x30,0x2c,0x30,0x78,0x33,0x32,0x2c,0x30,0x78,0x33,0x41,0x2c,0x30,0x78,0x30,0x41,0x2c, + 0x30,0x78,0x34,0x39,0x2c,0x30,0x78,0x30,0x36,0x2c,0x30,0x78,0x32,0x34,0x2c,0x30,0x78,0x35,0x43,0x2c,0x30,0x78,0x43,0x32,0x2c,0x30,0x78,0x44,0x33,0x2c,0x30,0x78, + 0x41,0x43,0x2c,0x30,0x78,0x36,0x32,0x2c,0x30,0x78,0x39,0x31,0x2c,0x30,0x78,0x39,0x35,0x2c,0x30,0x78,0x45,0x34,0x2c,0x30,0x78,0x37,0x39,0x2c,0x0a,0x30,0x78,0x45, + 0x37,0x2c,0x30,0x78,0x43,0x38,0x2c,0x30,0x78,0x33,0x37,0x2c,0x30,0x78,0x36,0x44,0x2c,0x30,0x78,0x38,0x44,0x2c,0x30,0x78,0x44,0x35,0x2c,0x30,0x78,0x34,0x45,0x2c, + 0x30,0x78,0x41,0x39,0x2c,0x30,0x78,0x36,0x43,0x2c,0x30,0x78,0x35,0x36,0x2c,0x30,0x78,0x46,0x34,0x2c,0x30,0x78,0x45,0x41,0x2c,0x30,0x78,0x36,0x35,0x2c,0x30,0x78, + 0x37,0x41,0x2c,0x30,0x78,0x41,0x45,0x2c,0x30,0x78,0x30,0x38,0x2c,0x0a,0x30,0x78,0x42,0x41,0x2c,0x30,0x78,0x37,0x38,0x2c,0x30,0x78,0x32,0x35,0x2c,0x30,0x78,0x32, + 0x45,0x2c,0x30,0x78,0x31,0x43,0x2c,0x30,0x78,0x41,0x36,0x2c,0x30,0x78,0x42,0x34,0x2c,0x30,0x78,0x43,0x36,0x2c,0x30,0x78,0x45,0x38,0x2c,0x30,0x78,0x44,0x44,0x2c, + 0x30,0x78,0x37,0x34,0x2c,0x30,0x78,0x31,0x46,0x2c,0x30,0x78,0x34,0x42,0x2c,0x30,0x78,0x42,0x44,0x2c,0x30,0x78,0x38,0x42,0x2c,0x30,0x78,0x38,0x41,0x2c,0x0a,0x30, + 0x78,0x37,0x30,0x2c,0x30,0x78,0x33,0x45,0x2c,0x30,0x78,0x42,0x35,0x2c,0x30,0x78,0x36,0x36,0x2c,0x30,0x78,0x34,0x38,0x2c,0x30,0x78,0x30,0x33,0x2c,0x30,0x78,0x46, + 0x36,0x2c,0x30,0x78,0x30,0x45,0x2c,0x30,0x78,0x36,0x31,0x2c,0x30,0x78,0x33,0x35,0x2c,0x30,0x78,0x35,0x37,0x2c,0x30,0x78,0x42,0x39,0x2c,0x30,0x78,0x38,0x36,0x2c, + 0x30,0x78,0x43,0x31,0x2c,0x30,0x78,0x31,0x44,0x2c,0x30,0x78,0x39,0x45,0x2c,0x0a,0x30,0x78,0x45,0x31,0x2c,0x30,0x78,0x46,0x38,0x2c,0x30,0x78,0x39,0x38,0x2c,0x30, + 0x78,0x31,0x31,0x2c,0x30,0x78,0x36,0x39,0x2c,0x30,0x78,0x44,0x39,0x2c,0x30,0x78,0x38,0x45,0x2c,0x30,0x78,0x39,0x34,0x2c,0x30,0x78,0x39,0x42,0x2c,0x30,0x78,0x31, + 0x45,0x2c,0x30,0x78,0x38,0x37,0x2c,0x30,0x78,0x45,0x39,0x2c,0x30,0x78,0x43,0x45,0x2c,0x30,0x78,0x35,0x35,0x2c,0x30,0x78,0x32,0x38,0x2c,0x30,0x78,0x44,0x46,0x2c, + 0x0a,0x30,0x78,0x38,0x43,0x2c,0x30,0x78,0x41,0x31,0x2c,0x30,0x78,0x38,0x39,0x2c,0x30,0x78,0x30,0x44,0x2c,0x30,0x78,0x42,0x46,0x2c,0x30,0x78,0x45,0x36,0x2c,0x30, + 0x78,0x34,0x32,0x2c,0x30,0x78,0x36,0x38,0x2c,0x30,0x78,0x34,0x31,0x2c,0x30,0x78,0x39,0x39,0x2c,0x30,0x78,0x32,0x44,0x2c,0x30,0x78,0x30,0x46,0x2c,0x30,0x78,0x42, + 0x30,0x2c,0x30,0x78,0x35,0x34,0x2c,0x30,0x78,0x42,0x42,0x2c,0x30,0x78,0x31,0x36,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x75,0x62,0x57, + 0x6f,0x72,0x64,0x28,0x69,0x6e,0x77,0x29,0x20,0x28,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x33,0x29,0x5d,0x20,0x3c,0x3c, + 0x20,0x32,0x34,0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x32,0x29,0x5d,0x20,0x3c,0x3c,0x20,0x31,0x36, + 0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x31,0x29,0x5d,0x20,0x3c,0x3c,0x20,0x38,0x29,0x20,0x7c,0x20, + 0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x30,0x29,0x5d,0x29,0x0a,0x76,0x6f,0x69,0x64,0x20,0x41,0x45,0x53,0x45,0x78,0x70,0x61, + 0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6b,0x65,0x79,0x62,0x75,0x66,0x29,0x0a,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69, + 0x6e,0x74,0x20,0x63,0x3d,0x38,0x2c,0x69,0x3d,0x31,0x3b,0x20,0x63,0x3c,0x34,0x30,0x3b,0x20,0x2b,0x2b,0x63,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x74,0x3d, + 0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x7c,0x7c,0x28,0x28,0x63,0x26,0x37,0x29,0x3d,0x3d,0x34,0x29,0x29,0x3f,0x53,0x75,0x62,0x57,0x6f,0x72,0x64,0x28,0x6b, + 0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x29,0x3a,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b, + 0x63,0x5d,0x3d,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x38,0x5d,0x5e,0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x3f,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x74,0x2c,0x32,0x34,0x55,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x28,0x75,0x63,0x68,0x61,0x72,0x34,0x29,0x28,0x72,0x63,0x6f,0x6e,0x5b,0x69,0x2b,0x2b, + 0x5d,0x2c,0x30,0x55,0x2c,0x30,0x55,0x2c,0x30,0x55,0x29,0x29,0x3a,0x74,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x69,0x66,0x6e, + 0x64,0x65,0x66,0x20,0x58,0x4d,0x52,0x49,0x47,0x5f,0x4b,0x45,0x43,0x43,0x41,0x4b,0x5f,0x43,0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x58,0x4d,0x52,0x49, + 0x47,0x5f,0x4b,0x45,0x43,0x43,0x41,0x4b,0x5f,0x43,0x4c,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74, + 0x61,0x6e,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6e,0x64,0x63,0x5b,0x32,0x34,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x30, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x38,0x30,0x38,0x32,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x61,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x62,0x2c,0x30, + 0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30, + 0x30,0x38,0x30,0x38,0x31,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x61,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x38,0x2c, + 0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x39,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30, + 0x30,0x30,0x30,0x30,0x61,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x62,0x2c,0x30,0x78,0x38,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x62,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x38,0x39,0x2c, + 0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x33,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x38,0x30,0x30,0x32,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x2c,0x0a,0x30,0x78,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x61,0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x61, + 0x2c,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x38,0x31,0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x38,0x30,0x38,0x30,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x2c,0x30,0x78,0x38,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x38,0x30,0x30,0x30,0x38,0x30,0x30,0x38,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f, + 0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x32,0x34,0x5d,0x20,0x3d, + 0x0a,0x7b,0x0a,0x31,0x2c,0x33,0x2c,0x36,0x2c,0x31,0x30,0x2c,0x31,0x35,0x2c,0x32,0x31,0x2c,0x32,0x38,0x2c,0x33,0x36,0x2c,0x34,0x35,0x2c,0x35,0x35,0x2c,0x32,0x2c, + 0x31,0x34,0x2c,0x0a,0x32,0x37,0x2c,0x34,0x31,0x2c,0x35,0x36,0x2c,0x38,0x2c,0x32,0x35,0x2c,0x34,0x33,0x2c,0x36,0x32,0x2c,0x31,0x38,0x2c,0x33,0x39,0x2c,0x36,0x31, + 0x2c,0x32,0x30,0x2c,0x34,0x34,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x32,0x34,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x31,0x30,0x2c,0x37, + 0x2c,0x31,0x31,0x2c,0x31,0x37,0x2c,0x31,0x38,0x2c,0x33,0x2c,0x35,0x2c,0x31,0x36,0x2c,0x38,0x2c,0x32,0x31,0x2c,0x32,0x34,0x2c,0x34,0x2c,0x0a,0x31,0x35,0x2c,0x32, + 0x33,0x2c,0x31,0x39,0x2c,0x31,0x33,0x2c,0x31,0x32,0x2c,0x32,0x2c,0x32,0x30,0x2c,0x31,0x34,0x2c,0x32,0x32,0x2c,0x39,0x2c,0x36,0x2c,0x31,0x0a,0x7d,0x3b,0x0a,0x76, + 0x6f,0x69,0x64,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30,0x5f,0x31,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69, + 0x6e,0x74,0x20,0x69,0x2c,0x72,0x6f,0x75,0x6e,0x64,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x2c,0x62,0x63,0x5b,0x35,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67, + 0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x30,0x3b,0x20,0x72,0x6f,0x75,0x6e,0x64,0x3c, + 0x32,0x34,0x3b,0x20,0x2b,0x2b,0x72,0x6f,0x75,0x6e,0x64,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d, + 0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x30,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x5b, + 0x31,0x5d,0x5e,0x73,0x74,0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x31,0x5d,0x3b,0x0a,0x62, + 0x63,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e,0x73, + 0x74,0x5b,0x32,0x32,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x33,0x5d,0x3d,0x73,0x74,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e, + 0x73,0x74,0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x3b,0x0a,0x62,0x63,0x5b,0x34,0x5d,0x3d,0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d, + 0x5e,0x73,0x74,0x5b,0x31,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x34,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75, + 0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x74,0x3d, + 0x62,0x63,0x5b,0x28,0x69,0x2b,0x34,0x29,0x20,0x25,0x20,0x35,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x62,0x63,0x5b,0x28,0x69,0x2b,0x31,0x29,0x20,0x25,0x20, + 0x35,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x20,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x35,0x5d,0x20,0x5e,0x3d, + 0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x74, + 0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x32,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x3b,0x0a,0x7d,0x0a,0x74,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61, + 0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x69, + 0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3b,0x0a,0x73, + 0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x2c,0x28,0x75,0x6c,0x6f, + 0x6e,0x67,0x29,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x69,0x5d,0x29,0x3b,0x0a,0x74,0x3d,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x7d,0x0a, + 0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69, + 0x3c,0x32,0x35,0x3b,0x20,0x69,0x2b,0x3d,0x35,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d,0x70,0x5b,0x35,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67, + 0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x35,0x3b,0x20,0x2b, + 0x2b,0x78,0x29,0x20,0x7b,0x0a,0x74,0x6d,0x70,0x5b,0x78,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x78,0x5d,0x5e,0x73, + 0x74,0x5b,0x69,0x2b,0x28,0x28,0x78,0x2b,0x32,0x29,0x20,0x25,0x20,0x35,0x29,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x78,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x28,0x28, + 0x78,0x2b,0x31,0x29,0x20,0x25,0x20,0x35,0x29,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a, + 0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x78,0x3d,0x30,0x3b,0x20,0x78,0x3c,0x35,0x3b,0x20,0x2b,0x2b,0x78,0x29,0x20,0x7b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x78, + 0x5d,0x3d,0x74,0x6d,0x70,0x5b,0x78,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x73,0x74,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72, + 0x6e,0x64,0x63,0x5b,0x72,0x6f,0x75,0x6e,0x64,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30, + 0x5f,0x32,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x20,0x69,0x2c,0x72,0x6f, + 0x75,0x6e,0x64,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x2c,0x62,0x63,0x5b,0x35,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f, + 0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x30,0x3b,0x20,0x72,0x6f,0x75,0x6e,0x64,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x72, + 0x6f,0x75,0x6e,0x64,0x29,0x20,0x7b,0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d, + 0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x30,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x37, + 0x5d,0x5e,0x73,0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x32,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b, + 0x31,0x5d,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b, + 0x32,0x31,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e,0x73,0x74, + 0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x5b,0x32,0x5d,0x5e,0x73,0x74, + 0x5b,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x37,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x32,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x34,0x5d, + 0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x33,0x5d,0x3d,0x73,0x74,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x33,0x5d,0x5e, + 0x73,0x74,0x5b,0x31,0x38,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x33,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x35,0x5d, + 0x5e,0x73,0x74,0x5b,0x31,0x30,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x35,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x30,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x62,0x63,0x5b,0x34, + 0x5d,0x3d,0x73,0x74,0x5b,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x34,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x39,0x5d,0x5e,0x73,0x74,0x5b,0x32, + 0x34,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x73,0x74,0x5b,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x31,0x31,0x5d,0x5e,0x73,0x74,0x5b, + 0x31,0x36,0x5d,0x5e,0x73,0x74,0x5b,0x32,0x31,0x5d,0x2c,0x31,0x55,0x4c,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b, + 0x0a,0x73,0x74,0x5b,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d, + 0x3b,0x0a,0x73,0x74,0x5b,0x31,0x35,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b, + 0x34,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b, + 0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x36,0x5d,0x20,0x5e,0x3d,0x20,0x62, + 0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x31,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x5d,0x20,0x5e,0x3d,0x20, + 0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x37,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x32,0x5d,0x20,0x5e,0x3d, + 0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x37,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x32,0x5d,0x20, + 0x5e,0x3d,0x20,0x62,0x63,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x38,0x5d,0x20, + 0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x38, + 0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x32,0x33,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x32,0x5d,0x3b,0x0a,0x73,0x74,0x5b, + 0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x39,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b, + 0x31,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x31,0x39,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x73, + 0x74,0x5b,0x32,0x34,0x5d,0x20,0x5e,0x3d,0x20,0x62,0x63,0x5b,0x33,0x5d,0x3b,0x0a,0x74,0x3d,0x73,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61, + 0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b, + 0x0a,0x62,0x63,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x5b,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x6b, + 0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x70,0x69,0x6c,0x6e,0x5b,0x69,0x5d,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x2c,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29, + 0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6f,0x74,0x63,0x5b,0x69,0x5d,0x29,0x3b,0x0a,0x74,0x3d,0x62,0x63,0x5b,0x30,0x5d,0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72, + 0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35, + 0x3b,0x20,0x69,0x2b,0x3d,0x35,0x29,0x20,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x74,0x6d,0x70,0x31,0x3d,0x73,0x74,0x5b,0x69,0x5d,0x2c,0x74,0x6d,0x70,0x32,0x3d, + 0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x5d,0x5e,0x73, + 0x74,0x5b,0x69,0x2b,0x32,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x3d,0x62, + 0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d,0x5e,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x31,0x5d, + 0x2c,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b, + 0x69,0x2b,0x32,0x5d,0x5e,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x32,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x29,0x3b,0x0a,0x73, + 0x74,0x5b,0x69,0x2b,0x33,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63,0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x33,0x5d,0x5e,0x74,0x6d,0x70,0x31,0x2c,0x73,0x74, + 0x5b,0x69,0x2b,0x33,0x5d,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x29,0x3b,0x0a,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x3d,0x62,0x69,0x74,0x73,0x65,0x6c,0x65,0x63, + 0x74,0x28,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x5e,0x74,0x6d,0x70,0x32,0x2c,0x73,0x74,0x5b,0x69,0x2b,0x34,0x5d,0x2c,0x74,0x6d,0x70,0x31,0x29,0x3b,0x0a,0x7d,0x0a, + 0x73,0x74,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x5f,0x72,0x6e,0x64,0x63,0x5b,0x72,0x6f,0x75,0x6e,0x64,0x5d,0x3b,0x0a,0x7d,0x0a, + 0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x0a,0x7b,0x0a, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x44,0x58,0x28,0x78,0x29,0x20,0x28, + 0x78,0x29,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61, + 0x74,0x34,0x20,0x61,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x2b,0x62,0x3b,0x0a,0x7d,0x0a,0x69, + 0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x73,0x75,0x62,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61, + 0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x2d,0x62,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e, + 0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61,0x2c,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x2a,0x62,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x64,0x69,0x76,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, + 0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x2f,0x62,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x20,0x5f,0x6d,0x6d,0x5f,0x61,0x6e,0x64,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61,0x2c,0x69,0x6e,0x74,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65, + 0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x61,0x29,0x26,0x28,0x69,0x6e,0x74,0x34,0x29, + 0x28,0x62,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x6f,0x72,0x5f,0x70,0x73,0x28, + 0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61,0x2c,0x69,0x6e,0x74,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61, + 0x74,0x34,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x61,0x29,0x7c,0x28,0x69,0x6e,0x74,0x34,0x29,0x28,0x62,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69, + 0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x66,0x6d,0x6f,0x64,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x76,0x2c,0x66, + 0x6c,0x6f,0x61,0x74,0x20,0x64,0x63,0x29,0x0a,0x7b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x64,0x3d,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x64,0x63,0x29, + 0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x3d,0x5f,0x6d,0x6d,0x5f,0x64,0x69,0x76,0x5f,0x70,0x73,0x28,0x76,0x2c,0x64,0x29,0x3b,0x0a,0x63,0x3d,0x74,0x72, + 0x75,0x6e,0x63,0x28,0x63,0x29,0x3b,0x0a,0x63,0x3d,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x63,0x2c,0x64,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x5f,0x6d,0x6d,0x5f,0x73,0x75,0x62,0x5f,0x70,0x73,0x28,0x76,0x2c,0x63,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x34, + 0x20,0x5f,0x6d,0x6d,0x5f,0x78,0x6f,0x72,0x5f,0x73,0x69,0x31,0x32,0x38,0x28,0x69,0x6e,0x74,0x34,0x20,0x61,0x2c,0x69,0x6e,0x74,0x34,0x20,0x62,0x29,0x0a,0x7b,0x0a, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x5e,0x62,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f, + 0x78,0x6f,0x72,0x5f,0x70,0x73,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x61,0x2c,0x69,0x6e,0x74,0x20,0x62,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, + 0x61,0x73,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x34,0x28,0x61,0x29,0x5e,0x28,0x69,0x6e,0x74,0x34,0x29,0x28,0x62,0x29,0x29,0x3b, + 0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x34,0x20,0x5f,0x6d,0x6d,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x72,0x5f,0x65,0x70,0x69,0x38,0x28,0x69, + 0x6e,0x74,0x34,0x20,0x61,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x6f,0x74,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x72,0x69,0x67,0x68,0x74,0x3d,0x38,0x2a,0x72,0x6f,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6c,0x65,0x66,0x74,0x3d, + 0x28,0x33,0x32,0x2d,0x38,0x2a,0x72,0x6f,0x74,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x69,0x6e,0x74,0x34,0x29,0x28,0x0a,0x28,0x28,0x75,0x69,0x6e, + 0x74,0x29,0x61,0x2e,0x78,0x3e,0x3e,0x72,0x69,0x67,0x68,0x74,0x29,0x7c,0x28,0x20,0x61,0x2e,0x79,0x3c,0x3c,0x6c,0x65,0x66,0x74,0x20,0x29,0x2c,0x0a,0x28,0x28,0x75, + 0x69,0x6e,0x74,0x29,0x61,0x2e,0x79,0x3e,0x3e,0x72,0x69,0x67,0x68,0x74,0x29,0x7c,0x28,0x20,0x61,0x2e,0x7a,0x3c,0x3c,0x6c,0x65,0x66,0x74,0x20,0x29,0x2c,0x0a,0x28, + 0x28,0x75,0x69,0x6e,0x74,0x29,0x61,0x2e,0x7a,0x3e,0x3e,0x72,0x69,0x67,0x68,0x74,0x29,0x7c,0x28,0x20,0x61,0x2e,0x77,0x3c,0x3c,0x6c,0x65,0x66,0x74,0x20,0x29,0x2c, + 0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x29,0x61,0x2e,0x77,0x3e,0x3e,0x72,0x69,0x67,0x68,0x74,0x29,0x7c,0x28,0x20,0x61,0x2e,0x78,0x3c,0x3c,0x6c,0x65,0x66,0x74,0x20, + 0x29,0x0a,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x34,0x2a,0x20,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x5f,0x70,0x74,0x72,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x2c,0x75,0x69,0x6e,0x74,0x20,0x6e,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x69,0x6e,0x74,0x20,0x2a,0x6c,0x70,0x61,0x64,0x29,0x20,0x7b,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x68,0x61,0x72,0x2a,0x29,0x6c,0x70,0x61,0x64,0x2b,0x28,0x69,0x64, + 0x78,0x26,0x4d,0x41,0x53,0x4b,0x29,0x2b,0x6e,0x2a,0x31,0x36,0x29,0x3b,0x20,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66, + 0x6d,0x61,0x5f,0x62,0x72,0x65,0x61,0x6b,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x78,0x29,0x0a,0x7b,0x0a,0x78,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x6e,0x64,0x5f,0x70, + 0x73,0x28,0x78,0x2c,0x30,0x78,0x46,0x45,0x46,0x46,0x46,0x46,0x46,0x46,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x5f,0x6d,0x6d,0x5f,0x6f,0x72,0x5f,0x70, + 0x73,0x28,0x78,0x2c,0x30,0x78,0x30,0x30,0x38,0x30,0x30,0x30,0x30,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x76,0x6f,0x69,0x64,0x20,0x73, + 0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x30,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x31,0x2c,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x6e,0x32,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x33,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x2a,0x20,0x6e,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20,0x64,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20,0x63,0x29,0x0a,0x7b,0x0a,0x6e, + 0x31,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x6e,0x31,0x2c,0x2a,0x63,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x6e,0x3d,0x5f, + 0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x6e,0x30,0x2c,0x2a,0x63,0x29,0x3b,0x0a,0x6e,0x6e,0x3d,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28, + 0x6e,0x31,0x2c,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x6e,0x6e,0x2c,0x6e,0x6e,0x29,0x29,0x3b,0x0a,0x6e,0x6e,0x3d,0x66,0x6d,0x61,0x5f,0x62,0x72, + 0x65,0x61,0x6b,0x28,0x6e,0x6e,0x29,0x3b,0x0a,0x2a,0x6e,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x2a,0x6e,0x2c,0x6e,0x6e,0x29,0x3b,0x0a,0x6e, + 0x33,0x3d,0x5f,0x6d,0x6d,0x5f,0x73,0x75,0x62,0x5f,0x70,0x73,0x28,0x6e,0x33,0x2c,0x2a,0x63,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x64,0x64,0x3d,0x5f, + 0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x6e,0x32,0x2c,0x2a,0x63,0x29,0x3b,0x0a,0x64,0x64,0x3d,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28, + 0x6e,0x33,0x2c,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f,0x70,0x73,0x28,0x64,0x64,0x2c,0x64,0x64,0x29,0x29,0x3b,0x0a,0x64,0x64,0x3d,0x66,0x6d,0x61,0x5f,0x62,0x72, + 0x65,0x61,0x6b,0x28,0x64,0x64,0x29,0x3b,0x0a,0x2a,0x64,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x2a,0x64,0x2c,0x64,0x64,0x29,0x3b,0x0a,0x2a, + 0x63,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x2a,0x63,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x29,0x3b,0x0a,0x2a,0x63,0x3d,0x5f,0x6d,0x6d,0x5f,0x61, + 0x64,0x64,0x5f,0x70,0x73,0x28,0x2a,0x63,0x2c,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x30,0x2e,0x37,0x33,0x34,0x33,0x37,0x35,0x66,0x29,0x29,0x3b,0x0a,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x72,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x6e,0x6e,0x2c,0x64,0x64,0x29,0x3b,0x0a,0x72,0x3d,0x5f,0x6d,0x6d, + 0x5f,0x61,0x6e,0x64,0x5f,0x70,0x73,0x28,0x72,0x2c,0x30,0x78,0x38,0x30,0x37,0x46,0x46,0x46,0x46,0x46,0x29,0x3b,0x0a,0x72,0x3d,0x5f,0x6d,0x6d,0x5f,0x6f,0x72,0x5f, + 0x70,0x73,0x28,0x72,0x2c,0x30,0x78,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x3b,0x0a,0x2a,0x63,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28, + 0x2a,0x63,0x2c,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x76,0x6f,0x69,0x64,0x20,0x72,0x6f,0x75,0x6e,0x64,0x5f,0x63,0x6f,0x6d,0x70,0x75, + 0x74,0x65,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x30,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x31,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x32, + 0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x33,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20, + 0x63,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20,0x72,0x29,0x0a,0x7b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x3d,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29, + 0x28,0x30,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x64,0x3d,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x30,0x2e,0x30,0x66,0x29,0x3b, + 0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x30,0x2c,0x6e,0x31,0x2c,0x6e,0x32,0x2c,0x6e,0x33,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c, + 0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x31,0x2c,0x6e,0x32,0x2c,0x6e,0x33,0x2c,0x6e,0x30,0x2c,0x72,0x6e,0x64, + 0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x32,0x2c,0x6e,0x33,0x2c,0x6e,0x30,0x2c, + 0x6e,0x31,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x33,0x2c, + 0x6e,0x30,0x2c,0x6e,0x31,0x2c,0x6e,0x32,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75, + 0x6e,0x64,0x28,0x6e,0x33,0x2c,0x6e,0x32,0x2c,0x6e,0x31,0x2c,0x6e,0x30,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73, + 0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x32,0x2c,0x6e,0x31,0x2c,0x6e,0x30,0x2c,0x6e,0x33,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64, + 0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x31,0x2c,0x6e,0x30,0x2c,0x6e,0x33,0x2c,0x6e,0x32,0x2c,0x72,0x6e,0x64,0x5f,0x63, + 0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x73,0x75,0x62,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x28,0x6e,0x30,0x2c,0x6e,0x33,0x2c,0x6e,0x32,0x2c,0x6e,0x31, + 0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x6e,0x2c,0x26,0x64,0x2c,0x63,0x29,0x3b,0x0a,0x64,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x6e,0x64,0x5f,0x70,0x73,0x28,0x64,0x2c, + 0x30,0x78,0x46,0x46,0x37,0x46,0x46,0x46,0x46,0x46,0x29,0x3b,0x0a,0x64,0x3d,0x5f,0x6d,0x6d,0x5f,0x6f,0x72,0x5f,0x70,0x73,0x28,0x64,0x2c,0x30,0x78,0x34,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x29,0x3b,0x0a,0x2a,0x72,0x20,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x64,0x64,0x5f,0x70,0x73,0x28,0x2a,0x72,0x2c,0x5f,0x6d,0x6d,0x5f,0x64,0x69, + 0x76,0x5f,0x70,0x73,0x28,0x6e,0x2c,0x64,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x34,0x20,0x73,0x69,0x6e,0x67,0x6c,0x65, + 0x5f,0x63,0x6f,0x6d,0x75,0x70,0x74,0x65,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x30,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x31,0x2c,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x6e,0x32,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x33,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x20,0x63,0x6e,0x74,0x2c,0x66,0x6c,0x6f,0x61,0x74, + 0x34,0x20,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20,0x73,0x75,0x6d,0x29,0x0a,0x7b,0x0a,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x3d,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x63,0x6e,0x74,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x72, + 0x3d,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x30,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69, + 0x3c,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x72,0x6f,0x75,0x6e,0x64,0x5f,0x63,0x6f,0x6d,0x70,0x75,0x74,0x65,0x28,0x6e,0x30,0x2c,0x6e,0x31,0x2c,0x6e, + 0x32,0x2c,0x6e,0x33,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x26,0x63,0x2c,0x26,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x3d,0x5f,0x6d,0x6d,0x5f,0x61,0x6e,0x64,0x5f,0x70, + 0x73,0x28,0x72,0x2c,0x30,0x78,0x38,0x30,0x37,0x46,0x46,0x46,0x46,0x46,0x29,0x3b,0x0a,0x72,0x3d,0x5f,0x6d,0x6d,0x5f,0x6f,0x72,0x5f,0x70,0x73,0x28,0x72,0x2c,0x30, + 0x78,0x34,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x29,0x3b,0x0a,0x2a,0x73,0x75,0x6d,0x3d,0x72,0x3b,0x20,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x78,0x3d,0x28,0x66, + 0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x35,0x33,0x36,0x38,0x37,0x30,0x38,0x38,0x30,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x72,0x3d,0x5f,0x6d,0x6d,0x5f,0x6d,0x75,0x6c,0x5f, + 0x70,0x73,0x28,0x72,0x2c,0x78,0x29,0x3b,0x20,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x69,0x6e,0x74,0x34,0x5f,0x72,0x74, + 0x65,0x28,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x76,0x6f,0x69,0x64,0x20,0x73,0x69,0x6e,0x67,0x6c,0x65,0x5f,0x63,0x6f,0x6d,0x75,0x70, + 0x74,0x65,0x5f,0x77,0x72,0x61,0x70,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x6f,0x74,0x2c,0x69,0x6e,0x74,0x34,0x20,0x76,0x30,0x2c,0x69, + 0x6e,0x74,0x34,0x20,0x76,0x31,0x2c,0x69,0x6e,0x74,0x34,0x20,0x76,0x32,0x2c,0x69,0x6e,0x74,0x34,0x20,0x76,0x33,0x2c,0x66,0x6c,0x6f,0x61,0x74,0x20,0x63,0x6e,0x74, + 0x2c,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x2a,0x20,0x73,0x75, + 0x6d,0x2c,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x34,0x2a,0x20,0x6f,0x75,0x74,0x29,0x0a,0x7b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6e,0x30, + 0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x5f,0x72,0x74,0x65,0x28,0x76,0x30,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, + 0x6e,0x31,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x5f,0x72,0x74,0x65,0x28,0x76,0x31,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74, + 0x34,0x20,0x6e,0x32,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x5f,0x72,0x74,0x65,0x28,0x76,0x32,0x29,0x3b,0x0a,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x6e,0x33,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x66,0x6c,0x6f,0x61,0x74,0x34,0x5f,0x72,0x74,0x65,0x28,0x76,0x33,0x29,0x3b,0x0a,0x69, + 0x6e,0x74,0x34,0x20,0x72,0x3d,0x73,0x69,0x6e,0x67,0x6c,0x65,0x5f,0x63,0x6f,0x6d,0x75,0x70,0x74,0x65,0x28,0x6e,0x30,0x2c,0x6e,0x31,0x2c,0x6e,0x32,0x2c,0x6e,0x33, + 0x2c,0x63,0x6e,0x74,0x2c,0x72,0x6e,0x64,0x5f,0x63,0x2c,0x73,0x75,0x6d,0x29,0x3b,0x0a,0x2a,0x6f,0x75,0x74,0x3d,0x72,0x6f,0x74,0x3d,0x3d,0x30,0x3f,0x72,0x3a,0x5f, + 0x6d,0x6d,0x5f,0x61,0x6c,0x69,0x67,0x6e,0x72,0x5f,0x65,0x70,0x69,0x38,0x28,0x72,0x2c,0x72,0x6f,0x74,0x29,0x3b,0x0a,0x7d,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6c,0x6f,0x6f,0x6b,0x5b,0x31,0x36,0x5d,0x5b,0x34, + 0x5d,0x3d,0x7b,0x0a,0x7b,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x7d,0x2c,0x0a,0x7b,0x30,0x2c,0x32,0x2c,0x33,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x30,0x2c,0x33,0x2c,0x31, + 0x2c,0x32,0x7d,0x2c,0x0a,0x7b,0x30,0x2c,0x33,0x2c,0x32,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x31,0x2c,0x30,0x2c,0x32,0x2c,0x33,0x7d,0x2c,0x0a,0x7b,0x31,0x2c,0x32,0x2c, + 0x33,0x2c,0x30,0x7d,0x2c,0x0a,0x7b,0x31,0x2c,0x33,0x2c,0x30,0x2c,0x32,0x7d,0x2c,0x0a,0x7b,0x31,0x2c,0x33,0x2c,0x32,0x2c,0x30,0x7d,0x2c,0x0a,0x7b,0x32,0x2c,0x31, + 0x2c,0x30,0x2c,0x33,0x7d,0x2c,0x0a,0x7b,0x32,0x2c,0x30,0x2c,0x33,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x32,0x2c,0x33,0x2c,0x31,0x2c,0x30,0x7d,0x2c,0x0a,0x7b,0x32,0x2c, + 0x33,0x2c,0x30,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x33,0x2c,0x31,0x2c,0x32,0x2c,0x30,0x7d,0x2c,0x0a,0x7b,0x33,0x2c,0x32,0x2c,0x30,0x2c,0x31,0x7d,0x2c,0x0a,0x7b,0x33, + 0x2c,0x30,0x2c,0x31,0x2c,0x32,0x7d,0x2c,0x0a,0x7b,0x33,0x2c,0x30,0x2c,0x32,0x2c,0x31,0x7d,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x63,0x63,0x6e,0x74,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x31, + 0x2e,0x33,0x34,0x33,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x32,0x38,0x31,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x33,0x35,0x39,0x33,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e, + 0x33,0x36,0x37,0x31,0x38,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x34,0x32,0x39,0x36,0x38,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x33,0x39,0x38,0x34,0x33,0x37,0x35,0x66, + 0x2c,0x0a,0x31,0x2e,0x33,0x38,0x32,0x38,0x31,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x33,0x30,0x34,0x36,0x38,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x34,0x31,0x34,0x30, + 0x36,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x32,0x37,0x33,0x34,0x33,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x32,0x35,0x37,0x38,0x31,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e, + 0x32,0x38,0x39,0x30,0x36,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x33,0x32,0x30,0x33,0x31,0x32,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x33,0x35,0x31,0x35,0x36,0x32,0x35,0x66, + 0x2c,0x0a,0x31,0x2e,0x33,0x33,0x35,0x39,0x33,0x37,0x35,0x66,0x2c,0x0a,0x31,0x2e,0x34,0x36,0x30,0x39,0x33,0x37,0x35,0x66,0x0a,0x7d,0x3b,0x0a,0x73,0x74,0x72,0x75, + 0x63,0x74,0x20,0x53,0x68,0x61,0x72,0x65,0x64,0x4d,0x65,0x6d,0x43,0x68,0x75,0x6e,0x6b,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x34,0x20,0x6f,0x75,0x74,0x5b,0x31,0x36,0x5d, + 0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x76,0x61,0x5b,0x31,0x36,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f, + 0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45, + 0x2a,0x31,0x36,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x31,0x28,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x20,0x2a,0x6c,0x70,0x61,0x64,0x5f,0x69,0x6e,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x20, + 0x2a,0x73,0x70,0x61,0x64,0x2c,0x75,0x69,0x6e,0x74,0x20,0x6e,0x75,0x6d,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x67,0x49,0x64,0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x63,0x68,0x75,0x6e,0x6b,0x3d,0x67,0x65, + 0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2f,0x31,0x36,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x20, + 0x6c,0x70,0x61,0x64,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63, + 0x68,0x61,0x72,0x2a,0x29,0x6c,0x70,0x61,0x64,0x5f,0x69,0x6e,0x2b,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x2a,0x28,0x67,0x49,0x64,0x78,0x2f,0x31,0x36,0x29,0x29,0x3b,0x0a, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x53,0x68,0x61,0x72,0x65,0x64,0x4d,0x65,0x6d,0x43,0x68,0x75,0x6e,0x6b,0x20,0x73,0x6d, + 0x65,0x6d,0x5f,0x69,0x6e,0x5b,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x73,0x74,0x72,0x75,0x63,0x74,0x20, + 0x53,0x68,0x61,0x72,0x65,0x64,0x4d,0x65,0x6d,0x43,0x68,0x75,0x6e,0x6b,0x2a,0x20,0x73,0x6d,0x65,0x6d,0x3d,0x73,0x6d,0x65,0x6d,0x5f,0x69,0x6e,0x2b,0x63,0x68,0x75, + 0x6e,0x6b,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x74,0x69,0x64,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x20,0x25,0x20,0x31, + 0x36,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x48,0x61,0x73,0x68,0x3d,0x67,0x49,0x64,0x78,0x2f,0x31,0x36,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73,0x3d, + 0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x73,0x70,0x61,0x64,0x29,0x5b,0x69,0x64,0x78,0x48,0x61,0x73,0x68,0x2a,0x35, + 0x30,0x5d,0x3e,0x3e,0x38,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x76,0x73,0x3d,0x28,0x66,0x6c,0x6f,0x61,0x74,0x34,0x29,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x69,0x64,0x64,0x3d,0x74,0x69,0x64,0x2f,0x34,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x74,0x69,0x64,0x6d,0x3d,0x74,0x69,0x64,0x20,0x25,0x20,0x34,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x3d,0x74, + 0x69,0x64,0x64,0x2a,0x31,0x36,0x2b,0x74,0x69,0x64,0x6d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x43,0x4e,0x5f,0x55, + 0x4e,0x52,0x4f,0x4c,0x4c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x49,0x54,0x45,0x52,0x41,0x54,0x49,0x4f,0x4e, + 0x53,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x20,0x7b,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45, + 0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74, + 0x2a,0x29,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x70,0x74,0x72,0x28,0x73,0x2c,0x74,0x69,0x64,0x64,0x2c,0x6c,0x70,0x61,0x64,0x29,0x29,0x5b,0x74, + 0x69,0x64,0x6d,0x5d,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x28,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29, + 0x29,0x5b,0x74,0x69,0x64,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f, + 0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7b,0x0a,0x73,0x69,0x6e,0x67,0x6c,0x65,0x5f,0x63,0x6f,0x6d,0x75,0x70,0x74,0x65,0x5f,0x77,0x72,0x61, + 0x70,0x28,0x0a,0x74,0x69,0x64,0x6d,0x2c,0x0a,0x2a,0x28,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x2b,0x6c,0x6f,0x6f,0x6b,0x5b,0x74,0x69,0x64,0x5d,0x5b,0x30, + 0x5d,0x29,0x2c,0x0a,0x2a,0x28,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x2b,0x6c,0x6f,0x6f,0x6b,0x5b,0x74,0x69,0x64,0x5d,0x5b,0x31,0x5d,0x29,0x2c,0x0a,0x2a, + 0x28,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x2b,0x6c,0x6f,0x6f,0x6b,0x5b,0x74,0x69,0x64,0x5d,0x5b,0x32,0x5d,0x29,0x2c,0x0a,0x2a,0x28,0x73,0x6d,0x65,0x6d, + 0x2d,0x3e,0x6f,0x75,0x74,0x2b,0x6c,0x6f,0x6f,0x6b,0x5b,0x74,0x69,0x64,0x5d,0x5b,0x33,0x5d,0x29,0x2c,0x0a,0x63,0x63,0x6e,0x74,0x5b,0x74,0x69,0x64,0x5d,0x2c,0x76, + 0x73,0x2c,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x2b,0x74,0x69,0x64,0x2c,0x0a,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x2b,0x74,0x69,0x64,0x0a,0x29,0x3b, + 0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45, + 0x29,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x58,0x6f,0x72,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65, + 0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x5d,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x64,0x64,0x3d,0x62,0x6c,0x6f, + 0x63,0x6b,0x2b,0x34,0x3b,0x20,0x64,0x64,0x3c,0x28,0x74,0x69,0x64,0x64,0x2b,0x31,0x29,0x2a,0x31,0x36,0x3b,0x20,0x64,0x64,0x2b,0x3d,0x34,0x29,0x20,0x7b,0x0a,0x6f, + 0x75,0x74,0x58,0x6f,0x72,0x20,0x5e,0x3d,0x20,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75, + 0x74,0x29,0x5b,0x64,0x64,0x5d,0x3b,0x0a,0x7d,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x5f,0x70,0x74,0x72,0x28,0x73,0x2c,0x74,0x69,0x64,0x64,0x2c,0x6c,0x70,0x61,0x64,0x29,0x29,0x5b,0x74,0x69,0x64,0x6d,0x5d,0x3d,0x6f,0x75,0x74, + 0x58,0x6f,0x72,0x5e,0x74,0x6d,0x70,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75, + 0x74,0x29,0x5b,0x74,0x69,0x64,0x5d,0x3d,0x6f,0x75,0x74,0x58,0x6f,0x72,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x3d,0x28,0x28, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x5d,0x2b, + 0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b, + 0x2b,0x34,0x5d,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x76,0x61,0x5f,0x74,0x6d,0x70,0x32,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x2b,0x20,0x38,0x5d,0x2b,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x2b,0x31,0x32,0x5d,0x3b,0x0a,0x28,0x28, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x74,0x69,0x64,0x5d,0x3d,0x76,0x61, + 0x5f,0x74,0x6d,0x70,0x31,0x2b,0x76,0x61,0x5f,0x74,0x6d,0x70,0x32,0x3b,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43, + 0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6f,0x75,0x74,0x32,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x74,0x69,0x64,0x5d,0x5e,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x74,0x69,0x64,0x2b,0x34,0x20,0x5d,0x5e,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x74,0x69,0x64,0x2b,0x38,0x5d,0x5e,0x28,0x28,0x5f,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x74,0x69,0x64,0x2b,0x31,0x32,0x5d,0x3b,0x0a,0x76,0x61,0x5f, + 0x74,0x6d,0x70,0x31,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b, + 0x62,0x6c,0x6f,0x63,0x6b,0x5d,0x2b,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61, + 0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x2b,0x34,0x5d,0x3b,0x0a,0x76,0x61,0x5f,0x74,0x6d,0x70,0x32,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x2b,0x38,0x5d,0x2b,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x2b,0x31,0x32,0x5d,0x3b,0x0a,0x76,0x61, + 0x5f,0x74,0x6d,0x70,0x31,0x3d,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x2b,0x76,0x61,0x5f,0x74,0x6d,0x70,0x32,0x3b,0x0a,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x3d,0x66, + 0x61,0x62,0x73,0x28,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x29,0x3b,0x0a,0x66,0x6c,0x6f,0x61,0x74,0x20,0x78,0x78,0x3d,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x2a,0x31, + 0x36,0x37,0x37,0x37,0x32,0x31,0x36,0x2e,0x30,0x66,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x78,0x78,0x5f,0x69,0x6e,0x74,0x3d,0x28,0x69,0x6e,0x74,0x29,0x78,0x78,0x3b,0x0a, + 0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x29,0x5b,0x74,0x69,0x64,0x5d,0x3d,0x6f, + 0x75,0x74,0x32,0x5e,0x78,0x78,0x5f,0x69,0x6e,0x74,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x66,0x6c,0x6f,0x61,0x74,0x2a,0x29,0x73,0x6d,0x65, + 0x6d,0x2d,0x3e,0x76,0x61,0x29,0x5b,0x74,0x69,0x64,0x5d,0x3d,0x76,0x61,0x5f,0x74,0x6d,0x70,0x31,0x2f,0x36,0x34,0x2e,0x30,0x66,0x3b,0x0a,0x6d,0x65,0x6d,0x5f,0x66, + 0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x76,0x73,0x3d,0x73,0x6d, + 0x65,0x6d,0x2d,0x3e,0x76,0x61,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x3d,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x5b,0x30,0x5d,0x2e,0x78,0x5e,0x73,0x6d,0x65,0x6d, + 0x2d,0x3e,0x6f,0x75,0x74,0x5b,0x30,0x5d,0x2e,0x79,0x5e,0x73,0x6d,0x65,0x6d,0x2d,0x3e,0x6f,0x75,0x74,0x5b,0x30,0x5d,0x2e,0x7a,0x5e,0x73,0x6d,0x65,0x6d,0x2d,0x3e, + 0x6f,0x75,0x74,0x5b,0x30,0x5d,0x2e,0x77,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e, + 0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x6b,0x69,0x70,0x5b,0x33,0x5d,0x3d,0x7b,0x0a,0x32,0x30,0x2c,0x32,0x32,0x2c,0x32,0x32,0x0a,0x7d,0x3b, + 0x0a,0x69,0x6e,0x6c,0x69,0x6e,0x65,0x20,0x76,0x6f,0x69,0x64,0x20,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x5f,0x35,0x31,0x32,0x28,0x75,0x69,0x6e,0x74,0x20,0x69, + 0x64,0x78,0x2c,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x69,0x6e,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c, + 0x6f,0x6e,0x67,0x2a,0x20,0x6f,0x75,0x74,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x61,0x73,0x68,0x5b,0x32,0x35,0x5d,0x3b,0x0a,0x68,0x61,0x73,0x68, + 0x5b,0x30,0x5d,0x3d,0x69,0x6e,0x5b,0x30,0x5d,0x5e,0x69,0x64,0x78,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x3b,0x20,0x69,0x3c,0x32, + 0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x68,0x61,0x73,0x68,0x5b,0x69,0x5d,0x3d,0x69,0x6e,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x69,0x6e,0x74,0x20,0x61,0x3d,0x30,0x3b,0x20,0x61,0x3c,0x33,0x3b,0x20,0x2b,0x2b,0x61,0x29,0x20,0x7b,0x0a,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31,0x36,0x30,0x30, + 0x5f,0x31,0x28,0x68,0x61,0x73,0x68,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x73,0x6b,0x69,0x70,0x5b,0x61, + 0x5d,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x6f,0x75,0x74,0x5b,0x69,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x6f,0x75,0x74,0x2b, + 0x3d,0x73,0x6b,0x69,0x70,0x5b,0x61,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71, + 0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x38,0x2c,0x38,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72, + 0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x30,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e,0x70, + 0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29, + 0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x49,0x64,0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x5b,0x38,0x2a,0x32,0x35,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x53,0x74,0x61,0x74,0x65,0x3d,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67,0x65,0x74,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x32,0x35,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78, + 0x3b,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x68,0x61,0x72,0x2a,0x29,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x2a,0x67, + 0x49,0x64,0x78,0x29,0x3b,0x0a,0x69,0x66,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3d,0x3d,0x30,0x29,0x20,0x7b,0x0a,0x23, + 0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x66,0x6f,0x72,0x28,0x75,0x69,0x6e,0x74, + 0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x69, + 0x5d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x38,0x20,0x2a,0x29,0x53,0x74,0x61,0x74, + 0x65,0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x30,0x2c,0x69,0x6e,0x70,0x75,0x74,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x53,0x74, + 0x61,0x74,0x65,0x5b,0x38,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x38,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x39,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b, + 0x39,0x5d,0x3b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x31,0x30,0x5d,0x3d,0x69,0x6e,0x70,0x75,0x74,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x39,0x5d,0x20,0x26,0x3d,0x20,0x30,0x78,0x30,0x30,0x46,0x46,0x46,0x46,0x46, + 0x46,0x55,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x39,0x5d,0x7c,0x3d, + 0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x29,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x3c, + 0x3c,0x32,0x34,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x31,0x30,0x5d, + 0x20,0x26,0x3d,0x20,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x2a,0x29,0x53,0x74,0x61,0x74,0x65,0x29,0x5b,0x31,0x30,0x5d,0x7c,0x3d,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x29,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x5f,0x69,0x64,0x28,0x30,0x29,0x3e,0x3e,0x38,0x29,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x31,0x31,0x3b,0x20,0x69,0x3c,0x32,0x35, + 0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x30,0x78,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x53,0x74,0x61,0x74, + 0x65,0x5b,0x31,0x36,0x5d,0x3d,0x30,0x78,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x6b,0x65,0x63,0x63, + 0x61,0x6b,0x66,0x31,0x36,0x30,0x30,0x5f,0x32,0x28,0x53,0x74,0x61,0x74,0x65,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c, + 0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x73,0x74,0x61,0x74, + 0x65,0x73,0x5b,0x69,0x5d,0x3d,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62, + 0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31, + 0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x30,0x30,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x69,0x6e,0x74,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x49,0x64,0x78,0x3d,0x67,0x65,0x74,0x49, + 0x64,0x78,0x28,0x29,0x2f,0x36,0x34,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5b,0x32,0x35,0x5d, + 0x3b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x3d,0x28,0x5f, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x68,0x61,0x72,0x2a,0x29,0x53,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x2a,0x67,0x49,0x64,0x78,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20, + 0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x69,0x2b,0x3d,0x67,0x65,0x74,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x29,0x20,0x7b,0x0a,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73, + 0x5b,0x69,0x5d,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e, + 0x43,0x45,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29, + 0x3b,0x20,0x69,0x3c,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x2f,0x35,0x31,0x32,0x3b,0x20,0x69,0x2b,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a, + 0x65,0x28,0x30,0x29,0x29,0x20,0x7b,0x0a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x5f,0x35,0x31,0x32,0x28,0x69,0x2c,0x53,0x74,0x61,0x74,0x65,0x2c,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29, + 0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x69,0x2a,0x35,0x31,0x32,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62, + 0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x38,0x2c,0x38,0x2c, + 0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x63,0x6e,0x32,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6f,0x75,0x74,0x70,0x75,0x74,0x2c,0x75, + 0x6c,0x6f,0x6e,0x67,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53, + 0x32,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b, + 0x65,0x79,0x32,0x5b,0x34,0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x74,0x65,0x78,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x67,0x49,0x64,0x78,0x3d,0x67,0x65,0x74,0x49,0x64,0x78,0x28,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2a,0x38,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32, + 0x35,0x36,0x3b,0x20,0x69,0x2b,0x3d,0x38,0x2a,0x38,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53, + 0x30,0x5f,0x43,0x5b,0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53,0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74, + 0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c, + 0x31,0x36,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x32,0x34,0x55,0x29,0x3b,0x0a,0x7d, + 0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x5f, + 0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x69,0x6e,0x31,0x5b,0x38,0x5d,0x5b,0x38,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x69,0x6e,0x32,0x5b,0x38,0x5d,0x5b,0x38,0x5d,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a, + 0x67,0x49,0x64,0x78,0x3b,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e, + 0x34,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x64,0x65,0x66,0x69,0x6e,0x65,0x64,0x28,0x5f,0x5f,0x54,0x61,0x68,0x69,0x74,0x69,0x5f,0x5f,0x29,0x20,0x7c,0x7c,0x20,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x64,0x28,0x5f,0x5f,0x50,0x69,0x74,0x63,0x61,0x69,0x72,0x6e,0x5f,0x5f,0x29,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30, + 0x3b,0x20,0x69,0x3c,0x34,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65, + 0x79,0x32,0x29,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x69,0x2b,0x34,0x5d,0x3b,0x0a,0x74,0x65,0x78,0x74,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28, + 0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x34,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x2a,0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x74,0x65,0x78,0x74,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x34,0x28,0x67,0x65, + 0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x34,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a, + 0x29,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32, + 0x29,0x5b,0x30,0x5d,0x3d,0x76,0x6c,0x6f,0x61,0x64,0x38,0x28,0x31,0x2c,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x29,0x73, + 0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x41,0x45,0x53,0x45,0x78,0x70,0x61,0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x45, + 0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41, + 0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e, + 0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x26,0x78,0x69,0x6e,0x31,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x5d,0x5b,0x67, + 0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20, + 0x78,0x69,0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64,0x3d,0x26,0x78,0x69,0x6e,0x31,0x5b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29, + 0x2b,0x31,0x29,0x20,0x25,0x20,0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x32,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x26,0x78,0x69,0x6e,0x32,0x5b,0x67,0x65,0x74,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x78,0x69,0x6e,0x32,0x5f,0x6c,0x6f,0x61,0x64,0x3d,0x26,0x78,0x69,0x6e,0x32,0x5b,0x28,0x67,0x65, + 0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x31,0x29,0x20,0x25,0x20,0x38,0x5d,0x5b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x30,0x29,0x5d,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x28,0x30,0x2c,0x30,0x2c, + 0x30,0x2c,0x30,0x29,0x3b,0x0a,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x32,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e, + 0x74,0x20,0x69,0x3d,0x30,0x2c,0x69,0x31,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x3b,0x20,0x69,0x3c,0x28,0x4d,0x45,0x4d, + 0x4f,0x52,0x59,0x3e,0x3e,0x37,0x29,0x3b,0x20,0x2b,0x2b,0x69,0x2c,0x69,0x31,0x3d,0x28,0x69,0x31,0x2b,0x31,0x36,0x29,0x20,0x25,0x20,0x28,0x4d,0x45,0x4d,0x4f,0x52, + 0x59,0x3e,0x3e,0x34,0x29,0x29,0x20,0x7b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x28,0x75,0x69,0x6e, + 0x74,0x29,0x69,0x31,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e, + 0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61, + 0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b, + 0x6a,0x29,0x0a,0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32, + 0x2c,0x41,0x45,0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79, + 0x32,0x29,0x5b,0x6a,0x5d,0x29,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e, + 0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5b,0x28,0x75,0x69,0x6e,0x74,0x29,0x69,0x31,0x2b,0x38,0x75,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69, + 0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d, + 0x20,0x2a,0x78,0x69,0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x30,0x0a,0x66, + 0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f, + 0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28, + 0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b,0x6a,0x5d,0x29,0x3b,0x0a,0x2a,0x78,0x69,0x6e, + 0x32,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41, + 0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69,0x6e,0x32,0x5f,0x6c,0x6f,0x61,0x64, + 0x3b,0x0a,0x7d,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x31,0x36,0x0a,0x66,0x6f,0x72,0x28,0x73,0x69,0x7a,0x65,0x5f,0x74, + 0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x31,0x36,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x0a,0x7b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c, + 0x6c,0x20,0x31,0x30,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x31,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x20,0x7b,0x0a, + 0x74,0x65,0x78,0x74,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45, + 0x53,0x33,0x2c,0x74,0x65,0x78,0x74,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x45,0x78,0x70,0x61,0x6e,0x64,0x65,0x64,0x4b,0x65,0x79,0x32,0x29,0x5b, + 0x6a,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e, + 0x43,0x45,0x29,0x3b,0x0a,0x2a,0x78,0x69,0x6e,0x31,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x65,0x78,0x74,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43, + 0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x74,0x65,0x78,0x74,0x20,0x5e,0x3d,0x20,0x2a,0x78,0x69, + 0x6e,0x31,0x5f,0x6c,0x6f,0x61,0x64,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x53,0x74,0x61,0x74,0x65,0x5f,0x62, + 0x75,0x66,0x5b,0x38,0x2a,0x32,0x35,0x5d,0x3b,0x0a,0x7b,0x0a,0x76,0x73,0x74,0x6f,0x72,0x65,0x32,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x65, + 0x78,0x74,0x29,0x2c,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x2b,0x34,0x2c,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x3b,0x0a,0x7d, + 0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a, + 0x7b,0x0a,0x69,0x66,0x28,0x21,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x31,0x29,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x53,0x74,0x61,0x74,0x65,0x3d,0x53,0x74,0x61,0x74,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x32,0x35,0x3b,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x32,0x35,0x3b,0x20,0x2b, + 0x2b,0x69,0x29,0x20,0x53,0x74,0x61,0x74,0x65,0x5b,0x69,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x6b,0x65,0x63,0x63,0x61,0x6b,0x66,0x31, + 0x36,0x30,0x30,0x5f,0x32,0x28,0x53,0x74,0x61,0x74,0x65,0x29,0x3b,0x0a,0x69,0x66,0x28,0x53,0x74,0x61,0x74,0x65,0x5b,0x33,0x5d,0x3c,0x3d,0x54,0x61,0x72,0x67,0x65, + 0x74,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6f,0x75,0x74,0x49,0x64,0x78,0x3d,0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x6f,0x75,0x74, + 0x70,0x75,0x74,0x2b,0x30,0x78,0x46,0x46,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x49,0x64,0x78,0x3c,0x30,0x78,0x46,0x46,0x29,0x0a,0x6f,0x75,0x74,0x70,0x75, + 0x74,0x5b,0x6f,0x75,0x74,0x49,0x64,0x78,0x5d,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a, + 0x7d,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45, + 0x29,0x3b,0x0a,0x7d,0x0a,0x00 +}; + +} // namespace xmrig diff --git a/src/backend/opencl/cl/cn/cryptonight_r.cl b/src/backend/opencl/cl/cn/cryptonight_r.cl new file mode 100644 index 000000000..0b7b7dae8 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_r.cl @@ -0,0 +1,144 @@ +__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) +__kernel void KERNEL_NAME(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +{ + ulong a[2], b[4]; + __local uint AES0[256], AES1[256], AES2[256], AES3[256]; + + const ulong gIdx = get_global_id(0) - get_global_offset(0); + + for(int i = get_local_id(0); i < 256; i += WORKSIZE) { + const uint tmp = AES0_C[i]; + AES0[i] = tmp; + AES1[i] = rotate(tmp, 8U); + AES2[i] = rotate(tmp, 16U); + AES3[i] = rotate(tmp, 24U); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + { + states += 25 * gIdx; + +# if defined(__NV_CL_C_VERSION) + Scratchpad += gIdx * (ITERATIONS >> 2); +# else +# if (STRIDED_INDEX == 0) + Scratchpad += gIdx * (MEMORY >> 4); +# elif (STRIDED_INDEX == 1) + Scratchpad += gIdx; +# elif (STRIDED_INDEX == 2) + Scratchpad += get_group_id(0) * (MEMORY >> 4) * WORKSIZE + MEM_CHUNK * get_local_id(0); +# endif +# endif + + a[0] = states[0] ^ states[4]; + a[1] = states[1] ^ states[5]; + + b[0] = states[2] ^ states[6]; + b[1] = states[3] ^ states[7]; + b[2] = states[8] ^ states[10]; + b[3] = states[9] ^ states[11]; + } + + ulong2 bx0 = ((ulong2 *)b)[0]; + ulong2 bx1 = ((ulong2 *)b)[1]; + + mem_fence(CLK_LOCAL_MEM_FENCE); + +# ifdef __NV_CL_C_VERSION + __local uint16 scratchpad_line_buf[WORKSIZE]; + __local uint16* scratchpad_line = scratchpad_line_buf + get_local_id(0); +# endif + + { + uint r0 = as_uint2(states[12]).s0; + uint r1 = as_uint2(states[12]).s1; + uint r2 = as_uint2(states[13]).s0; + uint r3 = as_uint2(states[13]).s1; + + #pragma unroll CN_UNROLL + for (int i = 0; i < ITERATIONS; ++i) { +# ifdef __NV_CL_C_VERSION + uint idx = a[0] & 0x1FFFC0; + uint idx1 = a[0] & 0x30; + + *scratchpad_line = *(__global uint16*)((__global uchar*)(Scratchpad) + idx); +# else + uint idx = a[0] & MASK; +# endif + + uint4 c = SCRATCHPAD_CHUNK(0); + c = AES_Round(AES0, AES1, AES2, AES3, c, ((uint4 *)a)[0]); + + { + const ulong2 chunk1 = as_ulong2(SCRATCHPAD_CHUNK(1)); + const ulong2 chunk2 = as_ulong2(SCRATCHPAD_CHUNK(2)); + const ulong2 chunk3 = as_ulong2(SCRATCHPAD_CHUNK(3)); + + c ^= as_uint4(chunk1) ^ as_uint4(chunk2) ^ as_uint4(chunk3); + + SCRATCHPAD_CHUNK(1) = as_uint4(chunk3 + bx1); + SCRATCHPAD_CHUNK(2) = as_uint4(chunk1 + bx0); + SCRATCHPAD_CHUNK(3) = as_uint4(chunk2 + ((ulong2 *)a)[0]); + } + + SCRATCHPAD_CHUNK(0) = as_uint4(bx0) ^ c; + +# ifdef __NV_CL_C_VERSION + *(__global uint16*)((__global uchar*)(Scratchpad) + idx) = *scratchpad_line; + + idx = as_ulong2(c).s0 & 0x1FFFC0; + idx1 = as_ulong2(c).s0 & 0x30; + + *scratchpad_line = *(__global uint16*)((__global uchar*)(Scratchpad) + idx); +# else + idx = as_ulong2(c).s0 & MASK; +# endif + + uint4 tmp = SCRATCHPAD_CHUNK(0); + + tmp.s0 ^= r0 + r1; + tmp.s1 ^= r2 + r3; + const uint r4 = as_uint2(a[0]).s0; + const uint r5 = as_uint2(a[1]).s0; + const uint r6 = as_uint4(bx0).s0; + const uint r7 = as_uint4(bx1).s0; + const uint r8 = as_uint4(bx1).s2; + +XMRIG_INCLUDE_RANDOM_MATH + + const uint2 al = (uint2)(as_uint2(a[0]).s0 ^ r2, as_uint2(a[0]).s1 ^ r3); + const uint2 ah = (uint2)(as_uint2(a[1]).s0 ^ r0, as_uint2(a[1]).s1 ^ r1); + + ulong2 t; + t.s0 = mul_hi(as_ulong2(c).s0, as_ulong2(tmp).s0); + t.s1 = as_ulong2(c).s0 * as_ulong2(tmp).s0; + { + const ulong2 chunk1 = as_ulong2(SCRATCHPAD_CHUNK(1)); + const ulong2 chunk2 = as_ulong2(SCRATCHPAD_CHUNK(2)); + const ulong2 chunk3 = as_ulong2(SCRATCHPAD_CHUNK(3)); + + c ^= as_uint4(chunk1) ^ as_uint4(chunk2) ^ as_uint4(chunk3); + + SCRATCHPAD_CHUNK(1) = as_uint4(chunk3 + bx1); + SCRATCHPAD_CHUNK(2) = as_uint4(chunk1 + bx0); + SCRATCHPAD_CHUNK(3) = as_uint4(chunk2 + ((ulong2 *)a)[0]); + } + + a[1] = as_ulong(ah) + t.s1; + a[0] = as_ulong(al) + t.s0; + + SCRATCHPAD_CHUNK(0) = ((uint4 *)a)[0]; + +# ifdef __NV_CL_C_VERSION + *(__global uint16*)((__global uchar*)(Scratchpad) + idx) = *scratchpad_line; +# endif + + ((uint4 *)a)[0] ^= tmp; + bx1 = bx0; + bx0 = as_ulong2(c); + } + } + + mem_fence(CLK_GLOBAL_MEM_FENCE); +} diff --git a/src/backend/opencl/cl/cn/cryptonight_r_cl.h b/src/backend/opencl/cl/cn/cryptonight_r_cl.h new file mode 100644 index 000000000..62da38098 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_r_cl.h @@ -0,0 +1,359 @@ +#pragma once + +namespace xmrig { + +static char cryptonight_r_defines_cl[7709] = { + 0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x29,0x20,0x2b,0x20,0x28,0x69,0x64,0x78,0x31,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0a, + 0x23,0x65,0x6c,0x73,0x65,0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29, + 0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x20,0x2b,0x20,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29, + 0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53, + 0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x20,0x2b,0x20,0x6d,0x75,0x6c,0x32,0x34,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x69,0x64,0x78,0x20,0x5e, + 0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x2c,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x29,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54, + 0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x4e,0x29,0x20,0x28,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a, + 0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x20, + 0x2b,0x20,0x28,0x28,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x25,0x20,0x28,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e, + 0x4b,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x2b,0x20,0x28,0x28,0x69,0x64,0x78,0x20,0x5e,0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x2f,0x20,0x28, + 0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x20,0x2a,0x20,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x28,0x4d, + 0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x54,0x5f,0x42,0x49,0x54,0x53,0x20,0x33,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4d,0x45,0x4d,0x5f, + 0x43,0x48,0x55,0x4e,0x4b,0x20,0x28,0x31,0x20,0x3c,0x3c,0x20,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x5f,0x45,0x58,0x50,0x4f,0x4e,0x45,0x4e,0x54,0x29,0x0a, + 0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x57,0x4f,0x4c,0x46,0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x4f,0x4c,0x46, + 0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32, + 0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64, + 0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32,0x20,0x3a,0x20,0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x78,0x6d,0x72, + 0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x20,0x61,0x6d,0x64, + 0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x6c, + 0x69,0x6e,0x65,0x20,0x69,0x6e,0x74,0x20,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d,0x64,0x5f,0x62,0x66,0x65,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x73,0x72,0x63,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x2b,0x77,0x69,0x64,0x74,0x68,0x29,0x3c,0x33,0x32, + 0x75,0x29,0x20,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x73,0x72,0x63,0x30,0x3c,0x3c,0x28,0x33,0x32,0x75,0x2d,0x6f,0x66,0x66,0x73,0x65,0x74,0x2d,0x77, + 0x69,0x64,0x74,0x68,0x29,0x29,0x3e,0x3e,0x28,0x33,0x32,0x75,0x2d,0x77,0x69,0x64,0x74,0x68,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x73,0x72, + 0x63,0x30,0x3e,0x3e,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x32,0x35,0x36,0x5d,0x20,0x3d,0x0a, + 0x7b,0x0a,0x30,0x78,0x41,0x35,0x36,0x33,0x36,0x33,0x43,0x36,0x55,0x2c,0x30,0x78,0x38,0x34,0x37,0x43,0x37,0x43,0x46,0x38,0x55,0x2c,0x30,0x78,0x39,0x39,0x37,0x37, + 0x37,0x37,0x45,0x45,0x55,0x2c,0x30,0x78,0x38,0x44,0x37,0x42,0x37,0x42,0x46,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x44,0x46,0x32,0x46,0x32,0x46,0x46,0x55,0x2c,0x30, + 0x78,0x42,0x44,0x36,0x42,0x36,0x42,0x44,0x36,0x55,0x2c,0x30,0x78,0x42,0x31,0x36,0x46,0x36,0x46,0x44,0x45,0x55,0x2c,0x30,0x78,0x35,0x34,0x43,0x35,0x43,0x35,0x39, + 0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x55,0x2c,0x30,0x78,0x41,0x39, + 0x36,0x37,0x36,0x37,0x43,0x45,0x55,0x2c,0x30,0x78,0x37,0x44,0x32,0x42,0x32,0x42,0x35,0x36,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x46,0x45,0x46,0x45,0x45,0x37,0x55, + 0x2c,0x30,0x78,0x36,0x32,0x44,0x37,0x44,0x37,0x42,0x35,0x55,0x2c,0x30,0x78,0x45,0x36,0x41,0x42,0x41,0x42,0x34,0x44,0x55,0x2c,0x30,0x78,0x39,0x41,0x37,0x36,0x37, + 0x36,0x45,0x43,0x55,0x2c,0x0a,0x30,0x78,0x34,0x35,0x43,0x41,0x43,0x41,0x38,0x46,0x55,0x2c,0x30,0x78,0x39,0x44,0x38,0x32,0x38,0x32,0x31,0x46,0x55,0x2c,0x30,0x78, + 0x34,0x30,0x43,0x39,0x43,0x39,0x38,0x39,0x55,0x2c,0x30,0x78,0x38,0x37,0x37,0x44,0x37,0x44,0x46,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x35,0x46,0x41,0x46,0x41,0x45, + 0x46,0x55,0x2c,0x30,0x78,0x45,0x42,0x35,0x39,0x35,0x39,0x42,0x32,0x55,0x2c,0x30,0x78,0x43,0x39,0x34,0x37,0x34,0x37,0x38,0x45,0x55,0x2c,0x30,0x78,0x30,0x42,0x46, + 0x30,0x46,0x30,0x46,0x42,0x55,0x2c,0x0a,0x30,0x78,0x45,0x43,0x41,0x44,0x41,0x44,0x34,0x31,0x55,0x2c,0x30,0x78,0x36,0x37,0x44,0x34,0x44,0x34,0x42,0x33,0x55,0x2c, + 0x30,0x78,0x46,0x44,0x41,0x32,0x41,0x32,0x35,0x46,0x55,0x2c,0x30,0x78,0x45,0x41,0x41,0x46,0x41,0x46,0x34,0x35,0x55,0x2c,0x0a,0x30,0x78,0x42,0x46,0x39,0x43,0x39, + 0x43,0x32,0x33,0x55,0x2c,0x30,0x78,0x46,0x37,0x41,0x34,0x41,0x34,0x35,0x33,0x55,0x2c,0x30,0x78,0x39,0x36,0x37,0x32,0x37,0x32,0x45,0x34,0x55,0x2c,0x30,0x78,0x35, + 0x42,0x43,0x30,0x43,0x30,0x39,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x32,0x42,0x37,0x42,0x37,0x37,0x35,0x55,0x2c,0x30,0x78,0x31,0x43,0x46,0x44,0x46,0x44,0x45,0x31, + 0x55,0x2c,0x30,0x78,0x41,0x45,0x39,0x33,0x39,0x33,0x33,0x44,0x55,0x2c,0x30,0x78,0x36,0x41,0x32,0x36,0x32,0x36,0x34,0x43,0x55,0x2c,0x0a,0x30,0x78,0x35,0x41,0x33, + 0x36,0x33,0x36,0x36,0x43,0x55,0x2c,0x30,0x78,0x34,0x31,0x33,0x46,0x33,0x46,0x37,0x45,0x55,0x2c,0x30,0x78,0x30,0x32,0x46,0x37,0x46,0x37,0x46,0x35,0x55,0x2c,0x30, + 0x78,0x34,0x46,0x43,0x43,0x43,0x43,0x38,0x33,0x55,0x2c,0x0a,0x30,0x78,0x35,0x43,0x33,0x34,0x33,0x34,0x36,0x38,0x55,0x2c,0x30,0x78,0x46,0x34,0x41,0x35,0x41,0x35, + 0x35,0x31,0x55,0x2c,0x30,0x78,0x33,0x34,0x45,0x35,0x45,0x35,0x44,0x31,0x55,0x2c,0x30,0x78,0x30,0x38,0x46,0x31,0x46,0x31,0x46,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39, + 0x33,0x37,0x31,0x37,0x31,0x45,0x32,0x55,0x2c,0x30,0x78,0x37,0x33,0x44,0x38,0x44,0x38,0x41,0x42,0x55,0x2c,0x30,0x78,0x35,0x33,0x33,0x31,0x33,0x31,0x36,0x32,0x55, + 0x2c,0x30,0x78,0x33,0x46,0x31,0x35,0x31,0x35,0x32,0x41,0x55,0x2c,0x0a,0x30,0x78,0x30,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x55,0x2c,0x30,0x78,0x35,0x32,0x43,0x37, + 0x43,0x37,0x39,0x35,0x55,0x2c,0x30,0x78,0x36,0x35,0x32,0x33,0x32,0x33,0x34,0x36,0x55,0x2c,0x30,0x78,0x35,0x45,0x43,0x33,0x43,0x33,0x39,0x44,0x55,0x2c,0x0a,0x30, + 0x78,0x32,0x38,0x31,0x38,0x31,0x38,0x33,0x30,0x55,0x2c,0x30,0x78,0x41,0x31,0x39,0x36,0x39,0x36,0x33,0x37,0x55,0x2c,0x30,0x78,0x30,0x46,0x30,0x35,0x30,0x35,0x30, + 0x41,0x55,0x2c,0x30,0x78,0x42,0x35,0x39,0x41,0x39,0x41,0x32,0x46,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x55,0x2c,0x30,0x78,0x33,0x36, + 0x31,0x32,0x31,0x32,0x32,0x34,0x55,0x2c,0x30,0x78,0x39,0x42,0x38,0x30,0x38,0x30,0x31,0x42,0x55,0x2c,0x30,0x78,0x33,0x44,0x45,0x32,0x45,0x32,0x44,0x46,0x55,0x2c, + 0x0a,0x30,0x78,0x32,0x36,0x45,0x42,0x45,0x42,0x43,0x44,0x55,0x2c,0x30,0x78,0x36,0x39,0x32,0x37,0x32,0x37,0x34,0x45,0x55,0x2c,0x30,0x78,0x43,0x44,0x42,0x32,0x42, + 0x32,0x37,0x46,0x55,0x2c,0x30,0x78,0x39,0x46,0x37,0x35,0x37,0x35,0x45,0x41,0x55,0x2c,0x0a,0x30,0x78,0x31,0x42,0x30,0x39,0x30,0x39,0x31,0x32,0x55,0x2c,0x30,0x78, + 0x39,0x45,0x38,0x33,0x38,0x33,0x31,0x44,0x55,0x2c,0x30,0x78,0x37,0x34,0x32,0x43,0x32,0x43,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x45,0x31,0x41,0x31,0x41,0x33,0x34, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x44,0x31,0x42,0x31,0x42,0x33,0x36,0x55,0x2c,0x30,0x78,0x42,0x32,0x36,0x45,0x36,0x45,0x44,0x43,0x55,0x2c,0x30,0x78,0x45,0x45,0x35, + 0x41,0x35,0x41,0x42,0x34,0x55,0x2c,0x30,0x78,0x46,0x42,0x41,0x30,0x41,0x30,0x35,0x42,0x55,0x2c,0x0a,0x30,0x78,0x46,0x36,0x35,0x32,0x35,0x32,0x41,0x34,0x55,0x2c, + 0x30,0x78,0x34,0x44,0x33,0x42,0x33,0x42,0x37,0x36,0x55,0x2c,0x30,0x78,0x36,0x31,0x44,0x36,0x44,0x36,0x42,0x37,0x55,0x2c,0x30,0x78,0x43,0x45,0x42,0x33,0x42,0x33, + 0x37,0x44,0x55,0x2c,0x0a,0x30,0x78,0x37,0x42,0x32,0x39,0x32,0x39,0x35,0x32,0x55,0x2c,0x30,0x78,0x33,0x45,0x45,0x33,0x45,0x33,0x44,0x44,0x55,0x2c,0x30,0x78,0x37, + 0x31,0x32,0x46,0x32,0x46,0x35,0x45,0x55,0x2c,0x30,0x78,0x39,0x37,0x38,0x34,0x38,0x34,0x31,0x33,0x55,0x2c,0x0a,0x30,0x78,0x46,0x35,0x35,0x33,0x35,0x33,0x41,0x36, + 0x55,0x2c,0x30,0x78,0x36,0x38,0x44,0x31,0x44,0x31,0x42,0x39,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x32,0x43,0x45,0x44, + 0x45,0x44,0x43,0x31,0x55,0x2c,0x0a,0x30,0x78,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x31,0x46,0x46,0x43,0x46,0x43,0x45,0x33,0x55,0x2c,0x30, + 0x78,0x43,0x38,0x42,0x31,0x42,0x31,0x37,0x39,0x55,0x2c,0x30,0x78,0x45,0x44,0x35,0x42,0x35,0x42,0x42,0x36,0x55,0x2c,0x0a,0x30,0x78,0x42,0x45,0x36,0x41,0x36,0x41, + 0x44,0x34,0x55,0x2c,0x30,0x78,0x34,0x36,0x43,0x42,0x43,0x42,0x38,0x44,0x55,0x2c,0x30,0x78,0x44,0x39,0x42,0x45,0x42,0x45,0x36,0x37,0x55,0x2c,0x30,0x78,0x34,0x42, + 0x33,0x39,0x33,0x39,0x37,0x32,0x55,0x2c,0x0a,0x30,0x78,0x44,0x45,0x34,0x41,0x34,0x41,0x39,0x34,0x55,0x2c,0x30,0x78,0x44,0x34,0x34,0x43,0x34,0x43,0x39,0x38,0x55, + 0x2c,0x30,0x78,0x45,0x38,0x35,0x38,0x35,0x38,0x42,0x30,0x55,0x2c,0x30,0x78,0x34,0x41,0x43,0x46,0x43,0x46,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x42,0x44,0x30, + 0x44,0x30,0x42,0x42,0x55,0x2c,0x30,0x78,0x32,0x41,0x45,0x46,0x45,0x46,0x43,0x35,0x55,0x2c,0x30,0x78,0x45,0x35,0x41,0x41,0x41,0x41,0x34,0x46,0x55,0x2c,0x30,0x78, + 0x31,0x36,0x46,0x42,0x46,0x42,0x45,0x44,0x55,0x2c,0x0a,0x30,0x78,0x43,0x35,0x34,0x33,0x34,0x33,0x38,0x36,0x55,0x2c,0x30,0x78,0x44,0x37,0x34,0x44,0x34,0x44,0x39, + 0x41,0x55,0x2c,0x30,0x78,0x35,0x35,0x33,0x33,0x33,0x33,0x36,0x36,0x55,0x2c,0x30,0x78,0x39,0x34,0x38,0x35,0x38,0x35,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78,0x43,0x46, + 0x34,0x35,0x34,0x35,0x38,0x41,0x55,0x2c,0x30,0x78,0x31,0x30,0x46,0x39,0x46,0x39,0x45,0x39,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x55,0x2c, + 0x30,0x78,0x38,0x31,0x37,0x46,0x37,0x46,0x46,0x45,0x55,0x2c,0x0a,0x30,0x78,0x46,0x30,0x35,0x30,0x35,0x30,0x41,0x30,0x55,0x2c,0x30,0x78,0x34,0x34,0x33,0x43,0x33, + 0x43,0x37,0x38,0x55,0x2c,0x30,0x78,0x42,0x41,0x39,0x46,0x39,0x46,0x32,0x35,0x55,0x2c,0x30,0x78,0x45,0x33,0x41,0x38,0x41,0x38,0x34,0x42,0x55,0x2c,0x0a,0x30,0x78, + 0x46,0x33,0x35,0x31,0x35,0x31,0x41,0x32,0x55,0x2c,0x30,0x78,0x46,0x45,0x41,0x33,0x41,0x33,0x35,0x44,0x55,0x2c,0x30,0x78,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x30, + 0x55,0x2c,0x30,0x78,0x38,0x41,0x38,0x46,0x38,0x46,0x30,0x35,0x55,0x2c,0x0a,0x30,0x78,0x41,0x44,0x39,0x32,0x39,0x32,0x33,0x46,0x55,0x2c,0x30,0x78,0x42,0x43,0x39, + 0x44,0x39,0x44,0x32,0x31,0x55,0x2c,0x30,0x78,0x34,0x38,0x33,0x38,0x33,0x38,0x37,0x30,0x55,0x2c,0x30,0x78,0x30,0x34,0x46,0x35,0x46,0x35,0x46,0x31,0x55,0x2c,0x0a, + 0x30,0x78,0x44,0x46,0x42,0x43,0x42,0x43,0x36,0x33,0x55,0x2c,0x30,0x78,0x43,0x31,0x42,0x36,0x42,0x36,0x37,0x37,0x55,0x2c,0x30,0x78,0x37,0x35,0x44,0x41,0x44,0x41, + 0x41,0x46,0x55,0x2c,0x30,0x78,0x36,0x33,0x32,0x31,0x32,0x31,0x34,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x31, + 0x41,0x46,0x46,0x46,0x46,0x45,0x35,0x55,0x2c,0x30,0x78,0x30,0x45,0x46,0x33,0x46,0x33,0x46,0x44,0x55,0x2c,0x30,0x78,0x36,0x44,0x44,0x32,0x44,0x32,0x42,0x46,0x55, + 0x2c,0x0a,0x30,0x78,0x34,0x43,0x43,0x44,0x43,0x44,0x38,0x31,0x55,0x2c,0x30,0x78,0x31,0x34,0x30,0x43,0x30,0x43,0x31,0x38,0x55,0x2c,0x30,0x78,0x33,0x35,0x31,0x33, + 0x31,0x33,0x32,0x36,0x55,0x2c,0x30,0x78,0x32,0x46,0x45,0x43,0x45,0x43,0x43,0x33,0x55,0x2c,0x0a,0x30,0x78,0x45,0x31,0x35,0x46,0x35,0x46,0x42,0x45,0x55,0x2c,0x30, + 0x78,0x41,0x32,0x39,0x37,0x39,0x37,0x33,0x35,0x55,0x2c,0x30,0x78,0x43,0x43,0x34,0x34,0x34,0x34,0x38,0x38,0x55,0x2c,0x30,0x78,0x33,0x39,0x31,0x37,0x31,0x37,0x32, + 0x45,0x55,0x2c,0x0a,0x30,0x78,0x35,0x37,0x43,0x34,0x43,0x34,0x39,0x33,0x55,0x2c,0x30,0x78,0x46,0x32,0x41,0x37,0x41,0x37,0x35,0x35,0x55,0x2c,0x30,0x78,0x38,0x32, + 0x37,0x45,0x37,0x45,0x46,0x43,0x55,0x2c,0x30,0x78,0x34,0x37,0x33,0x44,0x33,0x44,0x37,0x41,0x55,0x2c,0x0a,0x30,0x78,0x41,0x43,0x36,0x34,0x36,0x34,0x43,0x38,0x55, + 0x2c,0x30,0x78,0x45,0x37,0x35,0x44,0x35,0x44,0x42,0x41,0x55,0x2c,0x30,0x78,0x32,0x42,0x31,0x39,0x31,0x39,0x33,0x32,0x55,0x2c,0x30,0x78,0x39,0x35,0x37,0x33,0x37, + 0x33,0x45,0x36,0x55,0x2c,0x0a,0x30,0x78,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x30,0x55,0x2c,0x30,0x78,0x39,0x38,0x38,0x31,0x38,0x31,0x31,0x39,0x55,0x2c,0x30,0x78, + 0x44,0x31,0x34,0x46,0x34,0x46,0x39,0x45,0x55,0x2c,0x30,0x78,0x37,0x46,0x44,0x43,0x44,0x43,0x41,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x36,0x32,0x32,0x32,0x32,0x34, + 0x34,0x55,0x2c,0x30,0x78,0x37,0x45,0x32,0x41,0x32,0x41,0x35,0x34,0x55,0x2c,0x30,0x78,0x41,0x42,0x39,0x30,0x39,0x30,0x33,0x42,0x55,0x2c,0x30,0x78,0x38,0x33,0x38, + 0x38,0x38,0x38,0x30,0x42,0x55,0x2c,0x0a,0x30,0x78,0x43,0x41,0x34,0x36,0x34,0x36,0x38,0x43,0x55,0x2c,0x30,0x78,0x32,0x39,0x45,0x45,0x45,0x45,0x43,0x37,0x55,0x2c, + 0x30,0x78,0x44,0x33,0x42,0x38,0x42,0x38,0x36,0x42,0x55,0x2c,0x30,0x78,0x33,0x43,0x31,0x34,0x31,0x34,0x32,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x39,0x44,0x45,0x44, + 0x45,0x41,0x37,0x55,0x2c,0x30,0x78,0x45,0x32,0x35,0x45,0x35,0x45,0x42,0x43,0x55,0x2c,0x30,0x78,0x31,0x44,0x30,0x42,0x30,0x42,0x31,0x36,0x55,0x2c,0x30,0x78,0x37, + 0x36,0x44,0x42,0x44,0x42,0x41,0x44,0x55,0x2c,0x0a,0x30,0x78,0x33,0x42,0x45,0x30,0x45,0x30,0x44,0x42,0x55,0x2c,0x30,0x78,0x35,0x36,0x33,0x32,0x33,0x32,0x36,0x34, + 0x55,0x2c,0x30,0x78,0x34,0x45,0x33,0x41,0x33,0x41,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x45,0x30,0x41,0x30,0x41,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x44,0x42,0x34, + 0x39,0x34,0x39,0x39,0x32,0x55,0x2c,0x30,0x78,0x30,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x55,0x2c,0x30,0x78,0x36,0x43,0x32,0x34,0x32,0x34,0x34,0x38,0x55,0x2c,0x30, + 0x78,0x45,0x34,0x35,0x43,0x35,0x43,0x42,0x38,0x55,0x2c,0x0a,0x30,0x78,0x35,0x44,0x43,0x32,0x43,0x32,0x39,0x46,0x55,0x2c,0x30,0x78,0x36,0x45,0x44,0x33,0x44,0x33, + 0x42,0x44,0x55,0x2c,0x30,0x78,0x45,0x46,0x41,0x43,0x41,0x43,0x34,0x33,0x55,0x2c,0x30,0x78,0x41,0x36,0x36,0x32,0x36,0x32,0x43,0x34,0x55,0x2c,0x0a,0x30,0x78,0x41, + 0x38,0x39,0x31,0x39,0x31,0x33,0x39,0x55,0x2c,0x30,0x78,0x41,0x34,0x39,0x35,0x39,0x35,0x33,0x31,0x55,0x2c,0x30,0x78,0x33,0x37,0x45,0x34,0x45,0x34,0x44,0x33,0x55, + 0x2c,0x30,0x78,0x38,0x42,0x37,0x39,0x37,0x39,0x46,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x32,0x45,0x37,0x45,0x37,0x44,0x35,0x55,0x2c,0x30,0x78,0x34,0x33,0x43,0x38, + 0x43,0x38,0x38,0x42,0x55,0x2c,0x30,0x78,0x35,0x39,0x33,0x37,0x33,0x37,0x36,0x45,0x55,0x2c,0x30,0x78,0x42,0x37,0x36,0x44,0x36,0x44,0x44,0x41,0x55,0x2c,0x0a,0x30, + 0x78,0x38,0x43,0x38,0x44,0x38,0x44,0x30,0x31,0x55,0x2c,0x30,0x78,0x36,0x34,0x44,0x35,0x44,0x35,0x42,0x31,0x55,0x2c,0x30,0x78,0x44,0x32,0x34,0x45,0x34,0x45,0x39, + 0x43,0x55,0x2c,0x30,0x78,0x45,0x30,0x41,0x39,0x41,0x39,0x34,0x39,0x55,0x2c,0x0a,0x30,0x78,0x42,0x34,0x36,0x43,0x36,0x43,0x44,0x38,0x55,0x2c,0x30,0x78,0x46,0x41, + 0x35,0x36,0x35,0x36,0x41,0x43,0x55,0x2c,0x30,0x78,0x30,0x37,0x46,0x34,0x46,0x34,0x46,0x33,0x55,0x2c,0x30,0x78,0x32,0x35,0x45,0x41,0x45,0x41,0x43,0x46,0x55,0x2c, + 0x0a,0x30,0x78,0x41,0x46,0x36,0x35,0x36,0x35,0x43,0x41,0x55,0x2c,0x30,0x78,0x38,0x45,0x37,0x41,0x37,0x41,0x46,0x34,0x55,0x2c,0x30,0x78,0x45,0x39,0x41,0x45,0x41, + 0x45,0x34,0x37,0x55,0x2c,0x30,0x78,0x31,0x38,0x30,0x38,0x30,0x38,0x31,0x30,0x55,0x2c,0x0a,0x30,0x78,0x44,0x35,0x42,0x41,0x42,0x41,0x36,0x46,0x55,0x2c,0x30,0x78, + 0x38,0x38,0x37,0x38,0x37,0x38,0x46,0x30,0x55,0x2c,0x30,0x78,0x36,0x46,0x32,0x35,0x32,0x35,0x34,0x41,0x55,0x2c,0x30,0x78,0x37,0x32,0x32,0x45,0x32,0x45,0x35,0x43, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x34,0x31,0x43,0x31,0x43,0x33,0x38,0x55,0x2c,0x30,0x78,0x46,0x31,0x41,0x36,0x41,0x36,0x35,0x37,0x55,0x2c,0x30,0x78,0x43,0x37,0x42, + 0x34,0x42,0x34,0x37,0x33,0x55,0x2c,0x30,0x78,0x35,0x31,0x43,0x36,0x43,0x36,0x39,0x37,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x45,0x38,0x45,0x38,0x43,0x42,0x55,0x2c, + 0x30,0x78,0x37,0x43,0x44,0x44,0x44,0x44,0x41,0x31,0x55,0x2c,0x30,0x78,0x39,0x43,0x37,0x34,0x37,0x34,0x45,0x38,0x55,0x2c,0x30,0x78,0x32,0x31,0x31,0x46,0x31,0x46, + 0x33,0x45,0x55,0x2c,0x0a,0x30,0x78,0x44,0x44,0x34,0x42,0x34,0x42,0x39,0x36,0x55,0x2c,0x30,0x78,0x44,0x43,0x42,0x44,0x42,0x44,0x36,0x31,0x55,0x2c,0x30,0x78,0x38, + 0x36,0x38,0x42,0x38,0x42,0x30,0x44,0x55,0x2c,0x30,0x78,0x38,0x35,0x38,0x41,0x38,0x41,0x30,0x46,0x55,0x2c,0x0a,0x30,0x78,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x30, + 0x55,0x2c,0x30,0x78,0x34,0x32,0x33,0x45,0x33,0x45,0x37,0x43,0x55,0x2c,0x30,0x78,0x43,0x34,0x42,0x35,0x42,0x35,0x37,0x31,0x55,0x2c,0x30,0x78,0x41,0x41,0x36,0x36, + 0x36,0x36,0x43,0x43,0x55,0x2c,0x0a,0x30,0x78,0x44,0x38,0x34,0x38,0x34,0x38,0x39,0x30,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x55,0x2c,0x30, + 0x78,0x30,0x31,0x46,0x36,0x46,0x36,0x46,0x37,0x55,0x2c,0x30,0x78,0x31,0x32,0x30,0x45,0x30,0x45,0x31,0x43,0x55,0x2c,0x0a,0x30,0x78,0x41,0x33,0x36,0x31,0x36,0x31, + 0x43,0x32,0x55,0x2c,0x30,0x78,0x35,0x46,0x33,0x35,0x33,0x35,0x36,0x41,0x55,0x2c,0x30,0x78,0x46,0x39,0x35,0x37,0x35,0x37,0x41,0x45,0x55,0x2c,0x30,0x78,0x44,0x30, + 0x42,0x39,0x42,0x39,0x36,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39,0x31,0x38,0x36,0x38,0x36,0x31,0x37,0x55,0x2c,0x30,0x78,0x35,0x38,0x43,0x31,0x43,0x31,0x39,0x39,0x55, + 0x2c,0x30,0x78,0x32,0x37,0x31,0x44,0x31,0x44,0x33,0x41,0x55,0x2c,0x30,0x78,0x42,0x39,0x39,0x45,0x39,0x45,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x38,0x45,0x31, + 0x45,0x31,0x44,0x39,0x55,0x2c,0x30,0x78,0x31,0x33,0x46,0x38,0x46,0x38,0x45,0x42,0x55,0x2c,0x30,0x78,0x42,0x33,0x39,0x38,0x39,0x38,0x32,0x42,0x55,0x2c,0x30,0x78, + 0x33,0x33,0x31,0x31,0x31,0x31,0x32,0x32,0x55,0x2c,0x0a,0x30,0x78,0x42,0x42,0x36,0x39,0x36,0x39,0x44,0x32,0x55,0x2c,0x30,0x78,0x37,0x30,0x44,0x39,0x44,0x39,0x41, + 0x39,0x55,0x2c,0x30,0x78,0x38,0x39,0x38,0x45,0x38,0x45,0x30,0x37,0x55,0x2c,0x30,0x78,0x41,0x37,0x39,0x34,0x39,0x34,0x33,0x33,0x55,0x2c,0x0a,0x30,0x78,0x42,0x36, + 0x39,0x42,0x39,0x42,0x32,0x44,0x55,0x2c,0x30,0x78,0x32,0x32,0x31,0x45,0x31,0x45,0x33,0x43,0x55,0x2c,0x30,0x78,0x39,0x32,0x38,0x37,0x38,0x37,0x31,0x35,0x55,0x2c, + 0x30,0x78,0x32,0x30,0x45,0x39,0x45,0x39,0x43,0x39,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x43,0x45,0x43,0x45,0x38,0x37,0x55,0x2c,0x30,0x78,0x46,0x46,0x35,0x35,0x35, + 0x35,0x41,0x41,0x55,0x2c,0x30,0x78,0x37,0x38,0x32,0x38,0x32,0x38,0x35,0x30,0x55,0x2c,0x30,0x78,0x37,0x41,0x44,0x46,0x44,0x46,0x41,0x35,0x55,0x2c,0x0a,0x30,0x78, + 0x38,0x46,0x38,0x43,0x38,0x43,0x30,0x33,0x55,0x2c,0x30,0x78,0x46,0x38,0x41,0x31,0x41,0x31,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x30,0x38,0x39,0x38,0x39,0x30,0x39, + 0x55,0x2c,0x30,0x78,0x31,0x37,0x30,0x44,0x30,0x44,0x31,0x41,0x55,0x2c,0x0a,0x30,0x78,0x44,0x41,0x42,0x46,0x42,0x46,0x36,0x35,0x55,0x2c,0x30,0x78,0x33,0x31,0x45, + 0x36,0x45,0x36,0x44,0x37,0x55,0x2c,0x30,0x78,0x43,0x36,0x34,0x32,0x34,0x32,0x38,0x34,0x55,0x2c,0x30,0x78,0x42,0x38,0x36,0x38,0x36,0x38,0x44,0x30,0x55,0x2c,0x0a, + 0x30,0x78,0x43,0x33,0x34,0x31,0x34,0x31,0x38,0x32,0x55,0x2c,0x30,0x78,0x42,0x30,0x39,0x39,0x39,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x37,0x37,0x32,0x44,0x32,0x44, + 0x35,0x41,0x55,0x2c,0x30,0x78,0x31,0x31,0x30,0x46,0x30,0x46,0x31,0x45,0x55,0x2c,0x0a,0x30,0x78,0x43,0x42,0x42,0x30,0x42,0x30,0x37,0x42,0x55,0x2c,0x30,0x78,0x46, + 0x43,0x35,0x34,0x35,0x34,0x41,0x38,0x55,0x2c,0x30,0x78,0x44,0x36,0x42,0x42,0x42,0x42,0x36,0x44,0x55,0x2c,0x30,0x78,0x33,0x41,0x31,0x36,0x31,0x36,0x32,0x43,0x55, + 0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x42,0x59,0x54,0x45,0x28,0x78,0x2c,0x20,0x79,0x29,0x20,0x28,0x78,0x6d,0x72,0x69,0x67,0x5f,0x61,0x6d, + 0x64,0x5f,0x62,0x66,0x65,0x28,0x28,0x78,0x29,0x2c,0x20,0x28,0x79,0x29,0x20,0x3c,0x3c,0x20,0x33,0x55,0x2c,0x20,0x38,0x55,0x29,0x29,0x0a,0x23,0x69,0x66,0x20,0x28, + 0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x29,0x0a,0x69,0x6e,0x6c,0x69, + 0x6e,0x65,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x62,0x69,0x74,0x74,0x75,0x62,0x65,0x32,0x28,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x29,0x0a,0x7b, + 0x0a,0x78,0x3d,0x7e,0x78,0x3b,0x0a,0x6b,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x30,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x33,0x29, + 0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x30,0x3b,0x0a,0x6b,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45, + 0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c, + 0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x6b, + 0x2e,0x73,0x31,0x3b,0x0a,0x6b,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e, + 0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42, + 0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x2c, + 0x31,0x36,0x55,0x29,0x3b,0x0a,0x78,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x32,0x3b,0x0a,0x6b,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x31,0x29, + 0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x3b,0x0a,0x7d, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45, + 0x53,0x32,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x33,0x2c,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20,0x5e,0x3d, + 0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e, + 0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42, + 0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54, + 0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45, + 0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c, + 0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x30,0x29, + 0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58, + 0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x2e, + 0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x31,0x29,0x5d,0x5e,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41, + 0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b,0x0a,0x7d, + 0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e,0x64,0x5f,0x54,0x77,0x6f,0x5f,0x54,0x61,0x62,0x6c,0x65,0x73,0x28,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x30,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x2a,0x41,0x45,0x53,0x31,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x75,0x69,0x6e,0x74, + 0x34,0x20,0x6b,0x65,0x79,0x29,0x0a,0x7b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73, + 0x30,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73, + 0x33,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x58,0x2e,0x73,0x31,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x31,0x29,0x5d,0x5e,0x72,0x6f,0x74,0x61, + 0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28, + 0x58,0x2e,0x73,0x30,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x31,0x29,0x5d,0x5e,0x72, + 0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59, + 0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x6b,0x65,0x79,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x30,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x31,0x29, + 0x5d,0x5e,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x32,0x29,0x5d,0x5e,0x41,0x45,0x53,0x31, + 0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x33,0x29,0x5d,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b, + 0x0a,0x7d,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68,0x61,0x72, + 0x20,0x72,0x63,0x6f,0x6e,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x30,0x78,0x38,0x64,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x30,0x32,0x2c,0x30,0x78,0x30,0x34,0x2c,0x30, + 0x78,0x30,0x38,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x34,0x30,0x20,0x7d,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x75,0x63,0x68,0x61,0x72,0x20,0x73,0x62,0x6f,0x78,0x5b,0x32,0x35,0x36,0x5d,0x20,0x3d,0x0a, + 0x7b,0x0a,0x30,0x78,0x36,0x33,0x2c,0x30,0x78,0x37,0x43,0x2c,0x30,0x78,0x37,0x37,0x2c,0x30,0x78,0x37,0x42,0x2c,0x30,0x78,0x46,0x32,0x2c,0x30,0x78,0x36,0x42,0x2c, + 0x30,0x78,0x36,0x46,0x2c,0x30,0x78,0x43,0x35,0x2c,0x30,0x78,0x33,0x30,0x2c,0x30,0x78,0x30,0x31,0x2c,0x30,0x78,0x36,0x37,0x2c,0x30,0x78,0x32,0x42,0x2c,0x30,0x78, + 0x46,0x45,0x2c,0x30,0x78,0x44,0x37,0x2c,0x30,0x78,0x41,0x42,0x2c,0x30,0x78,0x37,0x36,0x2c,0x0a,0x30,0x78,0x43,0x41,0x2c,0x30,0x78,0x38,0x32,0x2c,0x30,0x78,0x43, + 0x39,0x2c,0x30,0x78,0x37,0x44,0x2c,0x30,0x78,0x46,0x41,0x2c,0x30,0x78,0x35,0x39,0x2c,0x30,0x78,0x34,0x37,0x2c,0x30,0x78,0x46,0x30,0x2c,0x30,0x78,0x41,0x44,0x2c, + 0x30,0x78,0x44,0x34,0x2c,0x30,0x78,0x41,0x32,0x2c,0x30,0x78,0x41,0x46,0x2c,0x30,0x78,0x39,0x43,0x2c,0x30,0x78,0x41,0x34,0x2c,0x30,0x78,0x37,0x32,0x2c,0x30,0x78, + 0x43,0x30,0x2c,0x0a,0x30,0x78,0x42,0x37,0x2c,0x30,0x78,0x46,0x44,0x2c,0x30,0x78,0x39,0x33,0x2c,0x30,0x78,0x32,0x36,0x2c,0x30,0x78,0x33,0x36,0x2c,0x30,0x78,0x33, + 0x46,0x2c,0x30,0x78,0x46,0x37,0x2c,0x30,0x78,0x43,0x43,0x2c,0x30,0x78,0x33,0x34,0x2c,0x30,0x78,0x41,0x35,0x2c,0x30,0x78,0x45,0x35,0x2c,0x30,0x78,0x46,0x31,0x2c, + 0x30,0x78,0x37,0x31,0x2c,0x30,0x78,0x44,0x38,0x2c,0x30,0x78,0x33,0x31,0x2c,0x30,0x78,0x31,0x35,0x2c,0x0a,0x30,0x78,0x30,0x34,0x2c,0x30,0x78,0x43,0x37,0x2c,0x30, + 0x78,0x32,0x33,0x2c,0x30,0x78,0x43,0x33,0x2c,0x30,0x78,0x31,0x38,0x2c,0x30,0x78,0x39,0x36,0x2c,0x30,0x78,0x30,0x35,0x2c,0x30,0x78,0x39,0x41,0x2c,0x30,0x78,0x30, + 0x37,0x2c,0x30,0x78,0x31,0x32,0x2c,0x30,0x78,0x38,0x30,0x2c,0x30,0x78,0x45,0x32,0x2c,0x30,0x78,0x45,0x42,0x2c,0x30,0x78,0x32,0x37,0x2c,0x30,0x78,0x42,0x32,0x2c, + 0x30,0x78,0x37,0x35,0x2c,0x0a,0x30,0x78,0x30,0x39,0x2c,0x30,0x78,0x38,0x33,0x2c,0x30,0x78,0x32,0x43,0x2c,0x30,0x78,0x31,0x41,0x2c,0x30,0x78,0x31,0x42,0x2c,0x30, + 0x78,0x36,0x45,0x2c,0x30,0x78,0x35,0x41,0x2c,0x30,0x78,0x41,0x30,0x2c,0x30,0x78,0x35,0x32,0x2c,0x30,0x78,0x33,0x42,0x2c,0x30,0x78,0x44,0x36,0x2c,0x30,0x78,0x42, + 0x33,0x2c,0x30,0x78,0x32,0x39,0x2c,0x30,0x78,0x45,0x33,0x2c,0x30,0x78,0x32,0x46,0x2c,0x30,0x78,0x38,0x34,0x2c,0x0a,0x30,0x78,0x35,0x33,0x2c,0x30,0x78,0x44,0x31, + 0x2c,0x30,0x78,0x30,0x30,0x2c,0x30,0x78,0x45,0x44,0x2c,0x30,0x78,0x32,0x30,0x2c,0x30,0x78,0x46,0x43,0x2c,0x30,0x78,0x42,0x31,0x2c,0x30,0x78,0x35,0x42,0x2c,0x30, + 0x78,0x36,0x41,0x2c,0x30,0x78,0x43,0x42,0x2c,0x30,0x78,0x42,0x45,0x2c,0x30,0x78,0x33,0x39,0x2c,0x30,0x78,0x34,0x41,0x2c,0x30,0x78,0x34,0x43,0x2c,0x30,0x78,0x35, + 0x38,0x2c,0x30,0x78,0x43,0x46,0x2c,0x0a,0x30,0x78,0x44,0x30,0x2c,0x30,0x78,0x45,0x46,0x2c,0x30,0x78,0x41,0x41,0x2c,0x30,0x78,0x46,0x42,0x2c,0x30,0x78,0x34,0x33, + 0x2c,0x30,0x78,0x34,0x44,0x2c,0x30,0x78,0x33,0x33,0x2c,0x30,0x78,0x38,0x35,0x2c,0x30,0x78,0x34,0x35,0x2c,0x30,0x78,0x46,0x39,0x2c,0x30,0x78,0x30,0x32,0x2c,0x30, + 0x78,0x37,0x46,0x2c,0x30,0x78,0x35,0x30,0x2c,0x30,0x78,0x33,0x43,0x2c,0x30,0x78,0x39,0x46,0x2c,0x30,0x78,0x41,0x38,0x2c,0x0a,0x30,0x78,0x35,0x31,0x2c,0x30,0x78, + 0x41,0x33,0x2c,0x30,0x78,0x34,0x30,0x2c,0x30,0x78,0x38,0x46,0x2c,0x30,0x78,0x39,0x32,0x2c,0x30,0x78,0x39,0x44,0x2c,0x30,0x78,0x33,0x38,0x2c,0x30,0x78,0x46,0x35, + 0x2c,0x30,0x78,0x42,0x43,0x2c,0x30,0x78,0x42,0x36,0x2c,0x30,0x78,0x44,0x41,0x2c,0x30,0x78,0x32,0x31,0x2c,0x30,0x78,0x31,0x30,0x2c,0x30,0x78,0x46,0x46,0x2c,0x30, + 0x78,0x46,0x33,0x2c,0x30,0x78,0x44,0x32,0x2c,0x0a,0x30,0x78,0x43,0x44,0x2c,0x30,0x78,0x30,0x43,0x2c,0x30,0x78,0x31,0x33,0x2c,0x30,0x78,0x45,0x43,0x2c,0x30,0x78, + 0x35,0x46,0x2c,0x30,0x78,0x39,0x37,0x2c,0x30,0x78,0x34,0x34,0x2c,0x30,0x78,0x31,0x37,0x2c,0x30,0x78,0x43,0x34,0x2c,0x30,0x78,0x41,0x37,0x2c,0x30,0x78,0x37,0x45, + 0x2c,0x30,0x78,0x33,0x44,0x2c,0x30,0x78,0x36,0x34,0x2c,0x30,0x78,0x35,0x44,0x2c,0x30,0x78,0x31,0x39,0x2c,0x30,0x78,0x37,0x33,0x2c,0x0a,0x30,0x78,0x36,0x30,0x2c, + 0x30,0x78,0x38,0x31,0x2c,0x30,0x78,0x34,0x46,0x2c,0x30,0x78,0x44,0x43,0x2c,0x30,0x78,0x32,0x32,0x2c,0x30,0x78,0x32,0x41,0x2c,0x30,0x78,0x39,0x30,0x2c,0x30,0x78, + 0x38,0x38,0x2c,0x30,0x78,0x34,0x36,0x2c,0x30,0x78,0x45,0x45,0x2c,0x30,0x78,0x42,0x38,0x2c,0x30,0x78,0x31,0x34,0x2c,0x30,0x78,0x44,0x45,0x2c,0x30,0x78,0x35,0x45, + 0x2c,0x30,0x78,0x30,0x42,0x2c,0x30,0x78,0x44,0x42,0x2c,0x0a,0x30,0x78,0x45,0x30,0x2c,0x30,0x78,0x33,0x32,0x2c,0x30,0x78,0x33,0x41,0x2c,0x30,0x78,0x30,0x41,0x2c, + 0x30,0x78,0x34,0x39,0x2c,0x30,0x78,0x30,0x36,0x2c,0x30,0x78,0x32,0x34,0x2c,0x30,0x78,0x35,0x43,0x2c,0x30,0x78,0x43,0x32,0x2c,0x30,0x78,0x44,0x33,0x2c,0x30,0x78, + 0x41,0x43,0x2c,0x30,0x78,0x36,0x32,0x2c,0x30,0x78,0x39,0x31,0x2c,0x30,0x78,0x39,0x35,0x2c,0x30,0x78,0x45,0x34,0x2c,0x30,0x78,0x37,0x39,0x2c,0x0a,0x30,0x78,0x45, + 0x37,0x2c,0x30,0x78,0x43,0x38,0x2c,0x30,0x78,0x33,0x37,0x2c,0x30,0x78,0x36,0x44,0x2c,0x30,0x78,0x38,0x44,0x2c,0x30,0x78,0x44,0x35,0x2c,0x30,0x78,0x34,0x45,0x2c, + 0x30,0x78,0x41,0x39,0x2c,0x30,0x78,0x36,0x43,0x2c,0x30,0x78,0x35,0x36,0x2c,0x30,0x78,0x46,0x34,0x2c,0x30,0x78,0x45,0x41,0x2c,0x30,0x78,0x36,0x35,0x2c,0x30,0x78, + 0x37,0x41,0x2c,0x30,0x78,0x41,0x45,0x2c,0x30,0x78,0x30,0x38,0x2c,0x0a,0x30,0x78,0x42,0x41,0x2c,0x30,0x78,0x37,0x38,0x2c,0x30,0x78,0x32,0x35,0x2c,0x30,0x78,0x32, + 0x45,0x2c,0x30,0x78,0x31,0x43,0x2c,0x30,0x78,0x41,0x36,0x2c,0x30,0x78,0x42,0x34,0x2c,0x30,0x78,0x43,0x36,0x2c,0x30,0x78,0x45,0x38,0x2c,0x30,0x78,0x44,0x44,0x2c, + 0x30,0x78,0x37,0x34,0x2c,0x30,0x78,0x31,0x46,0x2c,0x30,0x78,0x34,0x42,0x2c,0x30,0x78,0x42,0x44,0x2c,0x30,0x78,0x38,0x42,0x2c,0x30,0x78,0x38,0x41,0x2c,0x0a,0x30, + 0x78,0x37,0x30,0x2c,0x30,0x78,0x33,0x45,0x2c,0x30,0x78,0x42,0x35,0x2c,0x30,0x78,0x36,0x36,0x2c,0x30,0x78,0x34,0x38,0x2c,0x30,0x78,0x30,0x33,0x2c,0x30,0x78,0x46, + 0x36,0x2c,0x30,0x78,0x30,0x45,0x2c,0x30,0x78,0x36,0x31,0x2c,0x30,0x78,0x33,0x35,0x2c,0x30,0x78,0x35,0x37,0x2c,0x30,0x78,0x42,0x39,0x2c,0x30,0x78,0x38,0x36,0x2c, + 0x30,0x78,0x43,0x31,0x2c,0x30,0x78,0x31,0x44,0x2c,0x30,0x78,0x39,0x45,0x2c,0x0a,0x30,0x78,0x45,0x31,0x2c,0x30,0x78,0x46,0x38,0x2c,0x30,0x78,0x39,0x38,0x2c,0x30, + 0x78,0x31,0x31,0x2c,0x30,0x78,0x36,0x39,0x2c,0x30,0x78,0x44,0x39,0x2c,0x30,0x78,0x38,0x45,0x2c,0x30,0x78,0x39,0x34,0x2c,0x30,0x78,0x39,0x42,0x2c,0x30,0x78,0x31, + 0x45,0x2c,0x30,0x78,0x38,0x37,0x2c,0x30,0x78,0x45,0x39,0x2c,0x30,0x78,0x43,0x45,0x2c,0x30,0x78,0x35,0x35,0x2c,0x30,0x78,0x32,0x38,0x2c,0x30,0x78,0x44,0x46,0x2c, + 0x0a,0x30,0x78,0x38,0x43,0x2c,0x30,0x78,0x41,0x31,0x2c,0x30,0x78,0x38,0x39,0x2c,0x30,0x78,0x30,0x44,0x2c,0x30,0x78,0x42,0x46,0x2c,0x30,0x78,0x45,0x36,0x2c,0x30, + 0x78,0x34,0x32,0x2c,0x30,0x78,0x36,0x38,0x2c,0x30,0x78,0x34,0x31,0x2c,0x30,0x78,0x39,0x39,0x2c,0x30,0x78,0x32,0x44,0x2c,0x30,0x78,0x30,0x46,0x2c,0x30,0x78,0x42, + 0x30,0x2c,0x30,0x78,0x35,0x34,0x2c,0x30,0x78,0x42,0x42,0x2c,0x30,0x78,0x31,0x36,0x0a,0x7d,0x3b,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x75,0x62,0x57, + 0x6f,0x72,0x64,0x28,0x69,0x6e,0x77,0x29,0x20,0x28,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x33,0x29,0x5d,0x20,0x3c,0x3c, + 0x20,0x32,0x34,0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x32,0x29,0x5d,0x20,0x3c,0x3c,0x20,0x31,0x36, + 0x29,0x20,0x7c,0x20,0x28,0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x31,0x29,0x5d,0x20,0x3c,0x3c,0x20,0x38,0x29,0x20,0x7c,0x20, + 0x73,0x62,0x6f,0x78,0x5b,0x42,0x59,0x54,0x45,0x28,0x69,0x6e,0x77,0x2c,0x20,0x30,0x29,0x5d,0x29,0x0a,0x76,0x6f,0x69,0x64,0x20,0x41,0x45,0x53,0x45,0x78,0x70,0x61, + 0x6e,0x64,0x4b,0x65,0x79,0x32,0x35,0x36,0x28,0x75,0x69,0x6e,0x74,0x20,0x2a,0x6b,0x65,0x79,0x62,0x75,0x66,0x29,0x0a,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69, + 0x6e,0x74,0x20,0x63,0x3d,0x38,0x2c,0x69,0x3d,0x31,0x3b,0x20,0x63,0x3c,0x34,0x30,0x3b,0x20,0x2b,0x2b,0x63,0x29,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x74,0x3d, + 0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x7c,0x7c,0x28,0x28,0x63,0x26,0x37,0x29,0x3d,0x3d,0x34,0x29,0x29,0x3f,0x53,0x75,0x62,0x57,0x6f,0x72,0x64,0x28,0x6b, + 0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x29,0x3a,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x31,0x5d,0x3b,0x0a,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b, + 0x63,0x5d,0x3d,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x2d,0x38,0x5d,0x5e,0x28,0x28,0x21,0x28,0x63,0x26,0x37,0x29,0x29,0x3f,0x72,0x6f,0x74,0x61,0x74,0x65,0x28, + 0x74,0x2c,0x32,0x34,0x55,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x28,0x28,0x75,0x63,0x68,0x61,0x72,0x34,0x29,0x28,0x72,0x63,0x6f,0x6e,0x5b,0x69,0x2b,0x2b, + 0x5d,0x2c,0x30,0x55,0x2c,0x30,0x55,0x2c,0x30,0x55,0x29,0x29,0x3a,0x74,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x00 +}; + +static char cryptonight_r_cl[3424] = { + 0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73, + 0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69, + 0x64,0x20,0x4b,0x45,0x52,0x4e,0x45,0x4c,0x5f,0x4e,0x41,0x4d,0x45,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x69,0x6e, + 0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x5f, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x54,0x68,0x72,0x65,0x61, + 0x64,0x73,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x5b,0x32,0x5d,0x2c,0x62,0x5b,0x34,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x30,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x31,0x5b,0x32,0x35,0x36,0x5d,0x2c,0x41,0x45,0x53,0x32,0x5b,0x32,0x35,0x36, + 0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x67,0x49,0x64,0x78,0x3d,0x67,0x65, + 0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74, + 0x28,0x30,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x20, + 0x69,0x3c,0x32,0x35,0x36,0x3b,0x20,0x69,0x2b,0x3d,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x74,0x6d,0x70,0x3d,0x41,0x45,0x53,0x30,0x5f,0x43,0x5b,0x69,0x5d,0x3b,0x0a,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x41,0x45,0x53, + 0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74, + 0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0a,0x41,0x45,0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70, + 0x2c,0x32,0x34,0x55,0x29,0x3b,0x0a,0x7d,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46, + 0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7b,0x0a,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x64,0x28,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x49,0x54,0x45,0x52,0x41,0x54,0x49,0x4f,0x4e,0x53,0x3e,0x3e,0x32,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65, + 0x0a,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x2a,0x28,0x4d,0x45,0x4d,0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53, + 0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x31,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67, + 0x49,0x64,0x78,0x3b,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x32,0x29,0x0a, + 0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x28,0x4d,0x45,0x4d, + 0x4f,0x52,0x59,0x3e,0x3e,0x34,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2b,0x4d,0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x2a,0x67,0x65,0x74,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x61,0x5b,0x30,0x5d,0x3d,0x73, + 0x74,0x61,0x74,0x65,0x73,0x5b,0x30,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x34,0x5d,0x3b,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b, + 0x31,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x35,0x5d,0x3b,0x0a,0x62,0x5b,0x30,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x32,0x5d,0x5e,0x73,0x74,0x61, + 0x74,0x65,0x73,0x5b,0x36,0x5d,0x3b,0x0a,0x62,0x5b,0x31,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x33,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x37,0x5d, + 0x3b,0x0a,0x62,0x5b,0x32,0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x38,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x62,0x5b,0x33, + 0x5d,0x3d,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x39,0x5d,0x5e,0x73,0x74,0x61,0x74,0x65,0x73,0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x7d,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32, + 0x20,0x62,0x78,0x30,0x3d,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x62,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x62,0x78, + 0x31,0x3d,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x62,0x29,0x5b,0x31,0x5d,0x3b,0x0a,0x6d,0x65,0x6d,0x5f,0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c, + 0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f, + 0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x20,0x73,0x63,0x72,0x61, + 0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x5f,0x62,0x75,0x66,0x5b,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x20,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3d,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x5f,0x62,0x75,0x66,0x2b,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a, + 0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x30,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61,0x74,0x65,0x73, + 0x5b,0x31,0x32,0x5d,0x29,0x2e,0x73,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x31,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61,0x74,0x65, + 0x73,0x5b,0x31,0x32,0x5d,0x29,0x2e,0x73,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x32,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61,0x74, + 0x65,0x73,0x5b,0x31,0x33,0x5d,0x29,0x2e,0x73,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x33,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x73,0x74,0x61, + 0x74,0x65,0x73,0x5b,0x31,0x33,0x5d,0x29,0x2e,0x73,0x31,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x43,0x4e,0x5f,0x55, + 0x4e,0x52,0x4f,0x4c,0x4c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x49,0x54,0x45,0x52,0x41,0x54,0x49,0x4f,0x4e,0x53, + 0x3b,0x20,0x2b,0x2b,0x69,0x29,0x20,0x7b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f, + 0x4e,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x30,0x78,0x31,0x46,0x46,0x46,0x43,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69, + 0x64,0x78,0x31,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x30,0x78,0x33,0x30,0x3b,0x0a,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3d, + 0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63, + 0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x75,0x69, + 0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x4d,0x41,0x53,0x4b,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x34,0x20,0x63, + 0x3d,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3b,0x0a,0x63,0x3d,0x41,0x45,0x53,0x5f,0x52,0x6f,0x75,0x6e, + 0x64,0x28,0x41,0x45,0x53,0x30,0x2c,0x41,0x45,0x53,0x31,0x2c,0x41,0x45,0x53,0x32,0x2c,0x41,0x45,0x53,0x33,0x2c,0x63,0x2c,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20, + 0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x31,0x3d, + 0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x29,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x32,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43, + 0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32, + 0x20,0x63,0x68,0x75,0x6e,0x6b,0x33,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55, + 0x4e,0x4b,0x28,0x33,0x29,0x29,0x3b,0x0a,0x63,0x20,0x5e,0x3d,0x20,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x29,0x5e,0x61,0x73, + 0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x32,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x33,0x29,0x3b, + 0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68, + 0x75,0x6e,0x6b,0x33,0x2b,0x62,0x78,0x31,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x3d,0x61, + 0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x2b,0x62,0x78,0x30,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f, + 0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x32,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67, + 0x32,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30, + 0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x62,0x78,0x30,0x29,0x5e,0x63,0x3b,0x0a,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43, + 0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28, + 0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64, + 0x78,0x29,0x3d,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3b,0x0a,0x69,0x64,0x78,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e, + 0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x30,0x78,0x31,0x46,0x46,0x46,0x43,0x30,0x3b,0x0a,0x69,0x64,0x78,0x31,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67, + 0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x30,0x78,0x33,0x30,0x3b,0x0a,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3d,0x2a, + 0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68, + 0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x64,0x78, + 0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x26,0x4d,0x41,0x53,0x4b,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69, + 0x6e,0x74,0x34,0x20,0x74,0x6d,0x70,0x3d,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3b,0x0a,0x74,0x6d,0x70, + 0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x72,0x30,0x2b,0x72,0x31,0x3b,0x0a,0x74,0x6d,0x70,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x72,0x32,0x2b,0x72,0x33,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x34,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x30,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x35,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b,0x31,0x5d,0x29,0x2e,0x73,0x30,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x36,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x62,0x78,0x30,0x29,0x2e,0x73,0x30,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x37,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x62,0x78,0x31,0x29,0x2e,0x73,0x30,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x72,0x38,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x62,0x78,0x31,0x29,0x2e,0x73,0x32,0x3b, + 0x0a,0x58,0x4d,0x52,0x49,0x47,0x5f,0x49,0x4e,0x43,0x4c,0x55,0x44,0x45,0x5f,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x5f,0x4d,0x41,0x54,0x48,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x61,0x6c,0x3d,0x28,0x75,0x69,0x6e,0x74,0x32,0x29,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b,0x30,0x5d,0x29, + 0x2e,0x73,0x30,0x5e,0x72,0x32,0x2c,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b,0x30,0x5d,0x29,0x2e,0x73,0x31,0x5e,0x72,0x33,0x29,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x61,0x68,0x3d,0x28,0x75,0x69,0x6e,0x74,0x32,0x29,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b, + 0x31,0x5d,0x29,0x2e,0x73,0x30,0x5e,0x72,0x30,0x2c,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x5b,0x31,0x5d,0x29,0x2e,0x73,0x31,0x5e,0x72,0x31,0x29,0x3b, + 0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x74,0x3b,0x0a,0x74,0x2e,0x73,0x30,0x3d,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32, + 0x28,0x63,0x29,0x2e,0x73,0x30,0x2c,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73,0x30,0x29,0x3b,0x0a,0x74,0x2e,0x73,0x31,0x3d, + 0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x2e,0x73,0x30,0x2a,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x74,0x6d,0x70,0x29,0x2e,0x73, + 0x30,0x3b,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x31,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e, + 0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x32,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41, + 0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x63,0x68,0x75,0x6e,0x6b,0x33, + 0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33,0x29,0x29,0x3b, + 0x0a,0x63,0x20,0x5e,0x3d,0x20,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28, + 0x63,0x68,0x75,0x6e,0x6b,0x32,0x29,0x5e,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x33,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x31,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x33,0x2b,0x62,0x78, + 0x31,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x32,0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34, + 0x28,0x63,0x68,0x75,0x6e,0x6b,0x31,0x2b,0x62,0x78,0x30,0x29,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x33, + 0x29,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x34,0x28,0x63,0x68,0x75,0x6e,0x6b,0x32,0x2b,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x2a,0x29,0x61,0x29,0x5b, + 0x30,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x61,0x5b,0x31,0x5d,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61,0x68,0x29,0x2b,0x74,0x2e,0x73,0x31,0x3b,0x0a,0x61, + 0x5b,0x30,0x5d,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61,0x6c,0x29,0x2b,0x74,0x2e,0x73,0x30,0x3b,0x0a,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41, + 0x44,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x28,0x30,0x29,0x3d,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x64, + 0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x31,0x36,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x63,0x68,0x61,0x72,0x2a,0x29,0x28,0x53,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x29,0x2b,0x69,0x64,0x78,0x29,0x3d,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3b,0x0a,0x23,0x65, + 0x6e,0x64,0x69,0x66,0x0a,0x28,0x28,0x75,0x69,0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x3b,0x0a,0x62,0x78,0x31, + 0x3d,0x62,0x78,0x30,0x3b,0x0a,0x62,0x78,0x30,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x6d,0x65,0x6d,0x5f, + 0x66,0x65,0x6e,0x63,0x65,0x28,0x43,0x4c,0x4b,0x5f,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x7d,0x0a,0x00 +}; + +} // namespace xmrig diff --git a/src/backend/opencl/cl/cn/cryptonight_r_defines.cl b/src/backend/opencl/cl/cn/cryptonight_r_defines.cl new file mode 100644 index 000000000..2d87d5427 --- /dev/null +++ b/src/backend/opencl/cl/cn/cryptonight_r_defines.cl @@ -0,0 +1,16 @@ +#ifdef __NV_CL_C_VERSION +# define SCRATCHPAD_CHUNK(N) (*(__local uint4*)((__local uchar*)(scratchpad_line) + (idx1 ^ (N << 4)))) +#else +# if (STRIDED_INDEX == 0) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + (idx ^ (N << 4)))) +# elif (STRIDED_INDEX == 1) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + mul24(as_uint(idx ^ (N << 4)), Threads))) +# elif (STRIDED_INDEX == 2) +# define SCRATCHPAD_CHUNK(N) (*(__global uint4*)((__global uchar*)(Scratchpad) + (((idx ^ (N << 4)) % (MEM_CHUNK << 4)) + ((idx ^ (N << 4)) / (MEM_CHUNK << 4)) * WORKSIZE * (MEM_CHUNK << 4)))) +# endif +#endif + +#define ROT_BITS 32 +#define MEM_CHUNK (1 << MEM_CHUNK_EXPONENT) + +#include "wolf-aes.cl" diff --git a/src/backend/opencl/cl/cn/fast_div_heavy.cl b/src/backend/opencl/cl/cn/fast_div_heavy.cl new file mode 100644 index 000000000..d5f1a40b6 --- /dev/null +++ b/src/backend/opencl/cl/cn/fast_div_heavy.cl @@ -0,0 +1,31 @@ +#ifndef FAST_DIV_HEAVY_CL +#define FAST_DIV_HEAVY_CL + +#if (ALGO_FAMILY == FAMILY_CN_HEAVY) + +inline long fast_div_heavy(long _a, int _b) +{ + long a = abs(_a); + int b = abs(_b); + + float rcp = native_recip(convert_float_rte(b)); + float rcp2 = as_float(as_uint(rcp) + (32U << 23)); + + ulong q1 = convert_ulong(convert_float_rte(as_int2(a).s1) * rcp2); + a -= q1 * as_uint(b); + + float q2f = convert_float_rte(as_int2(a >> 12).s0) * rcp; + q2f = as_float(as_uint(q2f) + (12U << 23)); + long q2 = convert_long_rte(q2f); + int a2 = as_int2(a).s0 - as_int2(q2).s0 * b; + + int q3 = convert_int_rte(convert_float_rte(a2) * rcp); + q3 += (a2 - q3 * b) >> 31; + + const long q = q1 + q2 + q3; + return ((as_int2(_a).s1 ^ _b) < 0) ? -q : q; +} + +#endif + +#endif diff --git a/src/backend/opencl/cl/cn/fast_int_math_v2.cl b/src/backend/opencl/cl/cn/fast_int_math_v2.cl new file mode 100644 index 000000000..2c9849110 --- /dev/null +++ b/src/backend/opencl/cl/cn/fast_int_math_v2.cl @@ -0,0 +1,56 @@ +/* + * @author SChernykh + */ + +#if (ALGO_BASE == ALGO_CN_2) +inline uint get_reciprocal(uint a) +{ + const float a_hi = as_float((a >> 8) + ((126U + 31U) << 23)); + const float a_lo = convert_float_rte(a & 0xFF); + + const float r = native_recip(a_hi); + const float r_scaled = as_float(as_uint(r) + (64U << 23)); + + const float h = fma(a_lo, r, fma(a_hi, r, -1.0f)); + return (as_uint(r) << 9) - convert_int_rte(h * r_scaled); +} + +inline uint2 fast_div_v2(ulong a, uint b) +{ + const uint r = get_reciprocal(b); + const ulong k = mul_hi(as_uint2(a).s0, r) + ((ulong)(r) * as_uint2(a).s1) + a; + + const uint q = as_uint2(k).s1; + long tmp = a - ((ulong)(q) * b); + ((int*)&tmp)[1] -= (as_uint2(k).s1 < as_uint2(a).s1) ? b : 0; + + const int overshoot = ((int*)&tmp)[1] >> 31; + const int undershoot = as_int2(as_uint(b - 1) - tmp).s1 >> 31; + return (uint2)(q + overshoot - undershoot, as_uint2(tmp).s0 + (as_uint(overshoot) & b) - (as_uint(undershoot) & b)); +} + +inline uint fast_sqrt_v2(const ulong n1) +{ + float x = as_float((as_uint2(n1).s1 >> 9) + ((64U + 127U) << 23)); + + float x1 = native_rsqrt(x); + x = native_sqrt(x); + + // The following line does x1 *= 4294967296.0f; + x1 = as_float(as_uint(x1) + (32U << 23)); + + const uint x0 = as_uint(x) - (158U << 23); + const long delta0 = n1 - (as_ulong((uint2)(mul24(x0, x0), mul_hi(x0, x0))) << 18); + const float delta = convert_float_rte(as_int2(delta0).s1) * x1; + + uint result = (x0 << 10) + convert_int_rte(delta); + const uint s = result >> 1; + const uint b = result & 1; + + const ulong x2 = (ulong)(s) * (s + b) + ((ulong)(result) << 32) - n1; + if ((long)(x2 + as_int(b - 1)) >= 0) --result; + if ((long)(x2 + 0x100000000UL + s) < 0) ++result; + + return result; +} +#endif diff --git a/src/backend/opencl/cl/cn/groestl256.cl b/src/backend/opencl/cl/cn/groestl256.cl new file mode 100644 index 000000000..1139c4d43 --- /dev/null +++ b/src/backend/opencl/cl/cn/groestl256.cl @@ -0,0 +1,289 @@ +/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */ +/* + * Groestl256 + * + * ==========================(LICENSE BEGIN)============================ + * Copyright (c) 2014 djm34 + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * 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. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#define SPH_C64(x) x +#define SPH_ROTL64(x, y) rotate((x), (ulong)(y)) + + +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) + +#define B64_0(x) ((x) & 0xFF) +#define B64_1(x) (((x) >> 8) & 0xFF) +#define B64_2(x) (((x) >> 16) & 0xFF) +#define B64_3(x) (((x) >> 24) & 0xFF) +#define B64_4(x) (((x) >> 32) & 0xFF) +#define B64_5(x) (((x) >> 40) & 0xFF) +#define B64_6(x) (((x) >> 48) & 0xFF) +#define B64_7(x) ((x) >> 56) +#define R64 SPH_ROTL64 +#define PC64(j, r) ((sph_u64)((j) + (r))) +#define QC64(j, r) (((sph_u64)(r) << 56) ^ (~((sph_u64)(j) << 56))) + +static const __constant ulong T0_G[] = +{ + 0xc6a597f4a5f432c6UL, 0xf884eb9784976ff8UL, 0xee99c7b099b05eeeUL, 0xf68df78c8d8c7af6UL, + 0xff0de5170d17e8ffUL, 0xd6bdb7dcbddc0ad6UL, 0xdeb1a7c8b1c816deUL, 0x915439fc54fc6d91UL, + 0x6050c0f050f09060UL, 0x0203040503050702UL, 0xcea987e0a9e02eceUL, 0x567dac877d87d156UL, + 0xe719d52b192bcce7UL, 0xb56271a662a613b5UL, 0x4de69a31e6317c4dUL, 0xec9ac3b59ab559ecUL, + 0x8f4505cf45cf408fUL, 0x1f9d3ebc9dbca31fUL, 0x894009c040c04989UL, 0xfa87ef92879268faUL, + 0xef15c53f153fd0efUL, 0xb2eb7f26eb2694b2UL, 0x8ec90740c940ce8eUL, 0xfb0bed1d0b1de6fbUL, + 0x41ec822fec2f6e41UL, 0xb3677da967a91ab3UL, 0x5ffdbe1cfd1c435fUL, 0x45ea8a25ea256045UL, + 0x23bf46dabfdaf923UL, 0x53f7a602f7025153UL, 0xe496d3a196a145e4UL, 0x9b5b2ded5bed769bUL, + 0x75c2ea5dc25d2875UL, 0xe11cd9241c24c5e1UL, 0x3dae7ae9aee9d43dUL, 0x4c6a98be6abef24cUL, + 0x6c5ad8ee5aee826cUL, 0x7e41fcc341c3bd7eUL, 0xf502f1060206f3f5UL, 0x834f1dd14fd15283UL, + 0x685cd0e45ce48c68UL, 0x51f4a207f4075651UL, 0xd134b95c345c8dd1UL, 0xf908e9180818e1f9UL, + 0xe293dfae93ae4ce2UL, 0xab734d9573953eabUL, 0x6253c4f553f59762UL, 0x2a3f54413f416b2aUL, + 0x080c10140c141c08UL, 0x955231f652f66395UL, 0x46658caf65afe946UL, 0x9d5e21e25ee27f9dUL, + 0x3028607828784830UL, 0x37a16ef8a1f8cf37UL, 0x0a0f14110f111b0aUL, 0x2fb55ec4b5c4eb2fUL, + 0x0e091c1b091b150eUL, 0x2436485a365a7e24UL, 0x1b9b36b69bb6ad1bUL, 0xdf3da5473d4798dfUL, + 0xcd26816a266aa7cdUL, 0x4e699cbb69bbf54eUL, 0x7fcdfe4ccd4c337fUL, 0xea9fcfba9fba50eaUL, + 0x121b242d1b2d3f12UL, 0x1d9e3ab99eb9a41dUL, 0x5874b09c749cc458UL, 0x342e68722e724634UL, + 0x362d6c772d774136UL, 0xdcb2a3cdb2cd11dcUL, 0xb4ee7329ee299db4UL, 0x5bfbb616fb164d5bUL, + 0xa4f65301f601a5a4UL, 0x764decd74dd7a176UL, 0xb76175a361a314b7UL, 0x7dcefa49ce49347dUL, + 0x527ba48d7b8ddf52UL, 0xdd3ea1423e429fddUL, 0x5e71bc937193cd5eUL, 0x139726a297a2b113UL, + 0xa6f55704f504a2a6UL, 0xb96869b868b801b9UL, 0x0000000000000000UL, 0xc12c99742c74b5c1UL, + 0x406080a060a0e040UL, 0xe31fdd211f21c2e3UL, 0x79c8f243c8433a79UL, 0xb6ed772ced2c9ab6UL, + 0xd4beb3d9bed90dd4UL, 0x8d4601ca46ca478dUL, 0x67d9ce70d9701767UL, 0x724be4dd4bddaf72UL, + 0x94de3379de79ed94UL, 0x98d42b67d467ff98UL, 0xb0e87b23e82393b0UL, 0x854a11de4ade5b85UL, + 0xbb6b6dbd6bbd06bbUL, 0xc52a917e2a7ebbc5UL, 0x4fe59e34e5347b4fUL, 0xed16c13a163ad7edUL, + 0x86c51754c554d286UL, 0x9ad72f62d762f89aUL, 0x6655ccff55ff9966UL, 0x119422a794a7b611UL, + 0x8acf0f4acf4ac08aUL, 0xe910c9301030d9e9UL, 0x0406080a060a0e04UL, 0xfe81e798819866feUL, + 0xa0f05b0bf00baba0UL, 0x7844f0cc44ccb478UL, 0x25ba4ad5bad5f025UL, 0x4be3963ee33e754bUL, + 0xa2f35f0ef30eaca2UL, 0x5dfeba19fe19445dUL, 0x80c01b5bc05bdb80UL, 0x058a0a858a858005UL, + 0x3fad7eecadecd33fUL, 0x21bc42dfbcdffe21UL, 0x7048e0d848d8a870UL, 0xf104f90c040cfdf1UL, + 0x63dfc67adf7a1963UL, 0x77c1ee58c1582f77UL, 0xaf75459f759f30afUL, 0x426384a563a5e742UL, + 0x2030405030507020UL, 0xe51ad12e1a2ecbe5UL, 0xfd0ee1120e12effdUL, 0xbf6d65b76db708bfUL, + 0x814c19d44cd45581UL, 0x1814303c143c2418UL, 0x26354c5f355f7926UL, 0xc32f9d712f71b2c3UL, + 0xbee16738e13886beUL, 0x35a26afda2fdc835UL, 0x88cc0b4fcc4fc788UL, 0x2e395c4b394b652eUL, + 0x93573df957f96a93UL, 0x55f2aa0df20d5855UL, 0xfc82e39d829d61fcUL, 0x7a47f4c947c9b37aUL, + 0xc8ac8befacef27c8UL, 0xbae76f32e73288baUL, 0x322b647d2b7d4f32UL, 0xe695d7a495a442e6UL, + 0xc0a09bfba0fb3bc0UL, 0x199832b398b3aa19UL, 0x9ed12768d168f69eUL, 0xa37f5d817f8122a3UL, + 0x446688aa66aaee44UL, 0x547ea8827e82d654UL, 0x3bab76e6abe6dd3bUL, 0x0b83169e839e950bUL, + 0x8cca0345ca45c98cUL, 0xc729957b297bbcc7UL, 0x6bd3d66ed36e056bUL, 0x283c50443c446c28UL, + 0xa779558b798b2ca7UL, 0xbce2633de23d81bcUL, 0x161d2c271d273116UL, 0xad76419a769a37adUL, + 0xdb3bad4d3b4d96dbUL, 0x6456c8fa56fa9e64UL, 0x744ee8d24ed2a674UL, 0x141e28221e223614UL, + 0x92db3f76db76e492UL, 0x0c0a181e0a1e120cUL, 0x486c90b46cb4fc48UL, 0xb8e46b37e4378fb8UL, + 0x9f5d25e75de7789fUL, 0xbd6e61b26eb20fbdUL, 0x43ef862aef2a6943UL, 0xc4a693f1a6f135c4UL, + 0x39a872e3a8e3da39UL, 0x31a462f7a4f7c631UL, 0xd337bd5937598ad3UL, 0xf28bff868b8674f2UL, + 0xd532b156325683d5UL, 0x8b430dc543c54e8bUL, 0x6e59dceb59eb856eUL, 0xdab7afc2b7c218daUL, + 0x018c028f8c8f8e01UL, 0xb16479ac64ac1db1UL, 0x9cd2236dd26df19cUL, 0x49e0923be03b7249UL, + 0xd8b4abc7b4c71fd8UL, 0xacfa4315fa15b9acUL, 0xf307fd090709faf3UL, 0xcf25856f256fa0cfUL, + 0xcaaf8feaafea20caUL, 0xf48ef3898e897df4UL, 0x47e98e20e9206747UL, 0x1018202818283810UL, + 0x6fd5de64d5640b6fUL, 0xf088fb83888373f0UL, 0x4a6f94b16fb1fb4aUL, 0x5c72b8967296ca5cUL, + 0x3824706c246c5438UL, 0x57f1ae08f1085f57UL, 0x73c7e652c7522173UL, 0x975135f351f36497UL, + 0xcb238d652365aecbUL, 0xa17c59847c8425a1UL, 0xe89ccbbf9cbf57e8UL, 0x3e217c6321635d3eUL, + 0x96dd377cdd7cea96UL, 0x61dcc27fdc7f1e61UL, 0x0d861a9186919c0dUL, 0x0f851e9485949b0fUL, + 0xe090dbab90ab4be0UL, 0x7c42f8c642c6ba7cUL, 0x71c4e257c4572671UL, 0xccaa83e5aae529ccUL, + 0x90d83b73d873e390UL, 0x06050c0f050f0906UL, 0xf701f5030103f4f7UL, 0x1c12383612362a1cUL, + 0xc2a39ffea3fe3cc2UL, 0x6a5fd4e15fe18b6aUL, 0xaef94710f910beaeUL, 0x69d0d26bd06b0269UL, + 0x17912ea891a8bf17UL, 0x995829e858e87199UL, 0x3a2774692769533aUL, 0x27b94ed0b9d0f727UL, + 0xd938a948384891d9UL, 0xeb13cd351335deebUL, 0x2bb356ceb3cee52bUL, 0x2233445533557722UL, + 0xd2bbbfd6bbd604d2UL, 0xa9704990709039a9UL, 0x07890e8089808707UL, 0x33a766f2a7f2c133UL, + 0x2db65ac1b6c1ec2dUL, 0x3c22786622665a3cUL, 0x15922aad92adb815UL, 0xc92089602060a9c9UL, + 0x874915db49db5c87UL, 0xaaff4f1aff1ab0aaUL, 0x5078a0887888d850UL, 0xa57a518e7a8e2ba5UL, + 0x038f068a8f8a8903UL, 0x59f8b213f8134a59UL, 0x0980129b809b9209UL, 0x1a1734391739231aUL, + 0x65daca75da751065UL, 0xd731b553315384d7UL, 0x84c61351c651d584UL, 0xd0b8bbd3b8d303d0UL, + 0x82c31f5ec35edc82UL, 0x29b052cbb0cbe229UL, 0x5a77b4997799c35aUL, 0x1e113c3311332d1eUL, + 0x7bcbf646cb463d7bUL, 0xa8fc4b1ffc1fb7a8UL, 0x6dd6da61d6610c6dUL, 0x2c3a584e3a4e622cUL +}; + +static const __constant ulong T4_G[] = +{ + 0xA5F432C6C6A597F4UL, 0x84976FF8F884EB97UL, 0x99B05EEEEE99C7B0UL, 0x8D8C7AF6F68DF78CUL, + 0x0D17E8FFFF0DE517UL, 0xBDDC0AD6D6BDB7DCUL, 0xB1C816DEDEB1A7C8UL, 0x54FC6D91915439FCUL, + 0x50F090606050C0F0UL, 0x0305070202030405UL, 0xA9E02ECECEA987E0UL, 0x7D87D156567DAC87UL, + 0x192BCCE7E719D52BUL, 0x62A613B5B56271A6UL, 0xE6317C4D4DE69A31UL, 0x9AB559ECEC9AC3B5UL, + 0x45CF408F8F4505CFUL, 0x9DBCA31F1F9D3EBCUL, 0x40C04989894009C0UL, 0x879268FAFA87EF92UL, + 0x153FD0EFEF15C53FUL, 0xEB2694B2B2EB7F26UL, 0xC940CE8E8EC90740UL, 0x0B1DE6FBFB0BED1DUL, + 0xEC2F6E4141EC822FUL, 0x67A91AB3B3677DA9UL, 0xFD1C435F5FFDBE1CUL, 0xEA25604545EA8A25UL, + 0xBFDAF92323BF46DAUL, 0xF702515353F7A602UL, 0x96A145E4E496D3A1UL, 0x5BED769B9B5B2DEDUL, + 0xC25D287575C2EA5DUL, 0x1C24C5E1E11CD924UL, 0xAEE9D43D3DAE7AE9UL, 0x6ABEF24C4C6A98BEUL, + 0x5AEE826C6C5AD8EEUL, 0x41C3BD7E7E41FCC3UL, 0x0206F3F5F502F106UL, 0x4FD15283834F1DD1UL, + 0x5CE48C68685CD0E4UL, 0xF407565151F4A207UL, 0x345C8DD1D134B95CUL, 0x0818E1F9F908E918UL, + 0x93AE4CE2E293DFAEUL, 0x73953EABAB734D95UL, 0x53F597626253C4F5UL, 0x3F416B2A2A3F5441UL, + 0x0C141C08080C1014UL, 0x52F66395955231F6UL, 0x65AFE94646658CAFUL, 0x5EE27F9D9D5E21E2UL, + 0x2878483030286078UL, 0xA1F8CF3737A16EF8UL, 0x0F111B0A0A0F1411UL, 0xB5C4EB2F2FB55EC4UL, + 0x091B150E0E091C1BUL, 0x365A7E242436485AUL, 0x9BB6AD1B1B9B36B6UL, 0x3D4798DFDF3DA547UL, + 0x266AA7CDCD26816AUL, 0x69BBF54E4E699CBBUL, 0xCD4C337F7FCDFE4CUL, 0x9FBA50EAEA9FCFBAUL, + 0x1B2D3F12121B242DUL, 0x9EB9A41D1D9E3AB9UL, 0x749CC4585874B09CUL, 0x2E724634342E6872UL, + 0x2D774136362D6C77UL, 0xB2CD11DCDCB2A3CDUL, 0xEE299DB4B4EE7329UL, 0xFB164D5B5BFBB616UL, + 0xF601A5A4A4F65301UL, 0x4DD7A176764DECD7UL, 0x61A314B7B76175A3UL, 0xCE49347D7DCEFA49UL, + 0x7B8DDF52527BA48DUL, 0x3E429FDDDD3EA142UL, 0x7193CD5E5E71BC93UL, 0x97A2B113139726A2UL, + 0xF504A2A6A6F55704UL, 0x68B801B9B96869B8UL, 0x0000000000000000UL, 0x2C74B5C1C12C9974UL, + 0x60A0E040406080A0UL, 0x1F21C2E3E31FDD21UL, 0xC8433A7979C8F243UL, 0xED2C9AB6B6ED772CUL, + 0xBED90DD4D4BEB3D9UL, 0x46CA478D8D4601CAUL, 0xD970176767D9CE70UL, 0x4BDDAF72724BE4DDUL, + 0xDE79ED9494DE3379UL, 0xD467FF9898D42B67UL, 0xE82393B0B0E87B23UL, 0x4ADE5B85854A11DEUL, + 0x6BBD06BBBB6B6DBDUL, 0x2A7EBBC5C52A917EUL, 0xE5347B4F4FE59E34UL, 0x163AD7EDED16C13AUL, + 0xC554D28686C51754UL, 0xD762F89A9AD72F62UL, 0x55FF99666655CCFFUL, 0x94A7B611119422A7UL, + 0xCF4AC08A8ACF0F4AUL, 0x1030D9E9E910C930UL, 0x060A0E040406080AUL, 0x819866FEFE81E798UL, + 0xF00BABA0A0F05B0BUL, 0x44CCB4787844F0CCUL, 0xBAD5F02525BA4AD5UL, 0xE33E754B4BE3963EUL, + 0xF30EACA2A2F35F0EUL, 0xFE19445D5DFEBA19UL, 0xC05BDB8080C01B5BUL, 0x8A858005058A0A85UL, + 0xADECD33F3FAD7EECUL, 0xBCDFFE2121BC42DFUL, 0x48D8A8707048E0D8UL, 0x040CFDF1F104F90CUL, + 0xDF7A196363DFC67AUL, 0xC1582F7777C1EE58UL, 0x759F30AFAF75459FUL, 0x63A5E742426384A5UL, + 0x3050702020304050UL, 0x1A2ECBE5E51AD12EUL, 0x0E12EFFDFD0EE112UL, 0x6DB708BFBF6D65B7UL, + 0x4CD45581814C19D4UL, 0x143C24181814303CUL, 0x355F792626354C5FUL, 0x2F71B2C3C32F9D71UL, + 0xE13886BEBEE16738UL, 0xA2FDC83535A26AFDUL, 0xCC4FC78888CC0B4FUL, 0x394B652E2E395C4BUL, + 0x57F96A9393573DF9UL, 0xF20D585555F2AA0DUL, 0x829D61FCFC82E39DUL, 0x47C9B37A7A47F4C9UL, + 0xACEF27C8C8AC8BEFUL, 0xE73288BABAE76F32UL, 0x2B7D4F32322B647DUL, 0x95A442E6E695D7A4UL, + 0xA0FB3BC0C0A09BFBUL, 0x98B3AA19199832B3UL, 0xD168F69E9ED12768UL, 0x7F8122A3A37F5D81UL, + 0x66AAEE44446688AAUL, 0x7E82D654547EA882UL, 0xABE6DD3B3BAB76E6UL, 0x839E950B0B83169EUL, + 0xCA45C98C8CCA0345UL, 0x297BBCC7C729957BUL, 0xD36E056B6BD3D66EUL, 0x3C446C28283C5044UL, + 0x798B2CA7A779558BUL, 0xE23D81BCBCE2633DUL, 0x1D273116161D2C27UL, 0x769A37ADAD76419AUL, + 0x3B4D96DBDB3BAD4DUL, 0x56FA9E646456C8FAUL, 0x4ED2A674744EE8D2UL, 0x1E223614141E2822UL, + 0xDB76E49292DB3F76UL, 0x0A1E120C0C0A181EUL, 0x6CB4FC48486C90B4UL, 0xE4378FB8B8E46B37UL, + 0x5DE7789F9F5D25E7UL, 0x6EB20FBDBD6E61B2UL, 0xEF2A694343EF862AUL, 0xA6F135C4C4A693F1UL, + 0xA8E3DA3939A872E3UL, 0xA4F7C63131A462F7UL, 0x37598AD3D337BD59UL, 0x8B8674F2F28BFF86UL, + 0x325683D5D532B156UL, 0x43C54E8B8B430DC5UL, 0x59EB856E6E59DCEBUL, 0xB7C218DADAB7AFC2UL, + 0x8C8F8E01018C028FUL, 0x64AC1DB1B16479ACUL, 0xD26DF19C9CD2236DUL, 0xE03B724949E0923BUL, + 0xB4C71FD8D8B4ABC7UL, 0xFA15B9ACACFA4315UL, 0x0709FAF3F307FD09UL, 0x256FA0CFCF25856FUL, + 0xAFEA20CACAAF8FEAUL, 0x8E897DF4F48EF389UL, 0xE920674747E98E20UL, 0x1828381010182028UL, + 0xD5640B6F6FD5DE64UL, 0x888373F0F088FB83UL, 0x6FB1FB4A4A6F94B1UL, 0x7296CA5C5C72B896UL, + 0x246C54383824706CUL, 0xF1085F5757F1AE08UL, 0xC752217373C7E652UL, 0x51F36497975135F3UL, + 0x2365AECBCB238D65UL, 0x7C8425A1A17C5984UL, 0x9CBF57E8E89CCBBFUL, 0x21635D3E3E217C63UL, + 0xDD7CEA9696DD377CUL, 0xDC7F1E6161DCC27FUL, 0x86919C0D0D861A91UL, 0x85949B0F0F851E94UL, + 0x90AB4BE0E090DBABUL, 0x42C6BA7C7C42F8C6UL, 0xC457267171C4E257UL, 0xAAE529CCCCAA83E5UL, + 0xD873E39090D83B73UL, 0x050F090606050C0FUL, 0x0103F4F7F701F503UL, 0x12362A1C1C123836UL, + 0xA3FE3CC2C2A39FFEUL, 0x5FE18B6A6A5FD4E1UL, 0xF910BEAEAEF94710UL, 0xD06B026969D0D26BUL, + 0x91A8BF1717912EA8UL, 0x58E87199995829E8UL, 0x2769533A3A277469UL, 0xB9D0F72727B94ED0UL, + 0x384891D9D938A948UL, 0x1335DEEBEB13CD35UL, 0xB3CEE52B2BB356CEUL, 0x3355772222334455UL, + 0xBBD604D2D2BBBFD6UL, 0x709039A9A9704990UL, 0x8980870707890E80UL, 0xA7F2C13333A766F2UL, + 0xB6C1EC2D2DB65AC1UL, 0x22665A3C3C227866UL, 0x92ADB81515922AADUL, 0x2060A9C9C9208960UL, + 0x49DB5C87874915DBUL, 0xFF1AB0AAAAFF4F1AUL, 0x7888D8505078A088UL, 0x7A8E2BA5A57A518EUL, + 0x8F8A8903038F068AUL, 0xF8134A5959F8B213UL, 0x809B92090980129BUL, 0x1739231A1A173439UL, + 0xDA75106565DACA75UL, 0x315384D7D731B553UL, 0xC651D58484C61351UL, 0xB8D303D0D0B8BBD3UL, + 0xC35EDC8282C31F5EUL, 0xB0CBE22929B052CBUL, 0x7799C35A5A77B499UL, 0x11332D1E1E113C33UL, + 0xCB463D7B7BCBF646UL, 0xFC1FB7A8A8FC4B1FUL, 0xD6610C6D6DD6DA61UL, 0x3A4E622C2C3A584EUL +}; + +#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0_G[B64_0(a[b0])] \ + ^ R64(T0_G[B64_1(a[b1])], 8) \ + ^ R64(T0_G[B64_2(a[b2])], 16) \ + ^ R64(T0_G[B64_3(a[b3])], 24) \ + ^ T4_G[B64_4(a[b4])] \ + ^ R64(T4_G[B64_5(a[b5])], 8) \ + ^ R64(T4_G[B64_6(a[b6])], 16) \ + ^ R64(T4_G[B64_7(a[b7])], 24); \ + } while (0) + +#define ROUND_SMALL_P(a, r) do { \ + ulong t[8]; \ + a[0] ^= PC64(0x00, r); \ + a[1] ^= PC64(0x10, r); \ + a[2] ^= PC64(0x20, r); \ + a[3] ^= PC64(0x30, r); \ + a[4] ^= PC64(0x40, r); \ + a[5] ^= PC64(0x50, r); \ + a[6] ^= PC64(0x60, r); \ + a[7] ^= PC64(0x70, r); \ + RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \ + RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \ + RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \ + RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \ + RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \ + RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \ + RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \ + RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#define ROUND_SMALL_Pf(a,r) do { \ + a[0] ^= PC64(0x00, r); \ + a[1] ^= PC64(0x10, r); \ + a[2] ^= PC64(0x20, r); \ + a[3] ^= PC64(0x30, r); \ + a[4] ^= PC64(0x40, r); \ + a[5] ^= PC64(0x50, r); \ + a[6] ^= PC64(0x60, r); \ + a[7] ^= PC64(0x70, r); \ + RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \ + a[7] = t[7]; \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + ulong t[8]; \ + a[0] ^= QC64(0x00, r); \ + a[1] ^= QC64(0x10, r); \ + a[2] ^= QC64(0x20, r); \ + a[3] ^= QC64(0x30, r); \ + a[4] ^= QC64(0x40, r); \ + a[5] ^= QC64(0x50, r); \ + a[6] ^= QC64(0x60, r); \ + a[7] ^= QC64(0x70, r); \ + RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \ + RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \ + RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \ + RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \ + RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \ + RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \ + RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \ + RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#define PERM_SMALL_P(a) do { \ + for (int r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Pf(a) do { \ + for (int r = 0; r < 9; r ++) { \ + ROUND_SMALL_P(a, r);} \ + ROUND_SMALL_Pf(a,9); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + for (int r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + diff --git a/src/backend/opencl/cl/cn/jh.cl b/src/backend/opencl/cl/cn/jh.cl new file mode 100644 index 000000000..4db694159 --- /dev/null +++ b/src/backend/opencl/cl/cn/jh.cl @@ -0,0 +1,271 @@ +/* $Id: jh.c 255 2011-06-07 19:50:20Z tp $ */ +/* + * JH implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * 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. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#define SPH_JH_64 1 +#define SPH_LITTLE_ENDIAN 1 + +#define SPH_C32(x) x +#define SPH_C64(x) x +typedef uint sph_u32; +typedef ulong sph_u64; + +/* + * The internal bitslice representation may use either big-endian or + * little-endian (true bitslice operations do not care about the bit + * ordering, and the bit-swapping linear operations in JH happen to + * be invariant through endianness-swapping). The constants must be + * defined according to the chosen endianness; we use some + * byte-swapping macros for that. + */ + +#if SPH_LITTLE_ENDIAN + +#define C32e(x) ((SPH_C32(x) >> 24) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le + +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le + +#else + +#define C32e(x) SPH_C32(x) +#define dec32e_aligned sph_dec32be_aligned +#define enc32e sph_enc32be +#define C64e(x) SPH_C64(x) +#define dec64e_aligned sph_dec64be_aligned +#define enc64e sph_enc64be + +#endif + +#define Sb(x0, x1, x2, x3, c) do { \ + x3 = ~x3; \ + x0 ^= (c) & ~x2; \ + tmp = (c) ^ (x0 & x1); \ + x0 ^= x2 & x3; \ + x3 ^= ~x1 & x2; \ + x1 ^= x0 & x2; \ + x2 ^= x0 & ~x3; \ + x0 ^= x1 | x3; \ + x3 ^= x1 & x2; \ + x1 ^= tmp & x0; \ + x2 ^= tmp; \ + } while (0) + +#define Lb(x0, x1, x2, x3, x4, x5, x6, x7) do { \ + x4 ^= x1; \ + x5 ^= x2; \ + x6 ^= x3 ^ x0; \ + x7 ^= x0; \ + x0 ^= x5; \ + x1 ^= x6; \ + x2 ^= x7 ^ x4; \ + x3 ^= x4; \ + } while (0) + +static const __constant ulong C[] = +{ + 0x67F815DFA2DED572UL, 0x571523B70A15847BUL, 0xF6875A4D90D6AB81UL, 0x402BD1C3C54F9F4EUL, + 0x9CFA455CE03A98EAUL, 0x9A99B26699D2C503UL, 0x8A53BBF2B4960266UL, 0x31A2DB881A1456B5UL, + 0xDB0E199A5C5AA303UL, 0x1044C1870AB23F40UL, 0x1D959E848019051CUL, 0xDCCDE75EADEB336FUL, + 0x416BBF029213BA10UL, 0xD027BBF7156578DCUL, 0x5078AA3739812C0AUL, 0xD3910041D2BF1A3FUL, + 0x907ECCF60D5A2D42UL, 0xCE97C0929C9F62DDUL, 0xAC442BC70BA75C18UL, 0x23FCC663D665DFD1UL, + 0x1AB8E09E036C6E97UL, 0xA8EC6C447E450521UL, 0xFA618E5DBB03F1EEUL, 0x97818394B29796FDUL, + 0x2F3003DB37858E4AUL, 0x956A9FFB2D8D672AUL, 0x6C69B8F88173FE8AUL, 0x14427FC04672C78AUL, + 0xC45EC7BD8F15F4C5UL, 0x80BB118FA76F4475UL, 0xBC88E4AEB775DE52UL, 0xF4A3A6981E00B882UL, + 0x1563A3A9338FF48EUL, 0x89F9B7D524565FAAUL, 0xFDE05A7C20EDF1B6UL, 0x362C42065AE9CA36UL, + 0x3D98FE4E433529CEUL, 0xA74B9A7374F93A53UL, 0x86814E6F591FF5D0UL, 0x9F5AD8AF81AD9D0EUL, + 0x6A6234EE670605A7UL, 0x2717B96EBE280B8BUL, 0x3F1080C626077447UL, 0x7B487EC66F7EA0E0UL, + 0xC0A4F84AA50A550DUL, 0x9EF18E979FE7E391UL, 0xD48D605081727686UL, 0x62B0E5F3415A9E7EUL, + 0x7A205440EC1F9FFCUL, 0x84C9F4CE001AE4E3UL, 0xD895FA9DF594D74FUL, 0xA554C324117E2E55UL, + 0x286EFEBD2872DF5BUL, 0xB2C4A50FE27FF578UL, 0x2ED349EEEF7C8905UL, 0x7F5928EB85937E44UL, + 0x4A3124B337695F70UL, 0x65E4D61DF128865EUL, 0xE720B95104771BC7UL, 0x8A87D423E843FE74UL, + 0xF2947692A3E8297DUL, 0xC1D9309B097ACBDDUL, 0xE01BDC5BFB301B1DUL, 0xBF829CF24F4924DAUL, + 0xFFBF70B431BAE7A4UL, 0x48BCF8DE0544320DUL, 0x39D3BB5332FCAE3BUL, 0xA08B29E0C1C39F45UL, + 0x0F09AEF7FD05C9E5UL, 0x34F1904212347094UL, 0x95ED44E301B771A2UL, 0x4A982F4F368E3BE9UL, + 0x15F66CA0631D4088UL, 0xFFAF52874B44C147UL, 0x30C60AE2F14ABB7EUL, 0xE68C6ECCC5B67046UL, + 0x00CA4FBD56A4D5A4UL, 0xAE183EC84B849DDAUL, 0xADD1643045CE5773UL, 0x67255C1468CEA6E8UL, + 0x16E10ECBF28CDAA3UL, 0x9A99949A5806E933UL, 0x7B846FC220B2601FUL, 0x1885D1A07FACCED1UL, + 0xD319DD8DA15B5932UL, 0x46B4A5AAC01C9A50UL, 0xBA6B04E467633D9FUL, 0x7EEE560BAB19CAF6UL, + 0x742128A9EA79B11FUL, 0xEE51363B35F7BDE9UL, 0x76D350755AAC571DUL, 0x01707DA3FEC2463AUL, + 0x42D8A498AFC135F7UL, 0x79676B9E20ECED78UL, 0xA8DB3AEA15638341UL, 0x832C83324D3BC3FAUL, + 0xF347271C1F3B40A7UL, 0x9A762DB734F04059UL, 0xFD4F21D26C4E3EE7UL, 0xEF5957DC398DFDB8UL, + 0xDAEB492B490C9B8DUL, 0x0D70F36849D7A25BUL, 0x84558D7AD0AE3B7DUL, 0x658EF8E4F0E9A5F5UL, + 0x533B1036F4A2B8A0UL, 0x5AEC3E759E07A80CUL, 0x4F88E85692946891UL, 0x4CBCBAF8555CB05BUL, + 0x7B9487F3993BBBE3UL, 0x5D1C6B72D6F4DA75UL, 0x6DB334DC28ACAE64UL, 0x71DB28B850A5346CUL, + 0x2A518D10F2E261F8UL, 0xFC75DD593364DBE3UL, 0xA23FCE43F1BCAC1CUL, 0xB043E8023CD1BB67UL, + 0x75A12988CA5B0A33UL, 0x5C5316B44D19347FUL, 0x1E4D790EC3943B92UL, 0x3FAFEEB6D7757479UL, + 0x21391ABEF7D4A8EAUL, 0x5127234C097EF45CUL, 0xD23C32BA5324A326UL, 0xADD5A66D4A17A344UL, + 0x08C9F2AFA63E1DB5UL, 0x563C6B91983D5983UL, 0x4D608672A17CF84CUL, 0xF6C76E08CC3EE246UL, + 0x5E76BCB1B333982FUL, 0x2AE6C4EFA566D62BUL, 0x36D4C1BEE8B6F406UL, 0x6321EFBC1582EE74UL, + 0x69C953F40D4EC1FDUL, 0x26585806C45A7DA7UL, 0x16FAE0061614C17EUL, 0x3F9D63283DAF907EUL, + 0x0CD29B00E3F2C9D2UL, 0x300CD4B730CEAA5FUL, 0x9832E0F216512A74UL, 0x9AF8CEE3D830EB0DUL, + 0x9279F1B57B9EC54BUL, 0xD36886046EE651FFUL, 0x316796E6574D239BUL, 0x05750A17F3A6E6CCUL, + 0xCE6C3213D98176B1UL, 0x62A205F88452173CUL, 0x47154778B3CB2BF4UL, 0x486A9323825446FFUL, + 0x65655E4E0758DF38UL, 0x8E5086FC897CFCF2UL, 0x86CA0BD0442E7031UL, 0x4E477830A20940F0UL, + 0x8338F7D139EEA065UL, 0xBD3A2CE437E95EF7UL, 0x6FF8130126B29721UL, 0xE7DE9FEFD1ED44A3UL, + 0xD992257615DFA08BUL, 0xBE42DC12F6F7853CUL, 0x7EB027AB7CECA7D8UL, 0xDEA83EAADA7D8D53UL, + 0xD86902BD93CE25AAUL, 0xF908731AFD43F65AUL, 0xA5194A17DAEF5FC0UL, 0x6A21FD4C33664D97UL, + 0x701541DB3198B435UL, 0x9B54CDEDBB0F1EEAUL, 0x72409751A163D09AUL, 0xE26F4791BF9D75F6UL +}; + +#define Ceven_hi(r) (C[((r) << 2) + 0]) +#define Ceven_lo(r) (C[((r) << 2) + 1]) +#define Codd_hi(r) (C[((r) << 2) + 2]) +#define Codd_lo(r) (C[((r) << 2) + 3]) + +#define S(x0, x1, x2, x3, cb, r) do { \ + Sb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, cb ## hi(r)); \ + Sb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, cb ## lo(r)); \ + } while (0) + +#define L(x0, x1, x2, x3, x4, x5, x6, x7) do { \ + Lb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, \ + x4 ## h, x5 ## h, x6 ## h, x7 ## h); \ + Lb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, \ + x4 ## l, x5 ## l, x6 ## l, x7 ## l); \ + } while (0) + +#define Wz(x, c, n) do { \ + sph_u64 t = (x ## h & (c)) << (n); \ + x ## h = ((x ## h >> (n)) & (c)) | t; \ + t = (x ## l & (c)) << (n); \ + x ## l = ((x ## l >> (n)) & (c)) | t; \ + } while (0) + +#define W0(x) Wz(x, SPH_C64(0x5555555555555555), 1) +#define W1(x) Wz(x, SPH_C64(0x3333333333333333), 2) +#define W2(x) Wz(x, SPH_C64(0x0F0F0F0F0F0F0F0F), 4) +#define W3(x) Wz(x, SPH_C64(0x00FF00FF00FF00FF), 8) +#define W4(x) Wz(x, SPH_C64(0x0000FFFF0000FFFF), 16) +#define W5(x) Wz(x, SPH_C64(0x00000000FFFFFFFF), 32) +#define W6(x) do { \ + sph_u64 t = x ## h; \ + x ## h = x ## l; \ + x ## l = t; \ + } while (0) + +#define SL(ro) SLu(r + ro, ro) + +#define SLu(r, ro) do { \ + S(h0, h2, h4, h6, Ceven_, r); \ + S(h1, h3, h5, h7, Codd_, r); \ + L(h0, h2, h4, h6, h1, h3, h5, h7); \ + W ## ro(h1); \ + W ## ro(h3); \ + W ## ro(h5); \ + W ## ro(h7); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_JH + +/* + * The "small footprint" 64-bit version just uses a partially unrolled + * loop. + */ + +#define E8 do { \ + unsigned r; \ + for (r = 0; r < 42; r += 7) { \ + SL(0); \ + SL(1); \ + SL(2); \ + SL(3); \ + SL(4); \ + SL(5); \ + SL(6); \ + } \ + } while (0) + +#else + +/* + * On a "true 64-bit" architecture, we can unroll at will. + */ + +#define E8 do { \ + SLu( 0, 0); \ + SLu( 1, 1); \ + SLu( 2, 2); \ + SLu( 3, 3); \ + SLu( 4, 4); \ + SLu( 5, 5); \ + SLu( 6, 6); \ + SLu( 7, 0); \ + SLu( 8, 1); \ + SLu( 9, 2); \ + SLu(10, 3); \ + SLu(11, 4); \ + SLu(12, 5); \ + SLu(13, 6); \ + SLu(14, 0); \ + SLu(15, 1); \ + SLu(16, 2); \ + SLu(17, 3); \ + SLu(18, 4); \ + SLu(19, 5); \ + SLu(20, 6); \ + SLu(21, 0); \ + SLu(22, 1); \ + SLu(23, 2); \ + SLu(24, 3); \ + SLu(25, 4); \ + SLu(26, 5); \ + SLu(27, 6); \ + SLu(28, 0); \ + SLu(29, 1); \ + SLu(30, 2); \ + SLu(31, 3); \ + SLu(32, 4); \ + SLu(33, 5); \ + SLu(34, 6); \ + SLu(35, 0); \ + SLu(36, 1); \ + SLu(37, 2); \ + SLu(38, 3); \ + SLu(39, 4); \ + SLu(40, 5); \ + SLu(41, 6); \ + } while (0) + +#endif diff --git a/src/backend/opencl/cl/cn/keccak.cl b/src/backend/opencl/cl/cn/keccak.cl new file mode 100644 index 000000000..e677a2ed9 --- /dev/null +++ b/src/backend/opencl/cl/cn/keccak.cl @@ -0,0 +1,155 @@ +#ifndef XMRIG_KECCAK_CL +#define XMRIG_KECCAK_CL + + +static const __constant ulong keccakf_rndc[24] = +{ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 +}; + + +static const __constant uint keccakf_rotc[24] = +{ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + + +static const __constant uint keccakf_piln[24] = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + + +void keccakf1600_1(ulong *st) +{ + int i, round; + ulong t, bc[5]; + + #pragma unroll 1 + for (round = 0; round < 24; ++round) { + // Theta + bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; + bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21]; + bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22]; + bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; + bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; + + #pragma unroll 1 + for (i = 0; i < 5; ++i) { + t = bc[(i + 4) % 5] ^ rotate(bc[(i + 1) % 5], 1UL); + st[i ] ^= t; + st[i + 5] ^= t; + st[i + 10] ^= t; + st[i + 15] ^= t; + st[i + 20] ^= t; + } + + // Rho Pi + t = st[1]; + #pragma unroll 1 + for (i = 0; i < 24; ++i) { + bc[0] = st[keccakf_piln[i]]; + st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]); + t = bc[0]; + } + + #pragma unroll 1 + for (int i = 0; i < 25; i += 5) { + ulong tmp[5]; + + #pragma unroll 1 + for (int x = 0; x < 5; ++x) { + tmp[x] = bitselect(st[i + x] ^ st[i + ((x + 2) % 5)], st[i + x], st[i + ((x + 1) % 5)]); + } + + #pragma unroll 1 + for (int x = 0; x < 5; ++x) { + st[i + x] = tmp[x]; + } + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + + +void keccakf1600_2(__local ulong *st) +{ + int i, round; + ulong t, bc[5]; + + #pragma unroll 1 + for (round = 0; round < 24; ++round) { + bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20] ^ rotate(st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22], 1UL); + bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21] ^ rotate(st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23], 1UL); + bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22] ^ rotate(st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24], 1UL); + bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23] ^ rotate(st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20], 1UL); + bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24] ^ rotate(st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21], 1UL); + + st[0] ^= bc[4]; + st[5] ^= bc[4]; + st[10] ^= bc[4]; + st[15] ^= bc[4]; + st[20] ^= bc[4]; + + st[1] ^= bc[0]; + st[6] ^= bc[0]; + st[11] ^= bc[0]; + st[16] ^= bc[0]; + st[21] ^= bc[0]; + + st[2] ^= bc[1]; + st[7] ^= bc[1]; + st[12] ^= bc[1]; + st[17] ^= bc[1]; + st[22] ^= bc[1]; + + st[3] ^= bc[2]; + st[8] ^= bc[2]; + st[13] ^= bc[2]; + st[18] ^= bc[2]; + st[23] ^= bc[2]; + + st[4] ^= bc[3]; + st[9] ^= bc[3]; + st[14] ^= bc[3]; + st[19] ^= bc[3]; + st[24] ^= bc[3]; + + // Rho Pi + t = st[1]; + #pragma unroll 1 + for (i = 0; i < 24; ++i) { + bc[0] = st[keccakf_piln[i]]; + st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]); + t = bc[0]; + } + + #pragma unroll 1 + for (int i = 0; i < 25; i += 5) { + ulong tmp1 = st[i], tmp2 = st[i + 1]; + + st[i] = bitselect(st[i] ^ st[i + 2], st[i], st[i + 1]); + st[i + 1] = bitselect(st[i + 1] ^ st[i + 3], st[i + 1], st[i + 2]); + st[i + 2] = bitselect(st[i + 2] ^ st[i + 4], st[i + 2], st[i + 3]); + st[i + 3] = bitselect(st[i + 3] ^ tmp1, st[i + 3], st[i + 4]); + st[i + 4] = bitselect(st[i + 4] ^ tmp2, st[i + 4], tmp1); + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + + +#endif diff --git a/src/backend/opencl/cl/cn/wolf-aes.cl b/src/backend/opencl/cl/cn/wolf-aes.cl new file mode 100644 index 000000000..f65a908d1 --- /dev/null +++ b/src/backend/opencl/cl/cn/wolf-aes.cl @@ -0,0 +1,194 @@ +#ifndef WOLF_AES_CL +#define WOLF_AES_CL + +#ifdef cl_amd_media_ops2 +# pragma OPENCL EXTENSION cl_amd_media_ops2 : enable + +# define xmrig_amd_bfe(src0, src1, src2) amd_bfe(src0, src1, src2) +#else +/* taken from: https://www.khronos.org/registry/OpenCL/extensions/amd/cl_amd_media_ops2.txt + * Built-in Function: + * uintn amd_bfe (uintn src0, uintn src1, uintn src2) + * Description + * NOTE: operator >> below represent logical right shift + * offset = src1.s0 & 31; + * width = src2.s0 & 31; + * if width = 0 + * dst.s0 = 0; + * else if (offset + width) < 32 + * dst.s0 = (src0.s0 << (32 - offset - width)) >> (32 - width); + * else + * dst.s0 = src0.s0 >> offset; + * similar operation applied to other components of the vectors + */ +inline int xmrig_amd_bfe(const uint src0, const uint offset, const uint width) +{ + /* casts are removed because we can implement everything as uint + * int offset = src1; + * int width = src2; + * remove check for edge case, this function is always called with + * `width==8` + * @code + * if ( width == 0 ) + * return 0; + * @endcode + */ + if ((offset + width) < 32u) { + return (src0 << (32u - offset - width)) >> (32u - width); + } + + return src0 >> offset; +} +#endif + + +// AES table - the other three are generated on the fly + +static const __constant uint AES0_C[256] = +{ + 0xA56363C6U, 0x847C7CF8U, 0x997777EEU, 0x8D7B7BF6U, + 0x0DF2F2FFU, 0xBD6B6BD6U, 0xB16F6FDEU, 0x54C5C591U, + 0x50303060U, 0x03010102U, 0xA96767CEU, 0x7D2B2B56U, + 0x19FEFEE7U, 0x62D7D7B5U, 0xE6ABAB4DU, 0x9A7676ECU, + 0x45CACA8FU, 0x9D82821FU, 0x40C9C989U, 0x877D7DFAU, + 0x15FAFAEFU, 0xEB5959B2U, 0xC947478EU, 0x0BF0F0FBU, + 0xECADAD41U, 0x67D4D4B3U, 0xFDA2A25FU, 0xEAAFAF45U, + 0xBF9C9C23U, 0xF7A4A453U, 0x967272E4U, 0x5BC0C09BU, + 0xC2B7B775U, 0x1CFDFDE1U, 0xAE93933DU, 0x6A26264CU, + 0x5A36366CU, 0x413F3F7EU, 0x02F7F7F5U, 0x4FCCCC83U, + 0x5C343468U, 0xF4A5A551U, 0x34E5E5D1U, 0x08F1F1F9U, + 0x937171E2U, 0x73D8D8ABU, 0x53313162U, 0x3F15152AU, + 0x0C040408U, 0x52C7C795U, 0x65232346U, 0x5EC3C39DU, + 0x28181830U, 0xA1969637U, 0x0F05050AU, 0xB59A9A2FU, + 0x0907070EU, 0x36121224U, 0x9B80801BU, 0x3DE2E2DFU, + 0x26EBEBCDU, 0x6927274EU, 0xCDB2B27FU, 0x9F7575EAU, + 0x1B090912U, 0x9E83831DU, 0x742C2C58U, 0x2E1A1A34U, + 0x2D1B1B36U, 0xB26E6EDCU, 0xEE5A5AB4U, 0xFBA0A05BU, + 0xF65252A4U, 0x4D3B3B76U, 0x61D6D6B7U, 0xCEB3B37DU, + 0x7B292952U, 0x3EE3E3DDU, 0x712F2F5EU, 0x97848413U, + 0xF55353A6U, 0x68D1D1B9U, 0x00000000U, 0x2CEDEDC1U, + 0x60202040U, 0x1FFCFCE3U, 0xC8B1B179U, 0xED5B5BB6U, + 0xBE6A6AD4U, 0x46CBCB8DU, 0xD9BEBE67U, 0x4B393972U, + 0xDE4A4A94U, 0xD44C4C98U, 0xE85858B0U, 0x4ACFCF85U, + 0x6BD0D0BBU, 0x2AEFEFC5U, 0xE5AAAA4FU, 0x16FBFBEDU, + 0xC5434386U, 0xD74D4D9AU, 0x55333366U, 0x94858511U, + 0xCF45458AU, 0x10F9F9E9U, 0x06020204U, 0x817F7FFEU, + 0xF05050A0U, 0x443C3C78U, 0xBA9F9F25U, 0xE3A8A84BU, + 0xF35151A2U, 0xFEA3A35DU, 0xC0404080U, 0x8A8F8F05U, + 0xAD92923FU, 0xBC9D9D21U, 0x48383870U, 0x04F5F5F1U, + 0xDFBCBC63U, 0xC1B6B677U, 0x75DADAAFU, 0x63212142U, + 0x30101020U, 0x1AFFFFE5U, 0x0EF3F3FDU, 0x6DD2D2BFU, + 0x4CCDCD81U, 0x140C0C18U, 0x35131326U, 0x2FECECC3U, + 0xE15F5FBEU, 0xA2979735U, 0xCC444488U, 0x3917172EU, + 0x57C4C493U, 0xF2A7A755U, 0x827E7EFCU, 0x473D3D7AU, + 0xAC6464C8U, 0xE75D5DBAU, 0x2B191932U, 0x957373E6U, + 0xA06060C0U, 0x98818119U, 0xD14F4F9EU, 0x7FDCDCA3U, + 0x66222244U, 0x7E2A2A54U, 0xAB90903BU, 0x8388880BU, + 0xCA46468CU, 0x29EEEEC7U, 0xD3B8B86BU, 0x3C141428U, + 0x79DEDEA7U, 0xE25E5EBCU, 0x1D0B0B16U, 0x76DBDBADU, + 0x3BE0E0DBU, 0x56323264U, 0x4E3A3A74U, 0x1E0A0A14U, + 0xDB494992U, 0x0A06060CU, 0x6C242448U, 0xE45C5CB8U, + 0x5DC2C29FU, 0x6ED3D3BDU, 0xEFACAC43U, 0xA66262C4U, + 0xA8919139U, 0xA4959531U, 0x37E4E4D3U, 0x8B7979F2U, + 0x32E7E7D5U, 0x43C8C88BU, 0x5937376EU, 0xB76D6DDAU, + 0x8C8D8D01U, 0x64D5D5B1U, 0xD24E4E9CU, 0xE0A9A949U, + 0xB46C6CD8U, 0xFA5656ACU, 0x07F4F4F3U, 0x25EAEACFU, + 0xAF6565CAU, 0x8E7A7AF4U, 0xE9AEAE47U, 0x18080810U, + 0xD5BABA6FU, 0x887878F0U, 0x6F25254AU, 0x722E2E5CU, + 0x241C1C38U, 0xF1A6A657U, 0xC7B4B473U, 0x51C6C697U, + 0x23E8E8CBU, 0x7CDDDDA1U, 0x9C7474E8U, 0x211F1F3EU, + 0xDD4B4B96U, 0xDCBDBD61U, 0x868B8B0DU, 0x858A8A0FU, + 0x907070E0U, 0x423E3E7CU, 0xC4B5B571U, 0xAA6666CCU, + 0xD8484890U, 0x05030306U, 0x01F6F6F7U, 0x120E0E1CU, + 0xA36161C2U, 0x5F35356AU, 0xF95757AEU, 0xD0B9B969U, + 0x91868617U, 0x58C1C199U, 0x271D1D3AU, 0xB99E9E27U, + 0x38E1E1D9U, 0x13F8F8EBU, 0xB398982BU, 0x33111122U, + 0xBB6969D2U, 0x70D9D9A9U, 0x898E8E07U, 0xA7949433U, + 0xB69B9B2DU, 0x221E1E3CU, 0x92878715U, 0x20E9E9C9U, + 0x49CECE87U, 0xFF5555AAU, 0x78282850U, 0x7ADFDFA5U, + 0x8F8C8C03U, 0xF8A1A159U, 0x80898909U, 0x170D0D1AU, + 0xDABFBF65U, 0x31E6E6D7U, 0xC6424284U, 0xB86868D0U, + 0xC3414182U, 0xB0999929U, 0x772D2D5AU, 0x110F0F1EU, + 0xCBB0B07BU, 0xFC5454A8U, 0xD6BBBB6DU, 0x3A16162CU +}; + +#define BYTE(x, y) (xmrig_amd_bfe((x), (y) << 3U, 8U)) + +#if (ALGO == ALGO_CN_HEAVY_TUBE) +inline uint4 AES_Round_bittube2(const __local uint *AES0, const __local uint *AES1, uint4 x, uint4 k) +{ + x = ~x; + k.s0 ^= AES0[BYTE(x.s0, 0)] ^ AES1[BYTE(x.s1, 1)] ^ rotate(AES0[BYTE(x.s2, 2)] ^ AES1[BYTE(x.s3, 3)], 16U); + x.s0 ^= k.s0; + k.s1 ^= AES0[BYTE(x.s1, 0)] ^ AES1[BYTE(x.s2, 1)] ^ rotate(AES0[BYTE(x.s3, 2)] ^ AES1[BYTE(x.s0, 3)], 16U); + x.s1 ^= k.s1; + k.s2 ^= AES0[BYTE(x.s2, 0)] ^ AES1[BYTE(x.s3, 1)] ^ rotate(AES0[BYTE(x.s0, 2)] ^ AES1[BYTE(x.s1, 3)], 16U); + x.s2 ^= k.s2; + k.s3 ^= AES0[BYTE(x.s3, 0)] ^ AES1[BYTE(x.s0, 1)] ^ rotate(AES0[BYTE(x.s1, 2)] ^ AES1[BYTE(x.s2, 3)], 16U); + return k; +} +#endif + +uint4 AES_Round(const __local uint *AES0, const __local uint *AES1, const __local uint *AES2, const __local uint *AES3, const uint4 X, uint4 key) +{ + key.s0 ^= AES0[BYTE(X.s0, 0)] ^ AES1[BYTE(X.s1, 1)] ^ AES2[BYTE(X.s2, 2)] ^ AES3[BYTE(X.s3, 3)]; + key.s1 ^= AES0[BYTE(X.s1, 0)] ^ AES1[BYTE(X.s2, 1)] ^ AES2[BYTE(X.s3, 2)] ^ AES3[BYTE(X.s0, 3)]; + key.s2 ^= AES0[BYTE(X.s2, 0)] ^ AES1[BYTE(X.s3, 1)] ^ AES2[BYTE(X.s0, 2)] ^ AES3[BYTE(X.s1, 3)]; + key.s3 ^= AES0[BYTE(X.s3, 0)] ^ AES1[BYTE(X.s0, 1)] ^ AES2[BYTE(X.s1, 2)] ^ AES3[BYTE(X.s2, 3)]; + + return key; +} + +uint4 AES_Round_Two_Tables(const __local uint *AES0, const __local uint *AES1, const uint4 X, uint4 key) +{ + key.s0 ^= AES0[BYTE(X.s0, 0)] ^ AES1[BYTE(X.s1, 1)] ^ rotate(AES0[BYTE(X.s2, 2)] ^ AES1[BYTE(X.s3, 3)], 16U); + key.s1 ^= AES0[BYTE(X.s1, 0)] ^ AES1[BYTE(X.s2, 1)] ^ rotate(AES0[BYTE(X.s3, 2)] ^ AES1[BYTE(X.s0, 3)], 16U); + key.s2 ^= AES0[BYTE(X.s2, 0)] ^ AES1[BYTE(X.s3, 1)] ^ rotate(AES0[BYTE(X.s0, 2)] ^ AES1[BYTE(X.s1, 3)], 16U); + key.s3 ^= AES0[BYTE(X.s3, 0)] ^ AES1[BYTE(X.s0, 1)] ^ rotate(AES0[BYTE(X.s1, 2)] ^ AES1[BYTE(X.s2, 3)], 16U); + + return key; +} + + +static const __constant uchar rcon[8] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 }; + + +static const __constant uchar sbox[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + + +#define SubWord(inw) ((sbox[BYTE(inw, 3)] << 24) | (sbox[BYTE(inw, 2)] << 16) | (sbox[BYTE(inw, 1)] << 8) | sbox[BYTE(inw, 0)]) + + +void AESExpandKey256(uint *keybuf) +{ + //#pragma unroll 4 + for (uint c = 8, i = 1; c < 40; ++c) { + // For 256-bit keys, an sbox permutation is done every other 4th uint generated, AND every 8th + uint t = ((!(c & 7)) || ((c & 7) == 4)) ? SubWord(keybuf[c - 1]) : keybuf[c - 1]; + + // If the uint we're generating has an index that is a multiple of 8, rotate and XOR with the round constant, + // then XOR this with previously generated uint. If it's 4 after a multiple of 8, only the sbox permutation + // is done, followed by the XOR. If neither are true, only the XOR with the previously generated uint is done. + keybuf[c] = keybuf[c - 8] ^ ((!(c & 7)) ? rotate(t, 24U) ^ as_uint((uchar4)(rcon[i++], 0U, 0U, 0U)) : t); + } +} + +#endif diff --git a/src/backend/opencl/cl/cn/wolf-skein.cl b/src/backend/opencl/cl/cn/wolf-skein.cl new file mode 100644 index 000000000..f7862c923 --- /dev/null +++ b/src/backend/opencl/cl/cn/wolf-skein.cl @@ -0,0 +1,138 @@ +#ifndef WOLF_SKEIN_CL +#define WOLF_SKEIN_CL + +#ifdef cl_amd_media_ops +# pragma OPENCL EXTENSION cl_amd_media_ops : enable +# define xmrig_amd_bitalign(src0, src1, src2) amd_bitalign(src0, src1, src2) +#else +/* taken from https://www.khronos.org/registry/OpenCL/extensions/amd/cl_amd_media_ops.txt + * Build-in Function + * uintn amd_bitalign (uintn src0, uintn src1, uintn src2) + * Description + * dst.s0 = (uint) (((((long)src0.s0) << 32) | (long)src1.s0) >> (src2.s0 & 31)) + * similar operation applied to other components of the vectors. + * + * The implemented function is modified because the last is in our case always a scalar. + * We can ignore the bitwise AND operation. + */ +inline uint2 xmrig_amd_bitalign(const uint2 src0, const uint2 src1, const uint src2) +{ + uint2 result; + result.s0 = (uint) (((((long)src0.s0) << 32) | (long)src1.s0) >> (src2)); + result.s1 = (uint) (((((long)src0.s1) << 32) | (long)src1.s1) >> (src2)); + return result; +} +#endif + +// Vectorized Skein implementation macros and functions by Wolf + +#define SKEIN_KS_PARITY 0x1BD11BDAA9FC1A22 + +static const __constant ulong SKEIN256_IV[8] = +{ + 0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL, + 0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL, + 0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL, + 0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL +}; + +static const __constant ulong SKEIN512_256_IV[8] = +{ + 0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL, + 0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL, + 0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL, + 0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL +}; + +#define SKEIN_INJECT_KEY(p, s) do { \ + p += h; \ + p.s5 += t[s % 3]; \ + p.s6 += t[(s + 1) % 3]; \ + p.s7 += s; \ +} while(0) + +ulong SKEIN_ROT(const uint2 x, const uint y) +{ + if (y < 32) { + return(as_ulong(xmrig_amd_bitalign(x, x.s10, 32 - y))); + } + else { + return(as_ulong(xmrig_amd_bitalign(x.s10, x, 32 - (y - 32)))); + } +} + +void SkeinMix8(ulong4 *pv0, ulong4 *pv1, const uint rc0, const uint rc1, const uint rc2, const uint rc3) +{ + *pv0 += *pv1; + (*pv1).s0 = SKEIN_ROT(as_uint2((*pv1).s0), rc0); + (*pv1).s1 = SKEIN_ROT(as_uint2((*pv1).s1), rc1); + (*pv1).s2 = SKEIN_ROT(as_uint2((*pv1).s2), rc2); + (*pv1).s3 = SKEIN_ROT(as_uint2((*pv1).s3), rc3); + *pv1 ^= *pv0; +} + +ulong8 SkeinEvenRound(ulong8 p, const ulong8 h, const ulong *t, const uint s) +{ + SKEIN_INJECT_KEY(p, s); + ulong4 pv0 = p.even, pv1 = p.odd; + + SkeinMix8(&pv0, &pv1, 46, 36, 19, 37); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 33, 27, 14, 42); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 17, 49, 36, 39); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 44, 9, 54, 56); + return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5))); +} + +ulong8 SkeinOddRound(ulong8 p, const ulong8 h, const ulong *t, const uint s) +{ + SKEIN_INJECT_KEY(p, s); + ulong4 pv0 = p.even, pv1 = p.odd; + + SkeinMix8(&pv0, &pv1, 39, 30, 34, 24); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 13, 50, 10, 17); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 25, 29, 39, 43); + pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0)); + pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1)); + + SkeinMix8(&pv0, &pv1, 8, 35, 56, 22); + return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5))); +} + +ulong8 Skein512Block(ulong8 p, ulong8 h, ulong h8, const ulong *t) +{ + #pragma unroll + for(int i = 0; i < 18; ++i) + { + p = SkeinEvenRound(p, h, t, i); + ++i; + ulong tmp = h.s0; + h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0)); + h.s7 = h8; + h8 = tmp; + p = SkeinOddRound(p, h, t, i); + tmp = h.s0; + h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0)); + h.s7 = h8; + h8 = tmp; + } + + SKEIN_INJECT_KEY(p, 18); + return(p); +} + +#endif diff --git a/src/backend/opencl/cl/rx/aes.cl b/src/backend/opencl/cl/rx/aes.cl new file mode 100644 index 000000000..26d74f2fb --- /dev/null +++ b/src/backend/opencl/cl/rx/aes.cl @@ -0,0 +1,635 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +__constant static const uint AES_TABLE[2048] = +{ + 0xa56363c6U, 0x847c7cf8U, 0x997777eeU, 0x8d7b7bf6U, + 0x0df2f2ffU, 0xbd6b6bd6U, 0xb16f6fdeU, 0x54c5c591U, + 0x50303060U, 0x03010102U, 0xa96767ceU, 0x7d2b2b56U, + 0x19fefee7U, 0x62d7d7b5U, 0xe6abab4dU, 0x9a7676ecU, + 0x45caca8fU, 0x9d82821fU, 0x40c9c989U, 0x877d7dfaU, + 0x15fafaefU, 0xeb5959b2U, 0xc947478eU, 0x0bf0f0fbU, + 0xecadad41U, 0x67d4d4b3U, 0xfda2a25fU, 0xeaafaf45U, + 0xbf9c9c23U, 0xf7a4a453U, 0x967272e4U, 0x5bc0c09bU, + 0xc2b7b775U, 0x1cfdfde1U, 0xae93933dU, 0x6a26264cU, + 0x5a36366cU, 0x413f3f7eU, 0x02f7f7f5U, 0x4fcccc83U, + 0x5c343468U, 0xf4a5a551U, 0x34e5e5d1U, 0x08f1f1f9U, + 0x937171e2U, 0x73d8d8abU, 0x53313162U, 0x3f15152aU, + 0x0c040408U, 0x52c7c795U, 0x65232346U, 0x5ec3c39dU, + 0x28181830U, 0xa1969637U, 0x0f05050aU, 0xb59a9a2fU, + 0x0907070eU, 0x36121224U, 0x9b80801bU, 0x3de2e2dfU, + 0x26ebebcdU, 0x6927274eU, 0xcdb2b27fU, 0x9f7575eaU, + 0x1b090912U, 0x9e83831dU, 0x742c2c58U, 0x2e1a1a34U, + 0x2d1b1b36U, 0xb26e6edcU, 0xee5a5ab4U, 0xfba0a05bU, + 0xf65252a4U, 0x4d3b3b76U, 0x61d6d6b7U, 0xceb3b37dU, + 0x7b292952U, 0x3ee3e3ddU, 0x712f2f5eU, 0x97848413U, + 0xf55353a6U, 0x68d1d1b9U, 0x00000000U, 0x2cededc1U, + 0x60202040U, 0x1ffcfce3U, 0xc8b1b179U, 0xed5b5bb6U, + 0xbe6a6ad4U, 0x46cbcb8dU, 0xd9bebe67U, 0x4b393972U, + 0xde4a4a94U, 0xd44c4c98U, 0xe85858b0U, 0x4acfcf85U, + 0x6bd0d0bbU, 0x2aefefc5U, 0xe5aaaa4fU, 0x16fbfbedU, + 0xc5434386U, 0xd74d4d9aU, 0x55333366U, 0x94858511U, + 0xcf45458aU, 0x10f9f9e9U, 0x06020204U, 0x817f7ffeU, + 0xf05050a0U, 0x443c3c78U, 0xba9f9f25U, 0xe3a8a84bU, + 0xf35151a2U, 0xfea3a35dU, 0xc0404080U, 0x8a8f8f05U, + 0xad92923fU, 0xbc9d9d21U, 0x48383870U, 0x04f5f5f1U, + 0xdfbcbc63U, 0xc1b6b677U, 0x75dadaafU, 0x63212142U, + 0x30101020U, 0x1affffe5U, 0x0ef3f3fdU, 0x6dd2d2bfU, + 0x4ccdcd81U, 0x140c0c18U, 0x35131326U, 0x2fececc3U, + 0xe15f5fbeU, 0xa2979735U, 0xcc444488U, 0x3917172eU, + 0x57c4c493U, 0xf2a7a755U, 0x827e7efcU, 0x473d3d7aU, + 0xac6464c8U, 0xe75d5dbaU, 0x2b191932U, 0x957373e6U, + 0xa06060c0U, 0x98818119U, 0xd14f4f9eU, 0x7fdcdca3U, + 0x66222244U, 0x7e2a2a54U, 0xab90903bU, 0x8388880bU, + 0xca46468cU, 0x29eeeec7U, 0xd3b8b86bU, 0x3c141428U, + 0x79dedea7U, 0xe25e5ebcU, 0x1d0b0b16U, 0x76dbdbadU, + 0x3be0e0dbU, 0x56323264U, 0x4e3a3a74U, 0x1e0a0a14U, + 0xdb494992U, 0x0a06060cU, 0x6c242448U, 0xe45c5cb8U, + 0x5dc2c29fU, 0x6ed3d3bdU, 0xefacac43U, 0xa66262c4U, + 0xa8919139U, 0xa4959531U, 0x37e4e4d3U, 0x8b7979f2U, + 0x32e7e7d5U, 0x43c8c88bU, 0x5937376eU, 0xb76d6ddaU, + 0x8c8d8d01U, 0x64d5d5b1U, 0xd24e4e9cU, 0xe0a9a949U, + 0xb46c6cd8U, 0xfa5656acU, 0x07f4f4f3U, 0x25eaeacfU, + 0xaf6565caU, 0x8e7a7af4U, 0xe9aeae47U, 0x18080810U, + 0xd5baba6fU, 0x887878f0U, 0x6f25254aU, 0x722e2e5cU, + 0x241c1c38U, 0xf1a6a657U, 0xc7b4b473U, 0x51c6c697U, + 0x23e8e8cbU, 0x7cdddda1U, 0x9c7474e8U, 0x211f1f3eU, + 0xdd4b4b96U, 0xdcbdbd61U, 0x868b8b0dU, 0x858a8a0fU, + 0x907070e0U, 0x423e3e7cU, 0xc4b5b571U, 0xaa6666ccU, + 0xd8484890U, 0x05030306U, 0x01f6f6f7U, 0x120e0e1cU, + 0xa36161c2U, 0x5f35356aU, 0xf95757aeU, 0xd0b9b969U, + 0x91868617U, 0x58c1c199U, 0x271d1d3aU, 0xb99e9e27U, + 0x38e1e1d9U, 0x13f8f8ebU, 0xb398982bU, 0x33111122U, + 0xbb6969d2U, 0x70d9d9a9U, 0x898e8e07U, 0xa7949433U, + 0xb69b9b2dU, 0x221e1e3cU, 0x92878715U, 0x20e9e9c9U, + 0x49cece87U, 0xff5555aaU, 0x78282850U, 0x7adfdfa5U, + 0x8f8c8c03U, 0xf8a1a159U, 0x80898909U, 0x170d0d1aU, + 0xdabfbf65U, 0x31e6e6d7U, 0xc6424284U, 0xb86868d0U, + 0xc3414182U, 0xb0999929U, 0x772d2d5aU, 0x110f0f1eU, + 0xcbb0b07bU, 0xfc5454a8U, 0xd6bbbb6dU, 0x3a16162cU, + 0x6363c6a5U, 0x7c7cf884U, 0x7777ee99U, 0x7b7bf68dU, + 0xf2f2ff0dU, 0x6b6bd6bdU, 0x6f6fdeb1U, 0xc5c59154U, + 0x30306050U, 0x01010203U, 0x6767cea9U, 0x2b2b567dU, + 0xfefee719U, 0xd7d7b562U, 0xabab4de6U, 0x7676ec9aU, + 0xcaca8f45U, 0x82821f9dU, 0xc9c98940U, 0x7d7dfa87U, + 0xfafaef15U, 0x5959b2ebU, 0x47478ec9U, 0xf0f0fb0bU, + 0xadad41ecU, 0xd4d4b367U, 0xa2a25ffdU, 0xafaf45eaU, + 0x9c9c23bfU, 0xa4a453f7U, 0x7272e496U, 0xc0c09b5bU, + 0xb7b775c2U, 0xfdfde11cU, 0x93933daeU, 0x26264c6aU, + 0x36366c5aU, 0x3f3f7e41U, 0xf7f7f502U, 0xcccc834fU, + 0x3434685cU, 0xa5a551f4U, 0xe5e5d134U, 0xf1f1f908U, + 0x7171e293U, 0xd8d8ab73U, 0x31316253U, 0x15152a3fU, + 0x0404080cU, 0xc7c79552U, 0x23234665U, 0xc3c39d5eU, + 0x18183028U, 0x969637a1U, 0x05050a0fU, 0x9a9a2fb5U, + 0x07070e09U, 0x12122436U, 0x80801b9bU, 0xe2e2df3dU, + 0xebebcd26U, 0x27274e69U, 0xb2b27fcdU, 0x7575ea9fU, + 0x0909121bU, 0x83831d9eU, 0x2c2c5874U, 0x1a1a342eU, + 0x1b1b362dU, 0x6e6edcb2U, 0x5a5ab4eeU, 0xa0a05bfbU, + 0x5252a4f6U, 0x3b3b764dU, 0xd6d6b761U, 0xb3b37dceU, + 0x2929527bU, 0xe3e3dd3eU, 0x2f2f5e71U, 0x84841397U, + 0x5353a6f5U, 0xd1d1b968U, 0x00000000U, 0xededc12cU, + 0x20204060U, 0xfcfce31fU, 0xb1b179c8U, 0x5b5bb6edU, + 0x6a6ad4beU, 0xcbcb8d46U, 0xbebe67d9U, 0x3939724bU, + 0x4a4a94deU, 0x4c4c98d4U, 0x5858b0e8U, 0xcfcf854aU, + 0xd0d0bb6bU, 0xefefc52aU, 0xaaaa4fe5U, 0xfbfbed16U, + 0x434386c5U, 0x4d4d9ad7U, 0x33336655U, 0x85851194U, + 0x45458acfU, 0xf9f9e910U, 0x02020406U, 0x7f7ffe81U, + 0x5050a0f0U, 0x3c3c7844U, 0x9f9f25baU, 0xa8a84be3U, + 0x5151a2f3U, 0xa3a35dfeU, 0x404080c0U, 0x8f8f058aU, + 0x92923fadU, 0x9d9d21bcU, 0x38387048U, 0xf5f5f104U, + 0xbcbc63dfU, 0xb6b677c1U, 0xdadaaf75U, 0x21214263U, + 0x10102030U, 0xffffe51aU, 0xf3f3fd0eU, 0xd2d2bf6dU, + 0xcdcd814cU, 0x0c0c1814U, 0x13132635U, 0xececc32fU, + 0x5f5fbee1U, 0x979735a2U, 0x444488ccU, 0x17172e39U, + 0xc4c49357U, 0xa7a755f2U, 0x7e7efc82U, 0x3d3d7a47U, + 0x6464c8acU, 0x5d5dbae7U, 0x1919322bU, 0x7373e695U, + 0x6060c0a0U, 0x81811998U, 0x4f4f9ed1U, 0xdcdca37fU, + 0x22224466U, 0x2a2a547eU, 0x90903babU, 0x88880b83U, + 0x46468ccaU, 0xeeeec729U, 0xb8b86bd3U, 0x1414283cU, + 0xdedea779U, 0x5e5ebce2U, 0x0b0b161dU, 0xdbdbad76U, + 0xe0e0db3bU, 0x32326456U, 0x3a3a744eU, 0x0a0a141eU, + 0x494992dbU, 0x06060c0aU, 0x2424486cU, 0x5c5cb8e4U, + 0xc2c29f5dU, 0xd3d3bd6eU, 0xacac43efU, 0x6262c4a6U, + 0x919139a8U, 0x959531a4U, 0xe4e4d337U, 0x7979f28bU, + 0xe7e7d532U, 0xc8c88b43U, 0x37376e59U, 0x6d6ddab7U, + 0x8d8d018cU, 0xd5d5b164U, 0x4e4e9cd2U, 0xa9a949e0U, + 0x6c6cd8b4U, 0x5656acfaU, 0xf4f4f307U, 0xeaeacf25U, + 0x6565caafU, 0x7a7af48eU, 0xaeae47e9U, 0x08081018U, + 0xbaba6fd5U, 0x7878f088U, 0x25254a6fU, 0x2e2e5c72U, + 0x1c1c3824U, 0xa6a657f1U, 0xb4b473c7U, 0xc6c69751U, + 0xe8e8cb23U, 0xdddda17cU, 0x7474e89cU, 0x1f1f3e21U, + 0x4b4b96ddU, 0xbdbd61dcU, 0x8b8b0d86U, 0x8a8a0f85U, + 0x7070e090U, 0x3e3e7c42U, 0xb5b571c4U, 0x6666ccaaU, + 0x484890d8U, 0x03030605U, 0xf6f6f701U, 0x0e0e1c12U, + 0x6161c2a3U, 0x35356a5fU, 0x5757aef9U, 0xb9b969d0U, + 0x86861791U, 0xc1c19958U, 0x1d1d3a27U, 0x9e9e27b9U, + 0xe1e1d938U, 0xf8f8eb13U, 0x98982bb3U, 0x11112233U, + 0x6969d2bbU, 0xd9d9a970U, 0x8e8e0789U, 0x949433a7U, + 0x9b9b2db6U, 0x1e1e3c22U, 0x87871592U, 0xe9e9c920U, + 0xcece8749U, 0x5555aaffU, 0x28285078U, 0xdfdfa57aU, + 0x8c8c038fU, 0xa1a159f8U, 0x89890980U, 0x0d0d1a17U, + 0xbfbf65daU, 0xe6e6d731U, 0x424284c6U, 0x6868d0b8U, + 0x414182c3U, 0x999929b0U, 0x2d2d5a77U, 0x0f0f1e11U, + 0xb0b07bcbU, 0x5454a8fcU, 0xbbbb6dd6U, 0x16162c3aU, + 0x63c6a563U, 0x7cf8847cU, 0x77ee9977U, 0x7bf68d7bU, + 0xf2ff0df2U, 0x6bd6bd6bU, 0x6fdeb16fU, 0xc59154c5U, + 0x30605030U, 0x01020301U, 0x67cea967U, 0x2b567d2bU, + 0xfee719feU, 0xd7b562d7U, 0xab4de6abU, 0x76ec9a76U, + 0xca8f45caU, 0x821f9d82U, 0xc98940c9U, 0x7dfa877dU, + 0xfaef15faU, 0x59b2eb59U, 0x478ec947U, 0xf0fb0bf0U, + 0xad41ecadU, 0xd4b367d4U, 0xa25ffda2U, 0xaf45eaafU, + 0x9c23bf9cU, 0xa453f7a4U, 0x72e49672U, 0xc09b5bc0U, + 0xb775c2b7U, 0xfde11cfdU, 0x933dae93U, 0x264c6a26U, + 0x366c5a36U, 0x3f7e413fU, 0xf7f502f7U, 0xcc834fccU, + 0x34685c34U, 0xa551f4a5U, 0xe5d134e5U, 0xf1f908f1U, + 0x71e29371U, 0xd8ab73d8U, 0x31625331U, 0x152a3f15U, + 0x04080c04U, 0xc79552c7U, 0x23466523U, 0xc39d5ec3U, + 0x18302818U, 0x9637a196U, 0x050a0f05U, 0x9a2fb59aU, + 0x070e0907U, 0x12243612U, 0x801b9b80U, 0xe2df3de2U, + 0xebcd26ebU, 0x274e6927U, 0xb27fcdb2U, 0x75ea9f75U, + 0x09121b09U, 0x831d9e83U, 0x2c58742cU, 0x1a342e1aU, + 0x1b362d1bU, 0x6edcb26eU, 0x5ab4ee5aU, 0xa05bfba0U, + 0x52a4f652U, 0x3b764d3bU, 0xd6b761d6U, 0xb37dceb3U, + 0x29527b29U, 0xe3dd3ee3U, 0x2f5e712fU, 0x84139784U, + 0x53a6f553U, 0xd1b968d1U, 0x00000000U, 0xedc12cedU, + 0x20406020U, 0xfce31ffcU, 0xb179c8b1U, 0x5bb6ed5bU, + 0x6ad4be6aU, 0xcb8d46cbU, 0xbe67d9beU, 0x39724b39U, + 0x4a94de4aU, 0x4c98d44cU, 0x58b0e858U, 0xcf854acfU, + 0xd0bb6bd0U, 0xefc52aefU, 0xaa4fe5aaU, 0xfbed16fbU, + 0x4386c543U, 0x4d9ad74dU, 0x33665533U, 0x85119485U, + 0x458acf45U, 0xf9e910f9U, 0x02040602U, 0x7ffe817fU, + 0x50a0f050U, 0x3c78443cU, 0x9f25ba9fU, 0xa84be3a8U, + 0x51a2f351U, 0xa35dfea3U, 0x4080c040U, 0x8f058a8fU, + 0x923fad92U, 0x9d21bc9dU, 0x38704838U, 0xf5f104f5U, + 0xbc63dfbcU, 0xb677c1b6U, 0xdaaf75daU, 0x21426321U, + 0x10203010U, 0xffe51affU, 0xf3fd0ef3U, 0xd2bf6dd2U, + 0xcd814ccdU, 0x0c18140cU, 0x13263513U, 0xecc32fecU, + 0x5fbee15fU, 0x9735a297U, 0x4488cc44U, 0x172e3917U, + 0xc49357c4U, 0xa755f2a7U, 0x7efc827eU, 0x3d7a473dU, + 0x64c8ac64U, 0x5dbae75dU, 0x19322b19U, 0x73e69573U, + 0x60c0a060U, 0x81199881U, 0x4f9ed14fU, 0xdca37fdcU, + 0x22446622U, 0x2a547e2aU, 0x903bab90U, 0x880b8388U, + 0x468cca46U, 0xeec729eeU, 0xb86bd3b8U, 0x14283c14U, + 0xdea779deU, 0x5ebce25eU, 0x0b161d0bU, 0xdbad76dbU, + 0xe0db3be0U, 0x32645632U, 0x3a744e3aU, 0x0a141e0aU, + 0x4992db49U, 0x060c0a06U, 0x24486c24U, 0x5cb8e45cU, + 0xc29f5dc2U, 0xd3bd6ed3U, 0xac43efacU, 0x62c4a662U, + 0x9139a891U, 0x9531a495U, 0xe4d337e4U, 0x79f28b79U, + 0xe7d532e7U, 0xc88b43c8U, 0x376e5937U, 0x6ddab76dU, + 0x8d018c8dU, 0xd5b164d5U, 0x4e9cd24eU, 0xa949e0a9U, + 0x6cd8b46cU, 0x56acfa56U, 0xf4f307f4U, 0xeacf25eaU, + 0x65caaf65U, 0x7af48e7aU, 0xae47e9aeU, 0x08101808U, + 0xba6fd5baU, 0x78f08878U, 0x254a6f25U, 0x2e5c722eU, + 0x1c38241cU, 0xa657f1a6U, 0xb473c7b4U, 0xc69751c6U, + 0xe8cb23e8U, 0xdda17cddU, 0x74e89c74U, 0x1f3e211fU, + 0x4b96dd4bU, 0xbd61dcbdU, 0x8b0d868bU, 0x8a0f858aU, + 0x70e09070U, 0x3e7c423eU, 0xb571c4b5U, 0x66ccaa66U, + 0x4890d848U, 0x03060503U, 0xf6f701f6U, 0x0e1c120eU, + 0x61c2a361U, 0x356a5f35U, 0x57aef957U, 0xb969d0b9U, + 0x86179186U, 0xc19958c1U, 0x1d3a271dU, 0x9e27b99eU, + 0xe1d938e1U, 0xf8eb13f8U, 0x982bb398U, 0x11223311U, + 0x69d2bb69U, 0xd9a970d9U, 0x8e07898eU, 0x9433a794U, + 0x9b2db69bU, 0x1e3c221eU, 0x87159287U, 0xe9c920e9U, + 0xce8749ceU, 0x55aaff55U, 0x28507828U, 0xdfa57adfU, + 0x8c038f8cU, 0xa159f8a1U, 0x89098089U, 0x0d1a170dU, + 0xbf65dabfU, 0xe6d731e6U, 0x4284c642U, 0x68d0b868U, + 0x4182c341U, 0x9929b099U, 0x2d5a772dU, 0x0f1e110fU, + 0xb07bcbb0U, 0x54a8fc54U, 0xbb6dd6bbU, 0x162c3a16U, + 0xc6a56363U, 0xf8847c7cU, 0xee997777U, 0xf68d7b7bU, + 0xff0df2f2U, 0xd6bd6b6bU, 0xdeb16f6fU, 0x9154c5c5U, + 0x60503030U, 0x02030101U, 0xcea96767U, 0x567d2b2bU, + 0xe719fefeU, 0xb562d7d7U, 0x4de6ababU, 0xec9a7676U, + 0x8f45cacaU, 0x1f9d8282U, 0x8940c9c9U, 0xfa877d7dU, + 0xef15fafaU, 0xb2eb5959U, 0x8ec94747U, 0xfb0bf0f0U, + 0x41ecadadU, 0xb367d4d4U, 0x5ffda2a2U, 0x45eaafafU, + 0x23bf9c9cU, 0x53f7a4a4U, 0xe4967272U, 0x9b5bc0c0U, + 0x75c2b7b7U, 0xe11cfdfdU, 0x3dae9393U, 0x4c6a2626U, + 0x6c5a3636U, 0x7e413f3fU, 0xf502f7f7U, 0x834fccccU, + 0x685c3434U, 0x51f4a5a5U, 0xd134e5e5U, 0xf908f1f1U, + 0xe2937171U, 0xab73d8d8U, 0x62533131U, 0x2a3f1515U, + 0x080c0404U, 0x9552c7c7U, 0x46652323U, 0x9d5ec3c3U, + 0x30281818U, 0x37a19696U, 0x0a0f0505U, 0x2fb59a9aU, + 0x0e090707U, 0x24361212U, 0x1b9b8080U, 0xdf3de2e2U, + 0xcd26ebebU, 0x4e692727U, 0x7fcdb2b2U, 0xea9f7575U, + 0x121b0909U, 0x1d9e8383U, 0x58742c2cU, 0x342e1a1aU, + 0x362d1b1bU, 0xdcb26e6eU, 0xb4ee5a5aU, 0x5bfba0a0U, + 0xa4f65252U, 0x764d3b3bU, 0xb761d6d6U, 0x7dceb3b3U, + 0x527b2929U, 0xdd3ee3e3U, 0x5e712f2fU, 0x13978484U, + 0xa6f55353U, 0xb968d1d1U, 0x00000000U, 0xc12cededU, + 0x40602020U, 0xe31ffcfcU, 0x79c8b1b1U, 0xb6ed5b5bU, + 0xd4be6a6aU, 0x8d46cbcbU, 0x67d9bebeU, 0x724b3939U, + 0x94de4a4aU, 0x98d44c4cU, 0xb0e85858U, 0x854acfcfU, + 0xbb6bd0d0U, 0xc52aefefU, 0x4fe5aaaaU, 0xed16fbfbU, + 0x86c54343U, 0x9ad74d4dU, 0x66553333U, 0x11948585U, + 0x8acf4545U, 0xe910f9f9U, 0x04060202U, 0xfe817f7fU, + 0xa0f05050U, 0x78443c3cU, 0x25ba9f9fU, 0x4be3a8a8U, + 0xa2f35151U, 0x5dfea3a3U, 0x80c04040U, 0x058a8f8fU, + 0x3fad9292U, 0x21bc9d9dU, 0x70483838U, 0xf104f5f5U, + 0x63dfbcbcU, 0x77c1b6b6U, 0xaf75dadaU, 0x42632121U, + 0x20301010U, 0xe51affffU, 0xfd0ef3f3U, 0xbf6dd2d2U, + 0x814ccdcdU, 0x18140c0cU, 0x26351313U, 0xc32fececU, + 0xbee15f5fU, 0x35a29797U, 0x88cc4444U, 0x2e391717U, + 0x9357c4c4U, 0x55f2a7a7U, 0xfc827e7eU, 0x7a473d3dU, + 0xc8ac6464U, 0xbae75d5dU, 0x322b1919U, 0xe6957373U, + 0xc0a06060U, 0x19988181U, 0x9ed14f4fU, 0xa37fdcdcU, + 0x44662222U, 0x547e2a2aU, 0x3bab9090U, 0x0b838888U, + 0x8cca4646U, 0xc729eeeeU, 0x6bd3b8b8U, 0x283c1414U, + 0xa779dedeU, 0xbce25e5eU, 0x161d0b0bU, 0xad76dbdbU, + 0xdb3be0e0U, 0x64563232U, 0x744e3a3aU, 0x141e0a0aU, + 0x92db4949U, 0x0c0a0606U, 0x486c2424U, 0xb8e45c5cU, + 0x9f5dc2c2U, 0xbd6ed3d3U, 0x43efacacU, 0xc4a66262U, + 0x39a89191U, 0x31a49595U, 0xd337e4e4U, 0xf28b7979U, + 0xd532e7e7U, 0x8b43c8c8U, 0x6e593737U, 0xdab76d6dU, + 0x018c8d8dU, 0xb164d5d5U, 0x9cd24e4eU, 0x49e0a9a9U, + 0xd8b46c6cU, 0xacfa5656U, 0xf307f4f4U, 0xcf25eaeaU, + 0xcaaf6565U, 0xf48e7a7aU, 0x47e9aeaeU, 0x10180808U, + 0x6fd5babaU, 0xf0887878U, 0x4a6f2525U, 0x5c722e2eU, + 0x38241c1cU, 0x57f1a6a6U, 0x73c7b4b4U, 0x9751c6c6U, + 0xcb23e8e8U, 0xa17cddddU, 0xe89c7474U, 0x3e211f1fU, + 0x96dd4b4bU, 0x61dcbdbdU, 0x0d868b8bU, 0x0f858a8aU, + 0xe0907070U, 0x7c423e3eU, 0x71c4b5b5U, 0xccaa6666U, + 0x90d84848U, 0x06050303U, 0xf701f6f6U, 0x1c120e0eU, + 0xc2a36161U, 0x6a5f3535U, 0xaef95757U, 0x69d0b9b9U, + 0x17918686U, 0x9958c1c1U, 0x3a271d1dU, 0x27b99e9eU, + 0xd938e1e1U, 0xeb13f8f8U, 0x2bb39898U, 0x22331111U, + 0xd2bb6969U, 0xa970d9d9U, 0x07898e8eU, 0x33a79494U, + 0x2db69b9bU, 0x3c221e1eU, 0x15928787U, 0xc920e9e9U, + 0x8749ceceU, 0xaaff5555U, 0x50782828U, 0xa57adfdfU, + 0x038f8c8cU, 0x59f8a1a1U, 0x09808989U, 0x1a170d0dU, + 0x65dabfbfU, 0xd731e6e6U, 0x84c64242U, 0xd0b86868U, + 0x82c34141U, 0x29b09999U, 0x5a772d2dU, 0x1e110f0fU, + 0x7bcbb0b0U, 0xa8fc5454U, 0x6dd6bbbbU, 0x2c3a1616U, + 0x50a7f451U, 0x5365417eU, 0xc3a4171aU, 0x965e273aU, + 0xcb6bab3bU, 0xf1459d1fU, 0xab58faacU, 0x9303e34bU, + 0x55fa3020U, 0xf66d76adU, 0x9176cc88U, 0x254c02f5U, + 0xfcd7e54fU, 0xd7cb2ac5U, 0x80443526U, 0x8fa362b5U, + 0x495ab1deU, 0x671bba25U, 0x980eea45U, 0xe1c0fe5dU, + 0x02752fc3U, 0x12f04c81U, 0xa397468dU, 0xc6f9d36bU, + 0xe75f8f03U, 0x959c9215U, 0xeb7a6dbfU, 0xda595295U, + 0x2d83bed4U, 0xd3217458U, 0x2969e049U, 0x44c8c98eU, + 0x6a89c275U, 0x78798ef4U, 0x6b3e5899U, 0xdd71b927U, + 0xb64fe1beU, 0x17ad88f0U, 0x66ac20c9U, 0xb43ace7dU, + 0x184adf63U, 0x82311ae5U, 0x60335197U, 0x457f5362U, + 0xe07764b1U, 0x84ae6bbbU, 0x1ca081feU, 0x942b08f9U, + 0x58684870U, 0x19fd458fU, 0x876cde94U, 0xb7f87b52U, + 0x23d373abU, 0xe2024b72U, 0x578f1fe3U, 0x2aab5566U, + 0x0728ebb2U, 0x03c2b52fU, 0x9a7bc586U, 0xa50837d3U, + 0xf2872830U, 0xb2a5bf23U, 0xba6a0302U, 0x5c8216edU, + 0x2b1ccf8aU, 0x92b479a7U, 0xf0f207f3U, 0xa1e2694eU, + 0xcdf4da65U, 0xd5be0506U, 0x1f6234d1U, 0x8afea6c4U, + 0x9d532e34U, 0xa055f3a2U, 0x32e18a05U, 0x75ebf6a4U, + 0x39ec830bU, 0xaaef6040U, 0x069f715eU, 0x51106ebdU, + 0xf98a213eU, 0x3d06dd96U, 0xae053eddU, 0x46bde64dU, + 0xb58d5491U, 0x055dc471U, 0x6fd40604U, 0xff155060U, + 0x24fb9819U, 0x97e9bdd6U, 0xcc434089U, 0x779ed967U, + 0xbd42e8b0U, 0x888b8907U, 0x385b19e7U, 0xdbeec879U, + 0x470a7ca1U, 0xe90f427cU, 0xc91e84f8U, 0x00000000U, + 0x83868009U, 0x48ed2b32U, 0xac70111eU, 0x4e725a6cU, + 0xfbff0efdU, 0x5638850fU, 0x1ed5ae3dU, 0x27392d36U, + 0x64d90f0aU, 0x21a65c68U, 0xd1545b9bU, 0x3a2e3624U, + 0xb1670a0cU, 0x0fe75793U, 0xd296eeb4U, 0x9e919b1bU, + 0x4fc5c080U, 0xa220dc61U, 0x694b775aU, 0x161a121cU, + 0x0aba93e2U, 0xe52aa0c0U, 0x43e0223cU, 0x1d171b12U, + 0x0b0d090eU, 0xadc78bf2U, 0xb9a8b62dU, 0xc8a91e14U, + 0x8519f157U, 0x4c0775afU, 0xbbdd99eeU, 0xfd607fa3U, + 0x9f2601f7U, 0xbcf5725cU, 0xc53b6644U, 0x347efb5bU, + 0x7629438bU, 0xdcc623cbU, 0x68fcedb6U, 0x63f1e4b8U, + 0xcadc31d7U, 0x10856342U, 0x40229713U, 0x2011c684U, + 0x7d244a85U, 0xf83dbbd2U, 0x1132f9aeU, 0x6da129c7U, + 0x4b2f9e1dU, 0xf330b2dcU, 0xec52860dU, 0xd0e3c177U, + 0x6c16b32bU, 0x99b970a9U, 0xfa489411U, 0x2264e947U, + 0xc48cfca8U, 0x1a3ff0a0U, 0xd82c7d56U, 0xef903322U, + 0xc74e4987U, 0xc1d138d9U, 0xfea2ca8cU, 0x360bd498U, + 0xcf81f5a6U, 0x28de7aa5U, 0x268eb7daU, 0xa4bfad3fU, + 0xe49d3a2cU, 0x0d927850U, 0x9bcc5f6aU, 0x62467e54U, + 0xc2138df6U, 0xe8b8d890U, 0x5ef7392eU, 0xf5afc382U, + 0xbe805d9fU, 0x7c93d069U, 0xa92dd56fU, 0xb31225cfU, + 0x3b99acc8U, 0xa77d1810U, 0x6e639ce8U, 0x7bbb3bdbU, + 0x097826cdU, 0xf418596eU, 0x01b79aecU, 0xa89a4f83U, + 0x656e95e6U, 0x7ee6ffaaU, 0x08cfbc21U, 0xe6e815efU, + 0xd99be7baU, 0xce366f4aU, 0xd4099feaU, 0xd67cb029U, + 0xafb2a431U, 0x31233f2aU, 0x3094a5c6U, 0xc066a235U, + 0x37bc4e74U, 0xa6ca82fcU, 0xb0d090e0U, 0x15d8a733U, + 0x4a9804f1U, 0xf7daec41U, 0x0e50cd7fU, 0x2ff69117U, + 0x8dd64d76U, 0x4db0ef43U, 0x544daaccU, 0xdf0496e4U, + 0xe3b5d19eU, 0x1b886a4cU, 0xb81f2cc1U, 0x7f516546U, + 0x04ea5e9dU, 0x5d358c01U, 0x737487faU, 0x2e410bfbU, + 0x5a1d67b3U, 0x52d2db92U, 0x335610e9U, 0x1347d66dU, + 0x8c61d79aU, 0x7a0ca137U, 0x8e14f859U, 0x893c13ebU, + 0xee27a9ceU, 0x35c961b7U, 0xede51ce1U, 0x3cb1477aU, + 0x59dfd29cU, 0x3f73f255U, 0x79ce1418U, 0xbf37c773U, + 0xeacdf753U, 0x5baafd5fU, 0x146f3ddfU, 0x86db4478U, + 0x81f3afcaU, 0x3ec468b9U, 0x2c342438U, 0x5f40a3c2U, + 0x72c31d16U, 0x0c25e2bcU, 0x8b493c28U, 0x41950dffU, + 0x7101a839U, 0xdeb30c08U, 0x9ce4b4d8U, 0x90c15664U, + 0x6184cb7bU, 0x70b632d5U, 0x745c6c48U, 0x4257b8d0U, + 0xa7f45150U, 0x65417e53U, 0xa4171ac3U, 0x5e273a96U, + 0x6bab3bcbU, 0x459d1ff1U, 0x58faacabU, 0x03e34b93U, + 0xfa302055U, 0x6d76adf6U, 0x76cc8891U, 0x4c02f525U, + 0xd7e54ffcU, 0xcb2ac5d7U, 0x44352680U, 0xa362b58fU, + 0x5ab1de49U, 0x1bba2567U, 0x0eea4598U, 0xc0fe5de1U, + 0x752fc302U, 0xf04c8112U, 0x97468da3U, 0xf9d36bc6U, + 0x5f8f03e7U, 0x9c921595U, 0x7a6dbfebU, 0x595295daU, + 0x83bed42dU, 0x217458d3U, 0x69e04929U, 0xc8c98e44U, + 0x89c2756aU, 0x798ef478U, 0x3e58996bU, 0x71b927ddU, + 0x4fe1beb6U, 0xad88f017U, 0xac20c966U, 0x3ace7db4U, + 0x4adf6318U, 0x311ae582U, 0x33519760U, 0x7f536245U, + 0x7764b1e0U, 0xae6bbb84U, 0xa081fe1cU, 0x2b08f994U, + 0x68487058U, 0xfd458f19U, 0x6cde9487U, 0xf87b52b7U, + 0xd373ab23U, 0x024b72e2U, 0x8f1fe357U, 0xab55662aU, + 0x28ebb207U, 0xc2b52f03U, 0x7bc5869aU, 0x0837d3a5U, + 0x872830f2U, 0xa5bf23b2U, 0x6a0302baU, 0x8216ed5cU, + 0x1ccf8a2bU, 0xb479a792U, 0xf207f3f0U, 0xe2694ea1U, + 0xf4da65cdU, 0xbe0506d5U, 0x6234d11fU, 0xfea6c48aU, + 0x532e349dU, 0x55f3a2a0U, 0xe18a0532U, 0xebf6a475U, + 0xec830b39U, 0xef6040aaU, 0x9f715e06U, 0x106ebd51U, + 0x8a213ef9U, 0x06dd963dU, 0x053eddaeU, 0xbde64d46U, + 0x8d5491b5U, 0x5dc47105U, 0xd406046fU, 0x155060ffU, + 0xfb981924U, 0xe9bdd697U, 0x434089ccU, 0x9ed96777U, + 0x42e8b0bdU, 0x8b890788U, 0x5b19e738U, 0xeec879dbU, + 0x0a7ca147U, 0x0f427ce9U, 0x1e84f8c9U, 0x00000000U, + 0x86800983U, 0xed2b3248U, 0x70111eacU, 0x725a6c4eU, + 0xff0efdfbU, 0x38850f56U, 0xd5ae3d1eU, 0x392d3627U, + 0xd90f0a64U, 0xa65c6821U, 0x545b9bd1U, 0x2e36243aU, + 0x670a0cb1U, 0xe757930fU, 0x96eeb4d2U, 0x919b1b9eU, + 0xc5c0804fU, 0x20dc61a2U, 0x4b775a69U, 0x1a121c16U, + 0xba93e20aU, 0x2aa0c0e5U, 0xe0223c43U, 0x171b121dU, + 0x0d090e0bU, 0xc78bf2adU, 0xa8b62db9U, 0xa91e14c8U, + 0x19f15785U, 0x0775af4cU, 0xdd99eebbU, 0x607fa3fdU, + 0x2601f79fU, 0xf5725cbcU, 0x3b6644c5U, 0x7efb5b34U, + 0x29438b76U, 0xc623cbdcU, 0xfcedb668U, 0xf1e4b863U, + 0xdc31d7caU, 0x85634210U, 0x22971340U, 0x11c68420U, + 0x244a857dU, 0x3dbbd2f8U, 0x32f9ae11U, 0xa129c76dU, + 0x2f9e1d4bU, 0x30b2dcf3U, 0x52860decU, 0xe3c177d0U, + 0x16b32b6cU, 0xb970a999U, 0x489411faU, 0x64e94722U, + 0x8cfca8c4U, 0x3ff0a01aU, 0x2c7d56d8U, 0x903322efU, + 0x4e4987c7U, 0xd138d9c1U, 0xa2ca8cfeU, 0x0bd49836U, + 0x81f5a6cfU, 0xde7aa528U, 0x8eb7da26U, 0xbfad3fa4U, + 0x9d3a2ce4U, 0x9278500dU, 0xcc5f6a9bU, 0x467e5462U, + 0x138df6c2U, 0xb8d890e8U, 0xf7392e5eU, 0xafc382f5U, + 0x805d9fbeU, 0x93d0697cU, 0x2dd56fa9U, 0x1225cfb3U, + 0x99acc83bU, 0x7d1810a7U, 0x639ce86eU, 0xbb3bdb7bU, + 0x7826cd09U, 0x18596ef4U, 0xb79aec01U, 0x9a4f83a8U, + 0x6e95e665U, 0xe6ffaa7eU, 0xcfbc2108U, 0xe815efe6U, + 0x9be7bad9U, 0x366f4aceU, 0x099fead4U, 0x7cb029d6U, + 0xb2a431afU, 0x233f2a31U, 0x94a5c630U, 0x66a235c0U, + 0xbc4e7437U, 0xca82fca6U, 0xd090e0b0U, 0xd8a73315U, + 0x9804f14aU, 0xdaec41f7U, 0x50cd7f0eU, 0xf691172fU, + 0xd64d768dU, 0xb0ef434dU, 0x4daacc54U, 0x0496e4dfU, + 0xb5d19ee3U, 0x886a4c1bU, 0x1f2cc1b8U, 0x5165467fU, + 0xea5e9d04U, 0x358c015dU, 0x7487fa73U, 0x410bfb2eU, + 0x1d67b35aU, 0xd2db9252U, 0x5610e933U, 0x47d66d13U, + 0x61d79a8cU, 0x0ca1377aU, 0x14f8598eU, 0x3c13eb89U, + 0x27a9ceeeU, 0xc961b735U, 0xe51ce1edU, 0xb1477a3cU, + 0xdfd29c59U, 0x73f2553fU, 0xce141879U, 0x37c773bfU, + 0xcdf753eaU, 0xaafd5f5bU, 0x6f3ddf14U, 0xdb447886U, + 0xf3afca81U, 0xc468b93eU, 0x3424382cU, 0x40a3c25fU, + 0xc31d1672U, 0x25e2bc0cU, 0x493c288bU, 0x950dff41U, + 0x01a83971U, 0xb30c08deU, 0xe4b4d89cU, 0xc1566490U, + 0x84cb7b61U, 0xb632d570U, 0x5c6c4874U, 0x57b8d042U, + 0xf45150a7U, 0x417e5365U, 0x171ac3a4U, 0x273a965eU, + 0xab3bcb6bU, 0x9d1ff145U, 0xfaacab58U, 0xe34b9303U, + 0x302055faU, 0x76adf66dU, 0xcc889176U, 0x02f5254cU, + 0xe54ffcd7U, 0x2ac5d7cbU, 0x35268044U, 0x62b58fa3U, + 0xb1de495aU, 0xba25671bU, 0xea45980eU, 0xfe5de1c0U, + 0x2fc30275U, 0x4c8112f0U, 0x468da397U, 0xd36bc6f9U, + 0x8f03e75fU, 0x9215959cU, 0x6dbfeb7aU, 0x5295da59U, + 0xbed42d83U, 0x7458d321U, 0xe0492969U, 0xc98e44c8U, + 0xc2756a89U, 0x8ef47879U, 0x58996b3eU, 0xb927dd71U, + 0xe1beb64fU, 0x88f017adU, 0x20c966acU, 0xce7db43aU, + 0xdf63184aU, 0x1ae58231U, 0x51976033U, 0x5362457fU, + 0x64b1e077U, 0x6bbb84aeU, 0x81fe1ca0U, 0x08f9942bU, + 0x48705868U, 0x458f19fdU, 0xde94876cU, 0x7b52b7f8U, + 0x73ab23d3U, 0x4b72e202U, 0x1fe3578fU, 0x55662aabU, + 0xebb20728U, 0xb52f03c2U, 0xc5869a7bU, 0x37d3a508U, + 0x2830f287U, 0xbf23b2a5U, 0x0302ba6aU, 0x16ed5c82U, + 0xcf8a2b1cU, 0x79a792b4U, 0x07f3f0f2U, 0x694ea1e2U, + 0xda65cdf4U, 0x0506d5beU, 0x34d11f62U, 0xa6c48afeU, + 0x2e349d53U, 0xf3a2a055U, 0x8a0532e1U, 0xf6a475ebU, + 0x830b39ecU, 0x6040aaefU, 0x715e069fU, 0x6ebd5110U, + 0x213ef98aU, 0xdd963d06U, 0x3eddae05U, 0xe64d46bdU, + 0x5491b58dU, 0xc471055dU, 0x06046fd4U, 0x5060ff15U, + 0x981924fbU, 0xbdd697e9U, 0x4089cc43U, 0xd967779eU, + 0xe8b0bd42U, 0x8907888bU, 0x19e7385bU, 0xc879dbeeU, + 0x7ca1470aU, 0x427ce90fU, 0x84f8c91eU, 0x00000000U, + 0x80098386U, 0x2b3248edU, 0x111eac70U, 0x5a6c4e72U, + 0x0efdfbffU, 0x850f5638U, 0xae3d1ed5U, 0x2d362739U, + 0x0f0a64d9U, 0x5c6821a6U, 0x5b9bd154U, 0x36243a2eU, + 0x0a0cb167U, 0x57930fe7U, 0xeeb4d296U, 0x9b1b9e91U, + 0xc0804fc5U, 0xdc61a220U, 0x775a694bU, 0x121c161aU, + 0x93e20abaU, 0xa0c0e52aU, 0x223c43e0U, 0x1b121d17U, + 0x090e0b0dU, 0x8bf2adc7U, 0xb62db9a8U, 0x1e14c8a9U, + 0xf1578519U, 0x75af4c07U, 0x99eebbddU, 0x7fa3fd60U, + 0x01f79f26U, 0x725cbcf5U, 0x6644c53bU, 0xfb5b347eU, + 0x438b7629U, 0x23cbdcc6U, 0xedb668fcU, 0xe4b863f1U, + 0x31d7cadcU, 0x63421085U, 0x97134022U, 0xc6842011U, + 0x4a857d24U, 0xbbd2f83dU, 0xf9ae1132U, 0x29c76da1U, + 0x9e1d4b2fU, 0xb2dcf330U, 0x860dec52U, 0xc177d0e3U, + 0xb32b6c16U, 0x70a999b9U, 0x9411fa48U, 0xe9472264U, + 0xfca8c48cU, 0xf0a01a3fU, 0x7d56d82cU, 0x3322ef90U, + 0x4987c74eU, 0x38d9c1d1U, 0xca8cfea2U, 0xd498360bU, + 0xf5a6cf81U, 0x7aa528deU, 0xb7da268eU, 0xad3fa4bfU, + 0x3a2ce49dU, 0x78500d92U, 0x5f6a9bccU, 0x7e546246U, + 0x8df6c213U, 0xd890e8b8U, 0x392e5ef7U, 0xc382f5afU, + 0x5d9fbe80U, 0xd0697c93U, 0xd56fa92dU, 0x25cfb312U, + 0xacc83b99U, 0x1810a77dU, 0x9ce86e63U, 0x3bdb7bbbU, + 0x26cd0978U, 0x596ef418U, 0x9aec01b7U, 0x4f83a89aU, + 0x95e6656eU, 0xffaa7ee6U, 0xbc2108cfU, 0x15efe6e8U, + 0xe7bad99bU, 0x6f4ace36U, 0x9fead409U, 0xb029d67cU, + 0xa431afb2U, 0x3f2a3123U, 0xa5c63094U, 0xa235c066U, + 0x4e7437bcU, 0x82fca6caU, 0x90e0b0d0U, 0xa73315d8U, + 0x04f14a98U, 0xec41f7daU, 0xcd7f0e50U, 0x91172ff6U, + 0x4d768dd6U, 0xef434db0U, 0xaacc544dU, 0x96e4df04U, + 0xd19ee3b5U, 0x6a4c1b88U, 0x2cc1b81fU, 0x65467f51U, + 0x5e9d04eaU, 0x8c015d35U, 0x87fa7374U, 0x0bfb2e41U, + 0x67b35a1dU, 0xdb9252d2U, 0x10e93356U, 0xd66d1347U, + 0xd79a8c61U, 0xa1377a0cU, 0xf8598e14U, 0x13eb893cU, + 0xa9ceee27U, 0x61b735c9U, 0x1ce1ede5U, 0x477a3cb1U, + 0xd29c59dfU, 0xf2553f73U, 0x141879ceU, 0xc773bf37U, + 0xf753eacdU, 0xfd5f5baaU, 0x3ddf146fU, 0x447886dbU, + 0xafca81f3U, 0x68b93ec4U, 0x24382c34U, 0xa3c25f40U, + 0x1d1672c3U, 0xe2bc0c25U, 0x3c288b49U, 0x0dff4195U, + 0xa8397101U, 0x0c08deb3U, 0xb4d89ce4U, 0x566490c1U, + 0xcb7b6184U, 0x32d570b6U, 0x6c48745cU, 0xb8d04257U, + 0x5150a7f4U, 0x7e536541U, 0x1ac3a417U, 0x3a965e27U, + 0x3bcb6babU, 0x1ff1459dU, 0xacab58faU, 0x4b9303e3U, + 0x2055fa30U, 0xadf66d76U, 0x889176ccU, 0xf5254c02U, + 0x4ffcd7e5U, 0xc5d7cb2aU, 0x26804435U, 0xb58fa362U, + 0xde495ab1U, 0x25671bbaU, 0x45980eeaU, 0x5de1c0feU, + 0xc302752fU, 0x8112f04cU, 0x8da39746U, 0x6bc6f9d3U, + 0x03e75f8fU, 0x15959c92U, 0xbfeb7a6dU, 0x95da5952U, + 0xd42d83beU, 0x58d32174U, 0x492969e0U, 0x8e44c8c9U, + 0x756a89c2U, 0xf478798eU, 0x996b3e58U, 0x27dd71b9U, + 0xbeb64fe1U, 0xf017ad88U, 0xc966ac20U, 0x7db43aceU, + 0x63184adfU, 0xe582311aU, 0x97603351U, 0x62457f53U, + 0xb1e07764U, 0xbb84ae6bU, 0xfe1ca081U, 0xf9942b08U, + 0x70586848U, 0x8f19fd45U, 0x94876cdeU, 0x52b7f87bU, + 0xab23d373U, 0x72e2024bU, 0xe3578f1fU, 0x662aab55U, + 0xb20728ebU, 0x2f03c2b5U, 0x869a7bc5U, 0xd3a50837U, + 0x30f28728U, 0x23b2a5bfU, 0x02ba6a03U, 0xed5c8216U, + 0x8a2b1ccfU, 0xa792b479U, 0xf3f0f207U, 0x4ea1e269U, + 0x65cdf4daU, 0x06d5be05U, 0xd11f6234U, 0xc48afea6U, + 0x349d532eU, 0xa2a055f3U, 0x0532e18aU, 0xa475ebf6U, + 0x0b39ec83U, 0x40aaef60U, 0x5e069f71U, 0xbd51106eU, + 0x3ef98a21U, 0x963d06ddU, 0xddae053eU, 0x4d46bde6U, + 0x91b58d54U, 0x71055dc4U, 0x046fd406U, 0x60ff1550U, + 0x1924fb98U, 0xd697e9bdU, 0x89cc4340U, 0x67779ed9U, + 0xb0bd42e8U, 0x07888b89U, 0xe7385b19U, 0x79dbeec8U, + 0xa1470a7cU, 0x7ce90f42U, 0xf8c91e84U, 0x00000000U, + 0x09838680U, 0x3248ed2bU, 0x1eac7011U, 0x6c4e725aU, + 0xfdfbff0eU, 0x0f563885U, 0x3d1ed5aeU, 0x3627392dU, + 0x0a64d90fU, 0x6821a65cU, 0x9bd1545bU, 0x243a2e36U, + 0x0cb1670aU, 0x930fe757U, 0xb4d296eeU, 0x1b9e919bU, + 0x804fc5c0U, 0x61a220dcU, 0x5a694b77U, 0x1c161a12U, + 0xe20aba93U, 0xc0e52aa0U, 0x3c43e022U, 0x121d171bU, + 0x0e0b0d09U, 0xf2adc78bU, 0x2db9a8b6U, 0x14c8a91eU, + 0x578519f1U, 0xaf4c0775U, 0xeebbdd99U, 0xa3fd607fU, + 0xf79f2601U, 0x5cbcf572U, 0x44c53b66U, 0x5b347efbU, + 0x8b762943U, 0xcbdcc623U, 0xb668fcedU, 0xb863f1e4U, + 0xd7cadc31U, 0x42108563U, 0x13402297U, 0x842011c6U, + 0x857d244aU, 0xd2f83dbbU, 0xae1132f9U, 0xc76da129U, + 0x1d4b2f9eU, 0xdcf330b2U, 0x0dec5286U, 0x77d0e3c1U, + 0x2b6c16b3U, 0xa999b970U, 0x11fa4894U, 0x472264e9U, + 0xa8c48cfcU, 0xa01a3ff0U, 0x56d82c7dU, 0x22ef9033U, + 0x87c74e49U, 0xd9c1d138U, 0x8cfea2caU, 0x98360bd4U, + 0xa6cf81f5U, 0xa528de7aU, 0xda268eb7U, 0x3fa4bfadU, + 0x2ce49d3aU, 0x500d9278U, 0x6a9bcc5fU, 0x5462467eU, + 0xf6c2138dU, 0x90e8b8d8U, 0x2e5ef739U, 0x82f5afc3U, + 0x9fbe805dU, 0x697c93d0U, 0x6fa92dd5U, 0xcfb31225U, + 0xc83b99acU, 0x10a77d18U, 0xe86e639cU, 0xdb7bbb3bU, + 0xcd097826U, 0x6ef41859U, 0xec01b79aU, 0x83a89a4fU, + 0xe6656e95U, 0xaa7ee6ffU, 0x2108cfbcU, 0xefe6e815U, + 0xbad99be7U, 0x4ace366fU, 0xead4099fU, 0x29d67cb0U, + 0x31afb2a4U, 0x2a31233fU, 0xc63094a5U, 0x35c066a2U, + 0x7437bc4eU, 0xfca6ca82U, 0xe0b0d090U, 0x3315d8a7U, + 0xf14a9804U, 0x41f7daecU, 0x7f0e50cdU, 0x172ff691U, + 0x768dd64dU, 0x434db0efU, 0xcc544daaU, 0xe4df0496U, + 0x9ee3b5d1U, 0x4c1b886aU, 0xc1b81f2cU, 0x467f5165U, + 0x9d04ea5eU, 0x015d358cU, 0xfa737487U, 0xfb2e410bU, + 0xb35a1d67U, 0x9252d2dbU, 0xe9335610U, 0x6d1347d6U, + 0x9a8c61d7U, 0x377a0ca1U, 0x598e14f8U, 0xeb893c13U, + 0xceee27a9U, 0xb735c961U, 0xe1ede51cU, 0x7a3cb147U, + 0x9c59dfd2U, 0x553f73f2U, 0x1879ce14U, 0x73bf37c7U, + 0x53eacdf7U, 0x5f5baafdU, 0xdf146f3dU, 0x7886db44U, + 0xca81f3afU, 0xb93ec468U, 0x382c3424U, 0xc25f40a3U, + 0x1672c31dU, 0xbc0c25e2U, 0x288b493cU, 0xff41950dU, + 0x397101a8U, 0x08deb30cU, 0xd89ce4b4U, 0x6490c156U, + 0x7b6184cbU, 0xd570b632U, 0x48745c6cU, 0xd04257b8U, +}; + +__constant static const uint AES_KEY_FILL[16] = { + 0x6daca553, 0x62716609, 0xdbb5552b, 0xb4f44917, + 0x6d7caf07, 0x846a710d, 0x1725d378, 0x0da1dc4e, + 0x3f1262f1, 0x9f947ec6, 0xf4c0794f, 0x3e20e345, + 0x6aef8135, 0xb1ba317c, 0x16314c88, 0x49169154, +}; + +__constant static const uint AES_STATE_HASH[16] = { + 0x92b52c0d, 0x9fa856de, 0xcc82db47, 0xd7983aad, + 0x338d996e, 0x15c7b798, 0xf59e125a, 0xace78057, + 0x6a770017, 0xae62c7d0, 0x5079506b, 0xe8a07ce4, + 0x630a240c, 0x07ad828d, 0x79a10005, 0x7e994948, +}; + +uint get_byte32(uint a, uint start_bit) { return (a >> start_bit) & 0xFF; } + +#define fillAes_name fillAes1Rx4_scratchpad +#define outputSize RANDOMX_SCRATCHPAD_L3 +#define outputSize0 (outputSize + 64) +#define unroll_factor 8 +#define num_rounds 1 + #include "fillAes1Rx4.cl" +#undef num_rounds +#undef unroll_factor +#undef outputSize +#undef outputSize0 +#undef fillAes_name + +#define fillAes_name fillAes4Rx4_entropy +#define outputSize ENTROPY_SIZE +#define outputSize0 outputSize +#define unroll_factor 2 +#define num_rounds 4 + #include "fillAes1Rx4.cl" +#undef num_rounds +#undef unroll_factor +#undef outputSize +#undef outputSize0 +#undef fillAes_name + +#define inputSize RANDOMX_SCRATCHPAD_L3 + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void hashAes1Rx4(__global const void* input, __global void* hash, uint hashOffsetBytes, uint hashStrideBytes, uint batch_size) +{ + __local uint T[2048]; + + const uint global_index = get_global_id(0); + if (global_index >= batch_size * 4) + return; + + const uint idx = global_index / 4; + const uint sub = global_index % 4; + + for (uint i = get_local_id(0), step = get_local_size(0); i < 2048; i += step) + T[i] = AES_TABLE[i]; + + barrier(CLK_LOCAL_MEM_FENCE); + + uint x[4] = { AES_STATE_HASH[sub * 4], AES_STATE_HASH[sub * 4 + 1], AES_STATE_HASH[sub * 4 + 2], AES_STATE_HASH[sub * 4 + 3] }; + + const uint s1 = ((sub & 1) == 0) ? 8 : 24; + const uint s3 = ((sub & 1) == 0) ? 24 : 8; + + __global const uint4* p = ((__global uint4*) input) + idx * ((inputSize + 64) / sizeof(uint4)) + sub; + + __local const uint* const t0 = ((sub & 1) == 0) ? T : (T + 1024); + __local const uint* const t1 = ((sub & 1) == 0) ? (T + 256) : (T + 1792); + __local const uint* const t2 = ((sub & 1) == 0) ? (T + 512) : (T + 1536); + __local const uint* const t3 = ((sub & 1) == 0) ? (T + 768) : (T + 1280); + + #pragma unroll(8) + for (uint i = 0; i < inputSize / sizeof(uint4); i += 4, p += 4) + { + uint k[4], y[4]; + *(uint4*)(k) = *p; + y[0] = t0[get_byte32(x[0], 0)] ^ t1[get_byte32(x[1], s1)] ^ t2[get_byte32(x[2], 16)] ^ t3[get_byte32(x[3], s3)] ^ k[0]; + y[1] = t0[get_byte32(x[1], 0)] ^ t1[get_byte32(x[2], s1)] ^ t2[get_byte32(x[3], 16)] ^ t3[get_byte32(x[0], s3)] ^ k[1]; + y[2] = t0[get_byte32(x[2], 0)] ^ t1[get_byte32(x[3], s1)] ^ t2[get_byte32(x[0], 16)] ^ t3[get_byte32(x[1], s3)] ^ k[2]; + y[3] = t0[get_byte32(x[3], 0)] ^ t1[get_byte32(x[0], s1)] ^ t2[get_byte32(x[1], 16)] ^ t3[get_byte32(x[2], s3)] ^ k[3]; + x[0] = y[0]; + x[1] = y[1]; + x[2] = y[2]; + x[3] = y[3]; + } + + uint y[4]; + + y[0] = t0[get_byte32(x[0], 0)] ^ t1[get_byte32(x[1], s1)] ^ t2[get_byte32(x[2], 16)] ^ t3[get_byte32(x[3], s3)] ^ 0xf6fa8389; + y[1] = t0[get_byte32(x[1], 0)] ^ t1[get_byte32(x[2], s1)] ^ t2[get_byte32(x[3], 16)] ^ t3[get_byte32(x[0], s3)] ^ 0x8b24949f; + y[2] = t0[get_byte32(x[2], 0)] ^ t1[get_byte32(x[3], s1)] ^ t2[get_byte32(x[0], 16)] ^ t3[get_byte32(x[1], s3)] ^ 0x90dc56bf; + y[3] = t0[get_byte32(x[3], 0)] ^ t1[get_byte32(x[0], s1)] ^ t2[get_byte32(x[1], 16)] ^ t3[get_byte32(x[2], s3)] ^ 0x06890201; + + x[0] = t0[get_byte32(y[0], 0)] ^ t1[get_byte32(y[1], s1)] ^ t2[get_byte32(y[2], 16)] ^ t3[get_byte32(y[3], s3)] ^ 0x61b263d1; + x[1] = t0[get_byte32(y[1], 0)] ^ t1[get_byte32(y[2], s1)] ^ t2[get_byte32(y[3], 16)] ^ t3[get_byte32(y[0], s3)] ^ 0x51f4e03c; + x[2] = t0[get_byte32(y[2], 0)] ^ t1[get_byte32(y[3], s1)] ^ t2[get_byte32(y[0], 16)] ^ t3[get_byte32(y[1], s3)] ^ 0xee1043c6; + x[3] = t0[get_byte32(y[3], 0)] ^ t1[get_byte32(y[0], s1)] ^ t2[get_byte32(y[1], 16)] ^ t3[get_byte32(y[2], s3)] ^ 0xed18f99b; + + *((__global uint4*)(hash) + idx * (hashStrideBytes / sizeof(uint4)) + sub + (hashOffsetBytes / sizeof(uint4))) = *(uint4*)(x); +} diff --git a/src/backend/opencl/cl/rx/blake2b.cl b/src/backend/opencl/cl/rx/blake2b.cl new file mode 100644 index 000000000..b33e12064 --- /dev/null +++ b/src/backend/opencl/cl/rx/blake2b.cl @@ -0,0 +1,157 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +__constant static const uchar blake2b_sigma[12 * 16] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, + 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, + 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, + 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, + 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, + 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, + 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, + 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, + 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, +}; + +enum Blake2b_IV +{ + iv0 = 0x6a09e667f3bcc908ul, + iv1 = 0xbb67ae8584caa73bul, + iv2 = 0x3c6ef372fe94f82bul, + iv3 = 0xa54ff53a5f1d36f1ul, + iv4 = 0x510e527fade682d1ul, + iv5 = 0x9b05688c2b3e6c1ful, + iv6 = 0x1f83d9abfb41bd6bul, + iv7 = 0x5be0cd19137e2179ul, +}; + +ulong rotr64(ulong a, ulong shift) { return rotate(a, 64 - shift); } + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r * 16 + 2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r * 16 + 2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while (0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while (0) + +#define BLAKE2B_ROUNDS() ROUND(0);ROUND(1);ROUND(2);ROUND(3);ROUND(4);ROUND(5);ROUND(6);ROUND(7);ROUND(8);ROUND(9);ROUND(10);ROUND(11); + +void blake2b_512_process_single_block(ulong *h, const ulong* m, uint blockTemplateSize) +{ + ulong v[16] = + { + iv0 ^ 0x01010040, iv1, iv2, iv3, iv4 , iv5, iv6, iv7, + iv0 , iv1, iv2, iv3, iv4 ^ blockTemplateSize, iv5, ~iv6, iv7, + }; + + BLAKE2B_ROUNDS(); + + h[0] = v[0] ^ v[ 8] ^ iv0 ^ 0x01010040; + h[1] = v[1] ^ v[ 9] ^ iv1; + h[2] = v[2] ^ v[10] ^ iv2; + h[3] = v[3] ^ v[11] ^ iv3; + h[4] = v[4] ^ v[12] ^ iv4; + h[5] = v[5] ^ v[13] ^ iv5; + h[6] = v[6] ^ v[14] ^ iv6; + h[7] = v[7] ^ v[15] ^ iv7; +} + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void blake2b_initial_hash(__global void *out, __global const void* blockTemplate, uint blockTemplateSize, uint start_nonce) +{ + const uint global_index = get_global_id(0); + + __global const ulong* p = (__global const ulong*) blockTemplate; + ulong m[16] = { + (blockTemplateSize > 0) ? p[ 0] : 0, + (blockTemplateSize > 8) ? p[ 1] : 0, + (blockTemplateSize > 16) ? p[ 2] : 0, + (blockTemplateSize > 24) ? p[ 3] : 0, + (blockTemplateSize > 32) ? p[ 4] : 0, + (blockTemplateSize > 40) ? p[ 5] : 0, + (blockTemplateSize > 48) ? p[ 6] : 0, + (blockTemplateSize > 56) ? p[ 7] : 0, + (blockTemplateSize > 64) ? p[ 8] : 0, + (blockTemplateSize > 72) ? p[ 9] : 0, + (blockTemplateSize > 80) ? p[10] : 0, + (blockTemplateSize > 88) ? p[11] : 0, + (blockTemplateSize > 96) ? p[12] : 0, + (blockTemplateSize > 104) ? p[13] : 0, + (blockTemplateSize > 112) ? p[14] : 0, + (blockTemplateSize > 120) ? p[15] : 0, + }; + + if (blockTemplateSize % sizeof(ulong)) + m[blockTemplateSize / sizeof(ulong)] &= (ulong)(-1) >> (64 - (blockTemplateSize % sizeof(ulong)) * 8); + + const ulong nonce = start_nonce + global_index; + m[4] = (m[4] & ((ulong)(-1) >> 8)) | (nonce << 56); + m[5] = (m[5] & ((ulong)(-1) << 24)) | (nonce >> 8); + + ulong hash[8]; + blake2b_512_process_single_block(hash, m, blockTemplateSize); + + __global ulong* t = ((__global ulong*) out) + global_index * 8; + t[0] = hash[0]; + t[1] = hash[1]; + t[2] = hash[2]; + t[3] = hash[3]; + t[4] = hash[4]; + t[5] = hash[5]; + t[6] = hash[6]; + t[7] = hash[7]; +} + +#define in_len 256 + +#define out_len 32 +#define blake2b_512_process_double_block_name blake2b_512_process_double_block_32 +#define blake2b_hash_registers_name blake2b_hash_registers_32 + #include "blake2b_double_block.cl" +#undef blake2b_hash_registers_name +#undef blake2b_512_process_double_block_name +#undef out_len + +#define out_len 64 +#define blake2b_512_process_double_block_name blake2b_512_process_double_block_64 +#define blake2b_hash_registers_name blake2b_hash_registers_64 + #include "blake2b_double_block.cl" +#undef blake2b_hash_registers_name +#undef blake2b_512_process_double_block_name +#undef out_len diff --git a/src/backend/opencl/cl/rx/blake2b_double_block.cl b/src/backend/opencl/cl/rx/blake2b_double_block.cl new file mode 100644 index 000000000..fef7259fb --- /dev/null +++ b/src/backend/opencl/cl/rx/blake2b_double_block.cl @@ -0,0 +1,100 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +void blake2b_512_process_double_block_name(ulong *out, ulong* m, __global const ulong* in) +{ + ulong v[16] = + { + iv0 ^ (0x01010000u | out_len), iv1, iv2, iv3, iv4 , iv5, iv6, iv7, + iv0 , iv1, iv2, iv3, iv4 ^ 128, iv5, iv6, iv7, + }; + + BLAKE2B_ROUNDS(); + + ulong h[8]; + v[0] = h[0] = v[0] ^ v[8] ^ iv0 ^ (0x01010000u | out_len); + v[1] = h[1] = v[1] ^ v[9] ^ iv1; + v[2] = h[2] = v[2] ^ v[10] ^ iv2; + v[3] = h[3] = v[3] ^ v[11] ^ iv3; + v[4] = h[4] = v[4] ^ v[12] ^ iv4; + v[5] = h[5] = v[5] ^ v[13] ^ iv5; + v[6] = h[6] = v[6] ^ v[14] ^ iv6; + v[7] = h[7] = v[7] ^ v[15] ^ iv7; + v[8] = iv0; + v[9] = iv1; + v[10] = iv2; + v[11] = iv3; + v[12] = iv4 ^ in_len; + v[13] = iv5; + v[14] = ~iv6; + v[15] = iv7; + + m[ 0] = (in_len > 128) ? in[16] : 0; + m[ 1] = (in_len > 136) ? in[17] : 0; + m[ 2] = (in_len > 144) ? in[18] : 0; + m[ 3] = (in_len > 152) ? in[19] : 0; + m[ 4] = (in_len > 160) ? in[20] : 0; + m[ 5] = (in_len > 168) ? in[21] : 0; + m[ 6] = (in_len > 176) ? in[22] : 0; + m[ 7] = (in_len > 184) ? in[23] : 0; + m[ 8] = (in_len > 192) ? in[24] : 0; + m[ 9] = (in_len > 200) ? in[25] : 0; + m[10] = (in_len > 208) ? in[26] : 0; + m[11] = (in_len > 216) ? in[27] : 0; + m[12] = (in_len > 224) ? in[28] : 0; + m[13] = (in_len > 232) ? in[29] : 0; + m[14] = (in_len > 240) ? in[30] : 0; + m[15] = (in_len > 248) ? in[31] : 0; + + if (in_len % sizeof(ulong)) + m[(in_len - 128) / sizeof(ulong)] &= (ulong)(-1) >> (64 - (in_len % sizeof(ulong)) * 8); + + BLAKE2B_ROUNDS(); + + if (out_len > 0) out[0] = h[0] ^ v[0] ^ v[8]; + if (out_len > 8) out[1] = h[1] ^ v[1] ^ v[9]; + if (out_len > 16) out[2] = h[2] ^ v[2] ^ v[10]; + if (out_len > 24) out[3] = h[3] ^ v[3] ^ v[11]; + if (out_len > 32) out[4] = h[4] ^ v[4] ^ v[12]; + if (out_len > 40) out[5] = h[5] ^ v[5] ^ v[13]; + if (out_len > 48) out[6] = h[6] ^ v[6] ^ v[14]; + if (out_len > 56) out[7] = h[7] ^ v[7] ^ v[15]; +} + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void blake2b_hash_registers_name(__global void *out, __global const void* in, uint inStrideBytes) +{ + const uint global_index = get_global_id(0); + __global const ulong* p = ((__global const ulong*) in) + global_index * (inStrideBytes / sizeof(ulong)); + __global ulong* h = ((__global ulong*) out) + global_index * (out_len / sizeof(ulong)); + + ulong m[16] = { p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] }; + + ulong hash[8]; + blake2b_512_process_double_block_name(hash, m, p); + + if (out_len > 0) h[0] = hash[0]; + if (out_len > 8) h[1] = hash[1]; + if (out_len > 16) h[2] = hash[2]; + if (out_len > 24) h[3] = hash[3]; + if (out_len > 32) h[4] = hash[4]; + if (out_len > 40) h[5] = hash[5]; + if (out_len > 48) h[6] = hash[6]; + if (out_len > 56) h[7] = hash[7]; +} diff --git a/src/backend/opencl/cl/rx/fillAes1Rx4.cl b/src/backend/opencl/cl/rx/fillAes1Rx4.cl new file mode 100644 index 000000000..2a0033153 --- /dev/null +++ b/src/backend/opencl/cl/rx/fillAes1Rx4.cl @@ -0,0 +1,118 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void fillAes_name(__global void* state, __global void* out, uint batch_size, uint rx_version) +{ + __local uint T[2048]; + + const uint global_index = get_global_id(0); + if (global_index >= batch_size * 4) + return; + + const uint idx = global_index / 4; + const uint sub = global_index % 4; + + for (uint i = get_local_id(0), step = get_local_size(0); i < 2048; i += step) + T[i] = AES_TABLE[i]; + + barrier(CLK_LOCAL_MEM_FENCE); + +#if num_rounds != 4 + const uint k[4] = { AES_KEY_FILL[sub * 4], AES_KEY_FILL[sub * 4 + 1], AES_KEY_FILL[sub * 4 + 2], AES_KEY_FILL[sub * 4 + 3] }; +#else + const bool b1 = (rx_version < 104); + const bool b2 = (sub < 2); + + uint k[16]; + k[ 0] = b1 ? 0xf890465du : (b2 ? 0x6421aaddu : 0xb5826f73u); + k[ 1] = b1 ? 0x7ffbe4a6u : (b2 ? 0xd1833ddbu : 0xe3d6a7a6u); + k[ 2] = b1 ? 0x141f82b7u : (b2 ? 0x2f546d2bu : 0x3d518b6du); + k[ 3] = b1 ? 0xcf359e95u : (b2 ? 0x99e5d23fu : 0x229effb4u); + k[ 4] = b1 ? 0x6a55c450u : (b2 ? 0xb20e3450u : 0xc7566bf3u); + k[ 5] = b1 ? 0xfee8278au : (b2 ? 0xb6913f55u : 0x9c10b3d9u); + k[ 6] = b1 ? 0xbd5c5ac3u : (b2 ? 0x06f79d53u : 0xe9024d4eu); + k[ 7] = b1 ? 0x6741ffdcu : (b2 ? 0xa5dfcde5u : 0xb272b7d2u); + k[ 8] = b1 ? 0x114c47a4u : (b2 ? 0x5c3ed904u : 0xf273c9e7u); + k[ 9] = b1 ? 0xd524fde4u : (b2 ? 0x515e7bafu : 0xf765a38bu); + k[10] = b1 ? 0xa7279ad2u : (b2 ? 0x0aa4679fu : 0x2ba9660au); + k[11] = b1 ? 0x3d324aacu : (b2 ? 0x171c02bfu : 0xf63befa7u); + k[12] = b1 ? 0x810c3a2au : (b2 ? 0x85623763u : 0x7a7cd609u); + k[13] = b1 ? 0x99a9aeffu : (b2 ? 0xe78f5d08u : 0x915839deu); + k[14] = b1 ? 0x42d3dbd9u : (b2 ? 0xcd673785u : 0x0c06d1fdu); + k[15] = b1 ? 0x76f6db08u : (b2 ? 0xd8ded291u : 0xc0b0762du); +#endif + + __global uint* s = ((__global uint*) state) + idx * (64 / sizeof(uint)) + sub * (16 / sizeof(uint)); + uint x[4] = { s[0], s[1], s[2], s[3] }; + + const uint s1 = (sub & 1) ? 8 : 24; + const uint s3 = (sub & 1) ? 24 : 8; + + __global uint4* p = ((__global uint4*) out) + idx * (outputSize0 / sizeof(uint4)) + sub; + + const __local uint* const t0 = (sub & 1) ? T : (T + 1024); + const __local uint* const t1 = (sub & 1) ? (T + 256) : (T + 1792); + const __local uint* const t2 = (sub & 1) ? (T + 512) : (T + 1536); + const __local uint* const t3 = (sub & 1) ? (T + 768) : (T + 1280); + + #pragma unroll(unroll_factor) + for (uint i = 0; i < outputSize / sizeof(uint4); i += 4, p += 4) + { + uint y[4]; + +#if num_rounds != 4 + y[0] = t0[get_byte32(x[0], 0)] ^ t1[get_byte32(x[1], s1)] ^ t2[get_byte32(x[2], 16)] ^ t3[get_byte32(x[3], s3)] ^ k[0]; + y[1] = t0[get_byte32(x[1], 0)] ^ t1[get_byte32(x[2], s1)] ^ t2[get_byte32(x[3], 16)] ^ t3[get_byte32(x[0], s3)] ^ k[1]; + y[2] = t0[get_byte32(x[2], 0)] ^ t1[get_byte32(x[3], s1)] ^ t2[get_byte32(x[0], 16)] ^ t3[get_byte32(x[1], s3)] ^ k[2]; + y[3] = t0[get_byte32(x[3], 0)] ^ t1[get_byte32(x[0], s1)] ^ t2[get_byte32(x[1], 16)] ^ t3[get_byte32(x[2], s3)] ^ k[3]; + + *p = *(uint4*)(y); + + x[0] = y[0]; + x[1] = y[1]; + x[2] = y[2]; + x[3] = y[3]; +#else + y[0] = t0[get_byte32(x[0], 0)] ^ t1[get_byte32(x[1], s1)] ^ t2[get_byte32(x[2], 16)] ^ t3[get_byte32(x[3], s3)] ^ k[ 0]; + y[1] = t0[get_byte32(x[1], 0)] ^ t1[get_byte32(x[2], s1)] ^ t2[get_byte32(x[3], 16)] ^ t3[get_byte32(x[0], s3)] ^ k[ 1]; + y[2] = t0[get_byte32(x[2], 0)] ^ t1[get_byte32(x[3], s1)] ^ t2[get_byte32(x[0], 16)] ^ t3[get_byte32(x[1], s3)] ^ k[ 2]; + y[3] = t0[get_byte32(x[3], 0)] ^ t1[get_byte32(x[0], s1)] ^ t2[get_byte32(x[1], 16)] ^ t3[get_byte32(x[2], s3)] ^ k[ 3]; + + x[0] = t0[get_byte32(y[0], 0)] ^ t1[get_byte32(y[1], s1)] ^ t2[get_byte32(y[2], 16)] ^ t3[get_byte32(y[3], s3)] ^ k[ 4]; + x[1] = t0[get_byte32(y[1], 0)] ^ t1[get_byte32(y[2], s1)] ^ t2[get_byte32(y[3], 16)] ^ t3[get_byte32(y[0], s3)] ^ k[ 5]; + x[2] = t0[get_byte32(y[2], 0)] ^ t1[get_byte32(y[3], s1)] ^ t2[get_byte32(y[0], 16)] ^ t3[get_byte32(y[1], s3)] ^ k[ 6]; + x[3] = t0[get_byte32(y[3], 0)] ^ t1[get_byte32(y[0], s1)] ^ t2[get_byte32(y[1], 16)] ^ t3[get_byte32(y[2], s3)] ^ k[ 7]; + + y[0] = t0[get_byte32(x[0], 0)] ^ t1[get_byte32(x[1], s1)] ^ t2[get_byte32(x[2], 16)] ^ t3[get_byte32(x[3], s3)] ^ k[ 8]; + y[1] = t0[get_byte32(x[1], 0)] ^ t1[get_byte32(x[2], s1)] ^ t2[get_byte32(x[3], 16)] ^ t3[get_byte32(x[0], s3)] ^ k[ 9]; + y[2] = t0[get_byte32(x[2], 0)] ^ t1[get_byte32(x[3], s1)] ^ t2[get_byte32(x[0], 16)] ^ t3[get_byte32(x[1], s3)] ^ k[10]; + y[3] = t0[get_byte32(x[3], 0)] ^ t1[get_byte32(x[0], s1)] ^ t2[get_byte32(x[1], 16)] ^ t3[get_byte32(x[2], s3)] ^ k[11]; + + x[0] = t0[get_byte32(y[0], 0)] ^ t1[get_byte32(y[1], s1)] ^ t2[get_byte32(y[2], 16)] ^ t3[get_byte32(y[3], s3)] ^ k[12]; + x[1] = t0[get_byte32(y[1], 0)] ^ t1[get_byte32(y[2], s1)] ^ t2[get_byte32(y[3], 16)] ^ t3[get_byte32(y[0], s3)] ^ k[13]; + x[2] = t0[get_byte32(y[2], 0)] ^ t1[get_byte32(y[3], s1)] ^ t2[get_byte32(y[0], 16)] ^ t3[get_byte32(y[1], s3)] ^ k[14]; + x[3] = t0[get_byte32(y[3], 0)] ^ t1[get_byte32(y[0], s1)] ^ t2[get_byte32(y[1], 16)] ^ t3[get_byte32(y[2], s3)] ^ k[15]; + + *p = *(uint4*)(x); +#endif + } + + *(__global uint4*)(s) = *(uint4*)(x); +} diff --git a/src/backend/opencl/cl/rx/randomx.cl b/src/backend/opencl/cl/rx/randomx.cl new file mode 100644 index 000000000..eacabb28b --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx.cl @@ -0,0 +1,14 @@ +#include "../cn/algorithm.cl" + +#if (ALGO == ALGO_RX_0) +#include "randomx_constants_monero.h" +#elif (ALGO == ALGO_RX_WOW) +#include "randomx_constants_wow.h" +#elif (ALGO == ALGO_RX_LOKI) +#include "randomx_constants_loki.h" +#endif + +#include "aes.cl" +#include "blake2b.cl" +#include "randomx_vm.cl" +#include "randomx_jit.cl" diff --git a/src/backend/opencl/cl/rx/randomx_cl.h b/src/backend/opencl/cl/rx/randomx_cl.h new file mode 100644 index 000000000..e4fe558b1 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_cl.h @@ -0,0 +1,3874 @@ +#pragma once + +namespace xmrig { + +static char randomx_cl[123696] = { + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x30,0x20,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x43,0x4e,0x5f,0x31,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x32,0x20,0x32,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x20,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f, + 0x46,0x41,0x53,0x54,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x41,0x4c,0x46,0x20,0x35,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x58,0x41,0x4f,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x43,0x4e,0x5f,0x52,0x54,0x4f,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x52,0x57,0x5a,0x20,0x38,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x5a,0x4c,0x53,0x20,0x39,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c, + 0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x44,0x4f,0x55,0x42,0x4c,0x45,0x20,0x31,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f, + 0x47,0x50,0x55,0x20,0x31,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x4c,0x49,0x54,0x45,0x5f,0x30,0x20,0x31,0x32, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x4c,0x49,0x54,0x45,0x5f,0x31,0x20,0x31,0x33,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x30,0x20,0x31,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c, + 0x47,0x4f,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x54,0x55,0x42,0x45,0x20,0x31,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f, + 0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59,0x5f,0x58,0x48,0x56,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x43,0x4e, + 0x5f,0x50,0x49,0x43,0x4f,0x5f,0x30,0x20,0x31,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x30,0x20,0x31,0x38,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x57,0x4f,0x57,0x20,0x31,0x39,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41, + 0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x4c,0x4f,0x4b,0x49,0x20,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x41,0x52,0x32,0x5f, + 0x43,0x48,0x55,0x4b,0x57,0x41,0x20,0x32,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x41,0x52,0x32,0x5f,0x57,0x52,0x4b,0x5a,0x20, + 0x32,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x55,0x4e,0x4b,0x4e,0x4f,0x57,0x4e,0x20,0x30,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43, + 0x4e,0x5f,0x4c,0x49,0x54,0x45,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x48,0x45,0x41,0x56,0x59, + 0x20,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x43,0x4e,0x5f,0x50,0x49,0x43,0x4f,0x20,0x34,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x46,0x41,0x4d,0x49,0x4c,0x59,0x5f,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x5f,0x58,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x46,0x41, + 0x4d,0x49,0x4c,0x59,0x5f,0x41,0x52,0x47,0x4f,0x4e,0x32,0x20,0x36,0x0a,0x23,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f, + 0x52,0x58,0x5f,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x42,0x41, + 0x53,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x31,0x34,0x37,0x34,0x38,0x33,0x36,0x34,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x45,0x58,0x54,0x52,0x41,0x5f,0x53,0x49,0x5a,0x45,0x20,0x33,0x33,0x35,0x35,0x34,0x33,0x36,0x38,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x20,0x32,0x30,0x39, + 0x37,0x31,0x35,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f, + 0x4c,0x32,0x20,0x32,0x36,0x32,0x31,0x34,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x4c,0x31,0x20,0x31,0x36,0x33,0x38,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55, + 0x4d,0x50,0x5f,0x42,0x49,0x54,0x53,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f, + 0x46,0x46,0x53,0x45,0x54,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44, + 0x44,0x5f,0x52,0x53,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44, + 0x44,0x5f,0x4d,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f, + 0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d, + 0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x20,0x31, + 0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x20,0x34,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x20,0x34,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x20,0x38,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x20,0x32,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x20,0x31,0x35,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52,0x20,0x33,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x44,0x49,0x56,0x5f,0x4d,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53, + 0x51,0x52,0x54,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52, + 0x41,0x4e,0x43,0x48,0x20,0x32,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52, + 0x4f,0x55,0x4e,0x44,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f, + 0x52,0x45,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x4e,0x4f,0x50,0x20,0x30, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x49,0x54,0x45,0x4d,0x5f,0x53,0x49, + 0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49, + 0x5a,0x45,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x48,0x41,0x53,0x48,0x5f,0x53,0x49,0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x31,0x32,0x38,0x20,0x2b,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x38,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x45,0x47,0x49,0x53,0x54, + 0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a, + 0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x34,0x20,0x2d,0x20,0x52,0x45, + 0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f, + 0x43,0x4f,0x55,0x4e,0x54,0x20,0x28,0x28,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2f,0x20,0x34,0x29,0x20,0x2d,0x20,0x32,0x29,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f, + 0x53,0x49,0x5a,0x45,0x20,0x2b,0x20,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2b,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52, + 0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x49,0x4e,0x47, + 0x5f,0x4d,0x4f,0x44,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x20,0x3f,0x20,0x2d,0x31, + 0x20,0x3a,0x20,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x31,0x34,0x29,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x31,0x38,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x32,0x31,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28,0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20, + 0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x57,0x4f,0x57,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54, + 0x41,0x53,0x45,0x54,0x5f,0x42,0x41,0x53,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x31,0x34,0x37,0x34,0x38,0x33,0x36,0x34,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x45,0x58,0x54,0x52,0x41,0x5f,0x53,0x49,0x5a,0x45,0x20,0x33,0x33,0x35, + 0x35,0x34,0x33,0x36,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44, + 0x5f,0x4c,0x33,0x20,0x31,0x30,0x34,0x38,0x35,0x37,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41, + 0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x32,0x20,0x31,0x33,0x31,0x30,0x37,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x31,0x20,0x31,0x36,0x33,0x38,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x42,0x49,0x54,0x53,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x20,0x32,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x4d,0x55,0x4c,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d, + 0x55,0x4c,0x5f,0x4d,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c, + 0x48,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48, + 0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48, + 0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48, + 0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52, + 0x43,0x50,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52, + 0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x20,0x31, + 0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x20,0x35,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x20,0x31,0x30,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x20,0x30,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x20,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x20,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52,0x20,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x4e,0x4f,0x50,0x20,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54, + 0x5f,0x49,0x54,0x45,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52, + 0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x48,0x41,0x53,0x48,0x5f,0x53,0x49,0x5a,0x45, + 0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x31,0x32,0x38,0x20,0x2b,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x38,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4d,0x4d, + 0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20, + 0x2a,0x20,0x34,0x20,0x2d,0x20,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4d, + 0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x20,0x28,0x28,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2f,0x20,0x34, + 0x29,0x20,0x2d,0x20,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x45, + 0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2b,0x20,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2b,0x20,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x4f,0x55,0x4e,0x44,0x49,0x4e,0x47,0x5f,0x4d,0x4f,0x44,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f, + 0x55,0x4e,0x44,0x20,0x3f,0x20,0x2d,0x31,0x20,0x3a,0x20,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x20,0x28,0x33,0x32, + 0x20,0x2d,0x20,0x31,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x31,0x37,0x29,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x32,0x30,0x29,0x0a,0x23,0x65,0x6c,0x69,0x66,0x20,0x28, + 0x41,0x4c,0x47,0x4f,0x20,0x3d,0x3d,0x20,0x41,0x4c,0x47,0x4f,0x5f,0x52,0x58,0x5f,0x4c,0x4f,0x4b,0x49,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x42,0x41,0x53,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x31,0x34,0x37,0x34,0x38,0x33,0x36, + 0x34,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x45,0x58,0x54,0x52,0x41, + 0x5f,0x53,0x49,0x5a,0x45,0x20,0x33,0x33,0x35,0x35,0x34,0x33,0x36,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53, + 0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x20,0x32,0x30,0x39,0x37,0x31,0x35,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x32,0x20,0x32,0x36,0x32,0x31,0x34,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x31,0x20,0x31,0x36,0x33,0x38,0x34,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x42,0x49,0x54,0x53,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x20,0x32,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x20,0x37,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x20,0x31,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x49,0x58,0x4f,0x52,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52, + 0x4f,0x52,0x5f,0x52,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c, + 0x5f,0x52,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f, + 0x52,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52, + 0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x20,0x31, + 0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x20,0x35,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x20,0x31,0x36,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x20,0x35,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52,0x20,0x33,0x32,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x20,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x20,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x20,0x31,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x4e,0x4f,0x50,0x20,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x49,0x54,0x45,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x33,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x48, + 0x41,0x53,0x48,0x5f,0x53,0x49,0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45, + 0x20,0x28,0x31,0x32,0x38,0x20,0x2b,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x38, + 0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52, + 0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x34,0x20,0x2d,0x20,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x29,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x20,0x28,0x28,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f, + 0x53,0x49,0x5a,0x45,0x20,0x2f,0x20,0x34,0x29,0x20,0x2d,0x20,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f, + 0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2b,0x20,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53, + 0x49,0x5a,0x45,0x20,0x2b,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x34,0x29,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x55,0x4e,0x44,0x49,0x4e,0x47,0x5f,0x4d,0x4f,0x44,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x20,0x3f,0x20,0x2d,0x31,0x20,0x3a,0x20,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f, + 0x43,0x5f,0x4c,0x31,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x31,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x20,0x28,0x33, + 0x32,0x20,0x2d,0x20,0x31,0x38,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x20,0x28,0x33,0x32,0x20,0x2d,0x20,0x32,0x31,0x29, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x5f,0x54,0x41,0x42,0x4c,0x45,0x5b,0x32,0x30,0x34,0x38,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x30,0x78,0x61,0x35,0x36,0x33,0x36, + 0x33,0x63,0x36,0x55,0x2c,0x30,0x78,0x38,0x34,0x37,0x63,0x37,0x63,0x66,0x38,0x55,0x2c,0x30,0x78,0x39,0x39,0x37,0x37,0x37,0x37,0x65,0x65,0x55,0x2c,0x30,0x78,0x38, + 0x64,0x37,0x62,0x37,0x62,0x66,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x64,0x66,0x32,0x66,0x32,0x66,0x66,0x55,0x2c,0x30,0x78,0x62,0x64,0x36,0x62,0x36,0x62,0x64,0x36, + 0x55,0x2c,0x30,0x78,0x62,0x31,0x36,0x66,0x36,0x66,0x64,0x65,0x55,0x2c,0x30,0x78,0x35,0x34,0x63,0x35,0x63,0x35,0x39,0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x33, + 0x30,0x33,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x55,0x2c,0x30,0x78,0x61,0x39,0x36,0x37,0x36,0x37,0x63,0x65,0x55,0x2c,0x30, + 0x78,0x37,0x64,0x32,0x62,0x32,0x62,0x35,0x36,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x66,0x65,0x66,0x65,0x65,0x37,0x55,0x2c,0x30,0x78,0x36,0x32,0x64,0x37,0x64,0x37, + 0x62,0x35,0x55,0x2c,0x30,0x78,0x65,0x36,0x61,0x62,0x61,0x62,0x34,0x64,0x55,0x2c,0x30,0x78,0x39,0x61,0x37,0x36,0x37,0x36,0x65,0x63,0x55,0x2c,0x0a,0x30,0x78,0x34, + 0x35,0x63,0x61,0x63,0x61,0x38,0x66,0x55,0x2c,0x30,0x78,0x39,0x64,0x38,0x32,0x38,0x32,0x31,0x66,0x55,0x2c,0x30,0x78,0x34,0x30,0x63,0x39,0x63,0x39,0x38,0x39,0x55, + 0x2c,0x30,0x78,0x38,0x37,0x37,0x64,0x37,0x64,0x66,0x61,0x55,0x2c,0x0a,0x30,0x78,0x31,0x35,0x66,0x61,0x66,0x61,0x65,0x66,0x55,0x2c,0x30,0x78,0x65,0x62,0x35,0x39, + 0x35,0x39,0x62,0x32,0x55,0x2c,0x30,0x78,0x63,0x39,0x34,0x37,0x34,0x37,0x38,0x65,0x55,0x2c,0x30,0x78,0x30,0x62,0x66,0x30,0x66,0x30,0x66,0x62,0x55,0x2c,0x0a,0x30, + 0x78,0x65,0x63,0x61,0x64,0x61,0x64,0x34,0x31,0x55,0x2c,0x30,0x78,0x36,0x37,0x64,0x34,0x64,0x34,0x62,0x33,0x55,0x2c,0x30,0x78,0x66,0x64,0x61,0x32,0x61,0x32,0x35, + 0x66,0x55,0x2c,0x30,0x78,0x65,0x61,0x61,0x66,0x61,0x66,0x34,0x35,0x55,0x2c,0x0a,0x30,0x78,0x62,0x66,0x39,0x63,0x39,0x63,0x32,0x33,0x55,0x2c,0x30,0x78,0x66,0x37, + 0x61,0x34,0x61,0x34,0x35,0x33,0x55,0x2c,0x30,0x78,0x39,0x36,0x37,0x32,0x37,0x32,0x65,0x34,0x55,0x2c,0x30,0x78,0x35,0x62,0x63,0x30,0x63,0x30,0x39,0x62,0x55,0x2c, + 0x0a,0x30,0x78,0x63,0x32,0x62,0x37,0x62,0x37,0x37,0x35,0x55,0x2c,0x30,0x78,0x31,0x63,0x66,0x64,0x66,0x64,0x65,0x31,0x55,0x2c,0x30,0x78,0x61,0x65,0x39,0x33,0x39, + 0x33,0x33,0x64,0x55,0x2c,0x30,0x78,0x36,0x61,0x32,0x36,0x32,0x36,0x34,0x63,0x55,0x2c,0x0a,0x30,0x78,0x35,0x61,0x33,0x36,0x33,0x36,0x36,0x63,0x55,0x2c,0x30,0x78, + 0x34,0x31,0x33,0x66,0x33,0x66,0x37,0x65,0x55,0x2c,0x30,0x78,0x30,0x32,0x66,0x37,0x66,0x37,0x66,0x35,0x55,0x2c,0x30,0x78,0x34,0x66,0x63,0x63,0x63,0x63,0x38,0x33, + 0x55,0x2c,0x0a,0x30,0x78,0x35,0x63,0x33,0x34,0x33,0x34,0x36,0x38,0x55,0x2c,0x30,0x78,0x66,0x34,0x61,0x35,0x61,0x35,0x35,0x31,0x55,0x2c,0x30,0x78,0x33,0x34,0x65, + 0x35,0x65,0x35,0x64,0x31,0x55,0x2c,0x30,0x78,0x30,0x38,0x66,0x31,0x66,0x31,0x66,0x39,0x55,0x2c,0x0a,0x30,0x78,0x39,0x33,0x37,0x31,0x37,0x31,0x65,0x32,0x55,0x2c, + 0x30,0x78,0x37,0x33,0x64,0x38,0x64,0x38,0x61,0x62,0x55,0x2c,0x30,0x78,0x35,0x33,0x33,0x31,0x33,0x31,0x36,0x32,0x55,0x2c,0x30,0x78,0x33,0x66,0x31,0x35,0x31,0x35, + 0x32,0x61,0x55,0x2c,0x0a,0x30,0x78,0x30,0x63,0x30,0x34,0x30,0x34,0x30,0x38,0x55,0x2c,0x30,0x78,0x35,0x32,0x63,0x37,0x63,0x37,0x39,0x35,0x55,0x2c,0x30,0x78,0x36, + 0x35,0x32,0x33,0x32,0x33,0x34,0x36,0x55,0x2c,0x30,0x78,0x35,0x65,0x63,0x33,0x63,0x33,0x39,0x64,0x55,0x2c,0x0a,0x30,0x78,0x32,0x38,0x31,0x38,0x31,0x38,0x33,0x30, + 0x55,0x2c,0x30,0x78,0x61,0x31,0x39,0x36,0x39,0x36,0x33,0x37,0x55,0x2c,0x30,0x78,0x30,0x66,0x30,0x35,0x30,0x35,0x30,0x61,0x55,0x2c,0x30,0x78,0x62,0x35,0x39,0x61, + 0x39,0x61,0x32,0x66,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x65,0x55,0x2c,0x30,0x78,0x33,0x36,0x31,0x32,0x31,0x32,0x32,0x34,0x55,0x2c,0x30, + 0x78,0x39,0x62,0x38,0x30,0x38,0x30,0x31,0x62,0x55,0x2c,0x30,0x78,0x33,0x64,0x65,0x32,0x65,0x32,0x64,0x66,0x55,0x2c,0x0a,0x30,0x78,0x32,0x36,0x65,0x62,0x65,0x62, + 0x63,0x64,0x55,0x2c,0x30,0x78,0x36,0x39,0x32,0x37,0x32,0x37,0x34,0x65,0x55,0x2c,0x30,0x78,0x63,0x64,0x62,0x32,0x62,0x32,0x37,0x66,0x55,0x2c,0x30,0x78,0x39,0x66, + 0x37,0x35,0x37,0x35,0x65,0x61,0x55,0x2c,0x0a,0x30,0x78,0x31,0x62,0x30,0x39,0x30,0x39,0x31,0x32,0x55,0x2c,0x30,0x78,0x39,0x65,0x38,0x33,0x38,0x33,0x31,0x64,0x55, + 0x2c,0x30,0x78,0x37,0x34,0x32,0x63,0x32,0x63,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x65,0x31,0x61,0x31,0x61,0x33,0x34,0x55,0x2c,0x0a,0x30,0x78,0x32,0x64,0x31,0x62, + 0x31,0x62,0x33,0x36,0x55,0x2c,0x30,0x78,0x62,0x32,0x36,0x65,0x36,0x65,0x64,0x63,0x55,0x2c,0x30,0x78,0x65,0x65,0x35,0x61,0x35,0x61,0x62,0x34,0x55,0x2c,0x30,0x78, + 0x66,0x62,0x61,0x30,0x61,0x30,0x35,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x36,0x35,0x32,0x35,0x32,0x61,0x34,0x55,0x2c,0x30,0x78,0x34,0x64,0x33,0x62,0x33,0x62,0x37, + 0x36,0x55,0x2c,0x30,0x78,0x36,0x31,0x64,0x36,0x64,0x36,0x62,0x37,0x55,0x2c,0x30,0x78,0x63,0x65,0x62,0x33,0x62,0x33,0x37,0x64,0x55,0x2c,0x0a,0x30,0x78,0x37,0x62, + 0x32,0x39,0x32,0x39,0x35,0x32,0x55,0x2c,0x30,0x78,0x33,0x65,0x65,0x33,0x65,0x33,0x64,0x64,0x55,0x2c,0x30,0x78,0x37,0x31,0x32,0x66,0x32,0x66,0x35,0x65,0x55,0x2c, + 0x30,0x78,0x39,0x37,0x38,0x34,0x38,0x34,0x31,0x33,0x55,0x2c,0x0a,0x30,0x78,0x66,0x35,0x35,0x33,0x35,0x33,0x61,0x36,0x55,0x2c,0x30,0x78,0x36,0x38,0x64,0x31,0x64, + 0x31,0x62,0x39,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x32,0x63,0x65,0x64,0x65,0x64,0x63,0x31,0x55,0x2c,0x0a,0x30,0x78, + 0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x31,0x66,0x66,0x63,0x66,0x63,0x65,0x33,0x55,0x2c,0x30,0x78,0x63,0x38,0x62,0x31,0x62,0x31,0x37,0x39, + 0x55,0x2c,0x30,0x78,0x65,0x64,0x35,0x62,0x35,0x62,0x62,0x36,0x55,0x2c,0x0a,0x30,0x78,0x62,0x65,0x36,0x61,0x36,0x61,0x64,0x34,0x55,0x2c,0x30,0x78,0x34,0x36,0x63, + 0x62,0x63,0x62,0x38,0x64,0x55,0x2c,0x30,0x78,0x64,0x39,0x62,0x65,0x62,0x65,0x36,0x37,0x55,0x2c,0x30,0x78,0x34,0x62,0x33,0x39,0x33,0x39,0x37,0x32,0x55,0x2c,0x0a, + 0x30,0x78,0x64,0x65,0x34,0x61,0x34,0x61,0x39,0x34,0x55,0x2c,0x30,0x78,0x64,0x34,0x34,0x63,0x34,0x63,0x39,0x38,0x55,0x2c,0x30,0x78,0x65,0x38,0x35,0x38,0x35,0x38, + 0x62,0x30,0x55,0x2c,0x30,0x78,0x34,0x61,0x63,0x66,0x63,0x66,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x62,0x64,0x30,0x64,0x30,0x62,0x62,0x55,0x2c,0x30,0x78,0x32, + 0x61,0x65,0x66,0x65,0x66,0x63,0x35,0x55,0x2c,0x30,0x78,0x65,0x35,0x61,0x61,0x61,0x61,0x34,0x66,0x55,0x2c,0x30,0x78,0x31,0x36,0x66,0x62,0x66,0x62,0x65,0x64,0x55, + 0x2c,0x0a,0x30,0x78,0x63,0x35,0x34,0x33,0x34,0x33,0x38,0x36,0x55,0x2c,0x30,0x78,0x64,0x37,0x34,0x64,0x34,0x64,0x39,0x61,0x55,0x2c,0x30,0x78,0x35,0x35,0x33,0x33, + 0x33,0x33,0x36,0x36,0x55,0x2c,0x30,0x78,0x39,0x34,0x38,0x35,0x38,0x35,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78,0x63,0x66,0x34,0x35,0x34,0x35,0x38,0x61,0x55,0x2c,0x30, + 0x78,0x31,0x30,0x66,0x39,0x66,0x39,0x65,0x39,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x32,0x30,0x32,0x30,0x34,0x55,0x2c,0x30,0x78,0x38,0x31,0x37,0x66,0x37,0x66,0x66, + 0x65,0x55,0x2c,0x0a,0x30,0x78,0x66,0x30,0x35,0x30,0x35,0x30,0x61,0x30,0x55,0x2c,0x30,0x78,0x34,0x34,0x33,0x63,0x33,0x63,0x37,0x38,0x55,0x2c,0x30,0x78,0x62,0x61, + 0x39,0x66,0x39,0x66,0x32,0x35,0x55,0x2c,0x30,0x78,0x65,0x33,0x61,0x38,0x61,0x38,0x34,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x33,0x35,0x31,0x35,0x31,0x61,0x32,0x55, + 0x2c,0x30,0x78,0x66,0x65,0x61,0x33,0x61,0x33,0x35,0x64,0x55,0x2c,0x30,0x78,0x63,0x30,0x34,0x30,0x34,0x30,0x38,0x30,0x55,0x2c,0x30,0x78,0x38,0x61,0x38,0x66,0x38, + 0x66,0x30,0x35,0x55,0x2c,0x0a,0x30,0x78,0x61,0x64,0x39,0x32,0x39,0x32,0x33,0x66,0x55,0x2c,0x30,0x78,0x62,0x63,0x39,0x64,0x39,0x64,0x32,0x31,0x55,0x2c,0x30,0x78, + 0x34,0x38,0x33,0x38,0x33,0x38,0x37,0x30,0x55,0x2c,0x30,0x78,0x30,0x34,0x66,0x35,0x66,0x35,0x66,0x31,0x55,0x2c,0x0a,0x30,0x78,0x64,0x66,0x62,0x63,0x62,0x63,0x36, + 0x33,0x55,0x2c,0x30,0x78,0x63,0x31,0x62,0x36,0x62,0x36,0x37,0x37,0x55,0x2c,0x30,0x78,0x37,0x35,0x64,0x61,0x64,0x61,0x61,0x66,0x55,0x2c,0x30,0x78,0x36,0x33,0x32, + 0x31,0x32,0x31,0x34,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x31,0x61,0x66,0x66,0x66,0x66,0x65,0x35,0x55,0x2c, + 0x30,0x78,0x30,0x65,0x66,0x33,0x66,0x33,0x66,0x64,0x55,0x2c,0x30,0x78,0x36,0x64,0x64,0x32,0x64,0x32,0x62,0x66,0x55,0x2c,0x0a,0x30,0x78,0x34,0x63,0x63,0x64,0x63, + 0x64,0x38,0x31,0x55,0x2c,0x30,0x78,0x31,0x34,0x30,0x63,0x30,0x63,0x31,0x38,0x55,0x2c,0x30,0x78,0x33,0x35,0x31,0x33,0x31,0x33,0x32,0x36,0x55,0x2c,0x30,0x78,0x32, + 0x66,0x65,0x63,0x65,0x63,0x63,0x33,0x55,0x2c,0x0a,0x30,0x78,0x65,0x31,0x35,0x66,0x35,0x66,0x62,0x65,0x55,0x2c,0x30,0x78,0x61,0x32,0x39,0x37,0x39,0x37,0x33,0x35, + 0x55,0x2c,0x30,0x78,0x63,0x63,0x34,0x34,0x34,0x34,0x38,0x38,0x55,0x2c,0x30,0x78,0x33,0x39,0x31,0x37,0x31,0x37,0x32,0x65,0x55,0x2c,0x0a,0x30,0x78,0x35,0x37,0x63, + 0x34,0x63,0x34,0x39,0x33,0x55,0x2c,0x30,0x78,0x66,0x32,0x61,0x37,0x61,0x37,0x35,0x35,0x55,0x2c,0x30,0x78,0x38,0x32,0x37,0x65,0x37,0x65,0x66,0x63,0x55,0x2c,0x30, + 0x78,0x34,0x37,0x33,0x64,0x33,0x64,0x37,0x61,0x55,0x2c,0x0a,0x30,0x78,0x61,0x63,0x36,0x34,0x36,0x34,0x63,0x38,0x55,0x2c,0x30,0x78,0x65,0x37,0x35,0x64,0x35,0x64, + 0x62,0x61,0x55,0x2c,0x30,0x78,0x32,0x62,0x31,0x39,0x31,0x39,0x33,0x32,0x55,0x2c,0x30,0x78,0x39,0x35,0x37,0x33,0x37,0x33,0x65,0x36,0x55,0x2c,0x0a,0x30,0x78,0x61, + 0x30,0x36,0x30,0x36,0x30,0x63,0x30,0x55,0x2c,0x30,0x78,0x39,0x38,0x38,0x31,0x38,0x31,0x31,0x39,0x55,0x2c,0x30,0x78,0x64,0x31,0x34,0x66,0x34,0x66,0x39,0x65,0x55, + 0x2c,0x30,0x78,0x37,0x66,0x64,0x63,0x64,0x63,0x61,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x36,0x32,0x32,0x32,0x32,0x34,0x34,0x55,0x2c,0x30,0x78,0x37,0x65,0x32,0x61, + 0x32,0x61,0x35,0x34,0x55,0x2c,0x30,0x78,0x61,0x62,0x39,0x30,0x39,0x30,0x33,0x62,0x55,0x2c,0x30,0x78,0x38,0x33,0x38,0x38,0x38,0x38,0x30,0x62,0x55,0x2c,0x0a,0x30, + 0x78,0x63,0x61,0x34,0x36,0x34,0x36,0x38,0x63,0x55,0x2c,0x30,0x78,0x32,0x39,0x65,0x65,0x65,0x65,0x63,0x37,0x55,0x2c,0x30,0x78,0x64,0x33,0x62,0x38,0x62,0x38,0x36, + 0x62,0x55,0x2c,0x30,0x78,0x33,0x63,0x31,0x34,0x31,0x34,0x32,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x39,0x64,0x65,0x64,0x65,0x61,0x37,0x55,0x2c,0x30,0x78,0x65,0x32, + 0x35,0x65,0x35,0x65,0x62,0x63,0x55,0x2c,0x30,0x78,0x31,0x64,0x30,0x62,0x30,0x62,0x31,0x36,0x55,0x2c,0x30,0x78,0x37,0x36,0x64,0x62,0x64,0x62,0x61,0x64,0x55,0x2c, + 0x0a,0x30,0x78,0x33,0x62,0x65,0x30,0x65,0x30,0x64,0x62,0x55,0x2c,0x30,0x78,0x35,0x36,0x33,0x32,0x33,0x32,0x36,0x34,0x55,0x2c,0x30,0x78,0x34,0x65,0x33,0x61,0x33, + 0x61,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x65,0x30,0x61,0x30,0x61,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x64,0x62,0x34,0x39,0x34,0x39,0x39,0x32,0x55,0x2c,0x30,0x78, + 0x30,0x61,0x30,0x36,0x30,0x36,0x30,0x63,0x55,0x2c,0x30,0x78,0x36,0x63,0x32,0x34,0x32,0x34,0x34,0x38,0x55,0x2c,0x30,0x78,0x65,0x34,0x35,0x63,0x35,0x63,0x62,0x38, + 0x55,0x2c,0x0a,0x30,0x78,0x35,0x64,0x63,0x32,0x63,0x32,0x39,0x66,0x55,0x2c,0x30,0x78,0x36,0x65,0x64,0x33,0x64,0x33,0x62,0x64,0x55,0x2c,0x30,0x78,0x65,0x66,0x61, + 0x63,0x61,0x63,0x34,0x33,0x55,0x2c,0x30,0x78,0x61,0x36,0x36,0x32,0x36,0x32,0x63,0x34,0x55,0x2c,0x0a,0x30,0x78,0x61,0x38,0x39,0x31,0x39,0x31,0x33,0x39,0x55,0x2c, + 0x30,0x78,0x61,0x34,0x39,0x35,0x39,0x35,0x33,0x31,0x55,0x2c,0x30,0x78,0x33,0x37,0x65,0x34,0x65,0x34,0x64,0x33,0x55,0x2c,0x30,0x78,0x38,0x62,0x37,0x39,0x37,0x39, + 0x66,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x32,0x65,0x37,0x65,0x37,0x64,0x35,0x55,0x2c,0x30,0x78,0x34,0x33,0x63,0x38,0x63,0x38,0x38,0x62,0x55,0x2c,0x30,0x78,0x35, + 0x39,0x33,0x37,0x33,0x37,0x36,0x65,0x55,0x2c,0x30,0x78,0x62,0x37,0x36,0x64,0x36,0x64,0x64,0x61,0x55,0x2c,0x0a,0x30,0x78,0x38,0x63,0x38,0x64,0x38,0x64,0x30,0x31, + 0x55,0x2c,0x30,0x78,0x36,0x34,0x64,0x35,0x64,0x35,0x62,0x31,0x55,0x2c,0x30,0x78,0x64,0x32,0x34,0x65,0x34,0x65,0x39,0x63,0x55,0x2c,0x30,0x78,0x65,0x30,0x61,0x39, + 0x61,0x39,0x34,0x39,0x55,0x2c,0x0a,0x30,0x78,0x62,0x34,0x36,0x63,0x36,0x63,0x64,0x38,0x55,0x2c,0x30,0x78,0x66,0x61,0x35,0x36,0x35,0x36,0x61,0x63,0x55,0x2c,0x30, + 0x78,0x30,0x37,0x66,0x34,0x66,0x34,0x66,0x33,0x55,0x2c,0x30,0x78,0x32,0x35,0x65,0x61,0x65,0x61,0x63,0x66,0x55,0x2c,0x0a,0x30,0x78,0x61,0x66,0x36,0x35,0x36,0x35, + 0x63,0x61,0x55,0x2c,0x30,0x78,0x38,0x65,0x37,0x61,0x37,0x61,0x66,0x34,0x55,0x2c,0x30,0x78,0x65,0x39,0x61,0x65,0x61,0x65,0x34,0x37,0x55,0x2c,0x30,0x78,0x31,0x38, + 0x30,0x38,0x30,0x38,0x31,0x30,0x55,0x2c,0x0a,0x30,0x78,0x64,0x35,0x62,0x61,0x62,0x61,0x36,0x66,0x55,0x2c,0x30,0x78,0x38,0x38,0x37,0x38,0x37,0x38,0x66,0x30,0x55, + 0x2c,0x30,0x78,0x36,0x66,0x32,0x35,0x32,0x35,0x34,0x61,0x55,0x2c,0x30,0x78,0x37,0x32,0x32,0x65,0x32,0x65,0x35,0x63,0x55,0x2c,0x0a,0x30,0x78,0x32,0x34,0x31,0x63, + 0x31,0x63,0x33,0x38,0x55,0x2c,0x30,0x78,0x66,0x31,0x61,0x36,0x61,0x36,0x35,0x37,0x55,0x2c,0x30,0x78,0x63,0x37,0x62,0x34,0x62,0x34,0x37,0x33,0x55,0x2c,0x30,0x78, + 0x35,0x31,0x63,0x36,0x63,0x36,0x39,0x37,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x65,0x38,0x65,0x38,0x63,0x62,0x55,0x2c,0x30,0x78,0x37,0x63,0x64,0x64,0x64,0x64,0x61, + 0x31,0x55,0x2c,0x30,0x78,0x39,0x63,0x37,0x34,0x37,0x34,0x65,0x38,0x55,0x2c,0x30,0x78,0x32,0x31,0x31,0x66,0x31,0x66,0x33,0x65,0x55,0x2c,0x0a,0x30,0x78,0x64,0x64, + 0x34,0x62,0x34,0x62,0x39,0x36,0x55,0x2c,0x30,0x78,0x64,0x63,0x62,0x64,0x62,0x64,0x36,0x31,0x55,0x2c,0x30,0x78,0x38,0x36,0x38,0x62,0x38,0x62,0x30,0x64,0x55,0x2c, + 0x30,0x78,0x38,0x35,0x38,0x61,0x38,0x61,0x30,0x66,0x55,0x2c,0x0a,0x30,0x78,0x39,0x30,0x37,0x30,0x37,0x30,0x65,0x30,0x55,0x2c,0x30,0x78,0x34,0x32,0x33,0x65,0x33, + 0x65,0x37,0x63,0x55,0x2c,0x30,0x78,0x63,0x34,0x62,0x35,0x62,0x35,0x37,0x31,0x55,0x2c,0x30,0x78,0x61,0x61,0x36,0x36,0x36,0x36,0x63,0x63,0x55,0x2c,0x0a,0x30,0x78, + 0x64,0x38,0x34,0x38,0x34,0x38,0x39,0x30,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x55,0x2c,0x30,0x78,0x30,0x31,0x66,0x36,0x66,0x36,0x66,0x37, + 0x55,0x2c,0x30,0x78,0x31,0x32,0x30,0x65,0x30,0x65,0x31,0x63,0x55,0x2c,0x0a,0x30,0x78,0x61,0x33,0x36,0x31,0x36,0x31,0x63,0x32,0x55,0x2c,0x30,0x78,0x35,0x66,0x33, + 0x35,0x33,0x35,0x36,0x61,0x55,0x2c,0x30,0x78,0x66,0x39,0x35,0x37,0x35,0x37,0x61,0x65,0x55,0x2c,0x30,0x78,0x64,0x30,0x62,0x39,0x62,0x39,0x36,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x39,0x31,0x38,0x36,0x38,0x36,0x31,0x37,0x55,0x2c,0x30,0x78,0x35,0x38,0x63,0x31,0x63,0x31,0x39,0x39,0x55,0x2c,0x30,0x78,0x32,0x37,0x31,0x64,0x31,0x64, + 0x33,0x61,0x55,0x2c,0x30,0x78,0x62,0x39,0x39,0x65,0x39,0x65,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x38,0x65,0x31,0x65,0x31,0x64,0x39,0x55,0x2c,0x30,0x78,0x31, + 0x33,0x66,0x38,0x66,0x38,0x65,0x62,0x55,0x2c,0x30,0x78,0x62,0x33,0x39,0x38,0x39,0x38,0x32,0x62,0x55,0x2c,0x30,0x78,0x33,0x33,0x31,0x31,0x31,0x31,0x32,0x32,0x55, + 0x2c,0x0a,0x30,0x78,0x62,0x62,0x36,0x39,0x36,0x39,0x64,0x32,0x55,0x2c,0x30,0x78,0x37,0x30,0x64,0x39,0x64,0x39,0x61,0x39,0x55,0x2c,0x30,0x78,0x38,0x39,0x38,0x65, + 0x38,0x65,0x30,0x37,0x55,0x2c,0x30,0x78,0x61,0x37,0x39,0x34,0x39,0x34,0x33,0x33,0x55,0x2c,0x0a,0x30,0x78,0x62,0x36,0x39,0x62,0x39,0x62,0x32,0x64,0x55,0x2c,0x30, + 0x78,0x32,0x32,0x31,0x65,0x31,0x65,0x33,0x63,0x55,0x2c,0x30,0x78,0x39,0x32,0x38,0x37,0x38,0x37,0x31,0x35,0x55,0x2c,0x30,0x78,0x32,0x30,0x65,0x39,0x65,0x39,0x63, + 0x39,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x63,0x65,0x63,0x65,0x38,0x37,0x55,0x2c,0x30,0x78,0x66,0x66,0x35,0x35,0x35,0x35,0x61,0x61,0x55,0x2c,0x30,0x78,0x37,0x38, + 0x32,0x38,0x32,0x38,0x35,0x30,0x55,0x2c,0x30,0x78,0x37,0x61,0x64,0x66,0x64,0x66,0x61,0x35,0x55,0x2c,0x0a,0x30,0x78,0x38,0x66,0x38,0x63,0x38,0x63,0x30,0x33,0x55, + 0x2c,0x30,0x78,0x66,0x38,0x61,0x31,0x61,0x31,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x30,0x38,0x39,0x38,0x39,0x30,0x39,0x55,0x2c,0x30,0x78,0x31,0x37,0x30,0x64,0x30, + 0x64,0x31,0x61,0x55,0x2c,0x0a,0x30,0x78,0x64,0x61,0x62,0x66,0x62,0x66,0x36,0x35,0x55,0x2c,0x30,0x78,0x33,0x31,0x65,0x36,0x65,0x36,0x64,0x37,0x55,0x2c,0x30,0x78, + 0x63,0x36,0x34,0x32,0x34,0x32,0x38,0x34,0x55,0x2c,0x30,0x78,0x62,0x38,0x36,0x38,0x36,0x38,0x64,0x30,0x55,0x2c,0x0a,0x30,0x78,0x63,0x33,0x34,0x31,0x34,0x31,0x38, + 0x32,0x55,0x2c,0x30,0x78,0x62,0x30,0x39,0x39,0x39,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x37,0x37,0x32,0x64,0x32,0x64,0x35,0x61,0x55,0x2c,0x30,0x78,0x31,0x31,0x30, + 0x66,0x30,0x66,0x31,0x65,0x55,0x2c,0x0a,0x30,0x78,0x63,0x62,0x62,0x30,0x62,0x30,0x37,0x62,0x55,0x2c,0x30,0x78,0x66,0x63,0x35,0x34,0x35,0x34,0x61,0x38,0x55,0x2c, + 0x30,0x78,0x64,0x36,0x62,0x62,0x62,0x62,0x36,0x64,0x55,0x2c,0x30,0x78,0x33,0x61,0x31,0x36,0x31,0x36,0x32,0x63,0x55,0x2c,0x0a,0x30,0x78,0x36,0x33,0x36,0x33,0x63, + 0x36,0x61,0x35,0x55,0x2c,0x30,0x78,0x37,0x63,0x37,0x63,0x66,0x38,0x38,0x34,0x55,0x2c,0x30,0x78,0x37,0x37,0x37,0x37,0x65,0x65,0x39,0x39,0x55,0x2c,0x30,0x78,0x37, + 0x62,0x37,0x62,0x66,0x36,0x38,0x64,0x55,0x2c,0x0a,0x30,0x78,0x66,0x32,0x66,0x32,0x66,0x66,0x30,0x64,0x55,0x2c,0x30,0x78,0x36,0x62,0x36,0x62,0x64,0x36,0x62,0x64, + 0x55,0x2c,0x30,0x78,0x36,0x66,0x36,0x66,0x64,0x65,0x62,0x31,0x55,0x2c,0x30,0x78,0x63,0x35,0x63,0x35,0x39,0x31,0x35,0x34,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x33, + 0x30,0x36,0x30,0x35,0x30,0x55,0x2c,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x33,0x55,0x2c,0x30,0x78,0x36,0x37,0x36,0x37,0x63,0x65,0x61,0x39,0x55,0x2c,0x30, + 0x78,0x32,0x62,0x32,0x62,0x35,0x36,0x37,0x64,0x55,0x2c,0x0a,0x30,0x78,0x66,0x65,0x66,0x65,0x65,0x37,0x31,0x39,0x55,0x2c,0x30,0x78,0x64,0x37,0x64,0x37,0x62,0x35, + 0x36,0x32,0x55,0x2c,0x30,0x78,0x61,0x62,0x61,0x62,0x34,0x64,0x65,0x36,0x55,0x2c,0x30,0x78,0x37,0x36,0x37,0x36,0x65,0x63,0x39,0x61,0x55,0x2c,0x0a,0x30,0x78,0x63, + 0x61,0x63,0x61,0x38,0x66,0x34,0x35,0x55,0x2c,0x30,0x78,0x38,0x32,0x38,0x32,0x31,0x66,0x39,0x64,0x55,0x2c,0x30,0x78,0x63,0x39,0x63,0x39,0x38,0x39,0x34,0x30,0x55, + 0x2c,0x30,0x78,0x37,0x64,0x37,0x64,0x66,0x61,0x38,0x37,0x55,0x2c,0x0a,0x30,0x78,0x66,0x61,0x66,0x61,0x65,0x66,0x31,0x35,0x55,0x2c,0x30,0x78,0x35,0x39,0x35,0x39, + 0x62,0x32,0x65,0x62,0x55,0x2c,0x30,0x78,0x34,0x37,0x34,0x37,0x38,0x65,0x63,0x39,0x55,0x2c,0x30,0x78,0x66,0x30,0x66,0x30,0x66,0x62,0x30,0x62,0x55,0x2c,0x0a,0x30, + 0x78,0x61,0x64,0x61,0x64,0x34,0x31,0x65,0x63,0x55,0x2c,0x30,0x78,0x64,0x34,0x64,0x34,0x62,0x33,0x36,0x37,0x55,0x2c,0x30,0x78,0x61,0x32,0x61,0x32,0x35,0x66,0x66, + 0x64,0x55,0x2c,0x30,0x78,0x61,0x66,0x61,0x66,0x34,0x35,0x65,0x61,0x55,0x2c,0x0a,0x30,0x78,0x39,0x63,0x39,0x63,0x32,0x33,0x62,0x66,0x55,0x2c,0x30,0x78,0x61,0x34, + 0x61,0x34,0x35,0x33,0x66,0x37,0x55,0x2c,0x30,0x78,0x37,0x32,0x37,0x32,0x65,0x34,0x39,0x36,0x55,0x2c,0x30,0x78,0x63,0x30,0x63,0x30,0x39,0x62,0x35,0x62,0x55,0x2c, + 0x0a,0x30,0x78,0x62,0x37,0x62,0x37,0x37,0x35,0x63,0x32,0x55,0x2c,0x30,0x78,0x66,0x64,0x66,0x64,0x65,0x31,0x31,0x63,0x55,0x2c,0x30,0x78,0x39,0x33,0x39,0x33,0x33, + 0x64,0x61,0x65,0x55,0x2c,0x30,0x78,0x32,0x36,0x32,0x36,0x34,0x63,0x36,0x61,0x55,0x2c,0x0a,0x30,0x78,0x33,0x36,0x33,0x36,0x36,0x63,0x35,0x61,0x55,0x2c,0x30,0x78, + 0x33,0x66,0x33,0x66,0x37,0x65,0x34,0x31,0x55,0x2c,0x30,0x78,0x66,0x37,0x66,0x37,0x66,0x35,0x30,0x32,0x55,0x2c,0x30,0x78,0x63,0x63,0x63,0x63,0x38,0x33,0x34,0x66, + 0x55,0x2c,0x0a,0x30,0x78,0x33,0x34,0x33,0x34,0x36,0x38,0x35,0x63,0x55,0x2c,0x30,0x78,0x61,0x35,0x61,0x35,0x35,0x31,0x66,0x34,0x55,0x2c,0x30,0x78,0x65,0x35,0x65, + 0x35,0x64,0x31,0x33,0x34,0x55,0x2c,0x30,0x78,0x66,0x31,0x66,0x31,0x66,0x39,0x30,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x31,0x37,0x31,0x65,0x32,0x39,0x33,0x55,0x2c, + 0x30,0x78,0x64,0x38,0x64,0x38,0x61,0x62,0x37,0x33,0x55,0x2c,0x30,0x78,0x33,0x31,0x33,0x31,0x36,0x32,0x35,0x33,0x55,0x2c,0x30,0x78,0x31,0x35,0x31,0x35,0x32,0x61, + 0x33,0x66,0x55,0x2c,0x0a,0x30,0x78,0x30,0x34,0x30,0x34,0x30,0x38,0x30,0x63,0x55,0x2c,0x30,0x78,0x63,0x37,0x63,0x37,0x39,0x35,0x35,0x32,0x55,0x2c,0x30,0x78,0x32, + 0x33,0x32,0x33,0x34,0x36,0x36,0x35,0x55,0x2c,0x30,0x78,0x63,0x33,0x63,0x33,0x39,0x64,0x35,0x65,0x55,0x2c,0x0a,0x30,0x78,0x31,0x38,0x31,0x38,0x33,0x30,0x32,0x38, + 0x55,0x2c,0x30,0x78,0x39,0x36,0x39,0x36,0x33,0x37,0x61,0x31,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x35,0x30,0x61,0x30,0x66,0x55,0x2c,0x30,0x78,0x39,0x61,0x39,0x61, + 0x32,0x66,0x62,0x35,0x55,0x2c,0x0a,0x30,0x78,0x30,0x37,0x30,0x37,0x30,0x65,0x30,0x39,0x55,0x2c,0x30,0x78,0x31,0x32,0x31,0x32,0x32,0x34,0x33,0x36,0x55,0x2c,0x30, + 0x78,0x38,0x30,0x38,0x30,0x31,0x62,0x39,0x62,0x55,0x2c,0x30,0x78,0x65,0x32,0x65,0x32,0x64,0x66,0x33,0x64,0x55,0x2c,0x0a,0x30,0x78,0x65,0x62,0x65,0x62,0x63,0x64, + 0x32,0x36,0x55,0x2c,0x30,0x78,0x32,0x37,0x32,0x37,0x34,0x65,0x36,0x39,0x55,0x2c,0x30,0x78,0x62,0x32,0x62,0x32,0x37,0x66,0x63,0x64,0x55,0x2c,0x30,0x78,0x37,0x35, + 0x37,0x35,0x65,0x61,0x39,0x66,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x39,0x31,0x32,0x31,0x62,0x55,0x2c,0x30,0x78,0x38,0x33,0x38,0x33,0x31,0x64,0x39,0x65,0x55, + 0x2c,0x30,0x78,0x32,0x63,0x32,0x63,0x35,0x38,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x61,0x31,0x61,0x33,0x34,0x32,0x65,0x55,0x2c,0x0a,0x30,0x78,0x31,0x62,0x31,0x62, + 0x33,0x36,0x32,0x64,0x55,0x2c,0x30,0x78,0x36,0x65,0x36,0x65,0x64,0x63,0x62,0x32,0x55,0x2c,0x30,0x78,0x35,0x61,0x35,0x61,0x62,0x34,0x65,0x65,0x55,0x2c,0x30,0x78, + 0x61,0x30,0x61,0x30,0x35,0x62,0x66,0x62,0x55,0x2c,0x0a,0x30,0x78,0x35,0x32,0x35,0x32,0x61,0x34,0x66,0x36,0x55,0x2c,0x30,0x78,0x33,0x62,0x33,0x62,0x37,0x36,0x34, + 0x64,0x55,0x2c,0x30,0x78,0x64,0x36,0x64,0x36,0x62,0x37,0x36,0x31,0x55,0x2c,0x30,0x78,0x62,0x33,0x62,0x33,0x37,0x64,0x63,0x65,0x55,0x2c,0x0a,0x30,0x78,0x32,0x39, + 0x32,0x39,0x35,0x32,0x37,0x62,0x55,0x2c,0x30,0x78,0x65,0x33,0x65,0x33,0x64,0x64,0x33,0x65,0x55,0x2c,0x30,0x78,0x32,0x66,0x32,0x66,0x35,0x65,0x37,0x31,0x55,0x2c, + 0x30,0x78,0x38,0x34,0x38,0x34,0x31,0x33,0x39,0x37,0x55,0x2c,0x0a,0x30,0x78,0x35,0x33,0x35,0x33,0x61,0x36,0x66,0x35,0x55,0x2c,0x30,0x78,0x64,0x31,0x64,0x31,0x62, + 0x39,0x36,0x38,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x65,0x64,0x65,0x64,0x63,0x31,0x32,0x63,0x55,0x2c,0x0a,0x30,0x78, + 0x32,0x30,0x32,0x30,0x34,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x66,0x63,0x66,0x63,0x65,0x33,0x31,0x66,0x55,0x2c,0x30,0x78,0x62,0x31,0x62,0x31,0x37,0x39,0x63,0x38, + 0x55,0x2c,0x30,0x78,0x35,0x62,0x35,0x62,0x62,0x36,0x65,0x64,0x55,0x2c,0x0a,0x30,0x78,0x36,0x61,0x36,0x61,0x64,0x34,0x62,0x65,0x55,0x2c,0x30,0x78,0x63,0x62,0x63, + 0x62,0x38,0x64,0x34,0x36,0x55,0x2c,0x30,0x78,0x62,0x65,0x62,0x65,0x36,0x37,0x64,0x39,0x55,0x2c,0x30,0x78,0x33,0x39,0x33,0x39,0x37,0x32,0x34,0x62,0x55,0x2c,0x0a, + 0x30,0x78,0x34,0x61,0x34,0x61,0x39,0x34,0x64,0x65,0x55,0x2c,0x30,0x78,0x34,0x63,0x34,0x63,0x39,0x38,0x64,0x34,0x55,0x2c,0x30,0x78,0x35,0x38,0x35,0x38,0x62,0x30, + 0x65,0x38,0x55,0x2c,0x30,0x78,0x63,0x66,0x63,0x66,0x38,0x35,0x34,0x61,0x55,0x2c,0x0a,0x30,0x78,0x64,0x30,0x64,0x30,0x62,0x62,0x36,0x62,0x55,0x2c,0x30,0x78,0x65, + 0x66,0x65,0x66,0x63,0x35,0x32,0x61,0x55,0x2c,0x30,0x78,0x61,0x61,0x61,0x61,0x34,0x66,0x65,0x35,0x55,0x2c,0x30,0x78,0x66,0x62,0x66,0x62,0x65,0x64,0x31,0x36,0x55, + 0x2c,0x0a,0x30,0x78,0x34,0x33,0x34,0x33,0x38,0x36,0x63,0x35,0x55,0x2c,0x30,0x78,0x34,0x64,0x34,0x64,0x39,0x61,0x64,0x37,0x55,0x2c,0x30,0x78,0x33,0x33,0x33,0x33, + 0x36,0x36,0x35,0x35,0x55,0x2c,0x30,0x78,0x38,0x35,0x38,0x35,0x31,0x31,0x39,0x34,0x55,0x2c,0x0a,0x30,0x78,0x34,0x35,0x34,0x35,0x38,0x61,0x63,0x66,0x55,0x2c,0x30, + 0x78,0x66,0x39,0x66,0x39,0x65,0x39,0x31,0x30,0x55,0x2c,0x30,0x78,0x30,0x32,0x30,0x32,0x30,0x34,0x30,0x36,0x55,0x2c,0x30,0x78,0x37,0x66,0x37,0x66,0x66,0x65,0x38, + 0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x35,0x30,0x61,0x30,0x66,0x30,0x55,0x2c,0x30,0x78,0x33,0x63,0x33,0x63,0x37,0x38,0x34,0x34,0x55,0x2c,0x30,0x78,0x39,0x66, + 0x39,0x66,0x32,0x35,0x62,0x61,0x55,0x2c,0x30,0x78,0x61,0x38,0x61,0x38,0x34,0x62,0x65,0x33,0x55,0x2c,0x0a,0x30,0x78,0x35,0x31,0x35,0x31,0x61,0x32,0x66,0x33,0x55, + 0x2c,0x30,0x78,0x61,0x33,0x61,0x33,0x35,0x64,0x66,0x65,0x55,0x2c,0x30,0x78,0x34,0x30,0x34,0x30,0x38,0x30,0x63,0x30,0x55,0x2c,0x30,0x78,0x38,0x66,0x38,0x66,0x30, + 0x35,0x38,0x61,0x55,0x2c,0x0a,0x30,0x78,0x39,0x32,0x39,0x32,0x33,0x66,0x61,0x64,0x55,0x2c,0x30,0x78,0x39,0x64,0x39,0x64,0x32,0x31,0x62,0x63,0x55,0x2c,0x30,0x78, + 0x33,0x38,0x33,0x38,0x37,0x30,0x34,0x38,0x55,0x2c,0x30,0x78,0x66,0x35,0x66,0x35,0x66,0x31,0x30,0x34,0x55,0x2c,0x0a,0x30,0x78,0x62,0x63,0x62,0x63,0x36,0x33,0x64, + 0x66,0x55,0x2c,0x30,0x78,0x62,0x36,0x62,0x36,0x37,0x37,0x63,0x31,0x55,0x2c,0x30,0x78,0x64,0x61,0x64,0x61,0x61,0x66,0x37,0x35,0x55,0x2c,0x30,0x78,0x32,0x31,0x32, + 0x31,0x34,0x32,0x36,0x33,0x55,0x2c,0x0a,0x30,0x78,0x31,0x30,0x31,0x30,0x32,0x30,0x33,0x30,0x55,0x2c,0x30,0x78,0x66,0x66,0x66,0x66,0x65,0x35,0x31,0x61,0x55,0x2c, + 0x30,0x78,0x66,0x33,0x66,0x33,0x66,0x64,0x30,0x65,0x55,0x2c,0x30,0x78,0x64,0x32,0x64,0x32,0x62,0x66,0x36,0x64,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x63,0x64,0x38, + 0x31,0x34,0x63,0x55,0x2c,0x30,0x78,0x30,0x63,0x30,0x63,0x31,0x38,0x31,0x34,0x55,0x2c,0x30,0x78,0x31,0x33,0x31,0x33,0x32,0x36,0x33,0x35,0x55,0x2c,0x30,0x78,0x65, + 0x63,0x65,0x63,0x63,0x33,0x32,0x66,0x55,0x2c,0x0a,0x30,0x78,0x35,0x66,0x35,0x66,0x62,0x65,0x65,0x31,0x55,0x2c,0x30,0x78,0x39,0x37,0x39,0x37,0x33,0x35,0x61,0x32, + 0x55,0x2c,0x30,0x78,0x34,0x34,0x34,0x34,0x38,0x38,0x63,0x63,0x55,0x2c,0x30,0x78,0x31,0x37,0x31,0x37,0x32,0x65,0x33,0x39,0x55,0x2c,0x0a,0x30,0x78,0x63,0x34,0x63, + 0x34,0x39,0x33,0x35,0x37,0x55,0x2c,0x30,0x78,0x61,0x37,0x61,0x37,0x35,0x35,0x66,0x32,0x55,0x2c,0x30,0x78,0x37,0x65,0x37,0x65,0x66,0x63,0x38,0x32,0x55,0x2c,0x30, + 0x78,0x33,0x64,0x33,0x64,0x37,0x61,0x34,0x37,0x55,0x2c,0x0a,0x30,0x78,0x36,0x34,0x36,0x34,0x63,0x38,0x61,0x63,0x55,0x2c,0x30,0x78,0x35,0x64,0x35,0x64,0x62,0x61, + 0x65,0x37,0x55,0x2c,0x30,0x78,0x31,0x39,0x31,0x39,0x33,0x32,0x32,0x62,0x55,0x2c,0x30,0x78,0x37,0x33,0x37,0x33,0x65,0x36,0x39,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36, + 0x30,0x36,0x30,0x63,0x30,0x61,0x30,0x55,0x2c,0x30,0x78,0x38,0x31,0x38,0x31,0x31,0x39,0x39,0x38,0x55,0x2c,0x30,0x78,0x34,0x66,0x34,0x66,0x39,0x65,0x64,0x31,0x55, + 0x2c,0x30,0x78,0x64,0x63,0x64,0x63,0x61,0x33,0x37,0x66,0x55,0x2c,0x0a,0x30,0x78,0x32,0x32,0x32,0x32,0x34,0x34,0x36,0x36,0x55,0x2c,0x30,0x78,0x32,0x61,0x32,0x61, + 0x35,0x34,0x37,0x65,0x55,0x2c,0x30,0x78,0x39,0x30,0x39,0x30,0x33,0x62,0x61,0x62,0x55,0x2c,0x30,0x78,0x38,0x38,0x38,0x38,0x30,0x62,0x38,0x33,0x55,0x2c,0x0a,0x30, + 0x78,0x34,0x36,0x34,0x36,0x38,0x63,0x63,0x61,0x55,0x2c,0x30,0x78,0x65,0x65,0x65,0x65,0x63,0x37,0x32,0x39,0x55,0x2c,0x30,0x78,0x62,0x38,0x62,0x38,0x36,0x62,0x64, + 0x33,0x55,0x2c,0x30,0x78,0x31,0x34,0x31,0x34,0x32,0x38,0x33,0x63,0x55,0x2c,0x0a,0x30,0x78,0x64,0x65,0x64,0x65,0x61,0x37,0x37,0x39,0x55,0x2c,0x30,0x78,0x35,0x65, + 0x35,0x65,0x62,0x63,0x65,0x32,0x55,0x2c,0x30,0x78,0x30,0x62,0x30,0x62,0x31,0x36,0x31,0x64,0x55,0x2c,0x30,0x78,0x64,0x62,0x64,0x62,0x61,0x64,0x37,0x36,0x55,0x2c, + 0x0a,0x30,0x78,0x65,0x30,0x65,0x30,0x64,0x62,0x33,0x62,0x55,0x2c,0x30,0x78,0x33,0x32,0x33,0x32,0x36,0x34,0x35,0x36,0x55,0x2c,0x30,0x78,0x33,0x61,0x33,0x61,0x37, + 0x34,0x34,0x65,0x55,0x2c,0x30,0x78,0x30,0x61,0x30,0x61,0x31,0x34,0x31,0x65,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x34,0x39,0x39,0x32,0x64,0x62,0x55,0x2c,0x30,0x78, + 0x30,0x36,0x30,0x36,0x30,0x63,0x30,0x61,0x55,0x2c,0x30,0x78,0x32,0x34,0x32,0x34,0x34,0x38,0x36,0x63,0x55,0x2c,0x30,0x78,0x35,0x63,0x35,0x63,0x62,0x38,0x65,0x34, + 0x55,0x2c,0x0a,0x30,0x78,0x63,0x32,0x63,0x32,0x39,0x66,0x35,0x64,0x55,0x2c,0x30,0x78,0x64,0x33,0x64,0x33,0x62,0x64,0x36,0x65,0x55,0x2c,0x30,0x78,0x61,0x63,0x61, + 0x63,0x34,0x33,0x65,0x66,0x55,0x2c,0x30,0x78,0x36,0x32,0x36,0x32,0x63,0x34,0x61,0x36,0x55,0x2c,0x0a,0x30,0x78,0x39,0x31,0x39,0x31,0x33,0x39,0x61,0x38,0x55,0x2c, + 0x30,0x78,0x39,0x35,0x39,0x35,0x33,0x31,0x61,0x34,0x55,0x2c,0x30,0x78,0x65,0x34,0x65,0x34,0x64,0x33,0x33,0x37,0x55,0x2c,0x30,0x78,0x37,0x39,0x37,0x39,0x66,0x32, + 0x38,0x62,0x55,0x2c,0x0a,0x30,0x78,0x65,0x37,0x65,0x37,0x64,0x35,0x33,0x32,0x55,0x2c,0x30,0x78,0x63,0x38,0x63,0x38,0x38,0x62,0x34,0x33,0x55,0x2c,0x30,0x78,0x33, + 0x37,0x33,0x37,0x36,0x65,0x35,0x39,0x55,0x2c,0x30,0x78,0x36,0x64,0x36,0x64,0x64,0x61,0x62,0x37,0x55,0x2c,0x0a,0x30,0x78,0x38,0x64,0x38,0x64,0x30,0x31,0x38,0x63, + 0x55,0x2c,0x30,0x78,0x64,0x35,0x64,0x35,0x62,0x31,0x36,0x34,0x55,0x2c,0x30,0x78,0x34,0x65,0x34,0x65,0x39,0x63,0x64,0x32,0x55,0x2c,0x30,0x78,0x61,0x39,0x61,0x39, + 0x34,0x39,0x65,0x30,0x55,0x2c,0x0a,0x30,0x78,0x36,0x63,0x36,0x63,0x64,0x38,0x62,0x34,0x55,0x2c,0x30,0x78,0x35,0x36,0x35,0x36,0x61,0x63,0x66,0x61,0x55,0x2c,0x30, + 0x78,0x66,0x34,0x66,0x34,0x66,0x33,0x30,0x37,0x55,0x2c,0x30,0x78,0x65,0x61,0x65,0x61,0x63,0x66,0x32,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x35,0x36,0x35,0x63,0x61, + 0x61,0x66,0x55,0x2c,0x30,0x78,0x37,0x61,0x37,0x61,0x66,0x34,0x38,0x65,0x55,0x2c,0x30,0x78,0x61,0x65,0x61,0x65,0x34,0x37,0x65,0x39,0x55,0x2c,0x30,0x78,0x30,0x38, + 0x30,0x38,0x31,0x30,0x31,0x38,0x55,0x2c,0x0a,0x30,0x78,0x62,0x61,0x62,0x61,0x36,0x66,0x64,0x35,0x55,0x2c,0x30,0x78,0x37,0x38,0x37,0x38,0x66,0x30,0x38,0x38,0x55, + 0x2c,0x30,0x78,0x32,0x35,0x32,0x35,0x34,0x61,0x36,0x66,0x55,0x2c,0x30,0x78,0x32,0x65,0x32,0x65,0x35,0x63,0x37,0x32,0x55,0x2c,0x0a,0x30,0x78,0x31,0x63,0x31,0x63, + 0x33,0x38,0x32,0x34,0x55,0x2c,0x30,0x78,0x61,0x36,0x61,0x36,0x35,0x37,0x66,0x31,0x55,0x2c,0x30,0x78,0x62,0x34,0x62,0x34,0x37,0x33,0x63,0x37,0x55,0x2c,0x30,0x78, + 0x63,0x36,0x63,0x36,0x39,0x37,0x35,0x31,0x55,0x2c,0x0a,0x30,0x78,0x65,0x38,0x65,0x38,0x63,0x62,0x32,0x33,0x55,0x2c,0x30,0x78,0x64,0x64,0x64,0x64,0x61,0x31,0x37, + 0x63,0x55,0x2c,0x30,0x78,0x37,0x34,0x37,0x34,0x65,0x38,0x39,0x63,0x55,0x2c,0x30,0x78,0x31,0x66,0x31,0x66,0x33,0x65,0x32,0x31,0x55,0x2c,0x0a,0x30,0x78,0x34,0x62, + 0x34,0x62,0x39,0x36,0x64,0x64,0x55,0x2c,0x30,0x78,0x62,0x64,0x62,0x64,0x36,0x31,0x64,0x63,0x55,0x2c,0x30,0x78,0x38,0x62,0x38,0x62,0x30,0x64,0x38,0x36,0x55,0x2c, + 0x30,0x78,0x38,0x61,0x38,0x61,0x30,0x66,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x37,0x30,0x37,0x30,0x65,0x30,0x39,0x30,0x55,0x2c,0x30,0x78,0x33,0x65,0x33,0x65,0x37, + 0x63,0x34,0x32,0x55,0x2c,0x30,0x78,0x62,0x35,0x62,0x35,0x37,0x31,0x63,0x34,0x55,0x2c,0x30,0x78,0x36,0x36,0x36,0x36,0x63,0x63,0x61,0x61,0x55,0x2c,0x0a,0x30,0x78, + 0x34,0x38,0x34,0x38,0x39,0x30,0x64,0x38,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x33,0x30,0x36,0x30,0x35,0x55,0x2c,0x30,0x78,0x66,0x36,0x66,0x36,0x66,0x37,0x30,0x31, + 0x55,0x2c,0x30,0x78,0x30,0x65,0x30,0x65,0x31,0x63,0x31,0x32,0x55,0x2c,0x0a,0x30,0x78,0x36,0x31,0x36,0x31,0x63,0x32,0x61,0x33,0x55,0x2c,0x30,0x78,0x33,0x35,0x33, + 0x35,0x36,0x61,0x35,0x66,0x55,0x2c,0x30,0x78,0x35,0x37,0x35,0x37,0x61,0x65,0x66,0x39,0x55,0x2c,0x30,0x78,0x62,0x39,0x62,0x39,0x36,0x39,0x64,0x30,0x55,0x2c,0x0a, + 0x30,0x78,0x38,0x36,0x38,0x36,0x31,0x37,0x39,0x31,0x55,0x2c,0x30,0x78,0x63,0x31,0x63,0x31,0x39,0x39,0x35,0x38,0x55,0x2c,0x30,0x78,0x31,0x64,0x31,0x64,0x33,0x61, + 0x32,0x37,0x55,0x2c,0x30,0x78,0x39,0x65,0x39,0x65,0x32,0x37,0x62,0x39,0x55,0x2c,0x0a,0x30,0x78,0x65,0x31,0x65,0x31,0x64,0x39,0x33,0x38,0x55,0x2c,0x30,0x78,0x66, + 0x38,0x66,0x38,0x65,0x62,0x31,0x33,0x55,0x2c,0x30,0x78,0x39,0x38,0x39,0x38,0x32,0x62,0x62,0x33,0x55,0x2c,0x30,0x78,0x31,0x31,0x31,0x31,0x32,0x32,0x33,0x33,0x55, + 0x2c,0x0a,0x30,0x78,0x36,0x39,0x36,0x39,0x64,0x32,0x62,0x62,0x55,0x2c,0x30,0x78,0x64,0x39,0x64,0x39,0x61,0x39,0x37,0x30,0x55,0x2c,0x30,0x78,0x38,0x65,0x38,0x65, + 0x30,0x37,0x38,0x39,0x55,0x2c,0x30,0x78,0x39,0x34,0x39,0x34,0x33,0x33,0x61,0x37,0x55,0x2c,0x0a,0x30,0x78,0x39,0x62,0x39,0x62,0x32,0x64,0x62,0x36,0x55,0x2c,0x30, + 0x78,0x31,0x65,0x31,0x65,0x33,0x63,0x32,0x32,0x55,0x2c,0x30,0x78,0x38,0x37,0x38,0x37,0x31,0x35,0x39,0x32,0x55,0x2c,0x30,0x78,0x65,0x39,0x65,0x39,0x63,0x39,0x32, + 0x30,0x55,0x2c,0x0a,0x30,0x78,0x63,0x65,0x63,0x65,0x38,0x37,0x34,0x39,0x55,0x2c,0x30,0x78,0x35,0x35,0x35,0x35,0x61,0x61,0x66,0x66,0x55,0x2c,0x30,0x78,0x32,0x38, + 0x32,0x38,0x35,0x30,0x37,0x38,0x55,0x2c,0x30,0x78,0x64,0x66,0x64,0x66,0x61,0x35,0x37,0x61,0x55,0x2c,0x0a,0x30,0x78,0x38,0x63,0x38,0x63,0x30,0x33,0x38,0x66,0x55, + 0x2c,0x30,0x78,0x61,0x31,0x61,0x31,0x35,0x39,0x66,0x38,0x55,0x2c,0x30,0x78,0x38,0x39,0x38,0x39,0x30,0x39,0x38,0x30,0x55,0x2c,0x30,0x78,0x30,0x64,0x30,0x64,0x31, + 0x61,0x31,0x37,0x55,0x2c,0x0a,0x30,0x78,0x62,0x66,0x62,0x66,0x36,0x35,0x64,0x61,0x55,0x2c,0x30,0x78,0x65,0x36,0x65,0x36,0x64,0x37,0x33,0x31,0x55,0x2c,0x30,0x78, + 0x34,0x32,0x34,0x32,0x38,0x34,0x63,0x36,0x55,0x2c,0x30,0x78,0x36,0x38,0x36,0x38,0x64,0x30,0x62,0x38,0x55,0x2c,0x0a,0x30,0x78,0x34,0x31,0x34,0x31,0x38,0x32,0x63, + 0x33,0x55,0x2c,0x30,0x78,0x39,0x39,0x39,0x39,0x32,0x39,0x62,0x30,0x55,0x2c,0x30,0x78,0x32,0x64,0x32,0x64,0x35,0x61,0x37,0x37,0x55,0x2c,0x30,0x78,0x30,0x66,0x30, + 0x66,0x31,0x65,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78,0x62,0x30,0x62,0x30,0x37,0x62,0x63,0x62,0x55,0x2c,0x30,0x78,0x35,0x34,0x35,0x34,0x61,0x38,0x66,0x63,0x55,0x2c, + 0x30,0x78,0x62,0x62,0x62,0x62,0x36,0x64,0x64,0x36,0x55,0x2c,0x30,0x78,0x31,0x36,0x31,0x36,0x32,0x63,0x33,0x61,0x55,0x2c,0x0a,0x30,0x78,0x36,0x33,0x63,0x36,0x61, + 0x35,0x36,0x33,0x55,0x2c,0x30,0x78,0x37,0x63,0x66,0x38,0x38,0x34,0x37,0x63,0x55,0x2c,0x30,0x78,0x37,0x37,0x65,0x65,0x39,0x39,0x37,0x37,0x55,0x2c,0x30,0x78,0x37, + 0x62,0x66,0x36,0x38,0x64,0x37,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x32,0x66,0x66,0x30,0x64,0x66,0x32,0x55,0x2c,0x30,0x78,0x36,0x62,0x64,0x36,0x62,0x64,0x36,0x62, + 0x55,0x2c,0x30,0x78,0x36,0x66,0x64,0x65,0x62,0x31,0x36,0x66,0x55,0x2c,0x30,0x78,0x63,0x35,0x39,0x31,0x35,0x34,0x63,0x35,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x36, + 0x30,0x35,0x30,0x33,0x30,0x55,0x2c,0x30,0x78,0x30,0x31,0x30,0x32,0x30,0x33,0x30,0x31,0x55,0x2c,0x30,0x78,0x36,0x37,0x63,0x65,0x61,0x39,0x36,0x37,0x55,0x2c,0x30, + 0x78,0x32,0x62,0x35,0x36,0x37,0x64,0x32,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x65,0x65,0x37,0x31,0x39,0x66,0x65,0x55,0x2c,0x30,0x78,0x64,0x37,0x62,0x35,0x36,0x32, + 0x64,0x37,0x55,0x2c,0x30,0x78,0x61,0x62,0x34,0x64,0x65,0x36,0x61,0x62,0x55,0x2c,0x30,0x78,0x37,0x36,0x65,0x63,0x39,0x61,0x37,0x36,0x55,0x2c,0x0a,0x30,0x78,0x63, + 0x61,0x38,0x66,0x34,0x35,0x63,0x61,0x55,0x2c,0x30,0x78,0x38,0x32,0x31,0x66,0x39,0x64,0x38,0x32,0x55,0x2c,0x30,0x78,0x63,0x39,0x38,0x39,0x34,0x30,0x63,0x39,0x55, + 0x2c,0x30,0x78,0x37,0x64,0x66,0x61,0x38,0x37,0x37,0x64,0x55,0x2c,0x0a,0x30,0x78,0x66,0x61,0x65,0x66,0x31,0x35,0x66,0x61,0x55,0x2c,0x30,0x78,0x35,0x39,0x62,0x32, + 0x65,0x62,0x35,0x39,0x55,0x2c,0x30,0x78,0x34,0x37,0x38,0x65,0x63,0x39,0x34,0x37,0x55,0x2c,0x30,0x78,0x66,0x30,0x66,0x62,0x30,0x62,0x66,0x30,0x55,0x2c,0x0a,0x30, + 0x78,0x61,0x64,0x34,0x31,0x65,0x63,0x61,0x64,0x55,0x2c,0x30,0x78,0x64,0x34,0x62,0x33,0x36,0x37,0x64,0x34,0x55,0x2c,0x30,0x78,0x61,0x32,0x35,0x66,0x66,0x64,0x61, + 0x32,0x55,0x2c,0x30,0x78,0x61,0x66,0x34,0x35,0x65,0x61,0x61,0x66,0x55,0x2c,0x0a,0x30,0x78,0x39,0x63,0x32,0x33,0x62,0x66,0x39,0x63,0x55,0x2c,0x30,0x78,0x61,0x34, + 0x35,0x33,0x66,0x37,0x61,0x34,0x55,0x2c,0x30,0x78,0x37,0x32,0x65,0x34,0x39,0x36,0x37,0x32,0x55,0x2c,0x30,0x78,0x63,0x30,0x39,0x62,0x35,0x62,0x63,0x30,0x55,0x2c, + 0x0a,0x30,0x78,0x62,0x37,0x37,0x35,0x63,0x32,0x62,0x37,0x55,0x2c,0x30,0x78,0x66,0x64,0x65,0x31,0x31,0x63,0x66,0x64,0x55,0x2c,0x30,0x78,0x39,0x33,0x33,0x64,0x61, + 0x65,0x39,0x33,0x55,0x2c,0x30,0x78,0x32,0x36,0x34,0x63,0x36,0x61,0x32,0x36,0x55,0x2c,0x0a,0x30,0x78,0x33,0x36,0x36,0x63,0x35,0x61,0x33,0x36,0x55,0x2c,0x30,0x78, + 0x33,0x66,0x37,0x65,0x34,0x31,0x33,0x66,0x55,0x2c,0x30,0x78,0x66,0x37,0x66,0x35,0x30,0x32,0x66,0x37,0x55,0x2c,0x30,0x78,0x63,0x63,0x38,0x33,0x34,0x66,0x63,0x63, + 0x55,0x2c,0x0a,0x30,0x78,0x33,0x34,0x36,0x38,0x35,0x63,0x33,0x34,0x55,0x2c,0x30,0x78,0x61,0x35,0x35,0x31,0x66,0x34,0x61,0x35,0x55,0x2c,0x30,0x78,0x65,0x35,0x64, + 0x31,0x33,0x34,0x65,0x35,0x55,0x2c,0x30,0x78,0x66,0x31,0x66,0x39,0x30,0x38,0x66,0x31,0x55,0x2c,0x0a,0x30,0x78,0x37,0x31,0x65,0x32,0x39,0x33,0x37,0x31,0x55,0x2c, + 0x30,0x78,0x64,0x38,0x61,0x62,0x37,0x33,0x64,0x38,0x55,0x2c,0x30,0x78,0x33,0x31,0x36,0x32,0x35,0x33,0x33,0x31,0x55,0x2c,0x30,0x78,0x31,0x35,0x32,0x61,0x33,0x66, + 0x31,0x35,0x55,0x2c,0x0a,0x30,0x78,0x30,0x34,0x30,0x38,0x30,0x63,0x30,0x34,0x55,0x2c,0x30,0x78,0x63,0x37,0x39,0x35,0x35,0x32,0x63,0x37,0x55,0x2c,0x30,0x78,0x32, + 0x33,0x34,0x36,0x36,0x35,0x32,0x33,0x55,0x2c,0x30,0x78,0x63,0x33,0x39,0x64,0x35,0x65,0x63,0x33,0x55,0x2c,0x0a,0x30,0x78,0x31,0x38,0x33,0x30,0x32,0x38,0x31,0x38, + 0x55,0x2c,0x30,0x78,0x39,0x36,0x33,0x37,0x61,0x31,0x39,0x36,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x61,0x30,0x66,0x30,0x35,0x55,0x2c,0x30,0x78,0x39,0x61,0x32,0x66, + 0x62,0x35,0x39,0x61,0x55,0x2c,0x0a,0x30,0x78,0x30,0x37,0x30,0x65,0x30,0x39,0x30,0x37,0x55,0x2c,0x30,0x78,0x31,0x32,0x32,0x34,0x33,0x36,0x31,0x32,0x55,0x2c,0x30, + 0x78,0x38,0x30,0x31,0x62,0x39,0x62,0x38,0x30,0x55,0x2c,0x30,0x78,0x65,0x32,0x64,0x66,0x33,0x64,0x65,0x32,0x55,0x2c,0x0a,0x30,0x78,0x65,0x62,0x63,0x64,0x32,0x36, + 0x65,0x62,0x55,0x2c,0x30,0x78,0x32,0x37,0x34,0x65,0x36,0x39,0x32,0x37,0x55,0x2c,0x30,0x78,0x62,0x32,0x37,0x66,0x63,0x64,0x62,0x32,0x55,0x2c,0x30,0x78,0x37,0x35, + 0x65,0x61,0x39,0x66,0x37,0x35,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x31,0x32,0x31,0x62,0x30,0x39,0x55,0x2c,0x30,0x78,0x38,0x33,0x31,0x64,0x39,0x65,0x38,0x33,0x55, + 0x2c,0x30,0x78,0x32,0x63,0x35,0x38,0x37,0x34,0x32,0x63,0x55,0x2c,0x30,0x78,0x31,0x61,0x33,0x34,0x32,0x65,0x31,0x61,0x55,0x2c,0x0a,0x30,0x78,0x31,0x62,0x33,0x36, + 0x32,0x64,0x31,0x62,0x55,0x2c,0x30,0x78,0x36,0x65,0x64,0x63,0x62,0x32,0x36,0x65,0x55,0x2c,0x30,0x78,0x35,0x61,0x62,0x34,0x65,0x65,0x35,0x61,0x55,0x2c,0x30,0x78, + 0x61,0x30,0x35,0x62,0x66,0x62,0x61,0x30,0x55,0x2c,0x0a,0x30,0x78,0x35,0x32,0x61,0x34,0x66,0x36,0x35,0x32,0x55,0x2c,0x30,0x78,0x33,0x62,0x37,0x36,0x34,0x64,0x33, + 0x62,0x55,0x2c,0x30,0x78,0x64,0x36,0x62,0x37,0x36,0x31,0x64,0x36,0x55,0x2c,0x30,0x78,0x62,0x33,0x37,0x64,0x63,0x65,0x62,0x33,0x55,0x2c,0x0a,0x30,0x78,0x32,0x39, + 0x35,0x32,0x37,0x62,0x32,0x39,0x55,0x2c,0x30,0x78,0x65,0x33,0x64,0x64,0x33,0x65,0x65,0x33,0x55,0x2c,0x30,0x78,0x32,0x66,0x35,0x65,0x37,0x31,0x32,0x66,0x55,0x2c, + 0x30,0x78,0x38,0x34,0x31,0x33,0x39,0x37,0x38,0x34,0x55,0x2c,0x0a,0x30,0x78,0x35,0x33,0x61,0x36,0x66,0x35,0x35,0x33,0x55,0x2c,0x30,0x78,0x64,0x31,0x62,0x39,0x36, + 0x38,0x64,0x31,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x65,0x64,0x63,0x31,0x32,0x63,0x65,0x64,0x55,0x2c,0x0a,0x30,0x78, + 0x32,0x30,0x34,0x30,0x36,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x66,0x63,0x65,0x33,0x31,0x66,0x66,0x63,0x55,0x2c,0x30,0x78,0x62,0x31,0x37,0x39,0x63,0x38,0x62,0x31, + 0x55,0x2c,0x30,0x78,0x35,0x62,0x62,0x36,0x65,0x64,0x35,0x62,0x55,0x2c,0x0a,0x30,0x78,0x36,0x61,0x64,0x34,0x62,0x65,0x36,0x61,0x55,0x2c,0x30,0x78,0x63,0x62,0x38, + 0x64,0x34,0x36,0x63,0x62,0x55,0x2c,0x30,0x78,0x62,0x65,0x36,0x37,0x64,0x39,0x62,0x65,0x55,0x2c,0x30,0x78,0x33,0x39,0x37,0x32,0x34,0x62,0x33,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x34,0x61,0x39,0x34,0x64,0x65,0x34,0x61,0x55,0x2c,0x30,0x78,0x34,0x63,0x39,0x38,0x64,0x34,0x34,0x63,0x55,0x2c,0x30,0x78,0x35,0x38,0x62,0x30,0x65,0x38, + 0x35,0x38,0x55,0x2c,0x30,0x78,0x63,0x66,0x38,0x35,0x34,0x61,0x63,0x66,0x55,0x2c,0x0a,0x30,0x78,0x64,0x30,0x62,0x62,0x36,0x62,0x64,0x30,0x55,0x2c,0x30,0x78,0x65, + 0x66,0x63,0x35,0x32,0x61,0x65,0x66,0x55,0x2c,0x30,0x78,0x61,0x61,0x34,0x66,0x65,0x35,0x61,0x61,0x55,0x2c,0x30,0x78,0x66,0x62,0x65,0x64,0x31,0x36,0x66,0x62,0x55, + 0x2c,0x0a,0x30,0x78,0x34,0x33,0x38,0x36,0x63,0x35,0x34,0x33,0x55,0x2c,0x30,0x78,0x34,0x64,0x39,0x61,0x64,0x37,0x34,0x64,0x55,0x2c,0x30,0x78,0x33,0x33,0x36,0x36, + 0x35,0x35,0x33,0x33,0x55,0x2c,0x30,0x78,0x38,0x35,0x31,0x31,0x39,0x34,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x34,0x35,0x38,0x61,0x63,0x66,0x34,0x35,0x55,0x2c,0x30, + 0x78,0x66,0x39,0x65,0x39,0x31,0x30,0x66,0x39,0x55,0x2c,0x30,0x78,0x30,0x32,0x30,0x34,0x30,0x36,0x30,0x32,0x55,0x2c,0x30,0x78,0x37,0x66,0x66,0x65,0x38,0x31,0x37, + 0x66,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x61,0x30,0x66,0x30,0x35,0x30,0x55,0x2c,0x30,0x78,0x33,0x63,0x37,0x38,0x34,0x34,0x33,0x63,0x55,0x2c,0x30,0x78,0x39,0x66, + 0x32,0x35,0x62,0x61,0x39,0x66,0x55,0x2c,0x30,0x78,0x61,0x38,0x34,0x62,0x65,0x33,0x61,0x38,0x55,0x2c,0x0a,0x30,0x78,0x35,0x31,0x61,0x32,0x66,0x33,0x35,0x31,0x55, + 0x2c,0x30,0x78,0x61,0x33,0x35,0x64,0x66,0x65,0x61,0x33,0x55,0x2c,0x30,0x78,0x34,0x30,0x38,0x30,0x63,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x38,0x66,0x30,0x35,0x38, + 0x61,0x38,0x66,0x55,0x2c,0x0a,0x30,0x78,0x39,0x32,0x33,0x66,0x61,0x64,0x39,0x32,0x55,0x2c,0x30,0x78,0x39,0x64,0x32,0x31,0x62,0x63,0x39,0x64,0x55,0x2c,0x30,0x78, + 0x33,0x38,0x37,0x30,0x34,0x38,0x33,0x38,0x55,0x2c,0x30,0x78,0x66,0x35,0x66,0x31,0x30,0x34,0x66,0x35,0x55,0x2c,0x0a,0x30,0x78,0x62,0x63,0x36,0x33,0x64,0x66,0x62, + 0x63,0x55,0x2c,0x30,0x78,0x62,0x36,0x37,0x37,0x63,0x31,0x62,0x36,0x55,0x2c,0x30,0x78,0x64,0x61,0x61,0x66,0x37,0x35,0x64,0x61,0x55,0x2c,0x30,0x78,0x32,0x31,0x34, + 0x32,0x36,0x33,0x32,0x31,0x55,0x2c,0x0a,0x30,0x78,0x31,0x30,0x32,0x30,0x33,0x30,0x31,0x30,0x55,0x2c,0x30,0x78,0x66,0x66,0x65,0x35,0x31,0x61,0x66,0x66,0x55,0x2c, + 0x30,0x78,0x66,0x33,0x66,0x64,0x30,0x65,0x66,0x33,0x55,0x2c,0x30,0x78,0x64,0x32,0x62,0x66,0x36,0x64,0x64,0x32,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x38,0x31,0x34, + 0x63,0x63,0x64,0x55,0x2c,0x30,0x78,0x30,0x63,0x31,0x38,0x31,0x34,0x30,0x63,0x55,0x2c,0x30,0x78,0x31,0x33,0x32,0x36,0x33,0x35,0x31,0x33,0x55,0x2c,0x30,0x78,0x65, + 0x63,0x63,0x33,0x32,0x66,0x65,0x63,0x55,0x2c,0x0a,0x30,0x78,0x35,0x66,0x62,0x65,0x65,0x31,0x35,0x66,0x55,0x2c,0x30,0x78,0x39,0x37,0x33,0x35,0x61,0x32,0x39,0x37, + 0x55,0x2c,0x30,0x78,0x34,0x34,0x38,0x38,0x63,0x63,0x34,0x34,0x55,0x2c,0x30,0x78,0x31,0x37,0x32,0x65,0x33,0x39,0x31,0x37,0x55,0x2c,0x0a,0x30,0x78,0x63,0x34,0x39, + 0x33,0x35,0x37,0x63,0x34,0x55,0x2c,0x30,0x78,0x61,0x37,0x35,0x35,0x66,0x32,0x61,0x37,0x55,0x2c,0x30,0x78,0x37,0x65,0x66,0x63,0x38,0x32,0x37,0x65,0x55,0x2c,0x30, + 0x78,0x33,0x64,0x37,0x61,0x34,0x37,0x33,0x64,0x55,0x2c,0x0a,0x30,0x78,0x36,0x34,0x63,0x38,0x61,0x63,0x36,0x34,0x55,0x2c,0x30,0x78,0x35,0x64,0x62,0x61,0x65,0x37, + 0x35,0x64,0x55,0x2c,0x30,0x78,0x31,0x39,0x33,0x32,0x32,0x62,0x31,0x39,0x55,0x2c,0x30,0x78,0x37,0x33,0x65,0x36,0x39,0x35,0x37,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36, + 0x30,0x63,0x30,0x61,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x38,0x31,0x31,0x39,0x39,0x38,0x38,0x31,0x55,0x2c,0x30,0x78,0x34,0x66,0x39,0x65,0x64,0x31,0x34,0x66,0x55, + 0x2c,0x30,0x78,0x64,0x63,0x61,0x33,0x37,0x66,0x64,0x63,0x55,0x2c,0x0a,0x30,0x78,0x32,0x32,0x34,0x34,0x36,0x36,0x32,0x32,0x55,0x2c,0x30,0x78,0x32,0x61,0x35,0x34, + 0x37,0x65,0x32,0x61,0x55,0x2c,0x30,0x78,0x39,0x30,0x33,0x62,0x61,0x62,0x39,0x30,0x55,0x2c,0x30,0x78,0x38,0x38,0x30,0x62,0x38,0x33,0x38,0x38,0x55,0x2c,0x0a,0x30, + 0x78,0x34,0x36,0x38,0x63,0x63,0x61,0x34,0x36,0x55,0x2c,0x30,0x78,0x65,0x65,0x63,0x37,0x32,0x39,0x65,0x65,0x55,0x2c,0x30,0x78,0x62,0x38,0x36,0x62,0x64,0x33,0x62, + 0x38,0x55,0x2c,0x30,0x78,0x31,0x34,0x32,0x38,0x33,0x63,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x64,0x65,0x61,0x37,0x37,0x39,0x64,0x65,0x55,0x2c,0x30,0x78,0x35,0x65, + 0x62,0x63,0x65,0x32,0x35,0x65,0x55,0x2c,0x30,0x78,0x30,0x62,0x31,0x36,0x31,0x64,0x30,0x62,0x55,0x2c,0x30,0x78,0x64,0x62,0x61,0x64,0x37,0x36,0x64,0x62,0x55,0x2c, + 0x0a,0x30,0x78,0x65,0x30,0x64,0x62,0x33,0x62,0x65,0x30,0x55,0x2c,0x30,0x78,0x33,0x32,0x36,0x34,0x35,0x36,0x33,0x32,0x55,0x2c,0x30,0x78,0x33,0x61,0x37,0x34,0x34, + 0x65,0x33,0x61,0x55,0x2c,0x30,0x78,0x30,0x61,0x31,0x34,0x31,0x65,0x30,0x61,0x55,0x2c,0x0a,0x30,0x78,0x34,0x39,0x39,0x32,0x64,0x62,0x34,0x39,0x55,0x2c,0x30,0x78, + 0x30,0x36,0x30,0x63,0x30,0x61,0x30,0x36,0x55,0x2c,0x30,0x78,0x32,0x34,0x34,0x38,0x36,0x63,0x32,0x34,0x55,0x2c,0x30,0x78,0x35,0x63,0x62,0x38,0x65,0x34,0x35,0x63, + 0x55,0x2c,0x0a,0x30,0x78,0x63,0x32,0x39,0x66,0x35,0x64,0x63,0x32,0x55,0x2c,0x30,0x78,0x64,0x33,0x62,0x64,0x36,0x65,0x64,0x33,0x55,0x2c,0x30,0x78,0x61,0x63,0x34, + 0x33,0x65,0x66,0x61,0x63,0x55,0x2c,0x30,0x78,0x36,0x32,0x63,0x34,0x61,0x36,0x36,0x32,0x55,0x2c,0x0a,0x30,0x78,0x39,0x31,0x33,0x39,0x61,0x38,0x39,0x31,0x55,0x2c, + 0x30,0x78,0x39,0x35,0x33,0x31,0x61,0x34,0x39,0x35,0x55,0x2c,0x30,0x78,0x65,0x34,0x64,0x33,0x33,0x37,0x65,0x34,0x55,0x2c,0x30,0x78,0x37,0x39,0x66,0x32,0x38,0x62, + 0x37,0x39,0x55,0x2c,0x0a,0x30,0x78,0x65,0x37,0x64,0x35,0x33,0x32,0x65,0x37,0x55,0x2c,0x30,0x78,0x63,0x38,0x38,0x62,0x34,0x33,0x63,0x38,0x55,0x2c,0x30,0x78,0x33, + 0x37,0x36,0x65,0x35,0x39,0x33,0x37,0x55,0x2c,0x30,0x78,0x36,0x64,0x64,0x61,0x62,0x37,0x36,0x64,0x55,0x2c,0x0a,0x30,0x78,0x38,0x64,0x30,0x31,0x38,0x63,0x38,0x64, + 0x55,0x2c,0x30,0x78,0x64,0x35,0x62,0x31,0x36,0x34,0x64,0x35,0x55,0x2c,0x30,0x78,0x34,0x65,0x39,0x63,0x64,0x32,0x34,0x65,0x55,0x2c,0x30,0x78,0x61,0x39,0x34,0x39, + 0x65,0x30,0x61,0x39,0x55,0x2c,0x0a,0x30,0x78,0x36,0x63,0x64,0x38,0x62,0x34,0x36,0x63,0x55,0x2c,0x30,0x78,0x35,0x36,0x61,0x63,0x66,0x61,0x35,0x36,0x55,0x2c,0x30, + 0x78,0x66,0x34,0x66,0x33,0x30,0x37,0x66,0x34,0x55,0x2c,0x30,0x78,0x65,0x61,0x63,0x66,0x32,0x35,0x65,0x61,0x55,0x2c,0x0a,0x30,0x78,0x36,0x35,0x63,0x61,0x61,0x66, + 0x36,0x35,0x55,0x2c,0x30,0x78,0x37,0x61,0x66,0x34,0x38,0x65,0x37,0x61,0x55,0x2c,0x30,0x78,0x61,0x65,0x34,0x37,0x65,0x39,0x61,0x65,0x55,0x2c,0x30,0x78,0x30,0x38, + 0x31,0x30,0x31,0x38,0x30,0x38,0x55,0x2c,0x0a,0x30,0x78,0x62,0x61,0x36,0x66,0x64,0x35,0x62,0x61,0x55,0x2c,0x30,0x78,0x37,0x38,0x66,0x30,0x38,0x38,0x37,0x38,0x55, + 0x2c,0x30,0x78,0x32,0x35,0x34,0x61,0x36,0x66,0x32,0x35,0x55,0x2c,0x30,0x78,0x32,0x65,0x35,0x63,0x37,0x32,0x32,0x65,0x55,0x2c,0x0a,0x30,0x78,0x31,0x63,0x33,0x38, + 0x32,0x34,0x31,0x63,0x55,0x2c,0x30,0x78,0x61,0x36,0x35,0x37,0x66,0x31,0x61,0x36,0x55,0x2c,0x30,0x78,0x62,0x34,0x37,0x33,0x63,0x37,0x62,0x34,0x55,0x2c,0x30,0x78, + 0x63,0x36,0x39,0x37,0x35,0x31,0x63,0x36,0x55,0x2c,0x0a,0x30,0x78,0x65,0x38,0x63,0x62,0x32,0x33,0x65,0x38,0x55,0x2c,0x30,0x78,0x64,0x64,0x61,0x31,0x37,0x63,0x64, + 0x64,0x55,0x2c,0x30,0x78,0x37,0x34,0x65,0x38,0x39,0x63,0x37,0x34,0x55,0x2c,0x30,0x78,0x31,0x66,0x33,0x65,0x32,0x31,0x31,0x66,0x55,0x2c,0x0a,0x30,0x78,0x34,0x62, + 0x39,0x36,0x64,0x64,0x34,0x62,0x55,0x2c,0x30,0x78,0x62,0x64,0x36,0x31,0x64,0x63,0x62,0x64,0x55,0x2c,0x30,0x78,0x38,0x62,0x30,0x64,0x38,0x36,0x38,0x62,0x55,0x2c, + 0x30,0x78,0x38,0x61,0x30,0x66,0x38,0x35,0x38,0x61,0x55,0x2c,0x0a,0x30,0x78,0x37,0x30,0x65,0x30,0x39,0x30,0x37,0x30,0x55,0x2c,0x30,0x78,0x33,0x65,0x37,0x63,0x34, + 0x32,0x33,0x65,0x55,0x2c,0x30,0x78,0x62,0x35,0x37,0x31,0x63,0x34,0x62,0x35,0x55,0x2c,0x30,0x78,0x36,0x36,0x63,0x63,0x61,0x61,0x36,0x36,0x55,0x2c,0x0a,0x30,0x78, + 0x34,0x38,0x39,0x30,0x64,0x38,0x34,0x38,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x36,0x30,0x35,0x30,0x33,0x55,0x2c,0x30,0x78,0x66,0x36,0x66,0x37,0x30,0x31,0x66,0x36, + 0x55,0x2c,0x30,0x78,0x30,0x65,0x31,0x63,0x31,0x32,0x30,0x65,0x55,0x2c,0x0a,0x30,0x78,0x36,0x31,0x63,0x32,0x61,0x33,0x36,0x31,0x55,0x2c,0x30,0x78,0x33,0x35,0x36, + 0x61,0x35,0x66,0x33,0x35,0x55,0x2c,0x30,0x78,0x35,0x37,0x61,0x65,0x66,0x39,0x35,0x37,0x55,0x2c,0x30,0x78,0x62,0x39,0x36,0x39,0x64,0x30,0x62,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x38,0x36,0x31,0x37,0x39,0x31,0x38,0x36,0x55,0x2c,0x30,0x78,0x63,0x31,0x39,0x39,0x35,0x38,0x63,0x31,0x55,0x2c,0x30,0x78,0x31,0x64,0x33,0x61,0x32,0x37, + 0x31,0x64,0x55,0x2c,0x30,0x78,0x39,0x65,0x32,0x37,0x62,0x39,0x39,0x65,0x55,0x2c,0x0a,0x30,0x78,0x65,0x31,0x64,0x39,0x33,0x38,0x65,0x31,0x55,0x2c,0x30,0x78,0x66, + 0x38,0x65,0x62,0x31,0x33,0x66,0x38,0x55,0x2c,0x30,0x78,0x39,0x38,0x32,0x62,0x62,0x33,0x39,0x38,0x55,0x2c,0x30,0x78,0x31,0x31,0x32,0x32,0x33,0x33,0x31,0x31,0x55, + 0x2c,0x0a,0x30,0x78,0x36,0x39,0x64,0x32,0x62,0x62,0x36,0x39,0x55,0x2c,0x30,0x78,0x64,0x39,0x61,0x39,0x37,0x30,0x64,0x39,0x55,0x2c,0x30,0x78,0x38,0x65,0x30,0x37, + 0x38,0x39,0x38,0x65,0x55,0x2c,0x30,0x78,0x39,0x34,0x33,0x33,0x61,0x37,0x39,0x34,0x55,0x2c,0x0a,0x30,0x78,0x39,0x62,0x32,0x64,0x62,0x36,0x39,0x62,0x55,0x2c,0x30, + 0x78,0x31,0x65,0x33,0x63,0x32,0x32,0x31,0x65,0x55,0x2c,0x30,0x78,0x38,0x37,0x31,0x35,0x39,0x32,0x38,0x37,0x55,0x2c,0x30,0x78,0x65,0x39,0x63,0x39,0x32,0x30,0x65, + 0x39,0x55,0x2c,0x0a,0x30,0x78,0x63,0x65,0x38,0x37,0x34,0x39,0x63,0x65,0x55,0x2c,0x30,0x78,0x35,0x35,0x61,0x61,0x66,0x66,0x35,0x35,0x55,0x2c,0x30,0x78,0x32,0x38, + 0x35,0x30,0x37,0x38,0x32,0x38,0x55,0x2c,0x30,0x78,0x64,0x66,0x61,0x35,0x37,0x61,0x64,0x66,0x55,0x2c,0x0a,0x30,0x78,0x38,0x63,0x30,0x33,0x38,0x66,0x38,0x63,0x55, + 0x2c,0x30,0x78,0x61,0x31,0x35,0x39,0x66,0x38,0x61,0x31,0x55,0x2c,0x30,0x78,0x38,0x39,0x30,0x39,0x38,0x30,0x38,0x39,0x55,0x2c,0x30,0x78,0x30,0x64,0x31,0x61,0x31, + 0x37,0x30,0x64,0x55,0x2c,0x0a,0x30,0x78,0x62,0x66,0x36,0x35,0x64,0x61,0x62,0x66,0x55,0x2c,0x30,0x78,0x65,0x36,0x64,0x37,0x33,0x31,0x65,0x36,0x55,0x2c,0x30,0x78, + 0x34,0x32,0x38,0x34,0x63,0x36,0x34,0x32,0x55,0x2c,0x30,0x78,0x36,0x38,0x64,0x30,0x62,0x38,0x36,0x38,0x55,0x2c,0x0a,0x30,0x78,0x34,0x31,0x38,0x32,0x63,0x33,0x34, + 0x31,0x55,0x2c,0x30,0x78,0x39,0x39,0x32,0x39,0x62,0x30,0x39,0x39,0x55,0x2c,0x30,0x78,0x32,0x64,0x35,0x61,0x37,0x37,0x32,0x64,0x55,0x2c,0x30,0x78,0x30,0x66,0x31, + 0x65,0x31,0x31,0x30,0x66,0x55,0x2c,0x0a,0x30,0x78,0x62,0x30,0x37,0x62,0x63,0x62,0x62,0x30,0x55,0x2c,0x30,0x78,0x35,0x34,0x61,0x38,0x66,0x63,0x35,0x34,0x55,0x2c, + 0x30,0x78,0x62,0x62,0x36,0x64,0x64,0x36,0x62,0x62,0x55,0x2c,0x30,0x78,0x31,0x36,0x32,0x63,0x33,0x61,0x31,0x36,0x55,0x2c,0x0a,0x30,0x78,0x63,0x36,0x61,0x35,0x36, + 0x33,0x36,0x33,0x55,0x2c,0x30,0x78,0x66,0x38,0x38,0x34,0x37,0x63,0x37,0x63,0x55,0x2c,0x30,0x78,0x65,0x65,0x39,0x39,0x37,0x37,0x37,0x37,0x55,0x2c,0x30,0x78,0x66, + 0x36,0x38,0x64,0x37,0x62,0x37,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x66,0x30,0x64,0x66,0x32,0x66,0x32,0x55,0x2c,0x30,0x78,0x64,0x36,0x62,0x64,0x36,0x62,0x36,0x62, + 0x55,0x2c,0x30,0x78,0x64,0x65,0x62,0x31,0x36,0x66,0x36,0x66,0x55,0x2c,0x30,0x78,0x39,0x31,0x35,0x34,0x63,0x35,0x63,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x30,0x35, + 0x30,0x33,0x30,0x33,0x30,0x55,0x2c,0x30,0x78,0x30,0x32,0x30,0x33,0x30,0x31,0x30,0x31,0x55,0x2c,0x30,0x78,0x63,0x65,0x61,0x39,0x36,0x37,0x36,0x37,0x55,0x2c,0x30, + 0x78,0x35,0x36,0x37,0x64,0x32,0x62,0x32,0x62,0x55,0x2c,0x0a,0x30,0x78,0x65,0x37,0x31,0x39,0x66,0x65,0x66,0x65,0x55,0x2c,0x30,0x78,0x62,0x35,0x36,0x32,0x64,0x37, + 0x64,0x37,0x55,0x2c,0x30,0x78,0x34,0x64,0x65,0x36,0x61,0x62,0x61,0x62,0x55,0x2c,0x30,0x78,0x65,0x63,0x39,0x61,0x37,0x36,0x37,0x36,0x55,0x2c,0x0a,0x30,0x78,0x38, + 0x66,0x34,0x35,0x63,0x61,0x63,0x61,0x55,0x2c,0x30,0x78,0x31,0x66,0x39,0x64,0x38,0x32,0x38,0x32,0x55,0x2c,0x30,0x78,0x38,0x39,0x34,0x30,0x63,0x39,0x63,0x39,0x55, + 0x2c,0x30,0x78,0x66,0x61,0x38,0x37,0x37,0x64,0x37,0x64,0x55,0x2c,0x0a,0x30,0x78,0x65,0x66,0x31,0x35,0x66,0x61,0x66,0x61,0x55,0x2c,0x30,0x78,0x62,0x32,0x65,0x62, + 0x35,0x39,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x65,0x63,0x39,0x34,0x37,0x34,0x37,0x55,0x2c,0x30,0x78,0x66,0x62,0x30,0x62,0x66,0x30,0x66,0x30,0x55,0x2c,0x0a,0x30, + 0x78,0x34,0x31,0x65,0x63,0x61,0x64,0x61,0x64,0x55,0x2c,0x30,0x78,0x62,0x33,0x36,0x37,0x64,0x34,0x64,0x34,0x55,0x2c,0x30,0x78,0x35,0x66,0x66,0x64,0x61,0x32,0x61, + 0x32,0x55,0x2c,0x30,0x78,0x34,0x35,0x65,0x61,0x61,0x66,0x61,0x66,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x62,0x66,0x39,0x63,0x39,0x63,0x55,0x2c,0x30,0x78,0x35,0x33, + 0x66,0x37,0x61,0x34,0x61,0x34,0x55,0x2c,0x30,0x78,0x65,0x34,0x39,0x36,0x37,0x32,0x37,0x32,0x55,0x2c,0x30,0x78,0x39,0x62,0x35,0x62,0x63,0x30,0x63,0x30,0x55,0x2c, + 0x0a,0x30,0x78,0x37,0x35,0x63,0x32,0x62,0x37,0x62,0x37,0x55,0x2c,0x30,0x78,0x65,0x31,0x31,0x63,0x66,0x64,0x66,0x64,0x55,0x2c,0x30,0x78,0x33,0x64,0x61,0x65,0x39, + 0x33,0x39,0x33,0x55,0x2c,0x30,0x78,0x34,0x63,0x36,0x61,0x32,0x36,0x32,0x36,0x55,0x2c,0x0a,0x30,0x78,0x36,0x63,0x35,0x61,0x33,0x36,0x33,0x36,0x55,0x2c,0x30,0x78, + 0x37,0x65,0x34,0x31,0x33,0x66,0x33,0x66,0x55,0x2c,0x30,0x78,0x66,0x35,0x30,0x32,0x66,0x37,0x66,0x37,0x55,0x2c,0x30,0x78,0x38,0x33,0x34,0x66,0x63,0x63,0x63,0x63, + 0x55,0x2c,0x0a,0x30,0x78,0x36,0x38,0x35,0x63,0x33,0x34,0x33,0x34,0x55,0x2c,0x30,0x78,0x35,0x31,0x66,0x34,0x61,0x35,0x61,0x35,0x55,0x2c,0x30,0x78,0x64,0x31,0x33, + 0x34,0x65,0x35,0x65,0x35,0x55,0x2c,0x30,0x78,0x66,0x39,0x30,0x38,0x66,0x31,0x66,0x31,0x55,0x2c,0x0a,0x30,0x78,0x65,0x32,0x39,0x33,0x37,0x31,0x37,0x31,0x55,0x2c, + 0x30,0x78,0x61,0x62,0x37,0x33,0x64,0x38,0x64,0x38,0x55,0x2c,0x30,0x78,0x36,0x32,0x35,0x33,0x33,0x31,0x33,0x31,0x55,0x2c,0x30,0x78,0x32,0x61,0x33,0x66,0x31,0x35, + 0x31,0x35,0x55,0x2c,0x0a,0x30,0x78,0x30,0x38,0x30,0x63,0x30,0x34,0x30,0x34,0x55,0x2c,0x30,0x78,0x39,0x35,0x35,0x32,0x63,0x37,0x63,0x37,0x55,0x2c,0x30,0x78,0x34, + 0x36,0x36,0x35,0x32,0x33,0x32,0x33,0x55,0x2c,0x30,0x78,0x39,0x64,0x35,0x65,0x63,0x33,0x63,0x33,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x32,0x38,0x31,0x38,0x31,0x38, + 0x55,0x2c,0x30,0x78,0x33,0x37,0x61,0x31,0x39,0x36,0x39,0x36,0x55,0x2c,0x30,0x78,0x30,0x61,0x30,0x66,0x30,0x35,0x30,0x35,0x55,0x2c,0x30,0x78,0x32,0x66,0x62,0x35, + 0x39,0x61,0x39,0x61,0x55,0x2c,0x0a,0x30,0x78,0x30,0x65,0x30,0x39,0x30,0x37,0x30,0x37,0x55,0x2c,0x30,0x78,0x32,0x34,0x33,0x36,0x31,0x32,0x31,0x32,0x55,0x2c,0x30, + 0x78,0x31,0x62,0x39,0x62,0x38,0x30,0x38,0x30,0x55,0x2c,0x30,0x78,0x64,0x66,0x33,0x64,0x65,0x32,0x65,0x32,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x32,0x36,0x65,0x62, + 0x65,0x62,0x55,0x2c,0x30,0x78,0x34,0x65,0x36,0x39,0x32,0x37,0x32,0x37,0x55,0x2c,0x30,0x78,0x37,0x66,0x63,0x64,0x62,0x32,0x62,0x32,0x55,0x2c,0x30,0x78,0x65,0x61, + 0x39,0x66,0x37,0x35,0x37,0x35,0x55,0x2c,0x0a,0x30,0x78,0x31,0x32,0x31,0x62,0x30,0x39,0x30,0x39,0x55,0x2c,0x30,0x78,0x31,0x64,0x39,0x65,0x38,0x33,0x38,0x33,0x55, + 0x2c,0x30,0x78,0x35,0x38,0x37,0x34,0x32,0x63,0x32,0x63,0x55,0x2c,0x30,0x78,0x33,0x34,0x32,0x65,0x31,0x61,0x31,0x61,0x55,0x2c,0x0a,0x30,0x78,0x33,0x36,0x32,0x64, + 0x31,0x62,0x31,0x62,0x55,0x2c,0x30,0x78,0x64,0x63,0x62,0x32,0x36,0x65,0x36,0x65,0x55,0x2c,0x30,0x78,0x62,0x34,0x65,0x65,0x35,0x61,0x35,0x61,0x55,0x2c,0x30,0x78, + 0x35,0x62,0x66,0x62,0x61,0x30,0x61,0x30,0x55,0x2c,0x0a,0x30,0x78,0x61,0x34,0x66,0x36,0x35,0x32,0x35,0x32,0x55,0x2c,0x30,0x78,0x37,0x36,0x34,0x64,0x33,0x62,0x33, + 0x62,0x55,0x2c,0x30,0x78,0x62,0x37,0x36,0x31,0x64,0x36,0x64,0x36,0x55,0x2c,0x30,0x78,0x37,0x64,0x63,0x65,0x62,0x33,0x62,0x33,0x55,0x2c,0x0a,0x30,0x78,0x35,0x32, + 0x37,0x62,0x32,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x64,0x64,0x33,0x65,0x65,0x33,0x65,0x33,0x55,0x2c,0x30,0x78,0x35,0x65,0x37,0x31,0x32,0x66,0x32,0x66,0x55,0x2c, + 0x30,0x78,0x31,0x33,0x39,0x37,0x38,0x34,0x38,0x34,0x55,0x2c,0x0a,0x30,0x78,0x61,0x36,0x66,0x35,0x35,0x33,0x35,0x33,0x55,0x2c,0x30,0x78,0x62,0x39,0x36,0x38,0x64, + 0x31,0x64,0x31,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x30,0x78,0x63,0x31,0x32,0x63,0x65,0x64,0x65,0x64,0x55,0x2c,0x0a,0x30,0x78, + 0x34,0x30,0x36,0x30,0x32,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x65,0x33,0x31,0x66,0x66,0x63,0x66,0x63,0x55,0x2c,0x30,0x78,0x37,0x39,0x63,0x38,0x62,0x31,0x62,0x31, + 0x55,0x2c,0x30,0x78,0x62,0x36,0x65,0x64,0x35,0x62,0x35,0x62,0x55,0x2c,0x0a,0x30,0x78,0x64,0x34,0x62,0x65,0x36,0x61,0x36,0x61,0x55,0x2c,0x30,0x78,0x38,0x64,0x34, + 0x36,0x63,0x62,0x63,0x62,0x55,0x2c,0x30,0x78,0x36,0x37,0x64,0x39,0x62,0x65,0x62,0x65,0x55,0x2c,0x30,0x78,0x37,0x32,0x34,0x62,0x33,0x39,0x33,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x39,0x34,0x64,0x65,0x34,0x61,0x34,0x61,0x55,0x2c,0x30,0x78,0x39,0x38,0x64,0x34,0x34,0x63,0x34,0x63,0x55,0x2c,0x30,0x78,0x62,0x30,0x65,0x38,0x35,0x38, + 0x35,0x38,0x55,0x2c,0x30,0x78,0x38,0x35,0x34,0x61,0x63,0x66,0x63,0x66,0x55,0x2c,0x0a,0x30,0x78,0x62,0x62,0x36,0x62,0x64,0x30,0x64,0x30,0x55,0x2c,0x30,0x78,0x63, + 0x35,0x32,0x61,0x65,0x66,0x65,0x66,0x55,0x2c,0x30,0x78,0x34,0x66,0x65,0x35,0x61,0x61,0x61,0x61,0x55,0x2c,0x30,0x78,0x65,0x64,0x31,0x36,0x66,0x62,0x66,0x62,0x55, + 0x2c,0x0a,0x30,0x78,0x38,0x36,0x63,0x35,0x34,0x33,0x34,0x33,0x55,0x2c,0x30,0x78,0x39,0x61,0x64,0x37,0x34,0x64,0x34,0x64,0x55,0x2c,0x30,0x78,0x36,0x36,0x35,0x35, + 0x33,0x33,0x33,0x33,0x55,0x2c,0x30,0x78,0x31,0x31,0x39,0x34,0x38,0x35,0x38,0x35,0x55,0x2c,0x0a,0x30,0x78,0x38,0x61,0x63,0x66,0x34,0x35,0x34,0x35,0x55,0x2c,0x30, + 0x78,0x65,0x39,0x31,0x30,0x66,0x39,0x66,0x39,0x55,0x2c,0x30,0x78,0x30,0x34,0x30,0x36,0x30,0x32,0x30,0x32,0x55,0x2c,0x30,0x78,0x66,0x65,0x38,0x31,0x37,0x66,0x37, + 0x66,0x55,0x2c,0x0a,0x30,0x78,0x61,0x30,0x66,0x30,0x35,0x30,0x35,0x30,0x55,0x2c,0x30,0x78,0x37,0x38,0x34,0x34,0x33,0x63,0x33,0x63,0x55,0x2c,0x30,0x78,0x32,0x35, + 0x62,0x61,0x39,0x66,0x39,0x66,0x55,0x2c,0x30,0x78,0x34,0x62,0x65,0x33,0x61,0x38,0x61,0x38,0x55,0x2c,0x0a,0x30,0x78,0x61,0x32,0x66,0x33,0x35,0x31,0x35,0x31,0x55, + 0x2c,0x30,0x78,0x35,0x64,0x66,0x65,0x61,0x33,0x61,0x33,0x55,0x2c,0x30,0x78,0x38,0x30,0x63,0x30,0x34,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x30,0x35,0x38,0x61,0x38, + 0x66,0x38,0x66,0x55,0x2c,0x0a,0x30,0x78,0x33,0x66,0x61,0x64,0x39,0x32,0x39,0x32,0x55,0x2c,0x30,0x78,0x32,0x31,0x62,0x63,0x39,0x64,0x39,0x64,0x55,0x2c,0x30,0x78, + 0x37,0x30,0x34,0x38,0x33,0x38,0x33,0x38,0x55,0x2c,0x30,0x78,0x66,0x31,0x30,0x34,0x66,0x35,0x66,0x35,0x55,0x2c,0x0a,0x30,0x78,0x36,0x33,0x64,0x66,0x62,0x63,0x62, + 0x63,0x55,0x2c,0x30,0x78,0x37,0x37,0x63,0x31,0x62,0x36,0x62,0x36,0x55,0x2c,0x30,0x78,0x61,0x66,0x37,0x35,0x64,0x61,0x64,0x61,0x55,0x2c,0x30,0x78,0x34,0x32,0x36, + 0x33,0x32,0x31,0x32,0x31,0x55,0x2c,0x0a,0x30,0x78,0x32,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x55,0x2c,0x30,0x78,0x65,0x35,0x31,0x61,0x66,0x66,0x66,0x66,0x55,0x2c, + 0x30,0x78,0x66,0x64,0x30,0x65,0x66,0x33,0x66,0x33,0x55,0x2c,0x30,0x78,0x62,0x66,0x36,0x64,0x64,0x32,0x64,0x32,0x55,0x2c,0x0a,0x30,0x78,0x38,0x31,0x34,0x63,0x63, + 0x64,0x63,0x64,0x55,0x2c,0x30,0x78,0x31,0x38,0x31,0x34,0x30,0x63,0x30,0x63,0x55,0x2c,0x30,0x78,0x32,0x36,0x33,0x35,0x31,0x33,0x31,0x33,0x55,0x2c,0x30,0x78,0x63, + 0x33,0x32,0x66,0x65,0x63,0x65,0x63,0x55,0x2c,0x0a,0x30,0x78,0x62,0x65,0x65,0x31,0x35,0x66,0x35,0x66,0x55,0x2c,0x30,0x78,0x33,0x35,0x61,0x32,0x39,0x37,0x39,0x37, + 0x55,0x2c,0x30,0x78,0x38,0x38,0x63,0x63,0x34,0x34,0x34,0x34,0x55,0x2c,0x30,0x78,0x32,0x65,0x33,0x39,0x31,0x37,0x31,0x37,0x55,0x2c,0x0a,0x30,0x78,0x39,0x33,0x35, + 0x37,0x63,0x34,0x63,0x34,0x55,0x2c,0x30,0x78,0x35,0x35,0x66,0x32,0x61,0x37,0x61,0x37,0x55,0x2c,0x30,0x78,0x66,0x63,0x38,0x32,0x37,0x65,0x37,0x65,0x55,0x2c,0x30, + 0x78,0x37,0x61,0x34,0x37,0x33,0x64,0x33,0x64,0x55,0x2c,0x0a,0x30,0x78,0x63,0x38,0x61,0x63,0x36,0x34,0x36,0x34,0x55,0x2c,0x30,0x78,0x62,0x61,0x65,0x37,0x35,0x64, + 0x35,0x64,0x55,0x2c,0x30,0x78,0x33,0x32,0x32,0x62,0x31,0x39,0x31,0x39,0x55,0x2c,0x30,0x78,0x65,0x36,0x39,0x35,0x37,0x33,0x37,0x33,0x55,0x2c,0x0a,0x30,0x78,0x63, + 0x30,0x61,0x30,0x36,0x30,0x36,0x30,0x55,0x2c,0x30,0x78,0x31,0x39,0x39,0x38,0x38,0x31,0x38,0x31,0x55,0x2c,0x30,0x78,0x39,0x65,0x64,0x31,0x34,0x66,0x34,0x66,0x55, + 0x2c,0x30,0x78,0x61,0x33,0x37,0x66,0x64,0x63,0x64,0x63,0x55,0x2c,0x0a,0x30,0x78,0x34,0x34,0x36,0x36,0x32,0x32,0x32,0x32,0x55,0x2c,0x30,0x78,0x35,0x34,0x37,0x65, + 0x32,0x61,0x32,0x61,0x55,0x2c,0x30,0x78,0x33,0x62,0x61,0x62,0x39,0x30,0x39,0x30,0x55,0x2c,0x30,0x78,0x30,0x62,0x38,0x33,0x38,0x38,0x38,0x38,0x55,0x2c,0x0a,0x30, + 0x78,0x38,0x63,0x63,0x61,0x34,0x36,0x34,0x36,0x55,0x2c,0x30,0x78,0x63,0x37,0x32,0x39,0x65,0x65,0x65,0x65,0x55,0x2c,0x30,0x78,0x36,0x62,0x64,0x33,0x62,0x38,0x62, + 0x38,0x55,0x2c,0x30,0x78,0x32,0x38,0x33,0x63,0x31,0x34,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x61,0x37,0x37,0x39,0x64,0x65,0x64,0x65,0x55,0x2c,0x30,0x78,0x62,0x63, + 0x65,0x32,0x35,0x65,0x35,0x65,0x55,0x2c,0x30,0x78,0x31,0x36,0x31,0x64,0x30,0x62,0x30,0x62,0x55,0x2c,0x30,0x78,0x61,0x64,0x37,0x36,0x64,0x62,0x64,0x62,0x55,0x2c, + 0x0a,0x30,0x78,0x64,0x62,0x33,0x62,0x65,0x30,0x65,0x30,0x55,0x2c,0x30,0x78,0x36,0x34,0x35,0x36,0x33,0x32,0x33,0x32,0x55,0x2c,0x30,0x78,0x37,0x34,0x34,0x65,0x33, + 0x61,0x33,0x61,0x55,0x2c,0x30,0x78,0x31,0x34,0x31,0x65,0x30,0x61,0x30,0x61,0x55,0x2c,0x0a,0x30,0x78,0x39,0x32,0x64,0x62,0x34,0x39,0x34,0x39,0x55,0x2c,0x30,0x78, + 0x30,0x63,0x30,0x61,0x30,0x36,0x30,0x36,0x55,0x2c,0x30,0x78,0x34,0x38,0x36,0x63,0x32,0x34,0x32,0x34,0x55,0x2c,0x30,0x78,0x62,0x38,0x65,0x34,0x35,0x63,0x35,0x63, + 0x55,0x2c,0x0a,0x30,0x78,0x39,0x66,0x35,0x64,0x63,0x32,0x63,0x32,0x55,0x2c,0x30,0x78,0x62,0x64,0x36,0x65,0x64,0x33,0x64,0x33,0x55,0x2c,0x30,0x78,0x34,0x33,0x65, + 0x66,0x61,0x63,0x61,0x63,0x55,0x2c,0x30,0x78,0x63,0x34,0x61,0x36,0x36,0x32,0x36,0x32,0x55,0x2c,0x0a,0x30,0x78,0x33,0x39,0x61,0x38,0x39,0x31,0x39,0x31,0x55,0x2c, + 0x30,0x78,0x33,0x31,0x61,0x34,0x39,0x35,0x39,0x35,0x55,0x2c,0x30,0x78,0x64,0x33,0x33,0x37,0x65,0x34,0x65,0x34,0x55,0x2c,0x30,0x78,0x66,0x32,0x38,0x62,0x37,0x39, + 0x37,0x39,0x55,0x2c,0x0a,0x30,0x78,0x64,0x35,0x33,0x32,0x65,0x37,0x65,0x37,0x55,0x2c,0x30,0x78,0x38,0x62,0x34,0x33,0x63,0x38,0x63,0x38,0x55,0x2c,0x30,0x78,0x36, + 0x65,0x35,0x39,0x33,0x37,0x33,0x37,0x55,0x2c,0x30,0x78,0x64,0x61,0x62,0x37,0x36,0x64,0x36,0x64,0x55,0x2c,0x0a,0x30,0x78,0x30,0x31,0x38,0x63,0x38,0x64,0x38,0x64, + 0x55,0x2c,0x30,0x78,0x62,0x31,0x36,0x34,0x64,0x35,0x64,0x35,0x55,0x2c,0x30,0x78,0x39,0x63,0x64,0x32,0x34,0x65,0x34,0x65,0x55,0x2c,0x30,0x78,0x34,0x39,0x65,0x30, + 0x61,0x39,0x61,0x39,0x55,0x2c,0x0a,0x30,0x78,0x64,0x38,0x62,0x34,0x36,0x63,0x36,0x63,0x55,0x2c,0x30,0x78,0x61,0x63,0x66,0x61,0x35,0x36,0x35,0x36,0x55,0x2c,0x30, + 0x78,0x66,0x33,0x30,0x37,0x66,0x34,0x66,0x34,0x55,0x2c,0x30,0x78,0x63,0x66,0x32,0x35,0x65,0x61,0x65,0x61,0x55,0x2c,0x0a,0x30,0x78,0x63,0x61,0x61,0x66,0x36,0x35, + 0x36,0x35,0x55,0x2c,0x30,0x78,0x66,0x34,0x38,0x65,0x37,0x61,0x37,0x61,0x55,0x2c,0x30,0x78,0x34,0x37,0x65,0x39,0x61,0x65,0x61,0x65,0x55,0x2c,0x30,0x78,0x31,0x30, + 0x31,0x38,0x30,0x38,0x30,0x38,0x55,0x2c,0x0a,0x30,0x78,0x36,0x66,0x64,0x35,0x62,0x61,0x62,0x61,0x55,0x2c,0x30,0x78,0x66,0x30,0x38,0x38,0x37,0x38,0x37,0x38,0x55, + 0x2c,0x30,0x78,0x34,0x61,0x36,0x66,0x32,0x35,0x32,0x35,0x55,0x2c,0x30,0x78,0x35,0x63,0x37,0x32,0x32,0x65,0x32,0x65,0x55,0x2c,0x0a,0x30,0x78,0x33,0x38,0x32,0x34, + 0x31,0x63,0x31,0x63,0x55,0x2c,0x30,0x78,0x35,0x37,0x66,0x31,0x61,0x36,0x61,0x36,0x55,0x2c,0x30,0x78,0x37,0x33,0x63,0x37,0x62,0x34,0x62,0x34,0x55,0x2c,0x30,0x78, + 0x39,0x37,0x35,0x31,0x63,0x36,0x63,0x36,0x55,0x2c,0x0a,0x30,0x78,0x63,0x62,0x32,0x33,0x65,0x38,0x65,0x38,0x55,0x2c,0x30,0x78,0x61,0x31,0x37,0x63,0x64,0x64,0x64, + 0x64,0x55,0x2c,0x30,0x78,0x65,0x38,0x39,0x63,0x37,0x34,0x37,0x34,0x55,0x2c,0x30,0x78,0x33,0x65,0x32,0x31,0x31,0x66,0x31,0x66,0x55,0x2c,0x0a,0x30,0x78,0x39,0x36, + 0x64,0x64,0x34,0x62,0x34,0x62,0x55,0x2c,0x30,0x78,0x36,0x31,0x64,0x63,0x62,0x64,0x62,0x64,0x55,0x2c,0x30,0x78,0x30,0x64,0x38,0x36,0x38,0x62,0x38,0x62,0x55,0x2c, + 0x30,0x78,0x30,0x66,0x38,0x35,0x38,0x61,0x38,0x61,0x55,0x2c,0x0a,0x30,0x78,0x65,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x55,0x2c,0x30,0x78,0x37,0x63,0x34,0x32,0x33, + 0x65,0x33,0x65,0x55,0x2c,0x30,0x78,0x37,0x31,0x63,0x34,0x62,0x35,0x62,0x35,0x55,0x2c,0x30,0x78,0x63,0x63,0x61,0x61,0x36,0x36,0x36,0x36,0x55,0x2c,0x0a,0x30,0x78, + 0x39,0x30,0x64,0x38,0x34,0x38,0x34,0x38,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x35,0x30,0x33,0x30,0x33,0x55,0x2c,0x30,0x78,0x66,0x37,0x30,0x31,0x66,0x36,0x66,0x36, + 0x55,0x2c,0x30,0x78,0x31,0x63,0x31,0x32,0x30,0x65,0x30,0x65,0x55,0x2c,0x0a,0x30,0x78,0x63,0x32,0x61,0x33,0x36,0x31,0x36,0x31,0x55,0x2c,0x30,0x78,0x36,0x61,0x35, + 0x66,0x33,0x35,0x33,0x35,0x55,0x2c,0x30,0x78,0x61,0x65,0x66,0x39,0x35,0x37,0x35,0x37,0x55,0x2c,0x30,0x78,0x36,0x39,0x64,0x30,0x62,0x39,0x62,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x31,0x37,0x39,0x31,0x38,0x36,0x38,0x36,0x55,0x2c,0x30,0x78,0x39,0x39,0x35,0x38,0x63,0x31,0x63,0x31,0x55,0x2c,0x30,0x78,0x33,0x61,0x32,0x37,0x31,0x64, + 0x31,0x64,0x55,0x2c,0x30,0x78,0x32,0x37,0x62,0x39,0x39,0x65,0x39,0x65,0x55,0x2c,0x0a,0x30,0x78,0x64,0x39,0x33,0x38,0x65,0x31,0x65,0x31,0x55,0x2c,0x30,0x78,0x65, + 0x62,0x31,0x33,0x66,0x38,0x66,0x38,0x55,0x2c,0x30,0x78,0x32,0x62,0x62,0x33,0x39,0x38,0x39,0x38,0x55,0x2c,0x30,0x78,0x32,0x32,0x33,0x33,0x31,0x31,0x31,0x31,0x55, + 0x2c,0x0a,0x30,0x78,0x64,0x32,0x62,0x62,0x36,0x39,0x36,0x39,0x55,0x2c,0x30,0x78,0x61,0x39,0x37,0x30,0x64,0x39,0x64,0x39,0x55,0x2c,0x30,0x78,0x30,0x37,0x38,0x39, + 0x38,0x65,0x38,0x65,0x55,0x2c,0x30,0x78,0x33,0x33,0x61,0x37,0x39,0x34,0x39,0x34,0x55,0x2c,0x0a,0x30,0x78,0x32,0x64,0x62,0x36,0x39,0x62,0x39,0x62,0x55,0x2c,0x30, + 0x78,0x33,0x63,0x32,0x32,0x31,0x65,0x31,0x65,0x55,0x2c,0x30,0x78,0x31,0x35,0x39,0x32,0x38,0x37,0x38,0x37,0x55,0x2c,0x30,0x78,0x63,0x39,0x32,0x30,0x65,0x39,0x65, + 0x39,0x55,0x2c,0x0a,0x30,0x78,0x38,0x37,0x34,0x39,0x63,0x65,0x63,0x65,0x55,0x2c,0x30,0x78,0x61,0x61,0x66,0x66,0x35,0x35,0x35,0x35,0x55,0x2c,0x30,0x78,0x35,0x30, + 0x37,0x38,0x32,0x38,0x32,0x38,0x55,0x2c,0x30,0x78,0x61,0x35,0x37,0x61,0x64,0x66,0x64,0x66,0x55,0x2c,0x0a,0x30,0x78,0x30,0x33,0x38,0x66,0x38,0x63,0x38,0x63,0x55, + 0x2c,0x30,0x78,0x35,0x39,0x66,0x38,0x61,0x31,0x61,0x31,0x55,0x2c,0x30,0x78,0x30,0x39,0x38,0x30,0x38,0x39,0x38,0x39,0x55,0x2c,0x30,0x78,0x31,0x61,0x31,0x37,0x30, + 0x64,0x30,0x64,0x55,0x2c,0x0a,0x30,0x78,0x36,0x35,0x64,0x61,0x62,0x66,0x62,0x66,0x55,0x2c,0x30,0x78,0x64,0x37,0x33,0x31,0x65,0x36,0x65,0x36,0x55,0x2c,0x30,0x78, + 0x38,0x34,0x63,0x36,0x34,0x32,0x34,0x32,0x55,0x2c,0x30,0x78,0x64,0x30,0x62,0x38,0x36,0x38,0x36,0x38,0x55,0x2c,0x0a,0x30,0x78,0x38,0x32,0x63,0x33,0x34,0x31,0x34, + 0x31,0x55,0x2c,0x30,0x78,0x32,0x39,0x62,0x30,0x39,0x39,0x39,0x39,0x55,0x2c,0x30,0x78,0x35,0x61,0x37,0x37,0x32,0x64,0x32,0x64,0x55,0x2c,0x30,0x78,0x31,0x65,0x31, + 0x31,0x30,0x66,0x30,0x66,0x55,0x2c,0x0a,0x30,0x78,0x37,0x62,0x63,0x62,0x62,0x30,0x62,0x30,0x55,0x2c,0x30,0x78,0x61,0x38,0x66,0x63,0x35,0x34,0x35,0x34,0x55,0x2c, + 0x30,0x78,0x36,0x64,0x64,0x36,0x62,0x62,0x62,0x62,0x55,0x2c,0x30,0x78,0x32,0x63,0x33,0x61,0x31,0x36,0x31,0x36,0x55,0x2c,0x0a,0x30,0x78,0x35,0x30,0x61,0x37,0x66, + 0x34,0x35,0x31,0x55,0x2c,0x30,0x78,0x35,0x33,0x36,0x35,0x34,0x31,0x37,0x65,0x55,0x2c,0x30,0x78,0x63,0x33,0x61,0x34,0x31,0x37,0x31,0x61,0x55,0x2c,0x30,0x78,0x39, + 0x36,0x35,0x65,0x32,0x37,0x33,0x61,0x55,0x2c,0x0a,0x30,0x78,0x63,0x62,0x36,0x62,0x61,0x62,0x33,0x62,0x55,0x2c,0x30,0x78,0x66,0x31,0x34,0x35,0x39,0x64,0x31,0x66, + 0x55,0x2c,0x30,0x78,0x61,0x62,0x35,0x38,0x66,0x61,0x61,0x63,0x55,0x2c,0x30,0x78,0x39,0x33,0x30,0x33,0x65,0x33,0x34,0x62,0x55,0x2c,0x0a,0x30,0x78,0x35,0x35,0x66, + 0x61,0x33,0x30,0x32,0x30,0x55,0x2c,0x30,0x78,0x66,0x36,0x36,0x64,0x37,0x36,0x61,0x64,0x55,0x2c,0x30,0x78,0x39,0x31,0x37,0x36,0x63,0x63,0x38,0x38,0x55,0x2c,0x30, + 0x78,0x32,0x35,0x34,0x63,0x30,0x32,0x66,0x35,0x55,0x2c,0x0a,0x30,0x78,0x66,0x63,0x64,0x37,0x65,0x35,0x34,0x66,0x55,0x2c,0x30,0x78,0x64,0x37,0x63,0x62,0x32,0x61, + 0x63,0x35,0x55,0x2c,0x30,0x78,0x38,0x30,0x34,0x34,0x33,0x35,0x32,0x36,0x55,0x2c,0x30,0x78,0x38,0x66,0x61,0x33,0x36,0x32,0x62,0x35,0x55,0x2c,0x0a,0x30,0x78,0x34, + 0x39,0x35,0x61,0x62,0x31,0x64,0x65,0x55,0x2c,0x30,0x78,0x36,0x37,0x31,0x62,0x62,0x61,0x32,0x35,0x55,0x2c,0x30,0x78,0x39,0x38,0x30,0x65,0x65,0x61,0x34,0x35,0x55, + 0x2c,0x30,0x78,0x65,0x31,0x63,0x30,0x66,0x65,0x35,0x64,0x55,0x2c,0x0a,0x30,0x78,0x30,0x32,0x37,0x35,0x32,0x66,0x63,0x33,0x55,0x2c,0x30,0x78,0x31,0x32,0x66,0x30, + 0x34,0x63,0x38,0x31,0x55,0x2c,0x30,0x78,0x61,0x33,0x39,0x37,0x34,0x36,0x38,0x64,0x55,0x2c,0x30,0x78,0x63,0x36,0x66,0x39,0x64,0x33,0x36,0x62,0x55,0x2c,0x0a,0x30, + 0x78,0x65,0x37,0x35,0x66,0x38,0x66,0x30,0x33,0x55,0x2c,0x30,0x78,0x39,0x35,0x39,0x63,0x39,0x32,0x31,0x35,0x55,0x2c,0x30,0x78,0x65,0x62,0x37,0x61,0x36,0x64,0x62, + 0x66,0x55,0x2c,0x30,0x78,0x64,0x61,0x35,0x39,0x35,0x32,0x39,0x35,0x55,0x2c,0x0a,0x30,0x78,0x32,0x64,0x38,0x33,0x62,0x65,0x64,0x34,0x55,0x2c,0x30,0x78,0x64,0x33, + 0x32,0x31,0x37,0x34,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x39,0x36,0x39,0x65,0x30,0x34,0x39,0x55,0x2c,0x30,0x78,0x34,0x34,0x63,0x38,0x63,0x39,0x38,0x65,0x55,0x2c, + 0x0a,0x30,0x78,0x36,0x61,0x38,0x39,0x63,0x32,0x37,0x35,0x55,0x2c,0x30,0x78,0x37,0x38,0x37,0x39,0x38,0x65,0x66,0x34,0x55,0x2c,0x30,0x78,0x36,0x62,0x33,0x65,0x35, + 0x38,0x39,0x39,0x55,0x2c,0x30,0x78,0x64,0x64,0x37,0x31,0x62,0x39,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x62,0x36,0x34,0x66,0x65,0x31,0x62,0x65,0x55,0x2c,0x30,0x78, + 0x31,0x37,0x61,0x64,0x38,0x38,0x66,0x30,0x55,0x2c,0x30,0x78,0x36,0x36,0x61,0x63,0x32,0x30,0x63,0x39,0x55,0x2c,0x30,0x78,0x62,0x34,0x33,0x61,0x63,0x65,0x37,0x64, + 0x55,0x2c,0x0a,0x30,0x78,0x31,0x38,0x34,0x61,0x64,0x66,0x36,0x33,0x55,0x2c,0x30,0x78,0x38,0x32,0x33,0x31,0x31,0x61,0x65,0x35,0x55,0x2c,0x30,0x78,0x36,0x30,0x33, + 0x33,0x35,0x31,0x39,0x37,0x55,0x2c,0x30,0x78,0x34,0x35,0x37,0x66,0x35,0x33,0x36,0x32,0x55,0x2c,0x0a,0x30,0x78,0x65,0x30,0x37,0x37,0x36,0x34,0x62,0x31,0x55,0x2c, + 0x30,0x78,0x38,0x34,0x61,0x65,0x36,0x62,0x62,0x62,0x55,0x2c,0x30,0x78,0x31,0x63,0x61,0x30,0x38,0x31,0x66,0x65,0x55,0x2c,0x30,0x78,0x39,0x34,0x32,0x62,0x30,0x38, + 0x66,0x39,0x55,0x2c,0x0a,0x30,0x78,0x35,0x38,0x36,0x38,0x34,0x38,0x37,0x30,0x55,0x2c,0x30,0x78,0x31,0x39,0x66,0x64,0x34,0x35,0x38,0x66,0x55,0x2c,0x30,0x78,0x38, + 0x37,0x36,0x63,0x64,0x65,0x39,0x34,0x55,0x2c,0x30,0x78,0x62,0x37,0x66,0x38,0x37,0x62,0x35,0x32,0x55,0x2c,0x0a,0x30,0x78,0x32,0x33,0x64,0x33,0x37,0x33,0x61,0x62, + 0x55,0x2c,0x30,0x78,0x65,0x32,0x30,0x32,0x34,0x62,0x37,0x32,0x55,0x2c,0x30,0x78,0x35,0x37,0x38,0x66,0x31,0x66,0x65,0x33,0x55,0x2c,0x30,0x78,0x32,0x61,0x61,0x62, + 0x35,0x35,0x36,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x37,0x32,0x38,0x65,0x62,0x62,0x32,0x55,0x2c,0x30,0x78,0x30,0x33,0x63,0x32,0x62,0x35,0x32,0x66,0x55,0x2c,0x30, + 0x78,0x39,0x61,0x37,0x62,0x63,0x35,0x38,0x36,0x55,0x2c,0x30,0x78,0x61,0x35,0x30,0x38,0x33,0x37,0x64,0x33,0x55,0x2c,0x0a,0x30,0x78,0x66,0x32,0x38,0x37,0x32,0x38, + 0x33,0x30,0x55,0x2c,0x30,0x78,0x62,0x32,0x61,0x35,0x62,0x66,0x32,0x33,0x55,0x2c,0x30,0x78,0x62,0x61,0x36,0x61,0x30,0x33,0x30,0x32,0x55,0x2c,0x30,0x78,0x35,0x63, + 0x38,0x32,0x31,0x36,0x65,0x64,0x55,0x2c,0x0a,0x30,0x78,0x32,0x62,0x31,0x63,0x63,0x66,0x38,0x61,0x55,0x2c,0x30,0x78,0x39,0x32,0x62,0x34,0x37,0x39,0x61,0x37,0x55, + 0x2c,0x30,0x78,0x66,0x30,0x66,0x32,0x30,0x37,0x66,0x33,0x55,0x2c,0x30,0x78,0x61,0x31,0x65,0x32,0x36,0x39,0x34,0x65,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x66,0x34, + 0x64,0x61,0x36,0x35,0x55,0x2c,0x30,0x78,0x64,0x35,0x62,0x65,0x30,0x35,0x30,0x36,0x55,0x2c,0x30,0x78,0x31,0x66,0x36,0x32,0x33,0x34,0x64,0x31,0x55,0x2c,0x30,0x78, + 0x38,0x61,0x66,0x65,0x61,0x36,0x63,0x34,0x55,0x2c,0x0a,0x30,0x78,0x39,0x64,0x35,0x33,0x32,0x65,0x33,0x34,0x55,0x2c,0x30,0x78,0x61,0x30,0x35,0x35,0x66,0x33,0x61, + 0x32,0x55,0x2c,0x30,0x78,0x33,0x32,0x65,0x31,0x38,0x61,0x30,0x35,0x55,0x2c,0x30,0x78,0x37,0x35,0x65,0x62,0x66,0x36,0x61,0x34,0x55,0x2c,0x0a,0x30,0x78,0x33,0x39, + 0x65,0x63,0x38,0x33,0x30,0x62,0x55,0x2c,0x30,0x78,0x61,0x61,0x65,0x66,0x36,0x30,0x34,0x30,0x55,0x2c,0x30,0x78,0x30,0x36,0x39,0x66,0x37,0x31,0x35,0x65,0x55,0x2c, + 0x30,0x78,0x35,0x31,0x31,0x30,0x36,0x65,0x62,0x64,0x55,0x2c,0x0a,0x30,0x78,0x66,0x39,0x38,0x61,0x32,0x31,0x33,0x65,0x55,0x2c,0x30,0x78,0x33,0x64,0x30,0x36,0x64, + 0x64,0x39,0x36,0x55,0x2c,0x30,0x78,0x61,0x65,0x30,0x35,0x33,0x65,0x64,0x64,0x55,0x2c,0x30,0x78,0x34,0x36,0x62,0x64,0x65,0x36,0x34,0x64,0x55,0x2c,0x0a,0x30,0x78, + 0x62,0x35,0x38,0x64,0x35,0x34,0x39,0x31,0x55,0x2c,0x30,0x78,0x30,0x35,0x35,0x64,0x63,0x34,0x37,0x31,0x55,0x2c,0x30,0x78,0x36,0x66,0x64,0x34,0x30,0x36,0x30,0x34, + 0x55,0x2c,0x30,0x78,0x66,0x66,0x31,0x35,0x35,0x30,0x36,0x30,0x55,0x2c,0x0a,0x30,0x78,0x32,0x34,0x66,0x62,0x39,0x38,0x31,0x39,0x55,0x2c,0x30,0x78,0x39,0x37,0x65, + 0x39,0x62,0x64,0x64,0x36,0x55,0x2c,0x30,0x78,0x63,0x63,0x34,0x33,0x34,0x30,0x38,0x39,0x55,0x2c,0x30,0x78,0x37,0x37,0x39,0x65,0x64,0x39,0x36,0x37,0x55,0x2c,0x0a, + 0x30,0x78,0x62,0x64,0x34,0x32,0x65,0x38,0x62,0x30,0x55,0x2c,0x30,0x78,0x38,0x38,0x38,0x62,0x38,0x39,0x30,0x37,0x55,0x2c,0x30,0x78,0x33,0x38,0x35,0x62,0x31,0x39, + 0x65,0x37,0x55,0x2c,0x30,0x78,0x64,0x62,0x65,0x65,0x63,0x38,0x37,0x39,0x55,0x2c,0x0a,0x30,0x78,0x34,0x37,0x30,0x61,0x37,0x63,0x61,0x31,0x55,0x2c,0x30,0x78,0x65, + 0x39,0x30,0x66,0x34,0x32,0x37,0x63,0x55,0x2c,0x30,0x78,0x63,0x39,0x31,0x65,0x38,0x34,0x66,0x38,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55, + 0x2c,0x0a,0x30,0x78,0x38,0x33,0x38,0x36,0x38,0x30,0x30,0x39,0x55,0x2c,0x30,0x78,0x34,0x38,0x65,0x64,0x32,0x62,0x33,0x32,0x55,0x2c,0x30,0x78,0x61,0x63,0x37,0x30, + 0x31,0x31,0x31,0x65,0x55,0x2c,0x30,0x78,0x34,0x65,0x37,0x32,0x35,0x61,0x36,0x63,0x55,0x2c,0x0a,0x30,0x78,0x66,0x62,0x66,0x66,0x30,0x65,0x66,0x64,0x55,0x2c,0x30, + 0x78,0x35,0x36,0x33,0x38,0x38,0x35,0x30,0x66,0x55,0x2c,0x30,0x78,0x31,0x65,0x64,0x35,0x61,0x65,0x33,0x64,0x55,0x2c,0x30,0x78,0x32,0x37,0x33,0x39,0x32,0x64,0x33, + 0x36,0x55,0x2c,0x0a,0x30,0x78,0x36,0x34,0x64,0x39,0x30,0x66,0x30,0x61,0x55,0x2c,0x30,0x78,0x32,0x31,0x61,0x36,0x35,0x63,0x36,0x38,0x55,0x2c,0x30,0x78,0x64,0x31, + 0x35,0x34,0x35,0x62,0x39,0x62,0x55,0x2c,0x30,0x78,0x33,0x61,0x32,0x65,0x33,0x36,0x32,0x34,0x55,0x2c,0x0a,0x30,0x78,0x62,0x31,0x36,0x37,0x30,0x61,0x30,0x63,0x55, + 0x2c,0x30,0x78,0x30,0x66,0x65,0x37,0x35,0x37,0x39,0x33,0x55,0x2c,0x30,0x78,0x64,0x32,0x39,0x36,0x65,0x65,0x62,0x34,0x55,0x2c,0x30,0x78,0x39,0x65,0x39,0x31,0x39, + 0x62,0x31,0x62,0x55,0x2c,0x0a,0x30,0x78,0x34,0x66,0x63,0x35,0x63,0x30,0x38,0x30,0x55,0x2c,0x30,0x78,0x61,0x32,0x32,0x30,0x64,0x63,0x36,0x31,0x55,0x2c,0x30,0x78, + 0x36,0x39,0x34,0x62,0x37,0x37,0x35,0x61,0x55,0x2c,0x30,0x78,0x31,0x36,0x31,0x61,0x31,0x32,0x31,0x63,0x55,0x2c,0x0a,0x30,0x78,0x30,0x61,0x62,0x61,0x39,0x33,0x65, + 0x32,0x55,0x2c,0x30,0x78,0x65,0x35,0x32,0x61,0x61,0x30,0x63,0x30,0x55,0x2c,0x30,0x78,0x34,0x33,0x65,0x30,0x32,0x32,0x33,0x63,0x55,0x2c,0x30,0x78,0x31,0x64,0x31, + 0x37,0x31,0x62,0x31,0x32,0x55,0x2c,0x0a,0x30,0x78,0x30,0x62,0x30,0x64,0x30,0x39,0x30,0x65,0x55,0x2c,0x30,0x78,0x61,0x64,0x63,0x37,0x38,0x62,0x66,0x32,0x55,0x2c, + 0x30,0x78,0x62,0x39,0x61,0x38,0x62,0x36,0x32,0x64,0x55,0x2c,0x30,0x78,0x63,0x38,0x61,0x39,0x31,0x65,0x31,0x34,0x55,0x2c,0x0a,0x30,0x78,0x38,0x35,0x31,0x39,0x66, + 0x31,0x35,0x37,0x55,0x2c,0x30,0x78,0x34,0x63,0x30,0x37,0x37,0x35,0x61,0x66,0x55,0x2c,0x30,0x78,0x62,0x62,0x64,0x64,0x39,0x39,0x65,0x65,0x55,0x2c,0x30,0x78,0x66, + 0x64,0x36,0x30,0x37,0x66,0x61,0x33,0x55,0x2c,0x0a,0x30,0x78,0x39,0x66,0x32,0x36,0x30,0x31,0x66,0x37,0x55,0x2c,0x30,0x78,0x62,0x63,0x66,0x35,0x37,0x32,0x35,0x63, + 0x55,0x2c,0x30,0x78,0x63,0x35,0x33,0x62,0x36,0x36,0x34,0x34,0x55,0x2c,0x30,0x78,0x33,0x34,0x37,0x65,0x66,0x62,0x35,0x62,0x55,0x2c,0x0a,0x30,0x78,0x37,0x36,0x32, + 0x39,0x34,0x33,0x38,0x62,0x55,0x2c,0x30,0x78,0x64,0x63,0x63,0x36,0x32,0x33,0x63,0x62,0x55,0x2c,0x30,0x78,0x36,0x38,0x66,0x63,0x65,0x64,0x62,0x36,0x55,0x2c,0x30, + 0x78,0x36,0x33,0x66,0x31,0x65,0x34,0x62,0x38,0x55,0x2c,0x0a,0x30,0x78,0x63,0x61,0x64,0x63,0x33,0x31,0x64,0x37,0x55,0x2c,0x30,0x78,0x31,0x30,0x38,0x35,0x36,0x33, + 0x34,0x32,0x55,0x2c,0x30,0x78,0x34,0x30,0x32,0x32,0x39,0x37,0x31,0x33,0x55,0x2c,0x30,0x78,0x32,0x30,0x31,0x31,0x63,0x36,0x38,0x34,0x55,0x2c,0x0a,0x30,0x78,0x37, + 0x64,0x32,0x34,0x34,0x61,0x38,0x35,0x55,0x2c,0x30,0x78,0x66,0x38,0x33,0x64,0x62,0x62,0x64,0x32,0x55,0x2c,0x30,0x78,0x31,0x31,0x33,0x32,0x66,0x39,0x61,0x65,0x55, + 0x2c,0x30,0x78,0x36,0x64,0x61,0x31,0x32,0x39,0x63,0x37,0x55,0x2c,0x0a,0x30,0x78,0x34,0x62,0x32,0x66,0x39,0x65,0x31,0x64,0x55,0x2c,0x30,0x78,0x66,0x33,0x33,0x30, + 0x62,0x32,0x64,0x63,0x55,0x2c,0x30,0x78,0x65,0x63,0x35,0x32,0x38,0x36,0x30,0x64,0x55,0x2c,0x30,0x78,0x64,0x30,0x65,0x33,0x63,0x31,0x37,0x37,0x55,0x2c,0x0a,0x30, + 0x78,0x36,0x63,0x31,0x36,0x62,0x33,0x32,0x62,0x55,0x2c,0x30,0x78,0x39,0x39,0x62,0x39,0x37,0x30,0x61,0x39,0x55,0x2c,0x30,0x78,0x66,0x61,0x34,0x38,0x39,0x34,0x31, + 0x31,0x55,0x2c,0x30,0x78,0x32,0x32,0x36,0x34,0x65,0x39,0x34,0x37,0x55,0x2c,0x0a,0x30,0x78,0x63,0x34,0x38,0x63,0x66,0x63,0x61,0x38,0x55,0x2c,0x30,0x78,0x31,0x61, + 0x33,0x66,0x66,0x30,0x61,0x30,0x55,0x2c,0x30,0x78,0x64,0x38,0x32,0x63,0x37,0x64,0x35,0x36,0x55,0x2c,0x30,0x78,0x65,0x66,0x39,0x30,0x33,0x33,0x32,0x32,0x55,0x2c, + 0x0a,0x30,0x78,0x63,0x37,0x34,0x65,0x34,0x39,0x38,0x37,0x55,0x2c,0x30,0x78,0x63,0x31,0x64,0x31,0x33,0x38,0x64,0x39,0x55,0x2c,0x30,0x78,0x66,0x65,0x61,0x32,0x63, + 0x61,0x38,0x63,0x55,0x2c,0x30,0x78,0x33,0x36,0x30,0x62,0x64,0x34,0x39,0x38,0x55,0x2c,0x0a,0x30,0x78,0x63,0x66,0x38,0x31,0x66,0x35,0x61,0x36,0x55,0x2c,0x30,0x78, + 0x32,0x38,0x64,0x65,0x37,0x61,0x61,0x35,0x55,0x2c,0x30,0x78,0x32,0x36,0x38,0x65,0x62,0x37,0x64,0x61,0x55,0x2c,0x30,0x78,0x61,0x34,0x62,0x66,0x61,0x64,0x33,0x66, + 0x55,0x2c,0x0a,0x30,0x78,0x65,0x34,0x39,0x64,0x33,0x61,0x32,0x63,0x55,0x2c,0x30,0x78,0x30,0x64,0x39,0x32,0x37,0x38,0x35,0x30,0x55,0x2c,0x30,0x78,0x39,0x62,0x63, + 0x63,0x35,0x66,0x36,0x61,0x55,0x2c,0x30,0x78,0x36,0x32,0x34,0x36,0x37,0x65,0x35,0x34,0x55,0x2c,0x0a,0x30,0x78,0x63,0x32,0x31,0x33,0x38,0x64,0x66,0x36,0x55,0x2c, + 0x30,0x78,0x65,0x38,0x62,0x38,0x64,0x38,0x39,0x30,0x55,0x2c,0x30,0x78,0x35,0x65,0x66,0x37,0x33,0x39,0x32,0x65,0x55,0x2c,0x30,0x78,0x66,0x35,0x61,0x66,0x63,0x33, + 0x38,0x32,0x55,0x2c,0x0a,0x30,0x78,0x62,0x65,0x38,0x30,0x35,0x64,0x39,0x66,0x55,0x2c,0x30,0x78,0x37,0x63,0x39,0x33,0x64,0x30,0x36,0x39,0x55,0x2c,0x30,0x78,0x61, + 0x39,0x32,0x64,0x64,0x35,0x36,0x66,0x55,0x2c,0x30,0x78,0x62,0x33,0x31,0x32,0x32,0x35,0x63,0x66,0x55,0x2c,0x0a,0x30,0x78,0x33,0x62,0x39,0x39,0x61,0x63,0x63,0x38, + 0x55,0x2c,0x30,0x78,0x61,0x37,0x37,0x64,0x31,0x38,0x31,0x30,0x55,0x2c,0x30,0x78,0x36,0x65,0x36,0x33,0x39,0x63,0x65,0x38,0x55,0x2c,0x30,0x78,0x37,0x62,0x62,0x62, + 0x33,0x62,0x64,0x62,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x37,0x38,0x32,0x36,0x63,0x64,0x55,0x2c,0x30,0x78,0x66,0x34,0x31,0x38,0x35,0x39,0x36,0x65,0x55,0x2c,0x30, + 0x78,0x30,0x31,0x62,0x37,0x39,0x61,0x65,0x63,0x55,0x2c,0x30,0x78,0x61,0x38,0x39,0x61,0x34,0x66,0x38,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x35,0x36,0x65,0x39,0x35, + 0x65,0x36,0x55,0x2c,0x30,0x78,0x37,0x65,0x65,0x36,0x66,0x66,0x61,0x61,0x55,0x2c,0x30,0x78,0x30,0x38,0x63,0x66,0x62,0x63,0x32,0x31,0x55,0x2c,0x30,0x78,0x65,0x36, + 0x65,0x38,0x31,0x35,0x65,0x66,0x55,0x2c,0x0a,0x30,0x78,0x64,0x39,0x39,0x62,0x65,0x37,0x62,0x61,0x55,0x2c,0x30,0x78,0x63,0x65,0x33,0x36,0x36,0x66,0x34,0x61,0x55, + 0x2c,0x30,0x78,0x64,0x34,0x30,0x39,0x39,0x66,0x65,0x61,0x55,0x2c,0x30,0x78,0x64,0x36,0x37,0x63,0x62,0x30,0x32,0x39,0x55,0x2c,0x0a,0x30,0x78,0x61,0x66,0x62,0x32, + 0x61,0x34,0x33,0x31,0x55,0x2c,0x30,0x78,0x33,0x31,0x32,0x33,0x33,0x66,0x32,0x61,0x55,0x2c,0x30,0x78,0x33,0x30,0x39,0x34,0x61,0x35,0x63,0x36,0x55,0x2c,0x30,0x78, + 0x63,0x30,0x36,0x36,0x61,0x32,0x33,0x35,0x55,0x2c,0x0a,0x30,0x78,0x33,0x37,0x62,0x63,0x34,0x65,0x37,0x34,0x55,0x2c,0x30,0x78,0x61,0x36,0x63,0x61,0x38,0x32,0x66, + 0x63,0x55,0x2c,0x30,0x78,0x62,0x30,0x64,0x30,0x39,0x30,0x65,0x30,0x55,0x2c,0x30,0x78,0x31,0x35,0x64,0x38,0x61,0x37,0x33,0x33,0x55,0x2c,0x0a,0x30,0x78,0x34,0x61, + 0x39,0x38,0x30,0x34,0x66,0x31,0x55,0x2c,0x30,0x78,0x66,0x37,0x64,0x61,0x65,0x63,0x34,0x31,0x55,0x2c,0x30,0x78,0x30,0x65,0x35,0x30,0x63,0x64,0x37,0x66,0x55,0x2c, + 0x30,0x78,0x32,0x66,0x66,0x36,0x39,0x31,0x31,0x37,0x55,0x2c,0x0a,0x30,0x78,0x38,0x64,0x64,0x36,0x34,0x64,0x37,0x36,0x55,0x2c,0x30,0x78,0x34,0x64,0x62,0x30,0x65, + 0x66,0x34,0x33,0x55,0x2c,0x30,0x78,0x35,0x34,0x34,0x64,0x61,0x61,0x63,0x63,0x55,0x2c,0x30,0x78,0x64,0x66,0x30,0x34,0x39,0x36,0x65,0x34,0x55,0x2c,0x0a,0x30,0x78, + 0x65,0x33,0x62,0x35,0x64,0x31,0x39,0x65,0x55,0x2c,0x30,0x78,0x31,0x62,0x38,0x38,0x36,0x61,0x34,0x63,0x55,0x2c,0x30,0x78,0x62,0x38,0x31,0x66,0x32,0x63,0x63,0x31, + 0x55,0x2c,0x30,0x78,0x37,0x66,0x35,0x31,0x36,0x35,0x34,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x34,0x65,0x61,0x35,0x65,0x39,0x64,0x55,0x2c,0x30,0x78,0x35,0x64,0x33, + 0x35,0x38,0x63,0x30,0x31,0x55,0x2c,0x30,0x78,0x37,0x33,0x37,0x34,0x38,0x37,0x66,0x61,0x55,0x2c,0x30,0x78,0x32,0x65,0x34,0x31,0x30,0x62,0x66,0x62,0x55,0x2c,0x0a, + 0x30,0x78,0x35,0x61,0x31,0x64,0x36,0x37,0x62,0x33,0x55,0x2c,0x30,0x78,0x35,0x32,0x64,0x32,0x64,0x62,0x39,0x32,0x55,0x2c,0x30,0x78,0x33,0x33,0x35,0x36,0x31,0x30, + 0x65,0x39,0x55,0x2c,0x30,0x78,0x31,0x33,0x34,0x37,0x64,0x36,0x36,0x64,0x55,0x2c,0x0a,0x30,0x78,0x38,0x63,0x36,0x31,0x64,0x37,0x39,0x61,0x55,0x2c,0x30,0x78,0x37, + 0x61,0x30,0x63,0x61,0x31,0x33,0x37,0x55,0x2c,0x30,0x78,0x38,0x65,0x31,0x34,0x66,0x38,0x35,0x39,0x55,0x2c,0x30,0x78,0x38,0x39,0x33,0x63,0x31,0x33,0x65,0x62,0x55, + 0x2c,0x0a,0x30,0x78,0x65,0x65,0x32,0x37,0x61,0x39,0x63,0x65,0x55,0x2c,0x30,0x78,0x33,0x35,0x63,0x39,0x36,0x31,0x62,0x37,0x55,0x2c,0x30,0x78,0x65,0x64,0x65,0x35, + 0x31,0x63,0x65,0x31,0x55,0x2c,0x30,0x78,0x33,0x63,0x62,0x31,0x34,0x37,0x37,0x61,0x55,0x2c,0x0a,0x30,0x78,0x35,0x39,0x64,0x66,0x64,0x32,0x39,0x63,0x55,0x2c,0x30, + 0x78,0x33,0x66,0x37,0x33,0x66,0x32,0x35,0x35,0x55,0x2c,0x30,0x78,0x37,0x39,0x63,0x65,0x31,0x34,0x31,0x38,0x55,0x2c,0x30,0x78,0x62,0x66,0x33,0x37,0x63,0x37,0x37, + 0x33,0x55,0x2c,0x0a,0x30,0x78,0x65,0x61,0x63,0x64,0x66,0x37,0x35,0x33,0x55,0x2c,0x30,0x78,0x35,0x62,0x61,0x61,0x66,0x64,0x35,0x66,0x55,0x2c,0x30,0x78,0x31,0x34, + 0x36,0x66,0x33,0x64,0x64,0x66,0x55,0x2c,0x30,0x78,0x38,0x36,0x64,0x62,0x34,0x34,0x37,0x38,0x55,0x2c,0x0a,0x30,0x78,0x38,0x31,0x66,0x33,0x61,0x66,0x63,0x61,0x55, + 0x2c,0x30,0x78,0x33,0x65,0x63,0x34,0x36,0x38,0x62,0x39,0x55,0x2c,0x30,0x78,0x32,0x63,0x33,0x34,0x32,0x34,0x33,0x38,0x55,0x2c,0x30,0x78,0x35,0x66,0x34,0x30,0x61, + 0x33,0x63,0x32,0x55,0x2c,0x0a,0x30,0x78,0x37,0x32,0x63,0x33,0x31,0x64,0x31,0x36,0x55,0x2c,0x30,0x78,0x30,0x63,0x32,0x35,0x65,0x32,0x62,0x63,0x55,0x2c,0x30,0x78, + 0x38,0x62,0x34,0x39,0x33,0x63,0x32,0x38,0x55,0x2c,0x30,0x78,0x34,0x31,0x39,0x35,0x30,0x64,0x66,0x66,0x55,0x2c,0x0a,0x30,0x78,0x37,0x31,0x30,0x31,0x61,0x38,0x33, + 0x39,0x55,0x2c,0x30,0x78,0x64,0x65,0x62,0x33,0x30,0x63,0x30,0x38,0x55,0x2c,0x30,0x78,0x39,0x63,0x65,0x34,0x62,0x34,0x64,0x38,0x55,0x2c,0x30,0x78,0x39,0x30,0x63, + 0x31,0x35,0x36,0x36,0x34,0x55,0x2c,0x0a,0x30,0x78,0x36,0x31,0x38,0x34,0x63,0x62,0x37,0x62,0x55,0x2c,0x30,0x78,0x37,0x30,0x62,0x36,0x33,0x32,0x64,0x35,0x55,0x2c, + 0x30,0x78,0x37,0x34,0x35,0x63,0x36,0x63,0x34,0x38,0x55,0x2c,0x30,0x78,0x34,0x32,0x35,0x37,0x62,0x38,0x64,0x30,0x55,0x2c,0x0a,0x30,0x78,0x61,0x37,0x66,0x34,0x35, + 0x31,0x35,0x30,0x55,0x2c,0x30,0x78,0x36,0x35,0x34,0x31,0x37,0x65,0x35,0x33,0x55,0x2c,0x30,0x78,0x61,0x34,0x31,0x37,0x31,0x61,0x63,0x33,0x55,0x2c,0x30,0x78,0x35, + 0x65,0x32,0x37,0x33,0x61,0x39,0x36,0x55,0x2c,0x0a,0x30,0x78,0x36,0x62,0x61,0x62,0x33,0x62,0x63,0x62,0x55,0x2c,0x30,0x78,0x34,0x35,0x39,0x64,0x31,0x66,0x66,0x31, + 0x55,0x2c,0x30,0x78,0x35,0x38,0x66,0x61,0x61,0x63,0x61,0x62,0x55,0x2c,0x30,0x78,0x30,0x33,0x65,0x33,0x34,0x62,0x39,0x33,0x55,0x2c,0x0a,0x30,0x78,0x66,0x61,0x33, + 0x30,0x32,0x30,0x35,0x35,0x55,0x2c,0x30,0x78,0x36,0x64,0x37,0x36,0x61,0x64,0x66,0x36,0x55,0x2c,0x30,0x78,0x37,0x36,0x63,0x63,0x38,0x38,0x39,0x31,0x55,0x2c,0x30, + 0x78,0x34,0x63,0x30,0x32,0x66,0x35,0x32,0x35,0x55,0x2c,0x0a,0x30,0x78,0x64,0x37,0x65,0x35,0x34,0x66,0x66,0x63,0x55,0x2c,0x30,0x78,0x63,0x62,0x32,0x61,0x63,0x35, + 0x64,0x37,0x55,0x2c,0x30,0x78,0x34,0x34,0x33,0x35,0x32,0x36,0x38,0x30,0x55,0x2c,0x30,0x78,0x61,0x33,0x36,0x32,0x62,0x35,0x38,0x66,0x55,0x2c,0x0a,0x30,0x78,0x35, + 0x61,0x62,0x31,0x64,0x65,0x34,0x39,0x55,0x2c,0x30,0x78,0x31,0x62,0x62,0x61,0x32,0x35,0x36,0x37,0x55,0x2c,0x30,0x78,0x30,0x65,0x65,0x61,0x34,0x35,0x39,0x38,0x55, + 0x2c,0x30,0x78,0x63,0x30,0x66,0x65,0x35,0x64,0x65,0x31,0x55,0x2c,0x0a,0x30,0x78,0x37,0x35,0x32,0x66,0x63,0x33,0x30,0x32,0x55,0x2c,0x30,0x78,0x66,0x30,0x34,0x63, + 0x38,0x31,0x31,0x32,0x55,0x2c,0x30,0x78,0x39,0x37,0x34,0x36,0x38,0x64,0x61,0x33,0x55,0x2c,0x30,0x78,0x66,0x39,0x64,0x33,0x36,0x62,0x63,0x36,0x55,0x2c,0x0a,0x30, + 0x78,0x35,0x66,0x38,0x66,0x30,0x33,0x65,0x37,0x55,0x2c,0x30,0x78,0x39,0x63,0x39,0x32,0x31,0x35,0x39,0x35,0x55,0x2c,0x30,0x78,0x37,0x61,0x36,0x64,0x62,0x66,0x65, + 0x62,0x55,0x2c,0x30,0x78,0x35,0x39,0x35,0x32,0x39,0x35,0x64,0x61,0x55,0x2c,0x0a,0x30,0x78,0x38,0x33,0x62,0x65,0x64,0x34,0x32,0x64,0x55,0x2c,0x30,0x78,0x32,0x31, + 0x37,0x34,0x35,0x38,0x64,0x33,0x55,0x2c,0x30,0x78,0x36,0x39,0x65,0x30,0x34,0x39,0x32,0x39,0x55,0x2c,0x30,0x78,0x63,0x38,0x63,0x39,0x38,0x65,0x34,0x34,0x55,0x2c, + 0x0a,0x30,0x78,0x38,0x39,0x63,0x32,0x37,0x35,0x36,0x61,0x55,0x2c,0x30,0x78,0x37,0x39,0x38,0x65,0x66,0x34,0x37,0x38,0x55,0x2c,0x30,0x78,0x33,0x65,0x35,0x38,0x39, + 0x39,0x36,0x62,0x55,0x2c,0x30,0x78,0x37,0x31,0x62,0x39,0x32,0x37,0x64,0x64,0x55,0x2c,0x0a,0x30,0x78,0x34,0x66,0x65,0x31,0x62,0x65,0x62,0x36,0x55,0x2c,0x30,0x78, + 0x61,0x64,0x38,0x38,0x66,0x30,0x31,0x37,0x55,0x2c,0x30,0x78,0x61,0x63,0x32,0x30,0x63,0x39,0x36,0x36,0x55,0x2c,0x30,0x78,0x33,0x61,0x63,0x65,0x37,0x64,0x62,0x34, + 0x55,0x2c,0x0a,0x30,0x78,0x34,0x61,0x64,0x66,0x36,0x33,0x31,0x38,0x55,0x2c,0x30,0x78,0x33,0x31,0x31,0x61,0x65,0x35,0x38,0x32,0x55,0x2c,0x30,0x78,0x33,0x33,0x35, + 0x31,0x39,0x37,0x36,0x30,0x55,0x2c,0x30,0x78,0x37,0x66,0x35,0x33,0x36,0x32,0x34,0x35,0x55,0x2c,0x0a,0x30,0x78,0x37,0x37,0x36,0x34,0x62,0x31,0x65,0x30,0x55,0x2c, + 0x30,0x78,0x61,0x65,0x36,0x62,0x62,0x62,0x38,0x34,0x55,0x2c,0x30,0x78,0x61,0x30,0x38,0x31,0x66,0x65,0x31,0x63,0x55,0x2c,0x30,0x78,0x32,0x62,0x30,0x38,0x66,0x39, + 0x39,0x34,0x55,0x2c,0x0a,0x30,0x78,0x36,0x38,0x34,0x38,0x37,0x30,0x35,0x38,0x55,0x2c,0x30,0x78,0x66,0x64,0x34,0x35,0x38,0x66,0x31,0x39,0x55,0x2c,0x30,0x78,0x36, + 0x63,0x64,0x65,0x39,0x34,0x38,0x37,0x55,0x2c,0x30,0x78,0x66,0x38,0x37,0x62,0x35,0x32,0x62,0x37,0x55,0x2c,0x0a,0x30,0x78,0x64,0x33,0x37,0x33,0x61,0x62,0x32,0x33, + 0x55,0x2c,0x30,0x78,0x30,0x32,0x34,0x62,0x37,0x32,0x65,0x32,0x55,0x2c,0x30,0x78,0x38,0x66,0x31,0x66,0x65,0x33,0x35,0x37,0x55,0x2c,0x30,0x78,0x61,0x62,0x35,0x35, + 0x36,0x36,0x32,0x61,0x55,0x2c,0x0a,0x30,0x78,0x32,0x38,0x65,0x62,0x62,0x32,0x30,0x37,0x55,0x2c,0x30,0x78,0x63,0x32,0x62,0x35,0x32,0x66,0x30,0x33,0x55,0x2c,0x30, + 0x78,0x37,0x62,0x63,0x35,0x38,0x36,0x39,0x61,0x55,0x2c,0x30,0x78,0x30,0x38,0x33,0x37,0x64,0x33,0x61,0x35,0x55,0x2c,0x0a,0x30,0x78,0x38,0x37,0x32,0x38,0x33,0x30, + 0x66,0x32,0x55,0x2c,0x30,0x78,0x61,0x35,0x62,0x66,0x32,0x33,0x62,0x32,0x55,0x2c,0x30,0x78,0x36,0x61,0x30,0x33,0x30,0x32,0x62,0x61,0x55,0x2c,0x30,0x78,0x38,0x32, + 0x31,0x36,0x65,0x64,0x35,0x63,0x55,0x2c,0x0a,0x30,0x78,0x31,0x63,0x63,0x66,0x38,0x61,0x32,0x62,0x55,0x2c,0x30,0x78,0x62,0x34,0x37,0x39,0x61,0x37,0x39,0x32,0x55, + 0x2c,0x30,0x78,0x66,0x32,0x30,0x37,0x66,0x33,0x66,0x30,0x55,0x2c,0x30,0x78,0x65,0x32,0x36,0x39,0x34,0x65,0x61,0x31,0x55,0x2c,0x0a,0x30,0x78,0x66,0x34,0x64,0x61, + 0x36,0x35,0x63,0x64,0x55,0x2c,0x30,0x78,0x62,0x65,0x30,0x35,0x30,0x36,0x64,0x35,0x55,0x2c,0x30,0x78,0x36,0x32,0x33,0x34,0x64,0x31,0x31,0x66,0x55,0x2c,0x30,0x78, + 0x66,0x65,0x61,0x36,0x63,0x34,0x38,0x61,0x55,0x2c,0x0a,0x30,0x78,0x35,0x33,0x32,0x65,0x33,0x34,0x39,0x64,0x55,0x2c,0x30,0x78,0x35,0x35,0x66,0x33,0x61,0x32,0x61, + 0x30,0x55,0x2c,0x30,0x78,0x65,0x31,0x38,0x61,0x30,0x35,0x33,0x32,0x55,0x2c,0x30,0x78,0x65,0x62,0x66,0x36,0x61,0x34,0x37,0x35,0x55,0x2c,0x0a,0x30,0x78,0x65,0x63, + 0x38,0x33,0x30,0x62,0x33,0x39,0x55,0x2c,0x30,0x78,0x65,0x66,0x36,0x30,0x34,0x30,0x61,0x61,0x55,0x2c,0x30,0x78,0x39,0x66,0x37,0x31,0x35,0x65,0x30,0x36,0x55,0x2c, + 0x30,0x78,0x31,0x30,0x36,0x65,0x62,0x64,0x35,0x31,0x55,0x2c,0x0a,0x30,0x78,0x38,0x61,0x32,0x31,0x33,0x65,0x66,0x39,0x55,0x2c,0x30,0x78,0x30,0x36,0x64,0x64,0x39, + 0x36,0x33,0x64,0x55,0x2c,0x30,0x78,0x30,0x35,0x33,0x65,0x64,0x64,0x61,0x65,0x55,0x2c,0x30,0x78,0x62,0x64,0x65,0x36,0x34,0x64,0x34,0x36,0x55,0x2c,0x0a,0x30,0x78, + 0x38,0x64,0x35,0x34,0x39,0x31,0x62,0x35,0x55,0x2c,0x30,0x78,0x35,0x64,0x63,0x34,0x37,0x31,0x30,0x35,0x55,0x2c,0x30,0x78,0x64,0x34,0x30,0x36,0x30,0x34,0x36,0x66, + 0x55,0x2c,0x30,0x78,0x31,0x35,0x35,0x30,0x36,0x30,0x66,0x66,0x55,0x2c,0x0a,0x30,0x78,0x66,0x62,0x39,0x38,0x31,0x39,0x32,0x34,0x55,0x2c,0x30,0x78,0x65,0x39,0x62, + 0x64,0x64,0x36,0x39,0x37,0x55,0x2c,0x30,0x78,0x34,0x33,0x34,0x30,0x38,0x39,0x63,0x63,0x55,0x2c,0x30,0x78,0x39,0x65,0x64,0x39,0x36,0x37,0x37,0x37,0x55,0x2c,0x0a, + 0x30,0x78,0x34,0x32,0x65,0x38,0x62,0x30,0x62,0x64,0x55,0x2c,0x30,0x78,0x38,0x62,0x38,0x39,0x30,0x37,0x38,0x38,0x55,0x2c,0x30,0x78,0x35,0x62,0x31,0x39,0x65,0x37, + 0x33,0x38,0x55,0x2c,0x30,0x78,0x65,0x65,0x63,0x38,0x37,0x39,0x64,0x62,0x55,0x2c,0x0a,0x30,0x78,0x30,0x61,0x37,0x63,0x61,0x31,0x34,0x37,0x55,0x2c,0x30,0x78,0x30, + 0x66,0x34,0x32,0x37,0x63,0x65,0x39,0x55,0x2c,0x30,0x78,0x31,0x65,0x38,0x34,0x66,0x38,0x63,0x39,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55, + 0x2c,0x0a,0x30,0x78,0x38,0x36,0x38,0x30,0x30,0x39,0x38,0x33,0x55,0x2c,0x30,0x78,0x65,0x64,0x32,0x62,0x33,0x32,0x34,0x38,0x55,0x2c,0x30,0x78,0x37,0x30,0x31,0x31, + 0x31,0x65,0x61,0x63,0x55,0x2c,0x30,0x78,0x37,0x32,0x35,0x61,0x36,0x63,0x34,0x65,0x55,0x2c,0x0a,0x30,0x78,0x66,0x66,0x30,0x65,0x66,0x64,0x66,0x62,0x55,0x2c,0x30, + 0x78,0x33,0x38,0x38,0x35,0x30,0x66,0x35,0x36,0x55,0x2c,0x30,0x78,0x64,0x35,0x61,0x65,0x33,0x64,0x31,0x65,0x55,0x2c,0x30,0x78,0x33,0x39,0x32,0x64,0x33,0x36,0x32, + 0x37,0x55,0x2c,0x0a,0x30,0x78,0x64,0x39,0x30,0x66,0x30,0x61,0x36,0x34,0x55,0x2c,0x30,0x78,0x61,0x36,0x35,0x63,0x36,0x38,0x32,0x31,0x55,0x2c,0x30,0x78,0x35,0x34, + 0x35,0x62,0x39,0x62,0x64,0x31,0x55,0x2c,0x30,0x78,0x32,0x65,0x33,0x36,0x32,0x34,0x33,0x61,0x55,0x2c,0x0a,0x30,0x78,0x36,0x37,0x30,0x61,0x30,0x63,0x62,0x31,0x55, + 0x2c,0x30,0x78,0x65,0x37,0x35,0x37,0x39,0x33,0x30,0x66,0x55,0x2c,0x30,0x78,0x39,0x36,0x65,0x65,0x62,0x34,0x64,0x32,0x55,0x2c,0x30,0x78,0x39,0x31,0x39,0x62,0x31, + 0x62,0x39,0x65,0x55,0x2c,0x0a,0x30,0x78,0x63,0x35,0x63,0x30,0x38,0x30,0x34,0x66,0x55,0x2c,0x30,0x78,0x32,0x30,0x64,0x63,0x36,0x31,0x61,0x32,0x55,0x2c,0x30,0x78, + 0x34,0x62,0x37,0x37,0x35,0x61,0x36,0x39,0x55,0x2c,0x30,0x78,0x31,0x61,0x31,0x32,0x31,0x63,0x31,0x36,0x55,0x2c,0x0a,0x30,0x78,0x62,0x61,0x39,0x33,0x65,0x32,0x30, + 0x61,0x55,0x2c,0x30,0x78,0x32,0x61,0x61,0x30,0x63,0x30,0x65,0x35,0x55,0x2c,0x30,0x78,0x65,0x30,0x32,0x32,0x33,0x63,0x34,0x33,0x55,0x2c,0x30,0x78,0x31,0x37,0x31, + 0x62,0x31,0x32,0x31,0x64,0x55,0x2c,0x0a,0x30,0x78,0x30,0x64,0x30,0x39,0x30,0x65,0x30,0x62,0x55,0x2c,0x30,0x78,0x63,0x37,0x38,0x62,0x66,0x32,0x61,0x64,0x55,0x2c, + 0x30,0x78,0x61,0x38,0x62,0x36,0x32,0x64,0x62,0x39,0x55,0x2c,0x30,0x78,0x61,0x39,0x31,0x65,0x31,0x34,0x63,0x38,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x66,0x31,0x35, + 0x37,0x38,0x35,0x55,0x2c,0x30,0x78,0x30,0x37,0x37,0x35,0x61,0x66,0x34,0x63,0x55,0x2c,0x30,0x78,0x64,0x64,0x39,0x39,0x65,0x65,0x62,0x62,0x55,0x2c,0x30,0x78,0x36, + 0x30,0x37,0x66,0x61,0x33,0x66,0x64,0x55,0x2c,0x0a,0x30,0x78,0x32,0x36,0x30,0x31,0x66,0x37,0x39,0x66,0x55,0x2c,0x30,0x78,0x66,0x35,0x37,0x32,0x35,0x63,0x62,0x63, + 0x55,0x2c,0x30,0x78,0x33,0x62,0x36,0x36,0x34,0x34,0x63,0x35,0x55,0x2c,0x30,0x78,0x37,0x65,0x66,0x62,0x35,0x62,0x33,0x34,0x55,0x2c,0x0a,0x30,0x78,0x32,0x39,0x34, + 0x33,0x38,0x62,0x37,0x36,0x55,0x2c,0x30,0x78,0x63,0x36,0x32,0x33,0x63,0x62,0x64,0x63,0x55,0x2c,0x30,0x78,0x66,0x63,0x65,0x64,0x62,0x36,0x36,0x38,0x55,0x2c,0x30, + 0x78,0x66,0x31,0x65,0x34,0x62,0x38,0x36,0x33,0x55,0x2c,0x0a,0x30,0x78,0x64,0x63,0x33,0x31,0x64,0x37,0x63,0x61,0x55,0x2c,0x30,0x78,0x38,0x35,0x36,0x33,0x34,0x32, + 0x31,0x30,0x55,0x2c,0x30,0x78,0x32,0x32,0x39,0x37,0x31,0x33,0x34,0x30,0x55,0x2c,0x30,0x78,0x31,0x31,0x63,0x36,0x38,0x34,0x32,0x30,0x55,0x2c,0x0a,0x30,0x78,0x32, + 0x34,0x34,0x61,0x38,0x35,0x37,0x64,0x55,0x2c,0x30,0x78,0x33,0x64,0x62,0x62,0x64,0x32,0x66,0x38,0x55,0x2c,0x30,0x78,0x33,0x32,0x66,0x39,0x61,0x65,0x31,0x31,0x55, + 0x2c,0x30,0x78,0x61,0x31,0x32,0x39,0x63,0x37,0x36,0x64,0x55,0x2c,0x0a,0x30,0x78,0x32,0x66,0x39,0x65,0x31,0x64,0x34,0x62,0x55,0x2c,0x30,0x78,0x33,0x30,0x62,0x32, + 0x64,0x63,0x66,0x33,0x55,0x2c,0x30,0x78,0x35,0x32,0x38,0x36,0x30,0x64,0x65,0x63,0x55,0x2c,0x30,0x78,0x65,0x33,0x63,0x31,0x37,0x37,0x64,0x30,0x55,0x2c,0x0a,0x30, + 0x78,0x31,0x36,0x62,0x33,0x32,0x62,0x36,0x63,0x55,0x2c,0x30,0x78,0x62,0x39,0x37,0x30,0x61,0x39,0x39,0x39,0x55,0x2c,0x30,0x78,0x34,0x38,0x39,0x34,0x31,0x31,0x66, + 0x61,0x55,0x2c,0x30,0x78,0x36,0x34,0x65,0x39,0x34,0x37,0x32,0x32,0x55,0x2c,0x0a,0x30,0x78,0x38,0x63,0x66,0x63,0x61,0x38,0x63,0x34,0x55,0x2c,0x30,0x78,0x33,0x66, + 0x66,0x30,0x61,0x30,0x31,0x61,0x55,0x2c,0x30,0x78,0x32,0x63,0x37,0x64,0x35,0x36,0x64,0x38,0x55,0x2c,0x30,0x78,0x39,0x30,0x33,0x33,0x32,0x32,0x65,0x66,0x55,0x2c, + 0x0a,0x30,0x78,0x34,0x65,0x34,0x39,0x38,0x37,0x63,0x37,0x55,0x2c,0x30,0x78,0x64,0x31,0x33,0x38,0x64,0x39,0x63,0x31,0x55,0x2c,0x30,0x78,0x61,0x32,0x63,0x61,0x38, + 0x63,0x66,0x65,0x55,0x2c,0x30,0x78,0x30,0x62,0x64,0x34,0x39,0x38,0x33,0x36,0x55,0x2c,0x0a,0x30,0x78,0x38,0x31,0x66,0x35,0x61,0x36,0x63,0x66,0x55,0x2c,0x30,0x78, + 0x64,0x65,0x37,0x61,0x61,0x35,0x32,0x38,0x55,0x2c,0x30,0x78,0x38,0x65,0x62,0x37,0x64,0x61,0x32,0x36,0x55,0x2c,0x30,0x78,0x62,0x66,0x61,0x64,0x33,0x66,0x61,0x34, + 0x55,0x2c,0x0a,0x30,0x78,0x39,0x64,0x33,0x61,0x32,0x63,0x65,0x34,0x55,0x2c,0x30,0x78,0x39,0x32,0x37,0x38,0x35,0x30,0x30,0x64,0x55,0x2c,0x30,0x78,0x63,0x63,0x35, + 0x66,0x36,0x61,0x39,0x62,0x55,0x2c,0x30,0x78,0x34,0x36,0x37,0x65,0x35,0x34,0x36,0x32,0x55,0x2c,0x0a,0x30,0x78,0x31,0x33,0x38,0x64,0x66,0x36,0x63,0x32,0x55,0x2c, + 0x30,0x78,0x62,0x38,0x64,0x38,0x39,0x30,0x65,0x38,0x55,0x2c,0x30,0x78,0x66,0x37,0x33,0x39,0x32,0x65,0x35,0x65,0x55,0x2c,0x30,0x78,0x61,0x66,0x63,0x33,0x38,0x32, + 0x66,0x35,0x55,0x2c,0x0a,0x30,0x78,0x38,0x30,0x35,0x64,0x39,0x66,0x62,0x65,0x55,0x2c,0x30,0x78,0x39,0x33,0x64,0x30,0x36,0x39,0x37,0x63,0x55,0x2c,0x30,0x78,0x32, + 0x64,0x64,0x35,0x36,0x66,0x61,0x39,0x55,0x2c,0x30,0x78,0x31,0x32,0x32,0x35,0x63,0x66,0x62,0x33,0x55,0x2c,0x0a,0x30,0x78,0x39,0x39,0x61,0x63,0x63,0x38,0x33,0x62, + 0x55,0x2c,0x30,0x78,0x37,0x64,0x31,0x38,0x31,0x30,0x61,0x37,0x55,0x2c,0x30,0x78,0x36,0x33,0x39,0x63,0x65,0x38,0x36,0x65,0x55,0x2c,0x30,0x78,0x62,0x62,0x33,0x62, + 0x64,0x62,0x37,0x62,0x55,0x2c,0x0a,0x30,0x78,0x37,0x38,0x32,0x36,0x63,0x64,0x30,0x39,0x55,0x2c,0x30,0x78,0x31,0x38,0x35,0x39,0x36,0x65,0x66,0x34,0x55,0x2c,0x30, + 0x78,0x62,0x37,0x39,0x61,0x65,0x63,0x30,0x31,0x55,0x2c,0x30,0x78,0x39,0x61,0x34,0x66,0x38,0x33,0x61,0x38,0x55,0x2c,0x0a,0x30,0x78,0x36,0x65,0x39,0x35,0x65,0x36, + 0x36,0x35,0x55,0x2c,0x30,0x78,0x65,0x36,0x66,0x66,0x61,0x61,0x37,0x65,0x55,0x2c,0x30,0x78,0x63,0x66,0x62,0x63,0x32,0x31,0x30,0x38,0x55,0x2c,0x30,0x78,0x65,0x38, + 0x31,0x35,0x65,0x66,0x65,0x36,0x55,0x2c,0x0a,0x30,0x78,0x39,0x62,0x65,0x37,0x62,0x61,0x64,0x39,0x55,0x2c,0x30,0x78,0x33,0x36,0x36,0x66,0x34,0x61,0x63,0x65,0x55, + 0x2c,0x30,0x78,0x30,0x39,0x39,0x66,0x65,0x61,0x64,0x34,0x55,0x2c,0x30,0x78,0x37,0x63,0x62,0x30,0x32,0x39,0x64,0x36,0x55,0x2c,0x0a,0x30,0x78,0x62,0x32,0x61,0x34, + 0x33,0x31,0x61,0x66,0x55,0x2c,0x30,0x78,0x32,0x33,0x33,0x66,0x32,0x61,0x33,0x31,0x55,0x2c,0x30,0x78,0x39,0x34,0x61,0x35,0x63,0x36,0x33,0x30,0x55,0x2c,0x30,0x78, + 0x36,0x36,0x61,0x32,0x33,0x35,0x63,0x30,0x55,0x2c,0x0a,0x30,0x78,0x62,0x63,0x34,0x65,0x37,0x34,0x33,0x37,0x55,0x2c,0x30,0x78,0x63,0x61,0x38,0x32,0x66,0x63,0x61, + 0x36,0x55,0x2c,0x30,0x78,0x64,0x30,0x39,0x30,0x65,0x30,0x62,0x30,0x55,0x2c,0x30,0x78,0x64,0x38,0x61,0x37,0x33,0x33,0x31,0x35,0x55,0x2c,0x0a,0x30,0x78,0x39,0x38, + 0x30,0x34,0x66,0x31,0x34,0x61,0x55,0x2c,0x30,0x78,0x64,0x61,0x65,0x63,0x34,0x31,0x66,0x37,0x55,0x2c,0x30,0x78,0x35,0x30,0x63,0x64,0x37,0x66,0x30,0x65,0x55,0x2c, + 0x30,0x78,0x66,0x36,0x39,0x31,0x31,0x37,0x32,0x66,0x55,0x2c,0x0a,0x30,0x78,0x64,0x36,0x34,0x64,0x37,0x36,0x38,0x64,0x55,0x2c,0x30,0x78,0x62,0x30,0x65,0x66,0x34, + 0x33,0x34,0x64,0x55,0x2c,0x30,0x78,0x34,0x64,0x61,0x61,0x63,0x63,0x35,0x34,0x55,0x2c,0x30,0x78,0x30,0x34,0x39,0x36,0x65,0x34,0x64,0x66,0x55,0x2c,0x0a,0x30,0x78, + 0x62,0x35,0x64,0x31,0x39,0x65,0x65,0x33,0x55,0x2c,0x30,0x78,0x38,0x38,0x36,0x61,0x34,0x63,0x31,0x62,0x55,0x2c,0x30,0x78,0x31,0x66,0x32,0x63,0x63,0x31,0x62,0x38, + 0x55,0x2c,0x30,0x78,0x35,0x31,0x36,0x35,0x34,0x36,0x37,0x66,0x55,0x2c,0x0a,0x30,0x78,0x65,0x61,0x35,0x65,0x39,0x64,0x30,0x34,0x55,0x2c,0x30,0x78,0x33,0x35,0x38, + 0x63,0x30,0x31,0x35,0x64,0x55,0x2c,0x30,0x78,0x37,0x34,0x38,0x37,0x66,0x61,0x37,0x33,0x55,0x2c,0x30,0x78,0x34,0x31,0x30,0x62,0x66,0x62,0x32,0x65,0x55,0x2c,0x0a, + 0x30,0x78,0x31,0x64,0x36,0x37,0x62,0x33,0x35,0x61,0x55,0x2c,0x30,0x78,0x64,0x32,0x64,0x62,0x39,0x32,0x35,0x32,0x55,0x2c,0x30,0x78,0x35,0x36,0x31,0x30,0x65,0x39, + 0x33,0x33,0x55,0x2c,0x30,0x78,0x34,0x37,0x64,0x36,0x36,0x64,0x31,0x33,0x55,0x2c,0x0a,0x30,0x78,0x36,0x31,0x64,0x37,0x39,0x61,0x38,0x63,0x55,0x2c,0x30,0x78,0x30, + 0x63,0x61,0x31,0x33,0x37,0x37,0x61,0x55,0x2c,0x30,0x78,0x31,0x34,0x66,0x38,0x35,0x39,0x38,0x65,0x55,0x2c,0x30,0x78,0x33,0x63,0x31,0x33,0x65,0x62,0x38,0x39,0x55, + 0x2c,0x0a,0x30,0x78,0x32,0x37,0x61,0x39,0x63,0x65,0x65,0x65,0x55,0x2c,0x30,0x78,0x63,0x39,0x36,0x31,0x62,0x37,0x33,0x35,0x55,0x2c,0x30,0x78,0x65,0x35,0x31,0x63, + 0x65,0x31,0x65,0x64,0x55,0x2c,0x30,0x78,0x62,0x31,0x34,0x37,0x37,0x61,0x33,0x63,0x55,0x2c,0x0a,0x30,0x78,0x64,0x66,0x64,0x32,0x39,0x63,0x35,0x39,0x55,0x2c,0x30, + 0x78,0x37,0x33,0x66,0x32,0x35,0x35,0x33,0x66,0x55,0x2c,0x30,0x78,0x63,0x65,0x31,0x34,0x31,0x38,0x37,0x39,0x55,0x2c,0x30,0x78,0x33,0x37,0x63,0x37,0x37,0x33,0x62, + 0x66,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x66,0x37,0x35,0x33,0x65,0x61,0x55,0x2c,0x30,0x78,0x61,0x61,0x66,0x64,0x35,0x66,0x35,0x62,0x55,0x2c,0x30,0x78,0x36,0x66, + 0x33,0x64,0x64,0x66,0x31,0x34,0x55,0x2c,0x30,0x78,0x64,0x62,0x34,0x34,0x37,0x38,0x38,0x36,0x55,0x2c,0x0a,0x30,0x78,0x66,0x33,0x61,0x66,0x63,0x61,0x38,0x31,0x55, + 0x2c,0x30,0x78,0x63,0x34,0x36,0x38,0x62,0x39,0x33,0x65,0x55,0x2c,0x30,0x78,0x33,0x34,0x32,0x34,0x33,0x38,0x32,0x63,0x55,0x2c,0x30,0x78,0x34,0x30,0x61,0x33,0x63, + 0x32,0x35,0x66,0x55,0x2c,0x0a,0x30,0x78,0x63,0x33,0x31,0x64,0x31,0x36,0x37,0x32,0x55,0x2c,0x30,0x78,0x32,0x35,0x65,0x32,0x62,0x63,0x30,0x63,0x55,0x2c,0x30,0x78, + 0x34,0x39,0x33,0x63,0x32,0x38,0x38,0x62,0x55,0x2c,0x30,0x78,0x39,0x35,0x30,0x64,0x66,0x66,0x34,0x31,0x55,0x2c,0x0a,0x30,0x78,0x30,0x31,0x61,0x38,0x33,0x39,0x37, + 0x31,0x55,0x2c,0x30,0x78,0x62,0x33,0x30,0x63,0x30,0x38,0x64,0x65,0x55,0x2c,0x30,0x78,0x65,0x34,0x62,0x34,0x64,0x38,0x39,0x63,0x55,0x2c,0x30,0x78,0x63,0x31,0x35, + 0x36,0x36,0x34,0x39,0x30,0x55,0x2c,0x0a,0x30,0x78,0x38,0x34,0x63,0x62,0x37,0x62,0x36,0x31,0x55,0x2c,0x30,0x78,0x62,0x36,0x33,0x32,0x64,0x35,0x37,0x30,0x55,0x2c, + 0x30,0x78,0x35,0x63,0x36,0x63,0x34,0x38,0x37,0x34,0x55,0x2c,0x30,0x78,0x35,0x37,0x62,0x38,0x64,0x30,0x34,0x32,0x55,0x2c,0x0a,0x30,0x78,0x66,0x34,0x35,0x31,0x35, + 0x30,0x61,0x37,0x55,0x2c,0x30,0x78,0x34,0x31,0x37,0x65,0x35,0x33,0x36,0x35,0x55,0x2c,0x30,0x78,0x31,0x37,0x31,0x61,0x63,0x33,0x61,0x34,0x55,0x2c,0x30,0x78,0x32, + 0x37,0x33,0x61,0x39,0x36,0x35,0x65,0x55,0x2c,0x0a,0x30,0x78,0x61,0x62,0x33,0x62,0x63,0x62,0x36,0x62,0x55,0x2c,0x30,0x78,0x39,0x64,0x31,0x66,0x66,0x31,0x34,0x35, + 0x55,0x2c,0x30,0x78,0x66,0x61,0x61,0x63,0x61,0x62,0x35,0x38,0x55,0x2c,0x30,0x78,0x65,0x33,0x34,0x62,0x39,0x33,0x30,0x33,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x32, + 0x30,0x35,0x35,0x66,0x61,0x55,0x2c,0x30,0x78,0x37,0x36,0x61,0x64,0x66,0x36,0x36,0x64,0x55,0x2c,0x30,0x78,0x63,0x63,0x38,0x38,0x39,0x31,0x37,0x36,0x55,0x2c,0x30, + 0x78,0x30,0x32,0x66,0x35,0x32,0x35,0x34,0x63,0x55,0x2c,0x0a,0x30,0x78,0x65,0x35,0x34,0x66,0x66,0x63,0x64,0x37,0x55,0x2c,0x30,0x78,0x32,0x61,0x63,0x35,0x64,0x37, + 0x63,0x62,0x55,0x2c,0x30,0x78,0x33,0x35,0x32,0x36,0x38,0x30,0x34,0x34,0x55,0x2c,0x30,0x78,0x36,0x32,0x62,0x35,0x38,0x66,0x61,0x33,0x55,0x2c,0x0a,0x30,0x78,0x62, + 0x31,0x64,0x65,0x34,0x39,0x35,0x61,0x55,0x2c,0x30,0x78,0x62,0x61,0x32,0x35,0x36,0x37,0x31,0x62,0x55,0x2c,0x30,0x78,0x65,0x61,0x34,0x35,0x39,0x38,0x30,0x65,0x55, + 0x2c,0x30,0x78,0x66,0x65,0x35,0x64,0x65,0x31,0x63,0x30,0x55,0x2c,0x0a,0x30,0x78,0x32,0x66,0x63,0x33,0x30,0x32,0x37,0x35,0x55,0x2c,0x30,0x78,0x34,0x63,0x38,0x31, + 0x31,0x32,0x66,0x30,0x55,0x2c,0x30,0x78,0x34,0x36,0x38,0x64,0x61,0x33,0x39,0x37,0x55,0x2c,0x30,0x78,0x64,0x33,0x36,0x62,0x63,0x36,0x66,0x39,0x55,0x2c,0x0a,0x30, + 0x78,0x38,0x66,0x30,0x33,0x65,0x37,0x35,0x66,0x55,0x2c,0x30,0x78,0x39,0x32,0x31,0x35,0x39,0x35,0x39,0x63,0x55,0x2c,0x30,0x78,0x36,0x64,0x62,0x66,0x65,0x62,0x37, + 0x61,0x55,0x2c,0x30,0x78,0x35,0x32,0x39,0x35,0x64,0x61,0x35,0x39,0x55,0x2c,0x0a,0x30,0x78,0x62,0x65,0x64,0x34,0x32,0x64,0x38,0x33,0x55,0x2c,0x30,0x78,0x37,0x34, + 0x35,0x38,0x64,0x33,0x32,0x31,0x55,0x2c,0x30,0x78,0x65,0x30,0x34,0x39,0x32,0x39,0x36,0x39,0x55,0x2c,0x30,0x78,0x63,0x39,0x38,0x65,0x34,0x34,0x63,0x38,0x55,0x2c, + 0x0a,0x30,0x78,0x63,0x32,0x37,0x35,0x36,0x61,0x38,0x39,0x55,0x2c,0x30,0x78,0x38,0x65,0x66,0x34,0x37,0x38,0x37,0x39,0x55,0x2c,0x30,0x78,0x35,0x38,0x39,0x39,0x36, + 0x62,0x33,0x65,0x55,0x2c,0x30,0x78,0x62,0x39,0x32,0x37,0x64,0x64,0x37,0x31,0x55,0x2c,0x0a,0x30,0x78,0x65,0x31,0x62,0x65,0x62,0x36,0x34,0x66,0x55,0x2c,0x30,0x78, + 0x38,0x38,0x66,0x30,0x31,0x37,0x61,0x64,0x55,0x2c,0x30,0x78,0x32,0x30,0x63,0x39,0x36,0x36,0x61,0x63,0x55,0x2c,0x30,0x78,0x63,0x65,0x37,0x64,0x62,0x34,0x33,0x61, + 0x55,0x2c,0x0a,0x30,0x78,0x64,0x66,0x36,0x33,0x31,0x38,0x34,0x61,0x55,0x2c,0x30,0x78,0x31,0x61,0x65,0x35,0x38,0x32,0x33,0x31,0x55,0x2c,0x30,0x78,0x35,0x31,0x39, + 0x37,0x36,0x30,0x33,0x33,0x55,0x2c,0x30,0x78,0x35,0x33,0x36,0x32,0x34,0x35,0x37,0x66,0x55,0x2c,0x0a,0x30,0x78,0x36,0x34,0x62,0x31,0x65,0x30,0x37,0x37,0x55,0x2c, + 0x30,0x78,0x36,0x62,0x62,0x62,0x38,0x34,0x61,0x65,0x55,0x2c,0x30,0x78,0x38,0x31,0x66,0x65,0x31,0x63,0x61,0x30,0x55,0x2c,0x30,0x78,0x30,0x38,0x66,0x39,0x39,0x34, + 0x32,0x62,0x55,0x2c,0x0a,0x30,0x78,0x34,0x38,0x37,0x30,0x35,0x38,0x36,0x38,0x55,0x2c,0x30,0x78,0x34,0x35,0x38,0x66,0x31,0x39,0x66,0x64,0x55,0x2c,0x30,0x78,0x64, + 0x65,0x39,0x34,0x38,0x37,0x36,0x63,0x55,0x2c,0x30,0x78,0x37,0x62,0x35,0x32,0x62,0x37,0x66,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x33,0x61,0x62,0x32,0x33,0x64,0x33, + 0x55,0x2c,0x30,0x78,0x34,0x62,0x37,0x32,0x65,0x32,0x30,0x32,0x55,0x2c,0x30,0x78,0x31,0x66,0x65,0x33,0x35,0x37,0x38,0x66,0x55,0x2c,0x30,0x78,0x35,0x35,0x36,0x36, + 0x32,0x61,0x61,0x62,0x55,0x2c,0x0a,0x30,0x78,0x65,0x62,0x62,0x32,0x30,0x37,0x32,0x38,0x55,0x2c,0x30,0x78,0x62,0x35,0x32,0x66,0x30,0x33,0x63,0x32,0x55,0x2c,0x30, + 0x78,0x63,0x35,0x38,0x36,0x39,0x61,0x37,0x62,0x55,0x2c,0x30,0x78,0x33,0x37,0x64,0x33,0x61,0x35,0x30,0x38,0x55,0x2c,0x0a,0x30,0x78,0x32,0x38,0x33,0x30,0x66,0x32, + 0x38,0x37,0x55,0x2c,0x30,0x78,0x62,0x66,0x32,0x33,0x62,0x32,0x61,0x35,0x55,0x2c,0x30,0x78,0x30,0x33,0x30,0x32,0x62,0x61,0x36,0x61,0x55,0x2c,0x30,0x78,0x31,0x36, + 0x65,0x64,0x35,0x63,0x38,0x32,0x55,0x2c,0x0a,0x30,0x78,0x63,0x66,0x38,0x61,0x32,0x62,0x31,0x63,0x55,0x2c,0x30,0x78,0x37,0x39,0x61,0x37,0x39,0x32,0x62,0x34,0x55, + 0x2c,0x30,0x78,0x30,0x37,0x66,0x33,0x66,0x30,0x66,0x32,0x55,0x2c,0x30,0x78,0x36,0x39,0x34,0x65,0x61,0x31,0x65,0x32,0x55,0x2c,0x0a,0x30,0x78,0x64,0x61,0x36,0x35, + 0x63,0x64,0x66,0x34,0x55,0x2c,0x30,0x78,0x30,0x35,0x30,0x36,0x64,0x35,0x62,0x65,0x55,0x2c,0x30,0x78,0x33,0x34,0x64,0x31,0x31,0x66,0x36,0x32,0x55,0x2c,0x30,0x78, + 0x61,0x36,0x63,0x34,0x38,0x61,0x66,0x65,0x55,0x2c,0x0a,0x30,0x78,0x32,0x65,0x33,0x34,0x39,0x64,0x35,0x33,0x55,0x2c,0x30,0x78,0x66,0x33,0x61,0x32,0x61,0x30,0x35, + 0x35,0x55,0x2c,0x30,0x78,0x38,0x61,0x30,0x35,0x33,0x32,0x65,0x31,0x55,0x2c,0x30,0x78,0x66,0x36,0x61,0x34,0x37,0x35,0x65,0x62,0x55,0x2c,0x0a,0x30,0x78,0x38,0x33, + 0x30,0x62,0x33,0x39,0x65,0x63,0x55,0x2c,0x30,0x78,0x36,0x30,0x34,0x30,0x61,0x61,0x65,0x66,0x55,0x2c,0x30,0x78,0x37,0x31,0x35,0x65,0x30,0x36,0x39,0x66,0x55,0x2c, + 0x30,0x78,0x36,0x65,0x62,0x64,0x35,0x31,0x31,0x30,0x55,0x2c,0x0a,0x30,0x78,0x32,0x31,0x33,0x65,0x66,0x39,0x38,0x61,0x55,0x2c,0x30,0x78,0x64,0x64,0x39,0x36,0x33, + 0x64,0x30,0x36,0x55,0x2c,0x30,0x78,0x33,0x65,0x64,0x64,0x61,0x65,0x30,0x35,0x55,0x2c,0x30,0x78,0x65,0x36,0x34,0x64,0x34,0x36,0x62,0x64,0x55,0x2c,0x0a,0x30,0x78, + 0x35,0x34,0x39,0x31,0x62,0x35,0x38,0x64,0x55,0x2c,0x30,0x78,0x63,0x34,0x37,0x31,0x30,0x35,0x35,0x64,0x55,0x2c,0x30,0x78,0x30,0x36,0x30,0x34,0x36,0x66,0x64,0x34, + 0x55,0x2c,0x30,0x78,0x35,0x30,0x36,0x30,0x66,0x66,0x31,0x35,0x55,0x2c,0x0a,0x30,0x78,0x39,0x38,0x31,0x39,0x32,0x34,0x66,0x62,0x55,0x2c,0x30,0x78,0x62,0x64,0x64, + 0x36,0x39,0x37,0x65,0x39,0x55,0x2c,0x30,0x78,0x34,0x30,0x38,0x39,0x63,0x63,0x34,0x33,0x55,0x2c,0x30,0x78,0x64,0x39,0x36,0x37,0x37,0x37,0x39,0x65,0x55,0x2c,0x0a, + 0x30,0x78,0x65,0x38,0x62,0x30,0x62,0x64,0x34,0x32,0x55,0x2c,0x30,0x78,0x38,0x39,0x30,0x37,0x38,0x38,0x38,0x62,0x55,0x2c,0x30,0x78,0x31,0x39,0x65,0x37,0x33,0x38, + 0x35,0x62,0x55,0x2c,0x30,0x78,0x63,0x38,0x37,0x39,0x64,0x62,0x65,0x65,0x55,0x2c,0x0a,0x30,0x78,0x37,0x63,0x61,0x31,0x34,0x37,0x30,0x61,0x55,0x2c,0x30,0x78,0x34, + 0x32,0x37,0x63,0x65,0x39,0x30,0x66,0x55,0x2c,0x30,0x78,0x38,0x34,0x66,0x38,0x63,0x39,0x31,0x65,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55, + 0x2c,0x0a,0x30,0x78,0x38,0x30,0x30,0x39,0x38,0x33,0x38,0x36,0x55,0x2c,0x30,0x78,0x32,0x62,0x33,0x32,0x34,0x38,0x65,0x64,0x55,0x2c,0x30,0x78,0x31,0x31,0x31,0x65, + 0x61,0x63,0x37,0x30,0x55,0x2c,0x30,0x78,0x35,0x61,0x36,0x63,0x34,0x65,0x37,0x32,0x55,0x2c,0x0a,0x30,0x78,0x30,0x65,0x66,0x64,0x66,0x62,0x66,0x66,0x55,0x2c,0x30, + 0x78,0x38,0x35,0x30,0x66,0x35,0x36,0x33,0x38,0x55,0x2c,0x30,0x78,0x61,0x65,0x33,0x64,0x31,0x65,0x64,0x35,0x55,0x2c,0x30,0x78,0x32,0x64,0x33,0x36,0x32,0x37,0x33, + 0x39,0x55,0x2c,0x0a,0x30,0x78,0x30,0x66,0x30,0x61,0x36,0x34,0x64,0x39,0x55,0x2c,0x30,0x78,0x35,0x63,0x36,0x38,0x32,0x31,0x61,0x36,0x55,0x2c,0x30,0x78,0x35,0x62, + 0x39,0x62,0x64,0x31,0x35,0x34,0x55,0x2c,0x30,0x78,0x33,0x36,0x32,0x34,0x33,0x61,0x32,0x65,0x55,0x2c,0x0a,0x30,0x78,0x30,0x61,0x30,0x63,0x62,0x31,0x36,0x37,0x55, + 0x2c,0x30,0x78,0x35,0x37,0x39,0x33,0x30,0x66,0x65,0x37,0x55,0x2c,0x30,0x78,0x65,0x65,0x62,0x34,0x64,0x32,0x39,0x36,0x55,0x2c,0x30,0x78,0x39,0x62,0x31,0x62,0x39, + 0x65,0x39,0x31,0x55,0x2c,0x0a,0x30,0x78,0x63,0x30,0x38,0x30,0x34,0x66,0x63,0x35,0x55,0x2c,0x30,0x78,0x64,0x63,0x36,0x31,0x61,0x32,0x32,0x30,0x55,0x2c,0x30,0x78, + 0x37,0x37,0x35,0x61,0x36,0x39,0x34,0x62,0x55,0x2c,0x30,0x78,0x31,0x32,0x31,0x63,0x31,0x36,0x31,0x61,0x55,0x2c,0x0a,0x30,0x78,0x39,0x33,0x65,0x32,0x30,0x61,0x62, + 0x61,0x55,0x2c,0x30,0x78,0x61,0x30,0x63,0x30,0x65,0x35,0x32,0x61,0x55,0x2c,0x30,0x78,0x32,0x32,0x33,0x63,0x34,0x33,0x65,0x30,0x55,0x2c,0x30,0x78,0x31,0x62,0x31, + 0x32,0x31,0x64,0x31,0x37,0x55,0x2c,0x0a,0x30,0x78,0x30,0x39,0x30,0x65,0x30,0x62,0x30,0x64,0x55,0x2c,0x30,0x78,0x38,0x62,0x66,0x32,0x61,0x64,0x63,0x37,0x55,0x2c, + 0x30,0x78,0x62,0x36,0x32,0x64,0x62,0x39,0x61,0x38,0x55,0x2c,0x30,0x78,0x31,0x65,0x31,0x34,0x63,0x38,0x61,0x39,0x55,0x2c,0x0a,0x30,0x78,0x66,0x31,0x35,0x37,0x38, + 0x35,0x31,0x39,0x55,0x2c,0x30,0x78,0x37,0x35,0x61,0x66,0x34,0x63,0x30,0x37,0x55,0x2c,0x30,0x78,0x39,0x39,0x65,0x65,0x62,0x62,0x64,0x64,0x55,0x2c,0x30,0x78,0x37, + 0x66,0x61,0x33,0x66,0x64,0x36,0x30,0x55,0x2c,0x0a,0x30,0x78,0x30,0x31,0x66,0x37,0x39,0x66,0x32,0x36,0x55,0x2c,0x30,0x78,0x37,0x32,0x35,0x63,0x62,0x63,0x66,0x35, + 0x55,0x2c,0x30,0x78,0x36,0x36,0x34,0x34,0x63,0x35,0x33,0x62,0x55,0x2c,0x30,0x78,0x66,0x62,0x35,0x62,0x33,0x34,0x37,0x65,0x55,0x2c,0x0a,0x30,0x78,0x34,0x33,0x38, + 0x62,0x37,0x36,0x32,0x39,0x55,0x2c,0x30,0x78,0x32,0x33,0x63,0x62,0x64,0x63,0x63,0x36,0x55,0x2c,0x30,0x78,0x65,0x64,0x62,0x36,0x36,0x38,0x66,0x63,0x55,0x2c,0x30, + 0x78,0x65,0x34,0x62,0x38,0x36,0x33,0x66,0x31,0x55,0x2c,0x0a,0x30,0x78,0x33,0x31,0x64,0x37,0x63,0x61,0x64,0x63,0x55,0x2c,0x30,0x78,0x36,0x33,0x34,0x32,0x31,0x30, + 0x38,0x35,0x55,0x2c,0x30,0x78,0x39,0x37,0x31,0x33,0x34,0x30,0x32,0x32,0x55,0x2c,0x30,0x78,0x63,0x36,0x38,0x34,0x32,0x30,0x31,0x31,0x55,0x2c,0x0a,0x30,0x78,0x34, + 0x61,0x38,0x35,0x37,0x64,0x32,0x34,0x55,0x2c,0x30,0x78,0x62,0x62,0x64,0x32,0x66,0x38,0x33,0x64,0x55,0x2c,0x30,0x78,0x66,0x39,0x61,0x65,0x31,0x31,0x33,0x32,0x55, + 0x2c,0x30,0x78,0x32,0x39,0x63,0x37,0x36,0x64,0x61,0x31,0x55,0x2c,0x0a,0x30,0x78,0x39,0x65,0x31,0x64,0x34,0x62,0x32,0x66,0x55,0x2c,0x30,0x78,0x62,0x32,0x64,0x63, + 0x66,0x33,0x33,0x30,0x55,0x2c,0x30,0x78,0x38,0x36,0x30,0x64,0x65,0x63,0x35,0x32,0x55,0x2c,0x30,0x78,0x63,0x31,0x37,0x37,0x64,0x30,0x65,0x33,0x55,0x2c,0x0a,0x30, + 0x78,0x62,0x33,0x32,0x62,0x36,0x63,0x31,0x36,0x55,0x2c,0x30,0x78,0x37,0x30,0x61,0x39,0x39,0x39,0x62,0x39,0x55,0x2c,0x30,0x78,0x39,0x34,0x31,0x31,0x66,0x61,0x34, + 0x38,0x55,0x2c,0x30,0x78,0x65,0x39,0x34,0x37,0x32,0x32,0x36,0x34,0x55,0x2c,0x0a,0x30,0x78,0x66,0x63,0x61,0x38,0x63,0x34,0x38,0x63,0x55,0x2c,0x30,0x78,0x66,0x30, + 0x61,0x30,0x31,0x61,0x33,0x66,0x55,0x2c,0x30,0x78,0x37,0x64,0x35,0x36,0x64,0x38,0x32,0x63,0x55,0x2c,0x30,0x78,0x33,0x33,0x32,0x32,0x65,0x66,0x39,0x30,0x55,0x2c, + 0x0a,0x30,0x78,0x34,0x39,0x38,0x37,0x63,0x37,0x34,0x65,0x55,0x2c,0x30,0x78,0x33,0x38,0x64,0x39,0x63,0x31,0x64,0x31,0x55,0x2c,0x30,0x78,0x63,0x61,0x38,0x63,0x66, + 0x65,0x61,0x32,0x55,0x2c,0x30,0x78,0x64,0x34,0x39,0x38,0x33,0x36,0x30,0x62,0x55,0x2c,0x0a,0x30,0x78,0x66,0x35,0x61,0x36,0x63,0x66,0x38,0x31,0x55,0x2c,0x30,0x78, + 0x37,0x61,0x61,0x35,0x32,0x38,0x64,0x65,0x55,0x2c,0x30,0x78,0x62,0x37,0x64,0x61,0x32,0x36,0x38,0x65,0x55,0x2c,0x30,0x78,0x61,0x64,0x33,0x66,0x61,0x34,0x62,0x66, + 0x55,0x2c,0x0a,0x30,0x78,0x33,0x61,0x32,0x63,0x65,0x34,0x39,0x64,0x55,0x2c,0x30,0x78,0x37,0x38,0x35,0x30,0x30,0x64,0x39,0x32,0x55,0x2c,0x30,0x78,0x35,0x66,0x36, + 0x61,0x39,0x62,0x63,0x63,0x55,0x2c,0x30,0x78,0x37,0x65,0x35,0x34,0x36,0x32,0x34,0x36,0x55,0x2c,0x0a,0x30,0x78,0x38,0x64,0x66,0x36,0x63,0x32,0x31,0x33,0x55,0x2c, + 0x30,0x78,0x64,0x38,0x39,0x30,0x65,0x38,0x62,0x38,0x55,0x2c,0x30,0x78,0x33,0x39,0x32,0x65,0x35,0x65,0x66,0x37,0x55,0x2c,0x30,0x78,0x63,0x33,0x38,0x32,0x66,0x35, + 0x61,0x66,0x55,0x2c,0x0a,0x30,0x78,0x35,0x64,0x39,0x66,0x62,0x65,0x38,0x30,0x55,0x2c,0x30,0x78,0x64,0x30,0x36,0x39,0x37,0x63,0x39,0x33,0x55,0x2c,0x30,0x78,0x64, + 0x35,0x36,0x66,0x61,0x39,0x32,0x64,0x55,0x2c,0x30,0x78,0x32,0x35,0x63,0x66,0x62,0x33,0x31,0x32,0x55,0x2c,0x0a,0x30,0x78,0x61,0x63,0x63,0x38,0x33,0x62,0x39,0x39, + 0x55,0x2c,0x30,0x78,0x31,0x38,0x31,0x30,0x61,0x37,0x37,0x64,0x55,0x2c,0x30,0x78,0x39,0x63,0x65,0x38,0x36,0x65,0x36,0x33,0x55,0x2c,0x30,0x78,0x33,0x62,0x64,0x62, + 0x37,0x62,0x62,0x62,0x55,0x2c,0x0a,0x30,0x78,0x32,0x36,0x63,0x64,0x30,0x39,0x37,0x38,0x55,0x2c,0x30,0x78,0x35,0x39,0x36,0x65,0x66,0x34,0x31,0x38,0x55,0x2c,0x30, + 0x78,0x39,0x61,0x65,0x63,0x30,0x31,0x62,0x37,0x55,0x2c,0x30,0x78,0x34,0x66,0x38,0x33,0x61,0x38,0x39,0x61,0x55,0x2c,0x0a,0x30,0x78,0x39,0x35,0x65,0x36,0x36,0x35, + 0x36,0x65,0x55,0x2c,0x30,0x78,0x66,0x66,0x61,0x61,0x37,0x65,0x65,0x36,0x55,0x2c,0x30,0x78,0x62,0x63,0x32,0x31,0x30,0x38,0x63,0x66,0x55,0x2c,0x30,0x78,0x31,0x35, + 0x65,0x66,0x65,0x36,0x65,0x38,0x55,0x2c,0x0a,0x30,0x78,0x65,0x37,0x62,0x61,0x64,0x39,0x39,0x62,0x55,0x2c,0x30,0x78,0x36,0x66,0x34,0x61,0x63,0x65,0x33,0x36,0x55, + 0x2c,0x30,0x78,0x39,0x66,0x65,0x61,0x64,0x34,0x30,0x39,0x55,0x2c,0x30,0x78,0x62,0x30,0x32,0x39,0x64,0x36,0x37,0x63,0x55,0x2c,0x0a,0x30,0x78,0x61,0x34,0x33,0x31, + 0x61,0x66,0x62,0x32,0x55,0x2c,0x30,0x78,0x33,0x66,0x32,0x61,0x33,0x31,0x32,0x33,0x55,0x2c,0x30,0x78,0x61,0x35,0x63,0x36,0x33,0x30,0x39,0x34,0x55,0x2c,0x30,0x78, + 0x61,0x32,0x33,0x35,0x63,0x30,0x36,0x36,0x55,0x2c,0x0a,0x30,0x78,0x34,0x65,0x37,0x34,0x33,0x37,0x62,0x63,0x55,0x2c,0x30,0x78,0x38,0x32,0x66,0x63,0x61,0x36,0x63, + 0x61,0x55,0x2c,0x30,0x78,0x39,0x30,0x65,0x30,0x62,0x30,0x64,0x30,0x55,0x2c,0x30,0x78,0x61,0x37,0x33,0x33,0x31,0x35,0x64,0x38,0x55,0x2c,0x0a,0x30,0x78,0x30,0x34, + 0x66,0x31,0x34,0x61,0x39,0x38,0x55,0x2c,0x30,0x78,0x65,0x63,0x34,0x31,0x66,0x37,0x64,0x61,0x55,0x2c,0x30,0x78,0x63,0x64,0x37,0x66,0x30,0x65,0x35,0x30,0x55,0x2c, + 0x30,0x78,0x39,0x31,0x31,0x37,0x32,0x66,0x66,0x36,0x55,0x2c,0x0a,0x30,0x78,0x34,0x64,0x37,0x36,0x38,0x64,0x64,0x36,0x55,0x2c,0x30,0x78,0x65,0x66,0x34,0x33,0x34, + 0x64,0x62,0x30,0x55,0x2c,0x30,0x78,0x61,0x61,0x63,0x63,0x35,0x34,0x34,0x64,0x55,0x2c,0x30,0x78,0x39,0x36,0x65,0x34,0x64,0x66,0x30,0x34,0x55,0x2c,0x0a,0x30,0x78, + 0x64,0x31,0x39,0x65,0x65,0x33,0x62,0x35,0x55,0x2c,0x30,0x78,0x36,0x61,0x34,0x63,0x31,0x62,0x38,0x38,0x55,0x2c,0x30,0x78,0x32,0x63,0x63,0x31,0x62,0x38,0x31,0x66, + 0x55,0x2c,0x30,0x78,0x36,0x35,0x34,0x36,0x37,0x66,0x35,0x31,0x55,0x2c,0x0a,0x30,0x78,0x35,0x65,0x39,0x64,0x30,0x34,0x65,0x61,0x55,0x2c,0x30,0x78,0x38,0x63,0x30, + 0x31,0x35,0x64,0x33,0x35,0x55,0x2c,0x30,0x78,0x38,0x37,0x66,0x61,0x37,0x33,0x37,0x34,0x55,0x2c,0x30,0x78,0x30,0x62,0x66,0x62,0x32,0x65,0x34,0x31,0x55,0x2c,0x0a, + 0x30,0x78,0x36,0x37,0x62,0x33,0x35,0x61,0x31,0x64,0x55,0x2c,0x30,0x78,0x64,0x62,0x39,0x32,0x35,0x32,0x64,0x32,0x55,0x2c,0x30,0x78,0x31,0x30,0x65,0x39,0x33,0x33, + 0x35,0x36,0x55,0x2c,0x30,0x78,0x64,0x36,0x36,0x64,0x31,0x33,0x34,0x37,0x55,0x2c,0x0a,0x30,0x78,0x64,0x37,0x39,0x61,0x38,0x63,0x36,0x31,0x55,0x2c,0x30,0x78,0x61, + 0x31,0x33,0x37,0x37,0x61,0x30,0x63,0x55,0x2c,0x30,0x78,0x66,0x38,0x35,0x39,0x38,0x65,0x31,0x34,0x55,0x2c,0x30,0x78,0x31,0x33,0x65,0x62,0x38,0x39,0x33,0x63,0x55, + 0x2c,0x0a,0x30,0x78,0x61,0x39,0x63,0x65,0x65,0x65,0x32,0x37,0x55,0x2c,0x30,0x78,0x36,0x31,0x62,0x37,0x33,0x35,0x63,0x39,0x55,0x2c,0x30,0x78,0x31,0x63,0x65,0x31, + 0x65,0x64,0x65,0x35,0x55,0x2c,0x30,0x78,0x34,0x37,0x37,0x61,0x33,0x63,0x62,0x31,0x55,0x2c,0x0a,0x30,0x78,0x64,0x32,0x39,0x63,0x35,0x39,0x64,0x66,0x55,0x2c,0x30, + 0x78,0x66,0x32,0x35,0x35,0x33,0x66,0x37,0x33,0x55,0x2c,0x30,0x78,0x31,0x34,0x31,0x38,0x37,0x39,0x63,0x65,0x55,0x2c,0x30,0x78,0x63,0x37,0x37,0x33,0x62,0x66,0x33, + 0x37,0x55,0x2c,0x0a,0x30,0x78,0x66,0x37,0x35,0x33,0x65,0x61,0x63,0x64,0x55,0x2c,0x30,0x78,0x66,0x64,0x35,0x66,0x35,0x62,0x61,0x61,0x55,0x2c,0x30,0x78,0x33,0x64, + 0x64,0x66,0x31,0x34,0x36,0x66,0x55,0x2c,0x30,0x78,0x34,0x34,0x37,0x38,0x38,0x36,0x64,0x62,0x55,0x2c,0x0a,0x30,0x78,0x61,0x66,0x63,0x61,0x38,0x31,0x66,0x33,0x55, + 0x2c,0x30,0x78,0x36,0x38,0x62,0x39,0x33,0x65,0x63,0x34,0x55,0x2c,0x30,0x78,0x32,0x34,0x33,0x38,0x32,0x63,0x33,0x34,0x55,0x2c,0x30,0x78,0x61,0x33,0x63,0x32,0x35, + 0x66,0x34,0x30,0x55,0x2c,0x0a,0x30,0x78,0x31,0x64,0x31,0x36,0x37,0x32,0x63,0x33,0x55,0x2c,0x30,0x78,0x65,0x32,0x62,0x63,0x30,0x63,0x32,0x35,0x55,0x2c,0x30,0x78, + 0x33,0x63,0x32,0x38,0x38,0x62,0x34,0x39,0x55,0x2c,0x30,0x78,0x30,0x64,0x66,0x66,0x34,0x31,0x39,0x35,0x55,0x2c,0x0a,0x30,0x78,0x61,0x38,0x33,0x39,0x37,0x31,0x30, + 0x31,0x55,0x2c,0x30,0x78,0x30,0x63,0x30,0x38,0x64,0x65,0x62,0x33,0x55,0x2c,0x30,0x78,0x62,0x34,0x64,0x38,0x39,0x63,0x65,0x34,0x55,0x2c,0x30,0x78,0x35,0x36,0x36, + 0x34,0x39,0x30,0x63,0x31,0x55,0x2c,0x0a,0x30,0x78,0x63,0x62,0x37,0x62,0x36,0x31,0x38,0x34,0x55,0x2c,0x30,0x78,0x33,0x32,0x64,0x35,0x37,0x30,0x62,0x36,0x55,0x2c, + 0x30,0x78,0x36,0x63,0x34,0x38,0x37,0x34,0x35,0x63,0x55,0x2c,0x30,0x78,0x62,0x38,0x64,0x30,0x34,0x32,0x35,0x37,0x55,0x2c,0x0a,0x30,0x78,0x35,0x31,0x35,0x30,0x61, + 0x37,0x66,0x34,0x55,0x2c,0x30,0x78,0x37,0x65,0x35,0x33,0x36,0x35,0x34,0x31,0x55,0x2c,0x30,0x78,0x31,0x61,0x63,0x33,0x61,0x34,0x31,0x37,0x55,0x2c,0x30,0x78,0x33, + 0x61,0x39,0x36,0x35,0x65,0x32,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x62,0x63,0x62,0x36,0x62,0x61,0x62,0x55,0x2c,0x30,0x78,0x31,0x66,0x66,0x31,0x34,0x35,0x39,0x64, + 0x55,0x2c,0x30,0x78,0x61,0x63,0x61,0x62,0x35,0x38,0x66,0x61,0x55,0x2c,0x30,0x78,0x34,0x62,0x39,0x33,0x30,0x33,0x65,0x33,0x55,0x2c,0x0a,0x30,0x78,0x32,0x30,0x35, + 0x35,0x66,0x61,0x33,0x30,0x55,0x2c,0x30,0x78,0x61,0x64,0x66,0x36,0x36,0x64,0x37,0x36,0x55,0x2c,0x30,0x78,0x38,0x38,0x39,0x31,0x37,0x36,0x63,0x63,0x55,0x2c,0x30, + 0x78,0x66,0x35,0x32,0x35,0x34,0x63,0x30,0x32,0x55,0x2c,0x0a,0x30,0x78,0x34,0x66,0x66,0x63,0x64,0x37,0x65,0x35,0x55,0x2c,0x30,0x78,0x63,0x35,0x64,0x37,0x63,0x62, + 0x32,0x61,0x55,0x2c,0x30,0x78,0x32,0x36,0x38,0x30,0x34,0x34,0x33,0x35,0x55,0x2c,0x30,0x78,0x62,0x35,0x38,0x66,0x61,0x33,0x36,0x32,0x55,0x2c,0x0a,0x30,0x78,0x64, + 0x65,0x34,0x39,0x35,0x61,0x62,0x31,0x55,0x2c,0x30,0x78,0x32,0x35,0x36,0x37,0x31,0x62,0x62,0x61,0x55,0x2c,0x30,0x78,0x34,0x35,0x39,0x38,0x30,0x65,0x65,0x61,0x55, + 0x2c,0x30,0x78,0x35,0x64,0x65,0x31,0x63,0x30,0x66,0x65,0x55,0x2c,0x0a,0x30,0x78,0x63,0x33,0x30,0x32,0x37,0x35,0x32,0x66,0x55,0x2c,0x30,0x78,0x38,0x31,0x31,0x32, + 0x66,0x30,0x34,0x63,0x55,0x2c,0x30,0x78,0x38,0x64,0x61,0x33,0x39,0x37,0x34,0x36,0x55,0x2c,0x30,0x78,0x36,0x62,0x63,0x36,0x66,0x39,0x64,0x33,0x55,0x2c,0x0a,0x30, + 0x78,0x30,0x33,0x65,0x37,0x35,0x66,0x38,0x66,0x55,0x2c,0x30,0x78,0x31,0x35,0x39,0x35,0x39,0x63,0x39,0x32,0x55,0x2c,0x30,0x78,0x62,0x66,0x65,0x62,0x37,0x61,0x36, + 0x64,0x55,0x2c,0x30,0x78,0x39,0x35,0x64,0x61,0x35,0x39,0x35,0x32,0x55,0x2c,0x0a,0x30,0x78,0x64,0x34,0x32,0x64,0x38,0x33,0x62,0x65,0x55,0x2c,0x30,0x78,0x35,0x38, + 0x64,0x33,0x32,0x31,0x37,0x34,0x55,0x2c,0x30,0x78,0x34,0x39,0x32,0x39,0x36,0x39,0x65,0x30,0x55,0x2c,0x30,0x78,0x38,0x65,0x34,0x34,0x63,0x38,0x63,0x39,0x55,0x2c, + 0x0a,0x30,0x78,0x37,0x35,0x36,0x61,0x38,0x39,0x63,0x32,0x55,0x2c,0x30,0x78,0x66,0x34,0x37,0x38,0x37,0x39,0x38,0x65,0x55,0x2c,0x30,0x78,0x39,0x39,0x36,0x62,0x33, + 0x65,0x35,0x38,0x55,0x2c,0x30,0x78,0x32,0x37,0x64,0x64,0x37,0x31,0x62,0x39,0x55,0x2c,0x0a,0x30,0x78,0x62,0x65,0x62,0x36,0x34,0x66,0x65,0x31,0x55,0x2c,0x30,0x78, + 0x66,0x30,0x31,0x37,0x61,0x64,0x38,0x38,0x55,0x2c,0x30,0x78,0x63,0x39,0x36,0x36,0x61,0x63,0x32,0x30,0x55,0x2c,0x30,0x78,0x37,0x64,0x62,0x34,0x33,0x61,0x63,0x65, + 0x55,0x2c,0x0a,0x30,0x78,0x36,0x33,0x31,0x38,0x34,0x61,0x64,0x66,0x55,0x2c,0x30,0x78,0x65,0x35,0x38,0x32,0x33,0x31,0x31,0x61,0x55,0x2c,0x30,0x78,0x39,0x37,0x36, + 0x30,0x33,0x33,0x35,0x31,0x55,0x2c,0x30,0x78,0x36,0x32,0x34,0x35,0x37,0x66,0x35,0x33,0x55,0x2c,0x0a,0x30,0x78,0x62,0x31,0x65,0x30,0x37,0x37,0x36,0x34,0x55,0x2c, + 0x30,0x78,0x62,0x62,0x38,0x34,0x61,0x65,0x36,0x62,0x55,0x2c,0x30,0x78,0x66,0x65,0x31,0x63,0x61,0x30,0x38,0x31,0x55,0x2c,0x30,0x78,0x66,0x39,0x39,0x34,0x32,0x62, + 0x30,0x38,0x55,0x2c,0x0a,0x30,0x78,0x37,0x30,0x35,0x38,0x36,0x38,0x34,0x38,0x55,0x2c,0x30,0x78,0x38,0x66,0x31,0x39,0x66,0x64,0x34,0x35,0x55,0x2c,0x30,0x78,0x39, + 0x34,0x38,0x37,0x36,0x63,0x64,0x65,0x55,0x2c,0x30,0x78,0x35,0x32,0x62,0x37,0x66,0x38,0x37,0x62,0x55,0x2c,0x0a,0x30,0x78,0x61,0x62,0x32,0x33,0x64,0x33,0x37,0x33, + 0x55,0x2c,0x30,0x78,0x37,0x32,0x65,0x32,0x30,0x32,0x34,0x62,0x55,0x2c,0x30,0x78,0x65,0x33,0x35,0x37,0x38,0x66,0x31,0x66,0x55,0x2c,0x30,0x78,0x36,0x36,0x32,0x61, + 0x61,0x62,0x35,0x35,0x55,0x2c,0x0a,0x30,0x78,0x62,0x32,0x30,0x37,0x32,0x38,0x65,0x62,0x55,0x2c,0x30,0x78,0x32,0x66,0x30,0x33,0x63,0x32,0x62,0x35,0x55,0x2c,0x30, + 0x78,0x38,0x36,0x39,0x61,0x37,0x62,0x63,0x35,0x55,0x2c,0x30,0x78,0x64,0x33,0x61,0x35,0x30,0x38,0x33,0x37,0x55,0x2c,0x0a,0x30,0x78,0x33,0x30,0x66,0x32,0x38,0x37, + 0x32,0x38,0x55,0x2c,0x30,0x78,0x32,0x33,0x62,0x32,0x61,0x35,0x62,0x66,0x55,0x2c,0x30,0x78,0x30,0x32,0x62,0x61,0x36,0x61,0x30,0x33,0x55,0x2c,0x30,0x78,0x65,0x64, + 0x35,0x63,0x38,0x32,0x31,0x36,0x55,0x2c,0x0a,0x30,0x78,0x38,0x61,0x32,0x62,0x31,0x63,0x63,0x66,0x55,0x2c,0x30,0x78,0x61,0x37,0x39,0x32,0x62,0x34,0x37,0x39,0x55, + 0x2c,0x30,0x78,0x66,0x33,0x66,0x30,0x66,0x32,0x30,0x37,0x55,0x2c,0x30,0x78,0x34,0x65,0x61,0x31,0x65,0x32,0x36,0x39,0x55,0x2c,0x0a,0x30,0x78,0x36,0x35,0x63,0x64, + 0x66,0x34,0x64,0x61,0x55,0x2c,0x30,0x78,0x30,0x36,0x64,0x35,0x62,0x65,0x30,0x35,0x55,0x2c,0x30,0x78,0x64,0x31,0x31,0x66,0x36,0x32,0x33,0x34,0x55,0x2c,0x30,0x78, + 0x63,0x34,0x38,0x61,0x66,0x65,0x61,0x36,0x55,0x2c,0x0a,0x30,0x78,0x33,0x34,0x39,0x64,0x35,0x33,0x32,0x65,0x55,0x2c,0x30,0x78,0x61,0x32,0x61,0x30,0x35,0x35,0x66, + 0x33,0x55,0x2c,0x30,0x78,0x30,0x35,0x33,0x32,0x65,0x31,0x38,0x61,0x55,0x2c,0x30,0x78,0x61,0x34,0x37,0x35,0x65,0x62,0x66,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x62, + 0x33,0x39,0x65,0x63,0x38,0x33,0x55,0x2c,0x30,0x78,0x34,0x30,0x61,0x61,0x65,0x66,0x36,0x30,0x55,0x2c,0x30,0x78,0x35,0x65,0x30,0x36,0x39,0x66,0x37,0x31,0x55,0x2c, + 0x30,0x78,0x62,0x64,0x35,0x31,0x31,0x30,0x36,0x65,0x55,0x2c,0x0a,0x30,0x78,0x33,0x65,0x66,0x39,0x38,0x61,0x32,0x31,0x55,0x2c,0x30,0x78,0x39,0x36,0x33,0x64,0x30, + 0x36,0x64,0x64,0x55,0x2c,0x30,0x78,0x64,0x64,0x61,0x65,0x30,0x35,0x33,0x65,0x55,0x2c,0x30,0x78,0x34,0x64,0x34,0x36,0x62,0x64,0x65,0x36,0x55,0x2c,0x0a,0x30,0x78, + 0x39,0x31,0x62,0x35,0x38,0x64,0x35,0x34,0x55,0x2c,0x30,0x78,0x37,0x31,0x30,0x35,0x35,0x64,0x63,0x34,0x55,0x2c,0x30,0x78,0x30,0x34,0x36,0x66,0x64,0x34,0x30,0x36, + 0x55,0x2c,0x30,0x78,0x36,0x30,0x66,0x66,0x31,0x35,0x35,0x30,0x55,0x2c,0x0a,0x30,0x78,0x31,0x39,0x32,0x34,0x66,0x62,0x39,0x38,0x55,0x2c,0x30,0x78,0x64,0x36,0x39, + 0x37,0x65,0x39,0x62,0x64,0x55,0x2c,0x30,0x78,0x38,0x39,0x63,0x63,0x34,0x33,0x34,0x30,0x55,0x2c,0x30,0x78,0x36,0x37,0x37,0x37,0x39,0x65,0x64,0x39,0x55,0x2c,0x0a, + 0x30,0x78,0x62,0x30,0x62,0x64,0x34,0x32,0x65,0x38,0x55,0x2c,0x30,0x78,0x30,0x37,0x38,0x38,0x38,0x62,0x38,0x39,0x55,0x2c,0x30,0x78,0x65,0x37,0x33,0x38,0x35,0x62, + 0x31,0x39,0x55,0x2c,0x30,0x78,0x37,0x39,0x64,0x62,0x65,0x65,0x63,0x38,0x55,0x2c,0x0a,0x30,0x78,0x61,0x31,0x34,0x37,0x30,0x61,0x37,0x63,0x55,0x2c,0x30,0x78,0x37, + 0x63,0x65,0x39,0x30,0x66,0x34,0x32,0x55,0x2c,0x30,0x78,0x66,0x38,0x63,0x39,0x31,0x65,0x38,0x34,0x55,0x2c,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55, + 0x2c,0x0a,0x30,0x78,0x30,0x39,0x38,0x33,0x38,0x36,0x38,0x30,0x55,0x2c,0x30,0x78,0x33,0x32,0x34,0x38,0x65,0x64,0x32,0x62,0x55,0x2c,0x30,0x78,0x31,0x65,0x61,0x63, + 0x37,0x30,0x31,0x31,0x55,0x2c,0x30,0x78,0x36,0x63,0x34,0x65,0x37,0x32,0x35,0x61,0x55,0x2c,0x0a,0x30,0x78,0x66,0x64,0x66,0x62,0x66,0x66,0x30,0x65,0x55,0x2c,0x30, + 0x78,0x30,0x66,0x35,0x36,0x33,0x38,0x38,0x35,0x55,0x2c,0x30,0x78,0x33,0x64,0x31,0x65,0x64,0x35,0x61,0x65,0x55,0x2c,0x30,0x78,0x33,0x36,0x32,0x37,0x33,0x39,0x32, + 0x64,0x55,0x2c,0x0a,0x30,0x78,0x30,0x61,0x36,0x34,0x64,0x39,0x30,0x66,0x55,0x2c,0x30,0x78,0x36,0x38,0x32,0x31,0x61,0x36,0x35,0x63,0x55,0x2c,0x30,0x78,0x39,0x62, + 0x64,0x31,0x35,0x34,0x35,0x62,0x55,0x2c,0x30,0x78,0x32,0x34,0x33,0x61,0x32,0x65,0x33,0x36,0x55,0x2c,0x0a,0x30,0x78,0x30,0x63,0x62,0x31,0x36,0x37,0x30,0x61,0x55, + 0x2c,0x30,0x78,0x39,0x33,0x30,0x66,0x65,0x37,0x35,0x37,0x55,0x2c,0x30,0x78,0x62,0x34,0x64,0x32,0x39,0x36,0x65,0x65,0x55,0x2c,0x30,0x78,0x31,0x62,0x39,0x65,0x39, + 0x31,0x39,0x62,0x55,0x2c,0x0a,0x30,0x78,0x38,0x30,0x34,0x66,0x63,0x35,0x63,0x30,0x55,0x2c,0x30,0x78,0x36,0x31,0x61,0x32,0x32,0x30,0x64,0x63,0x55,0x2c,0x30,0x78, + 0x35,0x61,0x36,0x39,0x34,0x62,0x37,0x37,0x55,0x2c,0x30,0x78,0x31,0x63,0x31,0x36,0x31,0x61,0x31,0x32,0x55,0x2c,0x0a,0x30,0x78,0x65,0x32,0x30,0x61,0x62,0x61,0x39, + 0x33,0x55,0x2c,0x30,0x78,0x63,0x30,0x65,0x35,0x32,0x61,0x61,0x30,0x55,0x2c,0x30,0x78,0x33,0x63,0x34,0x33,0x65,0x30,0x32,0x32,0x55,0x2c,0x30,0x78,0x31,0x32,0x31, + 0x64,0x31,0x37,0x31,0x62,0x55,0x2c,0x0a,0x30,0x78,0x30,0x65,0x30,0x62,0x30,0x64,0x30,0x39,0x55,0x2c,0x30,0x78,0x66,0x32,0x61,0x64,0x63,0x37,0x38,0x62,0x55,0x2c, + 0x30,0x78,0x32,0x64,0x62,0x39,0x61,0x38,0x62,0x36,0x55,0x2c,0x30,0x78,0x31,0x34,0x63,0x38,0x61,0x39,0x31,0x65,0x55,0x2c,0x0a,0x30,0x78,0x35,0x37,0x38,0x35,0x31, + 0x39,0x66,0x31,0x55,0x2c,0x30,0x78,0x61,0x66,0x34,0x63,0x30,0x37,0x37,0x35,0x55,0x2c,0x30,0x78,0x65,0x65,0x62,0x62,0x64,0x64,0x39,0x39,0x55,0x2c,0x30,0x78,0x61, + 0x33,0x66,0x64,0x36,0x30,0x37,0x66,0x55,0x2c,0x0a,0x30,0x78,0x66,0x37,0x39,0x66,0x32,0x36,0x30,0x31,0x55,0x2c,0x30,0x78,0x35,0x63,0x62,0x63,0x66,0x35,0x37,0x32, + 0x55,0x2c,0x30,0x78,0x34,0x34,0x63,0x35,0x33,0x62,0x36,0x36,0x55,0x2c,0x30,0x78,0x35,0x62,0x33,0x34,0x37,0x65,0x66,0x62,0x55,0x2c,0x0a,0x30,0x78,0x38,0x62,0x37, + 0x36,0x32,0x39,0x34,0x33,0x55,0x2c,0x30,0x78,0x63,0x62,0x64,0x63,0x63,0x36,0x32,0x33,0x55,0x2c,0x30,0x78,0x62,0x36,0x36,0x38,0x66,0x63,0x65,0x64,0x55,0x2c,0x30, + 0x78,0x62,0x38,0x36,0x33,0x66,0x31,0x65,0x34,0x55,0x2c,0x0a,0x30,0x78,0x64,0x37,0x63,0x61,0x64,0x63,0x33,0x31,0x55,0x2c,0x30,0x78,0x34,0x32,0x31,0x30,0x38,0x35, + 0x36,0x33,0x55,0x2c,0x30,0x78,0x31,0x33,0x34,0x30,0x32,0x32,0x39,0x37,0x55,0x2c,0x30,0x78,0x38,0x34,0x32,0x30,0x31,0x31,0x63,0x36,0x55,0x2c,0x0a,0x30,0x78,0x38, + 0x35,0x37,0x64,0x32,0x34,0x34,0x61,0x55,0x2c,0x30,0x78,0x64,0x32,0x66,0x38,0x33,0x64,0x62,0x62,0x55,0x2c,0x30,0x78,0x61,0x65,0x31,0x31,0x33,0x32,0x66,0x39,0x55, + 0x2c,0x30,0x78,0x63,0x37,0x36,0x64,0x61,0x31,0x32,0x39,0x55,0x2c,0x0a,0x30,0x78,0x31,0x64,0x34,0x62,0x32,0x66,0x39,0x65,0x55,0x2c,0x30,0x78,0x64,0x63,0x66,0x33, + 0x33,0x30,0x62,0x32,0x55,0x2c,0x30,0x78,0x30,0x64,0x65,0x63,0x35,0x32,0x38,0x36,0x55,0x2c,0x30,0x78,0x37,0x37,0x64,0x30,0x65,0x33,0x63,0x31,0x55,0x2c,0x0a,0x30, + 0x78,0x32,0x62,0x36,0x63,0x31,0x36,0x62,0x33,0x55,0x2c,0x30,0x78,0x61,0x39,0x39,0x39,0x62,0x39,0x37,0x30,0x55,0x2c,0x30,0x78,0x31,0x31,0x66,0x61,0x34,0x38,0x39, + 0x34,0x55,0x2c,0x30,0x78,0x34,0x37,0x32,0x32,0x36,0x34,0x65,0x39,0x55,0x2c,0x0a,0x30,0x78,0x61,0x38,0x63,0x34,0x38,0x63,0x66,0x63,0x55,0x2c,0x30,0x78,0x61,0x30, + 0x31,0x61,0x33,0x66,0x66,0x30,0x55,0x2c,0x30,0x78,0x35,0x36,0x64,0x38,0x32,0x63,0x37,0x64,0x55,0x2c,0x30,0x78,0x32,0x32,0x65,0x66,0x39,0x30,0x33,0x33,0x55,0x2c, + 0x0a,0x30,0x78,0x38,0x37,0x63,0x37,0x34,0x65,0x34,0x39,0x55,0x2c,0x30,0x78,0x64,0x39,0x63,0x31,0x64,0x31,0x33,0x38,0x55,0x2c,0x30,0x78,0x38,0x63,0x66,0x65,0x61, + 0x32,0x63,0x61,0x55,0x2c,0x30,0x78,0x39,0x38,0x33,0x36,0x30,0x62,0x64,0x34,0x55,0x2c,0x0a,0x30,0x78,0x61,0x36,0x63,0x66,0x38,0x31,0x66,0x35,0x55,0x2c,0x30,0x78, + 0x61,0x35,0x32,0x38,0x64,0x65,0x37,0x61,0x55,0x2c,0x30,0x78,0x64,0x61,0x32,0x36,0x38,0x65,0x62,0x37,0x55,0x2c,0x30,0x78,0x33,0x66,0x61,0x34,0x62,0x66,0x61,0x64, + 0x55,0x2c,0x0a,0x30,0x78,0x32,0x63,0x65,0x34,0x39,0x64,0x33,0x61,0x55,0x2c,0x30,0x78,0x35,0x30,0x30,0x64,0x39,0x32,0x37,0x38,0x55,0x2c,0x30,0x78,0x36,0x61,0x39, + 0x62,0x63,0x63,0x35,0x66,0x55,0x2c,0x30,0x78,0x35,0x34,0x36,0x32,0x34,0x36,0x37,0x65,0x55,0x2c,0x0a,0x30,0x78,0x66,0x36,0x63,0x32,0x31,0x33,0x38,0x64,0x55,0x2c, + 0x30,0x78,0x39,0x30,0x65,0x38,0x62,0x38,0x64,0x38,0x55,0x2c,0x30,0x78,0x32,0x65,0x35,0x65,0x66,0x37,0x33,0x39,0x55,0x2c,0x30,0x78,0x38,0x32,0x66,0x35,0x61,0x66, + 0x63,0x33,0x55,0x2c,0x0a,0x30,0x78,0x39,0x66,0x62,0x65,0x38,0x30,0x35,0x64,0x55,0x2c,0x30,0x78,0x36,0x39,0x37,0x63,0x39,0x33,0x64,0x30,0x55,0x2c,0x30,0x78,0x36, + 0x66,0x61,0x39,0x32,0x64,0x64,0x35,0x55,0x2c,0x30,0x78,0x63,0x66,0x62,0x33,0x31,0x32,0x32,0x35,0x55,0x2c,0x0a,0x30,0x78,0x63,0x38,0x33,0x62,0x39,0x39,0x61,0x63, + 0x55,0x2c,0x30,0x78,0x31,0x30,0x61,0x37,0x37,0x64,0x31,0x38,0x55,0x2c,0x30,0x78,0x65,0x38,0x36,0x65,0x36,0x33,0x39,0x63,0x55,0x2c,0x30,0x78,0x64,0x62,0x37,0x62, + 0x62,0x62,0x33,0x62,0x55,0x2c,0x0a,0x30,0x78,0x63,0x64,0x30,0x39,0x37,0x38,0x32,0x36,0x55,0x2c,0x30,0x78,0x36,0x65,0x66,0x34,0x31,0x38,0x35,0x39,0x55,0x2c,0x30, + 0x78,0x65,0x63,0x30,0x31,0x62,0x37,0x39,0x61,0x55,0x2c,0x30,0x78,0x38,0x33,0x61,0x38,0x39,0x61,0x34,0x66,0x55,0x2c,0x0a,0x30,0x78,0x65,0x36,0x36,0x35,0x36,0x65, + 0x39,0x35,0x55,0x2c,0x30,0x78,0x61,0x61,0x37,0x65,0x65,0x36,0x66,0x66,0x55,0x2c,0x30,0x78,0x32,0x31,0x30,0x38,0x63,0x66,0x62,0x63,0x55,0x2c,0x30,0x78,0x65,0x66, + 0x65,0x36,0x65,0x38,0x31,0x35,0x55,0x2c,0x0a,0x30,0x78,0x62,0x61,0x64,0x39,0x39,0x62,0x65,0x37,0x55,0x2c,0x30,0x78,0x34,0x61,0x63,0x65,0x33,0x36,0x36,0x66,0x55, + 0x2c,0x30,0x78,0x65,0x61,0x64,0x34,0x30,0x39,0x39,0x66,0x55,0x2c,0x30,0x78,0x32,0x39,0x64,0x36,0x37,0x63,0x62,0x30,0x55,0x2c,0x0a,0x30,0x78,0x33,0x31,0x61,0x66, + 0x62,0x32,0x61,0x34,0x55,0x2c,0x30,0x78,0x32,0x61,0x33,0x31,0x32,0x33,0x33,0x66,0x55,0x2c,0x30,0x78,0x63,0x36,0x33,0x30,0x39,0x34,0x61,0x35,0x55,0x2c,0x30,0x78, + 0x33,0x35,0x63,0x30,0x36,0x36,0x61,0x32,0x55,0x2c,0x0a,0x30,0x78,0x37,0x34,0x33,0x37,0x62,0x63,0x34,0x65,0x55,0x2c,0x30,0x78,0x66,0x63,0x61,0x36,0x63,0x61,0x38, + 0x32,0x55,0x2c,0x30,0x78,0x65,0x30,0x62,0x30,0x64,0x30,0x39,0x30,0x55,0x2c,0x30,0x78,0x33,0x33,0x31,0x35,0x64,0x38,0x61,0x37,0x55,0x2c,0x0a,0x30,0x78,0x66,0x31, + 0x34,0x61,0x39,0x38,0x30,0x34,0x55,0x2c,0x30,0x78,0x34,0x31,0x66,0x37,0x64,0x61,0x65,0x63,0x55,0x2c,0x30,0x78,0x37,0x66,0x30,0x65,0x35,0x30,0x63,0x64,0x55,0x2c, + 0x30,0x78,0x31,0x37,0x32,0x66,0x66,0x36,0x39,0x31,0x55,0x2c,0x0a,0x30,0x78,0x37,0x36,0x38,0x64,0x64,0x36,0x34,0x64,0x55,0x2c,0x30,0x78,0x34,0x33,0x34,0x64,0x62, + 0x30,0x65,0x66,0x55,0x2c,0x30,0x78,0x63,0x63,0x35,0x34,0x34,0x64,0x61,0x61,0x55,0x2c,0x30,0x78,0x65,0x34,0x64,0x66,0x30,0x34,0x39,0x36,0x55,0x2c,0x0a,0x30,0x78, + 0x39,0x65,0x65,0x33,0x62,0x35,0x64,0x31,0x55,0x2c,0x30,0x78,0x34,0x63,0x31,0x62,0x38,0x38,0x36,0x61,0x55,0x2c,0x30,0x78,0x63,0x31,0x62,0x38,0x31,0x66,0x32,0x63, + 0x55,0x2c,0x30,0x78,0x34,0x36,0x37,0x66,0x35,0x31,0x36,0x35,0x55,0x2c,0x0a,0x30,0x78,0x39,0x64,0x30,0x34,0x65,0x61,0x35,0x65,0x55,0x2c,0x30,0x78,0x30,0x31,0x35, + 0x64,0x33,0x35,0x38,0x63,0x55,0x2c,0x30,0x78,0x66,0x61,0x37,0x33,0x37,0x34,0x38,0x37,0x55,0x2c,0x30,0x78,0x66,0x62,0x32,0x65,0x34,0x31,0x30,0x62,0x55,0x2c,0x0a, + 0x30,0x78,0x62,0x33,0x35,0x61,0x31,0x64,0x36,0x37,0x55,0x2c,0x30,0x78,0x39,0x32,0x35,0x32,0x64,0x32,0x64,0x62,0x55,0x2c,0x30,0x78,0x65,0x39,0x33,0x33,0x35,0x36, + 0x31,0x30,0x55,0x2c,0x30,0x78,0x36,0x64,0x31,0x33,0x34,0x37,0x64,0x36,0x55,0x2c,0x0a,0x30,0x78,0x39,0x61,0x38,0x63,0x36,0x31,0x64,0x37,0x55,0x2c,0x30,0x78,0x33, + 0x37,0x37,0x61,0x30,0x63,0x61,0x31,0x55,0x2c,0x30,0x78,0x35,0x39,0x38,0x65,0x31,0x34,0x66,0x38,0x55,0x2c,0x30,0x78,0x65,0x62,0x38,0x39,0x33,0x63,0x31,0x33,0x55, + 0x2c,0x0a,0x30,0x78,0x63,0x65,0x65,0x65,0x32,0x37,0x61,0x39,0x55,0x2c,0x30,0x78,0x62,0x37,0x33,0x35,0x63,0x39,0x36,0x31,0x55,0x2c,0x30,0x78,0x65,0x31,0x65,0x64, + 0x65,0x35,0x31,0x63,0x55,0x2c,0x30,0x78,0x37,0x61,0x33,0x63,0x62,0x31,0x34,0x37,0x55,0x2c,0x0a,0x30,0x78,0x39,0x63,0x35,0x39,0x64,0x66,0x64,0x32,0x55,0x2c,0x30, + 0x78,0x35,0x35,0x33,0x66,0x37,0x33,0x66,0x32,0x55,0x2c,0x30,0x78,0x31,0x38,0x37,0x39,0x63,0x65,0x31,0x34,0x55,0x2c,0x30,0x78,0x37,0x33,0x62,0x66,0x33,0x37,0x63, + 0x37,0x55,0x2c,0x0a,0x30,0x78,0x35,0x33,0x65,0x61,0x63,0x64,0x66,0x37,0x55,0x2c,0x30,0x78,0x35,0x66,0x35,0x62,0x61,0x61,0x66,0x64,0x55,0x2c,0x30,0x78,0x64,0x66, + 0x31,0x34,0x36,0x66,0x33,0x64,0x55,0x2c,0x30,0x78,0x37,0x38,0x38,0x36,0x64,0x62,0x34,0x34,0x55,0x2c,0x0a,0x30,0x78,0x63,0x61,0x38,0x31,0x66,0x33,0x61,0x66,0x55, + 0x2c,0x30,0x78,0x62,0x39,0x33,0x65,0x63,0x34,0x36,0x38,0x55,0x2c,0x30,0x78,0x33,0x38,0x32,0x63,0x33,0x34,0x32,0x34,0x55,0x2c,0x30,0x78,0x63,0x32,0x35,0x66,0x34, + 0x30,0x61,0x33,0x55,0x2c,0x0a,0x30,0x78,0x31,0x36,0x37,0x32,0x63,0x33,0x31,0x64,0x55,0x2c,0x30,0x78,0x62,0x63,0x30,0x63,0x32,0x35,0x65,0x32,0x55,0x2c,0x30,0x78, + 0x32,0x38,0x38,0x62,0x34,0x39,0x33,0x63,0x55,0x2c,0x30,0x78,0x66,0x66,0x34,0x31,0x39,0x35,0x30,0x64,0x55,0x2c,0x0a,0x30,0x78,0x33,0x39,0x37,0x31,0x30,0x31,0x61, + 0x38,0x55,0x2c,0x30,0x78,0x30,0x38,0x64,0x65,0x62,0x33,0x30,0x63,0x55,0x2c,0x30,0x78,0x64,0x38,0x39,0x63,0x65,0x34,0x62,0x34,0x55,0x2c,0x30,0x78,0x36,0x34,0x39, + 0x30,0x63,0x31,0x35,0x36,0x55,0x2c,0x0a,0x30,0x78,0x37,0x62,0x36,0x31,0x38,0x34,0x63,0x62,0x55,0x2c,0x30,0x78,0x64,0x35,0x37,0x30,0x62,0x36,0x33,0x32,0x55,0x2c, + 0x30,0x78,0x34,0x38,0x37,0x34,0x35,0x63,0x36,0x63,0x55,0x2c,0x30,0x78,0x64,0x30,0x34,0x32,0x35,0x37,0x62,0x38,0x55,0x2c,0x0a,0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f, + 0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59, + 0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x30,0x78,0x36,0x64,0x61,0x63,0x61,0x35,0x35,0x33,0x2c,0x30,0x78,0x36,0x32,0x37,0x31,0x36,0x36,0x30, + 0x39,0x2c,0x30,0x78,0x64,0x62,0x62,0x35,0x35,0x35,0x32,0x62,0x2c,0x30,0x78,0x62,0x34,0x66,0x34,0x34,0x39,0x31,0x37,0x2c,0x0a,0x30,0x78,0x36,0x64,0x37,0x63,0x61, + 0x66,0x30,0x37,0x2c,0x30,0x78,0x38,0x34,0x36,0x61,0x37,0x31,0x30,0x64,0x2c,0x30,0x78,0x31,0x37,0x32,0x35,0x64,0x33,0x37,0x38,0x2c,0x30,0x78,0x30,0x64,0x61,0x31, + 0x64,0x63,0x34,0x65,0x2c,0x0a,0x30,0x78,0x33,0x66,0x31,0x32,0x36,0x32,0x66,0x31,0x2c,0x30,0x78,0x39,0x66,0x39,0x34,0x37,0x65,0x63,0x36,0x2c,0x30,0x78,0x66,0x34, + 0x63,0x30,0x37,0x39,0x34,0x66,0x2c,0x30,0x78,0x33,0x65,0x32,0x30,0x65,0x33,0x34,0x35,0x2c,0x0a,0x30,0x78,0x36,0x61,0x65,0x66,0x38,0x31,0x33,0x35,0x2c,0x30,0x78, + 0x62,0x31,0x62,0x61,0x33,0x31,0x37,0x63,0x2c,0x30,0x78,0x31,0x36,0x33,0x31,0x34,0x63,0x38,0x38,0x2c,0x30,0x78,0x34,0x39,0x31,0x36,0x39,0x31,0x35,0x34,0x2c,0x0a, + 0x7d,0x3b,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x41,0x45,0x53,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x48,0x41,0x53,0x48,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x30,0x78,0x39,0x32,0x62,0x35,0x32,0x63,0x30,0x64,0x2c, + 0x30,0x78,0x39,0x66,0x61,0x38,0x35,0x36,0x64,0x65,0x2c,0x30,0x78,0x63,0x63,0x38,0x32,0x64,0x62,0x34,0x37,0x2c,0x30,0x78,0x64,0x37,0x39,0x38,0x33,0x61,0x61,0x64, + 0x2c,0x0a,0x30,0x78,0x33,0x33,0x38,0x64,0x39,0x39,0x36,0x65,0x2c,0x30,0x78,0x31,0x35,0x63,0x37,0x62,0x37,0x39,0x38,0x2c,0x30,0x78,0x66,0x35,0x39,0x65,0x31,0x32, + 0x35,0x61,0x2c,0x30,0x78,0x61,0x63,0x65,0x37,0x38,0x30,0x35,0x37,0x2c,0x0a,0x30,0x78,0x36,0x61,0x37,0x37,0x30,0x30,0x31,0x37,0x2c,0x30,0x78,0x61,0x65,0x36,0x32, + 0x63,0x37,0x64,0x30,0x2c,0x30,0x78,0x35,0x30,0x37,0x39,0x35,0x30,0x36,0x62,0x2c,0x30,0x78,0x65,0x38,0x61,0x30,0x37,0x63,0x65,0x34,0x2c,0x0a,0x30,0x78,0x36,0x33, + 0x30,0x61,0x32,0x34,0x30,0x63,0x2c,0x30,0x78,0x30,0x37,0x61,0x64,0x38,0x32,0x38,0x64,0x2c,0x30,0x78,0x37,0x39,0x61,0x31,0x30,0x30,0x30,0x35,0x2c,0x30,0x78,0x37, + 0x65,0x39,0x39,0x34,0x39,0x34,0x38,0x2c,0x0a,0x7d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x75,0x69,0x6e,0x74, + 0x20,0x61,0x2c,0x75,0x69,0x6e,0x74,0x20,0x73,0x74,0x61,0x72,0x74,0x5f,0x62,0x69,0x74,0x29,0x20,0x7b,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x61,0x3e,0x3e, + 0x73,0x74,0x61,0x72,0x74,0x5f,0x62,0x69,0x74,0x29,0x26,0x30,0x78,0x46,0x46,0x3b,0x20,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x66,0x69,0x6c,0x6c,0x41, + 0x65,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x31,0x52,0x78,0x34,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43, + 0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x30,0x20,0x28,0x6f,0x75,0x74, + 0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x20,0x2b,0x20,0x36,0x34,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x5f,0x66,0x61,0x63, + 0x74,0x6f,0x72,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x73,0x20,0x31,0x0a,0x5f,0x5f,0x61,0x74,0x74, + 0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36, + 0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x5f,0x6e, + 0x61,0x6d,0x65,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x73,0x74,0x61,0x74,0x65,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x6f,0x75,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x75,0x69,0x6e,0x74, + 0x20,0x72,0x78,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x54,0x5b,0x32,0x30, + 0x34,0x38,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d, + 0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2a,0x34,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x69,0x64,0x78,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2f,0x34,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x73,0x75,0x62,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x20,0x25,0x20,0x34,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20, + 0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x73,0x74,0x65,0x70,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x30,0x34,0x38,0x3b,0x20,0x69,0x2b,0x3d,0x73,0x74,0x65,0x70,0x29,0x0a,0x54,0x5b,0x69,0x5d,0x3d, + 0x41,0x45,0x53,0x5f,0x54,0x41,0x42,0x4c,0x45,0x5b,0x69,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f, + 0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x73,0x20,0x21,0x3d,0x20,0x34,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x5b,0x34,0x5d,0x3d,0x7b,0x20,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73, + 0x75,0x62,0x2a,0x34,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x31,0x5d,0x2c,0x41,0x45,0x53,0x5f, + 0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x32,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73, + 0x75,0x62,0x2a,0x34,0x2b,0x33,0x5d,0x20,0x7d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x62,0x31,0x3d,0x28, + 0x72,0x78,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3c,0x31,0x30,0x34,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x62,0x32,0x3d,0x28, + 0x73,0x75,0x62,0x3c,0x32,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x6b,0x5b,0x31,0x36,0x5d,0x3b,0x0a,0x6b,0x5b,0x20,0x30,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x66, + 0x38,0x39,0x30,0x34,0x36,0x35,0x64,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x36,0x34,0x32,0x31,0x61,0x61,0x64,0x64,0x75,0x3a,0x30,0x78,0x62,0x35,0x38,0x32,0x36, + 0x66,0x37,0x33,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x31,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x37,0x66,0x66,0x62,0x65,0x34,0x61,0x36,0x75,0x3a,0x28,0x62,0x32,0x3f, + 0x30,0x78,0x64,0x31,0x38,0x33,0x33,0x64,0x64,0x62,0x75,0x3a,0x30,0x78,0x65,0x33,0x64,0x36,0x61,0x37,0x61,0x36,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x32,0x5d,0x3d, + 0x62,0x31,0x3f,0x30,0x78,0x31,0x34,0x31,0x66,0x38,0x32,0x62,0x37,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x32,0x66,0x35,0x34,0x36,0x64,0x32,0x62,0x75,0x3a,0x30, + 0x78,0x33,0x64,0x35,0x31,0x38,0x62,0x36,0x64,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x33,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x63,0x66,0x33,0x35,0x39,0x65,0x39,0x35, + 0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x39,0x39,0x65,0x35,0x64,0x32,0x33,0x66,0x75,0x3a,0x30,0x78,0x32,0x32,0x39,0x65,0x66,0x66,0x62,0x34,0x75,0x29,0x3b,0x0a, + 0x6b,0x5b,0x20,0x34,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x36,0x61,0x35,0x35,0x63,0x34,0x35,0x30,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x62,0x32,0x30,0x65,0x33, + 0x34,0x35,0x30,0x75,0x3a,0x30,0x78,0x63,0x37,0x35,0x36,0x36,0x62,0x66,0x33,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x35,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x66,0x65, + 0x65,0x38,0x32,0x37,0x38,0x61,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x62,0x36,0x39,0x31,0x33,0x66,0x35,0x35,0x75,0x3a,0x30,0x78,0x39,0x63,0x31,0x30,0x62,0x33, + 0x64,0x39,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x36,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x62,0x64,0x35,0x63,0x35,0x61,0x63,0x33,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30, + 0x78,0x30,0x36,0x66,0x37,0x39,0x64,0x35,0x33,0x75,0x3a,0x30,0x78,0x65,0x39,0x30,0x32,0x34,0x64,0x34,0x65,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x37,0x5d,0x3d,0x62, + 0x31,0x3f,0x30,0x78,0x36,0x37,0x34,0x31,0x66,0x66,0x64,0x63,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x61,0x35,0x64,0x66,0x63,0x64,0x65,0x35,0x75,0x3a,0x30,0x78, + 0x62,0x32,0x37,0x32,0x62,0x37,0x64,0x32,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x38,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x31,0x31,0x34,0x63,0x34,0x37,0x61,0x34,0x75, + 0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x35,0x63,0x33,0x65,0x64,0x39,0x30,0x34,0x75,0x3a,0x30,0x78,0x66,0x32,0x37,0x33,0x63,0x39,0x65,0x37,0x75,0x29,0x3b,0x0a,0x6b, + 0x5b,0x20,0x39,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x64,0x35,0x32,0x34,0x66,0x64,0x65,0x34,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x35,0x31,0x35,0x65,0x37,0x62, + 0x61,0x66,0x75,0x3a,0x30,0x78,0x66,0x37,0x36,0x35,0x61,0x33,0x38,0x62,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x30,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x61,0x37,0x32, + 0x37,0x39,0x61,0x64,0x32,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x30,0x61,0x61,0x34,0x36,0x37,0x39,0x66,0x75,0x3a,0x30,0x78,0x32,0x62,0x61,0x39,0x36,0x36,0x30, + 0x61,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x31,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x33,0x64,0x33,0x32,0x34,0x61,0x61,0x63,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78, + 0x31,0x37,0x31,0x63,0x30,0x32,0x62,0x66,0x75,0x3a,0x30,0x78,0x66,0x36,0x33,0x62,0x65,0x66,0x61,0x37,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x32,0x5d,0x3d,0x62,0x31, + 0x3f,0x30,0x78,0x38,0x31,0x30,0x63,0x33,0x61,0x32,0x61,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x38,0x35,0x36,0x32,0x33,0x37,0x36,0x33,0x75,0x3a,0x30,0x78,0x37, + 0x61,0x37,0x63,0x64,0x36,0x30,0x39,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x33,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x39,0x39,0x61,0x39,0x61,0x65,0x66,0x66,0x75,0x3a, + 0x28,0x62,0x32,0x3f,0x30,0x78,0x65,0x37,0x38,0x66,0x35,0x64,0x30,0x38,0x75,0x3a,0x30,0x78,0x39,0x31,0x35,0x38,0x33,0x39,0x64,0x65,0x75,0x29,0x3b,0x0a,0x6b,0x5b, + 0x31,0x34,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x34,0x32,0x64,0x33,0x64,0x62,0x64,0x39,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x63,0x64,0x36,0x37,0x33,0x37,0x38, + 0x35,0x75,0x3a,0x30,0x78,0x30,0x63,0x30,0x36,0x64,0x31,0x66,0x64,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x35,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x37,0x36,0x66,0x36, + 0x64,0x62,0x30,0x38,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x64,0x38,0x64,0x65,0x64,0x32,0x39,0x31,0x75,0x3a,0x30,0x78,0x63,0x30,0x62,0x30,0x37,0x36,0x32,0x64, + 0x75,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x73,0x3d,0x28,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x20,0x73,0x74,0x61,0x74,0x65,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x36,0x34,0x2f,0x73,0x69,0x7a, + 0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x29,0x2b,0x73,0x75,0x62,0x2a,0x28,0x31,0x36,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x29, + 0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x78,0x5b,0x34,0x5d,0x3d,0x7b,0x20,0x73,0x5b,0x30,0x5d,0x2c,0x73,0x5b,0x31,0x5d,0x2c,0x73,0x5b,0x32,0x5d,0x2c,0x73,0x5b,0x33, + 0x5d,0x20,0x7d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x31,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x38,0x3a,0x32,0x34,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x33,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x32,0x34,0x3a,0x38,0x3b,0x0a,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x70,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a, + 0x29,0x20,0x6f,0x75,0x74,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x30,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75, + 0x69,0x6e,0x74,0x34,0x29,0x29,0x2b,0x73,0x75,0x62,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x30,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x54,0x3a,0x28,0x54,0x2b,0x31,0x30,0x32,0x34,0x29,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x31,0x3d,0x28,0x73,0x75,0x62,0x26,0x31, + 0x29,0x3f,0x28,0x54,0x2b,0x32,0x35,0x36,0x29,0x3a,0x28,0x54,0x2b,0x31,0x37,0x39,0x32,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x32,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x28,0x54,0x2b,0x35,0x31,0x32,0x29, + 0x3a,0x28,0x54,0x2b,0x31,0x35,0x33,0x36,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x74,0x33,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x28,0x54,0x2b,0x37,0x36,0x38,0x29,0x3a,0x28,0x54,0x2b,0x31,0x32,0x38,0x30,0x29, + 0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x5f,0x66,0x61,0x63,0x74,0x6f,0x72,0x29,0x0a, + 0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x2f,0x73,0x69,0x7a,0x65, + 0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x3b,0x20,0x69,0x2b,0x3d,0x34,0x2c,0x70,0x2b,0x3d,0x34,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x79,0x5b,0x34, + 0x5d,0x3b,0x0a,0x23,0x69,0x66,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x73,0x20,0x21,0x3d,0x20,0x34,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36, + 0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x30,0x5d,0x3b, + 0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c, + 0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b, + 0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74, + 0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x32,0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d, + 0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x33,0x5d,0x3b,0x0a,0x2a, + 0x70,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x79,0x29,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x79,0x5b,0x30,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d, + 0x79,0x5b,0x31,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x79,0x5b,0x32,0x5d,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d,0x79,0x5b,0x33,0x5d,0x3b,0x0a,0x23,0x65,0x6c,0x73, + 0x65,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31, + 0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d, + 0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x30,0x5d,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28, + 0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d, + 0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x31,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33, + 0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31, + 0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x32, + 0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74, + 0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32, + 0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x33,0x5d,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x79,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29, + 0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x34,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x74,0x30, + 0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c, + 0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20, + 0x35,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e, + 0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b, + 0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x36,0x5d,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33, + 0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x31, + 0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65, + 0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x37,0x5d,0x3b,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74, + 0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d, + 0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b, + 0x20,0x38,0x5d,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x39,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73, + 0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d, + 0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31, + 0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b, + 0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x30,0x29, + 0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28, + 0x79,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x32,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c, + 0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x33,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d, + 0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b, + 0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e, + 0x6b,0x5b,0x31,0x34,0x5d,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x30, + 0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65, + 0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x35,0x5d,0x3b,0x0a,0x2a,0x70,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x78, + 0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x73, + 0x29,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x78,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75, + 0x6e,0x64,0x73,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x5f,0x66,0x61,0x63,0x74,0x6f,0x72,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20, + 0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x30,0x0a,0x23,0x75, + 0x6e,0x64,0x65,0x66,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65, + 0x73,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x34,0x52,0x78,0x34,0x5f,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x20,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x30,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x5f,0x66,0x61,0x63,0x74,0x6f,0x72,0x20,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f, + 0x75,0x6e,0x64,0x73,0x20,0x34,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f, + 0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f, + 0x69,0x64,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x73, + 0x74,0x61,0x74,0x65,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x6f,0x75,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74, + 0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x75,0x69,0x6e,0x74,0x20,0x72,0x78,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x54,0x5b,0x32,0x30,0x34,0x38,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2a,0x34,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2f,0x34,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x75,0x62,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x20,0x25,0x20,0x34, + 0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x73,0x74, + 0x65,0x70,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x30,0x34,0x38,0x3b,0x20,0x69,0x2b, + 0x3d,0x73,0x74,0x65,0x70,0x29,0x0a,0x54,0x5b,0x69,0x5d,0x3d,0x41,0x45,0x53,0x5f,0x54,0x41,0x42,0x4c,0x45,0x5b,0x69,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65, + 0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x6e,0x75,0x6d,0x5f, + 0x72,0x6f,0x75,0x6e,0x64,0x73,0x20,0x21,0x3d,0x20,0x34,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6b,0x5b,0x34,0x5d,0x3d,0x7b,0x20,0x41,0x45, + 0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73,0x75,0x62,0x2a,0x34,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73, + 0x75,0x62,0x2a,0x34,0x2b,0x31,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x32,0x5d,0x2c,0x41,0x45, + 0x53,0x5f,0x4b,0x45,0x59,0x5f,0x46,0x49,0x4c,0x4c,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x33,0x5d,0x20,0x7d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x62,0x31,0x3d,0x28,0x72,0x78,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3c,0x31,0x30,0x34,0x29,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x62,0x32,0x3d,0x28,0x73,0x75,0x62,0x3c,0x32,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x6b,0x5b,0x31,0x36,0x5d,0x3b,0x0a, + 0x6b,0x5b,0x20,0x30,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x66,0x38,0x39,0x30,0x34,0x36,0x35,0x64,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x36,0x34,0x32,0x31,0x61, + 0x61,0x64,0x64,0x75,0x3a,0x30,0x78,0x62,0x35,0x38,0x32,0x36,0x66,0x37,0x33,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x31,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x37,0x66, + 0x66,0x62,0x65,0x34,0x61,0x36,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x64,0x31,0x38,0x33,0x33,0x64,0x64,0x62,0x75,0x3a,0x30,0x78,0x65,0x33,0x64,0x36,0x61,0x37, + 0x61,0x36,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x32,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x31,0x34,0x31,0x66,0x38,0x32,0x62,0x37,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30, + 0x78,0x32,0x66,0x35,0x34,0x36,0x64,0x32,0x62,0x75,0x3a,0x30,0x78,0x33,0x64,0x35,0x31,0x38,0x62,0x36,0x64,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x33,0x5d,0x3d,0x62, + 0x31,0x3f,0x30,0x78,0x63,0x66,0x33,0x35,0x39,0x65,0x39,0x35,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x39,0x39,0x65,0x35,0x64,0x32,0x33,0x66,0x75,0x3a,0x30,0x78, + 0x32,0x32,0x39,0x65,0x66,0x66,0x62,0x34,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x34,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x36,0x61,0x35,0x35,0x63,0x34,0x35,0x30,0x75, + 0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x62,0x32,0x30,0x65,0x33,0x34,0x35,0x30,0x75,0x3a,0x30,0x78,0x63,0x37,0x35,0x36,0x36,0x62,0x66,0x33,0x75,0x29,0x3b,0x0a,0x6b, + 0x5b,0x20,0x35,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x66,0x65,0x65,0x38,0x32,0x37,0x38,0x61,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x62,0x36,0x39,0x31,0x33,0x66, + 0x35,0x35,0x75,0x3a,0x30,0x78,0x39,0x63,0x31,0x30,0x62,0x33,0x64,0x39,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x36,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x62,0x64,0x35, + 0x63,0x35,0x61,0x63,0x33,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x30,0x36,0x66,0x37,0x39,0x64,0x35,0x33,0x75,0x3a,0x30,0x78,0x65,0x39,0x30,0x32,0x34,0x64,0x34, + 0x65,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x37,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x36,0x37,0x34,0x31,0x66,0x66,0x64,0x63,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78, + 0x61,0x35,0x64,0x66,0x63,0x64,0x65,0x35,0x75,0x3a,0x30,0x78,0x62,0x32,0x37,0x32,0x62,0x37,0x64,0x32,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x38,0x5d,0x3d,0x62,0x31, + 0x3f,0x30,0x78,0x31,0x31,0x34,0x63,0x34,0x37,0x61,0x34,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x35,0x63,0x33,0x65,0x64,0x39,0x30,0x34,0x75,0x3a,0x30,0x78,0x66, + 0x32,0x37,0x33,0x63,0x39,0x65,0x37,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x20,0x39,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x64,0x35,0x32,0x34,0x66,0x64,0x65,0x34,0x75,0x3a, + 0x28,0x62,0x32,0x3f,0x30,0x78,0x35,0x31,0x35,0x65,0x37,0x62,0x61,0x66,0x75,0x3a,0x30,0x78,0x66,0x37,0x36,0x35,0x61,0x33,0x38,0x62,0x75,0x29,0x3b,0x0a,0x6b,0x5b, + 0x31,0x30,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x61,0x37,0x32,0x37,0x39,0x61,0x64,0x32,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x30,0x61,0x61,0x34,0x36,0x37,0x39, + 0x66,0x75,0x3a,0x30,0x78,0x32,0x62,0x61,0x39,0x36,0x36,0x30,0x61,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x31,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x33,0x64,0x33,0x32, + 0x34,0x61,0x61,0x63,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x31,0x37,0x31,0x63,0x30,0x32,0x62,0x66,0x75,0x3a,0x30,0x78,0x66,0x36,0x33,0x62,0x65,0x66,0x61,0x37, + 0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x32,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x38,0x31,0x30,0x63,0x33,0x61,0x32,0x61,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x38, + 0x35,0x36,0x32,0x33,0x37,0x36,0x33,0x75,0x3a,0x30,0x78,0x37,0x61,0x37,0x63,0x64,0x36,0x30,0x39,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x33,0x5d,0x3d,0x62,0x31,0x3f, + 0x30,0x78,0x39,0x39,0x61,0x39,0x61,0x65,0x66,0x66,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x65,0x37,0x38,0x66,0x35,0x64,0x30,0x38,0x75,0x3a,0x30,0x78,0x39,0x31, + 0x35,0x38,0x33,0x39,0x64,0x65,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31,0x34,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x34,0x32,0x64,0x33,0x64,0x62,0x64,0x39,0x75,0x3a,0x28, + 0x62,0x32,0x3f,0x30,0x78,0x63,0x64,0x36,0x37,0x33,0x37,0x38,0x35,0x75,0x3a,0x30,0x78,0x30,0x63,0x30,0x36,0x64,0x31,0x66,0x64,0x75,0x29,0x3b,0x0a,0x6b,0x5b,0x31, + 0x35,0x5d,0x3d,0x62,0x31,0x3f,0x30,0x78,0x37,0x36,0x66,0x36,0x64,0x62,0x30,0x38,0x75,0x3a,0x28,0x62,0x32,0x3f,0x30,0x78,0x64,0x38,0x64,0x65,0x64,0x32,0x39,0x31, + 0x75,0x3a,0x30,0x78,0x63,0x30,0x62,0x30,0x37,0x36,0x32,0x64,0x75,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x2a,0x20,0x73,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x20,0x73,0x74,0x61,0x74,0x65,0x29, + 0x2b,0x69,0x64,0x78,0x2a,0x28,0x36,0x34,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x29,0x2b,0x73,0x75,0x62,0x2a,0x28,0x31,0x36,0x2f,0x73, + 0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x78,0x5b,0x34,0x5d,0x3d,0x7b,0x20,0x73,0x5b,0x30,0x5d,0x2c,0x73, + 0x5b,0x31,0x5d,0x2c,0x73,0x5b,0x32,0x5d,0x2c,0x73,0x5b,0x33,0x5d,0x20,0x7d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x31,0x3d,0x28, + 0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x38,0x3a,0x32,0x34,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x33,0x3d,0x28,0x73,0x75,0x62,0x26, + 0x31,0x29,0x3f,0x32,0x34,0x3a,0x38,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x70,0x3d,0x28,0x28,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x20,0x6f,0x75,0x74,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69, + 0x7a,0x65,0x30,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x29,0x2b,0x73,0x75,0x62,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x30,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x54,0x3a,0x28, + 0x54,0x2b,0x31,0x30,0x32,0x34,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x74,0x31,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x28,0x54,0x2b,0x32,0x35,0x36,0x29,0x3a,0x28,0x54,0x2b,0x31,0x37,0x39,0x32,0x29,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x32,0x3d,0x28,0x73,0x75, + 0x62,0x26,0x31,0x29,0x3f,0x28,0x54,0x2b,0x35,0x31,0x32,0x29,0x3a,0x28,0x54,0x2b,0x31,0x35,0x33,0x36,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x33,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x28,0x54,0x2b,0x37, + 0x36,0x38,0x29,0x3a,0x28,0x54,0x2b,0x31,0x32,0x38,0x30,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x75,0x6e,0x72, + 0x6f,0x6c,0x6c,0x5f,0x66,0x61,0x63,0x74,0x6f,0x72,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x6f,0x75,0x74, + 0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x3b,0x20,0x69,0x2b,0x3d,0x34,0x2c,0x70,0x2b,0x3d,0x34, + 0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x79,0x5b,0x34,0x5d,0x3b,0x0a,0x23,0x69,0x66,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x73,0x20,0x21,0x3d, + 0x20,0x34,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74, + 0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33, + 0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x30,0x5d,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28, + 0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d, + 0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36, + 0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x32,0x5d,0x3b, + 0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c, + 0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x33,0x5d,0x3b,0x0a,0x2a,0x70,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x79,0x29,0x3b,0x0a,0x78,0x5b,0x30,0x5d, + 0x3d,0x79,0x5b,0x30,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x79,0x5b,0x31,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x79,0x5b,0x32,0x5d,0x3b,0x0a,0x78,0x5b,0x33, + 0x5d,0x3d,0x79,0x5b,0x33,0x5d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29, + 0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x30,0x5d,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30, + 0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c, + 0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20, + 0x31,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e, + 0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b, + 0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x32,0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33, + 0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31, + 0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65, + 0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x33,0x5d,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x74, + 0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d, + 0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b, + 0x20,0x34,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x35,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65, + 0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73, + 0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x36,0x5d,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d, + 0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31, + 0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b, + 0x5b,0x20,0x37,0x5d,0x3b,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29, + 0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28, + 0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x38,0x5d,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c, + 0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x20,0x39,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d, + 0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b, + 0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e, + 0x6b,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30, + 0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65, + 0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32, + 0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d, + 0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33, + 0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x32,0x5d,0x3b,0x0a,0x78,0x5b,0x31, + 0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d, + 0x5e,0x6b,0x5b,0x31,0x33,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c, + 0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33, + 0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x34,0x5d,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30, + 0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74, + 0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x31,0x35,0x5d,0x3b,0x0a,0x2a,0x70, + 0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x78,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x73,0x29,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x78,0x29,0x3b,0x0a,0x7d,0x0a,0x23,0x75, + 0x6e,0x64,0x65,0x66,0x20,0x6e,0x75,0x6d,0x5f,0x72,0x6f,0x75,0x6e,0x64,0x73,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x5f,0x66,0x61, + 0x63,0x74,0x6f,0x72,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6f,0x75,0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6f,0x75, + 0x74,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x30,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x66,0x69,0x6c,0x6c,0x41,0x65,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x69,0x6e,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50, + 0x41,0x44,0x5f,0x4c,0x33,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67, + 0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69, + 0x64,0x20,0x68,0x61,0x73,0x68,0x41,0x65,0x73,0x31,0x52,0x78,0x34,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69, + 0x64,0x2a,0x20,0x69,0x6e,0x70,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x68,0x61,0x73,0x68,0x2c,0x75,0x69,0x6e, + 0x74,0x20,0x68,0x61,0x73,0x68,0x4f,0x66,0x66,0x73,0x65,0x74,0x42,0x79,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x68,0x61,0x73,0x68,0x53,0x74,0x72,0x69,0x64, + 0x65,0x42,0x79,0x74,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x20,0x54,0x5b,0x32,0x30,0x34,0x38,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2a,0x34,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2f,0x34,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x75,0x62,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x20,0x25,0x20,0x34,0x3b, + 0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2c,0x73,0x74,0x65, + 0x70,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x3b,0x20,0x69,0x3c,0x32,0x30,0x34,0x38,0x3b,0x20,0x69,0x2b,0x3d, + 0x73,0x74,0x65,0x70,0x29,0x0a,0x54,0x5b,0x69,0x5d,0x3d,0x41,0x45,0x53,0x5f,0x54,0x41,0x42,0x4c,0x45,0x5b,0x69,0x5d,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72, + 0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x78,0x5b,0x34,0x5d, + 0x3d,0x7b,0x20,0x41,0x45,0x53,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x48,0x41,0x53,0x48,0x5b,0x73,0x75,0x62,0x2a,0x34,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x53,0x54,0x41, + 0x54,0x45,0x5f,0x48,0x41,0x53,0x48,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x31,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x48,0x41,0x53,0x48,0x5b, + 0x73,0x75,0x62,0x2a,0x34,0x2b,0x32,0x5d,0x2c,0x41,0x45,0x53,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x48,0x41,0x53,0x48,0x5b,0x73,0x75,0x62,0x2a,0x34,0x2b,0x33,0x5d, + 0x20,0x7d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x31,0x3d,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f,0x38, + 0x3a,0x32,0x34,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x33,0x3d,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f, + 0x32,0x34,0x3a,0x38,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x20,0x70,0x3d,0x28,0x28, + 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x20,0x69,0x6e,0x70,0x75,0x74,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x28,0x69,0x6e, + 0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x2b,0x36,0x34,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x29,0x2b,0x73,0x75,0x62,0x3b,0x0a, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x30,0x3d,0x28,0x28,0x73, + 0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f,0x54,0x3a,0x28,0x54,0x2b,0x31,0x30,0x32,0x34,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x31,0x3d,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f, + 0x28,0x54,0x2b,0x32,0x35,0x36,0x29,0x3a,0x28,0x54,0x2b,0x31,0x37,0x39,0x32,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x32,0x3d,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f,0x28,0x54,0x2b,0x35, + 0x31,0x32,0x29,0x3a,0x28,0x54,0x2b,0x31,0x35,0x33,0x36,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x2a,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x74,0x33,0x3d,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3d,0x3d,0x30,0x29,0x3f,0x28,0x54,0x2b,0x37,0x36,0x38,0x29,0x3a, + 0x28,0x54,0x2b,0x31,0x32,0x38,0x30,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x38,0x29,0x0a,0x66,0x6f,0x72,0x20, + 0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x69,0x6e,0x70,0x75,0x74,0x53,0x69,0x7a,0x65,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69, + 0x6e,0x74,0x34,0x29,0x3b,0x20,0x69,0x2b,0x3d,0x34,0x2c,0x70,0x2b,0x3d,0x34,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x6b,0x5b,0x34,0x5d,0x2c,0x79,0x5b,0x34, + 0x5d,0x3b,0x0a,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x6b,0x29,0x3d,0x2a,0x70,0x3b,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b, + 0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e, + 0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x30,0x5d,0x3b,0x0a,0x79,0x5b, + 0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28, + 0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29, + 0x5d,0x5e,0x6b,0x5b,0x31,0x5d,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c, + 0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33, + 0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x32,0x5d,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d, + 0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33, + 0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x6b,0x5b,0x33,0x5d,0x3b,0x0a,0x78,0x5b,0x30,0x5d, + 0x3d,0x79,0x5b,0x30,0x5d,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x79,0x5b,0x31,0x5d,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x79,0x5b,0x32,0x5d,0x3b,0x0a,0x78,0x5b,0x33, + 0x5d,0x3d,0x79,0x5b,0x33,0x5d,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x20,0x79,0x5b,0x34,0x5d,0x3b,0x0a,0x79,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d, + 0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x66,0x36,0x66,0x61,0x38, + 0x33,0x38,0x39,0x3b,0x0a,0x79,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x38,0x62,0x32,0x34,0x39,0x34,0x39,0x66,0x3b,0x0a,0x79,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d, + 0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x39,0x30,0x64,0x63,0x35, + 0x36,0x62,0x66,0x3b,0x0a,0x79,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x78, + 0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x30,0x36,0x38,0x39,0x30,0x32,0x30,0x31,0x3b,0x0a,0x78,0x5b,0x30,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x31,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x31,0x36,0x29,0x5d, + 0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x36,0x31,0x62,0x32,0x36, + 0x33,0x64,0x31,0x3b,0x0a,0x78,0x5b,0x31,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x30,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x35,0x31,0x66,0x34,0x65,0x30,0x33,0x63,0x3b,0x0a,0x78,0x5b,0x32,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x32,0x5d,0x2c,0x30,0x29,0x5d,0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x33,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x31,0x36,0x29,0x5d, + 0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x65,0x65,0x31,0x30,0x34, + 0x33,0x63,0x36,0x3b,0x0a,0x78,0x5b,0x33,0x5d,0x3d,0x74,0x30,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x33,0x5d,0x2c,0x30,0x29,0x5d, + 0x5e,0x74,0x31,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x30,0x5d,0x2c,0x73,0x31,0x29,0x5d,0x5e,0x74,0x32,0x5b,0x67,0x65,0x74,0x5f, + 0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79,0x5b,0x31,0x5d,0x2c,0x31,0x36,0x29,0x5d,0x5e,0x74,0x33,0x5b,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x33,0x32,0x28,0x79, + 0x5b,0x32,0x5d,0x2c,0x73,0x33,0x29,0x5d,0x5e,0x30,0x78,0x65,0x64,0x31,0x38,0x66,0x39,0x39,0x62,0x3b,0x0a,0x2a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x34,0x2a,0x29,0x28,0x68,0x61,0x73,0x68,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x68,0x61,0x73,0x68,0x53,0x74,0x72,0x69,0x64,0x65,0x42,0x79, + 0x74,0x65,0x73,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x29,0x2b,0x73,0x75,0x62,0x2b,0x28,0x68,0x61,0x73,0x68,0x4f,0x66,0x66,0x73, + 0x65,0x74,0x42,0x79,0x74,0x65,0x73,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x34,0x29,0x29,0x29,0x3d,0x2a,0x28,0x75,0x69,0x6e,0x74,0x34,0x2a, + 0x29,0x28,0x78,0x29,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x63,0x68,0x61,0x72,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x73,0x69,0x67,0x6d,0x61,0x5b,0x31,0x32,0x2a,0x31,0x36,0x5d,0x3d,0x7b,0x0a,0x30,0x2c,0x31, + 0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x30,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c,0x31,0x33,0x2c,0x31,0x34,0x2c, + 0x31,0x35,0x2c,0x0a,0x31,0x34,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x36,0x2c,0x31,0x2c,0x31,0x32,0x2c,0x30,0x2c,0x32, + 0x2c,0x31,0x31,0x2c,0x37,0x2c,0x35,0x2c,0x33,0x2c,0x0a,0x31,0x31,0x2c,0x38,0x2c,0x31,0x32,0x2c,0x30,0x2c,0x35,0x2c,0x32,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x31, + 0x30,0x2c,0x31,0x34,0x2c,0x33,0x2c,0x36,0x2c,0x37,0x2c,0x31,0x2c,0x39,0x2c,0x34,0x2c,0x0a,0x37,0x2c,0x39,0x2c,0x33,0x2c,0x31,0x2c,0x31,0x33,0x2c,0x31,0x32,0x2c, + 0x31,0x31,0x2c,0x31,0x34,0x2c,0x32,0x2c,0x36,0x2c,0x35,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x30,0x2c,0x31,0x35,0x2c,0x38,0x2c,0x0a,0x39,0x2c,0x30,0x2c,0x35,0x2c,0x37, + 0x2c,0x32,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x31,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c,0x36,0x2c,0x38,0x2c,0x33,0x2c,0x31,0x33,0x2c,0x0a, + 0x32,0x2c,0x31,0x32,0x2c,0x36,0x2c,0x31,0x30,0x2c,0x30,0x2c,0x31,0x31,0x2c,0x38,0x2c,0x33,0x2c,0x34,0x2c,0x31,0x33,0x2c,0x37,0x2c,0x35,0x2c,0x31,0x35,0x2c,0x31, + 0x34,0x2c,0x31,0x2c,0x39,0x2c,0x0a,0x31,0x32,0x2c,0x35,0x2c,0x31,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x31,0x33,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x30,0x2c,0x37,0x2c, + 0x36,0x2c,0x33,0x2c,0x39,0x2c,0x32,0x2c,0x38,0x2c,0x31,0x31,0x2c,0x0a,0x31,0x33,0x2c,0x31,0x31,0x2c,0x37,0x2c,0x31,0x34,0x2c,0x31,0x32,0x2c,0x31,0x2c,0x33,0x2c, + 0x39,0x2c,0x35,0x2c,0x30,0x2c,0x31,0x35,0x2c,0x34,0x2c,0x38,0x2c,0x36,0x2c,0x32,0x2c,0x31,0x30,0x2c,0x0a,0x36,0x2c,0x31,0x35,0x2c,0x31,0x34,0x2c,0x39,0x2c,0x31, + 0x31,0x2c,0x33,0x2c,0x30,0x2c,0x38,0x2c,0x31,0x32,0x2c,0x32,0x2c,0x31,0x33,0x2c,0x37,0x2c,0x31,0x2c,0x34,0x2c,0x31,0x30,0x2c,0x35,0x2c,0x0a,0x31,0x30,0x2c,0x32, + 0x2c,0x38,0x2c,0x34,0x2c,0x37,0x2c,0x36,0x2c,0x31,0x2c,0x35,0x2c,0x31,0x35,0x2c,0x31,0x31,0x2c,0x39,0x2c,0x31,0x34,0x2c,0x33,0x2c,0x31,0x32,0x2c,0x31,0x33,0x2c, + 0x30,0x2c,0x0a,0x30,0x2c,0x31,0x2c,0x32,0x2c,0x33,0x2c,0x34,0x2c,0x35,0x2c,0x36,0x2c,0x37,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x30,0x2c,0x31,0x31,0x2c,0x31,0x32,0x2c, + 0x31,0x33,0x2c,0x31,0x34,0x2c,0x31,0x35,0x2c,0x0a,0x31,0x34,0x2c,0x31,0x30,0x2c,0x34,0x2c,0x38,0x2c,0x39,0x2c,0x31,0x35,0x2c,0x31,0x33,0x2c,0x36,0x2c,0x31,0x2c, + 0x31,0x32,0x2c,0x30,0x2c,0x32,0x2c,0x31,0x31,0x2c,0x37,0x2c,0x35,0x2c,0x33,0x2c,0x0a,0x7d,0x3b,0x0a,0x65,0x6e,0x75,0x6d,0x20,0x42,0x6c,0x61,0x6b,0x65,0x32,0x62, + 0x5f,0x49,0x56,0x0a,0x7b,0x0a,0x69,0x76,0x30,0x3d,0x30,0x78,0x36,0x61,0x30,0x39,0x65,0x36,0x36,0x37,0x66,0x33,0x62,0x63,0x63,0x39,0x30,0x38,0x75,0x6c,0x2c,0x0a, + 0x69,0x76,0x31,0x3d,0x30,0x78,0x62,0x62,0x36,0x37,0x61,0x65,0x38,0x35,0x38,0x34,0x63,0x61,0x61,0x37,0x33,0x62,0x75,0x6c,0x2c,0x0a,0x69,0x76,0x32,0x3d,0x30,0x78, + 0x33,0x63,0x36,0x65,0x66,0x33,0x37,0x32,0x66,0x65,0x39,0x34,0x66,0x38,0x32,0x62,0x75,0x6c,0x2c,0x0a,0x69,0x76,0x33,0x3d,0x30,0x78,0x61,0x35,0x34,0x66,0x66,0x35, + 0x33,0x61,0x35,0x66,0x31,0x64,0x33,0x36,0x66,0x31,0x75,0x6c,0x2c,0x0a,0x69,0x76,0x34,0x3d,0x30,0x78,0x35,0x31,0x30,0x65,0x35,0x32,0x37,0x66,0x61,0x64,0x65,0x36, + 0x38,0x32,0x64,0x31,0x75,0x6c,0x2c,0x0a,0x69,0x76,0x35,0x3d,0x30,0x78,0x39,0x62,0x30,0x35,0x36,0x38,0x38,0x63,0x32,0x62,0x33,0x65,0x36,0x63,0x31,0x66,0x75,0x6c, + 0x2c,0x0a,0x69,0x76,0x36,0x3d,0x30,0x78,0x31,0x66,0x38,0x33,0x64,0x39,0x61,0x62,0x66,0x62,0x34,0x31,0x62,0x64,0x36,0x62,0x75,0x6c,0x2c,0x0a,0x69,0x76,0x37,0x3d, + 0x30,0x78,0x35,0x62,0x65,0x30,0x63,0x64,0x31,0x39,0x31,0x33,0x37,0x65,0x32,0x31,0x37,0x39,0x75,0x6c,0x2c,0x0a,0x7d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x72, + 0x6f,0x74,0x72,0x36,0x34,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x73,0x68,0x69,0x66,0x74,0x29,0x20,0x7b,0x20,0x72,0x65,0x74, + 0x75,0x72,0x6e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x61,0x2c,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x29,0x3b,0x20,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x47,0x28,0x72,0x2c,0x20,0x69,0x2c,0x20,0x61,0x2c,0x20,0x62,0x2c,0x20,0x63,0x2c,0x20,0x64,0x29,0x20,0x5c,0x0a,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x61, + 0x3d,0x61,0x2b,0x62,0x2b,0x6d,0x5b,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x73,0x69,0x67,0x6d,0x61,0x5b,0x72,0x2a,0x31,0x36,0x2b,0x32,0x2a,0x69,0x2b,0x30,0x5d, + 0x5d,0x3b,0x20,0x5c,0x0a,0x64,0x3d,0x72,0x6f,0x74,0x72,0x36,0x34,0x28,0x64,0x5e,0x61,0x2c,0x33,0x32,0x29,0x3b,0x20,0x5c,0x0a,0x63,0x3d,0x63,0x2b,0x64,0x3b,0x20, + 0x5c,0x0a,0x62,0x3d,0x72,0x6f,0x74,0x72,0x36,0x34,0x28,0x62,0x5e,0x63,0x2c,0x32,0x34,0x29,0x3b,0x20,0x5c,0x0a,0x61,0x3d,0x61,0x2b,0x62,0x2b,0x6d,0x5b,0x62,0x6c, + 0x61,0x6b,0x65,0x32,0x62,0x5f,0x73,0x69,0x67,0x6d,0x61,0x5b,0x72,0x2a,0x31,0x36,0x2b,0x32,0x2a,0x69,0x2b,0x31,0x5d,0x5d,0x3b,0x20,0x5c,0x0a,0x64,0x3d,0x72,0x6f, + 0x74,0x72,0x36,0x34,0x28,0x64,0x5e,0x61,0x2c,0x31,0x36,0x29,0x3b,0x20,0x5c,0x0a,0x63,0x3d,0x63,0x2b,0x64,0x3b,0x20,0x5c,0x0a,0x62,0x3d,0x72,0x6f,0x74,0x72,0x36, + 0x34,0x28,0x62,0x5e,0x63,0x2c,0x36,0x33,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x72,0x29,0x20,0x5c,0x0a,0x64,0x6f,0x20,0x7b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x30,0x2c,0x76,0x5b,0x30,0x5d,0x2c,0x76,0x5b, + 0x34,0x5d,0x2c,0x76,0x5b,0x38,0x5d,0x2c,0x76,0x5b,0x31,0x32,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x31,0x2c,0x76,0x5b,0x31,0x5d,0x2c,0x76,0x5b,0x35, + 0x5d,0x2c,0x76,0x5b,0x39,0x5d,0x2c,0x76,0x5b,0x31,0x33,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x32,0x2c,0x76,0x5b,0x32,0x5d,0x2c,0x76,0x5b,0x36,0x5d, + 0x2c,0x76,0x5b,0x31,0x30,0x5d,0x2c,0x76,0x5b,0x31,0x34,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x33,0x2c,0x76,0x5b,0x33,0x5d,0x2c,0x76,0x5b,0x37,0x5d, + 0x2c,0x76,0x5b,0x31,0x31,0x5d,0x2c,0x76,0x5b,0x31,0x35,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x34,0x2c,0x76,0x5b,0x30,0x5d,0x2c,0x76,0x5b,0x35,0x5d, + 0x2c,0x76,0x5b,0x31,0x30,0x5d,0x2c,0x76,0x5b,0x31,0x35,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x35,0x2c,0x76,0x5b,0x31,0x5d,0x2c,0x76,0x5b,0x36,0x5d, + 0x2c,0x76,0x5b,0x31,0x31,0x5d,0x2c,0x76,0x5b,0x31,0x32,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x36,0x2c,0x76,0x5b,0x32,0x5d,0x2c,0x76,0x5b,0x37,0x5d, + 0x2c,0x76,0x5b,0x38,0x5d,0x2c,0x76,0x5b,0x31,0x33,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x47,0x28,0x72,0x2c,0x37,0x2c,0x76,0x5b,0x33,0x5d,0x2c,0x76,0x5b,0x34,0x5d,0x2c, + 0x76,0x5b,0x39,0x5d,0x2c,0x76,0x5b,0x31,0x34,0x5d,0x29,0x3b,0x20,0x5c,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x23,0x64,0x65,0x66,0x69, + 0x6e,0x65,0x20,0x42,0x4c,0x41,0x4b,0x45,0x32,0x42,0x5f,0x52,0x4f,0x55,0x4e,0x44,0x53,0x28,0x29,0x20,0x52,0x4f,0x55,0x4e,0x44,0x28,0x30,0x29,0x3b,0x52,0x4f,0x55, + 0x4e,0x44,0x28,0x31,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x32,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x33,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x34,0x29, + 0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x35,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x36,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x37,0x29,0x3b,0x52,0x4f,0x55,0x4e, + 0x44,0x28,0x38,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x39,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x31,0x30,0x29,0x3b,0x52,0x4f,0x55,0x4e,0x44,0x28,0x31,0x31, + 0x29,0x3b,0x0a,0x76,0x6f,0x69,0x64,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x73,0x69,0x6e,0x67, + 0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x68,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x6d, + 0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x76,0x5b,0x31,0x36,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x69,0x76,0x30,0x5e,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x30,0x34,0x30,0x2c,0x69,0x76,0x31,0x2c,0x69,0x76, + 0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34,0x20,0x2c,0x69,0x76,0x35,0x2c,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x69,0x76,0x30,0x20,0x2c,0x69,0x76,0x31, + 0x2c,0x69,0x76,0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34,0x5e,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x2c,0x69, + 0x76,0x35,0x2c,0x7e,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x7d,0x3b,0x0a,0x42,0x4c,0x41,0x4b,0x45,0x32,0x42,0x5f,0x52,0x4f,0x55,0x4e,0x44,0x53,0x28,0x29, + 0x3b,0x0a,0x68,0x5b,0x30,0x5d,0x3d,0x76,0x5b,0x30,0x5d,0x5e,0x76,0x5b,0x20,0x38,0x5d,0x5e,0x69,0x76,0x30,0x5e,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x30,0x34,0x30, + 0x3b,0x0a,0x68,0x5b,0x31,0x5d,0x3d,0x76,0x5b,0x31,0x5d,0x5e,0x76,0x5b,0x20,0x39,0x5d,0x5e,0x69,0x76,0x31,0x3b,0x0a,0x68,0x5b,0x32,0x5d,0x3d,0x76,0x5b,0x32,0x5d, + 0x5e,0x76,0x5b,0x31,0x30,0x5d,0x5e,0x69,0x76,0x32,0x3b,0x0a,0x68,0x5b,0x33,0x5d,0x3d,0x76,0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x31,0x31,0x5d,0x5e,0x69,0x76,0x33,0x3b, + 0x0a,0x68,0x5b,0x34,0x5d,0x3d,0x76,0x5b,0x34,0x5d,0x5e,0x76,0x5b,0x31,0x32,0x5d,0x5e,0x69,0x76,0x34,0x3b,0x0a,0x68,0x5b,0x35,0x5d,0x3d,0x76,0x5b,0x35,0x5d,0x5e, + 0x76,0x5b,0x31,0x33,0x5d,0x5e,0x69,0x76,0x35,0x3b,0x0a,0x68,0x5b,0x36,0x5d,0x3d,0x76,0x5b,0x36,0x5d,0x5e,0x76,0x5b,0x31,0x34,0x5d,0x5e,0x69,0x76,0x36,0x3b,0x0a, + 0x68,0x5b,0x37,0x5d,0x3d,0x76,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x31,0x35,0x5d,0x5e,0x69,0x76,0x37,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75, + 0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c, + 0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x69,0x6e,0x69,0x74,0x69, + 0x61,0x6c,0x5f,0x68,0x61,0x73,0x68,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x2a,0x6f,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x2c,0x75,0x69, + 0x6e,0x74,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x2c,0x75,0x69,0x6e,0x74,0x20,0x73,0x74,0x61,0x72,0x74,0x5f, + 0x6e,0x6f,0x6e,0x63,0x65,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x70,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67, + 0x2a,0x29,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6d,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x0a, + 0x28,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x30,0x29,0x3f,0x70,0x5b,0x20,0x30,0x5d,0x3a,0x30,0x2c,0x0a,0x28, + 0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x38,0x29,0x3f,0x70,0x5b,0x20,0x31,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x31,0x36,0x29,0x3f,0x70,0x5b,0x20,0x32,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x32,0x34,0x29,0x3f,0x70,0x5b,0x20,0x33,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x33,0x32,0x29,0x3f,0x70,0x5b,0x20,0x34,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x34,0x30,0x29,0x3f,0x70,0x5b,0x20,0x35,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x34,0x38,0x29,0x3f,0x70,0x5b,0x20,0x36,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x35,0x36,0x29,0x3f,0x70,0x5b,0x20,0x37,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x36,0x34,0x29,0x3f,0x70,0x5b,0x20,0x38,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x37,0x32,0x29,0x3f,0x70,0x5b,0x20,0x39,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x38,0x30,0x29,0x3f,0x70,0x5b,0x31,0x30,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x38,0x38,0x29,0x3f,0x70,0x5b,0x31,0x31,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x39,0x36,0x29,0x3f,0x70,0x5b,0x31,0x32,0x5d,0x3a,0x30,0x2c,0x0a,0x28,0x62, + 0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x31,0x30,0x34,0x29,0x3f,0x70,0x5b,0x31,0x33,0x5d,0x3a,0x30,0x2c,0x0a,0x28, + 0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x31,0x31,0x32,0x29,0x3f,0x70,0x5b,0x31,0x34,0x5d,0x3a,0x30,0x2c,0x0a, + 0x28,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x3e,0x31,0x32,0x30,0x29,0x3f,0x70,0x5b,0x31,0x35,0x5d,0x3a,0x30,0x2c, + 0x0a,0x7d,0x3b,0x0a,0x69,0x66,0x28,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f, + 0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x0a,0x6d,0x5b,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x2f,0x73,0x69, + 0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x5d,0x20,0x26,0x3d,0x20,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x2d,0x31,0x29,0x3e,0x3e,0x28,0x36,0x34, + 0x2d,0x28,0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f, + 0x6e,0x67,0x29,0x29,0x2a,0x38,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6e,0x6f,0x6e,0x63,0x65,0x3d,0x73,0x74,0x61,0x72,0x74, + 0x5f,0x6e,0x6f,0x6e,0x63,0x65,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x6d,0x5b,0x34,0x5d,0x3d,0x28,0x6d,0x5b,0x34,0x5d,0x26, + 0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x2d,0x31,0x29,0x3e,0x3e,0x38,0x29,0x29,0x7c,0x28,0x6e,0x6f,0x6e,0x63,0x65,0x3c,0x3c,0x35,0x36,0x29,0x3b,0x0a,0x6d, + 0x5b,0x35,0x5d,0x3d,0x28,0x6d,0x5b,0x35,0x5d,0x26,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x2d,0x31,0x29,0x3c,0x3c,0x32,0x34,0x29,0x29,0x7c,0x28,0x6e,0x6f, + 0x6e,0x63,0x65,0x3e,0x3e,0x38,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x61,0x73,0x68,0x5b,0x38,0x5d,0x3b,0x0a,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f, + 0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x73,0x69,0x6e,0x67,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x28,0x68,0x61,0x73,0x68,0x2c,0x6d,0x2c, + 0x62,0x6c,0x6f,0x63,0x6b,0x54,0x65,0x6d,0x70,0x6c,0x61,0x74,0x65,0x53,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f, + 0x6e,0x67,0x2a,0x20,0x74,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x20,0x6f,0x75,0x74,0x29,0x2b,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x38,0x3b,0x0a,0x74,0x5b,0x30,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x30,0x5d,0x3b,0x0a,0x74,0x5b,0x31,0x5d, + 0x3d,0x68,0x61,0x73,0x68,0x5b,0x31,0x5d,0x3b,0x0a,0x74,0x5b,0x32,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x32,0x5d,0x3b,0x0a,0x74,0x5b,0x33,0x5d,0x3d,0x68,0x61,0x73, + 0x68,0x5b,0x33,0x5d,0x3b,0x0a,0x74,0x5b,0x34,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x34,0x5d,0x3b,0x0a,0x74,0x5b,0x35,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x35,0x5d, + 0x3b,0x0a,0x74,0x5b,0x36,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x36,0x5d,0x3b,0x0a,0x74,0x5b,0x37,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x37,0x5d,0x3b,0x0a,0x7d,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x20,0x32,0x35,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6f,0x75,0x74,0x5f,0x6c, + 0x65,0x6e,0x20,0x33,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73, + 0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f, + 0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x33,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x62,0x6c,0x61,0x6b, + 0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x33,0x32,0x0a,0x76,0x6f,0x69,0x64,0x20,0x62,0x6c,0x61,0x6b,0x65, + 0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65, + 0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x6f,0x75,0x74,0x2c,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x6d,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x69,0x6e,0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x76,0x5b,0x31,0x36,0x5d,0x20,0x3d,0x0a,0x7b, + 0x0a,0x69,0x76,0x30,0x5e,0x28,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x75,0x7c,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x29,0x2c,0x69,0x76,0x31,0x2c,0x69, + 0x76,0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34,0x20,0x2c,0x69,0x76,0x35,0x2c,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x69,0x76,0x30,0x20,0x2c,0x69,0x76, + 0x31,0x2c,0x69,0x76,0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34,0x5e,0x31,0x32,0x38,0x2c,0x69,0x76,0x35,0x2c,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x7d, + 0x3b,0x0a,0x42,0x4c,0x41,0x4b,0x45,0x32,0x42,0x5f,0x52,0x4f,0x55,0x4e,0x44,0x53,0x28,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x5b,0x38,0x5d,0x3b,0x0a, + 0x76,0x5b,0x30,0x5d,0x3d,0x68,0x5b,0x30,0x5d,0x3d,0x76,0x5b,0x30,0x5d,0x5e,0x76,0x5b,0x38,0x5d,0x5e,0x69,0x76,0x30,0x5e,0x28,0x30,0x78,0x30,0x31,0x30,0x31,0x30, + 0x30,0x30,0x30,0x75,0x7c,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x29,0x3b,0x0a,0x76,0x5b,0x31,0x5d,0x3d,0x68,0x5b,0x31,0x5d,0x3d,0x76,0x5b,0x31,0x5d,0x5e,0x76,0x5b, + 0x39,0x5d,0x5e,0x69,0x76,0x31,0x3b,0x0a,0x76,0x5b,0x32,0x5d,0x3d,0x68,0x5b,0x32,0x5d,0x3d,0x76,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x31,0x30,0x5d,0x5e,0x69,0x76,0x32, + 0x3b,0x0a,0x76,0x5b,0x33,0x5d,0x3d,0x68,0x5b,0x33,0x5d,0x3d,0x76,0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x31,0x31,0x5d,0x5e,0x69,0x76,0x33,0x3b,0x0a,0x76,0x5b,0x34,0x5d, + 0x3d,0x68,0x5b,0x34,0x5d,0x3d,0x76,0x5b,0x34,0x5d,0x5e,0x76,0x5b,0x31,0x32,0x5d,0x5e,0x69,0x76,0x34,0x3b,0x0a,0x76,0x5b,0x35,0x5d,0x3d,0x68,0x5b,0x35,0x5d,0x3d, + 0x76,0x5b,0x35,0x5d,0x5e,0x76,0x5b,0x31,0x33,0x5d,0x5e,0x69,0x76,0x35,0x3b,0x0a,0x76,0x5b,0x36,0x5d,0x3d,0x68,0x5b,0x36,0x5d,0x3d,0x76,0x5b,0x36,0x5d,0x5e,0x76, + 0x5b,0x31,0x34,0x5d,0x5e,0x69,0x76,0x36,0x3b,0x0a,0x76,0x5b,0x37,0x5d,0x3d,0x68,0x5b,0x37,0x5d,0x3d,0x76,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x31,0x35,0x5d,0x5e,0x69, + 0x76,0x37,0x3b,0x0a,0x76,0x5b,0x38,0x5d,0x3d,0x69,0x76,0x30,0x3b,0x0a,0x76,0x5b,0x39,0x5d,0x3d,0x69,0x76,0x31,0x3b,0x0a,0x76,0x5b,0x31,0x30,0x5d,0x3d,0x69,0x76, + 0x32,0x3b,0x0a,0x76,0x5b,0x31,0x31,0x5d,0x3d,0x69,0x76,0x33,0x3b,0x0a,0x76,0x5b,0x31,0x32,0x5d,0x3d,0x69,0x76,0x34,0x5e,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3b,0x0a, + 0x76,0x5b,0x31,0x33,0x5d,0x3d,0x69,0x76,0x35,0x3b,0x0a,0x76,0x5b,0x31,0x34,0x5d,0x3d,0x7e,0x69,0x76,0x36,0x3b,0x0a,0x76,0x5b,0x31,0x35,0x5d,0x3d,0x69,0x76,0x37, + 0x3b,0x0a,0x6d,0x5b,0x20,0x30,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x32,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x36,0x5d,0x3a,0x30,0x3b,0x0a,0x6d, + 0x5b,0x20,0x31,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x33,0x36,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x37,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x32, + 0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x34,0x34,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x38,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x33,0x5d,0x3d,0x28, + 0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x35,0x32,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x39,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x34,0x5d,0x3d,0x28,0x69,0x6e,0x5f, + 0x6c,0x65,0x6e,0x3e,0x31,0x36,0x30,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x30,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x35,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e, + 0x3e,0x31,0x36,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x31,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x36,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x37, + 0x36,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x32,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x37,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x38,0x34,0x29,0x3f, + 0x69,0x6e,0x5b,0x32,0x33,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x38,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x39,0x32,0x29,0x3f,0x69,0x6e,0x5b, + 0x32,0x34,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x39,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x30,0x30,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x35,0x5d, + 0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x30,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x30,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x36,0x5d,0x3a,0x30,0x3b, + 0x0a,0x6d,0x5b,0x31,0x31,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x31,0x36,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x37,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b, + 0x31,0x32,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x32,0x34,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x38,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x33,0x5d, + 0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x33,0x32,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x39,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x34,0x5d,0x3d,0x28,0x69, + 0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x30,0x29,0x3f,0x69,0x6e,0x5b,0x33,0x30,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x35,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c, + 0x65,0x6e,0x3e,0x32,0x34,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x33,0x31,0x5d,0x3a,0x30,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x20,0x25,0x20,0x73,0x69, + 0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x0a,0x6d,0x5b,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x2d,0x31,0x32,0x38,0x29,0x2f,0x73,0x69,0x7a,0x65, + 0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x5d,0x20,0x26,0x3d,0x20,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x2d,0x31,0x29,0x3e,0x3e,0x28,0x36,0x34,0x2d,0x28, + 0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x2a,0x38,0x29,0x3b,0x0a,0x42,0x4c,0x41,0x4b, + 0x45,0x32,0x42,0x5f,0x52,0x4f,0x55,0x4e,0x44,0x53,0x28,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x30,0x29,0x20,0x6f,0x75,0x74,0x5b, + 0x30,0x5d,0x3d,0x68,0x5b,0x30,0x5d,0x5e,0x76,0x5b,0x30,0x5d,0x5e,0x76,0x5b,0x38,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x38,0x29, + 0x20,0x6f,0x75,0x74,0x5b,0x31,0x5d,0x3d,0x68,0x5b,0x31,0x5d,0x5e,0x76,0x5b,0x31,0x5d,0x5e,0x76,0x5b,0x39,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c, + 0x65,0x6e,0x3e,0x31,0x36,0x29,0x20,0x6f,0x75,0x74,0x5b,0x32,0x5d,0x3d,0x68,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x29,0x20,0x6f,0x75,0x74,0x5b,0x33,0x5d,0x3d,0x68,0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x33,0x5d,0x5e,0x76, + 0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x33,0x32,0x29,0x20,0x6f,0x75,0x74,0x5b,0x34,0x5d,0x3d,0x68,0x5b,0x34,0x5d, + 0x5e,0x76,0x5b,0x34,0x5d,0x5e,0x76,0x5b,0x31,0x32,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x30,0x29,0x20,0x6f,0x75,0x74,0x5b, + 0x35,0x5d,0x3d,0x68,0x5b,0x35,0x5d,0x5e,0x76,0x5b,0x35,0x5d,0x5e,0x76,0x5b,0x31,0x33,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34, + 0x38,0x29,0x20,0x6f,0x75,0x74,0x5b,0x36,0x5d,0x3d,0x68,0x5b,0x36,0x5d,0x5e,0x76,0x5b,0x36,0x5d,0x5e,0x76,0x5b,0x31,0x34,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75, + 0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x35,0x36,0x29,0x20,0x6f,0x75,0x74,0x5b,0x37,0x5d,0x3d,0x68,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x31,0x35,0x5d, + 0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f, + 0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20, + 0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x2a,0x6f,0x75,0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f, + 0x69,0x64,0x2a,0x20,0x69,0x6e,0x2c,0x75,0x69,0x6e,0x74,0x20,0x69,0x6e,0x53,0x74,0x72,0x69,0x64,0x65,0x42,0x79,0x74,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x70,0x3d,0x28, + 0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x20,0x69,0x6e,0x29,0x2b,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x69,0x6e,0x53,0x74,0x72,0x69,0x64,0x65,0x42,0x79,0x74,0x65,0x73,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75, + 0x6c,0x6f,0x6e,0x67,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x68,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x20,0x6f,0x75,0x74,0x29,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28, + 0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6d,0x5b, + 0x31,0x36,0x5d,0x3d,0x7b,0x20,0x70,0x5b,0x30,0x5d,0x2c,0x70,0x5b,0x31,0x5d,0x2c,0x70,0x5b,0x32,0x5d,0x2c,0x70,0x5b,0x33,0x5d,0x2c,0x70,0x5b,0x34,0x5d,0x2c,0x70, + 0x5b,0x35,0x5d,0x2c,0x70,0x5b,0x36,0x5d,0x2c,0x70,0x5b,0x37,0x5d,0x2c,0x70,0x5b,0x38,0x5d,0x2c,0x70,0x5b,0x39,0x5d,0x2c,0x70,0x5b,0x31,0x30,0x5d,0x2c,0x70,0x5b, + 0x31,0x31,0x5d,0x2c,0x70,0x5b,0x31,0x32,0x5d,0x2c,0x70,0x5b,0x31,0x33,0x5d,0x2c,0x70,0x5b,0x31,0x34,0x5d,0x2c,0x70,0x5b,0x31,0x35,0x5d,0x20,0x7d,0x3b,0x0a,0x75, + 0x6c,0x6f,0x6e,0x67,0x20,0x68,0x61,0x73,0x68,0x5b,0x38,0x5d,0x3b,0x0a,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73, + 0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x68,0x61,0x73,0x68,0x2c,0x6d,0x2c,0x70,0x29,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x30,0x29,0x20,0x68,0x5b,0x30,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x30,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75, + 0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x38,0x29,0x20,0x68,0x5b,0x31,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65, + 0x6e,0x3e,0x31,0x36,0x29,0x20,0x68,0x5b,0x32,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x32,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x32, + 0x34,0x29,0x20,0x68,0x5b,0x33,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x33,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x33,0x32,0x29,0x20, + 0x68,0x5b,0x34,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x34,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x30,0x29,0x20,0x68,0x5b,0x35, + 0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x35,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x38,0x29,0x20,0x68,0x5b,0x36,0x5d,0x3d,0x68, + 0x61,0x73,0x68,0x5b,0x36,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x35,0x36,0x29,0x20,0x68,0x5b,0x37,0x5d,0x3d,0x68,0x61,0x73,0x68, + 0x5b,0x37,0x5d,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f, + 0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6f,0x75, + 0x74,0x5f,0x6c,0x65,0x6e,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63, + 0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c, + 0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x73,0x5f,0x36,0x34,0x0a,0x76,0x6f,0x69,0x64,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73, + 0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x2a,0x6f,0x75,0x74,0x2c,0x75, + 0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x6d,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x69,0x6e, + 0x29,0x0a,0x7b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x76,0x5b,0x31,0x36,0x5d,0x20,0x3d,0x0a,0x7b,0x0a,0x69,0x76,0x30,0x5e,0x28,0x30,0x78,0x30,0x31,0x30,0x31,0x30, + 0x30,0x30,0x30,0x75,0x7c,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x29,0x2c,0x69,0x76,0x31,0x2c,0x69,0x76,0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34,0x20,0x2c,0x69, + 0x76,0x35,0x2c,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x69,0x76,0x30,0x20,0x2c,0x69,0x76,0x31,0x2c,0x69,0x76,0x32,0x2c,0x69,0x76,0x33,0x2c,0x69,0x76,0x34, + 0x5e,0x31,0x32,0x38,0x2c,0x69,0x76,0x35,0x2c,0x69,0x76,0x36,0x2c,0x69,0x76,0x37,0x2c,0x0a,0x7d,0x3b,0x0a,0x42,0x4c,0x41,0x4b,0x45,0x32,0x42,0x5f,0x52,0x4f,0x55, + 0x4e,0x44,0x53,0x28,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x5b,0x38,0x5d,0x3b,0x0a,0x76,0x5b,0x30,0x5d,0x3d,0x68,0x5b,0x30,0x5d,0x3d,0x76,0x5b,0x30, + 0x5d,0x5e,0x76,0x5b,0x38,0x5d,0x5e,0x69,0x76,0x30,0x5e,0x28,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x75,0x7c,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x29, + 0x3b,0x0a,0x76,0x5b,0x31,0x5d,0x3d,0x68,0x5b,0x31,0x5d,0x3d,0x76,0x5b,0x31,0x5d,0x5e,0x76,0x5b,0x39,0x5d,0x5e,0x69,0x76,0x31,0x3b,0x0a,0x76,0x5b,0x32,0x5d,0x3d, + 0x68,0x5b,0x32,0x5d,0x3d,0x76,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x31,0x30,0x5d,0x5e,0x69,0x76,0x32,0x3b,0x0a,0x76,0x5b,0x33,0x5d,0x3d,0x68,0x5b,0x33,0x5d,0x3d,0x76, + 0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x31,0x31,0x5d,0x5e,0x69,0x76,0x33,0x3b,0x0a,0x76,0x5b,0x34,0x5d,0x3d,0x68,0x5b,0x34,0x5d,0x3d,0x76,0x5b,0x34,0x5d,0x5e,0x76,0x5b, + 0x31,0x32,0x5d,0x5e,0x69,0x76,0x34,0x3b,0x0a,0x76,0x5b,0x35,0x5d,0x3d,0x68,0x5b,0x35,0x5d,0x3d,0x76,0x5b,0x35,0x5d,0x5e,0x76,0x5b,0x31,0x33,0x5d,0x5e,0x69,0x76, + 0x35,0x3b,0x0a,0x76,0x5b,0x36,0x5d,0x3d,0x68,0x5b,0x36,0x5d,0x3d,0x76,0x5b,0x36,0x5d,0x5e,0x76,0x5b,0x31,0x34,0x5d,0x5e,0x69,0x76,0x36,0x3b,0x0a,0x76,0x5b,0x37, + 0x5d,0x3d,0x68,0x5b,0x37,0x5d,0x3d,0x76,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x31,0x35,0x5d,0x5e,0x69,0x76,0x37,0x3b,0x0a,0x76,0x5b,0x38,0x5d,0x3d,0x69,0x76,0x30,0x3b, + 0x0a,0x76,0x5b,0x39,0x5d,0x3d,0x69,0x76,0x31,0x3b,0x0a,0x76,0x5b,0x31,0x30,0x5d,0x3d,0x69,0x76,0x32,0x3b,0x0a,0x76,0x5b,0x31,0x31,0x5d,0x3d,0x69,0x76,0x33,0x3b, + 0x0a,0x76,0x5b,0x31,0x32,0x5d,0x3d,0x69,0x76,0x34,0x5e,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3b,0x0a,0x76,0x5b,0x31,0x33,0x5d,0x3d,0x69,0x76,0x35,0x3b,0x0a,0x76,0x5b, + 0x31,0x34,0x5d,0x3d,0x7e,0x69,0x76,0x36,0x3b,0x0a,0x76,0x5b,0x31,0x35,0x5d,0x3d,0x69,0x76,0x37,0x3b,0x0a,0x6d,0x5b,0x20,0x30,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c, + 0x65,0x6e,0x3e,0x31,0x32,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x36,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x31,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e, + 0x31,0x33,0x36,0x29,0x3f,0x69,0x6e,0x5b,0x31,0x37,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x32,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x34,0x34, + 0x29,0x3f,0x69,0x6e,0x5b,0x31,0x38,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x33,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x35,0x32,0x29,0x3f,0x69, + 0x6e,0x5b,0x31,0x39,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x34,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x36,0x30,0x29,0x3f,0x69,0x6e,0x5b,0x32, + 0x30,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x35,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x36,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x31,0x5d,0x3a, + 0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x36,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x37,0x36,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x32,0x5d,0x3a,0x30,0x3b,0x0a, + 0x6d,0x5b,0x20,0x37,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x38,0x34,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x33,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20, + 0x38,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x39,0x32,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x34,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x20,0x39,0x5d,0x3d, + 0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x30,0x30,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x35,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x30,0x5d,0x3d,0x28,0x69,0x6e, + 0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x30,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x36,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x31,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65, + 0x6e,0x3e,0x32,0x31,0x36,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x37,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x32,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32, + 0x32,0x34,0x29,0x3f,0x69,0x6e,0x5b,0x32,0x38,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x33,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x33,0x32,0x29, + 0x3f,0x69,0x6e,0x5b,0x32,0x39,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x34,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x30,0x29,0x3f,0x69,0x6e, + 0x5b,0x33,0x30,0x5d,0x3a,0x30,0x3b,0x0a,0x6d,0x5b,0x31,0x35,0x5d,0x3d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x38,0x29,0x3f,0x69,0x6e,0x5b,0x33,0x31, + 0x5d,0x3a,0x30,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x20,0x25,0x20,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x0a, + 0x6d,0x5b,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x2d,0x31,0x32,0x38,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x5d,0x20,0x26,0x3d, + 0x20,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x2d,0x31,0x29,0x3e,0x3e,0x28,0x36,0x34,0x2d,0x28,0x69,0x6e,0x5f,0x6c,0x65,0x6e,0x20,0x25,0x20,0x73,0x69,0x7a,0x65, + 0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x2a,0x38,0x29,0x3b,0x0a,0x42,0x4c,0x41,0x4b,0x45,0x32,0x42,0x5f,0x52,0x4f,0x55,0x4e,0x44,0x53,0x28,0x29,0x3b, + 0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x30,0x29,0x20,0x6f,0x75,0x74,0x5b,0x30,0x5d,0x3d,0x68,0x5b,0x30,0x5d,0x5e,0x76,0x5b,0x30,0x5d,0x5e, + 0x76,0x5b,0x38,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x38,0x29,0x20,0x6f,0x75,0x74,0x5b,0x31,0x5d,0x3d,0x68,0x5b,0x31,0x5d,0x5e, + 0x76,0x5b,0x31,0x5d,0x5e,0x76,0x5b,0x39,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x36,0x29,0x20,0x6f,0x75,0x74,0x5b,0x32,0x5d, + 0x3d,0x68,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x32,0x5d,0x5e,0x76,0x5b,0x31,0x30,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x29, + 0x20,0x6f,0x75,0x74,0x5b,0x33,0x5d,0x3d,0x68,0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x33,0x5d,0x5e,0x76,0x5b,0x31,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f, + 0x6c,0x65,0x6e,0x3e,0x33,0x32,0x29,0x20,0x6f,0x75,0x74,0x5b,0x34,0x5d,0x3d,0x68,0x5b,0x34,0x5d,0x5e,0x76,0x5b,0x34,0x5d,0x5e,0x76,0x5b,0x31,0x32,0x5d,0x3b,0x0a, + 0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x30,0x29,0x20,0x6f,0x75,0x74,0x5b,0x35,0x5d,0x3d,0x68,0x5b,0x35,0x5d,0x5e,0x76,0x5b,0x35,0x5d,0x5e, + 0x76,0x5b,0x31,0x33,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x38,0x29,0x20,0x6f,0x75,0x74,0x5b,0x36,0x5d,0x3d,0x68,0x5b,0x36, + 0x5d,0x5e,0x76,0x5b,0x36,0x5d,0x5e,0x76,0x5b,0x31,0x34,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x35,0x36,0x29,0x20,0x6f,0x75,0x74, + 0x5b,0x37,0x5d,0x3d,0x68,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x37,0x5d,0x5e,0x76,0x5b,0x31,0x35,0x5d,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75, + 0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c, + 0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x2a,0x6f,0x75, + 0x74,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x69,0x6e,0x2c,0x75,0x69,0x6e,0x74,0x20,0x69, + 0x6e,0x53,0x74,0x72,0x69,0x64,0x65,0x42,0x79,0x74,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x70,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x20,0x69,0x6e,0x29,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x69,0x6e,0x53, + 0x74,0x72,0x69,0x64,0x65,0x42,0x79,0x74,0x65,0x73,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x68,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x29,0x20, + 0x6f,0x75,0x74,0x29,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x2f,0x73,0x69,0x7a,0x65,0x6f, + 0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x6d,0x5b,0x31,0x36,0x5d,0x3d,0x7b,0x20,0x70,0x5b,0x30,0x5d,0x2c,0x70,0x5b, + 0x31,0x5d,0x2c,0x70,0x5b,0x32,0x5d,0x2c,0x70,0x5b,0x33,0x5d,0x2c,0x70,0x5b,0x34,0x5d,0x2c,0x70,0x5b,0x35,0x5d,0x2c,0x70,0x5b,0x36,0x5d,0x2c,0x70,0x5b,0x37,0x5d, + 0x2c,0x70,0x5b,0x38,0x5d,0x2c,0x70,0x5b,0x39,0x5d,0x2c,0x70,0x5b,0x31,0x30,0x5d,0x2c,0x70,0x5b,0x31,0x31,0x5d,0x2c,0x70,0x5b,0x31,0x32,0x5d,0x2c,0x70,0x5b,0x31, + 0x33,0x5d,0x2c,0x70,0x5b,0x31,0x34,0x5d,0x2c,0x70,0x5b,0x31,0x35,0x5d,0x20,0x7d,0x3b,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x68,0x61,0x73,0x68,0x5b,0x38,0x5d,0x3b, + 0x0a,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62,0x6c,0x6f,0x63, + 0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x28,0x68,0x61,0x73,0x68,0x2c,0x6d,0x2c,0x70,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x30,0x29,0x20, + 0x68,0x5b,0x30,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x30,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x38,0x29,0x20,0x68,0x5b,0x31,0x5d, + 0x3d,0x68,0x61,0x73,0x68,0x5b,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x31,0x36,0x29,0x20,0x68,0x5b,0x32,0x5d,0x3d,0x68,0x61, + 0x73,0x68,0x5b,0x32,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x32,0x34,0x29,0x20,0x68,0x5b,0x33,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b, + 0x33,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x33,0x32,0x29,0x20,0x68,0x5b,0x34,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x34,0x5d,0x3b, + 0x0a,0x69,0x66,0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x30,0x29,0x20,0x68,0x5b,0x35,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x35,0x5d,0x3b,0x0a,0x69,0x66, + 0x28,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x34,0x38,0x29,0x20,0x68,0x5b,0x36,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x36,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x75, + 0x74,0x5f,0x6c,0x65,0x6e,0x3e,0x35,0x36,0x29,0x20,0x68,0x5b,0x37,0x5d,0x3d,0x68,0x61,0x73,0x68,0x5b,0x37,0x5d,0x3b,0x0a,0x7d,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66, + 0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x68,0x61,0x73,0x68,0x5f,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x75,0x6e, + 0x64,0x65,0x66,0x20,0x62,0x6c,0x61,0x6b,0x65,0x32,0x62,0x5f,0x35,0x31,0x32,0x5f,0x70,0x72,0x6f,0x63,0x65,0x73,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x62, + 0x6c,0x6f,0x63,0x6b,0x5f,0x6e,0x61,0x6d,0x65,0x0a,0x23,0x75,0x6e,0x64,0x65,0x66,0x20,0x6f,0x75,0x74,0x5f,0x6c,0x65,0x6e,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61, + 0x20,0x4f,0x50,0x45,0x4e,0x43,0x4c,0x20,0x45,0x58,0x54,0x45,0x4e,0x53,0x49,0x4f,0x4e,0x20,0x63,0x6c,0x5f,0x6b,0x68,0x72,0x5f,0x66,0x70,0x36,0x34,0x20,0x3a,0x20, + 0x65,0x6e,0x61,0x62,0x6c,0x65,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x53,0x69,0x7a,0x65,0x20,0x36,0x34,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x36,0x34,0x20,0x28,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x20,0x2d,0x20,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x53,0x69,0x7a, + 0x65,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x41,0x6c,0x69,0x67,0x6e,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x42,0x41,0x53,0x45,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2d,0x20,0x31,0x29,0x20,0x26, + 0x20,0x7e,0x28,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x53,0x69,0x7a,0x65,0x20,0x2d,0x20,0x31,0x29,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6d, + 0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x20,0x35,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x53, + 0x69,0x7a,0x65,0x20,0x31,0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55, + 0x4c,0x20,0x3c,0x3c,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20, + 0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55,0x4c,0x20,0x3c,0x3c,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x53,0x69, + 0x7a,0x65,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x61,0x73,0x20,0x31,0x30, + 0x32,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x63,0x6f,0x6e,0x73,0x74,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x30,0x78,0x33, + 0x30,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x34, + 0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x34,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x4d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55,0x4c,0x20, + 0x3c,0x3c,0x20,0x28,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x20,0x2b,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65, + 0x6e,0x74,0x42,0x69,0x74,0x73,0x29,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x43, + 0x6f,0x75,0x6e,0x74,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x20, + 0x28,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x43,0x6f,0x75,0x6e,0x74,0x20,0x2f,0x20,0x32,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x6f,0x6e, + 0x64,0x69,0x74,0x69,0x6f,0x6e,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x20,0x3c,0x3c,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x42, + 0x49,0x54,0x53,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x4f,0x66,0x66,0x73,0x65, + 0x74,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x74, + 0x6f,0x72,0x65,0x4c,0x33,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x20,0x31,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x61,0x74,0x61,0x73,0x65, + 0x74,0x45,0x78,0x74,0x72,0x61,0x49,0x74,0x65,0x6d,0x73,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x45,0x58,0x54, + 0x52,0x41,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2f,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x44,0x41,0x54,0x41,0x53,0x45,0x54,0x5f,0x49,0x54,0x45,0x4d,0x5f,0x53, + 0x49,0x5a,0x45,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4e,0x65,0x65,0x64,0x73,0x44,0x69,0x73,0x70,0x6c,0x61, + 0x63,0x65,0x6d,0x65,0x6e,0x74,0x20,0x35,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x09,0x09,0x30,0x0a, + 0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x09,0x09,0x33,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49, + 0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x09,0x09,0x36,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x09,0x09,0x09,0x31,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x48,0x49,0x46,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x09,0x31,0x35,0x0a,0x23, + 0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x31,0x37,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x36,0x34,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x31,0x38,0x0a,0x23,0x64,0x65, + 0x66,0x69,0x6e,0x65,0x20,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x31,0x39,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x09,0x32,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4e,0x55, + 0x4d,0x5f,0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x32,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4e,0x55,0x4d,0x5f,0x46,0x50, + 0x5f,0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x09,0x32,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f, + 0x50,0x09,0x09,0x09,0x28,0x38,0x20,0x3c,0x3c,0x20,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66, + 0x20,0x75,0x63,0x68,0x61,0x72,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x73,0x68,0x6f,0x72,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x69,0x6e,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x3b,0x0a, + 0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20, + 0x69,0x6e,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x3b,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x3b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42, + 0x69,0x74,0x73,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74, + 0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x3d,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x3e,0x3e,0x35,0x39,0x3b,0x20,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74, + 0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x3d,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x26,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x3b,0x0a, + 0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x2b,0x3d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x61,0x73,0x3b,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74, + 0x20,0x26,0x3d,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x20,0x3c,0x3c,0x3d,0x20,0x6d, + 0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x65,0x78, + 0x70,0x6f,0x6e,0x65,0x6e,0x74,0x7c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x67,0x65,0x74, + 0x53,0x74,0x61,0x74,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x29, + 0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x3d,0x63,0x6f,0x6e,0x73,0x74,0x45,0x78,0x70,0x6f,0x6e,0x65, + 0x6e,0x74,0x42,0x69,0x74,0x73,0x3b,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x7c,0x3d,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x3e,0x3e,0x28,0x36,0x34,0x2d, + 0x73,0x74,0x61,0x74,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x29,0x29,0x3c,0x3c,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x45,0x78,0x70, + 0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x3b,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x20,0x3c,0x3c,0x3d,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61, + 0x53,0x69,0x7a,0x65,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x20,0x67,0x65,0x74,0x46,0x6c,0x6f,0x61,0x74,0x4d,0x61,0x73,0x6b,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x29, + 0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x73,0x6b,0x32,0x32,0x62,0x69,0x74,0x3d,0x28,0x31,0x55,0x4c, + 0x3c,0x3c,0x32,0x32,0x29,0x2d,0x31,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x26,0x6d,0x61,0x73,0x6b,0x32,0x32,0x62, + 0x69,0x74,0x29,0x7c,0x67,0x65,0x74,0x53,0x74,0x61,0x74,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x29,0x3b,0x0a, + 0x7d,0x0a,0x76,0x6f,0x69,0x64,0x20,0x73,0x65,0x74,0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32, + 0x5f,0x74,0x20,0x2a,0x64,0x73,0x74,0x5f,0x62,0x75,0x66,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x4e,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x74,0x65,0x70,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30, + 0x29,0x2a,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x38,0x5f,0x74,0x2a,0x20,0x64,0x73,0x74,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x64,0x73,0x74,0x5f, + 0x62,0x75,0x66,0x29,0x2b,0x69,0x3b,0x0a,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x69,0x3c,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x29,0x2a,0x4e,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x64,0x73,0x74,0x29, + 0x3d,0x76,0x61,0x6c,0x75,0x65,0x3b,0x0a,0x64,0x73,0x74,0x2b,0x3d,0x73,0x74,0x65,0x70,0x3b,0x0a,0x69,0x2b,0x3d,0x73,0x74,0x65,0x70,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a, + 0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x69,0x6d,0x75,0x6c,0x5f,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x64,0x69,0x76,0x69,0x73,0x6f,0x72,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x28,0x64,0x69,0x76,0x69,0x73,0x6f,0x72,0x26,0x28,0x64,0x69,0x76,0x69,0x73,0x6f,0x72, + 0x2d,0x31,0x29,0x29,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x31,0x55,0x4c,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x70,0x32,0x65,0x78,0x70,0x36,0x33,0x3d,0x31,0x55,0x4c,0x3c,0x3c,0x36,0x33,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x20,0x71,0x75,0x6f,0x74,0x69,0x65,0x6e,0x74,0x3d,0x70,0x32,0x65,0x78,0x70,0x36,0x33,0x2f,0x64,0x69,0x76,0x69,0x73,0x6f,0x72,0x3b,0x0a,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x64,0x65,0x72,0x3d,0x70,0x32,0x65,0x78,0x70,0x36,0x33,0x20,0x25,0x20,0x64,0x69,0x76,0x69,0x73,0x6f,0x72, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x73,0x72,0x3d,0x33,0x31,0x2d,0x63,0x6c,0x7a,0x28,0x64,0x69,0x76,0x69, + 0x73,0x6f,0x72,0x29,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x30,0x3b,0x20,0x73,0x68,0x69, + 0x66,0x74,0x3c,0x3d,0x62,0x73,0x72,0x3b,0x20,0x2b,0x2b,0x73,0x68,0x69,0x66,0x74,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x62, + 0x3d,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x64,0x65,0x72,0x3e,0x3d,0x64,0x69,0x76,0x69,0x73,0x6f,0x72,0x2d,0x72,0x65,0x6d,0x61,0x69,0x6e,0x64,0x65,0x72,0x29,0x3b, + 0x0a,0x71,0x75,0x6f,0x74,0x69,0x65,0x6e,0x74,0x3d,0x28,0x71,0x75,0x6f,0x74,0x69,0x65,0x6e,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x62,0x3f,0x31,0x3a,0x30,0x29,0x3b, + 0x0a,0x72,0x65,0x6d,0x61,0x69,0x6e,0x64,0x65,0x72,0x3d,0x28,0x72,0x65,0x6d,0x61,0x69,0x6e,0x64,0x65,0x72,0x3c,0x3c,0x31,0x29,0x2d,0x28,0x62,0x3f,0x64,0x69,0x76, + 0x69,0x73,0x6f,0x72,0x3a,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x71,0x75,0x6f,0x74,0x69,0x65,0x6e,0x74,0x3b,0x0a,0x7d,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x61,0x2c,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x76,0x61,0x6c,0x75, + 0x65,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x28,0x28,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x26,0x28,0x61,0x29,0x29,0x5b,0x28,0x70,0x6f,0x73,0x69,0x74,0x69, + 0x6f,0x6e,0x29,0x5d,0x20,0x3d,0x20,0x28,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x20,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x75,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x20,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x61,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f, + 0x74,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x20,0x7b,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x61,0x3e,0x3e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69, + 0x6f,0x6e,0x3c,0x3c,0x33,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x3b,0x20,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d, + 0x61,0x78,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x20,0x6e,0x65,0x78,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x20,0x64,0x6f,0x20,0x7b,0x20,0x69,0x66,0x20,0x28,0x28, + 0x76,0x61,0x6c,0x75,0x65,0x29,0x20,0x3c,0x20,0x28,0x6e,0x65,0x78,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x29,0x20,0x28,0x76,0x61,0x6c,0x75,0x65,0x29,0x20,0x3d, + 0x20,0x28,0x6e,0x65,0x78,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x20,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x30,0x29,0x0a,0x5f,0x5f,0x61,0x74,0x74, + 0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x33, + 0x32,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x69,0x6e,0x69,0x74,0x5f,0x76,0x6d,0x28,0x5f, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5f,0x64,0x61,0x74,0x61, + 0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69, + 0x74,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f, + 0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x20,0x65,0x78,0x65,0x63, + 0x5f,0x74,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x74,0x79,0x70,0x65,0x64,0x65,0x66,0x20,0x75,0x69,0x6e,0x74,0x31,0x36,0x5f,0x74,0x20,0x65,0x78,0x65,0x63,0x5f, + 0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x65,0x63,0x75, + 0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5f,0x62,0x75,0x66,0x5b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49, + 0x5a,0x45,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x2a,0x28,0x33,0x32,0x2f,0x38,0x29,0x2a,0x73,0x69,0x7a,0x65,0x6f, + 0x66,0x28,0x65,0x78,0x65,0x63,0x5f,0x74,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x5d,0x3b,0x0a,0x73,0x65,0x74, + 0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5f,0x62,0x75,0x66,0x2c,0x73,0x69,0x7a,0x65,0x6f, + 0x66,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5f,0x62,0x75,0x66,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e, + 0x74,0x33,0x32,0x5f,0x74,0x29,0x2c,0x30,0x29,0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d, + 0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69, + 0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x64,0x78,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2f,0x38,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x75,0x62,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x20,0x25,0x20,0x38,0x3b,0x0a,0x5f, + 0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x65,0x78,0x65,0x63,0x5f,0x74,0x2a,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x3d,0x28,0x5f, + 0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x65,0x78,0x65,0x63,0x5f,0x74,0x2a,0x29,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5f,0x62, + 0x75,0x66,0x2b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2f,0x38,0x29,0x2a,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50, + 0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x2a,0x73,0x69,0x7a, + 0x65,0x6f,0x66,0x28,0x65,0x78,0x65,0x63,0x5f,0x74,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x5f, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x52,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x2b,0x69,0x64,0x78,0x2a,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45, + 0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x52,0x5b,0x73,0x75,0x62,0x5d,0x3d,0x30, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x65,0x6e,0x74,0x72,0x6f, + 0x70,0x79,0x3d,0x28,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x65,0x6e, + 0x74,0x72,0x6f,0x70,0x79,0x5f,0x64,0x61,0x74,0x61,0x29,0x2b,0x69,0x64,0x78,0x2a,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a, + 0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x20, + 0x41,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x29,0x28,0x52,0x2b,0x32,0x34,0x29,0x3b,0x0a,0x41,0x5b,0x73,0x75, + 0x62,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74, + 0x72,0x6f,0x70,0x79,0x5b,0x73,0x75,0x62,0x5d,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x75,0x62,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x74,0x65,0x72, + 0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x30,0x29,0x0a,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x5b,0x69,0x64,0x78,0x5d,0x3d,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x2b,0x31,0x32,0x38,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45, + 0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61, + 0x6e,0x67,0x65,0x64,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x3d,0x30,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c, + 0x2d,0x31,0x2c,0x2d,0x31,0x20,0x7d,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d, + 0x30,0x3b,0x20,0x69,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a, + 0x7b,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67, + 0x72,0x61,0x6d,0x2b,0x69,0x29,0x20,0x26,0x3d,0x20,0x7e,0x28,0x30,0x78,0x46,0x38,0x55,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x32,0x20,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x69,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74, + 0x32,0x20,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x66,0x66,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x73,0x74, + 0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x38,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73, + 0x72,0x63,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x31,0x36,0x29,0x26,0x37,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x41,0x44,0x44,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f, + 0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x2b, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52, + 0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x69,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x31,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66, + 0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x2b,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x53,0x55,0x42,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48, + 0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c, + 0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c, + 0x5f,0x52,0x43,0x50,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2d,0x31,0x29,0x29,0x0a,0x7b,0x0a, + 0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a, + 0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74, + 0x2c,0x69,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64, + 0x2c,0x64,0x73,0x74,0x2c,0x31,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67, + 0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x2b,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58, + 0x4f,0x52,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47, + 0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65, + 0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x69,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x31,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72, + 0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69, + 0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70, + 0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28, + 0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f, + 0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x69,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x2c,0x31,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x73,0x72,0x63,0x2c,0x69,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x73,0x72,0x63,0x2c,0x31,0x29,0x3b,0x0a,0x23,0x65, + 0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x73,0x72,0x63,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f, + 0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x2b,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x4d,0x55,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x69,0x29,0x7c,0x3d,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38, + 0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x2b,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x53,0x55,0x42,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55, + 0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x63, + 0x72,0x65,0x67,0x3d,0x64,0x73,0x74,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a, + 0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x63,0x68,0x61,0x6e,0x67,0x65,0x3d,0x67, + 0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x29, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x67,0x65,0x74, + 0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x2c,0x64,0x73,0x74,0x29,0x3d,0x3d,0x30, + 0x29,0x3f,0x2d,0x31,0x3a,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x63,0x68,0x61,0x6e,0x67,0x65,0x29,0x3b,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x69,0x29,0x3d,0x28,0x73,0x72, + 0x63,0x5f,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x63,0x72,0x65,0x67,0x7c,0x28,0x28,0x6c, + 0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x3d,0x2d,0x31,0x29,0x3f,0x30,0x78,0x39,0x30,0x3a,0x30,0x78,0x31,0x30,0x29,0x29,0x3c,0x3c,0x38,0x29,0x7c, + 0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x6c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x3c, + 0x3c,0x31,0x36,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3b,0x0a, + 0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61, + 0x6d,0x2b,0x69,0x29,0x3d,0x28,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x46,0x46,0x30,0x30,0x30,0x30,0x46,0x46,0x55,0x29,0x7c,0x28,0x28, + 0x63,0x72,0x65,0x67,0x7c,0x30,0x78,0x31,0x30,0x29,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x6c,0x61,0x73,0x74,0x43,0x68,0x61, + 0x6e,0x67,0x65,0x64,0x2b,0x31,0x29,0x7c,0x3d,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52, + 0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3c,0x3d,0x20,0x32,0x35,0x36,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x6d,0x70,0x3d,0x69, + 0x7c,0x28,0x69,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x74,0x6d,0x70, + 0x7c,0x28,0x74,0x6d,0x70,0x3c,0x3c,0x31,0x36,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3c,0x3c,0x33,0x32,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65, + 0x64,0x3d,0x30,0x78,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x31,0x55,0x4c,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x30,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x31,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x5b,0x32,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b, + 0x33,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x34,0x5d,0x3d,0x69,0x3b,0x0a, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x35,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x36,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74, + 0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x37,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x46,0x50,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x53,0x63,0x72,0x61, + 0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c, + 0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x61,0x73,0x74,0x5f,0x6d, + 0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x73, + 0x6c,0x6f,0x74,0x73,0x5f,0x75,0x73,0x65,0x64,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75, + 0x63,0x74,0x69,0x6f,0x6e,0x73,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74, + 0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74, + 0x69,0x6f,0x6e,0x5f,0x66,0x70,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68, + 0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x5f,0x6d,0x61,0x72,0x6b,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x66, + 0x61,0x6c,0x73,0x65,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x32,0x20,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x69,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f, + 0x74,0x20,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x66,0x66,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64, + 0x73,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x38,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x73,0x72,0x63,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x31,0x36,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x6d,0x6f,0x64,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x32,0x34,0x29,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x62,0x72, + 0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x29,0x29,0x21,0x3d, + 0x30,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f, + 0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x3b, + 0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f, + 0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x73, + 0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e, + 0x63,0x79,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65, + 0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x73,0x72,0x63, + 0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e, + 0x63,0x79,0x3d,0x28,0x64,0x73,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3e,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3f,0x64,0x73,0x74, + 0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3a,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x20,0x6d,0x65,0x6d,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x28,0x28,0x64,0x73,0x74,0x3d,0x3d,0x73,0x72,0x63, + 0x29,0x26,0x26,0x28,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x36,0x34,0x29,0x3e, + 0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x32,0x29,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79, + 0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x75,0x6c,0x6c,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x6d,0x65,0x6d, + 0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x75,0x6c,0x6c,0x5f,0x72, + 0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x30,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72, + 0x79,0x5f,0x6f,0x70,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x73,0x74,0x6f,0x72,0x65, + 0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x6e,0x6f,0x70,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20, + 0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x73,0x77,0x61,0x70,0x3d,0x66,0x61, + 0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c, + 0x20,0x69,0x73,0x5f,0x66,0x70,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x66,0x61, + 0x6c,0x73,0x65,0x3b,0x0a,0x64,0x6f,0x20,0x7b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74, + 0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f,0x72,0x65,0x61,0x64,0x5f, + 0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61, + 0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d, + 0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x29, + 0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65, + 0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f, + 0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d, + 0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69, + 0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79, + 0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f, + 0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f, + 0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63, + 0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f, + 0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64, + 0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f, + 0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b, + 0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65, + 0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f,0x72,0x65,0x61, + 0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72, + 0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55, + 0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55, + 0x4c,0x5f,0x52,0x43,0x50,0x29,0x0a,0x7b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x69,0x66,0x28,0x69, + 0x6e,0x73,0x74,0x2e,0x79,0x26,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2d,0x31,0x29,0x29,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x64,0x73,0x74,0x5f,0x6c,0x61, + 0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x73,0x5f,0x6e,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a, + 0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x3b, + 0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x29,0x0a, + 0x7b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x64,0x73,0x74, + 0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61, + 0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x66,0x75,0x6c,0x6c,0x5f,0x72, + 0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a, + 0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58, + 0x4f,0x52,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f, + 0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e, + 0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70, + 0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x73,0x5f,0x73,0x77,0x61,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69, + 0x66,0x28,0x64,0x73,0x74,0x21,0x3d,0x73,0x72,0x63,0x29,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74, + 0x65,0x6e,0x63,0x79,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x73,0x5f,0x6e,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d, + 0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b, + 0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63, + 0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61, + 0x64,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x20,0x25,0x3d,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69, + 0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x20,0x25,0x3d,0x20, + 0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79, + 0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74, + 0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61, + 0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79, + 0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65, + 0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46, + 0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x20,0x25,0x3d,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74, + 0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e, + 0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65, + 0x61,0x64,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x20,0x25,0x3d,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61, + 0x74,0x65,0x6e,0x63,0x79,0x2c,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c, + 0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70, + 0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b, + 0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a, + 0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x29,0x0a, + 0x7b,0x0a,0x64,0x73,0x74,0x20,0x25,0x3d,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e, + 0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73, + 0x74,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73, + 0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f, + 0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x2b,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63, + 0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74, + 0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73,0x65, + 0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x4d,0x55,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46, + 0x44,0x49,0x56,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e, + 0x74,0x46,0x6c,0x74,0x29,0x2b,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d, + 0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b, + 0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29, + 0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c, + 0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f, + 0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x2b,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x3b,0x0a,0x6c, + 0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46, + 0x50,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x66,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d, + 0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x29,0x0a,0x7b,0x0a,0x69,0x73,0x5f,0x73,0x72,0x63,0x5f,0x72,0x65,0x61,0x64,0x3d,0x66,0x61,0x6c,0x73, + 0x65,0x3b,0x0a,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x64,0x73,0x74,0x5f,0x6c, + 0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x6c,0x61,0x73, + 0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d, + 0x73,0x72,0x63,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a,0x69,0x73,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72, + 0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f, + 0x55,0x4e,0x44,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f, + 0x52,0x45,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x5f,0x72,0x65,0x61,0x64,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3b,0x0a, + 0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x28,0x6c,0x61,0x73,0x74,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f, + 0x6f,0x70,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52, + 0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a, + 0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x73,0x74,0x6f,0x72,0x65,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x6f, + 0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x3b,0x0a,0x69,0x73,0x5f,0x6e, + 0x6f,0x70,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x66,0x61,0x6c,0x73,0x65,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f, + 0x6e,0x6f,0x70,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x75,0x70, + 0x64,0x61,0x74,0x65,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x5f,0x6d,0x61,0x72,0x6b,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x7d,0x0a, + 0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72, + 0x67,0x65,0x74,0x5f,0x6d,0x61,0x72,0x6b,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a, + 0x29,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x69,0x29,0x7c,0x3d,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74, + 0x65,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x5f,0x6d,0x61,0x72,0x6b,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x69,0x73,0x5f,0x62, + 0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x69,0x72, + 0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f, + 0x73,0x6c,0x6f,0x74,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73, + 0x6c,0x6f,0x74,0x2c,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x69, + 0x66,0x28,0x69,0x73,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x29,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2c,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x63, + 0x66,0x72,0x6f,0x75,0x6e,0x64,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2c,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x69,0x73,0x5f,0x66,0x70,0x3f,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x46,0x50,0x3a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65, + 0x2c,0x64,0x73,0x74,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x73, + 0x77,0x61,0x70,0x29,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c, + 0x6f,0x74,0x2c,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x2c,0x73,0x72, + 0x63,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x6c, + 0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x3b,0x0a,0x75,0x70,0x64,0x61, + 0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2c,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64, + 0x5f,0x73,0x6c,0x6f,0x74,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70,0x29,0x0a,0x7b,0x0a,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3d, + 0x2d,0x31,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64, + 0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x20,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3c,0x30,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28, + 0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6a,0x5d,0x3d,0x3d,0x30,0x29,0x26,0x26,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69, + 0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6a,0x2b,0x31,0x5d,0x3d,0x3d,0x30,0x29,0x26,0x26,0x28,0x28,0x6a,0x2b,0x31,0x29,0x20,0x25,0x20,0x57,0x4f,0x52,0x4b,0x45, + 0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x29,0x0a,0x7b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x62,0x6c,0x6f,0x63,0x6b,0x65,0x64,0x3d,0x66,0x61,0x6c, + 0x73,0x65,0x3b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x3d,0x28,0x6a,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45, + 0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3b,0x20,0x6b,0x3c,0x6a,0x3b,0x20,0x2b, + 0x2b,0x6b,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x5d,0x7c,0x7c,0x28,0x6b,0x3d,0x3d, + 0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x29,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x65,0x78,0x65,0x63,0x75, + 0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x5d,0x5d,0x2e,0x78,0x3b,0x0a,0x69,0x66,0x28,0x28,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x30,0x78,0x32,0x30, + 0x3c,0x3c,0x38,0x29,0x29,0x3d,0x3d,0x30,0x29,0x26,0x26,0x28,0x28,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x30,0x78,0x35,0x30,0x3c,0x3c,0x38,0x29,0x29,0x21,0x3d,0x30, + 0x29,0x7c,0x7c,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x29,0x0a,0x7b,0x0a,0x62,0x6c,0x6f,0x63,0x6b,0x65,0x64,0x3d, + 0x74,0x72,0x75,0x65,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x21,0x62,0x6c,0x6f,0x63,0x6b,0x65, + 0x64,0x29,0x0a,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x3d,0x28,0x6a,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50, + 0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3b,0x20,0x6b,0x3c,0x6a,0x3b,0x20, + 0x2b,0x2b,0x6b,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x5d,0x7c,0x7c,0x28,0x6b,0x3d, + 0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x29,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x65,0x78,0x65,0x63, + 0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x5d,0x5d,0x2e,0x78,0x3b,0x0a,0x69,0x66,0x28,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x30,0x78,0x32,0x30, + 0x3c,0x3c,0x38,0x29,0x29,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6a,0x5d,0x3d,0x65,0x78, + 0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x5d,0x3b,0x0a,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b, + 0x6a,0x2b,0x31,0x5d,0x3d,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6b,0x2b,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x66,0x69,0x72, + 0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x3d,0x6b,0x29,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e, + 0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x6a,0x3b,0x0a,0x69,0x66,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72, + 0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x3d,0x6b,0x2b,0x31,0x29,0x20,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74, + 0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x6a,0x2b,0x31,0x3b,0x0a,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3d,0x6b,0x3b,0x0a,0x62,0x72,0x65, + 0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3c,0x30,0x29,0x0a,0x7b,0x0a,0x73,0x6c, + 0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3d,0x6a,0x3b,0x0a,0x7d,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x65,0x6c, + 0x73,0x65,0x0a,0x7b,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6a,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65, + 0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x20,0x6a,0x3c,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a, + 0x7b,0x0a,0x69,0x66,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6a,0x5d,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x73,0x6c,0x6f, + 0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x3d,0x6a,0x3b,0x0a,0x62,0x72,0x65,0x61,0x6b,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x3d,0x3d,0x30, + 0x29,0x0a,0x7b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x73,0x6c,0x6f,0x74,0x5f, + 0x74,0x6f,0x5f,0x75,0x73,0x65,0x3b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x66,0x70,0x3d,0x69,0x73,0x5f, + 0x66,0x70,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x29,0x0a,0x7b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c, + 0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64,0x3d,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2d,0x28,0x73, + 0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x20,0x25,0x20,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2b,0x57, + 0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3b,0x0a,0x7d,0x0a,0x2b,0x2b,0x6e,0x75,0x6d,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63, + 0x74,0x69,0x6f,0x6e,0x73,0x3b,0x0a,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73, + 0x65,0x5d,0x3d,0x69,0x3b,0x0a,0x2b,0x2b,0x6e,0x75,0x6d,0x5f,0x73,0x6c,0x6f,0x74,0x73,0x5f,0x75,0x73,0x65,0x64,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70, + 0x29,0x0a,0x7b,0x0a,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2b,0x31, + 0x5d,0x3d,0x69,0x3b,0x0a,0x2b,0x2b,0x6e,0x75,0x6d,0x5f,0x73,0x6c,0x6f,0x74,0x73,0x5f,0x75,0x73,0x65,0x64,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73, + 0x65,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2b,0x31,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x73,0x72,0x63, + 0x5f,0x72,0x65,0x61,0x64,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x2c,0x73,0x72,0x63,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d, + 0x61,0x78,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52, + 0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63, + 0x6c,0x65,0x2c,0x73,0x72,0x63,0x2c,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70, + 0x29,0x0a,0x7b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x6c,0x61,0x73,0x74,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x6f,0x70,0x5f,0x73,0x6c, + 0x6f,0x74,0x2c,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x63,0x66,0x72,0x6f,0x75,0x6e,0x64, + 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x3d,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63, + 0x79,0x7c,0x28,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74, + 0x65,0x6e,0x63,0x79,0x46,0x50,0x3d,0x74,0x7c,0x28,0x74,0x3c,0x3c,0x31,0x36,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63, + 0x79,0x46,0x50,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x7c,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c, + 0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x3c,0x3c,0x33,0x32,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70,0x29,0x0a, + 0x7b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x46,0x50,0x2c,0x64,0x73,0x74, + 0x2c,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x3d,0x67,0x65, + 0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x46,0x50,0x2c,0x64,0x73,0x74,0x29,0x3b, + 0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57,0x4f, + 0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x46,0x50,0x2c,0x64,0x73,0x74,0x2c,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65, + 0x0a,0x7b,0x0a,0x69,0x66,0x28,0x21,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x73,0x74,0x6f,0x72,0x65,0x26,0x26,0x21,0x69,0x73,0x5f,0x6e,0x6f,0x70,0x29, + 0x0a,0x7b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x64,0x73,0x74,0x2c, + 0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x73,0x77,0x61,0x70,0x29,0x0a,0x73,0x65,0x74,0x5f,0x62, + 0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x2c,0x73,0x72,0x63,0x2c,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74, + 0x65,0x6e,0x63,0x79,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78, + 0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48, + 0x41,0x53,0x48,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65, + 0x2c,0x64,0x73,0x74,0x2c,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x29,0x0a,0x7b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x3d,0x6e,0x65,0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x7c,0x28,0x6e,0x65, + 0x78,0x74,0x5f,0x6c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d, + 0x74,0x7c,0x28,0x74,0x3c,0x3c,0x31,0x36,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x7c,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3c,0x3c,0x33,0x32,0x29, + 0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x6d,0x65,0x6d,0x6f,0x72,0x79,0x5f,0x73,0x74,0x6f,0x72,0x65,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f, + 0x74,0x20,0x76,0x61,0x6c,0x75,0x65,0x3d,0x67,0x65,0x74,0x5f,0x62,0x79,0x74,0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63, + 0x6c,0x65,0x2c,0x64,0x73,0x74,0x29,0x3b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x76,0x61,0x6c,0x75,0x65,0x2c,0x73,0x6c,0x6f,0x74,0x5f,0x74, + 0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x3b,0x0a,0x73,0x65,0x74,0x5f,0x62,0x79,0x74, + 0x65,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x52,0x65,0x61,0x64,0x43,0x79,0x63,0x6c,0x65,0x2c,0x64,0x73,0x74,0x2c,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x0a, + 0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57, + 0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2b,0x31,0x3b,0x0a,0x69,0x66,0x28,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x3e, + 0x3d,0x53,0x74,0x6f,0x72,0x65,0x4c,0x33,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67, + 0x68,0x4c,0x61,0x74,0x65,0x6e,0x63,0x79,0x3d,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2f,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45, + 0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2b,0x31,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e, + 0x5b,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x5d,0x7c,0x7c,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e, + 0x5f,0x73,0x6c,0x6f,0x74,0x29,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f, + 0x74,0x5f,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61, + 0x6d,0x5b,0x69,0x5d,0x2e,0x78,0x7c,0x3d,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x3b,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65, + 0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x66,0x61,0x6c,0x73,0x65,0x3b,0x0a,0x7d,0x0a, + 0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70,0x29,0x0a,0x2b,0x2b,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74, + 0x3b,0x0a,0x64,0x6f,0x20,0x7b,0x0a,0x2b,0x2b,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x0a,0x7d, + 0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x3c,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x2a,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48, + 0x41,0x53,0x48,0x29,0x26,0x26,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69, + 0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x5d,0x21,0x3d,0x30,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68, + 0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x76,0x61,0x69, + 0x6c,0x61,0x62,0x6c,0x65,0x5f,0x73,0x6c,0x6f,0x74,0x2c,0x69,0x73,0x5f,0x66,0x70,0x3f,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2b,0x32,0x29, + 0x3a,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x2b,0x31,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x70,0x64,0x61,0x74,0x65,0x5f,0x6d,0x61,0x78,0x28, + 0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2c,0x69,0x73,0x5f,0x66,0x70,0x3f,0x28,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73, + 0x65,0x2b,0x31,0x29,0x3a,0x73,0x6c,0x6f,0x74,0x5f,0x74,0x6f,0x5f,0x75,0x73,0x65,0x29,0x3b,0x0a,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x65,0x78,0x65,0x63,0x75,0x74, + 0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5d,0x7c,0x7c,0x28,0x6c,0x61,0x73,0x74,0x5f, + 0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f, + 0x74,0x29,0x7c,0x7c,0x28,0x28,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74, + 0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x29,0x26,0x26,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69, + 0x6f,0x6e,0x5f,0x66,0x70,0x29,0x29,0x0a,0x7b,0x0a,0x2b,0x2b,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x0a,0x7d,0x0a,0x2d,0x2d, + 0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70,0x26,0x26,0x28,0x6c,0x61,0x73,0x74,0x5f, + 0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3e,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x63,0x66, + 0x72,0x6f,0x75,0x6e,0x64,0x29,0x29,0x0a,0x66,0x69,0x72,0x73,0x74,0x5f,0x61,0x6c,0x6c,0x6f,0x77,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x5f,0x63,0x66,0x72,0x6f,0x75, + 0x6e,0x64,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20, + 0x6d,0x61,0x3d,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x38,0x5d,0x29,0x26,0x43,0x61,0x63,0x68,0x65,0x4c, + 0x69,0x6e,0x65,0x41,0x6c,0x69,0x67,0x6e,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6d,0x78,0x3d,0x28,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x30,0x5d,0x29,0x26,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x41,0x6c,0x69,0x67,0x6e, + 0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x3d, + 0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x32,0x5d,0x29,0x3b,0x0a,0x61,0x64,0x64,0x72,0x65,0x73,0x73, + 0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x3d,0x28,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x31,0x29,0x7c, + 0x28,0x28,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x32,0x29,0x3f,0x33,0x55,0x3a,0x32,0x55,0x29,0x3c,0x3c,0x38, + 0x29,0x7c,0x28,0x28,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x34,0x29,0x3f,0x35,0x55,0x3a,0x34,0x55,0x29,0x3c, + 0x3c,0x31,0x36,0x29,0x7c,0x28,0x28,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x38,0x29,0x3f,0x37,0x55,0x3a,0x36, + 0x55,0x29,0x3c,0x3c,0x32,0x34,0x29,0x29,0x2a,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x3d,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x33,0x5d,0x26,0x44, + 0x61,0x74,0x61,0x73,0x65,0x74,0x45,0x78,0x74,0x72,0x61,0x49,0x74,0x65,0x6d,0x73,0x29,0x2a,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x53,0x69,0x7a,0x65,0x3b, + 0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x65,0x4d,0x61,0x73,0x6b,0x3d,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x2a, + 0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x2b,0x31,0x34,0x29,0x3b,0x0a,0x65,0x4d,0x61,0x73,0x6b,0x2e,0x78,0x3d,0x67,0x65,0x74,0x46,0x6c,0x6f,0x61,0x74,0x4d, + 0x61,0x73,0x6b,0x28,0x65,0x4d,0x61,0x73,0x6b,0x2e,0x78,0x29,0x3b,0x0a,0x65,0x4d,0x61,0x73,0x6b,0x2e,0x79,0x3d,0x67,0x65,0x74,0x46,0x6c,0x6f,0x61,0x74,0x4d,0x61, + 0x73,0x6b,0x28,0x65,0x4d,0x61,0x73,0x6b,0x2e,0x79,0x29,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x30,0x5d,0x3d,0x6d,0x61,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x31,0x5d,0x3d,0x6d,0x78,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x32,0x5d,0x3d,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x73,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31, + 0x36,0x29,0x29,0x5b,0x33,0x5d,0x3d,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x2a,0x29,0x28,0x52,0x2b,0x31,0x38,0x29,0x29,0x5b,0x30,0x5d,0x3d,0x65,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65, + 0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65, + 0x78,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5f,0x66,0x73,0x63,0x61,0x6c,0x5f,0x72,0x3d,0x2d, + 0x31,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70, + 0x72,0x6f,0x67,0x72,0x61,0x6d,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x28,0x52, + 0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2b,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x29,0x2f,0x73,0x69,0x7a,0x65, + 0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61, + 0x72,0x67,0x65,0x74,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6b,0x3d,0x2d,0x31,0x3b,0x0a,0x66,0x6f,0x72,0x20, + 0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x3b, + 0x20,0x2b,0x2b,0x69,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x21,0x28,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x69,0x5d,0x7c,0x7c, + 0x28,0x69,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x29,0x7c,0x7c,0x28,0x28,0x69, + 0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x29,0x26,0x26,0x66,0x69,0x72, + 0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x66,0x70,0x29,0x29,0x29,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3d,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20, + 0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3d,0x30,0x3b,0x0a,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x28,0x69,0x2b,0x6e,0x75,0x6d,0x5f,0x77,0x6f, + 0x72,0x6b,0x65,0x72,0x73,0x3c,0x3d,0x6c,0x61,0x73,0x74,0x5f,0x75,0x73,0x65,0x64,0x5f,0x73,0x6c,0x6f,0x74,0x29,0x26,0x26,0x28,0x28,0x69,0x2b,0x6e,0x75,0x6d,0x5f, + 0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x29,0x20,0x25,0x20,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x26,0x26,0x28,0x65, + 0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x69,0x2b,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5d,0x7c,0x7c,0x28,0x69, + 0x2b,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f, + 0x73,0x6c,0x6f,0x74,0x29,0x7c,0x7c,0x28,0x28,0x69,0x2b,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3d,0x3d,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e, + 0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x6c,0x6f,0x74,0x2b,0x31,0x29,0x26,0x26,0x66,0x69,0x72,0x73,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63, + 0x74,0x69,0x6f,0x6e,0x5f,0x66,0x70,0x29,0x29,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x28,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x26,0x31,0x29,0x26, + 0x26,0x28,0x28,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x69,0x2b, + 0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5d,0x5d,0x2e,0x78,0x26,0x28,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38,0x29,0x29,0x21,0x3d,0x30,0x29,0x29,0x0a, + 0x2b,0x2b,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3b,0x0a,0x2b,0x2b,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x7d, + 0x0a,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3d,0x28,0x28,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x2d,0x31,0x29,0x3c,0x3c,0x4e, + 0x55,0x4d,0x5f,0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3c,0x3c, + 0x4e,0x55,0x4d,0x5f,0x46,0x50,0x5f,0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x32,0x20,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e, + 0x5f,0x70,0x6c,0x61,0x6e,0x5b,0x69,0x5d,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x69,0x6e,0x73,0x74,0x3d,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x3b,0x0a, + 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x66,0x66,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x73,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x38,0x29,0x26,0x37,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x72,0x63,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x31,0x36,0x29,0x26,0x37, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6d,0x6f,0x64,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x32,0x34, + 0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x66,0x70,0x3d,0x28,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26, + 0x28,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38,0x29,0x29,0x21,0x3d,0x30,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x66,0x70,0x26,0x26,0x28,0x28,0x69,0x26,0x31,0x29,0x3d, + 0x3d,0x30,0x29,0x29,0x0a,0x2b,0x2b,0x69,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74, + 0x61,0x72,0x67,0x65,0x74,0x3d,0x28,0x73,0x72,0x63,0x5f,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x29,0x29,0x21,0x3d,0x30,0x3b, + 0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x26,0x26,0x28,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61, + 0x72,0x67,0x65,0x74,0x5f,0x73,0x6c,0x6f,0x74,0x3c,0x30,0x29,0x29,0x0a,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x5f,0x73,0x6c,0x6f,0x74, + 0x3d,0x6b,0x3b,0x0a,0x2b,0x2b,0x6b,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x32,0x29,0x20,0x25,0x20,0x34,0x3b,0x0a,0x69, + 0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52, + 0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x68,0x69,0x66,0x74,0x3c,0x3c,0x53,0x48,0x49,0x46,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b, + 0x0a,0x69,0x66,0x28,0x64,0x73,0x74,0x21,0x3d,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4e,0x65,0x65,0x64,0x73,0x44,0x69,0x73,0x70,0x6c,0x61,0x63,0x65,0x6d,0x65, + 0x6e,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x31,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29, + 0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d, + 0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58, + 0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x69,0x6e,0x73, + 0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73, + 0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70, + 0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x33, + 0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44, + 0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c, + 0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b, + 0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a, + 0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d, + 0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31, + 0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28, + 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32, + 0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70, + 0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65, + 0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f, + 0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4f,0x50,0x43, + 0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46, + 0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x69,0x6d, + 0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f, + 0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f, + 0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b, + 0x5d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b, + 0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a, + 0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73, + 0x74,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73, + 0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29, + 0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53, + 0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e, + 0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28, + 0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62, + 0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46, + 0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b, + 0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65, + 0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b, + 0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53, + 0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45, + 0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c, + 0x3d,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43, + 0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c, + 0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72, + 0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e, + 0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f, + 0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d, + 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63, + 0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78, + 0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46, + 0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f, + 0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f, + 0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43, + 0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74, + 0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f, + 0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43, + 0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50, + 0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e, + 0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64, + 0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x29,0x7c,0x28,0x36,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64, + 0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a, + 0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x29, + 0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c, + 0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x36,0x3c, + 0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d, + 0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b, + 0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f, + 0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d, + 0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d, + 0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66, + 0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b, + 0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c, + 0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x34,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a, + 0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d, + 0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d, + 0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f, + 0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43, + 0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x34,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73, + 0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69, + 0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75, + 0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46, + 0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63, + 0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a, + 0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64, + 0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a, + 0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x72,0x3d,0x69, + 0x6d,0x75,0x6c,0x5f,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29,0x3b,0x0a,0x69,0x66,0x28,0x72,0x3d,0x3d,0x31,0x29,0x0a, + 0x7b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50, + 0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78, + 0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46, + 0x53,0x45,0x54,0x29,0x7c,0x28,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c, + 0x3d,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43, + 0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x36,0x34,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c, + 0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x2d,0x31,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d, + 0x5f,0x69,0x6e,0x64,0x65,0x78,0x5d,0x3d,0x28,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x26,0x72,0x29,0x5b,0x30,0x5d, + 0x3b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x31,0x5d,0x3d,0x28,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x26,0x72,0x29,0x5b,0x31,0x5d,0x3b,0x0a,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x3d,0x32,0x3b,0x0a,0x7d, + 0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75, + 0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64, + 0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x35,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45, + 0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78, + 0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28, + 0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45, + 0x54,0x29,0x7c,0x28,0x33,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64, + 0x73,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a, + 0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d, + 0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x63, + 0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f, + 0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29, + 0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c, + 0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x29,0x7c,0x28,0x33,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d, + 0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65, + 0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69, + 0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d, + 0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e, + 0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61, + 0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75, + 0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d, + 0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64, + 0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x29,0x7c,0x28,0x37,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x3d,0x3d,0x64,0x73, + 0x74,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46, + 0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69, + 0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d, + 0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x6f, + 0x70,0x63,0x6f,0x64,0x65,0x3e,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e, + 0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a, + 0x7d,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e, + 0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53, + 0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x38,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45, + 0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d, + 0x28,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x3f,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3a,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x29,0x7c,0x6e,0x75,0x6d, + 0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73, + 0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x31,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45, + 0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78, + 0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d, + 0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f, + 0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x28,0x73,0x72,0x63,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29, + 0x3c,0x3c,0x28,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x2b,0x31,0x29,0x29,0x7c,0x28,0x31,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73, + 0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32, + 0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c, + 0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55, + 0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79, + 0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f, + 0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c, + 0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a, + 0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d, + 0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x64,0x73,0x74, + 0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54, + 0x29,0x7c,0x28,0x28,0x73,0x72,0x63,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x28,0x53,0x52, + 0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x2b,0x31,0x29,0x29,0x7c,0x28,0x31,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29, + 0x7c,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d, + 0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b, + 0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x64, + 0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53, + 0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4e,0x45, + 0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f, + 0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c, + 0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29, + 0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74, + 0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b, + 0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b, + 0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a, + 0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x29,0x0a, + 0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c, + 0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d,0x36,0x34, + 0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x33,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28, + 0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5f,0x66,0x73,0x63,0x61,0x6c,0x5f,0x72,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d, + 0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5f,0x66,0x73,0x63,0x61,0x6c,0x5f,0x72,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b, + 0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5f,0x66,0x73,0x63,0x61,0x6c,0x5f,0x72,0x3d,0x69,0x6d,0x6d,0x5f, + 0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f, + 0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43, + 0x4f,0x55,0x4e,0x54,0x2d,0x31,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5d,0x3d,0x30,0x3b,0x0a, + 0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x31,0x5d,0x3d,0x30,0x78,0x38,0x30,0x46,0x30,0x30,0x30,0x30,0x30,0x55, + 0x4c,0x3b,0x0a,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x3d,0x32,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f, + 0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63, + 0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x2b,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44, + 0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x28,0x73,0x72,0x63,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74, + 0x46,0x6c,0x74,0x29,0x3c,0x3c,0x28,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x2b,0x31,0x29,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x53,0x48,0x49,0x46,0x54,0x5f, + 0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x32,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63, + 0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f, + 0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20, + 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x31,0x3a,0x32,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28, + 0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x2b,0x52,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53, + 0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x35,0x3c,0x3c, + 0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65, + 0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f, + 0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b, + 0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, + 0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43, + 0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49, + 0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69, + 0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f, + 0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f, + 0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x6e, + 0x73,0x74,0x2e,0x78,0x3d,0x28,0x28,0x28,0x64,0x73,0x74,0x20,0x25,0x20,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x2b, + 0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x43,0x6f,0x75,0x6e,0x74,0x46,0x6c,0x74,0x29,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28, + 0x31,0x34,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70, + 0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f, + 0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46, + 0x53,0x51,0x52,0x54,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43, + 0x42,0x52,0x41,0x4e,0x43,0x48,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45, + 0x54,0x29,0x7c,0x28,0x39,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d,0x28, + 0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x63,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x2b,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e, + 0x4f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6d,0x6d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x7c,0x28,0x31,0x55,0x3c, + 0x3c,0x63,0x73,0x68,0x69,0x66,0x74,0x29,0x3b,0x0a,0x69,0x66,0x28,0x63,0x73,0x68,0x69,0x66,0x74,0x3e,0x30,0x29,0x0a,0x69,0x6d,0x6d,0x20,0x26,0x3d,0x20,0x7e,0x28, + 0x31,0x55,0x3c,0x3c,0x28,0x63,0x73,0x68,0x69,0x66,0x74,0x2d,0x31,0x29,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x49,0x4d, + 0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x2d,0x31,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69, + 0x6e,0x64,0x65,0x78,0x5d,0x3d,0x69,0x6d,0x6d,0x3b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x31,0x5d,0x3d, + 0x63,0x73,0x68,0x69,0x66,0x74,0x7c,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74, + 0x5f,0x73,0x6c,0x6f,0x74,0x29,0x3c,0x3c,0x35,0x29,0x3b,0x0a,0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x3d,0x32,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65, + 0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x7d,0x0a,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72, + 0x67,0x65,0x74,0x5f,0x73,0x6c,0x6f,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b, + 0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b, + 0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x3b, + 0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x29, + 0x0a,0x7b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x33,0x3c, + 0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x36,0x33,0x29,0x3c,0x3c,0x49,0x4d, + 0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29, + 0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d, + 0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x29,0x0a,0x7b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34, + 0x29,0x3e,0x3d,0x53,0x74,0x6f,0x72,0x65,0x4c,0x33,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x29,0x3f,0x33,0x3a,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34, + 0x29,0x3f,0x31,0x3a,0x32,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x28,0x64,0x73,0x74,0x3c,0x3c,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29, + 0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x7c,0x28,0x31,0x3c,0x3c,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45, + 0x54,0x29,0x7c,0x28,0x31,0x30,0x3c,0x3c,0x4f,0x50,0x43,0x4f,0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x3d, + 0x69,0x6d,0x6d,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6d,0x6d,0x5f,0x69,0x6e, + 0x64,0x65,0x78,0x3c,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x29,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x69,0x6d,0x6d, + 0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x2b,0x5d,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x30,0x78,0x46,0x43,0x31,0x46,0x46,0x46,0x46,0x46,0x55,0x29,0x7c,0x28, + 0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x31,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x31,0x3a,0x28,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, + 0x3d,0x3d,0x32,0x29,0x3f,0x4c,0x4f,0x43,0x5f,0x4c,0x32,0x3a,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29,0x29,0x3c,0x3c,0x32,0x31,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x0a, + 0x69,0x6e,0x73,0x74,0x2e,0x78,0x3d,0x49,0x4e,0x53,0x54,0x5f,0x4e,0x4f,0x50,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67, + 0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69, + 0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f, + 0x52,0x45,0x3b,0x0a,0x2a,0x28,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78, + 0x7c,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3b,0x0a,0x7d,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x32,0x30,0x29,0x29,0x5b,0x30,0x5d,0x3d,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x63,0x6f,0x6d,0x70,0x69, + 0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29, + 0x28,0x52,0x2b,0x28,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2b,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45,0x29, + 0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6c,0x6f, + 0x61,0x64,0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x2a,0x64,0x73,0x74,0x5f, + 0x62,0x75,0x66,0x2c,0x73,0x69,0x7a,0x65,0x5f,0x74,0x20,0x4e,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69,0x64, + 0x2a,0x20,0x73,0x72,0x63,0x5f,0x62,0x75,0x66,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2a,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x74,0x65,0x70,0x3d,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x73,0x69,0x7a,0x65,0x28,0x30,0x29,0x2a, + 0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x73,0x72,0x63,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x73,0x72,0x63,0x5f,0x62,0x75,0x66,0x29,0x2b,0x67,0x65,0x74,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x69,0x64,0x28,0x30,0x29, + 0x2a,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x2a,0x4e,0x2b,0x69,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x64,0x73,0x74,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x64, + 0x73,0x74,0x5f,0x62,0x75,0x66,0x29,0x2b,0x69,0x3b,0x0a,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x69,0x3c,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36, + 0x34,0x5f,0x74,0x29,0x2a,0x4e,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x64, + 0x73,0x74,0x29,0x3d,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x73,0x72,0x63,0x29,0x3b,0x0a, + 0x73,0x72,0x63,0x2b,0x3d,0x73,0x74,0x65,0x70,0x3b,0x0a,0x64,0x73,0x74,0x2b,0x3d,0x73,0x74,0x65,0x70,0x3b,0x0a,0x69,0x2b,0x3d,0x73,0x74,0x65,0x70,0x3b,0x0a,0x7d, + 0x0a,0x7d,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x6c,0x6f,0x61,0x64,0x5f,0x46,0x5f,0x45,0x5f,0x67,0x72,0x6f,0x75,0x70,0x73,0x28,0x69,0x6e,0x74,0x20,0x76,0x61, + 0x6c,0x75,0x65,0x2c,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x61,0x6e,0x64,0x4d,0x61,0x73,0x6b,0x2c,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6f,0x72, + 0x4d,0x61,0x73,0x6b,0x29,0x0a,0x7b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x74,0x3d,0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f, + 0x72,0x74,0x6e,0x28,0x76,0x61,0x6c,0x75,0x65,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x78,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28, + 0x74,0x29,0x3b,0x0a,0x78,0x20,0x26,0x3d,0x20,0x61,0x6e,0x64,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x78,0x7c,0x3d,0x6f,0x72,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x72,0x65,0x74, + 0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x78,0x29,0x3b,0x0a,0x7d,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x66,0x6d,0x61,0x5f,0x73, + 0x6f,0x66,0x74,0x28,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x61,0x2c,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x62,0x2c,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x63,0x2c,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x72,0x6f,0x75,0x6e, + 0x64,0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x3d,0x3d,0x30,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x66,0x6d,0x61,0x28,0x61,0x2c,0x62,0x2c,0x63,0x29,0x3b, + 0x0a,0x69,0x66,0x28,0x28,0x61,0x3d,0x3d,0x30,0x2e,0x30,0x29,0x7c,0x7c,0x28,0x62,0x3d,0x3d,0x30,0x2e,0x30,0x29,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x63, + 0x3b,0x0a,0x69,0x66,0x28,0x62,0x3d,0x3d,0x31,0x2e,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x63,0x3d,0x3d,0x30,0x2e,0x30,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e, + 0x20,0x61,0x3b,0x0a,0x69,0x66,0x28,0x63,0x3d,0x3d,0x2d,0x61,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d, + 0x69,0x6e,0x75,0x73,0x5f,0x7a,0x65,0x72,0x6f,0x3d,0x31,0x55,0x4c,0x3c,0x3c,0x36,0x33,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x72,0x6f,0x75,0x6e,0x64, + 0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x3d,0x3d,0x31,0x29,0x3f,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x6d,0x69,0x6e,0x75,0x73,0x5f,0x7a,0x65,0x72, + 0x6f,0x29,0x3a,0x30,0x2e,0x30,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74,0x69, + 0x73,0x73,0x61,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x35,0x32,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74, + 0x69,0x73,0x73,0x61,0x5f,0x6d,0x61,0x73,0x6b,0x3d,0x28,0x31,0x55,0x4c,0x3c,0x3c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x73,0x69,0x7a,0x65,0x29,0x2d,0x31, + 0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x68,0x69,0x67,0x68,0x5f,0x62, + 0x69,0x74,0x3d,0x31,0x55,0x4c,0x3c,0x3c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x3d,0x31,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x61,0x73,0x6b,0x3d,0x28,0x31,0x3c,0x3c,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e, + 0x74,0x5f,0x73,0x69,0x7a,0x65,0x29,0x2d,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65, + 0x6e,0x74,0x5f,0x61,0x3d,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x79,0x3e,0x3e,0x32,0x30,0x29,0x26,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e, + 0x74,0x5f,0x6d,0x61,0x73,0x6b,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f, + 0x62,0x3d,0x28,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x62,0x29,0x2e,0x79,0x3e,0x3e,0x32,0x30,0x29,0x26,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d, + 0x61,0x73,0x6b,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x3d,0x28, + 0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x29,0x2e,0x79,0x3e,0x3e,0x32,0x30,0x29,0x26,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x61,0x73,0x6b, + 0x3b,0x0a,0x69,0x66,0x28,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x61,0x3d,0x3d,0x32,0x30,0x34,0x37,0x29,0x7c,0x7c,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65, + 0x6e,0x74,0x5f,0x62,0x3d,0x3d,0x32,0x30,0x34,0x37,0x29,0x7c,0x7c,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x3d,0x3d,0x32,0x30,0x34,0x37,0x29,0x29, + 0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x69,0x6e,0x66,0x3d,0x32,0x30,0x34,0x37,0x55,0x4c,0x3c,0x3c,0x35,0x32, + 0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x69,0x6e,0x66,0x29,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x61,0x3d,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61, + 0x29,0x26,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x6d,0x61,0x73,0x6b,0x29,0x7c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x68,0x69,0x67,0x68,0x5f,0x62, + 0x69,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x62,0x3d,0x28,0x61, + 0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x62,0x29,0x26,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x6d,0x61,0x73,0x6b,0x29,0x7c,0x6d,0x61,0x6e,0x74,0x69,0x73, + 0x73,0x61,0x5f,0x68,0x69,0x67,0x68,0x5f,0x62,0x69,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x61,0x6e,0x74, + 0x69,0x73,0x73,0x61,0x5f,0x63,0x3d,0x28,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x63,0x29,0x26,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x6d,0x61,0x73, + 0x6b,0x29,0x7c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x68,0x69,0x67,0x68,0x5f,0x62,0x69,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x20,0x73,0x69,0x67,0x6e,0x5f,0x61,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x61,0x29,0x2e,0x79,0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x69,0x67,0x6e,0x5f,0x62,0x3d,0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x62,0x29, + 0x2e,0x79,0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x69,0x67,0x6e,0x5f,0x63,0x3d,0x61,0x73, + 0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x63,0x29,0x2e,0x79,0x3e,0x3e,0x33,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6d,0x75,0x6c,0x5f,0x72,0x65, + 0x73,0x75,0x6c,0x74,0x5b,0x32,0x5d,0x3b,0x0a,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f, + 0x61,0x2a,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x62,0x3b,0x0a,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x6d,0x75,0x6c,0x5f, + 0x68,0x69,0x28,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x61,0x2c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x62,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3d,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d, + 0x3e,0x3e,0x34,0x31,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x3d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x61,0x2b,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x62,0x2b,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72, + 0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x31,0x30,0x32,0x33,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x69,0x67,0x6e,0x5f,0x6d,0x75,0x6c,0x5f, + 0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x73,0x69,0x67,0x6e,0x5f,0x61,0x5e,0x73,0x69,0x67,0x6e,0x5f,0x62,0x3b,0x0a,0x69,0x66,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e, + 0x74,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3e,0x3d,0x32,0x30,0x34,0x37,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x20,0x69,0x6e,0x66,0x5f,0x72,0x6e,0x64,0x3d,0x28,0x32,0x30,0x34,0x37,0x55,0x4c,0x3c,0x3c,0x35,0x32,0x29,0x2d,0x28,0x72,0x6f,0x75,0x6e,0x64, + 0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x26,0x31,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x69,0x6e, + 0x66,0x5f,0x72,0x6e,0x64,0x29,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x32,0x5d, + 0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x74,0x5b,0x32,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65, + 0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x69,0x66,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x75,0x6c,0x5f,0x72, + 0x65,0x73,0x75,0x6c,0x74,0x3e,0x3d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x68, + 0x69,0x66,0x74,0x3d,0x32,0x33,0x2d,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c, + 0x74,0x5b,0x30,0x5d,0x3d,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72, + 0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x29,0x7c, + 0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3e,0x3e,0x28,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x29,0x29,0x3b,0x0a,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x32,0x3d,0x28,0x31,0x32,0x37,0x2d,0x35,0x32,0x29,0x2b,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x65, + 0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x2d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x29,0x3b,0x0a, + 0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3e,0x3d,0x36,0x34,0x29,0x0a,0x7b, + 0x0a,0x74,0x5b,0x30,0x5d,0x3d,0x30,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x63,0x3c,0x3c,0x28,0x73,0x68,0x69,0x66,0x74, + 0x32,0x2d,0x36,0x34,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x74,0x5b,0x30,0x5d,0x3d,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x63,0x3c, + 0x3c,0x73,0x68,0x69,0x66,0x74,0x32,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x73,0x68,0x69,0x66,0x74,0x32,0x3f,0x28,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x63, + 0x3e,0x3e,0x28,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x32,0x29,0x29,0x3a,0x30,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x74,0x5b,0x30, + 0x5d,0x3d,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3c,0x2d,0x35,0x32,0x29,0x3f,0x30,0x3a,0x28,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x63,0x3e,0x3e,0x28,0x2d, + 0x73,0x68,0x69,0x66,0x74,0x32,0x29,0x29,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x30,0x3b,0x0a,0x69,0x66,0x28,0x28,0x74,0x5b,0x30,0x5d,0x3d,0x3d,0x30,0x29,0x26,0x26, + 0x28,0x63,0x21,0x3d,0x30,0x2e,0x30,0x29,0x29,0x0a,0x74,0x5b,0x30,0x5d,0x3d,0x31,0x3b,0x0a,0x7d,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61, + 0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x65, + 0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x74,0x5b,0x30,0x5d,0x3d,0x30,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x3d,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x63,0x3c,0x3c,0x31, + 0x31,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x32,0x3d,0x28,0x31,0x32,0x37,0x2d,0x31,0x30,0x34,0x2d,0x65,0x78,0x70,0x5f,0x63, + 0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,0x2b,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x6d,0x75, + 0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x29,0x3b,0x0a,0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3e, + 0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30, + 0x5d,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x32,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65, + 0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x32,0x29,0x7c,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3f,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65, + 0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3e,0x3e,0x28,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x32,0x29,0x29,0x3a,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65, + 0x0a,0x7b,0x0a,0x73,0x68,0x69,0x66,0x74,0x32,0x3d,0x2d,0x73,0x68,0x69,0x66,0x74,0x32,0x3b,0x0a,0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x32,0x3e,0x3d,0x36,0x34, + 0x29,0x0a,0x7b,0x0a,0x73,0x68,0x69,0x66,0x74,0x32,0x2d,0x3d,0x36,0x34,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x28,0x73, + 0x68,0x69,0x66,0x74,0x32,0x3c,0x36,0x34,0x29,0x3f,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3e,0x3e,0x73,0x68,0x69,0x66,0x74,0x32, + 0x29,0x3a,0x30,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x30,0x3b,0x0a,0x69,0x66,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x3d,0x30,0x29,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x31,0x3b,0x0a,0x7d,0x0a,0x65,0x6c, + 0x73,0x65,0x0a,0x7b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30, + 0x5d,0x3e,0x3e,0x73,0x68,0x69,0x66,0x74,0x32,0x29,0x7c,0x28,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3c,0x3c,0x28,0x36,0x34,0x2d,0x73, + 0x68,0x69,0x66,0x74,0x32,0x29,0x29,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c, + 0x74,0x5b,0x31,0x5d,0x3e,0x3e,0x73,0x68,0x69,0x66,0x74,0x32,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72, + 0x65,0x73,0x75,0x6c,0x74,0x3d,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x63,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x69,0x67, + 0x6e,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x69,0x66,0x28,0x73,0x69,0x67,0x6e,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74, + 0x3d,0x3d,0x73,0x69,0x67,0x6e,0x5f,0x63,0x29,0x0a,0x7b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x2b,0x3d,0x74,0x5b,0x30,0x5d,0x3b, + 0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x2b,0x3d,0x74,0x5b,0x31,0x5d,0x2b,0x28,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c, + 0x74,0x5b,0x30,0x5d,0x3c,0x74,0x5b,0x30,0x5d,0x29,0x3f,0x31,0x3a,0x30,0x29,0x3b,0x0a,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3d, + 0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3c,0x74,0x5b,0x31,0x5d,0x29,0x3f,0x31,0x3a,0x30,0x3b,0x0a,0x73,0x69,0x67,0x6e,0x5f,0x66, + 0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x73,0x69,0x67,0x6e,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73, + 0x65,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x6f,0x72,0x72,0x6f,0x77,0x3d,0x28,0x66,0x6d,0x61,0x5f,0x72, + 0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3c,0x74,0x5b,0x30,0x5d,0x29,0x3f,0x31,0x3a,0x30,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30, + 0x5d,0x2d,0x3d,0x74,0x5b,0x30,0x5d,0x3b,0x0a,0x74,0x5b,0x31,0x5d,0x2b,0x3d,0x62,0x6f,0x72,0x72,0x6f,0x77,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e, + 0x74,0x33,0x32,0x5f,0x74,0x20,0x63,0x68,0x61,0x6e,0x67,0x65,0x5f,0x73,0x69,0x67,0x6e,0x3d,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d, + 0x3c,0x74,0x5b,0x31,0x5d,0x29,0x3f,0x31,0x3a,0x30,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x2d,0x3d,0x74,0x5b,0x31,0x5d,0x3b, + 0x0a,0x73,0x69,0x67,0x6e,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x73,0x69,0x67,0x6e,0x5f,0x6d,0x75,0x6c,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74, + 0x5e,0x63,0x68,0x61,0x6e,0x67,0x65,0x5f,0x73,0x69,0x67,0x6e,0x3b,0x0a,0x69,0x66,0x28,0x63,0x68,0x61,0x6e,0x67,0x65,0x5f,0x73,0x69,0x67,0x6e,0x29,0x0a,0x7b,0x0a, + 0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x2d,0x28,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x7e,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75, + 0x6c,0x74,0x5b,0x31,0x5d,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x2b,0x3d,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74, + 0x5b,0x30,0x5d,0x3f,0x30,0x3a,0x31,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x3d,0x30,0x29,0x0a, + 0x7b,0x0a,0x69,0x66,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x3d,0x30,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x30,0x2e, + 0x30,0x3b,0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2d,0x3d,0x36,0x34,0x3b,0x0a,0x66,0x6d,0x61,0x5f, + 0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3d,0x30,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x64,0x65,0x78, + 0x3d,0x63,0x6c,0x7a,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x64,0x65,0x78,0x29,0x0a,0x7b, + 0x0a,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x2d,0x3d,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x66,0x6d,0x61, + 0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3c,0x3c,0x69,0x6e,0x64,0x65,0x78, + 0x29,0x7c,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x30,0x5d,0x3e,0x3e,0x28,0x36,0x34,0x2d,0x69,0x6e,0x64,0x65,0x78,0x29,0x29,0x3b,0x0a,0x7d, + 0x0a,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3d,0x30,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x31,0x31,0x2b,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x6f,0x75,0x6e,0x64,0x5f,0x75,0x70,0x3d,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74, + 0x5b,0x30,0x5d,0x7c,0x7c,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x26,0x28,0x28,0x31,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x29,0x2d, + 0x31,0x29,0x29,0x29,0x3f,0x31,0x3a,0x30,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x20,0x3e,0x3e,0x3d,0x20,0x73,0x68,0x69,0x66, + 0x74,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x20,0x26,0x3d,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x6d,0x61,0x73, + 0x6b,0x3b,0x0a,0x69,0x66,0x28,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x2b,0x73,0x69,0x67,0x6e,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x3d,0x3d,0x32,0x29,0x0a,0x7b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x2b,0x3d,0x72,0x6f,0x75,0x6e,0x64,0x5f,0x75, + 0x70,0x3b,0x0a,0x69,0x66,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x3d,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x68,0x69, + 0x67,0x68,0x5f,0x62,0x69,0x74,0x29,0x0a,0x7b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x3d,0x30,0x3b,0x0a,0x2b,0x2b,0x65,0x78,0x70, + 0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74, + 0x5b,0x31,0x5d,0x7c,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x2b,0x65,0x78,0x70,0x5f,0x63,0x6f,0x72,0x72,0x65,0x63,0x74,0x69,0x6f,0x6e,0x29,0x3c,0x3c,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x5f,0x73,0x69, + 0x7a,0x65,0x3b,0x0a,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x7c,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x73,0x69, + 0x67,0x6e,0x5f,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x29,0x3c,0x3c,0x36,0x33,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x61,0x73,0x5f,0x64,0x6f, + 0x75,0x62,0x6c,0x65,0x28,0x66,0x6d,0x61,0x5f,0x72,0x65,0x73,0x75,0x6c,0x74,0x5b,0x31,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x64,0x69, + 0x76,0x5f,0x72,0x6e,0x64,0x28,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x61,0x2c,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x62,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x66,0x70,0x72,0x63,0x29,0x0a,0x7b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x79,0x30,0x3d,0x31,0x2e,0x30,0x2f,0x62,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x74,0x30,0x3d,0x61,0x2a,0x79,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x74,0x31,0x3d, + 0x66,0x6d,0x61,0x28,0x2d,0x62,0x2c,0x74,0x30,0x2c,0x61,0x29,0x3b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x66,0x6d,0x61,0x5f, + 0x73,0x6f,0x66,0x74,0x28,0x79,0x30,0x2c,0x74,0x31,0x2c,0x74,0x30,0x2c,0x66,0x70,0x72,0x63,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36, + 0x34,0x5f,0x74,0x20,0x69,0x6e,0x66,0x3d,0x32,0x30,0x34,0x37,0x55,0x4c,0x3c,0x3c,0x35,0x32,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34, + 0x5f,0x74,0x20,0x69,0x6e,0x66,0x5f,0x72,0x6e,0x64,0x3d,0x69,0x6e,0x66,0x2d,0x28,0x66,0x70,0x72,0x63,0x26,0x31,0x29,0x3b,0x0a,0x69,0x66,0x28,0x28,0x28,0x61,0x73, + 0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x72,0x65,0x73,0x75,0x6c,0x74,0x29,0x3e,0x3e,0x35,0x32,0x29,0x26,0x32,0x30,0x34,0x37,0x29,0x3d,0x3d,0x32,0x30,0x34,0x37,0x29, + 0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x69,0x6e,0x66,0x5f,0x72,0x6e,0x64,0x29,0x3b,0x0a,0x69,0x66,0x28,0x61, + 0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61,0x29,0x3d,0x3d,0x69,0x6e,0x66,0x29,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x61,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x28,0x61,0x3d,0x3d,0x62,0x29,0x3f,0x31,0x2e,0x30,0x3a,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x73,0x71, + 0x72,0x74,0x5f,0x72,0x6e,0x64,0x28,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x78,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x72,0x63,0x29,0x0a,0x7b, + 0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x79,0x30,0x3d,0x72,0x73,0x71,0x72,0x74,0x28,0x78,0x29,0x3b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x74,0x30,0x3d,0x79, + 0x30,0x2a,0x78,0x3b,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x74,0x31,0x3d,0x79,0x30,0x2a,0x2d,0x30,0x2e,0x35,0x3b,0x0a,0x74,0x31,0x3d,0x66,0x6d,0x61,0x28,0x74, + 0x31,0x2c,0x74,0x30,0x2c,0x30,0x2e,0x35,0x29,0x3b,0x09,0x09,0x09,0x09,0x09,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x79,0x31,0x5f, + 0x78,0x3d,0x66,0x6d,0x61,0x28,0x74,0x30,0x2c,0x74,0x31,0x2c,0x74,0x30,0x29,0x3b,0x09,0x0a,0x79,0x30,0x20,0x2a,0x3d,0x20,0x30,0x2e,0x35,0x3b,0x0a,0x79,0x30,0x3d, + 0x66,0x6d,0x61,0x28,0x79,0x30,0x2c,0x74,0x31,0x2c,0x79,0x30,0x29,0x3b,0x09,0x09,0x09,0x09,0x09,0x0a,0x74,0x31,0x3d,0x66,0x6d,0x61,0x28,0x2d,0x79,0x31,0x5f,0x78, + 0x2c,0x79,0x31,0x5f,0x78,0x2c,0x78,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3d,0x66,0x6d,0x61,0x5f, + 0x73,0x6f,0x66,0x74,0x28,0x74,0x31,0x2c,0x79,0x30,0x2c,0x79,0x31,0x5f,0x78,0x2c,0x66,0x70,0x72,0x63,0x29,0x3b,0x09,0x09,0x0a,0x69,0x66,0x28,0x2a,0x28,0x28,0x75, + 0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x20,0x26,0x78,0x29,0x3d,0x3d,0x28,0x32,0x30,0x34,0x37,0x55,0x4c,0x3c,0x3c,0x35,0x32,0x29,0x29,0x20,0x72,0x65,0x73, + 0x75,0x6c,0x74,0x3d,0x78,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x72,0x65,0x73,0x75,0x6c,0x74,0x3b,0x0a,0x7d,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x69,0x6e,0x6e,0x65,0x72,0x5f,0x6c,0x6f,0x6f,0x70,0x28,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x70,0x72,0x6f,0x67, + 0x72,0x61,0x6d,0x5f,0x6c,0x65,0x6e,0x67,0x74,0x68,0x2c,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32, + 0x5f,0x74,0x2a,0x20,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x73,0x75,0x62,0x2c,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x6f,0x66,0x66, + 0x73,0x65,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x67,0x72,0x6f,0x75,0x70, + 0x5f,0x41,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x52,0x2c,0x0a, + 0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66, + 0x70,0x72,0x63,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d, + 0x61,0x73,0x6b,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x78,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73, + 0x6b,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d,0x61,0x73,0x6b,0x0a,0x29, + 0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x75,0x62,0x32,0x3d,0x73,0x75,0x62,0x3e,0x3e,0x31,0x3b,0x0a,0x69,0x6d, + 0x6d,0x5f,0x62,0x75,0x66,0x5b,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x2b,0x31,0x5d,0x3d,0x66,0x70,0x72,0x63,0x3b,0x0a,0x23, + 0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x31,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x70, + 0x3d,0x30,0x3b,0x20,0x69,0x70,0x3c,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5f,0x6c,0x65,0x6e,0x67,0x74,0x68,0x3b,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75, + 0x66,0x5b,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x5d,0x3d,0x69,0x70,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20, + 0x69,0x6e,0x73,0x74,0x3d,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x69,0x70,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x4e,0x55,0x4d,0x5f, + 0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x28,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x2d, + 0x31,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3d,0x28, + 0x69,0x6e,0x73,0x74,0x3e,0x3e,0x4e,0x55,0x4d,0x5f,0x46,0x50,0x5f,0x49,0x4e,0x53,0x54,0x53,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x28,0x57,0x4f,0x52,0x4b, + 0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x2d,0x31,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e, + 0x75,0x6d,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3d,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x2d,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74, + 0x73,0x3b,0x0a,0x69,0x66,0x28,0x73,0x75,0x62,0x3c,0x3d,0x6e,0x75,0x6d,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6e,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x73,0x75,0x62,0x2d,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69, + 0x6e,0x73,0x74,0x73,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x66,0x70,0x3d,0x69,0x6e,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73, + 0x65,0x74,0x3c,0x6e,0x75,0x6d,0x5f,0x66,0x70,0x5f,0x69,0x6e,0x73,0x74,0x73,0x3b,0x0a,0x69,0x6e,0x73,0x74,0x3d,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70, + 0x72,0x6f,0x67,0x72,0x61,0x6d,0x5b,0x69,0x70,0x2b,0x28,0x69,0x73,0x5f,0x66,0x70,0x3f,0x73,0x75,0x62,0x32,0x3a,0x69,0x6e,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65, + 0x74,0x29,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x4f,0x50,0x43,0x4f, + 0x44,0x45,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x31,0x35,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x4c,0x4f,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x31,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x65,0x67,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x73,0x68,0x69,0x66,0x74,0x3d,0x69,0x73,0x5f,0x66,0x70, + 0x3f,0x34,0x3a,0x33,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x65,0x67,0x5f,0x62,0x61,0x73,0x65,0x5f,0x6f,0x66, + 0x66,0x73,0x65,0x74,0x3d,0x69,0x73,0x5f,0x66,0x70,0x3f,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3a,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x72,0x65,0x67,0x5f,0x62,0x61,0x73,0x65,0x5f,0x73,0x72,0x63,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x69, + 0x73,0x5f,0x66,0x70,0x3f,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x41,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3a,0x30,0x3b,0x0a,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x44,0x53,0x54,0x5f,0x4f,0x46,0x46, + 0x53,0x45,0x54,0x29,0x26,0x37,0x3b,0x0a,0x64,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x72,0x65,0x67,0x5f,0x62,0x61,0x73,0x65,0x5f,0x6f,0x66,0x66,0x73, + 0x65,0x74,0x2b,0x28,0x64,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3c,0x3c,0x72,0x65,0x67,0x5f,0x73,0x69,0x7a,0x65,0x5f,0x73,0x68,0x69,0x66,0x74,0x29,0x3b, + 0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x72,0x63,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x53,0x52,0x43,0x5f, + 0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x37,0x3b,0x0a,0x73,0x72,0x63,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x28,0x73,0x72,0x63,0x5f,0x6f,0x66,0x66,0x73,0x65, + 0x74,0x3c,0x3c,0x33,0x29,0x2b,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3f,0x30,0x3a,0x72,0x65,0x67,0x5f,0x62,0x61,0x73,0x65,0x5f,0x73,0x72,0x63,0x5f,0x6f, + 0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x64,0x73,0x74,0x5f,0x70,0x74, + 0x72,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x28,0x52,0x29,0x2b,0x64,0x73,0x74,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x73,0x72,0x63,0x5f,0x70,0x74,0x72,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x28,0x52,0x29,0x2b,0x73,0x72,0x63, + 0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x6d,0x6d,0x5f,0x6f,0x66,0x66, + 0x73,0x65,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x49,0x4d,0x4d,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x32,0x35,0x35,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x69,0x6d,0x6d,0x5f,0x70,0x74,0x72,0x3d,0x69,0x6d,0x6d,0x5f, + 0x62,0x75,0x66,0x2b,0x69,0x6d,0x6d,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x64,0x73,0x74,0x3d,0x2a,0x64,0x73, + 0x74,0x5f,0x70,0x74,0x72,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x73,0x72,0x63,0x3d,0x2a,0x73,0x72,0x63,0x5f,0x70,0x74,0x72,0x3b,0x0a,0x75,0x69, + 0x6e,0x74,0x32,0x20,0x69,0x6d,0x6d,0x3b,0x0a,0x69,0x6d,0x6d,0x2e,0x78,0x3d,0x69,0x6d,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x30,0x5d,0x3b,0x0a,0x69,0x6d,0x6d,0x2e,0x79, + 0x3d,0x69,0x6d,0x6d,0x5f,0x70,0x74,0x72,0x5b,0x31,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6c,0x6f,0x63,0x5f,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x69,0x6d,0x6d,0x2e,0x78,0x3e,0x3e,0x32,0x31,0x29, + 0x26,0x33,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6d,0x61,0x73,0x6b,0x3d,0x28,0x30,0x78,0x46,0x46,0x46,0x46, + 0x46,0x46,0x46,0x46,0x55,0x3e,0x3e,0x6c,0x6f,0x63,0x5f,0x73,0x68,0x69,0x66,0x74,0x29,0x2d,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20, + 0x69,0x73,0x5f,0x72,0x65,0x61,0x64,0x3d,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x21,0x3d,0x31,0x30,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x61, + 0x64,0x64,0x72,0x3d,0x69,0x73,0x5f,0x72,0x65,0x61,0x64,0x3f,0x28,0x28,0x6c,0x6f,0x63,0x5f,0x73,0x68,0x69,0x66,0x74,0x3d,0x3d,0x4c,0x4f,0x43,0x5f,0x4c,0x33,0x29, + 0x3f,0x30,0x3a,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x73,0x72,0x63,0x29,0x29,0x3a,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x64, + 0x73,0x74,0x29,0x3b,0x0a,0x61,0x64,0x64,0x72,0x2b,0x3d,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x69,0x6d,0x6d,0x2e,0x78,0x29,0x3b,0x0a,0x61,0x64,0x64, + 0x72,0x20,0x26,0x3d,0x20,0x6d,0x61,0x73,0x6b,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x70,0x74, + 0x72,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x2b,0x61,0x64,0x64,0x72,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x73,0x5f,0x72,0x65,0x61,0x64,0x29,0x0a,0x7b,0x0a,0x73,0x72,0x63,0x3d,0x2a,0x70,0x74,0x72,0x3b, + 0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x2a,0x70,0x74,0x72,0x3d,0x73,0x72,0x63,0x3b,0x0a,0x67,0x6f,0x74,0x6f,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x69, + 0x6f,0x6e,0x5f,0x65,0x6e,0x64,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53, + 0x5f,0x49,0x4d,0x4d,0x33,0x32,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29,0x20,0x73,0x72,0x63,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x28, + 0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x69,0x6d,0x6d,0x2e,0x78,0x29,0x29,0x29,0x3b,0x0a,0x69,0x66,0x28, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x3d,0x33,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56, + 0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29,0x20,0x73,0x72,0x63,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x2d,0x28, + 0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x73,0x72,0x63,0x29,0x29,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x30,0x29,0x20,0x64,0x73, + 0x74,0x2b,0x3d,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x69,0x6d,0x6d,0x2e,0x78,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x3e,0x3e,0x53,0x48,0x49,0x46,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x26,0x33, + 0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x32,0x29,0x20,0x64,0x73,0x74,0x2b,0x3d,0x73,0x72,0x63,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74,0x3b,0x0a, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x69,0x6d,0x6d,0x36,0x34,0x3d,0x2a,0x28,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74, + 0x2a,0x29,0x20,0x26,0x69,0x6d,0x6d,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x53,0x52,0x43,0x5f,0x49,0x53,0x5f,0x49,0x4d,0x4d, + 0x36,0x34,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29,0x20,0x73,0x72,0x63,0x3d,0x69,0x6d,0x6d,0x36,0x34,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x3d,0x3d,0x32,0x29,0x20,0x64,0x73,0x74,0x20,0x2a,0x3d,0x20,0x73,0x72,0x63,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x33,0x29,0x20,0x64, + 0x73,0x74,0x20,0x5e,0x3d,0x20,0x73,0x72,0x63,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x31,0x32,0x29, + 0x0a,0x7b,0x0a,0x69,0x66,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x29,0x20,0x73,0x72,0x63,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x63,0x6f,0x6e, + 0x76,0x65,0x72,0x74,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x72,0x74,0x6e,0x28,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x73,0x72,0x63,0x3e,0x3e,0x28, + 0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x2a,0x33,0x32,0x29,0x29,0x29,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41, + 0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29,0x20,0x73,0x72,0x63,0x20,0x5e,0x3d,0x20,0x30,0x78,0x38,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x4c,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x6d,0x75,0x6c, + 0x3d,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x53,0x48,0x49,0x46,0x54,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29,0x21,0x3d,0x30,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x61,0x3d,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x64,0x73,0x74,0x29,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x20,0x62,0x3d,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x73,0x72,0x63,0x29,0x3b,0x0a,0x64,0x73,0x74,0x3d, + 0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x66,0x6d,0x61,0x5f,0x73,0x6f,0x66,0x74,0x28,0x61,0x2c,0x69,0x73,0x5f,0x6d,0x75,0x6c,0x3f,0x62,0x3a,0x31,0x2e,0x30, + 0x2c,0x69,0x73,0x5f,0x6d,0x75,0x6c,0x3f,0x30,0x2e,0x30,0x3a,0x62,0x2c,0x66,0x70,0x72,0x63,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x39,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x2b,0x3d,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x69,0x6d,0x6d,0x2e, + 0x78,0x29,0x3b,0x0a,0x69,0x66,0x28,0x28,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x64,0x73,0x74,0x29,0x26,0x28,0x43,0x6f,0x6e,0x64,0x69,0x74,0x69, + 0x6f,0x6e,0x4d,0x61,0x73,0x6b,0x3c,0x3c,0x28,0x69,0x6d,0x6d,0x2e,0x79,0x26,0x33,0x31,0x29,0x29,0x29,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62, + 0x75,0x66,0x5b,0x49,0x4d,0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x5d,0x3d,0x28,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x28, + 0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x69,0x6d,0x6d,0x2e,0x79,0x29,0x3e,0x3e,0x35,0x29,0x2d,0x6e,0x75,0x6d,0x5f,0x69,0x6e,0x73,0x74,0x73,0x29,0x3b, + 0x0a,0x7d,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x37,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32, + 0x5f,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x31,0x3d,0x73,0x72,0x63,0x26,0x36,0x33,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x20,0x3e,0x20,0x30,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x68,0x69, + 0x66,0x74,0x32,0x3d,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x62,0x6f,0x6f,0x6c,0x20,0x69,0x73,0x5f,0x72,0x6f,0x6c, + 0x3d,0x28,0x69,0x6e,0x73,0x74,0x26,0x28,0x31,0x3c,0x3c,0x4e,0x45,0x47,0x41,0x54,0x49,0x56,0x45,0x5f,0x53,0x52,0x43,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x29,0x29, + 0x3b,0x0a,0x64,0x73,0x74,0x3d,0x28,0x64,0x73,0x74,0x3e,0x3e,0x28,0x69,0x73,0x5f,0x72,0x6f,0x6c,0x3f,0x73,0x68,0x69,0x66,0x74,0x32,0x3a,0x73,0x68,0x69,0x66,0x74, + 0x31,0x29,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x28,0x69,0x73,0x5f,0x72,0x6f,0x6c,0x3f,0x73,0x68,0x69,0x66,0x74,0x31,0x3a,0x73,0x68,0x69,0x66,0x74,0x32,0x29, + 0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x64,0x73,0x74,0x3d,0x28,0x64,0x73,0x74,0x3e,0x3e,0x73,0x68,0x69,0x66,0x74,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c, + 0x3c,0x28,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x31,0x29,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x31,0x34,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x73,0x71,0x72,0x74,0x5f, + 0x72,0x6e,0x64,0x28,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x64,0x73,0x74,0x29,0x2c,0x66,0x70,0x72,0x63,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73, + 0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x36,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x64,0x73,0x74, + 0x2c,0x73,0x72,0x63,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x34,0x29,0x0a,0x7b,0x0a,0x64,0x73, + 0x74,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x6d,0x75,0x6c,0x5f,0x68,0x69,0x28,0x28,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x64,0x73, + 0x74,0x29,0x2c,0x28,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x73,0x72,0x63,0x29,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f, + 0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x31,0x31,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x2a,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36, + 0x34,0x5f,0x74,0x2a,0x29,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x28,0x52,0x29,0x2b,0x28,0x64,0x73,0x74, + 0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5e,0x38,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x38, + 0x29,0x0a,0x7b,0x0a,0x2a,0x73,0x72,0x63,0x5f,0x70,0x74,0x72,0x3d,0x64,0x73,0x74,0x3b,0x0a,0x64,0x73,0x74,0x3d,0x73,0x72,0x63,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73, + 0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x31,0x35,0x29,0x0a,0x7b,0x0a,0x73,0x72,0x63,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28, + 0x63,0x6f,0x6e,0x76,0x65,0x72,0x74,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x5f,0x72,0x74,0x6e,0x28,0x28,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x29,0x28,0x73,0x72,0x63, + 0x3e,0x3e,0x28,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x2a,0x33,0x32,0x29,0x29,0x29,0x29,0x3b,0x0a,0x73,0x72,0x63,0x20,0x26,0x3d,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69, + 0x63,0x4d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x73,0x72,0x63,0x7c,0x3d,0x78,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73, + 0x6b,0x3b,0x0a,0x64,0x73,0x74,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x64,0x69,0x76,0x5f,0x72,0x6e,0x64,0x28,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c, + 0x65,0x28,0x64,0x73,0x74,0x29,0x2c,0x61,0x73,0x5f,0x64,0x6f,0x75,0x62,0x6c,0x65,0x28,0x73,0x72,0x63,0x29,0x2c,0x66,0x70,0x72,0x63,0x29,0x29,0x3b,0x0a,0x7d,0x0a, + 0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x3d,0x35,0x29,0x0a,0x7b,0x0a,0x64,0x73,0x74,0x3d,0x28,0x75,0x69,0x6e,0x74,0x36,0x34, + 0x5f,0x74,0x29,0x28,0x2d,0x28,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x64,0x73,0x74,0x29,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28, + 0x52,0x4f,0x55,0x4e,0x44,0x49,0x4e,0x47,0x5f,0x4d,0x4f,0x44,0x45,0x3c,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x49,0x4d,0x4d,0x5f,0x49, + 0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x2b,0x31,0x5d,0x3d,0x28,0x28,0x73,0x72,0x63,0x3e,0x3e,0x69,0x6d,0x6d,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29, + 0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x28,0x36,0x34,0x2d,0x69,0x6d,0x6d,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x29,0x29,0x29,0x26,0x33,0x3b,0x0a,0x67,0x6f,0x74,0x6f, + 0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x65,0x6e,0x64,0x3b,0x0a,0x7d,0x0a,0x2a,0x64,0x73,0x74,0x5f,0x70,0x74,0x72,0x3d,0x64,0x73,0x74,0x3b,0x0a, + 0x7d,0x0a,0x7d,0x0a,0x65,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x5f,0x65,0x6e,0x64,0x3a,0x0a,0x7b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b, + 0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a,0x69,0x70,0x3d,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x49,0x4d, + 0x4d,0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x5d,0x3b,0x0a,0x66,0x70,0x72,0x63,0x3d,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x5b,0x49,0x4d,0x4d, + 0x5f,0x49,0x4e,0x44,0x45,0x58,0x5f,0x43,0x4f,0x55,0x4e,0x54,0x2b,0x31,0x5d,0x3b,0x0a,0x69,0x70,0x2b,0x3d,0x6e,0x75,0x6d,0x5f,0x69,0x6e,0x73,0x74,0x73,0x2b,0x31, + 0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x66,0x70,0x72,0x63,0x3b,0x0a,0x7d,0x0a,0x23,0x69,0x66,0x20,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53, + 0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x20,0x3d,0x3d,0x20,0x31,0x36,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72, + 0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x33,0x32,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x23,0x65, + 0x6c,0x73,0x65,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f, + 0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x31,0x36,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65, + 0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x5f,0x76,0x6d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a, + 0x20,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x72,0x6f,0x75,0x6e,0x64,0x69, + 0x6e,0x67,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x73,0x2c,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x76,0x6f,0x69,0x64,0x2a,0x20,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x5f,0x70,0x74,0x72,0x2c,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6e,0x75,0x6d,0x5f, + 0x69,0x74,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x73,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x69,0x72,0x73,0x74,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32, + 0x5f,0x74,0x20,0x6c,0x61,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x76,0x6d,0x5f,0x73, + 0x74,0x61,0x74,0x65,0x73,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5b,0x28,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x53,0x49,0x5a,0x45,0x2a,0x32,0x29,0x2f,0x73,0x69, + 0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x5d,0x3b,0x0a,0x6c,0x6f,0x61,0x64,0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x76,0x6d,0x5f, + 0x73,0x74,0x61,0x74,0x65,0x73,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x2c,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x5f,0x6c,0x6f, + 0x63,0x61,0x6c,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x2c,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x29, + 0x3b,0x0a,0x62,0x61,0x72,0x72,0x69,0x65,0x72,0x28,0x43,0x4c,0x4b,0x5f,0x4c,0x4f,0x43,0x41,0x4c,0x5f,0x4d,0x45,0x4d,0x5f,0x46,0x45,0x4e,0x43,0x45,0x29,0x3b,0x0a, + 0x65,0x6e,0x75,0x6d,0x20,0x7b,0x20,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x3d,0x28,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41, + 0x53,0x48,0x3d,0x3d,0x31,0x36,0x29,0x3f,0x31,0x36,0x3a,0x38,0x20,0x7d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74, + 0x2a,0x20,0x52,0x3d,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x2b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69, + 0x64,0x28,0x30,0x29,0x2f,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x29,0x2a,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69, + 0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x20, + 0x46,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x29,0x28,0x52,0x2b,0x38,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61, + 0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x20,0x45,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x29,0x28,0x52,0x2b, + 0x31,0x36,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x69,0x64,0x78,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2f,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x3b,0x0a,0x63,0x6f,0x6e, + 0x73,0x74,0x20,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x75,0x62,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x20,0x25,0x20,0x49,0x44, + 0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6d,0x61,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x6d,0x78, + 0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x31,0x5d,0x3b, + 0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73, + 0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x32,0x5d,0x3b, + 0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x72,0x65,0x61,0x64,0x52,0x65,0x67, + 0x30,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20, + 0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x52,0x29,0x2b,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x30,0x78, + 0x66,0x66,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x72,0x65, + 0x61,0x64,0x52,0x65,0x67,0x31,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x28,0x28,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x52,0x29,0x2b,0x28,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x73,0x3e,0x3e,0x38,0x29,0x26,0x30,0x78,0x66,0x66,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x72,0x65,0x61,0x64,0x52,0x65,0x67,0x32,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32, + 0x5f,0x74,0x2a,0x29,0x28,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x52,0x29,0x2b,0x28,0x28,0x61,0x64,0x64, + 0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x3e,0x3e,0x31,0x36,0x29,0x26,0x30,0x78,0x66,0x66,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63, + 0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x72,0x65,0x61,0x64,0x52,0x65,0x67,0x33,0x3d,0x28,0x5f,0x5f,0x6c, + 0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f, + 0x74,0x2a,0x29,0x52,0x29,0x2b,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x3e,0x3e,0x32,0x34,0x29,0x29,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x3d,0x28,0x28,0x5f,0x5f, + 0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x33,0x5d,0x3b,0x0a,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x20,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x3d,0x28,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f,0x74,0x2a,0x29,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x5f,0x70,0x74, + 0x72,0x29,0x2b,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x4f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x36,0x34,0x2b,0x28,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x26,0x31,0x29,0x3c,0x3c,0x33,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x67, + 0x72,0x6f,0x75,0x70,0x5f,0x41,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x31,0x39,0x32,0x2b,0x28,0x28,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x26,0x31,0x29,0x3c,0x3c,0x33,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x65,0x4d,0x61,0x73,0x6b, + 0x3d,0x52,0x2b,0x31,0x38,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x5f,0x6c,0x65, + 0x6e,0x67,0x74,0x68,0x3d,0x28,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x32,0x30,0x29,0x29, + 0x5b,0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x66,0x70,0x72,0x63,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x29,0x5b,0x69,0x64,0x78,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74, + 0x20,0x73,0x70,0x41,0x64,0x64,0x72,0x30,0x3d,0x66,0x69,0x72,0x73,0x74,0x3f,0x6d,0x78,0x3a,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x70, + 0x41,0x64,0x64,0x72,0x31,0x3d,0x66,0x69,0x72,0x73,0x74,0x3f,0x6d,0x61,0x3a,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38, + 0x5f,0x74,0x2a,0x20,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x38,0x5f, + 0x74,0x2a,0x29,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x73,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x28,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x2b,0x36,0x34,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x62,0x6f,0x6f,0x6c,0x20,0x66,0x5f,0x67,0x72,0x6f,0x75,0x70,0x3d,0x28,0x73,0x75,0x62,0x3c,0x34,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f, + 0x75,0x62,0x6c,0x65,0x2a,0x20,0x66,0x65,0x3d,0x66,0x5f,0x67,0x72,0x6f,0x75,0x70,0x3f,0x28,0x46,0x2b,0x73,0x75,0x62,0x2a,0x32,0x29,0x3a,0x28,0x45,0x2b,0x28,0x73, + 0x75,0x62,0x2d,0x34,0x29,0x2a,0x32,0x29,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x20,0x66,0x3d,0x46,0x2b,0x73,0x75, + 0x62,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x20,0x65,0x3d,0x45,0x2b,0x73,0x75,0x62,0x3b,0x0a,0x63,0x6f,0x6e,0x73, + 0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x61,0x6e,0x64,0x4d,0x61,0x73,0x6b,0x3d,0x66,0x5f,0x67,0x72,0x6f,0x75,0x70,0x3f,0x28,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x29,0x28,0x2d,0x31,0x29,0x3a,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x4d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6f,0x72,0x4d,0x61,0x73,0x6b,0x31,0x3d,0x66,0x5f,0x67,0x72,0x6f,0x75,0x70,0x3f,0x30,0x3a, + 0x65,0x4d,0x61,0x73,0x6b,0x5b,0x30,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x6f,0x72,0x4d,0x61,0x73,0x6b,0x32, + 0x3d,0x66,0x5f,0x67,0x72,0x6f,0x75,0x70,0x3f,0x30,0x3a,0x65,0x4d,0x61,0x73,0x6b,0x5b,0x31,0x5d,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36, + 0x34,0x5f,0x74,0x20,0x78,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73,0x6b,0x3d,0x28,0x73,0x75,0x62,0x26,0x31,0x29,0x3f,0x65,0x4d,0x61,0x73,0x6b,0x5b, + 0x31,0x5d,0x3a,0x65,0x4d,0x61,0x73,0x6b,0x5b,0x30,0x5d,0x3b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x69, + 0x6d,0x6d,0x5f,0x62,0x75,0x66,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x52,0x2b,0x52,0x45,0x47, + 0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x5f, + 0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f, + 0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x3d,0x28,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a, + 0x29,0x28,0x52,0x2b,0x28,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x5f,0x53,0x49,0x5a,0x45,0x2b,0x49,0x4d,0x4d,0x5f,0x42,0x55,0x46,0x5f,0x53,0x49,0x5a,0x45, + 0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d,0x61,0x73,0x6b,0x3d,0x28,0x28,0x31,0x3c,0x3c,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45, + 0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x2d,0x31,0x29,0x3c,0x3c,0x28,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2f,0x49,0x44, + 0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x29,0x2a,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x20,0x66,0x70,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d,0x61,0x73,0x6b,0x3d,0x33,0x3c,0x3c,0x28,0x28,0x28,0x73,0x75,0x62,0x3e,0x3e,0x31, + 0x29,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x67,0x65,0x74,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2f,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48, + 0x29,0x2a,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x29,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x31,0x29,0x0a, + 0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x63,0x3d,0x30,0x3b,0x20,0x69,0x63,0x3c,0x6e,0x75,0x6d,0x5f,0x69,0x74,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x73, + 0x3b,0x20,0x2b,0x2b,0x69,0x63,0x29,0x0a,0x7b,0x0a,0x5f,0x5f,0x6c,0x6f,0x63,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x2a,0x72,0x3b,0x0a,0x5f, + 0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x2a,0x70,0x30,0x2c,0x2a,0x70,0x31,0x3b,0x0a,0x69,0x66,0x28,0x28,0x57,0x4f, + 0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3c,0x3d,0x38,0x29,0x7c,0x7c,0x28,0x73,0x75,0x62,0x3c,0x38,0x29,0x29,0x0a,0x7b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x73,0x70,0x4d,0x69,0x78,0x3d,0x2a,0x72,0x65,0x61,0x64,0x52,0x65,0x67,0x30,0x5e,0x2a,0x72, + 0x65,0x61,0x64,0x52,0x65,0x67,0x31,0x3b,0x0a,0x73,0x70,0x41,0x64,0x64,0x72,0x30,0x20,0x5e,0x3d,0x20,0x28,0x28,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x2a,0x29,0x26,0x73,0x70,0x4d,0x69,0x78,0x29,0x5b,0x30,0x5d,0x3b,0x0a,0x73,0x70,0x41,0x64,0x64,0x72,0x31,0x20,0x5e,0x3d,0x20,0x28,0x28,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x26,0x73,0x70,0x4d,0x69,0x78,0x29,0x5b,0x31,0x5d,0x3b,0x0a,0x73,0x70,0x41,0x64,0x64, + 0x72,0x30,0x20,0x26,0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x36,0x34,0x3b,0x0a,0x73,0x70,0x41,0x64,0x64,0x72, + 0x31,0x20,0x26,0x3d,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x36,0x34,0x3b,0x0a,0x70,0x30,0x3d,0x28,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x73,0x70,0x41,0x64, + 0x64,0x72,0x30,0x2b,0x73,0x75,0x62,0x2a,0x38,0x29,0x3b,0x0a,0x70,0x31,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x2a,0x29,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x73,0x70,0x41,0x64,0x64,0x72,0x31,0x2b,0x73,0x75,0x62,0x2a,0x38,0x29,0x3b,0x0a,0x72, + 0x3d,0x52,0x2b,0x73,0x75,0x62,0x3b,0x0a,0x2a,0x72,0x20,0x5e,0x3d,0x20,0x2a,0x70,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20,0x67,0x6c,0x6f,0x62, + 0x61,0x6c,0x5f,0x6d,0x65,0x6d,0x5f,0x64,0x61,0x74,0x61,0x3d,0x2a,0x70,0x31,0x3b,0x0a,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x71,0x3d,0x28,0x69,0x6e,0x74, + 0x33,0x32,0x5f,0x74,0x2a,0x29,0x26,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6d,0x65,0x6d,0x5f,0x64,0x61,0x74,0x61,0x3b,0x0a,0x66,0x65,0x5b,0x30,0x5d,0x3d,0x6c,0x6f, + 0x61,0x64,0x5f,0x46,0x5f,0x45,0x5f,0x67,0x72,0x6f,0x75,0x70,0x73,0x28,0x71,0x5b,0x30,0x5d,0x2c,0x61,0x6e,0x64,0x4d,0x61,0x73,0x6b,0x2c,0x6f,0x72,0x4d,0x61,0x73, + 0x6b,0x31,0x29,0x3b,0x0a,0x66,0x65,0x5b,0x31,0x5d,0x3d,0x6c,0x6f,0x61,0x64,0x5f,0x46,0x5f,0x45,0x5f,0x67,0x72,0x6f,0x75,0x70,0x73,0x28,0x71,0x5b,0x31,0x5d,0x2c, + 0x61,0x6e,0x64,0x4d,0x61,0x73,0x6b,0x2c,0x6f,0x72,0x4d,0x61,0x73,0x6b,0x32,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x28,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f, + 0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3d,0x3d,0x49,0x44,0x58,0x5f,0x57,0x49,0x44,0x54,0x48,0x29,0x7c,0x7c,0x28,0x73,0x75,0x62,0x3c,0x57,0x4f,0x52,0x4b,0x45, + 0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x29,0x29,0x0a,0x66,0x70,0x72,0x63,0x3d,0x69,0x6e,0x6e,0x65,0x72,0x5f,0x6c,0x6f,0x6f,0x70,0x28,0x70,0x72, + 0x6f,0x67,0x72,0x61,0x6d,0x5f,0x6c,0x65,0x6e,0x67,0x74,0x68,0x2c,0x63,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x64,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x2c,0x73,0x75, + 0x62,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2c,0x66,0x70,0x5f,0x72,0x65,0x67,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x66,0x70,0x5f,0x72,0x65, + 0x67,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x41,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x52,0x2c,0x69,0x6d,0x6d,0x5f,0x62,0x75,0x66,0x2c,0x62,0x61,0x74,0x63,0x68, + 0x5f,0x73,0x69,0x7a,0x65,0x2c,0x66,0x70,0x72,0x63,0x2c,0x66,0x70,0x5f,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d,0x61,0x73,0x6b,0x2c,0x78,0x65,0x78,0x70,0x6f, + 0x6e,0x65,0x6e,0x74,0x4d,0x61,0x73,0x6b,0x2c,0x77,0x6f,0x72,0x6b,0x65,0x72,0x73,0x5f,0x6d,0x61,0x73,0x6b,0x29,0x3b,0x0a,0x69,0x66,0x28,0x28,0x57,0x4f,0x52,0x4b, + 0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41,0x53,0x48,0x3c,0x3d,0x38,0x29,0x7c,0x7c,0x28,0x73,0x75,0x62,0x3c,0x38,0x29,0x29,0x0a,0x7b,0x0a,0x6d,0x78,0x20, + 0x5e,0x3d,0x20,0x2a,0x72,0x65,0x61,0x64,0x52,0x65,0x67,0x32,0x5e,0x2a,0x72,0x65,0x61,0x64,0x52,0x65,0x67,0x33,0x3b,0x0a,0x6d,0x78,0x20,0x26,0x3d,0x20,0x43,0x61, + 0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x41,0x6c,0x69,0x67,0x6e,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74, + 0x20,0x6e,0x65,0x78,0x74,0x5f,0x72,0x3d,0x2a,0x72,0x5e,0x2a,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x36,0x34,0x5f,0x74,0x2a,0x29,0x28,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x2b,0x6d,0x61,0x2b,0x73,0x75,0x62,0x2a,0x38,0x29,0x3b,0x0a,0x2a,0x72,0x3d,0x6e,0x65,0x78, + 0x74,0x5f,0x72,0x3b,0x0a,0x2a,0x70,0x31,0x3d,0x6e,0x65,0x78,0x74,0x5f,0x72,0x3b,0x0a,0x2a,0x70,0x30,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x66,0x5b, + 0x30,0x5d,0x29,0x5e,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x65,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x74,0x6d,0x70, + 0x3d,0x6d,0x61,0x3b,0x0a,0x6d,0x61,0x3d,0x6d,0x78,0x3b,0x0a,0x6d,0x78,0x3d,0x74,0x6d,0x70,0x3b,0x0a,0x73,0x70,0x41,0x64,0x64,0x72,0x30,0x3d,0x30,0x3b,0x0a,0x73, + 0x70,0x41,0x64,0x64,0x72,0x31,0x3d,0x30,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x28,0x57,0x4f,0x52,0x4b,0x45,0x52,0x53,0x5f,0x50,0x45,0x52,0x5f,0x48,0x41, + 0x53,0x48,0x3e,0x38,0x29,0x26,0x26,0x28,0x73,0x75,0x62,0x3e,0x3d,0x38,0x29,0x29,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x70,0x3d,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f, + 0x74,0x2a,0x29,0x76,0x6d,0x5f,0x73,0x74,0x61,0x74,0x65,0x73,0x29,0x2b,0x69,0x64,0x78,0x2a,0x28,0x56,0x4d,0x5f,0x53,0x54,0x41,0x54,0x45,0x5f,0x53,0x49,0x5a,0x45, + 0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x29,0x29,0x3b,0x0a,0x70,0x5b,0x73,0x75,0x62,0x5d,0x3d,0x52,0x5b,0x73,0x75,0x62, + 0x5d,0x3b,0x0a,0x69,0x66,0x28,0x73,0x75,0x62,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33, + 0x32,0x5f,0x74,0x2a,0x29,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x29,0x5b,0x69,0x64,0x78,0x5d,0x3d,0x66,0x70,0x72,0x63,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x6c, + 0x61,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x70,0x5b,0x73,0x75,0x62,0x2b,0x38,0x5d,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x46,0x5b,0x73,0x75,0x62,0x5d,0x29, + 0x5e,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x45,0x5b,0x73,0x75,0x62,0x5d,0x29,0x3b,0x0a,0x70,0x5b,0x73,0x75,0x62,0x2b,0x31,0x36,0x5d,0x3d,0x61,0x73,0x5f, + 0x75,0x6c,0x6f,0x6e,0x67,0x28,0x45,0x5b,0x73,0x75,0x62,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x73,0x75,0x62,0x3d,0x3d,0x30,0x29, + 0x0a,0x7b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x70,0x2b,0x31,0x36,0x29,0x29,0x5b, + 0x30,0x5d,0x3d,0x6d,0x61,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x29,0x28,0x70,0x2b,0x31, + 0x36,0x29,0x29,0x5b,0x31,0x5d,0x3d,0x6d,0x78,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65, + 0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b,0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b, + 0x65,0x72,0x6e,0x65,0x6c,0x20,0x76,0x6f,0x69,0x64,0x20,0x66,0x69,0x6e,0x64,0x5f,0x73,0x68,0x61,0x72,0x65,0x73,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20, + 0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x2a,0x20,0x68,0x61,0x73,0x68,0x65,0x73,0x2c,0x75,0x69,0x6e,0x74,0x36,0x34,0x5f,0x74,0x20, + 0x74,0x61,0x72,0x67,0x65,0x74,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x73,0x74,0x61,0x72,0x74,0x5f,0x6e,0x6f,0x6e,0x63,0x65,0x2c,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x2a,0x20,0x73,0x68,0x61,0x72,0x65,0x73,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f, + 0x69,0x64,0x28,0x30,0x29,0x3b,0x0a,0x69,0x66,0x28,0x68,0x61,0x73,0x68,0x65,0x73,0x5b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x34,0x2b, + 0x33,0x5d,0x3c,0x74,0x61,0x72,0x67,0x65,0x74,0x29,0x20,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x64,0x78,0x3d, + 0x61,0x74,0x6f,0x6d,0x69,0x63,0x5f,0x69,0x6e,0x63,0x28,0x73,0x68,0x61,0x72,0x65,0x73,0x2b,0x30,0x78,0x46,0x46,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x64,0x78,0x3c, + 0x30,0x78,0x46,0x46,0x29,0x20,0x7b,0x0a,0x73,0x68,0x61,0x72,0x65,0x73,0x5b,0x69,0x64,0x78,0x5d,0x3d,0x73,0x74,0x61,0x72,0x74,0x5f,0x6e,0x6f,0x6e,0x63,0x65,0x2b, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x7d,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4e,0x49,0x54, + 0x49,0x41,0x4c,0x5f,0x48,0x41,0x53,0x48,0x5f,0x53,0x49,0x5a,0x45,0x20,0x36,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x49,0x4e,0x54,0x45,0x52,0x4d,0x45, + 0x44,0x49,0x41,0x54,0x45,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47, + 0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x2a,0x20,0x31,0x36,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x43,0x4f,0x4d,0x50,0x49,0x4c,0x45,0x44,0x5f, + 0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x31,0x30,0x30,0x34,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x4e,0x55,0x4d,0x5f,0x56, + 0x47,0x50,0x52,0x5f,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x20,0x31,0x32,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73, + 0x73,0x61,0x53,0x69,0x7a,0x65,0x20,0x35,0x32,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x31, + 0x31,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55,0x4c,0x20,0x3c,0x3c,0x20, + 0x6d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x78,0x70,0x6f,0x6e, + 0x65,0x6e,0x74,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55,0x4c,0x20,0x3c,0x3c,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x53,0x69,0x7a,0x65,0x29,0x20,0x2d, + 0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x65,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x61,0x73,0x20,0x31,0x30,0x32,0x33,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x34,0x0a,0x23,0x64,0x65,0x66, + 0x69,0x6e,0x65,0x20,0x73,0x74,0x61,0x74,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x34,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x63,0x6f,0x6e,0x73,0x74,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74,0x73,0x20,0x30,0x78,0x33,0x30,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65, + 0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x4d,0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x4d,0x61,0x73,0x6b,0x20,0x28,0x28,0x31,0x55,0x4c,0x20,0x3c,0x3c,0x20,0x28,0x6d, + 0x61,0x6e,0x74,0x69,0x73,0x73,0x61,0x53,0x69,0x7a,0x65,0x20,0x2b,0x20,0x64,0x79,0x6e,0x61,0x6d,0x69,0x63,0x45,0x78,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x42,0x69,0x74, + 0x73,0x29,0x29,0x20,0x2d,0x20,0x31,0x29,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73, + 0x6b,0x5f,0x72,0x65,0x67,0x20,0x33,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73, + 0x6b,0x5f,0x72,0x65,0x67,0x20,0x33,0x39,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73, + 0x6b,0x5f,0x72,0x65,0x67,0x20,0x35,0x30,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73, + 0x6b,0x20,0x28,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x33,0x20,0x2d,0x20,0x38,0x29,0x0a,0x23,0x64, + 0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x42,0x49,0x54,0x53,0x20,0x38,0x0a,0x23,0x64,0x65,0x66,0x69,0x6e, + 0x65,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f,0x46,0x46,0x53,0x45,0x54,0x20,0x38,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c, + 0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65, + 0x73,0x73,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x2c,0x75,0x69,0x6e, + 0x74,0x20,0x69,0x6d,0x6d,0x33,0x32,0x2c,0x75,0x69,0x6e,0x74,0x20,0x6d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68, + 0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x31,0x30,0x65,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63, + 0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6d,0x6d,0x33,0x32,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x32,0x36,0x33, + 0x38,0x30,0x30,0x30,0x65,0x75,0x7c,0x28,0x6d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a, + 0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f, + 0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x69,0x6d,0x6d,0x33,0x32,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a, + 0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x32,0x66,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6d,0x6d, + 0x33,0x32,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a, + 0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74, + 0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56, + 0x45,0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x63,0x35,0x34,0x38,0x30,0x30,0x30,0x75,0x3b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x63,0x75,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c, + 0x3c,0x32,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x32,0x35,0x34,0x33,0x39,0x30,0x32,0x75,0x3b,0x09, + 0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x31,0x31,0x63,0x36,0x61,0x32,0x62,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x0a, + 0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x31,0x61,0x39,0x30,0x31,0x30,0x33,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x63,0x35, + 0x34,0x30,0x30,0x30,0x30,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x61,0x75, + 0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x32,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e, + 0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20, + 0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2c,0x69,0x6e,0x74,0x20,0x76,0x6d,0x63,0x6e,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x76,0x6d,0x63,0x6e,0x74, + 0x3e,0x3d,0x30,0x29,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x66,0x38,0x63,0x30,0x66,0x37,0x30,0x75,0x7c,0x28,0x76,0x6d,0x63,0x6e,0x74,0x26,0x31, + 0x35,0x29,0x7c,0x28,0x28,0x76,0x6d,0x63,0x6e,0x74,0x3e,0x3e,0x34,0x29,0x3c,0x3c,0x31,0x34,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32, + 0x38,0x39,0x30,0x30,0x30,0x65,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x30,0x30,0x75,0x7c,0x76,0x67,0x70,0x72, + 0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x39,0x30,0x30,0x30,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x30,0x30,0x75,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2b,0x31,0x29,0x3b,0x0a,0x72, + 0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x5f,0x66,0x70,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x2c,0x75,0x69,0x6e,0x74,0x20,0x69,0x6d,0x6d,0x33,0x32,0x2c,0x75,0x69, + 0x6e,0x74,0x20,0x6d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x2a, + 0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x31,0x30,0x65,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x69,0x6d,0x6d,0x33,0x32,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x32,0x36,0x33,0x38,0x30,0x30,0x30,0x65,0x75,0x7c,0x28,0x6d,0x61, + 0x73,0x6b,0x5f,0x72,0x65,0x67,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31, + 0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x36,0x38,0x33,0x38,0x35,0x39,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x33,0x32,0x33,0x38,0x35,0x39,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b, + 0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x5f,0x6c,0x6f,0x61,0x64,0x5f,0x66,0x70,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x76, + 0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20, + 0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x63,0x35,0x30,0x38,0x30,0x30,0x30,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78, + 0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x63,0x75,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3c,0x32,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73, + 0x65,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x32,0x35,0x34,0x33,0x39,0x30,0x32,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x64,0x31,0x31,0x63,0x36,0x61,0x32,0x62,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30, + 0x31,0x61,0x39,0x30,0x31,0x30,0x33,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x63,0x35,0x30,0x30,0x30,0x30,0x30,0x75,0x3b,0x09,0x09,0x09, + 0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x32,0x61,0x75,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3c,0x3c,0x32,0x34,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x5f, + 0x66,0x70,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e,0x74,0x20,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e, + 0x64,0x65,0x78,0x2c,0x69,0x6e,0x74,0x20,0x76,0x6d,0x63,0x6e,0x74,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x76,0x6d,0x63,0x6e,0x74,0x3e,0x3d,0x30,0x29,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x66,0x38,0x63,0x30,0x66,0x37,0x30,0x75,0x7c,0x28,0x76,0x6d,0x63,0x6e,0x74,0x26,0x31,0x35,0x29,0x7c,0x28,0x28,0x76,0x6d, + 0x63,0x6e,0x74,0x3e,0x3e,0x34,0x29,0x3c,0x3c,0x31,0x34,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x39,0x30,0x30,0x75, + 0x7c,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6a,0x69,0x74,0x5f,0x65,0x6d,0x69,0x74,0x5f,0x69,0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x28,0x5f,0x5f,0x67, + 0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x6c,0x61,0x73, + 0x74,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x2c,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x69,0x6e,0x73,0x74, + 0x2c,0x69,0x6e,0x74,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2c,0x69,0x6e,0x74,0x20,0x76,0x6d,0x63, + 0x6e,0x74,0x2c,0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x6f,0x70,0x63,0x6f,0x64, + 0x65,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x30,0x78,0x46,0x46,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x3d,0x28,0x69, + 0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x38,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x3d,0x28,0x69,0x6e,0x73, + 0x74,0x2e,0x78,0x3e,0x3e,0x31,0x36,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6d,0x6f,0x64,0x3d,0x69,0x6e,0x73,0x74,0x2e, + 0x78,0x3e,0x3e,0x32,0x34,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41, + 0x44,0x44,0x5f,0x52,0x53,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x6d,0x6f,0x64,0x3e,0x3e, + 0x32,0x29,0x20,0x25,0x20,0x34,0x3b,0x0a,0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x3e,0x30,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78, + 0x38,0x65,0x38,0x65,0x38,0x30,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x68,0x69,0x66,0x74,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x2a, + 0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x30,0x30,0x65,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c, + 0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x31,0x31,0x30,0x66,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31, + 0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78, + 0x38,0x30,0x31,0x30,0x31,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x73,0x72, + 0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x31,0x31,0x31,0x31,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c, + 0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x64,0x73,0x74,0x3d, + 0x3d,0x35,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x30,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c, + 0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x31,0x31,0x30,0x30,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31, + 0x37,0x29,0x7c,0x28,0x28,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29,0x3c,0x30,0x29,0x3f,0x30,0x78,0x63,0x31,0x3a,0x30,0x78,0x38, + 0x30,0x29,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68, + 0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a, + 0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c, + 0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c, + 0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62, + 0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70, + 0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53, + 0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a, + 0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67, + 0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29, + 0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b, + 0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74, + 0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a, + 0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x30,0x30,0x65,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c, + 0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x31,0x31,0x30,0x66,0x31,0x31,0x75,0x7c,0x28,0x64, + 0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66, + 0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x39,0x30,0x31,0x30,0x31,0x30,0x75, + 0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x39,0x31,0x31,0x31,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c, + 0x31,0x37,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x38,0x30,0x39,0x30,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a, + 0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x39,0x31,0x30,0x30,0x31,0x31,0x75, + 0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x28,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x69,0x6e, + 0x73,0x74,0x2e,0x79,0x29,0x3c,0x30,0x29,0x3f,0x30,0x78,0x63,0x31,0x3a,0x30,0x78,0x38,0x30,0x29,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42, + 0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f, + 0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a, + 0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20, + 0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65, + 0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64, + 0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c, + 0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f, + 0x61,0x64,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63, + 0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f, + 0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76, + 0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x39, + 0x30,0x30,0x65,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b, + 0x29,0x3d,0x30,0x78,0x38,0x32,0x39,0x31,0x30,0x66,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29, + 0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x7b,0x0a,0x23,0x69, + 0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x36,0x30, + 0x66,0x31,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a, + 0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x32,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x36,0x30,0x30,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x32,0x31, + 0x31,0x63,0x75,0x2b,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x39,0x30,0x30,0x30,0x66, + 0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x30,0x65,0x31,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c, + 0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x30,0x66,0x30,0x65,0x30,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x39,0x32,0x30,0x65,0x31,0x30,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x31,0x30,0x65,0x30,0x66,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x31,0x30,0x31,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37, + 0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45, + 0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x36,0x30,0x66,0x66,0x66,0x31,0x30,0x75,0x7c,0x28, + 0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x32,0x66,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x36,0x30,0x30,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30, + 0x30,0x30,0x32,0x31,0x31,0x63,0x75,0x2b,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x39, + 0x30,0x30,0x30,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69, + 0x66,0x0a,0x69,0x66,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29,0x3c,0x30,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29, + 0x3d,0x30,0x78,0x38,0x30,0x38,0x66,0x31,0x30,0x30,0x66,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d, + 0x30,0x78,0x39,0x32,0x30,0x65,0x66,0x66,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73, + 0x74,0x2e,0x79,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x31,0x30,0x65,0x30,0x66,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37, + 0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x31,0x30,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28, + 0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c, + 0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f, + 0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a, + 0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20, + 0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65, + 0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64, + 0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c, + 0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f, + 0x61,0x64,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63, + 0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f, + 0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76, + 0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53, + 0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x36,0x32,0x31,0x30,0x65,0x31,0x30,0x75,0x7c,0x28,0x64,0x73, + 0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x32,0x31,0x30,0x75,0x7c, + 0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x36,0x30,0x30,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x31,0x64,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x39,0x30, + 0x30,0x32,0x31,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x32,0x30,0x30,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x32,0x31,0x32,0x30,0x32,0x31,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x32,0x30,0x30, + 0x65,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x31,0x32,0x30,0x32,0x31, + 0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x31,0x30,0x30,0x65,0x31,0x30,0x75,0x7c, + 0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a, + 0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x38,0x65,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x09, + 0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x36,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09, + 0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x33,0x61,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x39,0x30,0x30,0x31,0x30,0x65,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e, + 0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67, + 0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65, + 0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66, + 0x69,0x78,0x65,0x64,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f, + 0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72, + 0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69, + 0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65, + 0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b, + 0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x36,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x33,0x61,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78, + 0x62,0x65,0x39,0x30,0x30,0x31,0x30,0x65,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c, + 0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55, + 0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x38,0x65,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c, + 0x3c,0x31,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x36,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63, + 0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x33,0x38,0x75,0x3b,0x09,0x09,0x09, + 0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x39,0x30,0x30,0x31,0x30,0x65,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37, + 0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f, + 0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68, + 0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a, + 0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c, + 0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c, + 0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62, + 0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70, + 0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53, + 0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a, + 0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67, + 0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29, + 0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b, + 0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74, + 0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a, + 0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x36,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b, + 0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x33,0x38,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0a, + 0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x39,0x30,0x30,0x31,0x30,0x65,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x09,0x09, + 0x09,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x28,0x69,0x6e,0x73, + 0x74,0x2e,0x79,0x2d,0x31,0x29,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3d, + 0x61,0x73,0x5f,0x75,0x69,0x6e,0x74,0x32,0x28,0x69,0x6d,0x75,0x6c,0x5f,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29,0x29, + 0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x30,0x30,0x30,0x66,0x66,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x78,0x3b,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e, + 0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x36,0x30,0x66,0x32,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c, + 0x31,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x33,0x38,0x30,0x32,0x32,0x30,0x75, + 0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x36,0x30,0x30,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30, + 0x30,0x30,0x30,0x32,0x31,0x31,0x63,0x75,0x2b,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38, + 0x39,0x30,0x30,0x30,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x31,0x30,0x31,0x31,0x63,0x75,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x30,0x65,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x09, + 0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x72,0x63,0x70,0x5f,0x76,0x61,0x6c,0x75,0x65,0x2e,0x79,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x38,0x30,0x30,0x66,0x30,0x65,0x30,0x66,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x32,0x30,0x65, + 0x32,0x30,0x31,0x31,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31, + 0x31,0x30,0x65,0x30,0x66,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39, + 0x32,0x31,0x30,0x32,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x72, + 0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x39,0x30,0x31,0x30,0x38,0x30,0x75,0x7c,0x28,0x64, + 0x73,0x74,0x3c,0x3c,0x39,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x39,0x31, + 0x31,0x31,0x38,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x39,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x0a,0x72,0x65,0x74,0x75,0x72, + 0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47, + 0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f, + 0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x38, + 0x39,0x30,0x31,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c, + 0x3c,0x39,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29, + 0x3c,0x30,0x29,0x20,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x65,0x30,0x30,0x66,0x66,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b, + 0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x38,0x39,0x30,0x33,0x65,0x31,0x30,0x75,0x7c,0x28,0x64,0x73, + 0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29, + 0x3d,0x30,0x78,0x38,0x38,0x31,0x30,0x66,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28, + 0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66, + 0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72, + 0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61, + 0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d, + 0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x70,0x3d,0x6a,0x69,0x74, + 0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x66,0x69,0x78,0x65,0x64,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70, + 0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73, + 0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x28,0x70,0x2c,0x70,0x72, + 0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f, + 0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e, + 0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32, + 0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68, + 0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x38,0x39,0x30,0x30,0x65,0x31,0x30,0x75,0x7c, + 0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a, + 0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29, + 0x20,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f, + 0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x66,0x61,0x30,0x31,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29, + 0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x38,0x66,0x31,0x30,0x63,0x30,0x75,0x7c,0x28,0x73, + 0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x65,0x61,0x32,0x30,0x66,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c, + 0x3c,0x31,0x29,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x65,0x61,0x30,0x31,0x30,0x31,0x30,0x75, + 0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x38, + 0x66,0x31,0x30,0x63,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x39,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x66,0x61,0x32,0x30,0x66, + 0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x7d,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20, + 0x75,0x69,0x6e,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x29,0x3f,0x69,0x6e,0x73,0x74,0x2e,0x79,0x3a,0x2d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x29,0x26,0x36,0x33,0x3b,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x66,0x61,0x30,0x38,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x73,0x68,0x69,0x66,0x74,0x3c, + 0x3c,0x38,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x65,0x61,0x32,0x38,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29, + 0x7c,0x28,0x28,0x36,0x34,0x2d,0x73,0x68,0x69,0x66,0x74,0x29,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x37,0x39, + 0x30,0x32,0x32,0x32,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70, + 0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x0a,0x7b,0x0a, + 0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x61,0x30,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x09,0x09, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x39,0x30,0x30,0x31,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73, + 0x74,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x39,0x30,0x30,0x31,0x32,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c, + 0x3c,0x31,0x37,0x29,0x3b,0x09,0x09,0x09,0x09,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x64,0x38,0x37,0x61,0x38,0x30,0x30,0x31,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x63,0x30,0x30,0x30,0x30,0x33,0x63,0x75,0x2b,0x28, + 0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x64,0x73,0x74,0x3c,0x3c,0x32,0x35,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x38,0x37,0x61, + 0x38,0x30,0x30,0x31,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x64,0x30,0x30,0x30,0x30,0x33,0x64,0x75,0x2b,0x28,0x64,0x73,0x74,0x3c,0x3c, + 0x31,0x29,0x2b,0x28,0x64,0x73,0x74,0x3c,0x3c,0x32,0x35,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x66,0x38,0x63,0x63,0x30,0x37,0x66,0x75, + 0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x30,0x30,0x30,0x33,0x63,0x75,0x2b, + 0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x32,0x36,0x39,0x33,0x63,0x75, + 0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x28,0x73,0x72,0x63,0x26,0x33,0x29,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x72,0x65,0x74, + 0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41, + 0x44,0x44,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44, + 0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30, + 0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73, + 0x73,0x5f,0x66,0x70,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61, + 0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73, + 0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65, + 0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28, + 0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f, + 0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76, + 0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32, + 0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a, + 0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x30,0x30,0x30,0x33,0x63,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x32,0x33,0x39,0x33,0x63,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29, + 0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x30,0x30,0x30,0x33,0x63,0x75, + 0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x34,0x30,0x30,0x32,0x36,0x39,0x33,0x63, + 0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x28,0x73,0x72,0x63,0x26,0x33,0x29,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x72,0x65, + 0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46, + 0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53, + 0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d, + 0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65, + 0x73,0x73,0x5f,0x66,0x70,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61, + 0x73,0x6b,0x5f,0x72,0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63, + 0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64, + 0x65,0x78,0x3f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66, + 0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74, + 0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f, + 0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a, + 0x32,0x38,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b, + 0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x30,0x30,0x30,0x33,0x63,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29, + 0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x34,0x30,0x30,0x32,0x33,0x39,0x33,0x63,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31, + 0x29,0x3b,0x0a,0x7d,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x32,0x61,0x37,0x61,0x36,0x37,0x33, + 0x64,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x38,0x29,0x3b,0x0a,0x72, + 0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x32,0x38,0x31,0x30,0x30,0x34,0x34,0x75,0x2b,0x28,0x28,0x64, + 0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x32,0x36,0x39,0x34,0x34,0x75,0x2b,0x28,0x28, + 0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x2b,0x28,0x28,0x73,0x72,0x63,0x26,0x33,0x29,0x3c,0x3c,0x31,0x30,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e, + 0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f, + 0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d, + 0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3e,0x3d,0x30,0x29,0x0a,0x7b, + 0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x5f,0x66, + 0x70,0x28,0x70,0x2c,0x73,0x72,0x63,0x2c,0x69,0x6e,0x73,0x74,0x2e,0x79,0x2c,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68, + 0x70,0x61,0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72, + 0x65,0x67,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x5f,0x6c,0x6f,0x61,0x64,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x29,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x70,0x72,0x65, + 0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3c,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x6f,0x61,0x64,0x32,0x5f,0x66,0x70,0x28,0x70,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72, + 0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x2d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3a,0x32,0x38,0x2c,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x30,0x29,0x3b,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x33,0x30,0x75,0x2b,0x28,0x28,0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x7d,0x0a, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51, + 0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f, + 0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x62,0x63,0x31,0x65,0x32,0x38,0x75,0x2b,0x28,0x28, + 0x64,0x73,0x74,0x26,0x33,0x29,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e, + 0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x4a,0x55,0x4d,0x50,0x5f,0x4f,0x46, + 0x46,0x53,0x45,0x54,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x69,0x6d,0x6d,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x79,0x7c,0x28,0x31,0x75,0x3c,0x3c,0x73,0x68,0x69,0x66,0x74, + 0x29,0x3b,0x0a,0x69,0x6d,0x6d,0x20,0x26,0x3d,0x20,0x7e,0x28,0x31,0x75,0x3c,0x3c,0x28,0x73,0x68,0x69,0x66,0x74,0x2d,0x31,0x29,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b, + 0x2b,0x29,0x3d,0x30,0x78,0x38,0x30,0x31,0x30,0x66,0x66,0x31,0x30,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29, + 0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x69,0x6d,0x6d,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x32,0x31,0x31,0x30,0x30,0x31,0x31,0x75, + 0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x37,0x29,0x7c,0x28,0x28,0x28,0x61,0x73,0x5f,0x69,0x6e,0x74,0x28,0x69,0x6d, + 0x6d,0x29,0x3c,0x30,0x29,0x3f,0x30,0x78,0x63,0x31,0x3a,0x30,0x78,0x38,0x30,0x29,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x63,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x4d,0x61,0x73,0x6b,0x52,0x65,0x67,0x3d,0x37,0x30,0x2b,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x3b,0x0a,0x2a, + 0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x36,0x30,0x65,0x30,0x30,0x31,0x30,0x75,0x7c,0x28,0x64,0x73,0x74,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x63,0x6f,0x6e,0x64, + 0x69,0x74,0x69,0x6f,0x6e,0x4d,0x61,0x73,0x6b,0x52,0x65,0x67,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x64,0x65,0x6c,0x74, + 0x61,0x3d,0x28,0x28,0x6c,0x61,0x73,0x74,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x2d,0x70,0x29,0x2d,0x31,0x29,0x3b,0x0a,0x2a,0x28, + 0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x66,0x38,0x34,0x30,0x30,0x30,0x30,0x75,0x7c,0x28,0x64,0x65,0x6c,0x74,0x61,0x26,0x30,0x78,0x46,0x46,0x46,0x46,0x29,0x3b, + 0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x68,0x69,0x66,0x74,0x3d,0x69,0x6e, + 0x73,0x74,0x2e,0x79,0x26,0x36,0x33,0x3b,0x0a,0x69,0x66,0x28,0x73,0x68,0x69,0x66,0x74,0x3d,0x3d,0x36,0x33,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d, + 0x30,0x78,0x38,0x65,0x30,0x65,0x38,0x31,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x38,0x66,0x30,0x66,0x39,0x66,0x31,0x31,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x3b,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78, + 0x38,0x37,0x30,0x65,0x30,0x66,0x30,0x65,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x38,0x36,0x30,0x65,0x38,0x33,0x30, + 0x65,0x75,0x3b,0x09,0x09,0x09,0x09,0x09,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x39,0x33,0x38,0x65,0x66, + 0x66,0x31,0x30,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x73,0x68,0x69,0x66,0x74,0x7c,0x28,0x32,0x3c,0x3c, + 0x31,0x36,0x29,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x38,0x65,0x30,0x38,0x30,0x65,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b, + 0x29,0x3d,0x30,0x78,0x38,0x66,0x34,0x32,0x39,0x65,0x30,0x65,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x39,0x34,0x32,0x30,0x38,0x38,0x31, + 0x75,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6d,0x61,0x73,0x6b,0x3d,0x28,0x28, + 0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x3c,0x31,0x34,0x29,0x3f,0x28,0x28,0x6d,0x6f,0x64,0x20,0x25,0x20,0x34,0x29,0x3f,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x4c,0x31,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x32,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67, + 0x29,0x3a,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73,0x6b,0x5f,0x72,0x65,0x67,0x3b,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x73,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x63,0x61,0x6c,0x63,0x5f,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x28,0x70,0x2c,0x64,0x73,0x74,0x2c,0x69,0x6e,0x73,0x74, + 0x2e,0x79,0x2c,0x6d,0x61,0x73,0x6b,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3d,0x34,0x38,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x37,0x65,0x30,0x30,0x30,0x32,0x31,0x30,0x75,0x7c,0x28, + 0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3c,0x3c,0x31,0x37,0x29,0x3b,0x09,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30, + 0x78,0x37,0x65,0x30,0x32,0x30,0x32,0x31,0x31,0x75,0x7c,0x28,0x73,0x72,0x63,0x3c,0x3c,0x31,0x29,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3c,0x3c,0x31,0x37, + 0x29,0x3b,0x09,0x0a,0x23,0x69,0x66,0x20,0x47,0x43,0x4e,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x20,0x3e,0x3d,0x20,0x31,0x34,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29, + 0x3d,0x30,0x78,0x64,0x63,0x37,0x34,0x38,0x30,0x30,0x30,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x63,0x75, + 0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x32, + 0x33,0x38,0x30,0x35,0x31,0x63,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x33,0x38,0x33,0x61,0x30,0x36,0x38,0x30,0x75,0x3b,0x0a,0x2a,0x28,0x70, + 0x2b,0x2b,0x29,0x3d,0x30,0x78,0x64,0x63,0x37,0x34,0x30,0x30,0x30,0x30,0x75,0x3b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30, + 0x31,0x63,0x75,0x7c,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, + 0x70,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45, + 0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x74,0x20,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72, + 0x65,0x61,0x64,0x28,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x70,0x30,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69, + 0x6e,0x74,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x69,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74, + 0x20,0x64,0x73,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x69,0x6e,0x73,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69, + 0x6e,0x74,0x20,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74, + 0x20,0x69,0x6e,0x74,0x20,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74, + 0x20,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x74,0x3b,0x0a,0x74,0x2e,0x78,0x3d,0x28,0x73,0x72,0x63, + 0x3d,0x3d,0x64,0x73,0x74,0x29,0x3f,0x28,0x28,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x4c,0x33,0x4d,0x61,0x73, + 0x6b,0x29,0x3e,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x53,0x43,0x52,0x41,0x54,0x43,0x48,0x50,0x41,0x44,0x5f,0x4c,0x32,0x29,0x3f,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x29,0x3a,0x6d,0x61,0x78,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61, + 0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x29,0x3b,0x0a,0x74,0x2e,0x79,0x3d,0x69,0x3b,0x0a,0x63,0x6f, + 0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x74,0x31,0x3d,0x74,0x2e,0x78,0x3b,0x0a,0x69,0x66,0x28,0x28,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61, + 0x72,0x67,0x65,0x74,0x3c,0x3d,0x74,0x31,0x29,0x26,0x26,0x28,0x74,0x31,0x3c,0x3d,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x29,0x0a,0x7b,0x0a,0x74, + 0x2e,0x78,0x3d,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x2b,0x31,0x3b,0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x20,0x69,0x66,0x28,0x28,0x6c,0x61,0x73,0x74, + 0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3e,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x26,0x26,0x28,0x74,0x31,0x3c,0x6c,0x61, + 0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x29,0x0a,0x7b,0x0a,0x74,0x2e,0x78,0x3d,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3b,0x0a,0x7d,0x0a,0x70,0x30,0x5b,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e, + 0x74,0x5d,0x3d,0x74,0x3b,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74, + 0x2b,0x31,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x5f,0x6a,0x69, + 0x74,0x5f,0x63,0x6f,0x64,0x65,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x65,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x70,0x30,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x2c,0x75,0x69,0x6e, + 0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x0a,0x7b,0x0a,0x69,0x6e,0x74,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74, + 0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x31,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28, + 0x69,0x6e,0x74,0x20,0x70,0x61,0x73,0x73,0x3d,0x30,0x3b,0x20,0x70,0x61,0x73,0x73,0x3c,0x32,0x3b,0x20,0x2b,0x2b,0x70,0x61,0x73,0x73,0x29,0x0a,0x7b,0x0a,0x23,0x69, + 0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x69,0x6e,0x74, + 0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x2d,0x31,0x2c,0x2d,0x31,0x2c, + 0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x20,0x7d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x75,0x6c,0x6f,0x6e,0x67, + 0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x30,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73, + 0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73,0x63,0x72, + 0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6c,0x61, + 0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x2d,0x31,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x3d,0x2d,0x31,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e, + 0x20,0x32,0x35,0x36,0x0a,0x69,0x6e,0x74,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72, + 0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x5b,0x38,0x5d,0x3d,0x7b,0x20,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x2c,0x2d, + 0x31,0x2c,0x2d,0x31,0x2c,0x2d,0x31,0x20,0x7d,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c, + 0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74, + 0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65, + 0x74,0x3d,0x30,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c, + 0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74, + 0x3d,0x30,0x3b,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x30,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67, + 0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x31,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61, + 0x73,0x73,0x3d,0x3d,0x30,0x29,0x0a,0x65,0x5b,0x69,0x5d,0x2e,0x78,0x20,0x26,0x3d,0x20,0x7e,0x28,0x30,0x78,0x66,0x38,0x75,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x75,0x69, + 0x6e,0x74,0x32,0x20,0x69,0x6e,0x73,0x74,0x3d,0x65,0x5b,0x69,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3d,0x69,0x6e,0x73,0x74,0x2e, + 0x78,0x26,0x30,0x78,0x46,0x46,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e, + 0x38,0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x3d,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x31,0x36, + 0x29,0x26,0x37,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6d,0x6f,0x64,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x3e,0x3e,0x32,0x34,0x3b,0x0a, + 0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38, + 0x29,0x29,0x0a,0x7b,0x0a,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x69,0x3b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20, + 0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x72, + 0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74, + 0x5b,0x6a,0x5d,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x6a,0x5d,0x3b,0x0a,0x23,0x65,0x6c,0x73, + 0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72, + 0x67,0x65,0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65, + 0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3b,0x0a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69, + 0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69, + 0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3b,0x0a,0x7d,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x34,0x30, + 0x3c,0x3c,0x38,0x29,0x29,0x0a,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x3d,0x69,0x3b,0x0a,0x7d,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20, + 0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67, + 0x65,0x64,0x5b,0x73,0x72,0x63,0x5d,0x2b,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x41,0x76,0x61,0x69,0x6c,0x61,0x62, + 0x6c,0x65,0x41,0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x2b,0x31,0x3b, + 0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74, + 0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x28,0x31,0x75,0x3c,0x3c,0x73,0x72,0x63,0x29,0x29,0x3f, + 0x28,0x28,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3e,0x3e,0x28,0x73,0x72,0x63,0x2a,0x38,0x29,0x29, + 0x26,0x30,0x78,0x46,0x46,0x29,0x2b,0x31,0x29,0x3a,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x41,0x76,0x61,0x69,0x6c, + 0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x28,0x31,0x75,0x3c,0x3c, + 0x64,0x73,0x74,0x29,0x29,0x3f,0x28,0x28,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3e,0x3e,0x28,0x64, + 0x73,0x74,0x2a,0x38,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x2b,0x31,0x29,0x3a,0x30,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e, + 0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d, + 0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x52,0x53,0x3b,0x0a,0x69, + 0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x29,0x0a,0x7b,0x0a, + 0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72, + 0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65, + 0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61, + 0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28, + 0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73, + 0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73, + 0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65, + 0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64,0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e, + 0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x64,0x73,0x74,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c, + 0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74, + 0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x41,0x44,0x44,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c, + 0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65, + 0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65, + 0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69, + 0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c, + 0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63, + 0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61, + 0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67, + 0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67, + 0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a, + 0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68, + 0x5f,0x72,0x65,0x61,0x64,0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73, + 0x72,0x63,0x2c,0x64,0x73,0x74,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74, + 0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74, + 0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50, + 0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74, + 0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30, + 0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64, + 0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c, + 0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52, + 0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c, + 0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26, + 0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c, + 0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31, + 0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65, + 0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64, + 0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x64,0x73, + 0x74,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61, + 0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46, + 0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52, + 0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65, + 0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75, + 0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38, + 0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43, + 0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28, + 0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28, + 0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c, + 0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63, + 0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64,0x28,0x70, + 0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x64,0x73,0x74,0x2c, + 0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76, + 0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c, + 0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29, + 0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52, + 0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52, + 0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65, + 0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75, + 0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38, + 0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b, + 0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44, + 0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c, + 0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26, + 0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c, + 0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31, + 0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65, + 0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64, + 0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x64,0x73, + 0x74,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64, + 0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61, + 0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x4d,0x55,0x4c,0x48,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x79,0x26,0x28,0x69,0x6e,0x73, + 0x74,0x2e,0x79,0x2d,0x31,0x29,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49, + 0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74, + 0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64, + 0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72, + 0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64, + 0x69,0x66,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4d,0x55,0x4c,0x5f,0x52,0x43,0x50,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x4e,0x45,0x47,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f, + 0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20, + 0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a, + 0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29, + 0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x63,0x6f, + 0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49, + 0x4e,0x45,0x47,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70, + 0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20, + 0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e, + 0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29, + 0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63, + 0x68,0x5f,0x72,0x65,0x61,0x64,0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c, + 0x73,0x72,0x63,0x2c,0x64,0x73,0x74,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61, + 0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68, + 0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73, + 0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x58,0x4f,0x52,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e, + 0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52, + 0x4f,0x4c,0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45, + 0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d, + 0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74, + 0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66, + 0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x49,0x52,0x4f,0x52,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x52,0x4f,0x4c,0x5f,0x52,0x3b,0x0a,0x69,0x66, + 0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x29,0x0a,0x7b,0x0a, + 0x69,0x66,0x28,0x73,0x72,0x63,0x21,0x3d,0x64,0x73,0x74,0x29,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52, + 0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65, + 0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x73,0x72, + 0x63,0x5d,0x3d,0x69,0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d, + 0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28, + 0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a, + 0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73, + 0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x73,0x72,0x63,0x2a,0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75, + 0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x73,0x72,0x63,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43, + 0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x28,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x29,0x7c,0x28,0x31,0x75,0x3c,0x3c,0x73,0x72,0x63,0x29,0x3b,0x0a,0x23,0x65,0x6e, + 0x64,0x69,0x66,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x57,0x41,0x50,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44, + 0x5f,0x52,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d, + 0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x57,0x41,0x50,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44, + 0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44,0x5f, + 0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63, + 0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64,0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74, + 0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x30,0x78,0x46,0x46,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72, + 0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65, + 0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73, + 0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69, + 0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x41,0x44,0x44, + 0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f, + 0x52,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65, + 0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64, + 0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x30,0x78, + 0x46,0x46,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61, + 0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c, + 0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e, + 0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58, + 0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x55,0x42,0x5f,0x4d,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52, + 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x43,0x41,0x4c,0x5f,0x52,0x2b,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x4d,0x55,0x4c,0x5f,0x52, + 0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d,0x29, + 0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x31,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75, + 0x6e,0x74,0x3d,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x72,0x65,0x61,0x64,0x28,0x70,0x30,0x2c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68, + 0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x2c,0x69,0x2c,0x73,0x72,0x63,0x2c,0x30,0x78,0x46,0x46,0x2c,0x69,0x6e,0x73,0x74,0x2c,0x73,0x72,0x63,0x41, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74, + 0x2c,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42, + 0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x2c,0x6c,0x61,0x73,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x29,0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75, + 0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x44,0x49,0x56,0x5f,0x4d, + 0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52, + 0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x46,0x53,0x51,0x52,0x54,0x5f,0x52,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f, + 0x46,0x52,0x45,0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d,0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x76,0x6f, + 0x6c,0x61,0x74,0x69,0x6c,0x65,0x20,0x75,0x69,0x6e,0x74,0x20,0x64,0x73,0x74,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x32,0x3d,0x64,0x73,0x74,0x41, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3b,0x0a,0x65,0x5b,0x64,0x73,0x74,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x32,0x5d,0x2e,0x78, + 0x7c,0x3d,0x28,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x65,0x5b,0x69,0x5d,0x2e,0x78,0x7c,0x3d,0x28,0x30,0x78,0x34,0x30,0x3c,0x3c,0x38,0x29,0x3b,0x0a, + 0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x23, + 0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x30,0x3b,0x20,0x6a,0x3c,0x38,0x3b, + 0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x6a,0x5d,0x3d,0x69,0x3b,0x0a, + 0x23,0x65,0x6c,0x73,0x65,0x0a,0x75,0x69,0x6e,0x74,0x20,0x74,0x3d,0x69,0x7c,0x28,0x69,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x74,0x3d,0x74,0x7c,0x28,0x74,0x3c,0x3c,0x31, + 0x36,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x74,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67, + 0x65,0x64,0x7c,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3c,0x3c,0x33,0x32,0x29,0x3b,0x0a,0x72,0x65, + 0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x30,0x78,0x46,0x46,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a,0x7d,0x0a, + 0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20, + 0x3e,0x20,0x32,0x35,0x36,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x64,0x73,0x74,0x5d,0x3d,0x69, + 0x3b,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67, + 0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a, + 0x38,0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x64,0x73,0x74,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x64,0x73,0x74,0x3b,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66,0x0a, + 0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x72,0x65,0x67,0x3d,0x30,0x3b,0x20,0x72,0x65,0x67,0x3c,0x38,0x3b,0x20,0x2b,0x2b,0x72,0x65,0x67,0x29,0x0a,0x7b,0x0a, + 0x23,0x69,0x66,0x20,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x20,0x3e,0x20,0x32,0x35,0x36,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65, + 0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72, + 0x67,0x65,0x74,0x5b,0x72,0x65,0x67,0x5d,0x2b,0x31,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65, + 0x41,0x74,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x72,0x65,0x67,0x5d,0x2b,0x31,0x3b,0x0a,0x69, + 0x66,0x28,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x21,0x3d,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68, + 0x54,0x61,0x72,0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x5b,0x72,0x65, + 0x67,0x5d,0x3d,0x69,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6c,0x73,0x65,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x61,0x76,0x61,0x69,0x6c,0x61,0x62, + 0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61, + 0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x26,0x28,0x31,0x75,0x3c,0x3c,0x72,0x65,0x67,0x29,0x29,0x3f,0x28,0x28, + 0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72,0x67, + 0x65,0x74,0x3e,0x3e,0x28,0x72,0x65,0x67,0x2a,0x38,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x2b,0x31,0x29,0x3a,0x30,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e, + 0x67,0x65,0x64,0x26,0x28,0x31,0x75,0x3c,0x3c,0x72,0x65,0x67,0x29,0x29,0x3f,0x28,0x28,0x28,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68, + 0x61,0x6e,0x67,0x65,0x64,0x3e,0x3e,0x28,0x72,0x65,0x67,0x2a,0x38,0x29,0x29,0x26,0x30,0x78,0x46,0x46,0x29,0x2b,0x31,0x29,0x3a,0x30,0x3b,0x0a,0x69,0x66,0x28,0x61, + 0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x21,0x3d,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72, + 0x67,0x65,0x74,0x29,0x0a,0x7b,0x0a,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x3d,0x28,0x72,0x65,0x67,0x69, + 0x73,0x74,0x65,0x72,0x4c,0x61,0x73,0x74,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x26,0x7e,0x28,0x30,0x78,0x46,0x46,0x75,0x6c,0x3c,0x3c,0x28,0x72,0x65,0x67,0x2a,0x38, + 0x29,0x29,0x29,0x7c,0x28,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x28,0x69,0x29,0x3c,0x3c,0x28,0x72,0x65,0x67,0x2a,0x38,0x29,0x29,0x3b,0x0a,0x72,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x57,0x61,0x73,0x43,0x68,0x61,0x6e,0x67,0x65,0x64,0x7c,0x3d,0x31,0x75,0x3c,0x3c,0x72,0x65,0x67,0x3b,0x0a,0x7d,0x0a,0x23,0x65,0x6e,0x64,0x69,0x66, + 0x0a,0x7d,0x0a,0x69,0x66,0x28,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63, + 0x68,0x54,0x61,0x72,0x67,0x65,0x74,0x21,0x3d,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x29,0x0a, + 0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x69,0x2b,0x31,0x3b,0x0a,0x69,0x66,0x28,0x73,0x63, + 0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x42,0x72,0x61,0x6e,0x63,0x68,0x54,0x61,0x72, + 0x67,0x65,0x74,0x21,0x3d,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x29,0x0a, + 0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69,0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x69,0x2b,0x31,0x3b,0x0a,0x7d, + 0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x43,0x42,0x52,0x41,0x4e,0x43,0x48,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45, + 0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d, + 0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x43,0x46,0x52,0x4f,0x55,0x4e,0x44,0x3b,0x0a,0x69,0x66,0x28,0x6f,0x70,0x63,0x6f,0x64,0x65, + 0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x29,0x0a,0x7b,0x0a,0x69,0x66,0x28,0x70,0x61,0x73,0x73,0x3d, + 0x3d,0x30,0x29,0x0a,0x7b,0x0a,0x65,0x5b,0x69,0x5d,0x2e,0x78,0x3d,0x69,0x6e,0x73,0x74,0x2e,0x78,0x7c,0x28,0x30,0x78,0x38,0x30,0x3c,0x3c,0x38,0x29,0x3b,0x0a,0x7d, + 0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x69,0x2b, + 0x31,0x3b,0x0a,0x69,0x66,0x28,0x28,0x6d,0x6f,0x64,0x3e,0x3e,0x34,0x29,0x3e,0x3d,0x31,0x34,0x29,0x0a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x48,0x69, + 0x67,0x68,0x41,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x41,0x74,0x3d,0x69,0x2b,0x31,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d, + 0x0a,0x6f,0x70,0x63,0x6f,0x64,0x65,0x2d,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x46,0x52,0x45,0x51,0x5f,0x49,0x53,0x54,0x4f,0x52,0x45,0x3b,0x0a,0x7d,0x0a, + 0x7d,0x0a,0x75,0x69,0x6e,0x74,0x20,0x70,0x72,0x65,0x76,0x3d,0x70,0x30,0x5b,0x30,0x5d,0x2e,0x78,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72, + 0x6f,0x6c,0x6c,0x28,0x31,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x6a,0x3d,0x31,0x3b,0x20,0x6a,0x3c,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f, + 0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3b,0x20,0x2b,0x2b,0x6a,0x29,0x0a,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x63,0x75,0x72,0x3d,0x70,0x30,0x5b, + 0x6a,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x63,0x75,0x72,0x2e,0x78,0x3e,0x3d,0x70,0x72,0x65,0x76,0x29,0x0a,0x7b,0x0a,0x70,0x72,0x65,0x76,0x3d,0x63,0x75,0x72,0x2e,0x78, + 0x3b,0x0a,0x63,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x69,0x6e,0x74,0x20,0x6a,0x31,0x3d,0x6a,0x2d,0x31,0x3b,0x0a,0x64,0x6f,0x20,0x7b,0x0a,0x70, + 0x30,0x5b,0x6a,0x31,0x2b,0x31,0x5d,0x3d,0x70,0x30,0x5b,0x6a,0x31,0x5d,0x3b,0x0a,0x2d,0x2d,0x6a,0x31,0x3b,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x28, + 0x6a,0x31,0x3e,0x3d,0x30,0x29,0x26,0x26,0x28,0x70,0x30,0x5b,0x6a,0x31,0x5d,0x2e,0x78,0x3e,0x3d,0x63,0x75,0x72,0x2e,0x78,0x29,0x29,0x3b,0x0a,0x70,0x30,0x5b,0x6a, + 0x31,0x2b,0x31,0x5d,0x3d,0x63,0x75,0x72,0x3b,0x0a,0x7d,0x0a,0x70,0x30,0x5b,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f,0x63,0x6f,0x75, + 0x6e,0x74,0x5d,0x2e,0x78,0x3d,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x0a,0x5f,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x20,0x70,0x72,0x65,0x66,0x65,0x63,0x74,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x73,0x74,0x61,0x63,0x6b,0x3d,0x28, + 0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74,0x2a,0x29,0x28,0x70,0x30,0x2b,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x5f, + 0x63,0x6f,0x75,0x6e,0x74,0x2b,0x31,0x29,0x3b,0x0a,0x65,0x6e,0x75,0x6d,0x20,0x7b,0x20,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67, + 0x70,0x72,0x73,0x3d,0x32,0x31,0x20,0x7d,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e, + 0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x3b,0x20,0x2b,0x2b,0x69, + 0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x63,0x74,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x73,0x74,0x61,0x63,0x6b,0x5b,0x69,0x5d,0x3d,0x4e,0x55,0x4d,0x5f,0x56,0x47, + 0x50,0x52,0x5f,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x53,0x2d,0x32,0x2d,0x69,0x2a,0x32,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x69,0x6e,0x74, + 0x2a,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72,0x73,0x3d,0x70,0x72,0x65,0x66,0x65,0x63,0x74,0x68,0x5f,0x76,0x67,0x70,0x72, + 0x73,0x5f,0x73,0x74,0x61,0x63,0x6b,0x2b,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x3b,0x0a,0x23,0x70,0x72,0x61, + 0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x28,0x38,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x52,0x41, + 0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63, + 0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72,0x73,0x5b,0x69,0x5d,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6b,0x3d,0x30,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x3d,0x70,0x30,0x5b,0x30,0x5d,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e, + 0x74,0x65,0x72,0x3d,0x30,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x73,0x5f,0x77,0x61,0x69,0x74,0x63,0x6e,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3d,0x36,0x33,0x3b,0x0a,0x69, + 0x6e,0x74,0x20,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x3d, + 0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e, + 0x74,0x2a,0x20,0x6c,0x61,0x73,0x74,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x70,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75, + 0x69,0x6e,0x74,0x20,0x73,0x69,0x7a,0x65,0x5f,0x6c,0x69,0x6d,0x69,0x74,0x3d,0x28,0x43,0x4f,0x4d,0x50,0x49,0x4c,0x45,0x44,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d, + 0x5f,0x53,0x49,0x5a,0x45,0x2d,0x32,0x30,0x30,0x29,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61, + 0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x73,0x74,0x61,0x72,0x74,0x5f,0x70,0x3d,0x70,0x3b,0x0a,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c, + 0x6c,0x28,0x31,0x29,0x0a,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x20,0x69,0x3c,0x52,0x41,0x4e,0x44,0x4f,0x4d,0x58,0x5f,0x50,0x52,0x4f, + 0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x3b,0x20,0x2b,0x2b,0x69,0x29,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x32,0x20,0x69,0x6e, + 0x73,0x74,0x3d,0x65,0x5b,0x69,0x5d,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x32,0x30,0x3c,0x3c,0x38,0x29,0x29,0x0a,0x6c,0x61, + 0x73,0x74,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x3d,0x70,0x3b,0x0a,0x62,0x6f,0x6f,0x6c,0x20,0x64,0x6f,0x6e,0x65,0x3d,0x66,0x61, + 0x6c,0x73,0x65,0x3b,0x0a,0x64,0x6f,0x20,0x7b,0x0a,0x75,0x69,0x6e,0x74,0x32,0x20,0x6a,0x69,0x74,0x5f,0x69,0x6e,0x73,0x74,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6a,0x69, + 0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x69,0x6e,0x74,0x20,0x6a,0x69,0x74,0x5f,0x76, + 0x6d,0x63,0x6e,0x74,0x3b,0x0a,0x69,0x66,0x28,0x21,0x64,0x6f,0x6e,0x65,0x26,0x26,0x28,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x2e,0x78, + 0x3d,0x3d,0x69,0x29,0x26,0x26,0x28,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61, + 0x62,0x6c,0x65,0x3e,0x30,0x29,0x29,0x0a,0x7b,0x0a,0x2b,0x2b,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69, + 0x6e,0x74,0x20,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3d,0x70,0x72,0x65,0x66,0x65,0x63,0x74,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x73,0x74,0x61,0x63,0x6b,0x5b, + 0x2d,0x2d,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x5d,0x3b, + 0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72,0x73,0x5b,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x2e, + 0x79,0x5d,0x3d,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x7c,0x28,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3c,0x3c,0x31,0x36,0x29,0x3b,0x0a,0x6a,0x69, + 0x74,0x5f,0x69,0x6e,0x73,0x74,0x3d,0x65,0x5b,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x2e,0x79,0x5d,0x3b,0x0a,0x6a,0x69,0x74,0x5f,0x70, + 0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3b,0x0a,0x6a,0x69,0x74,0x5f, + 0x76,0x6d,0x63,0x6e,0x74,0x3d,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3b,0x0a,0x73,0x5f,0x77,0x61,0x69,0x74,0x63,0x6e,0x74,0x5f,0x76,0x61,0x6c, + 0x75,0x65,0x3d,0x36,0x33,0x3b,0x0a,0x2b,0x2b,0x6b,0x3b,0x0a,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x64,0x61,0x74,0x61,0x3d,0x70,0x30,0x5b,0x6b,0x5d,0x3b, + 0x0a,0x7d,0x0a,0x65,0x6c,0x73,0x65,0x0a,0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76, + 0x67,0x70,0x72,0x73,0x5f,0x64,0x61,0x74,0x61,0x3d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72,0x73,0x5b,0x69,0x5d,0x3b,0x0a,0x63, + 0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72, + 0x73,0x5f,0x64,0x61,0x74,0x61,0x26,0x30,0x78,0x46,0x46,0x46,0x46,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x70,0x72,0x65,0x76,0x5f,0x6d,0x65, + 0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3d,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x65,0x64,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x64,0x61,0x74,0x61,0x3e, + 0x3e,0x31,0x36,0x3b,0x0a,0x69,0x66,0x28,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x29,0x0a,0x70,0x72,0x65,0x66,0x65,0x63,0x74,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f, + 0x73,0x74,0x61,0x63,0x6b,0x5b,0x6e,0x75,0x6d,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x73,0x5f,0x61,0x76,0x61,0x69,0x6c,0x61,0x62, + 0x6c,0x65,0x2b,0x2b,0x5d,0x3d,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3b,0x0a,0x69,0x66,0x28,0x69,0x6e,0x73,0x74,0x2e,0x78,0x26,0x28,0x30,0x78,0x38,0x30,0x3c,0x3c, + 0x38,0x29,0x29,0x0a,0x7b,0x0a,0x2b,0x2b,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3b,0x0a,0x73,0x5f,0x77,0x61,0x69,0x74,0x63,0x6e,0x74,0x5f,0x76, + 0x61,0x6c,0x75,0x65,0x3d,0x36,0x33,0x3b,0x0a,0x7d,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x69,0x6e,0x74,0x20,0x76,0x6d,0x63,0x6e,0x74,0x3d,0x6d,0x65,0x6d,0x5f,0x63, + 0x6f,0x75,0x6e,0x74,0x65,0x72,0x2d,0x70,0x72,0x65,0x76,0x5f,0x6d,0x65,0x6d,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x65,0x72,0x3b,0x0a,0x6a,0x69,0x74,0x5f,0x69,0x6e,0x73, + 0x74,0x3d,0x69,0x6e,0x73,0x74,0x3b,0x0a,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d, + 0x2d,0x76,0x67,0x70,0x72,0x5f,0x69,0x64,0x3b,0x0a,0x6a,0x69,0x74,0x5f,0x76,0x6d,0x63,0x6e,0x74,0x3d,0x28,0x76,0x6d,0x63,0x6e,0x74,0x3c,0x73,0x5f,0x77,0x61,0x69, + 0x74,0x63,0x6e,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x3f,0x76,0x6d,0x63,0x6e,0x74,0x3a,0x2d,0x31,0x3b,0x0a,0x69,0x66,0x28,0x76,0x6d,0x63,0x6e,0x74,0x3c,0x73, + 0x5f,0x77,0x61,0x69,0x74,0x63,0x6e,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x29,0x0a,0x73,0x5f,0x77,0x61,0x69,0x74,0x63,0x6e,0x74,0x5f,0x76,0x61,0x6c,0x75,0x65,0x3d, + 0x76,0x6d,0x63,0x6e,0x74,0x3b,0x0a,0x64,0x6f,0x6e,0x65,0x3d,0x74,0x72,0x75,0x65,0x3b,0x0a,0x7d,0x0a,0x70,0x3d,0x6a,0x69,0x74,0x5f,0x65,0x6d,0x69,0x74,0x5f,0x69, + 0x6e,0x73,0x74,0x72,0x75,0x63,0x74,0x69,0x6f,0x6e,0x28,0x70,0x2c,0x6c,0x61,0x73,0x74,0x5f,0x62,0x72,0x61,0x6e,0x63,0x68,0x5f,0x74,0x61,0x72,0x67,0x65,0x74,0x2c, + 0x6a,0x69,0x74,0x5f,0x69,0x6e,0x73,0x74,0x2c,0x6a,0x69,0x74,0x5f,0x70,0x72,0x65,0x66,0x65,0x74,0x63,0x68,0x5f,0x76,0x67,0x70,0x72,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x2c,0x6a,0x69,0x74,0x5f,0x76,0x6d,0x63,0x6e,0x74,0x2c,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x69,0x66,0x28,0x70,0x2d,0x73,0x74,0x61, + 0x72,0x74,0x5f,0x70,0x3e,0x73,0x69,0x7a,0x65,0x5f,0x6c,0x69,0x6d,0x69,0x74,0x29,0x0a,0x7b,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x38,0x30, + 0x31,0x64,0x30,0x63,0x75,0x3b,0x20,0x0a,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x7d,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x28,0x21,0x64,0x6f, + 0x6e,0x65,0x29,0x3b,0x0a,0x7d,0x0a,0x2a,0x28,0x70,0x2b,0x2b,0x29,0x3d,0x30,0x78,0x62,0x65,0x38,0x30,0x31,0x64,0x30,0x63,0x75,0x3b,0x20,0x0a,0x72,0x65,0x74,0x75, + 0x72,0x6e,0x20,0x70,0x3b,0x0a,0x7d,0x0a,0x5f,0x5f,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x5f,0x5f,0x28,0x28,0x72,0x65,0x71,0x64,0x5f,0x77,0x6f,0x72,0x6b, + 0x5f,0x67,0x72,0x6f,0x75,0x70,0x5f,0x73,0x69,0x7a,0x65,0x28,0x36,0x34,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0a,0x5f,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x20,0x76, + 0x6f,0x69,0x64,0x20,0x72,0x61,0x6e,0x64,0x6f,0x6d,0x78,0x5f,0x6a,0x69,0x74,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20, + 0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72, + 0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x69,0x6e,0x74,0x65,0x72,0x6d,0x65,0x64,0x69,0x61,0x74,0x65,0x5f,0x70, + 0x72,0x6f,0x67,0x72,0x61,0x6d,0x73,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x73,0x2c, + 0x75,0x69,0x6e,0x74,0x20,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x2c,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f, + 0x74,0x2a,0x20,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x2c,0x75,0x69,0x6e,0x74,0x33,0x32,0x5f,0x74,0x20,0x69,0x74,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x29,0x0a, + 0x7b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x3d,0x67,0x65,0x74,0x5f,0x67,0x6c, + 0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x2f,0x33,0x32,0x3b,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x73,0x75,0x62,0x3d,0x67,0x65, + 0x74,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x64,0x28,0x30,0x29,0x20,0x25,0x20,0x33,0x32,0x3b,0x0a,0x69,0x66,0x28,0x73,0x75,0x62,0x21,0x3d,0x30,0x29,0x0a, + 0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x20,0x65,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x32,0x2a,0x29,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78, + 0x2a,0x28,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x2b,0x28,0x31, + 0x32,0x38,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e, + 0x74,0x32,0x2a,0x20,0x70,0x30,0x3d,0x69,0x6e,0x74,0x65,0x72,0x6d,0x65,0x64,0x69,0x61,0x74,0x65,0x5f,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x73,0x2b,0x67,0x6c,0x6f, + 0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x49,0x4e,0x54,0x45,0x52,0x4d,0x45,0x44,0x49,0x41,0x54,0x45,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f, + 0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x32,0x29,0x29,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69, + 0x6e,0x74,0x2a,0x20,0x70,0x3d,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x73,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x43,0x4f,0x4d, + 0x50,0x49,0x4c,0x45,0x44,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d,0x5f,0x53,0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x69,0x6e,0x74,0x29,0x29, + 0x3b,0x0a,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x5f,0x6a,0x69,0x74,0x5f,0x63,0x6f,0x64,0x65,0x28,0x65,0x2c,0x70,0x30,0x2c,0x70,0x2c,0x62,0x61,0x74,0x63,0x68, + 0x5f,0x73,0x69,0x7a,0x65,0x29,0x3b,0x0a,0x69,0x66,0x28,0x69,0x74,0x65,0x72,0x61,0x74,0x69,0x6f,0x6e,0x3d,0x3d,0x30,0x29,0x0a,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e, + 0x67,0x5b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x5d,0x3d,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x6c,0x6f,0x6e, + 0x67,0x2a,0x20,0x52,0x3d,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x2b,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x33,0x32,0x3b,0x0a, + 0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x2b,0x3d,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x69,0x6e,0x64,0x65,0x78,0x2a,0x28,0x45,0x4e,0x54,0x52,0x4f,0x50,0x59,0x5f,0x53, + 0x49,0x5a,0x45,0x2f,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x75,0x6c,0x6f,0x6e,0x67,0x29,0x29,0x3b,0x0a,0x52,0x5b,0x30,0x5d,0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x31,0x5d, + 0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x32,0x5d,0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x33,0x5d,0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x34,0x5d,0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x35,0x5d, + 0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x36,0x5d,0x3d,0x30,0x3b,0x0a,0x52,0x5b,0x37,0x5d,0x3d,0x30,0x3b,0x0a,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x64,0x6f,0x75, + 0x62,0x6c,0x65,0x2a,0x20,0x41,0x3d,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x64,0x6f,0x75,0x62,0x6c,0x65,0x2a,0x29,0x28,0x52,0x2b,0x32,0x34,0x29,0x3b, + 0x0a,0x41,0x5b,0x30,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28, + 0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x30,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x31,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69, + 0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x32,0x5d,0x3d,0x67,0x65, + 0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b, + 0x32,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x33,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42, + 0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x33,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x34,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f, + 0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x34,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x35, + 0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72, + 0x6f,0x70,0x79,0x5b,0x35,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x36,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61,0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c, + 0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x36,0x5d,0x29,0x3b,0x0a,0x41,0x5b,0x37,0x5d,0x3d,0x67,0x65,0x74,0x53,0x6d,0x61, + 0x6c,0x6c,0x50,0x6f,0x73,0x69,0x74,0x69,0x76,0x65,0x46,0x6c,0x6f,0x61,0x74,0x42,0x69,0x74,0x73,0x28,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x37,0x5d,0x29,0x3b, + 0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x30,0x5d,0x3d,0x65,0x6e,0x74, + 0x72,0x6f,0x70,0x79,0x5b,0x38,0x5d,0x26,0x43,0x61,0x63,0x68,0x65,0x4c,0x69,0x6e,0x65,0x41,0x6c,0x69,0x67,0x6e,0x4d,0x61,0x73,0x6b,0x3b,0x0a,0x28,0x28,0x5f,0x5f, + 0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x36,0x29,0x29,0x5b,0x31,0x5d,0x3d,0x65,0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b, + 0x31,0x30,0x5d,0x3b,0x0a,0x75,0x69,0x6e,0x74,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x3d,0x65,0x6e,0x74,0x72,0x6f, + 0x70,0x79,0x5b,0x31,0x32,0x5d,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x37,0x29,0x29, + 0x5b,0x30,0x5d,0x3d,0x30,0x2b,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x31,0x29,0x3b,0x0a,0x61,0x64,0x64,0x72, + 0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x3e,0x3e,0x3d,0x20,0x31,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75, + 0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x37,0x29,0x29,0x5b,0x31,0x5d,0x3d,0x32,0x2b,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74, + 0x65,0x72,0x73,0x26,0x31,0x29,0x3b,0x0a,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x20,0x3e,0x3e,0x3d,0x20,0x31,0x3b,0x0a, + 0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x37,0x29,0x29,0x5b,0x32,0x5d,0x3d,0x34,0x2b,0x28,0x61, + 0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x31,0x29,0x3b,0x0a,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73, + 0x74,0x65,0x72,0x73,0x20,0x3e,0x3e,0x3d,0x20,0x31,0x3b,0x0a,0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b, + 0x31,0x37,0x29,0x29,0x5b,0x33,0x5d,0x3d,0x36,0x2b,0x28,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x52,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x26,0x31,0x29,0x3b,0x0a, + 0x28,0x28,0x5f,0x5f,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x75,0x69,0x6e,0x74,0x2a,0x29,0x28,0x52,0x2b,0x31,0x39,0x29,0x29,0x5b,0x30,0x5d,0x3d,0x28,0x65,0x6e,0x74, + 0x72,0x6f,0x70,0x79,0x5b,0x31,0x33,0x5d,0x26,0x44,0x61,0x74,0x61,0x73,0x65,0x74,0x45,0x78,0x74,0x72,0x61,0x49,0x74,0x65,0x6d,0x73,0x29,0x2a,0x43,0x61,0x63,0x68, + 0x65,0x4c,0x69,0x6e,0x65,0x53,0x69,0x7a,0x65,0x3b,0x0a,0x52,0x5b,0x32,0x30,0x5d,0x3d,0x67,0x65,0x74,0x46,0x6c,0x6f,0x61,0x74,0x4d,0x61,0x73,0x6b,0x28,0x65,0x6e, + 0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x34,0x5d,0x29,0x3b,0x0a,0x52,0x5b,0x32,0x31,0x5d,0x3d,0x67,0x65,0x74,0x46,0x6c,0x6f,0x61,0x74,0x4d,0x61,0x73,0x6b,0x28,0x65, + 0x6e,0x74,0x72,0x6f,0x70,0x79,0x5b,0x31,0x35,0x5d,0x29,0x3b,0x0a,0x7d,0x0a,0x00 +}; + +} // namespace xmrig diff --git a/src/backend/opencl/cl/rx/randomx_constants_loki.h b/src/backend/opencl/cl/rx/randomx_constants_loki.h new file mode 100644 index 000000000..7e461c192 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_constants_loki.h @@ -0,0 +1,96 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +//Dataset base size in bytes. Must be a power of 2. +#define RANDOMX_DATASET_BASE_SIZE 2147483648 + +//Dataset extra size. Must be divisible by 64. +#define RANDOMX_DATASET_EXTRA_SIZE 33554368 + +//Scratchpad L3 size in bytes. Must be a power of 2. +#define RANDOMX_SCRATCHPAD_L3 2097152 + +//Scratchpad L2 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L3. +#define RANDOMX_SCRATCHPAD_L2 262144 + +//Scratchpad L1 size in bytes. Must be a power of two (minimum 64) and less than or equal to RANDOMX_SCRATCHPAD_L2. +#define RANDOMX_SCRATCHPAD_L1 16384 + +//Jump condition mask size in bits. +#define RANDOMX_JUMP_BITS 8 + +//Jump condition mask offset in bits. The sum of RANDOMX_JUMP_BITS and RANDOMX_JUMP_OFFSET must not exceed 16. +#define RANDOMX_JUMP_OFFSET 8 + +//Integer instructions +#define RANDOMX_FREQ_IADD_RS 25 +#define RANDOMX_FREQ_IADD_M 7 +#define RANDOMX_FREQ_ISUB_R 16 +#define RANDOMX_FREQ_ISUB_M 7 +#define RANDOMX_FREQ_IMUL_R 16 +#define RANDOMX_FREQ_IMUL_M 4 +#define RANDOMX_FREQ_IMULH_R 4 +#define RANDOMX_FREQ_IMULH_M 1 +#define RANDOMX_FREQ_ISMULH_R 4 +#define RANDOMX_FREQ_ISMULH_M 1 +#define RANDOMX_FREQ_IMUL_RCP 8 +#define RANDOMX_FREQ_INEG_R 2 +#define RANDOMX_FREQ_IXOR_R 15 +#define RANDOMX_FREQ_IXOR_M 5 +#define RANDOMX_FREQ_IROR_R 8 +#define RANDOMX_FREQ_IROL_R 2 +#define RANDOMX_FREQ_ISWAP_R 4 + +//Floating point instructions +#define RANDOMX_FREQ_FSWAP_R 4 +#define RANDOMX_FREQ_FADD_R 16 +#define RANDOMX_FREQ_FADD_M 5 +#define RANDOMX_FREQ_FSUB_R 16 +#define RANDOMX_FREQ_FSUB_M 5 +#define RANDOMX_FREQ_FSCAL_R 6 +#define RANDOMX_FREQ_FMUL_R 32 +#define RANDOMX_FREQ_FDIV_M 4 +#define RANDOMX_FREQ_FSQRT_R 6 + +//Control instructions +#define RANDOMX_FREQ_CBRANCH 16 +#define RANDOMX_FREQ_CFROUND 1 + +//Store instruction +#define RANDOMX_FREQ_ISTORE 16 + +//No-op instruction +#define RANDOMX_FREQ_NOP 0 + +#define RANDOMX_DATASET_ITEM_SIZE 64 + +#define RANDOMX_PROGRAM_SIZE 320 + +#define HASH_SIZE 64 +#define ENTROPY_SIZE (128 + RANDOMX_PROGRAM_SIZE * 8) +#define REGISTERS_SIZE 256 +#define IMM_BUF_SIZE (RANDOMX_PROGRAM_SIZE * 4 - REGISTERS_SIZE) +#define IMM_INDEX_COUNT ((IMM_BUF_SIZE / 4) - 2) +#define VM_STATE_SIZE (REGISTERS_SIZE + IMM_BUF_SIZE + RANDOMX_PROGRAM_SIZE * 4) +#define ROUNDING_MODE (RANDOMX_FREQ_CFROUND ? -1 : 0) + +// Scratchpad L1/L2/L3 bits +#define LOC_L1 (32 - 14) +#define LOC_L2 (32 - 18) +#define LOC_L3 (32 - 21) diff --git a/src/backend/opencl/cl/rx/randomx_constants_monero.h b/src/backend/opencl/cl/rx/randomx_constants_monero.h new file mode 100644 index 000000000..1967a8c2c --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_constants_monero.h @@ -0,0 +1,96 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +//Dataset base size in bytes. Must be a power of 2. +#define RANDOMX_DATASET_BASE_SIZE 2147483648 + +//Dataset extra size. Must be divisible by 64. +#define RANDOMX_DATASET_EXTRA_SIZE 33554368 + +//Scratchpad L3 size in bytes. Must be a power of 2. +#define RANDOMX_SCRATCHPAD_L3 2097152 + +//Scratchpad L2 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L3. +#define RANDOMX_SCRATCHPAD_L2 262144 + +//Scratchpad L1 size in bytes. Must be a power of two (minimum 64) and less than or equal to RANDOMX_SCRATCHPAD_L2. +#define RANDOMX_SCRATCHPAD_L1 16384 + +//Jump condition mask size in bits. +#define RANDOMX_JUMP_BITS 8 + +//Jump condition mask offset in bits. The sum of RANDOMX_JUMP_BITS and RANDOMX_JUMP_OFFSET must not exceed 16. +#define RANDOMX_JUMP_OFFSET 8 + +//Integer instructions +#define RANDOMX_FREQ_IADD_RS 16 +#define RANDOMX_FREQ_IADD_M 7 +#define RANDOMX_FREQ_ISUB_R 16 +#define RANDOMX_FREQ_ISUB_M 7 +#define RANDOMX_FREQ_IMUL_R 16 +#define RANDOMX_FREQ_IMUL_M 4 +#define RANDOMX_FREQ_IMULH_R 4 +#define RANDOMX_FREQ_IMULH_M 1 +#define RANDOMX_FREQ_ISMULH_R 4 +#define RANDOMX_FREQ_ISMULH_M 1 +#define RANDOMX_FREQ_IMUL_RCP 8 +#define RANDOMX_FREQ_INEG_R 2 +#define RANDOMX_FREQ_IXOR_R 15 +#define RANDOMX_FREQ_IXOR_M 5 +#define RANDOMX_FREQ_IROR_R 8 +#define RANDOMX_FREQ_IROL_R 2 +#define RANDOMX_FREQ_ISWAP_R 4 + +//Floating point instructions +#define RANDOMX_FREQ_FSWAP_R 4 +#define RANDOMX_FREQ_FADD_R 16 +#define RANDOMX_FREQ_FADD_M 5 +#define RANDOMX_FREQ_FSUB_R 16 +#define RANDOMX_FREQ_FSUB_M 5 +#define RANDOMX_FREQ_FSCAL_R 6 +#define RANDOMX_FREQ_FMUL_R 32 +#define RANDOMX_FREQ_FDIV_M 4 +#define RANDOMX_FREQ_FSQRT_R 6 + +//Control instructions +#define RANDOMX_FREQ_CBRANCH 25 +#define RANDOMX_FREQ_CFROUND 1 + +//Store instruction +#define RANDOMX_FREQ_ISTORE 16 + +//No-op instruction +#define RANDOMX_FREQ_NOP 0 + +#define RANDOMX_DATASET_ITEM_SIZE 64 + +#define RANDOMX_PROGRAM_SIZE 256 + +#define HASH_SIZE 64 +#define ENTROPY_SIZE (128 + RANDOMX_PROGRAM_SIZE * 8) +#define REGISTERS_SIZE 256 +#define IMM_BUF_SIZE (RANDOMX_PROGRAM_SIZE * 4 - REGISTERS_SIZE) +#define IMM_INDEX_COUNT ((IMM_BUF_SIZE / 4) - 2) +#define VM_STATE_SIZE (REGISTERS_SIZE + IMM_BUF_SIZE + RANDOMX_PROGRAM_SIZE * 4) +#define ROUNDING_MODE (RANDOMX_FREQ_CFROUND ? -1 : 0) + +// Scratchpad L1/L2/L3 bits +#define LOC_L1 (32 - 14) +#define LOC_L2 (32 - 18) +#define LOC_L3 (32 - 21) diff --git a/src/backend/opencl/cl/rx/randomx_constants_wow.h b/src/backend/opencl/cl/rx/randomx_constants_wow.h new file mode 100644 index 000000000..8ff80ef65 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_constants_wow.h @@ -0,0 +1,96 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +//Dataset base size in bytes. Must be a power of 2. +#define RANDOMX_DATASET_BASE_SIZE 2147483648 + +//Dataset extra size. Must be divisible by 64. +#define RANDOMX_DATASET_EXTRA_SIZE 33554368 + +//Scratchpad L3 size in bytes. Must be a power of 2. +#define RANDOMX_SCRATCHPAD_L3 1048576 + +//Scratchpad L2 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L3. +#define RANDOMX_SCRATCHPAD_L2 131072 + +//Scratchpad L1 size in bytes. Must be a power of two (minimum 64) and less than or equal to RANDOMX_SCRATCHPAD_L2. +#define RANDOMX_SCRATCHPAD_L1 16384 + +//Jump condition mask size in bits. +#define RANDOMX_JUMP_BITS 8 + +//Jump condition mask offset in bits. The sum of RANDOMX_JUMP_BITS and RANDOMX_JUMP_OFFSET must not exceed 16. +#define RANDOMX_JUMP_OFFSET 8 + +//Integer instructions +#define RANDOMX_FREQ_IADD_RS 25 +#define RANDOMX_FREQ_IADD_M 7 +#define RANDOMX_FREQ_ISUB_R 16 +#define RANDOMX_FREQ_ISUB_M 7 +#define RANDOMX_FREQ_IMUL_R 16 +#define RANDOMX_FREQ_IMUL_M 4 +#define RANDOMX_FREQ_IMULH_R 4 +#define RANDOMX_FREQ_IMULH_M 1 +#define RANDOMX_FREQ_ISMULH_R 4 +#define RANDOMX_FREQ_ISMULH_M 1 +#define RANDOMX_FREQ_IMUL_RCP 8 +#define RANDOMX_FREQ_INEG_R 2 +#define RANDOMX_FREQ_IXOR_R 15 +#define RANDOMX_FREQ_IXOR_M 5 +#define RANDOMX_FREQ_IROR_R 10 +#define RANDOMX_FREQ_IROL_R 0 +#define RANDOMX_FREQ_ISWAP_R 4 + +//Floating point instructions +#define RANDOMX_FREQ_FSWAP_R 8 +#define RANDOMX_FREQ_FADD_R 20 +#define RANDOMX_FREQ_FADD_M 5 +#define RANDOMX_FREQ_FSUB_R 20 +#define RANDOMX_FREQ_FSUB_M 5 +#define RANDOMX_FREQ_FSCAL_R 6 +#define RANDOMX_FREQ_FMUL_R 20 +#define RANDOMX_FREQ_FDIV_M 4 +#define RANDOMX_FREQ_FSQRT_R 6 + +//Control instructions +#define RANDOMX_FREQ_CBRANCH 16 +#define RANDOMX_FREQ_CFROUND 1 + +//Store instruction +#define RANDOMX_FREQ_ISTORE 16 + +//No-op instruction +#define RANDOMX_FREQ_NOP 0 + +#define RANDOMX_DATASET_ITEM_SIZE 64 + +#define RANDOMX_PROGRAM_SIZE 256 + +#define HASH_SIZE 64 +#define ENTROPY_SIZE (128 + RANDOMX_PROGRAM_SIZE * 8) +#define REGISTERS_SIZE 256 +#define IMM_BUF_SIZE (RANDOMX_PROGRAM_SIZE * 4 - REGISTERS_SIZE) +#define IMM_INDEX_COUNT ((IMM_BUF_SIZE / 4) - 2) +#define VM_STATE_SIZE (REGISTERS_SIZE + IMM_BUF_SIZE + RANDOMX_PROGRAM_SIZE * 4) +#define ROUNDING_MODE (RANDOMX_FREQ_CFROUND ? -1 : 0) + +// Scratchpad L1/L2/L3 bits +#define LOC_L1 (32 - 14) +#define LOC_L2 (32 - 17) +#define LOC_L3 (32 - 20) diff --git a/src/backend/opencl/cl/rx/randomx_jit.cl b/src/backend/opencl/cl/rx/randomx_jit.cl new file mode 100644 index 000000000..1de7c82b4 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_jit.cl @@ -0,0 +1,1495 @@ +/* +Copyright (c) 2019 SChernykh +Portions Copyright (c) 2018-2019 tevador + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +#define INITIAL_HASH_SIZE 64 +#define INTERMEDIATE_PROGRAM_SIZE (RANDOMX_PROGRAM_SIZE * 16) +#define COMPILED_PROGRAM_SIZE 10048 +#define NUM_VGPR_REGISTERS 128 + +#define mantissaSize 52 +#define exponentSize 11 +#define mantissaMask ((1UL << mantissaSize) - 1) +#define exponentMask ((1UL << exponentSize) - 1) +#define exponentBias 1023 + +#define dynamicExponentBits 4 +#define staticExponentBits 4 +#define constExponentBits 0x300 +#define dynamicMantissaMask ((1UL << (mantissaSize + dynamicExponentBits)) - 1) + +#define ScratchpadL1Mask_reg 38 +#define ScratchpadL2Mask_reg 39 +#define ScratchpadL3Mask_reg 50 + +#define ScratchpadL3Mask (RANDOMX_SCRATCHPAD_L3 - 8) + +#define RANDOMX_JUMP_BITS 8 +#define RANDOMX_JUMP_OFFSET 8 + +__global uint* jit_scratchpad_calc_address(__global uint* p, uint src, uint imm32, uint mask_reg, uint batch_size) +{ + // s_add_i32 s14, s(16 + src * 2), imm32 + *(p++) = 0x810eff10u | (src << 1); + *(p++) = imm32; + + // v_and_b32 v28, s14, mask_reg + *(p++) = 0x2638000eu | (mask_reg << 9); + + return p; +} + +__global uint* jit_scratchpad_calc_fixed_address(__global uint* p, uint imm32, uint batch_size) +{ + // v_mov_b32 v28, imm32 + *(p++) = 0x7e3802ffu; + *(p++) = imm32; + + return p; +} + +__global uint* jit_scratchpad_load(__global uint* p, uint vgpr_index) +{ + // v28 = offset + +#if GCN_VERSION >= 14 + // global_load_dwordx2 v[vgpr_index:vgpr_index+1], v28, s[0:1] + *(p++) = 0xdc548000u; + *(p++) = 0x0000001cu | (vgpr_index << 24); +#else + *(p++) = 0x32543902u; // v_add_u32 v42, vcc, v2, v28 + *(p++) = 0xd11c6a2bu; // v_addc_u32 v43, vcc, v3, 0, vcc + *(p++) = 0x01a90103u; + *(p++) = 0xdc540000u; // flat_load_dwordx2 v[vgpr_index:vgpr_index+1], v[42:43] + *(p++) = 0x0000002au | (vgpr_index << 24); +#endif + + return p; +} + +__global uint* jit_scratchpad_load2(__global uint* p, uint vgpr_index, int vmcnt) +{ + // s_waitcnt vmcnt(N) + if (vmcnt >= 0) + *(p++) = 0xbf8c0f70u | (vmcnt & 15) | ((vmcnt >> 4) << 14); + + // v_readlane_b32 s14, vgpr_index, 0 + *(p++) = 0xd289000eu; + *(p++) = 0x00010100u | vgpr_index; + + // v_readlane_b32 s15, vgpr_index + 1, 0 + *(p++) = 0xd289000fu; + *(p++) = 0x00010100u | (vgpr_index + 1); + + return p; +} + +__global uint* jit_scratchpad_calc_address_fp(__global uint* p, uint src, uint imm32, uint mask_reg, uint batch_size) +{ + // s_add_i32 s14, s(16 + src * 2), imm32 + *(p++) = 0x810eff10u | (src << 1); + *(p++) = imm32; + + // v_and_b32 v28, s14, mask_reg + *(p++) = 0x2638000eu | (mask_reg << 9); + +#if GCN_VERSION >= 14 + // v_add_u32 v28, v28, v44 + *(p++) = 0x6838591cu; +#else + // v_add_u32 v28, vcc, v28, v44 + *(p++) = 0x3238591cu; +#endif + + return p; +} + +__global uint* jit_scratchpad_load_fp(__global uint* p, uint vgpr_index) +{ + // v28 = offset + +#if GCN_VERSION >= 14 + // global_load_dword v(vgpr_index), v28, s[0:1] + *(p++) = 0xdc508000u; + *(p++) = 0x0000001cu | (vgpr_index << 24); +#else + *(p++) = 0x32543902u; // v_add_u32 v42, vcc, v2, v28 + *(p++) = 0xd11c6a2bu; // v_addc_u32 v43, vcc, v3, 0, vcc + *(p++) = 0x01a90103u; + *(p++) = 0xdc500000u; // flat_load_dword v(vgpr_index), v[42:43] + *(p++) = 0x0000002au | (vgpr_index << 24); +#endif + + return p; +} + +__global uint* jit_scratchpad_load2_fp(__global uint* p, uint vgpr_index, int vmcnt) +{ + // s_waitcnt vmcnt(N) + if (vmcnt >= 0) + *(p++) = 0xbf8c0f70u | (vmcnt & 15) | ((vmcnt >> 4) << 14); + + // v_cvt_f64_i32 v[28:29], vgpr_index + *(p++) = 0x7e380900u | vgpr_index; + + return p; +} + +__global uint* jit_emit_instruction(__global uint* p, __global uint* last_branch_target, const uint2 inst, int prefetch_vgpr_index, int vmcnt, uint batch_size) +{ + uint opcode = inst.x & 0xFF; + const uint dst = (inst.x >> 8) & 7; + const uint src = (inst.x >> 16) & 7; + const uint mod = inst.x >> 24; + + if (opcode < RANDOMX_FREQ_IADD_RS) + { + const uint shift = (mod >> 2) % 4; + if (shift > 0) // p = 3/4 + { + // s_lshl_b64 s[14:15], s[(16 + src * 2):(17 + src * 2)], shift + *(p++) = 0x8e8e8010u | (src << 1) | (shift << 8); + + // s_add_u32 s(16 + dst * 2), s(16 + dst * 2), s14 + *(p++) = 0x80100e10u | (dst << 1) | (dst << 17); + + // s_addc_u32 s(17 + dst * 2), s(17 + dst * 2), s15 + *(p++) = 0x82110f11u | (dst << 1) | (dst << 17); + } + else // p = 1/4 + { + // s_add_u32 s(16 + dst * 2), s(16 + dst * 2), s(16 + src * 2) + *(p++) = 0x80101010u | (dst << 1) | (dst << 17) | (src << 9); + + // s_addc_u32 s(17 + dst * 2), s(17 + dst * 2), s(17 + src * 2) + *(p++) = 0x82111111u | (dst << 1) | (dst << 17) | (src << 9); + } + + if (dst == 5) // p = 1/8 + { + // s_add_u32 s(16 + dst * 2), s(16 + dst * 2), imm32 + *(p++) = 0x8010ff10u | (dst << 1) | (dst << 17); + *(p++) = inst.y; + + // s_addc_u32 s(17 + dst * 2), s(17 + dst * 2), ((inst.y < 0) ? -1 : 0) + *(p++) = 0x82110011u | (dst << 1) | (dst << 17) | (((as_int(inst.y) < 0) ? 0xc1 : 0x80) << 8); + } + + // 12*3/4 + 8*1/4 + 12/8 = 12.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IADD_RS; + + if (opcode < RANDOMX_FREQ_IADD_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // s_add_u32 s(16 + dst * 2), s(16 + dst * 2), s14 + *(p++) = 0x80100e10u | (dst << 1) | (dst << 17); + + // s_addc_u32 s(17 + dst * 2), s(17 + dst * 2), s15 + *(p++) = 0x82110f11u | (dst << 1) | (dst << 17); + } + + // (12*7/8 + 8*1/8 + 28) + 8 = 47.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IADD_M; + + if (opcode < RANDOMX_FREQ_ISUB_R) + { + if (src != dst) // p = 7/8 + { + // s_sub_u32 s(16 + dst * 2), s(16 + dst * 2), s(16 + src * 2) + *(p++) = 0x80901010u | (dst << 1) | (dst << 17) | (src << 9); + + // s_subb_u32 s(17 + dst * 2), s(17 + dst * 2), s(17 + src * 2) + *(p++) = 0x82911111u | (dst << 1) | (dst << 17) | (src << 9); + } + else // p = 1/8 + { + // s_sub_u32 s(16 + dst * 2), s(16 + dst * 2), imm32 + *(p++) = 0x8090ff10u | (dst << 1) | (dst << 17); + *(p++) = inst.y; + + // s_subb_u32 s(17 + dst * 2), s(17 + dst * 2), ((inst.y < 0) ? -1 : 0) + *(p++) = 0x82910011u | (dst << 1) | (dst << 17) | (((as_int(inst.y) < 0) ? 0xc1 : 0x80) << 8); + } + + // 8*7/8 + 12/8 = 8.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_ISUB_R; + + if (opcode < RANDOMX_FREQ_ISUB_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // s_sub_u32 s(16 + dst * 2), s(16 + dst * 2), s14 + *(p++) = 0x80900e10u | (dst << 1) | (dst << 17); + + // s_subb_u32 s(17 + dst * 2), s(17 + dst * 2), s15 + *(p++) = 0x82910f11u | (dst << 1) | (dst << 17); + } + + // (12*7/8 + 8*1/8 + 28) + 8 = 47.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_ISUB_M; + + if (opcode < RANDOMX_FREQ_IMUL_R) + { + if (src != dst) // p = 7/8 + { +#if GCN_VERSION >= 14 + // s_mul_hi_u32 s15, s(16 + dst * 2), s(16 + src * 2) + *(p++) = 0x960f1010u | (dst << 1) | (src << 9); +#else + // v_mov_b32 v28, s(16 + dst * 2) + *(p++) = 0x7e380210u | (dst << 1); + // v_mul_hi_u32 v28, v28, s(16 + src * 2) + *(p++) = 0xd286001cu; + *(p++) = 0x0000211cu + (src << 10); + // v_readlane_b32 s15, v28, 0 + *(p++) = 0xd289000fu; + *(p++) = 0x0001011cu; +#endif + + // s_mul_i32 s14, s(16 + dst * 2), s(17 + src * 2) + *(p++) = 0x920e1110u | (dst << 1) | (src << 9); + + // s_add_u32 s15, s15, s14 + *(p++) = 0x800f0e0fu; + + // s_mul_i32 s14, s(17 + dst * 2), s(16 + src * 2) + *(p++) = 0x920e1011u | (dst << 1) | (src << 9); + + // s_add_u32 s(17 + dst * 2), s15, s14 + *(p++) = 0x80110e0fu | (dst << 17); + + // s_mul_i32 s(16 + dst * 2), s(16 + dst * 2), s(16 + src * 2) + *(p++) = 0x92101010u | (dst << 1) | (dst << 17) | (src << 9); + } + else // p = 1/8 + { +#if GCN_VERSION >= 14 + // s_mul_hi_u32 s15, s(16 + dst * 2), imm32 + *(p++) = 0x960fff10u | (dst << 1); + *(p++) = inst.y; +#else + // v_mov_b32 v28, imm32 + *(p++) = 0x7e3802ffu; + *(p++) = inst.y; + // v_mul_hi_u32 v28, v28, s(16 + dst * 2) + *(p++) = 0xd286001cu; + *(p++) = 0x0000211cu + (dst << 10); + // v_readlane_b32 s15, v28, 0 + *(p++) = 0xd289000fu; + *(p++) = 0x0001011cu; +#endif + + if (as_int(inst.y) < 0) // p = 1/2 + { + // s_sub_u32 s15, s15, s(16 + dst * 2) + *(p++) = 0x808f100fu | (dst << 9); + } + + // s_mul_i32 s14, s(17 + dst * 2), imm32 + *(p++) = 0x920eff11u | (dst << 1); + *(p++) = inst.y; + + // s_add_u32 s(17 + dst * 2), s15, s14 + *(p++) = 0x80110e0fu | (dst << 17); + + // s_mul_i32 s(16 + dst * 2), s(16 + dst * 2), imm32 + *(p++) = 0x9210ff10u | (dst << 1) | (dst << 17); + *(p++) = inst.y; + } + + // 24*7/8 + 28*1/8 + 4*1/16 = 24.75 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IMUL_R; + + if (opcode < RANDOMX_FREQ_IMUL_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + +#if GCN_VERSION >= 14 + // s_mul_hi_u32 s33, s(16 + dst * 2), s14 + *(p++) = 0x96210e10u | (dst << 1); +#else + // v_mov_b32 v28, s(16 + dst * 2) + *(p++) = 0x7e380210u | (dst << 1); + // v_mul_hi_u32 v28, v28, s14 + *(p++) = 0xd286001cu; + *(p++) = 0x00001d1cu; + // v_readlane_b32 s33, v28, 0 + *(p++) = 0xd2890021u; + *(p++) = 0x0001011cu; +#endif + + // s_mul_i32 s32, s(16 + dst * 2), s15 + *(p++) = 0x92200f10u | (dst << 1); + + // s_add_u32 s33, s33, s32 + *(p++) = 0x80212021u; + + // s_mul_i32 s32, s(17 + dst * 2), s14 + *(p++) = 0x92200e11u | (dst << 1); + + // s_add_u32 s(17 + dst * 2), s33, s32 + *(p++) = 0x80112021u | (dst << 17); + + // s_mul_i32 s(16 + dst * 2), s(16 + dst * 2), s14 + *(p++) = 0x92100e10u | (dst << 1) | (dst << 17); + } + + // (12*7/8 + 8*1/8 + 28) + 24 = 63.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IMUL_M; + + if (opcode < RANDOMX_FREQ_IMULH_R) + { + *(p++) = 0xbe8e0110u | (dst << 1); // s_mov_b64 s[14:15], s[16 + dst * 2:17 + dst * 2] + *(p++) = 0xbea60110u | (src << 1); // s_mov_b64 s[38:39], s[16 + src * 2:17 + src * 2] + *(p++) = 0xbebc1e3au; // s_swappc_b64 s[60:61], s[58:59] + *(p++) = 0xbe90010eu | (dst << 17); // s_mov_b64 s[16 + dst * 2:17 + dst * 2], s[14:15] + + // 16 bytes + return p; + } + opcode -= RANDOMX_FREQ_IMULH_R; + + if (opcode < RANDOMX_FREQ_IMULH_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + *(p++) = 0xbea60110u | (dst << 1); // s_mov_b64 s[38:39], s[16 + src * 2:17 + src * 2] + *(p++) = 0xbebc1e3au; // s_swappc_b64 s[60:61], s[58:59] + *(p++) = 0xbe90010eu | (dst << 17); // s_mov_b64 s[16 + dst * 2:17 + dst * 2], s[14:15] + } + + // (12*7/8 + 8*1/8 + 28) + 12 = 51.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IMULH_M; + + if (opcode < RANDOMX_FREQ_ISMULH_R) + { + *(p++) = 0xbe8e0110u | (dst << 1); // s_mov_b64 s[14:15], s[16 + dst * 2:17 + dst * 2] + *(p++) = 0xbea60110u | (src << 1); // s_mov_b64 s[38:39], s[16 + src * 2:17 + src * 2] + *(p++) = 0xbebc1e38u; // s_swappc_b64 s[60:61], s[56:57] + *(p++) = 0xbe90010eu | (dst << 17); // s_mov_b64 s[16 + dst * 2:17 + dst * 2], s[14:15] + + // 16 bytes + return p; + } + opcode -= RANDOMX_FREQ_ISMULH_R; + + if (opcode < RANDOMX_FREQ_ISMULH_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + *(p++) = 0xbea60110u | (dst << 1); // s_mov_b64 s[38:39], s[16 + dst * 2:17 + dst * 2] + *(p++) = 0xbebc1e38u; // s_swappc_b64 s[60:61], s[56:57] + *(p++) = 0xbe90010eu | (dst << 17); // s_mov_b64 s[16 + dst * 2:17 + dst * 2], s[14:15] + } + + // (12*7/8 + 8*1/8 + 28) + 12 = 51.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_ISMULH_M; + + if (opcode < RANDOMX_FREQ_IMUL_RCP) + { + if (inst.y & (inst.y - 1)) + { + const uint2 rcp_value = as_uint2(imul_rcp_value(inst.y)); + + *(p++) = 0xbea000ffu; // s_mov_b32 s32, imm32 + *(p++) = rcp_value.x; +#if GCN_VERSION >= 14 + *(p++) = 0x960f2010u | (dst << 1); // s_mul_hi_u32 s15, s(16 + dst * 2), s32 +#else + // v_mov_b32 v28, s32 + *(p++) = 0x7e380220u; + // v_mul_hi_u32 v28, v28, s(16 + dst * 2) + *(p++) = 0xd286001cu; + *(p++) = 0x0000211cu + (dst << 10); + // v_readlane_b32 s15, v28, 0 + *(p++) = 0xd289000fu; + *(p++) = 0x0001011cu; +#endif + *(p++) = 0x920eff10u | (dst << 1); // s_mul_i32 s14, s(16 + dst * 2), imm32 + *(p++) = rcp_value.y; + *(p++) = 0x800f0e0fu; // s_add_u32 s15, s15, s14 + *(p++) = 0x920e2011u | (dst << 1); // s_mul_i32 s14, s(17 + dst * 2), s32 + *(p++) = 0x80110e0fu | (dst << 17); // s_add_u32 s(17 + dst * 2), s15, s14 + *(p++) = 0x92102010u | (dst << 1) | (dst << 17);// s_mul_i32 s(16 + dst * 2), s(16 + dst * 2), s32 + } + + // 36 bytes + return p; + } + opcode -= RANDOMX_FREQ_IMUL_RCP; + + if (opcode < RANDOMX_FREQ_INEG_R) + { + *(p++) = 0x80901080u | (dst << 9) | (dst << 17); // s_sub_u32 s(16 + dst * 2), 0, s(16 + dst * 2) + *(p++) = 0x82911180u | (dst << 9) | (dst << 17); // s_subb_u32 s(17 + dst * 2), 0, s(17 + dst * 2) + + // 8 bytes + return p; + } + opcode -= RANDOMX_FREQ_INEG_R; + + if (opcode < RANDOMX_FREQ_IXOR_R) + { + if (src != dst) // p = 7/8 + { + // s_xor_b64 s[16 + dst * 2:17 + dst * 2], s[16 + dst * 2:17 + dst * 2], s[16 + src * 2:17 + src * 2] + *(p++) = 0x88901010u | (dst << 1) | (dst << 17) | (src << 9); + } + else // p = 1/8 + { + if (as_int(inst.y) < 0) // p = 1/2 + { + // s_mov_b32 s62, imm32 + *(p++) = 0xbebe00ffu; + *(p++) = inst.y; + + // s_xor_b64 s[16 + dst * 2:17 + dst * 2], s[16 + dst * 2:17 + dst * 2], s[62:63] + *(p++) = 0x88903e10u | (dst << 1) | (dst << 17); + } + else + { + // s_xor_b32 s(16 + dst * 2), s(16 + dst * 2), imm32 + *(p++) = 0x8810ff10u | (dst << 1) | (dst << 17); + *(p++) = inst.y; + } + } + + // 4*7/8 + 12/16 + 8/16 = 4.75 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IXOR_R; + + if (opcode < RANDOMX_FREQ_IXOR_M) + { + if (prefetch_vgpr_index >= 0) + { + if (src != dst) // p = 7/8 + p = jit_scratchpad_calc_address(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + else // p = 1/8 + p = jit_scratchpad_calc_fixed_address(p, inst.y & ScratchpadL3Mask, batch_size); + + p = jit_scratchpad_load(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // s_xor_b64 s[16 + dst * 2:17 + dst * 2], s[16 + dst * 2:17 + dst * 2], s[14:15] + *(p++) = 0x88900e10u | (dst << 1) | (dst << 17); + } + + // (12*7/8 + 8*1/8 + 28) + 4 = 43.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IXOR_M; + + if (opcode < RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R) + { + if (src != dst) // p = 7/8 + { + if (opcode < RANDOMX_FREQ_IROR_R) + { + // s_lshr_b64 s[32:33], s[16 + dst * 2:17 + dst * 2], s(16 + src * 2) + *(p++) = 0x8fa01010u | (dst << 1) | (src << 9); + + // s_sub_u32 s15, 64, s(16 + src * 2) + *(p++) = 0x808f10c0u | (src << 9); + + // s_lshl_b64 s[34:35], s[16 + dst * 2:17 + dst * 2], s15 + *(p++) = 0x8ea20f10u | (dst << 1); + } + else + { + // s_lshl_b64 s[32:33], s[16 + dst * 2:17 + dst * 2], s(16 + src * 2) + *(p++) = 0x8ea01010u | (dst << 1) | (src << 9); + + // s_sub_u32 s15, 64, s(16 + src * 2) + *(p++) = 0x808f10c0u | (src << 9); + + // s_lshr_b64 s[34:35], s[16 + dst * 2:17 + dst * 2], s15 + *(p++) = 0x8fa20f10u | (dst << 1); + } + } + else // p = 1/8 + { + const uint shift = ((opcode < RANDOMX_FREQ_IROR_R) ? inst.y : -inst.y) & 63; + + // s_lshr_b64 s[32:33], s[16 + dst * 2:17 + dst * 2], shift + *(p++) = 0x8fa08010u | (dst << 1) | (shift << 8); + + // s_lshl_b64 s[34:35], s[16 + dst * 2:17 + dst * 2], 64 - shift + *(p++) = 0x8ea28010u | (dst << 1) | ((64 - shift) << 8); + } + + // s_or_b64 s[16 + dst * 2:17 + dst * 2], s[32:33], s[34:35] + *(p++) = 0x87902220u | (dst << 17); + + // 12*7/8 + 8/8 + 4 = 15.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R; + + if (opcode < RANDOMX_FREQ_ISWAP_R) + { + if (src != dst) + { + *(p++) = 0xbea00110u | (dst << 1); // s_mov_b64 s[32:33], s[16 + dst * 2:17 + dst * 2] + *(p++) = 0xbe900110u | (src << 1) | (dst << 17);// s_mov_b64 s[16 + dst * 2:17 + dst * 2], s[16 + src * 2:17 + src * 2] + *(p++) = 0xbe900120u | (src << 17); // s_mov_b64 s[16 + src * 2:17 + Src * 2], s[32:33] + } + + // 12*7/8 = 10.5 bytes on average + return p; + } + opcode -= RANDOMX_FREQ_ISWAP_R; + + if (opcode < RANDOMX_FREQ_FSWAP_R) + { + // ds_swizzle_b32 v(60 + dst * 2), v(60 + dst * 2) offset:0x8001 + *(p++) = 0xd87a8001u; + *(p++) = 0x3c00003cu + (dst << 1) + (dst << 25); + + // ds_swizzle_b32 v(61 + dst * 2), v(61 + dst * 2) offset:0x8001 + *(p++) = 0xd87a8001u; + *(p++) = 0x3d00003du + (dst << 1) + (dst << 25); + + // s_waitcnt lgkmcnt(0) + *(p++) = 0xbf8cc07fu; + + // 20 bytes + return p; + } + opcode -= RANDOMX_FREQ_FSWAP_R; + + if (opcode < RANDOMX_FREQ_FADD_R) + { + // v_add_f64 v[60 + dst * 2:61 + dst * 2], v[60 + dst * 2:61 + dst * 2], v[52 + src * 2:53 + src * 2] + *(p++) = 0xd280003cu + ((dst & 3) << 1); + *(p++) = 0x0002693cu + ((dst & 3) << 1) + ((src & 3) << 10); + + // 8 bytes + return p; + } + opcode -= RANDOMX_FREQ_FADD_R; + + if (opcode < RANDOMX_FREQ_FADD_M) + { + if (prefetch_vgpr_index >= 0) + { + p = jit_scratchpad_calc_address_fp(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + p = jit_scratchpad_load_fp(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2_fp(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // v_add_f64 v[60 + dst * 2:61 + dst * 2], v[60 + dst * 2:61 + dst * 2], v[28:29] + *(p++) = 0xd280003cu + ((dst & 3) << 1); + *(p++) = 0x0002393cu + ((dst & 3) << 1); + } + + // 32 + 8 = 40 bytes + return p; + } + opcode -= RANDOMX_FREQ_FADD_M; + + if (opcode < RANDOMX_FREQ_FSUB_R) + { + // v_add_f64 v[60 + dst * 2:61 + dst * 2], v[60 + dst * 2:61 + dst * 2], -v[52 + src * 2:53 + src * 2] + *(p++) = 0xd280003cu + ((dst & 3) << 1); + *(p++) = 0x4002693cu + ((dst & 3) << 1) + ((src & 3) << 10); + + // 8 bytes + return p; + } + opcode -= RANDOMX_FREQ_FSUB_R; + + if (opcode < RANDOMX_FREQ_FSUB_M) + { + if (prefetch_vgpr_index >= 0) + { + p = jit_scratchpad_calc_address_fp(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + p = jit_scratchpad_load_fp(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2_fp(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // v_add_f64 v[60 + dst * 2:61 + dst * 2], v[60 + dst * 2:61 + dst * 2], -v[28:29] + *(p++) = 0xd280003cu + ((dst & 3) << 1); + *(p++) = 0x4002393cu + ((dst & 3) << 1); + } + + // 32 + 8 = 40 bytes + return p; + } + opcode -= RANDOMX_FREQ_FSUB_M; + + if (opcode < RANDOMX_FREQ_FSCAL_R) + { + // v_xor_b32 v(61 + dst * 2), v(61 + dst * 2), v51 + *(p++) = 0x2a7a673du + ((dst & 3) << 1) + ((dst & 3) << 18); + + // 4 bytes + return p; + } + opcode -= RANDOMX_FREQ_FSCAL_R; + + if (opcode < RANDOMX_FREQ_FMUL_R) + { + // v_mul_f64 v[68 + dst * 2:69 + dst * 2], v[68 + dst * 2:69 + dst * 2], v[52 + src * 2:53 + src * 2] + *(p++) = 0xd2810044u + ((dst & 3) << 1); + *(p++) = 0x00026944u + ((dst & 3) << 1) + ((src & 3) << 10); + + // 8 bytes + return p; + } + opcode -= RANDOMX_FREQ_FMUL_R; + + if (opcode < RANDOMX_FREQ_FDIV_M) + { + if (prefetch_vgpr_index >= 0) + { + p = jit_scratchpad_calc_address_fp(p, src, inst.y, (mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg, batch_size); + p = jit_scratchpad_load_fp(p, prefetch_vgpr_index ? prefetch_vgpr_index : 28); + } + + if (prefetch_vgpr_index <= 0) + { + p = jit_scratchpad_load2_fp(p, prefetch_vgpr_index ? -prefetch_vgpr_index : 28, prefetch_vgpr_index ? vmcnt : 0); + + // s_swappc_b64 s[60:61], s[48 + dst * 2:49 + dst * 2] + *(p++) = 0xbebc1e30u + ((dst & 3) << 1); + } + + // 32 + 4 = 36 bytes + return p; + } + opcode -= RANDOMX_FREQ_FDIV_M; + + if (opcode < RANDOMX_FREQ_FSQRT_R) + { + // s_swappc_b64 s[60:61], s[40 + dst * 2:41 + dst * 2] + *(p++) = 0xbebc1e28u + ((dst & 3) << 1); + + // 4 bytes + return p; + } + opcode -= RANDOMX_FREQ_FSQRT_R; + + if (opcode < RANDOMX_FREQ_CBRANCH) + { + const int shift = (mod >> 4) + RANDOMX_JUMP_OFFSET; + uint imm = inst.y | (1u << shift); + imm &= ~(1u << (shift - 1)); + + // s_add_u32 s(16 + dst * 2), s(16 + dst * 2), imm32 + *(p++) = 0x8010ff10 | (dst << 1) | (dst << 17); + *(p++) = imm; + + // s_addc_u32 s(17 + dst * 2), s(17 + dst * 2), ((imm < 0) ? -1 : 0) + *(p++) = 0x82110011u | (dst << 1) | (dst << 17) | (((as_int(imm) < 0) ? 0xc1 : 0x80) << 8); + + const uint conditionMaskReg = 70 + (mod >> 4); + + // s_and_b32 s14, s(16 + dst * 2), conditionMaskReg + *(p++) = 0x860e0010u | (dst << 1) | (conditionMaskReg << 8); + + // s_cbranch_scc0 target + const int delta = ((last_branch_target - p) - 1); + *(p++) = 0xbf840000u | (delta & 0xFFFF); + + // 20 bytes + return p; + } + opcode -= RANDOMX_FREQ_CBRANCH; + + if (opcode < RANDOMX_FREQ_CFROUND) + { + const uint shift = inst.y & 63; + if (shift == 63) + { + *(p++) = 0x8e0e8110u | (src << 1); // s_lshl_b32 s14, s(16 + src * 2), 1 + *(p++) = 0x8f0f9f11u | (src << 1); // s_lshr_b32 s15, s(17 + src * 2), 31 + *(p++) = 0x870e0f0eu; // s_or_b32 s14, s14, s15 + *(p++) = 0x860e830eu; // s_and_b32 s14, s14, 3 + } + else + { + // s_bfe_u64 s[14:15], s[16:17], (shift,width=2) + *(p++) = 0x938eff10u | (src << 1); + *(p++) = shift | (2 << 16); + } + + // s_brev_b32 s14, s14 + *(p++) = 0xbe8e080eu; + + // s_lshr_b32 s66, s14, 30 + *(p++) = 0x8f429e0eu; + + // s_setreg_b32 hwreg(mode, 2, 2), s66 + *(p++) = 0xb9420881u; + + // 20 bytes + return p; + } + opcode -= RANDOMX_FREQ_CFROUND; + + if (opcode < RANDOMX_FREQ_ISTORE) + { + const uint mask = ((mod >> 4) < 14) ? ((mod % 4) ? ScratchpadL1Mask_reg : ScratchpadL2Mask_reg) : ScratchpadL3Mask_reg; + p = jit_scratchpad_calc_address(p, dst, inst.y, mask, batch_size); + + const uint vgpr_id = 48; + *(p++) = 0x7e000210u | (src << 1) | (vgpr_id << 17); // v_mov_b32 vgpr_id, s(16 + src * 2) + *(p++) = 0x7e020211u | (src << 1) | (vgpr_id << 17); // v_mov_b32 vgpr_id + 1, s(17 + src * 2) + + // v28 = offset + +#if GCN_VERSION >= 14 + // global_store_dwordx2 v28, v[vgpr_id:vgpr_id + 1], s[0:1] + *(p++) = 0xdc748000u; + *(p++) = 0x0000001cu | (vgpr_id << 8); +#else + // v_add_u32 v28, vcc, v28, v2 + *(p++) = 0x3238051cu; + // v_addc_u32 v29, vcc, 0, v3, vcc + *(p++) = 0x383a0680u; + // flat_store_dwordx2 v[28:29], v[vgpr_id:vgpr_id + 1] + *(p++) = 0xdc740000u; + *(p++) = 0x0000001cu | (vgpr_id << 8); +#endif + + // 28 bytes + return p; + } + opcode -= RANDOMX_FREQ_ISTORE; + + return p; +} + +int jit_prefetch_read( + __global uint2* p0, + const int prefetch_data_count, + const uint i, + const uint src, + const uint dst, + const uint2 inst, + const uint srcAvailableAt, + const uint scratchpadAvailableAt, + const uint scratchpadHighAvailableAt, + const int lastBranchTarget, + const int lastBranch) +{ + uint2 t; + t.x = (src == dst) ? (((inst.y & ScratchpadL3Mask) >= RANDOMX_SCRATCHPAD_L2) ? scratchpadHighAvailableAt : scratchpadAvailableAt) : max(scratchpadAvailableAt, srcAvailableAt); + t.y = i; + + const int t1 = t.x; + + if ((lastBranchTarget <= t1) && (t1 <= lastBranch)) + { + // Don't move prefetch inside previous branch scope + t.x = lastBranch + 1; + } + else if ((lastBranchTarget > lastBranch) && (t1 < lastBranchTarget)) + { + // Don't move prefetch outside current branch scope + t.x = lastBranchTarget; + } + + p0[prefetch_data_count] = t; + return prefetch_data_count + 1; +} + +__global uint* generate_jit_code(__global uint2* e, __global uint2* p0, __global uint* p, uint batch_size) +{ + int prefetch_data_count; + + #pragma unroll(1) + for (int pass = 0; pass < 2; ++pass) + { +#if RANDOMX_PROGRAM_SIZE > 256 + int registerLastChanged[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +#else + ulong registerLastChanged = 0; + uint registerWasChanged = 0; +#endif + + uint scratchpadAvailableAt = 0; + uint scratchpadHighAvailableAt = 0; + + int lastBranchTarget = -1; + int lastBranch = -1; + +#if RANDOMX_PROGRAM_SIZE > 256 + int registerLastChangedAtBranchTarget[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +#else + ulong registerLastChangedAtBranchTarget = 0; + uint registerWasChangedAtBranchTarget = 0; +#endif + uint scratchpadAvailableAtBranchTarget = 0; + uint scratchpadHighAvailableAtBranchTarget = 0; + + prefetch_data_count = 0; + + #pragma unroll(1) + for (uint i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) + { + // Clean flags + if (pass == 0) + e[i].x &= ~(0xf8u << 8); + + uint2 inst = e[i]; + uint opcode = inst.x & 0xFF; + const uint dst = (inst.x >> 8) & 7; + const uint src = (inst.x >> 16) & 7; + const uint mod = inst.x >> 24; + + if (pass == 1) + { + // Branch target + if (inst.x & (0x20 << 8)) + { + lastBranchTarget = i; +#if RANDOMX_PROGRAM_SIZE > 256 + #pragma unroll + for (int j = 0; j < 8; ++j) + registerLastChangedAtBranchTarget[j] = registerLastChanged[j]; +#else + registerLastChangedAtBranchTarget = registerLastChanged; + registerWasChangedAtBranchTarget = registerWasChanged; +#endif + scratchpadAvailableAtBranchTarget = scratchpadAvailableAt; + scratchpadHighAvailableAtBranchTarget = scratchpadHighAvailableAt; + } + + // Branch + if (inst.x & (0x40 << 8)) + lastBranch = i; + } + +#if RANDOMX_PROGRAM_SIZE > 256 + const uint srcAvailableAt = registerLastChanged[src] + 1; + const uint dstAvailableAt = registerLastChanged[dst] + 1; +#else + const uint srcAvailableAt = (registerWasChanged & (1u << src)) ? (((registerLastChanged >> (src * 8)) & 0xFF) + 1) : 0; + const uint dstAvailableAt = (registerWasChanged & (1u << dst)) ? (((registerLastChanged >> (dst * 8)) & 0xFF) + 1) : 0; +#endif + + if (opcode < RANDOMX_FREQ_IADD_RS) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_IADD_RS; + + if (opcode < RANDOMX_FREQ_IADD_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_IADD_M; + + if (opcode < RANDOMX_FREQ_ISUB_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_ISUB_R; + + if (opcode < RANDOMX_FREQ_ISUB_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_ISUB_M; + + if (opcode < RANDOMX_FREQ_IMUL_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_IMUL_R; + + if (opcode < RANDOMX_FREQ_IMUL_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_IMUL_M; + + if (opcode < RANDOMX_FREQ_IMULH_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_IMULH_R; + + if (opcode < RANDOMX_FREQ_IMULH_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_IMULH_M; + + if (opcode < RANDOMX_FREQ_ISMULH_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_ISMULH_R; + + if (opcode < RANDOMX_FREQ_ISMULH_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_ISMULH_M; + + if (opcode < RANDOMX_FREQ_IMUL_RCP) + { + if (inst.y & (inst.y - 1)) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + } + continue; + } + opcode -= RANDOMX_FREQ_IMUL_RCP; + + if (opcode < RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R; + + if (opcode < RANDOMX_FREQ_IXOR_M) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, dst, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_IXOR_M; + + if (opcode < RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + continue; + } + opcode -= RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R; + + if (opcode < RANDOMX_FREQ_ISWAP_R) + { + if (src != dst) + { +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; + registerLastChanged[src] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerLastChanged = (registerLastChanged & ~(0xFFul << (src * 8))) | ((ulong)(i) << (src * 8)); + registerWasChanged |= (1u << dst) | (1u << src); +#endif + } + continue; + } + opcode -= RANDOMX_FREQ_ISWAP_R; + + if (opcode < RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R) + { + continue; + } + opcode -= RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R; + + if (opcode < RANDOMX_FREQ_FADD_M) + { + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, 0xFF, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_FADD_M; + + if (opcode < RANDOMX_FREQ_FSUB_R) + { + continue; + } + opcode -= RANDOMX_FREQ_FSUB_R; + + if (opcode < RANDOMX_FREQ_FSUB_M) + { + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, 0xFF, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_FSUB_M; + + if (opcode < RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R) + { + continue; + } + opcode -= RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R; + + if (opcode < RANDOMX_FREQ_FDIV_M) + { + if (pass == 1) + prefetch_data_count = jit_prefetch_read(p0, prefetch_data_count, i, src, 0xFF, inst, srcAvailableAt, scratchpadAvailableAt, scratchpadHighAvailableAt, lastBranchTarget, lastBranch); + continue; + } + opcode -= RANDOMX_FREQ_FDIV_M; + + if (opcode < RANDOMX_FREQ_FSQRT_R) + { + continue; + } + opcode -= RANDOMX_FREQ_FSQRT_R; + + if (opcode < RANDOMX_FREQ_CBRANCH) + { + if (pass == 0) + { + // Workaround for a bug in AMD 18.6.1 driver + volatile uint dstAvailableAt2 = dstAvailableAt; + + // Mark branch target + e[dstAvailableAt2].x |= (0x20 << 8); + + // Mark branch + e[i].x |= (0x40 << 8); + + // Set all registers as changed at this instruction as per RandomX specification +#if RANDOMX_PROGRAM_SIZE > 256 + #pragma unroll + for (int j = 0; j < 8; ++j) + registerLastChanged[j] = i; +#else + uint t = i | (i << 8); + t = t | (t << 16); + registerLastChanged = t; + registerLastChanged = registerLastChanged | (registerLastChanged << 32); + registerWasChanged = 0xFF; +#endif + } + else + { + // Update only registers which really changed inside this branch +#if RANDOMX_PROGRAM_SIZE > 256 + registerLastChanged[dst] = i; +#else + registerLastChanged = (registerLastChanged & ~(0xFFul << (dst * 8))) | ((ulong)(i) << (dst * 8)); + registerWasChanged |= 1u << dst; +#endif + + for (int reg = 0; reg < 8; ++reg) + { +#if RANDOMX_PROGRAM_SIZE > 256 + const uint availableAtBranchTarget = registerLastChangedAtBranchTarget[reg] + 1; + const uint availableAt = registerLastChanged[reg] + 1; + if (availableAt != availableAtBranchTarget) + { + registerLastChanged[reg] = i; + } +#else + const uint availableAtBranchTarget = (registerWasChangedAtBranchTarget & (1u << reg)) ? (((registerLastChangedAtBranchTarget >> (reg * 8)) & 0xFF) + 1) : 0; + const uint availableAt = (registerWasChanged & (1u << reg)) ? (((registerLastChanged >> (reg * 8)) & 0xFF) + 1) : 0; + if (availableAt != availableAtBranchTarget) + { + registerLastChanged = (registerLastChanged & ~(0xFFul << (reg * 8))) | ((ulong)(i) << (reg * 8)); + registerWasChanged |= 1u << reg; + } +#endif + } + + if (scratchpadAvailableAtBranchTarget != scratchpadAvailableAt) + scratchpadAvailableAt = i + 1; + + if (scratchpadHighAvailableAtBranchTarget != scratchpadHighAvailableAt) + scratchpadHighAvailableAt = i + 1; + } + continue; + } + opcode -= RANDOMX_FREQ_CBRANCH; + + if (opcode < RANDOMX_FREQ_CFROUND) + { + continue; + } + opcode -= RANDOMX_FREQ_CFROUND; + + if (opcode < RANDOMX_FREQ_ISTORE) + { + if (pass == 0) + { + // Mark ISTORE + e[i].x = inst.x | (0x80 << 8); + } + else + { + scratchpadAvailableAt = i + 1; + if ((mod >> 4) >= 14) + scratchpadHighAvailableAt = i + 1; + } + continue; + } + opcode -= RANDOMX_FREQ_ISTORE; + } + } + + // Sort p0 + uint prev = p0[0].x; + #pragma unroll(1) + for (int j = 1; j < prefetch_data_count; ++j) + { + uint2 cur = p0[j]; + if (cur.x >= prev) + { + prev = cur.x; + continue; + } + + int j1 = j - 1; + do { + p0[j1 + 1] = p0[j1]; + --j1; + } while ((j1 >= 0) && (p0[j1].x >= cur.x)); + p0[j1 + 1] = cur; + } + p0[prefetch_data_count].x = RANDOMX_PROGRAM_SIZE; + + __global int* prefecth_vgprs_stack = (__global int*)(p0 + prefetch_data_count + 1); + + // v86 - v127 will be used for global memory loads + enum { num_prefetch_vgprs = 21 }; + + #pragma unroll + for (int i = 0; i < num_prefetch_vgprs; ++i) + prefecth_vgprs_stack[i] = NUM_VGPR_REGISTERS - 2 - i * 2; + + __global int* prefetched_vgprs = prefecth_vgprs_stack + num_prefetch_vgprs; + + #pragma unroll(8) + for (int i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) + prefetched_vgprs[i] = 0; + + int k = 0; + uint2 prefetch_data = p0[0]; + int mem_counter = 0; + int s_waitcnt_value = 63; + int num_prefetch_vgprs_available = num_prefetch_vgprs; + + __global uint* last_branch_target = p; + + const uint size_limit = (COMPILED_PROGRAM_SIZE - 200) / sizeof(uint); + __global uint* start_p = p; + + #pragma unroll(1) + for (int i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) + { + const uint2 inst = e[i]; + + if (inst.x & (0x20 << 8)) + last_branch_target = p; + + bool done = false; + do { + uint2 jit_inst; + int jit_prefetch_vgpr_index; + int jit_vmcnt; + + if (!done && (prefetch_data.x == i) && (num_prefetch_vgprs_available > 0)) + { + ++mem_counter; + const int vgpr_id = prefecth_vgprs_stack[--num_prefetch_vgprs_available]; + prefetched_vgprs[prefetch_data.y] = vgpr_id | (mem_counter << 16); + + jit_inst = e[prefetch_data.y]; + jit_prefetch_vgpr_index = vgpr_id; + jit_vmcnt = mem_counter; + + s_waitcnt_value = 63; + + ++k; + prefetch_data = p0[k]; + } + else + { + const int prefetched_vgprs_data = prefetched_vgprs[i]; + const int vgpr_id = prefetched_vgprs_data & 0xFFFF; + const int prev_mem_counter = prefetched_vgprs_data >> 16; + if (vgpr_id) + prefecth_vgprs_stack[num_prefetch_vgprs_available++] = vgpr_id; + + if (inst.x & (0x80 << 8)) + { + ++mem_counter; + s_waitcnt_value = 63; + } + + const int vmcnt = mem_counter - prev_mem_counter; + + jit_inst = inst; + jit_prefetch_vgpr_index = -vgpr_id; + jit_vmcnt = (vmcnt < s_waitcnt_value) ? vmcnt : -1; + + if (vmcnt < s_waitcnt_value) + s_waitcnt_value = vmcnt; + + done = true; + } + + p = jit_emit_instruction(p, last_branch_target, jit_inst, jit_prefetch_vgpr_index, jit_vmcnt, batch_size); + if (p - start_p > size_limit) + { + // Code size limit exceeded!!! + // Jump back to randomx_run kernel + *(p++) = 0xbe801d0cu; // s_setpc_b64 s[12:13] + return p; + } + } while (!done); + } + + // Jump back to randomx_run kernel + *(p++) = 0xbe801d0cu; // s_setpc_b64 s[12:13] + return p; +} + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void randomx_jit(__global ulong* entropy, __global ulong* registers, __global uint2* intermediate_programs, __global uint* programs, uint batch_size, __global uint32_t* rounding, uint32_t iteration) +{ + const uint global_index = get_global_id(0) / 32; + const uint sub = get_global_id(0) % 32; + + if (sub != 0) + return; + + __global uint2* e = (__global uint2*)(entropy + global_index * (ENTROPY_SIZE / sizeof(ulong)) + (128 / sizeof(ulong))); + __global uint2* p0 = intermediate_programs + global_index * (INTERMEDIATE_PROGRAM_SIZE / sizeof(uint2)); + __global uint* p = programs + global_index * (COMPILED_PROGRAM_SIZE / sizeof(uint)); + + generate_jit_code(e, p0, p, batch_size); + + if (iteration == 0) + rounding[global_index] = 0; + + __global ulong* R = registers + global_index * 32; + entropy += global_index * (ENTROPY_SIZE / sizeof(ulong)); + + // Group R registers + R[0] = 0; + R[1] = 0; + R[2] = 0; + R[3] = 0; + R[4] = 0; + R[5] = 0; + R[6] = 0; + R[7] = 0; + + // Group A registers + __global double* A = (__global double*)(R + 24); + A[0] = getSmallPositiveFloatBits(entropy[0]); + A[1] = getSmallPositiveFloatBits(entropy[1]); + A[2] = getSmallPositiveFloatBits(entropy[2]); + A[3] = getSmallPositiveFloatBits(entropy[3]); + A[4] = getSmallPositiveFloatBits(entropy[4]); + A[5] = getSmallPositiveFloatBits(entropy[5]); + A[6] = getSmallPositiveFloatBits(entropy[6]); + A[7] = getSmallPositiveFloatBits(entropy[7]); + + // ma, mx + ((__global uint*)(R + 16))[0] = entropy[8] & CacheLineAlignMask; + ((__global uint*)(R + 16))[1] = entropy[10]; + + // address registers + uint addressRegisters = entropy[12]; + ((__global uint*)(R + 17))[0] = 0 + (addressRegisters & 1); + addressRegisters >>= 1; + ((__global uint*)(R + 17))[1] = 2 + (addressRegisters & 1); + addressRegisters >>= 1; + ((__global uint*)(R + 17))[2] = 4 + (addressRegisters & 1); + addressRegisters >>= 1; + ((__global uint*)(R + 17))[3] = 6 + (addressRegisters & 1); + + // dataset offset + ((__global uint*)(R + 19))[0] = (entropy[13] & DatasetExtraItems) * CacheLineSize; + + // eMask + R[20] = getFloatMask(entropy[14]); + R[21] = getFloatMask(entropy[15]); +} diff --git a/src/backend/opencl/cl/rx/randomx_run_gfx803.asm b/src/backend/opencl/cl/rx/randomx_run_gfx803.asm new file mode 100644 index 000000000..47b41b572 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_run_gfx803.asm @@ -0,0 +1,712 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +.amdcl2 +.gpu GFX803 +.64bit +.arch_minor 0 +.arch_stepping 0 +.driver_version 203603 +.kernel randomx_run + .config + .dims x + .cws 64, 1, 1 + .sgprsnum 96 + # 6 waves per SIMD: 37-40 VGPRs + # 5 waves per SIMD: 41-48 VGPRs + # 4 waves per SIMD: 49-64 VGPRs + # 3 waves per SIMD: 65-84 VGPRs + # 2 waves per SIMD: 85-128 VGPRs + # 1 wave per SIMD: 129-256 VGPRs + .vgprsnum 128 + .localsize 256 + .floatmode 0xc0 + .pgmrsrc1 0x00ac035f + .pgmrsrc2 0x0000008c + .dx10clamp + .ieeemode + .useargs + .priority 0 + .arg _.global_offset_0, "size_t", long + .arg _.global_offset_1, "size_t", long + .arg _.global_offset_2, "size_t", long + .arg _.printf_buffer, "size_t", void*, global, , rdonly + .arg _.vqueue_pointer, "size_t", long + .arg _.aqlwrap_pointer, "size_t", long + .arg dataset, "uchar*", uchar*, global, const, rdonly + .arg scratchpad, "uchar*", uchar*, global, + .arg registers, "ulong*", ulong*, global, + .arg rounding_modes, "uint*", uint*, global, + .arg programs, "uint*", uint*, global, + .arg batch_size, "uint", uint + .arg rx_parameters, "uint", uint + .text + s_mov_b32 m0, 0x10000 + s_dcache_wb + s_waitcnt vmcnt(0) & lgkmcnt(0) + s_icache_inv + s_branch begin + + # pgmrsrc2 = 0x00000090, bits 1:5 = 8, so first 8 SGPRs (s0-s7) contain user data + # s8 contains group id + # v0 contains local id +begin: + s_mov_b32 s8, s6 + v_lshlrev_b32 v1, 6, s8 + v_add_u32 v1, vcc, v1, v0 + s_load_dwordx2 s[0:1], s[4:5], 0x0 + s_load_dwordx2 s[2:3], s[4:5], 0x40 + s_load_dwordx2 s[64:65], s[4:5], 0x48 + s_waitcnt lgkmcnt(0) + + # load rounding mode + s_lshl_b32 s16, s8, 2 + s_add_u32 s64, s64, s16 + s_addc_u32 s65, s65, 0 + v_mov_b32 v8, s64 + v_mov_b32 v9, s65 + flat_load_dword v8, v[8:9] + s_waitcnt vmcnt(0) + v_readlane_b32 s66, v8, 0 + s_setreg_b32 hwreg(mode, 2, 2), s66 + s_mov_b32 s67, 0 + + # used in FSQRT_R to check for "positive normal value" (v_cmpx_class_f64) + s_mov_b32 s68, 256 + s_mov_b32 s69, 0 + + v_add_u32 v1, vcc, s0, v1 + v_lshrrev_b32 v2, 6, v1 + v_lshlrev_b32 v3, 5, v2 + v_and_b32 v1, 63, v1 + v_mov_b32 v4, 0 + v_lshlrev_b64 v[3:4], 3, v[3:4] + v_lshlrev_b32 v5, 4, v1 + v_add_u32 v3, vcc, s2, v3 + v_mov_b32 v6, s3 + v_addc_u32 v4, vcc, v6, v4, vcc + v_lshlrev_b32 v41, 2, v1 + v_add_u32 v6, vcc, v3, v41 + v_addc_u32 v7, vcc, v4, 0, vcc + flat_load_dword v6, v[6:7] + v_mov_b32 v0, 0 + s_waitcnt vmcnt(0) + ds_write_b32 v41, v6 + s_waitcnt lgkmcnt(0) + s_mov_b64 s[0:1], exec + v_cmpx_le_u32 s[2:3], v1, 7 + s_cbranch_execz program_end + + # rx_parameters + s_load_dword s20, s[4:5], 0x5c + s_waitcnt lgkmcnt(0) + + # Scratchpad L1 size + s_bfe_u32 s21, s20, 0x050000 + s_lshl_b32 s21, 1, s21 + + # Scratchpad L2 size + s_bfe_u32 s22, s20, 0x050005 + s_lshl_b32 s22, 1, s22 + + # Scratchpad L3 size + s_bfe_u32 s23, s20, 0x05000A + s_lshl_b32 s23, 1, s23 + + # program iterations + s_bfe_u32 s24, s20, 0x04000F + s_lshl_b32 s24, 1, s24 + + # Base address for scratchpads + s_add_u32 s2, s23, 64 + v_mul_hi_u32 v20, v2, s2 + v_mul_lo_u32 v2, v2, s2 + + # v41, v44 = 0 + v_mov_b32 v41, 0 + v_mov_b32 v44, 0 + + ds_read_b32 v6, v0 offset:152 + v_cmp_lt_u32 s[2:3], v1, 4 + ds_read2_b64 v[34:37], v0 offset0:18 offset1:16 + ds_read_b64 v[11:12], v0 offset:136 + s_movk_i32 s9, 0x0 + s_mov_b64 s[6:7], exec + s_andn2_b64 exec, s[6:7], s[2:3] + ds_read_b64 v[13:14], v0 offset:160 + s_andn2_b64 exec, s[6:7], exec + v_mov_b32 v13, 0 + v_mov_b32 v14, 0 + s_mov_b64 exec, s[6:7] + + # compiled program size + s_mov_b64 s[6:7], s[8:9] + s_mulk_i32 s6, 10048 + + v_add_u32 v5, vcc, v0, v5 + v_add_u32 v5, vcc, v5, 64 + s_mov_b64 s[8:9], exec + s_andn2_b64 exec, s[8:9], s[2:3] + ds_read_b64 v[15:16], v0 offset:168 + s_andn2_b64 exec, s[8:9], exec + v_mov_b32 v15, 0 + v_mov_b32 v16, 0 + s_mov_b64 exec, s[8:9] + s_load_dwordx4 s[8:11], s[4:5], 0x30 + + # batch_size + s_load_dword s16, s[4:5], 0x58 + + s_load_dwordx2 s[4:5], s[4:5], 0x50 + v_lshlrev_b32 v1, 3, v1 + v_add_u32 v17, vcc, v0, v1 + s_waitcnt lgkmcnt(0) + v_add_u32 v2, vcc, s10, v2 + v_mov_b32 v18, s11 + v_addc_u32 v18, vcc, v18, v20, vcc + v_mov_b32 v19, 0xffffff + v_add_u32 v6, vcc, s8, v6 + v_mov_b32 v20, s9 + v_addc_u32 v20, vcc, v20, 0, vcc + ds_read_b64 v[21:22], v17 + s_add_u32 s4, s4, s6 + s_addc_u32 s5, s5, s7 + v_cndmask_b32 v19, v19, -1, s[2:3] + v_lshlrev_b32 v8, 3, v35 + v_lshlrev_b32 v7, 3, v34 + v_lshlrev_b32 v12, 3, v12 + v_lshlrev_b32 v10, 3, v11 + v_add_u32 v8, vcc, v8, v0 + v_add_u32 v7, vcc, v7, v0 + v_add_u32 v12, vcc, v12, v0 + v_add_u32 v0, vcc, v10, v0 + v_mov_b32 v10, v36 + v_mov_b32 v23, v37 + + # loop counter + s_sub_u32 s2, s24, 1 + + # batch_size + s_mov_b32 s3, s16 + + # Scratchpad masks for scratchpads + v_sub_u32 v38, vcc, s21, 8 + v_sub_u32 v39, vcc, s22, 8 + v_sub_u32 v50, vcc, s23, 8 + + # mask for FSCAL_R + v_mov_b32 v51, 0x80F00000 + + # swap v3 and v18 + v_mov_b32 v52, v3 + v_mov_b32 v3, v18 + v_mov_b32 v18, v52 + + # load scratchpad base address + v_readlane_b32 s0, v2, 0 + v_readlane_b32 s1, v3, 0 + + # save current executiom mask + s_mov_b64 s[36:37], exec + + # v41 = 0 on lane 0, set it to 8 on lane 1 + # v44 = 0 on lane 0, set it to 4 on lane 1 + s_mov_b64 exec, 2 + v_mov_b32 v41, 8 + v_mov_b32 v44, 4 + + # load group A registers + # Read low 8 bytes into lane 0 and high 8 bytes into lane 1 + s_mov_b64 exec, 3 + ds_read2_b64 v[52:55], v41 offset0:24 offset1:26 + ds_read2_b64 v[56:59], v41 offset0:28 offset1:30 + + # xmantissaMask + v_mov_b32 v77, (1 << 24) - 1 + + # xexponentMask + ds_read_b64 v[78:79], v41 offset:160 + + # Restore execution mask + s_mov_b64 exec, s[36:37] + + # sign mask (used in FSQRT_R) + v_mov_b32 v82, 0x80000000 + + # High 32 bits of "1.0" constant (used in FDIV_M) + v_mov_b32 v83, (1023 << 20) + + # Used to multiply FP64 values by 0.5 + v_mov_b32 v84, (1 << 20) + + s_getpc_b64 s[14:15] +cur_addr: + + # get addresses of FSQRT_R subroutines + s_add_u32 s40, s14, fsqrt_r_sub0 - cur_addr + s_addc_u32 s41, s15, 0 + s_add_u32 s42, s14, fsqrt_r_sub1 - cur_addr + s_addc_u32 s43, s15, 0 + s_add_u32 s44, s14, fsqrt_r_sub2 - cur_addr + s_addc_u32 s45, s15, 0 + s_add_u32 s46, s14, fsqrt_r_sub3 - cur_addr + s_addc_u32 s47, s15, 0 + + # get addresses of FDIV_M subroutines + s_add_u32 s48, s14, fdiv_m_sub0 - cur_addr + s_addc_u32 s49, s15, 0 + s_add_u32 s50, s14, fdiv_m_sub1 - cur_addr + s_addc_u32 s51, s15, 0 + s_add_u32 s52, s14, fdiv_m_sub2 - cur_addr + s_addc_u32 s53, s15, 0 + s_add_u32 s54, s14, fdiv_m_sub3 - cur_addr + s_addc_u32 s55, s15, 0 + + # get address for ISMULH_R subroutine + s_add_u32 s56, s14, ismulh_r_sub - cur_addr + s_addc_u32 s57, s15, 0 + + # get address for IMULH_R subroutine + s_add_u32 s58, s14, imulh_r_sub - cur_addr + s_addc_u32 s59, s15, 0 + + # used in IXOR_R instruction + s_mov_b32 s63, -1 + + # used in CBRANCH instruction + s_mov_b32 s70, (0xFF << 8) + s_mov_b32 s71, (0xFF << 9) + s_mov_b32 s72, (0xFF << 10) + s_mov_b32 s73, (0xFF << 11) + s_mov_b32 s74, (0xFF << 12) + s_mov_b32 s75, (0xFF << 13) + s_mov_b32 s76, (0xFF << 14) + s_mov_b32 s77, (0xFF << 15) + s_mov_b32 s78, (0xFF << 16) + s_mov_b32 s79, (0xFF << 17) + s_mov_b32 s80, (0xFF << 18) + s_mov_b32 s81, (0xFF << 19) + s_mov_b32 s82, (0xFF << 20) + s_mov_b32 s83, (0xFF << 21) + s_mov_b32 s84, (0xFF << 22) + s_mov_b32 s85, (0xFF << 23) + + # ScratchpadL3Mask64 + s_sub_u32 s86, s23, 64 + +main_loop: + # const uint2 spMix = as_uint2(R[readReg0] ^ R[readReg1]); + ds_read_b64 v[24:25], v0 + ds_read_b64 v[26:27], v12 + s_waitcnt lgkmcnt(0) + v_xor_b32 v25, v27, v25 + v_xor_b32 v24, v26, v24 + + # spAddr1 ^= spMix.y; + # spAddr0 ^= spMix.x; + v_xor_b32 v10, v25, v10 + v_xor_b32 v23, v24, v23 + + # spAddr1 &= ScratchpadL3Mask64; + # spAddr0 &= ScratchpadL3Mask64; + v_and_b32 v10, s86, v10 + v_and_b32 v23, s86, v23 + + # Offset for scratchpads + # offset1 = spAddr1 + sub * 8 + # offset0 = spAddr0 + sub * 8 + v_add_u32 v10, vcc, v10, v1 + v_add_u32 v23, vcc, v23, v1 + + # __global ulong* p1 = (__global ulong*)(scratchpad + offset1); + # __global ulong* p0 = (__global ulong*)(scratchpad + offset0); + v_add_u32 v26, vcc, v2, v10 + v_addc_u32 v27, vcc, v3, 0, vcc + v_add_u32 v23, vcc, v2, v23 + v_addc_u32 v24, vcc, v3, 0, vcc + + # load from spAddr1 + flat_load_dwordx2 v[28:29], v[26:27] + + # load from spAddr0 + flat_load_dwordx2 v[30:31], v[23:24] + s_waitcnt vmcnt(1) + + v_cvt_f64_i32 v[32:33], v28 + v_cvt_f64_i32 v[28:29], v29 + s_waitcnt vmcnt(0) + + # R[sub] ^= *p0; + v_xor_b32 v34, v21, v30 + v_xor_b32 v35, v22, v31 + + v_add_u32 v22, vcc, v6, v36 + v_addc_u32 v25, vcc, v20, 0, vcc + v_add_u32 v21, vcc, v22, v1 + v_addc_u32 v22, vcc, v25, 0, vcc + flat_load_dwordx2 v[21:22], v[21:22] + v_or_b32 v30, v32, v13 + v_and_b32 v31, v33, v19 + v_or_b32 v31, v31, v14 + v_or_b32 v28, v28, v15 + v_and_b32 v29, v29, v19 + v_or_b32 v29, v29, v16 + ds_write2_b64 v5, v[30:31], v[28:29] offset1:1 + s_waitcnt lgkmcnt(0) + + # Program 0 + + # load group F,E registers + # Read low 8 bytes into lane 0 and high 8 bytes into lane 1 + s_mov_b64 exec, 3 + ds_read2_b64 v[60:63], v41 offset0:8 offset1:10 + ds_read2_b64 v[64:67], v41 offset0:12 offset1:14 + ds_read2_b64 v[68:71], v41 offset0:16 offset1:18 + ds_read2_b64 v[72:75], v41 offset0:20 offset1:22 + + # load VM integer registers + v_readlane_b32 s16, v34, 0 + v_readlane_b32 s17, v35, 0 + v_readlane_b32 s18, v34, 1 + v_readlane_b32 s19, v35, 1 + v_readlane_b32 s20, v34, 2 + v_readlane_b32 s21, v35, 2 + v_readlane_b32 s22, v34, 3 + v_readlane_b32 s23, v35, 3 + v_readlane_b32 s24, v34, 4 + v_readlane_b32 s25, v35, 4 + v_readlane_b32 s26, v34, 5 + v_readlane_b32 s27, v35, 5 + v_readlane_b32 s28, v34, 6 + v_readlane_b32 s29, v35, 6 + v_readlane_b32 s30, v34, 7 + v_readlane_b32 s31, v35, 7 + + s_waitcnt lgkmcnt(0) + + # call JIT code + s_swappc_b64 s[12:13], s[4:5] + + # Write out group F,E registers + # Write low 8 bytes from lane 0 and high 8 bytes from lane 1 + ds_write2_b64 v41, v[60:61], v[62:63] offset0:8 offset1:10 + ds_write2_b64 v41, v[64:65], v[66:67] offset0:12 offset1:14 + ds_write2_b64 v41, v[68:69], v[70:71] offset0:16 offset1:18 + ds_write2_b64 v41, v[72:73], v[74:75] offset0:20 offset1:22 + + # store VM integer registers + v_writelane_b32 v28, s16, 0 + v_writelane_b32 v29, s17, 0 + v_writelane_b32 v28, s18, 1 + v_writelane_b32 v29, s19, 1 + v_writelane_b32 v28, s20, 2 + v_writelane_b32 v29, s21, 2 + v_writelane_b32 v28, s22, 3 + v_writelane_b32 v29, s23, 3 + v_writelane_b32 v28, s24, 4 + v_writelane_b32 v29, s25, 4 + v_writelane_b32 v28, s26, 5 + v_writelane_b32 v29, s27, 5 + v_writelane_b32 v28, s28, 6 + v_writelane_b32 v29, s29, 6 + v_writelane_b32 v28, s30, 7 + v_writelane_b32 v29, s31, 7 + + # Restore execution mask + s_mov_b64 exec, s[36:37] + + # Write out VM integer registers + ds_write_b64 v17, v[28:29] + + s_waitcnt lgkmcnt(0) + v_xor_b32 v21, v28, v21 + v_xor_b32 v22, v29, v22 + ds_read_b32 v28, v7 + ds_read_b32 v29, v8 + ds_write_b64 v17, v[21:22] + s_waitcnt lgkmcnt(1) + ds_read2_b64 v[30:33], v17 offset0:8 offset1:16 + v_xor_b32 v10, v28, v37 + s_waitcnt lgkmcnt(0) + v_xor_b32 v30, v32, v30 + v_xor_b32 v31, v33, v31 + v_xor_b32 v10, v10, v29 + flat_store_dwordx2 v[26:27], v[21:22] + v_and_b32 v10, 0x7fffffc0, v10 + flat_store_dwordx2 v[23:24], v[30:31] + s_cmp_eq_u32 s2, 0 + s_cbranch_scc1 main_loop_end + s_sub_i32 s2, s2, 1 + v_mov_b32 v37, v36 + v_mov_b32 v23, 0 + v_mov_b32 v36, v10 + v_mov_b32 v10, 0 + s_branch main_loop +main_loop_end: + + v_add_u32 v0, vcc, v18, v1 + v_addc_u32 v1, vcc, v4, 0, vcc + flat_store_dwordx2 v[0:1], v[21:22] + v_add_u32 v0, vcc, v0, 64 + v_addc_u32 v1, vcc, v1, 0, vcc + flat_store_dwordx2 v[0:1], v[30:31] + v_add_u32 v0, vcc, v0, 64 + v_addc_u32 v1, vcc, v1, 0, vcc + flat_store_dwordx2 v[0:1], v[32:33] + + # store rounding mode + v_mov_b32 v0, s64 + v_mov_b32 v1, s65 + v_mov_b32 v2, s66 + flat_store_dword v[0:1], v2 + +program_end: + s_endpgm + +fsqrt_r_sub0: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[68:69] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[68:69] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[68:69] + v_mov_b32 v48, v28 + v_sub_u32 v49, vcc, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[68:69] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[68:69], s[68:69] + v_mov_b32 v68, v42 + v_mov_b32 v69, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub1: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[70:71] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[70:71] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[70:71] + v_mov_b32 v48, v28 + v_sub_u32 v49, vcc, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[70:71] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[70:71], s[68:69] + v_mov_b32 v70, v42 + v_mov_b32 v71, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub2: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[72:73] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[72:73] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[72:73] + v_mov_b32 v48, v28 + v_sub_u32 v49, vcc, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[72:73] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[72:73], s[68:69] + v_mov_b32 v72, v42 + v_mov_b32 v73, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub3: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[74:75] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[74:75] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[74:75] + v_mov_b32 v48, v28 + v_sub_u32 v49, vcc, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[74:75] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[74:75], s[68:69] + v_mov_b32 v74, v42 + v_mov_b32 v75, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fdiv_m_sub0: + v_or_b32 v28, v28, v78 + v_and_b32 v29, v29, v77 + v_or_b32 v29, v29, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[68:69], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[68:69] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[68:69] + v_cmpx_eq_f64 s[14:15], v[68:69], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v68, v80 + v_mov_b32 v69, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub1: + v_or_b32 v28, v28, v78 + v_and_b32 v29, v29, v77 + v_or_b32 v29, v29, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[70:71], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[70:71] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[70:71] + v_cmpx_eq_f64 s[14:15], v[70:71], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v70, v80 + v_mov_b32 v71, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub2: + v_or_b32 v28, v28, v78 + v_and_b32 v29, v29, v77 + v_or_b32 v29, v29, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[72:73], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[72:73] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[72:73] + v_cmpx_eq_f64 s[14:15], v[72:73], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v72, v80 + v_mov_b32 v73, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub3: + v_or_b32 v28, v28, v78 + v_and_b32 v29, v29, v77 + v_or_b32 v29, v29, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[74:75], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[74:75] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[74:75] + v_cmpx_eq_f64 s[14:15], v[74:75], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v74, v80 + v_mov_b32 v75, v81 + s_setpc_b64 s[60:61] + +ismulh_r_sub: + s_mov_b64 exec, 1 + v_mov_b32 v45, s14 + v_mul_hi_u32 v40, s38, v45 + v_mov_b32 v47, s15 + v_mad_u64_u32 v[42:43], s[32:33], s38, v47, v[40:41] + v_mov_b32 v40, v42 + v_mad_u64_u32 v[45:46], s[32:33], s39, v45, v[40:41] + v_mad_u64_u32 v[42:43], s[32:33], s39, v47, v[43:44] + v_add_u32 v42, vcc, v42, v46 + v_addc_u32 v43, vcc, 0, v43, vcc + v_readlane_b32 s32, v42, 0 + v_readlane_b32 s33, v43, 0 + s_cmp_lt_i32 s15, 0 + s_cselect_b64 s[34:35], s[38:39], 0 + s_sub_u32 s32, s32, s34 + s_subb_u32 s33, s33, s35 + s_cmp_lt_i32 s39, 0 + s_cselect_b64 s[34:35], s[14:15], 0 + s_sub_u32 s14, s32, s34 + s_subb_u32 s15, s33, s35 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +imulh_r_sub: + s_mov_b64 exec, 1 + v_mov_b32 v45, s38 + v_mul_hi_u32 v40, s14, v45 + v_mov_b32 v47, s39 + v_mad_u64_u32 v[42:43], s[32:33], s14, v47, v[40:41] + v_mov_b32 v40, v42 + v_mad_u64_u32 v[45:46], s[32:33], s15, v45, v[40:41] + v_mad_u64_u32 v[42:43], s[32:33], s15, v47, v[43:44] + v_add_u32 v42, vcc, v42, v46 + v_addc_u32 v43, vcc, 0, v43, vcc + v_readlane_b32 s14, v42, 0 + v_readlane_b32 s15, v43, 0 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] diff --git a/src/backend/opencl/cl/rx/randomx_run_gfx803.h b/src/backend/opencl/cl/rx/randomx_run_gfx803.h new file mode 100644 index 000000000..0338efa98 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_run_gfx803.h @@ -0,0 +1,218 @@ +/* +This file was auto-generated from randomx_run_gfx803.asm: + +clrxasm randomx_run_gfx803.asm -o randomx_run_gfx803.bin +bin2h -c randomx_run_gfx803_bin < randomx_run_gfx803.bin > randomx_run_gfx803.h + +clrxasm can be downloaded here: https://github.com/CLRX/CLRX-mirror/releases +bin2h can be downloaded here: http://www.deadnode.org/sw/bin2h/ +*/ + +static unsigned char randomx_run_gfx803_bin[]={ +0x7f,0x45,0x4c,0x46,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x5b,0xaf,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x07,0x00,0x01,0x00,0x00 +,0x2e,0x73,0x68,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x73,0x79,0x6d,0x74,0x61,0x62,0x00,0x2e,0x63,0x6f,0x6d,0x6d,0x65 +,0x6e,0x74,0x00,0x2e,0x72,0x6f,0x64,0x61,0x74,0x61,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x00,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x26,0x5f,0x5f,0x4f,0x70 +,0x65,0x6e,0x43,0x4c,0x5f,0x72,0x61,0x6e,0x64,0x6f,0x6d,0x78,0x5f,0x72,0x75,0x6e,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x5f,0x6d,0x65,0x74,0x61,0x64,0x61,0x74,0x61 +,0x00,0x61,0x63,0x6c,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x5f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x00,0x00,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,0x01,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b +,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41 +,0x4d,0x44,0x2d,0x43,0x4f,0x4d,0x50,0x2d,0x4c,0x49,0x42,0x2d,0x76,0x30,0x2e,0x38,0x20,0x28,0x30,0x2e,0x30,0x2e,0x53,0x43,0x5f,0x42,0x55,0x49,0x4c,0x44,0x5f,0x4e +,0x55,0x4d,0x42,0x45,0x52,0x29,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00 +,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x01,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,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x64 +,0x75,0x6d,0x6d,0x79,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x00,0x67,0x65,0x6e,0x65,0x72,0x69,0x63,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x10,0x00,0x00 +,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00 +,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x50,0x00,0x00 +,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00 +,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00 +,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x01,0x00,0x00,0x00,0x90,0x00,0x00 +,0x00,0x07,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x01,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x04,0x00,0x00 +,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x0a,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,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xb0,0x00,0x00,0x00,0x08,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,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,0x01,0x00,0x00 +,0x00,0x01,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x08,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x5f,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x30,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e +,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x31,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f +,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x32,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x70,0x72,0x69,0x6e,0x74,0x66,0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x00 +,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x76,0x71,0x75,0x65,0x75,0x65,0x5f,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f +,0x2e,0x61,0x71,0x6c,0x77,0x72,0x61,0x70,0x5f,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x00 +,0x75,0x63,0x68,0x61,0x72,0x2a,0x00,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x00,0x75,0x63,0x68,0x61,0x72,0x2a,0x00,0x72,0x65,0x67,0x69,0x73,0x74,0x65 +,0x72,0x73,0x00,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x00,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x73,0x00,0x75,0x69,0x6e,0x74,0x2a,0x00,0x70 +,0x72,0x6f,0x67,0x72,0x61,0x6d,0x73,0x00,0x75,0x69,0x6e,0x74,0x2a,0x00,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x00,0x75,0x69,0x6e,0x74,0x00,0x72,0x78 +,0x5f,0x70,0x61,0x72,0x61,0x6d,0x65,0x74,0x65,0x72,0x73,0x00,0x75,0x69,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x45,0x4c,0x46,0x02,0x01,0x01,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xe0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x38,0x00,0x01,0x00,0x40,0x00,0x06,0x00,0x01 +,0x00,0x03,0x00,0x00,0x60,0x05,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0xb4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x73,0x68,0x73,0x74,0x72 +,0x74,0x61,0x62,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x6e,0x6f,0x74,0x65,0x00,0x2e,0x68,0x73,0x61,0x74,0x65,0x78,0x74,0x00,0x2e,0x73,0x79,0x6d,0x74 +,0x61,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x72,0x61,0x6e,0x64,0x6f,0x6d,0x78,0x5f,0x72,0x75,0x6e,0x5f +,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x00,0x5f,0x5f,0x68,0x73,0x61,0x5f,0x73,0x65,0x63,0x74,0x69,0x6f,0x6e,0x2e,0x68,0x73,0x61,0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x00 +,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0c,0x00,0x00 +,0x00,0x02,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x04,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x03,0x00,0x00 +,0x00,0x41,0x4d,0x44,0x00,0x04,0x00,0x07,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x41,0x4d,0x44,0x47,0x50,0x55,0x00 +,0x00,0x04,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x4d,0x44 +,0x20,0x48,0x53,0x41,0x20,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x20,0x46,0x69,0x6e,0x61,0x6c,0x69,0x7a,0x65,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00 +,0x00,0x1a,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x16,0x00,0x2d,0x68,0x73,0x61,0x5f,0x63,0x61,0x6c,0x6c,0x5f,0x63,0x6f,0x6e,0x76,0x65,0x6e,0x74 +,0x69,0x6f,0x6e,0x3d,0x30,0x00,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x01,0x00,0x00,0x00,0x01,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,0x5f,0x03,0xac,0x00,0x8c,0x00,0x00,0x00,0x09,0x00,0x0a,0x00,0x00,0x00,0x00 +,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x60,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0xfc,0xbe,0x00,0x00,0x01,0x00,0x00,0x00,0x84,0xc0,0x00,0x00,0x00,0x00,0x70,0x00,0x8c,0xbf,0x00,0x00,0x93,0xbf,0x00,0x00,0x82,0xbf,0x06,0x00,0x88 +,0xbe,0x01,0x00,0x12,0xd1,0x86,0x10,0x00,0x00,0x01,0x01,0x02,0x32,0x02,0x00,0x06,0xc0,0x00,0x00,0x00,0x00,0x82,0x00,0x06,0xc0,0x40,0x00,0x00,0x00,0x02,0x10,0x06 +,0xc0,0x48,0x00,0x00,0x00,0x7f,0x00,0x8c,0xbf,0x08,0x82,0x10,0x8e,0x40,0x10,0x40,0x80,0x41,0x80,0x41,0x82,0x40,0x02,0x10,0x7e,0x41,0x02,0x12,0x7e,0x00,0x00,0x50 +,0xdc,0x08,0x00,0x00,0x08,0x70,0x0f,0x8c,0xbf,0x42,0x00,0x89,0xd2,0x08,0x01,0x01,0x00,0x81,0x08,0x42,0xb9,0x80,0x00,0xc3,0xbe,0xff,0x00,0xc4,0xbe,0x00,0x01,0x00 +,0x00,0x80,0x00,0xc5,0xbe,0x00,0x02,0x02,0x32,0x86,0x02,0x04,0x20,0x85,0x04,0x06,0x24,0xbf,0x02,0x02,0x26,0x80,0x02,0x08,0x7e,0x03,0x00,0x8f,0xd2,0x83,0x06,0x02 +,0x00,0x84,0x02,0x0a,0x24,0x02,0x06,0x06,0x32,0x03,0x02,0x0c,0x7e,0x06,0x09,0x08,0x38,0x82,0x02,0x52,0x24,0x03,0x53,0x0c,0x32,0x07,0x6a,0x1c,0xd1,0x04,0x01,0xa9 +,0x01,0x00,0x00,0x50,0xdc,0x06,0x00,0x00,0x06,0x80,0x02,0x00,0x7e,0x70,0x0f,0x8c,0xbf,0x00,0x00,0x1a,0xd8,0x29,0x06,0x00,0x00,0x7f,0x00,0x8c,0xbf,0x7e,0x01,0x80 +,0xbe,0x02,0x00,0xdb,0xd0,0x01,0x0f,0x01,0x00,0x75,0x01,0x88,0xbf,0x02,0x05,0x02,0xc0,0x5c,0x00,0x00,0x00,0x7f,0x00,0x8c,0xbf,0x14,0xff,0x95,0x92,0x00,0x00,0x05 +,0x00,0x81,0x15,0x15,0x8e,0x14,0xff,0x96,0x92,0x05,0x00,0x05,0x00,0x81,0x16,0x16,0x8e,0x14,0xff,0x97,0x92,0x0a,0x00,0x05,0x00,0x81,0x17,0x17,0x8e,0x14,0xff,0x98 +,0x92,0x0f,0x00,0x04,0x00,0x81,0x18,0x18,0x8e,0x17,0xc0,0x02,0x80,0x14,0x00,0x86,0xd2,0x02,0x05,0x00,0x00,0x02,0x00,0x85,0xd2,0x02,0x05,0x00,0x00,0x80,0x02,0x52 +,0x7e,0x80,0x02,0x58,0x7e,0x98,0x00,0x6c,0xd8,0x00,0x00,0x00,0x06,0x02,0x00,0xc9,0xd0,0x01,0x09,0x01,0x00,0x12,0x10,0xee,0xd8,0x00,0x00,0x00,0x22,0x88,0x00,0xec +,0xd8,0x00,0x00,0x00,0x0b,0x00,0x00,0x09,0xb0,0x7e,0x01,0x86,0xbe,0x06,0x02,0xfe,0x89,0xa0,0x00,0xec,0xd8,0x00,0x00,0x00,0x0d,0x06,0x7e,0xfe,0x89,0x80,0x02,0x1a +,0x7e,0x80,0x02,0x1c,0x7e,0x06,0x01,0xfe,0xbe,0x08,0x01,0x86,0xbe,0x40,0x27,0x86,0xb7,0x00,0x0b,0x0a,0x32,0x05,0x6a,0x19,0xd1,0x05,0x81,0x01,0x00,0x7e,0x01,0x88 +,0xbe,0x08,0x02,0xfe,0x89,0xa8,0x00,0xec,0xd8,0x00,0x00,0x00,0x0f,0x08,0x7e,0xfe,0x89,0x80,0x02,0x1e,0x7e,0x80,0x02,0x20,0x7e,0x08,0x01,0xfe,0xbe,0x02,0x02,0x0a +,0xc0,0x30,0x00,0x00,0x00,0x02,0x04,0x02,0xc0,0x58,0x00,0x00,0x00,0x02,0x01,0x06,0xc0,0x50,0x00,0x00,0x00,0x83,0x02,0x02,0x24,0x00,0x03,0x22,0x32,0x7f,0x00,0x8c +,0xbf,0x0a,0x04,0x04,0x32,0x0b,0x02,0x24,0x7e,0x12,0x29,0x24,0x38,0xff,0x02,0x26,0x7e,0xff,0xff,0xff,0x00,0x08,0x0c,0x0c,0x32,0x09,0x02,0x28,0x7e,0x14,0x6a,0x1c +,0xd1,0x14,0x01,0xa9,0x01,0x00,0x00,0xec,0xd8,0x11,0x00,0x00,0x15,0x04,0x06,0x04,0x80,0x05,0x07,0x05,0x82,0x13,0x00,0x00,0xd1,0x13,0x83,0x09,0x00,0x83,0x46,0x10 +,0x24,0x83,0x44,0x0e,0x24,0x83,0x18,0x18,0x24,0x83,0x16,0x14,0x24,0x08,0x01,0x10,0x32,0x07,0x01,0x0e,0x32,0x0c,0x01,0x18,0x32,0x0a,0x01,0x00,0x32,0x24,0x03,0x14 +,0x7e,0x25,0x03,0x2e,0x7e,0x18,0x81,0x82,0x80,0x10,0x00,0x83,0xbe,0x26,0x6a,0x1a,0xd1,0x15,0x10,0x01,0x00,0x27,0x6a,0x1a,0xd1,0x16,0x10,0x01,0x00,0x32,0x6a,0x1a +,0xd1,0x17,0x10,0x01,0x00,0xff,0x02,0x66,0x7e,0x00,0x00,0xf0,0x80,0x03,0x03,0x68,0x7e,0x12,0x03,0x06,0x7e,0x34,0x03,0x24,0x7e,0x00,0x00,0x89,0xd2,0x02,0x01,0x01 +,0x00,0x01,0x00,0x89,0xd2,0x03,0x01,0x01,0x00,0x7e,0x01,0xa4,0xbe,0x82,0x01,0xfe,0xbe,0x88,0x02,0x52,0x7e,0x84,0x02,0x58,0x7e,0x83,0x01,0xfe,0xbe,0x18,0x1a,0xee +,0xd8,0x29,0x00,0x00,0x34,0x1c,0x1e,0xee,0xd8,0x29,0x00,0x00,0x38,0xff,0x02,0x9a,0x7e,0xff,0xff,0xff,0x00,0xa0,0x00,0xec,0xd8,0x29,0x00,0x00,0x4e,0x24,0x01,0xfe +,0xbe,0xff,0x02,0xa4,0x7e,0x00,0x00,0x00,0x80,0xff,0x02,0xa6,0x7e,0x00,0x00,0xf0,0x3f,0xff,0x02,0xa8,0x7e,0x00,0x00,0x10,0x00,0x00,0x1c,0x8e,0xbe,0x0e,0xff,0x28 +,0x80,0xe8,0x03,0x00,0x00,0x0f,0x80,0x29,0x82,0x0e,0xff,0x2a,0x80,0x4c,0x04,0x00,0x00,0x0f,0x80,0x2b,0x82,0x0e,0xff,0x2c,0x80,0xb0,0x04,0x00,0x00,0x0f,0x80,0x2d +,0x82,0x0e,0xff,0x2e,0x80,0x14,0x05,0x00,0x00,0x0f,0x80,0x2f,0x82,0x0e,0xff,0x30,0x80,0x78,0x05,0x00,0x00,0x0f,0x80,0x31,0x82,0x0e,0xff,0x32,0x80,0xe0,0x05,0x00 +,0x00,0x0f,0x80,0x33,0x82,0x0e,0xff,0x34,0x80,0x48,0x06,0x00,0x00,0x0f,0x80,0x35,0x82,0x0e,0xff,0x36,0x80,0xb0,0x06,0x00,0x00,0x0f,0x80,0x37,0x82,0x0e,0xff,0x38 +,0x80,0x18,0x07,0x00,0x00,0x0f,0x80,0x39,0x82,0x0e,0xff,0x3a,0x80,0x88,0x07,0x00,0x00,0x0f,0x80,0x3b,0x82,0xc1,0x00,0xbf,0xbe,0xff,0x00,0xc6,0xbe,0x00,0xff,0x00 +,0x00,0xff,0x00,0xc7,0xbe,0x00,0xfe,0x01,0x00,0xff,0x00,0xc8,0xbe,0x00,0xfc,0x03,0x00,0xff,0x00,0xc9,0xbe,0x00,0xf8,0x07,0x00,0xff,0x00,0xca,0xbe,0x00,0xf0,0x0f +,0x00,0xff,0x00,0xcb,0xbe,0x00,0xe0,0x1f,0x00,0xff,0x00,0xcc,0xbe,0x00,0xc0,0x3f,0x00,0xff,0x00,0xcd,0xbe,0x00,0x80,0x7f,0x00,0xff,0x00,0xce,0xbe,0x00,0x00,0xff +,0x00,0xff,0x00,0xcf,0xbe,0x00,0x00,0xfe,0x01,0xff,0x00,0xd0,0xbe,0x00,0x00,0xfc,0x03,0xff,0x00,0xd1,0xbe,0x00,0x00,0xf8,0x07,0xff,0x00,0xd2,0xbe,0x00,0x00,0xf0 +,0x0f,0xff,0x00,0xd3,0xbe,0x00,0x00,0xe0,0x1f,0xff,0x00,0xd4,0xbe,0x00,0x00,0xc0,0x3f,0xff,0x00,0xd5,0xbe,0x00,0x00,0x80,0x7f,0x17,0xc0,0xd6,0x80,0x00,0x00,0xec +,0xd8,0x00,0x00,0x00,0x18,0x00,0x00,0xec,0xd8,0x0c,0x00,0x00,0x1a,0x7f,0x00,0x8c,0xbf,0x1b,0x33,0x32,0x2a,0x1a,0x31,0x30,0x2a,0x19,0x15,0x14,0x2a,0x18,0x2f,0x2e +,0x2a,0x56,0x14,0x14,0x26,0x56,0x2e,0x2e,0x26,0x0a,0x03,0x14,0x32,0x17,0x03,0x2e,0x32,0x02,0x15,0x34,0x32,0x1b,0x6a,0x1c,0xd1,0x03,0x01,0xa9,0x01,0x02,0x2f,0x2e +,0x32,0x18,0x6a,0x1c,0xd1,0x03,0x01,0xa9,0x01,0x00,0x00,0x54,0xdc,0x1a,0x00,0x00,0x1c,0x00,0x00,0x54,0xdc,0x17,0x00,0x00,0x1e,0x71,0x0f,0x8c,0xbf,0x1c,0x09,0x40 +,0x7e,0x1d,0x09,0x38,0x7e,0x70,0x0f,0x8c,0xbf,0x15,0x3d,0x44,0x2a,0x16,0x3f,0x46,0x2a,0x06,0x49,0x2c,0x32,0x19,0x6a,0x1c,0xd1,0x14,0x01,0xa9,0x01,0x16,0x03,0x2a +,0x32,0x16,0x6a,0x1c,0xd1,0x19,0x01,0xa9,0x01,0x00,0x00,0x54,0xdc,0x15,0x00,0x00,0x15,0x20,0x1b,0x3c,0x28,0x21,0x27,0x3e,0x26,0x1f,0x1d,0x3e,0x28,0x1c,0x1f,0x38 +,0x28,0x1d,0x27,0x3a,0x26,0x1d,0x21,0x3a,0x28,0x00,0x01,0x9c,0xd8,0x05,0x1e,0x1c,0x00,0x7f,0x00,0x8c,0xbf,0x83,0x01,0xfe,0xbe,0x08,0x0a,0xee,0xd8,0x29,0x00,0x00 +,0x3c,0x0c,0x0e,0xee,0xd8,0x29,0x00,0x00,0x40,0x10,0x12,0xee,0xd8,0x29,0x00,0x00,0x44,0x14,0x16,0xee,0xd8,0x29,0x00,0x00,0x48,0x10,0x00,0x89,0xd2,0x22,0x01,0x01 +,0x00,0x11,0x00,0x89,0xd2,0x23,0x01,0x01,0x00,0x12,0x00,0x89,0xd2,0x22,0x03,0x01,0x00,0x13,0x00,0x89,0xd2,0x23,0x03,0x01,0x00,0x14,0x00,0x89,0xd2,0x22,0x05,0x01 +,0x00,0x15,0x00,0x89,0xd2,0x23,0x05,0x01,0x00,0x16,0x00,0x89,0xd2,0x22,0x07,0x01,0x00,0x17,0x00,0x89,0xd2,0x23,0x07,0x01,0x00,0x18,0x00,0x89,0xd2,0x22,0x09,0x01 +,0x00,0x19,0x00,0x89,0xd2,0x23,0x09,0x01,0x00,0x1a,0x00,0x89,0xd2,0x22,0x0b,0x01,0x00,0x1b,0x00,0x89,0xd2,0x23,0x0b,0x01,0x00,0x1c,0x00,0x89,0xd2,0x22,0x0d,0x01 +,0x00,0x1d,0x00,0x89,0xd2,0x23,0x0d,0x01,0x00,0x1e,0x00,0x89,0xd2,0x22,0x0f,0x01,0x00,0x1f,0x00,0x89,0xd2,0x23,0x0f,0x01,0x00,0x7f,0x00,0x8c,0xbf,0x04,0x1e,0x8c +,0xbe,0x08,0x0a,0x9c,0xd8,0x29,0x3c,0x3e,0x00,0x0c,0x0e,0x9c,0xd8,0x29,0x40,0x42,0x00,0x10,0x12,0x9c,0xd8,0x29,0x44,0x46,0x00,0x14,0x16,0x9c,0xd8,0x29,0x48,0x4a +,0x00,0x1c,0x00,0x8a,0xd2,0x10,0x00,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x11,0x00,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x12,0x02,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x13,0x02,0x01 +,0x00,0x1c,0x00,0x8a,0xd2,0x14,0x04,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x15,0x04,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x16,0x06,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x17,0x06,0x01 +,0x00,0x1c,0x00,0x8a,0xd2,0x18,0x08,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x19,0x08,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x1a,0x0a,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1b,0x0a,0x01 +,0x00,0x1c,0x00,0x8a,0xd2,0x1c,0x0c,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1d,0x0c,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x1e,0x0e,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1f,0x0e,0x01 +,0x00,0x24,0x01,0xfe,0xbe,0x00,0x00,0x9a,0xd8,0x11,0x1c,0x00,0x00,0x7f,0x00,0x8c,0xbf,0x1c,0x2b,0x2a,0x2a,0x1d,0x2d,0x2c,0x2a,0x00,0x00,0x6c,0xd8,0x07,0x00,0x00 +,0x1c,0x00,0x00,0x6c,0xd8,0x08,0x00,0x00,0x1d,0x00,0x00,0x9a,0xd8,0x11,0x15,0x00,0x00,0x7f,0x01,0x8c,0xbf,0x08,0x10,0xee,0xd8,0x11,0x00,0x00,0x1e,0x1c,0x4b,0x14 +,0x2a,0x7f,0x00,0x8c,0xbf,0x20,0x3d,0x3c,0x2a,0x21,0x3f,0x3e,0x2a,0x0a,0x3b,0x14,0x2a,0x00,0x00,0x74,0xdc,0x1a,0x15,0x00,0x00,0xff,0x14,0x14,0x26,0xc0,0xff,0xff +,0x7f,0x00,0x00,0x74,0xdc,0x17,0x1e,0x00,0x00,0x02,0x80,0x06,0xbf,0x06,0x00,0x85,0xbf,0x02,0x81,0x82,0x81,0x24,0x03,0x4a,0x7e,0x80,0x02,0x2e,0x7e,0x0a,0x03,0x48 +,0x7e,0x80,0x02,0x14,0x7e,0x5d,0xff,0x82,0xbf,0x12,0x03,0x00,0x32,0x01,0x6a,0x1c,0xd1,0x04,0x01,0xa9,0x01,0x00,0x00,0x74,0xdc,0x00,0x15,0x00,0x00,0x00,0x6a,0x19 +,0xd1,0x00,0x81,0x01,0x00,0x01,0x6a,0x1c,0xd1,0x01,0x01,0xa9,0x01,0x00,0x00,0x74,0xdc,0x00,0x1e,0x00,0x00,0x00,0x6a,0x19,0xd1,0x00,0x81,0x01,0x00,0x01,0x6a,0x1c +,0xd1,0x01,0x01,0xa9,0x01,0x00,0x00,0x74,0xdc,0x00,0x20,0x00,0x00,0x40,0x02,0x00,0x7e,0x41,0x02,0x02,0x7e,0x42,0x02,0x04,0x7e,0x00,0x00,0x70,0xdc,0x00,0x02,0x00 +,0x00,0x00,0x00,0x81,0xbf,0x81,0x08,0x43,0xb9,0x44,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x89,0x02,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9,0x62,0x34,0x1c,0x03,0x5c +,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00,0xcc +,0xd1,0x2a,0x55,0x12,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x44,0x89,0x00,0x00,0x2a,0x03,0x88,0x7e,0x2b,0x03,0x8a +,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x46,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x8d,0x02,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9,0x62 +,0x34,0x1c,0x03,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d,0xc2 +,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55,0x1a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x46,0x89,0x00,0x00,0x2a,0x03,0x8c +,0x7e,0x2b,0x03,0x8e,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x48,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x91,0x02,0x00,0x1c,0x03,0x60 +,0x7e,0x1d,0xa9,0x62,0x34,0x1c,0x03,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc +,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55,0x22,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x48,0x89,0x00 +,0x00,0x2a,0x03,0x90,0x7e,0x2b,0x03,0x92,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x4a,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x95,0x02 +,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9,0x62,0x34,0x1c,0x03,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa +,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55,0x2a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13 +,0xd0,0x4a,0x89,0x00,0x00,0x2a,0x03,0x94,0x7e,0x2b,0x03,0x96,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x9b,0x3a,0x26,0x1d,0x9f,0x3a +,0x28,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x44,0x61,0x02 +,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x12,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x12,0x05,0x0e,0x00,0x72 +,0xd0,0x44,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x88,0x7e,0x51,0x03,0x8a,0x7e,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38 +,0x28,0x1d,0x9b,0x3a,0x26,0x1d,0x9f,0x3a,0x28,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2 +,0x04,0x50,0x00,0x81,0xd2,0x46,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x1a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf +,0xd1,0x2a,0x39,0x1a,0x05,0x0e,0x00,0x72,0xd0,0x46,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x8c,0x7e,0x51,0x03,0x8e +,0x7e,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x9b,0x3a,0x26,0x1d,0x9f,0x3a,0x28,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca +,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x48,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x22,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc +,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x22,0x05,0x0e,0x00,0x72,0xd0,0x48,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe +,0xbe,0x50,0x03,0x90,0x7e,0x51,0x03,0x92,0x7e,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x9b,0x3a,0x26,0x1d,0x9f,0x3a,0x28,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60 +,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x4a,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x2a +,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x2a,0x05,0x0e,0x00,0x72,0xd0,0x4a,0x39,0x02,0x00,0x80,0x02,0xa0 +,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x94,0x7e,0x51,0x03,0x96,0x7e,0x3c,0x1d,0x80,0xbe,0x81,0x01,0xfe,0xbe,0x0e,0x02,0x5a,0x7e,0x28,0x00,0x86 +,0xd2,0x26,0x5a,0x02,0x00,0x0f,0x02,0x5e,0x7e,0x2a,0x20,0xe8,0xd1,0x26,0x5e,0xa2,0x04,0x2a,0x03,0x50,0x7e,0x2d,0x20,0xe8,0xd1,0x27,0x5a,0xa2,0x04,0x2a,0x20,0xe8 +,0xd1,0x27,0x5e,0xae,0x04,0x2a,0x5d,0x54,0x32,0x80,0x56,0x56,0x38,0x20,0x00,0x89,0xd2,0x2a,0x01,0x01,0x00,0x21,0x00,0x89,0xd2,0x2b,0x01,0x01,0x00,0x0f,0x80,0x04 +,0xbf,0x26,0x80,0xa2,0x85,0x20,0x22,0xa0,0x80,0x21,0x23,0xa1,0x82,0x27,0x80,0x04,0xbf,0x0e,0x80,0xa2,0x85,0x20,0x22,0x8e,0x80,0x21,0x23,0x8f,0x82,0x83,0x01,0xfe +,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x01,0xfe,0xbe,0x26,0x02,0x5a,0x7e,0x28,0x00,0x86,0xd2,0x0e,0x5a,0x02,0x00,0x27,0x02,0x5e,0x7e,0x2a,0x20,0xe8,0xd1,0x0e,0x5e,0xa2 +,0x04,0x2a,0x03,0x50,0x7e,0x2d,0x20,0xe8,0xd1,0x0f,0x5a,0xa2,0x04,0x2a,0x20,0xe8,0xd1,0x0f,0x5e,0xae,0x04,0x2a,0x5d,0x54,0x32,0x80,0x56,0x56,0x38,0x0e,0x00,0x89 +,0xd2,0x2a,0x01,0x01,0x00,0x0f,0x00,0x89,0xd2,0x2b,0x01,0x01,0x00,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x00,0x00,0x00,0x00,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,0x1a,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0xb4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x03,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x2a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x13,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00 +,0x00,0xb4,0x0b,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,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x0d,0x00,0x00,0x00,0x00,0x00 +,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,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,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,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,0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x01,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,0x27,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,0x24,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27 +,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x07,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,0x2c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62 +,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0f,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}; +const int randomx_run_gfx803_bin_size=6568; diff --git a/src/backend/opencl/cl/rx/randomx_run_gfx900.asm b/src/backend/opencl/cl/rx/randomx_run_gfx900.asm new file mode 100644 index 000000000..058b0d18e --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_run_gfx900.asm @@ -0,0 +1,688 @@ +/* +Copyright (c) 2019 SChernykh + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +.amdcl2 +.gpu GFX900 +.64bit +.arch_minor 0 +.arch_stepping 0 +.driver_version 223600 +.kernel randomx_run + .config + .dims x + .cws 64, 1, 1 + .sgprsnum 96 + # 6 waves per SIMD: 37-40 VGPRs + # 5 waves per SIMD: 41-48 VGPRs + # 4 waves per SIMD: 49-64 VGPRs + # 3 waves per SIMD: 65-84 VGPRs + # 2 waves per SIMD: 85-128 VGPRs + # 1 wave per SIMD: 129-256 VGPRs + .vgprsnum 128 + .localsize 256 + .floatmode 0xc0 + .pgmrsrc1 0x00ac035f + .pgmrsrc2 0x00000090 + .dx10clamp + .ieeemode + .useargs + .priority 0 + .arg _.global_offset_0, "size_t", long + .arg _.global_offset_1, "size_t", long + .arg _.global_offset_2, "size_t", long + .arg _.printf_buffer, "size_t", void*, global, , rdonly + .arg _.vqueue_pointer, "size_t", long + .arg _.aqlwrap_pointer, "size_t", long + .arg dataset, "uchar*", uchar*, global, const, rdonly + .arg scratchpad, "uchar*", uchar*, global, + .arg registers, "ulong*", ulong*, global, + .arg rounding_modes, "uint*", uint*, global, + .arg programs, "uint*", uint*, global, + .arg batch_size, "uint", uint + .arg rx_parameters, "uint", uint + .text + s_mov_b32 m0, 0x10000 + s_dcache_wb + s_waitcnt vmcnt(0) & lgkmcnt(0) + s_icache_inv + s_branch begin + + # pgmrsrc2 = 0x00000090, bits 1:5 = 8, so first 8 SGPRs (s0-s7) contain user data + # s8 contains group id + # v0 contains local id +begin: + v_lshl_add_u32 v1, s8, 6, v0 + s_load_dwordx2 s[0:1], s[4:5], 0x0 + s_load_dwordx2 s[2:3], s[4:5], 0x40 + s_load_dwordx2 s[64:65], s[4:5], 0x48 + s_waitcnt lgkmcnt(0) + + # load rounding mode + s_lshl_b32 s16, s8, 2 + s_add_u32 s64, s64, s16 + s_addc_u32 s65, s65, 0 + v_mov_b32 v8, 0 + global_load_dword v8, v8, s[64:65] + s_waitcnt vmcnt(0) + v_readlane_b32 s66, v8, 0 + s_setreg_b32 hwreg(mode, 2, 2), s66 + s_mov_b32 s67, 0 + + # used in FSQRT_R to check for "positive normal value" (v_cmpx_class_f64) + s_mov_b32 s68, 256 + s_mov_b32 s69, 0 + + v_add_u32 v1, s0, v1 + v_lshrrev_b32 v2, 6, v1 + v_lshlrev_b32 v3, 5, v2 + v_and_b32 v1, 63, v1 + v_mov_b32 v4, 0 + v_lshlrev_b64 v[3:4], 3, v[3:4] + v_lshlrev_b32 v5, 4, v1 + v_add_co_u32 v3, vcc, s2, v3 + v_mov_b32 v6, s3 + v_addc_co_u32 v4, vcc, v6, v4, vcc + v_lshlrev_b32 v41, 2, v1 + v_add_co_u32 v6, vcc, v3, v41 + v_addc_co_u32 v7, vcc, v4, 0, vcc + global_load_dword v6, v[6:7], off + v_mov_b32 v0, 0 + s_waitcnt vmcnt(0) + ds_write_b32 v41, v6 + s_waitcnt lgkmcnt(0) + s_mov_b64 s[0:1], exec + v_cmpx_le_u32 s[2:3], v1, 7 + s_cbranch_execz program_end + + # rx_parameters + s_load_dword s20, s[4:5], 0x5c + s_waitcnt lgkmcnt(0) + + # Scratchpad L1 size + s_bfe_u32 s21, s20, 0x050000 + s_lshl_b32 s21, 1, s21 + + # Scratchpad L2 size + s_bfe_u32 s22, s20, 0x050005 + s_lshl_b32 s22, 1, s22 + + # Scratchpad L3 size + s_bfe_u32 s23, s20, 0x05000A + s_lshl_b32 s23, 1, s23 + + # program iterations + s_bfe_u32 s24, s20, 0x04000F + s_lshl_b32 s24, 1, s24 + + # Base address for scratchpads + s_add_u32 s2, s23, 64 + v_mul_hi_u32 v20, v2, s2 + v_mul_lo_u32 v2, v2, s2 + + # v41, v44 = 0 + v_mov_b32 v41, 0 + v_mov_b32 v44, 0 + + ds_read_b32 v6, v0 offset:152 + v_cmp_lt_u32 s[2:3], v1, 4 + ds_read2_b64 v[34:37], v0 offset0:18 offset1:16 + ds_read_b64 v[11:12], v0 offset:136 + s_movk_i32 s9, 0x0 + s_mov_b64 s[6:7], exec + s_andn2_b64 exec, s[6:7], s[2:3] + ds_read_b64 v[13:14], v0 offset:160 + s_andn2_b64 exec, s[6:7], exec + v_mov_b32 v13, 0 + v_mov_b32 v14, 0 + s_mov_b64 exec, s[6:7] + + # compiled program size + s_mov_b64 s[6:7], s[8:9] + s_mulk_i32 s6, 10048 + + v_add3_u32 v5, v0, v5, 64 + s_mov_b64 s[8:9], exec + s_andn2_b64 exec, s[8:9], s[2:3] + ds_read_b64 v[15:16], v0 offset:168 + s_andn2_b64 exec, s[8:9], exec + v_mov_b32 v15, 0 + v_mov_b32 v16, 0 + s_mov_b64 exec, s[8:9] + s_load_dwordx4 s[8:11], s[4:5], 0x30 + + # batch_size + s_load_dword s16, s[4:5], 0x58 + + s_load_dwordx2 s[4:5], s[4:5], 0x50 + v_lshlrev_b32 v1, 3, v1 + v_add_u32 v17, v0, v1 + s_waitcnt lgkmcnt(0) + v_add_co_u32 v2, vcc, s10, v2 + v_mov_b32 v18, s11 + v_addc_co_u32 v18, vcc, v18, v20, vcc + v_mov_b32 v19, 0xffffff + v_add_co_u32 v6, vcc, s8, v6 + v_mov_b32 v20, s9 + v_addc_co_u32 v20, vcc, v20, 0, vcc + ds_read_b64 v[21:22], v17 + s_add_u32 s4, s4, s6 + s_addc_u32 s5, s5, s7 + v_cndmask_b32 v19, v19, -1, s[2:3] + v_lshl_add_u32 v8, v35, 3, v0 + v_lshl_add_u32 v7, v34, 3, v0 + v_lshl_add_u32 v12, v12, 3, v0 + v_lshl_add_u32 v0, v11, 3, v0 + v_mov_b32 v10, v36 + v_mov_b32 v23, v37 + + # loop counter + s_sub_u32 s2, s24, 1 + + # batch_size + s_mov_b32 s3, s16 + + # Scratchpad masks for scratchpads + v_sub_u32 v38, s21, 8 + v_sub_u32 v39, s22, 8 + v_sub_u32 v50, s23, 8 + + # mask for FSCAL_R + v_mov_b32 v51, 0x80F00000 + + # load scratchpad base address + v_readlane_b32 s0, v2, 0 + v_readlane_b32 s1, v18, 0 + + # save current executiom mask + s_mov_b64 s[36:37], exec + + # v41 = 0 on lane 0, set it to 8 on lane 1 + # v44 = 0 on lane 0, set it to 4 on lane 1 + s_mov_b64 exec, 2 + v_mov_b32 v41, 8 + v_mov_b32 v44, 4 + + # load group A registers + # Read low 8 bytes into lane 0 and high 8 bytes into lane 1 + s_mov_b64 exec, 3 + ds_read2_b64 v[52:55], v41 offset0:24 offset1:26 + ds_read2_b64 v[56:59], v41 offset0:28 offset1:30 + + # xmantissaMask + v_mov_b32 v77, (1 << 24) - 1 + + # xexponentMask + ds_read_b64 v[78:79], v41 offset:160 + + # Restore execution mask + s_mov_b64 exec, s[36:37] + + # sign mask (used in FSQRT_R) + v_mov_b32 v82, 0x80000000 + + # High 32 bits of "1.0" constant (used in FDIV_M) + v_mov_b32 v83, (1023 << 20) + + # Used to multiply FP64 values by 0.5 + v_mov_b32 v84, (1 << 20) + + s_getpc_b64 s[14:15] +cur_addr: + + # get addresses of FSQRT_R subroutines + s_add_u32 s40, s14, fsqrt_r_sub0 - cur_addr + s_addc_u32 s41, s15, 0 + s_add_u32 s42, s14, fsqrt_r_sub1 - cur_addr + s_addc_u32 s43, s15, 0 + s_add_u32 s44, s14, fsqrt_r_sub2 - cur_addr + s_addc_u32 s45, s15, 0 + s_add_u32 s46, s14, fsqrt_r_sub3 - cur_addr + s_addc_u32 s47, s15, 0 + + # get addresses of FDIV_M subroutines + s_add_u32 s48, s14, fdiv_m_sub0 - cur_addr + s_addc_u32 s49, s15, 0 + s_add_u32 s50, s14, fdiv_m_sub1 - cur_addr + s_addc_u32 s51, s15, 0 + s_add_u32 s52, s14, fdiv_m_sub2 - cur_addr + s_addc_u32 s53, s15, 0 + s_add_u32 s54, s14, fdiv_m_sub3 - cur_addr + s_addc_u32 s55, s15, 0 + + # get address for ISMULH_R subroutine + s_add_u32 s56, s14, ismulh_r_sub - cur_addr + s_addc_u32 s57, s15, 0 + + # get address for IMULH_R subroutine + s_add_u32 s58, s14, imulh_r_sub - cur_addr + s_addc_u32 s59, s15, 0 + + # used in IXOR_R instruction + s_mov_b32 s63, -1 + + # used in CBRANCH instruction + s_mov_b32 s70, (0xFF << 8) + s_mov_b32 s71, (0xFF << 9) + s_mov_b32 s72, (0xFF << 10) + s_mov_b32 s73, (0xFF << 11) + s_mov_b32 s74, (0xFF << 12) + s_mov_b32 s75, (0xFF << 13) + s_mov_b32 s76, (0xFF << 14) + s_mov_b32 s77, (0xFF << 15) + s_mov_b32 s78, (0xFF << 16) + s_mov_b32 s79, (0xFF << 17) + s_mov_b32 s80, (0xFF << 18) + s_mov_b32 s81, (0xFF << 19) + s_mov_b32 s82, (0xFF << 20) + s_mov_b32 s83, (0xFF << 21) + s_mov_b32 s84, (0xFF << 22) + s_mov_b32 s85, (0xFF << 23) + + # ScratchpadL3Mask64 + s_sub_u32 s86, s23, 64 + +main_loop: + # const uint2 spMix = as_uint2(R[readReg0] ^ R[readReg1]); + ds_read_b64 v[24:25], v0 + ds_read_b64 v[26:27], v12 + s_waitcnt lgkmcnt(0) + v_xor_b32 v25, v27, v25 + v_xor_b32 v24, v26, v24 + + # spAddr1 ^= spMix.y; + # spAddr0 ^= spMix.x; + v_xor_b32 v10, v25, v10 + v_xor_b32 v23, v24, v23 + + # spAddr1 &= ScratchpadL3Mask64; + # spAddr0 &= ScratchpadL3Mask64; + v_and_b32 v10, s86, v10 + v_and_b32 v23, s86, v23 + + # Offset for scratchpads + # offset1 = spAddr1 + sub * 8 + # offset0 = spAddr0 + sub * 8 + v_add_u32 v10, v10, v1 + v_add_u32 v23, v23, v1 + + # __global ulong* p1 = (__global ulong*)(scratchpad + offset1); + # __global ulong* p0 = (__global ulong*)(scratchpad + offset0); + v_add_co_u32 v26, vcc, v2, v10 + v_addc_co_u32 v27, vcc, v18, 0, vcc + v_add_co_u32 v23, vcc, v2, v23 + v_addc_co_u32 v24, vcc, v18, 0, vcc + + # load from spAddr1 + global_load_dwordx2 v[28:29], v[26:27], off + + # load from spAddr0 + global_load_dwordx2 v[30:31], v[23:24], off + s_waitcnt vmcnt(1) + + v_cvt_f64_i32 v[32:33], v28 + v_cvt_f64_i32 v[28:29], v29 + s_waitcnt vmcnt(0) + + # R[sub] ^= *p0; + v_xor_b32 v34, v21, v30 + v_xor_b32 v35, v22, v31 + + v_add_co_u32 v22, vcc, v6, v36 + v_addc_co_u32 v25, vcc, v20, 0, vcc + v_add_co_u32 v21, vcc, v22, v1 + v_addc_co_u32 v22, vcc, v25, 0, vcc + global_load_dwordx2 v[21:22], v[21:22], off + v_or_b32 v30, v32, v13 + v_and_or_b32 v31, v33, v19, v14 + v_or_b32 v28, v28, v15 + v_and_or_b32 v29, v29, v19, v16 + ds_write2_b64 v5, v[30:31], v[28:29] offset1:1 + s_waitcnt lgkmcnt(0) + + # Program 0 + + # load group F,E registers + # Read low 8 bytes into lane 0 and high 8 bytes into lane 1 + s_mov_b64 exec, 3 + ds_read2_b64 v[60:63], v41 offset0:8 offset1:10 + ds_read2_b64 v[64:67], v41 offset0:12 offset1:14 + ds_read2_b64 v[68:71], v41 offset0:16 offset1:18 + ds_read2_b64 v[72:75], v41 offset0:20 offset1:22 + + # load VM integer registers + v_readlane_b32 s16, v34, 0 + v_readlane_b32 s17, v35, 0 + v_readlane_b32 s18, v34, 1 + v_readlane_b32 s19, v35, 1 + v_readlane_b32 s20, v34, 2 + v_readlane_b32 s21, v35, 2 + v_readlane_b32 s22, v34, 3 + v_readlane_b32 s23, v35, 3 + v_readlane_b32 s24, v34, 4 + v_readlane_b32 s25, v35, 4 + v_readlane_b32 s26, v34, 5 + v_readlane_b32 s27, v35, 5 + v_readlane_b32 s28, v34, 6 + v_readlane_b32 s29, v35, 6 + v_readlane_b32 s30, v34, 7 + v_readlane_b32 s31, v35, 7 + + s_waitcnt lgkmcnt(0) + + # call JIT code + s_swappc_b64 s[12:13], s[4:5] + + # Write out group F,E registers + # Write low 8 bytes from lane 0 and high 8 bytes from lane 1 + ds_write2_b64 v41, v[60:61], v[62:63] offset0:8 offset1:10 + ds_write2_b64 v41, v[64:65], v[66:67] offset0:12 offset1:14 + ds_write2_b64 v41, v[68:69], v[70:71] offset0:16 offset1:18 + ds_write2_b64 v41, v[72:73], v[74:75] offset0:20 offset1:22 + + # store VM integer registers + v_writelane_b32 v28, s16, 0 + v_writelane_b32 v29, s17, 0 + v_writelane_b32 v28, s18, 1 + v_writelane_b32 v29, s19, 1 + v_writelane_b32 v28, s20, 2 + v_writelane_b32 v29, s21, 2 + v_writelane_b32 v28, s22, 3 + v_writelane_b32 v29, s23, 3 + v_writelane_b32 v28, s24, 4 + v_writelane_b32 v29, s25, 4 + v_writelane_b32 v28, s26, 5 + v_writelane_b32 v29, s27, 5 + v_writelane_b32 v28, s28, 6 + v_writelane_b32 v29, s29, 6 + v_writelane_b32 v28, s30, 7 + v_writelane_b32 v29, s31, 7 + + # Restore execution mask + s_mov_b64 exec, s[36:37] + + # Write out VM integer registers + ds_write_b64 v17, v[28:29] + + s_waitcnt lgkmcnt(0) + v_xor_b32 v21, v28, v21 + v_xor_b32 v22, v29, v22 + ds_read_b32 v28, v7 + ds_read_b32 v29, v8 + ds_write_b64 v17, v[21:22] + s_waitcnt lgkmcnt(1) + ds_read2_b64 v[30:33], v17 offset0:8 offset1:16 + v_xor_b32 v10, v28, v37 + s_waitcnt lgkmcnt(0) + v_xor_b32 v30, v32, v30 + v_xor_b32 v31, v33, v31 + v_xor_b32 v10, v10, v29 + global_store_dwordx2 v[26:27], v[21:22], off + v_and_b32 v10, 0x7fffffc0, v10 + global_store_dwordx2 v[23:24], v[30:31], off + s_cmp_eq_u32 s2, 0 + s_cbranch_scc1 main_loop_end + s_sub_i32 s2, s2, 1 + v_mov_b32 v37, v36 + v_mov_b32 v23, 0 + v_mov_b32 v36, v10 + v_mov_b32 v10, 0 + s_branch main_loop +main_loop_end: + + v_add_co_u32 v0, vcc, v3, v1 + v_addc_co_u32 v1, vcc, v4, 0, vcc + global_store_dwordx2 v[0:1], v[21:22], off + global_store_dwordx2 v[0:1], v[30:31], off inst_offset:64 + global_store_dwordx2 v[0:1], v[32:33], off inst_offset:128 + + # store rounding mode + v_mov_b32 v0, 0 + v_mov_b32 v1, s66 + global_store_dword v0, v1, s[64:65] + +program_end: + s_endpgm + +fsqrt_r_sub0: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[68:69] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[68:69] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[68:69] + v_mov_b32 v48, v28 + v_sub_u32 v49, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[68:69] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[68:69], s[68:69] + v_mov_b32 v68, v42 + v_mov_b32 v69, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub1: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[70:71] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[70:71] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[70:71] + v_mov_b32 v48, v28 + v_sub_u32 v49, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[70:71] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[70:71], s[68:69] + v_mov_b32 v70, v42 + v_mov_b32 v71, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub2: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[72:73] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[72:73] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[72:73] + v_mov_b32 v48, v28 + v_sub_u32 v49, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[72:73] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[72:73], s[68:69] + v_mov_b32 v72, v42 + v_mov_b32 v73, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fsqrt_r_sub3: + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rsq_f64 v[28:29], v[74:75] + + # Improve initial approximation (can be skipped) + #v_mul_f64 v[42:43], v[28:29], v[74:75] + #v_mul_f64 v[48:49], v[28:29], -0.5 + #v_fma_f64 v[48:49], v[48:49], v[42:43], 0.5 + #v_fma_f64 v[28:29], v[28:29], v[48:49], v[28:29] + + v_mul_f64 v[42:43], v[28:29], v[74:75] + v_mov_b32 v48, v28 + v_sub_u32 v49, v29, v84 + v_mov_b32 v46, v28 + v_xor_b32 v47, v49, v82 + v_fma_f64 v[46:47], v[46:47], v[42:43], 0.5 + v_fma_f64 v[42:43], v[42:43], v[46:47], v[42:43] + v_fma_f64 v[48:49], v[48:49], v[46:47], v[48:49] + v_fma_f64 v[46:47], -v[42:43], v[42:43], v[74:75] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[46:47], v[48:49], v[42:43] + v_cmpx_class_f64 s[14:15], v[74:75], s[68:69] + v_mov_b32 v74, v42 + v_mov_b32 v75, v43 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +fdiv_m_sub0: + v_or_b32 v28, v28, v78 + v_and_or_b32 v29, v29, v77, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[68:69], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[68:69] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[68:69] + v_cmpx_eq_f64 s[14:15], v[68:69], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v68, v80 + v_mov_b32 v69, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub1: + v_or_b32 v28, v28, v78 + v_and_or_b32 v29, v29, v77, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[70:71], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[70:71] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[70:71] + v_cmpx_eq_f64 s[14:15], v[70:71], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v70, v80 + v_mov_b32 v71, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub2: + v_or_b32 v28, v28, v78 + v_and_or_b32 v29, v29, v77, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[72:73], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[72:73] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[72:73] + v_cmpx_eq_f64 s[14:15], v[72:73], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v72, v80 + v_mov_b32 v73, v81 + s_setpc_b64 s[60:61] + +fdiv_m_sub3: + v_or_b32 v28, v28, v78 + v_and_or_b32 v29, v29, v77, v79 + s_setreg_b32 hwreg(mode, 2, 2), s67 + v_rcp_f64 v[48:49], v[28:29] + v_fma_f64 v[80:81], -v[28:29], v[48:49], 1.0 + v_fma_f64 v[48:49], v[48:49], v[80:81], v[48:49] + v_mul_f64 v[80:81], v[74:75], v[48:49] + v_fma_f64 v[42:43], -v[28:29], v[80:81], v[74:75] + s_setreg_b32 hwreg(mode, 2, 2), s66 + v_fma_f64 v[42:43], v[42:43], v[48:49], v[80:81] + v_div_fixup_f64 v[80:81], v[42:43], v[28:29], v[74:75] + v_cmpx_eq_f64 s[14:15], v[74:75], v[28:29] + v_mov_b32 v80, 0 + v_mov_b32 v81, v83 + s_mov_b64 exec, 3 + v_mov_b32 v74, v80 + v_mov_b32 v75, v81 + s_setpc_b64 s[60:61] + +ismulh_r_sub: + s_mov_b64 exec, 1 + v_mov_b32 v45, s14 + v_mul_hi_u32 v40, s38, v45 + v_mov_b32 v47, s15 + v_mad_u64_u32 v[42:43], s[32:33], s38, v47, v[40:41] + v_mov_b32 v40, v42 + v_mad_u64_u32 v[45:46], s[32:33], s39, v45, v[40:41] + v_mad_u64_u32 v[42:43], s[32:33], s39, v47, v[43:44] + v_add_co_u32 v42, vcc, v42, v46 + v_addc_co_u32 v43, vcc, 0, v43, vcc + v_readlane_b32 s32, v42, 0 + v_readlane_b32 s33, v43, 0 + s_cmp_lt_i32 s15, 0 + s_cselect_b64 s[34:35], s[38:39], 0 + s_sub_u32 s32, s32, s34 + s_subb_u32 s33, s33, s35 + s_cmp_lt_i32 s39, 0 + s_cselect_b64 s[34:35], s[14:15], 0 + s_sub_u32 s14, s32, s34 + s_subb_u32 s15, s33, s35 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] + +imulh_r_sub: + s_mov_b64 exec, 1 + v_mov_b32 v45, s38 + v_mul_hi_u32 v40, s14, v45 + v_mov_b32 v47, s39 + v_mad_u64_u32 v[42:43], s[32:33], s14, v47, v[40:41] + v_mov_b32 v40, v42 + v_mad_u64_u32 v[45:46], s[32:33], s15, v45, v[40:41] + v_mad_u64_u32 v[42:43], s[32:33], s15, v47, v[43:44] + v_add_co_u32 v42, vcc, v42, v46 + v_addc_co_u32 v43, vcc, 0, v43, vcc + v_readlane_b32 s14, v42, 0 + v_readlane_b32 s15, v43, 0 + s_mov_b64 exec, 3 + s_setpc_b64 s[60:61] diff --git a/src/backend/opencl/cl/rx/randomx_run_gfx900.h b/src/backend/opencl/cl/rx/randomx_run_gfx900.h new file mode 100644 index 000000000..977bb2932 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_run_gfx900.h @@ -0,0 +1,215 @@ +/* +This file was auto-generated from randomx_run_gfx900.asm: + +clrxasm randomx_run_gfx900.asm -o randomx_run_gfx900.bin +bin2h -c randomx_run_gfx900_bin < randomx_run_gfx900.bin > randomx_run_gfx900.h + +clrxasm can be downloaded here: https://github.com/CLRX/CLRX-mirror/releases +bin2h can be downloaded here: http://www.deadnode.org/sw/bin2h/ +*/ + +static unsigned char randomx_run_gfx900_bin[]={ +0x7f,0x45,0x4c,0x46,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x5b,0xaf,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x07,0x00,0x01,0x00,0x00 +,0x2e,0x73,0x68,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x73,0x79,0x6d,0x74,0x61,0x62,0x00,0x2e,0x63,0x6f,0x6d,0x6d,0x65 +,0x6e,0x74,0x00,0x2e,0x72,0x6f,0x64,0x61,0x74,0x61,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x00,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x26,0x5f,0x5f,0x4f,0x70 +,0x65,0x6e,0x43,0x4c,0x5f,0x72,0x61,0x6e,0x64,0x6f,0x6d,0x78,0x5f,0x72,0x75,0x6e,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x5f,0x6d,0x65,0x74,0x61,0x64,0x61,0x74,0x61 +,0x00,0x61,0x63,0x6c,0x5f,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x5f,0x73,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x00,0x00,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,0x01,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38 +,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41 +,0x4d,0x44,0x2d,0x43,0x4f,0x4d,0x50,0x2d,0x4c,0x49,0x42,0x2d,0x76,0x30,0x2e,0x38,0x20,0x28,0x30,0x2e,0x30,0x2e,0x53,0x43,0x5f,0x42,0x55,0x49,0x4c,0x44,0x5f,0x4e +,0x55,0x4d,0x42,0x45,0x52,0x29,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x68,0x00 +,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x01,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,0x15,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x64 +,0x75,0x6d,0x6d,0x79,0x5f,0x6b,0x65,0x72,0x6e,0x65,0x6c,0x00,0x47,0x46,0x58,0x39,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x06,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,0x01,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x06,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,0x01,0x00 +,0x00,0x00,0x40,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x05,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00 +,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,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,0x01,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x06,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,0x01,0x00 +,0x00,0x00,0x80,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x01,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0x07,0x00 +,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,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,0x01,0x00,0x00,0x00,0xa0,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00 +,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x0a,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,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xb0,0x00,0x00,0x00,0x08,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,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,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,0x01,0x00,0x00,0x00,0x01,0x00 +,0x00,0x00,0xc0,0x00,0x00,0x00,0x08,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,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x5f,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x30,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x67,0x6c,0x6f +,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66,0x73,0x65,0x74,0x5f,0x31,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x5f,0x6f,0x66,0x66 +,0x73,0x65,0x74,0x5f,0x32,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x70,0x72,0x69,0x6e,0x74,0x66,0x5f,0x62,0x75,0x66,0x66,0x65,0x72,0x00,0x73,0x69,0x7a +,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x76,0x71,0x75,0x65,0x75,0x65,0x5f,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x5f,0x2e,0x61,0x71 +,0x6c,0x77,0x72,0x61,0x70,0x5f,0x70,0x6f,0x69,0x6e,0x74,0x65,0x72,0x00,0x73,0x69,0x7a,0x65,0x5f,0x74,0x00,0x64,0x61,0x74,0x61,0x73,0x65,0x74,0x00,0x75,0x63,0x68 +,0x61,0x72,0x2a,0x00,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x00,0x75,0x63,0x68,0x61,0x72,0x2a,0x00,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x00 +,0x75,0x6c,0x6f,0x6e,0x67,0x2a,0x00,0x72,0x6f,0x75,0x6e,0x64,0x69,0x6e,0x67,0x5f,0x6d,0x6f,0x64,0x65,0x73,0x00,0x75,0x69,0x6e,0x74,0x2a,0x00,0x70,0x72,0x6f,0x67 +,0x72,0x61,0x6d,0x73,0x00,0x75,0x69,0x6e,0x74,0x2a,0x00,0x62,0x61,0x74,0x63,0x68,0x5f,0x73,0x69,0x7a,0x65,0x00,0x75,0x69,0x6e,0x74,0x00,0x72,0x78,0x5f,0x70,0x61 +,0x72,0x61,0x6d,0x65,0x74,0x65,0x72,0x73,0x00,0x75,0x69,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x45 +,0x4c,0x46,0x02,0x01,0x01,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xe0,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x38,0x00,0x01,0x00,0x40,0x00,0x06,0x00,0x01,0x00,0x03,0x00 +,0x00,0x60,0x05,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x0b +,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x73,0x68,0x73,0x74,0x72,0x74,0x61,0x62 +,0x00,0x2e,0x73,0x74,0x72,0x74,0x61,0x62,0x00,0x2e,0x6e,0x6f,0x74,0x65,0x00,0x2e,0x68,0x73,0x61,0x74,0x65,0x78,0x74,0x00,0x2e,0x73,0x79,0x6d,0x74,0x61,0x62,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x5f,0x5f,0x4f,0x70,0x65,0x6e,0x43,0x4c,0x5f,0x72,0x61,0x6e,0x64,0x6f,0x6d,0x78,0x5f,0x72,0x75,0x6e,0x5f,0x6b,0x65,0x72 +,0x6e,0x65,0x6c,0x00,0x5f,0x5f,0x68,0x73,0x61,0x5f,0x73,0x65,0x63,0x74,0x69,0x6f,0x6e,0x2e,0x68,0x73,0x61,0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x00,0x00,0x04,0x00 +,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x02,0x00 +,0x00,0x00,0x41,0x4d,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x04,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x41,0x4d +,0x44,0x00,0x04,0x00,0x07,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x41,0x4d,0x44,0x47,0x50,0x55,0x00,0x00,0x04,0x00 +,0x00,0x00,0x29,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x19,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x4d,0x44,0x20,0x48,0x53 +,0x41,0x20,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x20,0x46,0x69,0x6e,0x61,0x6c,0x69,0x7a,0x65,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x1a,0x00 +,0x00,0x00,0x05,0x00,0x00,0x00,0x41,0x4d,0x44,0x00,0x16,0x00,0x2d,0x68,0x73,0x61,0x5f,0x63,0x61,0x6c,0x6c,0x5f,0x63,0x6f,0x6e,0x76,0x65,0x6e,0x74,0x69,0x6f,0x6e +,0x3d,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x01,0x00,0x00,0x00,0x01,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,0x5f,0x03,0xac,0x00,0x90,0x00,0x00,0x00,0x29,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01 +,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x04,0x04,0x04,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00 +,0xfc,0xbe,0x00,0x00,0x01,0x00,0x00,0x00,0x84,0xc0,0x00,0x00,0x00,0x00,0x70,0x00,0x8c,0xbf,0x00,0x00,0x93,0xbf,0x00,0x00,0x82,0xbf,0x01,0x00,0xfd,0xd1,0x08,0x0c +,0x01,0x04,0x02,0x00,0x06,0xc0,0x00,0x00,0x00,0x00,0x82,0x00,0x06,0xc0,0x40,0x00,0x00,0x00,0x02,0x10,0x06,0xc0,0x48,0x00,0x00,0x00,0x7f,0xc0,0x8c,0xbf,0x08,0x82 +,0x10,0x8e,0x40,0x10,0x40,0x80,0x41,0x80,0x41,0x82,0x80,0x02,0x10,0x7e,0x00,0x80,0x50,0xdc,0x08,0x00,0x40,0x08,0x70,0x0f,0x8c,0xbf,0x42,0x00,0x89,0xd2,0x08,0x01 +,0x01,0x00,0x81,0x08,0x42,0xb9,0x80,0x00,0xc3,0xbe,0xff,0x00,0xc4,0xbe,0x00,0x01,0x00,0x00,0x80,0x00,0xc5,0xbe,0x00,0x02,0x02,0x68,0x86,0x02,0x04,0x20,0x85,0x04 +,0x06,0x24,0xbf,0x02,0x02,0x26,0x80,0x02,0x08,0x7e,0x03,0x00,0x8f,0xd2,0x83,0x06,0x02,0x00,0x84,0x02,0x0a,0x24,0x02,0x06,0x06,0x32,0x03,0x02,0x0c,0x7e,0x06,0x09 +,0x08,0x38,0x82,0x02,0x52,0x24,0x03,0x53,0x0c,0x32,0x07,0x6a,0x1c,0xd1,0x04,0x01,0xa9,0x01,0x00,0x80,0x50,0xdc,0x06,0x00,0x7f,0x06,0x80,0x02,0x00,0x7e,0x70,0x0f +,0x8c,0xbf,0x00,0x00,0x1a,0xd8,0x29,0x06,0x00,0x00,0x7f,0xc0,0x8c,0xbf,0x7e,0x01,0x80,0xbe,0x02,0x00,0xdb,0xd0,0x01,0x0f,0x01,0x00,0x68,0x01,0x88,0xbf,0x02,0x05 +,0x02,0xc0,0x5c,0x00,0x00,0x00,0x7f,0xc0,0x8c,0xbf,0x14,0xff,0x95,0x92,0x00,0x00,0x05,0x00,0x81,0x15,0x15,0x8e,0x14,0xff,0x96,0x92,0x05,0x00,0x05,0x00,0x81,0x16 +,0x16,0x8e,0x14,0xff,0x97,0x92,0x0a,0x00,0x05,0x00,0x81,0x17,0x17,0x8e,0x14,0xff,0x98,0x92,0x0f,0x00,0x04,0x00,0x81,0x18,0x18,0x8e,0x17,0xc0,0x02,0x80,0x14,0x00 +,0x86,0xd2,0x02,0x05,0x00,0x00,0x02,0x00,0x85,0xd2,0x02,0x05,0x00,0x00,0x80,0x02,0x52,0x7e,0x80,0x02,0x58,0x7e,0x98,0x00,0x6c,0xd8,0x00,0x00,0x00,0x06,0x02,0x00 +,0xc9,0xd0,0x01,0x09,0x01,0x00,0x12,0x10,0xee,0xd8,0x00,0x00,0x00,0x22,0x88,0x00,0xec,0xd8,0x00,0x00,0x00,0x0b,0x00,0x00,0x09,0xb0,0x7e,0x01,0x86,0xbe,0x06,0x02 +,0xfe,0x89,0xa0,0x00,0xec,0xd8,0x00,0x00,0x00,0x0d,0x06,0x7e,0xfe,0x89,0x80,0x02,0x1a,0x7e,0x80,0x02,0x1c,0x7e,0x06,0x01,0xfe,0xbe,0x08,0x01,0x86,0xbe,0x40,0x27 +,0x86,0xb7,0x05,0x00,0xff,0xd1,0x00,0x0b,0x02,0x03,0x7e,0x01,0x88,0xbe,0x08,0x02,0xfe,0x89,0xa8,0x00,0xec,0xd8,0x00,0x00,0x00,0x0f,0x08,0x7e,0xfe,0x89,0x80,0x02 +,0x1e,0x7e,0x80,0x02,0x20,0x7e,0x08,0x01,0xfe,0xbe,0x02,0x02,0x0a,0xc0,0x30,0x00,0x00,0x00,0x02,0x04,0x02,0xc0,0x58,0x00,0x00,0x00,0x02,0x01,0x06,0xc0,0x50,0x00 +,0x00,0x00,0x83,0x02,0x02,0x24,0x00,0x03,0x22,0x68,0x7f,0xc0,0x8c,0xbf,0x0a,0x04,0x04,0x32,0x0b,0x02,0x24,0x7e,0x12,0x29,0x24,0x38,0xff,0x02,0x26,0x7e,0xff,0xff +,0xff,0x00,0x08,0x0c,0x0c,0x32,0x09,0x02,0x28,0x7e,0x14,0x6a,0x1c,0xd1,0x14,0x01,0xa9,0x01,0x00,0x00,0xec,0xd8,0x11,0x00,0x00,0x15,0x04,0x06,0x04,0x80,0x05,0x07 +,0x05,0x82,0x13,0x00,0x00,0xd1,0x13,0x83,0x09,0x00,0x08,0x00,0xfd,0xd1,0x23,0x07,0x01,0x04,0x07,0x00,0xfd,0xd1,0x22,0x07,0x01,0x04,0x0c,0x00,0xfd,0xd1,0x0c,0x07 +,0x01,0x04,0x00,0x00,0xfd,0xd1,0x0b,0x07,0x01,0x04,0x24,0x03,0x14,0x7e,0x25,0x03,0x2e,0x7e,0x18,0x81,0x82,0x80,0x10,0x00,0x83,0xbe,0x26,0x00,0x35,0xd1,0x15,0x10 +,0x01,0x00,0x27,0x00,0x35,0xd1,0x16,0x10,0x01,0x00,0x32,0x00,0x35,0xd1,0x17,0x10,0x01,0x00,0xff,0x02,0x66,0x7e,0x00,0x00,0xf0,0x80,0x00,0x00,0x89,0xd2,0x02,0x01 +,0x01,0x00,0x01,0x00,0x89,0xd2,0x12,0x01,0x01,0x00,0x7e,0x01,0xa4,0xbe,0x82,0x01,0xfe,0xbe,0x88,0x02,0x52,0x7e,0x84,0x02,0x58,0x7e,0x83,0x01,0xfe,0xbe,0x18,0x1a +,0xee,0xd8,0x29,0x00,0x00,0x34,0x1c,0x1e,0xee,0xd8,0x29,0x00,0x00,0x38,0xff,0x02,0x9a,0x7e,0xff,0xff,0xff,0x00,0xa0,0x00,0xec,0xd8,0x29,0x00,0x00,0x4e,0x24,0x01 +,0xfe,0xbe,0xff,0x02,0xa4,0x7e,0x00,0x00,0x00,0x80,0xff,0x02,0xa6,0x7e,0x00,0x00,0xf0,0x3f,0xff,0x02,0xa8,0x7e,0x00,0x00,0x10,0x00,0x00,0x1c,0x8e,0xbe,0x0e,0xff +,0x28,0x80,0xc4,0x03,0x00,0x00,0x0f,0x80,0x29,0x82,0x0e,0xff,0x2a,0x80,0x28,0x04,0x00,0x00,0x0f,0x80,0x2b,0x82,0x0e,0xff,0x2c,0x80,0x8c,0x04,0x00,0x00,0x0f,0x80 +,0x2d,0x82,0x0e,0xff,0x2e,0x80,0xf0,0x04,0x00,0x00,0x0f,0x80,0x2f,0x82,0x0e,0xff,0x30,0x80,0x54,0x05,0x00,0x00,0x0f,0x80,0x31,0x82,0x0e,0xff,0x32,0x80,0xbc,0x05 +,0x00,0x00,0x0f,0x80,0x33,0x82,0x0e,0xff,0x34,0x80,0x24,0x06,0x00,0x00,0x0f,0x80,0x35,0x82,0x0e,0xff,0x36,0x80,0x8c,0x06,0x00,0x00,0x0f,0x80,0x37,0x82,0x0e,0xff +,0x38,0x80,0xf4,0x06,0x00,0x00,0x0f,0x80,0x39,0x82,0x0e,0xff,0x3a,0x80,0x64,0x07,0x00,0x00,0x0f,0x80,0x3b,0x82,0xc1,0x00,0xbf,0xbe,0xff,0x00,0xc6,0xbe,0x00,0xff +,0x00,0x00,0xff,0x00,0xc7,0xbe,0x00,0xfe,0x01,0x00,0xff,0x00,0xc8,0xbe,0x00,0xfc,0x03,0x00,0xff,0x00,0xc9,0xbe,0x00,0xf8,0x07,0x00,0xff,0x00,0xca,0xbe,0x00,0xf0 +,0x0f,0x00,0xff,0x00,0xcb,0xbe,0x00,0xe0,0x1f,0x00,0xff,0x00,0xcc,0xbe,0x00,0xc0,0x3f,0x00,0xff,0x00,0xcd,0xbe,0x00,0x80,0x7f,0x00,0xff,0x00,0xce,0xbe,0x00,0x00 +,0xff,0x00,0xff,0x00,0xcf,0xbe,0x00,0x00,0xfe,0x01,0xff,0x00,0xd0,0xbe,0x00,0x00,0xfc,0x03,0xff,0x00,0xd1,0xbe,0x00,0x00,0xf8,0x07,0xff,0x00,0xd2,0xbe,0x00,0x00 +,0xf0,0x0f,0xff,0x00,0xd3,0xbe,0x00,0x00,0xe0,0x1f,0xff,0x00,0xd4,0xbe,0x00,0x00,0xc0,0x3f,0xff,0x00,0xd5,0xbe,0x00,0x00,0x80,0x7f,0x17,0xc0,0xd6,0x80,0x00,0x00 +,0xec,0xd8,0x00,0x00,0x00,0x18,0x00,0x00,0xec,0xd8,0x0c,0x00,0x00,0x1a,0x7f,0xc0,0x8c,0xbf,0x1b,0x33,0x32,0x2a,0x1a,0x31,0x30,0x2a,0x19,0x15,0x14,0x2a,0x18,0x2f +,0x2e,0x2a,0x56,0x14,0x14,0x26,0x56,0x2e,0x2e,0x26,0x0a,0x03,0x14,0x68,0x17,0x03,0x2e,0x68,0x02,0x15,0x34,0x32,0x1b,0x6a,0x1c,0xd1,0x12,0x01,0xa9,0x01,0x02,0x2f +,0x2e,0x32,0x18,0x6a,0x1c,0xd1,0x12,0x01,0xa9,0x01,0x00,0x80,0x54,0xdc,0x1a,0x00,0x7f,0x1c,0x00,0x80,0x54,0xdc,0x17,0x00,0x7f,0x1e,0x71,0x0f,0x8c,0xbf,0x1c,0x09 +,0x40,0x7e,0x1d,0x09,0x38,0x7e,0x70,0x0f,0x8c,0xbf,0x15,0x3d,0x44,0x2a,0x16,0x3f,0x46,0x2a,0x06,0x49,0x2c,0x32,0x19,0x6a,0x1c,0xd1,0x14,0x01,0xa9,0x01,0x16,0x03 +,0x2a,0x32,0x16,0x6a,0x1c,0xd1,0x19,0x01,0xa9,0x01,0x00,0x80,0x54,0xdc,0x15,0x00,0x7f,0x15,0x20,0x1b,0x3c,0x28,0x1f,0x00,0x01,0xd2,0x21,0x27,0x3a,0x04,0x1c,0x1f +,0x38,0x28,0x1d,0x00,0x01,0xd2,0x1d,0x27,0x42,0x04,0x00,0x01,0x9c,0xd8,0x05,0x1e,0x1c,0x00,0x7f,0xc0,0x8c,0xbf,0x83,0x01,0xfe,0xbe,0x08,0x0a,0xee,0xd8,0x29,0x00 +,0x00,0x3c,0x0c,0x0e,0xee,0xd8,0x29,0x00,0x00,0x40,0x10,0x12,0xee,0xd8,0x29,0x00,0x00,0x44,0x14,0x16,0xee,0xd8,0x29,0x00,0x00,0x48,0x10,0x00,0x89,0xd2,0x22,0x01 +,0x01,0x00,0x11,0x00,0x89,0xd2,0x23,0x01,0x01,0x00,0x12,0x00,0x89,0xd2,0x22,0x03,0x01,0x00,0x13,0x00,0x89,0xd2,0x23,0x03,0x01,0x00,0x14,0x00,0x89,0xd2,0x22,0x05 +,0x01,0x00,0x15,0x00,0x89,0xd2,0x23,0x05,0x01,0x00,0x16,0x00,0x89,0xd2,0x22,0x07,0x01,0x00,0x17,0x00,0x89,0xd2,0x23,0x07,0x01,0x00,0x18,0x00,0x89,0xd2,0x22,0x09 +,0x01,0x00,0x19,0x00,0x89,0xd2,0x23,0x09,0x01,0x00,0x1a,0x00,0x89,0xd2,0x22,0x0b,0x01,0x00,0x1b,0x00,0x89,0xd2,0x23,0x0b,0x01,0x00,0x1c,0x00,0x89,0xd2,0x22,0x0d +,0x01,0x00,0x1d,0x00,0x89,0xd2,0x23,0x0d,0x01,0x00,0x1e,0x00,0x89,0xd2,0x22,0x0f,0x01,0x00,0x1f,0x00,0x89,0xd2,0x23,0x0f,0x01,0x00,0x7f,0xc0,0x8c,0xbf,0x04,0x1e +,0x8c,0xbe,0x08,0x0a,0x9c,0xd8,0x29,0x3c,0x3e,0x00,0x0c,0x0e,0x9c,0xd8,0x29,0x40,0x42,0x00,0x10,0x12,0x9c,0xd8,0x29,0x44,0x46,0x00,0x14,0x16,0x9c,0xd8,0x29,0x48 +,0x4a,0x00,0x1c,0x00,0x8a,0xd2,0x10,0x00,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x11,0x00,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x12,0x02,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x13,0x02 +,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x14,0x04,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x15,0x04,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x16,0x06,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x17,0x06 +,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x18,0x08,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x19,0x08,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x1a,0x0a,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1b,0x0a +,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x1c,0x0c,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1d,0x0c,0x01,0x00,0x1c,0x00,0x8a,0xd2,0x1e,0x0e,0x01,0x00,0x1d,0x00,0x8a,0xd2,0x1f,0x0e +,0x01,0x00,0x24,0x01,0xfe,0xbe,0x00,0x00,0x9a,0xd8,0x11,0x1c,0x00,0x00,0x7f,0xc0,0x8c,0xbf,0x1c,0x2b,0x2a,0x2a,0x1d,0x2d,0x2c,0x2a,0x00,0x00,0x6c,0xd8,0x07,0x00 +,0x00,0x1c,0x00,0x00,0x6c,0xd8,0x08,0x00,0x00,0x1d,0x00,0x00,0x9a,0xd8,0x11,0x15,0x00,0x00,0x7f,0xc1,0x8c,0xbf,0x08,0x10,0xee,0xd8,0x11,0x00,0x00,0x1e,0x1c,0x4b +,0x14,0x2a,0x7f,0xc0,0x8c,0xbf,0x20,0x3d,0x3c,0x2a,0x21,0x3f,0x3e,0x2a,0x0a,0x3b,0x14,0x2a,0x00,0x80,0x74,0xdc,0x1a,0x15,0x7f,0x00,0xff,0x14,0x14,0x26,0xc0,0xff +,0xff,0x7f,0x00,0x80,0x74,0xdc,0x17,0x1e,0x7f,0x00,0x02,0x80,0x06,0xbf,0x06,0x00,0x85,0xbf,0x02,0x81,0x82,0x81,0x24,0x03,0x4a,0x7e,0x80,0x02,0x2e,0x7e,0x0a,0x03 +,0x48,0x7e,0x80,0x02,0x14,0x7e,0x5d,0xff,0x82,0xbf,0x03,0x03,0x00,0x32,0x01,0x6a,0x1c,0xd1,0x04,0x01,0xa9,0x01,0x00,0x80,0x74,0xdc,0x00,0x15,0x7f,0x00,0x40,0x80 +,0x74,0xdc,0x00,0x1e,0x7f,0x00,0x80,0x80,0x74,0xdc,0x00,0x20,0x7f,0x00,0x80,0x02,0x00,0x7e,0x42,0x02,0x02,0x7e,0x00,0x80,0x70,0xdc,0x00,0x01,0x40,0x00,0x00,0x00 +,0x81,0xbf,0x81,0x08,0x43,0xb9,0x44,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x89,0x02,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9,0x62,0x6a,0x1c,0x03,0x5c,0x7e,0x31,0xa5 +,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55 +,0x12,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x44,0x89,0x00,0x00,0x2a,0x03,0x88,0x7e,0x2b,0x03,0x8a,0x7e,0x83,0x01 +,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x46,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x8d,0x02,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9,0x62,0x6a,0x1c,0x03 +,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00 +,0xcc,0xd1,0x2a,0x55,0x1a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x46,0x89,0x00,0x00,0x2a,0x03,0x8c,0x7e,0x2b,0x03 +,0x8e,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x48,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x91,0x02,0x00,0x1c,0x03,0x60,0x7e,0x1d,0xa9 +,0x62,0x6a,0x1c,0x03,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00,0xcc,0xd1,0x30,0x5d +,0xc2,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55,0x22,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x48,0x89,0x00,0x00,0x2a,0x03 +,0x90,0x7e,0x2b,0x03,0x92,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x81,0x08,0x43,0xb9,0x4a,0x4d,0x38,0x7e,0x2a,0x00,0x81,0xd2,0x1c,0x95,0x02,0x00,0x1c,0x03 +,0x60,0x7e,0x1d,0xa9,0x62,0x6a,0x1c,0x03,0x5c,0x7e,0x31,0xa5,0x5e,0x2a,0x2e,0x00,0xcc,0xd1,0x2e,0x55,0xc2,0x03,0x2a,0x00,0xcc,0xd1,0x2a,0x5d,0xaa,0x04,0x30,0x00 +,0xcc,0xd1,0x30,0x5d,0xc2,0x04,0x2e,0x00,0xcc,0xd1,0x2a,0x55,0x2a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2e,0x61,0xaa,0x04,0x0e,0x00,0x13,0xd0,0x4a,0x89 +,0x00,0x00,0x2a,0x03,0x94,0x7e,0x2b,0x03,0x96,0x7e,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x00,0x01,0xd2,0x1d,0x9b,0x3e,0x05,0x81,0x08 +,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x44,0x61,0x02,0x00,0x2a,0x00 +,0xcc,0xd1,0x1c,0xa1,0x12,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x12,0x05,0x0e,0x00,0x72,0xd0,0x44,0x39 +,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x88,0x7e,0x51,0x03,0x8a,0x7e,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x00 +,0x01,0xd2,0x1d,0x9b,0x3e,0x05,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00 +,0x81,0xd2,0x46,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x1a,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39 +,0x1a,0x05,0x0e,0x00,0x72,0xd0,0x46,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x8c,0x7e,0x51,0x03,0x8e,0x7e,0x3c,0x1d +,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x00,0x01,0xd2,0x1d,0x9b,0x3e,0x05,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00 +,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x48,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x22,0x25,0x81,0x08,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61 +,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x22,0x05,0x0e,0x00,0x72,0xd0,0x48,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03 +,0x90,0x7e,0x51,0x03,0x92,0x7e,0x3c,0x1d,0x80,0xbe,0x1c,0x9d,0x38,0x28,0x1d,0x00,0x01,0xd2,0x1d,0x9b,0x3e,0x05,0x81,0x08,0x43,0xb9,0x1c,0x4b,0x60,0x7e,0x50,0x00 +,0xcc,0xd1,0x1c,0x61,0xca,0x23,0x30,0x00,0xcc,0xd1,0x30,0xa1,0xc2,0x04,0x50,0x00,0x81,0xd2,0x4a,0x61,0x02,0x00,0x2a,0x00,0xcc,0xd1,0x1c,0xa1,0x2a,0x25,0x81,0x08 +,0x42,0xb9,0x2a,0x00,0xcc,0xd1,0x2a,0x61,0x42,0x05,0x50,0x00,0xdf,0xd1,0x2a,0x39,0x2a,0x05,0x0e,0x00,0x72,0xd0,0x4a,0x39,0x02,0x00,0x80,0x02,0xa0,0x7e,0x53,0x03 +,0xa2,0x7e,0x83,0x01,0xfe,0xbe,0x50,0x03,0x94,0x7e,0x51,0x03,0x96,0x7e,0x3c,0x1d,0x80,0xbe,0x81,0x01,0xfe,0xbe,0x0e,0x02,0x5a,0x7e,0x28,0x00,0x86,0xd2,0x26,0x5a +,0x02,0x00,0x0f,0x02,0x5e,0x7e,0x2a,0x20,0xe8,0xd1,0x26,0x5e,0xa2,0x04,0x2a,0x03,0x50,0x7e,0x2d,0x20,0xe8,0xd1,0x27,0x5a,0xa2,0x04,0x2a,0x20,0xe8,0xd1,0x27,0x5e +,0xae,0x04,0x2a,0x5d,0x54,0x32,0x80,0x56,0x56,0x38,0x20,0x00,0x89,0xd2,0x2a,0x01,0x01,0x00,0x21,0x00,0x89,0xd2,0x2b,0x01,0x01,0x00,0x0f,0x80,0x04,0xbf,0x26,0x80 +,0xa2,0x85,0x20,0x22,0xa0,0x80,0x21,0x23,0xa1,0x82,0x27,0x80,0x04,0xbf,0x0e,0x80,0xa2,0x85,0x20,0x22,0x8e,0x80,0x21,0x23,0x8f,0x82,0x83,0x01,0xfe,0xbe,0x3c,0x1d +,0x80,0xbe,0x81,0x01,0xfe,0xbe,0x26,0x02,0x5a,0x7e,0x28,0x00,0x86,0xd2,0x0e,0x5a,0x02,0x00,0x27,0x02,0x5e,0x7e,0x2a,0x20,0xe8,0xd1,0x0e,0x5e,0xa2,0x04,0x2a,0x03 +,0x50,0x7e,0x2d,0x20,0xe8,0xd1,0x0f,0x5a,0xa2,0x04,0x2a,0x20,0xe8,0xd1,0x0f,0x5e,0xae,0x04,0x2a,0x5d,0x54,0x32,0x80,0x56,0x56,0x38,0x0e,0x00,0x89,0xd2,0x2a,0x01 +,0x01,0x00,0x0f,0x00,0x89,0xd2,0x2b,0x01,0x01,0x00,0x83,0x01,0xfe,0xbe,0x3c,0x1d,0x80,0xbe,0x00,0x00,0x00,0x00,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,0x1a,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x0b +,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x03,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,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,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00 +,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00 +,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x00 +,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x0b +,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,0x22,0x00 +,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32 +,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,0x0b +,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43 +,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,0x13 +,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48 +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b +,0x00,0x00,0x00,0x01,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,0x27 +,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,0x24 +,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x38 +,0x07,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,0x2c +,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x40 +,0x0f,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}; +const int randomx_run_gfx900_bin_size=6496; diff --git a/src/backend/opencl/cl/rx/randomx_vm.cl b/src/backend/opencl/cl/rx/randomx_vm.cl new file mode 100644 index 000000000..e5cfa2be0 --- /dev/null +++ b/src/backend/opencl/cl/rx/randomx_vm.cl @@ -0,0 +1,2052 @@ +/* +Copyright (c) 2019 SChernykh +Portions Copyright (c) 2018-2019 tevador + +This file is part of RandomX OpenCL. + +RandomX OpenCL is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +RandomX OpenCL is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RandomX OpenCL. If not, see . +*/ + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable + +#define CacheLineSize 64 +#define ScratchpadL3Mask64 (RANDOMX_SCRATCHPAD_L3 - CacheLineSize) +#define CacheLineAlignMask ((RANDOMX_DATASET_BASE_SIZE - 1) & ~(CacheLineSize - 1)) + +#define mantissaSize 52 +#define exponentSize 11 +#define mantissaMask ((1UL << mantissaSize) - 1) +#define exponentMask ((1UL << exponentSize) - 1) +#define exponentBias 1023 +#define constExponentBits 0x300 +#define dynamicExponentBits 4 +#define staticExponentBits 4 +#define dynamicMantissaMask ((1UL << (mantissaSize + dynamicExponentBits)) - 1) + +#define RegistersCount 8 +#define RegisterCountFlt (RegistersCount / 2) +#define ConditionMask ((1 << RANDOMX_JUMP_BITS) - 1) +#define ConditionOffset RANDOMX_JUMP_OFFSET +#define StoreL3Condition 14 +#define DatasetExtraItems (RANDOMX_DATASET_EXTRA_SIZE / RANDOMX_DATASET_ITEM_SIZE) + +#define RegisterNeedsDisplacement 5 + +// +// VM state: +// +// Bytes 0-255: registers +// Bytes 256-1023: imm32 values (up to 192 values can be stored). IMUL_RCP and CBRANCH use 2 consecutive imm32 values. +// Bytes 1024-2047: up to 256 instructions +// +// Instruction encoding: +// +// Bits 0-2: dst (0-7) +// Bits 3-5: src (0-7) +// Bits 6-13: imm32/64 offset (in DWORDs, 0-191) +// Bit 14: src location (register, scratchpad) +// Bits 15-16: src shift (0-3), ADD/MUL switch for FMA instruction +// Bit 17: src=imm32 +// Bit 18: src=imm64 +// Bit 19: src = -src +// Bits 20-23: opcode (add_rs, add, mul, umul_hi, imul_hi, neg, xor, ror, swap, cbranch, store, fswap, fma, fsqrt, fdiv, cfround) +// Bits 24-27: how many parallel instructions to run starting with this one (1-16) +// Bits 28-31: how many of them are FP instructions (0-8) +// + +#define DST_OFFSET 0 +#define SRC_OFFSET 3 +#define IMM_OFFSET 6 +#define LOC_OFFSET 14 +#define SHIFT_OFFSET 15 +#define SRC_IS_IMM32_OFFSET 17 +#define SRC_IS_IMM64_OFFSET 18 +#define NEGATIVE_SRC_OFFSET 19 +#define OPCODE_OFFSET 20 +#define NUM_INSTS_OFFSET 24 +#define NUM_FP_INSTS_OFFSET 28 + +// ISWAP r0, r0 +#define INST_NOP (8 << OPCODE_OFFSET) + +typedef uchar uint8_t; +typedef ushort uint16_t; +typedef uint uint32_t; +typedef ulong uint64_t; + +typedef int int32_t; +typedef long int64_t; + +double getSmallPositiveFloatBits(uint64_t entropy) +{ + uint64_t exponent = entropy >> 59; //0..31 + uint64_t mantissa = entropy & mantissaMask; + exponent += exponentBias; + exponent &= exponentMask; + exponent <<= mantissaSize; + return as_double(exponent | mantissa); +} + +uint64_t getStaticExponent(uint64_t entropy) +{ + uint64_t exponent = constExponentBits; + exponent |= (entropy >> (64 - staticExponentBits)) << dynamicExponentBits; + exponent <<= mantissaSize; + return exponent; +} + +uint64_t getFloatMask(uint64_t entropy) +{ + const uint64_t mask22bit = (1UL << 22) - 1; + return (entropy & mask22bit) | getStaticExponent(entropy); +} + +void set_buffer(__local uint32_t *dst_buf, uint32_t N, const uint32_t value) +{ + uint32_t i = get_local_id(0) * sizeof(uint32_t); + const uint32_t step = get_local_size(0) * sizeof(uint32_t); + __local uint8_t* dst = ((__local uint8_t*)dst_buf) + i; + while (i < sizeof(uint32_t) * N) + { + *(__local uint32_t*)(dst) = value; + dst += step; + i += step; + } +} + +uint64_t imul_rcp_value(uint32_t divisor) +{ + if ((divisor & (divisor - 1)) == 0) + { + return 1UL; + } + + const uint64_t p2exp63 = 1UL << 63; + + uint64_t quotient = p2exp63 / divisor; + uint64_t remainder = p2exp63 % divisor; + + const uint32_t bsr = 31 - clz(divisor); + + for (uint32_t shift = 0; shift <= bsr; ++shift) + { + const bool b = (remainder >= divisor - remainder); + quotient = (quotient << 1) | (b ? 1 : 0); + remainder = (remainder << 1) - (b ? divisor : 0); + } + + return quotient; +} + +#define set_byte(a, position, value) do { ((uint8_t*)&(a))[(position)] = (value); } while (0) +uint32_t get_byte(uint64_t a, uint32_t position) { return (a >> (position << 3)) & 0xFF; } +#define update_max(value, next_value) do { if ((value) < (next_value)) (value) = (next_value); } while (0) + +__attribute__((reqd_work_group_size(32, 1, 1))) +__kernel void init_vm(__global const void* entropy_data, __global void* vm_states, __global uint32_t* rounding, uint32_t iteration) +{ +#if RANDOMX_PROGRAM_SIZE <= 256 + typedef uint8_t exec_t; +#else + typedef uint16_t exec_t; +#endif + + __local uint32_t execution_plan_buf[RANDOMX_PROGRAM_SIZE * WORKERS_PER_HASH * (32 / 8) * sizeof(exec_t) / sizeof(uint32_t)]; + + set_buffer(execution_plan_buf, sizeof(execution_plan_buf) / sizeof(uint32_t), 0); + barrier(CLK_LOCAL_MEM_FENCE); + + const uint32_t global_index = get_global_id(0); + const uint32_t idx = global_index / 8; + const uint32_t sub = global_index % 8; + + __local exec_t* execution_plan = (__local exec_t*)(execution_plan_buf + (get_local_id(0) / 8) * RANDOMX_PROGRAM_SIZE * WORKERS_PER_HASH * sizeof(exec_t) / sizeof(uint32_t)); + + __global uint64_t* R = ((__global uint64_t*)vm_states) + idx * VM_STATE_SIZE / sizeof(uint64_t); + R[sub] = 0; + + const __global uint64_t* entropy = ((const __global uint64_t*)entropy_data) + idx * ENTROPY_SIZE / sizeof(uint64_t); + + __global double* A = (__global double*)(R + 24); + A[sub] = getSmallPositiveFloatBits(entropy[sub]); + + if (sub == 0) + { + if (iteration == 0) + rounding[idx] = 0; + + __global uint2* src_program = (__global uint2*)(entropy + 128 / sizeof(uint64_t)); + +#if RANDOMX_PROGRAM_SIZE <= 256 + uint64_t registerLastChanged = 0; + uint64_t registerWasChanged = 0; +#else + int32_t registerLastChanged[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +#endif + + // Initialize CBRANCH instructions + for (uint32_t i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) + { + // Clear all src flags (branch target, FP, branch) + *(__global uint32_t*)(src_program + i) &= ~(0xF8U << 8); + + const uint2 src_inst = src_program[i]; + uint2 inst = src_inst; + + uint32_t opcode = inst.x & 0xff; + const uint32_t dst = (inst.x >> 8) & 7; + const uint32_t src = (inst.x >> 16) & 7; + + if (opcode < RANDOMX_FREQ_IADD_RS + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_ISUB_R + RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M) + { +#if RANDOMX_PROGRAM_SIZE <= 256 + set_byte(registerLastChanged, dst, i); + set_byte(registerWasChanged, dst, 1); +#else + registerLastChanged[dst] = i; +#endif + continue; + } + opcode -= RANDOMX_FREQ_IADD_RS + RANDOMX_FREQ_IADD_M + RANDOMX_FREQ_ISUB_R + RANDOMX_FREQ_ISUB_M + RANDOMX_FREQ_IMUL_R + RANDOMX_FREQ_IMUL_M + RANDOMX_FREQ_IMULH_R + RANDOMX_FREQ_IMULH_M + RANDOMX_FREQ_ISMULH_R + RANDOMX_FREQ_ISMULH_M; + + if (opcode < RANDOMX_FREQ_IMUL_RCP) + { + if (inst.y & (inst.y - 1)) + { +#if RANDOMX_PROGRAM_SIZE <= 256 + set_byte(registerLastChanged, dst, i); + set_byte(registerWasChanged, dst, 1); +#else + registerLastChanged[dst] = i; +#endif + } + continue; + } + opcode -= RANDOMX_FREQ_IMUL_RCP; + + if (opcode < RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R) + { +#if RANDOMX_PROGRAM_SIZE <= 256 + set_byte(registerLastChanged, dst, i); + set_byte(registerWasChanged, dst, 1); +#else + registerLastChanged[dst] = i; +#endif + continue; + } + opcode -= RANDOMX_FREQ_INEG_R + RANDOMX_FREQ_IXOR_R + RANDOMX_FREQ_IXOR_M + RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R; + + if (opcode < RANDOMX_FREQ_ISWAP_R) + { + if (src != dst) + { +#if RANDOMX_PROGRAM_SIZE <= 256 + set_byte(registerLastChanged, dst, i); + set_byte(registerWasChanged, dst, 1); + set_byte(registerLastChanged, src, i); + set_byte(registerWasChanged, src, 1); +#else + registerLastChanged[dst] = i; + registerLastChanged[src] = i; +#endif + } + continue; + } + opcode -= RANDOMX_FREQ_ISWAP_R; + + if (opcode < RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R) + { + // Mark FP instruction (src |= 0x20) + *(__global uint32_t*)(src_program + i) |= 0x20 << 8; + continue; + } + opcode -= RANDOMX_FREQ_FSWAP_R + RANDOMX_FREQ_FADD_R + RANDOMX_FREQ_FADD_M + RANDOMX_FREQ_FSUB_R + RANDOMX_FREQ_FSUB_M + RANDOMX_FREQ_FSCAL_R + RANDOMX_FREQ_FMUL_R + RANDOMX_FREQ_FDIV_M + RANDOMX_FREQ_FSQRT_R; + + if (opcode < RANDOMX_FREQ_CBRANCH) + { + const uint32_t creg = dst; +#if RANDOMX_PROGRAM_SIZE <= 256 + const uint32_t change = get_byte(registerLastChanged, dst); + const int32_t lastChanged = (get_byte(registerWasChanged, dst) == 0) ? -1 : (int32_t)(change); + + // Store condition register and branch target in CBRANCH instruction + *(__global uint32_t*)(src_program + i) = (src_inst.x & 0xFF0000FFU) | ((creg | ((lastChanged == -1) ? 0x90 : 0x10)) << 8) | (((uint32_t)(lastChanged) & 0xFF) << 16); +#else + const int32_t lastChanged = registerLastChanged[dst]; + + // Store condition register in CBRANCH instruction + *(__global uint32_t*)(src_program + i) = (src_inst.x & 0xFF0000FFU) | ((creg | 0x10) << 8); +#endif + + // Mark branch target instruction (src |= 0x40) + *(__global uint32_t*)(src_program + lastChanged + 1) |= 0x40 << 8; + +#if RANDOMX_PROGRAM_SIZE <= 256 + uint32_t tmp = i | (i << 8); + registerLastChanged = tmp | (tmp << 16); + registerLastChanged = registerLastChanged | (registerLastChanged << 32); + + registerWasChanged = 0x0101010101010101UL; +#else + registerLastChanged[0] = i; + registerLastChanged[1] = i; + registerLastChanged[2] = i; + registerLastChanged[3] = i; + registerLastChanged[4] = i; + registerLastChanged[5] = i; + registerLastChanged[6] = i; + registerLastChanged[7] = i; +#endif + } + } + + uint64_t registerLatency = 0; + uint64_t registerReadCycle = 0; + uint64_t registerLatencyFP = 0; + uint64_t registerReadCycleFP = 0; + uint32_t ScratchpadHighLatency = 0; + uint32_t ScratchpadLatency = 0; + + int32_t first_available_slot = 0; + int32_t first_allowed_slot_cfround = 0; + int32_t last_used_slot = -1; + int32_t last_memory_op_slot = -1; + + uint32_t num_slots_used = 0; + uint32_t num_instructions = 0; + + int32_t first_instruction_slot = -1; + bool first_instruction_fp = false; + + //if (global_index == 0) + //{ + // for (int j = 0; j < RANDOMX_PROGRAM_SIZE; ++j) + // { + // print_inst(src_program[j]); + // printf("\n"); + // } + // printf("\n"); + //} + + // Schedule instructions + bool update_branch_target_mark = false; + bool first_available_slot_is_branch_target = false; + for (uint32_t i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) + { + const uint2 inst = src_program[i]; + + uint32_t opcode = inst.x & 0xff; + uint32_t dst = (inst.x >> 8) & 7; + const uint32_t src = (inst.x >> 16) & 7; + const uint32_t mod = (inst.x >> 24); + + bool is_branch_target = (inst.x & (0x40 << 8)) != 0; + if (is_branch_target) + { + // If an instruction is a branch target, we can't move it before any previous instructions + first_available_slot = last_used_slot + 1; + + // Mark this slot as a branch target + // Whatever instruction takes this slot will receive branch target flag + first_available_slot_is_branch_target = true; + } + + const uint32_t dst_latency = get_byte(registerLatency, dst); + const uint32_t src_latency = get_byte(registerLatency, src); + const uint32_t reg_read_latency = (dst_latency > src_latency) ? dst_latency : src_latency; + const uint32_t mem_read_latency = ((dst == src) && ((inst.y & ScratchpadL3Mask64) >= RANDOMX_SCRATCHPAD_L2)) ? ScratchpadHighLatency : ScratchpadLatency; + + uint32_t full_read_latency = mem_read_latency; + update_max(full_read_latency, reg_read_latency); + + uint32_t latency = 0; + bool is_memory_op = false; + bool is_memory_store = false; + bool is_nop = false; + bool is_branch = false; + bool is_swap = false; + bool is_src_read = true; + bool is_fp = false; + bool is_cfround = false; + + do { + if (opcode < RANDOMX_FREQ_IADD_RS) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_IADD_RS; + + if (opcode < RANDOMX_FREQ_IADD_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_IADD_M; + + if (opcode < RANDOMX_FREQ_ISUB_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_ISUB_R; + + if (opcode < RANDOMX_FREQ_ISUB_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_ISUB_M; + + if (opcode < RANDOMX_FREQ_IMUL_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_IMUL_R; + + if (opcode < RANDOMX_FREQ_IMUL_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_IMUL_M; + + if (opcode < RANDOMX_FREQ_IMULH_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_IMULH_R; + + if (opcode < RANDOMX_FREQ_IMULH_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_IMULH_M; + + if (opcode < RANDOMX_FREQ_ISMULH_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_ISMULH_R; + + if (opcode < RANDOMX_FREQ_ISMULH_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_ISMULH_M; + + if (opcode < RANDOMX_FREQ_IMUL_RCP) + { + is_src_read = false; + if (inst.y & (inst.y - 1)) + latency = dst_latency; + else + is_nop = true; + break; + } + opcode -= RANDOMX_FREQ_IMUL_RCP; + + if (opcode < RANDOMX_FREQ_INEG_R) + { + is_src_read = false; + latency = dst_latency; + break; + } + opcode -= RANDOMX_FREQ_INEG_R; + + if (opcode < RANDOMX_FREQ_IXOR_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_IXOR_R; + + if (opcode < RANDOMX_FREQ_IXOR_M) + { + latency = full_read_latency; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_IXOR_M; + + if (opcode < RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R) + { + latency = reg_read_latency; + break; + } + opcode -= RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R; + + if (opcode < RANDOMX_FREQ_ISWAP_R) + { + is_swap = true; + if (dst != src) + latency = reg_read_latency; + else + is_nop = true; + break; + } + opcode -= RANDOMX_FREQ_ISWAP_R; + + if (opcode < RANDOMX_FREQ_FSWAP_R) + { + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FSWAP_R; + + if (opcode < RANDOMX_FREQ_FADD_R) + { + dst %= RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FADD_R; + + if (opcode < RANDOMX_FREQ_FADD_M) + { + dst %= RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + update_max(latency, src_latency); + update_max(latency, ScratchpadLatency); + is_fp = true; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_FADD_M; + + if (opcode < RANDOMX_FREQ_FSUB_R) + { + dst %= RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FSUB_R; + + if (opcode < RANDOMX_FREQ_FSUB_M) + { + dst %= RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + update_max(latency, src_latency); + update_max(latency, ScratchpadLatency); + is_fp = true; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_FSUB_M; + + if (opcode < RANDOMX_FREQ_FSCAL_R) + { + dst %= RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FSCAL_R; + + if (opcode < RANDOMX_FREQ_FMUL_R) + { + dst = (dst % RegisterCountFlt) + RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FMUL_R; + + if (opcode < RANDOMX_FREQ_FDIV_M) + { + dst = (dst % RegisterCountFlt) + RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + update_max(latency, src_latency); + update_max(latency, ScratchpadLatency); + is_fp = true; + is_memory_op = true; + break; + } + opcode -= RANDOMX_FREQ_FDIV_M; + + if (opcode < RANDOMX_FREQ_FSQRT_R) + { + dst = (dst % RegisterCountFlt) + RegisterCountFlt; + latency = get_byte(registerLatencyFP, dst); + is_fp = true; + is_src_read = false; + break; + } + opcode -= RANDOMX_FREQ_FSQRT_R; + + if (opcode < RANDOMX_FREQ_CBRANCH) + { + is_src_read = false; + is_branch = true; + latency = dst_latency; + + // We can't move CBRANCH before any previous instructions + first_available_slot = last_used_slot + 1; + break; + } + opcode -= RANDOMX_FREQ_CBRANCH; + + if (opcode < RANDOMX_FREQ_CFROUND) + { + latency = src_latency; + is_cfround = true; + break; + } + opcode -= RANDOMX_FREQ_CFROUND; + + if (opcode < RANDOMX_FREQ_ISTORE) + { + latency = reg_read_latency; + update_max(latency, (last_memory_op_slot + WORKERS_PER_HASH) / WORKERS_PER_HASH); + is_memory_op = true; + is_memory_store = true; + break; + } + opcode -= RANDOMX_FREQ_ISTORE; + + is_nop = true; + } while (false); + + if (is_nop) + { + if (is_branch_target) + { + // Mark next non-NOP instruction as the branch target instead of this NOP + update_branch_target_mark = true; + } + continue; + } + + if (update_branch_target_mark) + { + *(__global uint32_t*)(src_program + i) |= 0x40 << 8; + update_branch_target_mark = false; + is_branch_target = true; + } + + int32_t first_allowed_slot = first_available_slot; + update_max(first_allowed_slot, latency * WORKERS_PER_HASH); + if (is_cfround) + update_max(first_allowed_slot, first_allowed_slot_cfround); + else + update_max(first_allowed_slot, get_byte(is_fp ? registerReadCycleFP : registerReadCycle, dst) * WORKERS_PER_HASH); + + if (is_swap) + update_max(first_allowed_slot, get_byte(registerReadCycle, src) * WORKERS_PER_HASH); + + int32_t slot_to_use = last_used_slot + 1; + update_max(slot_to_use, first_allowed_slot); + + if (is_fp) + { + slot_to_use = -1; + for (int32_t j = first_allowed_slot; slot_to_use < 0; ++j) + { + if ((execution_plan[j] == 0) && (execution_plan[j + 1] == 0) && ((j + 1) % WORKERS_PER_HASH)) + { + bool blocked = false; + for (int32_t k = (j / WORKERS_PER_HASH) * WORKERS_PER_HASH; k < j; ++k) + { + if (execution_plan[k] || (k == first_instruction_slot)) + { + const uint32_t inst = src_program[execution_plan[k]].x; + + // If there is an integer instruction which is a branch target or a branch, or this FP instruction is a branch target itself, we can't reorder it to add more FP instructions to this cycle + if (((inst & (0x20 << 8)) == 0) && (((inst & (0x50 << 8)) != 0) || is_branch_target)) + { + blocked = true; + continue; + } + } + } + + if (!blocked) + { + for (int32_t k = (j / WORKERS_PER_HASH) * WORKERS_PER_HASH; k < j; ++k) + { + if (execution_plan[k] || (k == first_instruction_slot)) + { + const uint32_t inst = src_program[execution_plan[k]].x; + if ((inst & (0x20 << 8)) == 0) + { + execution_plan[j] = execution_plan[k]; + execution_plan[j + 1] = execution_plan[k + 1]; + if (first_instruction_slot == k) first_instruction_slot = j; + if (first_instruction_slot == k + 1) first_instruction_slot = j + 1; + slot_to_use = k; + break; + } + } + } + + if (slot_to_use < 0) + { + slot_to_use = j; + } + + break; + } + } + } + } + else + { + for (int32_t j = first_allowed_slot; j <= last_used_slot; ++j) + { + if (execution_plan[j] == 0) + { + slot_to_use = j; + break; + } + } + } + + if (i == 0) + { + first_instruction_slot = slot_to_use; + first_instruction_fp = is_fp; + } + + if (is_cfround) + { + first_allowed_slot_cfround = slot_to_use - (slot_to_use % WORKERS_PER_HASH) + WORKERS_PER_HASH; + } + + ++num_instructions; + + execution_plan[slot_to_use] = i; + ++num_slots_used; + + if (is_fp) + { + execution_plan[slot_to_use + 1] = i; + ++num_slots_used; + } + + const uint32_t next_latency = (slot_to_use / WORKERS_PER_HASH) + 1; + + if (is_src_read) + { + int32_t value = get_byte(registerReadCycle, src); + update_max(value, slot_to_use / WORKERS_PER_HASH); + set_byte(registerReadCycle, src, value); + } + + if (is_memory_op) + { + update_max(last_memory_op_slot, slot_to_use); + } + + if (is_cfround) + { + const uint32_t t = next_latency | (next_latency << 8); + registerLatencyFP = t | (t << 16); + registerLatencyFP = registerLatencyFP | (registerLatencyFP << 32); + } + else if (is_fp) + { + set_byte(registerLatencyFP, dst, next_latency); + + int32_t value = get_byte(registerReadCycleFP, dst); + update_max(value, slot_to_use / WORKERS_PER_HASH); + set_byte(registerReadCycleFP, dst, value); + } + else + { + if (!is_memory_store && !is_nop) + { + set_byte(registerLatency, dst, next_latency); + if (is_swap) + set_byte(registerLatency, src, next_latency); + + int32_t value = get_byte(registerReadCycle, dst); + update_max(value, slot_to_use / WORKERS_PER_HASH); + set_byte(registerReadCycle, dst, value); + } + + if (is_branch) + { + const uint32_t t = next_latency | (next_latency << 8); + registerLatency = t | (t << 16); + registerLatency = registerLatency | (registerLatency << 32); + } + + if (is_memory_store) + { + int32_t value = get_byte(registerReadCycle, dst); + update_max(value, slot_to_use / WORKERS_PER_HASH); + set_byte(registerReadCycle, dst, value); + ScratchpadLatency = (slot_to_use / WORKERS_PER_HASH) + 1; + if ((mod >> 4) >= StoreL3Condition) + ScratchpadHighLatency = (slot_to_use / WORKERS_PER_HASH) + 1; + } + } + + if (execution_plan[first_available_slot] || (first_available_slot == first_instruction_slot)) + { + if (first_available_slot_is_branch_target) + { + src_program[i].x |= 0x40 << 8; + first_available_slot_is_branch_target = false; + } + + if (is_fp) + ++first_available_slot; + + do { + ++first_available_slot; + } while ((first_available_slot < RANDOMX_PROGRAM_SIZE * WORKERS_PER_HASH) && (execution_plan[first_available_slot] != 0)); + } + + if (is_branch_target) + { + update_max(first_available_slot, is_fp ? (slot_to_use + 2) : (slot_to_use + 1)); + } + + update_max(last_used_slot, is_fp ? (slot_to_use + 1) : slot_to_use); + while (execution_plan[last_used_slot] || (last_used_slot == first_instruction_slot) || ((last_used_slot == first_instruction_slot + 1) && first_instruction_fp)) + { + ++last_used_slot; + } + --last_used_slot; + + if (is_fp && (last_used_slot >= first_allowed_slot_cfround)) + first_allowed_slot_cfround = last_used_slot + 1; + + //if (global_index == 0) + //{ + // printf("slot_to_use = %d, first_available_slot = %d, last_used_slot = %d\n", slot_to_use, first_available_slot, last_used_slot); + // for (int j = 0; j <= last_used_slot; ++j) + // { + // if (execution_plan[j] || (j == first_instruction_slot) || ((j == first_instruction_slot + 1) && first_instruction_fp)) + // { + // print_inst(src_program[execution_plan[j]]); + // printf(" | "); + // } + // else + // { + // printf(" | "); + // } + // if (((j + 1) % WORKERS_PER_HASH) == 0) printf("\n"); + // } + // printf("\n\n"); + //} + } + + //if (global_index == 0) + //{ + // printf("IPC = %.3f, WPC = %.3f, num_instructions = %u, num_slots_used = %u, first_instruction_slot = %d, last_used_slot = %d, registerLatency = %016llx, registerLatencyFP = %016llx \n", + // num_instructions / static_cast(last_used_slot / WORKERS_PER_HASH + 1), + // num_slots_used / static_cast(last_used_slot / WORKERS_PER_HASH + 1), + // num_instructions, + // num_slots_used, + // first_instruction_slot, + // last_used_slot, + // registerLatency, + // registerLatencyFP + // ); + + // //for (int j = 0; j < RANDOMX_PROGRAM_SIZE; ++j) + // //{ + // // print_inst(src_program[j]); + // // printf("\n"); + // //} + // //printf("\n"); + + // for (int j = 0; j <= last_used_slot; ++j) + // { + // if (execution_plan[j] || (j == first_instruction_slot) || ((j == first_instruction_slot + 1) && first_instruction_fp)) + // { + // print_inst(src_program[execution_plan[j]]); + // printf(" | "); + // } + // else + // { + // printf(" | "); + // } + // if (((j + 1) % WORKERS_PER_HASH) == 0) printf("\n"); + // } + // printf("\n\n"); + //} + + //atomicAdd((uint32_t*)num_vm_cycles, (last_used_slot / WORKERS_PER_HASH) + 1); + //atomicAdd((uint32_t*)(num_vm_cycles) + 1, num_slots_used); + + uint32_t ma = (uint32_t)(entropy[8]) & CacheLineAlignMask; + uint32_t mx = (uint32_t)(entropy[10]) & CacheLineAlignMask; + + uint32_t addressRegisters = (uint32_t)(entropy[12]); + addressRegisters = ((addressRegisters & 1) | (((addressRegisters & 2) ? 3U : 2U) << 8) | (((addressRegisters & 4) ? 5U : 4U) << 16) | (((addressRegisters & 8) ? 7U : 6U) << 24)) * sizeof(uint64_t); + + uint32_t datasetOffset = (entropy[13] & DatasetExtraItems) * CacheLineSize; + + ulong2 eMask = *(__global ulong2*)(entropy + 14); + eMask.x = getFloatMask(eMask.x); + eMask.y = getFloatMask(eMask.y); + + ((__global uint32_t*)(R + 16))[0] = ma; + ((__global uint32_t*)(R + 16))[1] = mx; + ((__global uint32_t*)(R + 16))[2] = addressRegisters; + ((__global uint32_t*)(R + 16))[3] = datasetOffset; + ((__global ulong2*)(R + 18))[0] = eMask; + + __global uint32_t* imm_buf = (__global uint32_t*)(R + REGISTERS_SIZE / sizeof(uint64_t)); + uint32_t imm_index = 0; + int32_t imm_index_fscal_r = -1; + __global uint32_t* compiled_program = (__global uint32_t*)(R + (REGISTERS_SIZE + IMM_BUF_SIZE) / sizeof(uint64_t)); + + // Generate opcodes for execute_vm + int32_t branch_target_slot = -1; + int32_t k = -1; + for (int32_t i = 0; i <= last_used_slot; ++i) + { + if (!(execution_plan[i] || (i == first_instruction_slot) || ((i == first_instruction_slot + 1) && first_instruction_fp))) + continue; + + uint32_t num_workers = 1; + uint32_t num_fp_insts = 0; + while ((i + num_workers <= last_used_slot) && ((i + num_workers) % WORKERS_PER_HASH) && (execution_plan[i + num_workers] || (i + num_workers == first_instruction_slot) || ((i + num_workers == first_instruction_slot + 1) && first_instruction_fp))) + { + if ((num_workers & 1) && ((src_program[execution_plan[i + num_workers]].x & (0x20 << 8)) != 0)) + ++num_fp_insts; + ++num_workers; + } + + //if (global_index == 0) + // printf("i = %d, num_workers = %u, num_fp_insts = %u\n", i, num_workers, num_fp_insts); + + num_workers = ((num_workers - 1) << NUM_INSTS_OFFSET) | (num_fp_insts << NUM_FP_INSTS_OFFSET); + + const uint2 src_inst = src_program[execution_plan[i]]; + uint2 inst = src_inst; + + uint32_t opcode = inst.x & 0xff; + const uint32_t dst = (inst.x >> 8) & 7; + const uint32_t src = (inst.x >> 16) & 7; + const uint32_t mod = (inst.x >> 24); + + const bool is_fp = (src_inst.x & (0x20 << 8)) != 0; + if (is_fp && ((i & 1) == 0)) + ++i; + + const bool is_branch_target = (src_inst.x & (0x40 << 8)) != 0; + if (is_branch_target && (branch_target_slot < 0)) + branch_target_slot = k; + + ++k; + + inst.x = INST_NOP; + + if (opcode < RANDOMX_FREQ_IADD_RS) + { + const uint32_t shift = (mod >> 2) % 4; + + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (shift << SHIFT_OFFSET); + + if (dst != RegisterNeedsDisplacement) + { + // Encode regular ADD (opcode 1) + inst.x |= (1 << OPCODE_OFFSET); + } + else + { + // Encode ADD with src and imm32 (opcode 0) + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = inst.y; + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IADD_RS; + + if (opcode < RANDOMX_FREQ_IADD_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (1 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IADD_M; + + if (opcode < RANDOMX_FREQ_ISUB_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << OPCODE_OFFSET) | (1 << NEGATIVE_SRC_OFFSET); + if (src == dst) + { + inst.x |= (imm_index << IMM_OFFSET) | (1 << SRC_IS_IMM32_OFFSET); + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = inst.y; + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISUB_R; + + if (opcode < RANDOMX_FREQ_ISUB_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (1 << OPCODE_OFFSET) | (1 << NEGATIVE_SRC_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISUB_M; + + if (opcode < RANDOMX_FREQ_IMUL_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (2 << OPCODE_OFFSET); + if (src == dst) + { + inst.x |= (imm_index << IMM_OFFSET) | (1 << SRC_IS_IMM32_OFFSET); + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = inst.y; + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IMUL_R; + + if (opcode < RANDOMX_FREQ_IMUL_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (2 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IMUL_M; + + if (opcode < RANDOMX_FREQ_IMULH_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (6 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IMULH_R; + + if (opcode < RANDOMX_FREQ_IMULH_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (6 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IMULH_M; + + if (opcode < RANDOMX_FREQ_ISMULH_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (4 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISMULH_R; + + if (opcode < RANDOMX_FREQ_ISMULH_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (4 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISMULH_M; + + if (opcode < RANDOMX_FREQ_IMUL_RCP) + { + const uint64_t r = imul_rcp_value(inst.y); + if (r == 1) + { + *(compiled_program++) = INST_NOP | num_workers; + continue; + } + + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (2 << OPCODE_OFFSET); + inst.x |= (imm_index << IMM_OFFSET) | (1 << SRC_IS_IMM64_OFFSET); + + if (imm_index < IMM_INDEX_COUNT - 1) + { + imm_buf[imm_index] = ((const uint32_t*)&r)[0]; + imm_buf[imm_index + 1] = ((const uint32_t*)&r)[1]; + imm_index += 2; + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IMUL_RCP; + + if (opcode < RANDOMX_FREQ_INEG_R) + { + inst.x = (dst << DST_OFFSET) | (5 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_INEG_R; + + if (opcode < RANDOMX_FREQ_IXOR_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (3 << OPCODE_OFFSET); + if (src == dst) + { + inst.x |= (imm_index << IMM_OFFSET) | (1 << SRC_IS_IMM32_OFFSET); + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = inst.y; + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IXOR_R; + + if (opcode < RANDOMX_FREQ_IXOR_M) + { + const uint32_t location = (src == dst) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (3 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IXOR_M; + + if (opcode < RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (7 << OPCODE_OFFSET); + if (src == dst) + { + inst.x |= (imm_index << IMM_OFFSET) | (1 << SRC_IS_IMM32_OFFSET); + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = inst.y; + } + if (opcode >= RANDOMX_FREQ_IROR_R) + { + inst.x |= (1 << NEGATIVE_SRC_OFFSET); + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_IROR_R + RANDOMX_FREQ_IROL_R; + + if (opcode < RANDOMX_FREQ_ISWAP_R) + { + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (8 << OPCODE_OFFSET); + + *(compiled_program++) = ((src != dst) ? inst.x : INST_NOP) | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISWAP_R; + + if (opcode < RANDOMX_FREQ_FSWAP_R) + { + inst.x = (dst << DST_OFFSET) | (11 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FSWAP_R; + + if (opcode < RANDOMX_FREQ_FADD_R) + { + inst.x = ((dst % RegisterCountFlt) << DST_OFFSET) | ((src % RegisterCountFlt) << (SRC_OFFSET + 1)) | (12 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FADD_R; + + if (opcode < RANDOMX_FREQ_FADD_M) + { + const uint32_t location = (mod % 4) ? 1 : 2; + inst.x = ((dst % RegisterCountFlt) << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (12 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FADD_M; + + if (opcode < RANDOMX_FREQ_FSUB_R) + { + inst.x = ((dst % RegisterCountFlt) << DST_OFFSET) | ((src % RegisterCountFlt) << (SRC_OFFSET + 1)) | (12 << OPCODE_OFFSET) | (1 << NEGATIVE_SRC_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FSUB_R; + + if (opcode < RANDOMX_FREQ_FSUB_M) + { + const uint32_t location = (mod % 4) ? 1 : 2; + inst.x = ((dst % RegisterCountFlt) << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (12 << OPCODE_OFFSET) | (1 << NEGATIVE_SRC_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FSUB_M; + + if (opcode < RANDOMX_FREQ_FSCAL_R) + { + inst.x = ((dst % RegisterCountFlt) << DST_OFFSET) | (1 << SRC_IS_IMM64_OFFSET) | (3 << OPCODE_OFFSET); + if (imm_index_fscal_r >= 0) + { + inst.x |= (imm_index_fscal_r << IMM_OFFSET); + } + else + { + imm_index_fscal_r = imm_index; + inst.x |= (imm_index << IMM_OFFSET); + + if (imm_index < IMM_INDEX_COUNT - 1) + { + imm_buf[imm_index] = 0; + imm_buf[imm_index + 1] = 0x80F00000UL; + imm_index += 2; + } + } + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FSCAL_R; + + if (opcode < RANDOMX_FREQ_FMUL_R) + { + inst.x = (((dst % RegisterCountFlt) + RegisterCountFlt) << DST_OFFSET) | ((src % RegisterCountFlt) << (SRC_OFFSET + 1)) | (1 << SHIFT_OFFSET) | (12 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FMUL_R; + + if (opcode < RANDOMX_FREQ_FDIV_M) + { + const uint32_t location = (mod % 4) ? 1 : 2; + inst.x = (((dst % RegisterCountFlt) + RegisterCountFlt) << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (15 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FDIV_M; + + if (opcode < RANDOMX_FREQ_FSQRT_R) + { + inst.x = (((dst % RegisterCountFlt) + RegisterCountFlt) << DST_OFFSET) | (14 << OPCODE_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_FSQRT_R; + + if (opcode < RANDOMX_FREQ_CBRANCH) + { + inst.x = (dst << DST_OFFSET) | (9 << OPCODE_OFFSET); + inst.x |= (imm_index << IMM_OFFSET); + + const uint32_t cshift = (mod >> 4) + ConditionOffset; + + uint32_t imm = inst.y | (1U << cshift); + if (cshift > 0) + imm &= ~(1U << (cshift - 1)); + + if (imm_index < IMM_INDEX_COUNT - 1) + { + imm_buf[imm_index] = imm; + imm_buf[imm_index + 1] = cshift | ((uint32_t)(branch_target_slot) << 5); + imm_index += 2; + } + else + { + // Data doesn't fit, skip it + inst.x = INST_NOP; + } + + branch_target_slot = -1; + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_CBRANCH; + + if (opcode < RANDOMX_FREQ_CFROUND) + { + inst.x = (src << SRC_OFFSET) | (13 << OPCODE_OFFSET) | ((inst.y & 63) << IMM_OFFSET); + + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_CFROUND; + + if (opcode < RANDOMX_FREQ_ISTORE) + { + const uint32_t location = ((mod >> 4) >= StoreL3Condition) ? 3 : ((mod % 4) ? 1 : 2); + inst.x = (dst << DST_OFFSET) | (src << SRC_OFFSET) | (1 << LOC_OFFSET) | (10 << OPCODE_OFFSET); + inst.x |= imm_index << IMM_OFFSET; + if (imm_index < IMM_INDEX_COUNT) + imm_buf[imm_index++] = (inst.y & 0xFC1FFFFFU) | (((location == 1) ? LOC_L1 : ((location == 2) ? LOC_L2 : LOC_L3)) << 21); + else + inst.x = INST_NOP; + *(compiled_program++) = inst.x | num_workers; + continue; + } + opcode -= RANDOMX_FREQ_ISTORE; + + *(compiled_program++) = inst.x | num_workers; + } + + ((__global uint32_t*)(R + 20))[0] = (uint32_t)(compiled_program - (__global uint32_t*)(R + (REGISTERS_SIZE + IMM_BUF_SIZE) / sizeof(uint64_t))); + } +} + +void load_buffer(__local uint64_t *dst_buf, size_t N, __global const void* src_buf) +{ + uint32_t i = get_local_id(0) * sizeof(uint64_t); + const uint32_t step = get_local_size(0) * sizeof(uint64_t); + __global const uint8_t* src = ((__global const uint8_t*)src_buf) + get_group_id(0) * sizeof(uint64_t) * N + i; + __local uint8_t* dst = ((__local uint8_t*)dst_buf) + i; + while (i < sizeof(uint64_t) * N) + { + *(__local uint64_t*)(dst) = *(__global uint64_t*)(src); + src += step; + dst += step; + i += step; + } +} + +double load_F_E_groups(int value, uint64_t andMask, uint64_t orMask) +{ + double t = convert_double_rtn(value); + uint64_t x = as_ulong(t); + x &= andMask; + x |= orMask; + return as_double(x); +} + +// You're one ugly motherfucker! +double fma_soft(double a, double b, double c, uint32_t rounding_mode) +{ + if (rounding_mode == 0) + return fma(a, b, c); + + if ((a == 0.0) || (b == 0.0)) + return c; + + if (b == 1.0) + { + if (c == 0.0) + return a; + + if (c == -a) + { + const uint64_t minus_zero = 1UL << 63; + return (rounding_mode == 1) ? as_double(minus_zero) : 0.0; + } + } + + const uint64_t mantissa_size = 52; + const uint64_t mantissa_mask = (1UL << mantissa_size) - 1; + const uint64_t mantissa_high_bit = 1UL << mantissa_size; + + const uint64_t exponent_size = 11; + const uint64_t exponent_mask = (1 << exponent_size) - 1; + + const uint32_t exponent_a = (as_uint2(a).y >> 20) & exponent_mask; + const uint32_t exponent_b = (as_uint2(b).y >> 20) & exponent_mask; + const uint32_t exponent_c = (as_uint2(c).y >> 20) & exponent_mask; + + if ((exponent_a == 2047) || (exponent_b == 2047) || (exponent_c == 2047)) + { + const uint64_t inf = 2047UL << 52; + return as_double(inf); + } + + const uint64_t mantissa_a = (as_ulong(a) & mantissa_mask) | mantissa_high_bit; + const uint64_t mantissa_b = (as_ulong(b) & mantissa_mask) | mantissa_high_bit; + const uint64_t mantissa_c = (as_ulong(c) & mantissa_mask) | mantissa_high_bit; + + const uint32_t sign_a = as_uint2(a).y >> 31; + const uint32_t sign_b = as_uint2(b).y >> 31; + const uint32_t sign_c = as_uint2(c).y >> 31; + + uint64_t mul_result[2]; + mul_result[0] = mantissa_a * mantissa_b; + mul_result[1] = mul_hi(mantissa_a, mantissa_b); + + uint32_t exp_correction = mul_result[1] >> 41; + uint32_t exponent_mul_result = exponent_a + exponent_b + exp_correction - 1023; + uint32_t sign_mul_result = sign_a ^ sign_b; + + if (exponent_mul_result >= 2047) + { + const uint64_t inf_rnd = (2047UL << 52) - (rounding_mode & 1); + return as_double(inf_rnd); + } + + uint64_t fma_result[2]; + uint64_t t[2]; + uint32_t exponent_fma_result; + + if (exponent_mul_result >= exponent_c) + { + uint32_t shift = 23 - exp_correction; + fma_result[0] = mul_result[0] << shift; + fma_result[1] = (mul_result[1] << shift) | (mul_result[0] >> (64 - shift)); + + int32_t shift2 = (127 - 52) + (int32_t)(exponent_c - exponent_mul_result); + + if (shift2 >= 0) + { + if (shift2 >= 64) + { + t[0] = 0; + t[1] = mantissa_c << (shift2 - 64); + } + else + { + t[0] = mantissa_c << shift2; + t[1] = shift2 ? (mantissa_c >> (64 - shift2)) : 0; + } + } + else + { + t[0] = (shift2 < -52) ? 0 : (mantissa_c >> (-shift2)); + t[1] = 0; + if ((t[0] == 0) && (c != 0.0)) + t[0] = 1; + } + + exponent_fma_result = exponent_mul_result; + } + else + { + t[0] = 0; + t[1] = mantissa_c << 11; + + int32_t shift2 = (127 - 104 - exp_correction) + (int32_t)(exponent_mul_result - exponent_c); + if (shift2 >= 0) + { + fma_result[0] = mul_result[0] << shift2; + fma_result[1] = (mul_result[1] << shift2) | (shift2 ? (mul_result[0] >> (64 - shift2)) : 0); + } + else + { + shift2 = -shift2; + if (shift2 >= 64) + { + shift2 -= 64; + fma_result[0] = (shift2 < 64) ? (mul_result[1] >> shift2) : 0; + fma_result[1] = 0; + if (fma_result[0] == 0) + fma_result[0] = 1; + } + else + { + fma_result[0] = (mul_result[0] >> shift2) | (mul_result[1] << (64 - shift2)); + fma_result[1] = mul_result[1] >> shift2; + } + } + + exponent_fma_result = exponent_c; + } + + uint32_t sign_fma_result; + + if (sign_mul_result == sign_c) + { + fma_result[0] += t[0]; + fma_result[1] += t[1] + ((fma_result[0] < t[0]) ? 1 : 0); + + exp_correction = (fma_result[1] < t[1]) ? 1 : 0; + sign_fma_result = sign_mul_result; + } + else + { + const uint32_t borrow = (fma_result[0] < t[0]) ? 1 : 0; + fma_result[0] -= t[0]; + + t[1] += borrow; + const uint32_t change_sign = (fma_result[1] < t[1]) ? 1 : 0; + fma_result[1] -= t[1]; + + sign_fma_result = sign_mul_result ^ change_sign; + if (change_sign) + { + fma_result[0] = -(int64_t)(fma_result[0]); + fma_result[1] = ~fma_result[1]; + fma_result[1] += fma_result[0] ? 0 : 1; + } + + if (fma_result[1] == 0) + { + if (fma_result[0] == 0) + return 0.0; + + exponent_fma_result -= 64; + fma_result[1] = fma_result[0]; + fma_result[0] = 0; + } + + const uint32_t index = clz(fma_result[1]); + if (index) + { + exponent_fma_result -= index; + fma_result[1] = (fma_result[1] << index) | (fma_result[0] >> (64 - index)); + } + + exp_correction = 0; + } + + const uint32_t shift = 11 + exp_correction; + const uint32_t round_up = (fma_result[0] || (fma_result[1] & ((1 << shift) - 1))) ? 1 : 0; + + fma_result[1] >>= shift; + fma_result[1] &= mantissa_mask; + if (rounding_mode + sign_fma_result == 2) + { + fma_result[1] += round_up; + if (fma_result[1] == mantissa_high_bit) + { + fma_result[1] = 0; + ++exponent_fma_result; + } + } + fma_result[1] |= (uint64_t)(exponent_fma_result + exp_correction) << mantissa_size; + fma_result[1] |= (uint64_t)(sign_fma_result) << 63; + + return as_double(fma_result[1]); +} + +double div_rnd(double a, double b, uint32_t fprc) +{ + double y0 = 1.0 / b; + + // Do 1 Newton-Raphson iteration to get correct rounding + const double t0 = a * y0; + const double t1 = fma(-b, t0, a); + double result = fma_soft(y0, t1, t0, fprc); + + // Check for infinity/NaN + const uint64_t inf = 2047UL << 52; + const uint64_t inf_rnd = inf - (fprc & 1); + + if (((as_ulong(result) >> 52) & 2047) == 2047) result = as_double(inf_rnd); + if (as_ulong(a) == inf) result = a; + + return (a == b) ? 1.0 : result; +} + +double sqrt_rnd(double x, uint32_t fprc) +{ + double y0 = rsqrt(x); + + // First Newton-Raphson iteration + double t0 = y0 * x; + double t1 = y0 * -0.5; + t1 = fma(t1, t0, 0.5); // 0.5 * (1.0 - y0 * y0 * x) + const double y1_x = fma(t0, t1, t0); // y1 * x = 0.5 * y0 * x * (3.0 - y0 * y0 * x) + + // Second Newton-Raphson iteration + y0 *= 0.5; + y0 = fma(y0, t1, y0); // 0.5 * y1 + t1 = fma(-y1_x, y1_x, x); // x * (1.0 - x * y1 * y1) + + double result = fma_soft(t1, y0, y1_x, fprc); // x * 0.5 * y1 * (3.0 - x * y1 * y1) + + // Check for infinity + if (*((uint64_t*) &x) == (2047UL << 52)) result = x; + + return result; +} + +uint32_t inner_loop( + const uint32_t program_length, + __local const uint32_t* compiled_program, + const int32_t sub, + __global uint8_t* scratchpad, + const uint32_t fp_reg_offset, + const uint32_t fp_reg_group_A_offset, + __local uint64_t* R, + __local uint32_t* imm_buf, + const uint32_t batch_size, + uint32_t fprc, + const uint32_t fp_workers_mask, + const uint64_t xexponentMask, + const uint32_t workers_mask +) +{ + const int32_t sub2 = sub >> 1; + imm_buf[IMM_INDEX_COUNT + 1] = fprc; + + #pragma unroll(1) + for (int32_t ip = 0; ip < program_length;) + { + imm_buf[IMM_INDEX_COUNT] = ip; + + uint32_t inst = compiled_program[ip]; + const int32_t num_workers = (inst >> NUM_INSTS_OFFSET) & (WORKERS_PER_HASH - 1); + const int32_t num_fp_insts = (inst >> NUM_FP_INSTS_OFFSET) & (WORKERS_PER_HASH - 1); + const int32_t num_insts = num_workers - num_fp_insts; + + if (sub <= num_workers) + { + const int32_t inst_offset = sub - num_fp_insts; + const bool is_fp = inst_offset < num_fp_insts; + inst = compiled_program[ip + (is_fp ? sub2 : inst_offset)]; + //if ((idx == 0) && (ic == 0)) + //{ + // printf("num_fp_insts = %u, sub = %u, ip = %u, inst = %08x\n", num_fp_insts, sub, ip + ((sub < num_fp_insts * 2) ? (sub / 2) : (sub - num_fp_insts)), inst); + //} + + //asm("// INSTRUCTION DECODING BEGIN"); + + uint32_t opcode = (inst >> OPCODE_OFFSET) & 15; + const uint32_t location = (inst >> LOC_OFFSET) & 1; + + const uint32_t reg_size_shift = is_fp ? 4 : 3; + const uint32_t reg_base_offset = is_fp ? fp_reg_offset : 0; + const uint32_t reg_base_src_offset = is_fp ? fp_reg_group_A_offset : 0; + + uint32_t dst_offset = (inst >> DST_OFFSET) & 7; + dst_offset = reg_base_offset + (dst_offset << reg_size_shift); + + uint32_t src_offset = (inst >> SRC_OFFSET) & 7; + src_offset = (src_offset << 3) + (location ? 0 : reg_base_src_offset); + + __local uint64_t* dst_ptr = (__local uint64_t*)((__local uint8_t*)(R) + dst_offset); + __local uint64_t* src_ptr = (__local uint64_t*)((__local uint8_t*)(R) + src_offset); + + const uint32_t imm_offset = (inst >> IMM_OFFSET) & 255; + __local const uint32_t* imm_ptr = imm_buf + imm_offset; + + uint64_t dst = *dst_ptr; + uint64_t src = *src_ptr; + uint2 imm; + imm.x = imm_ptr[0]; + imm.y = imm_ptr[1]; + + //asm("// INSTRUCTION DECODING END"); + + if (location) + { + //asm("// SCRATCHPAD ACCESS BEGIN"); + + const uint32_t loc_shift = (imm.x >> 21) & 31; + const uint32_t mask = (0xFFFFFFFFU >> loc_shift) - 7; + + const bool is_read = (opcode != 10); + uint32_t addr = is_read ? ((loc_shift == LOC_L3) ? 0 : (uint32_t)(src)) : (uint32_t)(dst); + addr += (int32_t)(imm.x); + addr &= mask; + + __global uint64_t* ptr = (__global uint64_t*)(scratchpad + addr); + + if (is_read) + { + src = *ptr; + } + else + { + *ptr = src; + goto execution_end; + } + + //asm("// SCRATCHPAD ACCESS END"); + } + + { + //asm("// EXECUTION BEGIN"); + + if (inst & (1 << SRC_IS_IMM32_OFFSET)) src = (uint64_t)((int64_t)((int32_t)(imm.x))); + + // Check instruction opcodes (most frequent instructions come first) + if (opcode <= 3) + { + //asm("// IADD_RS, IADD_M, ISUB_R, ISUB_M, IMUL_R, IMUL_M, IMUL_RCP, IXOR_R, IXOR_M, FSCAL_R (109/256) ------>"); + if (inst & (1 << NEGATIVE_SRC_OFFSET)) src = (uint64_t)(-(int64_t)(src)); + if (opcode == 0) dst += (int32_t)(imm.x); + const uint32_t shift = (inst >> SHIFT_OFFSET) & 3; + if (opcode < 2) dst += src << shift; + const uint64_t imm64 = *((uint64_t*) &imm); + if (inst & (1 << SRC_IS_IMM64_OFFSET)) src = imm64; + if (opcode == 2) dst *= src; + if (opcode == 3) dst ^= src; + //asm("// <------ IADD_RS, IADD_M, ISUB_R, ISUB_M, IMUL_R, IMUL_M, IMUL_RCP, IXOR_R, IXOR_M, FSCAL_R (109/256)"); + } + else if (opcode == 12) + { + //asm("// FADD_R, FADD_M, FSUB_R, FSUB_M, FMUL_R (74/256) ------>"); + + if (location) src = as_ulong(convert_double_rtn((int32_t)(src >> ((sub & 1) * 32)))); + if (inst & (1 << NEGATIVE_SRC_OFFSET)) src ^= 0x8000000000000000UL; + + const bool is_mul = (inst & (1 << SHIFT_OFFSET)) != 0; + const double a = as_double(dst); + const double b = as_double(src); + + dst = as_ulong(fma_soft(a, is_mul ? b : 1.0, is_mul ? 0.0 : b, fprc)); + + //asm("// <------ FADD_R, FADD_M, FSUB_R, FSUB_M, FMUL_R (74/256)"); + } + else if (opcode == 9) + { + //asm("// CBRANCH (16/256) ------>"); + dst += (int32_t)(imm.x); + if (((uint32_t)(dst) & (ConditionMask << (imm.y & 31))) == 0) + { + imm_buf[IMM_INDEX_COUNT] = (uint32_t)(((int32_t)(imm.y) >> 5) - num_insts); + } + //asm("// <------ CBRANCH (16/256)"); + } + else if (opcode == 7) + { + //asm("// IROR_R, IROL_R (10/256) ------>"); + uint32_t shift1 = src & 63; +#if RANDOMX_FREQ_IROL_R > 0 + const uint32_t shift2 = 64 - shift1; + const bool is_rol = (inst & (1 << NEGATIVE_SRC_OFFSET)); + dst = (dst >> (is_rol ? shift2 : shift1)) | (dst << (is_rol ? shift1 : shift2)); +#else + dst = (dst >> shift1) | (dst << (64 - shift1)); +#endif + //asm("// <------ IROR_R, IROL_R (10/256)"); + } + else if (opcode == 14) + { + //asm("// FSQRT_R (6/256) ------>"); + dst = as_ulong(sqrt_rnd(as_double(dst), fprc)); + //asm("// <------ FSQRT_R (6/256)"); + } + else if (opcode == 6) + { + //asm("// IMULH_R, IMULH_M (5/256) ------>"); + dst = mul_hi(dst, src); + //asm("// <------ IMULH_R, IMULH_M (5/256)"); + } + else if (opcode == 4) + { + //asm("// ISMULH_R, ISMULH_M (5/256) ------>"); + dst = (uint64_t)(mul_hi((int64_t)(dst), (int64_t)(src))); + //asm("// <------ ISMULH_R, ISMULH_M (5/256)"); + } + else if (opcode == 11) + { + //asm("// FSWAP_R (4/256) ------>"); + dst = *(__local uint64_t*)((__local uint8_t*)(R) + (dst_offset ^ 8)); + //asm("// <------ FSWAP_R (4/256)"); + } + else if (opcode == 8) + { + //asm("// ISWAP_R (4/256) ------>"); + *src_ptr = dst; + dst = src; + //asm("// <------ ISWAP_R (4/256)"); + } + else if (opcode == 15) + { + //asm("// FDIV_M (4/256) ------>"); + src = as_ulong(convert_double_rtn((int32_t)(src >> ((sub & 1) * 32)))); + src &= dynamicMantissaMask; + src |= xexponentMask; + dst = as_ulong(div_rnd(as_double(dst), as_double(src), fprc)); + //asm("// <------ FDIV_M (4/256)"); + } + else if (opcode == 5) + { + //asm("// INEG_R (2/256) ------>"); + dst = (uint64_t)(-(int64_t)(dst)); + //asm("// <------ INEG_R (2/256)"); + } + // CFROUND check will be skipped and removed entirely by the compiler if ROUNDING_MODE >= 0 + else if (ROUNDING_MODE < 0) + { + //asm("// CFROUND (1/256) ------>"); + imm_buf[IMM_INDEX_COUNT + 1] = ((src >> imm_offset) | (src << (64 - imm_offset))) & 3; + //asm("// <------ CFROUND (1/256)"); + goto execution_end; + } + + *dst_ptr = dst; + //asm("// EXECUTION END"); + } + } + + execution_end: + { + //asm("// SYNCHRONIZATION OF INSTRUCTION POINTER AND ROUNDING MODE BEGIN"); + + barrier(CLK_LOCAL_MEM_FENCE); + ip = imm_buf[IMM_INDEX_COUNT]; + fprc = imm_buf[IMM_INDEX_COUNT + 1]; + + //asm("// SYNCHRONIZATION OF INSTRUCTION POINTER AND ROUNDING MODE END"); + + ip += num_insts + 1; + } + } + + return fprc; +} + +#if WORKERS_PER_HASH == 16 +__attribute__((reqd_work_group_size(32, 1, 1))) +#else +__attribute__((reqd_work_group_size(16, 1, 1))) +#endif +__kernel void execute_vm(__global void* vm_states, __global void* rounding, __global void* scratchpads, __global const void* dataset_ptr, uint32_t batch_size, uint32_t num_iterations, uint32_t first, uint32_t last) +{ + // 2 hashes per warp, 4 KB shared memory for VM states + __local uint64_t vm_states_local[(VM_STATE_SIZE * 2) / sizeof(uint64_t)]; + + load_buffer(vm_states_local, sizeof(vm_states_local) / sizeof(uint64_t), vm_states); + + barrier(CLK_LOCAL_MEM_FENCE); + + enum { IDX_WIDTH = (WORKERS_PER_HASH == 16) ? 16 : 8 }; + + __local uint64_t* R = vm_states_local + (get_local_id(0) / IDX_WIDTH) * VM_STATE_SIZE / sizeof(uint64_t); + __local double* F = (__local double*)(R + 8); + __local double* E = (__local double*)(R + 16); + + const uint32_t global_index = get_global_id(0); + const int32_t idx = global_index / IDX_WIDTH; + const int32_t sub = global_index % IDX_WIDTH; + + uint32_t ma = ((__local uint32_t*)(R + 16))[0]; + uint32_t mx = ((__local uint32_t*)(R + 16))[1]; + + const uint32_t addressRegisters = ((__local uint32_t*)(R + 16))[2]; + __local const uint64_t* readReg0 = (__local uint64_t*)(((__local uint8_t*)R) + (addressRegisters & 0xff)); + __local const uint64_t* readReg1 = (__local uint64_t*)(((__local uint8_t*)R) + ((addressRegisters >> 8) & 0xff)); + __local const uint32_t* readReg2 = (__local uint32_t*)(((__local uint8_t*)R) + ((addressRegisters >> 16) & 0xff)); + __local const uint32_t* readReg3 = (__local uint32_t*)(((__local uint8_t*)R) + (addressRegisters >> 24)); + + const uint32_t datasetOffset = ((__local uint32_t*)(R + 16))[3]; + __global const uint8_t* dataset = ((__global const uint8_t*)dataset_ptr) + datasetOffset; + + const uint32_t fp_reg_offset = 64 + ((global_index & 1) << 3); + const uint32_t fp_reg_group_A_offset = 192 + ((global_index & 1) << 3); + + __local uint64_t* eMask = R + 18; + + const uint32_t program_length = ((__local uint32_t*)(R + 20))[0]; + uint32_t fprc = ((__global uint32_t*)rounding)[idx]; + + uint32_t spAddr0 = first ? mx : 0; + uint32_t spAddr1 = first ? ma : 0; + + __global uint8_t* scratchpad = ((__global uint8_t*)scratchpads) + idx * (uint64_t)(RANDOMX_SCRATCHPAD_L3 + 64); + + const bool f_group = (sub < 4); + + __local double* fe = f_group ? (F + sub * 2) : (E + (sub - 4) * 2); + __local double* f = F + sub; + __local double* e = E + sub; + + const uint64_t andMask = f_group ? (uint64_t)(-1) : dynamicMantissaMask; + const uint64_t orMask1 = f_group ? 0 : eMask[0]; + const uint64_t orMask2 = f_group ? 0 : eMask[1]; + const uint64_t xexponentMask = (sub & 1) ? eMask[1] : eMask[0]; + + __local uint32_t* imm_buf = (__local uint32_t*)(R + REGISTERS_SIZE / sizeof(uint64_t)); + __local const uint32_t* compiled_program = (__local const uint32_t*)(R + (REGISTERS_SIZE + IMM_BUF_SIZE) / sizeof(uint64_t)); + + const uint32_t workers_mask = ((1 << WORKERS_PER_HASH) - 1) << ((get_local_id(0) / IDX_WIDTH) * IDX_WIDTH); + const uint32_t fp_workers_mask = 3 << (((sub >> 1) << 1) + (get_local_id(0) / IDX_WIDTH) * IDX_WIDTH); + + #pragma unroll(1) + for (int ic = 0; ic < num_iterations; ++ic) + { + __local uint64_t *r; + __global uint64_t *p0, *p1; + if ((WORKERS_PER_HASH <= 8) || (sub < 8)) + { + const uint64_t spMix = *readReg0 ^ *readReg1; + spAddr0 ^= ((const uint32_t*)&spMix)[0]; + spAddr1 ^= ((const uint32_t*)&spMix)[1]; + spAddr0 &= ScratchpadL3Mask64; + spAddr1 &= ScratchpadL3Mask64; + + p0 = (__global uint64_t*)(scratchpad + spAddr0 + sub * 8); + p1 = (__global uint64_t*)(scratchpad + spAddr1 + sub * 8); + + r = R + sub; + *r ^= *p0; + + uint64_t global_mem_data = *p1; + int32_t* q = (int32_t*)&global_mem_data; + + fe[0] = load_F_E_groups(q[0], andMask, orMask1); + fe[1] = load_F_E_groups(q[1], andMask, orMask2); + } + + //if ((global_index == 0) && (ic == 0)) + //{ + // printf("ic = %d (before)\n", ic); + // for (int i = 0; i < 8; ++i) + // printf("f%d = %016llx\n", i, bit_cast(F[i])); + // for (int i = 0; i < 8; ++i) + // printf("e%d = %016llx\n", i, bit_cast(E[i])); + // printf("\n"); + //} + + if ((WORKERS_PER_HASH == IDX_WIDTH) || (sub < WORKERS_PER_HASH)) + fprc = inner_loop(program_length, compiled_program, sub, scratchpad, fp_reg_offset, fp_reg_group_A_offset, R, imm_buf, batch_size, fprc, fp_workers_mask, xexponentMask, workers_mask); + + //if ((global_index == 0) && (ic == RANDOMX_PROGRAM_ITERATIONS - 1)) + //{ + // printf("ic = %d (after)\n", ic); + // for (int i = 0; i < 8; ++i) + // printf("r%d = %016llx\n", i, R[i]); + // for (int i = 0; i < 8; ++i) + // printf("f%d = %016llx\n", i, bit_cast(F[i])); + // for (int i = 0; i < 8; ++i) + // printf("e%d = %016llx\n", i, bit_cast(E[i])); + // printf("\n"); + //} + + if ((WORKERS_PER_HASH <= 8) || (sub < 8)) + { + mx ^= *readReg2 ^ *readReg3; + mx &= CacheLineAlignMask; + + const uint64_t next_r = *r ^ *(__global const uint64_t*)(dataset + ma + sub * 8); + *r = next_r; + + *p1 = next_r; + *p0 = as_ulong(f[0]) ^ as_ulong(e[0]); + + uint32_t tmp = ma; + ma = mx; + mx = tmp; + + spAddr0 = 0; + spAddr1 = 0; + } + } + + //if (global_index == 0) + //{ + // for (int i = 0; i < 8; ++i) + // printf("r%d = %016llx\n", i, R[i]); + // for (int i = 0; i < 8; ++i) + // printf("fe%d = %016llx\n", i, bit_cast(F[i]) ^ bit_cast(E[i])); + // printf("\n"); + //} + + if ((WORKERS_PER_HASH > 8) && (sub >= 8)) + return; + + __global uint64_t* p = ((__global uint64_t*)vm_states) + idx * (VM_STATE_SIZE / sizeof(uint64_t)); + p[sub] = R[sub]; + + if (sub == 0) + { + ((__global uint32_t*)rounding)[idx] = fprc; + } + + if (last) + { + p[sub + 8] = as_ulong(F[sub]) ^ as_ulong(E[sub]); + p[sub + 16] = as_ulong(E[sub]); + } + else if (sub == 0) + { + ((__global uint32_t*)(p + 16))[0] = ma; + ((__global uint32_t*)(p + 16))[1] = mx; + } +} + +__attribute__((reqd_work_group_size(64, 1, 1))) +__kernel void find_shares(__global const uint64_t* hashes, uint64_t target, uint32_t start_nonce, __global uint32_t* shares) +{ + const uint32_t global_index = get_global_id(0); + + if (hashes[global_index * 4 + 3] < target) { + //if (global_index == 0) { + const uint32_t idx = atomic_inc(shares + 0xFF); + if (idx < 0xFF) { + shares[idx] = start_nonce + global_index; + } + } +} diff --git a/src/backend/opencl/generators/ocl_generic_cn_generator.cpp b/src/backend/opencl/generators/ocl_generic_cn_generator.cpp new file mode 100644 index 000000000..52ab32109 --- /dev/null +++ b/src/backend/opencl/generators/ocl_generic_cn_generator.cpp @@ -0,0 +1,118 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Algorithm.h" + + +#include + + +namespace xmrig { + + +constexpr const size_t oneMiB = 1024u * 1024u; + + +static inline uint32_t getMaxThreads(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.vendorId() == OCL_VENDOR_NVIDIA && (device.name().contains("P100") || device.name().contains("V100"))) { + return 40000u; + } + + return ((algorithm.l3() <= oneMiB) ? 2u : 1u) * 1000u; +} + + +static inline uint32_t getPossibleIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxThreads = getMaxThreads(device, algorithm); + const size_t minFreeMem = (maxThreads == 40000u ? 512u : 128u) * oneMiB; + const size_t availableMem = device.freeMemSize() - minFreeMem; + const size_t perThread = algorithm.l3() + 224u; + const auto maxIntensity = static_cast(availableMem / perThread); + + return std::min(maxThreads, maxIntensity); +} + + +static uint32_t getIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.type() == OclDevice::Raven) { + return 0; + } + + const uint32_t maxIntensity = getPossibleIntensity(device, algorithm); + + uint32_t intensity = (maxIntensity / (8 * device.computeUnits())) * device.computeUnits() * 8; + if (intensity == 0) { + return 0; + } + + if (device.vendorId() == OCL_VENDOR_AMD && (device.type() == OclDevice::Lexa || device.type() == OclDevice::Baffin || device.computeUnits() <= 16)) { + intensity /= 2; + + if (algorithm.family() == Algorithm::CN_HEAVY) { + intensity /= 2; + } + } + + return intensity; +} + + +static uint32_t getStridedIndex(const OclDevice &device, const Algorithm &algorithm) +{ + if (device.vendorId() != OCL_VENDOR_AMD) { + return 0; + } + + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 2 : 1; +} + + +bool ocl_generic_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (!algorithm.isCN()) { + return false; + } + + const uint32_t intensity = getIntensity(device, algorithm); + if (intensity == 0) { + return false; + } + + const uint32_t threadCount = ((device.globalMemSize() - intensity * 2 * algorithm.l3()) > 128 * oneMiB) ? 2 : 1; + + threads.add(OclThread(device.index(), intensity, 8, getStridedIndex(device, algorithm), 2, threadCount, 8)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/generators/ocl_generic_cn_gpu_generator.cpp b/src/backend/opencl/generators/ocl_generic_cn_gpu_generator.cpp new file mode 100644 index 000000000..338a7a78c --- /dev/null +++ b/src/backend/opencl/generators/ocl_generic_cn_gpu_generator.cpp @@ -0,0 +1,87 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/common/Algorithm.h" + + +#include + + +namespace xmrig { + + +constexpr const size_t oneMiB = 1024u * 1024u; + + + +bool ocl_generic_cn_gpu_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (algorithm != Algorithm::CN_GPU) { + return false; + } + + uint32_t worksize = 8; + uint32_t numThreads = 1u; + size_t minFreeMem = 128u * oneMiB; + + if (device.type() == OclDevice::Vega_10 || device.type() == OclDevice::Vega_20) { + minFreeMem = oneMiB; + worksize = 16; + } + else if (device.type() == OclDevice::Navi_10) { + numThreads = 2u; + } + else if (device.name() == "Fiji") { + worksize = 16; + } + + size_t maxThreads = device.computeUnits() * 6 * 8; + + const size_t maxAvailableFreeMem = device.freeMemSize() - minFreeMem; + const size_t memPerThread = std::min(device.maxMemAllocSize(), maxAvailableFreeMem); + + size_t memPerHash = algorithm.l3() + 240u; + size_t maxIntensity = memPerThread / memPerHash; + size_t possibleIntensity = std::min(maxThreads, maxIntensity); + size_t intensity = 0; + size_t cuUtilization = ((possibleIntensity * 100) / (worksize * device.computeUnits())) % 100; + + if (cuUtilization >= 75) { + intensity = (possibleIntensity / worksize) * worksize; + } + else { + intensity = (possibleIntensity / (worksize * device.computeUnits())) * device.computeUnits() * worksize; + } + + threads.add(OclThread(device.index(), intensity, worksize, numThreads, 1)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/generators/ocl_generic_rx_generator.cpp b/src/backend/opencl/generators/ocl_generic_rx_generator.cpp new file mode 100644 index 000000000..61ea74ed7 --- /dev/null +++ b/src/backend/opencl/generators/ocl_generic_rx_generator.cpp @@ -0,0 +1,51 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { + + +//constexpr const size_t oneMiB = 1024u * 1024u; + + + +bool ocl_generic_rx_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (algorithm.family() != Algorithm::RANDOM_X) { + return false; + } + +// threads.add(OclThread(device.index(), 500, 8, 1, true, false, 6)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/generators/ocl_vega_cn_generator.cpp b/src/backend/opencl/generators/ocl_vega_cn_generator.cpp new file mode 100644 index 000000000..dbaba1c53 --- /dev/null +++ b/src/backend/opencl/generators/ocl_vega_cn_generator.cpp @@ -0,0 +1,135 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Algorithm.h" + + +#include + + +namespace xmrig { + + +constexpr const size_t oneMiB = 1024u * 1024u; + + +static inline bool isMatch(const OclDevice &device, const Algorithm &algorithm) +{ + return algorithm.isCN() && + device.vendorId() == OCL_VENDOR_AMD && + (device.type() == OclDevice::Vega_10 || device.type() == OclDevice::Vega_20); +} + + +static inline uint32_t getMaxThreads(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t ratio = (algorithm.l3() <= oneMiB) ? 2u : 1u; + + if (device.type() == OclDevice::Vega_10) { + if (device.computeUnits() == 56 && algorithm.family() == Algorithm::CN && CnAlgo<>::base(algorithm) == Algorithm::CN_2) { + return 1792u; + } + } + + return ratio * 2024u; +} + + +static inline uint32_t getPossibleIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxThreads = getMaxThreads(device, algorithm); + const size_t availableMem = device.freeMemSize() - (128u * oneMiB); + const size_t perThread = algorithm.l3() + 224u; + const auto maxIntensity = static_cast(availableMem / perThread); + + return std::min(maxThreads, maxIntensity); +} + + +static inline uint32_t getIntensity(const OclDevice &device, const Algorithm &algorithm) +{ + const uint32_t maxIntensity = getPossibleIntensity(device, algorithm); + + if (device.type() == OclDevice::Vega_10) { + if (algorithm.family() == Algorithm::CN_HEAVY && device.computeUnits() == 64 && maxIntensity > 976) { + return 976; + } + } + + return maxIntensity / device.computeUnits() * device.computeUnits(); +} + + +static inline uint32_t getWorksize(const Algorithm &algorithm) +{ + if (algorithm.family() == Algorithm::CN_PICO) { + return 64; + } + + if (CnAlgo<>::base(algorithm) == Algorithm::CN_2) { + return 16; + } + + return 8; +} + + +static uint32_t getStridedIndex(const Algorithm &algorithm) +{ + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 2 : 1; +} + + +static inline uint32_t getMemChunk(const Algorithm &algorithm) +{ + return CnAlgo<>::base(algorithm) == Algorithm::CN_2 ? 1 : 2; +} + + +bool ocl_vega_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads) +{ + if (!isMatch(device, algorithm)) { + return false; + } + + const uint32_t intensity = getIntensity(device, algorithm); + if (intensity == 0) { + return false; + } + + const uint32_t worksize = getWorksize(algorithm); + const uint32_t memChunk = getMemChunk(algorithm); + + threads.add(OclThread(device.index(), intensity, worksize, getStridedIndex(algorithm), memChunk, 2, 8)); + + return true; +} + + +} // namespace xmrig diff --git a/src/backend/opencl/interfaces/IOclRunner.h b/src/backend/opencl/interfaces/IOclRunner.h new file mode 100644 index 000000000..c1718a2a7 --- /dev/null +++ b/src/backend/opencl/interfaces/IOclRunner.h @@ -0,0 +1,75 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_IOCLRUNNER_H +#define XMRIG_IOCLRUNNER_H + + +#include "base/tools/Object.h" + + +#include + + +using cl_context = struct _cl_context *; + + +namespace xmrig { + + +class Algorithm; +class Job; +class OclLaunchData; + + +class IOclRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE(IOclRunner) + + IOclRunner() = default; + virtual ~IOclRunner() = default; + + virtual void run(uint32_t nonce, uint32_t *hashOutput) = 0; + virtual void set(const Job &job, uint8_t *blob) = 0; + virtual cl_context ctx() const = 0; + virtual const Algorithm &algorithm() const = 0; + virtual const char *buildOptions() const = 0; + virtual const char *deviceKey() const = 0; + virtual const char *source() const = 0; + virtual const OclLaunchData &data() const = 0; + virtual size_t threadId() const = 0; + virtual uint32_t deviceIndex() const = 0; + virtual void build() = 0; + virtual void init() = 0; + +protected: + virtual size_t bufferSize() const = 0; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_IOCLRUNNER_H diff --git a/src/backend/opencl/kernels/Cn00RyoKernel.cpp b/src/backend/opencl/kernels/Cn00RyoKernel.cpp new file mode 100644 index 000000000..df987fa4f --- /dev/null +++ b/src/backend/opencl/kernels/Cn00RyoKernel.cpp @@ -0,0 +1,44 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/Cn00RyoKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Cn00RyoKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads * 64; + const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void cn00(__global int *Scratchpad, __global ulong *states) +void xmrig::Cn00RyoKernel::setArgs(cl_mem scratchpads, cl_mem states) +{ + setArg(0, sizeof(cl_mem), &scratchpads); + setArg(1, sizeof(cl_mem), &states); +} diff --git a/src/backend/opencl/kernels/Cn00RyoKernel.h b/src/backend/opencl/kernels/Cn00RyoKernel.h new file mode 100644 index 000000000..366f644e1 --- /dev/null +++ b/src/backend/opencl/kernels/Cn00RyoKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN00RYOKERNEL_H +#define XMRIG_CN00RYOKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn00RyoKernel : public OclKernel +{ +public: + inline Cn00RyoKernel(cl_program program) : OclKernel(program, "cn00") {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem scratchpads, cl_mem states); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN00RYOKERNEL_H */ diff --git a/src/backend/opencl/kernels/Cn0Kernel.cpp b/src/backend/opencl/kernels/Cn0Kernel.cpp new file mode 100644 index 000000000..a93e10059 --- /dev/null +++ b/src/backend/opencl/kernels/Cn0Kernel.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/Cn0Kernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Cn0Kernel::enqueue(cl_command_queue queue, uint32_t nonce, size_t threads) +{ + const size_t offset[2] = { nonce, 1 }; + const size_t gthreads[2] = { threads, 8 }; + static const size_t lthreads[2] = { 8, 8 }; + + enqueueNDRange(queue, 2, offset, gthreads, lthreads); +} + + +// __kernel void cn0(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +void xmrig::Cn0Kernel::setArgs(cl_mem input, cl_mem scratchpads, cl_mem states, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &input); + setArg(1, sizeof(cl_mem), &scratchpads); + setArg(2, sizeof(cl_mem), &states); + setArg(3, sizeof(uint32_t), &threads); +} diff --git a/src/backend/opencl/kernels/Cn0Kernel.h b/src/backend/opencl/kernels/Cn0Kernel.h new file mode 100644 index 000000000..1bb9a37a0 --- /dev/null +++ b/src/backend/opencl/kernels/Cn0Kernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN0KERNEL_H +#define XMRIG_CN0KERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn0Kernel : public OclKernel +{ +public: + inline Cn0Kernel(cl_program program) : OclKernel(program, "cn0") {} + + void enqueue(cl_command_queue queue, uint32_t nonce, size_t threads); + void setArgs(cl_mem input, cl_mem scratchpads, cl_mem states, uint32_t threads); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN0KERNEL_H */ diff --git a/src/backend/opencl/kernels/Cn1Kernel.cpp b/src/backend/opencl/kernels/Cn1Kernel.cpp new file mode 100644 index 000000000..fad7889c3 --- /dev/null +++ b/src/backend/opencl/kernels/Cn1Kernel.cpp @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "backend/opencl/kernels/Cn1Kernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +xmrig::Cn1Kernel::Cn1Kernel(cl_program program) + : OclKernel(program, "cn1") +{ +} + + +xmrig::Cn1Kernel::Cn1Kernel(cl_program program, uint64_t height) + : OclKernel(program, ("cn1_" + std::to_string(height)).c_str()) +{ + +} + + +void xmrig::Cn1Kernel::enqueue(cl_command_queue queue, uint32_t nonce, size_t threads, size_t worksize) +{ + const size_t offset = nonce; + const size_t gthreads = threads; + const size_t lthreads = worksize; + + enqueueNDRange(queue, 1, &offset, >hreads, <hreads); +} + + +// __kernel void cn1(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, uint Threads) +void xmrig::Cn1Kernel::setArgs(cl_mem input, cl_mem scratchpads, cl_mem states, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &input); + setArg(1, sizeof(cl_mem), &scratchpads); + setArg(2, sizeof(cl_mem), &states); + setArg(3, sizeof(uint32_t), &threads); +} diff --git a/src/backend/opencl/kernels/Cn1Kernel.h b/src/backend/opencl/kernels/Cn1Kernel.h new file mode 100644 index 000000000..08d33de2c --- /dev/null +++ b/src/backend/opencl/kernels/Cn1Kernel.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN1KERNEL_H +#define XMRIG_CN1KERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn1Kernel : public OclKernel +{ +public: + Cn1Kernel(cl_program program); + Cn1Kernel(cl_program program, uint64_t height); + + void enqueue(cl_command_queue queue, uint32_t nonce, size_t threads, size_t worksize); + void setArgs(cl_mem input, cl_mem scratchpads, cl_mem states, uint32_t threads); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN1KERNEL_H */ diff --git a/src/backend/opencl/kernels/Cn1RyoKernel.cpp b/src/backend/opencl/kernels/Cn1RyoKernel.cpp new file mode 100644 index 000000000..50254543c --- /dev/null +++ b/src/backend/opencl/kernels/Cn1RyoKernel.cpp @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "backend/opencl/kernels/Cn1RyoKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Cn1RyoKernel::enqueue(cl_command_queue queue, size_t threads, size_t worksize) +{ + const size_t gthreads = threads * 16; + const size_t lthreads = worksize * 16; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void cn1(__global int *lpad_in, __global int *spad, uint numThreads) +void xmrig::Cn1RyoKernel::setArgs(cl_mem scratchpads, cl_mem states, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &scratchpads); + setArg(1, sizeof(cl_mem), &states); + setArg(2, sizeof(uint32_t), &threads); +} diff --git a/src/backend/opencl/kernels/Cn1RyoKernel.h b/src/backend/opencl/kernels/Cn1RyoKernel.h new file mode 100644 index 000000000..31714f1ec --- /dev/null +++ b/src/backend/opencl/kernels/Cn1RyoKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN1RYOKERNEL_H +#define XMRIG_CN1RYOKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn1RyoKernel : public OclKernel +{ +public: + inline Cn1RyoKernel(cl_program program) : OclKernel(program, "cn1") {} + + void enqueue(cl_command_queue queue, size_t threads, size_t worksize); + void setArgs(cl_mem scratchpads, cl_mem states, uint32_t threads); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN1RYOKERNEL_H */ diff --git a/src/backend/opencl/kernels/Cn2Kernel.cpp b/src/backend/opencl/kernels/Cn2Kernel.cpp new file mode 100644 index 000000000..1dbb03b1b --- /dev/null +++ b/src/backend/opencl/kernels/Cn2Kernel.cpp @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/Cn2Kernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Cn2Kernel::enqueue(cl_command_queue queue, uint32_t nonce, size_t threads) +{ + const size_t offset[2] = { nonce, 1 }; + const size_t gthreads[2] = { threads, 8 }; + static const size_t lthreads[2] = { 8, 8 }; + + enqueueNDRange(queue, 2, offset, gthreads, lthreads); +} + + +// __kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3, uint Threads) +void xmrig::Cn2Kernel::setArgs(cl_mem scratchpads, cl_mem states, const std::vector &branches, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &scratchpads); + setArg(1, sizeof(cl_mem), &states); + setArg(6, sizeof(uint32_t), &threads); + + for (uint32_t i = 0; i < branches.size(); ++i) { + setArg(i + 2, sizeof(cl_mem), &branches[i]); + } +} diff --git a/src/backend/opencl/kernels/Cn2Kernel.h b/src/backend/opencl/kernels/Cn2Kernel.h new file mode 100644 index 000000000..cb4aaedef --- /dev/null +++ b/src/backend/opencl/kernels/Cn2Kernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN2KERNEL_H +#define XMRIG_CN2KERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn2Kernel : public OclKernel +{ +public: + inline Cn2Kernel(cl_program program) : OclKernel(program, "cn2") {} + + void enqueue(cl_command_queue queue, uint32_t nonce, size_t threads); + void setArgs(cl_mem scratchpads, cl_mem states, const std::vector &branches, uint32_t threads); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN2KERNEL_H */ diff --git a/src/backend/opencl/kernels/Cn2RyoKernel.cpp b/src/backend/opencl/kernels/Cn2RyoKernel.cpp new file mode 100644 index 000000000..e294eb24d --- /dev/null +++ b/src/backend/opencl/kernels/Cn2RyoKernel.cpp @@ -0,0 +1,53 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/Cn2RyoKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Cn2RyoKernel::enqueue(cl_command_queue queue, uint32_t nonce, size_t threads) +{ + const size_t offset[2] = { nonce, 1 }; + const size_t gthreads[2] = { threads, 8 }; + static const size_t lthreads[2] = { 8, 8 }; + + enqueueNDRange(queue, 2, offset, gthreads, lthreads); +} + + +// __kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *output, ulong Target, uint Threads) +void xmrig::Cn2RyoKernel::setArgs(cl_mem scratchpads, cl_mem states, cl_mem output, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &scratchpads); + setArg(1, sizeof(cl_mem), &states); + setArg(2, sizeof(cl_mem), &output); + setArg(4, sizeof(uint32_t), &threads); +} + + +void xmrig::Cn2RyoKernel::setTarget(uint64_t target) +{ + setArg(3, sizeof(cl_ulong), &target); +} diff --git a/src/backend/opencl/kernels/Cn2RyoKernel.h b/src/backend/opencl/kernels/Cn2RyoKernel.h new file mode 100644 index 000000000..2ef85bcb3 --- /dev/null +++ b/src/backend/opencl/kernels/Cn2RyoKernel.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CN2RYOKERNEL_H +#define XMRIG_CN2RYOKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Cn2RyoKernel : public OclKernel +{ +public: + inline Cn2RyoKernel(cl_program program) : OclKernel(program, "cn2") {} + + void enqueue(cl_command_queue queue, uint32_t nonce, size_t threads); + void setArgs(cl_mem scratchpads, cl_mem states, cl_mem output, uint32_t threads); + void setTarget(uint64_t target); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CN2RYOKERNEL_H */ diff --git a/src/backend/opencl/kernels/CnBranchKernel.cpp b/src/backend/opencl/kernels/CnBranchKernel.cpp new file mode 100644 index 000000000..a0813a74d --- /dev/null +++ b/src/backend/opencl/kernels/CnBranchKernel.cpp @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/CnBranchKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +namespace xmrig { + + +static const char *names[4] = { "Blake", "Groestl", "JH", "Skein" }; + + +} // namespace xmrig + + +xmrig::CnBranchKernel::CnBranchKernel(size_t index, cl_program program) : OclKernel(program, names[index]) +{ +} + + +void xmrig::CnBranchKernel::enqueue(cl_command_queue queue, uint32_t nonce, size_t threads, size_t worksize) +{ + const size_t offset = nonce; + const size_t gthreads = threads; + const size_t lthreads = worksize; + + enqueueNDRange(queue, 1, &offset, >hreads, <hreads); +} + + +// __kernel void Skein(__global ulong *states, __global uint *BranchBuf, __global uint *output, ulong Target, uint Threads) +void xmrig::CnBranchKernel::setArgs(cl_mem states, cl_mem branch, cl_mem output, uint32_t threads) +{ + setArg(0, sizeof(cl_mem), &states); + setArg(1, sizeof(cl_mem), &branch); + setArg(2, sizeof(cl_mem), &output); + setArg(4, sizeof(cl_uint), &threads); +} + + +void xmrig::CnBranchKernel::setTarget(uint64_t target) +{ + setArg(3, sizeof(cl_ulong), &target); +} diff --git a/src/backend/opencl/kernels/CnBranchKernel.h b/src/backend/opencl/kernels/CnBranchKernel.h new file mode 100644 index 000000000..a52c928d5 --- /dev/null +++ b/src/backend/opencl/kernels/CnBranchKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_CNBRANCHKERNEL_H +#define XMRIG_CNBRANCHKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class CnBranchKernel : public OclKernel +{ +public: + CnBranchKernel(size_t index, cl_program program); + void enqueue(cl_command_queue queue, uint32_t nonce, size_t threads, size_t worksize); + void setArgs(cl_mem states, cl_mem branch, cl_mem output, uint32_t threads); + void setTarget(uint64_t target); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_CNBRANCHKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.cpp b/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.cpp new file mode 100644 index 000000000..1b60d31bb --- /dev/null +++ b/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.cpp @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Blake2bHashRegistersKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void blake2b_hash_registers_32(__global void *out, __global const void* in, uint inStrideBytes) +// __kernel void blake2b_hash_registers_64(__global void *out, __global const void* in, uint inStrideBytes) +void xmrig::Blake2bHashRegistersKernel::setArgs(cl_mem out, cl_mem in, uint32_t inStrideBytes) +{ + setArg(0, sizeof(cl_mem), &out); + setArg(1, sizeof(cl_mem), &in); + setArg(2, sizeof(uint32_t), &inStrideBytes); +} diff --git a/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h b/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h new file mode 100644 index 000000000..538033a02 --- /dev/null +++ b/src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_BLAKE2BHASHREGISTERSKERNEL_H +#define XMRIG_BLAKE2BHASHREGISTERSKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Blake2bHashRegistersKernel : public OclKernel +{ +public: + inline Blake2bHashRegistersKernel(cl_program program, const char *name) : OclKernel(program, name) {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem out, cl_mem in, uint32_t inStrideBytes); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_BLAKE2BHASHREGISTERSKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.cpp b/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.cpp new file mode 100644 index 000000000..7b6126e0b --- /dev/null +++ b/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.cpp @@ -0,0 +1,58 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/Blake2bInitialHashKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::Blake2bInitialHashKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void blake2b_initial_hash(__global void *out, __global const void* blockTemplate, uint blockTemplateSize, uint start_nonce) +void xmrig::Blake2bInitialHashKernel::setArgs(cl_mem out, cl_mem blockTemplate) +{ + setArg(0, sizeof(cl_mem), &out); + setArg(1, sizeof(cl_mem), &blockTemplate); +} + + +void xmrig::Blake2bInitialHashKernel::setBlobSize(size_t size) +{ + const uint32_t s = size; + + setArg(2, sizeof(uint32_t), &s); +} + + +void xmrig::Blake2bInitialHashKernel::setNonce(uint32_t nonce) +{ + setArg(3, sizeof(uint32_t), &nonce); +} diff --git a/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.h b/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.h new file mode 100644 index 000000000..2eb6627b3 --- /dev/null +++ b/src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.h @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_BLAKE2BINITIALHASHKERNEL_H +#define XMRIG_BLAKE2BINITIALHASHKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Blake2bInitialHashKernel : public OclKernel +{ +public: + inline Blake2bInitialHashKernel(cl_program program) : OclKernel(program, "blake2b_initial_hash") {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem out, cl_mem blockTemplate); + void setBlobSize(size_t size); + void setNonce(uint32_t nonce); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_BLAKE2BINITIALHASHKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/ExecuteVmKernel.cpp b/src/backend/opencl/kernels/rx/ExecuteVmKernel.cpp new file mode 100644 index 000000000..2963ce6e5 --- /dev/null +++ b/src/backend/opencl/kernels/rx/ExecuteVmKernel.cpp @@ -0,0 +1,67 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/ExecuteVmKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::ExecuteVmKernel::enqueue(cl_command_queue queue, size_t threads, size_t worksize) +{ + const size_t gthreads = (worksize == 16) ? (threads * 16) : (threads * 8); + const size_t lthreads = (worksize == 16) ? 32 : 16; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void execute_vm(__global void* vm_states, __global void* rounding, __global void* scratchpads, __global const void* dataset_ptr, uint32_t batch_size, uint32_t num_iterations, uint32_t first, uint32_t last) +void xmrig::ExecuteVmKernel::setArgs(cl_mem vm_states, cl_mem rounding, cl_mem scratchpads, cl_mem dataset_ptr, uint32_t batch_size) +{ + setArg(0, sizeof(cl_mem), &vm_states); + setArg(1, sizeof(cl_mem), &rounding); + setArg(2, sizeof(cl_mem), &scratchpads); + setArg(3, sizeof(cl_mem), &dataset_ptr); + setArg(4, sizeof(uint32_t), &batch_size); +} + + +void xmrig::ExecuteVmKernel::setFirst(uint32_t first) +{ + setArg(6, sizeof(uint32_t), &first); +} + + +void xmrig::ExecuteVmKernel::setIterations(uint32_t num_iterations) +{ + setArg(5, sizeof(uint32_t), &num_iterations); + setFirst(1); + setLast(0); +} + + +void xmrig::ExecuteVmKernel::setLast(uint32_t last) +{ + setArg(7, sizeof(uint32_t), &last); +} diff --git a/src/backend/opencl/kernels/rx/ExecuteVmKernel.h b/src/backend/opencl/kernels/rx/ExecuteVmKernel.h new file mode 100644 index 000000000..4ab5813fe --- /dev/null +++ b/src/backend/opencl/kernels/rx/ExecuteVmKernel.h @@ -0,0 +1,51 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_EXECUTEVMKERNEL_H +#define XMRIG_EXECUTEVMKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class ExecuteVmKernel : public OclKernel +{ +public: + inline ExecuteVmKernel(cl_program program) : OclKernel(program, "execute_vm") {} + + void enqueue(cl_command_queue queue, size_t threads, size_t worksize); + void setArgs(cl_mem vm_states, cl_mem rounding, cl_mem scratchpads, cl_mem dataset_ptr, uint32_t batch_size); + void setFirst(uint32_t first); + void setIterations(uint32_t num_iterations); + void setLast(uint32_t last); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_EXECUTEVMKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/FillAesKernel.cpp b/src/backend/opencl/kernels/rx/FillAesKernel.cpp new file mode 100644 index 000000000..b196b406c --- /dev/null +++ b/src/backend/opencl/kernels/rx/FillAesKernel.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/FillAesKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::FillAesKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads * 4; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void fillAes1Rx4_scratchpad(__global void* state, __global void* out, uint batch_size, uint rx_version) +// __kernel void fillAes4Rx4_entropy(__global void* state, __global void* out, uint batch_size, uint rx_version) +void xmrig::FillAesKernel::setArgs(cl_mem state, cl_mem out, uint32_t batch_size, uint32_t rx_version) +{ + setArg(0, sizeof(cl_mem), &state); + setArg(1, sizeof(cl_mem), &out); + setArg(2, sizeof(uint32_t), &batch_size); + setArg(3, sizeof(uint32_t), &rx_version); +} diff --git a/src/backend/opencl/kernels/rx/FillAesKernel.h b/src/backend/opencl/kernels/rx/FillAesKernel.h new file mode 100644 index 000000000..59d7e59cb --- /dev/null +++ b/src/backend/opencl/kernels/rx/FillAesKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_FILLAESKERNEL_H +#define XMRIG_FILLAESKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class FillAesKernel : public OclKernel +{ +public: + inline FillAesKernel(cl_program program, const char *name) : OclKernel(program, name) {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem state, cl_mem out, uint32_t batch_size, uint32_t rx_version); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_FILLAESKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/FindSharesKernel.cpp b/src/backend/opencl/kernels/rx/FindSharesKernel.cpp new file mode 100644 index 000000000..583112ed8 --- /dev/null +++ b/src/backend/opencl/kernels/rx/FindSharesKernel.cpp @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/FindSharesKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::FindSharesKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void find_shares(__global const uint64_t* hashes, uint64_t target, uint32_t start_nonce, __global uint32_t* shares) +void xmrig::FindSharesKernel::setArgs(cl_mem hashes, cl_mem shares) +{ + setArg(0, sizeof(cl_mem), &hashes); + setArg(3, sizeof(cl_mem), &shares); +} + + +void xmrig::FindSharesKernel::setTarget(uint64_t target) +{ + setArg(1, sizeof(uint64_t), &target); +} + + +void xmrig::FindSharesKernel::setNonce(uint32_t nonce) +{ + setArg(2, sizeof(uint32_t), &nonce); +} diff --git a/src/backend/opencl/kernels/rx/FindSharesKernel.h b/src/backend/opencl/kernels/rx/FindSharesKernel.h new file mode 100644 index 000000000..b1fe1427a --- /dev/null +++ b/src/backend/opencl/kernels/rx/FindSharesKernel.h @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_FINDSHARESKERNEL_H +#define XMRIG_FINDSHARESKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class FindSharesKernel : public OclKernel +{ +public: + inline FindSharesKernel(cl_program program) : OclKernel(program, "find_shares") {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem hashes, cl_mem shares); + void setTarget(uint64_t target); + void setNonce(uint32_t nonce); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_FINDSHARESKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/HashAesKernel.cpp b/src/backend/opencl/kernels/rx/HashAesKernel.cpp new file mode 100644 index 000000000..3bdbc8bcd --- /dev/null +++ b/src/backend/opencl/kernels/rx/HashAesKernel.cpp @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/HashAesKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::HashAesKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads * 4; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void hashAes1Rx4(__global const void* input, __global void* hash, uint hashOffsetBytes, uint hashStrideBytes, uint batch_size) +void xmrig::HashAesKernel::setArgs(cl_mem input, cl_mem hash, uint32_t hashStrideBytes, uint32_t batch_size) +{ + const uint32_t hashOffsetBytes = 192; + + setArg(0, sizeof(cl_mem), &input); + setArg(1, sizeof(cl_mem), &hash); + setArg(2, sizeof(uint32_t), &hashOffsetBytes); + setArg(3, sizeof(uint32_t), &hashStrideBytes); + setArg(4, sizeof(uint32_t), &batch_size); +} diff --git a/src/backend/opencl/kernels/rx/HashAesKernel.h b/src/backend/opencl/kernels/rx/HashAesKernel.h new file mode 100644 index 000000000..410262394 --- /dev/null +++ b/src/backend/opencl/kernels/rx/HashAesKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_HASHAESKERNEL_H +#define XMRIG_HASHAESKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class HashAesKernel : public OclKernel +{ +public: + inline HashAesKernel(cl_program program) : OclKernel(program, "hashAes1Rx4") {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem input, cl_mem hash, uint32_t hashStrideBytes, uint32_t batch_size); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_HASHAESKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/InitVmKernel.cpp b/src/backend/opencl/kernels/rx/InitVmKernel.cpp new file mode 100644 index 000000000..f221995f9 --- /dev/null +++ b/src/backend/opencl/kernels/rx/InitVmKernel.cpp @@ -0,0 +1,47 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/InitVmKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::InitVmKernel::enqueue(cl_command_queue queue, size_t threads, uint32_t iteration) +{ + setArg(3, sizeof(uint32_t), &iteration); + + const size_t gthreads = threads * 8; + static const size_t lthreads = 32; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void init_vm(__global const void* entropy_data, __global void* vm_states, __global uint32_t* rounding, uint32_t iteration) +void xmrig::InitVmKernel::setArgs(cl_mem entropy_data, cl_mem vm_states, cl_mem rounding) +{ + setArg(0, sizeof(cl_mem), &entropy_data); + setArg(1, sizeof(cl_mem), &vm_states); + setArg(2, sizeof(cl_mem), &rounding); +} diff --git a/src/backend/opencl/kernels/rx/InitVmKernel.h b/src/backend/opencl/kernels/rx/InitVmKernel.h new file mode 100644 index 000000000..bba7cf431 --- /dev/null +++ b/src/backend/opencl/kernels/rx/InitVmKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_INITVMKERNEL_H +#define XMRIG_INITVMKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class InitVmKernel : public OclKernel +{ +public: + inline InitVmKernel(cl_program program) : OclKernel(program, "init_vm") {} + + void enqueue(cl_command_queue queue, size_t threads, uint32_t iteration); + void setArgs(cl_mem entropy_data, cl_mem vm_states, cl_mem rounding); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_INITVMKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/RxJitKernel.cpp b/src/backend/opencl/kernels/rx/RxJitKernel.cpp new file mode 100644 index 000000000..8a58aa0f6 --- /dev/null +++ b/src/backend/opencl/kernels/rx/RxJitKernel.cpp @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/RxJitKernel.h" +#include "backend/opencl/wrappers/OclLib.h" + + +void xmrig::RxJitKernel::enqueue(cl_command_queue queue, size_t threads, uint32_t iteration) +{ + setArg(6, sizeof(uint32_t), &iteration); + + const size_t gthreads = threads * 32; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +// __kernel void randomx_jit(__global ulong* entropy, __global ulong* registers, __global uint2* intermediate_programs, __global uint* programs, uint batch_size, __global uint32_t* rounding, uint32_t iteration) +void xmrig::RxJitKernel::setArgs(cl_mem entropy, cl_mem registers, cl_mem intermediate_programs, cl_mem programs, uint32_t batch_size, cl_mem rounding) +{ + setArg(0, sizeof(cl_mem), &entropy); + setArg(1, sizeof(cl_mem), ®isters); + setArg(2, sizeof(cl_mem), &intermediate_programs); + setArg(3, sizeof(cl_mem), &programs); + setArg(4, sizeof(uint32_t), &batch_size); + setArg(5, sizeof(cl_mem), &rounding); +} diff --git a/src/backend/opencl/kernels/rx/RxJitKernel.h b/src/backend/opencl/kernels/rx/RxJitKernel.h new file mode 100644 index 000000000..12464d870 --- /dev/null +++ b/src/backend/opencl/kernels/rx/RxJitKernel.h @@ -0,0 +1,48 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_RXJITKERNEL_H +#define XMRIG_RXJITKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class RxJitKernel : public OclKernel +{ +public: + inline RxJitKernel(cl_program program) : OclKernel(program, "randomx_jit") {} + + void enqueue(cl_command_queue queue, size_t threads, uint32_t iteration); + void setArgs(cl_mem entropy, cl_mem registers, cl_mem intermediate_programs, cl_mem programs, uint32_t batch_size, cl_mem rounding); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_RXJITKERNEL_H */ diff --git a/src/backend/opencl/kernels/rx/RxRunKernel.cpp b/src/backend/opencl/kernels/rx/RxRunKernel.cpp new file mode 100644 index 000000000..1946d7158 --- /dev/null +++ b/src/backend/opencl/kernels/rx/RxRunKernel.cpp @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/kernels/rx/RxRunKernel.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "crypto/common/Algorithm.h" +#include "crypto/randomx/randomx.h" +#include "crypto/rx/RxAlgo.h" + + +void xmrig::RxRunKernel::enqueue(cl_command_queue queue, size_t threads) +{ + const size_t gthreads = threads * 64; + static const size_t lthreads = 64; + + enqueueNDRange(queue, 1, nullptr, >hreads, <hreads); +} + + +void xmrig::RxRunKernel::setArgs(cl_mem dataset, cl_mem scratchpads, cl_mem registers, cl_mem rounding, cl_mem programs, uint32_t batch_size, const Algorithm &algorithm) +{ + setArg(0, sizeof(cl_mem), &dataset); + setArg(1, sizeof(cl_mem), &scratchpads); + setArg(2, sizeof(cl_mem), ®isters); + setArg(3, sizeof(cl_mem), &rounding); + setArg(4, sizeof(cl_mem), &programs); + setArg(5, sizeof(uint32_t), &batch_size); + + auto PowerOf2 = [](size_t N) + { + uint32_t result = 0; + while (N > 1) { + ++result; + N >>= 1; + } + + return result; + }; + + const auto *rx_conf = RxAlgo::base(algorithm); + const uint32_t rx_parameters = + (PowerOf2(rx_conf->ScratchpadL1_Size) << 0) | + (PowerOf2(rx_conf->ScratchpadL2_Size) << 5) | + (PowerOf2(rx_conf->ScratchpadL3_Size) << 10) | + (PowerOf2(rx_conf->ProgramIterations) << 15); + + setArg(6, sizeof(uint32_t), &rx_parameters); +} diff --git a/src/backend/opencl/kernels/rx/RxRunKernel.h b/src/backend/opencl/kernels/rx/RxRunKernel.h new file mode 100644 index 000000000..3af5a9807 --- /dev/null +++ b/src/backend/opencl/kernels/rx/RxRunKernel.h @@ -0,0 +1,51 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_RXRUNKERNEL_H +#define XMRIG_RXRUNKERNEL_H + + +#include "backend/opencl/wrappers/OclKernel.h" + + +namespace xmrig { + + +class Algorithm; + + +class RxRunKernel : public OclKernel +{ +public: + inline RxRunKernel(cl_program program) : OclKernel(program, "randomx_run") {} + + void enqueue(cl_command_queue queue, size_t threads); + void setArgs(cl_mem dataset, cl_mem scratchpads, cl_mem registers, cl_mem rounding, cl_mem programs, uint32_t batch_size, const Algorithm &algorithm); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_RXRUNKERNEL_H */ diff --git a/src/backend/opencl/opencl.cmake b/src/backend/opencl/opencl.cmake new file mode 100644 index 000000000..c5a6335fb --- /dev/null +++ b/src/backend/opencl/opencl.cmake @@ -0,0 +1,133 @@ +if (WITH_OPENCL) + add_definitions(/DCL_TARGET_OPENCL_VERSION=200) + add_definitions(/DCL_USE_DEPRECATED_OPENCL_1_2_APIS) + add_definitions(/DXMRIG_FEATURE_OPENCL) + + set(HEADERS_BACKEND_OPENCL + src/backend/opencl/cl/OclSource.h + src/backend/opencl/interfaces/IOclRunner.h + src/backend/opencl/kernels/Cn0Kernel.h + src/backend/opencl/kernels/Cn1Kernel.h + src/backend/opencl/kernels/Cn2Kernel.h + src/backend/opencl/kernels/CnBranchKernel.h + src/backend/opencl/OclBackend.h + src/backend/opencl/OclCache.h + src/backend/opencl/OclConfig.h + src/backend/opencl/OclGenerator.h + src/backend/opencl/OclInterleave.h + src/backend/opencl/OclLaunchData.h + src/backend/opencl/OclThread.h + src/backend/opencl/OclThreads.h + src/backend/opencl/OclWorker.h + src/backend/opencl/runners/OclBaseRunner.h + src/backend/opencl/runners/OclCnRunner.h + src/backend/opencl/runners/tools/OclCnR.h + src/backend/opencl/wrappers/OclContext.h + src/backend/opencl/wrappers/OclDevice.h + src/backend/opencl/wrappers/OclError.h + src/backend/opencl/wrappers/OclKernel.h + src/backend/opencl/wrappers/OclLib.h + src/backend/opencl/wrappers/OclPlatform.h + src/backend/opencl/wrappers/OclVendor.h + ) + + set(SOURCES_BACKEND_OPENCL + src/backend/opencl/cl/OclSource.cpp + src/backend/opencl/generators/ocl_generic_cn_generator.cpp + src/backend/opencl/generators/ocl_vega_cn_generator.cpp + src/backend/opencl/kernels/Cn0Kernel.cpp + src/backend/opencl/kernels/Cn1Kernel.cpp + src/backend/opencl/kernels/Cn2Kernel.cpp + src/backend/opencl/kernels/CnBranchKernel.cpp + src/backend/opencl/OclBackend.cpp + src/backend/opencl/OclCache.cpp + src/backend/opencl/OclConfig.cpp + src/backend/opencl/OclInterleave.cpp + src/backend/opencl/OclLaunchData.cpp + src/backend/opencl/OclThread.cpp + src/backend/opencl/OclThreads.cpp + src/backend/opencl/OclWorker.cpp + src/backend/opencl/runners/OclBaseRunner.cpp + src/backend/opencl/runners/OclCnRunner.cpp + src/backend/opencl/runners/tools/OclCnR.cpp + src/backend/opencl/wrappers/OclContext.cpp + src/backend/opencl/wrappers/OclDevice.cpp + src/backend/opencl/wrappers/OclError.cpp + src/backend/opencl/wrappers/OclKernel.cpp + src/backend/opencl/wrappers/OclLib.cpp + src/backend/opencl/wrappers/OclPlatform.cpp + ) + + if (WIN32) + list(APPEND SOURCES_BACKEND_OPENCL src/backend/opencl/OclCache_win.cpp) + else() + list(APPEND SOURCES_BACKEND_OPENCL src/backend/opencl/OclCache_unix.cpp) + endif() + + if (WITH_RANDOMX) + list(APPEND HEADERS_BACKEND_OPENCL + src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h + src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.h + src/backend/opencl/kernels/rx/ExecuteVmKernel.h + src/backend/opencl/kernels/rx/FillAesKernel.h + src/backend/opencl/kernels/rx/FindSharesKernel.h + src/backend/opencl/kernels/rx/HashAesKernel.cpp + src/backend/opencl/kernels/rx/InitVmKernel.h + src/backend/opencl/kernels/rx/RxJitKernel.h + src/backend/opencl/kernels/rx/RxRunKernel.h + src/backend/opencl/runners/OclRxBaseRunner.h + src/backend/opencl/runners/OclRxJitRunner.h + src/backend/opencl/runners/OclRxVmRunner.h + src/backend/opencl/runners/tools/OclRxDataset.h + ) + + list(APPEND SOURCES_BACKEND_OPENCL + src/backend/opencl/generators/ocl_generic_rx_generator.cpp + src/backend/opencl/kernels/rx/Blake2bHashRegistersKernel.cpp + src/backend/opencl/kernels/rx/Blake2bInitialHashKernel.cpp + src/backend/opencl/kernels/rx/ExecuteVmKernel.cpp + src/backend/opencl/kernels/rx/FillAesKernel.cpp + src/backend/opencl/kernels/rx/FindSharesKernel.cpp + src/backend/opencl/kernels/rx/HashAesKernel.cpp + src/backend/opencl/kernels/rx/InitVmKernel.cpp + src/backend/opencl/kernels/rx/RxJitKernel.cpp + src/backend/opencl/kernels/rx/RxRunKernel.cpp + src/backend/opencl/runners/OclRxBaseRunner.cpp + src/backend/opencl/runners/OclRxJitRunner.cpp + src/backend/opencl/runners/OclRxVmRunner.cpp + src/backend/opencl/runners/tools/OclRxDataset.cpp + ) + endif() + + if (WITH_CN_GPU AND CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND HEADERS_BACKEND_OPENCL + src/backend/opencl/kernels/Cn00RyoKernel.h + src/backend/opencl/kernels/Cn1RyoKernel.h + src/backend/opencl/kernels/Cn2RyoKernel.h + src/backend/opencl/runners/OclRyoRunner.h + ) + + list(APPEND SOURCES_BACKEND_OPENCL + src/backend/opencl/generators/ocl_generic_cn_gpu_generator.cpp + src/backend/opencl/kernels/Cn00RyoKernel.cpp + src/backend/opencl/kernels/Cn1RyoKernel.cpp + src/backend/opencl/kernels/Cn2RyoKernel.cpp + src/backend/opencl/runners/OclRyoRunner.cpp + ) + endif() + + if (WITH_STRICT_CACHE) + add_definitions(/DXMRIG_STRICT_OPENCL_CACHE) + else() + remove_definitions(/DXMRIG_STRICT_OPENCL_CACHE) + endif() + + if (WITH_INTERLEAVE_DEBUG_LOG) + add_definitions(/DXMRIG_INTERLEAVE_DEBUG) + endif() +else() + remove_definitions(/DXMRIG_FEATURE_OPENCL) + + set(HEADERS_BACKEND_OPENCL "") + set(SOURCES_BACKEND_OPENCL "") +endif() diff --git a/src/backend/opencl/runners/OclBaseRunner.cpp b/src/backend/opencl/runners/OclBaseRunner.cpp new file mode 100644 index 000000000..43cffab21 --- /dev/null +++ b/src/backend/opencl/runners/OclBaseRunner.cpp @@ -0,0 +1,152 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/cl/OclSource.h" +#include "backend/opencl/OclCache.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/runners/OclBaseRunner.h" +#include "backend/opencl/wrappers/OclError.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "crypto/common/VirtualMemory.h" + + +xmrig::OclBaseRunner::OclBaseRunner(size_t id, const OclLaunchData &data) : + m_algorithm(data.algorithm), + m_ctx(data.ctx), + m_source(OclSource::get(data.algorithm)), + m_data(data), + m_align(OclLib::getUint(data.device.id(), CL_DEVICE_MEM_BASE_ADDR_ALIGN)), + m_threadId(id) +{ + m_deviceKey = data.device.name(); + +# ifdef XMRIG_STRICT_OPENCL_CACHE + m_deviceKey += ":"; + m_deviceKey += data.platform.version(); + + m_deviceKey += ":"; + m_deviceKey += OclLib::getString(data.device.id(), CL_DRIVER_VERSION); +# endif + +# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) + m_deviceKey += ":64"; +# endif +} + + +xmrig::OclBaseRunner::~OclBaseRunner() +{ + OclLib::release(m_program); + OclLib::release(m_input); + OclLib::release(m_output); + OclLib::release(m_buffer); + OclLib::release(m_queue); +} + + +size_t xmrig::OclBaseRunner::bufferSize() const +{ + return align(Job::kMaxBlobSize) + align(sizeof(cl_uint) * 0x100); +} + + +uint32_t xmrig::OclBaseRunner::deviceIndex() const +{ + return data().thread.index(); +} + + +void xmrig::OclBaseRunner::build() +{ + m_program = OclCache::build(this); + + if (m_program == nullptr) { + throw std::runtime_error(OclError::toString(CL_INVALID_PROGRAM)); + } +} + + +void xmrig::OclBaseRunner::init() +{ + m_queue = OclLib::createCommandQueue(m_ctx, data().device.id()); + + constexpr size_t oneGiB = 1024 * 1024 * 1024; + size_t size = bufferSize(); + + if (size < oneGiB && data().device.freeMemSize() >= oneGiB) { + size = oneGiB; + } + + m_buffer = OclLib::createBuffer(m_ctx, CL_MEM_READ_WRITE, size); + m_input = createSubBuffer(CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY, Job::kMaxBlobSize); + m_output = createSubBuffer(CL_MEM_READ_WRITE, sizeof(cl_uint) * 0x100); +} + + +cl_mem xmrig::OclBaseRunner::createSubBuffer(cl_mem_flags flags, size_t size) +{ + auto mem = OclLib::createSubBuffer(m_buffer, flags, m_offset, size); + + m_offset += align(size); + + return mem; +} + + +size_t xmrig::OclBaseRunner::align(size_t size) const +{ + return VirtualMemory::align(size, m_align); +} + + +void xmrig::OclBaseRunner::enqueueReadBuffer(cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr) +{ + const cl_int ret = OclLib::enqueueReadBuffer(m_queue, buffer, blocking_read, offset, size, ptr, 0, nullptr, nullptr); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } +} + + +void xmrig::OclBaseRunner::enqueueWriteBuffer(cl_mem buffer, cl_bool blocking_write, size_t offset, size_t size, const void *ptr) +{ + const cl_int ret = OclLib::enqueueWriteBuffer(m_queue, buffer, blocking_write, offset, size, ptr, 0, nullptr, nullptr); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } +} + + +void xmrig::OclBaseRunner::finalize(uint32_t *hashOutput) +{ + enqueueReadBuffer(m_output, CL_TRUE, 0, sizeof(cl_uint) * 0x100, hashOutput); + + uint32_t &results = hashOutput[0xFF]; + if (results > 0xFF) { + results = 0xFF; + } +} diff --git a/src/backend/opencl/runners/OclBaseRunner.h b/src/backend/opencl/runners/OclBaseRunner.h new file mode 100644 index 000000000..a6ab05877 --- /dev/null +++ b/src/backend/opencl/runners/OclBaseRunner.h @@ -0,0 +1,92 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLBASERUNNER_H +#define XMRIG_OCLBASERUNNER_H + + +#include + + +#include "3rdparty/cl.h" +#include "backend/opencl/interfaces/IOclRunner.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { + + +class OclLaunchData; + + +class OclBaseRunner : public IOclRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclBaseRunner) + + OclBaseRunner(size_t id, const OclLaunchData &data); + ~OclBaseRunner() override; + +protected: + inline cl_context ctx() const override { return m_ctx; } + inline const Algorithm &algorithm() const override { return m_algorithm; } + inline const char *buildOptions() const override { return m_options.c_str(); } + inline const char *deviceKey() const override { return m_deviceKey.c_str(); } + inline const char *source() const override { return m_source; } + inline const OclLaunchData &data() const override { return m_data; } + inline size_t threadId() const override { return m_threadId; } + + size_t bufferSize() const override; + uint32_t deviceIndex() const override; + void build() override; + void init() override; + +protected: + cl_mem createSubBuffer(cl_mem_flags flags, size_t size); + size_t align(size_t size) const; + void enqueueReadBuffer(cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr); + void enqueueWriteBuffer(cl_mem buffer, cl_bool blocking_write, size_t offset, size_t size, const void *ptr); + void finalize(uint32_t *hashOutput); + + Algorithm m_algorithm; + cl_command_queue m_queue = nullptr; + cl_context m_ctx; + cl_mem m_buffer = nullptr; + cl_mem m_input = nullptr; + cl_mem m_output = nullptr; + cl_program m_program = nullptr; + const char *m_source; + const OclLaunchData &m_data; + const size_t m_align; + const size_t m_threadId; + size_t m_offset = 0; + std::string m_deviceKey; + std::string m_options; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLBASERUNNER_H diff --git a/src/backend/opencl/runners/OclCnRunner.cpp b/src/backend/opencl/runners/OclCnRunner.cpp new file mode 100644 index 000000000..65e9611f3 --- /dev/null +++ b/src/backend/opencl/runners/OclCnRunner.cpp @@ -0,0 +1,187 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/runners/OclCnRunner.h" + +#include "backend/opencl/kernels/Cn0Kernel.h" +#include "backend/opencl/kernels/Cn1Kernel.h" +#include "backend/opencl/kernels/Cn2Kernel.h" +#include "backend/opencl/kernels/CnBranchKernel.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/runners/tools/OclCnR.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "crypto/cn/CnAlgo.h" + + +xmrig::OclCnRunner::OclCnRunner(size_t index, const OclLaunchData &data) : OclBaseRunner(index, data) +{ + uint32_t stridedIndex = data.thread.stridedIndex(); + if (data.device.vendorId() == OCL_VENDOR_NVIDIA) { + stridedIndex = 0; + } + else if (stridedIndex == 1 && (m_algorithm.family() == Algorithm::CN_PICO || (m_algorithm.family() == Algorithm::CN && CnAlgo<>::base(m_algorithm) == Algorithm::CN_2))) { + stridedIndex = 2; + } + + m_options += " -DITERATIONS=" + std::to_string(CnAlgo<>::iterations(m_algorithm)) + "U"; + m_options += " -DMASK=" + std::to_string(CnAlgo<>::mask(m_algorithm)) + "U"; + m_options += " -DWORKSIZE=" + std::to_string(data.thread.worksize()) + "U"; + m_options += " -DSTRIDED_INDEX=" + std::to_string(stridedIndex) + "U"; + m_options += " -DMEM_CHUNK_EXPONENT=" + std::to_string(1u << data.thread.memChunk()) + "U"; + m_options += " -DMEMORY=" + std::to_string(m_algorithm.l3()) + "LU"; + m_options += " -DALGO=" + std::to_string(m_algorithm.id()); + m_options += " -DALGO_BASE=" + std::to_string(CnAlgo<>::base(m_algorithm)); + m_options += " -DALGO_FAMILY=" + std::to_string(m_algorithm.family()); + m_options += " -DCN_UNROLL=" + std::to_string(data.thread.unrollFactor()); +} + + +xmrig::OclCnRunner::~OclCnRunner() +{ + delete m_cn0; + delete m_cn1; + delete m_cn2; + + OclLib::release(m_scratchpads); + OclLib::release(m_states); + + for (size_t i = 0; i < BRANCH_MAX; ++i) { + delete m_branchKernels[i]; + OclLib::release(m_branches[i]); + } + + if (m_algorithm == Algorithm::CN_R) { + OclLib::release(m_cnr); + OclCnR::clear(); + } +} + + +size_t xmrig::OclCnRunner::bufferSize() const +{ + const size_t g_thd = data().thread.intensity(); + + return OclBaseRunner::bufferSize() + + align(m_algorithm.l3() * g_thd) + + align(200 * g_thd) + + (align(sizeof(cl_uint) * (g_thd + 2)) * BRANCH_MAX); +} + + +void xmrig::OclCnRunner::run(uint32_t nonce, uint32_t *hashOutput) +{ + static const cl_uint zero = 0; + + const size_t g_intensity = data().thread.intensity(); + const size_t w_size = data().thread.worksize(); + const size_t g_thd = ((g_intensity + w_size - 1u) / w_size) * w_size; + + assert(g_thd % w_size == 0); + + for (size_t i = 0; i < BRANCH_MAX; ++i) { + enqueueWriteBuffer(m_branches[i], CL_FALSE, sizeof(cl_uint) * g_intensity, sizeof(cl_uint), &zero); + } + + enqueueWriteBuffer(m_output, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(cl_uint), &zero); + + m_cn0->enqueue(m_queue, nonce, g_thd); + m_cn1->enqueue(m_queue, nonce, g_thd, w_size); + m_cn2->enqueue(m_queue, nonce, g_thd); + + for (auto kernel : m_branchKernels) { + kernel->enqueue(m_queue, nonce, g_thd, w_size); + } + + finalize(hashOutput); +} + + +void xmrig::OclCnRunner::set(const Job &job, uint8_t *blob) +{ + if (job.size() > (Job::kMaxBlobSize - 4)) { + throw std::length_error("job size too big"); + } + + blob[job.size()] = 0x01; + memset(blob + job.size() + 1, 0, Job::kMaxBlobSize - job.size() - 1); + + enqueueWriteBuffer(m_input, CL_TRUE, 0, Job::kMaxBlobSize, blob); + + if (m_algorithm == Algorithm::CN_R && m_height != job.height()) { + delete m_cn1; + + m_height = job.height(); + m_cnr = OclCnR::get(*this, m_height); + m_cn1 = new Cn1Kernel(m_cnr, m_height); + m_cn1->setArgs(m_input, m_scratchpads, m_states, data().thread.intensity()); + } + + for (auto kernel : m_branchKernels) { + kernel->setTarget(job.target()); + } +} + + +void xmrig::OclCnRunner::build() +{ + OclBaseRunner::build(); + + const uint32_t intensity = data().thread.intensity(); + + m_cn0 = new Cn0Kernel(m_program); + m_cn0->setArgs(m_input, m_scratchpads, m_states, intensity); + + m_cn2 = new Cn2Kernel(m_program); + m_cn2->setArgs(m_scratchpads, m_states, m_branches, intensity); + + if (m_algorithm != Algorithm::CN_R) { + m_cn1 = new Cn1Kernel(m_program); + m_cn1->setArgs(m_input, m_scratchpads, m_states, intensity); + } + + for (size_t i = 0; i < BRANCH_MAX; ++i) { + auto kernel = new CnBranchKernel(i, m_program); + kernel->setArgs(m_states, m_branches[i], m_output, intensity); + + m_branchKernels[i] = kernel; + } +} + + +void xmrig::OclCnRunner::init() +{ + OclBaseRunner::init(); + + const size_t g_thd = data().thread.intensity(); + + m_scratchpads = createSubBuffer(CL_MEM_READ_WRITE, m_algorithm.l3() * g_thd); + m_states = createSubBuffer(CL_MEM_READ_WRITE, 200 * g_thd); + + for (size_t i = 0; i < BRANCH_MAX; ++i) { + m_branches[i] = createSubBuffer(CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2)); + } +} diff --git a/src/backend/opencl/runners/OclCnRunner.h b/src/backend/opencl/runners/OclCnRunner.h new file mode 100644 index 000000000..bd20019fc --- /dev/null +++ b/src/backend/opencl/runners/OclCnRunner.h @@ -0,0 +1,82 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLCNRUNNER_H +#define XMRIG_OCLCNRUNNER_H + + +#include "backend/opencl/runners/OclBaseRunner.h" + + +namespace xmrig { + + +class Cn0Kernel; +class Cn1Kernel; +class Cn2Kernel; +class CnBranchKernel; + + +class OclCnRunner : public OclBaseRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclCnRunner) + + OclCnRunner(size_t index, const OclLaunchData &data); + ~OclCnRunner() override; + +protected: + size_t bufferSize() const override; + void run(uint32_t nonce, uint32_t *hashOutput) override; + void set(const Job &job, uint8_t *blob) override; + void build() override; + void init() override; + +private: + enum Branches : size_t { + BRANCH_BLAKE_256, + BRANCH_GROESTL_256, + BRANCH_JH_256, + BRANCH_SKEIN_512, + BRANCH_MAX + }; + + + cl_mem m_scratchpads = nullptr; + cl_mem m_states = nullptr; + cl_program m_cnr = nullptr; + Cn0Kernel *m_cn0 = nullptr; + Cn1Kernel *m_cn1 = nullptr; + Cn2Kernel *m_cn2 = nullptr; + uint64_t m_height = 0; + + std::vector m_branches = { nullptr, nullptr, nullptr, nullptr }; + std::vector m_branchKernels = { nullptr, nullptr, nullptr, nullptr }; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLCNRUNNER_H diff --git a/src/backend/opencl/runners/OclRxBaseRunner.cpp b/src/backend/opencl/runners/OclRxBaseRunner.cpp new file mode 100644 index 000000000..640803dae --- /dev/null +++ b/src/backend/opencl/runners/OclRxBaseRunner.cpp @@ -0,0 +1,187 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "backend/opencl/runners/OclRxBaseRunner.h" + +#include "backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h" +#include "backend/opencl/kernels/rx/Blake2bInitialHashKernel.h" +#include "backend/opencl/kernels/rx/FillAesKernel.h" +#include "backend/opencl/kernels/rx/FindSharesKernel.h" +#include "backend/opencl/kernels/rx/HashAesKernel.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/net/stratum/Job.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxDataset.h" + + +xmrig::OclRxBaseRunner::OclRxBaseRunner(size_t index, const OclLaunchData &data) : OclBaseRunner(index, data) +{ + switch (data.thread.worksize()) { + case 2: + case 4: + case 8: + case 16: + m_worksize = data.thread.worksize(); + break; + + default: + m_worksize = 8; + } + + if (data.device.type() == OclDevice::Vega_10 || data.device.type() == OclDevice::Vega_20) { + m_gcn_version = 14; + } + + m_options += " -DALGO=" + std::to_string(m_algorithm.id()); + m_options += " -DWORKERS_PER_HASH=" + std::to_string(m_worksize); + m_options += " -DGCN_VERSION=" + std::to_string(m_gcn_version); +} + + +xmrig::OclRxBaseRunner::~OclRxBaseRunner() +{ + delete m_fillAes1Rx4_scratchpad; + delete m_fillAes4Rx4_entropy; + delete m_hashAes1Rx4; + delete m_blake2b_initial_hash; + delete m_blake2b_hash_registers_32; + delete m_blake2b_hash_registers_64; + delete m_find_shares; + + OclLib::release(m_entropy); + OclLib::release(m_hashes); + OclLib::release(m_rounding); + OclLib::release(m_scratchpads); +} + + +void xmrig::OclRxBaseRunner::run(uint32_t nonce, uint32_t *hashOutput) +{ + static const uint32_t zero = 0; + + m_blake2b_initial_hash->setNonce(nonce); + m_find_shares->setNonce(nonce); + + enqueueWriteBuffer(m_output, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(uint32_t), &zero); + + const uint32_t g_intensity = data().thread.intensity(); + + m_blake2b_initial_hash->enqueue(m_queue, g_intensity); + m_fillAes1Rx4_scratchpad->enqueue(m_queue, g_intensity); + + const uint32_t programCount = RxAlgo::programCount(m_algorithm); + + for (uint32_t i = 0; i < programCount; ++i) { + m_fillAes4Rx4_entropy->enqueue(m_queue, g_intensity); + + execute(i); + + if (i == programCount - 1) { + m_hashAes1Rx4->enqueue(m_queue, g_intensity); + m_blake2b_hash_registers_32->enqueue(m_queue, g_intensity); + } + else { + m_blake2b_hash_registers_64->enqueue(m_queue, g_intensity); + } + } + + m_find_shares->enqueue(m_queue, g_intensity); + + finalize(hashOutput); + + OclLib::finish(m_queue); +} + + +void xmrig::OclRxBaseRunner::set(const Job &job, uint8_t *blob) +{ + if (!data().thread.isDatasetHost() && m_seed != job.seed()) { + m_seed = job.seed(); + + auto dataset = Rx::dataset(job, 0); + enqueueWriteBuffer(data().dataset->get(), CL_TRUE, 0, dataset->size(), dataset->raw()); + } + + if (job.size() < Job::kMaxBlobSize) { + memset(blob + job.size(), 0, Job::kMaxBlobSize - job.size()); + } + + enqueueWriteBuffer(m_input, CL_TRUE, 0, Job::kMaxBlobSize, blob); + + m_blake2b_initial_hash->setBlobSize(job.size()); + m_find_shares->setTarget(job.target()); +} + + +size_t xmrig::OclRxBaseRunner::bufferSize() const +{ + const size_t g_thd = data().thread.intensity(); + + return OclBaseRunner::bufferSize() + + align((m_algorithm.l3() + 64) * g_thd) + + align(64 * g_thd) + + align((128 + 2560) * g_thd) + + align(sizeof(uint32_t) * g_thd); +} + + +void xmrig::OclRxBaseRunner::build() +{ + OclBaseRunner::build(); + + const uint32_t batch_size = data().thread.intensity(); + const uint32_t rx_version = RxAlgo::version(m_algorithm); + + m_fillAes1Rx4_scratchpad = new FillAesKernel(m_program, "fillAes1Rx4_scratchpad"); + m_fillAes1Rx4_scratchpad->setArgs(m_hashes, m_scratchpads, batch_size, rx_version); + + m_fillAes4Rx4_entropy = new FillAesKernel(m_program, "fillAes4Rx4_entropy"); + m_fillAes4Rx4_entropy->setArgs(m_hashes, m_entropy, batch_size, rx_version); + + m_hashAes1Rx4 = new HashAesKernel(m_program); + + m_blake2b_initial_hash = new Blake2bInitialHashKernel(m_program); + m_blake2b_initial_hash->setArgs(m_hashes, m_input); + + m_blake2b_hash_registers_32 = new Blake2bHashRegistersKernel(m_program, "blake2b_hash_registers_32"); + m_blake2b_hash_registers_64 = new Blake2bHashRegistersKernel(m_program, "blake2b_hash_registers_64"); + + m_find_shares = new FindSharesKernel(m_program); + m_find_shares->setArgs(m_hashes, m_output); +} + + +void xmrig::OclRxBaseRunner::init() +{ + OclBaseRunner::init(); + + const size_t g_thd = data().thread.intensity(); + + m_scratchpads = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, (m_algorithm.l3() + 64) * g_thd); + m_hashes = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, 64 * g_thd); + m_entropy = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, (128 + 2560) * g_thd); + m_rounding = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, sizeof(uint32_t) * g_thd); +} diff --git a/src/backend/opencl/runners/OclRxBaseRunner.h b/src/backend/opencl/runners/OclRxBaseRunner.h new file mode 100644 index 000000000..48b0ff8e8 --- /dev/null +++ b/src/backend/opencl/runners/OclRxBaseRunner.h @@ -0,0 +1,81 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLRXBASERUNNER_H +#define XMRIG_OCLRXBASERUNNER_H + + +#include "backend/opencl/runners/OclBaseRunner.h" +#include "base/tools/Buffer.h" + + +namespace xmrig { + + +class Blake2bHashRegistersKernel; +class Blake2bInitialHashKernel; +class FillAesKernel; +class FindSharesKernel; +class HashAesKernel; + + +class OclRxBaseRunner : public OclBaseRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclRxBaseRunner) + + OclRxBaseRunner(size_t index, const OclLaunchData &data); + ~OclRxBaseRunner() override; + +protected: + size_t bufferSize() const override; + void build() override; + void init() override; + void run(uint32_t nonce, uint32_t *hashOutput) override; + void set(const Job &job, uint8_t *blob) override; + +protected: + virtual void execute(uint32_t iteration) = 0; + + Blake2bHashRegistersKernel *m_blake2b_hash_registers_32 = nullptr; + Blake2bHashRegistersKernel *m_blake2b_hash_registers_64 = nullptr; + Blake2bInitialHashKernel *m_blake2b_initial_hash = nullptr; + Buffer m_seed; + cl_mem m_entropy = nullptr; + cl_mem m_hashes = nullptr; + cl_mem m_rounding = nullptr; + cl_mem m_scratchpads = nullptr; + FillAesKernel *m_fillAes1Rx4_scratchpad = nullptr; + FillAesKernel *m_fillAes4Rx4_entropy = nullptr; + FindSharesKernel *m_find_shares = nullptr; + HashAesKernel *m_hashAes1Rx4 = nullptr; + uint32_t m_gcn_version = 12; + uint32_t m_worksize = 8; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLRXBASERUNNER_H diff --git a/src/backend/opencl/runners/OclRxJitRunner.cpp b/src/backend/opencl/runners/OclRxJitRunner.cpp new file mode 100644 index 000000000..0bf39437c --- /dev/null +++ b/src/backend/opencl/runners/OclRxJitRunner.cpp @@ -0,0 +1,149 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "backend/opencl/runners/OclRxJitRunner.h" + +#include "backend/opencl/cl/rx/randomx_run_gfx803.h" +#include "backend/opencl/cl/rx/randomx_run_gfx900.h" +#include "backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h" +#include "backend/opencl/kernels/rx/HashAesKernel.h" +#include "backend/opencl/kernels/rx/RxJitKernel.h" +#include "backend/opencl/kernels/rx/RxRunKernel.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "backend/opencl/wrappers/OclError.h" + + +xmrig::OclRxJitRunner::OclRxJitRunner(size_t index, const OclLaunchData &data) : OclRxBaseRunner(index, data) +{ +} + + +xmrig::OclRxJitRunner::~OclRxJitRunner() +{ + delete m_randomx_jit; + delete m_randomx_run; + + OclLib::release(m_asmProgram); + OclLib::release(m_intermediate_programs); + OclLib::release(m_programs); + OclLib::release(m_registers); +} + + +size_t xmrig::OclRxJitRunner::bufferSize() const +{ + const size_t g_thd = data().thread.intensity(); + + return OclRxBaseRunner::bufferSize() + align(256 * g_thd) + align(5120 * g_thd) + align(10048 * g_thd); +} + + +void xmrig::OclRxJitRunner::build() +{ + OclRxBaseRunner::build(); + + const uint32_t batch_size = data().thread.intensity(); + + m_hashAes1Rx4->setArgs(m_scratchpads, m_registers, 256, batch_size); + m_blake2b_hash_registers_32->setArgs(m_hashes, m_registers, 256); + m_blake2b_hash_registers_64->setArgs(m_hashes, m_registers, 256); + + m_randomx_jit = new RxJitKernel(m_program); + m_randomx_jit->setArgs(m_entropy, m_registers, m_intermediate_programs, m_programs, batch_size, m_rounding); + + if (!loadAsmProgram()) { + throw std::runtime_error(OclError::toString(CL_INVALID_PROGRAM)); + } + + m_randomx_run = new RxRunKernel(m_asmProgram); + m_randomx_run->setArgs(data().dataset->get(), m_scratchpads, m_registers, m_rounding, m_programs, batch_size, m_algorithm); +} + + +void xmrig::OclRxJitRunner::execute(uint32_t iteration) +{ + const uint32_t g_intensity = data().thread.intensity(); + + m_randomx_jit->enqueue(m_queue, g_intensity, iteration); + + OclLib::finish(m_queue); + + m_randomx_run->enqueue(m_queue, g_intensity); +} + + +void xmrig::OclRxJitRunner::init() +{ + OclRxBaseRunner::init(); + + const size_t g_thd = data().thread.intensity(); + + m_registers = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, 256 * g_thd); + m_intermediate_programs = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, 5120 * g_thd); + m_programs = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, 10048 * g_thd); +} + + +bool xmrig::OclRxJitRunner::loadAsmProgram() +{ + // Adrenaline drivers on Windows and amdgpu-pro drivers on Linux use ELF header's flags (offset 0x30) to store internal device ID + // Read it from compiled OpenCL code and substitute this ID into pre-compiled binary to make sure the driver accepts it + uint32_t elf_header_flags = 0; + const uint32_t elf_header_flags_offset = 0x30; + + size_t bin_size; + if (OclLib::getProgramInfo(m_program, CL_PROGRAM_BINARY_SIZES, sizeof(bin_size), &bin_size) != CL_SUCCESS) { + return false; + } + + std::vector binary_data(bin_size); + char* tmp[1] = { binary_data.data() }; + if (OclLib::getProgramInfo(m_program, CL_PROGRAM_BINARIES, sizeof(char*), tmp) != CL_SUCCESS) { + return false; + } + + if (bin_size >= elf_header_flags_offset + sizeof(uint32_t)) { + elf_header_flags = *reinterpret_cast((binary_data.data() + elf_header_flags_offset)); + } + + const size_t len = (m_gcn_version == 14) ? randomx_run_gfx900_bin_size : randomx_run_gfx803_bin_size; + unsigned char *binary = (m_gcn_version == 14) ? randomx_run_gfx900_bin : randomx_run_gfx803_bin; + + // Set correct internal device ID in the pre-compiled binary + if (elf_header_flags) { + *reinterpret_cast(binary + elf_header_flags_offset) = elf_header_flags; + } + + cl_int status; + cl_int ret; + cl_device_id device = data().device.id(); + + m_asmProgram = OclLib::createProgramWithBinary(ctx(), 1, &device, &len, (const unsigned char**) &binary, &status, &ret); + if (ret != CL_SUCCESS) { + return false; + } + + return OclLib::buildProgram(m_asmProgram, 1, &device) == CL_SUCCESS; +} diff --git a/src/backend/opencl/runners/OclRxJitRunner.h b/src/backend/opencl/runners/OclRxJitRunner.h new file mode 100644 index 000000000..db885bab4 --- /dev/null +++ b/src/backend/opencl/runners/OclRxJitRunner.h @@ -0,0 +1,68 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLRXJITRUNNER_H +#define XMRIG_OCLRXJITRUNNER_H + + +#include "backend/opencl/runners/OclRxBaseRunner.h" + + +namespace xmrig { + + +class RxJitKernel; +class RxRunKernel; + + +class OclRxJitRunner : public OclRxBaseRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclRxJitRunner) + + OclRxJitRunner(size_t index, const OclLaunchData &data); + ~OclRxJitRunner() override; + +protected: + size_t bufferSize() const override; + void build() override; + void execute(uint32_t iteration) override; + void init() override; + +private: + bool loadAsmProgram(); + + cl_mem m_intermediate_programs = nullptr; + cl_mem m_programs = nullptr; + cl_mem m_registers = nullptr; + cl_program m_asmProgram = nullptr; + RxJitKernel *m_randomx_jit = nullptr; + RxRunKernel *m_randomx_run = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLRXRUNNER_H diff --git a/src/backend/opencl/runners/OclRxVmRunner.cpp b/src/backend/opencl/runners/OclRxVmRunner.cpp new file mode 100644 index 000000000..57f5be3ca --- /dev/null +++ b/src/backend/opencl/runners/OclRxVmRunner.cpp @@ -0,0 +1,107 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "backend/opencl/runners/OclRxVmRunner.h" + +#include "backend/opencl/kernels/rx/Blake2bHashRegistersKernel.h" +#include "backend/opencl/kernels/rx/ExecuteVmKernel.h" +#include "backend/opencl/kernels/rx/HashAesKernel.h" +#include "backend/opencl/kernels/rx/InitVmKernel.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "crypto/rx/RxAlgo.h" + + +#include + + +xmrig::OclRxVmRunner::OclRxVmRunner(size_t index, const OclLaunchData &data) : OclRxBaseRunner(index, data) +{ +} + + +xmrig::OclRxVmRunner::~OclRxVmRunner() +{ + delete m_init_vm; + delete m_execute_vm; + + OclLib::release(m_vm_states); +} + + +size_t xmrig::OclRxVmRunner::bufferSize() const +{ + return OclRxBaseRunner::bufferSize() + (align(2560 * data().thread.intensity())); +} + + +void xmrig::OclRxVmRunner::build() +{ + OclRxBaseRunner::build(); + + const uint32_t batch_size = data().thread.intensity(); + const uint32_t hashStrideBytes = RxAlgo::programSize(m_algorithm) * 8; + + m_hashAes1Rx4->setArgs(m_scratchpads, m_vm_states, hashStrideBytes, batch_size); + m_blake2b_hash_registers_32->setArgs(m_hashes, m_vm_states, hashStrideBytes); + m_blake2b_hash_registers_64->setArgs(m_hashes, m_vm_states, hashStrideBytes); + + m_init_vm = new InitVmKernel(m_program); + m_init_vm->setArgs(m_entropy, m_vm_states, m_rounding); + + m_execute_vm = new ExecuteVmKernel(m_program); + m_execute_vm->setArgs(m_vm_states, m_rounding, m_scratchpads, data().dataset->get(), batch_size); +} + + +void xmrig::OclRxVmRunner::execute(uint32_t iteration) +{ + const uint32_t bfactor = std::min(data().thread.bfactor(), 8u); + const uint32_t num_iterations = RxAlgo::programIterations(m_algorithm) >> bfactor; + const uint32_t g_intensity = data().thread.intensity(); + + m_init_vm->enqueue(m_queue, g_intensity, iteration); + + m_execute_vm->setIterations(num_iterations); + + for (int j = 0, n = 1 << bfactor; j < n; ++j) { + if (j == n - 1) { + m_execute_vm->setLast(1); + } + + m_execute_vm->enqueue(m_queue, g_intensity, m_worksize); + + if (j == 0) { + m_execute_vm->setFirst(0); + } + } +} + + +void xmrig::OclRxVmRunner::init() +{ + OclRxBaseRunner::init(); + + m_vm_states = createSubBuffer(CL_MEM_READ_WRITE, 2560 * data().thread.intensity()); +} diff --git a/src/backend/opencl/runners/OclRxVmRunner.h b/src/backend/opencl/runners/OclRxVmRunner.h new file mode 100644 index 000000000..8d044e744 --- /dev/null +++ b/src/backend/opencl/runners/OclRxVmRunner.h @@ -0,0 +1,63 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLRXVMRUNNER_H +#define XMRIG_OCLRXVMRUNNER_H + + +#include "backend/opencl/runners/OclRxBaseRunner.h" + + +namespace xmrig { + + +class ExecuteVmKernel; +class InitVmKernel; + + +class OclRxVmRunner : public OclRxBaseRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclRxVmRunner) + + OclRxVmRunner(size_t index, const OclLaunchData &data); + ~OclRxVmRunner() override; + +protected: + size_t bufferSize() const override; + void build() override; + void execute(uint32_t iteration) override; + void init() override; + +private: + cl_mem m_vm_states = nullptr; + ExecuteVmKernel *m_execute_vm = nullptr; + InitVmKernel *m_init_vm = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLRXVMRUNNER_H diff --git a/src/backend/opencl/runners/OclRyoRunner.cpp b/src/backend/opencl/runners/OclRyoRunner.cpp new file mode 100644 index 000000000..47e9098d6 --- /dev/null +++ b/src/backend/opencl/runners/OclRyoRunner.cpp @@ -0,0 +1,136 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/runners/OclRyoRunner.h" + +#include "backend/opencl/kernels/Cn00RyoKernel.h" +#include "backend/opencl/kernels/Cn0Kernel.h" +#include "backend/opencl/kernels/Cn1RyoKernel.h" +#include "backend/opencl/kernels/Cn2RyoKernel.h" +#include "backend/opencl/kernels/CnBranchKernel.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/net/stratum/Job.h" +#include "crypto/cn/CnAlgo.h" + + +xmrig::OclRyoRunner::OclRyoRunner(size_t index, const OclLaunchData &data) : OclBaseRunner(index, data) +{ + m_options += " -DITERATIONS=" + std::to_string(CnAlgo<>::iterations(m_algorithm)) + "U"; + m_options += " -DMASK=" + std::to_string(CnAlgo<>::mask(m_algorithm)) + "U"; + m_options += " -DWORKSIZE=" + std::to_string(data.thread.worksize()) + "U"; + m_options += " -DMEMORY=" + std::to_string(m_algorithm.l3()) + "LU"; + m_options += " -DCN_UNROLL=" + std::to_string(data.thread.unrollFactor()); + + m_options += " -cl-fp32-correctly-rounded-divide-sqrt"; +} + + +xmrig::OclRyoRunner::~OclRyoRunner() +{ + delete m_cn00; + delete m_cn0; + delete m_cn1; + delete m_cn2; + + OclLib::release(m_scratchpads); + OclLib::release(m_states); +} + + +size_t xmrig::OclRyoRunner::bufferSize() const +{ + const size_t g_thd = data().thread.intensity(); + + return OclBaseRunner::bufferSize() + align(data().algorithm.l3() * g_thd) + align(200 * g_thd); +} + + +void xmrig::OclRyoRunner::run(uint32_t nonce, uint32_t *hashOutput) +{ + static const cl_uint zero = 0; + + const size_t g_intensity = data().thread.intensity(); + const size_t w_size = data().thread.worksize(); + const size_t g_thd = ((g_intensity + w_size - 1u) / w_size) * w_size; + + assert(g_thd % w_size == 0); + + enqueueWriteBuffer(m_output, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(cl_uint), &zero); + + m_cn0->enqueue(m_queue, nonce, g_thd); + m_cn00->enqueue(m_queue, g_thd); + m_cn1->enqueue(m_queue, g_thd, w_size); + m_cn2->enqueue(m_queue, nonce, g_thd); + + finalize(hashOutput); +} + + +void xmrig::OclRyoRunner::set(const Job &job, uint8_t *blob) +{ + if (job.size() > (Job::kMaxBlobSize - 4)) { + throw std::length_error("job size too big"); + } + + blob[job.size()] = 0x01; + memset(blob + job.size() + 1, 0, Job::kMaxBlobSize - job.size() - 1); + + enqueueWriteBuffer(m_input, CL_TRUE, 0, Job::kMaxBlobSize, blob); + + m_cn2->setTarget(job.target()); +} + + +void xmrig::OclRyoRunner::build() +{ + OclBaseRunner::build(); + + const uint32_t intensity = data().thread.intensity(); + + m_cn00 = new Cn00RyoKernel(m_program); + m_cn00->setArgs(m_scratchpads, m_states); + + m_cn0 = new Cn0Kernel(m_program); + m_cn0->setArgs(m_input, m_scratchpads, m_states, intensity); + + m_cn1 = new Cn1RyoKernel(m_program); + m_cn1->setArgs(m_scratchpads, m_states, intensity); + + m_cn2 = new Cn2RyoKernel(m_program); + m_cn2->setArgs(m_scratchpads, m_states, m_output, intensity); +} + + +void xmrig::OclRyoRunner::init() +{ + OclBaseRunner::init(); + + const size_t g_thd = data().thread.intensity(); + + m_scratchpads = createSubBuffer(CL_MEM_READ_WRITE, data().algorithm.l3() * g_thd); + m_states = createSubBuffer(CL_MEM_READ_WRITE, 200 * g_thd); +} diff --git a/src/backend/opencl/runners/OclRyoRunner.h b/src/backend/opencl/runners/OclRyoRunner.h new file mode 100644 index 000000000..fd9f41c31 --- /dev/null +++ b/src/backend/opencl/runners/OclRyoRunner.h @@ -0,0 +1,70 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLRYORUNNER_H +#define XMRIG_OCLRYORUNNER_H + + +#include "backend/opencl/runners/OclBaseRunner.h" + + +namespace xmrig { + + +class Cn00RyoKernel; +class Cn0Kernel; +class Cn1RyoKernel; +class Cn2RyoKernel; + + +class OclRyoRunner : public OclBaseRunner +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclRyoRunner) + + OclRyoRunner(size_t index, const OclLaunchData &data); + + ~OclRyoRunner() override; + +protected: + size_t bufferSize() const override; + void run(uint32_t nonce, uint32_t *hashOutput) override; + void set(const Job &job, uint8_t *blob) override; + void build() override; + void init() override; + +private: + cl_mem m_scratchpads = nullptr; + cl_mem m_states = nullptr; + Cn00RyoKernel *m_cn00 = nullptr; + Cn0Kernel *m_cn0 = nullptr; + Cn1RyoKernel *m_cn1 = nullptr; + Cn2RyoKernel *m_cn2 = nullptr; +}; + + +} /* namespace xmrig */ + + +#endif // XMRIG_OCLRYORUNNER_H diff --git a/src/backend/opencl/runners/tools/OclCnR.cpp b/src/backend/opencl/runners/tools/OclCnR.cpp new file mode 100644 index 000000000..ed415194f --- /dev/null +++ b/src/backend/opencl/runners/tools/OclCnR.cpp @@ -0,0 +1,307 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "backend/opencl/runners/tools/OclCnR.h" + +#include "backend/opencl/cl/cn/cryptonight_r_cl.h" +#include "backend/opencl/interfaces/IOclRunner.h" +#include "backend/opencl/OclCache.h" +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/OclThread.h" +#include "backend/opencl/wrappers/OclError.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "base/tools/Baton.h" +#include "base/tools/Chrono.h" +#include "crypto/cn/CryptoNight_monero.h" + + +#include +#include +#include +#include +#include +#include +#include + + +namespace xmrig { + + +class CnrCacheEntry +{ +public: + inline CnrCacheEntry(const Algorithm &algo, uint64_t offset, uint32_t index, cl_program program) : + program(program), + m_algo(algo), + m_index(index), + m_offset(offset) + {} + + inline bool isExpired(uint64_t offset) const { return m_offset + OclCnR::kHeightChunkSize < offset; } + inline bool match(const Algorithm &algo, uint64_t offset, uint32_t index) const { return m_algo == algo && m_offset == offset && m_index == index; } + inline bool match(const IOclRunner &runner, uint64_t offset) const { return match(runner.algorithm(), offset, runner.deviceIndex()); } + inline void release() { OclLib::release(program); } + + cl_program program; + +private: + const Algorithm m_algo; + const uint32_t m_index; + const uint64_t m_offset; +}; + + +class CnrCache +{ +public: + CnrCache() = default; + + inline cl_program search(const IOclRunner &runner, uint64_t offset) { return search(runner.algorithm(), offset, runner.deviceIndex()); } + + + inline cl_program search(const Algorithm &algo, uint64_t offset, uint32_t index) + { + std::lock_guard lock(m_mutex); + + for (const auto &entry : m_data) { + if (entry.match(algo, offset, index)) { + return entry.program; + } + } + + return nullptr; + } + + + void add(const Algorithm &algo, uint64_t offset, uint32_t index, cl_program program) + { + if (search(algo, offset, index)) { + OclLib::release(program); + + return; + } + + std::lock_guard lock(m_mutex); + + gc(offset); + m_data.emplace_back(algo, offset, index, program); + } + + + void clear() + { + std::lock_guard lock(m_mutex); + + for (auto &entry : m_data) { + entry.release(); + } + + m_data.clear(); + } + + +private: + void gc(uint64_t offset) + { + for (size_t i = 0; i < m_data.size();) { + const auto &entry = m_data[i]; + + if (entry.isExpired(offset)) { + m_data.back().release(); + m_data.pop_back(); + } + else { + ++i; + } + } + } + + + std::mutex m_mutex; + std::vector m_data; +}; + + +static CnrCache cache; + + +class CnrBuilder +{ +public: + CnrBuilder() = default; + + cl_program build(const IOclRunner &runner, uint64_t offset) + { + # ifdef APP_DEBUG + const uint64_t ts = Chrono::steadyMSecs(); + # endif + + std::lock_guard lock(m_mutex); + cl_program program = cache.search(runner, offset); + if (program) { + return program; + } + + cl_int ret; + const std::string source = getSource(offset); + cl_device_id device = runner.data().device.id(); + const char *s = source.c_str(); + + program = OclLib::createProgramWithSource(runner.ctx(), 1, &s, nullptr, &ret); + if (ret != CL_SUCCESS) { + return nullptr; + } + + if (OclLib::buildProgram(program, 1, &device, runner.buildOptions()) != CL_SUCCESS) { + printf("BUILD LOG:\n%s\n", OclLib::getProgramBuildLog(program, device).data()); + + OclLib::release(program); + return nullptr; + } + + LOG_DEBUG(GREEN_BOLD("[ocl]") " programs for heights %" PRIu64 " - %" PRIu64 " compiled. (%" PRIu64 "ms)", offset, offset + OclCnR::kHeightChunkSize - 1, Chrono::steadyMSecs() - ts); + + cache.add(runner.algorithm(), offset, runner.deviceIndex(), program); + + return program; + } + +private: + std::string getCode(const V4_Instruction *code, int code_size) const + { + std::stringstream s; + + for (int i = 0; i < code_size; ++i) { + const V4_Instruction inst = code[i]; + + const uint32_t a = inst.dst_index; + const uint32_t b = inst.src_index; + + switch (inst.opcode) + { + case MUL: + s << 'r' << a << "*=r" << b << ';'; + break; + + case ADD: + s << 'r' << a << "+=r" << b << '+' << inst.C << "U;"; + break; + + case SUB: + s << 'r' << a << "-=r" << b << ';'; + break; + + case ROR: + case ROL: + s << 'r' << a << "=rotate(r" << a << ((inst.opcode == ROR) ? ",ROT_BITS-r" : ",r") << b << ");"; + break; + + case XOR: + s << 'r' << a << "^=r" << b << ';'; + break; + } + + s << '\n'; + } + + return s.str(); + } + + + std::string getSource(uint64_t offset) const + { + std::string source(cryptonight_r_defines_cl); + + for (size_t i = 0; i < OclCnR::kHeightChunkSize; ++i) { + V4_Instruction code[256]; + const int code_size = v4_random_math_init(code, offset + i); + const std::string kernel = std::regex_replace(cryptonight_r_cl, std::regex("XMRIG_INCLUDE_RANDOM_MATH"), getCode(code, code_size)); + + source += std::regex_replace(kernel, std::regex("KERNEL_NAME"), "cn1_" + std::to_string(offset + i)); + } + + return source; + } + + + std::mutex m_mutex; +}; + + +class CnrBaton : public Baton +{ +public: + inline CnrBaton(const IOclRunner &runner, uint64_t offset) : + runner(runner), + offset(offset) + {} + + const IOclRunner &runner; + const uint64_t offset; +}; + + +static CnrBuilder builder; +static std::mutex bg_mutex; + + +} // namespace xmrig + + + +cl_program xmrig::OclCnR::get(const IOclRunner &runner, uint64_t height) +{ + const uint64_t offset = (height / kHeightChunkSize) * kHeightChunkSize; + + if (offset + kHeightChunkSize - height == 1) { + auto baton = new CnrBaton(runner, offset + kHeightChunkSize); + + uv_queue_work(uv_default_loop(), &baton->req, + [](uv_work_t *req) { + auto baton = static_cast(req->data); + + std::lock_guard lock(bg_mutex); + + builder.build(baton->runner, baton->offset); + }, + [](uv_work_t *req, int) { delete static_cast(req->data); } + ); + } + + cl_program program = cache.search(runner, offset); + if (program) { + return program; + } + + return builder.build(runner, offset);; +} + + +void xmrig::OclCnR::clear() +{ + std::lock_guard lock(bg_mutex); + + cache.clear(); +} diff --git a/src/backend/opencl/runners/tools/OclCnR.h b/src/backend/opencl/runners/tools/OclCnR.h new file mode 100644 index 000000000..d4b5bb064 --- /dev/null +++ b/src/backend/opencl/runners/tools/OclCnR.h @@ -0,0 +1,56 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLCNR_H +#define XMRIG_OCLCNR_H + + +#include +#include + + +using cl_program = struct _cl_program *; + + +namespace xmrig { + + +class Algorithm; +class IOclRunner; + + +class OclCnR +{ +public: + constexpr static size_t kHeightChunkSize = 10; + + static cl_program get(const IOclRunner &runner, uint64_t height); + static void clear(); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLCNR_H */ diff --git a/src/backend/opencl/runners/tools/OclRxDataset.cpp b/src/backend/opencl/runners/tools/OclRxDataset.cpp new file mode 100644 index 000000000..b1d83bd0b --- /dev/null +++ b/src/backend/opencl/runners/tools/OclRxDataset.cpp @@ -0,0 +1,54 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/runners/tools/OclRxDataset.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "crypto/rx/Rx.h" +#include "crypto/rx/RxDataset.h" + + +void xmrig::OclRxDataset::createBuffer(cl_context ctx, const Job &job, bool host) +{ + if (m_dataset) { + return; + } + + cl_int ret; + + if (host) { + auto dataset = Rx::dataset(job, 0); + + m_dataset = OclLib::createBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, RxDataset::maxSize(), dataset->raw(), &ret); + } + else { + m_dataset = OclLib::createBuffer(ctx, CL_MEM_READ_ONLY, RxDataset::maxSize(), nullptr, &ret); + } +} + + +xmrig::OclRxDataset::~OclRxDataset() +{ + OclLib::release(m_dataset); +} diff --git a/src/backend/opencl/runners/tools/OclRxDataset.h b/src/backend/opencl/runners/tools/OclRxDataset.h new file mode 100644 index 000000000..314a2f5d6 --- /dev/null +++ b/src/backend/opencl/runners/tools/OclRxDataset.h @@ -0,0 +1,68 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLRXDATASET_H +#define XMRIG_OCLRXDATASET_H + + +#include "base/tools/Object.h" + + +#include + + +using cl_context = struct _cl_context *; +using cl_mem = struct _cl_mem *; + + +namespace xmrig { + + +class Job; + + +class OclRxDataset +{ +public: + XMRIG_DISABLE_COPY_MOVE(OclRxDataset) + + OclRxDataset() = default; + ~OclRxDataset(); + + inline cl_mem get() const { return m_dataset; } + + void createBuffer(cl_context ctx,const Job &job, bool host); + +private: + cl_mem m_dataset = nullptr; +}; + + +using OclRxDatasetPtr = std::shared_ptr; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_OCLINTERLEAVE_H */ diff --git a/src/backend/opencl/wrappers/OclContext.cpp b/src/backend/opencl/wrappers/OclContext.cpp new file mode 100644 index 000000000..a25593350 --- /dev/null +++ b/src/backend/opencl/wrappers/OclContext.cpp @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/wrappers/OclContext.h" +#include "backend/opencl/wrappers/OclLib.h" + + +xmrig::OclContext::OclContext(const OclDevice &device) +{ + std::vector ids = { device.id() }; + m_ctx = OclLib::createContext(ids); +} + + +xmrig::OclContext::~OclContext() +{ + if (m_ctx) { + OclLib::release(m_ctx); + } +} + + +bool xmrig::OclContext::init(const std::vector &devices, std::vector &threads, const Job &job) +{ + if (!m_ctx) { + std::vector ids(devices.size()); + for (size_t i = 0; i < devices.size(); ++i) { + ids[i] = devices[i].id(); + } + + m_ctx = OclLib::createContext(ids); + } + + if (!m_ctx) { + return false; + } + + for (OclLaunchData &data : threads) { + data.ctx = m_ctx; + +# ifdef XMRIG_ALGO_RANDOMX + if (data.algorithm.family() == Algorithm::RANDOM_X) { + data.dataset->createBuffer(m_ctx, job, data.thread.isDatasetHost()); + } +# endif + } + + return true; +} diff --git a/src/backend/opencl/wrappers/OclContext.h b/src/backend/opencl/wrappers/OclContext.h new file mode 100644 index 000000000..8f2cc432c --- /dev/null +++ b/src/backend/opencl/wrappers/OclContext.h @@ -0,0 +1,65 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLCONTEXT_H +#define XMRIG_OCLCONTEXT_H + + +#include "backend/opencl/OclLaunchData.h" +#include "backend/opencl/wrappers/OclDevice.h" +#include "base/tools/Object.h" + + +using cl_context = struct _cl_context *; + + +namespace xmrig { + + +class Job; + + +class OclContext +{ +public: + XMRIG_DISABLE_COPY_MOVE(OclContext) + + OclContext() = default; + OclContext(const OclDevice &device); + ~OclContext(); + + bool init(const std::vector &devices, std::vector &threads, const Job &job); + + inline bool isValid() const { return m_ctx != nullptr; } + inline cl_context ctx() const { return m_ctx; } + +private: + cl_context m_ctx = nullptr; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLCONTEXT_H */ diff --git a/src/backend/opencl/wrappers/OclDevice.cpp b/src/backend/opencl/wrappers/OclDevice.cpp new file mode 100644 index 000000000..f63387173 --- /dev/null +++ b/src/backend/opencl/wrappers/OclDevice.cpp @@ -0,0 +1,207 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/wrappers/OclDevice.h" + +#include "backend/opencl/OclGenerator.h" +#include "backend/opencl/OclThreads.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" +#include "crypto/cn/CnAlgo.h" +#include "crypto/common/Algorithm.h" +#include "rapidjson/document.h" + + +#include + + +typedef union +{ + struct { cl_uint type; cl_uint data[5]; } raw; + struct { cl_uint type; cl_char unused[17]; cl_char bus; cl_char device; cl_char function; } pcie; +} topology_amd; + + +namespace xmrig { + + +#ifdef XMRIG_ALGO_RANDOMX +extern bool ocl_generic_rx_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); +#endif + +#ifdef XMRIG_ALGO_CN_GPU +extern bool ocl_generic_cn_gpu_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); +#endif + +extern bool ocl_vega_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); +extern bool ocl_generic_cn_generator(const OclDevice &device, const Algorithm &algorithm, OclThreads &threads); + + +ocl_gen_config_fun generators[] = { +# ifdef XMRIG_ALGO_RANDOMX + ocl_generic_rx_generator, +# endif +# ifdef XMRIG_ALGO_CN_GPU + ocl_generic_cn_gpu_generator, +# endif + ocl_vega_cn_generator, + ocl_generic_cn_generator +}; + + +static OclVendor getVendorId(const String &vendor) +{ + if (vendor.contains("Advanced Micro Devices") || vendor.contains("AMD")) { + return OCL_VENDOR_AMD; + } + + if (vendor.contains("NVIDIA")) { + return OCL_VENDOR_NVIDIA; + } + + if (vendor.contains("Intel")) { + return OCL_VENDOR_INTEL; + } + + return OCL_VENDOR_UNKNOWN; +} + + +static OclDevice::Type getType(const String &name) +{ + if (name == "gfx900" || name == "gfx901") { + return OclDevice::Vega_10; + } + + if (name == "gfx902" || name == "gfx903") { + return OclDevice::Raven; + } + + if (name == "gfx906" || name == "gfx907") { + return OclDevice::Vega_20; + } + + if (name == "gfx1010") { + return OclDevice::Navi_10; + } + + if (name == "gfx804") { + return OclDevice::Lexa; + } + + if (name == "Baffin") { + return OclDevice::Baffin; + } + + if (name == "gfx803" || name.contains("polaris") || name == "Ellesmere") { + return OclDevice::Polaris; + } + + return OclDevice::Unknown; +} + + +} // namespace xmrig + + +xmrig::OclDevice::OclDevice(uint32_t index, cl_device_id id, cl_platform_id platform) : + m_id(id), + m_platform(platform), + m_board(OclLib::getString(id, 0x4038 /* CL_DEVICE_BOARD_NAME_AMD */)), + m_name(OclLib::getString(id, CL_DEVICE_NAME)), + m_vendor(OclLib::getString(id, CL_DEVICE_VENDOR)), + m_computeUnits(OclLib::getUint(id, CL_DEVICE_MAX_COMPUTE_UNITS, 1)), + m_index(index) +{ + m_vendorId = getVendorId(m_vendor); + m_type = getType(m_name); + + if (m_vendorId == OCL_VENDOR_AMD) { + topology_amd topology; + + if (OclLib::getDeviceInfo(id, 0x4037 /* CL_DEVICE_TOPOLOGY_AMD */, sizeof(topology), &topology, nullptr) == CL_SUCCESS && topology.raw.type == 1) { + m_topology = true; + m_pciTopology = PciTopology(static_cast(topology.pcie.bus), static_cast(topology.pcie.device), static_cast(topology.pcie.function)); + } + } + else if (m_vendorId == OCL_VENDOR_NVIDIA) { + cl_uint bus = 0; + if (OclLib::getDeviceInfo(id, 0x4008 /* CL_DEVICE_PCI_BUS_ID_NV */, sizeof (bus), &bus, nullptr) == CL_SUCCESS) { + m_topology = true; + cl_uint slot = OclLib::getUint(id, 0x4009 /* CL_DEVICE_PCI_SLOT_ID_NV */); + m_pciTopology = PciTopology(bus, (slot >> 3) & 0xff, slot & 7); + } + } +} + + +size_t xmrig::OclDevice::freeMemSize() const +{ + return std::min(maxMemAllocSize(), globalMemSize()); +} + + +size_t xmrig::OclDevice::globalMemSize() const +{ + return OclLib::getUlong(id(), CL_DEVICE_GLOBAL_MEM_SIZE); +} + + +size_t xmrig::OclDevice::maxMemAllocSize() const +{ + return OclLib::getUlong(id(), CL_DEVICE_MAX_MEM_ALLOC_SIZE); +} + + +xmrig::String xmrig::OclDevice::printableName() const +{ + const size_t size = m_board.size() + m_name.size() + 64; + char *buf = new char[size](); + + if (m_board.isNull()) { + snprintf(buf, size, GREEN_BOLD("%s"), m_name.data()); + } + else { + snprintf(buf, size, GREEN_BOLD("%s") " (" CYAN_BOLD("%s") ")", m_board.data(), m_name.data()); + } + + return buf; +} + + +uint32_t xmrig::OclDevice::clock() const +{ + return OclLib::getUint(id(), CL_DEVICE_MAX_CLOCK_FREQUENCY); +} + + +void xmrig::OclDevice::generate(const Algorithm &algorithm, OclThreads &threads) const +{ + for (auto fn : generators) { + if (fn(*this, algorithm, threads)) { + return; + } + } +} diff --git a/src/backend/opencl/wrappers/OclDevice.h b/src/backend/opencl/wrappers/OclDevice.h new file mode 100644 index 000000000..517fa2bdb --- /dev/null +++ b/src/backend/opencl/wrappers/OclDevice.h @@ -0,0 +1,102 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLDEVICE_H +#define XMRIG_OCLDEVICE_H + + +#include + + +#include "backend/common/misc/PciTopology.h" +#include "backend/opencl/wrappers/OclVendor.h" +#include "base/tools/String.h" + + +using cl_device_id = struct _cl_device_id *; +using cl_platform_id = struct _cl_platform_id *; + + +namespace xmrig { + + +class Algorithm; +class OclThreads; + + +class OclDevice +{ +public: + enum Type { + Unknown, + Baffin, + Polaris, + Lexa, + Vega_10, + Vega_20, + Raven, + Navi_10 + }; + + OclDevice() = delete; + OclDevice(uint32_t index, cl_device_id id, cl_platform_id platform); + + size_t freeMemSize() const; + size_t globalMemSize() const; + size_t maxMemAllocSize() const; + String printableName() const; + uint32_t clock() const; + void generate(const Algorithm &algorithm, OclThreads &threads) const; + + inline bool hasTopology() const { return m_topology; } + inline bool isValid() const { return m_id != nullptr && m_platform != nullptr; } + inline cl_device_id id() const { return m_id; } + inline const PciTopology &topology() const { return m_pciTopology; } + inline const String &board() const { return m_board.isNull() ? m_name : m_board; } + inline const String &name() const { return m_name; } + inline const String &vendor() const { return m_vendor; } + inline OclVendor vendorId() const { return m_vendorId; } + inline Type type() const { return m_type; } + inline uint32_t computeUnits() const { return m_computeUnits; } + inline uint32_t index() const { return m_index; } + +private: + bool m_topology = false; + cl_device_id m_id = nullptr; + cl_platform_id m_platform = nullptr; + const String m_board; + const String m_name; + const String m_vendor; + const uint32_t m_computeUnits = 1; + const uint32_t m_index = 0; + OclVendor m_vendorId = OCL_VENDOR_UNKNOWN; + PciTopology m_pciTopology; + Type m_type = Unknown; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLDEVICE_H */ diff --git a/src/backend/opencl/wrappers/OclError.cpp b/src/backend/opencl/wrappers/OclError.cpp new file mode 100644 index 000000000..29e92b38f --- /dev/null +++ b/src/backend/opencl/wrappers/OclError.cpp @@ -0,0 +1,160 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/wrappers/OclError.h" + + +const char *xmrig::OclError::toString(cl_int ret) +{ + switch(ret) + { + case CL_SUCCESS: + return "CL_SUCCESS"; + case CL_DEVICE_NOT_FOUND: + return "CL_DEVICE_NOT_FOUND"; + case CL_DEVICE_NOT_AVAILABLE: + return "CL_DEVICE_NOT_AVAILABLE"; + case CL_COMPILER_NOT_AVAILABLE: + return "CL_COMPILER_NOT_AVAILABLE"; + case CL_MEM_OBJECT_ALLOCATION_FAILURE: + return "CL_MEM_OBJECT_ALLOCATION_FAILURE"; + case CL_OUT_OF_RESOURCES: + return "CL_OUT_OF_RESOURCES"; + case CL_OUT_OF_HOST_MEMORY: + return "CL_OUT_OF_HOST_MEMORY"; + case CL_PROFILING_INFO_NOT_AVAILABLE: + return "CL_PROFILING_INFO_NOT_AVAILABLE"; + case CL_MEM_COPY_OVERLAP: + return "CL_MEM_COPY_OVERLAP"; + case CL_IMAGE_FORMAT_MISMATCH: + return "CL_IMAGE_FORMAT_MISMATCH"; + case CL_IMAGE_FORMAT_NOT_SUPPORTED: + return "CL_IMAGE_FORMAT_NOT_SUPPORTED"; + case CL_BUILD_PROGRAM_FAILURE: + return "CL_BUILD_PROGRAM_FAILURE"; + case CL_MAP_FAILURE: + return "CL_MAP_FAILURE"; + case CL_MISALIGNED_SUB_BUFFER_OFFSET: + return "CL_MISALIGNED_SUB_BUFFER_OFFSET"; + case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST: + return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"; + case CL_COMPILE_PROGRAM_FAILURE: + return "CL_COMPILE_PROGRAM_FAILURE"; + case CL_LINKER_NOT_AVAILABLE: + return "CL_LINKER_NOT_AVAILABLE"; + case CL_LINK_PROGRAM_FAILURE: + return "CL_LINK_PROGRAM_FAILURE"; + case CL_DEVICE_PARTITION_FAILED: + return "CL_DEVICE_PARTITION_FAILED"; + case CL_KERNEL_ARG_INFO_NOT_AVAILABLE: + return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE"; + case CL_INVALID_VALUE: + return "CL_INVALID_VALUE"; + case CL_INVALID_DEVICE_TYPE: + return "CL_INVALID_DEVICE_TYPE"; + case CL_INVALID_PLATFORM: + return "CL_INVALID_PLATFORM"; + case CL_INVALID_DEVICE: + return "CL_INVALID_DEVICE"; + case CL_INVALID_CONTEXT: + return "CL_INVALID_CONTEXT"; + case CL_INVALID_QUEUE_PROPERTIES: + return "CL_INVALID_QUEUE_PROPERTIES"; + case CL_INVALID_COMMAND_QUEUE: + return "CL_INVALID_COMMAND_QUEUE"; + case CL_INVALID_HOST_PTR: + return "CL_INVALID_HOST_PTR"; + case CL_INVALID_MEM_OBJECT: + return "CL_INVALID_MEM_OBJECT"; + case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: + return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"; + case CL_INVALID_IMAGE_SIZE: + return "CL_INVALID_IMAGE_SIZE"; + case CL_INVALID_SAMPLER: + return "CL_INVALID_SAMPLER"; + case CL_INVALID_BINARY: + return "CL_INVALID_BINARY"; + case CL_INVALID_BUILD_OPTIONS: + return "CL_INVALID_BUILD_OPTIONS"; + case CL_INVALID_PROGRAM: + return "CL_INVALID_PROGRAM"; + case CL_INVALID_PROGRAM_EXECUTABLE: + return "CL_INVALID_PROGRAM_EXECUTABLE"; + case CL_INVALID_KERNEL_NAME: + return "CL_INVALID_KERNEL_NAME"; + case CL_INVALID_KERNEL_DEFINITION: + return "CL_INVALID_KERNEL_DEFINITION"; + case CL_INVALID_KERNEL: + return "CL_INVALID_KERNEL"; + case CL_INVALID_ARG_INDEX: + return "CL_INVALID_ARG_INDEX"; + case CL_INVALID_ARG_VALUE: + return "CL_INVALID_ARG_VALUE"; + case CL_INVALID_ARG_SIZE: + return "CL_INVALID_ARG_SIZE"; + case CL_INVALID_KERNEL_ARGS: + return "CL_INVALID_KERNEL_ARGS"; + case CL_INVALID_WORK_DIMENSION: + return "CL_INVALID_WORK_DIMENSION"; + case CL_INVALID_WORK_GROUP_SIZE: + return "CL_INVALID_WORK_GROUP_SIZE"; + case CL_INVALID_WORK_ITEM_SIZE: + return "CL_INVALID_WORK_ITEM_SIZE"; + case CL_INVALID_GLOBAL_OFFSET: + return "CL_INVALID_GLOBAL_OFFSET"; + case CL_INVALID_EVENT_WAIT_LIST: + return "CL_INVALID_EVENT_WAIT_LIST"; + case CL_INVALID_EVENT: + return "CL_INVALID_EVENT"; + case CL_INVALID_OPERATION: + return "CL_INVALID_OPERATION"; + case CL_INVALID_GL_OBJECT: + return "CL_INVALID_GL_OBJECT"; + case CL_INVALID_BUFFER_SIZE: + return "CL_INVALID_BUFFER_SIZE"; + case CL_INVALID_MIP_LEVEL: + return "CL_INVALID_MIP_LEVEL"; + case CL_INVALID_GLOBAL_WORK_SIZE: + return "CL_INVALID_GLOBAL_WORK_SIZE"; + case CL_INVALID_PROPERTY: + return "CL_INVALID_PROPERTY"; + case CL_INVALID_IMAGE_DESCRIPTOR: + return "CL_INVALID_IMAGE_DESCRIPTOR"; + case CL_INVALID_COMPILER_OPTIONS: + return "CL_INVALID_COMPILER_OPTIONS"; + case CL_INVALID_LINKER_OPTIONS: + return "CL_INVALID_LINKER_OPTIONS"; + case CL_INVALID_DEVICE_PARTITION_COUNT: + return "CL_INVALID_DEVICE_PARTITION_COUNT"; +#ifdef CL_VERSION_2_0 + case CL_INVALID_PIPE_SIZE: + return "CL_INVALID_PIPE_SIZE"; + case CL_INVALID_DEVICE_QUEUE: + return "CL_INVALID_DEVICE_QUEUE"; +#endif + default: + return "UNKNOWN_ERROR"; + } +} diff --git a/src/backend/opencl/wrappers/OclError.h b/src/backend/opencl/wrappers/OclError.h new file mode 100644 index 000000000..a9a30859e --- /dev/null +++ b/src/backend/opencl/wrappers/OclError.h @@ -0,0 +1,50 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLERROR_H +#define XMRIG_OCLERROR_H + + +#include "3rdparty/cl.h" + + +#define OCL_ERR_SUCCESS (0) +#define OCL_ERR_API (2) +#define OCL_ERR_BAD_PARAMS (1) + + +namespace xmrig { + + +class OclError +{ +public: + static const char *toString(cl_int ret); +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLERROR_H */ diff --git a/src/backend/opencl/wrappers/OclKernel.cpp b/src/backend/opencl/wrappers/OclKernel.cpp new file mode 100644 index 000000000..7de93c472 --- /dev/null +++ b/src/backend/opencl/wrappers/OclKernel.cpp @@ -0,0 +1,71 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/common/Tags.h" +#include "backend/opencl/wrappers/OclError.h" +#include "backend/opencl/wrappers/OclKernel.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" + + +#include + + +xmrig::OclKernel::OclKernel(cl_program program, const char *name) : + m_name(name) +{ + m_kernel = OclLib::createKernel(program, name); +} + + +xmrig::OclKernel::~OclKernel() +{ + OclLib::release(m_kernel); +} + + +void xmrig::OclKernel::enqueueNDRange(cl_command_queue queue, uint32_t work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size) +{ + const cl_int ret = OclLib::enqueueNDRangeKernel(queue, m_kernel, work_dim, global_work_offset, global_work_size, local_work_size, 0, nullptr, nullptr); + if (ret != CL_SUCCESS) { + LOG_ERR("%s" RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("clEnqueueNDRangeKernel") RED(" for kernel ") RED_BOLD("%s"), + ocl_tag(), OclError::toString(ret), name().data()); + + throw std::runtime_error(OclError::toString(ret)); + } +} + + +void xmrig::OclKernel::setArg(uint32_t index, size_t size, const void *value) +{ + const cl_int ret = OclLib::setKernelArg(m_kernel, index, size, value); + if (ret != CL_SUCCESS) { + LOG_ERR("%s" RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("clSetKernelArg") RED(" for kernel ") RED_BOLD("%s") + RED(" argument ") RED_BOLD("%u") RED(" size ") RED_BOLD("%zu"), + ocl_tag(), OclError::toString(ret), name().data(), index, size); + + throw std::runtime_error(OclError::toString(ret)); + } +} diff --git a/src/backend/opencl/wrappers/OclKernel.h b/src/backend/opencl/wrappers/OclKernel.h new file mode 100644 index 000000000..8664d1300 --- /dev/null +++ b/src/backend/opencl/wrappers/OclKernel.h @@ -0,0 +1,66 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLKERNEL_H +#define XMRIG_OCLKERNEL_H + + +#include "base/tools/Object.h" +#include "base/tools/String.h" + + +using cl_command_queue = struct _cl_command_queue *; +using cl_kernel = struct _cl_kernel *; +using cl_mem = struct _cl_mem *; +using cl_program = struct _cl_program *; + + +namespace xmrig { + + +class OclKernel +{ +public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(OclKernel) + + OclKernel(cl_program program, const char *name); + virtual ~OclKernel(); + + inline bool isValid() const { return m_kernel != nullptr; } + inline cl_kernel kernel() const { return m_kernel; } + inline const String &name() const { return m_name; } + + void enqueueNDRange(cl_command_queue queue, uint32_t work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size); + void setArg(uint32_t index, size_t size, const void *value); + +private: + cl_kernel m_kernel = nullptr; + const String m_name; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLKERNEL_H */ diff --git a/src/backend/opencl/wrappers/OclLib.cpp b/src/backend/opencl/wrappers/OclLib.cpp new file mode 100644 index 000000000..687c4c0ae --- /dev/null +++ b/src/backend/opencl/wrappers/OclLib.cpp @@ -0,0 +1,831 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include + + +#include "backend/common/Tags.h" +#include "backend/opencl/wrappers/OclError.h" +#include "backend/opencl/wrappers/OclLib.h" +#include "base/io/log/Log.h" + +#if defined(OCL_DEBUG_REFERENCE_COUNT) +# define LOG_REFS(x, ...) xmrig::Log::print(xmrig::Log::WARNING, x, ##__VA_ARGS__) +#else +# define LOG_REFS(x, ...) +#endif + + +static uv_lib_t oclLib; + +static const char *kErrorTemplate = MAGENTA_BG_BOLD(WHITE_BOLD_S " ocl ") RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("%s"); + +static const char *kBuildProgram = "clBuildProgram"; +static const char *kCreateBuffer = "clCreateBuffer"; +static const char *kCreateCommandQueue = "clCreateCommandQueue"; +static const char *kCreateCommandQueueWithProperties = "clCreateCommandQueueWithProperties"; +static const char *kCreateContext = "clCreateContext"; +static const char *kCreateKernel = "clCreateKernel"; +static const char *kCreateProgramWithBinary = "clCreateProgramWithBinary"; +static const char *kCreateProgramWithSource = "clCreateProgramWithSource"; +static const char *kCreateSubBuffer = "clCreateSubBuffer"; +static const char *kEnqueueNDRangeKernel = "clEnqueueNDRangeKernel"; +static const char *kEnqueueReadBuffer = "clEnqueueReadBuffer"; +static const char *kEnqueueWriteBuffer = "clEnqueueWriteBuffer"; +static const char *kFinish = "clFinish"; +static const char *kGetCommandQueueInfo = "clGetCommandQueueInfo"; +static const char *kGetContextInfo = "clGetContextInfo"; +static const char *kGetDeviceIDs = "clGetDeviceIDs"; +static const char *kGetDeviceInfo = "clGetDeviceInfo"; +static const char *kGetKernelInfo = "clGetKernelInfo"; +static const char *kGetMemObjectInfo = "clGetMemObjectInfo"; +static const char *kGetPlatformIDs = "clGetPlatformIDs"; +static const char *kGetPlatformInfo = "clGetPlatformInfo"; +static const char *kGetProgramBuildInfo = "clGetProgramBuildInfo"; +static const char *kGetProgramInfo = "clGetProgramInfo"; +static const char *kReleaseCommandQueue = "clReleaseCommandQueue"; +static const char *kReleaseContext = "clReleaseContext"; +static const char *kReleaseDevice = "clReleaseDevice"; +static const char *kReleaseKernel = "clReleaseKernel"; +static const char *kReleaseMemObject = "clReleaseMemObject"; +static const char *kReleaseProgram = "clReleaseProgram"; +static const char *kSetKernelArg = "clSetKernelArg"; +static const char *kSetMemObjectDestructorCallback = "clSetMemObjectDestructorCallback"; +static const char *kUnloadPlatformCompiler = "clUnloadPlatformCompiler"; + + +#if defined(CL_VERSION_2_0) +typedef cl_command_queue (CL_API_CALL *createCommandQueueWithProperties_t)(cl_context, cl_device_id, const cl_queue_properties *, cl_int *); +#endif + +typedef cl_command_queue (CL_API_CALL *createCommandQueue_t)(cl_context, cl_device_id, cl_command_queue_properties, cl_int *); +typedef cl_context (CL_API_CALL *createContext_t)(const cl_context_properties *, cl_uint, const cl_device_id *, void (CL_CALLBACK *pfn_notify)(const char *, const void *, size_t, void *), void *, cl_int *); +typedef cl_int (CL_API_CALL *buildProgram_t)(cl_program, cl_uint, const cl_device_id *, const char *, void (CL_CALLBACK *pfn_notify)(cl_program, void *), void *); +typedef cl_int (CL_API_CALL *enqueueNDRangeKernel_t)(cl_command_queue, cl_kernel, cl_uint, const size_t *, const size_t *, const size_t *, cl_uint, const cl_event *, cl_event *); +typedef cl_int (CL_API_CALL *enqueueReadBuffer_t)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void *, cl_uint, const cl_event *, cl_event *); +typedef cl_int (CL_API_CALL *enqueueWriteBuffer_t)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void *, cl_uint, const cl_event *, cl_event *); +typedef cl_int (CL_API_CALL *finish_t)(cl_command_queue); +typedef cl_int (CL_API_CALL *getCommandQueueInfo_t)(cl_command_queue, cl_command_queue_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getContextInfo_t)(cl_context, cl_context_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getDeviceIDs_t)(cl_platform_id, cl_device_type, cl_uint, cl_device_id *, cl_uint *); +typedef cl_int (CL_API_CALL *getDeviceInfo_t)(cl_device_id, cl_device_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getKernelInfo_t)(cl_kernel, cl_kernel_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getMemObjectInfo_t)(cl_mem, cl_mem_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getPlatformIDs_t)(cl_uint, cl_platform_id *, cl_uint *); +typedef cl_int (CL_API_CALL *getPlatformInfo_t)(cl_platform_id, cl_platform_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getProgramBuildInfo_t)(cl_program, cl_device_id, cl_program_build_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *getProgramInfo_t)(cl_program, cl_program_info, size_t, void *, size_t *); +typedef cl_int (CL_API_CALL *releaseCommandQueue_t)(cl_command_queue); +typedef cl_int (CL_API_CALL *releaseContext_t)(cl_context); +typedef cl_int (CL_API_CALL *releaseDevice_t)(cl_device_id device); +typedef cl_int (CL_API_CALL *releaseKernel_t)(cl_kernel); +typedef cl_int (CL_API_CALL *releaseMemObject_t)(cl_mem); +typedef cl_int (CL_API_CALL *releaseProgram_t)(cl_program); +typedef cl_int (CL_API_CALL *setKernelArg_t)(cl_kernel, cl_uint, size_t, const void *); +typedef cl_int (CL_API_CALL *setMemObjectDestructorCallback_t)(cl_mem, void (CL_CALLBACK *)(cl_mem, void *), void *); +typedef cl_int (CL_API_CALL *unloadPlatformCompiler_t)(cl_platform_id); +typedef cl_kernel (CL_API_CALL *createKernel_t)(cl_program, const char *, cl_int *); +typedef cl_mem (CL_API_CALL *createBuffer_t)(cl_context, cl_mem_flags, size_t, void *, cl_int *); +typedef cl_mem (CL_API_CALL *createSubBuffer_t)(cl_mem, cl_mem_flags, cl_buffer_create_type, const void *, cl_int *); +typedef cl_program (CL_API_CALL *createProgramWithBinary_t)(cl_context, cl_uint, const cl_device_id *, const size_t *, const unsigned char **, cl_int *, cl_int *); +typedef cl_program (CL_API_CALL *createProgramWithSource_t)(cl_context, cl_uint, const char **, const size_t *, cl_int *); + +#if defined(CL_VERSION_2_0) +static createCommandQueueWithProperties_t pCreateCommandQueueWithProperties = nullptr; +#endif + +static buildProgram_t pBuildProgram = nullptr; +static createBuffer_t pCreateBuffer = nullptr; +static createCommandQueue_t pCreateCommandQueue = nullptr; +static createContext_t pCreateContext = nullptr; +static createKernel_t pCreateKernel = nullptr; +static createProgramWithBinary_t pCreateProgramWithBinary = nullptr; +static createProgramWithSource_t pCreateProgramWithSource = nullptr; +static createSubBuffer_t pCreateSubBuffer = nullptr; +static enqueueNDRangeKernel_t pEnqueueNDRangeKernel = nullptr; +static enqueueReadBuffer_t pEnqueueReadBuffer = nullptr; +static enqueueWriteBuffer_t pEnqueueWriteBuffer = nullptr; +static finish_t pFinish = nullptr; +static getCommandQueueInfo_t pGetCommandQueueInfo = nullptr; +static getContextInfo_t pGetContextInfo = nullptr; +static getDeviceIDs_t pGetDeviceIDs = nullptr; +static getDeviceInfo_t pGetDeviceInfo = nullptr; +static getKernelInfo_t pGetKernelInfo = nullptr; +static getMemObjectInfo_t pGetMemObjectInfo = nullptr; +static getPlatformIDs_t pGetPlatformIDs = nullptr; +static getPlatformInfo_t pGetPlatformInfo = nullptr; +static getProgramBuildInfo_t pGetProgramBuildInfo = nullptr; +static getProgramInfo_t pGetProgramInfo = nullptr; +static releaseCommandQueue_t pReleaseCommandQueue = nullptr; +static releaseContext_t pReleaseContext = nullptr; +static releaseDevice_t pReleaseDevice = nullptr; +static releaseKernel_t pReleaseKernel = nullptr; +static releaseMemObject_t pReleaseMemObject = nullptr; +static releaseProgram_t pReleaseProgram = nullptr; +static setKernelArg_t pSetKernelArg = nullptr; +static setMemObjectDestructorCallback_t pSetMemObjectDestructorCallback = nullptr; +static unloadPlatformCompiler_t pUnloadPlatformCompiler = nullptr; + +#define DLSYM(x) if (uv_dlsym(&oclLib, k##x, reinterpret_cast(&p##x)) == -1) { return false; } + + +namespace xmrig { + +bool OclLib::m_initialized = false; +bool OclLib::m_ready = false; +String OclLib::m_loader; + + +template +static String getOclString(FUNC fn, OBJ obj, PARAM param) +{ + size_t size = 0; + if (fn(obj, param, 0, nullptr, &size) != CL_SUCCESS) { + return String(); + } + + char *buf = new char[size](); + fn(obj, param, size, buf, nullptr); + + return String(buf); +} + + +} // namespace xmrig + + +bool xmrig::OclLib::init(const char *fileName) +{ + if (!m_initialized) { + m_loader = fileName == nullptr ? defaultLoader() : fileName; + m_ready = uv_dlopen(m_loader, &oclLib) == 0 && load(); + m_initialized = true; + } + + return m_ready; +} + + +const char *xmrig::OclLib::lastError() +{ + return uv_dlerror(&oclLib); +} + + +void xmrig::OclLib::close() +{ + uv_dlclose(&oclLib); +} + + +bool xmrig::OclLib::load() +{ + DLSYM(CreateCommandQueue); + DLSYM(CreateContext); + DLSYM(BuildProgram); + DLSYM(EnqueueNDRangeKernel); + DLSYM(EnqueueReadBuffer); + DLSYM(EnqueueWriteBuffer); + DLSYM(Finish); + DLSYM(GetDeviceIDs); + DLSYM(GetDeviceInfo); + DLSYM(GetPlatformInfo); + DLSYM(GetPlatformIDs); + DLSYM(GetProgramBuildInfo); + DLSYM(GetProgramInfo); + DLSYM(SetKernelArg); + DLSYM(CreateKernel); + DLSYM(CreateBuffer); + DLSYM(CreateProgramWithBinary); + DLSYM(CreateProgramWithSource); + DLSYM(ReleaseMemObject); + DLSYM(ReleaseProgram); + DLSYM(ReleaseKernel); + DLSYM(ReleaseCommandQueue); + DLSYM(ReleaseContext); + DLSYM(GetKernelInfo); + DLSYM(GetCommandQueueInfo); + DLSYM(GetMemObjectInfo); + DLSYM(GetContextInfo); + DLSYM(ReleaseDevice); + DLSYM(UnloadPlatformCompiler); + DLSYM(SetMemObjectDestructorCallback); + DLSYM(CreateSubBuffer); + +# if defined(CL_VERSION_2_0) + uv_dlsym(&oclLib, kCreateCommandQueueWithProperties, reinterpret_cast(&pCreateCommandQueueWithProperties)); +# endif + + return true; +} + + +const char *xmrig::OclLib::defaultLoader() +{ +# if defined(__APPLE__) + return "/System/Library/Frameworks/OpenCL.framework/OpenCL"; +# elif defined(_WIN32) + return "OpenCL.dll"; +# else + return "libOpenCL.so"; +# endif +} + + +cl_command_queue xmrig::OclLib::createCommandQueue(cl_context context, cl_device_id device, cl_int *errcode_ret) noexcept +{ + cl_command_queue result; + +# if defined(CL_VERSION_2_0) + if (pCreateCommandQueueWithProperties) { + const cl_queue_properties commandQueueProperties[] = { 0, 0, 0 }; + result = pCreateCommandQueueWithProperties(context, device, commandQueueProperties, errcode_ret); + } + else { +# endif + const cl_command_queue_properties commandQueueProperties = { 0 }; + result = pCreateCommandQueue(context, device, commandQueueProperties, errcode_ret); +# if defined(CL_VERSION_2_0) + } +# endif + + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(*errcode_ret), kCreateCommandQueueWithProperties); + + return nullptr; + } + + return result; +} + + +cl_command_queue xmrig::OclLib::createCommandQueue(cl_context context, cl_device_id device) +{ + cl_int ret; + cl_command_queue queue = createCommandQueue(context, device, &ret); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } + + return queue; +} + + +cl_context xmrig::OclLib::createContext(const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK *pfn_notify)(const char *, const void *, size_t, void *), void *user_data, cl_int *errcode_ret) +{ + assert(pCreateContext != nullptr); + + auto result = pCreateContext(properties, num_devices, devices, pfn_notify, user_data, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(*errcode_ret), kCreateContext); + + return nullptr; + } + + return result; +} + + +cl_context xmrig::OclLib::createContext(const std::vector &ids) +{ + cl_int ret; + return createContext(nullptr, static_cast(ids.size()), ids.data(), nullptr, nullptr, &ret); +} + + +cl_int xmrig::OclLib::buildProgram(cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void (CL_CALLBACK *pfn_notify)(cl_program program, void *user_data), void *user_data) noexcept +{ + assert(pBuildProgram != nullptr); + + const cl_int ret = pBuildProgram(program, num_devices, device_list, options, pfn_notify, user_data); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kBuildProgram); + } + + return ret; +} + + +cl_int xmrig::OclLib::enqueueNDRangeKernel(cl_command_queue command_queue, cl_kernel kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept +{ + assert(pEnqueueNDRangeKernel != nullptr); + + return pEnqueueNDRangeKernel(command_queue, kernel, work_dim, global_work_offset, global_work_size, local_work_size, num_events_in_wait_list, event_wait_list, event); +} + + +cl_int xmrig::OclLib::enqueueReadBuffer(cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept +{ + assert(pEnqueueReadBuffer != nullptr); + + const cl_int ret = pEnqueueReadBuffer(command_queue, buffer, blocking_read, offset, size, ptr, num_events_in_wait_list, event_wait_list, event); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kEnqueueReadBuffer); + } + + return ret; +} + + +cl_int xmrig::OclLib::enqueueWriteBuffer(cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_write, size_t offset, size_t size, const void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept +{ + assert(pEnqueueWriteBuffer != nullptr); + + const cl_int ret = pEnqueueWriteBuffer(command_queue, buffer, blocking_write, offset, size, ptr, num_events_in_wait_list, event_wait_list, event); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kEnqueueWriteBuffer); + } + + return ret; +} + + +cl_int xmrig::OclLib::finish(cl_command_queue command_queue) noexcept +{ + assert(pFinish != nullptr); + + return pFinish(command_queue); +} + + +cl_int xmrig::OclLib::getCommandQueueInfo(cl_command_queue command_queue, cl_command_queue_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + return pGetCommandQueueInfo(command_queue, param_name, param_value_size, param_value, param_value_size_ret); +} + + +cl_int xmrig::OclLib::getContextInfo(cl_context context, cl_context_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + return pGetContextInfo(context, param_name, param_value_size, param_value, param_value_size_ret); +} + + +cl_int xmrig::OclLib::getDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices) noexcept +{ + assert(pGetDeviceIDs != nullptr); + + return pGetDeviceIDs(platform, device_type, num_entries, devices, num_devices); +} + + +cl_int xmrig::OclLib::getDeviceInfo(cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + assert(pGetDeviceInfo != nullptr); + + const cl_int ret = pGetDeviceInfo(device, param_name, param_value_size, param_value, param_value_size_ret); + if (ret != CL_SUCCESS && param_name != 0x4038) { + LOG_ERR("Error %s when calling %s, param 0x%04x", OclError::toString(ret), kGetDeviceInfo, param_name); + } + + return ret; +} + + +cl_int xmrig::OclLib::getKernelInfo(cl_kernel kernel, cl_kernel_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + return pGetKernelInfo(kernel, param_name, param_value_size, param_value, param_value_size_ret); +} + + +cl_int xmrig::OclLib::getMemObjectInfo(cl_mem memobj, cl_mem_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + return pGetMemObjectInfo(memobj, param_name, param_value_size, param_value, param_value_size_ret); +} + + +cl_int xmrig::OclLib::getPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms) +{ + assert(pGetPlatformIDs != nullptr); + + return pGetPlatformIDs(num_entries, platforms, num_platforms); +} + + +cl_int xmrig::OclLib::getPlatformInfo(cl_platform_id platform, cl_platform_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + assert(pGetPlatformInfo != nullptr); + + return pGetPlatformInfo(platform, param_name, param_value_size, param_value, param_value_size_ret); +} + + +cl_int xmrig::OclLib::getProgramBuildInfo(cl_program program, cl_device_id device, cl_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept +{ + assert(pGetProgramBuildInfo != nullptr); + + const cl_int ret = pGetProgramBuildInfo(program, device, param_name, param_value_size, param_value, param_value_size_ret); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kGetProgramBuildInfo); + } + + return ret; +} + + +cl_int xmrig::OclLib::getProgramInfo(cl_program program, cl_program_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) +{ + assert(pGetProgramInfo != nullptr); + + const cl_int ret = pGetProgramInfo(program, param_name, param_value_size, param_value, param_value_size_ret); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kGetProgramInfo); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_command_queue command_queue) noexcept +{ + assert(pReleaseCommandQueue != nullptr); + assert(pGetCommandQueueInfo != nullptr); + + if (command_queue == nullptr) { + return CL_SUCCESS; + } + + LOG_REFS("%p %u ~queue", command_queue, getUint(command_queue, CL_QUEUE_REFERENCE_COUNT)); + + finish(command_queue); + + cl_int ret = pReleaseCommandQueue(command_queue); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseCommandQueue); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_context context) noexcept +{ + assert(pReleaseContext != nullptr); + + LOG_REFS("%p %u ~context", context, getUint(context, CL_CONTEXT_REFERENCE_COUNT)); + + const cl_int ret = pReleaseContext(context); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseContext); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_device_id id) noexcept +{ + assert(pReleaseDevice != nullptr); + + LOG_REFS("%p %u ~device", id, getUint(id, CL_DEVICE_REFERENCE_COUNT)); + + const cl_int ret = pReleaseDevice(id); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseDevice); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_kernel kernel) noexcept +{ + assert(pReleaseKernel != nullptr); + + if (kernel == nullptr) { + return CL_SUCCESS; + } + + LOG_REFS("%p %u ~kernel %s", kernel, getUint(kernel, CL_KERNEL_REFERENCE_COUNT), getString(kernel, CL_KERNEL_FUNCTION_NAME).data()); + + const cl_int ret = pReleaseKernel(kernel); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseKernel); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_mem mem_obj) noexcept +{ + assert(pReleaseMemObject != nullptr); + + if (mem_obj == nullptr) { + return CL_SUCCESS; + } + + LOG_REFS("%p %u ~mem %zub", mem_obj, getUint(mem_obj, CL_MEM_REFERENCE_COUNT), getUlong(mem_obj, CL_MEM_SIZE)); + + const cl_int ret = pReleaseMemObject(mem_obj); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseMemObject); + } + + return ret; +} + + +cl_int xmrig::OclLib::release(cl_program program) noexcept +{ + assert(pReleaseProgram != nullptr); + + if (program == nullptr) { + return CL_SUCCESS; + } + + LOG_REFS("%p %u ~program %s", program, getUint(program, CL_PROGRAM_REFERENCE_COUNT), getString(program, CL_PROGRAM_KERNEL_NAMES).data()); + + const cl_int ret = pReleaseProgram(program); + if (ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(ret), kReleaseProgram); + } + + return ret; +} + + +cl_int xmrig::OclLib::setKernelArg(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) noexcept +{ + assert(pSetKernelArg != nullptr); + + return pSetKernelArg(kernel, arg_index, arg_size, arg_value); +} + + +cl_int xmrig::OclLib::unloadPlatformCompiler(cl_platform_id platform) noexcept +{ + return pUnloadPlatformCompiler(platform); +} + + +cl_kernel xmrig::OclLib::createKernel(cl_program program, const char *kernel_name, cl_int *errcode_ret) noexcept +{ + assert(pCreateKernel != nullptr); + + auto result = pCreateKernel(program, kernel_name, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR("%s" RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("clCreateKernel") RED(" for kernel ") RED_BOLD("%s"), + ocl_tag(), OclError::toString(*errcode_ret), kernel_name); + + return nullptr; + } + + return result; +} + + +cl_kernel xmrig::OclLib::createKernel(cl_program program, const char *kernel_name) +{ + cl_int ret; + cl_kernel kernel = createKernel(program, kernel_name, &ret); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } + + return kernel; +} + + +cl_mem xmrig::OclLib::createBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr) +{ + cl_int ret; + cl_mem mem = createBuffer(context, flags, size, host_ptr, &ret); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } + + return mem; +} + + +cl_mem xmrig::OclLib::createBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) noexcept +{ + assert(pCreateBuffer != nullptr); + + auto result = pCreateBuffer(context, flags, size, host_ptr, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR("%s" RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("%s") RED(" with buffer size ") RED_BOLD("%zu"), + ocl_tag(), OclError::toString(*errcode_ret), kCreateBuffer, size); + + return nullptr; + } + + return result; +} + + +cl_mem xmrig::OclLib::createSubBuffer(cl_mem buffer, cl_mem_flags flags, size_t offset, size_t size, cl_int *errcode_ret) noexcept +{ + const cl_buffer_region region = { offset, size }; + + auto result = pCreateSubBuffer(buffer, flags, CL_BUFFER_CREATE_TYPE_REGION, ®ion, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR("%s" RED(" error ") RED_BOLD("%s") RED(" when calling ") RED_BOLD("%s") RED(" with offset ") RED_BOLD("%zu") RED(" and size ") RED_BOLD("%zu"), + ocl_tag(), OclError::toString(*errcode_ret), kCreateSubBuffer, offset, size); + + return nullptr; + } + + return result; +} + + +cl_mem xmrig::OclLib::createSubBuffer(cl_mem buffer, cl_mem_flags flags, size_t offset, size_t size) +{ + cl_int ret; + cl_mem mem = createSubBuffer(buffer, flags, offset, size, &ret); + if (ret != CL_SUCCESS) { + throw std::runtime_error(OclError::toString(ret)); + } + + return mem; +} + + +cl_program xmrig::OclLib::createProgramWithBinary(cl_context context, cl_uint num_devices, const cl_device_id *device_list, const size_t *lengths, const unsigned char **binaries, cl_int *binary_status, cl_int *errcode_ret) noexcept +{ + assert(pCreateProgramWithBinary != nullptr); + + auto result = pCreateProgramWithBinary(context, num_devices, device_list, lengths, binaries, binary_status, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(*errcode_ret), kCreateProgramWithBinary); + + return nullptr; + } + + return result; +} + + +cl_program xmrig::OclLib::createProgramWithSource(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) noexcept +{ + assert(pCreateProgramWithSource != nullptr); + + auto result = pCreateProgramWithSource(context, count, strings, lengths, errcode_ret); + if (*errcode_ret != CL_SUCCESS) { + LOG_ERR(kErrorTemplate, OclError::toString(*errcode_ret), kCreateProgramWithSource); + + return nullptr; + } + + return result; +} + + +cl_uint xmrig::OclLib::getNumPlatforms() noexcept +{ + cl_uint count = 0; + cl_int ret; + + if ((ret = OclLib::getPlatformIDs(0, nullptr, &count)) != CL_SUCCESS) { + LOG_ERR("Error %s when calling clGetPlatformIDs for number of platforms.", OclError::toString(ret)); + } + + if (count == 0) { + LOG_ERR("No OpenCL platform found."); + } + + return count; +} + + +cl_uint xmrig::OclLib::getUint(cl_command_queue command_queue, cl_command_queue_info param_name, cl_uint defaultValue) noexcept +{ + getCommandQueueInfo(command_queue, param_name, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_uint xmrig::OclLib::getUint(cl_context context, cl_context_info param_name, cl_uint defaultValue) noexcept +{ + getContextInfo(context, param_name, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_uint xmrig::OclLib::getUint(cl_device_id id, cl_device_info param, cl_uint defaultValue) noexcept +{ + getDeviceInfo(id, param, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_uint xmrig::OclLib::getUint(cl_kernel kernel, cl_kernel_info param_name, cl_uint defaultValue) noexcept +{ + getKernelInfo(kernel, param_name, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_uint xmrig::OclLib::getUint(cl_mem memobj, cl_mem_info param_name, cl_uint defaultValue) noexcept +{ + getMemObjectInfo(memobj, param_name, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_uint xmrig::OclLib::getUint(cl_program program, cl_program_info param, cl_uint defaultValue) noexcept +{ + getProgramInfo(program, param, sizeof(cl_uint), &defaultValue); + + return defaultValue; +} + + +cl_ulong xmrig::OclLib::getUlong(cl_device_id id, cl_device_info param, cl_ulong defaultValue) noexcept +{ + getDeviceInfo(id, param, sizeof(cl_ulong), &defaultValue); + + return defaultValue; +} + + +cl_ulong xmrig::OclLib::getUlong(cl_mem memobj, cl_mem_info param_name, cl_ulong defaultValue) noexcept +{ + getMemObjectInfo(memobj, param_name, sizeof(cl_ulong), &defaultValue); + + return defaultValue; +} + + +std::vector xmrig::OclLib::getPlatformIDs() noexcept +{ + const uint32_t count = getNumPlatforms(); + std::vector platforms(count); + + if (count) { + getPlatformIDs(count, platforms.data(), nullptr); + } + + return platforms; +} + + +xmrig::String xmrig::OclLib::getProgramBuildLog(cl_program program, cl_device_id device) noexcept +{ + size_t size = 0; + if (getProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &size) != CL_SUCCESS) { + return String(); + } + + char *log = new char[size + 1](); + + if (getProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, size, log, nullptr) != CL_SUCCESS) { + delete [] log; + return String(); + } + + return log; +} + + +xmrig::String xmrig::OclLib::getString(cl_device_id id, cl_device_info param) noexcept +{ + return getOclString(OclLib::getDeviceInfo, id, param); +} + + +xmrig::String xmrig::OclLib::getString(cl_kernel kernel, cl_kernel_info param_name) noexcept +{ + return getOclString(OclLib::getKernelInfo, kernel, param_name); +} + + +xmrig::String xmrig::OclLib::getString(cl_platform_id platform, cl_platform_info param_name) noexcept +{ + return getOclString(OclLib::getPlatformInfo, platform, param_name); +} + + +xmrig::String xmrig::OclLib::getString(cl_program program, cl_program_info param_name) noexcept +{ + return getOclString(OclLib::getProgramInfo, program, param_name); +} diff --git a/src/backend/opencl/wrappers/OclLib.h b/src/backend/opencl/wrappers/OclLib.h new file mode 100644 index 000000000..893e2a25b --- /dev/null +++ b/src/backend/opencl/wrappers/OclLib.h @@ -0,0 +1,114 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLLIB_H +#define XMRIG_OCLLIB_H + + +#include + + +#include "3rdparty/cl.h" +#include "base/tools/String.h" + + +namespace xmrig { + + +class OclLib +{ +public: + static bool init(const char *fileName = nullptr); + static const char *lastError(); + static void close(); + + static inline bool isInitialized() { return m_initialized; } + static inline const String &loader() { return m_loader; } + + static cl_command_queue createCommandQueue(cl_context context, cl_device_id device, cl_int *errcode_ret) noexcept; + static cl_command_queue createCommandQueue(cl_context context, cl_device_id device); + static cl_context createContext(const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK *pfn_notify)(const char *, const void *, size_t, void *), void *user_data, cl_int *errcode_ret); + static cl_context createContext(const std::vector &ids); + static cl_int buildProgram(cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options = nullptr, void (CL_CALLBACK *pfn_notify)(cl_program program, void *user_data) = nullptr, void *user_data = nullptr) noexcept; + static cl_int enqueueNDRangeKernel(cl_command_queue command_queue, cl_kernel kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept; + static cl_int enqueueReadBuffer(cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept; + static cl_int enqueueWriteBuffer(cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_write, size_t offset, size_t size, const void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) noexcept; + static cl_int finish(cl_command_queue command_queue) noexcept; + static cl_int getCommandQueueInfo(cl_command_queue command_queue, cl_command_queue_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr) noexcept; + static cl_int getContextInfo(cl_context context, cl_context_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr) noexcept; + static cl_int getDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices) noexcept; + static cl_int getDeviceInfo(cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr) noexcept; + static cl_int getKernelInfo(cl_kernel kernel, cl_kernel_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr) noexcept; + static cl_int getMemObjectInfo(cl_mem memobj, cl_mem_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr) noexcept; + static cl_int getPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms); + static cl_int getPlatformInfo(cl_platform_id platform, cl_platform_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept; + static cl_int getProgramBuildInfo(cl_program program, cl_device_id device, cl_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) noexcept; + static cl_int getProgramInfo(cl_program program, cl_program_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret = nullptr); + static cl_int release(cl_command_queue command_queue) noexcept; + static cl_int release(cl_context context) noexcept; + static cl_int release(cl_device_id id) noexcept; + static cl_int release(cl_kernel kernel) noexcept; + static cl_int release(cl_mem mem_obj) noexcept; + static cl_int release(cl_program program) noexcept; + static cl_int setKernelArg(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) noexcept; + static cl_int unloadPlatformCompiler(cl_platform_id platform) noexcept; + static cl_kernel createKernel(cl_program program, const char *kernel_name, cl_int *errcode_ret) noexcept; + static cl_kernel createKernel(cl_program program, const char *kernel_name); + static cl_mem createBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr = nullptr); + static cl_mem createBuffer(cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) noexcept; + static cl_mem createSubBuffer(cl_mem buffer, cl_mem_flags flags, size_t offset, size_t size, cl_int *errcode_ret) noexcept; + static cl_mem createSubBuffer(cl_mem buffer, cl_mem_flags flags, size_t offset, size_t size); + static cl_program createProgramWithBinary(cl_context context, cl_uint num_devices, const cl_device_id *device_list, const size_t *lengths, const unsigned char **binaries, cl_int *binary_status, cl_int *errcode_ret) noexcept; + static cl_program createProgramWithSource(cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) noexcept; + static cl_uint getNumPlatforms() noexcept; + static cl_uint getUint(cl_command_queue command_queue, cl_command_queue_info param_name, cl_uint defaultValue = 0) noexcept; + static cl_uint getUint(cl_context context, cl_context_info param_name, cl_uint defaultValue = 0) noexcept; + static cl_uint getUint(cl_device_id id, cl_device_info param, cl_uint defaultValue = 0) noexcept; + static cl_uint getUint(cl_kernel kernel, cl_kernel_info param_name, cl_uint defaultValue = 0) noexcept; + static cl_uint getUint(cl_mem memobj, cl_mem_info param_name, cl_uint defaultValue = 0) noexcept; + static cl_uint getUint(cl_program program, cl_program_info param, cl_uint defaultValue = 0) noexcept; + static cl_ulong getUlong(cl_device_id id, cl_device_info param, cl_ulong defaultValue = 0) noexcept; + static cl_ulong getUlong(cl_mem memobj, cl_mem_info param_name, cl_ulong defaultValue = 0) noexcept; + static std::vector getPlatformIDs() noexcept; + static String getProgramBuildLog(cl_program program, cl_device_id device) noexcept; + static String getString(cl_device_id id, cl_device_info param) noexcept; + static String getString(cl_kernel kernel, cl_kernel_info param_name) noexcept; + static String getString(cl_platform_id platform, cl_platform_info param_name) noexcept; + static String getString(cl_program program, cl_program_info param_name) noexcept; + + +private: + static bool load(); + static const char *defaultLoader(); + + static bool m_initialized; + static bool m_ready; + static String m_loader; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLLIB_H */ diff --git a/src/backend/opencl/wrappers/OclPlatform.cpp b/src/backend/opencl/wrappers/OclPlatform.cpp new file mode 100644 index 000000000..987ec5e30 --- /dev/null +++ b/src/backend/opencl/wrappers/OclPlatform.cpp @@ -0,0 +1,139 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "backend/opencl/wrappers/OclLib.h" +#include "backend/opencl/wrappers/OclPlatform.h" +#include "rapidjson/document.h" + + +std::vector xmrig::OclPlatform::get() +{ + const std::vector platforms = OclLib::getPlatformIDs(); + std::vector out; + if (platforms.empty()) { + return out; + } + + out.reserve(platforms.size()); + + for (size_t i = 0; i < platforms.size(); i++) { + out.emplace_back(i, platforms[i]); + } + + return out; +} + + +void xmrig::OclPlatform::print() +{ + const auto platforms = OclPlatform::get(); + + printf("%-28s%zu\n\n", "Number of platforms:", platforms.size()); + + for (const auto &platform : platforms) { + printf(" %-26s%zu\n", "Index:", platform.index()); + printf(" %-26s%s\n", "Profile:", platform.profile().data()); + printf(" %-26s%s\n", "Version:", platform.version().data()); + printf(" %-26s%s\n", "Name:", platform.name().data()); + printf(" %-26s%s\n", "Vendor:", platform.vendor().data()); + printf(" %-26s%s\n\n", "Extensions:", platform.extensions().data()); + } +} + + +rapidjson::Value xmrig::OclPlatform::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + auto &allocator = doc.GetAllocator(); + + if (!isValid()) { + return Value(kNullType); + } + + Value out(kObjectType); + out.AddMember("index", index(), allocator); + out.AddMember("profile", profile().toJSON(doc), allocator); + out.AddMember("version", version().toJSON(doc), allocator); + out.AddMember("name", name().toJSON(doc), allocator); + out.AddMember("vendor", vendor().toJSON(doc), allocator); + out.AddMember("extensions", extensions().toJSON(doc), allocator); + + return out; +} + + +std::vector xmrig::OclPlatform::devices() const +{ + std::vector out; + if (!isValid()) { + return out; + } + + cl_uint num_devices = 0; + OclLib::getDeviceIDs(id(), CL_DEVICE_TYPE_GPU, 0, nullptr, &num_devices); + if (num_devices == 0) { + return out; + } + + out.reserve(num_devices); + std::vector devices(num_devices); + OclLib::getDeviceIDs(id(), CL_DEVICE_TYPE_GPU, num_devices, devices.data(), nullptr); + + for (size_t i = 0; i < devices.size(); ++i) { + out.emplace_back(i, devices[i], id()); + } + + return out; +} + + +xmrig::String xmrig::OclPlatform::extensions() const +{ + return OclLib::getString(id(), CL_PLATFORM_EXTENSIONS); +} + + +xmrig::String xmrig::OclPlatform::name() const +{ + return OclLib::getString(id(), CL_PLATFORM_NAME); +} + + +xmrig::String xmrig::OclPlatform::profile() const +{ + return OclLib::getString(id(), CL_PLATFORM_PROFILE); +} + + +xmrig::String xmrig::OclPlatform::vendor() const +{ + return OclLib::getString(id(), CL_PLATFORM_VENDOR); +} + + +xmrig::String xmrig::OclPlatform::version() const +{ + return OclLib::getString(id(), CL_PLATFORM_VERSION); +} diff --git a/src/backend/opencl/wrappers/OclPlatform.h b/src/backend/opencl/wrappers/OclPlatform.h new file mode 100644 index 000000000..133e84755 --- /dev/null +++ b/src/backend/opencl/wrappers/OclPlatform.h @@ -0,0 +1,72 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLPLATFORM_H +#define XMRIG_OCLPLATFORM_H + + +#include + + +#include "backend/opencl/wrappers/OclDevice.h" +#include "base/tools/String.h" + + +using cl_platform_id = struct _cl_platform_id *; + + +namespace xmrig { + + +class OclPlatform +{ +public: + OclPlatform() = default; + OclPlatform(size_t index, cl_platform_id id) : m_id(id), m_index(index) {} + + static std::vector get(); + static void print(); + + inline bool isValid() const { return m_id != nullptr; } + inline cl_platform_id id() const { return m_id; } + inline size_t index() const { return m_index; } + + rapidjson::Value toJSON(rapidjson::Document &doc) const; + std::vector devices() const; + String extensions() const; + String name() const; + String profile() const; + String vendor() const; + String version() const; + +private: + cl_platform_id m_id = nullptr; + size_t m_index = 0; +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLPLATFORM_H */ diff --git a/src/backend/opencl/wrappers/OclVendor.h b/src/backend/opencl/wrappers/OclVendor.h new file mode 100644 index 000000000..def59b77b --- /dev/null +++ b/src/backend/opencl/wrappers/OclVendor.h @@ -0,0 +1,43 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OCLVENDOR_H +#define XMRIG_OCLVENDOR_H + + +namespace xmrig { + + +enum OclVendor : unsigned { + OCL_VENDOR_UNKNOWN, + OCL_VENDOR_AMD, + OCL_VENDOR_NVIDIA, + OCL_VENDOR_INTEL +}; + + +} // namespace xmrig + + +#endif /* XMRIG_OCLVENDOR_H */ diff --git a/src/base/api/Api.cpp b/src/base/api/Api.cpp index f358ac4b4..b52e6976d 100644 --- a/src/base/api/Api.cpp +++ b/src/base/api/Api.cpp @@ -139,6 +139,9 @@ void xmrig::Api::exec(IApiRequest &request) # endif # ifdef XMRIG_FEATURE_TLS features.PushBack("tls", allocator); +# endif +# ifdef XMRIG_FEATURE_OPENCL + features.PushBack("opencl", allocator); # endif request.reply().AddMember("features", features, allocator); } diff --git a/src/base/io/log/Log.cpp b/src/base/io/log/Log.cpp index 4e3bd5a5c..250bc3c4c 100644 --- a/src/base/io/log/Log.cpp +++ b/src/base/io/log/Log.cpp @@ -91,6 +91,10 @@ public: std::lock_guard lock(m_mutex); + if (Log::background && m_backends.empty()) { + return; + } + timestamp(level, size, offset); color(level, size); @@ -111,7 +115,7 @@ public: if (!m_backends.empty()) { for (ILogBackend *backend : m_backends) { backend->print(level, m_buf, offset, size, true); - backend->print(level, txt.c_str(), offset, txt.size(), false); + backend->print(level, txt.c_str(), offset ? (offset - 11) : 0, txt.size(), false); } } else { @@ -190,8 +194,9 @@ private: }; -bool Log::colors = true; -LogPrivate *Log::d = new LogPrivate(); +bool Log::background = false; +bool Log::colors = true; +LogPrivate *Log::d = new LogPrivate(); } /* namespace xmrig */ diff --git a/src/base/io/log/Log.h b/src/base/io/log/Log.h index d8bcb44a7..3517b61d4 100644 --- a/src/base/io/log/Log.h +++ b/src/base/io/log/Log.h @@ -54,6 +54,7 @@ public: static void print(const char *fmt, ...); static void print(Level level, const char *fmt, ...); + static bool background; static bool colors; private: diff --git a/src/base/io/log/backends/SysLog.h b/src/base/io/log/backends/SysLog.h index 0e8d0f8ed..d131784b4 100644 --- a/src/base/io/log/backends/SysLog.h +++ b/src/base/io/log/backends/SysLog.h @@ -37,7 +37,7 @@ class SysLog : public ILogBackend { public: SysLog(); - ~SysLog(); + ~SysLog() override; protected: void print(int level, const char *line, size_t offset, size_t size, bool colors) override; diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 152f6bccd..3740655df 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -184,7 +184,10 @@ int xmrig::Base::init() Platform::setProcessPriority(config()->cpu().priority()); # endif - if (!config()->isBackground()) { + if (config()->isBackground()) { + Log::background = true; + } + else { Log::add(new ConsoleLog()); } diff --git a/src/base/kernel/Entry.cpp b/src/base/kernel/Entry.cpp index f9e97c2d7..605f8e20a 100644 --- a/src/base/kernel/Entry.cpp +++ b/src/base/kernel/Entry.cpp @@ -35,6 +35,11 @@ # include #endif +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/wrappers/OclLib.h" +# include "backend/opencl/wrappers/OclPlatform.h" +#endif + #include "base/kernel/Entry.h" #include "base/kernel/Process.h" #include "core/config/usage.h" @@ -142,6 +147,12 @@ xmrig::Entry::Id xmrig::Entry::get(const Process &process) } # endif +# ifdef XMRIG_FEATURE_OPENCL + if (args.hasArg("--print-platforms")) { + return Platforms; + } +# endif + return Default; } @@ -161,6 +172,14 @@ int xmrig::Entry::exec(const Process &process, Id id) return exportTopology(process); # endif +# ifdef XMRIG_FEATURE_OPENCL + case Platforms: + if (OclLib::init()) { + OclPlatform::print(); + } + return 0; +# endif + default: break; } diff --git a/src/base/kernel/Entry.h b/src/base/kernel/Entry.h index c0bde080d..a459410fd 100644 --- a/src/base/kernel/Entry.h +++ b/src/base/kernel/Entry.h @@ -39,7 +39,8 @@ public: Default, Usage, Version, - Topo + Topo, + Platforms }; static Id get(const Process &process); diff --git a/src/base/kernel/config/BaseConfig.cpp b/src/base/kernel/config/BaseConfig.cpp index 4600a1f4b..3da06b57a 100644 --- a/src/base/kernel/config/BaseConfig.cpp +++ b/src/base/kernel/config/BaseConfig.cpp @@ -134,6 +134,7 @@ bool xmrig::BaseConfig::read(const IJsonReader &reader, const char *fileName) Log::colors = reader.getBool("colors", Log::colors); m_logFile = reader.getString("log-file"); m_userAgent = reader.getString("user-agent"); + m_version = reader.getUint("version"); setPrintTime(reader.getUint("print-time", 60)); diff --git a/src/base/kernel/config/BaseConfig.h b/src/base/kernel/config/BaseConfig.h index c5cf29a36..b58c47b6c 100644 --- a/src/base/kernel/config/BaseConfig.h +++ b/src/base/kernel/config/BaseConfig.h @@ -56,6 +56,7 @@ public: inline const String &apiId() const { return m_apiId; } inline const String &apiWorkerId() const { return m_apiWorkerId; } inline uint32_t printTime() const { return m_printTime; } + inline uint32_t version() const { return m_version; } inline bool isWatch() const override { return m_watch && !m_fileName.isNull(); } inline const String &fileName() const override { return m_fileName; } @@ -80,7 +81,8 @@ protected: String m_fileName; String m_logFile; String m_userAgent; - uint32_t m_printTime; + uint32_t m_printTime = 60; + uint32_t m_version = 0; private: inline void setPrintTime(uint32_t printTime) { if (printTime <= 3600) { m_printTime = printTime; } } diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 8043c6e91..12e7d8485 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -33,11 +33,12 @@ #endif -#include "base/kernel/config/BaseTransform.h" -#include "base/kernel/Process.h" -#include "base/io/log/Log.h" -#include "base/kernel/interfaces/IConfig.h" #include "base/io/json/JsonChain.h" +#include "base/io/log/Log.h" +#include "base/kernel/config/BaseTransform.h" +#include "base/kernel/interfaces/IConfig.h" +#include "base/kernel/Process.h" +#include "base/net/stratum/Pool.h" #include "core/config/Config_platform.h" @@ -138,7 +139,19 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch break; case IConfig::UrlKey: /* --url */ - return add(doc, kPools, "url", arg, true); + { + if (!doc.HasMember(kPools)) { + doc.AddMember(rapidjson::StringRef(kPools), rapidjson::kArrayType, doc.GetAllocator()); + } + + rapidjson::Value &array = doc[kPools]; + if (array.Size() == 0 || Pool(array[array.Size() - 1]).isValid()) { + array.PushBack(rapidjson::kObjectType, doc.GetAllocator()); + } + + set(doc, array[array.Size() - 1], "url", arg); + break; + } case IConfig::UserKey: /* --user */ return add(doc, kPools, "user", arg); diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp index f44415d58..325fce1c8 100644 --- a/src/base/net/stratum/BaseClient.cpp +++ b/src/base/net/stratum/BaseClient.cpp @@ -42,7 +42,8 @@ xmrig::BaseClient::BaseClient(int id, IClientListener *listener) : m_retries(5), m_failures(0), m_state(UnconnectedState), - m_retryPause(5000) + m_retryPause(5000), + m_enabled(true) { } diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 9e1c7ffbc..56bdc1263 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -64,7 +64,8 @@ protected: HostLookupState, ConnectingState, ConnectedState, - ClosingState + ClosingState, + ReconnectingState }; inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index fe1823369..b87466ab0 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -70,21 +70,15 @@ static const char *states[] = { "host-lookup", "connecting", "connected", - "closing" + "closing", + "reconnecting" }; #endif xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : BaseClient(id, listener), - m_agent(agent), - m_tls(nullptr), - m_expire(0), - m_jobs(0), - m_keepAlive(0), - m_key(0), - m_stream(nullptr), - m_socket(nullptr) + m_agent(agent) { m_key = m_storage.add(this); m_dns = new Dns(this); @@ -234,10 +228,16 @@ void xmrig::Client::tick(uint64_t now) else if (m_keepAlive && now > m_keepAlive) { ping(); } + + return; } - if (m_expire && now > m_expire && m_state == ConnectingState) { - connect(); + if (m_state == ReconnectingState && m_expire && now > m_expire) { + return connect(); + } + + if (m_state == ConnectingState && m_expire && now > m_expire) { + return reconnect(); } } @@ -447,7 +447,6 @@ int xmrig::Client::resolve(const String &host) { setState(HostLookupState); - m_expire = 0; m_recvBuf.reset(); if (m_failures == -1) { @@ -754,6 +753,8 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co void xmrig::Client::ping() { send(snprintf(m_sendBuf, sizeof(m_sendBuf), "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId.data())); + + m_keepAlive = 0; } @@ -810,12 +811,10 @@ void xmrig::Client::reconnect() return m_listener->onClose(this, -1); } - setState(ConnectingState); + setState(ReconnectingState); m_failures++; m_listener->onClose(this, static_cast(m_failures)); - - m_expire = Chrono::steadyMSecs() + m_retryPause; } @@ -827,6 +826,23 @@ void xmrig::Client::setState(SocketState state) return; } + switch (state) { + case HostLookupState: + m_expire = 0; + break; + + case ConnectingState: + m_expire = Chrono::steadyMSecs() + kConnectTimeout; + break; + + case ReconnectingState: + m_expire = Chrono::steadyMSecs() + m_retryPause; + break; + + default: + break; + } + m_state = state; } @@ -884,6 +900,12 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) LOG_ERR("[%s] connect error: \"%s\"", client->url(), uv_strerror(status)); } + if (client->state() != ConnectingState) { + LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state()); + + return; + } + delete req; client->close(); return; diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index 46030abaf..ff2bf7f6a 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -56,12 +56,13 @@ class JobResult; class Client : public BaseClient, public IDnsListener, public ILineListener { public: - constexpr static int kResponseTimeout = 20 * 1000; + constexpr static uint64_t kConnectTimeout = 20 * 1000; + constexpr static uint64_t kResponseTimeout = 20 * 1000; # ifdef XMRIG_FEATURE_TLS - constexpr static int kInputBufferSize = 1024 * 16; + constexpr static size_t kInputBufferSize = 1024 * 16; # else - constexpr static int kInputBufferSize = 1024 * 2; + constexpr static size_t kInputBufferSize = 1024 * 2; # endif Client(int id, const char *agent, IClientListener *listener); @@ -122,19 +123,19 @@ private: static inline Client *getClient(void *data) { return m_storage.get(data); } - char m_sendBuf[2048]; + char m_sendBuf[2048] = { 0 }; const char *m_agent; Dns *m_dns; RecvBuf m_recvBuf; std::bitset m_extensions; String m_rpcId; - Tls *m_tls; - uint64_t m_expire; - uint64_t m_jobs; - uint64_t m_keepAlive; - uintptr_t m_key; - uv_stream_t *m_stream; - uv_tcp_t *m_socket; + Tls *m_tls = nullptr; + uint64_t m_expire = 0; + uint64_t m_jobs = 0; + uint64_t m_keepAlive = 0; + uintptr_t m_key = 0; + uv_stream_t *m_stream = nullptr; + uv_tcp_t *m_socket = nullptr; static Storage m_storage; }; diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index 04bd82d87..c86ecba53 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -25,32 +25,18 @@ */ -#include -#include +#include +#include #include "base/net/stratum/Job.h" #include "base/tools/Buffer.h" -xmrig::Job::Job() : - m_blob(), - m_seedHash() -{ -} - - xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) : m_algorithm(algorithm), m_nicehash(nicehash), - m_clientId(clientId), - m_blob(), - m_seedHash() -{ -} - - -xmrig::Job::~Job() + m_clientId(clientId) { } @@ -96,7 +82,7 @@ bool xmrig::Job::setBlob(const char *blob) bool xmrig::Job::setSeedHash(const char *hash) { - if (!hash || (strlen(hash) != sizeof(m_seedHash) * 2)) { + if (!hash || (strlen(hash) != kMaxSeedSize * 2)) { return false; } @@ -104,7 +90,9 @@ bool xmrig::Job::setSeedHash(const char *hash) m_rawSeedHash = hash; # endif - return Buffer::fromHex(hash, sizeof(m_seedHash) * 2, m_seedHash); + m_seed = Buffer::fromHex(hash, kMaxSeedSize * 2); + + return !m_seed.isEmpty(); } @@ -173,9 +161,9 @@ void xmrig::Job::copy(const Job &other) m_height = other.m_height; m_target = other.m_target; m_index = other.m_index; + m_seed = other.m_seed; memcpy(m_blob, other.m_blob, sizeof(m_blob)); - memcpy(m_seedHash, other.m_seedHash, sizeof(m_seedHash)); # ifdef XMRIG_PROXY_PROJECT m_rawSeedHash = other.m_rawSeedHash; diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index 2b256a12f..eafd10e3c 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -28,10 +28,11 @@ #define XMRIG_JOB_H -#include -#include +#include +#include +#include "base/tools/Buffer.h" #include "base/tools/String.h" #include "crypto/common/Algorithm.h" @@ -45,10 +46,11 @@ public: // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk. // SECOR increase requirements for blob size: https://github.com/xmrig/xmrig/issues/913 static constexpr const size_t kMaxBlobSize = 128; + static constexpr const size_t kMaxSeedSize = 32; - Job(); + Job() = default; Job(bool nicehash, const Algorithm &algorithm, const String &clientId); - ~Job(); + ~Job() = default; bool isEqual(const Job &other) const; bool setBlob(const char *blob); @@ -60,11 +62,11 @@ public: inline bool isValid() const { return m_size > 0 && m_diff > 0; } inline bool setId(const char *id) { return m_id = id; } inline const Algorithm &algorithm() const { return m_algorithm; } + inline const Buffer &seed() const { return m_seed; } inline const String &clientId() const { return m_clientId; } inline const String &id() const { return m_id; } inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + 39); } inline const uint8_t *blob() const { return m_blob; } - inline const uint8_t *seedHash() const { return m_seedHash; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + 39); } inline uint64_t diff() const { return m_diff; } @@ -97,15 +99,15 @@ private: Algorithm m_algorithm; bool m_nicehash = false; + Buffer m_seed; size_t m_size = 0; String m_clientId; String m_id; uint64_t m_diff = 0; uint64_t m_height = 0; uint64_t m_target = 0; - uint8_t m_blob[kMaxBlobSize]; + uint8_t m_blob[kMaxBlobSize]{ 0 }; uint8_t m_index = 0; - uint8_t m_seedHash[32]; # ifdef XMRIG_PROXY_PROJECT char m_rawBlob[kMaxBlobSize * 2 + 8]; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 4d15ea473..ba31c35d7 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -200,6 +200,9 @@ bool xmrig::Pool::isEqual(const Pool &other) const bool xmrig::Pool::parse(const char *url) { assert(url != nullptr); + if (url == nullptr) { + return false; + } const char *p = strstr(url, "://"); const char *base = url; diff --git a/src/base/tools/Buffer.cpp b/src/base/tools/Buffer.cpp index 05a68cb4c..c12e601db 100644 --- a/src/base/tools/Buffer.cpp +++ b/src/base/tools/Buffer.cpp @@ -53,14 +53,7 @@ static inline uint8_t hf_bin2hex(uint8_t c) } -xmrig::Buffer::Buffer() : - m_data(nullptr), - m_size(0) -{ -} - - -xmrig::Buffer::Buffer(Buffer &&other) : +xmrig::Buffer::Buffer(Buffer &&other) noexcept : m_data(other.m_data), m_size(other.m_size) { @@ -138,11 +131,13 @@ bool xmrig::Buffer::fromHex(const uint8_t *in, size_t size, uint8_t *out) xmrig::Buffer xmrig::Buffer::fromHex(const char *data, size_t size) { if (data == nullptr || size % 2 != 0) { - return Buffer(); + return {}; } Buffer buf(size / 2); - fromHex(data, size, buf.data()); + if (!fromHex(data, size, buf.data())) { + return {}; + } return buf; } @@ -157,12 +152,6 @@ void xmrig::Buffer::toHex(const uint8_t *in, size_t size, uint8_t *out) } -xmrig::String xmrig::Buffer::toHex(const uint8_t *in, size_t size) -{ - return Buffer(reinterpret_cast(in), size).toHex(); -} - - xmrig::String xmrig::Buffer::toHex() const { if (m_size == 0) { diff --git a/src/base/tools/Buffer.h b/src/base/tools/Buffer.h index 28f92b9e1..363e4697e 100644 --- a/src/base/tools/Buffer.h +++ b/src/base/tools/Buffer.h @@ -35,14 +35,15 @@ namespace xmrig { class Buffer { public: - Buffer(); - Buffer(Buffer &&other); + Buffer() = default; + Buffer(Buffer &&other) noexcept; Buffer(const Buffer &other); Buffer(const char *data, size_t size); Buffer(size_t size); ~Buffer(); + inline bool isEmpty() const { return size() == 0; } inline bool isEqual(const Buffer &other) const { return m_size == other.m_size && (m_size == 0 || memcmp(m_data, other.m_data, m_size) == 0); } inline char *data() { return m_data; } inline const char *data() const { return m_data; } @@ -55,7 +56,7 @@ public: inline bool operator!=(const Buffer &other) const { return !isEqual(other); } inline bool operator==(const Buffer &other) const { return isEqual(other); } - inline Buffer &operator=(Buffer &&other) { move(std::move(other)); return *this; } + inline Buffer &operator=(Buffer &&other) noexcept { move(std::move(other)); return *this; } inline Buffer &operator=(const Buffer &other) { from(other); return *this; } @@ -67,12 +68,13 @@ public: inline static bool fromHex(const char *in, size_t size, uint8_t *out) { return fromHex(reinterpret_cast(in), size, out); } inline static Buffer fromHex(const char *data) { return fromHex(data, strlen(data)); } inline static Buffer fromHex(const String &str) { return fromHex(str.data(), str.size()); } + inline static String toHex(const char *in, size_t size) { return Buffer(in, size).toHex(); } + inline static String toHex(const uint8_t *in, size_t size) { return Buffer(reinterpret_cast(in), size).toHex(); } inline static void toHex(const char *in, size_t size, char *out) { return toHex(reinterpret_cast(in), size, reinterpret_cast(out)); } inline static void toHex(const uint8_t *in, size_t size, char *out) { return toHex(in, size, reinterpret_cast(out)); } static bool fromHex(const uint8_t *in, size_t size, uint8_t *out); static Buffer fromHex(const char *data, size_t size); - static String toHex(const uint8_t *in, size_t size); static void toHex(const uint8_t *in, size_t size, uint8_t *out); String toHex() const; @@ -80,8 +82,8 @@ private: void copy(const char *data, size_t size); void move(Buffer &&other); - char *m_data; - size_t m_size; + char *m_data = nullptr; + size_t m_size = 0; }; diff --git a/src/base/tools/Object.h b/src/base/tools/Object.h new file mode 100644 index 000000000..7e460e444 --- /dev/null +++ b/src/base/tools/Object.h @@ -0,0 +1,52 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_OBJECT_H +#define XMRIG_OBJECT_H + + +#include + + +namespace xmrig { + + +#define XMRIG_DISABLE_COPY_MOVE(X) \ + X(const X &other) = delete; \ + X(X &&other) = delete; \ + X &operator=(const X &other) = delete; \ + X &operator=(X &&other) = delete; + + +#define XMRIG_DISABLE_COPY_MOVE_DEFAULT(X) \ + X() = delete; \ + X(const X &other) = delete; \ + X(X &&other) = delete; \ + X &operator=(const X &other) = delete; \ + X &operator=(X &&other) = delete; + + +} /* namespace xmrig */ + +#endif /* XMRIG_OBJECT_H */ diff --git a/src/base/tools/String.cpp b/src/base/tools/String.cpp index 7778c6da6..b11d67745 100644 --- a/src/base/tools/String.cpp +++ b/src/base/tools/String.cpp @@ -31,7 +31,6 @@ xmrig::String::String(const char *str) : - m_data(nullptr), m_size(str == nullptr ? 0 : strlen(str)) { if (m_size == 0) { @@ -44,7 +43,6 @@ xmrig::String::String(const char *str) : xmrig::String::String(const char *str, size_t size) : - m_data(nullptr), m_size(size) { if (str == nullptr) { @@ -60,7 +58,6 @@ xmrig::String::String(const char *str, size_t size) : xmrig::String::String(const String &other) : - m_data(nullptr), m_size(other.m_size) { if (other.m_data == nullptr) { @@ -117,7 +114,7 @@ std::vector xmrig::String::split(char sep) const for (pos = 0; pos < m_size; ++pos) { if (m_data[pos] == sep) { if ((pos - start) > 0) { - out.push_back(String(m_data + start, pos - start)); + out.emplace_back(m_data + start, pos - start); } start = pos + 1; @@ -125,7 +122,7 @@ std::vector xmrig::String::split(char sep) const } if ((pos - start) > 0) { - out.push_back(String(m_data + start, pos - start)); + out.emplace_back(m_data + start, pos - start); } return out; @@ -146,6 +143,20 @@ xmrig::String &xmrig::String::toLower() } +xmrig::String &xmrig::String::toUpper() +{ + if (isNull() || isEmpty()) { + return *this; + } + + for (size_t i = 0; i < size(); ++i) { + m_data[i] = static_cast(toupper(m_data[i])); + } + + return *this; +} + + xmrig::String xmrig::String::join(const std::vector &vec, char sep) { if (vec.empty()) { diff --git a/src/base/tools/String.h b/src/base/tools/String.h index 2c47d8501..0f3656410 100644 --- a/src/base/tools/String.h +++ b/src/base/tools/String.h @@ -46,9 +46,9 @@ namespace xmrig { class String { public: - inline String() : m_data(nullptr), m_size(0) {} - inline String(char *str) : m_data(str), m_size(str == nullptr ? 0 : strlen(str)) {} - inline String(String &&other) : m_data(other.m_data), m_size(other.m_size) { other.m_data = nullptr; other.m_size = 0; } + inline String() = default; + inline String(char *str) : m_data(str), m_size(str == nullptr ? 0 : strlen(str)) {} + inline String(String &&other) noexcept : m_data(other.m_data), m_size(other.m_size) { other.m_data = nullptr; other.m_size = 0; } String(const char *str); String(const char *str, size_t size); @@ -81,12 +81,13 @@ public: inline String &operator=(const char *str) { copy(str); return *this; } inline String &operator=(const String &str) { copy(str); return *this; } inline String &operator=(std::nullptr_t) { delete [] m_data; m_data = nullptr; m_size = 0; return *this; } - inline String &operator=(String &&other) { move(std::move(other)); return *this; } + inline String &operator=(String &&other) noexcept { move(std::move(other)); return *this; } rapidjson::Value toJSON() const; rapidjson::Value toJSON(rapidjson::Document &doc) const; std::vector split(char sep) const; String &toLower(); + String &toUpper(); static String join(const std::vector &vec, char sep); @@ -96,8 +97,8 @@ private: void move(char *str); void move(String &&other); - char *m_data; - size_t m_size; + char *m_data = nullptr; + size_t m_size = 0; }; diff --git a/src/config.json b/src/config.json index af3bd32a5..c9f53f269 100644 --- a/src/config.json +++ b/src/config.json @@ -11,6 +11,7 @@ "restricted": true }, "autosave": true, + "version": 1, "background": false, "colors": true, "randomx": { @@ -23,6 +24,7 @@ "hw-aes": null, "priority": null, "asm": true, + "argon2-impl": null, "cn/0": false, "cn-lite/0": false }, diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index 26a5d7e75..d382d7aaa 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -24,8 +24,8 @@ #include +#include #include -#include #include "backend/common/Hashrate.h" @@ -34,6 +34,7 @@ #include "base/io/log/Log.h" #include "base/kernel/Platform.h" #include "base/net/stratum/Job.h" +#include "base/tools/Object.h" #include "base/tools/Timer.h" #include "core/config/Config.h" #include "core/Controller.h" @@ -50,16 +51,29 @@ #endif +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/OclBackend.h" +#endif + + +#ifdef XMRIG_ALGO_RANDOMX +# include "crypto/rx/RxConfig.h" +#endif + + namespace xmrig { +static std::mutex mutex; + + class MinerPrivate { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(MinerPrivate) + inline MinerPrivate(Controller *controller) : controller(controller) { - uv_rwlock_init(&rwlock); - # ifdef XMRIG_ALGO_RANDOMX Rx::init(); # endif @@ -68,8 +82,6 @@ public: inline ~MinerPrivate() { - uv_rwlock_destroy(&rwlock); - delete timer; for (IBackend *backend : backends) { @@ -108,7 +120,7 @@ public: } - inline void handleJobChange(bool reset) + inline void handleJobChange() { active = true; @@ -135,7 +147,7 @@ public: # ifdef XMRIG_FEATURE_API - void getMiner(rapidjson::Value &reply, rapidjson::Document &doc, int version) const + void getMiner(rapidjson::Value &reply, rapidjson::Document &doc, int) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); @@ -144,25 +156,6 @@ public: reply.AddMember("kind", APP_KIND, allocator); reply.AddMember("ua", StringRef(Platform::userAgent()), allocator); reply.AddMember("cpu", Cpu::toJSON(doc), allocator); - - Value hugepages; - - if (!backends.empty() && backends.front()->type() == "cpu") { - const auto pages = static_cast(backends.front())->hugePages(); - if (version > 1) { - hugepages.SetArray(); - hugepages.PushBack(pages.first, allocator); - hugepages.PushBack(pages.second, allocator); - } - else { - hugepages = pages.first == pages.second; - } - } - else { - hugepages = false; - } - - reply.AddMember("hugepages", hugepages, allocator); reply.AddMember("donate_level", controller->config()->pools().donateLevel(), allocator); Value algo(kArrayType); @@ -239,10 +232,19 @@ public: # endif +# ifdef XMRIG_ALGO_RANDOMX + bool initRX(IRxListener *listener) + { + return Rx::init(job, controller->config()->rx().threads(), controller->config()->cpu().isHugePages(), controller->config()->rx().isNUMA(), listener); + } +# endif + + Algorithm algorithm; Algorithms algorithms; bool active = false; bool enabled = true; + bool reset = true; Controller *controller; Job job; mutable std::map maxHashrate; @@ -250,7 +252,6 @@ public: String userJobId; Timer *timer = nullptr; uint64_t ticks = 0; - uv_rwlock_t rwlock; }; @@ -271,6 +272,10 @@ xmrig::Miner::Miner(Controller *controller) d_ptr->backends.push_back(new CpuBackend(controller)); +# ifdef XMRIG_FEATURE_OPENCL + d_ptr->backends.push_back(new OclBackend(controller)); +# endif + d_ptr->rebuild(); } @@ -307,11 +312,9 @@ const std::vector &xmrig::Miner::backends() const xmrig::Job xmrig::Miner::job() const { - uv_rwlock_rdlock(&d_ptr->rwlock); - Job job = d_ptr->job; - uv_rwlock_rdunlock(&d_ptr->rwlock); + std::lock_guard lock(mutex); - return job; + return d_ptr->job; } @@ -387,12 +390,12 @@ void xmrig::Miner::setJob(const Job &job, bool donate) d_ptr->algorithm = job.algorithm(); - uv_rwlock_wrlock(&d_ptr->rwlock); + mutex.lock(); const uint8_t index = donate ? 1 : 0; - const bool reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); - d_ptr->job = job; + d_ptr->reset = !(d_ptr->job.index() == 1 && index == 0 && d_ptr->userJobId == job.id()); + d_ptr->job = job; d_ptr->job.setIndex(index); if (index == 0) { @@ -400,16 +403,16 @@ void xmrig::Miner::setJob(const Job &job, bool donate) } # ifdef XMRIG_ALGO_RANDOMX - Rx::init(d_ptr->job, - d_ptr->controller->config()->rx().threads(), - d_ptr->controller->config()->cpu().isHugePages(), - d_ptr->controller->config()->rx().isNUMA() - ); + const bool ready = d_ptr->initRX(this); +# else + constexpr const bool ready = true; # endif - uv_rwlock_wrunlock(&d_ptr->rwlock); + mutex.unlock(); - d_ptr->handleJobChange(reset); + if (ready) { + d_ptr->handleJobChange(); + } } @@ -488,6 +491,27 @@ void xmrig::Miner::onRequest(IApiRequest &request) setEnabled(true); } + else if (request.rpcMethod() == "stop") { + request.accept(); + + stop(); + } + } + + for (IBackend *backend : d_ptr->backends) { + backend->handleRequest(request); } } #endif + + +#ifdef XMRIG_ALGO_RANDOMX +void xmrig::Miner::onDatasetReady() +{ + if (!Rx::isReady(job())) { + return; + } + + d_ptr->handleJobChange(); +} +#endif diff --git a/src/core/Miner.h b/src/core/Miner.h index 6fc75cd09..21568f122 100644 --- a/src/core/Miner.h +++ b/src/core/Miner.h @@ -29,6 +29,7 @@ #include +#include "backend/common/interfaces/IRxListener.h" #include "base/api/interfaces/IApiListener.h" #include "base/kernel/interfaces/IBaseListener.h" #include "base/kernel/interfaces/ITimerListener.h" @@ -44,7 +45,7 @@ class MinerPrivate; class IBackend; -class Miner : public ITimerListener, public IBaseListener, public IApiListener +class Miner : public ITimerListener, public IBaseListener, public IApiListener, public IRxListener { public: Miner(Controller *controller); @@ -69,6 +70,10 @@ protected: void onRequest(IApiRequest &request) override; # endif +# ifdef XMRIG_ALGO_RANDOMX + void onDatasetReady() override; +# endif + private: MinerPrivate *d_ptr; }; diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp index 44aa60299..33e5e54fe 100644 --- a/src/core/config/Config.cpp +++ b/src/core/config/Config.cpp @@ -38,36 +38,119 @@ #include "rapidjson/prettywriter.h" +#ifdef XMRIG_ALGO_RANDOMX +# include "crypto/rx/RxConfig.h" +#endif + + +#ifdef XMRIG_FEATURE_OPENCL +# include "backend/opencl/OclConfig.h" +#endif + + namespace xmrig { -static const char *kCPU = "cpu"; +static const char *kCPU = "cpu"; +static constexpr const uint32_t kVersion = 1; #ifdef XMRIG_ALGO_RANDOMX static const char *kRandomX = "randomx"; #endif +#ifdef XMRIG_FEATURE_OPENCL +static const char *kOcl = "opencl"; +#endif + + +class ConfigPrivate +{ +public: + CpuConfig cpu; + +# ifdef XMRIG_ALGO_RANDOMX + RxConfig rx; +# endif + +# ifdef XMRIG_FEATURE_OPENCL + OclConfig cl; +# endif +}; + } -xmrig::Config::Config() : BaseConfig() +xmrig::Config::Config() : BaseConfig(), + d_ptr(new ConfigPrivate()) { } +xmrig::Config::~Config() +{ + delete d_ptr; +} + + +const xmrig::CpuConfig &xmrig::Config::cpu() const +{ + return d_ptr->cpu; +} + + +#ifdef XMRIG_FEATURE_OPENCL +const xmrig::OclConfig &xmrig::Config::cl() const +{ + return d_ptr->cl; +} +#endif + + +#ifdef XMRIG_ALGO_RANDOMX +const xmrig::RxConfig &xmrig::Config::rx() const +{ + return d_ptr->rx; +} +#endif + + +bool xmrig::Config::isShouldSave() const +{ + if (!isAutoSave()) { + return false; + } + + if (version() < kVersion) { + return true; + } + +# ifdef XMRIG_FEATURE_OPENCL + if (cl().isShouldSave()) { + return true; + } +# endif + + return (m_upgrade || cpu().isShouldSave()); +} + + bool xmrig::Config::read(const IJsonReader &reader, const char *fileName) { if (!BaseConfig::read(reader, fileName)) { return false; } - m_cpu.read(reader.getValue(kCPU)); + d_ptr->cpu.read(reader.getValue(kCPU), version()); # ifdef XMRIG_ALGO_RANDOMX - if (!m_rx.read(reader.getValue(kRandomX))) { + if (!d_ptr->rx.read(reader.getValue(kRandomX))) { m_upgrade = true; } # endif +# ifdef XMRIG_FEATURE_OPENCL + d_ptr->cl.read(reader.getValue(kOcl)); +# endif + return true; } @@ -81,20 +164,26 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const auto &allocator = doc.GetAllocator(); Value api(kObjectType); - api.AddMember("id", m_apiId.toJSON(), allocator); - api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); + api.AddMember("id", m_apiId.toJSON(), allocator); + api.AddMember("worker-id", m_apiWorkerId.toJSON(), allocator); doc.AddMember("api", api, allocator); doc.AddMember("http", m_http.toJSON(doc), allocator); doc.AddMember("autosave", isAutoSave(), allocator); + doc.AddMember("version", kVersion, allocator); doc.AddMember("background", isBackground(), allocator); doc.AddMember("colors", Log::colors, allocator); # ifdef XMRIG_ALGO_RANDOMX - doc.AddMember(StringRef(kRandomX), m_rx.toJSON(doc), allocator); + doc.AddMember(StringRef(kRandomX), rx().toJSON(doc), allocator); +# endif + + doc.AddMember(StringRef(kCPU), cpu().toJSON(doc), allocator); + +# ifdef XMRIG_FEATURE_OPENCL + doc.AddMember(StringRef(kOcl), cl().toJSON(doc), allocator); # endif - doc.AddMember(StringRef(kCPU), m_cpu.toJSON(doc), allocator); doc.AddMember("donate-level", m_pools.donateLevel(), allocator); doc.AddMember("donate-over-proxy", m_pools.proxyDonate(), allocator); doc.AddMember("log-file", m_logFile.toJSON(), allocator); diff --git a/src/core/config/Config.h b/src/core/config/Config.h index 0014cb05a..7c7bc5338 100644 --- a/src/core/config/Config.h +++ b/src/core/config/Config.h @@ -34,39 +34,37 @@ #include "rapidjson/fwd.h" -#ifdef XMRIG_ALGO_RANDOMX -# include "crypto/rx/RxConfig.h" -#endif - - namespace xmrig { +class ConfigPrivate; class IThread; +class RxConfig; +class OclConfig; class Config : public BaseConfig { public: Config(); + ~Config() override; + const CpuConfig &cpu() const; + +# ifdef XMRIG_FEATURE_OPENCL + const OclConfig &cl() const; +# endif + +# ifdef XMRIG_ALGO_RANDOMX + const RxConfig &rx() const; +# endif + + bool isShouldSave() const; bool read(const IJsonReader &reader, const char *fileName) override; void getJSON(rapidjson::Document &doc) const override; - inline bool isShouldSave() const { return (m_shouldSave || m_upgrade || m_cpu.isShouldSave()) && isAutoSave(); } - inline const CpuConfig &cpu() const { return m_cpu; } - -# ifdef XMRIG_ALGO_RANDOMX - inline const RxConfig &rx() const { return m_rx; } -# endif - private: - bool m_shouldSave = false; - CpuConfig m_cpu; - -# ifdef XMRIG_ALGO_RANDOMX - RxConfig m_rx; -# endif + ConfigPrivate *d_ptr; }; diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp index 622855af6..ce0d324c7 100644 --- a/src/core/config/ConfigTransform.cpp +++ b/src/core/config/ConfigTransform.cpp @@ -96,6 +96,8 @@ void xmrig::ConfigTransform::finalize(rapidjson::Document &doc) BaseTransform::finalize(doc); if (m_threads) { + doc.AddMember("version", 1, allocator); + if (!doc.HasMember(kCpu)) { doc.AddMember(StringRef(kCpu), Value(kObjectType), allocator); } diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index 2f8534461..c8b2e6e64 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -45,6 +45,7 @@ R"===( "restricted": true }, "autosave": true, + "version": 1, "background": false, "colors": true, "randomx": { @@ -57,6 +58,7 @@ R"===( "hw-aes": null, "priority": null, "asm": true, + "argon2-impl": null, "cn/0": false, "cn-lite/0": false }, diff --git a/src/crypto/argon2/Hash.h b/src/crypto/argon2/Hash.h new file mode 100644 index 000000000..b337f1934 --- /dev/null +++ b/src/crypto/argon2/Hash.h @@ -0,0 +1,52 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ARGON2_HASH_H +#define XMRIG_ARGON2_HASH_H + + +#include "3rdparty/argon2.h" +#include "crypto/cn/CryptoNight.h" +#include "crypto/common/Algorithm.h" + + +namespace xmrig { namespace argon2 { + + +template +inline void single_hash(const uint8_t *__restrict__ input, size_t size, uint8_t *__restrict__ output, cryptonight_ctx **__restrict__ ctx, uint64_t) +{ + if (ALGO == Algorithm::AR2_CHUKWA) { + argon2id_hash_raw_ex(3, 512, 1, input, size, input, 16, output, 32, ctx[0]->memory); + } + else if (ALGO == Algorithm::AR2_WRKZ) { + argon2id_hash_raw_ex(4, 256, 1, input, size, input, 16, output, 32, ctx[0]->memory); + } +} + + +}} // namespace xmrig::argon2 + + +#endif /* XMRIG_ARGON2_HASH_H */ diff --git a/src/crypto/argon2/Impl.cpp b/src/crypto/argon2/Impl.cpp new file mode 100644 index 000000000..d0f267f95 --- /dev/null +++ b/src/crypto/argon2/Impl.cpp @@ -0,0 +1,62 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "3rdparty/argon2.h" +#include "base/tools/String.h" +#include "crypto/argon2/Impl.h" + + + +namespace xmrig { + + +static bool selected = false; +static String implName; + + +} // namespace xmrig + + +bool xmrig::argon2::Impl::select(const String &nameHint) +{ + if (!selected) { + if (nameHint.isEmpty() || argon2_select_impl_by_name(nameHint) == 0) { + argon2_select_impl(); + } + + selected = true; + implName = argon2_get_impl_name(); + + return true; + } + + return false; +} + + +const xmrig::String &xmrig::argon2::Impl::name() +{ + return implName; +} diff --git a/src/crypto/argon2/Impl.h b/src/crypto/argon2/Impl.h new file mode 100644 index 000000000..006dbd35f --- /dev/null +++ b/src/crypto/argon2/Impl.h @@ -0,0 +1,49 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018-2019 SChernykh + * Copyright 2016-2019 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_ARGON2_IMPL_H +#define XMRIG_ARGON2_IMPL_H + + +namespace xmrig { + + +class String; + + +namespace argon2 { + + +class Impl +{ +public: + static bool select(const String &nameHint); + static const String &name(); +}; + + +}} // namespace xmrig::argon2 + + +#endif /* XMRIG_ARGON2_IMPL_H */ diff --git a/src/crypto/cn/CnAlgo.h b/src/crypto/cn/CnAlgo.h index ed64331a9..296c52b73 100644 --- a/src/crypto/cn/CnAlgo.h +++ b/src/crypto/cn/CnAlgo.h @@ -27,8 +27,8 @@ #define XMRIG_CN_ALGO_H -#include -#include +#include +#include #include "crypto/common/Algorithm.h" @@ -42,19 +42,13 @@ template class CnAlgo { public: - constexpr inline CnAlgo() - { - static_assert(ALGO != Algorithm::INVALID && m_memory[ALGO] > 0, "invalid CRYPTONIGHT algorithm"); - static_assert(sizeof(m_memory) / sizeof(m_memory)[0] == Algorithm::MAX, "memory table size mismatch"); - static_assert(sizeof(m_iterations) / sizeof(m_iterations)[0] == Algorithm::MAX, "iterations table size mismatch"); - static_assert(sizeof(m_base) / sizeof(m_base)[0] == Algorithm::MAX, "iterations table size mismatch"); - } + constexpr CnAlgo() {}; - constexpr inline Algorithm::Id base() const { return m_base[ALGO]; } + constexpr inline Algorithm::Id base() const { static_assert(ALGO > Algorithm::INVALID && ALGO < Algorithm::RX_0, "invalid CRYPTONIGHT algorithm"); return Algorithm::CN_2; } constexpr inline bool isHeavy() const { return memory() == CN_MEMORY * 2; } - constexpr inline bool isR() const { return ALGO == Algorithm::CN_R || ALGO == Algorithm::CN_WOW; } - constexpr inline size_t memory() const { return m_memory[ALGO]; } - constexpr inline uint32_t iterations() const { return m_iterations[ALGO]; } + constexpr inline bool isR() const { return ALGO == Algorithm::CN_R; } + constexpr inline size_t memory() const { static_assert(ALGO > Algorithm::INVALID && ALGO < Algorithm::RX_0, "invalid CRYPTONIGHT algorithm"); return CN_MEMORY; } + constexpr inline uint32_t iterations() const { static_assert(ALGO > Algorithm::INVALID && ALGO < Algorithm::RX_0, "invalid CRYPTONIGHT algorithm"); return CN_ITER; } constexpr inline uint32_t mask() const { return ((memory() - 1) / 16) * 16; } inline static size_t memory(Algorithm::Id algo) @@ -79,6 +73,54 @@ public: return 0; } + inline static uint32_t iterations(Algorithm::Id algo) + { + switch (algo) { + case Algorithm::CN_0: + case Algorithm::CN_1: + case Algorithm::CN_2: + case Algorithm::CN_R: + case Algorithm::CN_RTO: + return CN_ITER; + + case Algorithm::CN_FAST: + case Algorithm::CN_HALF: +# ifdef XMRIG_ALGO_CN_LITE + case Algorithm::CN_LITE_0: + case Algorithm::CN_LITE_1: +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + case Algorithm::CN_HEAVY_0: + case Algorithm::CN_HEAVY_TUBE: + case Algorithm::CN_HEAVY_XHV: +# endif + return CN_ITER / 2; + + case Algorithm::CN_RWZ: + case Algorithm::CN_ZLS: + return 0x60000; + + case Algorithm::CN_XAO: + case Algorithm::CN_DOUBLE: + return CN_ITER * 2; + +# ifdef XMRIG_ALGO_CN_GPU + case Algorithm::CN_GPU: + return 0xC000; +# endif + +# ifdef XMRIG_ALGO_CN_PICO + case Algorithm::CN_PICO_0: + return CN_ITER / 8; +# endif + + default: + break; + } + + return 0; + } + inline static uint32_t mask(Algorithm::Id algo) { # ifdef XMRIG_ALGO_CN_GPU @@ -96,124 +138,97 @@ public: return ((memory(algo) - 1) / 16) * 16; } + inline static Algorithm::Id base(Algorithm::Id algo) + { + switch (algo) { + case Algorithm::CN_0: + case Algorithm::CN_XAO: +# ifdef XMRIG_ALGO_CN_LITE + case Algorithm::CN_LITE_0: +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + case Algorithm::CN_HEAVY_0: + case Algorithm::CN_HEAVY_XHV: +# endif + return Algorithm::CN_0; + + case Algorithm::CN_1: + case Algorithm::CN_FAST: + case Algorithm::CN_RTO: +# ifdef XMRIG_ALGO_CN_LITE + case Algorithm::CN_LITE_1: +# endif +# ifdef XMRIG_ALGO_CN_HEAVY + case Algorithm::CN_HEAVY_TUBE: + return Algorithm::CN_1; +# endif + + case Algorithm::CN_2: + case Algorithm::CN_R: + case Algorithm::CN_HALF: + case Algorithm::CN_RWZ: + case Algorithm::CN_ZLS: + case Algorithm::CN_DOUBLE: +# ifdef XMRIG_ALGO_CN_PICO + case Algorithm::CN_PICO_0: +# endif + return Algorithm::CN_2; + +# ifdef XMRIG_ALGO_CN_GPU + case Algorithm::CN_GPU: + return Algorithm::CN_GPU; +# endif + + default: + break; + } + + return Algorithm::INVALID; + } + private: constexpr const static size_t CN_MEMORY = 0x200000; constexpr const static uint32_t CN_ITER = 0x80000; - - constexpr const static size_t m_memory[] = { - CN_MEMORY, // CN_0 - CN_MEMORY, // CN_1 - CN_MEMORY, // CN_2 - CN_MEMORY, // CN_R - CN_MEMORY, // CN_WOW - CN_MEMORY, // CN_FAST - CN_MEMORY, // CN_HALF - CN_MEMORY, // CN_XAO - CN_MEMORY, // CN_RTO - CN_MEMORY, // CN_RWZ - CN_MEMORY, // CN_ZLS - CN_MEMORY, // CN_DOUBLE -# ifdef XMRIG_ALGO_CN_GPU - CN_MEMORY, // CN_GPU -# endif -# ifdef XMRIG_ALGO_CN_LITE - CN_MEMORY / 2, // CN_LITE_0 - CN_MEMORY / 2, // CN_LITE_1 -# endif -# ifdef XMRIG_ALGO_CN_HEAVY - CN_MEMORY * 2, // CN_HEAVY_0 - CN_MEMORY * 2, // CN_HEAVY_TUBE - CN_MEMORY * 2, // CN_HEAVY_XHV -# endif -# ifdef XMRIG_ALGO_CN_PICO - CN_MEMORY / 8, // CN_PICO_0 -# endif -# ifdef XMRIG_ALGO_RANDOMX - 0, // RX_0 - 0, // RX_WOW - 0, // RX_LOKI -# endif - }; - - constexpr const static uint32_t m_iterations[] = { - CN_ITER, // CN_0 - CN_ITER, // CN_1 - CN_ITER, // CN_2 - CN_ITER, // CN_R - CN_ITER, // CN_WOW - CN_ITER / 2, // CN_FAST - CN_ITER / 2, // CN_HALF - CN_ITER * 2, // CN_XAO - CN_ITER, // CN_RTO - 0x60000, // CN_RWZ - 0x60000, // CN_ZLS - CN_ITER * 2, // CN_DOUBLE -# ifdef XMRIG_ALGO_CN_GPU - 0xC000, // CN_GPU -# endif -# ifdef XMRIG_ALGO_CN_LITE - CN_ITER / 2, // CN_LITE_0 - CN_ITER / 2, // CN_LITE_1 -# endif -# ifdef XMRIG_ALGO_CN_HEAVY - CN_ITER / 2, // CN_HEAVY_0 - CN_ITER / 2, // CN_HEAVY_TUBE - CN_ITER / 2, // CN_HEAVY_XHV -# endif -# ifdef XMRIG_ALGO_CN_PICO - CN_ITER / 8, // CN_PICO_0 -# endif -# ifdef XMRIG_ALGO_RANDOMX - 0, // RX_0 - 0, // RX_WOW - 0, // RX_LOKI -# endif - }; - - constexpr const static Algorithm::Id m_base[] = { - Algorithm::CN_0, // CN_0 - Algorithm::CN_1, // CN_1 - Algorithm::CN_2, // CN_2 - Algorithm::CN_2, // CN_R - Algorithm::CN_2, // CN_WOW - Algorithm::CN_1, // CN_FAST - Algorithm::CN_2, // CN_HALF - Algorithm::CN_0, // CN_XAO - Algorithm::CN_1, // CN_RTO - Algorithm::CN_2, // CN_RWZ - Algorithm::CN_2, // CN_ZLS - Algorithm::CN_2, // CN_DOUBLE -# ifdef XMRIG_ALGO_CN_GPU - Algorithm::CN_GPU, // CN_GPU -# endif -# ifdef XMRIG_ALGO_CN_LITE - Algorithm::CN_0, // CN_LITE_0 - Algorithm::CN_1, // CN_LITE_1 -# endif -# ifdef XMRIG_ALGO_CN_HEAVY - Algorithm::CN_0, // CN_HEAVY_0 - Algorithm::CN_1, // CN_HEAVY_TUBE - Algorithm::CN_0, // CN_HEAVY_XHV -# endif -# ifdef XMRIG_ALGO_CN_PICO - Algorithm::CN_2, // CN_PICO_0, -# endif -# ifdef XMRIG_ALGO_RANDOMX - Algorithm::INVALID, // RX_0 - Algorithm::INVALID, // RX_WOW - Algorithm::INVALID, // RX_LOKI -# endif - }; }; -#ifdef XMRIG_ALGO_CN_GPU -template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFFC0; } -#endif +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_0; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_0; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_0; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_0; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_0; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_1; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_1; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_1; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_1; } +template<> constexpr inline Algorithm::Id CnAlgo::base() const { return Algorithm::CN_1; } -#ifdef XMRIG_ALGO_CN_PICO -template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFF0; } -#endif + +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER * 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER * 2; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return 0x60000; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return 0x60000; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return 0xC000; } +template<> constexpr inline uint32_t CnAlgo::iterations() const { return CN_ITER / 8; } + + +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY / 2; } +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY / 2; } +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY * 2; } +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY * 2; } +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY * 2; } +template<> constexpr inline size_t CnAlgo::memory() const { return CN_MEMORY / 8; } + + +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFFC0; } +template<> constexpr inline uint32_t CnAlgo::mask() const { return 0x1FFF0; } } /* namespace xmrig */ diff --git a/src/crypto/cn/CnHash.cpp b/src/crypto/cn/CnHash.cpp index a2f8880cf..c6fe944e6 100644 --- a/src/crypto/cn/CnHash.cpp +++ b/src/crypto/cn/CnHash.cpp @@ -23,7 +23,7 @@ * along with this program. If not, see . */ -#include +#include #include "backend/cpu/Cpu.h" @@ -38,6 +38,11 @@ #endif +#ifdef XMRIG_ALGO_ARGON2 +# include "crypto/argon2/Hash.h" +#endif + + #define ADD_FN(algo) \ m_map[algo][AV_SINGLE][Assembly::NONE] = cryptonight_single_hash; \ m_map[algo][AV_SINGLE_SOFT][Assembly::NONE] = cryptonight_single_hash; \ @@ -61,12 +66,6 @@ m_map[algo][AV_DOUBLE][Assembly::BULLDOZER] = cryptonight_double_hash_asm; -extern "C" void cnv2_mainloop_ivybridge_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_ryzen_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_mainloop_bulldozer_asm(cryptonight_ctx **ctx); -extern "C" void cnv2_double_mainloop_sandybridge_asm(cryptonight_ctx **ctx); - - namespace xmrig { @@ -94,7 +93,7 @@ cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm = nullptr; template static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t mask = CnAlgo().mask()) { - const uint8_t* p = reinterpret_cast(src); + auto p = reinterpret_cast(src); // Workaround for Visual Studio placing trampoline in debug builds. # if defined(_MSC_VER) @@ -112,7 +111,7 @@ static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t ma memcpy((void*) dst, (const void*) src, size); - uint8_t* patched_data = reinterpret_cast(dst); + auto patched_data = reinterpret_cast(dst); for (size_t i = 0; i + sizeof(uint32_t) <= size; ++i) { switch (*(uint32_t*)(patched_data + i)) { case CnAlgo().iterations(): @@ -130,7 +129,7 @@ static void patchCode(T dst, U src, const uint32_t iterations, const uint32_t ma static void patchAsmVariants() { const int allocation_size = 65536; - uint8_t *base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); + auto base = static_cast(VirtualMemory::allocateExecutableMemory(allocation_size)); cn_half_mainloop_ivybridge_asm = reinterpret_cast (base + 0x0000); cn_half_mainloop_ryzen_asm = reinterpret_cast (base + 0x1000); @@ -211,7 +210,6 @@ xmrig::CnHash::CnHash() ADD_FN(Algorithm::CN_1); ADD_FN(Algorithm::CN_2); ADD_FN(Algorithm::CN_R); - ADD_FN(Algorithm::CN_WOW); ADD_FN(Algorithm::CN_FAST); ADD_FN(Algorithm::CN_HALF); ADD_FN(Algorithm::CN_XAO); @@ -223,7 +221,6 @@ xmrig::CnHash::CnHash() ADD_FN_ASM(Algorithm::CN_2); ADD_FN_ASM(Algorithm::CN_HALF); ADD_FN_ASM(Algorithm::CN_R); - ADD_FN_ASM(Algorithm::CN_WOW); ADD_FN_ASM(Algorithm::CN_RWZ); ADD_FN_ASM(Algorithm::CN_ZLS); ADD_FN_ASM(Algorithm::CN_DOUBLE); @@ -249,6 +246,13 @@ xmrig::CnHash::CnHash() ADD_FN_ASM(Algorithm::CN_PICO_0); # endif +# ifdef XMRIG_ALGO_ARGON2 + m_map[Algorithm::AR2_CHUKWA][AV_SINGLE][Assembly::NONE] = argon2::single_hash; + m_map[Algorithm::AR2_CHUKWA][AV_SINGLE_SOFT][Assembly::NONE] = argon2::single_hash; + m_map[Algorithm::AR2_WRKZ][AV_SINGLE][Assembly::NONE] = argon2::single_hash; + m_map[Algorithm::AR2_WRKZ][AV_SINGLE_SOFT][Assembly::NONE] = argon2::single_hash; +# endif + # ifdef XMRIG_FEATURE_ASM patchAsmVariants(); # endif diff --git a/src/crypto/cn/CnHash.h b/src/crypto/cn/CnHash.h index e4a7ebd22..92f4df942 100644 --- a/src/crypto/cn/CnHash.h +++ b/src/crypto/cn/CnHash.h @@ -27,8 +27,8 @@ #define XMRIG_CN_HASH_H -#include -#include +#include +#include #include "crypto/cn/CnAlgo.h" @@ -41,8 +41,8 @@ struct cryptonight_ctx; namespace xmrig { -typedef void (*cn_hash_fun)(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx **ctx, uint64_t height); -typedef void (*cn_mainloop_fun)(cryptonight_ctx **ctx); +using cn_hash_fun = void (*)(const uint8_t *, size_t, uint8_t *, cryptonight_ctx **, uint64_t); +using cn_mainloop_fun = void (*)(cryptonight_ctx **); class CnHash diff --git a/src/crypto/cn/CryptoNight_test.h b/src/crypto/cn/CryptoNight_test.h index 77cbbb8e1..644895704 100644 --- a/src/crypto/cn/CryptoNight_test.h +++ b/src/crypto/cn/CryptoNight_test.h @@ -30,6 +30,9 @@ #include +namespace xmrig { + + const static uint8_t test_input[380] = { 0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00, 0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B, @@ -81,21 +84,6 @@ const static cn_r_test_input_data cn_r_test_input[] = { }; -// "cn/wow" -const static uint8_t test_output_wow[] = { - 0x9d, 0x47, 0xbf, 0x4c, 0x41, 0xb7, 0xe8, 0xe7, 0x27, 0xe6, 0x81, 0x71, 0x5a, 0xcb, 0x47, 0xfa, 0x16, 0x77, 0xcd, 0xba, 0x9c, 0xa7, 0xbc, 0xb0, 0x5a, 0xd8, 0xcc, 0x8a, 0xbd, 0x5d, 0xaa, 0x66, - 0x0d, 0x4a, 0x49, 0x5c, 0xb8, 0x44, 0xa3, 0xca, 0x8b, 0xa4, 0xed, 0xb8, 0xe6, 0xbc, 0xf8, 0x29, 0xef, 0x1c, 0x06, 0xd9, 0xcd, 0xea, 0x2b, 0x62, 0xca, 0x46, 0xc2, 0xa2, 0x1b, 0x8b, 0x0a, 0x79, - 0xa1, 0xd6, 0xd8, 0x48, 0xb5, 0xc5, 0x91, 0x5f, 0xcc, 0xd2, 0xf6, 0x4c, 0xf2, 0x16, 0xc6, 0xb1, 0xa0, 0x2c, 0xf7, 0xc7, 0x7b, 0xc8, 0x0d, 0x8d, 0x4e, 0x51, 0xb4, 0x19, 0xe8, 0x8f, 0xf0, 0xdd, - 0xaf, 0x3a, 0x85, 0x44, 0xa0, 0x22, 0x1a, 0x14, 0x8c, 0x2a, 0xc9, 0x04, 0x84, 0xb1, 0x98, 0x61, 0xe3, 0xaf, 0xca, 0x33, 0xfe, 0x17, 0x02, 0x1e, 0xfb, 0x8a, 0xd6, 0x49, 0x6b, 0x56, 0x79, 0x15, - 0x31, 0x33, 0x99, 0xe0, 0x96, 0x3a, 0xe8, 0xa9, 0x9d, 0xab, 0x8a, 0xf6, 0x6d, 0x34, 0x3e, 0x09, 0x7d, 0xae, 0x0c, 0x0f, 0xeb, 0x08, 0xdb, 0xc4, 0x3c, 0xcd, 0xaf, 0xef, 0x55, 0x15, 0xf4, 0x13, - 0x60, 0x21, 0xc6, 0xef, 0x90, 0xbf, 0xf9, 0xae, 0x94, 0xa7, 0x50, 0x6d, 0x62, 0x3d, 0x3a, 0x7a, 0x86, 0xc1, 0x75, 0x6d, 0x65, 0x5f, 0x50, 0xdd, 0x55, 0x8f, 0x71, 0x6d, 0x64, 0x62, 0x2a, 0x34, - 0x2b, 0x13, 0x00, 0x05, 0x35, 0xf3, 0xdb, 0x5f, 0x9b, 0x9b, 0x84, 0xa6, 0x5c, 0x43, 0x51, 0xf3, 0x86, 0xcd, 0x2c, 0xde, 0xde, 0xbb, 0x8c, 0x3a, 0xd2, 0xea, 0xb0, 0x86, 0xe6, 0xa3, 0xfe, 0xe5, - 0xfc, 0x0e, 0x1d, 0xad, 0x8e, 0x89, 0x57, 0x49, 0xdc, 0x90, 0xeb, 0x69, 0x0b, 0xc1, 0xba, 0x05, 0x9a, 0x1c, 0xd7, 0x72, 0xaf, 0xaa, 0xf6, 0x5a, 0x10, 0x6b, 0xf9, 0xe5, 0xe6, 0xb8, 0x05, 0x03, - 0xb6, 0x0b, 0x0a, 0xfe, 0x14, 0x4d, 0xef, 0xf7, 0xd9, 0x03, 0xed, 0x2d, 0x55, 0x45, 0xe7, 0x7e, 0xbe, 0x66, 0xa3, 0xc5, 0x1f, 0xee, 0x70, 0x16, 0xee, 0xb8, 0xfe, 0xe9, 0xeb, 0x63, 0x0c, 0x0f, - 0x64, 0x77, 0x4b, 0x27, 0xe7, 0xd5, 0xfe, 0xc8, 0x62, 0xfc, 0x4c, 0x0c, 0x13, 0xac, 0x6b, 0xf0, 0x91, 0x23, 0xb6, 0xf0, 0x5b, 0xb0, 0xe4, 0xb7, 0x5c, 0x97, 0xf3, 0x79, 0xa2, 0xb3, 0xa6, 0x79, -}; - - // "cn/r" const static uint8_t test_output_r[] = { 0xf7, 0x59, 0x58, 0x8a, 0xd5, 0x7e, 0x75, 0x84, 0x67, 0x29, 0x54, 0x43, 0xa9, 0xbd, 0x71, 0x49, 0x0a, 0xbf, 0xf8, 0xe9, 0xda, 0xd1, 0xb9, 0x5b, 0x6b, 0xf2, 0xf5, 0xd0, 0xd7, 0x83, 0x87, 0xbc, @@ -365,9 +353,43 @@ const static uint8_t test_output_gpu[160] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif +#ifdef XMRIG_ALGO_ARGON2 +// "argon2/chukwa" +const static uint8_t argon2_chukwa_test_out[160] = { + 0xC1, 0x58, 0xA1, 0x05, 0xAE, 0x75, 0xC7, 0x56, 0x1C, 0xFD, 0x02, 0x90, 0x83, 0xA4, 0x7A, 0x87, + 0x65, 0x3D, 0x51, 0xF9, 0x14, 0x12, 0x8E, 0x21, 0xC1, 0x97, 0x1D, 0x8B, 0x10, 0xC4, 0x90, 0x34, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// "argon2/wrkz" +const static uint8_t argon2_wrkz_test_out[160] = { + 0x35, 0xE0, 0x83, 0xD4, 0xB9, 0xC6, 0x4C, 0x2A, 0x68, 0x82, 0x0A, 0x43, 0x1F, 0x61, 0x31, 0x19, + 0x98, 0xA8, 0xCD, 0x18, 0x64, 0xDB, 0xA4, 0x07, 0x7E, 0x25, 0xB7, 0xF1, 0x21, 0xD5, 0x4B, 0xD1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#endif + + +} // namespace xmrig + + #endif /* XMRIG_CRYPTONIGHT_TEST_H */ diff --git a/src/crypto/cn/CryptoNight_x86.h b/src/crypto/cn/CryptoNight_x86.h index ae51cd182..9fb606d49 100644 --- a/src/crypto/cn/CryptoNight_x86.h +++ b/src/crypto/cn/CryptoNight_x86.h @@ -514,7 +514,6 @@ static inline __m128i int_sqrt_v2(const uint64_t n0) } -void wow_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); void v4_soft_aes_compile_code(const V4_Instruction *code, int code_size, void *machine_code, xmrig::Assembly ASM); @@ -576,10 +575,7 @@ inline void cryptonight_single_hash(const uint8_t *__restrict__ input, size_t si V4_Instruction code[256]; const int code_size = v4_random_math_init(code, height); - if (ALGO == Algorithm::CN_WOW) { - wow_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); - } - else if (ALGO == Algorithm::CN_R) { + if (ALGO == Algorithm::CN_R) { v4_soft_aes_compile_code(code, code_size, reinterpret_cast(ctx[0]->generated_code), Assembly::NONE); } @@ -812,9 +808,7 @@ extern cn_mainloop_fun cn_double_double_mainloop_sandybridge_asm; } // namespace xmrig -void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); -void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM); @@ -832,20 +826,6 @@ void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* m } -template<> -void cn_r_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) -{ - wow_compile_code(code, code_size, machine_code, ASM); -} - - -template<> -void cn_r_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) -{ - wow_compile_code_double(code, code_size, machine_code, ASM); -} - - namespace xmrig { diff --git a/src/crypto/cn/asm/CryptonightR_template.S b/src/crypto/cn/asm/CryptonightR_template.S index d2974d160..c7e3caa08 100644 --- a/src/crypto/cn/asm/CryptonightR_template.S +++ b/src/crypto/cn/asm/CryptonightR_template.S @@ -529,9 +529,7 @@ PUBLIC FN_PREFIX(CryptonightR_instruction_mov254) PUBLIC FN_PREFIX(CryptonightR_instruction_mov255) PUBLIC FN_PREFIX(CryptonightR_instruction_mov256) -#include "CryptonightWOW_template.inc" #include "CryptonightR_template.inc" -#include "CryptonightWOW_soft_aes_template.inc" #include "CryptonightR_soft_aes_template.inc" FN_PREFIX(CryptonightR_instruction0): @@ -1593,3 +1591,7 @@ FN_PREFIX(CryptonightR_instruction_mov254): FN_PREFIX(CryptonightR_instruction_mov255): FN_PREFIX(CryptonightR_instruction_mov256): + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/crypto/cn/asm/CryptonightR_template.asm b/src/crypto/cn/asm/CryptonightR_template.asm index 250eca3d0..8424434da 100644 --- a/src/crypto/cn/asm/CryptonightR_template.asm +++ b/src/crypto/cn/asm/CryptonightR_template.asm @@ -516,9 +516,7 @@ PUBLIC CryptonightR_instruction_mov254 PUBLIC CryptonightR_instruction_mov255 PUBLIC CryptonightR_instruction_mov256 -INCLUDE CryptonightWOW_template_win.inc INCLUDE CryptonightR_template_win.inc -INCLUDE CryptonightWOW_soft_aes_template_win.inc INCLUDE CryptonightR_soft_aes_template_win.inc CryptonightR_instruction0: diff --git a/src/crypto/cn/asm/CryptonightR_template.h b/src/crypto/cn/asm/CryptonightR_template.h index d9159a8f2..fc6ea8815 100644 --- a/src/crypto/cn/asm/CryptonightR_template.h +++ b/src/crypto/cn/asm/CryptonightR_template.h @@ -2,18 +2,6 @@ extern "C" { - void CryptonightWOW_template_part1(); - void CryptonightWOW_template_mainloop(); - void CryptonightWOW_template_part2(); - void CryptonightWOW_template_part3(); - void CryptonightWOW_template_end(); - void CryptonightWOW_template_double_part1(); - void CryptonightWOW_template_double_mainloop(); - void CryptonightWOW_template_double_part2(); - void CryptonightWOW_template_double_part3(); - void CryptonightWOW_template_double_part4(); - void CryptonightWOW_template_double_end(); - void CryptonightR_template_part1(); void CryptonightR_template_mainloop(); void CryptonightR_template_part2(); @@ -26,18 +14,6 @@ extern "C" void CryptonightR_template_double_part4(); void CryptonightR_template_double_end(); - void CryptonightWOW_soft_aes_template_part1(); - void CryptonightWOW_soft_aes_template_mainloop(); - void CryptonightWOW_soft_aes_template_part2(); - void CryptonightWOW_soft_aes_template_part3(); - void CryptonightWOW_soft_aes_template_end(); - void CryptonightWOW_soft_aes_template_double_part1(); - void CryptonightWOW_soft_aes_template_double_mainloop(); - void CryptonightWOW_soft_aes_template_double_part2(); - void CryptonightWOW_soft_aes_template_double_part3(); - void CryptonightWOW_soft_aes_template_double_part4(); - void CryptonightWOW_soft_aes_template_double_end(); - void CryptonightR_soft_aes_template_part1(); void CryptonightR_soft_aes_template_mainloop(); void CryptonightR_soft_aes_template_part2(); diff --git a/src/crypto/cn/asm/CryptonightWOW_soft_aes_template.inc b/src/crypto/cn/asm/CryptonightWOW_soft_aes_template.inc deleted file mode 100644 index 53b7016a0..000000000 --- a/src/crypto/cn/asm/CryptonightWOW_soft_aes_template.inc +++ /dev/null @@ -1,268 +0,0 @@ -PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part1) -PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop) -PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part2) -PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_part3) -PUBLIC FN_PREFIX(CryptonightWOW_soft_aes_template_end) - -ALIGN(64) -FN_PREFIX(CryptonightWOW_soft_aes_template_part1): - mov rcx, [rcx] - - mov QWORD PTR [rsp+8], rcx - push rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 232 - - mov eax, [rcx+96] - mov ebx, [rcx+100] - mov esi, [rcx+104] - mov edx, [rcx+108] - mov [rsp+144], eax - mov [rsp+148], ebx - mov [rsp+152], esi - mov [rsp+156], edx - - mov rax, QWORD PTR [rcx+48] - mov r10, rcx - xor rax, QWORD PTR [rcx+16] - mov r8, QWORD PTR [rcx+32] - xor r8, QWORD PTR [rcx] - mov r9, QWORD PTR [rcx+40] - xor r9, QWORD PTR [rcx+8] - movq xmm4, rax - mov rdx, QWORD PTR [rcx+56] - xor rdx, QWORD PTR [rcx+24] - mov r11, QWORD PTR [rcx+224] - mov rcx, QWORD PTR [rcx+88] - xor rcx, QWORD PTR [r10+72] - mov rax, QWORD PTR [r10+80] - movq xmm0, rdx - xor rax, QWORD PTR [r10+64] - - movaps XMMWORD PTR [rsp+16], xmm6 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+48], xmm8 - movaps XMMWORD PTR [rsp+64], xmm9 - movaps XMMWORD PTR [rsp+80], xmm10 - movaps XMMWORD PTR [rsp+96], xmm11 - movaps XMMWORD PTR [rsp+112], xmm12 - movaps XMMWORD PTR [rsp+128], xmm13 - - movq xmm5, rax - - mov rax, r8 - punpcklqdq xmm4, xmm0 - and eax, 2097136 - movq xmm10, QWORD PTR [r10+96] - movq xmm0, rcx - mov rcx, QWORD PTR [r10+104] - xorps xmm9, xmm9 - mov QWORD PTR [rsp+328], rax - movq xmm12, r11 - mov QWORD PTR [rsp+320], r9 - punpcklqdq xmm5, xmm0 - movq xmm13, rcx - mov r12d, 524288 - - ALIGN(64) -FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop): - movd xmm11, r12d - mov r12, QWORD PTR [r10+272] - lea r13, QWORD PTR [rax+r11] - mov esi, DWORD PTR [r13] - movq xmm0, r9 - mov r10d, DWORD PTR [r13+4] - movq xmm7, r8 - mov ebp, DWORD PTR [r13+12] - mov r14d, DWORD PTR [r13+8] - mov rdx, QWORD PTR [rsp+328] - movzx ecx, sil - shr esi, 8 - punpcklqdq xmm7, xmm0 - mov r15d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - mov edi, DWORD PTR [r12+rcx*4] - movzx ecx, r14b - shr r14d, 8 - mov ebx, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - shr ebp, 8 - mov r9d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - xor r15d, DWORD PTR [r12+rcx*4+1024] - movzx ecx, r14b - shr r14d, 8 - mov eax, r14d - shr eax, 8 - xor edi, DWORD PTR [r12+rcx*4+1024] - add eax, 256 - movzx ecx, bpl - shr ebp, 8 - xor ebx, DWORD PTR [r12+rcx*4+1024] - movzx ecx, sil - shr esi, 8 - xor r9d, DWORD PTR [r12+rcx*4+1024] - add r12, 2048 - movzx ecx, r10b - shr r10d, 8 - add r10d, 256 - mov r11d, DWORD PTR [r12+rax*4] - xor r11d, DWORD PTR [r12+rcx*4] - xor r11d, r9d - movzx ecx, sil - mov r10d, DWORD PTR [r12+r10*4] - shr esi, 8 - add esi, 256 - xor r10d, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - xor r10d, ebx - shr ebp, 8 - movd xmm1, r11d - add ebp, 256 - movq r11, xmm12 - mov r9d, DWORD PTR [r12+rcx*4] - xor r9d, DWORD PTR [r12+rsi*4] - mov eax, DWORD PTR [r12+rbp*4] - xor r9d, edi - movzx ecx, r14b - movd xmm0, r10d - movd xmm2, r9d - xor eax, DWORD PTR [r12+rcx*4] - mov rcx, rdx - xor eax, r15d - punpckldq xmm2, xmm1 - xor rcx, 16 - movd xmm6, eax - mov rax, rdx - punpckldq xmm6, xmm0 - xor rax, 32 - punpckldq xmm6, xmm2 - xor rdx, 48 - movdqu xmm2, XMMWORD PTR [rcx+r11] - pxor xmm6, xmm7 - paddq xmm2, xmm4 - movdqu xmm1, XMMWORD PTR [rax+r11] - movdqu xmm0, XMMWORD PTR [rdx+r11] - paddq xmm0, xmm5 - movdqu XMMWORD PTR [rcx+r11], xmm0 - movdqu XMMWORD PTR [rax+r11], xmm2 - movq rcx, xmm13 - paddq xmm1, xmm7 - movdqu XMMWORD PTR [rdx+r11], xmm1 - movq rdi, xmm6 - mov r10, rdi - and r10d, 2097136 - movdqa xmm0, xmm6 - pxor xmm0, xmm4 - movdqu XMMWORD PTR [r13], xmm0 - - mov ebx, [rsp+144] - mov ebp, [rsp+152] - add ebx, [rsp+148] - add ebp, [rsp+156] - shl rbp, 32 - or rbx, rbp - - xor rbx, QWORD PTR [r10+r11] - lea r14, QWORD PTR [r10+r11] - mov rbp, QWORD PTR [r14+8] - - mov [rsp+160], rbx - mov [rsp+168], rdi - mov [rsp+176], rbp - mov [rsp+184], r10 - mov r10, rsp - - mov ebx, [rsp+144] - mov esi, [rsp+148] - mov edi, [rsp+152] - mov ebp, [rsp+156] - - movd esp, xmm7 - movaps xmm0, xmm7 - psrldq xmm0, 8 - movd r15d, xmm0 - movd eax, xmm4 - movd edx, xmm5 - -FN_PREFIX(CryptonightWOW_soft_aes_template_part2): - mov rsp, r10 - mov [rsp+144], ebx - mov [rsp+148], esi - mov [rsp+152], edi - mov [rsp+156], ebp - - mov rbx, [rsp+160] - mov rdi, [rsp+168] - mov rbp, [rsp+176] - mov r10, [rsp+184] - - mov r9, r10 - xor r9, 16 - mov rcx, r10 - xor rcx, 32 - xor r10, 48 - mov rax, rbx - mul rdi - movdqu xmm2, XMMWORD PTR [r9+r11] - movdqu xmm1, XMMWORD PTR [rcx+r11] - paddq xmm1, xmm7 - movq xmm0, rax - movq xmm3, rdx - xor rax, QWORD PTR [r11+rcx+8] - xor rdx, QWORD PTR [rcx+r11] - punpcklqdq xmm3, xmm0 - add r8, rdx - movdqu xmm0, XMMWORD PTR [r10+r11] - pxor xmm2, xmm3 - paddq xmm0, xmm5 - paddq xmm2, xmm4 - movdqu XMMWORD PTR [r9+r11], xmm0 - movdqa xmm5, xmm4 - mov r9, QWORD PTR [rsp+320] - movdqa xmm4, xmm6 - add r9, rax - movdqu XMMWORD PTR [rcx+r11], xmm2 - movdqu XMMWORD PTR [r10+r11], xmm1 - mov r10, QWORD PTR [rsp+304] - movd r12d, xmm11 - mov QWORD PTR [r14], r8 - xor r8, rbx - mov rax, r8 - mov QWORD PTR [r14+8], r9 - and eax, 2097136 - xor r9, rbp - mov QWORD PTR [rsp+320], r9 - mov QWORD PTR [rsp+328], rax - sub r12d, 1 - jne FN_PREFIX(CryptonightWOW_soft_aes_template_mainloop) - -FN_PREFIX(CryptonightWOW_soft_aes_template_part3): - movaps xmm6, XMMWORD PTR [rsp+16] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+48] - movaps xmm9, XMMWORD PTR [rsp+64] - movaps xmm10, XMMWORD PTR [rsp+80] - movaps xmm11, XMMWORD PTR [rsp+96] - movaps xmm12, XMMWORD PTR [rsp+112] - movaps xmm13, XMMWORD PTR [rsp+128] - - add rsp, 232 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - pop rbx - ret -FN_PREFIX(CryptonightWOW_soft_aes_template_end): diff --git a/src/crypto/cn/asm/CryptonightWOW_soft_aes_template_win.inc b/src/crypto/cn/asm/CryptonightWOW_soft_aes_template_win.inc deleted file mode 100644 index b3202b781..000000000 --- a/src/crypto/cn/asm/CryptonightWOW_soft_aes_template_win.inc +++ /dev/null @@ -1,268 +0,0 @@ -PUBLIC CryptonightWOW_soft_aes_template_part1 -PUBLIC CryptonightWOW_soft_aes_template_mainloop -PUBLIC CryptonightWOW_soft_aes_template_part2 -PUBLIC CryptonightWOW_soft_aes_template_part3 -PUBLIC CryptonightWOW_soft_aes_template_end - -ALIGN(64) -CryptonightWOW_soft_aes_template_part1: - mov rcx, [rcx] - - mov QWORD PTR [rsp+8], rcx - push rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 232 - - mov eax, [rcx+96] - mov ebx, [rcx+100] - mov esi, [rcx+104] - mov edx, [rcx+108] - mov [rsp+144], eax - mov [rsp+148], ebx - mov [rsp+152], esi - mov [rsp+156], edx - - mov rax, QWORD PTR [rcx+48] - mov r10, rcx - xor rax, QWORD PTR [rcx+16] - mov r8, QWORD PTR [rcx+32] - xor r8, QWORD PTR [rcx] - mov r9, QWORD PTR [rcx+40] - xor r9, QWORD PTR [rcx+8] - movq xmm4, rax - mov rdx, QWORD PTR [rcx+56] - xor rdx, QWORD PTR [rcx+24] - mov r11, QWORD PTR [rcx+224] - mov rcx, QWORD PTR [rcx+88] - xor rcx, QWORD PTR [r10+72] - mov rax, QWORD PTR [r10+80] - movq xmm0, rdx - xor rax, QWORD PTR [r10+64] - - movaps XMMWORD PTR [rsp+16], xmm6 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+48], xmm8 - movaps XMMWORD PTR [rsp+64], xmm9 - movaps XMMWORD PTR [rsp+80], xmm10 - movaps XMMWORD PTR [rsp+96], xmm11 - movaps XMMWORD PTR [rsp+112], xmm12 - movaps XMMWORD PTR [rsp+128], xmm13 - - movq xmm5, rax - - mov rax, r8 - punpcklqdq xmm4, xmm0 - and eax, 2097136 - movq xmm10, QWORD PTR [r10+96] - movq xmm0, rcx - mov rcx, QWORD PTR [r10+104] - xorps xmm9, xmm9 - mov QWORD PTR [rsp+328], rax - movq xmm12, r11 - mov QWORD PTR [rsp+320], r9 - punpcklqdq xmm5, xmm0 - movq xmm13, rcx - mov r12d, 524288 - - ALIGN(64) -CryptonightWOW_soft_aes_template_mainloop: - movd xmm11, r12d - mov r12, QWORD PTR [r10+272] - lea r13, QWORD PTR [rax+r11] - mov esi, DWORD PTR [r13] - movq xmm0, r9 - mov r10d, DWORD PTR [r13+4] - movq xmm7, r8 - mov ebp, DWORD PTR [r13+12] - mov r14d, DWORD PTR [r13+8] - mov rdx, QWORD PTR [rsp+328] - movzx ecx, sil - shr esi, 8 - punpcklqdq xmm7, xmm0 - mov r15d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - mov edi, DWORD PTR [r12+rcx*4] - movzx ecx, r14b - shr r14d, 8 - mov ebx, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - shr ebp, 8 - mov r9d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - xor r15d, DWORD PTR [r12+rcx*4+1024] - movzx ecx, r14b - shr r14d, 8 - mov eax, r14d - shr eax, 8 - xor edi, DWORD PTR [r12+rcx*4+1024] - add eax, 256 - movzx ecx, bpl - shr ebp, 8 - xor ebx, DWORD PTR [r12+rcx*4+1024] - movzx ecx, sil - shr esi, 8 - xor r9d, DWORD PTR [r12+rcx*4+1024] - add r12, 2048 - movzx ecx, r10b - shr r10d, 8 - add r10d, 256 - mov r11d, DWORD PTR [r12+rax*4] - xor r11d, DWORD PTR [r12+rcx*4] - xor r11d, r9d - movzx ecx, sil - mov r10d, DWORD PTR [r12+r10*4] - shr esi, 8 - add esi, 256 - xor r10d, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - xor r10d, ebx - shr ebp, 8 - movd xmm1, r11d - add ebp, 256 - movq r11, xmm12 - mov r9d, DWORD PTR [r12+rcx*4] - xor r9d, DWORD PTR [r12+rsi*4] - mov eax, DWORD PTR [r12+rbp*4] - xor r9d, edi - movzx ecx, r14b - movd xmm0, r10d - movd xmm2, r9d - xor eax, DWORD PTR [r12+rcx*4] - mov rcx, rdx - xor eax, r15d - punpckldq xmm2, xmm1 - xor rcx, 16 - movd xmm6, eax - mov rax, rdx - punpckldq xmm6, xmm0 - xor rax, 32 - punpckldq xmm6, xmm2 - xor rdx, 48 - movdqu xmm2, XMMWORD PTR [rcx+r11] - pxor xmm6, xmm7 - paddq xmm2, xmm4 - movdqu xmm1, XMMWORD PTR [rax+r11] - movdqu xmm0, XMMWORD PTR [rdx+r11] - paddq xmm0, xmm5 - movdqu XMMWORD PTR [rcx+r11], xmm0 - movdqu XMMWORD PTR [rax+r11], xmm2 - movq rcx, xmm13 - paddq xmm1, xmm7 - movdqu XMMWORD PTR [rdx+r11], xmm1 - movq rdi, xmm6 - mov r10, rdi - and r10d, 2097136 - movdqa xmm0, xmm6 - pxor xmm0, xmm4 - movdqu XMMWORD PTR [r13], xmm0 - - mov ebx, [rsp+144] - mov ebp, [rsp+152] - add ebx, [rsp+148] - add ebp, [rsp+156] - shl rbp, 32 - or rbx, rbp - - xor rbx, QWORD PTR [r10+r11] - lea r14, QWORD PTR [r10+r11] - mov rbp, QWORD PTR [r14+8] - - mov [rsp+160], rbx - mov [rsp+168], rdi - mov [rsp+176], rbp - mov [rsp+184], r10 - mov r10, rsp - - mov ebx, [rsp+144] - mov esi, [rsp+148] - mov edi, [rsp+152] - mov ebp, [rsp+156] - - movd esp, xmm7 - movaps xmm0, xmm7 - psrldq xmm0, 8 - movd r15d, xmm0 - movd eax, xmm4 - movd edx, xmm5 - -CryptonightWOW_soft_aes_template_part2: - mov rsp, r10 - mov [rsp+144], ebx - mov [rsp+148], esi - mov [rsp+152], edi - mov [rsp+156], ebp - - mov rbx, [rsp+160] - mov rdi, [rsp+168] - mov rbp, [rsp+176] - mov r10, [rsp+184] - - mov r9, r10 - xor r9, 16 - mov rcx, r10 - xor rcx, 32 - xor r10, 48 - mov rax, rbx - mul rdi - movdqu xmm2, XMMWORD PTR [r9+r11] - movdqu xmm1, XMMWORD PTR [rcx+r11] - paddq xmm1, xmm7 - movq xmm0, rax - movq xmm3, rdx - xor rax, QWORD PTR [r11+rcx+8] - xor rdx, QWORD PTR [rcx+r11] - punpcklqdq xmm3, xmm0 - add r8, rdx - movdqu xmm0, XMMWORD PTR [r10+r11] - pxor xmm2, xmm3 - paddq xmm0, xmm5 - paddq xmm2, xmm4 - movdqu XMMWORD PTR [r9+r11], xmm0 - movdqa xmm5, xmm4 - mov r9, QWORD PTR [rsp+320] - movdqa xmm4, xmm6 - add r9, rax - movdqu XMMWORD PTR [rcx+r11], xmm2 - movdqu XMMWORD PTR [r10+r11], xmm1 - mov r10, QWORD PTR [rsp+304] - movd r12d, xmm11 - mov QWORD PTR [r14], r8 - xor r8, rbx - mov rax, r8 - mov QWORD PTR [r14+8], r9 - and eax, 2097136 - xor r9, rbp - mov QWORD PTR [rsp+320], r9 - mov QWORD PTR [rsp+328], rax - sub r12d, 1 - jne CryptonightWOW_soft_aes_template_mainloop - -CryptonightWOW_soft_aes_template_part3: - movaps xmm6, XMMWORD PTR [rsp+16] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+48] - movaps xmm9, XMMWORD PTR [rsp+64] - movaps xmm10, XMMWORD PTR [rsp+80] - movaps xmm11, XMMWORD PTR [rsp+96] - movaps xmm12, XMMWORD PTR [rsp+112] - movaps xmm13, XMMWORD PTR [rsp+128] - - add rsp, 232 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - pop rbx - ret -CryptonightWOW_soft_aes_template_end: diff --git a/src/crypto/cn/asm/CryptonightWOW_template.inc b/src/crypto/cn/asm/CryptonightWOW_template.inc deleted file mode 100644 index 82d455f6d..000000000 --- a/src/crypto/cn/asm/CryptonightWOW_template.inc +++ /dev/null @@ -1,491 +0,0 @@ -PUBLIC FN_PREFIX(CryptonightWOW_template_part1) -PUBLIC FN_PREFIX(CryptonightWOW_template_mainloop) -PUBLIC FN_PREFIX(CryptonightWOW_template_part2) -PUBLIC FN_PREFIX(CryptonightWOW_template_part3) -PUBLIC FN_PREFIX(CryptonightWOW_template_end) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_part1) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_mainloop) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_part2) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_part3) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_part4) -PUBLIC FN_PREFIX(CryptonightWOW_template_double_end) - -ALIGN(64) -FN_PREFIX(CryptonightWOW_template_part1): - mov rcx, [rcx] - - mov QWORD PTR [rsp+16], rbx - mov QWORD PTR [rsp+24], rbp - mov QWORD PTR [rsp+32], rsi - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - push rdi - sub rsp, 64 - mov r12, rcx - mov r8, QWORD PTR [r12+32] - mov rdx, r12 - xor r8, QWORD PTR [r12] - mov r15, QWORD PTR [r12+40] - mov r9, r8 - xor r15, QWORD PTR [r12+8] - mov r11, QWORD PTR [r12+224] - mov r12, QWORD PTR [r12+56] - xor r12, QWORD PTR [rdx+24] - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - movaps XMMWORD PTR [rsp+48], xmm6 - movq xmm0, r12 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+16], xmm8 - movaps XMMWORD PTR [rsp], xmm9 - mov r12, QWORD PTR [rdx+88] - xor r12, QWORD PTR [rdx+72] - movq xmm6, rax - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm6, xmm0 - and r9d, 2097136 - movq xmm0, r12 - movq xmm7, rax - punpcklqdq xmm7, xmm0 - mov r10d, r9d - movq xmm9, rsp - mov rsp, r8 - mov r8d, 524288 - - mov ebx, [rdx+96] - mov esi, [rdx+100] - mov edi, [rdx+104] - mov ebp, [rdx+108] - - ALIGN(64) -FN_PREFIX(CryptonightWOW_template_mainloop): - movdqa xmm5, XMMWORD PTR [r9+r11] - movq xmm0, r15 - movq xmm4, rsp - punpcklqdq xmm4, xmm0 - lea rdx, QWORD PTR [r9+r11] - - aesenc xmm5, xmm4 - movd r10d, xmm5 - and r10d, 2097136 - - mov r12d, r9d - mov eax, r9d - xor r9d, 48 - xor r12d, 16 - xor eax, 32 - movdqu xmm0, XMMWORD PTR [r9+r11] - movdqu xmm2, XMMWORD PTR [r12+r11] - movdqu xmm1, XMMWORD PTR [rax+r11] - paddq xmm0, xmm7 - paddq xmm2, xmm6 - paddq xmm1, xmm4 - movdqu XMMWORD PTR [r12+r11], xmm0 - movq r12, xmm5 - movdqu XMMWORD PTR [rax+r11], xmm2 - movdqu XMMWORD PTR [r9+r11], xmm1 - - movdqa xmm0, xmm5 - pxor xmm0, xmm6 - movdqu XMMWORD PTR [rdx], xmm0 - - lea r13d, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or r13, rdx - - xor r13, QWORD PTR [r10+r11] - mov r14, QWORD PTR [r10+r11+8] - - movd eax, xmm6 - movd edx, xmm7 - pextrd r9d, xmm7, 2 - -FN_PREFIX(CryptonightWOW_template_part2): - mov rax, r13 - mul r12 - movq xmm0, rax - movq xmm3, rdx - punpcklqdq xmm3, xmm0 - - mov r9d, r10d - mov r12d, r10d - xor r9d, 16 - xor r12d, 32 - xor r10d, 48 - movdqa xmm1, XMMWORD PTR [r12+r11] - xor rdx, QWORD PTR [r12+r11] - xor rax, QWORD PTR [r11+r12+8] - movdqa xmm2, XMMWORD PTR [r9+r11] - pxor xmm3, xmm2 - paddq xmm7, XMMWORD PTR [r10+r11] - paddq xmm1, xmm4 - paddq xmm3, xmm6 - movdqu XMMWORD PTR [r9+r11], xmm7 - movdqu XMMWORD PTR [r12+r11], xmm3 - movdqu XMMWORD PTR [r10+r11], xmm1 - - movdqa xmm7, xmm6 - add r15, rax - add rsp, rdx - xor r10, 48 - mov QWORD PTR [r10+r11], rsp - xor rsp, r13 - mov r9d, esp - mov QWORD PTR [r10+r11+8], r15 - and r9d, 2097136 - xor r15, r14 - movdqa xmm6, xmm5 - dec r8d - jnz FN_PREFIX(CryptonightWOW_template_mainloop) - -FN_PREFIX(CryptonightWOW_template_part3): - movq rsp, xmm9 - - mov rbx, QWORD PTR [rsp+136] - mov rbp, QWORD PTR [rsp+144] - mov rsi, QWORD PTR [rsp+152] - movaps xmm6, XMMWORD PTR [rsp+48] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+16] - movaps xmm9, XMMWORD PTR [rsp] - add rsp, 64 - pop rdi - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - ret 0 -FN_PREFIX(CryptonightWOW_template_end): - -ALIGN(64) -FN_PREFIX(CryptonightWOW_template_double_part1): - mov rdx, [rcx+8] - mov rcx, [rcx] - - mov QWORD PTR [rsp+24], rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 320 - mov r14, QWORD PTR [rcx+32] - mov r8, rcx - xor r14, QWORD PTR [rcx] - mov r12, QWORD PTR [rcx+40] - mov ebx, r14d - mov rsi, QWORD PTR [rcx+224] - and ebx, 2097136 - xor r12, QWORD PTR [rcx+8] - mov rcx, QWORD PTR [rcx+56] - xor rcx, QWORD PTR [r8+24] - mov rax, QWORD PTR [r8+48] - xor rax, QWORD PTR [r8+16] - mov r15, QWORD PTR [rdx+32] - xor r15, QWORD PTR [rdx] - movq xmm0, rcx - mov rcx, QWORD PTR [r8+88] - xor rcx, QWORD PTR [r8+72] - mov r13, QWORD PTR [rdx+40] - mov rdi, QWORD PTR [rdx+224] - xor r13, QWORD PTR [rdx+8] - movaps XMMWORD PTR [rsp+160], xmm6 - movaps XMMWORD PTR [rsp+176], xmm7 - movaps XMMWORD PTR [rsp+192], xmm8 - movaps XMMWORD PTR [rsp+208], xmm9 - movaps XMMWORD PTR [rsp+224], xmm10 - movaps XMMWORD PTR [rsp+240], xmm11 - movaps XMMWORD PTR [rsp+256], xmm12 - movaps XMMWORD PTR [rsp+272], xmm13 - movaps XMMWORD PTR [rsp+288], xmm14 - movaps XMMWORD PTR [rsp+304], xmm15 - movq xmm7, rax - mov rax, QWORD PTR [r8+80] - xor rax, QWORD PTR [r8+64] - - movaps xmm1, XMMWORD PTR [rdx+96] - movaps xmm2, XMMWORD PTR [r8+96] - movaps XMMWORD PTR [rsp], xmm1 - movaps XMMWORD PTR [rsp+16], xmm2 - - mov r8d, r15d - punpcklqdq xmm7, xmm0 - movq xmm0, rcx - mov rcx, QWORD PTR [rdx+56] - xor rcx, QWORD PTR [rdx+24] - movq xmm9, rax - mov QWORD PTR [rsp+128], rsi - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - punpcklqdq xmm9, xmm0 - movq xmm0, rcx - mov rcx, QWORD PTR [rdx+88] - xor rcx, QWORD PTR [rdx+72] - movq xmm8, rax - mov QWORD PTR [rsp+136], rdi - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm8, xmm0 - and r8d, 2097136 - movq xmm0, rcx - mov r11d, 524288 - movq xmm10, rax - punpcklqdq xmm10, xmm0 - - movq xmm14, QWORD PTR [rsp+128] - movq xmm15, QWORD PTR [rsp+136] - - ALIGN(64) -FN_PREFIX(CryptonightWOW_template_double_mainloop): - movdqu xmm6, XMMWORD PTR [rbx+rsi] - movq xmm0, r12 - mov ecx, ebx - movq xmm3, r14 - punpcklqdq xmm3, xmm0 - xor ebx, 16 - aesenc xmm6, xmm3 - movq rdx, xmm6 - movq xmm4, r15 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - xor ebx, 48 - paddq xmm0, xmm7 - movdqu xmm1, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm0 - paddq xmm1, xmm3 - xor ebx, 16 - mov eax, ebx - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm1 - paddq xmm0, xmm9 - movdqu XMMWORD PTR [rax+rsi], xmm0 - movdqa xmm0, xmm6 - pxor xmm0, xmm7 - movdqu XMMWORD PTR [rcx+rsi], xmm0 - mov esi, edx - movdqu xmm5, XMMWORD PTR [r8+rdi] - and esi, 2097136 - mov ecx, r8d - movq xmm0, r13 - punpcklqdq xmm4, xmm0 - xor r8d, 16 - aesenc xmm5, xmm4 - movdqu xmm0, XMMWORD PTR [r8+rdi] - xor r8d, 48 - paddq xmm0, xmm8 - movdqu xmm1, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm0 - paddq xmm1, xmm4 - xor r8d, 16 - mov eax, r8d - xor rax, 32 - movdqu xmm0, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm1 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rdi], xmm0 - movdqa xmm0, xmm5 - pxor xmm0, xmm8 - movdqu XMMWORD PTR [rcx+rdi], xmm0 - movq rdi, xmm5 - movq rcx, xmm14 - mov ebp, edi - mov r8, QWORD PTR [rcx+rsi] - mov r10, QWORD PTR [rcx+rsi+8] - lea r9, QWORD PTR [rcx+rsi] - xor esi, 16 - - movq xmm0, rsp - movq xmm1, rsi - movq xmm2, rdi - movq xmm11, rbp - movq xmm12, r15 - movq xmm13, rdx - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp+16] - mov esi, DWORD PTR [rsp+20] - mov edi, DWORD PTR [rsp+24] - mov ebp, DWORD PTR [rsp+28] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - xor r8, rax - - movd esp, xmm3 - pextrd r15d, xmm3, 2 - movd eax, xmm7 - movd edx, xmm9 - pextrd r9d, xmm9, 2 - -FN_PREFIX(CryptonightWOW_template_double_part2): - - movq rsp, xmm0 - mov DWORD PTR [rsp+16], ebx - mov DWORD PTR [rsp+20], esi - mov DWORD PTR [rsp+24], edi - mov DWORD PTR [rsp+28], ebp - - movq rsi, xmm1 - movq rdi, xmm2 - movq rbp, xmm11 - movq r15, xmm12 - movq rdx, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rbx, r8 - mov rax, r8 - mul rdx - and ebp, 2097136 - mov r8, rax - movq xmm1, rdx - movq xmm0, r8 - punpcklqdq xmm1, xmm0 - pxor xmm1, XMMWORD PTR [rcx+rsi] - xor esi, 48 - paddq xmm1, xmm7 - movdqu xmm2, XMMWORD PTR [rsi+rcx] - xor rdx, QWORD PTR [rsi+rcx] - paddq xmm2, xmm3 - xor r8, QWORD PTR [rsi+rcx+8] - movdqu XMMWORD PTR [rsi+rcx], xmm1 - xor esi, 16 - mov eax, esi - mov rsi, rcx - movdqu xmm0, XMMWORD PTR [rax+rcx] - movdqu XMMWORD PTR [rax+rcx], xmm2 - paddq xmm0, xmm9 - add r12, r8 - xor rax, 32 - add r14, rdx - movdqa xmm9, xmm7 - movdqa xmm7, xmm6 - movdqu XMMWORD PTR [rax+rcx], xmm0 - mov QWORD PTR [r9+8], r12 - xor r12, r10 - mov QWORD PTR [r9], r14 - movq rcx, xmm15 - xor r14, rbx - mov r10d, ebp - mov ebx, r14d - xor ebp, 16 - and ebx, 2097136 - mov r8, QWORD PTR [r10+rcx] - mov r9, QWORD PTR [r10+rcx+8] - - movq xmm0, rsp - movq xmm1, rbx - movq xmm2, rsi - movq xmm11, rdi - movq xmm12, rbp - movq xmm13, r15 - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp] - mov esi, DWORD PTR [rsp+4] - mov edi, DWORD PTR [rsp+8] - mov ebp, DWORD PTR [rsp+12] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - - xor r8, rax - movq xmm3, r8 - - movd esp, xmm4 - pextrd r15d, xmm4, 2 - movd eax, xmm8 - movd edx, xmm10 - pextrd r9d, xmm10, 2 - -FN_PREFIX(CryptonightWOW_template_double_part3): - - movq rsp, xmm0 - mov DWORD PTR [rsp], ebx - mov DWORD PTR [rsp+4], esi - mov DWORD PTR [rsp+8], edi - mov DWORD PTR [rsp+12], ebp - - movq rbx, xmm1 - movq rsi, xmm2 - movq rdi, xmm11 - movq rbp, xmm12 - movq r15, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rax, r8 - mul rdi - movq xmm1, rdx - movq xmm0, rax - punpcklqdq xmm1, xmm0 - mov rdi, rcx - mov r8, rax - pxor xmm1, XMMWORD PTR [rbp+rcx] - xor ebp, 48 - paddq xmm1, xmm8 - xor r8, QWORD PTR [rbp+rcx+8] - xor rdx, QWORD PTR [rbp+rcx] - add r13, r8 - movdqu xmm2, XMMWORD PTR [rbp+rcx] - add r15, rdx - movdqu XMMWORD PTR [rbp+rcx], xmm1 - paddq xmm2, xmm4 - xor ebp, 16 - mov eax, ebp - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbp+rcx] - movdqu XMMWORD PTR [rbp+rcx], xmm2 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rcx], xmm0 - movq rax, xmm3 - movdqa xmm10, xmm8 - mov QWORD PTR [r10+rcx], r15 - movdqa xmm8, xmm5 - xor r15, rax - mov QWORD PTR [r10+rcx+8], r13 - mov r8d, r15d - xor r13, r9 - and r8d, 2097136 - dec r11d - jnz FN_PREFIX(CryptonightWOW_template_double_mainloop) - -FN_PREFIX(CryptonightWOW_template_double_part4): - - mov rbx, QWORD PTR [rsp+400] - movaps xmm6, XMMWORD PTR [rsp+160] - movaps xmm7, XMMWORD PTR [rsp+176] - movaps xmm8, XMMWORD PTR [rsp+192] - movaps xmm9, XMMWORD PTR [rsp+208] - movaps xmm10, XMMWORD PTR [rsp+224] - movaps xmm11, XMMWORD PTR [rsp+240] - movaps xmm12, XMMWORD PTR [rsp+256] - movaps xmm13, XMMWORD PTR [rsp+272] - movaps xmm14, XMMWORD PTR [rsp+288] - movaps xmm15, XMMWORD PTR [rsp+304] - add rsp, 320 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - ret 0 -FN_PREFIX(CryptonightWOW_template_double_end): diff --git a/src/crypto/cn/asm/CryptonightWOW_template_win.inc b/src/crypto/cn/asm/CryptonightWOW_template_win.inc deleted file mode 100644 index 644c01f13..000000000 --- a/src/crypto/cn/asm/CryptonightWOW_template_win.inc +++ /dev/null @@ -1,491 +0,0 @@ -PUBLIC CryptonightWOW_template_part1 -PUBLIC CryptonightWOW_template_mainloop -PUBLIC CryptonightWOW_template_part2 -PUBLIC CryptonightWOW_template_part3 -PUBLIC CryptonightWOW_template_end -PUBLIC CryptonightWOW_template_double_part1 -PUBLIC CryptonightWOW_template_double_mainloop -PUBLIC CryptonightWOW_template_double_part2 -PUBLIC CryptonightWOW_template_double_part3 -PUBLIC CryptonightWOW_template_double_part4 -PUBLIC CryptonightWOW_template_double_end - -ALIGN(64) -CryptonightWOW_template_part1: - mov rcx, [rcx] - - mov QWORD PTR [rsp+16], rbx - mov QWORD PTR [rsp+24], rbp - mov QWORD PTR [rsp+32], rsi - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - push rdi - sub rsp, 64 - mov r12, rcx - mov r8, QWORD PTR [r12+32] - mov rdx, r12 - xor r8, QWORD PTR [r12] - mov r15, QWORD PTR [r12+40] - mov r9, r8 - xor r15, QWORD PTR [r12+8] - mov r11, QWORD PTR [r12+224] - mov r12, QWORD PTR [r12+56] - xor r12, QWORD PTR [rdx+24] - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - movaps XMMWORD PTR [rsp+48], xmm6 - movq xmm0, r12 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+16], xmm8 - movaps XMMWORD PTR [rsp], xmm9 - mov r12, QWORD PTR [rdx+88] - xor r12, QWORD PTR [rdx+72] - movq xmm6, rax - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm6, xmm0 - and r9d, 2097136 - movq xmm0, r12 - movq xmm7, rax - punpcklqdq xmm7, xmm0 - mov r10d, r9d - movq xmm9, rsp - mov rsp, r8 - mov r8d, 524288 - - mov ebx, [rdx+96] - mov esi, [rdx+100] - mov edi, [rdx+104] - mov ebp, [rdx+108] - - ALIGN(64) -CryptonightWOW_template_mainloop: - movdqa xmm5, XMMWORD PTR [r9+r11] - movq xmm0, r15 - movq xmm4, rsp - punpcklqdq xmm4, xmm0 - lea rdx, QWORD PTR [r9+r11] - - aesenc xmm5, xmm4 - movd r10d, xmm5 - and r10d, 2097136 - - mov r12d, r9d - mov eax, r9d - xor r9d, 48 - xor r12d, 16 - xor eax, 32 - movdqu xmm0, XMMWORD PTR [r9+r11] - movdqu xmm2, XMMWORD PTR [r12+r11] - movdqu xmm1, XMMWORD PTR [rax+r11] - paddq xmm0, xmm7 - paddq xmm2, xmm6 - paddq xmm1, xmm4 - movdqu XMMWORD PTR [r12+r11], xmm0 - movq r12, xmm5 - movdqu XMMWORD PTR [rax+r11], xmm2 - movdqu XMMWORD PTR [r9+r11], xmm1 - - movdqa xmm0, xmm5 - pxor xmm0, xmm6 - movdqu XMMWORD PTR [rdx], xmm0 - - lea r13d, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or r13, rdx - - xor r13, QWORD PTR [r10+r11] - mov r14, QWORD PTR [r10+r11+8] - - movd eax, xmm6 - movd edx, xmm7 - pextrd r9d, xmm7, 2 - -CryptonightWOW_template_part2: - mov rax, r13 - mul r12 - movq xmm0, rax - movq xmm3, rdx - punpcklqdq xmm3, xmm0 - - mov r9d, r10d - mov r12d, r10d - xor r9d, 16 - xor r12d, 32 - xor r10d, 48 - movdqa xmm1, XMMWORD PTR [r12+r11] - xor rdx, QWORD PTR [r12+r11] - xor rax, QWORD PTR [r11+r12+8] - movdqa xmm2, XMMWORD PTR [r9+r11] - pxor xmm3, xmm2 - paddq xmm7, XMMWORD PTR [r10+r11] - paddq xmm1, xmm4 - paddq xmm3, xmm6 - movdqu XMMWORD PTR [r9+r11], xmm7 - movdqu XMMWORD PTR [r12+r11], xmm3 - movdqu XMMWORD PTR [r10+r11], xmm1 - - movdqa xmm7, xmm6 - add r15, rax - add rsp, rdx - xor r10, 48 - mov QWORD PTR [r10+r11], rsp - xor rsp, r13 - mov r9d, esp - mov QWORD PTR [r10+r11+8], r15 - and r9d, 2097136 - xor r15, r14 - movdqa xmm6, xmm5 - dec r8d - jnz CryptonightWOW_template_mainloop - -CryptonightWOW_template_part3: - movq rsp, xmm9 - - mov rbx, QWORD PTR [rsp+136] - mov rbp, QWORD PTR [rsp+144] - mov rsi, QWORD PTR [rsp+152] - movaps xmm6, XMMWORD PTR [rsp+48] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+16] - movaps xmm9, XMMWORD PTR [rsp] - add rsp, 64 - pop rdi - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - ret 0 -CryptonightWOW_template_end: - -ALIGN(64) -CryptonightWOW_template_double_part1: - mov rdx, [rcx+8] - mov rcx, [rcx] - - mov QWORD PTR [rsp+24], rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 320 - mov r14, QWORD PTR [rcx+32] - mov r8, rcx - xor r14, QWORD PTR [rcx] - mov r12, QWORD PTR [rcx+40] - mov ebx, r14d - mov rsi, QWORD PTR [rcx+224] - and ebx, 2097136 - xor r12, QWORD PTR [rcx+8] - mov rcx, QWORD PTR [rcx+56] - xor rcx, QWORD PTR [r8+24] - mov rax, QWORD PTR [r8+48] - xor rax, QWORD PTR [r8+16] - mov r15, QWORD PTR [rdx+32] - xor r15, QWORD PTR [rdx] - movq xmm0, rcx - mov rcx, QWORD PTR [r8+88] - xor rcx, QWORD PTR [r8+72] - mov r13, QWORD PTR [rdx+40] - mov rdi, QWORD PTR [rdx+224] - xor r13, QWORD PTR [rdx+8] - movaps XMMWORD PTR [rsp+160], xmm6 - movaps XMMWORD PTR [rsp+176], xmm7 - movaps XMMWORD PTR [rsp+192], xmm8 - movaps XMMWORD PTR [rsp+208], xmm9 - movaps XMMWORD PTR [rsp+224], xmm10 - movaps XMMWORD PTR [rsp+240], xmm11 - movaps XMMWORD PTR [rsp+256], xmm12 - movaps XMMWORD PTR [rsp+272], xmm13 - movaps XMMWORD PTR [rsp+288], xmm14 - movaps XMMWORD PTR [rsp+304], xmm15 - movq xmm7, rax - mov rax, QWORD PTR [r8+80] - xor rax, QWORD PTR [r8+64] - - movaps xmm1, XMMWORD PTR [rdx+96] - movaps xmm2, XMMWORD PTR [r8+96] - movaps XMMWORD PTR [rsp], xmm1 - movaps XMMWORD PTR [rsp+16], xmm2 - - mov r8d, r15d - punpcklqdq xmm7, xmm0 - movq xmm0, rcx - mov rcx, QWORD PTR [rdx+56] - xor rcx, QWORD PTR [rdx+24] - movq xmm9, rax - mov QWORD PTR [rsp+128], rsi - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - punpcklqdq xmm9, xmm0 - movq xmm0, rcx - mov rcx, QWORD PTR [rdx+88] - xor rcx, QWORD PTR [rdx+72] - movq xmm8, rax - mov QWORD PTR [rsp+136], rdi - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm8, xmm0 - and r8d, 2097136 - movq xmm0, rcx - mov r11d, 524288 - movq xmm10, rax - punpcklqdq xmm10, xmm0 - - movq xmm14, QWORD PTR [rsp+128] - movq xmm15, QWORD PTR [rsp+136] - - ALIGN(64) -CryptonightWOW_template_double_mainloop: - movdqu xmm6, XMMWORD PTR [rbx+rsi] - movq xmm0, r12 - mov ecx, ebx - movq xmm3, r14 - punpcklqdq xmm3, xmm0 - xor ebx, 16 - aesenc xmm6, xmm3 - movq rdx, xmm6 - movq xmm4, r15 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - xor ebx, 48 - paddq xmm0, xmm7 - movdqu xmm1, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm0 - paddq xmm1, xmm3 - xor ebx, 16 - mov eax, ebx - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm1 - paddq xmm0, xmm9 - movdqu XMMWORD PTR [rax+rsi], xmm0 - movdqa xmm0, xmm6 - pxor xmm0, xmm7 - movdqu XMMWORD PTR [rcx+rsi], xmm0 - mov esi, edx - movdqu xmm5, XMMWORD PTR [r8+rdi] - and esi, 2097136 - mov ecx, r8d - movq xmm0, r13 - punpcklqdq xmm4, xmm0 - xor r8d, 16 - aesenc xmm5, xmm4 - movdqu xmm0, XMMWORD PTR [r8+rdi] - xor r8d, 48 - paddq xmm0, xmm8 - movdqu xmm1, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm0 - paddq xmm1, xmm4 - xor r8d, 16 - mov eax, r8d - xor rax, 32 - movdqu xmm0, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm1 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rdi], xmm0 - movdqa xmm0, xmm5 - pxor xmm0, xmm8 - movdqu XMMWORD PTR [rcx+rdi], xmm0 - movq rdi, xmm5 - movq rcx, xmm14 - mov ebp, edi - mov r8, QWORD PTR [rcx+rsi] - mov r10, QWORD PTR [rcx+rsi+8] - lea r9, QWORD PTR [rcx+rsi] - xor esi, 16 - - movq xmm0, rsp - movq xmm1, rsi - movq xmm2, rdi - movq xmm11, rbp - movq xmm12, r15 - movq xmm13, rdx - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp+16] - mov esi, DWORD PTR [rsp+20] - mov edi, DWORD PTR [rsp+24] - mov ebp, DWORD PTR [rsp+28] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - xor r8, rax - - movd esp, xmm3 - pextrd r15d, xmm3, 2 - movd eax, xmm7 - movd edx, xmm9 - pextrd r9d, xmm9, 2 - -CryptonightWOW_template_double_part2: - - movq rsp, xmm0 - mov DWORD PTR [rsp+16], ebx - mov DWORD PTR [rsp+20], esi - mov DWORD PTR [rsp+24], edi - mov DWORD PTR [rsp+28], ebp - - movq rsi, xmm1 - movq rdi, xmm2 - movq rbp, xmm11 - movq r15, xmm12 - movq rdx, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rbx, r8 - mov rax, r8 - mul rdx - and ebp, 2097136 - mov r8, rax - movq xmm1, rdx - movq xmm0, r8 - punpcklqdq xmm1, xmm0 - pxor xmm1, XMMWORD PTR [rcx+rsi] - xor esi, 48 - paddq xmm1, xmm7 - movdqu xmm2, XMMWORD PTR [rsi+rcx] - xor rdx, QWORD PTR [rsi+rcx] - paddq xmm2, xmm3 - xor r8, QWORD PTR [rsi+rcx+8] - movdqu XMMWORD PTR [rsi+rcx], xmm1 - xor esi, 16 - mov eax, esi - mov rsi, rcx - movdqu xmm0, XMMWORD PTR [rax+rcx] - movdqu XMMWORD PTR [rax+rcx], xmm2 - paddq xmm0, xmm9 - add r12, r8 - xor rax, 32 - add r14, rdx - movdqa xmm9, xmm7 - movdqa xmm7, xmm6 - movdqu XMMWORD PTR [rax+rcx], xmm0 - mov QWORD PTR [r9+8], r12 - xor r12, r10 - mov QWORD PTR [r9], r14 - movq rcx, xmm15 - xor r14, rbx - mov r10d, ebp - mov ebx, r14d - xor ebp, 16 - and ebx, 2097136 - mov r8, QWORD PTR [r10+rcx] - mov r9, QWORD PTR [r10+rcx+8] - - movq xmm0, rsp - movq xmm1, rbx - movq xmm2, rsi - movq xmm11, rdi - movq xmm12, rbp - movq xmm13, r15 - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp] - mov esi, DWORD PTR [rsp+4] - mov edi, DWORD PTR [rsp+8] - mov ebp, DWORD PTR [rsp+12] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - - xor r8, rax - movq xmm3, r8 - - movd esp, xmm4 - pextrd r15d, xmm4, 2 - movd eax, xmm8 - movd edx, xmm10 - pextrd r9d, xmm10, 2 - -CryptonightWOW_template_double_part3: - - movq rsp, xmm0 - mov DWORD PTR [rsp], ebx - mov DWORD PTR [rsp+4], esi - mov DWORD PTR [rsp+8], edi - mov DWORD PTR [rsp+12], ebp - - movq rbx, xmm1 - movq rsi, xmm2 - movq rdi, xmm11 - movq rbp, xmm12 - movq r15, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rax, r8 - mul rdi - movq xmm1, rdx - movq xmm0, rax - punpcklqdq xmm1, xmm0 - mov rdi, rcx - mov r8, rax - pxor xmm1, XMMWORD PTR [rbp+rcx] - xor ebp, 48 - paddq xmm1, xmm8 - xor r8, QWORD PTR [rbp+rcx+8] - xor rdx, QWORD PTR [rbp+rcx] - add r13, r8 - movdqu xmm2, XMMWORD PTR [rbp+rcx] - add r15, rdx - movdqu XMMWORD PTR [rbp+rcx], xmm1 - paddq xmm2, xmm4 - xor ebp, 16 - mov eax, ebp - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbp+rcx] - movdqu XMMWORD PTR [rbp+rcx], xmm2 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rcx], xmm0 - movq rax, xmm3 - movdqa xmm10, xmm8 - mov QWORD PTR [r10+rcx], r15 - movdqa xmm8, xmm5 - xor r15, rax - mov QWORD PTR [r10+rcx+8], r13 - mov r8d, r15d - xor r13, r9 - and r8d, 2097136 - dec r11d - jnz CryptonightWOW_template_double_mainloop - -CryptonightWOW_template_double_part4: - - mov rbx, QWORD PTR [rsp+400] - movaps xmm6, XMMWORD PTR [rsp+160] - movaps xmm7, XMMWORD PTR [rsp+176] - movaps xmm8, XMMWORD PTR [rsp+192] - movaps xmm9, XMMWORD PTR [rsp+208] - movaps xmm10, XMMWORD PTR [rsp+224] - movaps xmm11, XMMWORD PTR [rsp+240] - movaps xmm12, XMMWORD PTR [rsp+256] - movaps xmm13, XMMWORD PTR [rsp+272] - movaps xmm14, XMMWORD PTR [rsp+288] - movaps xmm15, XMMWORD PTR [rsp+304] - add rsp, 320 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - ret 0 -CryptonightWOW_template_double_end: diff --git a/src/crypto/cn/asm/cn_main_loop.S b/src/crypto/cn/asm/cn_main_loop.S index 7aed6c20b..609b0fe8e 100644 --- a/src/crypto/cn/asm/cn_main_loop.S +++ b/src/crypto/cn/asm/cn_main_loop.S @@ -71,3 +71,7 @@ FN_PREFIX(cnv2_rwz_double_mainloop_asm): add rsp, 48 ret 0 mov eax, 3735929054 + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/crypto/cn/asm/win64/CryptonightR_template.asm b/src/crypto/cn/asm/win64/CryptonightR_template.asm index 250eca3d0..8424434da 100644 --- a/src/crypto/cn/asm/win64/CryptonightR_template.asm +++ b/src/crypto/cn/asm/win64/CryptonightR_template.asm @@ -516,9 +516,7 @@ PUBLIC CryptonightR_instruction_mov254 PUBLIC CryptonightR_instruction_mov255 PUBLIC CryptonightR_instruction_mov256 -INCLUDE CryptonightWOW_template_win.inc INCLUDE CryptonightR_template_win.inc -INCLUDE CryptonightWOW_soft_aes_template_win.inc INCLUDE CryptonightR_soft_aes_template_win.inc CryptonightR_instruction0: diff --git a/src/crypto/cn/asm/win64/CryptonightWOW_soft_aes_template_win.inc b/src/crypto/cn/asm/win64/CryptonightWOW_soft_aes_template_win.inc deleted file mode 100644 index 1c73f77c1..000000000 --- a/src/crypto/cn/asm/win64/CryptonightWOW_soft_aes_template_win.inc +++ /dev/null @@ -1,268 +0,0 @@ -PUBLIC CryptonightWOW_soft_aes_template_part1 -PUBLIC CryptonightWOW_soft_aes_template_mainloop -PUBLIC CryptonightWOW_soft_aes_template_part2 -PUBLIC CryptonightWOW_soft_aes_template_part3 -PUBLIC CryptonightWOW_soft_aes_template_end - -ALIGN(64) -CryptonightWOW_soft_aes_template_part1: - mov rcx, [rcx] - - mov QWORD PTR [rsp+8], rcx - push rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 232 - - mov eax, [rcx+96] - mov ebx, [rcx+100] - mov esi, [rcx+104] - mov edx, [rcx+108] - mov [rsp+144], eax - mov [rsp+148], ebx - mov [rsp+152], esi - mov [rsp+156], edx - - mov rax, QWORD PTR [rcx+48] - mov r10, rcx - xor rax, QWORD PTR [rcx+16] - mov r8, QWORD PTR [rcx+32] - xor r8, QWORD PTR [rcx] - mov r9, QWORD PTR [rcx+40] - xor r9, QWORD PTR [rcx+8] - movd xmm4, rax - mov rdx, QWORD PTR [rcx+56] - xor rdx, QWORD PTR [rcx+24] - mov r11, QWORD PTR [rcx+224] - mov rcx, QWORD PTR [rcx+88] - xor rcx, QWORD PTR [r10+72] - mov rax, QWORD PTR [r10+80] - movd xmm0, rdx - xor rax, QWORD PTR [r10+64] - - movaps XMMWORD PTR [rsp+16], xmm6 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+48], xmm8 - movaps XMMWORD PTR [rsp+64], xmm9 - movaps XMMWORD PTR [rsp+80], xmm10 - movaps XMMWORD PTR [rsp+96], xmm11 - movaps XMMWORD PTR [rsp+112], xmm12 - movaps XMMWORD PTR [rsp+128], xmm13 - - movd xmm5, rax - - mov rax, r8 - punpcklqdq xmm4, xmm0 - and eax, 2097136 - movd xmm10, QWORD PTR [r10+96] - movd xmm0, rcx - mov rcx, QWORD PTR [r10+104] - xorps xmm9, xmm9 - mov QWORD PTR [rsp+328], rax - movd xmm12, r11 - mov QWORD PTR [rsp+320], r9 - punpcklqdq xmm5, xmm0 - movd xmm13, rcx - mov r12d, 524288 - - ALIGN(64) -CryptonightWOW_soft_aes_template_mainloop: - movd xmm11, r12d - mov r12, QWORD PTR [r10+272] - lea r13, QWORD PTR [rax+r11] - mov esi, DWORD PTR [r13] - movd xmm0, r9 - mov r10d, DWORD PTR [r13+4] - movd xmm7, r8 - mov ebp, DWORD PTR [r13+12] - mov r14d, DWORD PTR [r13+8] - mov rdx, QWORD PTR [rsp+328] - movzx ecx, sil - shr esi, 8 - punpcklqdq xmm7, xmm0 - mov r15d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - mov edi, DWORD PTR [r12+rcx*4] - movzx ecx, r14b - shr r14d, 8 - mov ebx, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - shr ebp, 8 - mov r9d, DWORD PTR [r12+rcx*4] - movzx ecx, r10b - shr r10d, 8 - xor r15d, DWORD PTR [r12+rcx*4+1024] - movzx ecx, r14b - shr r14d, 8 - mov eax, r14d - shr eax, 8 - xor edi, DWORD PTR [r12+rcx*4+1024] - add eax, 256 - movzx ecx, bpl - shr ebp, 8 - xor ebx, DWORD PTR [r12+rcx*4+1024] - movzx ecx, sil - shr esi, 8 - xor r9d, DWORD PTR [r12+rcx*4+1024] - add r12, 2048 - movzx ecx, r10b - shr r10d, 8 - add r10d, 256 - mov r11d, DWORD PTR [r12+rax*4] - xor r11d, DWORD PTR [r12+rcx*4] - xor r11d, r9d - movzx ecx, sil - mov r10d, DWORD PTR [r12+r10*4] - shr esi, 8 - add esi, 256 - xor r10d, DWORD PTR [r12+rcx*4] - movzx ecx, bpl - xor r10d, ebx - shr ebp, 8 - movd xmm1, r11d - add ebp, 256 - movd r11, xmm12 - mov r9d, DWORD PTR [r12+rcx*4] - xor r9d, DWORD PTR [r12+rsi*4] - mov eax, DWORD PTR [r12+rbp*4] - xor r9d, edi - movzx ecx, r14b - movd xmm0, r10d - movd xmm2, r9d - xor eax, DWORD PTR [r12+rcx*4] - mov rcx, rdx - xor eax, r15d - punpckldq xmm2, xmm1 - xor rcx, 16 - movd xmm6, eax - mov rax, rdx - punpckldq xmm6, xmm0 - xor rax, 32 - punpckldq xmm6, xmm2 - xor rdx, 48 - movdqu xmm2, XMMWORD PTR [rcx+r11] - pxor xmm6, xmm7 - paddq xmm2, xmm4 - movdqu xmm1, XMMWORD PTR [rax+r11] - movdqu xmm0, XMMWORD PTR [rdx+r11] - paddq xmm0, xmm5 - movdqu XMMWORD PTR [rcx+r11], xmm0 - movdqu XMMWORD PTR [rax+r11], xmm2 - movd rcx, xmm13 - paddq xmm1, xmm7 - movdqu XMMWORD PTR [rdx+r11], xmm1 - movd rdi, xmm6 - mov r10, rdi - and r10d, 2097136 - movdqa xmm0, xmm6 - pxor xmm0, xmm4 - movdqu XMMWORD PTR [r13], xmm0 - - mov ebx, [rsp+144] - mov ebp, [rsp+152] - add ebx, [rsp+148] - add ebp, [rsp+156] - shl rbp, 32 - or rbx, rbp - - xor rbx, QWORD PTR [r10+r11] - lea r14, QWORD PTR [r10+r11] - mov rbp, QWORD PTR [r14+8] - - mov [rsp+160], rbx - mov [rsp+168], rdi - mov [rsp+176], rbp - mov [rsp+184], r10 - mov r10, rsp - - mov ebx, [rsp+144] - mov esi, [rsp+148] - mov edi, [rsp+152] - mov ebp, [rsp+156] - - movd esp, xmm7 - movaps xmm0, xmm7 - psrldq xmm0, 8 - movd r15d, xmm0 - movd eax, xmm4 - movd edx, xmm5 - -CryptonightWOW_soft_aes_template_part2: - mov rsp, r10 - mov [rsp+144], ebx - mov [rsp+148], esi - mov [rsp+152], edi - mov [rsp+156], ebp - - mov rbx, [rsp+160] - mov rdi, [rsp+168] - mov rbp, [rsp+176] - mov r10, [rsp+184] - - mov r9, r10 - xor r9, 16 - mov rcx, r10 - xor rcx, 32 - xor r10, 48 - mov rax, rbx - mul rdi - movdqu xmm2, XMMWORD PTR [r9+r11] - movdqu xmm1, XMMWORD PTR [rcx+r11] - paddq xmm1, xmm7 - movd xmm0, rax - movd xmm3, rdx - xor rax, QWORD PTR [r11+rcx+8] - xor rdx, QWORD PTR [rcx+r11] - punpcklqdq xmm3, xmm0 - add r8, rdx - movdqu xmm0, XMMWORD PTR [r10+r11] - pxor xmm2, xmm3 - paddq xmm0, xmm5 - paddq xmm2, xmm4 - movdqu XMMWORD PTR [r9+r11], xmm0 - movdqa xmm5, xmm4 - mov r9, QWORD PTR [rsp+320] - movdqa xmm4, xmm6 - add r9, rax - movdqu XMMWORD PTR [rcx+r11], xmm2 - movdqu XMMWORD PTR [r10+r11], xmm1 - mov r10, QWORD PTR [rsp+304] - movd r12d, xmm11 - mov QWORD PTR [r14], r8 - xor r8, rbx - mov rax, r8 - mov QWORD PTR [r14+8], r9 - and eax, 2097136 - xor r9, rbp - mov QWORD PTR [rsp+320], r9 - mov QWORD PTR [rsp+328], rax - sub r12d, 1 - jne CryptonightWOW_soft_aes_template_mainloop - -CryptonightWOW_soft_aes_template_part3: - movaps xmm6, XMMWORD PTR [rsp+16] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+48] - movaps xmm9, XMMWORD PTR [rsp+64] - movaps xmm10, XMMWORD PTR [rsp+80] - movaps xmm11, XMMWORD PTR [rsp+96] - movaps xmm12, XMMWORD PTR [rsp+112] - movaps xmm13, XMMWORD PTR [rsp+128] - - add rsp, 232 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - pop rbx - ret -CryptonightWOW_soft_aes_template_end: diff --git a/src/crypto/cn/asm/win64/CryptonightWOW_template_win.inc b/src/crypto/cn/asm/win64/CryptonightWOW_template_win.inc deleted file mode 100644 index 55c8c8df3..000000000 --- a/src/crypto/cn/asm/win64/CryptonightWOW_template_win.inc +++ /dev/null @@ -1,491 +0,0 @@ -PUBLIC CryptonightWOW_template_part1 -PUBLIC CryptonightWOW_template_mainloop -PUBLIC CryptonightWOW_template_part2 -PUBLIC CryptonightWOW_template_part3 -PUBLIC CryptonightWOW_template_end -PUBLIC CryptonightWOW_template_double_part1 -PUBLIC CryptonightWOW_template_double_mainloop -PUBLIC CryptonightWOW_template_double_part2 -PUBLIC CryptonightWOW_template_double_part3 -PUBLIC CryptonightWOW_template_double_part4 -PUBLIC CryptonightWOW_template_double_end - -ALIGN(64) -CryptonightWOW_template_part1: - mov rcx, [rcx] - - mov QWORD PTR [rsp+16], rbx - mov QWORD PTR [rsp+24], rbp - mov QWORD PTR [rsp+32], rsi - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - push rdi - sub rsp, 64 - mov r12, rcx - mov r8, QWORD PTR [r12+32] - mov rdx, r12 - xor r8, QWORD PTR [r12] - mov r15, QWORD PTR [r12+40] - mov r9, r8 - xor r15, QWORD PTR [r12+8] - mov r11, QWORD PTR [r12+224] - mov r12, QWORD PTR [r12+56] - xor r12, QWORD PTR [rdx+24] - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - movaps XMMWORD PTR [rsp+48], xmm6 - movd xmm0, r12 - movaps XMMWORD PTR [rsp+32], xmm7 - movaps XMMWORD PTR [rsp+16], xmm8 - movaps XMMWORD PTR [rsp], xmm9 - mov r12, QWORD PTR [rdx+88] - xor r12, QWORD PTR [rdx+72] - movd xmm6, rax - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm6, xmm0 - and r9d, 2097136 - movd xmm0, r12 - movd xmm7, rax - punpcklqdq xmm7, xmm0 - mov r10d, r9d - movd xmm9, rsp - mov rsp, r8 - mov r8d, 524288 - - mov ebx, [rdx+96] - mov esi, [rdx+100] - mov edi, [rdx+104] - mov ebp, [rdx+108] - - ALIGN(64) -CryptonightWOW_template_mainloop: - movdqa xmm5, XMMWORD PTR [r9+r11] - movd xmm0, r15 - movd xmm4, rsp - punpcklqdq xmm4, xmm0 - lea rdx, QWORD PTR [r9+r11] - - aesenc xmm5, xmm4 - movd r10d, xmm5 - and r10d, 2097136 - - mov r12d, r9d - mov eax, r9d - xor r9d, 48 - xor r12d, 16 - xor eax, 32 - movdqu xmm0, XMMWORD PTR [r9+r11] - movdqu xmm2, XMMWORD PTR [r12+r11] - movdqu xmm1, XMMWORD PTR [rax+r11] - paddq xmm0, xmm7 - paddq xmm2, xmm6 - paddq xmm1, xmm4 - movdqu XMMWORD PTR [r12+r11], xmm0 - movd r12, xmm5 - movdqu XMMWORD PTR [rax+r11], xmm2 - movdqu XMMWORD PTR [r9+r11], xmm1 - - movdqa xmm0, xmm5 - pxor xmm0, xmm6 - movdqu XMMWORD PTR [rdx], xmm0 - - lea r13d, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or r13, rdx - - xor r13, QWORD PTR [r10+r11] - mov r14, QWORD PTR [r10+r11+8] - - movd eax, xmm6 - movd edx, xmm7 - pextrd r9d, xmm7, 2 - -CryptonightWOW_template_part2: - mov rax, r13 - mul r12 - movd xmm0, rax - movd xmm3, rdx - punpcklqdq xmm3, xmm0 - - mov r9d, r10d - mov r12d, r10d - xor r9d, 16 - xor r12d, 32 - xor r10d, 48 - movdqa xmm1, XMMWORD PTR [r12+r11] - xor rdx, QWORD PTR [r12+r11] - xor rax, QWORD PTR [r11+r12+8] - movdqa xmm2, XMMWORD PTR [r9+r11] - pxor xmm3, xmm2 - paddq xmm7, XMMWORD PTR [r10+r11] - paddq xmm1, xmm4 - paddq xmm3, xmm6 - movdqu XMMWORD PTR [r9+r11], xmm7 - movdqu XMMWORD PTR [r12+r11], xmm3 - movdqu XMMWORD PTR [r10+r11], xmm1 - - movdqa xmm7, xmm6 - add r15, rax - add rsp, rdx - xor r10, 48 - mov QWORD PTR [r10+r11], rsp - xor rsp, r13 - mov r9d, esp - mov QWORD PTR [r10+r11+8], r15 - and r9d, 2097136 - xor r15, r14 - movdqa xmm6, xmm5 - dec r8d - jnz CryptonightWOW_template_mainloop - -CryptonightWOW_template_part3: - movd rsp, xmm9 - - mov rbx, QWORD PTR [rsp+136] - mov rbp, QWORD PTR [rsp+144] - mov rsi, QWORD PTR [rsp+152] - movaps xmm6, XMMWORD PTR [rsp+48] - movaps xmm7, XMMWORD PTR [rsp+32] - movaps xmm8, XMMWORD PTR [rsp+16] - movaps xmm9, XMMWORD PTR [rsp] - add rsp, 64 - pop rdi - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - ret 0 -CryptonightWOW_template_end: - -ALIGN(64) -CryptonightWOW_template_double_part1: - mov rdx, [rcx+8] - mov rcx, [rcx] - - mov QWORD PTR [rsp+24], rbx - push rbp - push rsi - push rdi - push r12 - push r13 - push r14 - push r15 - sub rsp, 320 - mov r14, QWORD PTR [rcx+32] - mov r8, rcx - xor r14, QWORD PTR [rcx] - mov r12, QWORD PTR [rcx+40] - mov ebx, r14d - mov rsi, QWORD PTR [rcx+224] - and ebx, 2097136 - xor r12, QWORD PTR [rcx+8] - mov rcx, QWORD PTR [rcx+56] - xor rcx, QWORD PTR [r8+24] - mov rax, QWORD PTR [r8+48] - xor rax, QWORD PTR [r8+16] - mov r15, QWORD PTR [rdx+32] - xor r15, QWORD PTR [rdx] - movd xmm0, rcx - mov rcx, QWORD PTR [r8+88] - xor rcx, QWORD PTR [r8+72] - mov r13, QWORD PTR [rdx+40] - mov rdi, QWORD PTR [rdx+224] - xor r13, QWORD PTR [rdx+8] - movaps XMMWORD PTR [rsp+160], xmm6 - movaps XMMWORD PTR [rsp+176], xmm7 - movaps XMMWORD PTR [rsp+192], xmm8 - movaps XMMWORD PTR [rsp+208], xmm9 - movaps XMMWORD PTR [rsp+224], xmm10 - movaps XMMWORD PTR [rsp+240], xmm11 - movaps XMMWORD PTR [rsp+256], xmm12 - movaps XMMWORD PTR [rsp+272], xmm13 - movaps XMMWORD PTR [rsp+288], xmm14 - movaps XMMWORD PTR [rsp+304], xmm15 - movd xmm7, rax - mov rax, QWORD PTR [r8+80] - xor rax, QWORD PTR [r8+64] - - movaps xmm1, XMMWORD PTR [rdx+96] - movaps xmm2, XMMWORD PTR [r8+96] - movaps XMMWORD PTR [rsp], xmm1 - movaps XMMWORD PTR [rsp+16], xmm2 - - mov r8d, r15d - punpcklqdq xmm7, xmm0 - movd xmm0, rcx - mov rcx, QWORD PTR [rdx+56] - xor rcx, QWORD PTR [rdx+24] - movd xmm9, rax - mov QWORD PTR [rsp+128], rsi - mov rax, QWORD PTR [rdx+48] - xor rax, QWORD PTR [rdx+16] - punpcklqdq xmm9, xmm0 - movd xmm0, rcx - mov rcx, QWORD PTR [rdx+88] - xor rcx, QWORD PTR [rdx+72] - movd xmm8, rax - mov QWORD PTR [rsp+136], rdi - mov rax, QWORD PTR [rdx+80] - xor rax, QWORD PTR [rdx+64] - punpcklqdq xmm8, xmm0 - and r8d, 2097136 - movd xmm0, rcx - mov r11d, 524288 - movd xmm10, rax - punpcklqdq xmm10, xmm0 - - movd xmm14, QWORD PTR [rsp+128] - movd xmm15, QWORD PTR [rsp+136] - - ALIGN(64) -CryptonightWOW_template_double_mainloop: - movdqu xmm6, XMMWORD PTR [rbx+rsi] - movd xmm0, r12 - mov ecx, ebx - movd xmm3, r14 - punpcklqdq xmm3, xmm0 - xor ebx, 16 - aesenc xmm6, xmm3 - movd rdx, xmm6 - movd xmm4, r15 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - xor ebx, 48 - paddq xmm0, xmm7 - movdqu xmm1, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm0 - paddq xmm1, xmm3 - xor ebx, 16 - mov eax, ebx - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbx+rsi] - movdqu XMMWORD PTR [rbx+rsi], xmm1 - paddq xmm0, xmm9 - movdqu XMMWORD PTR [rax+rsi], xmm0 - movdqa xmm0, xmm6 - pxor xmm0, xmm7 - movdqu XMMWORD PTR [rcx+rsi], xmm0 - mov esi, edx - movdqu xmm5, XMMWORD PTR [r8+rdi] - and esi, 2097136 - mov ecx, r8d - movd xmm0, r13 - punpcklqdq xmm4, xmm0 - xor r8d, 16 - aesenc xmm5, xmm4 - movdqu xmm0, XMMWORD PTR [r8+rdi] - xor r8d, 48 - paddq xmm0, xmm8 - movdqu xmm1, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm0 - paddq xmm1, xmm4 - xor r8d, 16 - mov eax, r8d - xor rax, 32 - movdqu xmm0, XMMWORD PTR [r8+rdi] - movdqu XMMWORD PTR [r8+rdi], xmm1 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rdi], xmm0 - movdqa xmm0, xmm5 - pxor xmm0, xmm8 - movdqu XMMWORD PTR [rcx+rdi], xmm0 - movd rdi, xmm5 - movd rcx, xmm14 - mov ebp, edi - mov r8, QWORD PTR [rcx+rsi] - mov r10, QWORD PTR [rcx+rsi+8] - lea r9, QWORD PTR [rcx+rsi] - xor esi, 16 - - movd xmm0, rsp - movd xmm1, rsi - movd xmm2, rdi - movd xmm11, rbp - movd xmm12, r15 - movd xmm13, rdx - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp+16] - mov esi, DWORD PTR [rsp+20] - mov edi, DWORD PTR [rsp+24] - mov ebp, DWORD PTR [rsp+28] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - xor r8, rax - - movd esp, xmm3 - pextrd r15d, xmm3, 2 - movd eax, xmm7 - movd edx, xmm9 - pextrd r9d, xmm9, 2 - -CryptonightWOW_template_double_part2: - - movd rsp, xmm0 - mov DWORD PTR [rsp+16], ebx - mov DWORD PTR [rsp+20], esi - mov DWORD PTR [rsp+24], edi - mov DWORD PTR [rsp+28], ebp - - movd rsi, xmm1 - movd rdi, xmm2 - movd rbp, xmm11 - movd r15, xmm12 - movd rdx, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rbx, r8 - mov rax, r8 - mul rdx - and ebp, 2097136 - mov r8, rax - movd xmm1, rdx - movd xmm0, r8 - punpcklqdq xmm1, xmm0 - pxor xmm1, XMMWORD PTR [rcx+rsi] - xor esi, 48 - paddq xmm1, xmm7 - movdqu xmm2, XMMWORD PTR [rsi+rcx] - xor rdx, QWORD PTR [rsi+rcx] - paddq xmm2, xmm3 - xor r8, QWORD PTR [rsi+rcx+8] - movdqu XMMWORD PTR [rsi+rcx], xmm1 - xor esi, 16 - mov eax, esi - mov rsi, rcx - movdqu xmm0, XMMWORD PTR [rax+rcx] - movdqu XMMWORD PTR [rax+rcx], xmm2 - paddq xmm0, xmm9 - add r12, r8 - xor rax, 32 - add r14, rdx - movdqa xmm9, xmm7 - movdqa xmm7, xmm6 - movdqu XMMWORD PTR [rax+rcx], xmm0 - mov QWORD PTR [r9+8], r12 - xor r12, r10 - mov QWORD PTR [r9], r14 - movd rcx, xmm15 - xor r14, rbx - mov r10d, ebp - mov ebx, r14d - xor ebp, 16 - and ebx, 2097136 - mov r8, QWORD PTR [r10+rcx] - mov r9, QWORD PTR [r10+rcx+8] - - movd xmm0, rsp - movd xmm1, rbx - movd xmm2, rsi - movd xmm11, rdi - movd xmm12, rbp - movd xmm13, r15 - mov [rsp+104], rcx - mov [rsp+112], r9 - - mov ebx, DWORD PTR [rsp] - mov esi, DWORD PTR [rsp+4] - mov edi, DWORD PTR [rsp+8] - mov ebp, DWORD PTR [rsp+12] - - lea eax, [ebx+esi] - lea edx, [edi+ebp] - shl rdx, 32 - or rax, rdx - - xor r8, rax - movd xmm3, r8 - - movd esp, xmm4 - pextrd r15d, xmm4, 2 - movd eax, xmm8 - movd edx, xmm10 - pextrd r9d, xmm10, 2 - -CryptonightWOW_template_double_part3: - - movd rsp, xmm0 - mov DWORD PTR [rsp], ebx - mov DWORD PTR [rsp+4], esi - mov DWORD PTR [rsp+8], edi - mov DWORD PTR [rsp+12], ebp - - movd rbx, xmm1 - movd rsi, xmm2 - movd rdi, xmm11 - movd rbp, xmm12 - movd r15, xmm13 - mov rcx, [rsp+104] - mov r9, [rsp+112] - - mov rax, r8 - mul rdi - movd xmm1, rdx - movd xmm0, rax - punpcklqdq xmm1, xmm0 - mov rdi, rcx - mov r8, rax - pxor xmm1, XMMWORD PTR [rbp+rcx] - xor ebp, 48 - paddq xmm1, xmm8 - xor r8, QWORD PTR [rbp+rcx+8] - xor rdx, QWORD PTR [rbp+rcx] - add r13, r8 - movdqu xmm2, XMMWORD PTR [rbp+rcx] - add r15, rdx - movdqu XMMWORD PTR [rbp+rcx], xmm1 - paddq xmm2, xmm4 - xor ebp, 16 - mov eax, ebp - xor rax, 32 - movdqu xmm0, XMMWORD PTR [rbp+rcx] - movdqu XMMWORD PTR [rbp+rcx], xmm2 - paddq xmm0, xmm10 - movdqu XMMWORD PTR [rax+rcx], xmm0 - movd rax, xmm3 - movdqa xmm10, xmm8 - mov QWORD PTR [r10+rcx], r15 - movdqa xmm8, xmm5 - xor r15, rax - mov QWORD PTR [r10+rcx+8], r13 - mov r8d, r15d - xor r13, r9 - and r8d, 2097136 - dec r11d - jnz CryptonightWOW_template_double_mainloop - -CryptonightWOW_template_double_part4: - - mov rbx, QWORD PTR [rsp+400] - movaps xmm6, XMMWORD PTR [rsp+160] - movaps xmm7, XMMWORD PTR [rsp+176] - movaps xmm8, XMMWORD PTR [rsp+192] - movaps xmm9, XMMWORD PTR [rsp+208] - movaps xmm10, XMMWORD PTR [rsp+224] - movaps xmm11, XMMWORD PTR [rsp+240] - movaps xmm12, XMMWORD PTR [rsp+256] - movaps xmm13, XMMWORD PTR [rsp+272] - movaps xmm14, XMMWORD PTR [rsp+288] - movaps xmm15, XMMWORD PTR [rsp+304] - add rsp, 320 - pop r15 - pop r14 - pop r13 - pop r12 - pop rdi - pop rsi - pop rbp - ret 0 -CryptonightWOW_template_double_end: diff --git a/src/crypto/cn/r/CryptonightR_gen.cpp b/src/crypto/cn/r/CryptonightR_gen.cpp index 3b80f8051..30f723632 100644 --- a/src/crypto/cn/r/CryptonightR_gen.cpp +++ b/src/crypto/cn/r/CryptonightR_gen.cpp @@ -99,20 +99,6 @@ static inline void add_random_math(uint8_t* &p, const V4_Instruction* code, int } } -void wow_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) -{ - uint8_t* p0 = reinterpret_cast(machine_code); - uint8_t* p = p0; - - add_code(p, CryptonightWOW_template_part1, CryptonightWOW_template_part2); - add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); - add_code(p, CryptonightWOW_template_part2, CryptonightWOW_template_part3); - *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_mainloop) - ((const uint8_t*)CryptonightWOW_template_part1)) - (p - p0)); - add_code(p, CryptonightWOW_template_part3, CryptonightWOW_template_end); - - xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); -} - void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { uint8_t* p0 = reinterpret_cast(machine_code); @@ -127,22 +113,6 @@ void v4_compile_code(const V4_Instruction* code, int code_size, void* machine_co xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } -void wow_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) -{ - uint8_t* p0 = reinterpret_cast(machine_code); - uint8_t* p = p0; - - add_code(p, CryptonightWOW_template_double_part1, CryptonightWOW_template_double_part2); - add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); - add_code(p, CryptonightWOW_template_double_part2, CryptonightWOW_template_double_part3); - add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); - add_code(p, CryptonightWOW_template_double_part3, CryptonightWOW_template_double_part4); - *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_template_double_mainloop) - ((const uint8_t*)CryptonightWOW_template_double_part1)) - (p - p0)); - add_code(p, CryptonightWOW_template_double_part4, CryptonightWOW_template_double_end); - - xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); -} - void v4_compile_code_double(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { uint8_t* p0 = reinterpret_cast(machine_code); @@ -159,20 +129,6 @@ void v4_compile_code_double(const V4_Instruction* code, int code_size, void* mac xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); } -void wow_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) -{ - uint8_t* p0 = reinterpret_cast(machine_code); - uint8_t* p = p0; - - add_code(p, CryptonightWOW_soft_aes_template_part1, CryptonightWOW_soft_aes_template_part2); - add_random_math(p, code, code_size, instructions, instructions_mov, false, ASM); - add_code(p, CryptonightWOW_soft_aes_template_part2, CryptonightWOW_soft_aes_template_part3); - *(int*)(p - 4) = static_cast((((const uint8_t*)CryptonightWOW_soft_aes_template_mainloop) - ((const uint8_t*)CryptonightWOW_soft_aes_template_part1)) - (p - p0)); - add_code(p, CryptonightWOW_soft_aes_template_part3, CryptonightWOW_soft_aes_template_end); - - xmrig::VirtualMemory::flushInstructionCache(machine_code, p - p0); -} - void v4_soft_aes_compile_code(const V4_Instruction* code, int code_size, void* machine_code, xmrig::Assembly ASM) { uint8_t* p0 = reinterpret_cast(machine_code); diff --git a/src/crypto/cn/r/variant4_random_math.h b/src/crypto/cn/r/variant4_random_math.h index 48f0f6ce0..732900612 100644 --- a/src/crypto/cn/r/variant4_random_math.h +++ b/src/crypto/cn/r/variant4_random_math.h @@ -255,7 +255,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh code_size = 0; int total_iterations = 0; - r8_used = (ALGO == xmrig::Algorithm::CN_WOW); + r8_used = false; // Generate random code to achieve minimal required latency for our abstract CPU // Try to get this latency for all 4 registers @@ -299,7 +299,7 @@ static int v4_random_math_init(struct V4_Instruction* code, const uint64_t heigh // Don't do ADD/SUB/XOR with the same register if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) { // a is always < 4, so we don't need to check bounds here - b = (ALGO == xmrig::Algorithm::CN_WOW) ? (a + 4) : 8; + b = 8; src_index = b; } diff --git a/src/crypto/common/Algorithm.cpp b/src/crypto/common/Algorithm.cpp index db6cb234b..eb1b17982 100644 --- a/src/crypto/common/Algorithm.cpp +++ b/src/crypto/common/Algorithm.cpp @@ -24,27 +24,24 @@ */ -#include -#include -#include -#include +#include "crypto/common/Algorithm.h" #include "crypto/cn/CnAlgo.h" -#include "crypto/common/Algorithm.h" #include "rapidjson/document.h" +#include +#include +#include +#include + + #ifdef _MSC_VER # define strcasecmp _stricmp #endif -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif - - namespace xmrig { @@ -67,7 +64,6 @@ static AlgoName const algorithm_names[] = { { "cryptonight_v8", nullptr, Algorithm::CN_2 }, { "cryptonight/r", "cn/r", Algorithm::CN_R }, { "cryptonight_r", nullptr, Algorithm::CN_R }, - { "cryptonight/wow", "cn/wow", Algorithm::CN_WOW }, { "cryptonight/fast", "cn/fast", Algorithm::CN_FAST }, { "cryptonight/msr", "cn/msr", Algorithm::CN_FAST }, { "cryptonight/half", "cn/half", Algorithm::CN_HALF }, @@ -116,30 +112,17 @@ static AlgoName const algorithm_names[] = { { "randomx/loki", "rx/loki", Algorithm::RX_LOKI }, { "RandomXL", nullptr, Algorithm::RX_LOKI }, # endif +# ifdef XMRIG_ALGO_ARGON2 + { "argon2/chukwa", nullptr, Algorithm::AR2_CHUKWA }, + { "chukwa", nullptr, Algorithm::AR2_CHUKWA }, + { "argon2/wrkz", nullptr, Algorithm::AR2_WRKZ }, +# endif }; } /* namespace xmrig */ -int xmrig::Algorithm::maxIntensity() const -{ -# ifdef XMRIG_ALGO_RANDOMX - if (family() == RANDOM_X) { - return 1; - } -# endif - -# ifdef XMRIG_ALGO_CN_GPU - if (m_id == CN_GPU) { - return 1; - } -# endif - - return 5; -} - - rapidjson::Value xmrig::Algorithm::toJSON() const { using namespace rapidjson; @@ -170,6 +153,8 @@ size_t xmrig::Algorithm::l2() const size_t xmrig::Algorithm::l3() const { + constexpr size_t oneMiB = 0x100000; + const Family f = family(); assert(f != UNKNOWN); @@ -179,8 +164,6 @@ size_t xmrig::Algorithm::l3() const # ifdef XMRIG_ALGO_RANDOMX if (f == RANDOM_X) { - constexpr size_t oneMiB = 0x100000; - switch (m_id) { case RX_0: case RX_LOKI: @@ -195,10 +178,49 @@ size_t xmrig::Algorithm::l3() const } # endif +# ifdef XMRIG_ALGO_ARGON2 + if (f == ARGON2) { + switch (m_id) { + case AR2_CHUKWA: + return oneMiB / 2; + + case AR2_WRKZ: + return oneMiB / 4; + + default: + break; + } + } +# endif + return 0; } +uint32_t xmrig::Algorithm::maxIntensity() const +{ +# ifdef XMRIG_ALGO_RANDOMX + if (family() == RANDOM_X) { + return 1; + } +# endif + +# ifdef XMRIG_ALGO_ARGON2 + if (family() == ARGON2) { + return 1; + } +# endif + +# ifdef XMRIG_ALGO_CN_GPU + if (m_id == CN_GPU) { + return 1; + } +# endif + + return 5; +} + + xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) { switch (id) { @@ -206,7 +228,6 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) case CN_1: case CN_2: case CN_R: - case CN_WOW: case CN_FAST: case CN_HALF: case CN_XAO: @@ -244,9 +265,14 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id) return RANDOM_X; # endif - case INVALID: - case MAX: - return UNKNOWN; +# ifdef XMRIG_ALGO_ARGON2 + case AR2_CHUKWA: + case AR2_WRKZ: + return ARGON2; +# endif + + default: + break; } return UNKNOWN; @@ -259,9 +285,9 @@ xmrig::Algorithm::Id xmrig::Algorithm::parse(const char *name) return INVALID; } - for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { - if ((strcasecmp(name, algorithm_names[i].name) == 0) || (algorithm_names[i].shortName != nullptr && strcasecmp(name, algorithm_names[i].shortName) == 0)) { - return algorithm_names[i].id; + for (const AlgoName &item : algorithm_names) { + if ((strcasecmp(name, item.name) == 0) || (item.shortName != nullptr && strcasecmp(name, item.shortName) == 0)) { + return item.id; } } @@ -271,9 +297,9 @@ xmrig::Algorithm::Id xmrig::Algorithm::parse(const char *name) const char *xmrig::Algorithm::name(bool shortName) const { - for (size_t i = 0; i < ARRAY_SIZE(algorithm_names); i++) { - if (algorithm_names[i].id == m_id) { - return shortName ? algorithm_names[i].shortName : algorithm_names[i].name; + for (const AlgoName &item : algorithm_names) { + if (item.id == m_id) { + return (shortName && item.shortName) ? item.shortName : item.name; } } diff --git a/src/crypto/common/Algorithm.h b/src/crypto/common/Algorithm.h index 92fcc61e7..79ea77347 100644 --- a/src/crypto/common/Algorithm.h +++ b/src/crypto/common/Algorithm.h @@ -39,13 +39,16 @@ namespace xmrig { class Algorithm { public: + // Changes in following file is required if this enum changed: + // + // src/backend/opencl/cl/cn/algorithm.cl + // enum Id : int { INVALID = -1, CN_0, // "cn/0" CryptoNight (original). CN_1, // "cn/1" CryptoNight variant 1 also known as Monero7 and CryptoNightV7. CN_2, // "cn/2" CryptoNight variant 2. CN_R, // "cn/r" CryptoNightR (Monero's variant 4). - CN_WOW, // "cn/wow" CryptoNightR (Wownero). CN_FAST, // "cn/fast" CryptoNight variant 1 with half iterations. CN_HALF, // "cn/half" CryptoNight variant 2 with half iterations (Masari/Torque). CN_XAO, // "cn/xao" CryptoNight variant 0 (modified, Alloy only). @@ -53,26 +56,18 @@ public: CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft). CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius). CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH). -# ifdef XMRIG_ALGO_CN_GPU CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo). -# endif -# ifdef XMRIG_ALGO_CN_LITE CN_LITE_0, // "cn-lite/0" CryptoNight-Lite variant 0. CN_LITE_1, // "cn-lite/1" CryptoNight-Lite variant 1. -# endif -# ifdef XMRIG_ALGO_CN_HEAVY CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB). CN_HEAVY_TUBE, // "cn-heavy/tube" CryptoNight-Heavy (modified, TUBE only). CN_HEAVY_XHV, // "cn-heavy/xhv" CryptoNight-Heavy (modified, Haven Protocol only). -# endif -# ifdef XMRIG_ALGO_CN_PICO CN_PICO_0, // "cn-pico" CryptoNight Turtle (TRTL) -# endif -# ifdef XMRIG_ALGO_RANDOMX RX_0, // "rx/0" RandomX (reference configuration). RX_WOW, // "rx/wow" RandomWOW (Wownero). RX_LOKI, // "rx/loki" RandomXL (Loki). -# endif + AR2_CHUKWA, // "argon2/chukwa" Argon2id (Chukwa). + AR2_WRKZ, // "argon2/wrkz" Argon2id (WRKZ) MAX }; @@ -82,13 +77,15 @@ public: CN_LITE, CN_HEAVY, CN_PICO, - RANDOM_X + RANDOM_X, + ARGON2 }; - inline Algorithm() {} + inline Algorithm() = default; inline Algorithm(const char *algo) : m_id(parse(algo)) {} inline Algorithm(Id id) : m_id(id) {} + inline bool isCN() const { auto f = family(); return f == CN || f == CN_LITE || f == CN_HEAVY || f == CN_PICO; } inline bool isEqual(const Algorithm &other) const { return m_id == other.m_id; } inline bool isValid() const { return m_id != INVALID; } inline const char *name() const { return name(false); } @@ -102,10 +99,10 @@ public: inline bool operator==(const Algorithm &other) const { return isEqual(other); } inline operator Algorithm::Id() const { return m_id; } - int maxIntensity() const; rapidjson::Value toJSON() const; size_t l2() const; size_t l3() const; + uint32_t maxIntensity() const; static Family family(Id id); static Id parse(const char *name); @@ -117,7 +114,7 @@ private: }; -typedef std::vector Algorithms; +using Algorithms = std::vector; } /* namespace xmrig */ diff --git a/src/crypto/randomx/aes_hash.cpp b/src/crypto/randomx/aes_hash.cpp index 5d6cb7438..fe149dfec 100644 --- a/src/crypto/randomx/aes_hash.cpp +++ b/src/crypto/randomx/aes_hash.cpp @@ -26,8 +26,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "soft_aes.h" -#include "randomx.h" +#include "crypto/randomx/soft_aes.h" +#include "crypto/randomx/randomx.h" #define AES_HASH_1R_STATE0 0xd7983aad, 0xcc82db47, 0x9fa856de, 0x92b52c0d #define AES_HASH_1R_STATE1 0xace78057, 0xf59e125a, 0x15c7b798, 0x338d996e diff --git a/src/crypto/randomx/allocator.cpp b/src/crypto/randomx/allocator.cpp index 2ddbed98b..ff708a62c 100644 --- a/src/crypto/randomx/allocator.cpp +++ b/src/crypto/randomx/allocator.cpp @@ -27,10 +27,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include -#include "allocator.hpp" -#include "intrin_portable.h" -#include "virtual_memory.hpp" -#include "common.hpp" +#include "crypto/randomx/allocator.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/virtual_memory.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { @@ -47,7 +47,7 @@ namespace randomx { rx_aligned_free(ptr); } - template class AlignedAllocator; + template struct AlignedAllocator; void* LargePageAllocator::allocMemory(size_t count) { return allocLargePagesMemory(count); @@ -57,4 +57,4 @@ namespace randomx { freePagedMemory(ptr, count); }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/argon2_core.c b/src/crypto/randomx/argon2_core.c index 4b8fa43d6..971766082 100644 --- a/src/crypto/randomx/argon2_core.c +++ b/src/crypto/randomx/argon2_core.c @@ -46,9 +46,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "argon2_core.h" -#include "blake2/blake2.h" -#include "blake2/blake2-impl.h" +#include "crypto/randomx/argon2_core.h" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/blake2/blake2-impl.h" #ifdef GENKAT #include "genkat.h" @@ -263,19 +263,6 @@ int rxa2_validate_inputs(const argon2_context *context) { return ARGON2_INCORRECT_PARAMETER; } - if (NULL == context->out) { - return ARGON2_OUTPUT_PTR_NULL; - } - - /* Validate output length */ - if (ARGON2_MIN_OUTLEN > context->outlen) { - return ARGON2_OUTPUT_TOO_SHORT; - } - - if (ARGON2_MAX_OUTLEN < context->outlen) { - return ARGON2_OUTPUT_TOO_LONG; - } - /* Validate password (required param) */ if (NULL == context->pwd) { if (0 != context->pwdlen) { @@ -418,31 +405,31 @@ void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type return; } - blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + rx_blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); store32(&value, context->lanes); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, context->outlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, context->m_cost); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, context->t_cost); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, context->version); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, (uint32_t)type); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); store32(&value, context->pwdlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); if (context->pwd != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + rx_blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, context->pwdlen); if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { @@ -452,17 +439,17 @@ void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type } store32(&value, context->saltlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); if (context->salt != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->salt, context->saltlen); + rx_blake2b_update(&BlakeHash, (const uint8_t *)context->salt, context->saltlen); } store32(&value, context->secretlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); if (context->secret != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + rx_blake2b_update(&BlakeHash, (const uint8_t *)context->secret, context->secretlen); if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { @@ -472,14 +459,14 @@ void rxa2_initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type } store32(&value, context->adlen); - blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + rx_blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); if (context->ad != NULL) { - blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + rx_blake2b_update(&BlakeHash, (const uint8_t *)context->ad, context->adlen); } - blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); + rx_blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); } int rxa2_argon_initialize(argon2_instance_t *instance, argon2_context *context) { diff --git a/src/crypto/randomx/argon2_core.h b/src/crypto/randomx/argon2_core.h index efd56d991..274a01c74 100644 --- a/src/crypto/randomx/argon2_core.h +++ b/src/crypto/randomx/argon2_core.h @@ -36,7 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define ARGON2_CORE_H #include -#include "argon2.h" +#include "crypto/randomx/argon2.h" #if defined(__cplusplus) extern "C" { diff --git a/src/crypto/randomx/argon2_ref.c b/src/crypto/randomx/argon2_ref.c index 018b985b8..157eda862 100644 --- a/src/crypto/randomx/argon2_ref.c +++ b/src/crypto/randomx/argon2_ref.c @@ -36,12 +36,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "argon2.h" -#include "argon2_core.h" +#include "crypto/randomx/argon2.h" +#include "crypto/randomx/argon2_core.h" -#include "blake2/blamka-round-ref.h" -#include "blake2/blake2-impl.h" -#include "blake2/blake2.h" +#include "crypto/randomx/blake2/blamka-round-ref.h" +#include "crypto/randomx/blake2/blake2-impl.h" +#include "crypto/randomx/blake2/blake2.h" /* * Function fills a new memory block and optionally XORs the old block over the new one. diff --git a/src/crypto/randomx/asm/program_loop_load.inc b/src/crypto/randomx/asm/program_loop_load.inc index 374af66ad..c29332313 100644 --- a/src/crypto/randomx/asm/program_loop_load.inc +++ b/src/crypto/randomx/asm/program_loop_load.inc @@ -1,5 +1,3 @@ - mov rdx, rax - and eax, RANDOMX_SCRATCHPAD_MASK lea rcx, [rsi+rax] push rcx xor r8, qword ptr [rcx+0] @@ -10,8 +8,6 @@ xor r13, qword ptr [rcx+40] xor r14, qword ptr [rcx+48] xor r15, qword ptr [rcx+56] - ror rdx, 32 - and edx, RANDOMX_SCRATCHPAD_MASK lea rcx, [rsi+rdx] push rcx cvtdq2pd xmm0, qword ptr [rcx+0] diff --git a/src/crypto/randomx/asm/program_loop_store.inc b/src/crypto/randomx/asm/program_loop_store.inc index 53164cb07..1ba1635c6 100644 --- a/src/crypto/randomx/asm/program_loop_store.inc +++ b/src/crypto/randomx/asm/program_loop_store.inc @@ -1,4 +1,3 @@ - xor eax, eax pop rcx mov qword ptr [rcx+0], r8 mov qword ptr [rcx+8], r9 diff --git a/src/crypto/randomx/asm/program_prologue_linux.inc b/src/crypto/randomx/asm/program_prologue_linux.inc index ffde152cb..4e1685de8 100644 --- a/src/crypto/randomx/asm/program_prologue_linux.inc +++ b/src/crypto/randomx/asm/program_prologue_linux.inc @@ -12,6 +12,13 @@ mov rcx, rdi mov rbp, qword ptr [rsi] ;# "mx", "ma" mov rdi, qword ptr [rsi+8] ;# uint8_t* dataset + + ;# dataset prefetch for the first iteration of the main loop + mov rax, rbp + shr rax, 32 + and eax, RANDOMX_DATASET_BASE_MASK + prefetchnta byte ptr [rdi+rax] + mov rsi, rdx ;# uint8_t* scratchpad mov rax, rbp diff --git a/src/crypto/randomx/asm/program_prologue_win64.inc b/src/crypto/randomx/asm/program_prologue_win64.inc index 590a98de9..a93862653 100644 --- a/src/crypto/randomx/asm/program_prologue_win64.inc +++ b/src/crypto/randomx/asm/program_prologue_win64.inc @@ -24,6 +24,13 @@ push rcx ;# RegisterFile& registerFile mov rbp, qword ptr [rdx] ;# "mx", "ma" mov rdi, qword ptr [rdx+8] ;# uint8_t* dataset + + ;# dataset prefetch for the first iteration of the main loop + mov rax, rbp + shr rax, 32 + and eax, RANDOMX_DATASET_BASE_MASK + prefetchnta byte ptr [rdi+rax] + mov rsi, r8 ;# uint8_t* scratchpad mov rbx, r9 ;# loop counter diff --git a/src/crypto/randomx/blake2/blake2-impl.h b/src/crypto/randomx/blake2/blake2-impl.h index 617f7c8a3..28f0e3011 100644 --- a/src/crypto/randomx/blake2/blake2-impl.h +++ b/src/crypto/randomx/blake2/blake2-impl.h @@ -37,7 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "endian.h" +#include "crypto/randomx/blake2/endian.h" static FORCE_INLINE uint64_t load48(const void *src) { const uint8_t *p = (const uint8_t *)src; diff --git a/src/crypto/randomx/blake2/blake2.h b/src/crypto/randomx/blake2/blake2.h index 7ac301ce4..4d364c36c 100644 --- a/src/crypto/randomx/blake2/blake2.h +++ b/src/crypto/randomx/blake2/blake2.h @@ -85,16 +85,14 @@ extern "C" { }; /* Streaming API */ - int blake2b_init(blake2b_state *S, size_t outlen); - int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, - size_t keylen); - int blake2b_init_param(blake2b_state *S, const blake2b_param *P); - int blake2b_update(blake2b_state *S, const void *in, size_t inlen); - int blake2b_final(blake2b_state *S, void *out, size_t outlen); + int rx_blake2b_init(blake2b_state *S, size_t outlen); + int rx_blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen); + int rx_blake2b_init_param(blake2b_state *S, const blake2b_param *P); + int rx_blake2b_update(blake2b_state *S, const void *in, size_t inlen); + int rx_blake2b_final(blake2b_state *S, void *out, size_t outlen); /* Simple API */ - int blake2b(void *out, size_t outlen, const void *in, size_t inlen, - const void *key, size_t keylen); + int rx_blake2b(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen); /* Argon2 Team - Begin Code */ int rxa2_blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); diff --git a/src/crypto/randomx/blake2/blake2b.c b/src/crypto/randomx/blake2/blake2b.c index 5931ee5c2..d2e028878 100644 --- a/src/crypto/randomx/blake2/blake2b.c +++ b/src/crypto/randomx/blake2/blake2b.c @@ -36,8 +36,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "blake2.h" -#include "blake2-impl.h" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/blake2/blake2-impl.h" static const uint64_t blake2b_IV[8] = { UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), @@ -105,7 +105,7 @@ int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { } /* Sequential blake2b initialization */ -int blake2b_init(blake2b_state *S, size_t outlen) { +int rx_blake2b_init(blake2b_state *S, size_t outlen) { blake2b_param P; if (S == NULL) { @@ -133,7 +133,7 @@ int blake2b_init(blake2b_state *S, size_t outlen) { return blake2b_init_param(S, &P); } -int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen) { +int rx_blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen) { blake2b_param P; if (S == NULL) { @@ -172,14 +172,14 @@ int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t ke uint8_t block[BLAKE2B_BLOCKBYTES]; memset(block, 0, BLAKE2B_BLOCKBYTES); memcpy(block, key, keylen); - blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + rx_blake2b_update(S, block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ //clear_internal_memory(block, BLAKE2B_BLOCKBYTES); } return 0; } -static void blake2b_compress(blake2b_state *S, const uint8_t *block) { +static void rx_blake2b_compress(blake2b_state *S, const uint8_t *block) { uint64_t m[16]; uint64_t v[16]; unsigned int i, r; @@ -237,7 +237,7 @@ static void blake2b_compress(blake2b_state *S, const uint8_t *block) { #undef ROUND } -int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { +int rx_blake2b_update(blake2b_state *S, const void *in, size_t inlen) { const uint8_t *pin = (const uint8_t *)in; if (inlen == 0) { @@ -260,14 +260,14 @@ int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { size_t fill = BLAKE2B_BLOCKBYTES - left; memcpy(&S->buf[left], pin, fill); blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress(S, S->buf); + rx_blake2b_compress(S, S->buf); S->buflen = 0; inlen -= fill; pin += fill; /* Avoid buffer copies when possible */ while (inlen > BLAKE2B_BLOCKBYTES) { blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); - blake2b_compress(S, pin); + rx_blake2b_compress(S, pin); inlen -= BLAKE2B_BLOCKBYTES; pin += BLAKE2B_BLOCKBYTES; } @@ -277,7 +277,7 @@ int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { return 0; } -int blake2b_final(blake2b_state *S, void *out, size_t outlen) { +int rx_blake2b_final(blake2b_state *S, void *out, size_t outlen) { uint8_t buffer[BLAKE2B_OUTBYTES] = { 0 }; unsigned int i; @@ -294,7 +294,7 @@ int blake2b_final(blake2b_state *S, void *out, size_t outlen) { blake2b_increment_counter(S, S->buflen); blake2b_set_lastblock(S); memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ - blake2b_compress(S, S->buf); + rx_blake2b_compress(S, S->buf); for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ store64(buffer + sizeof(S->h[i]) * i, S->h[i]); @@ -307,7 +307,7 @@ int blake2b_final(blake2b_state *S, void *out, size_t outlen) { return 0; } -int blake2b(void *out, size_t outlen, const void *in, size_t inlen, +int rx_blake2b(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen) { blake2b_state S; int ret = -1; @@ -326,20 +326,20 @@ int blake2b(void *out, size_t outlen, const void *in, size_t inlen, } if (keylen > 0) { - if (blake2b_init_key(&S, outlen, key, keylen) < 0) { + if (rx_blake2b_init_key(&S, outlen, key, keylen) < 0) { goto fail; } } else { - if (blake2b_init(&S, outlen) < 0) { + if (rx_blake2b_init(&S, outlen) < 0) { goto fail; } } - if (blake2b_update(&S, in, inlen) < 0) { + if (rx_blake2b_update(&S, in, inlen) < 0) { goto fail; } - ret = blake2b_final(&S, out, outlen); + ret = rx_blake2b_final(&S, out, outlen); fail: //clear_internal_memory(&S, sizeof(S)); @@ -369,26 +369,26 @@ int rxa2_blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { } while ((void)0, 0) if (outlen <= BLAKE2B_OUTBYTES) { - TRY(blake2b_init(&blake_state, outlen)); - TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); - TRY(blake2b_update(&blake_state, in, inlen)); - TRY(blake2b_final(&blake_state, out, outlen)); + TRY(rx_blake2b_init(&blake_state, outlen)); + TRY(rx_blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(rx_blake2b_update(&blake_state, in, inlen)); + TRY(rx_blake2b_final(&blake_state, out, outlen)); } else { uint32_t toproduce; uint8_t out_buffer[BLAKE2B_OUTBYTES]; uint8_t in_buffer[BLAKE2B_OUTBYTES]; - TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); - TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); - TRY(blake2b_update(&blake_state, in, inlen)); - TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + TRY(rx_blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + TRY(rx_blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(rx_blake2b_update(&blake_state, in, inlen)); + TRY(rx_blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); out += BLAKE2B_OUTBYTES / 2; toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; while (toproduce > BLAKE2B_OUTBYTES) { memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); - TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + TRY(rx_blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, BLAKE2B_OUTBYTES, NULL, 0)); memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); out += BLAKE2B_OUTBYTES / 2; @@ -396,7 +396,7 @@ int rxa2_blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { } memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); - TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + TRY(rx_blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, 0)); memcpy(out, out_buffer, toproduce); } diff --git a/src/crypto/randomx/blake2/blamka-round-ref.h b/src/crypto/randomx/blake2/blamka-round-ref.h index f1fb50bf8..45606b8f8 100644 --- a/src/crypto/randomx/blake2/blamka-round-ref.h +++ b/src/crypto/randomx/blake2/blamka-round-ref.h @@ -35,8 +35,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef BLAKE_ROUND_MKA_H #define BLAKE_ROUND_MKA_H -#include "blake2.h" -#include "blake2-impl.h" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/blake2/blake2-impl.h" /* designed by the Lyra PHC team */ static FORCE_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { diff --git a/src/crypto/randomx/blake2/endian.h b/src/crypto/randomx/blake2/endian.h index c7afed261..8fd6b9706 100644 --- a/src/crypto/randomx/blake2/endian.h +++ b/src/crypto/randomx/blake2/endian.h @@ -3,8 +3,10 @@ #include #if defined(_MSC_VER) -#define FORCE_INLINE __inline -#elif defined(__GNUC__) || defined(__clang__) +#define FORCE_INLINE __forceinline +#elif defined(__GNUC__) +#define FORCE_INLINE __attribute__((always_inline)) inline +#elif defined(__clang__) #define FORCE_INLINE __inline__ #else #define FORCE_INLINE diff --git a/src/crypto/randomx/blake2_generator.cpp b/src/crypto/randomx/blake2_generator.cpp index dcf51cecc..edfe2e34c 100644 --- a/src/crypto/randomx/blake2_generator.cpp +++ b/src/crypto/randomx/blake2_generator.cpp @@ -27,9 +27,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include -#include "blake2/blake2.h" -#include "blake2/endian.h" -#include "blake2_generator.hpp" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/blake2/endian.h" +#include "crypto/randomx/blake2_generator.hpp" namespace randomx { @@ -46,7 +46,7 @@ namespace randomx { return data[dataIndex++]; } - uint32_t Blake2Generator::getInt32() { + uint32_t Blake2Generator::getUInt32() { checkData(4); auto ret = load32(&data[dataIndex]); dataIndex += 4; @@ -55,8 +55,8 @@ namespace randomx { void Blake2Generator::checkData(const size_t bytesNeeded) { if (dataIndex + bytesNeeded > sizeof(data)) { - blake2b(data, sizeof(data), data, sizeof(data), nullptr, 0); + rx_blake2b(data, sizeof(data), data, sizeof(data), nullptr, 0); dataIndex = 0; } } -} \ No newline at end of file +} diff --git a/src/crypto/randomx/blake2_generator.hpp b/src/crypto/randomx/blake2_generator.hpp index b5ac0801c..5e7f61f25 100644 --- a/src/crypto/randomx/blake2_generator.hpp +++ b/src/crypto/randomx/blake2_generator.hpp @@ -36,7 +36,7 @@ namespace randomx { public: Blake2Generator(const void* seed, size_t seedSize, int nonce = 0); uint8_t getByte(); - uint32_t getInt32(); + uint32_t getUInt32(); private: void checkData(const size_t); diff --git a/src/crypto/randomx/bytecode_machine.cpp b/src/crypto/randomx/bytecode_machine.cpp index 8447318e7..55a639358 100644 --- a/src/crypto/randomx/bytecode_machine.cpp +++ b/src/crypto/randomx/bytecode_machine.cpp @@ -26,8 +26,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "bytecode_machine.hpp" -#include "reciprocal.h" +#include "crypto/randomx/bytecode_machine.hpp" +#include "crypto/randomx/reciprocal.h" namespace randomx { @@ -244,7 +244,7 @@ namespace randomx { if (opcode < RandomX_CurrentConfig.CEIL_IMUL_RCP) { uint64_t divisor = instr.getImm32(); - if (!isPowerOf2(divisor)) { + if (!isZeroOrPowerOf2(divisor)) { auto dst = instr.dst % RegistersCount; ibc.type = InstructionType::IMUL_R; ibc.idst = &nreg->r[dst]; diff --git a/src/crypto/randomx/bytecode_machine.hpp b/src/crypto/randomx/bytecode_machine.hpp index 810f854aa..8aee78d89 100644 --- a/src/crypto/randomx/bytecode_machine.hpp +++ b/src/crypto/randomx/bytecode_machine.hpp @@ -28,10 +28,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "common.hpp" -#include "intrin_portable.h" -#include "instruction.hpp" -#include "program.hpp" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/instruction.hpp" +#include "crypto/randomx/program.hpp" namespace randomx { diff --git a/src/crypto/randomx/common.hpp b/src/crypto/randomx/common.hpp index 7f7ea0edb..da36f2c5b 100644 --- a/src/crypto/randomx/common.hpp +++ b/src/crypto/randomx/common.hpp @@ -31,9 +31,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "blake2/endian.h" -#include "configuration.h" -#include "randomx.h" +#include "crypto/randomx/blake2/endian.h" +#include "crypto/randomx/configuration.h" +#include "crypto/randomx/randomx.h" namespace randomx { @@ -137,7 +137,7 @@ namespace randomx { constexpr int RegisterNeedsDisplacement = 5; //x86 r13 register constexpr int RegisterNeedsSib = 4; //x86 r12 register - inline bool isPowerOf2(uint64_t x) { + inline bool isZeroOrPowerOf2(uint64_t x) { return (x & (x - 1)) == 0; } diff --git a/src/crypto/randomx/dataset.cpp b/src/crypto/randomx/dataset.cpp index b094b1cb4..8aeafffd8 100644 --- a/src/crypto/randomx/dataset.cpp +++ b/src/crypto/randomx/dataset.cpp @@ -39,17 +39,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "common.hpp" -#include "dataset.hpp" -#include "virtual_memory.hpp" -#include "superscalar.hpp" -#include "blake2_generator.hpp" -#include "reciprocal.h" -#include "blake2/endian.h" -#include "argon2.h" -#include "argon2_core.h" -#include "jit_compiler.hpp" -#include "intrin_portable.h" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/dataset.hpp" +#include "crypto/randomx/virtual_memory.hpp" +#include "crypto/randomx/superscalar.hpp" +#include "crypto/randomx/blake2_generator.hpp" +#include "crypto/randomx/reciprocal.h" +#include "crypto/randomx/blake2/endian.h" +#include "crypto/randomx/argon2.h" +#include "crypto/randomx/argon2_core.h" +#include "crypto/randomx/jit_compiler.hpp" +#include "crypto/randomx/intrin_portable.h" //static_assert(RANDOMX_ARGON_MEMORY % (RANDOMX_ARGON_LANES * ARGON2_SYNC_POINTS) == 0, "RANDOMX_ARGON_MEMORY - invalid value"); static_assert(ARGON2_BLOCK_SIZE == randomx::ArgonBlockSize, "Unpexpected value of ARGON2_BLOCK_SIZE"); diff --git a/src/crypto/randomx/dataset.hpp b/src/crypto/randomx/dataset.hpp index 42d4f05eb..6c179b5d1 100644 --- a/src/crypto/randomx/dataset.hpp +++ b/src/crypto/randomx/dataset.hpp @@ -31,9 +31,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "common.hpp" -#include "superscalar_program.hpp" -#include "allocator.hpp" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/superscalar_program.hpp" +#include "crypto/randomx/allocator.hpp" /* Global scope for C binding */ struct randomx_dataset { diff --git a/src/crypto/randomx/instruction.hpp b/src/crypto/randomx/instruction.hpp index 1904afc0c..446ebfa87 100644 --- a/src/crypto/randomx/instruction.hpp +++ b/src/crypto/randomx/instruction.hpp @@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "blake2/endian.h" +#include "crypto/randomx/blake2/endian.h" namespace randomx { @@ -77,13 +77,13 @@ namespace randomx { void setImm32(uint32_t val) { return store32(&imm32, val); } - int getModMem() const { - return mod % 4; //bits 0-1 + uint32_t getModMem() const { + return mod & 3; //bits 0-1 } - int getModShift() const { - return (mod >> 2) % 4; //bits 2-3 + uint32_t getModShift() const { + return (mod >> 2) & 3; //bits 2-3 } - int getModCond() const { + uint32_t getModCond() const { return mod >> 4; //bits 4-7 } void setMod(uint8_t val) { diff --git a/src/crypto/randomx/instructions_portable.cpp b/src/crypto/randomx/instructions_portable.cpp index 8f0592dda..b28203a9c 100644 --- a/src/crypto/randomx/instructions_portable.cpp +++ b/src/crypto/randomx/instructions_portable.cpp @@ -28,9 +28,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "common.hpp" -#include "intrin_portable.h" -#include "blake2/endian.h" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/blake2/endian.h" #if defined(__SIZEOF_INT128__) typedef unsigned __int128 uint128_t; diff --git a/src/crypto/randomx/intrin_portable.h b/src/crypto/randomx/intrin_portable.h index 83acbe65d..e49160967 100644 --- a/src/crypto/randomx/intrin_portable.h +++ b/src/crypto/randomx/intrin_portable.h @@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "blake2/endian.h" +#include "crypto/randomx/blake2/endian.h" constexpr int32_t unsigned32ToSigned2sCompl(uint32_t x) { return (-1 == ~0) ? (int32_t)x : (x > INT32_MAX ? (-(int32_t)(UINT32_MAX - x) - 1) : (int32_t)x); diff --git a/src/crypto/randomx/jit_compiler.hpp b/src/crypto/randomx/jit_compiler.hpp index bd9c2b0e4..03b605085 100644 --- a/src/crypto/randomx/jit_compiler.hpp +++ b/src/crypto/randomx/jit_compiler.hpp @@ -29,9 +29,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #if defined(_M_X64) || defined(__x86_64__) -#include "jit_compiler_x86.hpp" +#include "crypto/randomx/jit_compiler_x86.hpp" #elif defined(__aarch64__) -#include "jit_compiler_a64.hpp" +#include "crypto/randomx/jit_compiler_a64.hpp" #else -#include "jit_compiler_fallback.hpp" +#include "crypto/randomx/jit_compiler_fallback.hpp" #endif diff --git a/src/crypto/randomx/jit_compiler_a64.hpp b/src/crypto/randomx/jit_compiler_a64.hpp index 58aa25c4d..4b0bed665 100644 --- a/src/crypto/randomx/jit_compiler_a64.hpp +++ b/src/crypto/randomx/jit_compiler_a64.hpp @@ -31,7 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "common.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { @@ -70,4 +70,4 @@ namespace randomx { return 0; } }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/jit_compiler_fallback.hpp b/src/crypto/randomx/jit_compiler_fallback.hpp index 8103a6321..bc3638589 100644 --- a/src/crypto/randomx/jit_compiler_fallback.hpp +++ b/src/crypto/randomx/jit_compiler_fallback.hpp @@ -31,7 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "common.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { @@ -70,4 +70,4 @@ namespace randomx { return 0; } }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/jit_compiler_x86.cpp b/src/crypto/randomx/jit_compiler_x86.cpp index 6f04e28a1..2f6cfbda5 100644 --- a/src/crypto/randomx/jit_compiler_x86.cpp +++ b/src/crypto/randomx/jit_compiler_x86.cpp @@ -29,12 +29,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "jit_compiler_x86.hpp" -#include "jit_compiler_x86_static.hpp" -#include "superscalar.hpp" -#include "program.hpp" -#include "reciprocal.h" -#include "virtual_memory.hpp" +#include "crypto/randomx/jit_compiler_x86.hpp" +#include "crypto/randomx/jit_compiler_x86_static.hpp" +#include "crypto/randomx/superscalar.hpp" +#include "crypto/randomx/program.hpp" +#include "crypto/randomx/reciprocal.h" +#include "crypto/randomx/virtual_memory.hpp" namespace randomx { /* @@ -76,6 +76,8 @@ namespace randomx { */ + const uint8_t* codePrefetchScratchpad = (uint8_t*)&randomx_prefetch_scratchpad; + const uint8_t* codePrefetchScratchpadEnd = (uint8_t*)&randomx_prefetch_scratchpad_end; const uint8_t* codePrologue = (uint8_t*)&randomx_program_prologue; const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin; const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load; @@ -93,6 +95,7 @@ namespace randomx { const uint8_t* codeShhEnd = (uint8_t*)&randomx_sshash_end; const uint8_t* codeShhInit = (uint8_t*)&randomx_sshash_init; + const int32_t prefetchScratchpadSize = codePrefetchScratchpadEnd - codePrefetchScratchpad; const int32_t prologueSize = codeLoopBegin - codePrologue; const int32_t loopLoadSize = codeProgamStart - codeLoopLoad; const int32_t readDatasetSize = codeReadDatasetLightSshInit - codeReadDataset; @@ -160,7 +163,7 @@ namespace randomx { static const uint8_t REX_MAXPD[] = { 0x66, 0x41, 0x0f, 0x5f }; static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e }; static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 }; - static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x50, 0x0F, 0xAE, 0x14, 0x24, 0x58 }; + static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x44, 0x24, 0xFC, 0x0F, 0xAE, 0x54, 0x24, 0xFC }; static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 }; static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 }; static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 }; @@ -181,7 +184,7 @@ namespace randomx { static const uint8_t REX_TEST[] = { 0x49, 0xF7 }; static const uint8_t JZ[] = { 0x0f, 0x84 }; static const uint8_t RET = 0xc3; - static const uint8_t LEA_32[] = { 0x67, 0x41, 0x8d }; + static const uint8_t LEA_32[] = { 0x41, 0x8d }; static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 }; static const uint8_t ADD_EBX_I[] = { 0x81, 0xc3 }; @@ -197,7 +200,7 @@ namespace randomx { // static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 }; size_t JitCompilerX86::getCodeSize() { - return codePos - prologueSize; + return codePos < prologueSize ? 0 : codePos - prologueSize; } JitCompilerX86::JitCompilerX86() { @@ -214,18 +217,18 @@ namespace randomx { generateProgramPrologue(prog, pcfg); memcpy(code + codePos, RandomX_CurrentConfig.codeReadDatasetTweaked, readDatasetSize); codePos += readDatasetSize; - generateProgramEpilogue(prog); + generateProgramEpilogue(prog, pcfg); } void JitCompilerX86::generateProgramLight(Program& prog, ProgramConfiguration& pcfg, uint32_t datasetOffset) { generateProgramPrologue(prog, pcfg); - emit(RandomX_CurrentConfig.codeReadDatasetLightSshInitTweaked, readDatasetLightInitSize); - emit(ADD_EBX_I); - emit32(datasetOffset / CacheLineSize); - emitByte(CALL); - emit32(superScalarHashOffset - (codePos + 4)); - emit(codeReadDatasetLightSshFin, readDatasetLightFinSize); - generateProgramEpilogue(prog); + emit(RandomX_CurrentConfig.codeReadDatasetLightSshInitTweaked, readDatasetLightInitSize, code, codePos); + emit(ADD_EBX_I, code, codePos); + emit32(datasetOffset / CacheLineSize, code, codePos); + emitByte(CALL, code, codePos); + emit32(superScalarHashOffset - (codePos + 4), code, codePos); + emit(codeReadDatasetLightSshFin, readDatasetLightFinSize, code, codePos); + generateProgramEpilogue(prog, pcfg); } template @@ -238,23 +241,23 @@ namespace randomx { Instruction& instr = prog(i); generateSuperscalarCode(instr, reciprocalCache); } - emit(codeShhLoad, codeSshLoadSize); + emit(codeShhLoad, codeSshLoadSize, code, codePos); if (j < RandomX_CurrentConfig.CacheAccesses - 1) { - emit(REX_MOV_RR64); - emitByte(0xd8 + prog.getAddressRegister()); - emit(RandomX_CurrentConfig.codeShhPrefetchTweaked, codeSshPrefetchSize); + emit(REX_MOV_RR64, code, codePos); + emitByte(0xd8 + prog.getAddressRegister(), code, codePos); + emit(RandomX_CurrentConfig.codeShhPrefetchTweaked, codeSshPrefetchSize, code, codePos); #ifdef RANDOMX_ALIGN int align = (codePos % 16); while (align != 0) { int nopSize = 16 - align; if (nopSize > 8) nopSize = 8; - emit(NOPX[nopSize - 1], nopSize); + emit(NOPX[nopSize - 1], nopSize, code, codePos); align = (codePos % 16); } #endif } } - emitByte(RET); + emitByte(RET, code, codePos); } template @@ -265,508 +268,672 @@ namespace randomx { } void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) { - instructionOffsets.clear(); - for (unsigned i = 0; i < 8; ++i) { - registerUsage[i] = -1; - } + memset(registerUsage, -1, sizeof(registerUsage)); + + codePos = ((uint8_t*)randomx_program_prologue_first_load) - ((uint8_t*)randomx_program_prologue); + code[codePos + 2] = 0xc0 + pcfg.readReg0; + code[codePos + 5] = 0xc0 + pcfg.readReg1; + *(uint32_t*)(code + codePos + 10) = RandomX_CurrentConfig.ScratchpadL3Mask64_Calculated; + *(uint32_t*)(code + codePos + 20) = RandomX_CurrentConfig.ScratchpadL3Mask64_Calculated; + codePos = prologueSize; memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask)); - emit(REX_XOR_RAX_R64); - emitByte(0xc0 + pcfg.readReg0); - emit(REX_XOR_RAX_R64); - emitByte(0xc0 + pcfg.readReg1); - memcpy(code + codePos, RandomX_CurrentConfig.codeLoopLoadTweaked, loopLoadSize); + memcpy(code + codePos, codeLoopLoad, loopLoadSize); codePos += loopLoadSize; for (unsigned i = 0; i < prog.getSize(); ++i) { Instruction& instr = prog(i); instr.src %= RegistersCount; instr.dst %= RegistersCount; - generateCode(instr, i); + instructionOffsets[i] = codePos; + (this->*(engine[instr.opcode]))(instr, i); } - emit(REX_MOV_RR); - emitByte(0xc0 + pcfg.readReg2); - emit(REX_XOR_EAX); - emitByte(0xc0 + pcfg.readReg3); + emit(REX_MOV_RR, code, codePos); + emitByte(0xc0 + pcfg.readReg2, code, codePos); + emit(REX_XOR_EAX, code, codePos); + emitByte(0xc0 + pcfg.readReg3, code, codePos); } - void JitCompilerX86::generateProgramEpilogue(Program& prog) { + void JitCompilerX86::generateProgramEpilogue(Program& prog, ProgramConfiguration& pcfg) { + emit(REX_MOV_RR64, code, codePos); + emitByte(0xc0 + pcfg.readReg0, code, codePos); + emit(REX_XOR_RAX_R64, code, codePos); + emitByte(0xc0 + pcfg.readReg1, code, codePos); + emit(RandomX_CurrentConfig.codePrefetchScratchpadTweaked, prefetchScratchpadSize, code, codePos); memcpy(code + codePos, codeLoopStore, loopStoreSize); codePos += loopStoreSize; - emit(SUB_EBX); - emit(JNZ); - emit32(prologueSize - codePos - 4); - emitByte(JMP); - emit32(epilogueOffset - codePos - 4); - } - - void JitCompilerX86::generateCode(Instruction& instr, int i) { - instructionOffsets.push_back(codePos); - auto generator = engine[instr.opcode]; - (this->*generator)(instr, i); + emit(SUB_EBX, code, codePos); + emit(JNZ, code, codePos); + emit32(prologueSize - codePos - 4, code, codePos); + emitByte(JMP, code, codePos); + emit32(epilogueOffset - codePos - 4, code, codePos); } void JitCompilerX86::generateSuperscalarCode(Instruction& instr, std::vector &reciprocalCache) { switch ((SuperscalarInstructionType)instr.opcode) { case randomx::SuperscalarInstructionType::ISUB_R: - emit(REX_SUB_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_SUB_RR, code, codePos); + emitByte(0xc0 + 8 * instr.dst + instr.src, code, codePos); break; case randomx::SuperscalarInstructionType::IXOR_R: - emit(REX_XOR_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_XOR_RR, code, codePos); + emitByte(0xc0 + 8 * instr.dst + instr.src, code, codePos); break; case randomx::SuperscalarInstructionType::IADD_RS: - emit(REX_LEA); - emitByte(0x04 + 8 * instr.dst); - genSIB(instr.getModShift(), instr.src, instr.dst); + emit(REX_LEA, code, codePos); + emitByte(0x04 + 8 * instr.dst, code, codePos); + genSIB(instr.getModShift(), instr.src, instr.dst, code, codePos); break; case randomx::SuperscalarInstructionType::IMUL_R: - emit(REX_IMUL_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_IMUL_RR, code, codePos); + emitByte(0xc0 + 8 * instr.dst + instr.src, code, codePos); break; case randomx::SuperscalarInstructionType::IROR_C: - emit(REX_ROT_I8); - emitByte(0xc8 + instr.dst); - emitByte(instr.getImm32() & 63); + emit(REX_ROT_I8, code, codePos); + emitByte(0xc8 + instr.dst, code, codePos); + emitByte(instr.getImm32() & 63, code, codePos); break; case randomx::SuperscalarInstructionType::IADD_C7: - emit(REX_81); - emitByte(0xc0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_81, code, codePos); + emitByte(0xc0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); break; case randomx::SuperscalarInstructionType::IXOR_C7: - emit(REX_XOR_RI); - emitByte(0xf0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_XOR_RI, code, codePos); + emitByte(0xf0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); break; case randomx::SuperscalarInstructionType::IADD_C8: - emit(REX_81); - emitByte(0xc0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_81, code, codePos); + emitByte(0xc0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); #ifdef RANDOMX_ALIGN - emit(NOP1); + emit(NOP1, code, codePos); #endif break; case randomx::SuperscalarInstructionType::IXOR_C8: - emit(REX_XOR_RI); - emitByte(0xf0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_XOR_RI, code, codePos); + emitByte(0xf0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); #ifdef RANDOMX_ALIGN - emit(NOP1); + emit(NOP1, code, codePos); #endif break; case randomx::SuperscalarInstructionType::IADD_C9: - emit(REX_81); - emitByte(0xc0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_81, code, codePos); + emitByte(0xc0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); #ifdef RANDOMX_ALIGN - emit(NOP2); + emit(NOP2, code, codePos); #endif break; case randomx::SuperscalarInstructionType::IXOR_C9: - emit(REX_XOR_RI); - emitByte(0xf0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_XOR_RI, code, codePos); + emitByte(0xf0 + instr.dst, code, codePos); + emit32(instr.getImm32(), code, codePos); #ifdef RANDOMX_ALIGN - emit(NOP2); + emit(NOP2, code, codePos); #endif break; case randomx::SuperscalarInstructionType::IMULH_R: - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_R); - emitByte(0xe0 + instr.src); - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_RR64, code, codePos); + emitByte(0xc0 + instr.dst, code, codePos); + emit(REX_MUL_R, code, codePos); + emitByte(0xe0 + instr.src, code, codePos); + emit(REX_MOV_R64R, code, codePos); + emitByte(0xc2 + 8 * instr.dst, code, codePos); break; case randomx::SuperscalarInstructionType::ISMULH_R: - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_R); - emitByte(0xe8 + instr.src); - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_RR64, code, codePos); + emitByte(0xc0 + instr.dst, code, codePos); + emit(REX_MUL_R, code, codePos); + emitByte(0xe8 + instr.src, code, codePos); + emit(REX_MOV_R64R, code, codePos); + emitByte(0xc2 + 8 * instr.dst, code, codePos); break; case randomx::SuperscalarInstructionType::IMUL_RCP: - emit(MOV_RAX_I); - emit64(reciprocalCache[instr.getImm32()]); - emit(REX_IMUL_RM); - emitByte(0xc0 + 8 * instr.dst); + emit(MOV_RAX_I, code, codePos); + emit64(reciprocalCache[instr.getImm32()], code, codePos); + emit(REX_IMUL_RM, code, codePos); + emitByte(0xc0 + 8 * instr.dst, code, codePos); break; default: UNREACHABLE; } } - void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) { - emit(LEA_32); - emitByte(0x80 + instr.src + (rax ? 0 : 8)); + void JitCompilerX86::genAddressReg(Instruction& instr, uint8_t* code, int& codePos, bool rax) { + emit(LEA_32, code, codePos); + emitByte(0x80 + instr.src + (rax ? 0 : 8), code, codePos); if (instr.src == RegisterNeedsSib) { - emitByte(0x24); + emitByte(0x24, code, codePos); } - emit32(instr.getImm32()); + emit32(instr.getImm32(), code, codePos); if (rax) - emitByte(AND_EAX_I); + emitByte(AND_EAX_I, code, codePos); else - emit(AND_ECX_I); - emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + emit(AND_ECX_I, code, codePos); + emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask, code, codePos); } - void JitCompilerX86::genAddressRegDst(Instruction& instr) { - emit(LEA_32); - emitByte(0x80 + instr.dst); + void JitCompilerX86::genAddressRegDst(Instruction& instr, uint8_t* code, int& codePos) { + emit(LEA_32, code, codePos); + emitByte(0x80 + instr.dst, code, codePos); if (instr.dst == RegisterNeedsSib) { - emitByte(0x24); + emitByte(0x24, code, codePos); } - emit32(instr.getImm32()); - emitByte(AND_EAX_I); + emit32(instr.getImm32(), code, codePos); + emitByte(AND_EAX_I, code, codePos); if (instr.getModCond() < StoreL3Condition) { - emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask); + emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask, code, codePos); } else { - emit32(ScratchpadL3Mask); + emit32(ScratchpadL3Mask, code, codePos); } } - void JitCompilerX86::genAddressImm(Instruction& instr) { - emit32(instr.getImm32() & ScratchpadL3Mask); + void JitCompilerX86::genAddressImm(Instruction& instr, uint8_t* code, int& codePos) { + emit32(instr.getImm32() & ScratchpadL3Mask, code, codePos); } + static const uint32_t template_IADD_RS[8] = { + 0x048d4f, + 0x0c8d4f, + 0x148d4f, + 0x1c8d4f, + 0x248d4f, + 0xac8d4f, + 0x348d4f, + 0x3c8d4f, + }; + void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) { + int pos = codePos; + uint8_t* const p = code + pos; + registerUsage[instr.dst] = i; - emit(REX_LEA); - if (instr.dst == RegisterNeedsDisplacement) - emitByte(0xac); - else - emitByte(0x04 + 8 * instr.dst); - genSIB(instr.getModShift(), instr.src, instr.dst); - if (instr.dst == RegisterNeedsDisplacement) - emit32(instr.getImm32()); + + const uint32_t sib = (instr.getModShift() << 6) | (instr.src << 3) | instr.dst; + *(uint32_t*)(p) = template_IADD_RS[instr.dst] | (sib << 24); + *(uint32_t*)(p + 4) = instr.getImm32(); + + codePos = pos + ((instr.dst == RegisterNeedsDisplacement) ? 8 : 4); } + static const uint32_t template_IADD_M[8] = { + 0x0604034c, + 0x060c034c, + 0x0614034c, + 0x061c034c, + 0x0624034c, + 0x062c034c, + 0x0634034c, + 0x063c034c, + }; + void JitCompilerX86::h_IADD_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr); - emit(REX_ADD_RM); - emitByte(0x04 + 8 * instr.dst); - emitByte(0x06); + genAddressReg(instr, p, pos); + emit32(template_IADD_M[instr.dst], p, pos); } else { - emit(REX_ADD_RM); - emitByte(0x86 + 8 * instr.dst); - genAddressImm(instr); + emit(REX_ADD_RM, p, pos); + emitByte(0x86 + 8 * instr.dst, p, pos); + genAddressImm(instr, p, pos); } + + codePos = pos; } - void JitCompilerX86::genSIB(int scale, int index, int base) { - emitByte((scale << 6) | (index << 3) | base); + void JitCompilerX86::genSIB(int scale, int index, int base, uint8_t* code, int& codePos) { + emitByte((scale << 6) | (index << 3) | base, code, codePos); } void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - emit(REX_SUB_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_SUB_RR, p, pos); + emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos); } else { - emit(REX_81); - emitByte(0xe8 + instr.dst); - emit32(instr.getImm32()); + emit(REX_81, p, pos); + emitByte(0xe8 + instr.dst, p, pos); + emit32(instr.getImm32(), p, pos); } + + codePos = pos; } void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr); - emit(REX_SUB_RM); - emitByte(0x04 + 8 * instr.dst); - emitByte(0x06); + genAddressReg(instr, p, pos); + emit(REX_SUB_RM, p, pos); + emitByte(0x04 + 8 * instr.dst, p, pos); + emitByte(0x06, p, pos); } else { - emit(REX_SUB_RM); - emitByte(0x86 + 8 * instr.dst); - genAddressImm(instr); + emit(REX_SUB_RM, p, pos); + emitByte(0x86 + 8 * instr.dst, p, pos); + genAddressImm(instr, p, pos); } + + codePos = pos; } void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - emit(REX_IMUL_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_IMUL_RR, p, pos); + emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos); } else { - emit(REX_IMUL_RRI); - emitByte(0xc0 + 9 * instr.dst); - emit32(instr.getImm32()); + emit(REX_IMUL_RRI, p, pos); + emitByte(0xc0 + 9 * instr.dst, p, pos); + emit32(instr.getImm32(), p, pos); } + + codePos = pos; } void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr); - emit(REX_IMUL_RM); - emitByte(0x04 + 8 * instr.dst); - emitByte(0x06); + genAddressReg(instr, p, pos); + emit(REX_IMUL_RM, p, pos); + emitByte(0x04 + 8 * instr.dst, p, pos); + emitByte(0x06, p, pos); } else { - emit(REX_IMUL_RM); - emitByte(0x86 + 8 * instr.dst); - genAddressImm(instr); + emit(REX_IMUL_RM, p, pos); + emitByte(0x86 + 8 * instr.dst, p, pos); + genAddressImm(instr, p, pos); } + + codePos = pos; } void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_R); - emitByte(0xe0 + instr.src); - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_MUL_R, p, pos); + emitByte(0xe0 + instr.src, p, pos); + emit(REX_MOV_R64R, p, pos); + emitByte(0xc2 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr, false); - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_MEM); + genAddressReg(instr, p, pos, false); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_MUL_MEM, p, pos); } else { - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_M); - emitByte(0xa6); - genAddressImm(instr); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_MUL_M, p, pos); + emitByte(0xa6, p, pos); + genAddressImm(instr, p, pos); } - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_R64R, p, pos); + emitByte(0xc2 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_R); - emitByte(0xe8 + instr.src); - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_MUL_R, p, pos); + emitByte(0xe8 + instr.src, p, pos); + emit(REX_MOV_R64R, p, pos); + emitByte(0xc2 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr, false); - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_IMUL_MEM); + genAddressReg(instr, p, pos, false); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_IMUL_MEM, p, pos); } else { - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.dst); - emit(REX_MUL_M); - emitByte(0xae); - genAddressImm(instr); + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emit(REX_MUL_M, p, pos); + emitByte(0xae, p, pos); + genAddressImm(instr, p, pos); } - emit(REX_MOV_R64R); - emitByte(0xc2 + 8 * instr.dst); + emit(REX_MOV_R64R, p, pos); + emitByte(0xc2 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + uint64_t divisor = instr.getImm32(); - if (!isPowerOf2(divisor)) { + if (!isZeroOrPowerOf2(divisor)) { registerUsage[instr.dst] = i; - emit(MOV_RAX_I); - emit64(randomx_reciprocal_fast(divisor)); - emit(REX_IMUL_RM); - emitByte(0xc0 + 8 * instr.dst); + emit(MOV_RAX_I, p, pos); + emit64(randomx_reciprocal_fast(divisor), p, pos); + emit(REX_IMUL_RM, p, pos); + emitByte(0xc0 + 8 * instr.dst, p, pos); } + + codePos = pos; } void JitCompilerX86::h_INEG_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; - emit(REX_NEG); - emitByte(0xd8 + instr.dst); + emit(REX_NEG, p, pos); + emitByte(0xd8 + instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - emit(REX_XOR_RR); - emitByte(0xc0 + 8 * instr.dst + instr.src); + emit(REX_XOR_RR, p, pos); + emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos); } else { - emit(REX_XOR_RI); - emitByte(0xf0 + instr.dst); - emit32(instr.getImm32()); + emit(REX_XOR_RI, p, pos); + emitByte(0xf0 + instr.dst, p, pos); + emit32(instr.getImm32(), p, pos); } + + codePos = pos; } void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - genAddressReg(instr); - emit(REX_XOR_RM); - emitByte(0x04 + 8 * instr.dst); - emitByte(0x06); + genAddressReg(instr, p, pos); + emit(REX_XOR_RM, p, pos); + emitByte(0x04 + 8 * instr.dst, p, pos); + emitByte(0x06, p, pos); } else { - emit(REX_XOR_RM); - emitByte(0x86 + 8 * instr.dst); - genAddressImm(instr); + emit(REX_XOR_RM, p, pos); + emitByte(0x86 + 8 * instr.dst, p, pos); + genAddressImm(instr, p, pos); } + + codePos = pos; } void JitCompilerX86::h_IROR_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - emit(REX_MOV_RR); - emitByte(0xc8 + instr.src); - emit(REX_ROT_CL); - emitByte(0xc8 + instr.dst); + emit(REX_MOV_RR, p, pos); + emitByte(0xc8 + instr.src, p, pos); + emit(REX_ROT_CL, p, pos); + emitByte(0xc8 + instr.dst, p, pos); } else { - emit(REX_ROT_I8); - emitByte(0xc8 + instr.dst); - emitByte(instr.getImm32() & 63); + emit(REX_ROT_I8, p, pos); + emitByte(0xc8 + instr.dst, p, pos); + emitByte(instr.getImm32() & 63, p, pos); } + + codePos = pos; } void JitCompilerX86::h_IROL_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + registerUsage[instr.dst] = i; if (instr.src != instr.dst) { - emit(REX_MOV_RR); - emitByte(0xc8 + instr.src); - emit(REX_ROT_CL); - emitByte(0xc0 + instr.dst); + emit(REX_MOV_RR, p, pos); + emitByte(0xc8 + instr.src, p, pos); + emit(REX_ROT_CL, p, pos); + emitByte(0xc0 + instr.dst, p, pos); } else { - emit(REX_ROT_I8); - emitByte(0xc0 + instr.dst); - emitByte(instr.getImm32() & 63); + emit(REX_ROT_I8, p, pos); + emitByte(0xc0 + instr.dst, p, pos); + emitByte(instr.getImm32() & 63, p, pos); } + + codePos = pos; } void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + if (instr.src != instr.dst) { registerUsage[instr.dst] = i; registerUsage[instr.src] = i; - emit(REX_XCHG); - emitByte(0xc0 + instr.src + 8 * instr.dst); + emit(REX_XCHG, p, pos); + emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos); } + + codePos = pos; } void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) { - emit(SHUFPD); - emitByte(0xc0 + 9 * instr.dst); - emitByte(1); + uint8_t* const p = code; + int pos = codePos; + + emit(SHUFPD, p, pos); + emitByte(0xc0 + 9 * instr.dst, p, pos); + emitByte(1, p, pos); + + codePos = pos; } void JitCompilerX86::h_FADD_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; instr.src %= RegisterCountFlt; - emit(REX_ADDPD); - emitByte(0xc0 + instr.src + 8 * instr.dst); + emit(REX_ADDPD, p, pos); + emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FADD_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; - genAddressReg(instr); - emit(REX_CVTDQ2PD_XMM12); - emit(REX_ADDPD); - emitByte(0xc4 + 8 * instr.dst); + genAddressReg(instr, p, pos); + emit(REX_CVTDQ2PD_XMM12, p, pos); + emit(REX_ADDPD, p, pos); + emitByte(0xc4 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; instr.src %= RegisterCountFlt; - emit(REX_SUBPD); - emitByte(0xc0 + instr.src + 8 * instr.dst); + emit(REX_SUBPD, p, pos); + emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; - genAddressReg(instr); - emit(REX_CVTDQ2PD_XMM12); - emit(REX_SUBPD); - emitByte(0xc4 + 8 * instr.dst); + genAddressReg(instr, p, pos); + emit(REX_CVTDQ2PD_XMM12, p, pos); + emit(REX_SUBPD, p, pos); + emitByte(0xc4 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; - emit(REX_XORPS); - emitByte(0xc7 + 8 * instr.dst); + emit(REX_XORPS, p, pos); + emitByte(0xc7 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; instr.src %= RegisterCountFlt; - emit(REX_MULPD); - emitByte(0xe0 + instr.src + 8 * instr.dst); + emit(REX_MULPD, p, pos); + emitByte(0xe0 + instr.src + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; - genAddressReg(instr); - emit(REX_CVTDQ2PD_XMM12); - emit(REX_ANDPS_XMM12); - emit(REX_DIVPD); - emitByte(0xe4 + 8 * instr.dst); + genAddressReg(instr, p, pos); + emit(REX_CVTDQ2PD_XMM12, p, pos); + emit(REX_ANDPS_XMM12, p, pos); + emit(REX_DIVPD, p, pos); + emitByte(0xe4 + 8 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + instr.dst %= RegisterCountFlt; - emit(SQRTPD); - emitByte(0xe4 + 9 * instr.dst); + emit(SQRTPD, p, pos); + emitByte(0xe4 + 9 * instr.dst, p, pos); + + codePos = pos; } void JitCompilerX86::h_CFROUND(Instruction& instr, int i) { - emit(REX_MOV_RR64); - emitByte(0xc0 + instr.src); + uint8_t* const p = code; + int pos = codePos; + + emit(REX_MOV_RR64, p, pos); + emitByte(0xc0 + instr.src, p, pos); int rotate = (13 - (instr.getImm32() & 63)) & 63; if (rotate != 0) { - emit(ROL_RAX); - emitByte(rotate); + emit(ROL_RAX, p, pos); + emitByte(rotate, p, pos); } - emit(AND_OR_MOV_LDMXCSR); + emit(AND_OR_MOV_LDMXCSR, p, pos); + + codePos = pos; } void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) { + uint8_t* const p = code; + int pos = codePos; + int reg = instr.dst; int target = registerUsage[reg] + 1; - emit(REX_ADD_I); - emitByte(0xc0 + reg); + emit(REX_ADD_I, p, pos); + emitByte(0xc0 + reg, p, pos); int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset; uint32_t imm = instr.getImm32() | (1UL << shift); if (RandomX_CurrentConfig.JumpOffset > 0 || shift > 0) imm &= ~(1UL << (shift - 1)); - emit32(imm); - emit(REX_TEST); - emitByte(0xc0 + reg); - emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift); - emit(JZ); - emit32(instructionOffsets[target] - (codePos + 4)); + emit32(imm, p, pos); + emit(REX_TEST, p, pos); + emitByte(0xc0 + reg, p, pos); + emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift, p, pos); + emit(JZ, p, pos); + emit32(instructionOffsets[target] - (pos + 4), p, pos); //mark all registers as used - for (unsigned j = 0; j < RegistersCount; ++j) { - registerUsage[j] = i; + uint64_t* r = (uint64_t*) registerUsage; + uint64_t k = i; + k |= k << 32; + for (unsigned j = 0; j < RegistersCount / 2; ++j) { + r[j] = k; } + + codePos = pos; } void JitCompilerX86::h_ISTORE(Instruction& instr, int i) { - genAddressRegDst(instr); - emit(REX_MOV_MR); - emitByte(0x04 + 8 * instr.src); - emitByte(0x06); + uint8_t* const p = code; + int pos = codePos; + + genAddressRegDst(instr, p, pos); + emit(REX_MOV_MR, p, pos); + emitByte(0x04 + 8 * instr.src, p, pos); + emitByte(0x06, p, pos); + + codePos = pos; } void JitCompilerX86::h_NOP(Instruction& instr, int i) { - emit(NOP1); + emit(NOP1, code, codePos); } InstructionGeneratorX86 JitCompilerX86::engine[256] = {}; diff --git a/src/crypto/randomx/jit_compiler_x86.hpp b/src/crypto/randomx/jit_compiler_x86.hpp index a81c8f4e6..942fe8210 100644 --- a/src/crypto/randomx/jit_compiler_x86.hpp +++ b/src/crypto/randomx/jit_compiler_x86.hpp @@ -31,12 +31,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "common.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { class Program; - class ProgramConfiguration; + struct ProgramConfiguration; class SuperscalarProgram; class JitCompilerX86; class Instruction; @@ -66,42 +66,41 @@ namespace randomx { size_t getCodeSize(); static InstructionGeneratorX86 engine[256]; - std::vector instructionOffsets; + int32_t instructionOffsets[512]; int registerUsage[RegistersCount]; uint8_t* code; int32_t codePos; void generateProgramPrologue(Program&, ProgramConfiguration&); - void generateProgramEpilogue(Program&); - void genAddressReg(Instruction&, bool); - void genAddressRegDst(Instruction&); - void genAddressImm(Instruction&); - void genSIB(int scale, int index, int base); + void generateProgramEpilogue(Program&, ProgramConfiguration&); + static void genAddressReg(Instruction&, uint8_t* code, int& codePos, bool rax = true); + static void genAddressRegDst(Instruction&, uint8_t* code, int& codePos); + static void genAddressImm(Instruction&, uint8_t* code, int& codePos); + static void genSIB(int scale, int index, int base, uint8_t* code, int& codePos); - void generateCode(Instruction&, int); void generateSuperscalarCode(Instruction &, std::vector &); - void emitByte(uint8_t val) { + static void emitByte(uint8_t val, uint8_t* code, int& codePos) { code[codePos] = val; - codePos++; + ++codePos; } - void emit32(uint32_t val) { + static void emit32(uint32_t val, uint8_t* code, int& codePos) { memcpy(code + codePos, &val, sizeof val); codePos += sizeof val; } - void emit64(uint64_t val) { + static void emit64(uint64_t val, uint8_t* code, int& codePos) { memcpy(code + codePos, &val, sizeof val); codePos += sizeof val; } template - void emit(const uint8_t (&src)[N]) { - emit(src, N); + static void emit(const uint8_t (&src)[N], uint8_t* code, int& codePos) { + emit(src, N, code, codePos); } - void emit(const uint8_t* src, size_t count) { + static void emit(const uint8_t* src, size_t count, uint8_t* code, int& codePos) { memcpy(code + codePos, src, count); codePos += count; } @@ -138,4 +137,4 @@ namespace randomx { void h_NOP(Instruction&, int); }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/jit_compiler_x86_static.S b/src/crypto/randomx/jit_compiler_x86_static.S index 67d2bdbc8..c20cd7433 100644 --- a/src/crypto/randomx/jit_compiler_x86_static.S +++ b/src/crypto/randomx/jit_compiler_x86_static.S @@ -37,7 +37,10 @@ #define WINABI #endif +.global DECL(randomx_prefetch_scratchpad) +.global DECL(randomx_prefetch_scratchpad_end) .global DECL(randomx_program_prologue) +.global DECL(randomx_program_prologue_first_load) .global DECL(randomx_program_loop_begin) .global DECL(randomx_program_loop_load) .global DECL(randomx_program_start) @@ -61,6 +64,16 @@ #define db .byte +DECL(randomx_prefetch_scratchpad): + mov rdx, rax + and eax, RANDOMX_SCRATCHPAD_MASK + prefetcht0 [rsi+rax] + ror rdx, 32 + and edx, RANDOMX_SCRATCHPAD_MASK + prefetcht0 [rsi+rdx] + +DECL(randomx_prefetch_scratchpad_end): + .balign 64 DECL(randomx_program_prologue): #if defined(WINABI) @@ -71,6 +84,14 @@ DECL(randomx_program_prologue): movapd xmm13, xmmword ptr [mantissaMask+rip] movapd xmm14, xmmword ptr [exp240+rip] movapd xmm15, xmmword ptr [scaleMask+rip] + +DECL(randomx_program_prologue_first_load): + xor rax, r8 + xor rax, r8 + mov rdx, rax + and eax, RANDOMX_SCRATCHPAD_MASK + ror rdx, 32 + and edx, RANDOMX_SCRATCHPAD_MASK jmp DECL(randomx_program_loop_begin) .balign 64 @@ -206,3 +227,7 @@ DECL(randomx_reciprocal_fast): mov rcx, rdi #endif #include "asm/randomx_reciprocal.inc" + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/src/crypto/randomx/jit_compiler_x86_static.asm b/src/crypto/randomx/jit_compiler_x86_static.asm index 5ecfb435a..73fa503ad 100644 --- a/src/crypto/randomx/jit_compiler_x86_static.asm +++ b/src/crypto/randomx/jit_compiler_x86_static.asm @@ -28,7 +28,10 @@ IFDEF RAX _RANDOMX_JITX86_STATIC SEGMENT PAGE READ EXECUTE +PUBLIC randomx_prefetch_scratchpad +PUBLIC randomx_prefetch_scratchpad_end PUBLIC randomx_program_prologue +PUBLIC randomx_program_prologue_first_load PUBLIC randomx_program_loop_begin PUBLIC randomx_program_loop_load PUBLIC randomx_program_start @@ -50,15 +53,36 @@ RANDOMX_SCRATCHPAD_MASK EQU 2097088 RANDOMX_DATASET_BASE_MASK EQU 2147483584 RANDOMX_CACHE_MASK EQU 4194303 +randomx_prefetch_scratchpad PROC + mov rdx, rax + and eax, RANDOMX_SCRATCHPAD_MASK + prefetcht0 [rsi+rax] + ror rdx, 32 + and edx, RANDOMX_SCRATCHPAD_MASK + prefetcht0 [rsi+rdx] +randomx_prefetch_scratchpad ENDP + +randomx_prefetch_scratchpad_end PROC +randomx_prefetch_scratchpad_end ENDP + ALIGN 64 randomx_program_prologue PROC include asm/program_prologue_win64.inc movapd xmm13, xmmword ptr [mantissaMask] movapd xmm14, xmmword ptr [exp240] movapd xmm15, xmmword ptr [scaleMask] - jmp randomx_program_loop_begin randomx_program_prologue ENDP +randomx_program_prologue_first_load PROC + xor rax, r8 + xor rax, r8 + mov rdx, rax + and eax, RANDOMX_SCRATCHPAD_MASK + ror rdx, 32 + and edx, RANDOMX_SCRATCHPAD_MASK + jmp randomx_program_loop_begin +randomx_program_prologue_first_load ENDP + ALIGN 64 include asm/program_xmm_constants.inc diff --git a/src/crypto/randomx/jit_compiler_x86_static.hpp b/src/crypto/randomx/jit_compiler_x86_static.hpp index ba1968627..0a62c986e 100644 --- a/src/crypto/randomx/jit_compiler_x86_static.hpp +++ b/src/crypto/randomx/jit_compiler_x86_static.hpp @@ -29,7 +29,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once extern "C" { + void randomx_prefetch_scratchpad(); + void randomx_prefetch_scratchpad_end(); void randomx_program_prologue(); + void randomx_program_prologue_first_load(); void randomx_program_loop_begin(); void randomx_program_loop_load(); void randomx_program_start(); diff --git a/src/crypto/randomx/program.hpp b/src/crypto/randomx/program.hpp index ef8ac748a..404607589 100644 --- a/src/crypto/randomx/program.hpp +++ b/src/crypto/randomx/program.hpp @@ -29,9 +29,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "common.hpp" -#include "instruction.hpp" -#include "blake2/endian.h" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/instruction.hpp" +#include "crypto/randomx/blake2/endian.h" namespace randomx { diff --git a/src/crypto/randomx/randomx.cpp b/src/crypto/randomx/randomx.cpp index 9e88bc6db..516807042 100644 --- a/src/crypto/randomx/randomx.cpp +++ b/src/crypto/randomx/randomx.cpp @@ -26,14 +26,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "randomx.h" -#include "dataset.hpp" -#include "vm_interpreted.hpp" -#include "vm_interpreted_light.hpp" -#include "vm_compiled.hpp" -#include "vm_compiled_light.hpp" -#include "blake2/blake2.h" -#include "jit_compiler_x86_static.hpp" +#include "crypto/randomx/randomx.h" +#include "crypto/randomx/dataset.hpp" +#include "crypto/randomx/vm_interpreted.hpp" +#include "crypto/randomx/vm_interpreted_light.hpp" +#include "crypto/randomx/vm_compiled.hpp" +#include "crypto/randomx/vm_compiled_light.hpp" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/jit_compiler_x86_static.hpp" #include RandomX_ConfigurationWownero::RandomX_ConfigurationWownero() @@ -44,12 +44,14 @@ RandomX_ConfigurationWownero::RandomX_ConfigurationWownero() ScratchpadL2_Size = 131072; ScratchpadL3_Size = 1048576; + RANDOMX_FREQ_IADD_RS = 25; RANDOMX_FREQ_IROR_R = 10; RANDOMX_FREQ_IROL_R = 0; RANDOMX_FREQ_FSWAP_R = 8; RANDOMX_FREQ_FADD_R = 20; RANDOMX_FREQ_FSUB_R = 20; RANDOMX_FREQ_FMUL_R = 20; + RANDOMX_FREQ_CBRANCH = 16; fillAes4Rx4_Key[0] = rx_set_int_vec_i128(0xcf359e95, 0x141f82b7, 0x7ffbe4a6, 0xf890465d); fillAes4Rx4_Key[1] = rx_set_int_vec_i128(0x6741ffdc, 0xbd5c5ac3, 0xfee8278a, 0x6a55c450); @@ -68,6 +70,9 @@ RandomX_ConfigurationLoki::RandomX_ConfigurationLoki() ArgonSalt = "RandomXL\x12"; ProgramSize = 320; ProgramCount = 7; + + RANDOMX_FREQ_IADD_RS = 25; + RANDOMX_FREQ_CBRANCH = 16; } RandomX_ConfigurationBase::RandomX_ConfigurationBase() @@ -87,7 +92,7 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase() , ProgramCount(8) , JumpBits(8) , JumpOffset(8) - , RANDOMX_FREQ_IADD_RS(25) + , RANDOMX_FREQ_IADD_RS(16) , RANDOMX_FREQ_IADD_M(7) , RANDOMX_FREQ_ISUB_R(16) , RANDOMX_FREQ_ISUB_M(7) @@ -113,7 +118,7 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase() , RANDOMX_FREQ_FMUL_R(32) , RANDOMX_FREQ_FDIV_M(4) , RANDOMX_FREQ_FSQRT_R(6) - , RANDOMX_FREQ_CBRANCH(16) + , RANDOMX_FREQ_CBRANCH(25) , RANDOMX_FREQ_CFROUND(1) , RANDOMX_FREQ_ISTORE(16) , RANDOMX_FREQ_NOP(0) @@ -144,9 +149,9 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase() memcpy(codeReadDatasetLightSshInitTweaked, a, b - a); } { - const uint8_t* a = (const uint8_t*)&randomx_program_loop_load; - const uint8_t* b = (const uint8_t*)&randomx_program_start; - memcpy(codeLoopLoadTweaked, a, b - a); + const uint8_t* a = (const uint8_t*)&randomx_prefetch_scratchpad; + const uint8_t* b = (const uint8_t*)&randomx_prefetch_scratchpad_end; + memcpy(codePrefetchScratchpadTweaked, a, b - a); } #endif } @@ -172,8 +177,8 @@ void RandomX_ConfigurationBase::Apply() ScratchpadL3Mask64_Calculated = ((ScratchpadL3_Size / sizeof(uint64_t)) / 8 - 1) * 64; #if defined(_M_X64) || defined(__x86_64__) - *(uint32_t*)(codeLoopLoadTweaked + 4) = ScratchpadL3Mask64_Calculated; - *(uint32_t*)(codeLoopLoadTweaked + 50) = ScratchpadL3Mask64_Calculated; + *(uint32_t*)(codePrefetchScratchpadTweaked + 4) = ScratchpadL3Mask64_Calculated; + *(uint32_t*)(codePrefetchScratchpadTweaked + 18) = ScratchpadL3Mask64_Calculated; #endif ConditionMask_Calculated = (1 << JumpBits) - 1; @@ -430,12 +435,12 @@ extern "C" { assert(inputSize == 0 || input != nullptr); assert(output != nullptr); alignas(16) uint64_t tempHash[8]; - blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); + rx_blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); machine->initScratchpad(&tempHash); machine->resetRoundingMode(); for (uint32_t chain = 0; chain < RandomX_CurrentConfig.ProgramCount - 1; ++chain) { machine->run(&tempHash); - blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); + rx_blake2b(tempHash, sizeof(tempHash), machine->getRegisterFile(), sizeof(randomx::RegisterFile), nullptr, 0); } machine->run(&tempHash); machine->getFinalResult(output, RANDOMX_HASH_SIZE); diff --git a/src/crypto/randomx/randomx.h b/src/crypto/randomx/randomx.h index d688189fe..05b7bdc8f 100644 --- a/src/crypto/randomx/randomx.h +++ b/src/crypto/randomx/randomx.h @@ -29,10 +29,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef RANDOMX_H #define RANDOMX_H -#include -#include +#include +#include #include -#include "intrin_portable.h" +#include "crypto/randomx/intrin_portable.h" #define RANDOMX_HASH_SIZE 32 #define RANDOMX_DATASET_ITEM_SIZE 64 @@ -41,17 +41,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define RANDOMX_EXPORT #endif -typedef enum { + +enum randomx_flags { RANDOMX_FLAG_DEFAULT = 0, RANDOMX_FLAG_LARGE_PAGES = 1, RANDOMX_FLAG_HARD_AES = 2, RANDOMX_FLAG_FULL_MEM = 4, RANDOMX_FLAG_JIT = 8, -} randomx_flags; +}; + + +struct randomx_dataset; +struct randomx_cache; +class randomx_vm; -typedef struct randomx_dataset randomx_dataset; -typedef struct randomx_cache randomx_cache; -typedef struct randomx_vm randomx_vm; struct RandomX_ConfigurationBase { @@ -116,7 +119,7 @@ struct RandomX_ConfigurationBase uint8_t codeShhPrefetchTweaked[20]; uint8_t codeReadDatasetTweaked[64]; uint8_t codeReadDatasetLightSshInitTweaked[68]; - uint8_t codeLoopLoadTweaked[140]; + uint8_t codePrefetchScratchpadTweaked[32]; uint32_t CacheLineAlignMask_Calculated; uint32_t DatasetExtraItems_Calculated; diff --git a/src/crypto/randomx/reciprocal.c b/src/crypto/randomx/reciprocal.c index 22620f53a..87cda2677 100644 --- a/src/crypto/randomx/reciprocal.c +++ b/src/crypto/randomx/reciprocal.c @@ -27,7 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include -#include "reciprocal.h" +#include "crypto/randomx/reciprocal.h" /* Calculates rcp = 2**x / divisor for highest integer x such that rcp < 2**64. diff --git a/src/crypto/randomx/soft_aes.cpp b/src/crypto/randomx/soft_aes.cpp index 3e82fa2ef..04fb7ac0e 100644 --- a/src/crypto/randomx/soft_aes.cpp +++ b/src/crypto/randomx/soft_aes.cpp @@ -1,5 +1,6 @@ /* Copyright (c) 2018-2019, tevador +Copyright (c) 2019 SChernykh All rights reserved. @@ -26,339 +27,93 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "soft_aes.h" +#include "crypto/randomx/soft_aes.h" -alignas(16) const uint8_t sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, -}; +alignas(64) uint32_t lutEnc0[256]; +alignas(64) uint32_t lutEnc1[256]; +alignas(64) uint32_t lutEnc2[256]; +alignas(64) uint32_t lutEnc3[256]; -alignas(16) const uint32_t lutEnc0[256] = { - 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, - 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, - 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, - 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, - 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, - 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, - 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, - 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, - 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, - 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, - 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, - 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, - 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, - 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, - 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, - 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, - 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, - 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, - 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, - 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, - 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, - 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, - 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, - 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, - 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, - 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, - 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, - 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, - 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, - 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, - 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, - 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, -}; +alignas(64) uint32_t lutDec0[256]; +alignas(64) uint32_t lutDec1[256]; +alignas(64) uint32_t lutDec2[256]; +alignas(64) uint32_t lutDec3[256]; -alignas(16) const uint32_t lutEnc1[256] = { - 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, - 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, - 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, - 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, - 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, - 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, - 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, - 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, - 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, - 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, - 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, - 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, - 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, - 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, - 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, - 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, - 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, - 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, - 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, - 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, - 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, - 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, - 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, - 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, - 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, - 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, - 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, - 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, - 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, - 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, - 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, - 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, -}; +static uint32_t mul_gf2(uint32_t b, uint32_t c) +{ + uint32_t s = 0; + for (uint32_t i = b, j = c, k = 1; (k < 0x100) && j; k <<= 1) + { + if (j & k) + { + s ^= i; + j ^= k; + } -alignas(16) const uint32_t lutEnc2[256] = { - 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, - 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, - 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, - 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, - 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, - 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, - 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, - 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, - 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, - 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, - 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, - 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, - 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, - 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, - 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, - 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, - 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, - 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, - 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, - 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, - 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, - 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, - 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, - 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, - 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, - 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, - 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, - 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, - 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, - 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, - 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, - 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, -}; + i <<= 1; + if (i & 0x100) + i ^= (1 << 8) | (1 << 4) | (1 << 3) | (1 << 1) | (1 << 0); + } -alignas(16) const uint32_t lutEnc3[256] = { - 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, - 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, - 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, - 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, - 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, - 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, - 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, - 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, - 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, - 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, - 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, - 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, - 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, - 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, - 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, - 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, - 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, - 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, - 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, - 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, - 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, - 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, - 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, - 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, - 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, - 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, - 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, - 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, - 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, - 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, - 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, - 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, -}; - -alignas(16) const uint32_t lutDec0[256] = { - 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, - 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, - 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, - 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, - 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, - 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, - 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, - 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, - 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, - 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, - 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, - 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, - 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, - 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, - 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, - 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, - 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, - 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, - 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, - 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, - 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, - 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, - 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, - 0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, - 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, - 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, - 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, - 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, - 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, - 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, - 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, - 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, -}; - -alignas(16) const uint32_t lutDec1[256] = { - 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, - 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, - 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, - 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, - 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, - 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, - 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, - 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, - 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, - 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, - 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, - 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, - 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, - 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, - 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, - 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, - 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, - 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, - 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, - 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, - 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, - 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, - 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, - 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, - 0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, - 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, - 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, - 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, - 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, - 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, - 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, - 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042, -}; - -alignas(16) const uint32_t lutDec2[256] = { - 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, - 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, - 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, - 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, - 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, - 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, - 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, - 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, - 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe, - 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, - 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, - 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, - 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, - 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, - 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, - 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, - 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, - 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, - 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, - 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, - 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, - 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, - 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, - 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, - 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, - 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, - 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, - 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, - 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, - 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, - 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, - 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257, -}; - -alignas(16) const uint32_t lutDec3[256] = { - 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, - 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, - 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, - 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, - 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, - 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, - 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, - 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, - 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6, - 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, - 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, - 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, - 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, - 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, - 0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, - 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, - 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, - 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, - 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1, - 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, - 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, - 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, - 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, - 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, - 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, - 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, - 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, - 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, - 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, - 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, - 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, - 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8, -}; - -rx_vec_i128 soft_aesenc(rx_vec_i128 in, rx_vec_i128 key) { - uint32_t s0, s1, s2, s3; - - s0 = rx_vec_i128_w(in); - s1 = rx_vec_i128_z(in); - s2 = rx_vec_i128_y(in); - s3 = rx_vec_i128_x(in); - - rx_vec_i128 out = rx_set_int_vec_i128( - (lutEnc0[s0 & 0xff] ^ lutEnc1[(s3 >> 8) & 0xff] ^ lutEnc2[(s2 >> 16) & 0xff] ^ lutEnc3[s1 >> 24]), - (lutEnc0[s1 & 0xff] ^ lutEnc1[(s0 >> 8) & 0xff] ^ lutEnc2[(s3 >> 16) & 0xff] ^ lutEnc3[s2 >> 24]), - (lutEnc0[s2 & 0xff] ^ lutEnc1[(s1 >> 8) & 0xff] ^ lutEnc2[(s0 >> 16) & 0xff] ^ lutEnc3[s3 >> 24]), - (lutEnc0[s3 & 0xff] ^ lutEnc1[(s2 >> 8) & 0xff] ^ lutEnc2[(s1 >> 16) & 0xff] ^ lutEnc3[s0 >> 24]) - ); - - return rx_xor_vec_i128(out, key); + return s; } -rx_vec_i128 soft_aesdec(rx_vec_i128 in, rx_vec_i128 key) { - uint32_t s0, s1, s2, s3; +#define ROTL8(x,shift) ((uint8_t) ((x) << (shift)) | ((x) >> (8 - (shift)))) - s0 = rx_vec_i128_w(in); - s1 = rx_vec_i128_z(in); - s2 = rx_vec_i128_y(in); - s3 = rx_vec_i128_x(in); +static struct SAESInitializer +{ + SAESInitializer() + { + static uint8_t sbox[256]; + static uint8_t sbox_reverse[256]; - rx_vec_i128 out = rx_set_int_vec_i128( - (lutDec0[s0 & 0xff] ^ lutDec1[(s1 >> 8) & 0xff] ^ lutDec2[(s2 >> 16) & 0xff] ^ lutDec3[s3 >> 24]), - (lutDec0[s1 & 0xff] ^ lutDec1[(s2 >> 8) & 0xff] ^ lutDec2[(s3 >> 16) & 0xff] ^ lutDec3[s0 >> 24]), - (lutDec0[s2 & 0xff] ^ lutDec1[(s3 >> 8) & 0xff] ^ lutDec2[(s0 >> 16) & 0xff] ^ lutDec3[s1 >> 24]), - (lutDec0[s3 & 0xff] ^ lutDec1[(s0 >> 8) & 0xff] ^ lutDec2[(s1 >> 16) & 0xff] ^ lutDec3[s2 >> 24]) - ); + uint8_t p = 1, q = 1; - return rx_xor_vec_i128(out, key); -} + do { + p = p ^ (p << 1) ^ (p & 0x80 ? 0x1B : 0); + + q ^= q << 1; + q ^= q << 2; + q ^= q << 4; + q ^= (q & 0x80) ? 0x09 : 0; + + const uint8_t value = q ^ ROTL8(q, 1) ^ ROTL8(q, 2) ^ ROTL8(q, 3) ^ ROTL8(q, 4) ^ 0x63; + sbox[p] = value; + sbox_reverse[value] = p; + } while (p != 1); + + sbox[0] = 0x63; + sbox_reverse[0x63] = 0; + + for (uint32_t i = 0; i < 0x100; ++i) + { + union + { + uint32_t w; + uint8_t p[4]; + }; + + uint32_t s = sbox[i]; + p[0] = mul_gf2(s, 2); + p[1] = s; + p[2] = s; + p[3] = mul_gf2(s, 3); + + lutEnc0[i] = w; w = (w << 8) | (w >> 24); + lutEnc1[i] = w; w = (w << 8) | (w >> 24); + lutEnc2[i] = w; w = (w << 8) | (w >> 24); + lutEnc3[i] = w; + + s = sbox_reverse[i]; + p[0] = mul_gf2(s, 0xe); + p[1] = mul_gf2(s, 0x9); + p[2] = mul_gf2(s, 0xd); + p[3] = mul_gf2(s, 0xb); + + lutDec0[i] = w; w = (w << 8) | (w >> 24); + lutDec1[i] = w; w = (w << 8) | (w >> 24); + lutDec2[i] = w; w = (w << 8) | (w >> 24); + lutDec3[i] = w; + } + } +} aes_initializer; diff --git a/src/crypto/randomx/soft_aes.h b/src/crypto/randomx/soft_aes.h index 254f8d630..f4142aae2 100644 --- a/src/crypto/randomx/soft_aes.h +++ b/src/crypto/randomx/soft_aes.h @@ -1,5 +1,6 @@ /* Copyright (c) 2018-2019, tevador +Copyright (c) 2019 SChernykh All rights reserved. @@ -29,18 +30,82 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "intrin_portable.h" +#include "crypto/randomx/intrin_portable.h" -rx_vec_i128 soft_aesenc(rx_vec_i128 in, rx_vec_i128 key); +extern uint32_t lutEnc0[256]; +extern uint32_t lutEnc1[256]; +extern uint32_t lutEnc2[256]; +extern uint32_t lutEnc3[256]; +extern uint32_t lutDec0[256]; +extern uint32_t lutDec1[256]; +extern uint32_t lutDec2[256]; +extern uint32_t lutDec3[256]; -rx_vec_i128 soft_aesdec(rx_vec_i128 in, rx_vec_i128 key); +template rx_vec_i128 aesenc(rx_vec_i128 in, rx_vec_i128 key); +template rx_vec_i128 aesdec(rx_vec_i128 in, rx_vec_i128 key); -template -inline rx_vec_i128 aesenc(rx_vec_i128 in, rx_vec_i128 key) { - return soft ? soft_aesenc(in, key) : rx_aesenc_vec_i128(in, key); +template<> +FORCE_INLINE rx_vec_i128 aesenc(rx_vec_i128 in, rx_vec_i128 key) { + volatile uint8_t s[16]; + memcpy((void*) s, &in, 16); + + uint32_t s0 = lutEnc0[s[ 0]]; + uint32_t s1 = lutEnc0[s[ 4]]; + uint32_t s2 = lutEnc0[s[ 8]]; + uint32_t s3 = lutEnc0[s[12]]; + + s0 ^= lutEnc1[s[ 5]]; + s1 ^= lutEnc1[s[ 9]]; + s2 ^= lutEnc1[s[13]]; + s3 ^= lutEnc1[s[ 1]]; + + s0 ^= lutEnc2[s[10]]; + s1 ^= lutEnc2[s[14]]; + s2 ^= lutEnc2[s[ 2]]; + s3 ^= lutEnc2[s[ 6]]; + + s0 ^= lutEnc3[s[15]]; + s1 ^= lutEnc3[s[ 3]]; + s2 ^= lutEnc3[s[ 7]]; + s3 ^= lutEnc3[s[11]]; + + return rx_xor_vec_i128(rx_set_int_vec_i128(s3, s2, s1, s0), key); } -template -inline rx_vec_i128 aesdec(rx_vec_i128 in, rx_vec_i128 key) { - return soft ? soft_aesdec(in, key) : rx_aesdec_vec_i128(in, key); -} \ No newline at end of file +template<> +FORCE_INLINE rx_vec_i128 aesdec(rx_vec_i128 in, rx_vec_i128 key) { + volatile uint8_t s[16]; + memcpy((void*) s, &in, 16); + + uint32_t s0 = lutDec0[s[ 0]]; + uint32_t s1 = lutDec0[s[ 4]]; + uint32_t s2 = lutDec0[s[ 8]]; + uint32_t s3 = lutDec0[s[12]]; + + s0 ^= lutDec1[s[13]]; + s1 ^= lutDec1[s[ 1]]; + s2 ^= lutDec1[s[ 5]]; + s3 ^= lutDec1[s[ 9]]; + + s0 ^= lutDec2[s[10]]; + s1 ^= lutDec2[s[14]]; + s2 ^= lutDec2[s[ 2]]; + s3 ^= lutDec2[s[ 6]]; + + s0 ^= lutDec3[s[ 7]]; + s1 ^= lutDec3[s[11]]; + s2 ^= lutDec3[s[15]]; + s3 ^= lutDec3[s[ 3]]; + + return rx_xor_vec_i128(rx_set_int_vec_i128(s3, s2, s1, s0), key); +} + +template<> +FORCE_INLINE rx_vec_i128 aesenc(rx_vec_i128 in, rx_vec_i128 key) { + return rx_aesenc_vec_i128(in, key); +} + +template<> +FORCE_INLINE rx_vec_i128 aesdec(rx_vec_i128 in, rx_vec_i128 key) { + return rx_aesdec_vec_i128(in, key); +} diff --git a/src/crypto/randomx/superscalar.cpp b/src/crypto/randomx/superscalar.cpp index 0ca1fe693..aaa91f620 100644 --- a/src/crypto/randomx/superscalar.cpp +++ b/src/crypto/randomx/superscalar.cpp @@ -26,12 +26,12 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "configuration.h" -#include "program.hpp" -#include "blake2/endian.h" -#include "superscalar.hpp" -#include "intrin_portable.h" -#include "reciprocal.h" +#include "crypto/randomx/configuration.h" +#include "crypto/randomx/program.hpp" +#include "crypto/randomx/blake2/endian.h" +#include "crypto/randomx/superscalar.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/reciprocal.h" namespace randomx { @@ -329,7 +329,7 @@ namespace randomx { return false; if (availableRegisters.size() > 1) { - index = gen.getInt32() % availableRegisters.size(); + index = gen.getUInt32() % availableRegisters.size(); } else { index = 0; @@ -442,7 +442,7 @@ namespace randomx { case SuperscalarInstructionType::IADD_C8: case SuperscalarInstructionType::IADD_C9: { mod_ = 0; - imm32_ = gen.getInt32(); + imm32_ = gen.getUInt32(); opGroup_ = SuperscalarInstructionType::IADD_C7; opGroupPar_ = -1; } break; @@ -451,7 +451,7 @@ namespace randomx { case SuperscalarInstructionType::IXOR_C8: case SuperscalarInstructionType::IXOR_C9: { mod_ = 0; - imm32_ = gen.getInt32(); + imm32_ = gen.getUInt32(); opGroup_ = SuperscalarInstructionType::IXOR_C7; opGroupPar_ = -1; } break; @@ -461,7 +461,7 @@ namespace randomx { mod_ = 0; imm32_ = 0; opGroup_ = SuperscalarInstructionType::IMULH_R; - opGroupPar_ = gen.getInt32(); + opGroupPar_ = gen.getUInt32(); } break; case SuperscalarInstructionType::ISMULH_R: { @@ -469,14 +469,14 @@ namespace randomx { mod_ = 0; imm32_ = 0; opGroup_ = SuperscalarInstructionType::ISMULH_R; - opGroupPar_ = gen.getInt32(); + opGroupPar_ = gen.getUInt32(); } break; case SuperscalarInstructionType::IMUL_RCP: { mod_ = 0; do { - imm32_ = gen.getInt32(); - } while ((imm32_ & (imm32_ - 1)) == 0); + imm32_ = gen.getUInt32(); + } while (isZeroOrPowerOf2(imm32_)); opGroup_ = SuperscalarInstructionType::IMUL_RCP; opGroupPar_ = -1; } break; diff --git a/src/crypto/randomx/superscalar.hpp b/src/crypto/randomx/superscalar.hpp index bc101c453..fd2a593b4 100644 --- a/src/crypto/randomx/superscalar.hpp +++ b/src/crypto/randomx/superscalar.hpp @@ -30,8 +30,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "superscalar_program.hpp" -#include "blake2_generator.hpp" +#include "crypto/randomx/superscalar_program.hpp" +#include "crypto/randomx/blake2_generator.hpp" namespace randomx { // Intel Ivy Bridge reference @@ -57,4 +57,4 @@ namespace randomx { void generateSuperscalar(SuperscalarProgram& prog, Blake2Generator& gen); void executeSuperscalar(uint64_t(&r)[8], SuperscalarProgram& prog, std::vector *reciprocals = nullptr); -} \ No newline at end of file +} diff --git a/src/crypto/randomx/superscalar_program.hpp b/src/crypto/randomx/superscalar_program.hpp index dbb0b1635..dc173591b 100644 --- a/src/crypto/randomx/superscalar_program.hpp +++ b/src/crypto/randomx/superscalar_program.hpp @@ -29,8 +29,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "instruction.hpp" -#include "common.hpp" +#include "crypto/randomx/instruction.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { @@ -70,4 +70,4 @@ namespace randomx { int asicLatencies[8]; }; -} \ No newline at end of file +} diff --git a/src/crypto/randomx/virtual_machine.cpp b/src/crypto/randomx/virtual_machine.cpp index c216de697..2913c7e5e 100644 --- a/src/crypto/randomx/virtual_machine.cpp +++ b/src/crypto/randomx/virtual_machine.cpp @@ -29,12 +29,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "virtual_machine.hpp" -#include "common.hpp" -#include "aes_hash.hpp" -#include "blake2/blake2.h" -#include "intrin_portable.h" -#include "allocator.hpp" +#include "crypto/randomx/virtual_machine.hpp" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/aes_hash.hpp" +#include "crypto/randomx/blake2/blake2.h" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/allocator.hpp" randomx_vm::~randomx_vm() { @@ -111,7 +111,7 @@ namespace randomx { template void VmBase::getFinalResult(void* out, size_t outSize) { hashAes1Rx4(scratchpad, ScratchpadSize, ®.a); - blake2b(out, outSize, ®, sizeof(RegisterFile), nullptr, 0); + rx_blake2b(out, outSize, ®, sizeof(RegisterFile), nullptr, 0); } template diff --git a/src/crypto/randomx/virtual_machine.hpp b/src/crypto/randomx/virtual_machine.hpp index cba79d724..2dc89bb57 100644 --- a/src/crypto/randomx/virtual_machine.hpp +++ b/src/crypto/randomx/virtual_machine.hpp @@ -29,8 +29,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "common.hpp" -#include "program.hpp" +#include "crypto/randomx/common.hpp" +#include "crypto/randomx/program.hpp" /* Global namespace for C binding */ class randomx_vm diff --git a/src/crypto/randomx/virtual_memory.cpp b/src/crypto/randomx/virtual_memory.cpp index 661740fc9..06165ffb6 100644 --- a/src/crypto/randomx/virtual_memory.cpp +++ b/src/crypto/randomx/virtual_memory.cpp @@ -30,7 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "crypto/common/VirtualMemory.h" -#include "virtual_memory.hpp" +#include "crypto/randomx/virtual_memory.hpp" void* allocExecutableMemory(std::size_t bytes) { diff --git a/src/crypto/randomx/vm_compiled.cpp b/src/crypto/randomx/vm_compiled.cpp index 4d14c7931..f3b9758c4 100644 --- a/src/crypto/randomx/vm_compiled.cpp +++ b/src/crypto/randomx/vm_compiled.cpp @@ -26,8 +26,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "vm_compiled.hpp" -#include "common.hpp" +#include "crypto/randomx/vm_compiled.hpp" +#include "crypto/randomx/common.hpp" namespace randomx { diff --git a/src/crypto/randomx/vm_compiled.hpp b/src/crypto/randomx/vm_compiled.hpp index 05b34b9c7..6fa824155 100644 --- a/src/crypto/randomx/vm_compiled.hpp +++ b/src/crypto/randomx/vm_compiled.hpp @@ -30,10 +30,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "virtual_machine.hpp" -#include "jit_compiler.hpp" -#include "allocator.hpp" -#include "dataset.hpp" +#include "crypto/randomx/virtual_machine.hpp" +#include "crypto/randomx/jit_compiler.hpp" +#include "crypto/randomx/allocator.hpp" +#include "crypto/randomx/dataset.hpp" namespace randomx { diff --git a/src/crypto/randomx/vm_compiled_light.cpp b/src/crypto/randomx/vm_compiled_light.cpp index 6009216b3..02115cefd 100644 --- a/src/crypto/randomx/vm_compiled_light.cpp +++ b/src/crypto/randomx/vm_compiled_light.cpp @@ -26,8 +26,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "vm_compiled_light.hpp" -#include "common.hpp" +#include "crypto/randomx/vm_compiled_light.hpp" +#include "crypto/randomx/common.hpp" #include namespace randomx { diff --git a/src/crypto/randomx/vm_compiled_light.hpp b/src/crypto/randomx/vm_compiled_light.hpp index 6cd3cb203..4d8638a82 100644 --- a/src/crypto/randomx/vm_compiled_light.hpp +++ b/src/crypto/randomx/vm_compiled_light.hpp @@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "vm_compiled.hpp" +#include "crypto/randomx/vm_compiled.hpp" namespace randomx { diff --git a/src/crypto/randomx/vm_interpreted.cpp b/src/crypto/randomx/vm_interpreted.cpp index f4c1e05c9..e21ecfe69 100644 --- a/src/crypto/randomx/vm_interpreted.cpp +++ b/src/crypto/randomx/vm_interpreted.cpp @@ -26,10 +26,10 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "vm_interpreted.hpp" -#include "dataset.hpp" -#include "intrin_portable.h" -#include "reciprocal.h" +#include "crypto/randomx/vm_interpreted.hpp" +#include "crypto/randomx/dataset.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/reciprocal.h" namespace randomx { diff --git a/src/crypto/randomx/vm_interpreted.hpp b/src/crypto/randomx/vm_interpreted.hpp index 1dc9ab6dc..b369ab110 100644 --- a/src/crypto/randomx/vm_interpreted.hpp +++ b/src/crypto/randomx/vm_interpreted.hpp @@ -31,10 +31,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "common.hpp" -#include "virtual_machine.hpp" -#include "bytecode_machine.hpp" -#include "intrin_portable.h" -#include "allocator.hpp" +#include "crypto/randomx/virtual_machine.hpp" +#include "crypto/randomx/bytecode_machine.hpp" +#include "crypto/randomx/intrin_portable.h" +#include "crypto/randomx/allocator.hpp" namespace randomx { diff --git a/src/crypto/randomx/vm_interpreted_light.cpp b/src/crypto/randomx/vm_interpreted_light.cpp index 9c97187b2..bed6f35bc 100644 --- a/src/crypto/randomx/vm_interpreted_light.cpp +++ b/src/crypto/randomx/vm_interpreted_light.cpp @@ -26,8 +26,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "vm_interpreted_light.hpp" -#include "dataset.hpp" +#include "crypto/randomx/vm_interpreted_light.hpp" +#include "crypto/randomx/dataset.hpp" namespace randomx { diff --git a/src/crypto/randomx/vm_interpreted_light.hpp b/src/crypto/randomx/vm_interpreted_light.hpp index 1a35c5801..c8abba2cf 100644 --- a/src/crypto/randomx/vm_interpreted_light.hpp +++ b/src/crypto/randomx/vm_interpreted_light.hpp @@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include -#include "vm_interpreted.hpp" +#include "crypto/randomx/vm_interpreted.hpp" namespace randomx { diff --git a/src/crypto/rx/Rx.cpp b/src/crypto/rx/Rx.cpp index 8e757ddf2..76ab07c44 100644 --- a/src/crypto/rx/Rx.cpp +++ b/src/crypto/rx/Rx.cpp @@ -25,9 +25,20 @@ */ -#include -#include -#include +#include "crypto/rx/Rx.h" + +#include "backend/common/interfaces/IRxListener.h" +#include "backend/cpu/Cpu.h" +#include "base/io/log/Log.h" +#include "base/kernel/Platform.h" +#include "base/net/stratum/Job.h" +#include "base/tools/Buffer.h" +#include "base/tools/Chrono.h" +#include "base/tools/Handle.h" +#include "base/tools/Object.h" +#include "crypto/rx/RxAlgo.h" +#include "crypto/rx/RxCache.h" +#include "crypto/rx/RxDataset.h" #ifdef XMRIG_FEATURE_HWLOC @@ -36,16 +47,10 @@ #endif -#include "backend/cpu/Cpu.h" -#include "base/io/log/Log.h" -#include "base/kernel/Platform.h" -#include "base/net/stratum/Job.h" -#include "base/tools/Buffer.h" -#include "base/tools/Chrono.h" -#include "crypto/rx/Rx.h" -#include "crypto/rx/RxAlgo.h" -#include "crypto/rx/RxCache.h" -#include "crypto/rx/RxDataset.h" +#include +#include +#include +#include namespace xmrig { @@ -56,6 +61,7 @@ class RxPrivate; static const char *tag = BLUE_BG(WHITE_BOLD_S " rx ") " "; static RxPrivate *d_ptr = nullptr; +static std::mutex mutex; #ifdef XMRIG_FEATURE_HWLOC @@ -88,9 +94,15 @@ inline static void bindToNUMANode(uint32_t) {} class RxPrivate { public: - inline RxPrivate() : - m_seed() + XMRIG_DISABLE_COPY_MOVE(RxPrivate) + + inline RxPrivate() { + m_async = new uv_async_t; + m_async->data = this; + + uv_async_init(uv_default_loop(), m_async, RxPrivate::onReady); + # ifdef XMRIG_FEATURE_HWLOC if (Cpu::info()->nodes() > 1) { for (uint32_t nodeId : HwlocCpuInfo::nodeIndexes()) { @@ -107,6 +119,8 @@ public: inline ~RxPrivate() { + Handle::close(m_async); + for (auto const &item : datasets) { delete item.second; } @@ -117,8 +131,9 @@ public: inline bool isNUMA() const { return m_numa; } inline const Algorithm &algorithm() const { return m_algorithm; } - inline const uint8_t *seed() const { return m_seed; } + inline const Buffer &seed() const { return m_seed; } inline size_t count() const { return isNUMA() ? datasets.size() : 1; } + inline void asyncSend() { m_ready++; if (m_ready == count()) { uv_async_send(m_async); } } static void allocate(uint32_t nodeId) @@ -132,12 +147,12 @@ public: LOG_INFO("%s" CYAN_BOLD("#%u") MAGENTA_BOLD(" allocate") CYAN_BOLD(" %zu MB") BLACK_BOLD(" (%zu+%zu) for RandomX dataset & cache"), tag, nodeId, - (RxDataset::size() + RxCache::size()) / 1024 / 1024, - RxDataset::size() / 1024 / 1024, - RxCache::size() / 1024 / 1024 + (RxDataset::maxSize() + RxCache::maxSize()) / 1024 / 1024, + RxDataset::maxSize() / 1024 / 1024, + RxCache::maxSize() / 1024 / 1024 ); - RxDataset *dataset = new RxDataset(d_ptr->m_hugePages); + auto dataset = new RxDataset(d_ptr->m_hugePages); d_ptr->datasets[nodeId] = dataset; if (dataset->get() != nullptr) { @@ -163,14 +178,14 @@ public: static void initDataset(uint32_t nodeId, uint32_t threads) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); const uint64_t ts = Chrono::steadyMSecs(); d_ptr->getOrAllocate(nodeId)->init(d_ptr->seed(), threads); - d_ptr->m_ready++; + d_ptr->asyncSend(); - LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, Chrono::steadyMSecs() - ts); + LOG_INFO("%s" CYAN_BOLD("#%u") GREEN(" init done ") CYAN_BOLD("%zu/%zu") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, nodeId, d_ptr->m_ready, d_ptr->count(), Chrono::steadyMSecs() - ts); } @@ -196,7 +211,7 @@ public: } - inline void setState(const Job &job, bool hugePages, bool numa) + inline void setState(const Job &job, bool hugePages, bool numa, IRxListener *listener) { if (m_algorithm != job.algorithm()) { m_algorithm = RxAlgo::apply(job.algorithm()); @@ -205,35 +220,85 @@ public: m_ready = 0; m_numa = numa && Cpu::info()->nodes() > 1; m_hugePages = hugePages; - - memcpy(m_seed, job.seedHash(), sizeof(m_seed)); + m_listener = listener; + m_seed = job.seed(); } inline bool isReady(const Job &job) { - return m_ready == count() && m_algorithm == job.algorithm() && memcmp(m_seed, job.seedHash(), sizeof(m_seed)) == 0; + return m_ready == count() && m_algorithm == job.algorithm() && m_seed == job.seed(); } std::map datasets; - std::mutex mutex; private: - bool m_hugePages = true; - bool m_numa = true; + static void onReady(uv_async_t *) + { + if (d_ptr->m_listener) { + d_ptr->m_listener->onDatasetReady(); + } + } + Algorithm m_algorithm; - size_t m_ready = 0; - uint8_t m_seed[32]; + bool m_hugePages = true; + bool m_numa = true; + Buffer m_seed; + IRxListener *m_listener = nullptr; + size_t m_ready = 0; + uv_async_t *m_async; }; } // namespace xmrig +bool xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa, IRxListener *listener) +{ + if (job.algorithm().family() != Algorithm::RANDOM_X) { + return true; + } + + std::lock_guard lock(mutex); + + if (d_ptr->isReady(job)) { + return true; + } + + d_ptr->setState(job, hugePages, numa, listener); + const uint32_t threads = initThreads < 1 ? static_cast(Cpu::info()->threads()) : static_cast(initThreads); + const String buf = Buffer::toHex(job.seed().data(), 8); + + LOG_INFO("%s" MAGENTA_BOLD("init dataset%s") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."), + tag, + d_ptr->count() > 1 ? "s" : "", + job.algorithm().shortName(), + threads, + buf.data() + ); + +# ifdef XMRIG_FEATURE_HWLOC + if (d_ptr->isNUMA()) { + for (auto const &item : d_ptr->datasets) { + std::thread thread(RxPrivate::initDataset, item.first, threads); + thread.detach(); + } + } + else +# endif + { + std::thread thread(RxPrivate::initDataset, 0, threads); + thread.detach(); + } + + return false; +} + + bool xmrig::Rx::isReady(const Job &job) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); return d_ptr->isReady(job); } @@ -241,7 +306,7 @@ bool xmrig::Rx::isReady(const Job &job) xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId) { - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); if (!d_ptr->isReady(job)) { return nullptr; } @@ -253,7 +318,7 @@ xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId) std::pair xmrig::Rx::hugePages() { std::pair pages(0, 0); - std::lock_guard lock(d_ptr->mutex); + std::lock_guard lock(mutex); for (auto const &item : d_ptr->datasets) { if (!item.second) { @@ -281,43 +346,3 @@ void xmrig::Rx::init() { d_ptr = new RxPrivate(); } - - -void xmrig::Rx::init(const Job &job, int initThreads, bool hugePages, bool numa) -{ - if (job.algorithm().family() != Algorithm::RANDOM_X) { - return; - } - - std::lock_guard lock(d_ptr->mutex); - - if (d_ptr->isReady(job)) { - return; - } - - d_ptr->setState(job, hugePages, numa); - const uint32_t threads = initThreads < 1 ? static_cast(Cpu::info()->threads()) : static_cast(initThreads); - const String buf = Buffer::toHex(job.seedHash(), 8); - - LOG_INFO("%s" MAGENTA_BOLD("init dataset%s") " algo " WHITE_BOLD("%s (") CYAN_BOLD("%u") WHITE_BOLD(" threads)") BLACK_BOLD(" seed %s..."), - tag, - d_ptr->count() > 1 ? "s" : "", - job.algorithm().shortName(), - threads, - buf.data() - ); - -# ifdef XMRIG_FEATURE_HWLOC - if (d_ptr->isNUMA()) { - for (auto const &item : d_ptr->datasets) { - std::thread thread(RxPrivate::initDataset, item.first, threads); - thread.detach(); - } - } - else -# endif - { - std::thread thread(RxPrivate::initDataset, 0, threads); - thread.detach(); - } -} diff --git a/src/crypto/rx/Rx.h b/src/crypto/rx/Rx.h index 1a383055a..9392e80db 100644 --- a/src/crypto/rx/Rx.h +++ b/src/crypto/rx/Rx.h @@ -28,7 +28,7 @@ #define XMRIG_RX_H -#include +#include #include @@ -37,19 +37,20 @@ namespace xmrig class Algorithm; -class RxDataset; +class IRxListener; class Job; +class RxDataset; class Rx { public: + static bool init(const Job &job, int initThreads, bool hugePages, bool numa, IRxListener *listener); static bool isReady(const Job &job); static RxDataset *dataset(const Job &job, uint32_t nodeId); static std::pair hugePages(); static void destroy(); static void init(); - static void init(const Job &job, int initThreads, bool hugePages, bool numa); }; diff --git a/src/crypto/rx/RxAlgo.cpp b/src/crypto/rx/RxAlgo.cpp index b0e92e6e0..4aed2b3cd 100644 --- a/src/crypto/rx/RxAlgo.cpp +++ b/src/crypto/rx/RxAlgo.cpp @@ -31,39 +31,49 @@ xmrig::Algorithm::Id xmrig::RxAlgo::apply(Algorithm::Id algorithm) { - switch (algorithm) { - case Algorithm::RX_WOW: - randomx_apply_config(RandomX_WowneroConfig); - break; - - case Algorithm::RX_LOKI: - randomx_apply_config(RandomX_LokiConfig); - break; - - default: - randomx_apply_config(RandomX_MoneroConfig); - break; - } + randomx_apply_config(*base(algorithm)); return algorithm; } -size_t xmrig::RxAlgo::l3(Algorithm::Id algorithm) +RandomX_ConfigurationBase *xmrig::RxAlgo::base(Algorithm::Id algorithm) { switch (algorithm) { - case Algorithm::RX_0: - return RandomX_MoneroConfig.ScratchpadL3_Size; - case Algorithm::RX_WOW: - return RandomX_WowneroConfig.ScratchpadL3_Size; + return &RandomX_WowneroConfig; case Algorithm::RX_LOKI: - return RandomX_LokiConfig.ScratchpadL3_Size; + return &RandomX_LokiConfig; + break; default: break; } - return 0; + return &RandomX_MoneroConfig; +} + + +uint32_t xmrig::RxAlgo::version(Algorithm::Id algorithm) +{ + return algorithm == Algorithm::RX_WOW ? 103 : 104; +} + + +uint32_t xmrig::RxAlgo::programCount(Algorithm::Id algorithm) +{ + return base(algorithm)->ProgramCount; +} + + +uint32_t xmrig::RxAlgo::programIterations(Algorithm::Id algorithm) +{ + return base(algorithm)->ProgramIterations; +} + + +uint32_t xmrig::RxAlgo::programSize(Algorithm::Id algorithm) +{ + return base(algorithm)->ProgramSize; } diff --git a/src/crypto/rx/RxAlgo.h b/src/crypto/rx/RxAlgo.h index dd3f0aa73..3d8389504 100644 --- a/src/crypto/rx/RxAlgo.h +++ b/src/crypto/rx/RxAlgo.h @@ -28,8 +28,8 @@ #define XMRIG_RX_ALGO_H -#include -#include +#include +#include #include "crypto/common/Algorithm.h" @@ -46,7 +46,11 @@ class RxAlgo { public: static Algorithm::Id apply(Algorithm::Id algorithm); - static size_t l3(Algorithm::Id algorithm); + static RandomX_ConfigurationBase *base(Algorithm::Id algorithm); + static uint32_t programCount(Algorithm::Id algorithm); + static uint32_t programIterations(Algorithm::Id algorithm); + static uint32_t programSize(Algorithm::Id algorithm); + static uint32_t version(Algorithm::Id algorithm); }; diff --git a/src/crypto/rx/RxCache.cpp b/src/crypto/rx/RxCache.cpp index 92c366a2e..e8fcb6857 100644 --- a/src/crypto/rx/RxCache.cpp +++ b/src/crypto/rx/RxCache.cpp @@ -34,8 +34,7 @@ static_assert(RANDOMX_FLAG_LARGE_PAGES == 1, "RANDOMX_FLAG_LARGE_PAGES flag mism -xmrig::RxCache::RxCache(bool hugePages) : - m_seed() +xmrig::RxCache::RxCache(bool hugePages) { if (hugePages) { m_flags = RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES; @@ -62,22 +61,14 @@ xmrig::RxCache::~RxCache() } -bool xmrig::RxCache::init(const uint8_t *seed) +bool xmrig::RxCache::init(const Buffer &seed) { - if (isReady(seed)) { + if (m_seed == seed) { return false; } - memcpy(m_seed, seed, sizeof(m_seed)); - randomx_init_cache(m_cache, m_seed, sizeof(m_seed)); - - m_initCount++; + m_seed = seed; + randomx_init_cache(m_cache, m_seed.data(), m_seed.size()); return true; } - - -bool xmrig::RxCache::isReady(const uint8_t *seed) const -{ - return m_initCount && memcmp(m_seed, seed, sizeof(m_seed)) == 0; -} diff --git a/src/crypto/rx/RxCache.h b/src/crypto/rx/RxCache.h index e6b2397ca..f01e50872 100644 --- a/src/crypto/rx/RxCache.h +++ b/src/crypto/rx/RxCache.h @@ -28,9 +28,11 @@ #define XMRIG_RX_CACHE_H -#include +#include +#include "base/tools/Buffer.h" +#include "base/tools/Object.h" #include "crypto/randomx/configuration.h" @@ -44,26 +46,24 @@ namespace xmrig class RxCache { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxCache) + RxCache(bool hugePages = true); ~RxCache(); inline bool isHugePages() const { return m_flags & 1; } inline bool isJIT() const { return m_flags & 8; } - inline const uint8_t *seed() const { return m_seed; } + inline const Buffer &seed() const { return m_seed; } inline randomx_cache *get() const { return m_cache; } - inline uint64_t initCount() const { return m_initCount; } - bool init(const uint8_t *seed); + bool init(const Buffer &seed); - static inline constexpr size_t size() { return RANDOMX_CACHE_MAX_SIZE; } + static inline constexpr size_t maxSize() { return RANDOMX_CACHE_MAX_SIZE; } private: - bool isReady(const uint8_t *seed) const; - + Buffer m_seed; int m_flags = 0; randomx_cache *m_cache = nullptr; - uint64_t m_initCount = 0; - uint8_t m_seed[32]; }; diff --git a/src/crypto/rx/RxDataset.cpp b/src/crypto/rx/RxDataset.cpp index 50459a555..7384a9825 100644 --- a/src/crypto/rx/RxDataset.cpp +++ b/src/crypto/rx/RxDataset.cpp @@ -64,7 +64,7 @@ xmrig::RxDataset::~RxDataset() } -bool xmrig::RxDataset::init(const uint8_t *seed, uint32_t numThreads) +bool xmrig::RxDataset::init(const Buffer &seed, uint32_t numThreads) { cache()->init(seed); @@ -72,13 +72,13 @@ bool xmrig::RxDataset::init(const uint8_t *seed, uint32_t numThreads) return true; } - const uint32_t datasetItemCount = randomx_dataset_item_count(); + const uint64_t datasetItemCount = randomx_dataset_item_count(); if (numThreads > 1) { std::vector threads; threads.reserve(numThreads); - for (uint32_t i = 0; i < numThreads; ++i) { + for (uint64_t i = 0; i < numThreads; ++i) { const uint32_t a = (datasetItemCount * i) / numThreads; const uint32_t b = (datasetItemCount * (i + 1)) / numThreads; threads.emplace_back(randomx_init_dataset, m_dataset, m_cache->get(), a, b - a); @@ -99,16 +99,22 @@ bool xmrig::RxDataset::init(const uint8_t *seed, uint32_t numThreads) std::pair xmrig::RxDataset::hugePages() const { constexpr size_t twoMiB = 2u * 1024u * 1024u; - constexpr const size_t total = (VirtualMemory::align(size(), twoMiB) + VirtualMemory::align(RxCache::size(), twoMiB)) / twoMiB; + constexpr const size_t total = (VirtualMemory::align(maxSize(), twoMiB) + VirtualMemory::align(RxCache::maxSize(), twoMiB)) / twoMiB; size_t count = 0; if (isHugePages()) { - count += VirtualMemory::align(size(), twoMiB) / twoMiB; + count += VirtualMemory::align(maxSize(), twoMiB) / twoMiB; } if (m_cache->isHugePages()) { - count += VirtualMemory::align(RxCache::size(), twoMiB) / twoMiB; + count += VirtualMemory::align(RxCache::maxSize(), twoMiB) / twoMiB; } - return std::pair(count, total); + return { count, total }; +} + + +void *xmrig::RxDataset::raw() const +{ + return m_dataset ? randomx_get_dataset_memory(m_dataset) : nullptr; } diff --git a/src/crypto/rx/RxDataset.h b/src/crypto/rx/RxDataset.h index 932f4ed94..e1b359a40 100644 --- a/src/crypto/rx/RxDataset.h +++ b/src/crypto/rx/RxDataset.h @@ -30,6 +30,7 @@ #include "crypto/common/Algorithm.h" #include "crypto/randomx/configuration.h" +#include "base/tools/Object.h" struct randomx_dataset; @@ -39,23 +40,28 @@ namespace xmrig { +class Buffer; class RxCache; class RxDataset { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxDataset) + RxDataset(bool hugePages = true); ~RxDataset(); inline bool isHugePages() const { return m_flags & 1; } inline randomx_dataset *get() const { return m_dataset; } inline RxCache *cache() const { return m_cache; } + inline size_t size() const { return maxSize(); } - bool init(const uint8_t *seed, uint32_t numThreads); + bool init(const Buffer &seed, uint32_t numThreads); std::pair hugePages() const; + void *raw() const; - static inline constexpr size_t size() { return RANDOMX_DATASET_MAX_SIZE; } + static inline constexpr size_t maxSize() { return RANDOMX_DATASET_MAX_SIZE; } private: Algorithm m_algorithm; diff --git a/src/crypto/rx/RxVm.h b/src/crypto/rx/RxVm.h index d7e617e4d..5154b66d7 100644 --- a/src/crypto/rx/RxVm.h +++ b/src/crypto/rx/RxVm.h @@ -28,10 +28,13 @@ #define XMRIG_RX_VM_H -#include +#include "base/tools/Object.h" -struct randomx_vm; +#include + + +class randomx_vm; namespace xmrig @@ -44,6 +47,8 @@ class RxDataset; class RxVm { public: + XMRIG_DISABLE_COPY_MOVE_DEFAULT(RxVm); + RxVm(RxDataset *dataset, uint8_t *scratchpad, bool softAes); ~RxVm(); diff --git a/src/net/JobResult.h b/src/net/JobResult.h index 2c2fded53..87bf3be92 100644 --- a/src/net/JobResult.h +++ b/src/net/JobResult.h @@ -28,7 +28,7 @@ #include -#include +#include #include "base/tools/String.h" @@ -41,7 +41,7 @@ namespace xmrig { class JobResult { public: - inline JobResult() {} + JobResult() = delete; inline JobResult(const Job &job, uint32_t nonce, const uint8_t *result) : algorithm(job.algorithm()), @@ -56,6 +56,7 @@ public: inline const uint8_t *result() const { return m_result; } inline uint64_t actualDiff() const { return Job::toDiff(reinterpret_cast(m_result)[3]); } + inline uint8_t *result() { return m_result; } const Algorithm algorithm; const String clientId; @@ -65,7 +66,7 @@ public: const uint8_t index = 0; private: - uint8_t m_result[32]; + uint8_t m_result[32] = { 0 }; }; diff --git a/src/net/JobResults.cpp b/src/net/JobResults.cpp index 40c2e50be..c6bd68bb4 100644 --- a/src/net/JobResults.cpp +++ b/src/net/JobResults.cpp @@ -23,79 +23,246 @@ */ -#include +#include "net/JobResults.h" + +#include "base/io/log/Log.h" +#include "base/tools/Handle.h" +#include "base/tools/Object.h" +#include "net/interfaces/IJobResultListener.h" +#include "net/JobResult.h" + + +#ifdef XMRIG_ALGO_RANDOMX +# include "crypto/randomx/randomx.h" +# include "crypto/rx/Rx.h" +# include "crypto/rx/RxVm.h" +#endif + + +#if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) +# include "base/tools/Baton.h" +# include "crypto/cn/CnCtx.h" +# include "crypto/cn/CnHash.h" +# include "crypto/cn/CryptoNight.h" +# include "crypto/common/VirtualMemory.h" +#endif + + +#include #include #include #include -#include "base/tools/Handle.h" -#include "net/interfaces/IJobResultListener.h" -#include "net/JobResult.h" -#include "net/JobResults.h" - - namespace xmrig { +#if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) +class JobBundle +{ +public: + inline JobBundle(const Job &job, uint32_t *results, size_t count) : + job(job), + nonces(count) + { + memcpy(nonces.data(), results, sizeof(uint32_t) * count); + } + + Job job; + std::vector nonces; +}; + + +class JobBaton : public Baton +{ +public: + inline JobBaton(std::list &&bundles, IJobResultListener *listener, bool hwAES) : + hwAES(hwAES), + listener(listener), + bundles(std::move(bundles)) + {} + + const bool hwAES; + IJobResultListener *listener; + std::list bundles; + std::vector results; + uint32_t errors = 0; +}; + + +static inline void checkHash(const JobBundle &bundle, std::vector &results, uint32_t nonce, uint8_t hash[32], uint32_t &errors) +{ + if (*reinterpret_cast(hash + 24) < bundle.job.target()) { + results.emplace_back(bundle.job, nonce, hash); + } + else { + LOG_ERR("COMPUTE ERROR"); // TODO Extend information. + errors++; + } +} + + +static void getResults(JobBundle &bundle, std::vector &results, uint32_t &errors, bool hwAES) +{ + const auto &algorithm = bundle.job.algorithm(); + auto memory = new VirtualMemory(algorithm.l3(), false); + uint8_t hash[32]{ 0 }; + + if (algorithm.family() == Algorithm::RANDOM_X) { +# ifdef XMRIG_ALGO_RANDOMX + RxDataset *dataset = Rx::dataset(bundle.job, 0); + if (dataset == nullptr) { + errors += bundle.nonces.size(); + + return; + } + + auto vm = new RxVm(dataset, memory->scratchpad(), !hwAES); + + for (uint32_t nonce : bundle.nonces) { + *bundle.job.nonce() = nonce; + + randomx_calculate_hash(vm->get(), bundle.job.blob(), bundle.job.size(), hash); + + checkHash(bundle, results, nonce, hash, errors); + } + + delete vm; +# endif + } + else if (algorithm.family() == Algorithm::ARGON2) { + errors += bundle.nonces.size(); // TODO ARGON2 + } + else { + cryptonight_ctx *ctx[1]; + CnCtx::create(ctx, memory->scratchpad(), memory->size(), 1); + + for (uint32_t nonce : bundle.nonces) { + *bundle.job.nonce() = nonce; + + CnHash::fn(algorithm, hwAES ? CnHash::AV_SINGLE : CnHash::AV_SINGLE_SOFT, Assembly::NONE)(bundle.job.blob(), bundle.job.size(), hash, ctx, bundle.job.height()); + + checkHash(bundle, results, nonce, hash, errors); + } + } + + delete memory; +} +#endif + + class JobResultsPrivate { public: - inline JobResultsPrivate(IJobResultListener *listener) : - listener(listener) - { - async = new uv_async_t; - async->data = this; + XMRIG_DISABLE_COPY_MOVE_DEFAULT(JobResultsPrivate) - uv_async_init(uv_default_loop(), async, JobResultsPrivate::onResult); + inline JobResultsPrivate(IJobResultListener *listener, bool hwAES) : + m_hwAES(hwAES), + m_listener(listener) + { + m_async = new uv_async_t; + m_async->data = this; + + uv_async_init(uv_default_loop(), m_async, JobResultsPrivate::onResult); } inline ~JobResultsPrivate() { - Handle::close(async); + Handle::close(m_async); } - void submit(const JobResult &result) + inline void submit(const JobResult &result) { - mutex.lock(); - queue.push_back(result); - mutex.unlock(); + std::lock_guard lock(m_mutex); + m_results.push_back(result); - uv_async_send(async); + uv_async_send(m_async); } +# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) + inline void submit(const Job &job, uint32_t *results, size_t count) + { + std::lock_guard lock(m_mutex); + m_bundles.emplace_back(job, results, count); + + uv_async_send(m_async); + } +# endif + + private: static void onResult(uv_async_t *handle) { static_cast(handle->data)->submit(); } +# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) + inline void submit() + { + std::list bundles; + std::list results; + + m_mutex.lock(); + m_bundles.swap(bundles); + m_results.swap(results); + m_mutex.unlock(); + + for (const auto &result : results) { + m_listener->onJobResult(result); + } + + if (bundles.empty()) { + return; + } + + auto baton = new JobBaton(std::move(bundles), m_listener, m_hwAES); + + uv_queue_work(uv_default_loop(), &baton->req, + [](uv_work_t *req) { + auto baton = static_cast(req->data); + + for (JobBundle &bundle : baton->bundles) { + getResults(bundle, baton->results, baton->errors, baton->hwAES); + } + }, + [](uv_work_t *req, int) { + auto baton = static_cast(req->data); + + for (const auto &result : baton->results) { + baton->listener->onJobResult(result); + } + + delete baton; + } + ); + } +# else inline void submit() { std::list results; - mutex.lock(); + m_mutex.lock(); + m_results.swap(results); + m_mutex.unlock(); - while (!queue.empty()) { - results.push_back(std::move(queue.front())); - queue.pop_front(); + for (const auto &result : results) { + m_listener->onJobResult(result); } - - mutex.unlock(); - - for (auto result : results) { - listener->onJobResult(result); - } - - results.clear(); } +# endif - IJobResultListener *listener; - std::list queue; - std::mutex mutex; - uv_async_t *async; +private: + const bool m_hwAES; + IJobResultListener *m_listener; + std::list m_results; + std::mutex m_mutex; + uv_async_t *m_async; + +# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) + std::list m_bundles; +# endif }; @@ -106,11 +273,11 @@ static JobResultsPrivate *handler = nullptr; -void xmrig::JobResults::setListener(IJobResultListener *listener) +void xmrig::JobResults::setListener(IJobResultListener *listener, bool hwAES) { assert(handler == nullptr); - handler = new JobResultsPrivate(listener); + handler = new JobResultsPrivate(listener, hwAES); } @@ -124,6 +291,12 @@ void xmrig::JobResults::stop() } +void xmrig::JobResults::submit(const Job &job, uint32_t nonce, const uint8_t *result) +{ + submit(JobResult(job, nonce, result)); +} + + void xmrig::JobResults::submit(const JobResult &result) { assert(handler != nullptr); @@ -132,3 +305,13 @@ void xmrig::JobResults::submit(const JobResult &result) handler->submit(result); } } + + +#if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) +void xmrig::JobResults::submit(const Job &job, uint32_t *results, size_t count) +{ + if (handler) { + handler->submit(job, results, count); + } +} +#endif diff --git a/src/net/JobResults.h b/src/net/JobResults.h index e7082acb8..4d16d27bf 100644 --- a/src/net/JobResults.h +++ b/src/net/JobResults.h @@ -27,19 +27,29 @@ #define XMRIG_JOBRESULTS_H +#include +#include + + namespace xmrig { class IJobResultListener; +class Job; class JobResult; class JobResults { public: - static void setListener(IJobResultListener *listener); + static void setListener(IJobResultListener *listener, bool hwAES); static void stop(); + static void submit(const Job &job, uint32_t nonce, const uint8_t *result); static void submit(const JobResult &result); + +# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA) + static void submit(const Job &job, uint32_t *results, size_t count); +# endif }; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 3ab8bec05..2b3f4b5f2 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -60,7 +60,7 @@ xmrig::Network::Network(Controller *controller) : m_donate(nullptr), m_timer(nullptr) { - JobResults::setListener(this); + JobResults::setListener(this, controller->config()->cpu().isHwAES()); controller->addListener(this); # ifdef XMRIG_FEATURE_API