From c47098c9066413784e9ea61e69c273ee5498e0df Mon Sep 17 00:00:00 2001 From: "Wei, CHEN" Date: Sat, 17 Mar 2018 03:57:29 +0800 Subject: [PATCH 1/3] Change prototype of function to int8_t --- jni/iri-pearldiver-exlib.c | 17 ++++++++++------- src/dcurl.c | 4 ++-- src/dcurl.h | 2 +- src/pow_cl.c | 18 +++++++++++------- src/pow_cl.h | 2 +- src/pow_sse.c | 20 +++++++++++--------- src/pow_sse.h | 2 +- test/common.h | 1 + test/test_pow_cl.c | 14 +++++++------- test/test_pow_sse.c | 12 ++++++------ 10 files changed, 51 insertions(+), 41 deletions(-) diff --git a/jni/iri-pearldiver-exlib.c b/jni/iri-pearldiver-exlib.c index 99d7d77..f45e31d 100644 --- a/jni/iri-pearldiver-exlib.c +++ b/jni/iri-pearldiver-exlib.c @@ -2,10 +2,11 @@ #include #include "../src/dcurl.h" #include "../src/trinary/trinary.h" +#include -static char *int_to_char_array(jint *arr, int size) +static int8_t *int_to_char_array(jint *arr, int size) { - char *ret = malloc(size); + int8_t *ret = malloc(size); if (!ret) return NULL; @@ -15,7 +16,7 @@ static char *int_to_char_array(jint *arr, int size) return ret; } -static jint *char_to_int_array(char *arr, int size) +static jint *char_to_int_array(int8_t *arr, int size) { jint *ret = malloc(sizeof(jint) * size); if (!ret) @@ -43,7 +44,7 @@ Java_com_iota_iri_hash_PearlDiver_exlib_1search(JNIEnv *env, { /* Convert ***INT*** array (TRITS) to ***CHAR*** array (TRYTES) */ jint *c_trits = (*env)->GetIntArrayElements(env, trits, NULL); - char *char_trits = int_to_char_array(c_trits, 8019); + int8_t *char_trits = int_to_char_array(c_trits, 8019); if (!char_trits) return JNI_FALSE; @@ -53,10 +54,11 @@ Java_com_iota_iri_hash_PearlDiver_exlib_1search(JNIEnv *env, return JNI_FALSE; /****************************************************************/ - Trytes_t *result = dcurl_entry(arg_trytes, mwm); + int8_t *result = dcurl_entry(arg_trytes->data, mwm); /* Convert ***CHAR*** array(TRYTES) to ***INT*** array (TRITS) */ - Trits_t *ret_trits = trits_from_trytes(result); + Trytes_t *ret_trytes = initTrytes(result, 2673); + Trits_t *ret_trits = trits_from_trytes(ret_trytes); if (!ret_trits) return JNI_FALSE; @@ -70,7 +72,8 @@ Java_com_iota_iri_hash_PearlDiver_exlib_1search(JNIEnv *env, /* Free */ free(char_trits); free(int_trits); - freeTrobject(result); + free(result); + freeTrobject(ret_trytes); freeTrobject(arg_trits); freeTrobject(arg_trytes); freeTrobject(ret_trits); diff --git a/src/dcurl.c b/src/dcurl.c index 0b572ee..80cccfc 100644 --- a/src/dcurl.c +++ b/src/dcurl.c @@ -82,7 +82,7 @@ void dcurl_destroy() #endif } -Trytes_t *dcurl_entry(Trytes_t *trytes, int mwm) +int8_t *dcurl_entry(int8_t *trytes, int mwm) { static int num_cpu_thread = 0; static int num_gpu_thread = 0; @@ -118,7 +118,7 @@ Trytes_t *dcurl_entry(Trytes_t *trytes, int mwm) pthread_mutex_unlock(&mtx); } - Trytes_t *ret_trytes = NULL; + int8_t *ret_trytes = NULL; switch (selected_entry) { case 1: diff --git a/src/dcurl.h b/src/dcurl.h index 61eea8e..7157010 100644 --- a/src/dcurl.h +++ b/src/dcurl.h @@ -5,6 +5,6 @@ int dcurl_init(int max_cpu_thread, int max_gpu_thread); void dcurl_destroy(); -Trytes_t *dcurl_entry(Trytes_t *trytes, int mwm); +int8_t *dcurl_entry(int8_t *trytes, int mwm); #endif diff --git a/src/pow_cl.c b/src/pow_cl.c index 37fd7fd..9294c14 100644 --- a/src/pow_cl.c +++ b/src/pow_cl.c @@ -195,9 +195,10 @@ static int8_t *pwork(int8_t *state, int mwm, int index) int8_t *buf = malloc(HASH_LENGTH); if (found > 0) { - if (CL_SUCCESS != clEnqueueReadBuffer( - titan->cmdq, titan->buffer[0], CL_TRUE, 0, - HASH_LENGTH * sizeof(int8_t), buf, 1, &ev, NULL)) { + if (CL_SUCCESS != clEnqueueReadBuffer(titan->cmdq, titan->buffer[0], + CL_TRUE, 0, + HASH_LENGTH * sizeof(int8_t), buf, + 1, &ev, NULL)) { return NULL; /* Read buffer failed */ } } @@ -243,10 +244,9 @@ static int8_t *tx_to_cstate(Trytes_t *tx) return c_state; } -Trytes_t *PowCL(Trytes_t *trytes, int mwm, int index) +int8_t *PowCL(int8_t *trytes, int mwm, int index) { - // Trytes_t *trytes_t = initTrytes(trytes, 2673); - Trytes_t *trytes_t = trytes; + Trytes_t *trytes_t = initTrytes(trytes, 2673); Trits_t *tr = trits_from_trytes(trytes_t); if (!tr) @@ -264,10 +264,14 @@ Trytes_t *PowCL(Trytes_t *trytes, int mwm, int index) HASH_LENGTH * sizeof(int8_t)); Trytes_t *last = trytes_from_trits(tr); + int8_t *ret_data = last->data; freeTrobject(tr); + freeTrobject(trytes_t); + /* hack */ + free(last); free(c_state); free(ret); - return last; + return ret_data; } diff --git a/src/pow_cl.h b/src/pow_cl.h index 83b8398..cec091a 100644 --- a/src/pow_cl.h +++ b/src/pow_cl.h @@ -3,7 +3,7 @@ #include "./trinary/trinary.h" -Trytes_t *PowCL(Trytes_t *trytes, int mwm, int index); +int8_t *PowCL(int8_t *trytes, int mwm, int index); int pwork_ctx_init(int context_size); void pwork_ctx_destroy(int context_size); diff --git a/src/pow_sse.c b/src/pow_sse.c index 6be927c..02583a9 100644 --- a/src/pow_sse.c +++ b/src/pow_sse.c @@ -244,7 +244,11 @@ static void incrN128(int n, __m128i *mid_low, __m128i *mid_high) } } -static long long int pwork128(int8_t mid[], int mwm, int8_t nonce[], int n, int id) +static long long int pwork128(int8_t mid[], + int mwm, + int8_t nonce[], + int n, + int id) { __m128i lmid[STATE_LENGTH], hmid[STATE_LENGTH]; para128(mid, lmid, hmid); @@ -324,7 +328,7 @@ static int8_t *tx_to_cstate(Trytes_t *tx) return c_state; } -static Trytes_t *nonce_to_result(Trytes_t *tx, Trytes_t *nonce) +static int8_t *nonce_to_result(Trytes_t *tx, Trytes_t *nonce) { int rst_len = tx->len - NonceTrinarySize / 3 + nonce->len; int8_t *rst = (int8_t *) malloc(rst_len); @@ -335,10 +339,7 @@ static Trytes_t *nonce_to_result(Trytes_t *tx, Trytes_t *nonce) memcpy(rst + tx->len - NonceTrinarySize / 3, nonce->data, rst_len - (tx->len - NonceTrinarySize / 3)); - Trytes_t *ret = initTrytes(rst, rst_len); - free(rst); - - return ret; + return rst; } int pow_sse_init(int num_task) @@ -366,12 +367,12 @@ void pow_sse_destroy() free(countSSE); } -Trytes_t *PowSSE(Trytes_t *trytes, int mwm, int index) +int8_t *PowSSE(int8_t *trytes, int mwm, int index) { stopSSE[index] = 0; countSSE[index] = 0; - Trytes_t *trytes_t = trytes; + Trytes_t *trytes_t = initTrytes(trytes, 2673); int8_t *c_state = tx_to_cstate(trytes_t); if (!c_state) @@ -421,7 +422,7 @@ Trytes_t *PowSSE(Trytes_t *trytes, int mwm, int index) if (!nonce) return NULL; - Trytes_t *last_result = nonce_to_result(trytes_t, nonce); + int8_t *last_result = nonce_to_result(trytes_t, nonce); /* Free memory */ free(c_state); @@ -431,6 +432,7 @@ Trytes_t *PowSSE(Trytes_t *trytes, int mwm, int index) free(nonce_array); free(threads); free(pitem); + freeTrobject(trytes_t); freeTrobject(nonce_t); freeTrobject(nonce); diff --git a/src/pow_sse.h b/src/pow_sse.h index f896a70..d82ea18 100644 --- a/src/pow_sse.h +++ b/src/pow_sse.h @@ -15,7 +15,7 @@ struct _pwork_struct { long long int ret; }; -Trytes_t *PowSSE(Trytes_t *trytes, int mwm, int index); +int8_t *PowSSE(int8_t *trytes, int mwm, int index); int pow_sse_init(int num_task); void pow_sse_destroy(); diff --git a/test/common.h b/test/common.h index 17d8e06..e140717 100644 --- a/test/common.h +++ b/test/common.h @@ -12,6 +12,7 @@ #endif #include +#include #ifdef NDEBUG #undef NDEBUG diff --git a/test/test_pow_cl.c b/test/test_pow_cl.c index 2566468..82ecb01 100644 --- a/test/test_pow_cl.c +++ b/test/test_pow_cl.c @@ -3,7 +3,7 @@ int main() { - char *txt = + char *trytes = "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999999999999999999999999999999999999999999999999999999999999" @@ -44,15 +44,15 @@ int main() "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999"; - Trytes_t *trytes = initTrytes((signed char *) txt, 2673); int mwm = 14; /* test OpenCL Implementation with mwm = 14 */ pwork_ctx_init(1); - Trytes_t *ret_trytes = PowCL(trytes, mwm, 0); + int8_t *ret_trytes = PowCL(trytes, mwm, 0); pwork_ctx_destroy(1); - Trytes_t *hash_trytes = hashTrytes(ret_trytes); + Trytes_t *trytes_t = initTrytes(ret_trytes, 2673); + Trytes_t *hash_trytes = hashTrytes(trytes_t); /* Validation */ Trits_t *ret_trits = trits_from_trytes(hash_trytes); @@ -60,10 +60,10 @@ int main() assert(ret_trits->data[i] == 0); } - freeTrobject(trytes); - freeTrobject(ret_trytes); + free(ret_trytes); + freeTrobject(trytes_t); freeTrobject(hash_trytes); freeTrobject(ret_trits); return 0; -} \ No newline at end of file +} diff --git a/test/test_pow_sse.c b/test/test_pow_sse.c index 2352f52..7069d1d 100644 --- a/test/test_pow_sse.c +++ b/test/test_pow_sse.c @@ -3,7 +3,7 @@ int main() { - char *txt = + char *trytes = "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999999999999999999999999999999999999999999999999999999999999" @@ -44,15 +44,15 @@ int main() "9999999999999999999999999999999999999999999999999999999999999999999999" "9999999999999"; - Trytes_t *trytes = initTrytes((signed char *) txt, 2673); int mwm = 14; /* test SSE Implementation with mwm = 14 */ pow_sse_init(1); - Trytes_t *ret_trytes = PowSSE(trytes, mwm, 0); + int8_t *ret_trytes = PowSSE(trytes, mwm, 0); pow_sse_destroy(); - Trytes_t *hash_trytes = hashTrytes(ret_trytes); + Trytes_t *trytes_t = initTrytes(ret_trytes, 2673); + Trytes_t *hash_trytes = hashTrytes(trytes_t); /* Validation */ Trits_t *ret_trits = trits_from_trytes(hash_trytes); @@ -60,8 +60,8 @@ int main() assert(ret_trits->data[i] == 0); } - freeTrobject(trytes); - freeTrobject(ret_trytes); + free(ret_trytes); + freeTrobject(trytes_t); freeTrobject(hash_trytes); freeTrobject(ret_trits); From 595cb60715e54950c59aaec26341b922a220ca2c Mon Sep 17 00:00:00 2001 From: "Wei, CHEN" Date: Sat, 17 Mar 2018 05:11:22 +0800 Subject: [PATCH 2/3] A test program for multi-thread PoW --- test/test_multi_pow.py | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 test/test_multi_pow.py diff --git a/test/test_multi_pow.py b/test/test_multi_pow.py new file mode 100644 index 0000000..601b11e --- /dev/null +++ b/test/test_multi_pow.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- + +import ctypes +import sys +import argparse +import _thread +import iota +from iota import TryteString +from iota.crypto import Curl + +TRYTES_LIST_PATH = "./test/trytes.txt" +DCURL_PATH = "./libdcurl.so" +NUM_TRYTES = 10 + +join_list = [] +for i in range(NUM_TRYTES): + join_list.append(_thread.allocate_lock()) + +# return list of trytes # +def read_trytes(FILE_PATH): + f = open(FILE_PATH, 'r') + row = f.readlines() + tmp = [] + for r in row: + tmp.append(r.split('\n')[0]) + return tmp + +def hash(trytes): + curl = Curl() + curl.absorb(trytes.as_trits()) + trits_out = [] + curl.squeeze(trits_out) + return TryteString.from_trits(trits_out) + +def validate(trytes, mwm): + trits = trytes.as_trits() + for i in range(len(trits) - 1, len(trits) - mwm - 1, -1): + if trits[i] != 0: + return False + return True + +def call_dcurl(idx, mwm, lib, trytes_list): + tmp = str(trytes_list[idx]).encode('ascii') + ret = lib.dcurl_entry(tmp, mwm) + trytes = TryteString(ret) + + hash_trytes = hash(trytes) + print(hash_trytes) + if validate(hash_trytes, mwm) is not True: + sys.exit(1) + + join_list[idx].release() + +def testing(dcurl_parameter): + num_cpu = dcurl_parameter[0] + num_gpu = dcurl_parameter[1] + trytes_list = read_trytes(TRYTES_LIST_PATH) + + # Settings of shared library + libdcurl = ctypes.cdll.LoadLibrary(DCURL_PATH) + libdcurl.dcurl_init.argtypes = [ctypes.c_int, ctypes.c_int] + libdcurl.dcurl_entry.argtypes = [ctypes.c_char_p, ctypes.c_int] + libdcurl.dcurl_entry.restype = ctypes.c_char_p + + libdcurl.dcurl_init(num_cpu, num_gpu) + + for i in range(NUM_TRYTES): + join_list[i].acquire() + _thread.start_new_thread(call_dcurl, (i, 14, libdcurl, trytes_list, )) + + # threadpool.join() + for i in range(NUM_TRYTES): + while join_list[i].locked(): pass + + libdcurl.dcurl_destroy() + +if __name__ == "__main__": + # Parsing arguments + parser = argparse.ArgumentParser() + parser.add_argument("--gpu_enable", type = int); + args = parser.parse_args() + + # Select testing set, (x, y) which means + # (MAX_CPU_THREAD, MAX_GPU_THREAD) in dcurl + test_set = (0, 0) + if args.gpu_enable == 0: + test_set = (2, 0) + else: + test_set = (2, 1) + + testing(test_set) + + sys.exit(0) From d9d968d93596b70517bfb7d0df3ccb00d55cc366 Mon Sep 17 00:00:00 2001 From: "Wei, CHEN" Date: Sat, 17 Mar 2018 05:43:54 +0800 Subject: [PATCH 3/3] Add test program for Multi-PoW in makefile "make DISABLE_OPENCL=0" would launch test program with GPU, vice versa. Test program will issue 10 threads at the same time to do PoW --- Makefile | 10 +++++++++- test/test_multi_pow.py | 3 +-- test/trytes.txt | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 test/trytes.txt diff --git a/Makefile b/Makefile index f7348d3..3235e59 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ DISABLE_JNI ?= 1 CFLAGS = -Os -fPIC -g LDFLAGS = -lpthread +PYFLAGS = --gpu_enable # FIXME: avoid hardcoded architecture flags. We might support advanced SIMD # instructions for Intel and Arm later. @@ -17,6 +18,9 @@ CFLAGS += \ -DENABLE_OPENCL \ -I$(OPENCL_PATH)/include LDFLAGS += -L$(OPENCL_LIB) -lOpenCL +PYFLAGS += 1 +else +PYFLAGS += 0 endif # FIXME: avoid hardcoded OS path @@ -93,10 +97,14 @@ $(OUT)/libdcurl.so: $(OBJS) $(VECHO) " LD\t$@\n" $(Q)$(CC) -shared -o $@ $^ $(LDFLAGS) +test_multi_pow: test/test_multi_pow.py $(OUT)/libdcurl.so + $(Q)$(PRINTF) "*** Validating $< ***\n" + $(Q)python3 $< $(PYFLAGS) && $(PRINTF) "\t$(PASS_COLOR)[ Verified ]$(NO_COLOR)\n" + $(OUT)/test_%.done: $(OUT)/test_% $(Q)$(PRINTF) "*** Validating $< ***\n" $(Q)./$< && $(PRINTF) "\t$(PASS_COLOR)[ Verified ]$(NO_COLOR)\n" -check: $(addsuffix .done, $(TESTS)) +check: $(addsuffix .done, $(TESTS)) test_multi_pow clean: $(RM) -r $(OUT) diff --git a/test/test_multi_pow.py b/test/test_multi_pow.py index 601b11e..5b394d0 100644 --- a/test/test_multi_pow.py +++ b/test/test_multi_pow.py @@ -9,7 +9,7 @@ from iota.crypto import Curl TRYTES_LIST_PATH = "./test/trytes.txt" -DCURL_PATH = "./libdcurl.so" +DCURL_PATH = "./build/libdcurl.so" NUM_TRYTES = 10 join_list = [] @@ -45,7 +45,6 @@ def call_dcurl(idx, mwm, lib, trytes_list): trytes = TryteString(ret) hash_trytes = hash(trytes) - print(hash_trytes) if validate(hash_trytes, mwm) is not True: sys.exit(1) diff --git a/test/trytes.txt b/test/trytes.txt new file mode 100644 index 0000000..0a01cb1 --- /dev/null +++ b/test/trytes.txt @@ -0,0 +1,10 @@ +ABVA99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999FJVRVRXWSO99999999999999999BBMEVYD99999999999999999999JEIQLQWEXOHLGVCPBNLYHUNVEMGTVQJMFWDMSRFFTCYXYLZJNFHNUNELXUHNTZIPEEMJEC9PEKZKGCJFD999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999FJVRVRXWSO99999999999999999999999999999999999999999999999999999999999999999999999 +MBUBWCEADDACGDFAGAOCHCQBMCHD9CICZBMCMBJA9BABZCLDLDCBLDACXAUC999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999VSXYBHPNEMR9999999999999999BBMEVYD99999999999999999999HLUQWTOSHBXUBMVCCWRFGNSFGTEQWOFVYPSJVKDGTG9EFDDFSRGQGZKGCLGVACCZPYOJIMIFF9JLQTXCC999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999VSXYBHPNEMR9999999999999999999999999999999999999999999999999999999999999999999999 +NCFATCVBGDHBECMDECJBZBDDKCLCNCRANCMDHC9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999VIWRGNZEYRXBEWQT99999999999BBMEVYD99999999999999999999JZIFITRNGDPUWYREZGKQMWJZJUZHBRVNAJIQOJQBDFMDPFDPNDIVMLANUOQDCJLITHLMTHDLNPCFJRQDD999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999VIWRGNZEYRXBEWQT99999999999999999999999999999999999999999999999999999999999999999 +UAXCZBSAKBSANAWBOCACLA99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999UWK999999999999999999999999BBMEVYD99999999999999999999LY9IPMACQKQRDVVAQVHACBGGBTJIODZUEKOOXYYPIYCYVCYKX9NXOICNGZUWLLVFEUKTXZDRYIXJAABZW999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999UWK999999999999999999999999999999999999999999999999999999999999999999999999999999 +IBBDNDGBUAFBGDGCBBKDTBRACCQCYAWARBZA999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999LCE999999999999999999999999BBMEVYD99999999999999999999YYLRPZKTAIPVHUEOIMFHPWAWLUCHJNTADSAVGWVZEDYG9ZMEIQRRAJYRPJVJYOSZGEYQLVADW9XEBFLXX999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999LCE999999999999999999999999999999999999999999999999999999999999999999999999999999 +CATB99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999BBMEVYD99999999999999999999FFUKENIKBELOFXIKCRQSXVEIXEYLGEVKSTS9YWSTLJSBUAQSL9IJEXQDAEYEHJVLFQU9Y9OPIJPCWZSTB999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999999999999999999999999999999999999999999999999999999999 +CATB99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999BBMEVYD99999999999999999999FFUKENIKBELOFXIKCRQSXVEIXEYLGEVKSTS9YWSTLJSBUAQSL9IJEXQDAEYEHJVLFQU9Y9OPIJPCWZSTB999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999999999999999999999999999999999999999999999999999999999 +UBFBZCLCDCGC9DUBTAIC9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999JSTONDGUYNAVGVSQNZRI9999999BBMEVYD99999999999999999999VHOFYIIY9ZKGYXLBEXFHVI9EJILPUBPPQBCOCJREOQGJEKQHVDLGOYZSRKGMQIJLIWKZ9NMMXKOYDHVDW999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999JSTONDGUYNAVGVSQNZRI9999999999999999999999999999999999999999999999999999999999999 +TBLDCAYCSCKAOBBCBBDCQCSAHCNBYCOBJCCBSBICTASBDBTCJC9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999CHOJ99999999999999999999999BBMEVYD99999999999999999999OBHDWPAZEQQZIWPMLPYUMFIGZCJKCQWTIAXNZTXLFE9OOYSFMATYB9FNGRHPHUXWZGBNNRBYXPXNJMPDC999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999CHOJ99999999999999999999999999999999999999999999999999999999999999999999999999999 +CATB99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9Y999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999BBMEVYD99999999999999999999FFUKENIKBELOFXIKCRQSXVEIXEYLGEVKSTS9YWSTLJSBUAQSL9IJEXQDAEYEHJVLFQU9Y9OPIJPCWZSTB999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999IYQXEBFELRMMHYOUXTF99999999999999999999999999999999999999999999999999999999999999