1
0
mirror of https://github.com/xmrig/xmrig.git synced 2025-12-06 23:52:38 -05:00

Compare commits

...

62 Commits

Author SHA1 Message Date
XMRig
72b7d934f6 v4.3.0-beta 2019-10-10 13:58:43 +07:00
XMRig
08e9e834b9 Merge branch 'evo' into beta 2019-10-10 13:34:18 +07:00
xmrig
c26c4ce714 Update CHANGELOG.md 2019-10-09 13:11:35 +07:00
XMRig
61ab47cc95 Improved CPU profile generation. 2019-10-09 12:58:11 +07:00
XMRig
7db7b3727d Improved OpenCL profile generation, don't create unnecessary (equal to main profile) profiles. 2019-10-09 11:11:43 +07:00
xmrig
1d03b942a5 Update ALGORITHMS.md 2019-10-09 09:26:56 +07:00
XMRig
ee87f73d5e #1227 Added "arqma" value for "coin" option. 2019-10-09 09:20:54 +07:00
XMRig
bb7bff9115 Added command line option --cpu-memory-pool. 2019-10-09 08:45:06 +07:00
xmrig
1e5fdde9ba Merge pull request #1227 from SChernykh/evo
RandomX (Arqma variant) support
2019-10-09 07:56:00 +07:00
SChernykh
2b29a4c20f RandomX (Arqma variant) support 2019-10-08 19:00:19 +02:00
XMRig
119e7ea7bf Merge branch 'feature-hugepages-pool' into evo 2019-10-08 09:47:01 +07:00
XMRig
58c81be1f1 Updated default config and docs. 2019-10-08 09:41:36 +07:00
XMRig
d3b137c817 Fixed crash. 2019-10-08 08:50:33 +07:00
XMRig
9dce868fb9 Added "memory-pool" option. 2019-10-07 23:38:01 +07:00
XMRig
c4170fbb86 Removed unnecessary error message. 2019-10-07 21:11:58 +07:00
XMRig
2dc4ceae29 Added class NUMAMemoryPool. 2019-10-07 20:39:04 +07:00
XMRig
0e0a26f644 Fixed Linux build. 2019-10-07 13:37:12 +07:00
XMRig
68d77b02d7 Added initial memory pool support. 2019-10-07 12:36:40 +07:00
XMRig
c13c83b902 VirtualMemory class refactoring. 2019-10-06 17:49:15 +07:00
XMRig
72c9d94390 Use hwloc for set thread affinity. 2019-10-06 14:40:42 +07:00
xmrig
9101469308 Update CHANGELOG.md 2019-10-06 12:02:43 +07:00
XMRig
759573ace3 Merge branch 'optimize-numa' into evo 2019-10-06 11:21:31 +07:00
XMRig
0a1836e5a8 Fixed exit condition for RxQueue. 2019-10-06 11:19:32 +07:00
XMRig
8af1075c98 Removed uv_try_write for console log. 2019-10-06 11:03:01 +07:00
xmrig
91498ec690 Merge pull request #1220 from SChernykh/evo
Refactored JIT compiler for x86, small RandomX speedup
2019-10-06 08:16:40 +07:00
XMRig
59b62dcb77 Added class RxQueue, class Rx now thin static wrapper on top of RxQueue. 2019-10-06 07:47:41 +07:00
SChernykh
10f9b29e03 Refactored JIT compiler for x86, small RandomX speedup 2019-10-05 21:40:21 +02:00
XMRig
d5af5cf8f8 Fixed exit. 2019-10-05 11:24:22 +07:00
XMRig
05928ccc25 Implemented RxNUMAStorage. 2019-10-05 08:24:28 +07:00
XMRig
ad6dc876b3 Simplified VirtualMemory::bindToNUMANode. 2019-10-04 19:52:15 +07:00
XMRig
207dae418d Added RxNUMAStorage stub. 2019-10-04 18:43:03 +07:00
XMRig
7508411faf Extended "numa" option for RandomX. 2019-10-04 10:49:55 +07:00
XMRig
f34031a984 Added interface IRxStorage and RxBasicStorage class. 2019-10-04 08:45:13 +07:00
XMRig
d1aadc2e3b More cleanup. 2019-10-03 07:45:25 +07:00
XMRig
6d8cf91568 Added class RxSeed. 2019-10-03 04:48:36 +07:00
XMRig
96b2560f79 v4.2.1-beta 2019-10-02 10:33:12 +07:00
XMRig
923d47fff0 Merge branch 'evo' into beta 2019-10-02 10:32:34 +07:00
xmrig
542a27a032 Update CHANGELOG.md 2019-10-02 07:25:17 +07:00
xmrig
a7e8ac6cf8 Update CHANGELOG.md 2019-10-02 07:23:49 +07:00
XMRig
42fd146c2b #1212 Fixed RandomX dataset re-initialization. 2019-10-02 06:35:49 +07:00
XMRig
34468782cd Merge branch 'dev' into evo 2019-10-01 07:26:18 +07:00
XMRig
3badeb56a0 Fixed support for systems where total count of NUMA nodes not equal usable count. 2019-10-01 07:19:13 +07:00
XMRig
bc18b5d0be Fixed msvc build. 2019-10-01 01:25:47 +07:00
XMRig
158d2e4302 #1150 Fixed argon2 header conflict. 2019-10-01 01:18:22 +07:00
XMRig
f60118ee79 Merge branch 'opencl-shared-data' into evo 2019-09-30 08:33:02 +07:00
XMRig
6bc217e985 Fixed excessive memory allocation. 2019-09-30 08:28:25 +07:00
XMRig
3560b6a3c2 Added clRetainMemObject support. 2019-09-30 07:30:14 +07:00
XMRig
77eecdd2c2 RandomX dataset specific code moved into OclSharedData class. 2019-09-30 06:59:44 +07:00
XMRig
f4943b77f3 Class OclInterleave renamed to OclSharedData and added class OclSharedState. 2019-09-30 05:18:53 +07:00
XMRig
c908ef2489 v4.3.0-evo 2019-09-29 04:27:23 +07:00
XMRig
d21155f3c6 Merge branch 'beta' into evo 2019-09-29 04:26:57 +07:00
XMRig
da39ed2ce0 v3.2.1-dev 2019-09-29 04:25:35 +07:00
XMRig
06500761fb Merge branch 'master' into dev 2019-09-29 04:25:06 +07:00
xmrig
919a6c0cc4 Update README.md 2019-09-29 04:10:38 +07:00
XMRig
427b6516e0 v3.2.0 2019-09-28 23:03:12 +07:00
XMRig
eae9009b98 Merge branch 'dev' 2019-09-28 22:56:55 +07:00
xmrig
8e9e8cd169 Update ALGORITHMS.md 2019-09-28 09:00:50 +07:00
xmrig
f96538dfba Update ALGORITHMS.md 2019-09-28 08:43:31 +07:00
xmrig
9ad174c129 Update ALGORITHMS.md 2019-09-28 08:28:31 +07:00
XMRig
17b40ac4ad v3.2.0-dev 2019-09-28 03:40:53 +07:00
xmrig
3cbbc94249 Merge pull request #1184 from msembinelli/master
Improve grammar and spelling on usage section
2019-09-21 03:19:17 +07:00
Matthew Sembinelli
cbc08e696f Improve grammar and spelling on usage section 2019-09-20 14:06:38 -06:00
122 changed files with 10579 additions and 7791 deletions

View File

@@ -1,3 +1,14 @@
# v4.3.0-beta
- [#1227](https://github.com/xmrig/xmrig/pull/1227) Added new algorithm `rx/arq`, RandomX variant for upcoming ArQmA fork.
- [#808](https://github.com/xmrig/xmrig/issues/808#issuecomment-539297156) Added experimental support for persistent memory for CPU mining threads.
- [#1221](https://github.com/xmrig/xmrig/issues/1221) Improved RandomX dataset memory usage and initialization speed for NUMA machines.
# v4.2.1-beta
- [#1150](https://github.com/xmrig/xmrig/issues/1150) Fixed build on FreeBSD.
- [#1175](https://github.com/xmrig/xmrig/issues/1175) Fixed support for systems where total count of NUMA nodes not equal usable nodes count.
- [#1199](https://github.com/xmrig/xmrig/issues/1199) Fixed excessive memory allocation for OpenCL threads with low intensity.
- [#1212](https://github.com/xmrig/xmrig/issues/1212) Fixed low RandomX performance after fast algorithm switching.
# v4.2.0-beta
- [#1202](https://github.com/xmrig/xmrig/issues/1202) Fixed algorithm verification in donate strategy.
- Added per pool option `coin` with single possible value `monero` for pools without algorithm negotiation, for upcoming Monero fork.
@@ -23,6 +34,10 @@
- [#268](https://github.com/xmrig/xmrig-amd/pull/268) [#270](https://github.com/xmrig/xmrig-amd/pull/270) [#271](https://github.com/xmrig/xmrig-amd/pull/271) [#273](https://github.com/xmrig/xmrig-amd/pull/273) [#274](https://github.com/xmrig/xmrig-amd/pull/274) [#1171](https://github.com/xmrig/xmrig/pull/1171) Added RandomX support for OpenCL, thanks [@SChernykh](https://github.com/SChernykh).
- Algorithm `cn/wow` removed, as no longer alive.
# v3.2.0
- Added per pool option `coin` with single possible value `monero` for pools without algorithm negotiation, for upcoming Monero fork.
- [#1183](https://github.com/xmrig/xmrig/issues/1183) Fixed compatibility with systemd.
# v3.1.3
- [#1180](https://github.com/xmrig/xmrig/issues/1180) Fixed possible duplicated shares after algorithm switching.
- Fixed wrong config file permissions after write (only gcc builds on recent Windows 10 affected).

View File

@@ -55,6 +55,7 @@ set(HEADERS
)
set(HEADERS_CRYPTO
src/backend/common/interfaces/IMemoryPool.h
src/crypto/cn/asm/CryptonightR_template.h
src/crypto/cn/c_blake256.h
src/crypto/cn/c_groestl.h
@@ -73,6 +74,7 @@ set(HEADERS_CRYPTO
src/crypto/common/Algorithm.h
src/crypto/common/Coin.h
src/crypto/common/keccak.h
src/crypto/common/MemoryPool.h
src/crypto/common/Nonce.h
src/crypto/common/portable/mm_malloc.h
src/crypto/common/VirtualMemory.h
@@ -111,10 +113,22 @@ set(SOURCES_CRYPTO
src/crypto/common/Algorithm.cpp
src/crypto/common/Coin.cpp
src/crypto/common/keccak.cpp
src/crypto/common/MemoryPool.cpp
src/crypto/common/Nonce.cpp
src/crypto/common/VirtualMemory.cpp
)
if (WITH_HWLOC)
list(APPEND HEADERS_CRYPTO
src/crypto/common/NUMAMemoryPool.h
)
list(APPEND SOURCES_CRYPTO
src/crypto/common/NUMAMemoryPool.cpp
src/crypto/common/VirtualMemory_hwloc.cpp
)
endif()
if (WIN32)
set(SOURCES_OS
"${SOURCES_OS}"

View File

@@ -1,5 +1,7 @@
# XMRig
**:warning: [Monero will change PoW algorithm to RandomX on November 30.](https://github.com/xmrig/xmrig/issues/1204)**
[![Github All Releases](https://img.shields.io/github/downloads/xmrig/xmrig/total.svg)](https://github.com/xmrig/xmrig/releases)
[![GitHub release](https://img.shields.io/github/release/xmrig/xmrig/all.svg)](https://github.com/xmrig/xmrig/releases)
[![GitHub Release Date](https://img.shields.io/github/release-date-pre/xmrig/xmrig.svg)](https://github.com/xmrig/xmrig/releases)
@@ -26,56 +28,71 @@ XMRig is a high performance RandomX and CryptoNight CPU miner, with official sup
* Clone with `git clone https://github.com/xmrig/xmrig.git` :hammer: [Build instructions](https://github.com/xmrig/xmrig/wiki/Build).
## Usage
Preferend way to configure miner is [JSON config file](src/config.json) as more flexible and human frendly, command line interface not cover all features, for example mining profiles for different algorithms. Most impotant options can be changed in runtime without miner restart by editing config or via API.
The preferred way to configure the miner is the [JSON config file](src/config.json) as it is more flexible and human friendly. The command line interface does not cover all features, such as mining profiles for different algorithms. Important options can be changed during runtime without miner restart by editing the config file or executing API calls.
### Options
### Command line options
```
-a, --algo=ALGO specify the algorithm to use
cn/r, cn/2, cn/1, cn/0, cn/double, cn/half, cn/fast,
cn/rwz, cn/zls, cn/xao, cn/rto, cn/gpu,
cn-lite/1,
cn-heavy/xhv, cn-heavy/tube, cn-heavy/0,
cn-pico,
rx/wow, rx/loki
Network:
-o, --url=URL URL of mining server
-O, --userpass=U:P username:password pair for mining server
-a, --algo=ALGO mining algorithm https://xmrig.com/docs/algorithms
--coin=COIN specify coin instead of algorithm
-u, --user=USERNAME username for mining server
-p, --pass=PASSWORD password for mining server
--rig-id=ID rig identifier for pool-side statistics (needs pool support)
-t, --threads=N number of miner threads
-v, --av=N algorithm variation, 0 auto select
-O, --userpass=U:P username:password pair for mining server
-k, --keepalive send keepalived packet for prevent timeout (needs pool support)
--nicehash enable nicehash.com support
--rig-id=ID rig identifier for pool-side statistics (needs pool support)
--tls enable SSL/TLS support (needs pool support)
--tls-fingerprint=F pool TLS certificate fingerprint, if set enable strict certificate pinning
--tls-fingerprint=HEX pool TLS certificate fingerprint for strict certificate pinning
--daemon use daemon RPC instead of pool for solo mining
--daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)
-r, --retries=N number of times to retry before switch to backup server (default: 5)
-R, --retry-pause=N time to pause between retries (default: 5)
--user-agent set custom user-agent string for pool
--donate-level=N donate level, default 5%% (5 minutes in 100 minutes)
--donate-over-proxy=N control donate over xmrig-proxy feature
CPU backend:
--no-cpu disable CPU mining backend
-t, --threads=N number of CPU threads
-v, --av=N algorithm variation, 0 auto select
--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1
--cpu-priority set process priority (0 idle, 2 normal to 5 highest)
--cpu-max-threads-hint=N maximum CPU threads count (in percentage) hint for autoconfig
--cpu-memory-pool=N number of 2 MB pages for persistent memory pool, -1 (auto), 0 (disable)
--no-huge-pages disable huge pages support
--no-color disable colored output
--donate-level=N donate level, default 5% (5 minutes in 100 minutes)
--user-agent set custom user-agent string for pool
-B, --background run the miner in the background
-c, --config=FILE load a JSON-format configuration file
-l, --log-file=FILE log all output to a file
--asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer.
--print-time=N print hashrate report every N seconds
--asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer
--randomx-init=N threads count to initialize RandomX dataset
--randomx-no-numa disable NUMA support for RandomX
API:
--api-worker-id=ID custom worker-id for API
--api-id=ID custom instance ID for API
--http-enabled enable HTTP API
--http-host=HOST bind host for HTTP API (default: 127.0.0.1)
--http-port=N bind port for HTTP API
--http-access-token=T access token for HTTP API
--http-no-restricted enable full remote access to HTTP API (only if access token set)
--randomx-init=N threads count to initialize RandomX dataset
--randomx-no-numa disable NUMA support for RandomX
--export-topology export hwloc topology to a XML file and exit
--dry-run test configuration and exit
-h, --help display this help and exit
OpenCL backend:
--opencl enable OpenCL mining backend
--opencl-devices=N list of OpenCL devices to use
--opencl-platform=N OpenCL platform index or name
--opencl-loader=N path to OpenCL-ICD-Loader (OpenCL.dll or libOpenCL.so)
--opencl-no-cache disable OpenCL cache
--print-platforms print available OpenCL platforms and exit
Logging:
-l, --log-file=FILE log all output to a file
--print-time=N print hashrate report every N seconds
--no-color disable colored output
Misc:
-c, --config=FILE load a JSON-format configuration file
-B, --background run the miner in the background
-V, --version output version information and exit
-h, --help display this help and exit
--dry-run test configuration and exit
--export-topology export hwloc topology to a XML file and exit
```
## Donations

View File

@@ -4,9 +4,12 @@ if (WITH_RANDOMX)
list(APPEND HEADERS_CRYPTO
src/crypto/rx/Rx.h
src/crypto/rx/RxAlgo.h
src/crypto/rx/RxBasicStorage.h
src/crypto/rx/RxCache.h
src/crypto/rx/RxConfig.h
src/crypto/rx/RxDataset.h
src/crypto/rx/RxQueue.h
src/crypto/rx/RxSeed.h
src/crypto/rx/RxVm.h
)
@@ -32,9 +35,11 @@ if (WITH_RANDOMX)
src/crypto/randomx/vm_interpreted.cpp
src/crypto/rx/Rx.cpp
src/crypto/rx/RxAlgo.cpp
src/crypto/rx/RxBasicStorage.cpp
src/crypto/rx/RxCache.cpp
src/crypto/rx/RxConfig.cpp
src/crypto/rx/RxDataset.cpp
src/crypto/rx/RxQueue.cpp
src/crypto/rx/RxVm.cpp
)
@@ -63,6 +68,21 @@ if (WITH_RANDOMX)
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()
if (WITH_HWLOC)
list(APPEND HEADERS_CRYPTO
src/crypto/rx/RxNUMAStorage.h
)
list(APPEND SOURCES_CRYPTO
src/crypto/rx/RxConfig_hwloc.cpp
src/crypto/rx/RxNUMAStorage.cpp
)
else()
list(APPEND SOURCES_CRYPTO
src/crypto/rx/RxConfig_basic.cpp
)
endif()
else()
remove_definitions(/DXMRIG_ALGO_RANDOMX)
endif()

View File

@@ -1,36 +1,23 @@
# Algorithms
Since version 3 mining [algorithm](#algorithm-names) should specified for each pool separately (`algo` option), earlier versions was use one global `algo` option and per pool `variant` option (this option was removed in v3). If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) you may not specify this option at all.
#### Example
```json
{
"pools": [
{
"url": "...",
"algo": "cn/r",
...
}
],
...
}
```
Algorithm can be defined in 3 ways:
#### Pools with mining algorithm negotiation support.
1. By pool, using algorithm negotiation, in this case no need specify algorithm on miner side.
2. Per pool `coin` option, currently only usable values for this option is `monero` and `arqma`.
3. Per pool `algo` option.
* [www.hashvault.pro](https://www.hashvault.pro/)
* [moneroocean.stream](https://moneroocean.stream)
## Algorithm names
Option `coin` useful for pools without algorithm negotiation support or daemon to allow automatically switch algorithm in next hard fork.
## Algorithm names
| Name | Memory | Version | Notes |
|------|--------|---------|-------|
| `rx/arq` | 256 KB | 4.3.0+ | RandomARQ (RandomX variant for ArQmA). |
| `rx/0` | 2 MB | 3.2.0+ | RandomX (Monero). |
| `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. |
| `rx/wow` | 1 MB | 3.0.0+ | RandomWOW (RandomX variant for Wownero). |
| `rx/loki` | 2 MB | 3.0.0+ | RandomXL (RandomX variant for Loki). |
| `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. |
@@ -50,3 +37,21 @@ Since version 3 mining [algorithm](#algorithm-names) should specified for each p
| `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). |
## Migration to v3
Since version 3 mining [algorithm](#algorithm-names) should specified for each pool separately (`algo` option), earlier versions was use one global `algo` option and per pool `variant` option (this option was removed in v3). If your pool support [mining algorithm negotiation](https://github.com/xmrig/xmrig-proxy/issues/168) you may not specify this option at all.
#### Example
```json
{
"pools": [
{
"url": "...",
"algo": "cn/r",
"coin": null
...
}
],
...
}
```

View File

@@ -97,3 +97,6 @@ Allow override automatically detected Argon2 implementation, this option added m
#### `max-threads-hint` (since v4.2.0)
Maximum CPU threads count (in percentage) hint for autoconfig. [CPU_MAX_USAGE.md](CPU_MAX_USAGE.md)
#### `memory-pool` (since v4.3.0)
Use continuous, persistent memory block for mining threads, useful for preserve huge pages allocation while algorithm swithing. Default value `false` (feature disabled) or `true` or specific count of 2 MB huge pages.

View File

@@ -59,6 +59,7 @@ function rx()
'randomx_constants_monero.h',
'randomx_constants_wow.h',
'randomx_constants_loki.h',
'randomx_constants_arqma.h',
'aes.cl',
'blake2b.cl',
'randomx_vm.cl',

View File

@@ -22,7 +22,7 @@ set(ARGON2_X86_64_SOURCES arch/x86_64/lib/argon2-arch.c arch/x86_64/lib/cpu-flag
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}/../../)
target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set_target_properties(argon2-${FEATURE} PROPERTIES POSITION_INDEPENDENT_CODE True)
@@ -38,7 +38,7 @@ if (CMAKE_C_COMPILER_ID MATCHES MSVC)
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}/../../)
target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set_target_properties(argon2-${FEATURE} PROPERTIES POSITION_INDEPENDENT_CODE True)
@@ -84,5 +84,5 @@ endif()
add_library(argon2 STATIC ${ARGON2_SOURCES})
target_link_libraries(argon2 ${ARGON2_LIBS})
target_include_directories(argon2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(argon2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../)
target_include_directories(argon2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib)

View File

@@ -15,7 +15,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "argon2.h"
#include "3rdparty/argon2.h"
#include "encoding.h"
#include "core.h"

View File

@@ -14,7 +14,7 @@
#ifndef ARGON2_CORE_H
#define ARGON2_CORE_H
#include "argon2.h"
#include "3rdparty/argon2.h"
#if defined(_MSC_VER)
#define ALIGN(n) __declspec(align(16))

View File

@@ -1,6 +1,6 @@
#ifndef ENCODING_H
#define ENCODING_H
#include "argon2.h"
#include "3rdparty/argon2.h"
#define ARGON2_MAX_DECODED_LANES UINT32_C(255)
#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8)

View File

@@ -3,7 +3,7 @@
#include "impl-select.h"
#include "argon2.h"
#include "3rdparty/argon2.h"
#define BENCH_SAMPLES 1024
#define BENCH_MEM_BLOCKS 512

View File

@@ -36,7 +36,6 @@
#include "core/config/Config.h"
#include "core/Controller.h"
#include "core/Miner.h"
#include "crypto/common/VirtualMemory.h"
#include "net/Network.h"
#include "Summary.h"
#include "version.h"
@@ -80,8 +79,6 @@ int xmrig::App::exec()
m_console = new Console(this);
}
VirtualMemory::init(m_controller->config()->cpu().isHugePages());
Summary::print(m_controller);
if (m_controller->config()->isDryRun()) {

View File

@@ -38,6 +38,11 @@ const char *ocl_tag();
#endif
#ifdef XMRIG_ALGO_RANDOMX
const char *rx_tag();
#endif
} // namespace xmrig

View File

@@ -48,12 +48,21 @@ 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 setAlias(const Algorithm &algo, const char *profile) { m_aliases[algo] = profile; }
inline void move(const char *profile, T &&threads)
inline size_t move(const char *profile, T &&threads)
{
if (has(profile)) {
return 0;
}
const size_t count = threads.count();
if (!threads.isEmpty()) {
m_profiles.insert({ profile, std::move(threads) });
}
return count;
}
const T &get(const String &profileName) const;

View File

@@ -34,8 +34,7 @@ xmrig::Worker::Worker(size_t id, int64_t affinity, int priority) :
m_affinity(affinity),
m_id(id),
m_hashCount(0),
m_timestamp(0),
m_count(0)
m_timestamp(0)
{
m_node = VirtualMemory::bindToNUMANode(affinity);

View File

@@ -54,8 +54,8 @@ protected:
const size_t m_id;
std::atomic<uint64_t> m_hashCount;
std::atomic<uint64_t> m_timestamp;
uint32_t m_node = 0;
uint64_t m_count;
uint32_t m_node = 0;
uint64_t m_count = 0;
};

View File

@@ -100,6 +100,7 @@ void xmrig::Workers<T>::start(const std::vector<T> &data)
}
d_ptr->hashrate = new Hashrate(m_workers.size());
Nonce::touch(T::backend());
for (Thread<T> *worker : m_workers) {
worker->start(Workers<T>::onReady);

View File

@@ -3,6 +3,7 @@ set(HEADERS_BACKEND_COMMON
src/backend/common/Tags.h
src/backend/common/interfaces/IBackend.h
src/backend/common/interfaces/IRxListener.h
src/backend/common/interfaces/IRxStorage.h
src/backend/common/interfaces/IThread.h
src/backend/common/interfaces/IWorker.h
src/backend/common/misc/PciTopology.h

View File

@@ -5,7 +5,9 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
@@ -22,47 +24,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_OCLRXDATASET_H
#define XMRIG_OCLRXDATASET_H
#ifndef XMRIG_IMEMORYPOOL_H
#define XMRIG_IMEMORYPOOL_H
#include "base/tools/Object.h"
#include <memory>
using cl_context = struct _cl_context *;
using cl_mem = struct _cl_mem *;
#include <cstddef>
#include <cstdint>
namespace xmrig {
class Job;
class OclRxDataset
class IMemoryPool
{
public:
XMRIG_DISABLE_COPY_MOVE(OclRxDataset)
virtual ~IMemoryPool() = default;
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;
virtual bool isHugePages(uint32_t node) const = 0;
virtual uint8_t *get(size_t size, uint32_t node) = 0;
virtual void release(uint32_t node) = 0;
};
using OclRxDatasetPtr = std::shared_ptr<OclRxDataset>;
} /* namespace xmrig */
#endif /* XMRIG_OCLINTERLEAVE_H */
#endif /* XMRIG_IMEMORYPOOL_H */

View File

@@ -0,0 +1,53 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2016-2018 XMRig <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_IRXSTORAGE_H
#define XMRIG_IRXSTORAGE_H
#include <cstdint>
#include <utility>
namespace xmrig {
class Job;
class RxDataset;
class RxSeed;
class IRxStorage
{
public:
virtual ~IRxStorage() = default;
virtual RxDataset *dataset(const Job &job, uint32_t nodeId) const = 0;
virtual std::pair<uint32_t, uint32_t> hugePages() const = 0;
virtual void init(const RxSeed &seed, uint32_t threads, bool hugePages) = 0;
};
} /* namespace xmrig */
#endif // XMRIG_IRXSTORAGE_H

View File

@@ -111,13 +111,13 @@ public:
return;
}
LOG_INFO("%s" GREEN_BOLD(" READY") " threads %s%zu/%zu (%zu)" CLEAR " huge pages %s%zu/%zu %1.0f%%" CLEAR " memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"),
LOG_INFO("%s" GREEN_BOLD(" READY") " threads %s%zu/%zu (%zu)" CLEAR " huge pages %s%1.0f%% %zu/%zu" CLEAR " memory " CYAN_BOLD("%zu KB") BLACK_BOLD(" (%" PRIu64 " ms)"),
tag,
m_errors == 0 ? CYAN_BOLD_S : YELLOW_BOLD_S,
m_started, 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<double>(m_hugePages) / m_pages * 100.0,
m_hugePages, m_pages,
memory() / 1024,
Chrono::steadyMSecs() - m_ts
);

View File

@@ -23,48 +23,27 @@
*/
#include "backend/cpu/Cpu.h"
#include "backend/cpu/CpuConfig.h"
#include "backend/cpu/CpuConfig_gen.h"
#include "backend/cpu/Cpu.h"
#include "base/io/json/Json.h"
#include "rapidjson/document.h"
namespace xmrig {
static const char *kCn = "cn";
static const char *kEnabled = "enabled";
static const char *kHugePages = "huge-pages";
static const char *kHwAes = "hw-aes";
static const char *kMaxThreadsHint = "max-threads-hint";
static const char *kMemoryPool = "memory-pool";
static const char *kPriority = "priority";
#ifdef XMRIG_FEATURE_ASM
static const char *kAsm = "asm";
#endif
#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";
static const char *kArgon2Impl = "argon2-impl";
#endif
@@ -90,6 +69,7 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const
obj.AddMember(StringRef(kHugePages), m_hugePages, allocator);
obj.AddMember(StringRef(kHwAes), m_aes == AES_AUTO ? Value(kNullType) : Value(m_aes == AES_HW), allocator);
obj.AddMember(StringRef(kPriority), priority() != -1 ? Value(priority()) : Value(kNullType), allocator);
obj.AddMember(StringRef(kMemoryPool), m_memoryPool < 1 ? Value(m_memoryPool < 0) : Value(m_memoryPool), allocator);
if (m_threads.isEmpty()) {
obj.AddMember(StringRef(kMaxThreadsHint), m_limit, allocator);
@@ -109,6 +89,12 @@ rapidjson::Value xmrig::CpuConfig::toJSON(rapidjson::Document &doc) const
}
size_t xmrig::CpuConfig::memPoolSize() const
{
return m_memoryPool < 0 ? Cpu::info()->threads() : m_memoryPool;
}
std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, const Algorithm &algorithm) const
{
std::vector<CpuLaunchData> out;
@@ -128,7 +114,7 @@ std::vector<xmrig::CpuLaunchData> xmrig::CpuConfig::get(const Miner *miner, cons
}
void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
void xmrig::CpuConfig::read(const rapidjson::Value &value)
{
if (value.IsObject()) {
m_enabled = Json::getBool(value, kEnabled, m_enabled);
@@ -137,6 +123,7 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
setAesMode(Json::getValue(value, kHwAes));
setPriority(Json::getInt(value, kPriority, -1));
setMemoryPool(Json::getValue(value, kMemoryPool));
# ifdef XMRIG_FEATURE_ASM
m_assembly = Json::getValue(value, kAsm);
@@ -146,16 +133,14 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
m_argon2Impl = Json::getString(value, kArgon2Impl);
# endif
if (!m_threads.read(value)) {
generate();
}
m_threads.read(value);
if (version == 0) {
generateArgon2();
}
generate();
}
else if (value.IsBool() && value.IsFalse()) {
m_enabled = false;
else if (value.IsBool()) {
m_enabled = value.GetBool();
generate();
}
else {
generate();
@@ -165,52 +150,40 @@ void xmrig::CpuConfig::read(const rapidjson::Value &value, uint32_t version)
void xmrig::CpuConfig::generate()
{
m_shouldSave = true;
ICpuInfo *cpu = Cpu::info();
if (!isEnabled() || m_threads.has("*")) {
return;
}
m_threads.disable(Algorithm::CN_0);
m_threads.move(kCn, cpu->threads(Algorithm::CN_0, m_limit));
size_t count = 0;
# ifdef XMRIG_ALGO_CN_GPU
m_threads.move(kCnGPU, cpu->threads(Algorithm::CN_GPU, m_limit));
# endif
count += xmrig::generate<Algorithm::CN>(m_threads, m_limit);
count += xmrig::generate<Algorithm::CN_LITE>(m_threads, m_limit);
count += xmrig::generate<Algorithm::CN_HEAVY>(m_threads, m_limit);
count += xmrig::generate<Algorithm::CN_PICO>(m_threads, m_limit);
count += xmrig::generate<Algorithm::RANDOM_X>(m_threads, m_limit);
count += xmrig::generate<Algorithm::ARGON2>(m_threads, m_limit);
# ifdef XMRIG_ALGO_CN_LITE
m_threads.disable(Algorithm::CN_LITE_0);
m_threads.move(kCnLite, cpu->threads(Algorithm::CN_LITE_1, m_limit));
# endif
# ifdef XMRIG_ALGO_CN_HEAVY
m_threads.move(kCnHeavy, cpu->threads(Algorithm::CN_HEAVY_0, m_limit));
# endif
# ifdef XMRIG_ALGO_CN_PICO
m_threads.move(kCnPico, cpu->threads(Algorithm::CN_PICO_0, m_limit));
# endif
# ifdef XMRIG_ALGO_RANDOMX
m_threads.move(kRx, cpu->threads(Algorithm::RX_0, m_limit));
m_threads.move(kRxWOW, cpu->threads(Algorithm::RX_WOW, m_limit));
# endif
generateArgon2();
m_shouldSave = count > 0;
}
void xmrig::CpuConfig::generateArgon2()
void xmrig::CpuConfig::setAesMode(const rapidjson::Value &value)
{
# ifdef XMRIG_ALGO_ARGON2
m_threads.move(kArgon2, Cpu::info()->threads(Algorithm::AR2_CHUKWA, m_limit));
# endif
}
void xmrig::CpuConfig::setAesMode(const rapidjson::Value &aesMode)
{
if (aesMode.IsBool()) {
m_aes = aesMode.GetBool() ? AES_HW : AES_SOFT;
if (value.IsBool()) {
m_aes = value.GetBool() ? AES_HW : AES_SOFT;
}
else {
m_aes = AES_AUTO;
}
}
void xmrig::CpuConfig::setMemoryPool(const rapidjson::Value &value)
{
if (value.IsBool()) {
m_memoryPool = value.GetBool() ? -1 : 0;
}
else if (value.IsInt()) {
m_memoryPool = value.GetInt();
}
}

View File

@@ -48,8 +48,9 @@ public:
bool isHwAES() const;
rapidjson::Value toJSON(rapidjson::Document &doc) const;
size_t memPoolSize() const;
std::vector<CpuLaunchData> get(const Miner *miner, const Algorithm &algorithm) const;
void read(const rapidjson::Value &value, uint32_t version);
void read(const rapidjson::Value &value);
inline bool isEnabled() const { return m_enabled; }
inline bool isHugePages() const { return m_hugePages; }
@@ -61,8 +62,8 @@ public:
private:
void generate();
void generateArgon2();
void setAesMode(const rapidjson::Value &aesMode);
void setAesMode(const rapidjson::Value &value);
void setMemoryPool(const rapidjson::Value &value);
inline void setPriority(int priority) { m_priority = (priority >= -1 && priority <= 5) ? priority : -1; }
@@ -71,6 +72,7 @@ private:
bool m_enabled = true;
bool m_hugePages = true;
bool m_shouldSave = false;
int m_memoryPool = 0;
int m_priority = -1;
String m_argon2Impl;
Threads<CpuThreads> m_threads;

View File

@@ -0,0 +1,149 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_CPUCONFIG_GEN_H
#define XMRIG_CPUCONFIG_GEN_H
#include "backend/common/Threads.h"
#include "backend/cpu/Cpu.h"
#include "backend/cpu/CpuThreads.h"
namespace xmrig {
static inline size_t generate(const char *key, Threads<CpuThreads> &threads, const Algorithm &algorithm, uint32_t limit)
{
if (threads.isExist(algorithm) || threads.has(key)) {
return 0;
}
return threads.move(key, Cpu::info()->threads(algorithm, limit));
}
template<Algorithm::Family FAMILY>
static inline size_t generate(Threads<CpuThreads> &, uint32_t) { return 0; }
template<>
size_t inline generate<Algorithm::CN>(Threads<CpuThreads> &threads, uint32_t limit)
{
size_t count = 0;
count += generate("cn", threads, Algorithm::CN_0, limit);
if (!threads.isExist(Algorithm::CN_0)) {
threads.disable(Algorithm::CN_0);
++count;
}
# ifdef XMRIG_ALGO_CN_GPU
count += generate("cn/gpu", threads, Algorithm::CN_GPU, limit);
# endif
return count;
}
#ifdef XMRIG_ALGO_CN_LITE
template<>
size_t inline generate<Algorithm::CN_LITE>(Threads<CpuThreads> &threads, uint32_t limit)
{
size_t count = 0;
count += generate("cn-lite", threads, Algorithm::CN_LITE_1, limit);
if (!threads.isExist(Algorithm::CN_LITE_0)) {
threads.disable(Algorithm::CN_LITE_0);
++count;
}
return count;
}
#endif
#ifdef XMRIG_ALGO_CN_HEAVY
template<>
size_t inline generate<Algorithm::CN_HEAVY>(Threads<CpuThreads> &threads, uint32_t limit)
{
return generate("cn-heavy", threads, Algorithm::CN_HEAVY_0, limit);
}
#endif
#ifdef XMRIG_ALGO_CN_PICO
template<>
size_t inline generate<Algorithm::CN_PICO>(Threads<CpuThreads> &threads, uint32_t limit)
{
return generate("cn-pico", threads, Algorithm::CN_PICO_0, limit);
}
#endif
#ifdef XMRIG_ALGO_RANDOMX
template<>
size_t inline generate<Algorithm::RANDOM_X>(Threads<CpuThreads> &threads, uint32_t limit)
{
size_t count = 0;
auto wow = Cpu::info()->threads(Algorithm::RX_WOW, limit);
if (!threads.isExist(Algorithm::RX_ARQ)) {
auto arq = Cpu::info()->threads(Algorithm::RX_ARQ, limit);
if (arq == wow) {
threads.setAlias(Algorithm::RX_ARQ, "rx/wow");
++count;
}
else {
count += threads.move("rx/arq", std::move(arq));
}
}
if (!threads.isExist(Algorithm::RX_WOW)) {
count += threads.move("rx/wow", std::move(wow));
}
count += generate("rx", threads, Algorithm::RX_0, limit);
return count;
}
#endif
#ifdef XMRIG_ALGO_ARGON2
template<>
size_t inline generate<Algorithm::ARGON2>(Threads<CpuThreads> &threads, uint32_t limit)
{
return generate("argon2", threads, Algorithm::AR2_CHUKWA, limit);
}
#endif
} /* namespace xmrig */
#endif /* XMRIG_CPUCONFIG_GEN_H */

View File

@@ -120,6 +120,16 @@ xmrig::CpuThreads::CpuThreads(size_t count, uint32_t intensity)
}
bool xmrig::CpuThreads::isEqual(const CpuThreads &other) const
{
if (isEmpty() && other.isEmpty()) {
return true;
}
return count() == other.count() && std::equal(m_data.begin(), m_data.end(), other.m_data.begin());
}
rapidjson::Value xmrig::CpuThreads::toJSON(rapidjson::Document &doc) const
{
using namespace rapidjson;

View File

@@ -38,7 +38,7 @@ namespace xmrig {
class CpuThreads
{
public:
inline CpuThreads() {}
inline CpuThreads() = default;
inline CpuThreads(size_t count) : m_data(count) {}
CpuThreads(const rapidjson::Value &value);
@@ -51,6 +51,10 @@ public:
inline void add(int64_t affinity, uint32_t intensity) { add(CpuThread(affinity, intensity)); }
inline void reserve(size_t capacity) { m_data.reserve(capacity); }
inline bool operator!=(const CpuThreads &other) const { return !isEqual(other); }
inline bool operator==(const CpuThreads &other) const { return isEqual(other); }
bool isEqual(const CpuThreads &other) const;
rapidjson::Value toJSON(rapidjson::Document &doc) const;
private:

View File

@@ -62,19 +62,19 @@ xmrig::CpuWorker<N>::CpuWorker(size_t id, const CpuLaunchData &data) :
m_miner(data.miner),
m_ctx()
{
m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages);
m_memory = new VirtualMemory(m_algorithm.l3() * N, data.hugePages, true, m_node);
}
template<size_t N>
xmrig::CpuWorker<N>::~CpuWorker()
{
CnCtx::release(m_ctx, N);
delete m_memory;
# ifdef XMRIG_ALGO_RANDOMX
delete m_vm;
# endif
CnCtx::release(m_ctx, N);
delete m_memory;
}

View File

@@ -2,6 +2,7 @@ set(HEADERS_BACKEND_CPU
src/backend/cpu/Cpu.h
src/backend/cpu/CpuBackend.h
src/backend/cpu/CpuConfig.h
src/backend/cpu/CpuConfig_gen.h
src/backend/cpu/CpuLaunchData.cpp
src/backend/cpu/CpuThread.h
src/backend/cpu/CpuThreads.h

View File

@@ -46,7 +46,6 @@
namespace xmrig {
std::vector<uint32_t> HwlocCpuInfo::m_nodeIndexes;
uint32_t HwlocCpuInfo::m_features = 0;
@@ -177,7 +176,7 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo()
m_threads = countByType(m_topology, HWLOC_OBJ_PU);
m_cores = countByType(m_topology, HWLOC_OBJ_CORE);
m_nodes = std::max<size_t>(countByType(m_topology, HWLOC_OBJ_NUMANODE), 1);
m_nodes = std::max(hwloc_bitmap_weight(hwloc_topology_get_complete_nodeset(m_topology)), 1);
m_packages = countByType(m_topology, HWLOC_OBJ_PACKAGE);
if (m_nodes > 1) {
@@ -185,11 +184,11 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo()
m_features |= SET_THISTHREAD_MEMBIND;
}
m_nodeIndexes.reserve(m_nodes);
m_nodeset.reserve(m_nodes);
hwloc_obj_t node = nullptr;
while ((node = hwloc_get_next_obj_by_type(m_topology, HWLOC_OBJ_NUMANODE, node)) != nullptr) {
m_nodeIndexes.emplace_back(node->os_index);
m_nodeset.emplace_back(node->os_index);
}
}
}
@@ -201,6 +200,20 @@ xmrig::HwlocCpuInfo::~HwlocCpuInfo()
}
bool xmrig::HwlocCpuInfo::membind(hwloc_const_bitmap_t nodeset)
{
if (!hwloc_topology_get_support(m_topology)->membind->set_thisthread_membind) {
return false;
}
# if HWLOC_API_VERSION >= 0x20000
return hwloc_set_membind(m_topology, nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD | HWLOC_MEMBIND_BYNODESET) >= 0;
# else
return hwloc_set_membind_nodeset(m_topology, nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD) >= 0;
# endif
}
xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
{
if (L2() == 0 && L3() == 0) {

View File

@@ -30,8 +30,9 @@
#include "base/tools/Object.h"
using hwloc_obj_t = struct hwloc_obj *;
using hwloc_topology_t = struct hwloc_topology *;
using hwloc_const_bitmap_t = const struct hwloc_bitmap_s *;
using hwloc_obj_t = struct hwloc_obj *;
using hwloc_topology_t = struct hwloc_topology *;
namespace xmrig {
@@ -52,7 +53,11 @@ public:
~HwlocCpuInfo() override;
static inline bool has(Feature feature) { return m_features & feature; }
static inline const std::vector<uint32_t> &nodeIndexes() { return m_nodeIndexes; }
inline const std::vector<uint32_t> &nodeset() const { return m_nodeset; }
inline hwloc_topology_t topology() const { return m_topology; }
bool membind(hwloc_const_bitmap_t nodeset);
protected:
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
@@ -67,7 +72,7 @@ protected:
private:
void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const;
static std::vector<uint32_t> m_nodeIndexes;
static uint32_t m_features;
char m_backend[20] = { 0 };
@@ -76,6 +81,7 @@ private:
size_t m_cores = 0;
size_t m_nodes = 0;
size_t m_packages = 0;
std::vector<uint32_t> m_nodeset;
};

View File

@@ -35,6 +35,7 @@
#include "backend/opencl/OclConfig.h"
#include "backend/opencl/OclLaunchData.h"
#include "backend/opencl/OclWorker.h"
#include "backend/opencl/runners/tools/OclSharedState.h"
#include "backend/opencl/wrappers/OclContext.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "base/io/log/Log.h"
@@ -164,7 +165,7 @@ public:
}
inline void start()
inline void start(const Job &job)
{
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,
@@ -194,6 +195,8 @@ public:
i++;
}
OclSharedState::start(threads, job);
status.start(threads.size());
workers.start(threads);
}
@@ -329,7 +332,7 @@ void xmrig::OclBackend::setJob(const Job &job)
return stop();
}
if (!d_ptr->context.init(d_ptr->devices, threads, job)) {
if (!d_ptr->context.init(d_ptr->devices, threads)) {
LOG_WARN("%s " RED_BOLD("disabled") YELLOW(" (OpenCL context unavailable)"), tag);
return stop();
@@ -338,7 +341,7 @@ void xmrig::OclBackend::setJob(const Job &job)
stop();
d_ptr->threads = std::move(threads);
d_ptr->start();
d_ptr->start(job);
}
@@ -371,6 +374,8 @@ void xmrig::OclBackend::stop()
d_ptr->workers.stop();
d_ptr->threads.clear();
OclSharedState::release();
LOG_INFO("%s" YELLOW(" stopped") BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts);
}

View File

@@ -24,21 +24,18 @@
#include "backend/opencl/OclConfig.h"
#include "backend/opencl/OclConfig_gen.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "base/io/json/Json.h"
#include "base/io/log/Log.h"
#include "rapidjson/document.h"
#include <algorithm>
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 *kDevicesHint = "devices-hint";
static const char *kEnabled = "enabled";
static const char *kINTEL = "INTEL";
@@ -47,69 +44,9 @@ 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<OclThreads>;
static size_t generate(const char *key, Threads<OclThreads> &threads, const Algorithm &algorithm, const std::vector<OclDevice> &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;
}
static inline std::vector<OclDevice> filterDevices(const std::vector<OclDevice> &devices, const std::vector<uint32_t> &hints)
{
std::vector<OclDevice> out;
out.reserve(std::min(devices.size(), hints.size()));
for (const auto &device : devices) {
auto it = std::find(hints.begin(), hints.end(), device.index());
if (it != hints.end()) {
out.emplace_back(device);
}
}
return out;
}
}
@@ -193,32 +130,13 @@ std::vector<xmrig::OclLaunchData> xmrig::OclConfig::get(const Miner *miner, cons
continue;
}
# ifdef XMRIG_ALGO_RANDOMX
auto dataset = algorithm.family() == Algorithm::RANDOM_X ? std::make_shared<OclRxDataset>() : nullptr;
# endif
if (thread.threads().size() > 1) {
auto interleave = std::make_shared<OclInterleave>(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));
out.emplace_back(miner, algorithm, *this, platform, thread, devices[thread.index()], affinity);
}
}
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));
out.emplace_back(miner, algorithm, *this, platform, thread, devices[thread.index()], thread.threads().front());
}
}
@@ -270,39 +188,11 @@ void xmrig::OclConfig::generate()
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
count += xmrig::generate<Algorithm::CN>(m_threads, devices);
count += xmrig::generate<Algorithm::CN_LITE>(m_threads, devices);
count += xmrig::generate<Algorithm::CN_HEAVY>(m_threads, devices);
count += xmrig::generate<Algorithm::CN_PICO>(m_threads, devices);
count += xmrig::generate<Algorithm::RANDOM_X>(m_threads, devices);
m_shouldSave = count > 0;
}

View File

@@ -0,0 +1,152 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_OCLCONFIG_GEN_H
#define XMRIG_OCLCONFIG_GEN_H
#include "backend/common/Threads.h"
#include "backend/opencl/OclThreads.h"
#include <algorithm>
namespace xmrig {
static inline size_t generate(const char *key, Threads<OclThreads> &threads, const Algorithm &algorithm, const std::vector<OclDevice> &devices)
{
if (threads.isExist(algorithm) || threads.has(key)) {
return 0;
}
return threads.move(key, OclThreads(devices, algorithm));
}
template<Algorithm::Family FAMILY>
static inline size_t generate(Threads<OclThreads> &, const std::vector<OclDevice> &) { return 0; }
template<>
size_t inline generate<Algorithm::CN>(Threads<OclThreads> &threads, const std::vector<OclDevice> &devices)
{
size_t count = 0;
count += generate("cn", threads, Algorithm::CN_0, devices);
count += generate("cn/2", threads, Algorithm::CN_2, devices);
if (!threads.isExist(Algorithm::CN_0)) {
threads.disable(Algorithm::CN_0);
count++;
}
# ifdef XMRIG_ALGO_CN_GPU
count += generate("cn/gpu", threads, Algorithm::CN_GPU, devices);
# endif
return count;
}
#ifdef XMRIG_ALGO_CN_LITE
template<>
size_t inline generate<Algorithm::CN_LITE>(Threads<OclThreads> &threads, const std::vector<OclDevice> &devices)
{
size_t count = generate("cn-lite", threads, Algorithm::CN_LITE_1, devices);
if (!threads.isExist(Algorithm::CN_LITE_0)) {
threads.disable(Algorithm::CN_LITE_0);
++count;
}
return count;
}
#endif
#ifdef XMRIG_ALGO_CN_HEAVY
template<>
size_t inline generate<Algorithm::CN_HEAVY>(Threads<OclThreads> &threads, const std::vector<OclDevice> &devices)
{
return generate("cn-heavy", threads, Algorithm::CN_HEAVY_0, devices);
}
#endif
#ifdef XMRIG_ALGO_CN_PICO
template<>
size_t inline generate<Algorithm::CN_PICO>(Threads<OclThreads> &threads, const std::vector<OclDevice> &devices)
{
return generate("cn-pico", threads, Algorithm::CN_PICO_0, devices);
}
#endif
#ifdef XMRIG_ALGO_RANDOMX
template<>
size_t inline generate<Algorithm::RANDOM_X>(Threads<OclThreads> &threads, const std::vector<OclDevice> &devices)
{
size_t count = 0;
auto rx = OclThreads(devices, Algorithm::RX_0);
auto wow = OclThreads(devices, Algorithm::RX_WOW);
auto arq = OclThreads(devices, Algorithm::RX_ARQ);
if (!threads.isExist(Algorithm::RX_WOW) && wow != rx) {
count += threads.move("rx/wow", std::move(wow));
}
if (!threads.isExist(Algorithm::RX_ARQ) && arq != rx) {
count += threads.move("rx/arq", std::move(arq));
}
count += threads.move("rx", std::move(rx));
return count;
}
#endif
static inline std::vector<OclDevice> filterDevices(const std::vector<OclDevice> &devices, const std::vector<uint32_t> &hints)
{
std::vector<OclDevice> out;
out.reserve(std::min(devices.size(), hints.size()));
for (const auto &device : devices) {
auto it = std::find(hints.begin(), hints.end(), device.index());
if (it != hints.end()) {
out.emplace_back(device);
}
}
return out;
}
} /* namespace xmrig */
#endif /* XMRIG_OCLCONFIG_GEN_H */

View File

@@ -27,19 +27,14 @@
#define XMRIG_OCLLAUNCHDATA_H
#include "backend/opencl/OclInterleave.h"
#include "backend/opencl/OclThread.h"
#include "backend/opencl/runners/tools/OclSharedData.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 *;
@@ -72,11 +67,6 @@ public:
const OclDevice device;
const OclPlatform platform;
const OclThread thread;
OclInterleavePtr interleave;
# ifdef XMRIG_ALGO_RANDOMX
OclRxDatasetPtr dataset;
# endif
};

View File

@@ -44,6 +44,24 @@ xmrig::OclThreads::OclThreads(const rapidjson::Value &value)
}
xmrig::OclThreads::OclThreads(const std::vector<OclDevice> &devices, const Algorithm &algorithm)
{
for (const OclDevice &device : devices) {
device.generate(algorithm, *this);
}
}
bool xmrig::OclThreads::isEqual(const OclThreads &other) const
{
if (isEmpty() && other.isEmpty()) {
return true;
}
return count() == other.count() && std::equal(m_data.begin(), m_data.end(), other.m_data.begin());
}
rapidjson::Value xmrig::OclThreads::toJSON(rapidjson::Document &doc) const
{
using namespace rapidjson;

View File

@@ -30,6 +30,7 @@
#include "backend/opencl/OclThread.h"
#include "backend/opencl/wrappers/OclDevice.h"
namespace xmrig {
@@ -40,6 +41,7 @@ class OclThreads
public:
OclThreads() = default;
OclThreads(const rapidjson::Value &value);
OclThreads(const std::vector<OclDevice> &devices, const Algorithm &algorithm);
inline bool isEmpty() const { return m_data.empty(); }
inline const std::vector<OclThread> &data() const { return m_data; }
@@ -47,6 +49,10 @@ public:
inline void add(OclThread &&thread) { m_data.push_back(thread); }
inline void reserve(size_t capacity) { m_data.reserve(capacity); }
inline bool operator!=(const OclThreads &other) const { return !isEqual(other); }
inline bool operator==(const OclThreads &other) const { return isEqual(other); }
bool isEqual(const OclThreads &other) const;
rapidjson::Value toJSON(rapidjson::Document &doc) const;
private:

View File

@@ -28,6 +28,8 @@
#include "backend/common/Tags.h"
#include "backend/opencl/runners/OclCnRunner.h"
#include "backend/opencl/runners/tools/OclSharedData.h"
#include "backend/opencl/runners/tools/OclSharedState.h"
#include "base/io/log/Log.h"
#include "base/tools/Chrono.h"
#include "core/Miner.h"
@@ -75,7 +77,7 @@ xmrig::OclWorker::OclWorker(size_t id, const OclLaunchData &data) :
m_algorithm(data.algorithm),
m_miner(data.miner),
m_intensity(data.thread.intensity()),
m_interleave(data.interleave)
m_sharedData(OclSharedState::get(data.device.index()))
{
switch (m_algorithm.family()) {
case Algorithm::RANDOM_X:
@@ -149,9 +151,7 @@ void xmrig::OclWorker::start()
while (Nonce::sequence(Nonce::OPENCL) > 0) {
if (!isReady()) {
if (m_interleave) {
m_interleave->setResumeCounter(0);
}
m_sharedData.setResumeCounter(0);
do {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
@@ -162,9 +162,7 @@ void xmrig::OclWorker::start()
break;
}
if (m_interleave) {
m_interleave->resumeDelay(m_id);
}
m_sharedData.resumeDelay(m_id);
if (!consumeJob()) {
return;
@@ -172,9 +170,7 @@ void xmrig::OclWorker::start()
}
while (!Nonce::isOutdated(Nonce::OPENCL, m_job.sequence())) {
if (m_interleave) {
m_interleave->adjustDelay(m_id);
}
m_sharedData.adjustDelay(m_id);
const uint64_t t = Chrono::steadyMSecs();
@@ -233,9 +229,7 @@ void xmrig::OclWorker::storeStats(uint64_t t)
m_count += m_intensity;
if (m_interleave) {
m_interleave->setRunTime(Chrono::steadyMSecs() - t);
}
m_sharedData.setRunTime(Chrono::steadyMSecs() - t);
Worker::storeStats();
}

View File

@@ -67,7 +67,7 @@ private:
const Miner *m_miner;
const uint32_t m_intensity;
IOclRunner *m_runner = nullptr;
OclInterleavePtr m_interleave;
OclSharedData &m_sharedData;
WorkerJob<1> m_job;
};

View File

@@ -19,8 +19,9 @@
#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 ALGO_RX_ARQMA 21
#define ALGO_AR2_CHUKWA 22
#define ALGO_AR2_WRKZ 23
#define FAMILY_UNKNOWN 0
#define FAMILY_CN 1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,358 +2,379 @@
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,
static char cryptonight_r_defines_cl[8353] = {
0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0d,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,
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,0x0d,
0x23,0x65,0x6c,0x73,0x65,0x0d,0x23,0x69,0x66,0x20,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x20,0x3d,0x3d,0x20,0x30,0x29,0x0d,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,
0x29,0x0d,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,0x0d,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,
0x20,0x28,0x4e,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x2c,0x20,0x54,0x68,0x72,0x65,0x61,0x64,0x73,0x29,0x29,0x29,0x0d,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,0x0d,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,
0x45,0x4d,0x5f,0x43,0x48,0x55,0x4e,0x4b,0x20,0x3c,0x3c,0x20,0x34,0x29,0x29,0x29,0x29,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,
0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x52,0x4f,0x54,0x5f,0x42,0x49,0x54,0x53,0x20,0x33,0x32,0x0d,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,0x0d,
0x23,0x69,0x66,0x6e,0x64,0x65,0x66,0x20,0x57,0x4f,0x4c,0x46,0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0d,0x23,0x64,0x65,0x66,0x69,0x6e,0x65,0x20,0x57,0x4f,0x4c,0x46,
0x5f,0x41,0x45,0x53,0x5f,0x43,0x4c,0x0d,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x63,0x6c,0x5f,0x61,0x6d,0x64,0x5f,0x6d,0x65,0x64,0x69,0x61,0x5f,0x6f,0x70,0x73,0x32,
0x0d,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,0x0d,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,
0x5f,0x62,0x66,0x65,0x28,0x73,0x72,0x63,0x30,0x2c,0x20,0x73,0x72,0x63,0x31,0x2c,0x20,0x73,0x72,0x63,0x32,0x29,0x0d,0x23,0x65,0x6c,0x73,0x65,0x0d,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
0x20,0x73,0x72,0x63,0x30,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,
0x75,0x69,0x6e,0x74,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x0d,0x7b,0x0d,0x69,0x66,0x20,0x28,0x28,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2b,0x20,0x77,0x69,0x64,0x74,
0x68,0x29,0x20,0x3c,0x20,0x33,0x32,0x75,0x29,0x20,0x7b,0x0d,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x28,0x73,0x72,0x63,0x30,0x20,0x3c,0x3c,0x20,0x28,0x33,0x32,0x75,
0x20,0x2d,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x20,0x2d,0x20,0x77,0x69,0x64,0x74,0x68,0x29,0x29,0x20,0x3e,0x3e,0x20,0x28,0x33,0x32,0x75,0x20,0x2d,0x20,0x77,0x69,
0x64,0x74,0x68,0x29,0x3b,0x0d,0x7d,0x0d,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x73,0x72,0x63,0x30,0x20,0x3e,0x3e,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x3b,0x0d,0x7d,
0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,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,0x0d,0x7b,0x0d,0x30,0x78,0x41,0x35,0x36,0x33,0x36,0x33,0x43,0x36,0x55,
0x2c,0x20,0x30,0x78,0x38,0x34,0x37,0x43,0x37,0x43,0x46,0x38,0x55,0x2c,0x20,0x30,0x78,0x39,0x39,0x37,0x37,0x37,0x37,0x45,0x45,0x55,0x2c,0x20,0x30,0x78,0x38,0x44,
0x37,0x42,0x37,0x42,0x46,0x36,0x55,0x2c,0x0d,0x30,0x78,0x30,0x44,0x46,0x32,0x46,0x32,0x46,0x46,0x55,0x2c,0x20,0x30,0x78,0x42,0x44,0x36,0x42,0x36,0x42,0x44,0x36,
0x55,0x2c,0x20,0x30,0x78,0x42,0x31,0x36,0x46,0x36,0x46,0x44,0x45,0x55,0x2c,0x20,0x30,0x78,0x35,0x34,0x43,0x35,0x43,0x35,0x39,0x31,0x55,0x2c,0x0d,0x30,0x78,0x35,
0x30,0x33,0x30,0x33,0x30,0x36,0x30,0x55,0x2c,0x20,0x30,0x78,0x30,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x55,0x2c,0x20,0x30,0x78,0x41,0x39,0x36,0x37,0x36,0x37,0x43,
0x45,0x55,0x2c,0x20,0x30,0x78,0x37,0x44,0x32,0x42,0x32,0x42,0x35,0x36,0x55,0x2c,0x0d,0x30,0x78,0x31,0x39,0x46,0x45,0x46,0x45,0x45,0x37,0x55,0x2c,0x20,0x30,0x78,
0x36,0x32,0x44,0x37,0x44,0x37,0x42,0x35,0x55,0x2c,0x20,0x30,0x78,0x45,0x36,0x41,0x42,0x41,0x42,0x34,0x44,0x55,0x2c,0x20,0x30,0x78,0x39,0x41,0x37,0x36,0x37,0x36,
0x45,0x43,0x55,0x2c,0x0d,0x30,0x78,0x34,0x35,0x43,0x41,0x43,0x41,0x38,0x46,0x55,0x2c,0x20,0x30,0x78,0x39,0x44,0x38,0x32,0x38,0x32,0x31,0x46,0x55,0x2c,0x20,0x30,
0x78,0x34,0x30,0x43,0x39,0x43,0x39,0x38,0x39,0x55,0x2c,0x20,0x30,0x78,0x38,0x37,0x37,0x44,0x37,0x44,0x46,0x41,0x55,0x2c,0x0d,0x30,0x78,0x31,0x35,0x46,0x41,0x46,
0x41,0x45,0x46,0x55,0x2c,0x20,0x30,0x78,0x45,0x42,0x35,0x39,0x35,0x39,0x42,0x32,0x55,0x2c,0x20,0x30,0x78,0x43,0x39,0x34,0x37,0x34,0x37,0x38,0x45,0x55,0x2c,0x20,
0x30,0x78,0x30,0x42,0x46,0x30,0x46,0x30,0x46,0x42,0x55,0x2c,0x0d,0x30,0x78,0x45,0x43,0x41,0x44,0x41,0x44,0x34,0x31,0x55,0x2c,0x20,0x30,0x78,0x36,0x37,0x44,0x34,
0x44,0x34,0x42,0x33,0x55,0x2c,0x20,0x30,0x78,0x46,0x44,0x41,0x32,0x41,0x32,0x35,0x46,0x55,0x2c,0x20,0x30,0x78,0x45,0x41,0x41,0x46,0x41,0x46,0x34,0x35,0x55,0x2c,
0x0d,0x30,0x78,0x42,0x46,0x39,0x43,0x39,0x43,0x32,0x33,0x55,0x2c,0x20,0x30,0x78,0x46,0x37,0x41,0x34,0x41,0x34,0x35,0x33,0x55,0x2c,0x20,0x30,0x78,0x39,0x36,0x37,
0x32,0x37,0x32,0x45,0x34,0x55,0x2c,0x20,0x30,0x78,0x35,0x42,0x43,0x30,0x43,0x30,0x39,0x42,0x55,0x2c,0x0d,0x30,0x78,0x43,0x32,0x42,0x37,0x42,0x37,0x37,0x35,0x55,
0x2c,0x20,0x30,0x78,0x31,0x43,0x46,0x44,0x46,0x44,0x45,0x31,0x55,0x2c,0x20,0x30,0x78,0x41,0x45,0x39,0x33,0x39,0x33,0x33,0x44,0x55,0x2c,0x20,0x30,0x78,0x36,0x41,
0x32,0x36,0x32,0x36,0x34,0x43,0x55,0x2c,0x0d,0x30,0x78,0x35,0x41,0x33,0x36,0x33,0x36,0x36,0x43,0x55,0x2c,0x20,0x30,0x78,0x34,0x31,0x33,0x46,0x33,0x46,0x37,0x45,
0x55,0x2c,0x20,0x30,0x78,0x30,0x32,0x46,0x37,0x46,0x37,0x46,0x35,0x55,0x2c,0x20,0x30,0x78,0x34,0x46,0x43,0x43,0x43,0x43,0x38,0x33,0x55,0x2c,0x0d,0x30,0x78,0x35,
0x43,0x33,0x34,0x33,0x34,0x36,0x38,0x55,0x2c,0x20,0x30,0x78,0x46,0x34,0x41,0x35,0x41,0x35,0x35,0x31,0x55,0x2c,0x20,0x30,0x78,0x33,0x34,0x45,0x35,0x45,0x35,0x44,
0x31,0x55,0x2c,0x20,0x30,0x78,0x30,0x38,0x46,0x31,0x46,0x31,0x46,0x39,0x55,0x2c,0x0d,0x30,0x78,0x39,0x33,0x37,0x31,0x37,0x31,0x45,0x32,0x55,0x2c,0x20,0x30,0x78,
0x37,0x33,0x44,0x38,0x44,0x38,0x41,0x42,0x55,0x2c,0x20,0x30,0x78,0x35,0x33,0x33,0x31,0x33,0x31,0x36,0x32,0x55,0x2c,0x20,0x30,0x78,0x33,0x46,0x31,0x35,0x31,0x35,
0x32,0x41,0x55,0x2c,0x0d,0x30,0x78,0x30,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x55,0x2c,0x20,0x30,0x78,0x35,0x32,0x43,0x37,0x43,0x37,0x39,0x35,0x55,0x2c,0x20,0x30,
0x78,0x36,0x35,0x32,0x33,0x32,0x33,0x34,0x36,0x55,0x2c,0x20,0x30,0x78,0x35,0x45,0x43,0x33,0x43,0x33,0x39,0x44,0x55,0x2c,0x0d,0x30,0x78,0x32,0x38,0x31,0x38,0x31,
0x38,0x33,0x30,0x55,0x2c,0x20,0x30,0x78,0x41,0x31,0x39,0x36,0x39,0x36,0x33,0x37,0x55,0x2c,0x20,0x30,0x78,0x30,0x46,0x30,0x35,0x30,0x35,0x30,0x41,0x55,0x2c,0x20,
0x30,0x78,0x42,0x35,0x39,0x41,0x39,0x41,0x32,0x46,0x55,0x2c,0x0d,0x30,0x78,0x30,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x55,0x2c,0x20,0x30,0x78,0x33,0x36,0x31,0x32,
0x31,0x32,0x32,0x34,0x55,0x2c,0x20,0x30,0x78,0x39,0x42,0x38,0x30,0x38,0x30,0x31,0x42,0x55,0x2c,0x20,0x30,0x78,0x33,0x44,0x45,0x32,0x45,0x32,0x44,0x46,0x55,0x2c,
0x0d,0x30,0x78,0x32,0x36,0x45,0x42,0x45,0x42,0x43,0x44,0x55,0x2c,0x20,0x30,0x78,0x36,0x39,0x32,0x37,0x32,0x37,0x34,0x45,0x55,0x2c,0x20,0x30,0x78,0x43,0x44,0x42,
0x32,0x42,0x32,0x37,0x46,0x55,0x2c,0x20,0x30,0x78,0x39,0x46,0x37,0x35,0x37,0x35,0x45,0x41,0x55,0x2c,0x0d,0x30,0x78,0x31,0x42,0x30,0x39,0x30,0x39,0x31,0x32,0x55,
0x2c,0x20,0x30,0x78,0x39,0x45,0x38,0x33,0x38,0x33,0x31,0x44,0x55,0x2c,0x20,0x30,0x78,0x37,0x34,0x32,0x43,0x32,0x43,0x35,0x38,0x55,0x2c,0x20,0x30,0x78,0x32,0x45,
0x31,0x41,0x31,0x41,0x33,0x34,0x55,0x2c,0x0d,0x30,0x78,0x32,0x44,0x31,0x42,0x31,0x42,0x33,0x36,0x55,0x2c,0x20,0x30,0x78,0x42,0x32,0x36,0x45,0x36,0x45,0x44,0x43,
0x55,0x2c,0x20,0x30,0x78,0x45,0x45,0x35,0x41,0x35,0x41,0x42,0x34,0x55,0x2c,0x20,0x30,0x78,0x46,0x42,0x41,0x30,0x41,0x30,0x35,0x42,0x55,0x2c,0x0d,0x30,0x78,0x46,
0x36,0x35,0x32,0x35,0x32,0x41,0x34,0x55,0x2c,0x20,0x30,0x78,0x34,0x44,0x33,0x42,0x33,0x42,0x37,0x36,0x55,0x2c,0x20,0x30,0x78,0x36,0x31,0x44,0x36,0x44,0x36,0x42,
0x37,0x55,0x2c,0x20,0x30,0x78,0x43,0x45,0x42,0x33,0x42,0x33,0x37,0x44,0x55,0x2c,0x0d,0x30,0x78,0x37,0x42,0x32,0x39,0x32,0x39,0x35,0x32,0x55,0x2c,0x20,0x30,0x78,
0x33,0x45,0x45,0x33,0x45,0x33,0x44,0x44,0x55,0x2c,0x20,0x30,0x78,0x37,0x31,0x32,0x46,0x32,0x46,0x35,0x45,0x55,0x2c,0x20,0x30,0x78,0x39,0x37,0x38,0x34,0x38,0x34,
0x31,0x33,0x55,0x2c,0x0d,0x30,0x78,0x46,0x35,0x35,0x33,0x35,0x33,0x41,0x36,0x55,0x2c,0x20,0x30,0x78,0x36,0x38,0x44,0x31,0x44,0x31,0x42,0x39,0x55,0x2c,0x20,0x30,
0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x55,0x2c,0x20,0x30,0x78,0x32,0x43,0x45,0x44,0x45,0x44,0x43,0x31,0x55,0x2c,0x0d,0x30,0x78,0x36,0x30,0x32,0x30,0x32,
0x30,0x34,0x30,0x55,0x2c,0x20,0x30,0x78,0x31,0x46,0x46,0x43,0x46,0x43,0x45,0x33,0x55,0x2c,0x20,0x30,0x78,0x43,0x38,0x42,0x31,0x42,0x31,0x37,0x39,0x55,0x2c,0x20,
0x30,0x78,0x45,0x44,0x35,0x42,0x35,0x42,0x42,0x36,0x55,0x2c,0x0d,0x30,0x78,0x42,0x45,0x36,0x41,0x36,0x41,0x44,0x34,0x55,0x2c,0x20,0x30,0x78,0x34,0x36,0x43,0x42,
0x43,0x42,0x38,0x44,0x55,0x2c,0x20,0x30,0x78,0x44,0x39,0x42,0x45,0x42,0x45,0x36,0x37,0x55,0x2c,0x20,0x30,0x78,0x34,0x42,0x33,0x39,0x33,0x39,0x37,0x32,0x55,0x2c,
0x0d,0x30,0x78,0x44,0x45,0x34,0x41,0x34,0x41,0x39,0x34,0x55,0x2c,0x20,0x30,0x78,0x44,0x34,0x34,0x43,0x34,0x43,0x39,0x38,0x55,0x2c,0x20,0x30,0x78,0x45,0x38,0x35,
0x38,0x35,0x38,0x42,0x30,0x55,0x2c,0x20,0x30,0x78,0x34,0x41,0x43,0x46,0x43,0x46,0x38,0x35,0x55,0x2c,0x0d,0x30,0x78,0x36,0x42,0x44,0x30,0x44,0x30,0x42,0x42,0x55,
0x2c,0x20,0x30,0x78,0x32,0x41,0x45,0x46,0x45,0x46,0x43,0x35,0x55,0x2c,0x20,0x30,0x78,0x45,0x35,0x41,0x41,0x41,0x41,0x34,0x46,0x55,0x2c,0x20,0x30,0x78,0x31,0x36,
0x46,0x42,0x46,0x42,0x45,0x44,0x55,0x2c,0x0d,0x30,0x78,0x43,0x35,0x34,0x33,0x34,0x33,0x38,0x36,0x55,0x2c,0x20,0x30,0x78,0x44,0x37,0x34,0x44,0x34,0x44,0x39,0x41,
0x55,0x2c,0x20,0x30,0x78,0x35,0x35,0x33,0x33,0x33,0x33,0x36,0x36,0x55,0x2c,0x20,0x30,0x78,0x39,0x34,0x38,0x35,0x38,0x35,0x31,0x31,0x55,0x2c,0x0d,0x30,0x78,0x43,
0x46,0x34,0x35,0x34,0x35,0x38,0x41,0x55,0x2c,0x20,0x30,0x78,0x31,0x30,0x46,0x39,0x46,0x39,0x45,0x39,0x55,0x2c,0x20,0x30,0x78,0x30,0x36,0x30,0x32,0x30,0x32,0x30,
0x34,0x55,0x2c,0x20,0x30,0x78,0x38,0x31,0x37,0x46,0x37,0x46,0x46,0x45,0x55,0x2c,0x0d,0x30,0x78,0x46,0x30,0x35,0x30,0x35,0x30,0x41,0x30,0x55,0x2c,0x20,0x30,0x78,
0x34,0x34,0x33,0x43,0x33,0x43,0x37,0x38,0x55,0x2c,0x20,0x30,0x78,0x42,0x41,0x39,0x46,0x39,0x46,0x32,0x35,0x55,0x2c,0x20,0x30,0x78,0x45,0x33,0x41,0x38,0x41,0x38,
0x34,0x42,0x55,0x2c,0x0d,0x30,0x78,0x46,0x33,0x35,0x31,0x35,0x31,0x41,0x32,0x55,0x2c,0x20,0x30,0x78,0x46,0x45,0x41,0x33,0x41,0x33,0x35,0x44,0x55,0x2c,0x20,0x30,
0x78,0x43,0x30,0x34,0x30,0x34,0x30,0x38,0x30,0x55,0x2c,0x20,0x30,0x78,0x38,0x41,0x38,0x46,0x38,0x46,0x30,0x35,0x55,0x2c,0x0d,0x30,0x78,0x41,0x44,0x39,0x32,0x39,
0x32,0x33,0x46,0x55,0x2c,0x20,0x30,0x78,0x42,0x43,0x39,0x44,0x39,0x44,0x32,0x31,0x55,0x2c,0x20,0x30,0x78,0x34,0x38,0x33,0x38,0x33,0x38,0x37,0x30,0x55,0x2c,0x20,
0x30,0x78,0x30,0x34,0x46,0x35,0x46,0x35,0x46,0x31,0x55,0x2c,0x0d,0x30,0x78,0x44,0x46,0x42,0x43,0x42,0x43,0x36,0x33,0x55,0x2c,0x20,0x30,0x78,0x43,0x31,0x42,0x36,
0x42,0x36,0x37,0x37,0x55,0x2c,0x20,0x30,0x78,0x37,0x35,0x44,0x41,0x44,0x41,0x41,0x46,0x55,0x2c,0x20,0x30,0x78,0x36,0x33,0x32,0x31,0x32,0x31,0x34,0x32,0x55,0x2c,
0x0d,0x30,0x78,0x33,0x30,0x31,0x30,0x31,0x30,0x32,0x30,0x55,0x2c,0x20,0x30,0x78,0x31,0x41,0x46,0x46,0x46,0x46,0x45,0x35,0x55,0x2c,0x20,0x30,0x78,0x30,0x45,0x46,
0x33,0x46,0x33,0x46,0x44,0x55,0x2c,0x20,0x30,0x78,0x36,0x44,0x44,0x32,0x44,0x32,0x42,0x46,0x55,0x2c,0x0d,0x30,0x78,0x34,0x43,0x43,0x44,0x43,0x44,0x38,0x31,0x55,
0x2c,0x20,0x30,0x78,0x31,0x34,0x30,0x43,0x30,0x43,0x31,0x38,0x55,0x2c,0x20,0x30,0x78,0x33,0x35,0x31,0x33,0x31,0x33,0x32,0x36,0x55,0x2c,0x20,0x30,0x78,0x32,0x46,
0x45,0x43,0x45,0x43,0x43,0x33,0x55,0x2c,0x0d,0x30,0x78,0x45,0x31,0x35,0x46,0x35,0x46,0x42,0x45,0x55,0x2c,0x20,0x30,0x78,0x41,0x32,0x39,0x37,0x39,0x37,0x33,0x35,
0x55,0x2c,0x20,0x30,0x78,0x43,0x43,0x34,0x34,0x34,0x34,0x38,0x38,0x55,0x2c,0x20,0x30,0x78,0x33,0x39,0x31,0x37,0x31,0x37,0x32,0x45,0x55,0x2c,0x0d,0x30,0x78,0x35,
0x37,0x43,0x34,0x43,0x34,0x39,0x33,0x55,0x2c,0x20,0x30,0x78,0x46,0x32,0x41,0x37,0x41,0x37,0x35,0x35,0x55,0x2c,0x20,0x30,0x78,0x38,0x32,0x37,0x45,0x37,0x45,0x46,
0x43,0x55,0x2c,0x20,0x30,0x78,0x34,0x37,0x33,0x44,0x33,0x44,0x37,0x41,0x55,0x2c,0x0d,0x30,0x78,0x41,0x43,0x36,0x34,0x36,0x34,0x43,0x38,0x55,0x2c,0x20,0x30,0x78,
0x45,0x37,0x35,0x44,0x35,0x44,0x42,0x41,0x55,0x2c,0x20,0x30,0x78,0x32,0x42,0x31,0x39,0x31,0x39,0x33,0x32,0x55,0x2c,0x20,0x30,0x78,0x39,0x35,0x37,0x33,0x37,0x33,
0x45,0x36,0x55,0x2c,0x0d,0x30,0x78,0x41,0x30,0x36,0x30,0x36,0x30,0x43,0x30,0x55,0x2c,0x20,0x30,0x78,0x39,0x38,0x38,0x31,0x38,0x31,0x31,0x39,0x55,0x2c,0x20,0x30,
0x78,0x44,0x31,0x34,0x46,0x34,0x46,0x39,0x45,0x55,0x2c,0x20,0x30,0x78,0x37,0x46,0x44,0x43,0x44,0x43,0x41,0x33,0x55,0x2c,0x0d,0x30,0x78,0x36,0x36,0x32,0x32,0x32,
0x32,0x34,0x34,0x55,0x2c,0x20,0x30,0x78,0x37,0x45,0x32,0x41,0x32,0x41,0x35,0x34,0x55,0x2c,0x20,0x30,0x78,0x41,0x42,0x39,0x30,0x39,0x30,0x33,0x42,0x55,0x2c,0x20,
0x30,0x78,0x38,0x33,0x38,0x38,0x38,0x38,0x30,0x42,0x55,0x2c,0x0d,0x30,0x78,0x43,0x41,0x34,0x36,0x34,0x36,0x38,0x43,0x55,0x2c,0x20,0x30,0x78,0x32,0x39,0x45,0x45,
0x45,0x45,0x43,0x37,0x55,0x2c,0x20,0x30,0x78,0x44,0x33,0x42,0x38,0x42,0x38,0x36,0x42,0x55,0x2c,0x20,0x30,0x78,0x33,0x43,0x31,0x34,0x31,0x34,0x32,0x38,0x55,0x2c,
0x0d,0x30,0x78,0x37,0x39,0x44,0x45,0x44,0x45,0x41,0x37,0x55,0x2c,0x20,0x30,0x78,0x45,0x32,0x35,0x45,0x35,0x45,0x42,0x43,0x55,0x2c,0x20,0x30,0x78,0x31,0x44,0x30,
0x42,0x30,0x42,0x31,0x36,0x55,0x2c,0x20,0x30,0x78,0x37,0x36,0x44,0x42,0x44,0x42,0x41,0x44,0x55,0x2c,0x0d,0x30,0x78,0x33,0x42,0x45,0x30,0x45,0x30,0x44,0x42,0x55,
0x2c,0x20,0x30,0x78,0x35,0x36,0x33,0x32,0x33,0x32,0x36,0x34,0x55,0x2c,0x20,0x30,0x78,0x34,0x45,0x33,0x41,0x33,0x41,0x37,0x34,0x55,0x2c,0x20,0x30,0x78,0x31,0x45,
0x30,0x41,0x30,0x41,0x31,0x34,0x55,0x2c,0x0d,0x30,0x78,0x44,0x42,0x34,0x39,0x34,0x39,0x39,0x32,0x55,0x2c,0x20,0x30,0x78,0x30,0x41,0x30,0x36,0x30,0x36,0x30,0x43,
0x55,0x2c,0x20,0x30,0x78,0x36,0x43,0x32,0x34,0x32,0x34,0x34,0x38,0x55,0x2c,0x20,0x30,0x78,0x45,0x34,0x35,0x43,0x35,0x43,0x42,0x38,0x55,0x2c,0x0d,0x30,0x78,0x35,
0x44,0x43,0x32,0x43,0x32,0x39,0x46,0x55,0x2c,0x20,0x30,0x78,0x36,0x45,0x44,0x33,0x44,0x33,0x42,0x44,0x55,0x2c,0x20,0x30,0x78,0x45,0x46,0x41,0x43,0x41,0x43,0x34,
0x33,0x55,0x2c,0x20,0x30,0x78,0x41,0x36,0x36,0x32,0x36,0x32,0x43,0x34,0x55,0x2c,0x0d,0x30,0x78,0x41,0x38,0x39,0x31,0x39,0x31,0x33,0x39,0x55,0x2c,0x20,0x30,0x78,
0x41,0x34,0x39,0x35,0x39,0x35,0x33,0x31,0x55,0x2c,0x20,0x30,0x78,0x33,0x37,0x45,0x34,0x45,0x34,0x44,0x33,0x55,0x2c,0x20,0x30,0x78,0x38,0x42,0x37,0x39,0x37,0x39,
0x46,0x32,0x55,0x2c,0x0d,0x30,0x78,0x33,0x32,0x45,0x37,0x45,0x37,0x44,0x35,0x55,0x2c,0x20,0x30,0x78,0x34,0x33,0x43,0x38,0x43,0x38,0x38,0x42,0x55,0x2c,0x20,0x30,
0x78,0x35,0x39,0x33,0x37,0x33,0x37,0x36,0x45,0x55,0x2c,0x20,0x30,0x78,0x42,0x37,0x36,0x44,0x36,0x44,0x44,0x41,0x55,0x2c,0x0d,0x30,0x78,0x38,0x43,0x38,0x44,0x38,
0x44,0x30,0x31,0x55,0x2c,0x20,0x30,0x78,0x36,0x34,0x44,0x35,0x44,0x35,0x42,0x31,0x55,0x2c,0x20,0x30,0x78,0x44,0x32,0x34,0x45,0x34,0x45,0x39,0x43,0x55,0x2c,0x20,
0x30,0x78,0x45,0x30,0x41,0x39,0x41,0x39,0x34,0x39,0x55,0x2c,0x0d,0x30,0x78,0x42,0x34,0x36,0x43,0x36,0x43,0x44,0x38,0x55,0x2c,0x20,0x30,0x78,0x46,0x41,0x35,0x36,
0x35,0x36,0x41,0x43,0x55,0x2c,0x20,0x30,0x78,0x30,0x37,0x46,0x34,0x46,0x34,0x46,0x33,0x55,0x2c,0x20,0x30,0x78,0x32,0x35,0x45,0x41,0x45,0x41,0x43,0x46,0x55,0x2c,
0x0d,0x30,0x78,0x41,0x46,0x36,0x35,0x36,0x35,0x43,0x41,0x55,0x2c,0x20,0x30,0x78,0x38,0x45,0x37,0x41,0x37,0x41,0x46,0x34,0x55,0x2c,0x20,0x30,0x78,0x45,0x39,0x41,
0x45,0x41,0x45,0x34,0x37,0x55,0x2c,0x20,0x30,0x78,0x31,0x38,0x30,0x38,0x30,0x38,0x31,0x30,0x55,0x2c,0x0d,0x30,0x78,0x44,0x35,0x42,0x41,0x42,0x41,0x36,0x46,0x55,
0x2c,0x20,0x30,0x78,0x38,0x38,0x37,0x38,0x37,0x38,0x46,0x30,0x55,0x2c,0x20,0x30,0x78,0x36,0x46,0x32,0x35,0x32,0x35,0x34,0x41,0x55,0x2c,0x20,0x30,0x78,0x37,0x32,
0x32,0x45,0x32,0x45,0x35,0x43,0x55,0x2c,0x0d,0x30,0x78,0x32,0x34,0x31,0x43,0x31,0x43,0x33,0x38,0x55,0x2c,0x20,0x30,0x78,0x46,0x31,0x41,0x36,0x41,0x36,0x35,0x37,
0x55,0x2c,0x20,0x30,0x78,0x43,0x37,0x42,0x34,0x42,0x34,0x37,0x33,0x55,0x2c,0x20,0x30,0x78,0x35,0x31,0x43,0x36,0x43,0x36,0x39,0x37,0x55,0x2c,0x0d,0x30,0x78,0x32,
0x33,0x45,0x38,0x45,0x38,0x43,0x42,0x55,0x2c,0x20,0x30,0x78,0x37,0x43,0x44,0x44,0x44,0x44,0x41,0x31,0x55,0x2c,0x20,0x30,0x78,0x39,0x43,0x37,0x34,0x37,0x34,0x45,
0x38,0x55,0x2c,0x20,0x30,0x78,0x32,0x31,0x31,0x46,0x31,0x46,0x33,0x45,0x55,0x2c,0x0d,0x30,0x78,0x44,0x44,0x34,0x42,0x34,0x42,0x39,0x36,0x55,0x2c,0x20,0x30,0x78,
0x44,0x43,0x42,0x44,0x42,0x44,0x36,0x31,0x55,0x2c,0x20,0x30,0x78,0x38,0x36,0x38,0x42,0x38,0x42,0x30,0x44,0x55,0x2c,0x20,0x30,0x78,0x38,0x35,0x38,0x41,0x38,0x41,
0x30,0x46,0x55,0x2c,0x0d,0x30,0x78,0x39,0x30,0x37,0x30,0x37,0x30,0x45,0x30,0x55,0x2c,0x20,0x30,0x78,0x34,0x32,0x33,0x45,0x33,0x45,0x37,0x43,0x55,0x2c,0x20,0x30,
0x78,0x43,0x34,0x42,0x35,0x42,0x35,0x37,0x31,0x55,0x2c,0x20,0x30,0x78,0x41,0x41,0x36,0x36,0x36,0x36,0x43,0x43,0x55,0x2c,0x0d,0x30,0x78,0x44,0x38,0x34,0x38,0x34,
0x38,0x39,0x30,0x55,0x2c,0x20,0x30,0x78,0x30,0x35,0x30,0x33,0x30,0x33,0x30,0x36,0x55,0x2c,0x20,0x30,0x78,0x30,0x31,0x46,0x36,0x46,0x36,0x46,0x37,0x55,0x2c,0x20,
0x30,0x78,0x31,0x32,0x30,0x45,0x30,0x45,0x31,0x43,0x55,0x2c,0x0d,0x30,0x78,0x41,0x33,0x36,0x31,0x36,0x31,0x43,0x32,0x55,0x2c,0x20,0x30,0x78,0x35,0x46,0x33,0x35,
0x33,0x35,0x36,0x41,0x55,0x2c,0x20,0x30,0x78,0x46,0x39,0x35,0x37,0x35,0x37,0x41,0x45,0x55,0x2c,0x20,0x30,0x78,0x44,0x30,0x42,0x39,0x42,0x39,0x36,0x39,0x55,0x2c,
0x0d,0x30,0x78,0x39,0x31,0x38,0x36,0x38,0x36,0x31,0x37,0x55,0x2c,0x20,0x30,0x78,0x35,0x38,0x43,0x31,0x43,0x31,0x39,0x39,0x55,0x2c,0x20,0x30,0x78,0x32,0x37,0x31,
0x44,0x31,0x44,0x33,0x41,0x55,0x2c,0x20,0x30,0x78,0x42,0x39,0x39,0x45,0x39,0x45,0x32,0x37,0x55,0x2c,0x0d,0x30,0x78,0x33,0x38,0x45,0x31,0x45,0x31,0x44,0x39,0x55,
0x2c,0x20,0x30,0x78,0x31,0x33,0x46,0x38,0x46,0x38,0x45,0x42,0x55,0x2c,0x20,0x30,0x78,0x42,0x33,0x39,0x38,0x39,0x38,0x32,0x42,0x55,0x2c,0x20,0x30,0x78,0x33,0x33,
0x31,0x31,0x31,0x31,0x32,0x32,0x55,0x2c,0x0d,0x30,0x78,0x42,0x42,0x36,0x39,0x36,0x39,0x44,0x32,0x55,0x2c,0x20,0x30,0x78,0x37,0x30,0x44,0x39,0x44,0x39,0x41,0x39,
0x55,0x2c,0x20,0x30,0x78,0x38,0x39,0x38,0x45,0x38,0x45,0x30,0x37,0x55,0x2c,0x20,0x30,0x78,0x41,0x37,0x39,0x34,0x39,0x34,0x33,0x33,0x55,0x2c,0x0d,0x30,0x78,0x42,
0x36,0x39,0x42,0x39,0x42,0x32,0x44,0x55,0x2c,0x20,0x30,0x78,0x32,0x32,0x31,0x45,0x31,0x45,0x33,0x43,0x55,0x2c,0x20,0x30,0x78,0x39,0x32,0x38,0x37,0x38,0x37,0x31,
0x35,0x55,0x2c,0x20,0x30,0x78,0x32,0x30,0x45,0x39,0x45,0x39,0x43,0x39,0x55,0x2c,0x0d,0x30,0x78,0x34,0x39,0x43,0x45,0x43,0x45,0x38,0x37,0x55,0x2c,0x20,0x30,0x78,
0x46,0x46,0x35,0x35,0x35,0x35,0x41,0x41,0x55,0x2c,0x20,0x30,0x78,0x37,0x38,0x32,0x38,0x32,0x38,0x35,0x30,0x55,0x2c,0x20,0x30,0x78,0x37,0x41,0x44,0x46,0x44,0x46,
0x41,0x35,0x55,0x2c,0x0d,0x30,0x78,0x38,0x46,0x38,0x43,0x38,0x43,0x30,0x33,0x55,0x2c,0x20,0x30,0x78,0x46,0x38,0x41,0x31,0x41,0x31,0x35,0x39,0x55,0x2c,0x20,0x30,
0x78,0x38,0x30,0x38,0x39,0x38,0x39,0x30,0x39,0x55,0x2c,0x20,0x30,0x78,0x31,0x37,0x30,0x44,0x30,0x44,0x31,0x41,0x55,0x2c,0x0d,0x30,0x78,0x44,0x41,0x42,0x46,0x42,
0x46,0x36,0x35,0x55,0x2c,0x20,0x30,0x78,0x33,0x31,0x45,0x36,0x45,0x36,0x44,0x37,0x55,0x2c,0x20,0x30,0x78,0x43,0x36,0x34,0x32,0x34,0x32,0x38,0x34,0x55,0x2c,0x20,
0x30,0x78,0x42,0x38,0x36,0x38,0x36,0x38,0x44,0x30,0x55,0x2c,0x0d,0x30,0x78,0x43,0x33,0x34,0x31,0x34,0x31,0x38,0x32,0x55,0x2c,0x20,0x30,0x78,0x42,0x30,0x39,0x39,
0x39,0x39,0x32,0x39,0x55,0x2c,0x20,0x30,0x78,0x37,0x37,0x32,0x44,0x32,0x44,0x35,0x41,0x55,0x2c,0x20,0x30,0x78,0x31,0x31,0x30,0x46,0x30,0x46,0x31,0x45,0x55,0x2c,
0x0d,0x30,0x78,0x43,0x42,0x42,0x30,0x42,0x30,0x37,0x42,0x55,0x2c,0x20,0x30,0x78,0x46,0x43,0x35,0x34,0x35,0x34,0x41,0x38,0x55,0x2c,0x20,0x30,0x78,0x44,0x36,0x42,
0x42,0x42,0x42,0x36,0x44,0x55,0x2c,0x20,0x30,0x78,0x33,0x41,0x31,0x36,0x31,0x36,0x32,0x43,0x55,0x0d,0x7d,0x3b,0x0d,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,0x0d,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,0x0d,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,0x20,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,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x78,0x2c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x29,0x0d,0x7b,0x0d,0x78,0x20,0x3d,0x20,0x7e,0x78,0x3b,0x0d,0x6b,
0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,
0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,
0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,0x20,
0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,0x78,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x30,0x3b,0x0d,0x6b,0x2e,0x73,0x31,0x20,0x5e,0x3d,
0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,
0x28,0x78,0x2e,0x73,0x32,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,
0x73,0x33,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x20,0x33,0x29,0x5d,0x2c,0x20,0x31,
0x36,0x55,0x29,0x3b,0x0d,0x78,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x31,0x3b,0x0d,0x6b,0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,
0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x33,0x2c,
0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x20,0x32,0x29,
0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x20,0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,0x78,
0x2e,0x73,0x32,0x20,0x5e,0x3d,0x20,0x6b,0x2e,0x73,0x32,0x3b,0x0d,0x6b,0x2e,0x73,0x33,0x20,0x5e,0x3d,0x20,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,
0x2e,0x73,0x33,0x2c,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x30,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,
0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x31,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,
0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x78,0x2e,0x73,0x32,0x2c,0x20,0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,
0x6b,0x3b,0x0d,0x7d,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,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,0x20,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,0x20,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,0x20,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,0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0d,0x7b,0x0d,
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,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,
0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,0x28,
0x58,0x2e,0x73,0x32,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,0x33,0x29,0x5d,0x3b,
0x0d,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,0x20,0x30,0x29,0x5d,0x20,0x5e,
0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,0x45,
0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x20,0x33,0x29,0x5d,
0x3b,0x0d,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,0x20,0x30,0x29,0x5d,0x20,
0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,0x54,
0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x33,0x29,
0x5d,0x3b,0x0d,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,0x20,0x30,0x29,0x5d,
0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x32,0x5b,0x42,0x59,
0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x33,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x20,0x33,
0x29,0x5d,0x3b,0x0d,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b,0x0d,0x7d,0x0d,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,0x20,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,
0x20,0x63,0x6f,0x6e,0x73,0x74,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x58,0x2c,0x20,0x75,0x69,0x6e,0x74,0x34,0x20,0x6b,0x65,0x79,0x29,0x0d,0x7b,0x0d,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,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,
0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,
0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,
0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,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,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,
0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,
0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x20,0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,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,0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,
0x54,0x45,0x28,0x58,0x2e,0x73,0x33,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,
0x58,0x2e,0x73,0x30,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x33,0x29,0x5d,0x2c,
0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,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,
0x20,0x30,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x30,0x2c,0x20,0x31,0x29,0x5d,0x20,0x5e,0x20,0x72,0x6f,0x74,
0x61,0x74,0x65,0x28,0x41,0x45,0x53,0x30,0x5b,0x42,0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x31,0x2c,0x20,0x32,0x29,0x5d,0x20,0x5e,0x20,0x41,0x45,0x53,0x31,0x5b,0x42,
0x59,0x54,0x45,0x28,0x58,0x2e,0x73,0x32,0x2c,0x20,0x33,0x29,0x5d,0x2c,0x20,0x31,0x36,0x55,0x29,0x3b,0x0d,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6b,0x65,0x79,0x3b,
0x0d,0x7d,0x0d,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,0x20,0x3d,0x20,0x7b,0x20,0x30,0x78,0x38,0x64,0x2c,0x20,0x30,0x78,0x30,0x31,0x2c,0x20,0x30,0x78,0x30,0x32,0x2c,0x20,0x30,
0x78,0x30,0x34,0x2c,0x20,0x30,0x78,0x30,0x38,0x2c,0x20,0x30,0x78,0x31,0x30,0x2c,0x20,0x30,0x78,0x32,0x30,0x2c,0x20,0x30,0x78,0x34,0x30,0x20,0x7d,0x3b,0x0d,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,0x0d,0x7b,0x0d,0x30,0x78,0x36,0x33,0x2c,0x20,0x30,0x78,0x37,0x43,0x2c,0x20,0x30,0x78,0x37,0x37,0x2c,0x20,0x30,0x78,0x37,
0x42,0x2c,0x20,0x30,0x78,0x46,0x32,0x2c,0x20,0x30,0x78,0x36,0x42,0x2c,0x20,0x30,0x78,0x36,0x46,0x2c,0x20,0x30,0x78,0x43,0x35,0x2c,0x20,0x30,0x78,0x33,0x30,0x2c,
0x20,0x30,0x78,0x30,0x31,0x2c,0x20,0x30,0x78,0x36,0x37,0x2c,0x20,0x30,0x78,0x32,0x42,0x2c,0x20,0x30,0x78,0x46,0x45,0x2c,0x20,0x30,0x78,0x44,0x37,0x2c,0x20,0x30,
0x78,0x41,0x42,0x2c,0x20,0x30,0x78,0x37,0x36,0x2c,0x0d,0x30,0x78,0x43,0x41,0x2c,0x20,0x30,0x78,0x38,0x32,0x2c,0x20,0x30,0x78,0x43,0x39,0x2c,0x20,0x30,0x78,0x37,
0x44,0x2c,0x20,0x30,0x78,0x46,0x41,0x2c,0x20,0x30,0x78,0x35,0x39,0x2c,0x20,0x30,0x78,0x34,0x37,0x2c,0x20,0x30,0x78,0x46,0x30,0x2c,0x20,0x30,0x78,0x41,0x44,0x2c,
0x20,0x30,0x78,0x44,0x34,0x2c,0x20,0x30,0x78,0x41,0x32,0x2c,0x20,0x30,0x78,0x41,0x46,0x2c,0x20,0x30,0x78,0x39,0x43,0x2c,0x20,0x30,0x78,0x41,0x34,0x2c,0x20,0x30,
0x78,0x37,0x32,0x2c,0x20,0x30,0x78,0x43,0x30,0x2c,0x0d,0x30,0x78,0x42,0x37,0x2c,0x20,0x30,0x78,0x46,0x44,0x2c,0x20,0x30,0x78,0x39,0x33,0x2c,0x20,0x30,0x78,0x32,
0x36,0x2c,0x20,0x30,0x78,0x33,0x36,0x2c,0x20,0x30,0x78,0x33,0x46,0x2c,0x20,0x30,0x78,0x46,0x37,0x2c,0x20,0x30,0x78,0x43,0x43,0x2c,0x20,0x30,0x78,0x33,0x34,0x2c,
0x20,0x30,0x78,0x41,0x35,0x2c,0x20,0x30,0x78,0x45,0x35,0x2c,0x20,0x30,0x78,0x46,0x31,0x2c,0x20,0x30,0x78,0x37,0x31,0x2c,0x20,0x30,0x78,0x44,0x38,0x2c,0x20,0x30,
0x78,0x33,0x31,0x2c,0x20,0x30,0x78,0x31,0x35,0x2c,0x0d,0x30,0x78,0x30,0x34,0x2c,0x20,0x30,0x78,0x43,0x37,0x2c,0x20,0x30,0x78,0x32,0x33,0x2c,0x20,0x30,0x78,0x43,
0x33,0x2c,0x20,0x30,0x78,0x31,0x38,0x2c,0x20,0x30,0x78,0x39,0x36,0x2c,0x20,0x30,0x78,0x30,0x35,0x2c,0x20,0x30,0x78,0x39,0x41,0x2c,0x20,0x30,0x78,0x30,0x37,0x2c,
0x20,0x30,0x78,0x31,0x32,0x2c,0x20,0x30,0x78,0x38,0x30,0x2c,0x20,0x30,0x78,0x45,0x32,0x2c,0x20,0x30,0x78,0x45,0x42,0x2c,0x20,0x30,0x78,0x32,0x37,0x2c,0x20,0x30,
0x78,0x42,0x32,0x2c,0x20,0x30,0x78,0x37,0x35,0x2c,0x0d,0x30,0x78,0x30,0x39,0x2c,0x20,0x30,0x78,0x38,0x33,0x2c,0x20,0x30,0x78,0x32,0x43,0x2c,0x20,0x30,0x78,0x31,
0x41,0x2c,0x20,0x30,0x78,0x31,0x42,0x2c,0x20,0x30,0x78,0x36,0x45,0x2c,0x20,0x30,0x78,0x35,0x41,0x2c,0x20,0x30,0x78,0x41,0x30,0x2c,0x20,0x30,0x78,0x35,0x32,0x2c,
0x20,0x30,0x78,0x33,0x42,0x2c,0x20,0x30,0x78,0x44,0x36,0x2c,0x20,0x30,0x78,0x42,0x33,0x2c,0x20,0x30,0x78,0x32,0x39,0x2c,0x20,0x30,0x78,0x45,0x33,0x2c,0x20,0x30,
0x78,0x32,0x46,0x2c,0x20,0x30,0x78,0x38,0x34,0x2c,0x0d,0x30,0x78,0x35,0x33,0x2c,0x20,0x30,0x78,0x44,0x31,0x2c,0x20,0x30,0x78,0x30,0x30,0x2c,0x20,0x30,0x78,0x45,
0x44,0x2c,0x20,0x30,0x78,0x32,0x30,0x2c,0x20,0x30,0x78,0x46,0x43,0x2c,0x20,0x30,0x78,0x42,0x31,0x2c,0x20,0x30,0x78,0x35,0x42,0x2c,0x20,0x30,0x78,0x36,0x41,0x2c,
0x20,0x30,0x78,0x43,0x42,0x2c,0x20,0x30,0x78,0x42,0x45,0x2c,0x20,0x30,0x78,0x33,0x39,0x2c,0x20,0x30,0x78,0x34,0x41,0x2c,0x20,0x30,0x78,0x34,0x43,0x2c,0x20,0x30,
0x78,0x35,0x38,0x2c,0x20,0x30,0x78,0x43,0x46,0x2c,0x0d,0x30,0x78,0x44,0x30,0x2c,0x20,0x30,0x78,0x45,0x46,0x2c,0x20,0x30,0x78,0x41,0x41,0x2c,0x20,0x30,0x78,0x46,
0x42,0x2c,0x20,0x30,0x78,0x34,0x33,0x2c,0x20,0x30,0x78,0x34,0x44,0x2c,0x20,0x30,0x78,0x33,0x33,0x2c,0x20,0x30,0x78,0x38,0x35,0x2c,0x20,0x30,0x78,0x34,0x35,0x2c,
0x20,0x30,0x78,0x46,0x39,0x2c,0x20,0x30,0x78,0x30,0x32,0x2c,0x20,0x30,0x78,0x37,0x46,0x2c,0x20,0x30,0x78,0x35,0x30,0x2c,0x20,0x30,0x78,0x33,0x43,0x2c,0x20,0x30,
0x78,0x39,0x46,0x2c,0x20,0x30,0x78,0x41,0x38,0x2c,0x0d,0x30,0x78,0x35,0x31,0x2c,0x20,0x30,0x78,0x41,0x33,0x2c,0x20,0x30,0x78,0x34,0x30,0x2c,0x20,0x30,0x78,0x38,
0x46,0x2c,0x20,0x30,0x78,0x39,0x32,0x2c,0x20,0x30,0x78,0x39,0x44,0x2c,0x20,0x30,0x78,0x33,0x38,0x2c,0x20,0x30,0x78,0x46,0x35,0x2c,0x20,0x30,0x78,0x42,0x43,0x2c,
0x20,0x30,0x78,0x42,0x36,0x2c,0x20,0x30,0x78,0x44,0x41,0x2c,0x20,0x30,0x78,0x32,0x31,0x2c,0x20,0x30,0x78,0x31,0x30,0x2c,0x20,0x30,0x78,0x46,0x46,0x2c,0x20,0x30,
0x78,0x46,0x33,0x2c,0x20,0x30,0x78,0x44,0x32,0x2c,0x0d,0x30,0x78,0x43,0x44,0x2c,0x20,0x30,0x78,0x30,0x43,0x2c,0x20,0x30,0x78,0x31,0x33,0x2c,0x20,0x30,0x78,0x45,
0x43,0x2c,0x20,0x30,0x78,0x35,0x46,0x2c,0x20,0x30,0x78,0x39,0x37,0x2c,0x20,0x30,0x78,0x34,0x34,0x2c,0x20,0x30,0x78,0x31,0x37,0x2c,0x20,0x30,0x78,0x43,0x34,0x2c,
0x20,0x30,0x78,0x41,0x37,0x2c,0x20,0x30,0x78,0x37,0x45,0x2c,0x20,0x30,0x78,0x33,0x44,0x2c,0x20,0x30,0x78,0x36,0x34,0x2c,0x20,0x30,0x78,0x35,0x44,0x2c,0x20,0x30,
0x78,0x31,0x39,0x2c,0x20,0x30,0x78,0x37,0x33,0x2c,0x0d,0x30,0x78,0x36,0x30,0x2c,0x20,0x30,0x78,0x38,0x31,0x2c,0x20,0x30,0x78,0x34,0x46,0x2c,0x20,0x30,0x78,0x44,
0x43,0x2c,0x20,0x30,0x78,0x32,0x32,0x2c,0x20,0x30,0x78,0x32,0x41,0x2c,0x20,0x30,0x78,0x39,0x30,0x2c,0x20,0x30,0x78,0x38,0x38,0x2c,0x20,0x30,0x78,0x34,0x36,0x2c,
0x20,0x30,0x78,0x45,0x45,0x2c,0x20,0x30,0x78,0x42,0x38,0x2c,0x20,0x30,0x78,0x31,0x34,0x2c,0x20,0x30,0x78,0x44,0x45,0x2c,0x20,0x30,0x78,0x35,0x45,0x2c,0x20,0x30,
0x78,0x30,0x42,0x2c,0x20,0x30,0x78,0x44,0x42,0x2c,0x0d,0x30,0x78,0x45,0x30,0x2c,0x20,0x30,0x78,0x33,0x32,0x2c,0x20,0x30,0x78,0x33,0x41,0x2c,0x20,0x30,0x78,0x30,
0x41,0x2c,0x20,0x30,0x78,0x34,0x39,0x2c,0x20,0x30,0x78,0x30,0x36,0x2c,0x20,0x30,0x78,0x32,0x34,0x2c,0x20,0x30,0x78,0x35,0x43,0x2c,0x20,0x30,0x78,0x43,0x32,0x2c,
0x20,0x30,0x78,0x44,0x33,0x2c,0x20,0x30,0x78,0x41,0x43,0x2c,0x20,0x30,0x78,0x36,0x32,0x2c,0x20,0x30,0x78,0x39,0x31,0x2c,0x20,0x30,0x78,0x39,0x35,0x2c,0x20,0x30,
0x78,0x45,0x34,0x2c,0x20,0x30,0x78,0x37,0x39,0x2c,0x0d,0x30,0x78,0x45,0x37,0x2c,0x20,0x30,0x78,0x43,0x38,0x2c,0x20,0x30,0x78,0x33,0x37,0x2c,0x20,0x30,0x78,0x36,
0x44,0x2c,0x20,0x30,0x78,0x38,0x44,0x2c,0x20,0x30,0x78,0x44,0x35,0x2c,0x20,0x30,0x78,0x34,0x45,0x2c,0x20,0x30,0x78,0x41,0x39,0x2c,0x20,0x30,0x78,0x36,0x43,0x2c,
0x20,0x30,0x78,0x35,0x36,0x2c,0x20,0x30,0x78,0x46,0x34,0x2c,0x20,0x30,0x78,0x45,0x41,0x2c,0x20,0x30,0x78,0x36,0x35,0x2c,0x20,0x30,0x78,0x37,0x41,0x2c,0x20,0x30,
0x78,0x41,0x45,0x2c,0x20,0x30,0x78,0x30,0x38,0x2c,0x0d,0x30,0x78,0x42,0x41,0x2c,0x20,0x30,0x78,0x37,0x38,0x2c,0x20,0x30,0x78,0x32,0x35,0x2c,0x20,0x30,0x78,0x32,
0x45,0x2c,0x20,0x30,0x78,0x31,0x43,0x2c,0x20,0x30,0x78,0x41,0x36,0x2c,0x20,0x30,0x78,0x42,0x34,0x2c,0x20,0x30,0x78,0x43,0x36,0x2c,0x20,0x30,0x78,0x45,0x38,0x2c,
0x20,0x30,0x78,0x44,0x44,0x2c,0x20,0x30,0x78,0x37,0x34,0x2c,0x20,0x30,0x78,0x31,0x46,0x2c,0x20,0x30,0x78,0x34,0x42,0x2c,0x20,0x30,0x78,0x42,0x44,0x2c,0x20,0x30,
0x78,0x38,0x42,0x2c,0x20,0x30,0x78,0x38,0x41,0x2c,0x0d,0x30,0x78,0x37,0x30,0x2c,0x20,0x30,0x78,0x33,0x45,0x2c,0x20,0x30,0x78,0x42,0x35,0x2c,0x20,0x30,0x78,0x36,
0x36,0x2c,0x20,0x30,0x78,0x34,0x38,0x2c,0x20,0x30,0x78,0x30,0x33,0x2c,0x20,0x30,0x78,0x46,0x36,0x2c,0x20,0x30,0x78,0x30,0x45,0x2c,0x20,0x30,0x78,0x36,0x31,0x2c,
0x20,0x30,0x78,0x33,0x35,0x2c,0x20,0x30,0x78,0x35,0x37,0x2c,0x20,0x30,0x78,0x42,0x39,0x2c,0x20,0x30,0x78,0x38,0x36,0x2c,0x20,0x30,0x78,0x43,0x31,0x2c,0x20,0x30,
0x78,0x31,0x44,0x2c,0x20,0x30,0x78,0x39,0x45,0x2c,0x0d,0x30,0x78,0x45,0x31,0x2c,0x20,0x30,0x78,0x46,0x38,0x2c,0x20,0x30,0x78,0x39,0x38,0x2c,0x20,0x30,0x78,0x31,
0x31,0x2c,0x20,0x30,0x78,0x36,0x39,0x2c,0x20,0x30,0x78,0x44,0x39,0x2c,0x20,0x30,0x78,0x38,0x45,0x2c,0x20,0x30,0x78,0x39,0x34,0x2c,0x20,0x30,0x78,0x39,0x42,0x2c,
0x20,0x30,0x78,0x31,0x45,0x2c,0x20,0x30,0x78,0x38,0x37,0x2c,0x20,0x30,0x78,0x45,0x39,0x2c,0x20,0x30,0x78,0x43,0x45,0x2c,0x20,0x30,0x78,0x35,0x35,0x2c,0x20,0x30,
0x78,0x32,0x38,0x2c,0x20,0x30,0x78,0x44,0x46,0x2c,0x0d,0x30,0x78,0x38,0x43,0x2c,0x20,0x30,0x78,0x41,0x31,0x2c,0x20,0x30,0x78,0x38,0x39,0x2c,0x20,0x30,0x78,0x30,
0x44,0x2c,0x20,0x30,0x78,0x42,0x46,0x2c,0x20,0x30,0x78,0x45,0x36,0x2c,0x20,0x30,0x78,0x34,0x32,0x2c,0x20,0x30,0x78,0x36,0x38,0x2c,0x20,0x30,0x78,0x34,0x31,0x2c,
0x20,0x30,0x78,0x39,0x39,0x2c,0x20,0x30,0x78,0x32,0x44,0x2c,0x20,0x30,0x78,0x30,0x46,0x2c,0x20,0x30,0x78,0x42,0x30,0x2c,0x20,0x30,0x78,0x35,0x34,0x2c,0x20,0x30,
0x78,0x42,0x42,0x2c,0x20,0x30,0x78,0x31,0x36,0x0d,0x7d,0x3b,0x0d,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,0x0d,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,0x0d,0x7b,0x0d,0x66,0x6f,0x72,0x20,0x28,0x75,0x69,0x6e,0x74,0x20,0x63,0x20,0x3d,0x20,
0x38,0x2c,0x20,0x69,0x20,0x3d,0x20,0x31,0x3b,0x20,0x63,0x20,0x3c,0x20,0x34,0x30,0x3b,0x20,0x2b,0x2b,0x63,0x29,0x20,0x7b,0x0d,0x75,0x69,0x6e,0x74,0x20,0x74,0x20,
0x3d,0x20,0x28,0x28,0x21,0x28,0x63,0x20,0x26,0x20,0x37,0x29,0x29,0x20,0x7c,0x7c,0x20,0x28,0x28,0x63,0x20,0x26,0x20,0x37,0x29,0x20,0x3d,0x3d,0x20,0x34,0x29,0x29,
0x20,0x3f,0x20,0x53,0x75,0x62,0x57,0x6f,0x72,0x64,0x28,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x20,0x2d,0x20,0x31,0x5d,0x29,0x20,0x3a,0x20,0x6b,0x65,0x79,0x62,
0x75,0x66,0x5b,0x63,0x20,0x2d,0x20,0x31,0x5d,0x3b,0x0d,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x5d,0x20,0x3d,0x20,0x6b,0x65,0x79,0x62,0x75,0x66,0x5b,0x63,0x20,
0x2d,0x20,0x38,0x5d,0x20,0x5e,0x20,0x28,0x28,0x21,0x28,0x63,0x20,0x26,0x20,0x37,0x29,0x29,0x20,0x3f,0x20,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x2c,0x20,0x32,
0x34,0x55,0x29,0x20,0x5e,0x20,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,0x20,0x30,0x55,0x2c,0x20,0x30,0x55,0x2c,0x20,0x30,0x55,0x29,0x29,0x20,0x3a,0x20,0x74,0x29,0x3b,0x0d,0x7d,0x0d,0x7d,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,
0x00
};
static char cryptonight_r_cl[3424] = {
static char cryptonight_r_cl[3415] = {
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,
0x69,0x7a,0x65,0x28,0x57,0x4f,0x52,0x4b,0x53,0x49,0x5a,0x45,0x2c,0x31,0x2c,0x31,0x29,0x29,0x29,0x0d,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,
0x64,0x73,0x29,0x0d,0x7b,0x0d,0x75,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x5b,0x32,0x5d,0x2c,0x62,0x5b,0x34,0x5d,0x3b,0x0d,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,
0x5d,0x2c,0x41,0x45,0x53,0x33,0x5b,0x32,0x35,0x36,0x5d,0x3b,0x0d,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,0x30,0x29,0x3b,0x0d,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,0x0d,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,0x0d,0x41,0x45,0x53,0x30,0x5b,0x69,0x5d,0x3d,0x74,0x6d,0x70,0x3b,0x0d,0x41,0x45,0x53,
0x31,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x38,0x55,0x29,0x3b,0x0d,0x41,0x45,0x53,0x32,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,
0x61,0x74,0x65,0x28,0x74,0x6d,0x70,0x2c,0x31,0x36,0x55,0x29,0x3b,0x0d,0x41,0x45,0x53,0x33,0x5b,0x69,0x5d,0x3d,0x72,0x6f,0x74,0x61,0x74,0x65,0x28,0x74,0x6d,0x70,
0x2c,0x32,0x34,0x55,0x29,0x3b,0x0d,0x7d,0x0d,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,0x0d,0x7b,0x0d,0x73,0x74,0x61,0x74,0x65,0x73,0x2b,0x3d,0x32,0x35,0x2a,0x67,0x49,0x64,0x78,0x3b,0x0d,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,0x0d,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,0x0d,0x23,0x65,0x6c,0x73,0x65,
0x0d,0x23,0x69,0x66,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x3d,0x3d,0x30,0x29,0x0d,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,0x0d,0x23,0x65,0x6c,0x69,0x66,0x28,0x53,0x54,0x52,0x49,0x44,
0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x3d,0x3d,0x31,0x29,0x0d,0x53,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x2b,0x3d,0x67,0x49,0x64,0x78,0x3b,0x0d,0x23,
0x65,0x6c,0x69,0x66,0x28,0x53,0x54,0x52,0x49,0x44,0x45,0x44,0x5f,0x49,0x4e,0x44,0x45,0x58,0x3d,0x3d,0x32,0x29,0x0d,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,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,0x7d,0x0d,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,0x0d,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,0x0d,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,0x0d,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,
0x49,0x4f,0x4e,0x0d,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,0x0d,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,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,0x7b,0x0d,
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,
0x0d,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,0x0d,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,0x0d,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,0x0d,0x23,0x70,0x72,0x61,0x67,0x6d,0x61,0x20,0x75,0x6e,0x72,0x6f,0x6c,0x6c,0x20,0x43,0x4e,0x5f,0x55,0x4e,0x52,0x4f,0x4c,0x4c,0x0d,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,0x0d,
0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0d,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,
0x78,0x3d,0x61,0x5b,0x30,0x5d,0x26,0x30,0x78,0x31,0x46,0x46,0x46,0x43,0x30,0x3b,0x0d,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x31,0x3d,0x61,0x5b,0x30,0x5d,0x26,
0x30,0x78,0x33,0x30,0x3b,0x0d,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,0x0d,0x23,0x65,0x6c,0x73,0x65,0x0d,0x75,0x69,0x6e,0x74,0x20,0x69,0x64,0x78,0x3d,0x61,0x5b,
0x30,0x5d,0x26,0x4d,0x41,0x53,0x4b,0x3b,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,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,0x0d,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,
0x0d,0x7b,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,0x7d,0x0d,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,0x0d,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,
0x4f,0x4e,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,0x23,0x65,0x6c,0x73,0x65,0x0d,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,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,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,0x0d,0x74,0x6d,0x70,0x2e,0x73,0x30,0x20,0x5e,0x3d,0x20,0x72,0x30,
0x2b,0x72,0x31,0x3b,0x0d,0x74,0x6d,0x70,0x2e,0x73,0x31,0x20,0x5e,0x3d,0x20,0x72,0x32,0x2b,0x72,0x33,0x3b,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x20,0x74,
0x3b,0x0d,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,0x0d,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,0x0d,0x7b,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,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,0x0d,0x7d,0x0d,0x61,0x5b,
0x31,0x5d,0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x28,0x61,0x68,0x29,0x2b,0x74,0x2e,0x73,0x31,0x3b,0x0d,0x61,0x5b,0x30,0x5d,0x3d,0x61,0x73,0x5f,0x75,0x6c,
0x6f,0x6e,0x67,0x28,0x61,0x6c,0x29,0x2b,0x74,0x2e,0x73,0x30,0x3b,0x0d,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,0x0d,0x23,0x69,0x66,0x64,0x65,0x66,0x20,0x5f,0x5f,0x4e,0x56,0x5f,0x43,
0x4c,0x5f,0x43,0x5f,0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x0d,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
0x78,0x29,0x3d,0x2a,0x73,0x63,0x72,0x61,0x74,0x63,0x68,0x70,0x61,0x64,0x5f,0x6c,0x69,0x6e,0x65,0x3b,0x0d,0x23,0x65,0x6e,0x64,0x69,0x66,0x0d,0x28,0x28,0x75,0x69,
0x6e,0x74,0x34,0x20,0x2a,0x29,0x61,0x29,0x5b,0x30,0x5d,0x20,0x5e,0x3d,0x20,0x74,0x6d,0x70,0x3b,0x0d,0x62,0x78,0x31,0x3d,0x62,0x78,0x30,0x3b,0x0d,0x62,0x78,0x30,
0x3d,0x61,0x73,0x5f,0x75,0x6c,0x6f,0x6e,0x67,0x32,0x28,0x63,0x29,0x3b,0x0d,0x7d,0x0d,0x7d,0x0d,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,0x0d,0x7d,0x0d,0x00
};
} // namespace xmrig

View File

@@ -6,6 +6,8 @@
#include "randomx_constants_wow.h"
#elif (ALGO == ALGO_RX_LOKI)
#include "randomx_constants_loki.h"
#elif (ALGO == ALGO_RX_ARQMA)
#include "randomx_constants_arqma.h"
#endif
#include "aes.cl"

File diff suppressed because it is too large Load Diff

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
//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 262144
//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 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 - 17)
#define LOC_L3 (32 - 18)

View File

@@ -13,8 +13,8 @@ if (WITH_OPENCL)
src/backend/opencl/OclBackend.h
src/backend/opencl/OclCache.h
src/backend/opencl/OclConfig.h
src/backend/opencl/OclConfig_gen.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
@@ -22,6 +22,8 @@ if (WITH_OPENCL)
src/backend/opencl/runners/OclBaseRunner.h
src/backend/opencl/runners/OclCnRunner.h
src/backend/opencl/runners/tools/OclCnR.h
src/backend/opencl/runners/tools/OclSharedData.h
src/backend/opencl/runners/tools/OclSharedState.h
src/backend/opencl/wrappers/OclContext.h
src/backend/opencl/wrappers/OclDevice.h
src/backend/opencl/wrappers/OclError.h
@@ -42,7 +44,6 @@ if (WITH_OPENCL)
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
@@ -50,6 +51,8 @@ if (WITH_OPENCL)
src/backend/opencl/runners/OclBaseRunner.cpp
src/backend/opencl/runners/OclCnRunner.cpp
src/backend/opencl/runners/tools/OclCnR.cpp
src/backend/opencl/runners/tools/OclSharedData.cpp
src/backend/opencl/runners/tools/OclSharedState.cpp
src/backend/opencl/wrappers/OclContext.cpp
src/backend/opencl/wrappers/OclDevice.cpp
src/backend/opencl/wrappers/OclError.cpp
@@ -78,7 +81,6 @@ if (WITH_OPENCL)
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
@@ -95,7 +97,6 @@ if (WITH_OPENCL)
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()

View File

@@ -23,10 +23,11 @@
*/
#include "backend/opencl/runners/OclBaseRunner.h"
#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/runners/tools/OclSharedState.h"
#include "backend/opencl/wrappers/OclError.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "base/io/log/Log.h"
@@ -34,6 +35,9 @@
#include "crypto/common/VirtualMemory.h"
constexpr size_t oneGiB = 1024 * 1024 * 1024;
xmrig::OclBaseRunner::OclBaseRunner(size_t id, const OclLaunchData &data) :
m_algorithm(data.algorithm),
m_ctx(data.ctx),
@@ -93,16 +97,17 @@ void xmrig::OclBaseRunner::build()
void xmrig::OclBaseRunner::init()
{
m_queue = OclLib::createCommandQueue(m_ctx, data().device.id());
m_queue = OclLib::createCommandQueue(m_ctx, data().device.id());
constexpr size_t oneGiB = 1024 * 1024 * 1024;
size_t size = bufferSize();
size_t size = align(bufferSize());
if (size < oneGiB && data().device.vendorId() == OCL_VENDOR_AMD && data().device.freeMemSize() >= oneGiB) {
size = oneGiB;
m_buffer = OclSharedState::get(data().device.index()).createBuffer(m_ctx, size, m_offset);
}
else {
m_buffer = OclLib::createBuffer(m_ctx, CL_MEM_READ_WRITE, size);
}
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);
}

View File

@@ -30,6 +30,7 @@
#include "backend/opencl/kernels/rx/FindSharesKernel.h"
#include "backend/opencl/kernels/rx/HashAesKernel.h"
#include "backend/opencl/OclLaunchData.h"
#include "backend/opencl/runners/tools/OclSharedState.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "base/net/stratum/Job.h"
#include "crypto/rx/Rx.h"
@@ -75,6 +76,7 @@ xmrig::OclRxBaseRunner::~OclRxBaseRunner()
OclLib::release(m_hashes);
OclLib::release(m_rounding);
OclLib::release(m_scratchpads);
OclLib::release(m_dataset);
}
@@ -120,7 +122,7 @@ void xmrig::OclRxBaseRunner::set(const Job &job, uint8_t *blob)
m_seed = job.seed();
auto dataset = Rx::dataset(job, 0);
enqueueWriteBuffer(data().dataset->get(), CL_TRUE, 0, dataset->size(), dataset->raw());
enqueueWriteBuffer(m_dataset, CL_TRUE, 0, RxDataset::maxSize(), dataset->raw());
}
if (job.size() < Job::kMaxBlobSize) {
@@ -177,4 +179,5 @@ void xmrig::OclRxBaseRunner::init()
m_hashes = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, 64 * m_intensity);
m_entropy = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, (128 + 2560) * m_intensity);
m_rounding = createSubBuffer(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS, sizeof(uint32_t) * m_intensity);
m_dataset = OclSharedState::get(data().device.index()).dataset();
}

View File

@@ -62,6 +62,7 @@ protected:
Blake2bHashRegistersKernel *m_blake2b_hash_registers_64 = nullptr;
Blake2bInitialHashKernel *m_blake2b_initial_hash = nullptr;
Buffer m_seed;
cl_mem m_dataset = nullptr;
cl_mem m_entropy = nullptr;
cl_mem m_hashes = nullptr;
cl_mem m_rounding = nullptr;

View File

@@ -74,7 +74,7 @@ void xmrig::OclRxJitRunner::build()
}
m_randomx_run = new RxRunKernel(m_asmProgram);
m_randomx_run->setArgs(data().dataset->get(), m_scratchpads, m_registers, m_rounding, m_programs, m_intensity, m_algorithm);
m_randomx_run->setArgs(m_dataset, m_scratchpads, m_registers, m_rounding, m_programs, m_intensity, m_algorithm);
}

View File

@@ -70,7 +70,7 @@ void xmrig::OclRxVmRunner::build()
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(), m_intensity);
m_execute_vm->setArgs(m_vm_states, m_rounding, m_scratchpads, m_dataset, m_intensity);
}

View File

@@ -23,17 +23,44 @@
*/
#include "backend/opencl/OclInterleave.h"
#include "backend/opencl/runners/tools/OclSharedData.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "base/io/log/Log.h"
#include "base/tools/Chrono.h"
#include "crypto/rx/Rx.h"
#include "crypto/rx/RxDataset.h"
#include <algorithm>
#include <cinttypes>
#include <stdexcept>
#include <thread>
uint64_t xmrig::OclInterleave::adjustDelay(size_t id)
constexpr size_t oneGiB = 1024 * 1024 * 1024;
cl_mem xmrig::OclSharedData::createBuffer(cl_context context, size_t size, size_t &offset)
{
std::lock_guard<std::mutex> lock(m_mutex);
offset += size * m_offset++;
size = std::max(size * m_threads, oneGiB);
if (!m_buffer) {
m_buffer = OclLib::createBuffer(context, CL_MEM_READ_WRITE, size);
}
return OclLib::retain(m_buffer);
}
uint64_t xmrig::OclSharedData::adjustDelay(size_t id)
{
if (m_threads < 2) {
return 0;
}
const uint64_t t0 = Chrono::steadyMSecs();
uint64_t delay = 0;
@@ -69,8 +96,12 @@ uint64_t xmrig::OclInterleave::adjustDelay(size_t id)
}
uint64_t xmrig::OclInterleave::resumeDelay(size_t id)
uint64_t xmrig::OclSharedData::resumeDelay(size_t id)
{
if (m_threads < 2) {
return 0;
}
uint64_t delay = 0;
{
@@ -99,14 +130,28 @@ uint64_t xmrig::OclInterleave::resumeDelay(size_t id)
}
void xmrig::OclInterleave::setResumeCounter(uint32_t value)
void xmrig::OclSharedData::release()
{
OclLib::release(m_buffer);
# ifdef XMRIG_ALGO_RANDOMX
OclLib::release(m_dataset);
# endif
}
void xmrig::OclSharedData::setResumeCounter(uint32_t value)
{
if (m_threads < 2) {
return;
}
std::lock_guard<std::mutex> lock(m_mutex);
m_resumeCounter = value;
}
void xmrig::OclInterleave::setRunTime(uint64_t time)
void xmrig::OclSharedData::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
@@ -116,3 +161,34 @@ void xmrig::OclInterleave::setRunTime(uint64_t time)
std::lock_guard<std::mutex> lock(m_mutex);
m_averageRunTime = m_averageRunTime * (1.0 - averagingBias) + time * averagingBias;
}
#ifdef XMRIG_ALGO_RANDOMX
cl_mem xmrig::OclSharedData::dataset() const
{
if (!m_dataset) {
throw std::runtime_error("RandomX dataset is not available");
}
return OclLib::retain(m_dataset);
}
void xmrig::OclSharedData::createDataset(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);
}
}
#endif

View File

@@ -22,42 +22,62 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_OCLINTERLEAVE_H
#define XMRIG_OCLINTERLEAVE_H
#ifndef XMRIG_OCLSHAREDDATA_H
#define XMRIG_OCLSHAREDDATA_H
#include <memory>
#include <mutex>
using cl_context = struct _cl_context *;
using cl_mem = struct _cl_mem *;
namespace xmrig {
class OclInterleave
class Job;
class OclSharedData
{
public:
OclInterleave() = delete;
inline OclInterleave(size_t threads) : m_threads(threads) {}
OclSharedData() = default;
cl_mem createBuffer(cl_context context, size_t size, size_t &offset);
uint64_t adjustDelay(size_t id);
uint64_t resumeDelay(size_t id);
void release();
void setResumeCounter(uint32_t value);
void setRunTime(uint64_t time);
inline size_t threads() const { return m_threads; }
inline OclSharedData &operator++() { ++m_threads; return *this; }
# ifdef XMRIG_ALGO_RANDOMX
cl_mem dataset() const;
void createDataset(cl_context ctx, const Job &job, bool host);
# endif
private:
const size_t m_threads;
cl_mem m_buffer = nullptr;
double m_averageRunTime = 0.0;
double m_threshold = 0.95;
size_t m_offset = 0;
size_t m_threads = 0;
std::mutex m_mutex;
uint32_t m_resumeCounter = 0;
uint64_t m_timestamp = 0;
# ifdef XMRIG_ALGO_RANDOMX
cl_mem m_dataset = nullptr;
# endif
};
using OclInterleavePtr = std::shared_ptr<OclInterleave>;
} /* namespace xmrig */
#endif /* XMRIG_OCLINTERLEAVE_H */
#endif /* XMRIG_OCLSHAREDDATA_H */

View File

@@ -0,0 +1,74 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "backend/opencl/runners/tools/OclSharedState.h"
#include "backend/opencl/runners/tools/OclSharedData.h"
#include <cassert>
#include <map>
namespace xmrig {
static std::map<uint32_t, OclSharedData> map;
} // namespace xmrig
xmrig::OclSharedData &xmrig::OclSharedState::get(uint32_t index)
{
return map[index];
}
void xmrig::OclSharedState::release()
{
for (auto &kv : map) {
kv.second.release();
}
map.clear();
}
void xmrig::OclSharedState::start(const std::vector<OclLaunchData> &threads, const Job &job)
{
assert(map.empty());
for (const auto &data : threads) {
auto &sharedData = map[data.device.index()];
++sharedData;
# ifdef XMRIG_ALGO_RANDOMX
if (data.algorithm.family() == Algorithm::RANDOM_X) {
sharedData.createDataset(data.ctx, job, data.thread.isDatasetHost());
}
# endif
}
}

View File

@@ -0,0 +1,47 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_OCLSHAREDSTATE_H
#define XMRIG_OCLSHAREDSTATE_H
#include "backend/opencl/OclLaunchData.h"
namespace xmrig {
class OclSharedState
{
public:
static OclSharedData &get(uint32_t index);
static void release();
static void start(const std::vector<OclLaunchData> &threads, const Job &job);
};
} /* namespace xmrig */
#endif /* XMRIG_OCLSHAREDSTATE_H */

View File

@@ -24,6 +24,7 @@
#include "backend/opencl/wrappers/OclContext.h"
#include "backend/opencl/runners/tools/OclSharedState.h"
#include "backend/opencl/wrappers/OclLib.h"
@@ -42,7 +43,7 @@ xmrig::OclContext::~OclContext()
}
bool xmrig::OclContext::init(const std::vector<OclDevice> &devices, std::vector<OclLaunchData> &threads, const Job &job)
bool xmrig::OclContext::init(const std::vector<OclDevice> &devices, std::vector<OclLaunchData> &threads)
{
if (!m_ctx) {
std::vector<cl_device_id> ids(devices.size());
@@ -59,12 +60,6 @@ bool xmrig::OclContext::init(const std::vector<OclDevice> &devices, std::vector<
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;

View File

@@ -49,7 +49,7 @@ public:
OclContext(const OclDevice &device);
~OclContext();
bool init(const std::vector<OclDevice> &devices, std::vector<OclLaunchData> &threads, const Job &job);
bool init(const std::vector<OclDevice> &devices, std::vector<OclLaunchData> &threads);
inline bool isValid() const { return m_ctx != nullptr; }
inline cl_context ctx() const { return m_ctx; }

View File

@@ -73,6 +73,7 @@ static const char *kReleaseDevice = "clReleaseDevice";
static const char *kReleaseKernel = "clReleaseKernel";
static const char *kReleaseMemObject = "clReleaseMemObject";
static const char *kReleaseProgram = "clReleaseProgram";
static const char *kRetainMemObject = "clRetainMemObject";
static const char *kRetainProgram = "clRetainProgram";
static const char *kSetKernelArg = "clSetKernelArg";
static const char *kSetMemObjectDestructorCallback = "clSetMemObjectDestructorCallback";
@@ -106,6 +107,7 @@ 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 *retainMemObject_t)(cl_mem);
typedef cl_int (CL_API_CALL *retainProgram_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 *);
@@ -148,6 +150,7 @@ static releaseDevice_t pReleaseDevice = nu
static releaseKernel_t pReleaseKernel = nullptr;
static releaseMemObject_t pReleaseMemObject = nullptr;
static releaseProgram_t pReleaseProgram = nullptr;
static retainMemObject_t pRetainMemObject = nullptr;
static retainProgram_t pRetainProgram = nullptr;
static setKernelArg_t pSetKernelArg = nullptr;
static setMemObjectDestructorCallback_t pSetMemObjectDestructorCallback = nullptr;
@@ -239,6 +242,7 @@ bool xmrig::OclLib::load()
DLSYM(SetMemObjectDestructorCallback);
DLSYM(CreateSubBuffer);
DLSYM(RetainProgram);
DLSYM(RetainMemObject);
# if defined(CL_VERSION_2_0)
uv_dlsym(&oclLib, kCreateCommandQueueWithProperties, reinterpret_cast<void**>(&pCreateCommandQueueWithProperties));
@@ -670,6 +674,18 @@ cl_mem xmrig::OclLib::createSubBuffer(cl_mem buffer, cl_mem_flags flags, size_t
}
cl_mem xmrig::OclLib::retain(cl_mem memobj) noexcept
{
assert(pRetainMemObject != nullptr);
if (memobj != nullptr) {
pRetainMemObject(memobj);
}
return memobj;
}
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);

View File

@@ -79,6 +79,7 @@ public:
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_mem retain(cl_mem memobj) noexcept;
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_program retain(cl_program program) noexcept;

View File

@@ -98,7 +98,14 @@ elseif (APPLE)
else()
set(SOURCES_OS
src/base/io/json/Json_unix.cpp
src/base/kernel//Platform_unix.cpp
src/base/kernel/Platform_unix.cpp
)
endif()
if (WITH_HWLOC)
list(APPEND SOURCES_OS
src/base/kernel/Platform_hwloc.cpp
)
endif()

View File

@@ -31,10 +31,10 @@
#include <algorithm>
#include <cstring>
#include <ctime>
#include <mutex>
#include <string.h>
#include <string>
#include <time.h>
#include <uv.h>
#include <vector>
@@ -42,6 +42,7 @@
#include "base/io/log/Log.h"
#include "base/kernel/interfaces/ILogBackend.h"
#include "base/tools/Chrono.h"
#include "base/tools/Object.h"
namespace xmrig {
@@ -67,10 +68,10 @@ static const char *colors_map[] = {
class LogPrivate
{
public:
inline LogPrivate() :
m_buf()
{
}
XMRIG_DISABLE_COPY_MOVE(LogPrivate)
LogPrivate() = default;
inline ~LogPrivate()
@@ -134,7 +135,7 @@ private:
const uint64_t ms = Chrono::currentMSecsSinceEpoch();
time_t now = ms / 1000;
tm stime;
tm stime{};
# ifdef _WIN32
localtime_s(&stime, &now);
@@ -188,7 +189,7 @@ private:
}
char m_buf[4096];
char m_buf[4096]{};
std::mutex m_mutex;
std::vector<ILogBackend*> m_backends;
};

View File

@@ -47,7 +47,6 @@ xmrig::ConsoleLog::ConsoleLog()
}
uv_tty_set_mode(m_tty, UV_TTY_MODE_NORMAL);
m_stream = reinterpret_cast<uv_stream_t*>(m_tty);
# ifdef WIN32
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
@@ -68,25 +67,14 @@ xmrig::ConsoleLog::~ConsoleLog()
}
void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t size, bool colors)
void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t, bool colors)
{
if (!m_tty || Log::colors != colors) {
return;
}
# ifdef _WIN32
uv_buf_t buf = uv_buf_init(const_cast<char *>(line), static_cast<unsigned int>(size));
# else
uv_buf_t buf = uv_buf_init(const_cast<char *>(line), size);
# endif
if (!isWritable()) {
fputs(line, stdout);
fflush(stdout);
}
else {
uv_try_write(m_stream, &buf, 1);
}
fputs(line, stdout);
fflush(stdout);
}
@@ -95,13 +83,3 @@ bool xmrig::ConsoleLog::isSupported() const
const uv_handle_type type = uv_guess_handle(1);
return type == UV_TTY || type == UV_NAMED_PIPE;
}
bool xmrig::ConsoleLog::isWritable() const
{
if (!m_stream || uv_is_writable(m_stream) != 1) {
return false;
}
return isSupported();
}

View File

@@ -51,10 +51,8 @@ protected:
private:
bool isSupported() const;
bool isWritable() const;
uv_stream_t *m_stream = nullptr;
uv_tty_t *m_tty = nullptr;
uv_tty_t *m_tty = nullptr;
};

View File

@@ -23,7 +23,10 @@
*/
#include <string.h>
#include "base/kernel/Platform.h"
#include <cstring>
#include <uv.h>
@@ -33,13 +36,14 @@
#endif
#include "Platform.h"
namespace xmrig {
String Platform::m_userAgent;
} // namespace xmrig
xmrig::String Platform::m_userAgent;
void Platform::init(const char *userAgent)
void xmrig::Platform::init(const char *userAgent)
{
# ifdef XMRIG_FEATURE_TLS
SSL_library_init();

View File

@@ -26,12 +26,15 @@
#define XMRIG_PLATFORM_H
#include <stdint.h>
#include <cstdint>
#include "base/tools/String.h"
namespace xmrig {
class Platform
{
public:
@@ -56,8 +59,11 @@ public:
private:
static char *createUserAgent();
static xmrig::String m_userAgent;
static String m_userAgent;
};
} // namespace xmrig
#endif /* XMRIG_PLATFORM_H */

View File

@@ -5,6 +5,7 @@
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
@@ -23,32 +24,26 @@
*/
#include "backend/opencl/runners/tools/OclRxDataset.h"
#include "backend/opencl/wrappers/OclLib.h"
#include "crypto/rx/Rx.h"
#include "crypto/rx/RxDataset.h"
#include "base/kernel/Platform.h"
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "backend/cpu/Cpu.h"
void xmrig::OclRxDataset::createBuffer(cl_context ctx, const Job &job, bool host)
#include <hwloc.h>
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{
if (m_dataset) {
return;
auto cpu = static_cast<HwlocCpuInfo *>(Cpu::info());
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast<unsigned>(cpu_id));
if (pu == nullptr) {
return false;
}
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);
if (hwloc_set_cpubind(cpu->topology(), pu->cpuset, HWLOC_CPUBIND_THREAD | HWLOC_CPUBIND_STRICT) >= 0) {
return true;
}
}
xmrig::OclRxDataset::~OclRxDataset()
{
OclLib::release(m_dataset);
return hwloc_set_cpubind(cpu->topology(), pu->cpuset, HWLOC_CPUBIND_THREAD) >= 0;
}

View File

@@ -30,7 +30,7 @@
#include <uv.h>
#include "Platform.h"
#include "base/kernel/Platform.h"
#include "version.h"
#ifdef XMRIG_NVIDIA_PROJECT
@@ -38,7 +38,7 @@
#endif
char *Platform::createUserAgent()
char *xmrig::Platform::createUserAgent()
{
constexpr const size_t max = 256;
@@ -60,7 +60,8 @@ char *Platform::createUserAgent()
}
bool Platform::setThreadAffinity(uint64_t cpu_id)
#ifndef XMRIG_FEATURE_HWLOC
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{
thread_port_t mach_thread;
thread_affinity_policy_data_t policy = { static_cast<integer_t>(cpu_id) };
@@ -68,25 +69,26 @@ bool Platform::setThreadAffinity(uint64_t cpu_id)
return thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1) == KERN_SUCCESS;
}
#endif
uint32_t Platform::setTimerResolution(uint32_t resolution)
uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution)
{
return resolution;
}
void Platform::restoreTimerResolution()
void xmrig::Platform::restoreTimerResolution()
{
}
void Platform::setProcessPriority(int priority)
void xmrig::Platform::setProcessPriority(int priority)
{
}
void Platform::setThreadPriority(int priority)
void xmrig::Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;

View File

@@ -39,7 +39,7 @@
#include <uv.h>
#include "Platform.h"
#include "base/kernel/Platform.h"
#include "version.h"
#ifdef XMRIG_NVIDIA_PROJECT
@@ -52,7 +52,7 @@ typedef cpuset_t cpu_set_t;
#endif
char *Platform::createUserAgent()
char *xmrig::Platform::createUserAgent()
{
constexpr const size_t max = 256;
@@ -84,7 +84,8 @@ char *Platform::createUserAgent()
}
bool Platform::setThreadAffinity(uint64_t cpu_id)
#ifndef XMRIG_FEATURE_HWLOC
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{
cpu_set_t mn;
CPU_ZERO(&mn);
@@ -96,25 +97,26 @@ bool Platform::setThreadAffinity(uint64_t cpu_id)
return sched_setaffinity(gettid(), sizeof(cpu_set_t), &mn) == 0;
# endif
}
#endif
uint32_t Platform::setTimerResolution(uint32_t resolution)
uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution)
{
return resolution;
}
void Platform::restoreTimerResolution()
void xmrig::Platform::restoreTimerResolution()
{
}
void Platform::setProcessPriority(int priority)
void xmrig::Platform::setProcessPriority(int priority)
{
}
void Platform::setThreadPriority(int priority)
void xmrig::Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;

View File

@@ -29,8 +29,8 @@
#include <uv.h>
#include "base/kernel/Platform.h"
#include "base/io/log/Log.h"
#include "Platform.h"
#include "version.h"
@@ -51,10 +51,10 @@ static inline OSVERSIONINFOEX winOsVersion()
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (ntdll ) {
RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(GetProcAddress(ntdll, "RtlGetVersion"));
auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(GetProcAddress(ntdll, "RtlGetVersion"));
if (pRtlGetVersion) {
pRtlGetVersion((LPOSVERSIONINFO) &result);
pRtlGetVersion(reinterpret_cast<LPOSVERSIONINFO>(&result));
}
}
@@ -62,7 +62,7 @@ static inline OSVERSIONINFOEX winOsVersion()
}
char *Platform::createUserAgent()
char *xmrig::Platform::createUserAgent()
{
const auto osver = winOsVersion();
constexpr const size_t max = 256;
@@ -91,7 +91,8 @@ char *Platform::createUserAgent()
}
bool Platform::setThreadAffinity(uint64_t cpu_id)
#ifndef XMRIG_FEATURE_HWLOC
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{
if (cpu_id >= 64) {
LOG_ERR("Unable to set affinity. Windows supports only affinity up to 63.");
@@ -99,9 +100,10 @@ bool Platform::setThreadAffinity(uint64_t cpu_id)
return SetThreadAffinityMask(GetCurrentThread(), 1ULL << cpu_id) != 0;
}
#endif
uint32_t Platform::setTimerResolution(uint32_t resolution)
uint32_t xmrig::Platform::setTimerResolution(uint32_t resolution)
{
# ifdef XMRIG_AMD_PROJECT
TIMECAPS tc;
@@ -119,7 +121,7 @@ uint32_t Platform::setTimerResolution(uint32_t resolution)
}
void Platform::restoreTimerResolution()
void xmrig::Platform::restoreTimerResolution()
{
# ifdef XMRIG_AMD_PROJECT
if (timerResolution) {
@@ -129,7 +131,7 @@ void Platform::restoreTimerResolution()
}
void Platform::setProcessPriority(int priority)
void xmrig::Platform::setProcessPriority(int priority)
{
if (priority == -1) {
return;
@@ -166,7 +168,7 @@ void Platform::setProcessPriority(int priority)
}
void Platform::setThreadPriority(int priority)
void xmrig::Platform::setThreadPriority(int priority)
{
if (priority == -1) {
return;

View File

@@ -56,7 +56,6 @@ 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; }

View File

@@ -89,6 +89,7 @@ public:
RandomXInitKey = 1022,
RandomXNumaKey = 1023,
CPUMaxThreadsKey = 1026,
MemoryPoolKey = 1027,
// xmrig amd
OclPlatformKey = 1400,

View File

@@ -908,8 +908,14 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status)
LOG_ERR("[%s] connect error: \"%s\"", client->url(), uv_strerror(status));
}
if (client->state() == ReconnectingState) {
return;
}
if (client->state() != ConnectingState) {
LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state());
if (!client->isQuiet()) {
LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state());
}
return;
}

View File

@@ -23,6 +23,7 @@
"huge-pages": true,
"hw-aes": null,
"priority": null,
"memory-pool": false,
"max-threads-hint": 100,
"asm": true,
"argon2-impl": null,

View File

@@ -23,15 +23,17 @@
*/
#include <cassert>
#include "backend/cpu/Cpu.h"
#include "core/Controller.h"
#include "backend/cpu/Cpu.h"
#include "core/config/Config.h"
#include "core/Miner.h"
#include "crypto/common/VirtualMemory.h"
#include "net/Network.h"
#include <cassert>
xmrig::Controller::Controller(Process *process) :
Base(process)
{
@@ -41,6 +43,8 @@ xmrig::Controller::Controller(Process *process) :
xmrig::Controller::~Controller()
{
delete m_network;
VirtualMemory::destroy();
}
@@ -48,7 +52,10 @@ int xmrig::Controller::init()
{
Base::init();
VirtualMemory::init(config()->cpu().memPoolSize(), config()->cpu().isHugePages());
m_network = new Network(this);
return 0;
}

View File

@@ -72,12 +72,8 @@ class MinerPrivate
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(MinerPrivate)
inline MinerPrivate(Controller *controller) : controller(controller)
{
# ifdef XMRIG_ALGO_RANDOMX
Rx::init();
# endif
}
inline MinerPrivate(Controller *controller) : controller(controller) {}
inline ~MinerPrivate()
@@ -232,9 +228,9 @@ public:
# ifdef XMRIG_ALGO_RANDOMX
bool initRX(IRxListener *listener)
inline bool initRX()
{
return Rx::init(job, controller->config()->rx().threads(), controller->config()->cpu().isHugePages(), controller->config()->rx().isNUMA(), listener);
return Rx::init(job, controller->config()->rx(), controller->config()->cpu().isHugePages());
}
# endif
@@ -261,6 +257,10 @@ public:
xmrig::Miner::Miner(Controller *controller)
: d_ptr(new MinerPrivate(controller))
{
# ifdef XMRIG_ALGO_RANDOMX
Rx::init(this);
# endif
controller->addListener(this);
# ifdef XMRIG_FEATURE_API
@@ -402,7 +402,7 @@ void xmrig::Miner::setJob(const Job &job, bool donate)
}
# ifdef XMRIG_ALGO_RANDOMX
const bool ready = d_ptr->initRX(this);
const bool ready = d_ptr->initRX();
# else
constexpr const bool ready = true;
# endif

View File

@@ -33,6 +33,7 @@
#include "base/api/interfaces/IApiListener.h"
#include "base/kernel/interfaces/IBaseListener.h"
#include "base/kernel/interfaces/ITimerListener.h"
#include "base/tools/Object.h"
#include "crypto/common/Algorithm.h"
@@ -48,6 +49,8 @@ class IBackend;
class Miner : public ITimerListener, public IBaseListener, public IApiListener, public IRxListener
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(Miner)
Miner(Controller *controller);
~Miner() override;

View File

@@ -23,9 +23,9 @@
*/
#include <algorithm>
#include <string.h>
#include <cstring>
#include <uv.h>
#include <inttypes.h>
#include <cinttypes>
#include "backend/cpu/Cpu.h"
@@ -50,8 +50,7 @@
namespace xmrig {
static const char *kCPU = "cpu";
static constexpr const uint32_t kVersion = 1;
static const char *kCPU = "cpu";
#ifdef XMRIG_ALGO_RANDOMX
static const char *kRandomX = "randomx";
@@ -79,7 +78,7 @@ public:
}
xmrig::Config::Config() : BaseConfig(),
xmrig::Config::Config() :
d_ptr(new ConfigPrivate())
{
}
@@ -119,10 +118,6 @@ bool xmrig::Config::isShouldSave() const
return false;
}
if (version() < kVersion) {
return true;
}
# ifdef XMRIG_FEATURE_OPENCL
if (cl().isShouldSave()) {
return true;
@@ -139,7 +134,7 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName)
return false;
}
d_ptr->cpu.read(reader.getValue(kCPU), version());
d_ptr->cpu.read(reader.getValue(kCPU));
# ifdef XMRIG_ALGO_RANDOMX
if (!d_ptr->rx.read(reader.getValue(kRandomX))) {
@@ -170,7 +165,6 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const
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);

View File

@@ -26,11 +26,12 @@
#define XMRIG_CONFIG_H
#include <stdint.h>
#include <cstdint>
#include "backend/cpu/CpuConfig.h"
#include "base/kernel/config/BaseConfig.h"
#include "base/tools/Object.h"
#include "rapidjson/fwd.h"
@@ -46,6 +47,8 @@ class OclConfig;
class Config : public BaseConfig
{
public:
XMRIG_DISABLE_COPY_MOVE(Config);
Config();
~Config() override;

View File

@@ -141,6 +141,10 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
case IConfig::CPUMaxThreadsKey: /* --cpu-max-threads-hint */
return set(doc, kCpu, "max-threads-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
case IConfig::MemoryPoolKey: /* --cpu-memory-pool */
return set(doc, kCpu, "memory-pool", static_cast<int64_t>(strtol(arg, nullptr, 10)));
break;
# ifdef XMRIG_FEATURE_ASM
case IConfig::AssemblyKey: /* --asm */
return set(doc, kCpu, "asm", arg);

View File

@@ -57,6 +57,7 @@ R"===(
"huge-pages": true,
"hw-aes": null,
"priority": null,
"memory-pool": false,
"max-threads-hint": 100,
"asm": true,
"argon2-impl": null,

View File

@@ -84,6 +84,7 @@ static const option options[] = {
{ "no-cpu", 0, nullptr, IConfig::CPUKey },
{ "max-cpu-usage", 1, nullptr, IConfig::CPUMaxThreadsKey },
{ "cpu-max-threads-hint", 1, nullptr, IConfig::CPUMaxThreadsKey },
{ "cpu-memory-pool", 1, nullptr, IConfig::MemoryPoolKey },
# ifdef XMRIG_FEATURE_TLS
{ "tls", 0, nullptr, IConfig::TlsKey },
{ "tls-fingerprint", 1, nullptr, IConfig::FingerprintKey },

View File

@@ -46,6 +46,7 @@ static inline const std::string &usage()
u += "Usage: " APP_ID " [OPTIONS]\n\nNetwork:\n";
u += " -o, --url=URL URL of mining server\n";
u += " -a, --algo=ALGO mining algorithm https://xmrig.com/docs/algorithms\n";
u += " --coin=COIN specify coin instead of algorithm\n";
u += " -u, --user=USERNAME username for mining server\n";
u += " -p, --pass=PASSWORD password for mining server\n";
u += " -O, --userpass=U:P username:password pair for mining server\n";
@@ -77,6 +78,7 @@ static inline const std::string &usage()
u += " --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n";
u += " --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n";
u += " --cpu-max-threads-hint=N maximum CPU threads count (in percentage) hint for autoconfig\n";
u += " --cpu-memory-pool=N number of 2 MB pages for persistent memory pool, -1 (auto), 0 (disable)\n";
u += " --no-huge-pages disable huge pages support\n";
u += " --asm=ASM ASM optimizations, possible values: auto, none, intel, ryzen, bulldozer\n";

View File

@@ -110,6 +110,8 @@ static AlgoName const algorithm_names[] = {
{ "RandomWOW", nullptr, Algorithm::RX_WOW },
{ "randomx/loki", "rx/loki", Algorithm::RX_LOKI },
{ "RandomXL", nullptr, Algorithm::RX_LOKI },
{ "randomx/arq", "rx/arq", Algorithm::RX_ARQ },
{ "RandomARQ", nullptr, Algorithm::RX_ARQ },
# endif
# ifdef XMRIG_ALGO_ARGON2
{ "argon2/chukwa", nullptr, Algorithm::AR2_CHUKWA },
@@ -141,6 +143,9 @@ size_t xmrig::Algorithm::l2() const
case RX_WOW:
return 0x20000;
case RX_ARQ:
return 0x10000;
default:
break;
}
@@ -171,6 +176,9 @@ size_t xmrig::Algorithm::l3() const
case RX_WOW:
return oneMiB;
case RX_ARQ:
return oneMiB / 4;
default:
break;
}
@@ -261,6 +269,7 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id)
case RX_0:
case RX_WOW:
case RX_LOKI:
case RX_ARQ:
return RANDOM_X;
# endif

View File

@@ -66,6 +66,7 @@ public:
RX_0, // "rx/0" RandomX (reference configuration).
RX_WOW, // "rx/wow" RandomWOW (Wownero).
RX_LOKI, // "rx/loki" RandomXL (Loki).
RX_ARQ, // "rx/arq" RandomARQ (Arqma).
AR2_CHUKWA, // "argon2/chukwa" Argon2id (Chukwa).
AR2_WRKZ, // "argon2/wrkz" Argon2id (WRKZ)
MAX

View File

@@ -49,6 +49,8 @@ struct CoinName
static CoinName const coin_names[] = {
{ "monero", Coin::MONERO },
{ "xmr", Coin::MONERO },
{ "arqma", Coin::ARQMA },
{ "arq", Coin::ARQMA }
};
@@ -58,8 +60,15 @@ static CoinName const coin_names[] = {
xmrig::Algorithm::Id xmrig::Coin::algorithm(uint8_t blobVersion) const
{
if (id() == MONERO) {
switch (id()) {
case MONERO:
return (blobVersion >= 12) ? Algorithm::RX_0 : Algorithm::CN_R;
case ARQMA:
return (blobVersion >= 15) ? Algorithm::RX_ARQ : Algorithm::CN_PICO_0;
case INVALID:
break;
}
return Algorithm::INVALID;

View File

@@ -40,6 +40,7 @@ public:
enum Id : int {
INVALID = -1,
MONERO,
ARQMA
};

View File

@@ -0,0 +1,95 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/MemoryPool.h"
#include "crypto/common/VirtualMemory.h"
#include <cassert>
namespace xmrig {
constexpr size_t pageSize = 2 * 1024 * 1024;
} // namespace xmrig
xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node) :
m_size(size)
{
if (!size) {
return;
}
m_memory = new VirtualMemory(size * pageSize, hugePages, false, node);
}
xmrig::MemoryPool::~MemoryPool()
{
delete m_memory;
}
bool xmrig::MemoryPool::isHugePages(uint32_t) const
{
return m_memory && m_memory->isHugePages();
}
uint8_t *xmrig::MemoryPool::get(size_t size, uint32_t)
{
assert(!(size % pageSize));
if (!m_memory || (m_memory->size() - m_offset) < size) {
return nullptr;
}
uint8_t *out = m_memory->scratchpad() + m_offset;
m_offset += size;
++m_refs;
return out;
}
void xmrig::MemoryPool::release(uint32_t)
{
assert(m_refs > 0);
if (m_refs > 0) {
--m_refs;
}
if (m_refs == 0) {
m_offset = 0;
}
}

View File

@@ -0,0 +1,66 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_MEMORYPOOL_H
#define XMRIG_MEMORYPOOL_H
#include "backend/common/interfaces/IMemoryPool.h"
#include "base/tools/Object.h"
namespace xmrig {
class VirtualMemory;
class MemoryPool : public IMemoryPool
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(MemoryPool)
MemoryPool(size_t size, bool hugePages, uint32_t node = 0);
~MemoryPool() override;
protected:
bool isHugePages(uint32_t node) const override;
uint8_t *get(size_t size, uint32_t node) override;
void release(uint32_t node) override;
private:
size_t m_size = 0;
size_t m_refs = 0;
size_t m_offset = 0;
VirtualMemory *m_memory = nullptr;
};
} /* namespace xmrig */
#endif /* XMRIG_MEMORYPOOL_H */

View File

@@ -0,0 +1,106 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/NUMAMemoryPool.h"
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include "crypto/common/MemoryPool.h"
#include <algorithm>
namespace xmrig {
constexpr size_t pageSize = 2 * 1024 * 1024;
} // namespace xmrig
xmrig::NUMAMemoryPool::NUMAMemoryPool(size_t size, bool hugePages) :
m_hugePages(hugePages),
m_nodeSize(std::max<size_t>(size / Cpu::info()->nodes(), 1)),
m_size(size)
{
}
xmrig::NUMAMemoryPool::~NUMAMemoryPool()
{
for (auto kv : m_map) {
delete kv.second;
}
}
bool xmrig::NUMAMemoryPool::isHugePages(uint32_t node) const
{
if (!m_size) {
return false;
}
return getOrCreate(node)->isHugePages(node);
}
uint8_t *xmrig::NUMAMemoryPool::get(size_t size, uint32_t node)
{
if (!m_size) {
return nullptr;
}
return getOrCreate(node)->get(size, node);
}
void xmrig::NUMAMemoryPool::release(uint32_t node)
{
const auto pool = get(node);
if (pool) {
pool->release(node);
}
}
xmrig::IMemoryPool *xmrig::NUMAMemoryPool::get(uint32_t node) const
{
return m_map.count(node) ? m_map.at(node) : nullptr;
}
xmrig::IMemoryPool *xmrig::NUMAMemoryPool::getOrCreate(uint32_t node) const
{
auto pool = get(node);
if (!pool) {
pool = new MemoryPool(m_nodeSize, m_hugePages, node);
m_map.insert({ node, pool });
}
return pool;
}

View File

@@ -0,0 +1,72 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_NUMAMEMORYPOOL_H
#define XMRIG_NUMAMEMORYPOOL_H
#include "backend/common/interfaces/IMemoryPool.h"
#include "base/tools/Object.h"
#include <map>
namespace xmrig {
class IMemoryPool;
class NUMAMemoryPool : public IMemoryPool
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(NUMAMemoryPool)
NUMAMemoryPool(size_t size, bool hugePages);
~NUMAMemoryPool() override;
protected:
bool isHugePages(uint32_t node) const override;
uint8_t *get(size_t size, uint32_t node) override;
void release(uint32_t node) override;
private:
IMemoryPool *get(uint32_t node) const;
IMemoryPool *getOrCreate(uint32_t node) const;
bool m_hugePages = true;
size_t m_nodeSize = 0;
size_t m_size = 0;
mutable std::map<uint32_t, IMemoryPool *> m_map;
};
} /* namespace xmrig */
#endif /* XMRIG_NUMAMEMORYPOOL_H */

View File

@@ -25,61 +25,102 @@
*/
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include "base/io/log/Log.h"
#include "crypto/common/MemoryPool.h"
#include "crypto/common/portable/mm_malloc.h"
#ifdef XMRIG_FEATURE_HWLOC
# include <hwloc.h>
# include "backend/cpu/platform/HwlocCpuInfo.h"
#
# if HWLOC_API_VERSION < 0x00010b00
# define HWLOC_OBJ_NUMANODE HWLOC_OBJ_NODE
# endif
# include "crypto/common/NUMAMemoryPool.h"
#endif
#include "base/io/log/Log.h"
#include "crypto/common/VirtualMemory.h"
#include <cinttypes>
#include <mutex>
uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity)
namespace xmrig {
static IMemoryPool *pool = nullptr;
static std::mutex mutex;
} // namespace xmrig
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node, size_t alignSize) :
m_size(align(size)),
m_node(node)
{
# ifdef XMRIG_FEATURE_HWLOC
if (affinity < 0 || !HwlocCpuInfo::has(HwlocCpuInfo::SET_THISTHREAD_MEMBIND)) {
return 0;
}
if (usePool) {
std::lock_guard<std::mutex> lock(mutex);
if (hugePages && !pool->isHugePages(node) && allocateLargePagesMemory()) {
return;
}
hwloc_topology_t topology;
hwloc_topology_init(&topology);
hwloc_topology_load(topology);
m_scratchpad = pool->get(m_size, node);
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, pool->isHugePages(node));
m_flags.set(FLAG_EXTERNAL, true);
const unsigned puId = static_cast<unsigned>(affinity);
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(topology, puId);
# if HWLOC_API_VERSION >= 0x20000
if (pu == nullptr || hwloc_set_membind(topology, pu->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD | HWLOC_MEMBIND_BYNODESET) < 0) {
# else
if (pu == nullptr || hwloc_set_membind_nodeset(topology, pu->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_THREAD) < 0) {
# endif
LOG_WARN("CPU #%02u warning: \"can't bind memory\"", puId);
}
uint32_t nodeId = 0;
if (pu) {
hwloc_obj_t node = nullptr;
while ((node = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, node)) != nullptr) {
if (hwloc_bitmap_intersects(node->cpuset, pu->cpuset)) {
nodeId = node->os_index;
break;
}
return;
}
}
hwloc_topology_destroy(topology);
if (hugePages && allocateLargePagesMemory()) {
return;
}
return nodeId;
# else
return 0;
# endif
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, alignSize));
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (m_flags.test(FLAG_EXTERNAL)) {
std::lock_guard<std::mutex> lock(mutex);
pool->release(m_node);
}
else if (isHugePages()) {
freeLargePagesMemory();
}
else {
_mm_free(m_scratchpad);
}
}
#ifndef XMRIG_FEATURE_HWLOC
uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t)
{
return 0;
}
#endif
void xmrig::VirtualMemory::destroy()
{
delete pool;
}
void xmrig::VirtualMemory::init(size_t poolSize, bool hugePages)
{
if (!pool) {
osInit();
}
# ifdef XMRIG_FEATURE_HWLOC
if (Cpu::info()->nodes() > 1) {
pool = new NUMAMemoryPool(align(poolSize, Cpu::info()->nodes()), hugePages);
} else
# endif
{
pool = new MemoryPool(poolSize, hugePages);
}
}

View File

@@ -28,8 +28,12 @@
#define XMRIG_VIRTUALMEMORY_H
#include <stddef.h>
#include <stdint.h>
#include "base/tools/Object.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <utility>
@@ -39,43 +43,50 @@ namespace xmrig {
class VirtualMemory
{
public:
inline VirtualMemory() {}
VirtualMemory(size_t size, bool hugePages = true, size_t align = 64);
XMRIG_DISABLE_COPY_MOVE_DEFAULT(VirtualMemory)
VirtualMemory(size_t size, bool hugePages, bool usePool, uint32_t node = 0, size_t alignSize = 64);
~VirtualMemory();
inline bool isHugePages() const { return m_flags & HUGEPAGES; }
inline bool isHugePages() const { return m_flags.test(FLAG_HUGEPAGES); }
inline size_t size() const { return m_size; }
inline uint8_t *scratchpad() const { return m_scratchpad; }
inline std::pair<size_t, size_t> hugePages() const
{
return std::pair<size_t, size_t>(isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152);
return { isHugePages() ? (align(size()) / 2097152) : 0, align(size()) / 2097152 };
}
static bool isHugepagesAvailable();
static uint32_t bindToNUMANode(int64_t affinity);
static void *allocateExecutableMemory(size_t size);
static void *allocateLargePagesMemory(size_t size);
static void destroy();
static void flushInstructionCache(void *p, size_t size);
static void freeLargePagesMemory(void *p, size_t size);
static void init(bool hugePages);
static void init(size_t poolSize, bool hugePages);
static void protectExecutableMemory(void *p, size_t size);
static void unprotectExecutableMemory(void *p, size_t size);
static inline bool isHugepagesAvailable() { return (m_globalFlags & HUGEPAGES_AVAILABLE) != 0; }
static inline constexpr size_t align(size_t pos, size_t align = 2097152) { return ((pos - 1) / align + 1) * align; }
private:
enum Flags {
HUGEPAGES_AVAILABLE = 1,
HUGEPAGES = 2,
LOCK = 4
FLAG_HUGEPAGES,
FLAG_LOCK,
FLAG_EXTERNAL,
FLAG_MAX
};
static int m_globalFlags;
static void osInit();
int m_flags = 0;
size_t m_size = 0;
uint8_t *m_scratchpad = nullptr;
bool allocateLargePagesMemory();
void freeLargePagesMemory();
const size_t m_size;
const uint32_t m_node;
std::bitset<FLAG_MAX> m_flags;
uint8_t *m_scratchpad = nullptr;
};

View File

@@ -0,0 +1,56 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
* Copyright 2018-2019 tevador <tevador@gmail.com>
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "crypto/common/VirtualMemory.h"
#include "backend/cpu/Cpu.h"
#include "backend/cpu/platform/HwlocCpuInfo.h"
#include "base/io/log/Log.h"
#include <hwloc.h>
uint32_t xmrig::VirtualMemory::bindToNUMANode(int64_t affinity)
{
if (affinity < 0 || Cpu::info()->nodes() < 2) {
return 0;
}
auto cpu = static_cast<HwlocCpuInfo *>(Cpu::info());
hwloc_obj_t pu = hwloc_get_pu_obj_by_os_index(cpu->topology(), static_cast<unsigned>(affinity));
char *buffer;
hwloc_bitmap_asprintf(&buffer, pu->cpuset);
if (pu == nullptr || !cpu->membind(pu->nodeset)) {
LOG_WARN("CPU #%02" PRId64 " warning: \"can't bind memory\"", affinity);
return 0;
}
return hwloc_bitmap_first(pu->nodeset);
}

View File

@@ -25,7 +25,7 @@
*/
#include <stdlib.h>
#include <cstdlib>
#include <sys/mman.h>
@@ -38,51 +38,12 @@
#endif
int xmrig::VirtualMemory::m_globalFlags = 0;
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) :
m_size(VirtualMemory::align(size))
bool xmrig::VirtualMemory::isHugepagesAvailable()
{
if (hugePages) {
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags |= HUGEPAGES;
madvise(m_scratchpad, size, MADV_RANDOM | MADV_WILLNEED);
if (mlock(m_scratchpad, m_size) == 0) {
m_flags |= LOCK;
}
return;
}
}
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, align));
return true;
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (isHugePages()) {
if (m_flags & LOCK) {
munlock(m_scratchpad, m_size);
}
freeLargePagesMemory(m_scratchpad, m_size);
}
else {
_mm_free(m_scratchpad);
}
}
void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size)
{
# if defined(__APPLE__)
@@ -123,14 +84,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t size)
}
void xmrig::VirtualMemory::init(bool hugePages)
{
if (hugePages) {
m_globalFlags = HUGEPAGES | HUGEPAGES_AVAILABLE;
}
}
void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size)
{
mprotect(p, size, PROT_READ | PROT_EXEC);
@@ -141,3 +94,37 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size)
{
mprotect(p, size, PROT_WRITE | PROT_EXEC);
}
void xmrig::VirtualMemory::osInit()
{
}
bool xmrig::VirtualMemory::allocateLargePagesMemory()
{
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, true);
madvise(m_scratchpad, m_size, MADV_RANDOM | MADV_WILLNEED);
if (mlock(m_scratchpad, m_size) == 0) {
m_flags.set(FLAG_LOCK, true);
}
return true;
}
return false;
}
void xmrig::VirtualMemory::freeLargePagesMemory()
{
if (m_flags.test(FLAG_LOCK)) {
munlock(m_scratchpad, m_size);
}
freeLargePagesMemory(m_scratchpad, m_size);
}

View File

@@ -36,6 +36,12 @@
#include "crypto/common/VirtualMemory.h"
namespace xmrig {
static bool hugepagesAvailable = false;
/*****************************************************************
SetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
@@ -83,7 +89,7 @@ static BOOL SetLockPagesPrivilege() {
static LSA_UNICODE_STRING StringToLsaUnicodeString(LPCTSTR string) {
LSA_UNICODE_STRING lsaString;
DWORD dwLen = (DWORD) wcslen(string);
const auto dwLen = (DWORD) wcslen(string);
lsaString.Buffer = (LPWSTR) string;
lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR));
lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR));
@@ -141,37 +147,12 @@ static BOOL TrySetLockPagesPrivilege() {
}
int xmrig::VirtualMemory::m_globalFlags = 0;
} // namespace xmrig
xmrig::VirtualMemory::VirtualMemory(size_t size, bool hugePages, size_t align) :
m_size(VirtualMemory::align(size))
bool xmrig::VirtualMemory::isHugepagesAvailable()
{
if (hugePages) {
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags |= HUGEPAGES;
return;
}
}
m_scratchpad = static_cast<uint8_t*>(_mm_malloc(m_size, align));
}
xmrig::VirtualMemory::~VirtualMemory()
{
if (!m_scratchpad) {
return;
}
if (isHugePages()) {
freeLargePagesMemory(m_scratchpad, m_size);
}
else {
_mm_free(m_scratchpad);
}
return hugepagesAvailable;
}
@@ -206,20 +187,6 @@ void xmrig::VirtualMemory::freeLargePagesMemory(void *p, size_t)
}
void xmrig::VirtualMemory::init(bool hugePages)
{
if (!hugePages) {
return;
}
m_globalFlags = HUGEPAGES;
if (TrySetLockPagesPrivilege()) {
m_globalFlags |= HUGEPAGES_AVAILABLE;
}
}
void xmrig::VirtualMemory::protectExecutableMemory(void *p, size_t size)
{
DWORD oldProtect;
@@ -232,3 +199,28 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size)
DWORD oldProtect;
VirtualProtect(p, size, PAGE_EXECUTE_READWRITE, &oldProtect);
}
void xmrig::VirtualMemory::osInit()
{
hugepagesAvailable = TrySetLockPagesPrivilege();
}
bool xmrig::VirtualMemory::allocateLargePagesMemory()
{
m_scratchpad = static_cast<uint8_t*>(allocateLargePagesMemory(m_size));
if (m_scratchpad) {
m_flags.set(FLAG_HUGEPAGES, true);
return true;
}
return false;
}
void xmrig::VirtualMemory::freeLargePagesMemory()
{
freeLargePagesMemory(m_scratchpad, m_size);
}

View File

@@ -268,8 +268,6 @@ namespace randomx {
}
void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) {
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;
@@ -280,13 +278,21 @@ namespace randomx {
memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask));
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;
instructionOffsets[i] = codePos;
(this->*(engine[instr.opcode]))(instr, i);
//mark all registers as used
uint64_t* r = (uint64_t*)registerUsage;
uint64_t k = codePos;
k |= k << 32;
for (unsigned j = 0; j < RegistersCount / 2; ++j) {
r[j] = k;
}
for (int i = 0, n = static_cast<int>(RandomX_CurrentConfig.ProgramSize); i < n; ++i) {
Instruction instr = prog(i);
*((uint64_t*)&instr) &= (uint64_t(-1) - (0xFFFF << 8)) | ((RegistersCount - 1) << 8) | ((RegistersCount - 1) << 16);
(this->*(engine[instr.opcode]))(instr);
}
emit(REX_MOV_RR, code, codePos);
emitByte(0xc0 + pcfg.readReg2, code, codePos);
emit(REX_XOR_EAX, code, codePos);
@@ -402,7 +408,7 @@ namespace randomx {
}
}
void JitCompilerX86::genAddressReg(Instruction& instr, uint8_t* code, int& codePos, bool rax) {
void JitCompilerX86::genAddressReg(const 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) {
@@ -416,7 +422,7 @@ namespace randomx {
emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask, code, codePos);
}
void JitCompilerX86::genAddressRegDst(Instruction& instr, uint8_t* code, int& codePos) {
void JitCompilerX86::genAddressRegDst(const Instruction& instr, uint8_t* code, int& codePos) {
emit(LEA_32, code, codePos);
emitByte(0x80 + instr.dst, code, codePos);
if (instr.dst == RegisterNeedsSib) {
@@ -432,7 +438,7 @@ namespace randomx {
}
}
void JitCompilerX86::genAddressImm(Instruction& instr, uint8_t* code, int& codePos) {
void JitCompilerX86::genAddressImm(const Instruction& instr, uint8_t* code, int& codePos) {
emit32(instr.getImm32() & ScratchpadL3Mask, code, codePos);
}
@@ -447,17 +453,18 @@ namespace randomx {
0x3c8d4f,
};
void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) {
void JitCompilerX86::h_IADD_RS(const Instruction& instr) {
int pos = codePos;
uint8_t* const p = code + pos;
registerUsage[instr.dst] = i;
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);
pos += ((instr.dst == RegisterNeedsDisplacement) ? 8 : 4);
registerUsage[instr.dst] = pos;
codePos = pos;
}
static const uint32_t template_IADD_M[8] = {
@@ -471,11 +478,10 @@ namespace randomx {
0x063c034c,
};
void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
void JitCompilerX86::h_IADD_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos);
emit32(template_IADD_M[instr.dst], p, pos);
@@ -486,6 +492,7 @@ namespace randomx {
genAddressImm(instr, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
@@ -493,11 +500,10 @@ namespace randomx {
emitByte((scale << 6) | (index << 3) | base, code, codePos);
}
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
void JitCompilerX86::h_ISUB_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_SUB_RR, p, pos);
emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos);
@@ -508,14 +514,14 @@ namespace randomx {
emit32(instr.getImm32(), p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
void JitCompilerX86::h_ISUB_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos);
emit(REX_SUB_RM, p, pos);
@@ -528,14 +534,14 @@ namespace randomx {
genAddressImm(instr, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
void JitCompilerX86::h_IMUL_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_IMUL_RR, p, pos);
emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos);
@@ -546,14 +552,14 @@ namespace randomx {
emit32(instr.getImm32(), p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
void JitCompilerX86::h_IMUL_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos);
emit(REX_IMUL_RM, p, pos);
@@ -566,14 +572,14 @@ namespace randomx {
genAddressImm(instr, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
void JitCompilerX86::h_IMULH_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
emit(REX_MOV_RR64, p, pos);
emitByte(0xc0 + instr.dst, p, pos);
emit(REX_MUL_R, p, pos);
@@ -581,14 +587,14 @@ namespace randomx {
emit(REX_MOV_R64R, p, pos);
emitByte(0xc2 + 8 * instr.dst, p, pos);
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
void JitCompilerX86::h_IMULH_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos, false);
emit(REX_MOV_RR64, p, pos);
@@ -605,14 +611,14 @@ namespace randomx {
emit(REX_MOV_R64R, p, pos);
emitByte(0xc2 + 8 * instr.dst, p, pos);
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
void JitCompilerX86::h_ISMULH_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
emit(REX_MOV_RR64, p, pos);
emitByte(0xc0 + instr.dst, p, pos);
emit(REX_MUL_R, p, pos);
@@ -620,14 +626,14 @@ namespace randomx {
emit(REX_MOV_R64R, p, pos);
emitByte(0xc2 + 8 * instr.dst, p, pos);
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
void JitCompilerX86::h_ISMULH_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos, false);
emit(REX_MOV_RR64, p, pos);
@@ -644,41 +650,41 @@ namespace randomx {
emit(REX_MOV_R64R, p, pos);
emitByte(0xc2 + 8 * instr.dst, p, pos);
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
void JitCompilerX86::h_IMUL_RCP(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
uint64_t divisor = instr.getImm32();
if (!isZeroOrPowerOf2(divisor)) {
registerUsage[instr.dst] = i;
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);
registerUsage[instr.dst] = pos;
}
codePos = pos;
}
void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
void JitCompilerX86::h_INEG_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
emit(REX_NEG, p, pos);
emitByte(0xd8 + instr.dst, p, pos);
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
void JitCompilerX86::h_IXOR_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_XOR_RR, p, pos);
emitByte(0xc0 + 8 * instr.dst + instr.src, p, pos);
@@ -689,14 +695,14 @@ namespace randomx {
emit32(instr.getImm32(), p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
void JitCompilerX86::h_IXOR_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, p, pos);
emit(REX_XOR_RM, p, pos);
@@ -709,14 +715,14 @@ namespace randomx {
genAddressImm(instr, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
void JitCompilerX86::h_IROR_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_MOV_RR, p, pos);
emitByte(0xc8 + instr.src, p, pos);
@@ -729,14 +735,14 @@ namespace randomx {
emitByte(instr.getImm32() & 63, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
void JitCompilerX86::h_IROL_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_MOV_RR, p, pos);
emitByte(0xc8 + instr.src, p, pos);
@@ -749,24 +755,25 @@ namespace randomx {
emitByte(instr.getImm32() & 63, p, pos);
}
registerUsage[instr.dst] = pos;
codePos = pos;
}
void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
void JitCompilerX86::h_ISWAP_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
if (instr.src != instr.dst) {
registerUsage[instr.dst] = i;
registerUsage[instr.src] = i;
emit(REX_XCHG, p, pos);
emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos);
registerUsage[instr.dst] = pos;
registerUsage[instr.src] = pos;
}
codePos = pos;
}
void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
void JitCompilerX86::h_FSWAP_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
@@ -777,105 +784,105 @@ namespace randomx {
codePos = pos;
}
void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
void JitCompilerX86::h_FADD_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
const uint32_t src = instr.src % RegisterCountFlt;
emit(REX_ADDPD, p, pos);
emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos);
emitByte(0xc0 + src + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
void JitCompilerX86::h_FADD_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
genAddressReg(instr, p, pos);
emit(REX_CVTDQ2PD_XMM12, p, pos);
emit(REX_ADDPD, p, pos);
emitByte(0xc4 + 8 * instr.dst, p, pos);
emitByte(0xc4 + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) {
void JitCompilerX86::h_FSUB_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
const uint32_t src = instr.src % RegisterCountFlt;
emit(REX_SUBPD, p, pos);
emitByte(0xc0 + instr.src + 8 * instr.dst, p, pos);
emitByte(0xc0 + src + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
void JitCompilerX86::h_FSUB_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
genAddressReg(instr, p, pos);
emit(REX_CVTDQ2PD_XMM12, p, pos);
emit(REX_SUBPD, p, pos);
emitByte(0xc4 + 8 * instr.dst, p, pos);
emitByte(0xc4 + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
void JitCompilerX86::h_FSCAL_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
emit(REX_XORPS, p, pos);
emitByte(0xc7 + 8 * instr.dst, p, pos);
emitByte(0xc7 + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) {
void JitCompilerX86::h_FMUL_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
const uint32_t src = instr.src % RegisterCountFlt;
emit(REX_MULPD, p, pos);
emitByte(0xe0 + instr.src + 8 * instr.dst, p, pos);
emitByte(0xe0 + src + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
void JitCompilerX86::h_FDIV_M(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
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);
emitByte(0xe4 + 8 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
void JitCompilerX86::h_FSQRT_R(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
instr.dst %= RegisterCountFlt;
const uint32_t dst = instr.dst % RegisterCountFlt;
emit(SQRTPD, p, pos);
emitByte(0xe4 + 9 * instr.dst, p, pos);
emitByte(0xe4 + 9 * dst, p, pos);
codePos = pos;
}
void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
void JitCompilerX86::h_CFROUND(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
@@ -891,12 +898,11 @@ namespace randomx {
codePos = pos;
}
void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) {
void JitCompilerX86::h_CBRANCH(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
int reg = instr.dst;
int target = registerUsage[reg] + 1;
emit(REX_ADD_I, p, pos);
emitByte(0xc0 + reg, p, pos);
int shift = instr.getModCond() + RandomX_CurrentConfig.JumpOffset;
@@ -908,10 +914,10 @@ namespace randomx {
emitByte(0xc0 + reg, p, pos);
emit32(RandomX_CurrentConfig.ConditionMask_Calculated << shift, p, pos);
emit(JZ, p, pos);
emit32(instructionOffsets[target] - (pos + 4), p, pos);
emit32(registerUsage[reg] - (pos + 4), p, pos);
//mark all registers as used
uint64_t* r = (uint64_t*) registerUsage;
uint64_t k = i;
uint64_t k = pos;
k |= k << 32;
for (unsigned j = 0; j < RegistersCount / 2; ++j) {
r[j] = k;
@@ -920,7 +926,7 @@ namespace randomx {
codePos = pos;
}
void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
void JitCompilerX86::h_ISTORE(const Instruction& instr) {
uint8_t* const p = code;
int pos = codePos;
@@ -932,7 +938,7 @@ namespace randomx {
codePos = pos;
}
void JitCompilerX86::h_NOP(Instruction& instr, int i) {
void JitCompilerX86::h_NOP(const Instruction& instr) {
emit(NOP1, code, codePos);
}

View File

@@ -41,7 +41,7 @@ namespace randomx {
class JitCompilerX86;
class Instruction;
typedef void(JitCompilerX86::*InstructionGeneratorX86)(Instruction&, int);
typedef void(JitCompilerX86::*InstructionGeneratorX86)(const Instruction&);
constexpr uint32_t CodeSize = 64 * 1024;
@@ -66,16 +66,15 @@ namespace randomx {
size_t getCodeSize();
static InstructionGeneratorX86 engine[256];
int32_t instructionOffsets[512];
int registerUsage[RegistersCount];
uint8_t* code;
int32_t codePos;
void generateProgramPrologue(Program&, ProgramConfiguration&);
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 genAddressReg(const Instruction&, uint8_t* code, int& codePos, bool rax = true);
static void genAddressRegDst(const Instruction&, uint8_t* code, int& codePos);
static void genAddressImm(const Instruction&, uint8_t* code, int& codePos);
static void genSIB(int scale, int index, int base, uint8_t* code, int& codePos);
void generateSuperscalarCode(Instruction &, std::vector<uint64_t> &);
@@ -105,36 +104,36 @@ namespace randomx {
codePos += count;
}
void h_IADD_RS(Instruction&, int);
void h_IADD_M(Instruction&, int);
void h_ISUB_R(Instruction&, int);
void h_ISUB_M(Instruction&, int);
void h_IMUL_R(Instruction&, int);
void h_IMUL_M(Instruction&, int);
void h_IMULH_R(Instruction&, int);
void h_IMULH_M(Instruction&, int);
void h_ISMULH_R(Instruction&, int);
void h_ISMULH_M(Instruction&, int);
void h_IMUL_RCP(Instruction&, int);
void h_INEG_R(Instruction&, int);
void h_IXOR_R(Instruction&, int);
void h_IXOR_M(Instruction&, int);
void h_IROR_R(Instruction&, int);
void h_IROL_R(Instruction&, int);
void h_ISWAP_R(Instruction&, int);
void h_FSWAP_R(Instruction&, int);
void h_FADD_R(Instruction&, int);
void h_FADD_M(Instruction&, int);
void h_FSUB_R(Instruction&, int);
void h_FSUB_M(Instruction&, int);
void h_FSCAL_R(Instruction&, int);
void h_FMUL_R(Instruction&, int);
void h_FDIV_M(Instruction&, int);
void h_FSQRT_R(Instruction&, int);
void h_CBRANCH(Instruction&, int);
void h_CFROUND(Instruction&, int);
void h_ISTORE(Instruction&, int);
void h_NOP(Instruction&, int);
void h_IADD_RS(const Instruction&);
void h_IADD_M(const Instruction&);
void h_ISUB_R(const Instruction&);
void h_ISUB_M(const Instruction&);
void h_IMUL_R(const Instruction&);
void h_IMUL_M(const Instruction&);
void h_IMULH_R(const Instruction&);
void h_IMULH_M(const Instruction&);
void h_ISMULH_R(const Instruction&);
void h_ISMULH_M(const Instruction&);
void h_IMUL_RCP(const Instruction&);
void h_INEG_R(const Instruction&);
void h_IXOR_R(const Instruction&);
void h_IXOR_M(const Instruction&);
void h_IROR_R(const Instruction&);
void h_IROL_R(const Instruction&);
void h_ISWAP_R(const Instruction&);
void h_FSWAP_R(const Instruction&);
void h_FADD_R(const Instruction&);
void h_FADD_M(const Instruction&);
void h_FSUB_R(const Instruction&);
void h_FSUB_M(const Instruction&);
void h_FSCAL_R(const Instruction&);
void h_FMUL_R(const Instruction&);
void h_FDIV_M(const Instruction&);
void h_FSQRT_R(const Instruction&);
void h_CBRANCH(const Instruction&);
void h_CFROUND(const Instruction&);
void h_ISTORE(const Instruction&);
void h_NOP(const Instruction&);
};
}

View File

@@ -82,6 +82,16 @@ RandomX_ConfigurationLoki::RandomX_ConfigurationLoki()
RANDOMX_FREQ_CBRANCH = 16;
}
RandomX_ConfigurationArqma::RandomX_ConfigurationArqma()
{
ArgonIterations = 1;
ArgonSalt = "RandomARQ\x01";
ProgramIterations = 1024;
ProgramCount = 4;
ScratchpadL2_Size = 131072;
ScratchpadL3_Size = 262144;
}
RandomX_ConfigurationBase::RandomX_ConfigurationBase()
: ArgonMemory(262144)
, ArgonIterations(3)
@@ -248,6 +258,7 @@ void RandomX_ConfigurationBase::Apply()
RandomX_ConfigurationMonero RandomX_MoneroConfig;
RandomX_ConfigurationWownero RandomX_WowneroConfig;
RandomX_ConfigurationLoki RandomX_LokiConfig;
RandomX_ConfigurationArqma RandomX_ArqmaConfig;
RandomX_ConfigurationBase RandomX_CurrentConfig;

View File

@@ -176,10 +176,12 @@ struct RandomX_ConfigurationBase
struct RandomX_ConfigurationMonero : public RandomX_ConfigurationBase {};
struct RandomX_ConfigurationWownero : public RandomX_ConfigurationBase { RandomX_ConfigurationWownero(); };
struct RandomX_ConfigurationLoki : public RandomX_ConfigurationBase { RandomX_ConfigurationLoki(); };
struct RandomX_ConfigurationArqma : public RandomX_ConfigurationBase { RandomX_ConfigurationArqma(); };
extern RandomX_ConfigurationMonero RandomX_MoneroConfig;
extern RandomX_ConfigurationWownero RandomX_WowneroConfig;
extern RandomX_ConfigurationLoki RandomX_LokiConfig;
extern RandomX_ConfigurationArqma RandomX_ArqmaConfig;
extern RandomX_ConfigurationBase RandomX_CurrentConfig;

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