From fa0a35aa5a2dac695e4452587f5c9b18e5943be0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:11:36 -1100 Subject: [PATCH 001/385] Split out Tetris --- src/cc/dapps/dappstd.c | 1020 +++++++++++++++++ src/cc/gamescc.cpp | 2048 +--------------------------------- src/cc/gamescc.h | 32 +- src/cc/tetris.c | 758 +++++++++++++ src/cc/tetris.cpp | 2376 +--------------------------------------- src/cc/tetris.h | 197 ++++ 6 files changed, 2046 insertions(+), 4385 deletions(-) create mode 100644 src/cc/dapps/dappstd.c create mode 100644 src/cc/tetris.c create mode 100644 src/cc/tetris.h diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c new file mode 100644 index 000000000..ec8045b2f --- /dev/null +++ b/src/cc/dapps/dappstd.c @@ -0,0 +1,1020 @@ +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +// requires CHAINNAME and GAMEMAIN() to be #defined + +#include +#include +#include +#include +#include +#include +#include + +char USERPASS[8192]; uint16_t GAMES_PORT; +char Gametxidstr[67]; +char *clonestr(char *str); + +#define MAXSTR 1024 +char whoami[MAXSTR]; + +#define SMALLVAL 0.000000000000001 +#define SATOSHIDEN ((uint64_t)100000000L) +#define dstr(x) ((double)(x) / SATOSHIDEN) +#define KOMODO_ASSETCHAIN_MAXLEN 65 +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100]; + +#ifndef _BITS256 +#define _BITS256 +union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; +typedef union _bits256 bits256; +#endif + +#ifdef _WIN32 +#ifdef _MSC_VER +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; +} +#endif // _MSC_VER +#endif + +double OS_milliseconds() +{ + struct timeval tv; double millis; +#ifdef __MINGW32__ + mingw_gettimeofday(&tv,NULL); +#else + gettimeofday(&tv,NULL); +#endif + millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.); + //printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis); + return(millis); +} + +int32_t _unhex(char c) +{ + if ( c >= '0' && c <= '9' ) + return(c - '0'); + else if ( c >= 'a' && c <= 'f' ) + return(c - 'a' + 10); + else if ( c >= 'A' && c <= 'F' ) + return(c - 'A' + 10); + return(-1); +} + +int32_t is_hexstr(char *str,int32_t n) +{ + int32_t i; + if ( str == 0 || str[0] == 0 ) + return(0); + for (i=0; str[i]!=0; i++) + { + if ( n > 0 && i >= n ) + break; + if ( _unhex(str[i]) < 0 ) + break; + } + if ( n == 0 ) + return(i); + return(i == n); +} + +int32_t unhex(char c) +{ + int32_t hex; + if ( (hex= _unhex(c)) < 0 ) + { + //printf("unhex: illegal hexchar.(%c)\n",c); + } + return(hex); +} + +unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } + +int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex) +{ + int32_t adjust,i = 0; + //printf("decode.(%s)\n",hex); + if ( is_hexstr(hex,n) <= 0 ) + { + memset(bytes,0,n); + return(n); + } + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) + { + if ( n > 0 ) + { + bytes[0] = unhex(hex[0]); + printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); + } + bytes++; + hex++; + adjust = 1; + } else adjust = 0; + if ( n > 0 ) + { + for (i=0; i>4) & 0xf); + hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); + //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); + } + hexbytes[len*2] = 0; + //printf("len.%ld\n",len*2+1); + return((int32_t)len*2+1); +} + +char *bits256_str(char hexstr[65],bits256 x) +{ + init_hexbytes_noT(hexstr,x.bytes,sizeof(x)); + return(hexstr); +} + +long _stripwhite(char *buf,int accept) +{ + int32_t i,j,c; + if ( buf == 0 || buf[0] == 0 ) + return(0); + for (i=j=0; buf[i]!=0; i++) + { + buf[j] = c = buf[i]; + if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) + j++; + } + buf[j] = 0; + return(j); +} + +char *parse_conf_line(char *line,char *field) +{ + line += strlen(field); + for (; *line!='='&&*line!=0; line++) + break; + if ( *line == 0 ) + return(0); + if ( *line == '=' ) + line++; + while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) + line[strlen(line)-1] = 0; + //printf("LINE.(%s)\n",line); + _stripwhite(line,0); + return(clonestr(line)); +} + +int32_t safecopy(char *dest,char *src,long len) +{ + int32_t i = -1; + if ( src != 0 && dest != 0 && src != dest ) + { + if ( dest != 0 ) + memset(dest,0,len); + for (i=0; i buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +uint8_t *OS_fileptr(long *allocsizep,char *fname) +{ + long filesize = 0; uint8_t *buf = 0; void *retptr; + *allocsizep = 0; + retptr = OS_loadfile(fname,&buf,&filesize,allocsizep); + return((uint8_t *)retptr); +} + +struct MemoryStruct { char *memory; size_t size; }; +struct return_string { char *ptr; size_t len; }; + +// return data from the server +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) + + +/************************************************************************ + * + * Initialize the string handler so that it is thread safe + * + ************************************************************************/ + +void init_string(struct return_string *s) +{ + s->len = 0; + s->ptr = (char *)calloc(1,s->len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr,"init_string malloc() failed\n"); + exit(-1); + } + s->ptr[0] = '\0'; +} + +/************************************************************************ + * + * Use the "writer" to accumulate text until done + * + ************************************************************************/ + +size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) +{ + size_t new_len = s->len + size*nmemb; + s->ptr = (char *)realloc(s->ptr,new_len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr, "accumulate realloc() failed\n"); + exit(-1); + } + memcpy(s->ptr+s->len,ptr,size*nmemb); + s->ptr[new_len] = '\0'; + s->len = new_len; + return(size * nmemb); +} + +/************************************************************************ + * + * return the current system time in milliseconds + * + ************************************************************************/ + +#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field +#ifdef EXTRACT_BITCOIND_RESULT + +/************************************************************************ + * + * perform post processing of the results + * + ************************************************************************/ + +char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) +{ + long i,j,len; char *retstr = 0; cJSON *json,*result,*error; + //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + return(rpcstr); + } + json = cJSON_Parse(rpcstr); + if ( json == 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); + free(rpcstr); + return(0); + } + result = cJSON_GetObjectItem(json,"result"); + error = cJSON_GetObjectItem(json,"error"); + if ( error != 0 && result != 0 ) + { + if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) + { + retstr = cJSON_Print(result); + len = strlen(retstr); + if ( retstr[0] == '"' && retstr[len-1] == '"' ) + { + for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); + } + free(rpcstr); + } else retstr = rpcstr; + free_json(json); + //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); + return(retstr); +} +#endif + +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + +/************************************************************************ + * + * perform the query + * + ************************************************************************/ + +char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) +{ + static int didinit,count,count2; static double elapsedsum,elapsedsum2; + struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; + char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; + if ( didinit == 0 ) + { + didinit = 1; + curl_global_init(CURL_GLOBAL_ALL); //init the curl session + } + numretries = 0; + if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) + specialcase = 1; + else specialcase = 0; + if ( url[0] == 0 ) + strcpy(url,"http://127.0.0.1:7876/nxt"); + if ( specialcase != 0 && 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); +try_again: + if ( retstrp != 0 ) + *retstrp = 0; + starttime = OS_milliseconds(); + curl_handle = curl_easy_init(); + init_string(&s); + headers = curl_slist_append(0,"Expect:"); + + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle,CURLOPT_URL, url); + curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function + curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback + curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash + curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + if ( strncmp(url,"https",5) == 0 ) + { + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); + } + if ( userpass != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); + databuf = 0; + if ( params != 0 ) + { + if ( command != 0 && specialcase == 0 ) + { + len = strlen(params); + if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { + bracket0 = bracket1 = (char *)""; + } + else + { + bracket0 = (char *)"["; + bracket1 = (char *)"]"; + } + + databuf = (char *)malloc(256 + strlen(command) + strlen(params)); + sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); + //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); + // + } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); + curl_easy_setopt(curl_handle,CURLOPT_POST,1L); + if ( databuf != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); + else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); + } + //laststart = milliseconds(); + res = curl_easy_perform(curl_handle); + curl_slist_free_all(headers); + curl_easy_cleanup(curl_handle); + if ( databuf != 0 ) // clean up temporary buffer + { + free(databuf); + databuf = 0; + } + if ( res != CURLE_OK ) + { + numretries++; + if ( specialcase != 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); + free(s.ptr); + return(0); + } + else if ( numretries >= 1 ) + { + //printf("Maximum number of retries exceeded!\n"); + free(s.ptr); + return(0); + } + if ( (rand() % 1000) == 0 ) + printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); + free(s.ptr); + sleep((1< (%s)\n",params,s.ptr); + count2++; + elapsedsum2 += (OS_milliseconds() - starttime); + if ( (count2 % 10000) == 0) + printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); + return(s.ptr); + } + } + printf("bitcoind_RPC: impossible case\n"); + free(s.ptr); + return(0); +} + +static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) +{ + size_t realsize = (size * nmemb); + struct MemoryStruct *mem = (struct MemoryStruct *)data; + mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); + if ( mem->memory != 0 ) + { + if ( ptr != 0 ) + memcpy(&(mem->memory[mem->size]),ptr,realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + //printf("got %d bytes\n",(int32_t)(size*nmemb)); + return(realsize); +} + +char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) +{ + struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; + if ( (cHandle= *cHandlep) == NULL ) + *cHandlep = cHandle = curl_easy_init(); + else curl_easy_reset(cHandle); + //#ifdef DEBUG + //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); + //#endif + curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); + //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); + curl_easy_setopt(cHandle,CURLOPT_URL,url); + curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); + if ( userpass != 0 && userpass[0] != 0 ) + curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); + if ( postfields != 0 && postfields[0] != 0 ) + { + curl_easy_setopt(cHandle,CURLOPT_POST,1); + curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); + } + if ( hdr0 != NULL && hdr0[0] != 0 ) + { + //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); + headers = curl_slist_append(headers,hdr0); + if ( hdr1 != 0 && hdr1[0] != 0 ) + headers = curl_slist_append(headers,hdr1); + if ( hdr2 != 0 && hdr2[0] != 0 ) + headers = curl_slist_append(headers,hdr2); + if ( hdr3 != 0 && hdr3[0] != 0 ) + headers = curl_slist_append(headers,hdr3); + } //headers = curl_slist_append(0,"Expect:"); + if ( headers != 0 ) + curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); + //res = curl_easy_perform(cHandle); + memset(&chunk,0,sizeof(chunk)); + curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); + curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); + curl_easy_perform(cHandle); + curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); + if ( headers != 0 ) + curl_slist_free_all(headers); + if ( code != 200 ) + printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); + return(chunk.memory); +} + +uint16_t _komodo_userpass(char *username, char *password, FILE *fp) +{ + char *rpcuser,*rpcpassword,*str,*ipaddress,line[8192]; uint16_t port = 0; + rpcuser = rpcpassword = 0; + username[0] = password[0] = 0; + while ( fgets(line,sizeof(line),fp) != 0 ) + { + if ( line[0] == '#' ) + continue; + //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); + if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) + rpcuser = parse_conf_line(str,(char *)"rpcuser"); + else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) + rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); + else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) + { + port = atoi(parse_conf_line(str,(char *)"rpcport")); + //fprintf(stderr,"rpcport.%u in file\n",port); + } + else if ( (str= strstr(line,(char *)"ipaddress")) != 0 ) + { + ipaddress = parse_conf_line(str,(char *)"ipaddress"); + strcpy(IPADDRESS,ipaddress); + } + } + if ( rpcuser != 0 && rpcpassword != 0 ) + { + strcpy(username,rpcuser); + strcpy(password,rpcpassword); + } + //printf("rpcuser.(%s) rpcpassword.(%s) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress); + if ( rpcuser != 0 ) + free(rpcuser); + if ( rpcpassword != 0 ) + free(rpcpassword); + return(port); +} + +uint16_t komodo_userpass(char *userpass,char *symbol) +{ + FILE *fp; uint16_t port = 0; char fname[512],username[512],password[512],confname[KOMODO_ASSETCHAIN_MAXLEN]; + userpass[0] = 0; + if ( strcmp("KMD",symbol) == 0 ) + { +#ifdef __APPLE__ + sprintf(confname,"Komodo.conf"); +#else + sprintf(confname,"komodo.conf"); +#endif + } + else sprintf(confname,"%s.conf",symbol); + //komodo_statefname(fname,symbol,confname); + if ( (fp= fopen(confname,"rb")) != 0 ) + { + port = _komodo_userpass(username,password,fp); + sprintf(userpass,"%s:%s",username,password); + if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) + strcpy(USERPASS,userpass); + fclose(fp); + } + return(port); +} + +#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) + +char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) +{ + //static void *cHandle; + char url[512],*retstr=0,*retstr2=0,postdata[8192]; + if ( params == 0 || params[0] == 0 ) + params = (char *)"[]"; + if ( strlen(params) < sizeof(postdata)-128 ) + { + sprintf(url,(char *)"http://%s:%u",IPADDRESS,port); + sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); + //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,USERPASS); + retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); + //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); + } + return(retstr2); +} + +int32_t issue_games_events(bits256 gametxid,uint32_t eventid,int32_t c) +{ + static FILE *fp; + char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); +} + +int32_t games_sendrawtransaction(char *rawtx) +{ + char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; + params = (char *)malloc(strlen(rawtx) + 16); + sprintf(params,"[\"%s\"]",rawtx); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"sendrawtransaction",params,GAMES_PORT)) != 0 ) + { + if ( 0 ) // causes 4th level crash + { + static FILE *fp; + if ( fp == 0 ) + fp = fopen("games.sendlog","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%s\n",retstr); + fflush(fp); + } + } + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + if ( (hexstr= jstr(resobj,0)) != 0 && is_hexstr(hexstr,64) == 64 ) + retval = 0; + } + free_json(retjson); + } + + /* log sendrawtx result in file */ + + /* + FILE *debug_file; + debug_file = fopen("tx_debug.log", "a"); + fprintf(debug_file, "%s\n", retstr); + fflush(debug_file); + fclose(debug_file); + */ + + free(retstr); + } + free(params); + return(retval); +} + +int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) +{ + char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx,*pastkeys,*keys; int32_t i,len,numpastkeys,retflag = -1; cJSON *retjson,*resobj; uint8_t *pastcmp; + if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) + { + if ( rs->keystrokeshex != 0 ) + { + if ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + if ( waitflag == 0 ) + return(0); + else if ( 0 ) + { + while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + //fprintf(stderr,"pre-rebroadcast\n"); + sleep(10); + } + } + } + free(rs->keystrokeshex), rs->keystrokeshex = 0; + } + if ( 0 && (pastkeys= games_keystrokesload(&numpastkeys,seed,1)) != 0 ) + { + sprintf(params,"[\"extract\",\"17\",\"[%%22%s%%22]\"]",Gametxidstr); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (keys= jstr(resobj,(char *)"keystrokes")) != 0 ) + { + len = strlen(keys) / 2; + pastcmp = (uint8_t *)malloc(len + 1); + decode_hex(pastcmp,len,keys); + fprintf(stderr,"keystrokes.(%s) vs pastkeys\n",keys); + for (i=0; i> keystrokes.log",ASSETCHAINS_SYMBOL,Gametxidstr,hexstr); + if ( system(cmd) != 0 ) + fprintf(stderr,"error issuing (%s)\n",cmd); + } + else + { + static FILE *fp; + if ( fp == 0 ) + fp = fopen("keystrokes.log","a"); + sprintf(params,"[\"keystrokes\",\"17\",\"[%%22%s%%22,%%22%s%%22]\"]",Gametxidstr,hexstr); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( fp != 0 ) + { + fprintf(fp,"%s\n",params); + fprintf(fp,"%s\n",retstr); + fflush(fp); + } + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (rawtx= jstr(resobj,(char *)"hex")) != 0 ) + { + if ( rs->keystrokeshex != 0 ) + free(rs->keystrokeshex); + if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) + { + rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); + strcpy(rs->keystrokeshex,rawtx); + retflag = 1; + } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); + //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); + } + free_json(retjson); + } + free(retstr); + } + if ( 0 && waitflag != 0 && rs->keystrokeshex != 0 ) + { + while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + //fprintf(stderr,"post-rebroadcast\n"); + sleep(3); + } + free(rs->keystrokeshex), rs->keystrokeshex = 0; + } + } + } + return(retflag); +} + +int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) +{ + char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; + if ( rs->guiflag == 0 ) + return(-1); + if ( gametxidstr == 0 || *gametxidstr == 0 ) + return(retval); + if ( 0 ) + { + sprintf(fname,"%s.gameinfo",gametxidstr); + sprintf(cmd,"./komodo-cli -ac_name=%s cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",ASSETCHAINS_SYMBOL,gametxidstr,fname); + if ( system(cmd) != 0 ) + fprintf(stderr,"error issuing (%s)\n",cmd); + else filestr = (char *)OS_fileptr(&allocsize,fname); + } + else + { + sprintf(params,"[\"gameinfo\",\"17\",\"[%%22%s%%22]\"]",gametxidstr); + filestr = komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT); + } + if ( filestr != 0 ) + { + if ( (retjson= cJSON_Parse(filestr)) != 0 && (resultjson= jobj(retjson,(char *)"result")) != 0 ) + { + //fprintf(stderr,"gameinfo.(%s)\n",jprint(resultjson,0)); + if ( (array= jarray(&n,resultjson,(char *)"players")) != 0 ) + { + for (i=0; iP,(int32_t)strlen(datastr)/2,datastr); + fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0)); + rs->restoring = 1; + } + } + } + } + } + free_json(retjson); + } + free(filestr); + } + return(retval); +} + +#ifdef _WIN32 +#ifdef _MSC_VER +__inline int msver(void) { + switch (_MSC_VER) { + case 1500: return 2008; + case 1600: return 2010; + case 1700: return 2012; + case 1800: return 2013; + case 1900: return 2015; + //case 1910: return 2017; + default: return (_MSC_VER / 100); + } +} + +static inline bool is_x64(void) { +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) + return 1; +#elif defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) + return 1; +#else + return 0; +#endif +} + +#define BUILD_DATE __DATE__ " " __TIME__ +#endif // _WIN32 +#endif // _MSC_VER + +int main(int argc, char **argv) +{ + uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192]; +#ifdef _WIN32 +#ifdef _MSC_VER + printf("*** games for Windows [ Build %s ] ***\n", BUILD_DATE); + const char* arch = is_x64() ? "64-bits" : "32-bits"; + printf(" Built with VC++ %d (%ld) %s\n\n", msver(), _MSC_FULL_VER, arch); +#endif +#endif + + for (i=j=0; argv[0][i]!=0&&j payload) -{ - uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; - if ( (len= payload.size()) > 36 ) - { - len -= 36; - for (i=0; i<32; i++) - ((uint8_t *)&gametxid)[i] = payload[len+i]; - eventid = (uint32_t)payload[len+32]; - eventid |= (uint32_t)payload[len+33] << 8; - eventid |= (uint32_t)payload[len+34] << 16; - eventid |= (uint32_t)payload[len+35] << 24; - for (i=0; i payload); +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk); +int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); +void games_packitemstr(char *packitemstr,struct games_packitem *item); +int64_t games_cashout(struct games_player *P); + CScript games_newgameopret(int64_t buyin,int32_t maxplayers) { @@ -1343,99 +1335,6 @@ UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -int64_t games_cashout(struct games_player *P) -{ - int32_t dungeonlevel; int64_t mult=10,cashout = 0; - if ( P->amulet != 0 ) - mult *= 5; - dungeonlevel = P->dungeonlevel; - if ( P->amulet != 0 && dungeonlevel < 26 ) - dungeonlevel = 26; - cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; - return(cashout); -} - -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; - *cashoutp = 0; - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - free(keystrokes); - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - - for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); - } - *cashoutp = 0; - return(0); - } - } - if ( gametxid != prevgame ) - { - prevgame = gametxid; - bad++; - disp_gamesplayerdata(newdata); - disp_gamesplayerdata(playerdata); - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - } - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); - return(-1); -} - UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { //vin0 -> highlander vout from creategame TCBOO @@ -1657,1928 +1556,11 @@ UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) -{ - return(true); -} +#include "tetris.cpp" -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) -{ - return(-1); -} +#else // STANDALONE -void games_packitemstr(char *packitemstr,struct games_packitem *item) -{ - sprintf(packitemstr,"not yet"); -} -#else - - -#include -#include -#include -#include -#include -#include -#include - -char USERPASS[8192]; uint16_t GAMES_PORT; -char Gametxidstr[67]; -char *clonestr(char *str); - -#define MAXSTR 1024 -char whoami[MAXSTR]; - -#define SMALLVAL 0.000000000000001 -#define SATOSHIDEN ((uint64_t)100000000L) -#define dstr(x) ((double)(x) / SATOSHIDEN) -#define KOMODO_ASSETCHAIN_MAXLEN 65 -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100]; - -#ifndef _BITS256 -#define _BITS256 -union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; -typedef union _bits256 bits256; -#endif - -#ifdef _WIN32 -#ifdef _MSC_VER -int gettimeofday(struct timeval * tp, struct timezone * tzp) -{ - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); - - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; - - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - time = ((uint64_t)file_time.dwLowDateTime); - time += ((uint64_t)file_time.dwHighDateTime) << 32; - - tp->tv_sec = (long)((time - EPOCH) / 10000000L); - tp->tv_usec = (long)(system_time.wMilliseconds * 1000); - return 0; -} -#endif // _MSC_VER -#endif - - - -double OS_milliseconds() -{ - struct timeval tv; double millis; -#ifdef __MINGW32__ - mingw_gettimeofday(&tv,NULL); -#else - gettimeofday(&tv,NULL); -#endif - millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.); - //printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis); - return(millis); -} - -int32_t _unhex(char c) -{ - if ( c >= '0' && c <= '9' ) - return(c - '0'); - else if ( c >= 'a' && c <= 'f' ) - return(c - 'a' + 10); - else if ( c >= 'A' && c <= 'F' ) - return(c - 'A' + 10); - return(-1); -} - -int32_t is_hexstr(char *str,int32_t n) -{ - int32_t i; - if ( str == 0 || str[0] == 0 ) - return(0); - for (i=0; str[i]!=0; i++) - { - if ( n > 0 && i >= n ) - break; - if ( _unhex(str[i]) < 0 ) - break; - } - if ( n == 0 ) - return(i); - return(i == n); -} - -int32_t unhex(char c) -{ - int32_t hex; - if ( (hex= _unhex(c)) < 0 ) - { - //printf("unhex: illegal hexchar.(%c)\n",c); - } - return(hex); -} - -unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } - -int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex) -{ - int32_t adjust,i = 0; - //printf("decode.(%s)\n",hex); - if ( is_hexstr(hex,n) <= 0 ) - { - memset(bytes,0,n); - return(n); - } - if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) - hex[--n] = 0; - if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) - { - if ( n > 0 ) - { - bytes[0] = unhex(hex[0]); - printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); - } - bytes++; - hex++; - adjust = 1; - } else adjust = 0; - if ( n > 0 ) - { - for (i=0; i>4) & 0xf); - hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); - //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); - } - hexbytes[len*2] = 0; - //printf("len.%ld\n",len*2+1); - return((int32_t)len*2+1); -} - -char *bits256_str(char hexstr[65],bits256 x) -{ - init_hexbytes_noT(hexstr,x.bytes,sizeof(x)); - return(hexstr); -} - -long _stripwhite(char *buf,int accept) -{ - int32_t i,j,c; - if ( buf == 0 || buf[0] == 0 ) - return(0); - for (i=j=0; buf[i]!=0; i++) - { - buf[j] = c = buf[i]; - if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) - j++; - } - buf[j] = 0; - return(j); -} - -char *parse_conf_line(char *line,char *field) -{ - line += strlen(field); - for (; *line!='='&&*line!=0; line++) - break; - if ( *line == 0 ) - return(0); - if ( *line == '=' ) - line++; - while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) - line[strlen(line)-1] = 0; - //printf("LINE.(%s)\n",line); - _stripwhite(line,0); - return(clonestr(line)); -} - -int32_t safecopy(char *dest,char *src,long len) -{ - int32_t i = -1; - if ( src != 0 && dest != 0 && src != dest ) - { - if ( dest != 0 ) - memset(dest,0,len); - for (i=0; i buflen ) - { - *allocsizep = filesize; - *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); - } - rewind(fp); - if ( buf == 0 ) - printf("Null buf ???\n"); - else - { - if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) - printf("error reading filesize.%ld\n",(long)filesize); - buf[filesize] = 0; - } - fclose(fp); - *lenp = filesize; - //printf("loaded.(%s)\n",buf); - } //else printf("OS_loadfile couldnt load.(%s)\n",fname); - return(buf); -} - -uint8_t *OS_fileptr(long *allocsizep,char *fname) -{ - long filesize = 0; uint8_t *buf = 0; void *retptr; - *allocsizep = 0; - retptr = OS_loadfile(fname,&buf,&filesize,allocsizep); - return((uint8_t *)retptr); -} - -struct MemoryStruct { char *memory; size_t size; }; -struct return_string { char *ptr; size_t len; }; - -// return data from the server -#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) -#define CURL_GLOBAL_SSL (1<<0) -#define CURL_GLOBAL_WIN32 (1<<1) - - -/************************************************************************ - * - * Initialize the string handler so that it is thread safe - * - ************************************************************************/ - -void init_string(struct return_string *s) -{ - s->len = 0; - s->ptr = (char *)calloc(1,s->len+1); - if ( s->ptr == NULL ) - { - fprintf(stderr,"init_string malloc() failed\n"); - exit(-1); - } - s->ptr[0] = '\0'; -} - -/************************************************************************ - * - * Use the "writer" to accumulate text until done - * - ************************************************************************/ - -size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) -{ - size_t new_len = s->len + size*nmemb; - s->ptr = (char *)realloc(s->ptr,new_len+1); - if ( s->ptr == NULL ) - { - fprintf(stderr, "accumulate realloc() failed\n"); - exit(-1); - } - memcpy(s->ptr+s->len,ptr,size*nmemb); - s->ptr[new_len] = '\0'; - s->len = new_len; - return(size * nmemb); -} - -/************************************************************************ - * - * return the current system time in milliseconds - * - ************************************************************************/ - -#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field -#ifdef EXTRACT_BITCOIND_RESULT - -/************************************************************************ - * - * perform post processing of the results - * - ************************************************************************/ - -char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) -{ - long i,j,len; char *retstr = 0; cJSON *json,*result,*error; - //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); - if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) - { - if ( strcmp(command,"signrawtransaction") != 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); - return(rpcstr); - } - json = cJSON_Parse(rpcstr); - if ( json == 0 ) - { - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); - free(rpcstr); - return(0); - } - result = cJSON_GetObjectItem(json,"result"); - error = cJSON_GetObjectItem(json,"error"); - if ( error != 0 && result != 0 ) - { - if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) - { - retstr = cJSON_Print(result); - len = strlen(retstr); - if ( retstr[0] == '"' && retstr[len-1] == '"' ) - { - for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) - { - if ( strcmp(command,"signrawtransaction") != 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); - } - free(rpcstr); - } else retstr = rpcstr; - free_json(json); - //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); - return(retstr); -} -#endif - -#ifdef _WIN32 -#ifdef _MSC_VER -#define sleep(x) Sleep(1000*(x)) -#endif -#endif - -/************************************************************************ - * - * perform the query - * - ************************************************************************/ - -char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) -{ - static int didinit,count,count2; static double elapsedsum,elapsedsum2; - struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; - char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; - if ( didinit == 0 ) - { - didinit = 1; - curl_global_init(CURL_GLOBAL_ALL); //init the curl session - } - numretries = 0; - if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) - specialcase = 1; - else specialcase = 0; - if ( url[0] == 0 ) - strcpy(url,"http://127.0.0.1:7876/nxt"); - if ( specialcase != 0 && 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); -try_again: - if ( retstrp != 0 ) - *retstrp = 0; - starttime = OS_milliseconds(); - curl_handle = curl_easy_init(); - init_string(&s); - headers = curl_slist_append(0,"Expect:"); - - curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl_handle,CURLOPT_URL, url); - curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function - curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback - curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash - curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - if ( strncmp(url,"https",5) == 0 ) - { - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); - } - if ( userpass != 0 ) - curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); - databuf = 0; - if ( params != 0 ) - { - if ( command != 0 && specialcase == 0 ) - { - len = strlen(params); - if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { - bracket0 = bracket1 = (char *)""; - } - else - { - bracket0 = (char *)"["; - bracket1 = (char *)"]"; - } - - databuf = (char *)malloc(256 + strlen(command) + strlen(params)); - sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); - //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); - // - } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); - curl_easy_setopt(curl_handle,CURLOPT_POST,1L); - if ( databuf != 0 ) - curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); - else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); - } - //laststart = milliseconds(); - res = curl_easy_perform(curl_handle); - curl_slist_free_all(headers); - curl_easy_cleanup(curl_handle); - if ( databuf != 0 ) // clean up temporary buffer - { - free(databuf); - databuf = 0; - } - if ( res != CURLE_OK ) - { - numretries++; - if ( specialcase != 0 ) - { - printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); - free(s.ptr); - return(0); - } - else if ( numretries >= 1 ) - { - //printf("Maximum number of retries exceeded!\n"); - free(s.ptr); - return(0); - } - if ( (rand() % 1000) == 0 ) - printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); - free(s.ptr); - sleep((1< (%s)\n",params,s.ptr); - count2++; - elapsedsum2 += (OS_milliseconds() - starttime); - if ( (count2 % 10000) == 0) - printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); - return(s.ptr); - } - } - printf("bitcoind_RPC: impossible case\n"); - free(s.ptr); - return(0); -} - -static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) -{ - size_t realsize = (size * nmemb); - struct MemoryStruct *mem = (struct MemoryStruct *)data; - mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); - if ( mem->memory != 0 ) - { - if ( ptr != 0 ) - memcpy(&(mem->memory[mem->size]),ptr,realsize); - mem->size += realsize; - mem->memory[mem->size] = 0; - } - //printf("got %d bytes\n",(int32_t)(size*nmemb)); - return(realsize); -} - -char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) -{ - struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; - if ( (cHandle= *cHandlep) == NULL ) - *cHandlep = cHandle = curl_easy_init(); - else curl_easy_reset(cHandle); - //#ifdef DEBUG - //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); - //#endif - curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); - //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); - curl_easy_setopt(cHandle,CURLOPT_URL,url); - curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); - if ( userpass != 0 && userpass[0] != 0 ) - curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); - if ( postfields != 0 && postfields[0] != 0 ) - { - curl_easy_setopt(cHandle,CURLOPT_POST,1); - curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); - } - if ( hdr0 != NULL && hdr0[0] != 0 ) - { - //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); - headers = curl_slist_append(headers,hdr0); - if ( hdr1 != 0 && hdr1[0] != 0 ) - headers = curl_slist_append(headers,hdr1); - if ( hdr2 != 0 && hdr2[0] != 0 ) - headers = curl_slist_append(headers,hdr2); - if ( hdr3 != 0 && hdr3[0] != 0 ) - headers = curl_slist_append(headers,hdr3); - } //headers = curl_slist_append(0,"Expect:"); - if ( headers != 0 ) - curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); - //res = curl_easy_perform(cHandle); - memset(&chunk,0,sizeof(chunk)); - curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); - curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); - curl_easy_perform(cHandle); - curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); - if ( headers != 0 ) - curl_slist_free_all(headers); - if ( code != 200 ) - printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); - return(chunk.memory); -} - -uint16_t _komodo_userpass(char *username, char *password, FILE *fp) -{ - char *rpcuser,*rpcpassword,*str,*ipaddress,line[8192]; uint16_t port = 0; - rpcuser = rpcpassword = 0; - username[0] = password[0] = 0; - while ( fgets(line,sizeof(line),fp) != 0 ) - { - if ( line[0] == '#' ) - continue; - //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); - if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) - rpcuser = parse_conf_line(str,(char *)"rpcuser"); - else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) - rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); - else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) - { - port = atoi(parse_conf_line(str,(char *)"rpcport")); - //fprintf(stderr,"rpcport.%u in file\n",port); - } - else if ( (str= strstr(line,(char *)"ipaddress")) != 0 ) - { - ipaddress = parse_conf_line(str,(char *)"ipaddress"); - strcpy(IPADDRESS,ipaddress); - } - } - if ( rpcuser != 0 && rpcpassword != 0 ) - { - strcpy(username,rpcuser); - strcpy(password,rpcpassword); - } - //printf("rpcuser.(%s) rpcpassword.(%s) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress); - if ( rpcuser != 0 ) - free(rpcuser); - if ( rpcpassword != 0 ) - free(rpcpassword); - return(port); -} - -uint16_t komodo_userpass(char *userpass,char *symbol) -{ - FILE *fp; uint16_t port = 0; char fname[512],username[512],password[512],confname[KOMODO_ASSETCHAIN_MAXLEN]; - userpass[0] = 0; - if ( strcmp("KMD",symbol) == 0 ) - { -#ifdef __APPLE__ - sprintf(confname,"Komodo.conf"); -#else - sprintf(confname,"komodo.conf"); -#endif - } - else sprintf(confname,"%s.conf",symbol); - //komodo_statefname(fname,symbol,confname); - if ( (fp= fopen(confname,"rb")) != 0 ) - { - port = _komodo_userpass(username,password,fp); - sprintf(userpass,"%s:%s",username,password); - if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) - strcpy(USERPASS,userpass); - fclose(fp); - } - return(port); -} - -#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) - -char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) -{ - //static void *cHandle; - char url[512],*retstr=0,*retstr2=0,postdata[8192]; - if ( params == 0 || params[0] == 0 ) - params = (char *)"[]"; - if ( strlen(params) < sizeof(postdata)-128 ) - { - sprintf(url,(char *)"http://%s:%u",IPADDRESS,port); - sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); - //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,USERPASS); - retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); - //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); - } - return(retstr2); -} - -int32_t issue_games_events(bits256 gametxid,uint32_t eventid,int32_t c) -{ - static FILE *fp; - char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} - -int32_t games_sendrawtransaction(char *rawtx) -{ - char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; - params = (char *)malloc(strlen(rawtx) + 16); - sprintf(params,"[\"%s\"]",rawtx); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"sendrawtransaction",params,GAMES_PORT)) != 0 ) - { - if ( 0 ) // causes 4th level crash - { - static FILE *fp; - if ( fp == 0 ) - fp = fopen("games.sendlog","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%s\n",retstr); - fflush(fp); - } - } - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - if ( (hexstr= jstr(resobj,0)) != 0 && is_hexstr(hexstr,64) == 64 ) - retval = 0; - } - free_json(retjson); - } - - /* log sendrawtx result in file */ - - /* - FILE *debug_file; - debug_file = fopen("tx_debug.log", "a"); - fprintf(debug_file, "%s\n", retstr); - fflush(debug_file); - fclose(debug_file); - */ - - free(retstr); - } - free(params); - return(retval); -} - -int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) -{ - char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx,*pastkeys,*keys; int32_t i,len,numpastkeys,retflag = -1; cJSON *retjson,*resobj; uint8_t *pastcmp; - if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) - { - if ( rs->keystrokeshex != 0 ) - { - if ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - if ( waitflag == 0 ) - return(0); - else if ( 0 ) - { - while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - //fprintf(stderr,"pre-rebroadcast\n"); - sleep(10); - } - } - } - free(rs->keystrokeshex), rs->keystrokeshex = 0; - } - if ( 0 && (pastkeys= games_keystrokesload(&numpastkeys,seed,1)) != 0 ) - { - sprintf(params,"[\"extract\",\"17\",\"[%%22%s%%22]\"]",Gametxidstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (keys= jstr(resobj,(char *)"keystrokes")) != 0 ) - { - len = strlen(keys) / 2; - pastcmp = (uint8_t *)malloc(len + 1); - decode_hex(pastcmp,len,keys); - fprintf(stderr,"keystrokes.(%s) vs pastkeys\n",keys); - for (i=0; i> keystrokes.log",ASSETCHAINS_SYMBOL,Gametxidstr,hexstr); - if ( system(cmd) != 0 ) - fprintf(stderr,"error issuing (%s)\n",cmd); - } - else - { - static FILE *fp; - if ( fp == 0 ) - fp = fopen("keystrokes.log","a"); - sprintf(params,"[\"keystrokes\",\"17\",\"[%%22%s%%22,%%22%s%%22]\"]",Gametxidstr,hexstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( fp != 0 ) - { - fprintf(fp,"%s\n",params); - fprintf(fp,"%s\n",retstr); - fflush(fp); - } - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (rawtx= jstr(resobj,(char *)"hex")) != 0 ) - { - if ( rs->keystrokeshex != 0 ) - free(rs->keystrokeshex); - if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) - { - rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); - strcpy(rs->keystrokeshex,rawtx); - retflag = 1; - } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); - //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); - } - free_json(retjson); - } - free(retstr); - } - if ( 0 && waitflag != 0 && rs->keystrokeshex != 0 ) - { - while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - //fprintf(stderr,"post-rebroadcast\n"); - sleep(3); - } - free(rs->keystrokeshex), rs->keystrokeshex = 0; - } - } - } - return(retflag); -} - -int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) -{ - char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; - if ( rs->guiflag == 0 ) - return(-1); - if ( gametxidstr == 0 || *gametxidstr == 0 ) - return(retval); - if ( 0 ) - { - sprintf(fname,"%s.gameinfo",gametxidstr); - sprintf(cmd,"./komodo-cli -ac_name=%s cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",ASSETCHAINS_SYMBOL,gametxidstr,fname); - if ( system(cmd) != 0 ) - fprintf(stderr,"error issuing (%s)\n",cmd); - else filestr = (char *)OS_fileptr(&allocsize,fname); - } - else - { - sprintf(params,"[\"gameinfo\",\"17\",\"[%%22%s%%22]\"]",gametxidstr); - filestr = komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT); - } - if ( filestr != 0 ) - { - if ( (retjson= cJSON_Parse(filestr)) != 0 && (resultjson= jobj(retjson,(char *)"result")) != 0 ) - { - //fprintf(stderr,"gameinfo.(%s)\n",jprint(resultjson,0)); - if ( (array= jarray(&n,resultjson,(char *)"players")) != 0 ) - { - for (i=0; iP,(int32_t)strlen(datastr)/2,datastr); - fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0)); - rs->restoring = 1; - } - } - } - } - } - free_json(retjson); - } - free(filestr); - } - return(retval); -} - -#ifdef _WIN32 -#ifdef _MSC_VER -__inline int msver(void) { - switch (_MSC_VER) { - case 1500: return 2008; - case 1600: return 2010; - case 1700: return 2012; - case 1800: return 2013; - case 1900: return 2015; - //case 1910: return 2017; - default: return (_MSC_VER / 100); - } -} - -static inline bool is_x64(void) { -#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) - return 1; -#elif defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) - return 1; -#else - return 0; -#endif -} - -#define BUILD_DATE __DATE__ " " __TIME__ -#endif // _WIN32 -#endif // _MSC_VER - -int main(int argc, char **argv) -{ - uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192]; -#ifdef _WIN32 -#ifdef _MSC_VER - printf("*** games for Windows [ Build %s ] ***\n", BUILD_DATE); - const char* arch = is_x64() ? "64-bits" : "32-bits"; - printf(" Built with VC++ %d (%ld) %s\n\n", msver(), _MSC_FULL_VER, arch); -#endif -#endif - - for (i=j=0; argv[0][i]!=0&&j // for FILE -#include // for bool -#include -#include -#include -#include -#include -#include - -#ifdef BUILD_GAMESCC -#include "rogue/cursesd.h" -#else -#include -#endif - -/* - Convert a tetromino type to its corresponding cell. - */ -#define TYPE_TO_CELL(x) ((x)+1) - -/* - Strings for how you would print a tetris board. - */ -#define TC_EMPTY_STR " " -#define TC_BLOCK_STR "\u2588" - -/* - Questions about a tetris cell. - */ -#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) -#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) - -/* - How many cells in a tetromino? - */ -#define TETRIS 4 -/* - How many tetrominos? - */ -#define NUM_TETROMINOS 7 -/* - How many orientations of a tetromino? - */ -#define NUM_ORIENTATIONS 4 - -/* - Level constants. - */ -#define MAX_LEVEL 19 -#define LINES_PER_LEVEL 10 - -/* - A "cell" is a 1x1 block within a tetris board. - */ -typedef enum { - TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ -} tetris_cell; - -/* - A "type" is a type/shape of a tetromino. Not including orientation. - */ -typedef enum { - TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z -} tetris_type; - -/* - A row,column pair. Negative numbers allowed, because we need them for - offsets. - */ -typedef struct { - int row; - int col; -} tetris_location; - -/* - A "block" is a struct that contains information about a tetromino. - Specifically, what type it is, what orientation it has, and where it is. - */ -typedef struct { - int typ; - int ori; - tetris_location loc; -} tetris_block; - -/* - All possible moves to give as input to the game. - */ -typedef enum { - TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE -} tetris_move; - -/* - A game object! - */ -typedef struct { - /* - Game board stuff: - */ - int rows; - int cols; - char *board; - /* - Scoring information: - */ - int points; - int level; - /* - Falling block is the one currently going down. Next block is the one that - will be falling after this one. Stored is the block that you can swap out. - */ - tetris_block falling; - tetris_block next; - tetris_block stored; - /* - Number of game ticks until the block will move down. - */ - int ticks_till_gravity; - /* - Number of lines until you advance to the next level. - */ - int lines_remaining; -} tetris_game; - -/* - This array stores all necessary information about the cells that are filled by - each tetromino. The first index is the type of the tetromino (i.e. shape, - e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final - array contains 4 tetris_location objects, each mapping to an offset from a - point on the upper left that is the tetromino "origin". - */ -extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; - -/* - This array tells you how many ticks per gravity by level. Decreases as level - increases, to add difficulty. - */ -extern int GRAVITY_LEVEL[MAX_LEVEL+1]; - -// Data structure manipulation. -void tg_init(tetris_game *obj, int rows, int cols); -tetris_game *tg_create(int rows, int cols); -void tg_destroy(tetris_game *obj); -void tg_delete(tetris_game *obj); -tetris_game *tg_load(FILE *f); -void tg_save(tetris_game *obj, FILE *f); - -// Public methods not related to memory: -char tg_get(tetris_game *obj, int row, int col); -bool tg_check(tetris_game *obj, int row, int col); -bool tg_tick(tetris_game *obj, tetris_move move); -void tg_print(tetris_game *obj, FILE *f); - -#endif // TETRIS_H - - -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -/******************************************************************************* - Array Definitions - *******************************************************************************/ - -tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = { - // I - {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, - // J - {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, - {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, - // L - {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, - {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, - // O - {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, - // S - {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, - {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, - {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, - // T - {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, - // Z - {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, - {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, -}; - -int GRAVITY_LEVEL[MAX_LEVEL+1] = { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, - //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 -}; - -/******************************************************************************* - Helper Functions for Blocks - *******************************************************************************/ - -void sleep_milli(int milliseconds) -{ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = milliseconds * 1000 * 1000; - nanosleep(&ts, NULL); -} - -/* - Return the block at the given row and column. - */ -char tg_get(tetris_game *obj, int row, int column) -{ - return obj->board[obj->cols * row + column]; -} - -/* - Set the block at the given row and column. - */ -static void tg_set(tetris_game *obj, int row, int column, char value) -{ - obj->board[obj->cols * row + column] = value; -} - -/* - Check whether a row and column are in bounds. - */ -bool tg_check(tetris_game *obj, int row, int col) -{ - return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; -} - -/* - Place a block onto the board. - */ -static void tg_put(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, - TYPE_TO_CELL(block.typ)); - } -} - -/* - Clear a block out of the board. - */ -static void tg_remove(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); - } -} - -/* - Check if a block can be placed on the board. - */ -static bool tg_fits(tetris_game *obj, tetris_block block) -{ - int i, r, c; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - r = block.loc.row + cell.row; - c = block.loc.col + cell.col; - if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { - return false; - } - } - return true; -} - -/* - Return a random tetromino type. - */ -static int random_tetromino(void) -{ - return rand() % NUM_TETROMINOS; -} - -/* - Create a new falling block and populate the next falling block with a random - one. - */ -static void tg_new_falling(tetris_game *obj) -{ - // Put in a new falling tetromino. - obj->falling = obj->next; - obj->next.typ = random_tetromino(); - obj->next.ori = 0; - obj->next.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; -} - -/******************************************************************************* - Game Turn Helpers - *******************************************************************************/ - -/* - Tick gravity, and move the block down if gravity should act. - */ -static void tg_do_gravity_tick(tetris_game *obj) -{ - obj->ticks_till_gravity--; - if (obj->ticks_till_gravity <= 0) { - tg_remove(obj, obj->falling); - obj->falling.loc.row++; - if (tg_fits(obj, obj->falling)) { - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - } else { - obj->falling.loc.row--; - tg_put(obj, obj->falling); - - tg_new_falling(obj); - } - tg_put(obj, obj->falling); - } -} - -/* - Move the falling tetris block left (-1) or right (+1). - */ -static void tg_move(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - obj->falling.loc.col += direction; - if (!tg_fits(obj, obj->falling)) { - obj->falling.loc.col -= direction; - } - tg_put(obj, obj->falling); -} - -/* - Send the falling tetris block to the bottom. - */ -static void tg_down(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - while (tg_fits(obj, obj->falling)) { - obj->falling.loc.row++; - } - obj->falling.loc.row--; - tg_put(obj, obj->falling); - tg_new_falling(obj); -} - -/* - Rotate the falling block in either direction (+/-1). - */ -static void tg_rotate(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - - while (true) { - obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; - - // If the new orientation fits, we're done. - if (tg_fits(obj, obj->falling)) - break; - - // Otherwise, try moving left to make it fit. - obj->falling.loc.col--; - if (tg_fits(obj, obj->falling)) - break; - - // Finally, try moving right to make it fit. - obj->falling.loc.col += 2; - if (tg_fits(obj, obj->falling)) - break; - - // Put it back in its original location and try the next orientation. - obj->falling.loc.col--; - // Worst case, we come back to the original orientation and it fits, so this - // loop will terminate. - } - - tg_put(obj, obj->falling); -} - -/* - Swap the falling block with the block in the hold buffer. - */ -static void tg_hold(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - if (obj->stored.typ == -1) { - obj->stored = obj->falling; - tg_new_falling(obj); - } else { - int typ = obj->falling.typ, ori = obj->falling.ori; - obj->falling.typ = obj->stored.typ; - obj->falling.ori = obj->stored.ori; - obj->stored.typ = typ; - obj->stored.ori = ori; - while (!tg_fits(obj, obj->falling)) { - obj->falling.loc.row--; - } - } - tg_put(obj, obj->falling); -} - -/* - Perform the action specified by the move. - */ -static void tg_handle_move(tetris_game *obj, tetris_move move) -{ - switch (move) { - case TM_LEFT: - tg_move(obj, -1); - break; - case TM_RIGHT: - tg_move(obj, 1); - break; - case TM_DROP: - tg_down(obj); - break; - case TM_CLOCK: - tg_rotate(obj, 1); - break; - case TM_COUNTER: - tg_rotate(obj, -1); - break; - case TM_HOLD: - tg_hold(obj); - break; - default: - // pass - break; - } -} - -/* - Return true if line i is full. - */ -static bool tg_line_full(tetris_game *obj, int i) -{ - int j; - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) - return false; - } - return true; -} - -/* - Shift every row above r down one. - */ -static void tg_shift_lines(tetris_game *obj, int r) -{ - int i, j; - for (i = r-1; i >= 0; i--) { - for (j = 0; j < obj->cols; j++) { - tg_set(obj, i+1, j, tg_get(obj, i, j)); - tg_set(obj, i, j, TC_EMPTY); - } - } -} - -/* - Find rows that are filled, remove them, shift, and return the number of - cleared rows. - */ -static int tg_check_lines(tetris_game *obj) -{ - int i, nlines = 0; - tg_remove(obj, obj->falling); // don't want to mess up falling block - - for (i = obj->rows-1; i >= 0; i--) { - if (tg_line_full(obj, i)) { - tg_shift_lines(obj, i); - i++; // do this line over again since they're shifted - nlines++; - } - } - - tg_put(obj, obj->falling); // replace - return nlines; -} - -/* - Adjust the score for the game, given how many lines were just cleared. - */ -static void tg_adjust_score(tetris_game *obj, int lines_cleared) -{ - static int line_multiplier[] = {0, 40, 100, 300, 1200}; - obj->points += line_multiplier[lines_cleared] * (obj->level + 1); - if (lines_cleared >= obj->lines_remaining) { - obj->level = MIN(MAX_LEVEL, obj->level + 1); - lines_cleared -= obj->lines_remaining; - obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; - } else { - obj->lines_remaining -= lines_cleared; - } -} - -/* - Return true if the game is over. - */ -static bool tg_game_over(tetris_game *obj) -{ - int i, j; - bool over = false; - tg_remove(obj, obj->falling); - for (i = 0; i < 2; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - over = true; - } - } - } - tg_put(obj, obj->falling); - return over; -} - -/******************************************************************************* - Main Public Functions - *******************************************************************************/ - -/* - Do a single game tick: process gravity, user input, and score. Return true if - the game is still running, false if it is over. - */ -bool tg_tick(tetris_game *obj, tetris_move move) -{ - int lines_cleared; - // Handle gravity. - tg_do_gravity_tick(obj); - - // Handle input. - tg_handle_move(obj, move); - - // Check for cleared lines - lines_cleared = tg_check_lines(obj); - - tg_adjust_score(obj, lines_cleared); - - // Return whether the game will continue (NOT whether it's over) - return !tg_game_over(obj); -} - -void tg_init(tetris_game *obj, int rows, int cols) -{ - // Initialization logic - obj->rows = rows; - obj->cols = cols; - obj->board = (char *)malloc(rows * cols); - memset(obj->board, TC_EMPTY, rows * cols); - obj->points = 0; - obj->level = 0; - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - obj->lines_remaining = LINES_PER_LEVEL; - srand(time(NULL)); - tg_new_falling(obj); - tg_new_falling(obj); - obj->stored.typ = -1; - obj->stored.ori = 0; - obj->stored.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; - printf("%d", obj->falling.loc.col); -} - -tetris_game *tg_create(int rows, int cols) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - tg_init(obj, rows, cols); - return obj; -} - -void tg_destroy(tetris_game *obj) -{ - // Cleanup logic - free(obj->board); -} - -void tg_delete(tetris_game *obj) { - tg_destroy(obj); - free(obj); -} - -/* - Load a game from a file. - */ -tetris_game *tg_load(FILE *f) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) - { - fprintf(stderr,"read game error\n"); - free(obj); - obj = 0; - } - else - { - obj->board = (char *)malloc(obj->rows * obj->cols); - if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - { - fprintf(stderr,"fread error\n"); - free(obj->board); - free(obj); - obj = 0; - } - } - return obj; -} - -/* - Save a game to a file. - */ -void tg_save(tetris_game *obj, FILE *f) -{ - if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) - fprintf(stderr,"error writing tetrisgame\n"); - else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - fprintf(stderr,"error writing board\n"); -} - -/* - Print a game board to a file. Really just for early debugging. - */ -void tg_print(tetris_game *obj, FILE *f) { - int i, j; - for (i = 0; i < obj->rows; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) { - fputs(TC_EMPTY_STR, f); - } else { - fputs(TC_BLOCK_STR, f); - } - } - fputc('\n', f); - } -} - -/* - 2 columns per cell makes the game much nicer. - */ -#define COLS_PER_CELL 2 -/* - Macro to print a cell of a specific type to a window. - */ -#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ -waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) -#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') - -/* - Print the tetris board onto the ncurses window. - */ -void display_board(WINDOW *w, tetris_game *obj) -{ - int i, j; - box(w, 0, 0); - for (i = 0; i < obj->rows; i++) { - wmove(w, 1 + i, 1); - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - ADD_BLOCK(w,tg_get(obj, i, j)); - } else { - ADD_EMPTY(w); - } - } - } - wnoutrefresh(w); -} - -/* - Display a tetris piece in a dedicated window. - */ -void display_piece(WINDOW *w, tetris_block block) -{ - int b; - tetris_location c; - wclear(w); - box(w, 0, 0); - if (block.typ == -1) { - wnoutrefresh(w); - return; - } - for (b = 0; b < TETRIS; b++) { - c = TETROMINOS[block.typ][block.ori][b]; - wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); - ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); - } - wnoutrefresh(w); -} - -/* - Display score information in a dedicated window. - */ -void display_score(WINDOW *w, tetris_game *tg) -{ - wclear(w); - box(w, 0, 0); - wprintw(w, (char *)"Score\n%d\n", tg->points); - wprintw(w, (char *)"Level\n%d\n", tg->level); - wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); - wnoutrefresh(w); -} - -/* - Save and exit the game. - */ -void save(tetris_game *game, WINDOW *w) -{ - FILE *f; - - wclear(w); - box(w, 0, 0); // return the border - wmove(w, 1, 1); - wprintw(w, (char *)"Save and exit? [Y/n] "); - wrefresh(w); - timeout(-1); - if (getch() == 'n') { - timeout(0); - return; - } - f = fopen("tetris.save", "w"); - tg_save(game, f); - fclose(f); - tg_delete(game); - endwin(); - fprintf(stderr,"Game saved to \"tetris.save\".\n"); - fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); - exit(EXIT_SUCCESS); -} - -/* - Do the NCURSES initialization steps for color blocks. - */ -void init_colors(void) -{ - start_color(); - //init_color(COLOR_ORANGE, 1000, 647, 0); - init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); - init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); - init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); - init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); - init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); - init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); - init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); -} - -/* - Main tetris game! - */ -#ifdef STANDALONE -char *clonestr(char *str) -{ - char *clone; int32_t len; - if ( str == 0 || str[0] == 0 ) - { - printf("warning cloning nullstr.%p\n",str); -#ifdef __APPLE__ - while ( 1 ) sleep(1); -#endif - str = (char *)""; - } - len = strlen(str); - clone = (char *)calloc(1,len+16); - strcpy(clone,str); - return(clone); -} - -int tetris(int argc, char **argv) -{ - tetris_game *tg; - tetris_move move = TM_NONE; - bool running = true; - WINDOW *board, *next, *hold, *score; - int32_t c,skipcount=0; bits256 gametxid; uint32_t eventid = 0; - memset(&gametxid,0,sizeof(gametxid)); - // Load file if given a filename. - if (argc >= 2) { - FILE *f = fopen(argv[1], "r"); - if (f == NULL) { - perror("tetris"); - exit(EXIT_FAILURE); - } - tg = tg_load(f); - fclose(f); - } else { - // Otherwise create new game. - tg = tg_create(22, 10); - } - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors - - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - int32_t counter = 0; - // Game loop - while (running) { - running = tg_tick(tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - c = getch(); - if ( c != -1 || skipcount == 0x3fff ) - { - if ( skipcount > 0 ) - issue_games_events(gametxid,eventid-skipcount,skipcount | 0x4000); - if ( c != -1 ) - issue_games_events(gametxid,eventid,c); - skipcount = 0; - } else skipcount++; - eventid++; - switch ( c ) - { - case KEY_LEFT: - move = TM_LEFT; - break; - case KEY_RIGHT: - move = TM_RIGHT; - break; - case KEY_UP: - move = TM_CLOCK; - break; - case KEY_DOWN: - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break; - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } - } - - // Deinitialize NCurses - wclear(stdscr); - endwin(); - // Output ending message. - printf("Game over!\n"); - printf("You finished with %d points on level %d.\n", tg->points, tg->level); - - // Deinitialize Tetris - tg_delete(tg); - return 0; -} - -int32_t games_replay(uint64_t seed,int32_t sleeptime) -{ - return(-1); -} +#include "tetris.c" #endif diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 19e5f8d26..07a1f8e65 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -20,7 +20,7 @@ std::string MYCCLIBNAME = (char *)"gamescc"; #define GAMES_MAXKEYSTROKESGAP 60 #define GAMES_MAXPLAYERS 64 #define GAMES_REGISTRATIONSIZE (100 * 10000) -#define GAMES_REGISTRATION 5 +#define GAMES_REGISTRATION 1 #define GAMES_RNGMULT 11109 #define GAMES_RNGOFFSET 13849 @@ -29,7 +29,6 @@ std::string MYCCLIBNAME = (char *)"gamescc"; #define MYCCNAME "games" std::string Games_pname; -#define GAMENAME "sudoku" #define RPC_FUNCS \ { (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \ @@ -104,33 +103,4 @@ if ( cp->evalcode == EVAL_GAMES ) \ } #endif -#define MAXPACK 23 -struct games_packitem -{ - int32_t type,launch,count,which,hplus,dplus,arm,flags,group; - char damage[8],hurldmg[8]; -}; - -struct games_player -{ - int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; - struct games_packitem gamespack[MAXPACK]; -}; - -struct games_state -{ - uint64_t seed; - char *keystrokes,*keystrokeshex; - uint32_t needflush,replaydone; - int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; - FILE *logfp; - struct games_player P; - char buffered[10000]; - uint8_t playerdata[10000]; -}; - -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); -void games_packitemstr(char *packitemstr,struct games_packitem *item); - - #endif diff --git a/src/cc/tetris.c b/src/cc/tetris.c new file mode 100644 index 000000000..4ffd27575 --- /dev/null +++ b/src/cc/tetris.c @@ -0,0 +1,758 @@ + +#include "tetris.h" +#include "dapps/dappstd.c" + + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + + +#include // for FILE +#include // for bool +#include +#include +#include +#include +#include +#include + +#ifdef BUILD_GAMESCC +#include "rogue/cursesd.h" +#else +#include +#endif + + +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +/******************************************************************************* + Array Definitions + *******************************************************************************/ + +const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = +{ + // I + {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, + {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, + {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, + {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, + // J + {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, + {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, + // L + {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, + {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, + // O + {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, + // S + {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, + {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, + {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, + // T + {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, + // Z + {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, + {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, +}; + +const int GRAVITY_LEVEL[MAX_LEVEL+1] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 +}; + +/******************************************************************************* + Helper Functions for Blocks + *******************************************************************************/ + +void sleep_milli(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = milliseconds * 1000 * 1000; + nanosleep(&ts, NULL); +} + +/* + Return the block at the given row and column. + */ +char tg_get(tetris_game *obj, int row, int column) +{ + return obj->board[obj->cols * row + column]; +} + +/* + Set the block at the given row and column. + */ +static void tg_set(tetris_game *obj, int row, int column, char value) +{ + obj->board[obj->cols * row + column] = value; +} + +/* + Check whether a row and column are in bounds. + */ +bool tg_check(tetris_game *obj, int row, int col) +{ + return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; +} + +/* + Place a block onto the board. + */ +static void tg_put(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, + TYPE_TO_CELL(block.typ)); + } +} + +/* + Clear a block out of the board. + */ +static void tg_remove(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); + } +} + +/* + Check if a block can be placed on the board. + */ +static bool tg_fits(tetris_game *obj, tetris_block block) +{ + int i, r, c; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + r = block.loc.row + cell.row; + c = block.loc.col + cell.col; + if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { + return false; + } + } + return true; +} + +/* + Create a new falling block and populate the next falling block with a random + one. + */ +static void tg_new_falling(tetris_game *obj) +{ + // Put in a new falling tetromino. + obj->falling = obj->next; + obj->next.typ = random_tetromino(); + obj->next.ori = 0; + obj->next.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; +} + +/******************************************************************************* + Game Turn Helpers + *******************************************************************************/ + +/* + Tick gravity, and move the block down if gravity should act. + */ +static void tg_do_gravity_tick(tetris_game *obj) +{ + obj->ticks_till_gravity--; + if (obj->ticks_till_gravity <= 0) { + tg_remove(obj, obj->falling); + obj->falling.loc.row++; + if (tg_fits(obj, obj->falling)) { + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + } else { + obj->falling.loc.row--; + tg_put(obj, obj->falling); + + tg_new_falling(obj); + } + tg_put(obj, obj->falling); + } +} + +/* + Move the falling tetris block left (-1) or right (+1). + */ +static void tg_move(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + obj->falling.loc.col += direction; + if (!tg_fits(obj, obj->falling)) { + obj->falling.loc.col -= direction; + } + tg_put(obj, obj->falling); +} + +/* + Send the falling tetris block to the bottom. + */ +static void tg_down(tetris_game *obj) +{ + tg_remove(obj, obj->falling); + while (tg_fits(obj, obj->falling)) { + obj->falling.loc.row++; + } + obj->falling.loc.row--; + tg_put(obj, obj->falling); + tg_new_falling(obj); +} + +/* + Rotate the falling block in either direction (+/-1). + */ +static void tg_rotate(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + + while (true) { + obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; + + // If the new orientation fits, we're done. + if (tg_fits(obj, obj->falling)) + break; + + // Otherwise, try moving left to make it fit. + obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) + break; + + // Finally, try moving right to make it fit. + obj->falling.loc.col += 2; + if (tg_fits(obj, obj->falling)) + break; + + // Put it back in its original location and try the next orientation. + obj->falling.loc.col--; + // Worst case, we come back to the original orientation and it fits, so this + // loop will terminate. + } + + tg_put(obj, obj->falling); +} + +/* + Swap the falling block with the block in the hold buffer. + */ +static void tg_hold(tetris_game *obj) +{ + tg_remove(obj, obj->falling); + if (obj->stored.typ == -1) { + obj->stored = obj->falling; + tg_new_falling(obj); + } else { + int typ = obj->falling.typ, ori = obj->falling.ori; + obj->falling.typ = obj->stored.typ; + obj->falling.ori = obj->stored.ori; + obj->stored.typ = typ; + obj->stored.ori = ori; + while (!tg_fits(obj, obj->falling)) { + obj->falling.loc.row--; + } + } + tg_put(obj, obj->falling); +} + +/* + Perform the action specified by the move. + */ +static void tg_handle_move(tetris_game *obj, tetris_move move) +{ + switch (move) { + case TM_LEFT: + tg_move(obj, -1); + break; + case TM_RIGHT: + tg_move(obj, 1); + break; + case TM_DROP: + tg_down(obj); + break; + case TM_CLOCK: + tg_rotate(obj, 1); + break; + case TM_COUNTER: + tg_rotate(obj, -1); + break; + case TM_HOLD: + tg_hold(obj); + break; + default: + // pass + break; + } +} + +/* + Return true if line i is full. + */ +static bool tg_line_full(tetris_game *obj, int i) +{ + int j; + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) + return false; + } + return true; +} + +/* + Shift every row above r down one. + */ +static void tg_shift_lines(tetris_game *obj, int r) +{ + int i, j; + for (i = r-1; i >= 0; i--) { + for (j = 0; j < obj->cols; j++) { + tg_set(obj, i+1, j, tg_get(obj, i, j)); + tg_set(obj, i, j, TC_EMPTY); + } + } +} + +/* + Find rows that are filled, remove them, shift, and return the number of + cleared rows. + */ +static int tg_check_lines(tetris_game *obj) +{ + int i, nlines = 0; + tg_remove(obj, obj->falling); // don't want to mess up falling block + + for (i = obj->rows-1; i >= 0; i--) { + if (tg_line_full(obj, i)) { + tg_shift_lines(obj, i); + i++; // do this line over again since they're shifted + nlines++; + } + } + + tg_put(obj, obj->falling); // replace + return nlines; +} + +/* + Adjust the score for the game, given how many lines were just cleared. + */ +static void tg_adjust_score(tetris_game *obj, int lines_cleared) +{ + static int line_multiplier[] = {0, 40, 100, 300, 1200}; + obj->points += line_multiplier[lines_cleared] * (obj->level + 1); + if (lines_cleared >= obj->lines_remaining) { + obj->level = MIN(MAX_LEVEL, obj->level + 1); + lines_cleared -= obj->lines_remaining; + obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; + } else { + obj->lines_remaining -= lines_cleared; + } +} + +/* + Return true if the game is over. + */ +static bool tg_game_over(tetris_game *obj) +{ + int i, j; + bool over = false; + tg_remove(obj, obj->falling); + for (i = 0; i < 2; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + over = true; + } + } + } + tg_put(obj, obj->falling); + return over; +} + +/******************************************************************************* + Main Public Functions + *******************************************************************************/ + +/* + Do a single game tick: process gravity, user input, and score. Return true if + the game is still running, false if it is over. + */ +bool tg_tick(tetris_game *obj, tetris_move move) +{ + int lines_cleared; + // Handle gravity. + tg_do_gravity_tick(obj); + + // Handle input. + tg_handle_move(obj, move); + + // Check for cleared lines + lines_cleared = tg_check_lines(obj); + + tg_adjust_score(obj, lines_cleared); + + // Return whether the game will continue (NOT whether it's over) + return !tg_game_over(obj); +} + +void tg_init(tetris_game *obj, int rows, int cols) +{ + // Initialization logic + obj->rows = rows; + obj->cols = cols; + obj->board = (char *)malloc(rows * cols); + memset(obj->board, TC_EMPTY, rows * cols); + obj->points = 0; + obj->level = 0; + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + obj->lines_remaining = LINES_PER_LEVEL; + //srand(time(NULL)); + tg_new_falling(obj); + tg_new_falling(obj); + obj->stored.typ = -1; + obj->stored.ori = 0; + obj->stored.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; + printf("%d", obj->falling.loc.col); +} + +tetris_game *tg_create(int rows, int cols) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + tg_init(obj, rows, cols); + return obj; +} + +void tg_destroy(tetris_game *obj) +{ + // Cleanup logic + free(obj->board); +} + +void tg_delete(tetris_game *obj) { + tg_destroy(obj); + free(obj); +} + +/* + Load a game from a file. + */ +tetris_game *tg_load(FILE *f) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) + { + fprintf(stderr,"read game error\n"); + free(obj); + obj = 0; + } + else + { + obj->board = (char *)malloc(obj->rows * obj->cols); + if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + { + fprintf(stderr,"fread error\n"); + free(obj->board); + free(obj); + obj = 0; + } + } + return obj; +} + +/* + Save a game to a file. + */ +void tg_save(tetris_game *obj, FILE *f) +{ + if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) + fprintf(stderr,"error writing tetrisgame\n"); + else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + fprintf(stderr,"error writing board\n"); +} + +/* + Print a game board to a file. Really just for early debugging. + */ +void tg_print(tetris_game *obj, FILE *f) { + int i, j; + for (i = 0; i < obj->rows; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) { + fputs(TC_EMPTY_STR, f); + } else { + fputs(TC_BLOCK_STR, f); + } + } + fputc('\n', f); + } +} + +/* + 2 columns per cell makes the game much nicer. + */ +#define COLS_PER_CELL 2 +/* + Macro to print a cell of a specific type to a window. + */ +#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ +waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) +#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') + +/* + Print the tetris board onto the ncurses window. + */ +void display_board(WINDOW *w, tetris_game *obj) +{ + int i, j; + box(w, 0, 0); + for (i = 0; i < obj->rows; i++) { + wmove(w, 1 + i, 1); + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + ADD_BLOCK(w,tg_get(obj, i, j)); + } else { + ADD_EMPTY(w); + } + } + } + wnoutrefresh(w); +} + +/* + Display a tetris piece in a dedicated window. + */ +void display_piece(WINDOW *w, tetris_block block) +{ + int b; + tetris_location c; + wclear(w); + box(w, 0, 0); + if (block.typ == -1) { + wnoutrefresh(w); + return; + } + for (b = 0; b < TETRIS; b++) { + c = TETROMINOS[block.typ][block.ori][b]; + wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); + ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); + } + wnoutrefresh(w); +} + +/* + Display score information in a dedicated window. + */ +void display_score(WINDOW *w, tetris_game *tg) +{ + wclear(w); + box(w, 0, 0); + wprintw(w, (char *)"Score\n%d\n", tg->points); + wprintw(w, (char *)"Level\n%d\n", tg->level); + wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); + wnoutrefresh(w); +} + +/* + Save and exit the game. + */ +void save(tetris_game *game, WINDOW *w) +{ + FILE *f; + + wclear(w); + box(w, 0, 0); // return the border + wmove(w, 1, 1); + wprintw(w, (char *)"Save and exit? [Y/n] "); + wrefresh(w); + timeout(-1); + if (getch() == 'n') { + timeout(0); + return; + } + f = fopen("tetris.save", "w"); + tg_save(game, f); + fclose(f); + tg_delete(game); + endwin(); + fprintf(stderr,"Game saved to \"tetris.save\".\n"); + fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); + exit(EXIT_SUCCESS); +} + +/* + Do the NCURSES initialization steps for color blocks. + */ +void init_colors(void) +{ + start_color(); + //init_color(COLOR_ORANGE, 1000, 647, 0); + init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); + init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); + init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); + init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); + init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); + init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); + init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); +} + +/* + Main tetris game! + */ +#ifdef STANDALONE +char *clonestr(char *str) +{ + char *clone; int32_t len; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + len = strlen(str); + clone = (char *)calloc(1,len+16); + strcpy(clone,str); + return(clone); +} + +int tetris(int argc, char **argv) +{ + tetris_game *tg; + tetris_move move = TM_NONE; + bool running = true; + WINDOW *board, *next, *hold, *score; + int32_t c,skipcount=0; bits256 gametxid; uint32_t eventid = 0; + memset(&gametxid,0,sizeof(gametxid)); + // Load file if given a filename. + if (argc >= 2) { + FILE *f = fopen(argv[1], "r"); + if (f == NULL) { + perror("tetris"); + exit(EXIT_FAILURE); + } + tg = tg_load(f); + fclose(f); + } else { + // Otherwise create new game. + tg = tg_create(22, 10); + } + // NCURSES initialization: + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + keypad(stdscr, TRUE); // allow arrow keys + timeout(0); // no blocking on getch() + curs_set(0); // set the cursor to invisible + init_colors(); // setup tetris colors + + // Create windows for each section of the interface. + board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); + next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); + hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); + score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); + int32_t counter = 0; + // Game loop + while (running) { + running = tg_tick(tg, move); + display_board(board, tg); + display_piece(next, tg->next); + display_piece(hold, tg->stored); + display_score(score, tg); + if ( (counter++ % 5) == 0 ) + doupdate(); + sleep_milli(10); + c = getch(); + if ( c != -1 || skipcount == 0x3fff ) + { + if ( skipcount > 0 ) + issue_games_events(gametxid,eventid-skipcount,skipcount | 0x4000); + if ( c != -1 ) + issue_games_events(gametxid,eventid,c); + skipcount = 0; + } else skipcount++; + eventid++; + switch ( c ) + { + case KEY_LEFT: + move = TM_LEFT; + break; + case KEY_RIGHT: + move = TM_RIGHT; + break; + case KEY_UP: + move = TM_CLOCK; + break; + case KEY_DOWN: + move = TM_DROP; + break; + case 'q': + running = false; + move = TM_NONE; + break; + case 'p': + wclear(board); + box(board, 0, 0); + wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); + wprintw(board, "PAUSED"); + wrefresh(board); + timeout(-1); + getch(); + timeout(0); + move = TM_NONE; + break; + case 's': + save(tg, board); + move = TM_NONE; + break; + case ' ': + move = TM_HOLD; + break; + default: + move = TM_NONE; + } + } + + // Deinitialize NCurses + wclear(stdscr); + endwin(); + // Output ending message. + printf("Game over!\n"); + printf("You finished with %d points on level %d.\n", tg->points, tg->level); + + // Deinitialize Tetris + tg_delete(tg); + return 0; +} + +int32_t games_replay(uint64_t seed,int32_t sleeptime) +{ + return(-1); +} diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index d6ae473fe..fd833d7b7 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -1,939 +1,4 @@ -/***************************************************************************/ -/** https://github.com/brenns10/tetris - @file main.c - @author Stephen Brennan - @date Created Wednesday, 10 June 2015 - @brief Main program for tetris. - @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised - BSD License. See LICENSE.txt for details. - *******************************************************************************/ - - -#ifndef TETRIS_H -#define TETRIS_H - -#include // for FILE -#include // for bool -#include -#include -#include -#include -#include - -#include -#include - -//#include -//#include - - -/* - Convert a tetromino type to its corresponding cell. - */ -#define TYPE_TO_CELL(x) ((x)+1) - -/* - Strings for how you would print a tetris board. - */ -#define TC_EMPTY_STR " " -#define TC_BLOCK_STR "\u2588" - -/* - Questions about a tetris cell. - */ -#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) -#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) - -/* - How many cells in a tetromino? - */ -#define TETRIS 4 -/* - How many tetrominos? - */ -#define NUM_TETROMINOS 7 -/* - How many orientations of a tetromino? - */ -#define NUM_ORIENTATIONS 4 - -/* - Level constants. - */ -#define MAX_LEVEL 19 -#define LINES_PER_LEVEL 10 - -/* - A "cell" is a 1x1 block within a tetris board. - */ -typedef enum { - TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ -} tetris_cell; - -/* - A "type" is a type/shape of a tetromino. Not including orientation. - */ -typedef enum { - TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z -} tetris_type; - -/* - A row,column pair. Negative numbers allowed, because we need them for - offsets. - */ -typedef struct { - int row; - int col; -} tetris_location; - -/* - A "block" is a struct that contains information about a tetromino. - Specifically, what type it is, what orientation it has, and where it is. - */ -typedef struct { - int typ; - int ori; - tetris_location loc; -} tetris_block; - -/* - All possible moves to give as input to the game. - */ -typedef enum { - TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE -} tetris_move; - -/* - A game object! - */ -typedef struct { - /* - Game board stuff: - */ - int rows; - int cols; - char *board; - /* - Scoring information: - */ - int points; - int level; - /* - Falling block is the one currently going down. Next block is the one that - will be falling after this one. Stored is the block that you can swap out. - */ - tetris_block falling; - tetris_block next; - tetris_block stored; - /* - Number of game ticks until the block will move down. - */ - int ticks_till_gravity; - /* - Number of lines until you advance to the next level. - */ - int lines_remaining; -} tetris_game; - -/* - This array stores all necessary information about the cells that are filled by - each tetromino. The first index is the type of the tetromino (i.e. shape, - e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final - array contains 4 tetris_location objects, each mapping to an offset from a - point on the upper left that is the tetromino "origin". - */ -extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; - -/* - This array tells you how many ticks per gravity by level. Decreases as level - increases, to add difficulty. - */ -extern int GRAVITY_LEVEL[MAX_LEVEL+1]; - -// Data structure manipulation. -void tg_init(tetris_game *obj, int rows, int cols); -tetris_game *tg_create(int rows, int cols); -void tg_destroy(tetris_game *obj); -void tg_delete(tetris_game *obj); -tetris_game *tg_load(FILE *f); -void tg_save(tetris_game *obj, FILE *f); - -// Public methods not related to memory: -char tg_get(tetris_game *obj, int row, int col); -bool tg_check(tetris_game *obj, int row, int col); -bool tg_tick(tetris_game *obj, tetris_move move); -void tg_print(tetris_game *obj, FILE *f); - -#endif // TETRIS_H - - -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -/******************************************************************************* - Array Definitions - *******************************************************************************/ - -tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = { - // I - {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, - // J - {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, - {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, - // L - {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, - {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, - // O - {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, - // S - {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, - {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, - {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, - // T - {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, - // Z - {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, - {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, -}; - -int GRAVITY_LEVEL[MAX_LEVEL+1] = { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, - //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 -}; - -/******************************************************************************* - Helper Functions for Blocks - *******************************************************************************/ - -void sleep_milli(int milliseconds) -{ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = milliseconds * 1000 * 1000; - nanosleep(&ts, NULL); -} - -/* - Return the block at the given row and column. - */ -char tg_get(tetris_game *obj, int row, int column) -{ - return obj->board[obj->cols * row + column]; -} - -/* - Set the block at the given row and column. - */ -static void tg_set(tetris_game *obj, int row, int column, char value) -{ - obj->board[obj->cols * row + column] = value; -} - -/* - Check whether a row and column are in bounds. - */ -bool tg_check(tetris_game *obj, int row, int col) -{ - return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; -} - -/* - Place a block onto the board. - */ -static void tg_put(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, - TYPE_TO_CELL(block.typ)); - } -} - -/* - Clear a block out of the board. - */ -static void tg_remove(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); - } -} - -/* - Check if a block can be placed on the board. - */ -static bool tg_fits(tetris_game *obj, tetris_block block) -{ - int i, r, c; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - r = block.loc.row + cell.row; - c = block.loc.col + cell.col; - if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { - return false; - } - } - return true; -} - -/* - Return a random tetromino type. - */ -static int random_tetromino(void) { - return rand() % NUM_TETROMINOS; -} - -/* - Create a new falling block and populate the next falling block with a random - one. - */ -static void tg_new_falling(tetris_game *obj) -{ - // Put in a new falling tetromino. - obj->falling = obj->next; - obj->next.typ = random_tetromino(); - obj->next.ori = 0; - obj->next.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; -} - -/******************************************************************************* - Game Turn Helpers - *******************************************************************************/ - -/* - Tick gravity, and move the block down if gravity should act. - */ -static void tg_do_gravity_tick(tetris_game *obj) -{ - obj->ticks_till_gravity--; - if (obj->ticks_till_gravity <= 0) { - tg_remove(obj, obj->falling); - obj->falling.loc.row++; - if (tg_fits(obj, obj->falling)) { - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - } else { - obj->falling.loc.row--; - tg_put(obj, obj->falling); - - tg_new_falling(obj); - } - tg_put(obj, obj->falling); - } -} - -/* - Move the falling tetris block left (-1) or right (+1). - */ -static void tg_move(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - obj->falling.loc.col += direction; - if (!tg_fits(obj, obj->falling)) { - obj->falling.loc.col -= direction; - } - tg_put(obj, obj->falling); -} - -/* - Send the falling tetris block to the bottom. - */ -static void tg_down(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - while (tg_fits(obj, obj->falling)) { - obj->falling.loc.row++; - } - obj->falling.loc.row--; - tg_put(obj, obj->falling); - tg_new_falling(obj); -} - -/* - Rotate the falling block in either direction (+/-1). - */ -static void tg_rotate(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - - while (true) { - obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; - - // If the new orientation fits, we're done. - if (tg_fits(obj, obj->falling)) - break; - - // Otherwise, try moving left to make it fit. - obj->falling.loc.col--; - if (tg_fits(obj, obj->falling)) - break; - - // Finally, try moving right to make it fit. - obj->falling.loc.col += 2; - if (tg_fits(obj, obj->falling)) - break; - - // Put it back in its original location and try the next orientation. - obj->falling.loc.col--; - // Worst case, we come back to the original orientation and it fits, so this - // loop will terminate. - } - - tg_put(obj, obj->falling); -} - -/* - Swap the falling block with the block in the hold buffer. - */ -static void tg_hold(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - if (obj->stored.typ == -1) { - obj->stored = obj->falling; - tg_new_falling(obj); - } else { - int typ = obj->falling.typ, ori = obj->falling.ori; - obj->falling.typ = obj->stored.typ; - obj->falling.ori = obj->stored.ori; - obj->stored.typ = typ; - obj->stored.ori = ori; - while (!tg_fits(obj, obj->falling)) { - obj->falling.loc.row--; - } - } - tg_put(obj, obj->falling); -} - -/* - Perform the action specified by the move. - */ -static void tg_handle_move(tetris_game *obj, tetris_move move) -{ - switch (move) { - case TM_LEFT: - tg_move(obj, -1); - break; - case TM_RIGHT: - tg_move(obj, 1); - break; - case TM_DROP: - tg_down(obj); - break; - case TM_CLOCK: - tg_rotate(obj, 1); - break; - case TM_COUNTER: - tg_rotate(obj, -1); - break; - case TM_HOLD: - tg_hold(obj); - break; - default: - // pass - break; - } -} - -/* - Return true if line i is full. - */ -static bool tg_line_full(tetris_game *obj, int i) -{ - int j; - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) - return false; - } - return true; -} - -/* - Shift every row above r down one. - */ -static void tg_shift_lines(tetris_game *obj, int r) -{ - int i, j; - for (i = r-1; i >= 0; i--) { - for (j = 0; j < obj->cols; j++) { - tg_set(obj, i+1, j, tg_get(obj, i, j)); - tg_set(obj, i, j, TC_EMPTY); - } - } -} - -/* - Find rows that are filled, remove them, shift, and return the number of - cleared rows. - */ -static int tg_check_lines(tetris_game *obj) -{ - int i, nlines = 0; - tg_remove(obj, obj->falling); // don't want to mess up falling block - - for (i = obj->rows-1; i >= 0; i--) { - if (tg_line_full(obj, i)) { - tg_shift_lines(obj, i); - i++; // do this line over again since they're shifted - nlines++; - } - } - - tg_put(obj, obj->falling); // replace - return nlines; -} - -/* - Adjust the score for the game, given how many lines were just cleared. - */ -static void tg_adjust_score(tetris_game *obj, int lines_cleared) -{ - static int line_multiplier[] = {0, 40, 100, 300, 1200}; - obj->points += line_multiplier[lines_cleared] * (obj->level + 1); - if (lines_cleared >= obj->lines_remaining) { - obj->level = MIN(MAX_LEVEL, obj->level + 1); - lines_cleared -= obj->lines_remaining; - obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; - } else { - obj->lines_remaining -= lines_cleared; - } -} - -/* - Return true if the game is over. - */ -static bool tg_game_over(tetris_game *obj) -{ - int i, j; - bool over = false; - tg_remove(obj, obj->falling); - for (i = 0; i < 2; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - over = true; - } - } - } - tg_put(obj, obj->falling); - return over; -} - -/******************************************************************************* - Main Public Functions - *******************************************************************************/ - -/* - Do a single game tick: process gravity, user input, and score. Return true if - the game is still running, false if it is over. - */ -bool tg_tick(tetris_game *obj, tetris_move move) -{ - int lines_cleared; - // Handle gravity. - tg_do_gravity_tick(obj); - - // Handle input. - tg_handle_move(obj, move); - - // Check for cleared lines - lines_cleared = tg_check_lines(obj); - - tg_adjust_score(obj, lines_cleared); - - // Return whether the game will continue (NOT whether it's over) - return !tg_game_over(obj); -} - -void tg_init(tetris_game *obj, int rows, int cols) -{ - // Initialization logic - obj->rows = rows; - obj->cols = cols; - obj->board = (char *)malloc(rows * cols); - memset(obj->board, TC_EMPTY, rows * cols); - obj->points = 0; - obj->level = 0; - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - obj->lines_remaining = LINES_PER_LEVEL; - srand(time(NULL)); - tg_new_falling(obj); - tg_new_falling(obj); - obj->stored.typ = -1; - obj->stored.ori = 0; - obj->stored.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; - printf("%d", obj->falling.loc.col); -} - -tetris_game *tg_create(int rows, int cols) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - tg_init(obj, rows, cols); - return obj; -} - -void tg_destroy(tetris_game *obj) -{ - // Cleanup logic - free(obj->board); -} - -void tg_delete(tetris_game *obj) { - tg_destroy(obj); - free(obj); -} - -/* - Load a game from a file. - */ -tetris_game *tg_load(FILE *f) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) - { - fprintf(stderr,"read game error\n"); - free(obj); - obj = 0; - } - else - { - obj->board = (char *)malloc(obj->rows * obj->cols); - if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - { - fprintf(stderr,"fread error\n"); - free(obj->board); - free(obj); - obj = 0; - } - } - return obj; -} - -/* - Save a game to a file. - */ -void tg_save(tetris_game *obj, FILE *f) -{ - if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) - fprintf(stderr,"error writing tetrisgame\n"); - else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - fprintf(stderr,"error writing board\n"); -} - -/* - Print a game board to a file. Really just for early debugging. - */ -void tg_print(tetris_game *obj, FILE *f) { - int i, j; - for (i = 0; i < obj->rows; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) { - fputs(TC_EMPTY_STR, f); - } else { - fputs(TC_BLOCK_STR, f); - } - } - fputc('\n', f); - } -} - -/* - 2 columns per cell makes the game much nicer. - */ -#define COLS_PER_CELL 2 -/* - Macro to print a cell of a specific type to a window. - */ -#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ -waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) -#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') - -/* - Print the tetris board onto the ncurses window. - */ -void display_board(WINDOW *w, tetris_game *obj) -{ - int i, j; - box(w, 0, 0); - for (i = 0; i < obj->rows; i++) { - wmove(w, 1 + i, 1); - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - ADD_BLOCK(w,tg_get(obj, i, j)); - } else { - ADD_EMPTY(w); - } - } - } - wnoutrefresh(w); -} - -/* - Display a tetris piece in a dedicated window. - */ -void display_piece(WINDOW *w, tetris_block block) -{ - int b; - tetris_location c; - wclear(w); - box(w, 0, 0); - if (block.typ == -1) { - wnoutrefresh(w); - return; - } - for (b = 0; b < TETRIS; b++) { - c = TETROMINOS[block.typ][block.ori][b]; - wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); - ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); - } - wnoutrefresh(w); -} - -/* - Display score information in a dedicated window. - */ -void display_score(WINDOW *w, tetris_game *tg) -{ - wclear(w); - box(w, 0, 0); - wprintw(w, "Score\n%d\n", tg->points); - wprintw(w, "Level\n%d\n", tg->level); - wprintw(w, "Lines\n%d\n", tg->lines_remaining); - wnoutrefresh(w); -} - -/* - Boss mode! Make it look like you're doing work. - */ -void boss_mode(void) -{ - clear(); - //Mix_PauseMusic(); - printw("user@workstation-312:~/Documents/presentation $ ls -l\n" - "total 528\n" - "drwxr-xr-x 2 user users 4096 Jun 9 17:05 .\n" - "drwxr-xr-x 4 user users 4096 Jun 10 09:52 ..\n" - "-rw-r--r-- 1 user users 88583 Jun 9 14:13 figure1.png\n" - "-rw-r--r-- 1 user users 65357 Jun 9 15:40 figure2.png\n" - "-rw-r--r-- 1 user users 4469 Jun 9 16:17 presentation.aux\n" - "-rw-r--r-- 1 user users 42858 Jun 9 16:17 presentation.log\n" - "-rw-r--r-- 1 user users 2516 Jun 9 16:17 presentation.nav\n" - "-rw-r--r-- 1 user users 183 Jun 9 16:17 presentation.out\n" - "-rw-r--r-- 1 user users 349607 Jun 9 16:17 presentation.pdf\n" - "-rw-r--r-- 1 user users 0 Jun 9 16:17 presentation.snm\n" - "-rw-r--r-- 1 user users 9284 Jun 9 17:05 presentation.tex\n" - "-rw-r--r-- 1 user users 229 Jun 9 16:17 presentation.toc\n" - "\n" - "user@workstation-312:~/Documents/presentation $ "); - echo(); - timeout(-1); - while (getch() != KEY_F(1)); - timeout(0); - noecho(); - clear(); - //Mix_ResumeMusic(); -} - -/* - Save and exit the game. - */ -void save(tetris_game *game, WINDOW *w) -{ - FILE *f; - - wclear(w); - box(w, 0, 0); // return the border - wmove(w, 1, 1); - wprintw(w, "Save and exit? [Y/n] "); - wrefresh(w); - timeout(-1); - if (getch() == 'n') { - timeout(0); - return; - } - f = fopen("tetris.save", "w"); - tg_save(game, f); - fclose(f); - tg_delete(game); - endwin(); - printf("Game saved to \"tetris.save\".\n"); - printf("Resume by passing the filename as an argument to this program.\n"); - exit(EXIT_SUCCESS); -} - -/* - Do the NCURSES initialization steps for color blocks. - */ -void init_colors(void) -{ - start_color(); - //init_color(COLOR_ORANGE, 1000, 647, 0); - init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); - init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); - init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); - init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); - init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); - init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); - init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); -} - -/* - Main tetris game! - */ -#ifdef STANDALONE - -int main(int argc, char **argv) -{ - tetris_game *tg; - tetris_move move = TM_NONE; - bool running = true; - WINDOW *board, *next, *hold, *score; - //Mix_Music *music; - - // Load file if given a filename. - if (argc >= 2) { - FILE *f = fopen(argv[1], "r"); - if (f == NULL) { - perror("tetris"); - exit(EXIT_FAILURE); - } - tg = tg_load(f); - fclose(f); - } else { - // Otherwise create new game. - tg = tg_create(22, 10); - } - - /* Initialize music. - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - fprintf(stderr, "unable to initialize SDL\n"); - exit(EXIT_FAILURE); - } - if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { - fprintf(stderr, "unable to initialize SDL_mixer\n"); - exit(EXIT_FAILURE); - } - if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) != 0) { - fprintf(stderr, "unable to initialize audio\n"); - exit(EXIT_FAILURE); - } - Mix_AllocateChannels(1); // only need background music - music = Mix_LoadMUS("tetris.mp3"); - if (music) { - Mix_PlayMusic(music, -1); - }*/ - - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors - - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - int32_t counter = 0; - // Game loop - while (running) { - running = tg_tick(tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - - switch (getch()) { - case KEY_LEFT: - move = TM_LEFT; - break; - case KEY_RIGHT: - move = TM_RIGHT; - break; - case KEY_UP: - move = TM_CLOCK; - break; - case KEY_DOWN: - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 'b': - boss_mode(); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break; - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } - } - - // Deinitialize NCurses - wclear(stdscr); - endwin(); - - /* Deinitialize Sound - Mix_HaltMusic(); - Mix_FreeMusic(music); - Mix_CloseAudio(); - Mix_Quit();*/ - - // Output ending message. - printf("Game over!\n"); - printf("You finished with %d points on level %d.\n", tg->points, tg->level); - - // Deinitialize Tetris - tg_delete(tg); - return 0; -} -#else - /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -949,973 +14,55 @@ int main(int argc, char **argv) * * ******************************************************************************/ -#include "cJSON.h" -#include "CCinclude.h" +// game specific code for daemon -#define TETRIS_REGISTRATION 5 -#define TETRIS_REGISTRATIONSIZE (100 * 10000) -#define TETRIS_MAXPLAYERS 64 // need to send unused fees back to globalCC address to prevent leeching -#define TETRIS_MAXKEYSTROKESGAP 60 -#define TETRIS_MAXITERATIONS 777 - - -std::string Tetris_pname = ""; - -CScript tetris_newgameopret(int64_t buyin,int32_t maxplayers) +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { - CScript opret; uint8_t evalcode = EVAL_TETRIS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'G' << buyin << maxplayers); - return(opret); -} - -CScript tetris_registeropret(uint256 gametxid,uint256 playertxid) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; - //fprintf(stderr,"opret.(%s %s).R\n",gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << gametxid << playertxid); - return(opret); -} - -CScript tetris_keystrokesopret(uint256 gametxid,uint256 batontxid,CPubKey pk,std::vectorkeystrokes) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'K' << gametxid << batontxid << pk << keystrokes); - return(opret); -} - -CScript tetris_highlanderopret(uint8_t funcid,uint256 gametxid,int32_t regslot,CPubKey pk,std::vectorplayerdata,std::string pname) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; std::string symbol(ASSETCHAINS_SYMBOL); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << gametxid << symbol << pname << regslot << pk << playerdata ); - return(opret); -} - -uint8_t tetris_highlanderopretdecode(uint256 &gametxid, uint256 &tokenid, int32_t ®slot, CPubKey &pk, std::vector &playerdata, std::string &symbol, std::string &pname,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets, opretsDummy; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description, oprets)) == 'c' ) + uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; + if ( (len= payload.size()) > 36 ) { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, opretsDummy)) != 0 ) - { - //fprintf(stderr,"decode opret %c tokenid.%s\n",script[1],tokenid.GetHex().c_str()); - GetNonfungibleData(tokenid, vopretNonfungible); //load nonfungible data from the 'tokenbase' tx - vopret = vopretNonfungible; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> gametxid; ss >> symbol; ss >> pname; ss >> regslot; ss >> pk; ss >> playerdata) != 0 && e == EVAL_TETRIS && (f == 'H' || f == 'Q') ) - { - return(f); - } - fprintf(stderr,"SKIP obsolete: e.%d f.%c game.%s regslot.%d psize.%d\n",e,f,gametxid.GetHex().c_str(),regslot,(int32_t)playerdata.size()); - return(0); -} - -uint8_t tetris_keystrokesopretdecode(uint256 &gametxid,uint256 &batontxid,CPubKey &pk,std::vector &keystrokes,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> batontxid; ss >> pk; ss >> keystrokes) != 0 && e == EVAL_TETRIS && f == 'K' ) - { - return(f); - } - return(0); -} - -uint8_t tetris_registeropretdecode(uint256 &gametxid,uint256 &tokenid,uint256 &playertxid,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,oprets)) == 'c' ) - { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, oprets)) != 0 ) - { - GetOpretBlob(oprets, OPRETID_TETRISGAMEDATA, vopretDummy); // blob from non-creation tx opret - vopret = vopretDummy; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> playertxid) != 0 && e == EVAL_TETRIS && f == 'R' ) - { - return(f); - } - //fprintf(stderr,"e.%d f.%c game.%s playertxid.%s\n",e,f,gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - return(0); -} - -uint8_t tetris_newgameopreturndecode(int64_t &buyin,int32_t &maxplayers,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> buyin; ss >> maxplayers) != 0 && e == EVAL_TETRIS && f == 'G' ) - { - return(f); - } - return(0); -} - -void tetris_univalue(UniValue &result,const char *method,int64_t maxplayers,int64_t buyin) -{ - if ( method != 0 ) - { - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method",method)); - } - if ( maxplayers > 0 ) - result.push_back(Pair("maxplayers",maxplayers)); - if ( buyin >= 0 ) - { - result.push_back(Pair("buyin",ValueFromAmount(buyin))); - if ( buyin == 0 ) - result.push_back(Pair("type","newbie")); - else result.push_back(Pair("type","buyin")); - } -} - -int32_t tetris_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx,char *mytetrisaddr) -{ - int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; char destaddr[64]; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(mytetrisaddr,destaddr) == 0 ) - return(1); - //else fprintf(stderr,"myaddr.%s vs %s\n",mytetrisaddr,destaddr); - } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"vout %d is unspent\n",vout); - } - return(0); -} - -int32_t tetris_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) -{ - uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey tetrispk; uint64_t txfee = 10000; - buyin = maxplayers = 0; - if ( (txid == zeroid || myGetTransaction(txid,tx,hashBlock) != 0) && (numvouts= tx.vout.size()) > 1 ) - { - if ( txid != zeroid ) - gameheight = komodo_blockheight(hashBlock); - else - { - txid = tx.GetHash(); - //fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1)); - } - if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1,0) == txfee) ) - { - if ( tetris_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' ) - { - if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS || buyin < 0 ) - return(-6); - if ( numvouts > 2*maxplayers+1 ) - { - for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) +int64_t games_cashout(struct games_player *P) { - int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct tetris_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - datastr = (char *)malloc(playerdata.size()*2+1); - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - for (i=0; i TETRIS_MAXITERATIONS ) - break; - } - obj.push_back(Pair("gametxid",gametxid.GetHex())); - if ( txid != playertxid ) - obj.push_back(Pair("batontxid",txid.GetHex())); - obj.push_back(Pair("playertxid",playertxid.GetHex())); - if ( tokenid != zeroid ) - obj.push_back(Pair("tokenid",tokenid.GetHex())); - else obj.push_back(Pair("tokenid",playertxid.GetHex())); - if ( datastr != 0 ) - { - obj.push_back(Pair("data",datastr)); - free(datastr); - } - obj.push_back(Pair("pack",a)); - obj.push_back(Pair("packsize",(int64_t)P.packsize)); - obj.push_back(Pair("hitpoints",(int64_t)P.hitpoints)); - obj.push_back(Pair("strength",(int64_t)(P.strength&0xffff))); - obj.push_back(Pair("maxstrength",(int64_t)(P.strength>>16))); - obj.push_back(Pair("level",(int64_t)P.level)); - obj.push_back(Pair("experience",(int64_t)P.experience)); - obj.push_back(Pair("dungeonlevel",(int64_t)P.dungeonlevel)); - obj.push_back(Pair("chain",symbol)); - obj.push_back(Pair("pname",pname)); - return(obj); + int32_t dungeonlevel; int64_t mult=10,cashout = 0; + if ( P->amulet != 0 ) + mult *= 5; + dungeonlevel = P->dungeonlevel; + if ( P->amulet != 0 && dungeonlevel < 26 ) + dungeonlevel = 26; + cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; + return(cashout); } -int32_t tetris_iterateplayer(uint256 ®istertxid,uint256 firsttxid,int32_t firstvout,uint256 lasttxid) // retrace playertxid vins to reach highlander <- this verifies player is valid and tetris_playerdataspend makes sure it can only be used once -{ - uint256 spenttxid,txid = firsttxid; int32_t spentvini,n,vout = firstvout; - registertxid = zeroid; - if ( vout < 0 ) - return(-1); - n = 0; - while ( (spentvini= myIsutxo_spent(spenttxid,txid,vout)) == 0 ) - { - txid = spenttxid; - vout = spentvini; - if ( registertxid == zeroid ) - registertxid = txid; - if ( ++n >= TETRIS_MAXITERATIONS ) - { - fprintf(stderr,"tetris_iterateplayer n.%d, seems something is wrong\n",n); - return(-2); - } - } - if ( txid == lasttxid ) - return(0); - else - { - fprintf(stderr,"firsttxid.%s/v%d -> %s != last.%s\n",firsttxid.ToString().c_str(),firstvout,txid.ToString().c_str(),lasttxid.ToString().c_str()); - return(-1); - } -} - -/* - playertxid is whoever owns the nonfungible satoshi and it might have been bought and sold many times. - highlander is the game winning tx with the player data and is the only place where the unique player data exists - origplayergame is the gametxid that ends up being won by the highlander and they are linked directly as the highlander tx spends gametxid.vout0 - */ - -int32_t tetris_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint256 &tokenid,CPubKey &pk,std::vector &playerdata,std::string &symbol,std::string &pname,uint256 playertxid) -{ - uint256 origplayertxid,hashBlock,gametxid,registertxid; CTransaction gametx,playertx,highlandertx; std::vector vopret; uint8_t *script,e,f; int32_t i,regslot,gameheight,numvouts,maxplayers; int64_t buyin; - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 && (numvouts= playertx.vout.size()) > 0 ) - { - if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' ) - { - origplayergame = gametxid; - if ( tokenid != zeroid ) - { - playertxid = tokenid; - if ( myGetTransaction(playertxid,playertx,hashBlock) == 0 || (numvouts= playertx.vout.size()) <= 0 ) - { - fprintf(stderr,"couldnt get tokenid.%s\n",playertxid.GetHex().c_str()); - return(-2); - } - } - if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - //fprintf(stderr,"playertxid.%s got vin.%s/v%d gametxid.%s iterate.%d\n",playertxid.ToString().c_str(),playertx.vin[1].prevout.hash.ToString().c_str(),(int32_t)playertx.vin[1].prevout.n-maxplayers,gametxid.ToString().c_str(),tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid)); - if ( (tokenid != zeroid || playertx.vin[1].prevout.hash == gametxid) && tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid) == 0 ) - { - // if registertxid has vin from pk, it can be used - return(0); - } else fprintf(stderr,"hash mismatch or illegal gametxid\n"); - } else fprintf(stderr,"invalid game %s\n",gametxid.GetHex().c_str()); - } //else fprintf(stderr,"invalid player funcid.%c\n",f); - } else fprintf(stderr,"couldnt get playertxid.%s\n",playertxid.GetHex().c_str()); - return(-1); -} - -int32_t tetris_playerdataspend(CMutableTransaction &mtx,uint256 playertxid,int32_t vout,uint256 origplayergame) -{ - int64_t txfee = 10000; CTransaction tx; uint256 hashBlock; - if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation - { - mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); - return(0); - } - else - { - vout = 0; - if ( myGetTransaction(playertxid,tx,hashBlock) != 0 && tx.vout[vout].nValue == 1 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation - { - mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); - return(0); - } - } - return(-1); - } -} - -int32_t tetris_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) -{ - int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; - batonvalue = numkeys = numplayers = batonht = 0; - playertxid = batontxid = zeroid; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - numplayers++; - Getscriptaddress(ccaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(destaddr,ccaddr) == 0 ) - { - matches++; - regslot = i; - matchtx = spenttx; - } //else fprintf(stderr,"%d+1 doesnt match %s vs %s\n",i,ccaddr,destaddr); - } //else fprintf(stderr,"%d+1 couldnt find spenttx.%s\n",i,spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"%d+1 unspent\n",i); - } - if ( matches == 1 ) - { - numvouts = matchtx.vout.size(); - //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); - if ( tetris_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) - { - //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - if ( tokenid != zeroid ) - active = tokenid; - else active = playertxid; - if ( active == zeroid || tetris_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) - { - txid = matchtx.GetHash(); - //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); - n = 0; - while ( CCgettxout(txid,0,1,0) < 0 ) - { - spenttxid = zeroid; - spentvini = -1; - if ( (spentvini= myIsutxo_spent(spenttxid,txid,0)) >= 0 ) - txid = spenttxid; - else - { - if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - return(-2); - } - } - txid = spenttxid; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) // game is over? - { - return(0); - } - if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) - { - uint256 g,b; CPubKey p; std::vector k; - if ( tetris_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) - { - keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); - for (i=0; i= TETRIS_MAXITERATIONS ) - { - fprintf(stderr,"tetris_findbaton n.%d, seems something is wrong\n",n); - return(-5); - } - } - //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); - batontxid = txid; - batonvout = 0; // not vini - // how to detect timeout, bailedout, highlander - hashBlock = zeroid; - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) - { - if ( hashBlock == zeroid ) - batonht = komodo_nextheight(); - else if ( (pindex= komodo_blockindex(hashBlock)) == 0 ) - return(-4); - else batonht = pindex->GetHeight(); - batonvalue = batontx.vout[0].nValue; - //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); - return(0); - } else fprintf(stderr,"couldnt find baton\n"); - } else fprintf(stderr,"error with playerdata\n"); - } else fprintf(stderr,"findbaton opret error\n"); - } - return(-1); -} - -int32_t tetris_playersalive(int32_t &openslots,int32_t &numplayers,uint256 gametxid,int32_t maxplayers,int32_t gameht,CTransaction gametx) -{ - int32_t i,n,vout,spentvini,registration_open = 0,alive = 0; CTransaction tx; uint256 txid,spenttxid,hashBlock; CBlockIndex *pindex; uint64_t txfee = 10000; - numplayers = openslots = 0; - if ( komodo_nextheight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) - registration_open = 1; - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) - break; - if ( n++ > TETRIS_MAXITERATIONS ) - break; - } - if ( txid != zeroid ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 ) - { - if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) - { - if ( pindex->GetHeight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) - alive++; - } - } - } - } - } - else if ( registration_open != 0 ) - openslots++; - } - //fprintf(stderr,"numalive.%d openslots.%d\n",alive,openslots); - return(alive); -} - -uint64_t tetris_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mytetrisaddr) -{ - CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; - if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 ) - { - ht = pindex->GetHeight(); - delay = TETRIS_REGISTRATION * (maxplayers > 1); - obj.push_back(Pair("height",ht)); - obj.push_back(Pair("start",ht+delay)); - if ( komodo_nextheight() > ht+delay ) - { - if ( (pindex= komodo_chainactive(ht+delay)) != 0 ) - { - hashBlock = pindex->GetBlockHash(); - obj.push_back(Pair("starthash",hashBlock.ToString())); - memcpy(&seed,&hashBlock,sizeof(seed)); - seed &= (1LL << 62) - 1; - obj.push_back(Pair("seed",(int64_t)seed)); - if ( tetris_iamregistered(maxplayers,gametxid,tx,mytetrisaddr) > 0 ) - sprintf(cmd,"cc/tetris %llu %s",(long long)seed,gametxid.ToString().c_str()); - else sprintf(cmd,"./komodo-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",ASSETCHAINS_SYMBOL,EVAL_TETRIS,gametxid.ToString().c_str()); - obj.push_back(Pair("run",cmd)); - } - } - obj.push_back(Pair("alive",tetris_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); - obj.push_back(Pair("openslots",openslots)); - obj.push_back(Pair("numplayers",numplayers)); - } - obj.push_back(Pair("maxplayers",maxplayers)); - obj.push_back(Pair("buyin",ValueFromAmount(buyin))); - return(seed); -} - -void tetris_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gametxid,CTransaction gametx,int32_t vout,int32_t maxplayers,char *mytetrisaddr) -{ - // identify if bailout or quit or timed out - uint256 batontxid,spenttxid,gtxid,ptxid,tokenid,hashBlock,playertxid; CTransaction spenttx,batontx; int32_t numplayers,regslot,numkeys,batonvout,batonht,retval; int64_t batonvalue; std::vector playerdata; char destaddr[64]; std::string symbol,pname; - destaddr[0] = 0; - if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - } - obj.push_back(Pair("slot",(int64_t)vout-1)); - if ( (retval= tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,destaddr,numplayers,symbol,pname)) == 0 ) - { - if ( CCgettxout(gametxid,maxplayers+vout,1,0) == 10000 ) - { - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 ) - { - if ( tetris_registeropretdecode(gtxid,tokenid,ptxid,batontx.vout[batontx.vout.size()-1].scriptPubKey) == 'R' && ptxid == playertxid && gtxid == gametxid ) - obj.push_back(Pair("status","registered")); - else obj.push_back(Pair("status","alive")); - } else obj.push_back(Pair("status","error")); - } else obj.push_back(Pair("status","finished")); - obj.push_back(Pair("baton",batontxid.ToString())); - obj.push_back(Pair("tokenid",tokenid.ToString())); - obj.push_back(Pair("batonaddr",destaddr)); - obj.push_back(Pair("ismine",strcmp(mytetrisaddr,destaddr)==0)); - obj.push_back(Pair("batonvout",(int64_t)batonvout)); - obj.push_back(Pair("batonvalue",ValueFromAmount(batonvalue))); - obj.push_back(Pair("batonht",(int64_t)batonht)); - if ( playerdata.size() > 0 ) - obj.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,gametxid))); - } else fprintf(stderr,"findbaton err.%d\n",retval); -} - -int64_t tetris_registrationbaton(CMutableTransaction &mtx,uint256 gametxid,CTransaction gametx,int32_t maxplayers) -{ - int32_t vout,j,r; int64_t nValue; - if ( gametx.vout.size() > maxplayers+1 ) - { - r = rand() % maxplayers; - for (j=0; j 0 ) - { - result.push_back(Pair("hex",rawtx)); - if ( DecodeHexTx(tx,rawtx) != 0 ) - { - if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) - RelayTransaction(tx); - result.push_back(Pair("txid",tx.GetHash().ToString())); - result.push_back(Pair("result","success")); - } else result.push_back(Pair("error","decode hex")); - } else result.push_back(Pair("error","couldnt finalize CCtx")); - return(result); -} - -UniValue tetris_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey tetrispk,mypk; char *jsonstr; uint64_t inputsum,change,required,buyin=0; int32_t i,n,maxplayers = 1; - if ( txfee == 0 ) - txfee = 10000; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - maxplayers = juint(jitem(params,0),0); - if ( n > 1 ) - buyin = jdouble(jitem(params,1),0) * COIN + 0.0000000049; - } - } - if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS ) - return(cclib_error(result,"illegal maxplayers")); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - tetris_univalue(result,"newgame",maxplayers,buyin); - required = (3*txfee + maxplayers*(TETRIS_REGISTRATIONSIZE+txfee)); - if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,required,16,cp->unspendableCCaddr)) >= required ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,tetrispk)); // for highlander TCBOO creation - for (i=0; ievalcode,TETRIS_REGISTRATIONSIZE,tetrispk,tetrispk)); - for (i=0; ievalcode,txfee,tetrispk,tetrispk)); - if ( (change= inputsum - required) >= txfee ) - mtx.vout.push_back(MakeCC1vout(cp->evalcode,change,tetrispk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_newgameopret(buyin,maxplayers)); - return(tetris_rawtxresult(result,rawtx,1)); - } - else return(cclib_error(result,"illegal maxplayers")); - return(result); -} - -UniValue tetris_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); std::vector playerdata; uint256 playertxid,tokenid,origplayergame;int32_t n; CPubKey pk; bits256 t; std::string symbol,pname; - result.push_back(Pair("result","success")); - tetris_univalue(result,"playerinfo",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - playertxid = juint256(jitem(params,0)); - if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"invalid playerdata")); - result.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,origplayergame))); - } else return(cclib_error(result,"no playertxid")); - return(result); - } else return(cclib_error(result,"couldnt reparse params")); -} - -UniValue tetris_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - // vin0 -> TETRIS_REGISTRATIONSIZE 1of2 registration baton from creategame - // vin1 -> optional nonfungible character vout @ - // vin2 -> original creation TCBOO playerdata used - // vin3+ -> buyin - // vout0 -> keystrokes/completion baton - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); char destaddr[64],coinaddr[64]; uint256 tokenid,gametxid,origplayergame,playertxid,hashBlock; int32_t err,maxplayers,gameheight,n,numvouts,vout=1; int64_t inputsum,buyin,CCchange=0; CPubKey pk,mypk,tetrispk,burnpk; CTransaction tx,playertx; std::vector playerdata; std::string rawtx,symbol,pname; bits256 t; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - burnpk = pubkey2pk(ParseHex(CC_BURNPUBKEY)); - tetrispk = GetUnspendable(cp,0); - tetris_univalue(result,"register",-1,-1); - playertxid = tokenid = zeroid; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - if ( (err= tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( n > 1 ) - { - playertxid = juint256(jitem(params,1)); - if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"couldnt extract valid playerdata")); - if ( tokenid != zeroid ) // if it is tokentransfer this will be 0 - vout = 1; - } - if ( komodo_nextheight() > gameheight + TETRIS_MAXKEYSTROKESGAP ) - return(cclib_error(result,"didnt register in time, TETRIS_MAXKEYSTROKESGAP")); - tetris_univalue(result,0,maxplayers,buyin); - GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); - if ( tetris_iamregistered(maxplayers,gametxid,tx,coinaddr) > 0 ) - return(cclib_error(result,"already registered")); - if ( (inputsum= tetris_registrationbaton(mtx,gametxid,tx,maxplayers)) != TETRIS_REGISTRATIONSIZE ) - return(cclib_error(result,"couldnt find available registration baton")); - else if ( playertxid != zeroid && tetris_playerdataspend(mtx,playertxid,vout,origplayergame) < 0 ) - return(cclib_error(result,"couldnt find playerdata to spend")); - else if ( buyin > 0 && AddNormalinputs(mtx,mypk,buyin,64) < buyin ) - return(cclib_error(result,"couldnt find enough normal funds for buyin")); - if ( tokenid != zeroid ) - { - mtx.vin.push_back(CTxIn(tokenid,0)); // spending cc marker as token is burned - char unspendableTokenAddr[64]; uint8_t tokenpriv[32]; struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - CPubKey unspPk = GetUnspendable(cpTokens, tokenpriv); - GetCCaddress(cpTokens, unspendableTokenAddr, unspPk); - CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); - } - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,buyin + inputsum - txfee,tetrispk,mypk)); - GetCCaddress1of2(cp,destaddr,tetrispk,tetrispk); - CCaddr1of2set(cp,tetrispk,tetrispk,cp->CCpriv,destaddr); - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode, 1, burnpk)); - - uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; - CScript opretRegister = tetris_registeropret(gametxid, playertxid); - if ( playertxid != zeroid ) - { - voutPubkeysEmpty.push_back(burnpk); - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 ) - { - std::vector> oprets; - if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, oprets)) != 0) - { // if token in the opret - didtx = 1; - if ( funcid == 'c' ) - tid = tokenid == zeroid ? playertxid : tokenid; - vscript_t vopretRegister; - GetOpReturnData(opretRegister, vopretRegister); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, - EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, std::make_pair(OPRETID_TETRISGAMEDATA, vopretRegister))); - } - } - } - if ( didtx == 0 ) - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, opretRegister); - - return(tetris_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"no gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -UniValue tetris_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - // vin0 -> baton from registration or previous keystrokes - // vout0 -> new baton - // opret -> user input chars - // being killed should auto broadcast (possible to be suppressed?) - // respawn to be prevented by including timestamps - int32_t nextheight = komodo_nextheight(); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); - UniValue result(UniValue::VOBJ); CPubKey tetrispk,mypk; uint256 gametxid,playertxid,batontxid; int64_t batonvalue,buyin; std::vector keystrokes,playerdata; int32_t numplayers,regslot,numkeys,batonht,batonvout,n,elapsed,gameheight,maxplayers; CTransaction tx; CTxOut txout; char *keystrokestr,destaddr[64]; std::string rawtx,symbol,pname; bits256 t; uint8_t mypriv[32]; - if ( txfee == 0 ) - txfee = 10000; - tetris_univalue(result,"keystrokes",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - result.push_back(Pair("keystrokes",keystrokestr)); - keystrokes = ParseHex(keystrokestr); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,destaddr,tetrispk,mypk); - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1) == 0 ) - { - if ( tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,tx,maxplayers,destaddr,numplayers,symbol,pname) == 0 ) - { - result.push_back(Pair("batontxid",batontxid.GetHex())); - result.push_back(Pair("playertxid",playertxid.GetHex())); - if ( maxplayers == 1 || nextheight <= batonht+TETRIS_MAXKEYSTROKESGAP ) - { - mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); //this validates user if pk - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,batonvalue-txfee,tetrispk,mypk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,tetrispk,mypk,mypriv,destaddr); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_keystrokesopret(gametxid,batontxid,mypk,keystrokes)); - //fprintf(stderr,"KEYSTROKES.(%s)\n",rawtx.c_str()); - return(tetris_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"keystrokes tx was too late")); - } else return(cclib_error(result,"couldnt find batontxid")); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -char *tetris_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *tetrisaddr) -{ - CPubKey tetrispk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct tetris_player P,endP; - tetrispk = GetUnspendable(cp,0); - *numkeysp = 0; - seed = 0; - num = numkeys = 0; - playertxid = zeroid; - str[0] = 0; - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) - { - if ( (retval= tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,tetrisaddr,numplayers,symbol,pname)) == 0 ) - { - UniValue obj; - seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,tetrisaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i no playerdata\n"); - newdata.resize(0); - *numkeysp = numkeys; - return(keystrokes); - /* P.gold = (P.gold * 8) / 10; - if ( keystrokes != 0 ) - { - free(keystrokes); - keystrokes = 0; - *numkeysp = 0; - return(keystrokes); - }*/ - } - else - { - sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - //fprintf(stderr,"%s\n",str); - *numkeysp = numkeys; - return(keystrokes); - } - } else num = 0; - } - else - { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); - if ( keystrokes != 0 ) - free(keystrokes), keystrokes = 0; - } - } else fprintf(stderr,"extractgame: invalid game\n"); - //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); - return(0); -} - -UniValue tetris_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); CPubKey pk,tetrispk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],tetrisaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; - pk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method","extract")); - tetrisaddr[0] = 0; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( n == 2 ) - { - if ( (pubstr= jstr(jitem(params,1),0)) != 0 ) - { - if (strlen(pubstr) == 66 ) - { - decode_hex(pub33,33,pubstr); - pk = buf2pk(pub33); - } - else if ( strlen(pubstr) < 36 ) - strcpy(tetrisaddr,pubstr); - } - //fprintf(stderr,"gametxid.%s %s\n",gametxid.GetHex().c_str(),pubstr); - } - if ( tetrisaddr[0] == 0 ) - GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); - result.push_back(Pair("tetrisaddr",tetrisaddr)); - str[0] = 0; - if ( (keystrokes= tetris_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) - { - result.push_back(Pair("status","success")); - flag = 1; - hexstr = (char *)malloc(numkeys*2 + 1); - for (i=0; i playerdata,uint256 gametxid,CPubKey pk) +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,tetrisaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed,mult = 10; CPubKey tetrispk; struct tetris_player P; + char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; *cashoutp = 0; - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); - //fprintf(stderr,"call extractgame\n"); - if ( (keystrokes= tetris_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) + gamespk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,gamesaddr,gamespk,pk); + if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) { - //fprintf(stderr,"numkeys.%d tetris_extractgame %s\n",numkeys,gametxid.GetHex().c_str()); free(keystrokes); - sprintf(fname,"tetris.%llu.pack",(long long)seed); + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); remove(fname); - - //fprintf(stderr,"extracted.(%s)\n",str); - for (i=0; i>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,tetrisaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); } } - sprintf(fname,"tetris.%llu.pack",(long long)seed); + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); remove(fname); - //fprintf(stderr,"no keys tetris_extractgame %s\n",gametxid.GetHex().c_str()); + //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); return(-1); } -UniValue tetris_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) +int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon { - //vin0 -> highlander vout from creategame TCBOO - //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit - //vins2+ -> rest of unspent registration utxo so all newgame vouts are spent - //vout0 -> nonfungible character with pack @ - //vout1 -> 1% ingame gold and all the buyins - - // detect if last to bailout - // vin0 -> kestrokes baton of completed game with Q - // vout0 -> playerdata marker - // vout0 -> 1% ingame gold - // get any playerdata, get all keystrokes, replay game and compare final state - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mytetrisaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,tetrispk; uint8_t player[10000],mypriv[32],funcid; - struct CCcontract_info *cpTokens, tokensC; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method",method)); - result.push_back(Pair("mytetrisaddr",mytetrisaddr)); - if ( strcmp(method,"bailout") == 0 ) - { - funcid = 'Q'; - mult = 10; //100000; - } - else - { - funcid = 'H'; - mult = 20; //200000; - } - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,mytetrisaddr,numplayers,symbol,pname) == 0 ) - { - UniValue obj; struct tetris_player P; - seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,mytetrisaddr); - fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i 0 ) - { - newdata.resize(num); - for (i=0; i no playerdata\n"); - newdata.resize(0); - //P.gold = (P.gold * 8) / 10; - } - else - { - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - if ( P.amulet != 0 ) - mult *= 5; - dungeonlevel = P.dungeonlevel; - if ( P.amulet != 0 && dungeonlevel < 21 ) - dungeonlevel = 21; - cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; - fprintf(stderr,"\nextracted $$$gold.%d -> %.8f TETRIS hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); - if ( funcid == 'H' && maxplayers > 1 ) - { - if ( P.amulet == 0 ) - { - if ( numplayers != maxplayers ) - return(cclib_error(result,"numplayers != maxplayers")); - else if ( tetris_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) - return(cclib_error(result,"highlander must be a winner or last one standing")); - } - cashout += numplayers * buyin; - } - if ( cashout >= txfee ) - { - if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,cashout,16,cp->unspendableCCaddr)) > (uint64_t)P.gold*mult ) - CCchange = (inputsum - cashout); - mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - } - } - } - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),tetrispk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,tetrispk,mypk,mypriv,mytetrisaddr); - CScript opret; - if ( pname.size() == 0 ) - pname = Tetris_pname; - if ( newdata.size() == 0 ) - { - opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, nodata,pname); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,opret); - //fprintf(stderr,"nodata finalizetx.(%s)\n",rawtx.c_str()); - } - else - { - opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, newdata,pname); - char seedstr[32]; - sprintf(seedstr,"%llu",(long long)seed); - std::vector vopretNonfungible; - GetOpReturnData(opret, vopretNonfungible); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), std::string(seedstr), gametxid.GetHex(), vopretNonfungible)); - } - return(tetris_rawtxresult(result,rawtx,1)); - } - result.push_back(Pair("result","success")); - } else fprintf(stderr,"illegal game err.%d\n",err); - } else fprintf(stderr,"parameters only n.%d\n",n); - } - return(result); + return(-1); } -UniValue tetris_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +void games_packitemstr(char *packitemstr,struct games_packitem *item) { - return(tetris_finishgame(txfee,cp,params,"bailout")); + sprintf(packitemstr,"not yet"); } -UniValue tetris_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - return(tetris_finishgame(txfee,cp,params,"highlander")); -} - -UniValue tetris_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char mytetrisaddr[64],str[64]; CPubKey mypk,tetrispk; - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method","gameinfo")); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - txid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",txid.GetHex())); - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,0) == 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("gameheight",(int64_t)gameheight)); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); - //fprintf(stderr,"mytetrisaddr.%s\n",mytetrisaddr); - seed = tetris_gamefields(result,maxplayers,buyin,txid,mytetrisaddr); - result.push_back(Pair("seed",(int64_t)seed)); - for (i=0; i > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - GetCCaddress(cp,coinaddr,tetrispk); - SetCCunspents(unspentOutputs,coinaddr); - nextheight = komodo_nextheight(); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( it->second.satoshis != txfee || vout != 0 ) // reject any that are not highlander markers - continue; - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+TETRIS_MAXKEYSTROKESGAP ) - { - tetris_playersalive(openslots,numplayers,txid,maxplayers,gameheight,tx); - if ( openslots > 0 ) - a.push_back(txid.GetHex()); - } - } - result.push_back(Pair("result","success")); - tetris_univalue(result,"pending",-1,-1); - result.push_back(Pair("pending",a)); - result.push_back(Pair("numpending",(int64_t)a.size())); - return(result); -} - -UniValue tetris_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey tetrispk,mypk,pk; std::string symbol,pname; char coinaddr[64]; - std::vector > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetTokensCCaddress(cp,coinaddr,mypk); - SetCCunspents(unspentOutputs,coinaddr); - tetris_univalue(result,"players",-1,-1); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( it->second.satoshis != 1 || vout > 1 ) - continue; - if ( tetris_playerdata(cp,gametxid,tokenid,pk,playerdata,symbol,pname,txid) == 0 )//&& pk == mypk ) - { - a.push_back(txid.GetHex()); - //a.push_back(Pair("playerdata",tetris_playerobj(playerdata))); - } - } - result.push_back(Pair("playerdata",a)); - result.push_back(Pair("numplayerdata",(int64_t)a.size())); - return(result); -} - -UniValue tetris_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR),b(UniValue::VARR); uint256 txid,hashBlock,gametxid,tokenid,playertxid; int32_t vout,maxplayers,gameheight,numvouts; CPubKey tetrispk,mypk; char coinaddr[64]; CTransaction tx,gametx; int64_t buyin; - std::vector > addressIndex; - //std::vector > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); - //SetCCunspents(unspentOutputs,coinaddr); - SetCCtxids(addressIndex,coinaddr); - tetris_univalue(result,"games",-1,-1); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - //for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); - if ( vout == 0 ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - if ( tetris_registeropretdecode(gametxid,tokenid,playertxid,tx.vout[numvouts-1].scriptPubKey) == 'R' ) - { - if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - if ( CCgettxout(txid,vout,1,0) < 0 ) - b.push_back(gametxid.GetHex()); - else a.push_back(gametxid.GetHex()); - } - } - } - } - } - result.push_back(Pair("pastgames",b)); - result.push_back(Pair("games",a)); - result.push_back(Pair("numgames",(int64_t)(a.size()+b.size()))); - return(result); -} - -UniValue tetris_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); int32_t n; char *namestr = 0; - tetris_univalue(result,"setname",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - if ( (namestr= jstri(params,0)) != 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("pname",namestr)); - tetris_pname = namestr; - return(result); - } - } - } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt get name")); - return(result); -} - -bool tetris_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) -{ - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid,tokentx=0; int32_t i,maxplayers,enabled = 0,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,txid,tokenid,batontxid,playertxid,ptxid; int64_t buyin,cashout; std::vector playerdata,keystrokes; std::string symbol,pname; - if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 ) - { - if (height < 21274 ) - return(true); - else if ( height > 50000 ) - enabled = 1; - } else enabled = 1; - if ( (numvouts= tx.vout.size()) > 1 ) - { - txid = tx.GetHash(); - scriptPubKey = tx.vout[numvouts-1].scriptPubKey; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 ) - { - script = (uint8_t *)vopret.data(); - funcid = script[1]; - if ( (e= script[0]) == EVAL_TOKENS ) - { - tokentx = funcid; - if ( (funcid= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) - { - if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) - { - fprintf(stderr,"ht.%d couldnt decode tokens opret (%c)\n",height,script[1]); - } else e = EVAL_TETRIS, decoded = 1; - } else e = EVAL_TETRIS, decoded = 1; - } - if ( e == EVAL_TETRIS ) - { - //fprintf(stderr,"ht.%d tetris.(%c)\n",height,script[1]); - if ( decoded == 0 ) - { - switch ( funcid ) - { - case 'G': // seems just need to make sure no vout abuse is left to do - gametx = tx; - gametxid = tx.GetHash(); - gameheight = height; - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,zeroid,0)) != 0 ) - { - fprintf(stderr,"height.%d %s tetris_isvalidgame error.%d\n",height,gametxid.GetHex().c_str(),err); - return eval->Invalid("invalid gametxid"); - } - //fprintf(stderr,"height.%d %s tetris_isvalidgame\n",height,gametxid.GetHex().c_str()); - return(true); - break; - case 'R': - if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' ) - { - return eval->Invalid("couldnt decode register opret"); - } - // baton is created - // validation is done below - break; - case 'K': - if ( (funcid= tetris_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' ) - { - return eval->Invalid("couldnt decode keystrokes opret"); - } - // spending the baton proves it is the user if the pk is the signer - return(true); - break; - case 'H': case 'Q': - // done in the next switch statement as there are some H/Q tx with playerdata which would skip this section - break; - default: - return eval->Invalid("illegal tetris non-decoded funcid"); - break; - } - } - switch ( funcid ) - { - case 'R': // register - // verify vout amounts are as they should be and no vins that shouldnt be - return(true); - case 'H': // win - case 'Q': // bailout - if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) - { - //fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height); - //if ( height > 20000 ) - return eval->Invalid("couldnt decode H/Q opret"); - } - // verify pk belongs to this tx - if ( tokentx == 'c' && playerdata.size() > 0 ) - { - static char laststr[512]; char cashstr[512]; - if ( tetris_playerdata_validate(&cashout,ptxid,cp,playerdata,gametxid,pk) < 0 ) - { - sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",tokentx,decoded,height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); - if ( strcmp(laststr,cashstr) != 0 ) - { - strcpy(laststr,cashstr); - fprintf(stderr,"%s\n",cashstr); - } - if ( enabled != 0 ) - return eval->Invalid("mismatched playerdata"); - } - if ( funcid == 'H' ) - cashout *= 2; - sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); - if ( strcmp(laststr,cashstr) != 0 ) - { - strcpy(laststr,cashstr); - fprintf(stderr,"%s\n",cashstr); - } - if ( enabled != 0 && tx.vout[2].nValue != cashout ) - return eval->Invalid("mismatched cashout amount"); - } - if ( funcid == 'Q' ) - { - // verify vin/vout - } - else // 'H' - { - // verify vin/vout and proper payouts - } - return(true); - break; - default: - return eval->Invalid("illegal tetris funcid"); - break; - } - } else return eval->Invalid("illegal evalcode"); - } else return eval->Invalid("opret too small"); - } else return eval->Invalid("not enough vouts"); return(true); } -#endif diff --git a/src/cc/tetris.h b/src/cc/tetris.h new file mode 100644 index 000000000..f032bf2da --- /dev/null +++ b/src/cc/tetris.h @@ -0,0 +1,197 @@ +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#ifndef H_TETRIS_H +#define H_TETRIS_H + +#define GAMENAME "tetris" +#define GAMEMAIN tetris +#define CHAINNAME "GTEST" + +#define MAXPACK 23 +struct games_packitem +{ + int32_t type,launch,count,which,hplus,dplus,arm,flags,group; + char damage[8],hurldmg[8]; +}; + +struct games_player +{ + int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; + struct games_packitem gamespack[MAXPACK]; +}; + +struct games_state +{ + uint64_t seed; + char *keystrokes,*keystrokeshex; + uint32_t needflush,replaydone; + int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; + FILE *logfp; + struct games_player P; + char buffered[10000]; + uint8_t playerdata[10000]; +}; + + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + +/* + Convert a tetromino type to its corresponding cell. + */ +#define TYPE_TO_CELL(x) ((x)+1) + +/* + Strings for how you would print a tetris board. + */ +#define TC_EMPTY_STR " " +#define TC_BLOCK_STR "\u2588" + +/* + Questions about a tetris cell. + */ +#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) +#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) + +/* + How many cells in a tetromino? + */ +#define TETRIS 4 +/* + How many tetrominos? + */ +#define NUM_TETROMINOS 7 +/* + How many orientations of a tetromino? + */ +#define NUM_ORIENTATIONS 4 + +/* + Level constants. + */ +#define MAX_LEVEL 19 +#define LINES_PER_LEVEL 10 + +/* + A "cell" is a 1x1 block within a tetris board. + */ +typedef enum { + TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ +} tetris_cell; + +/* + A "type" is a type/shape of a tetromino. Not including orientation. + */ +typedef enum { + TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z +} tetris_type; + +/* + A row,column pair. Negative numbers allowed, because we need them for + offsets. + */ +typedef struct { + int row; + int col; +} tetris_location; + +/* + A "block" is a struct that contains information about a tetromino. + Specifically, what type it is, what orientation it has, and where it is. + */ +typedef struct { + int typ; + int ori; + tetris_location loc; +} tetris_block; + +/* + All possible moves to give as input to the game. + */ +typedef enum { + TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE +} tetris_move; + +/* + A game object! + */ +typedef struct { + /* + Game board stuff: + */ + int rows; + int cols; + char *board; + /* + Scoring information: + */ + int points; + int level; + /* + Falling block is the one currently going down. Next block is the one that + will be falling after this one. Stored is the block that you can swap out. + */ + tetris_block falling; + tetris_block next; + tetris_block stored; + /* + Number of game ticks until the block will move down. + */ + int ticks_till_gravity; + /* + Number of lines until you advance to the next level. + */ + int lines_remaining; +} tetris_game; + +/* + This array stores all necessary information about the cells that are filled by + each tetromino. The first index is the type of the tetromino (i.e. shape, + e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final + array contains 4 tetris_location objects, each mapping to an offset from a + point on the upper left that is the tetromino "origin". + */ +extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; + +/* + This array tells you how many ticks per gravity by level. Decreases as level + increases, to add difficulty. + */ +extern int GRAVITY_LEVEL[MAX_LEVEL+1]; + +// Data structure manipulation. +void tg_init(tetris_game *obj, int rows, int cols); +tetris_game *tg_create(int rows, int cols); +void tg_destroy(tetris_game *obj); +void tg_delete(tetris_game *obj); +tetris_game *tg_load(FILE *f); +void tg_save(tetris_game *obj, FILE *f); + +// Public methods not related to memory: +char tg_get(tetris_game *obj, int row, int col); +bool tg_check(tetris_game *obj, int row, int col); +bool tg_tick(tetris_game *obj, tetris_move move); +void tg_print(tetris_game *obj, FILE *f); + +#endif + From c5b7efd7f8c25acf310619f15d9b203f7bde8a50 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:26:24 -1100 Subject: [PATCH 002/385] Optimize --- src/cc/gamescc.cpp | 114 ++++----------------------------------------- src/cc/tetris.c | 11 ++++- src/cc/tetris.cpp | 85 +++++++++++++++++++++++++++++++++ src/cc/tetris.h | 88 +++++++++++++++++----------------- 4 files changed, 148 insertions(+), 150 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 11ceb3345..869205acc 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -14,15 +14,18 @@ ******************************************************************************/ #include "gamescc.h" - -#include "tetris.h" - -static int random_tetromino(void) -{ - return rand() % NUM_TETROMINOS; -} +#include "tetris.c" // replace with game code #ifndef STANDALONE +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload); +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk); +int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); +void games_packitemstr(char *packitemstr,struct games_packitem *item); +int64_t games_cashout(struct games_player *P); +char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr); + +#include "tetris.cpp" // replace with game specific functions + /* ./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\" { @@ -55,12 +58,6 @@ static int random_tetromino(void) ./c cclib events 17 \"[%226d%22,%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,1]\" */ -int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload); -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk); -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); -void games_packitemstr(char *packitemstr,struct games_packitem *item); -int64_t games_cashout(struct games_player *P); - CScript games_newgameopret(int64_t buyin,int32_t maxplayers) { @@ -1193,91 +1190,6 @@ UniValue games_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } else return(cclib_error(result,"couldnt reparse params")); } -char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) -{ - CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; - gamespk = GetUnspendable(cp,0); - *numkeysp = 0; - seed = 0; - num = numkeys = 0; - playertxid = zeroid; - str[0] = 0; - if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) - { - if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) - { - UniValue obj; - seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i no playerdata\n"); - newdata.resize(0); - *numkeysp = numkeys; - return(keystrokes); - /* P.gold = (P.gold * 8) / 10; - if ( keystrokes != 0 ) - { - free(keystrokes); - keystrokes = 0; - *numkeysp = 0; - return(keystrokes); - }*/ - } - else - { - sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - //fprintf(stderr,"%s\n",str); - *numkeysp = numkeys; - return(keystrokes); - } - } else num = 0; - } - else - { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); - if ( keystrokes != 0 ) - free(keystrokes), keystrokes = 0; - } - } else fprintf(stderr,"extractgame: invalid game\n"); - //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); - return(0); -} - UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; @@ -1556,11 +1468,5 @@ UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -#include "tetris.cpp" - -#else // STANDALONE - -#include "tetris.c" - #endif diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 4ffd27575..94ceda83b 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -1,7 +1,10 @@ #include "tetris.h" -#include "dapps/dappstd.c" +static int random_tetromino(void) +{ + return rand() % NUM_TETROMINOS; +} /***************************************************************************/ /** https://github.com/brenns10/tetris @@ -622,10 +625,12 @@ void init_colors(void) init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); } +#else /* Main tetris game! */ -#ifdef STANDALONE +#include "dapps/dappstd.c" + char *clonestr(char *str) { char *clone; int32_t len; @@ -756,3 +761,5 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) { return(-1); } +#endif + diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index fd833d7b7..4d0be1e96 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -128,6 +128,91 @@ int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct C return(-1); } +char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) +{ + CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; + gamespk = GetUnspendable(cp,0); + *numkeysp = 0; + seed = 0; + num = numkeys = 0; + playertxid = zeroid; + str[0] = 0; + if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) + { + if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) + { + UniValue obj; + seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); + //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); + memset(&P,0,sizeof(P)); + if ( playerdata.size() > 0 ) + { + for (i=0; i no playerdata\n"); + newdata.resize(0); + *numkeysp = numkeys; + return(keystrokes); + /* P.gold = (P.gold * 8) / 10; + if ( keystrokes != 0 ) + { + free(keystrokes); + keystrokes = 0; + *numkeysp = 0; + return(keystrokes); + }*/ + } + else + { + sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); + //fprintf(stderr,"%s\n",str); + *numkeysp = numkeys; + return(keystrokes); + } + } else num = 0; + } + else + { + fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); + if ( keystrokes != 0 ) + free(keystrokes), keystrokes = 0; + } + } else fprintf(stderr,"extractgame: invalid game\n"); + //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); + return(0); +} + int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon { return(-1); diff --git a/src/cc/tetris.h b/src/cc/tetris.h index f032bf2da..b239a1644 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -1,51 +1,7 @@ -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ #ifndef H_TETRIS_H #define H_TETRIS_H -#define GAMENAME "tetris" -#define GAMEMAIN tetris -#define CHAINNAME "GTEST" - -#define MAXPACK 23 -struct games_packitem -{ - int32_t type,launch,count,which,hplus,dplus,arm,flags,group; - char damage[8],hurldmg[8]; -}; - -struct games_player -{ - int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; - struct games_packitem gamespack[MAXPACK]; -}; - -struct games_state -{ - uint64_t seed; - char *keystrokes,*keystrokeshex; - uint32_t needflush,replaydone; - int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; - FILE *logfp; - struct games_player P; - char buffered[10000]; - uint8_t playerdata[10000]; -}; - - /***************************************************************************/ /** https://github.com/brenns10/tetris @file main.c @@ -193,5 +149,49 @@ bool tg_check(tetris_game *obj, int row, int col); bool tg_tick(tetris_game *obj, tetris_move move); void tg_print(tetris_game *obj, FILE *f); +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +#define GAMENAME "tetris" +#define GAMEMAIN tetris +#define CHAINNAME "GTEST" + +#define MAXPACK 23 +struct games_packitem +{ + int32_t type,launch,count,which,hplus,dplus,arm,flags,group; + char damage[8],hurldmg[8]; +}; + +struct games_player +{ + int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; + struct games_packitem gamespack[MAXPACK]; +}; + +struct games_state +{ + uint64_t seed; + char *keystrokes,*keystrokeshex; + uint32_t needflush,replaydone; + int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; + FILE *logfp; + struct games_player P; + char buffered[10000]; + uint8_t playerdata[10000]; +}; + + #endif From f9c20dab7876d7f08ccd0411fcbcf7311dee27f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:27:25 -1100 Subject: [PATCH 003/385] Def standalone --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 94ceda83b..7c6ff768e 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -625,7 +625,7 @@ void init_colors(void) init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); } -#else +#ifdef STANDALONE /* Main tetris game! */ From a3d531714ec633ee3f685e493c12958500aee6ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:28:28 -1100 Subject: [PATCH 004/385] Extern const --- src/cc/tetris.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index b239a1644..e2639cba1 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -127,13 +127,13 @@ typedef struct { array contains 4 tetris_location objects, each mapping to an offset from a point on the upper left that is the tetromino "origin". */ -extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; +extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; /* This array tells you how many ticks per gravity by level. Decreases as level increases, to add difficulty. */ -extern int GRAVITY_LEVEL[MAX_LEVEL+1]; +extern const int GRAVITY_LEVEL[MAX_LEVEL+1]; // Data structure manipulation. void tg_init(tetris_game *obj, int rows, int cols); From 8c71d44ba66aabfde1cdad6055d94185d3ae14dc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:31:43 -1100 Subject: [PATCH 005/385] Reorder --- src/cc/gamescc.cpp | 26 -------------------------- src/cc/tetris.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 869205acc..f62a8699c 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -17,12 +17,6 @@ #include "tetris.c" // replace with game code #ifndef STANDALONE -int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload); -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk); -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); -void games_packitemstr(char *packitemstr,struct games_packitem *item); -int64_t games_cashout(struct games_player *P); -char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr); #include "tetris.cpp" // replace with game specific functions @@ -551,26 +545,6 @@ int32_t games_playersalive(int32_t &openslots,int32_t &numplayers,uint256 gametx return(alive); } -void disp_gamesplayerdata(std::vector playerdata) -{ - struct games_player P; int32_t i; char packitemstr[512]; - if ( playerdata.size() > 0 ) - { - for (i=0; i>16,P.level,P.experience,P.dungeonlevel); - for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) { int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct games_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 4d0be1e96..cb9c47cc8 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -14,6 +14,10 @@ * * ******************************************************************************/ +int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname); +int32_t games_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0); +uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr); + // game specific code for daemon int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) @@ -47,6 +51,26 @@ int64_t games_cashout(struct games_player *P) return(cashout); } +void disp_gamesplayerdata(std::vector playerdata) +{ + struct games_player P; int32_t i; char packitemstr[512]; + if ( playerdata.size() > 0 ) + { + for (i=0; i>16,P.level,P.experience,P.dungeonlevel); + for (i=0; i playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; From 43bdea08406e8d7e0b759c555c2d77085464583e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:33:49 -1100 Subject: [PATCH 006/385] Reorder --- src/cc/tetris.cpp | 174 +++++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index cb9c47cc8..f9e4e167a 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -20,6 +20,16 @@ uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 // game specific code for daemon +void games_packitemstr(char *packitemstr,struct games_packitem *item) +{ + sprintf(packitemstr,"not yet"); +} + +int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon +{ + return(-1); +} + int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; @@ -71,87 +81,6 @@ void disp_gamesplayerdata(std::vector playerdata) } } -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; - *cashoutp = 0; - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - free(keystrokes); - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - - for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); - } - *cashoutp = 0; - return(0); - } - } - if ( gametxid != prevgame ) - { - prevgame = gametxid; - bad++; - disp_gamesplayerdata(newdata); - disp_gamesplayerdata(playerdata); - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - } - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); - return(-1); -} - char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) { CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; @@ -237,16 +166,87 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto return(0); } -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { + static uint32_t good,bad; static uint256 prevgame; + char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; + *cashoutp = 0; + gamespk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,gamesaddr,gamespk,pk); + if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) + { + free(keystrokes); + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); + remove(fname); + + for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); + } + *cashoutp = 0; + return(0); + } + } + if ( gametxid != prevgame ) + { + prevgame = gametxid; + bad++; + disp_gamesplayerdata(newdata); + disp_gamesplayerdata(playerdata); + fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); + } + } + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); + remove(fname); + //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); return(-1); } -void games_packitemstr(char *packitemstr,struct games_packitem *item) -{ - sprintf(packitemstr,"not yet"); -} - bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { return(true); From c166507c62a7afb2b21d69243a968a28fe51907d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:36:06 -1100 Subject: [PATCH 007/385] rand() --- src/cc/tetris.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 7c6ff768e..d3e9911a1 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -1,6 +1,12 @@ #include "tetris.h" +/* + In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events + */ + +int rand(); + static int random_tetromino(void) { return rand() % NUM_TETROMINOS; From d5e26e7bc590a061aabe1ae336bd66e7fae20ab4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:44:10 -1100 Subject: [PATCH 008/385] Declare rs --- src/cc/tetris.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index d3e9911a1..874a6437d 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -2,7 +2,7 @@ #include "tetris.h" /* - In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events + In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. */ int rand(); @@ -654,14 +654,40 @@ char *clonestr(char *str) return(clone); } +struct games_state globalR; + int tetris(int argc, char **argv) { tetris_game *tg; tetris_move move = TM_NONE; bool running = true; WINDOW *board, *next, *hold, *score; + struct games_state *rs = &globalR; int32_t c,skipcount=0; bits256 gametxid; uint32_t eventid = 0; memset(&gametxid,0,sizeof(gametxid)); + memset(rs,0,sizeof(*rs)); + rs->guiflag = 1; + rs->sleeptime = 1; // non-zero to allow refresh() + if ( argc == 3 && strlen(argv[2]) == 64 ) + { +#ifdef _WIN32 +#ifdef _MSC_VER + rs->seed = _strtoui64(argv[1], NULL, 10); +#else + rs->seed = atol(argv[1]); // windows, but not MSVC +#endif // _MSC_VER +#else + rs->seed = atol(argv[1]); // non-windows +#endif // _WIN32 + strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata\n"); + if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + { + fprintf(stderr,"invalid gametxid, or already started\n"); + return(-1); + } + } else rs->seed = 777; + // Load file if given a filename. if (argc >= 2) { FILE *f = fopen(argv[1], "r"); From 226179dcd386417dded5910f9c28154d5f905868 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:45:17 -1100 Subject: [PATCH 009/385] Skip rand() --- src/cc/tetris.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 874a6437d..adcf098f5 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -5,11 +5,10 @@ In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. */ -int rand(); - static int random_tetromino(void) { - return rand() % NUM_TETROMINOS; + return(0); + //return rand() % NUM_TETROMINOS; } /***************************************************************************/ From b4dd00266d9c2496f0e039a3e2d708e61bb3d540 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 00:55:53 -1100 Subject: [PATCH 010/385] Active rngnext --- src/cc/tetris.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index adcf098f5..db88c0659 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -3,12 +3,14 @@ /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. + + also, the standalone game needs to support argv of seed gametxid, along with replay args */ -static int random_tetromino(void) +static int random_tetromino(struct games_state *rs) { - return(0); - //return rand() % NUM_TETROMINOS; + rs->seed = _games_rngnext(rs->seed); + return(rs->seed % NUM_TETROMINOS); } /***************************************************************************/ @@ -173,11 +175,11 @@ static bool tg_fits(tetris_game *obj, tetris_block block) Create a new falling block and populate the next falling block with a random one. */ -static void tg_new_falling(tetris_game *obj) +static void tg_new_falling(struct games_state *rs,tetris_game *obj) { // Put in a new falling tetromino. obj->falling = obj->next; - obj->next.typ = random_tetromino(); + obj->next.typ = random_tetromino(rs); obj->next.ori = 0; obj->next.loc.row = 0; obj->next.loc.col = obj->cols/2 - 2; @@ -190,7 +192,7 @@ static void tg_new_falling(tetris_game *obj) /* Tick gravity, and move the block down if gravity should act. */ -static void tg_do_gravity_tick(tetris_game *obj) +static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj) { obj->ticks_till_gravity--; if (obj->ticks_till_gravity <= 0) { @@ -202,7 +204,7 @@ static void tg_do_gravity_tick(tetris_game *obj) obj->falling.loc.row--; tg_put(obj, obj->falling); - tg_new_falling(obj); + tg_new_falling(rs,obj); } tg_put(obj, obj->falling); } @@ -411,11 +413,11 @@ static bool tg_game_over(tetris_game *obj) Do a single game tick: process gravity, user input, and score. Return true if the game is still running, false if it is over. */ -bool tg_tick(tetris_game *obj, tetris_move move) +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) { int lines_cleared; // Handle gravity. - tg_do_gravity_tick(obj); + tg_do_gravity_tick(rs,obj); // Handle input. tg_handle_move(obj, move); @@ -687,7 +689,7 @@ int tetris(int argc, char **argv) } } else rs->seed = 777; - // Load file if given a filename. + /* Load file if given a filename. if (argc >= 2) { FILE *f = fopen(argv[1], "r"); if (f == NULL) { @@ -699,7 +701,9 @@ int tetris(int argc, char **argv) } else { // Otherwise create new game. tg = tg_create(22, 10); - } + }*/ + tg = tg_create(22, 10); + // NCURSES initialization: initscr(); // initialize curses cbreak(); // pass key presses to program, but not signals @@ -717,7 +721,7 @@ int tetris(int argc, char **argv) int32_t counter = 0; // Game loop while (running) { - running = tg_tick(tg, move); + running = tg_tick(rs,tg, move); display_board(board, tg); display_piece(next, tg->next); display_piece(hold, tg->stored); From 46dba9071ba32f439570e7bd8bc390b0103e677c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 01:49:11 -1100 Subject: [PATCH 011/385] Add keystrokes replay --- src/cc/dapps/dappstd.c | 318 ++++++++++++++++++++++++++++------------- src/cc/tetris.c | 65 +++++++-- 2 files changed, 274 insertions(+), 109 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index ec8045b2f..033633665 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -688,33 +688,6 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) return(retstr2); } -int32_t issue_games_events(bits256 gametxid,uint32_t eventid,int32_t c) -{ - static FILE *fp; - char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} - int32_t games_sendrawtransaction(char *rawtx) { char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; @@ -781,91 +754,240 @@ int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,cha } free(rs->keystrokeshex), rs->keystrokeshex = 0; } - if ( 0 && (pastkeys= games_keystrokesload(&numpastkeys,seed,1)) != 0 ) - { - sprintf(params,"[\"extract\",\"17\",\"[%%22%s%%22]\"]",Gametxidstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (keys= jstr(resobj,(char *)"keystrokes")) != 0 ) - { - len = strlen(keys) / 2; - pastcmp = (uint8_t *)malloc(len + 1); - decode_hex(pastcmp,len,keys); - fprintf(stderr,"keystrokes.(%s) vs pastkeys\n",keys); - for (i=0; i> keystrokes.log",ASSETCHAINS_SYMBOL,Gametxidstr,hexstr); - if ( system(cmd) != 0 ) - fprintf(stderr,"error issuing (%s)\n",cmd); - } - else - { - static FILE *fp; - if ( fp == 0 ) - fp = fopen("keystrokes.log","a"); - sprintf(params,"[\"keystrokes\",\"17\",\"[%%22%s%%22,%%22%s%%22]\"]",Gametxidstr,hexstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + if ( fp != 0 ) { - if ( fp != 0 ) + fprintf(fp,"%s\n",params); + fprintf(fp,"%s\n",retstr); + fflush(fp); + } + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (rawtx= jstr(resobj,(char *)"hex")) != 0 ) { - fprintf(fp,"%s\n",params); - fprintf(fp,"%s\n",retstr); - fflush(fp); - } - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (rawtx= jstr(resobj,(char *)"hex")) != 0 ) + if ( rs->keystrokeshex != 0 ) + free(rs->keystrokeshex); + if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) { - if ( rs->keystrokeshex != 0 ) - free(rs->keystrokeshex); - if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) - { - rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); - strcpy(rs->keystrokeshex,rawtx); - retflag = 1; - } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); - //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); - } - free_json(retjson); + rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); + strcpy(rs->keystrokeshex,rawtx); + retflag = 1; + } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); + //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); } - free(retstr); - } - if ( 0 && waitflag != 0 && rs->keystrokeshex != 0 ) - { - while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - //fprintf(stderr,"post-rebroadcast\n"); - sleep(3); - } - free(rs->keystrokeshex), rs->keystrokeshex = 0; + free_json(retjson); } + free(retstr); } } return(retflag); } +int32_t gamesfname(char *fname,uint64_t seed,int32_t counter) +{ + sprintf(fname,"%s.%llu.%d",GAMENAME,(long long)seed,counter); + return(0); +} + +int32_t flushkeystrokes_local(struct games_state *rs,int32_t waitflag) +{ +#ifdef STANDALONE + char fname[1024]; FILE *fp; int32_t i,retflag = -1; + rs->counter++; + gamesfname(fname,rs->seed,rs->counter); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(rs->buffered,1,rs->num,fp) == rs->num ) + { + rs->num = 0; + retflag = 0; + fclose(fp); + gamesfname(fname,rs->seed,rs->counter+1); + if ( (fp= fopen(fname,"wb")) != 0 ) // truncate next file + fclose(fp); + //fprintf(stderr,"savefile <- %s retflag.%d\n",fname,retflag); + //} + } else fprintf(stderr,"error writing (%s)\n",fname); + } else fprintf(stderr,"error creating (%s)\n",fname); + return(retflag); +#else + return(0); +#endif +} + +#ifndef STANDALONE +// stubs for inside daemon + +int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) +{ + return(0); +} + +int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) +{ + return(-1); +} +#endif + +int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag) +{ + if ( rs->num > 0 ) + { + if ( games_progress(rs,waitflag,rs->seed,rs->buffered,rs->num) > 0 ) + { + flushkeystrokes_local(rs,waitflag); + memset(rs->buffered,0,sizeof(rs->buffered)); + } + } + return(0); +} + +void games_bailout(struct games_state *rs) +{ + flushkeystrokes(rs,1); +} + +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + +int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) +{ + struct games_state *rs; FILE *fp; int32_t i,n; + rs = (struct games_state *)calloc(1,sizeof(*rs)); + rs->seed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = sleepmillis * 1000; + if ( player != 0 ) + { + rs->P = *player; + rs->restoring = 1; + //fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints); + if ( rs->P.packsize > MAXPACK ) + rs->P.packsize = MAXPACK; + } + globalR = *rs; + uint32_t starttime = (uint32_t)time(NULL); + gamesiterate(rs); + if ( 0 ) + { + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); + sleep(2); + starttime = (uint32_t)time(NULL); + for (i=0; i<10000; i++) + { + memset(rs,0,sizeof(*rs)); + rs->seed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = 0; + gamesiterate(rs); + } + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime); + sleep(3); + } + // extract playerdata + + /*if ( (fp= fopen("checkfile","wb")) != 0 ) + { + //save_file(rs,fp,0); + //fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + }*/ + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + n = rs->playersize; + free(rs); + return(n); +} + +long get_filesize(FILE *fp) +{ + long fsize,fpos = ftell(fp); + fseek(fp,0,SEEK_END); + fsize = ftell(fp); + fseek(fp,fpos,SEEK_SET); + return(fsize); +} + +char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) +{ + char fname[1024],*keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; + *numkeysp = 0; + while ( 1 ) + { + gamesfname(fname,seed,counter); + //printf("check (%s)\n",fname); + if ( (fp= fopen(fname,"rb")) == 0 ) + break; + if ( (fsize= get_filesize(fp)) <= 0 ) + { + fclose(fp); + //printf("fsize.%ld\n",fsize); + break; + } + if ( (keystrokes= (char *)realloc(keystrokes,num+fsize)) == 0 ) + { + fprintf(stderr,"error reallocating keystrokes\n"); + fclose(fp); + return(0); + } + if ( fread(&keystrokes[num],1,fsize,fp) != fsize ) + { + fprintf(stderr,"error reading keystrokes from (%s)\n",fname); + fclose(fp); + free(keystrokes); + return(0); + } + fclose(fp); + num += fsize; + counter++; + //fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); + } + *numkeysp = num; + return(keystrokes); +} + +int32_t games_replay(uint64_t seed,int32_t sleeptime) +{ + FILE *fp; char fname[1024]; char *keystrokes = 0; long fsize; int32_t i,num=0,counter = 0; struct games_state *rs; struct games_player P,*player = 0; + if ( seed == 0 ) + seed = 777; + keystrokes = games_keystrokesload(&num,seed,counter); + if ( num > 0 ) + { + sprintf(fname,"%s.%llu.player",GAMENAME,(long long)seed); + if ( (fp=fopen(fname,"rb")) != 0 ) + { + if ( fread(&P,1,sizeof(P),fp) > 0 ) + { + //printf("max size player\n"); + player = &P; + } + fclose(fp); + } + games_replay2(0,seed,keystrokes,num,player,sleeptime); + mvaddstr(LINES - 2, 0, (char *)"replay completed"); + endwin(); + my_exit(0); + } + if ( keystrokes != 0 ) + free(keystrokes); + return(num); +} + int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) { char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; diff --git a/src/cc/tetris.c b/src/cc/tetris.c index db88c0659..5e873e5c4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -638,6 +638,34 @@ void init_colors(void) */ #include "dapps/dappstd.c" +int32_t issue_games_events(struct games_state *rs,bits256 gametxid,uint32_t eventid,char c) +{ + static FILE *fp; + char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); + rs->buffered[rs->num++] = c; + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); +} + char *clonestr(char *str) { char *clone; int32_t len; @@ -730,34 +758,49 @@ int tetris(int argc, char **argv) doupdate(); sleep_milli(10); c = getch(); - if ( c != -1 || skipcount == 0x3fff ) + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + if ( c < 0 || skipcount == 0x7f ) { if ( skipcount > 0 ) - issue_games_events(gametxid,eventid-skipcount,skipcount | 0x4000); + issue_games_events(rs,gametxid,eventid-skipcount,skipcount | 0x80); if ( c != -1 ) - issue_games_events(gametxid,eventid,c); + issue_games_events(rs,gametxid,eventid,c); skipcount = 0; } else skipcount++; eventid++; switch ( c ) { - case KEY_LEFT: + case 'h': move = TM_LEFT; break; - case KEY_RIGHT: + case 'l': move = TM_RIGHT; break; - case KEY_UP: + case 'k': move = TM_CLOCK; break; - case KEY_DOWN: + case 'j': move = TM_DROP; break; case 'q': running = false; move = TM_NONE; break; - case 'p': + /*case 'p': wclear(board); box(board, 0, 0); wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); @@ -771,7 +814,7 @@ int tetris(int argc, char **argv) case 's': save(tg, board); move = TM_NONE; - break; + break;*/ case ' ': move = TM_HOLD; break; @@ -792,9 +835,9 @@ int tetris(int argc, char **argv) return 0; } -int32_t games_replay(uint64_t seed,int32_t sleeptime) +void gamesiterate(struct games_state *rs) { - return(-1); + } #endif From c9a3844f54799b77c862c38f9faf06c3a0a08a1e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 01:52:18 -1100 Subject: [PATCH 012/385] Test --- src/cc/tetris.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index e2639cba1..40a9c97cb 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -137,7 +137,7 @@ extern const int GRAVITY_LEVEL[MAX_LEVEL+1]; // Data structure manipulation. void tg_init(tetris_game *obj, int rows, int cols); -tetris_game *tg_create(int rows, int cols); +tetris_game *tg_create(struct games_state *rs,int rows, int cols); void tg_destroy(tetris_game *obj); void tg_delete(tetris_game *obj); tetris_game *tg_load(FILE *f); @@ -146,7 +146,7 @@ void tg_save(tetris_game *obj, FILE *f); // Public methods not related to memory: char tg_get(tetris_game *obj, int row, int col); bool tg_check(tetris_game *obj, int row, int col); -bool tg_tick(tetris_game *obj, tetris_move move); +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move); void tg_print(tetris_game *obj, FILE *f); /****************************************************************************** @@ -192,6 +192,7 @@ struct games_state uint8_t playerdata[10000]; }; +uint64_t _games_rngnext(uint64_t initseed); #endif From a49081204962ba5076cdf59ec509d2182b6c4911 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 01:54:09 -1100 Subject: [PATCH 013/385] struct games_state *rs, --- src/cc/tetris.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 5e873e5c4..4dbb71f89 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -226,7 +226,7 @@ static void tg_move(tetris_game *obj, int direction) /* Send the falling tetris block to the bottom. */ -static void tg_down(tetris_game *obj) +static void tg_down(struct games_state *rs,tetris_game *obj) { tg_remove(obj, obj->falling); while (tg_fits(obj, obj->falling)) { @@ -234,7 +234,7 @@ static void tg_down(tetris_game *obj) } obj->falling.loc.row--; tg_put(obj, obj->falling); - tg_new_falling(obj); + tg_new_falling(rs,obj); } /* @@ -273,12 +273,12 @@ static void tg_rotate(tetris_game *obj, int direction) /* Swap the falling block with the block in the hold buffer. */ -static void tg_hold(tetris_game *obj) +static void tg_hold(struct games_state *rs,tetris_game *obj) { tg_remove(obj, obj->falling); if (obj->stored.typ == -1) { obj->stored = obj->falling; - tg_new_falling(obj); + tg_new_falling(rs,obj); } else { int typ = obj->falling.typ, ori = obj->falling.ori; obj->falling.typ = obj->stored.typ; @@ -431,7 +431,7 @@ bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) return !tg_game_over(obj); } -void tg_init(tetris_game *obj, int rows, int cols) +void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) { // Initialization logic obj->rows = rows; @@ -443,8 +443,8 @@ void tg_init(tetris_game *obj, int rows, int cols) obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; obj->lines_remaining = LINES_PER_LEVEL; //srand(time(NULL)); - tg_new_falling(obj); - tg_new_falling(obj); + tg_new_falling(rs,obj); + tg_new_falling(ts,obj); obj->stored.typ = -1; obj->stored.ori = 0; obj->stored.loc.row = 0; @@ -452,10 +452,10 @@ void tg_init(tetris_game *obj, int rows, int cols) printf("%d", obj->falling.loc.col); } -tetris_game *tg_create(int rows, int cols) +tetris_game *tg_create(struct games_state *rs,int rows, int cols) { tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - tg_init(obj, rows, cols); + tg_init(rs,obj, rows, cols); return obj; } From 30df5445c762767263c3312560624476bac74c02 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 01:57:07 -1100 Subject: [PATCH 014/385] struct games_state *rs, --- src/cc/tetris.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 4dbb71f89..1b039dc6f 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -295,7 +295,7 @@ static void tg_hold(struct games_state *rs,tetris_game *obj) /* Perform the action specified by the move. */ -static void tg_handle_move(tetris_game *obj, tetris_move move) +static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move) { switch (move) { case TM_LEFT: @@ -305,7 +305,7 @@ static void tg_handle_move(tetris_game *obj, tetris_move move) tg_move(obj, 1); break; case TM_DROP: - tg_down(obj); + tg_down(rs,obj); break; case TM_CLOCK: tg_rotate(obj, 1); @@ -314,7 +314,7 @@ static void tg_handle_move(tetris_game *obj, tetris_move move) tg_rotate(obj, -1); break; case TM_HOLD: - tg_hold(obj); + tg_hold(rs,obj); break; default: // pass @@ -420,7 +420,7 @@ bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) tg_do_gravity_tick(rs,obj); // Handle input. - tg_handle_move(obj, move); + tg_handle_move(rs,obj, move); // Check for cleared lines lines_cleared = tg_check_lines(obj); @@ -444,7 +444,7 @@ void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) obj->lines_remaining = LINES_PER_LEVEL; //srand(time(NULL)); tg_new_falling(rs,obj); - tg_new_falling(ts,obj); + tg_new_falling(rs,obj); obj->stored.typ = -1; obj->stored.ori = 0; obj->stored.loc.row = 0; @@ -728,9 +728,9 @@ int tetris(int argc, char **argv) fclose(f); } else { // Otherwise create new game. - tg = tg_create(22, 10); + tg = tg_create(rs,22, 10); }*/ - tg = tg_create(22, 10); + tg = tg_create(rs,22, 10); // NCURSES initialization: initscr(); // initialize curses From 8e6f5a6a2dd9e45b90c7d4d7d603f0901a157941 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Tue, 26 Mar 2019 20:59:31 +0800 Subject: [PATCH 015/385] initial commit for backup release tx needs testing, i think it half works. --- src/cc/CCinclude.h | 1 + src/cc/CCutils.cpp | 14 +++++++++++++- src/cc/payments.cpp | 6 ++++-- src/cc/rewards.cpp | 21 +++++++-------------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 13d7236d4..839fd2c95 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -247,6 +247,7 @@ void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, c int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode); bool IsCCInput(CScript const& scriptSig); +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); uint256 revuint256(uint256 txid); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index a3bf0a68b..887550a0c 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -168,6 +168,18 @@ bool IsCCInput(CScript const& scriptSig) return true; } +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime) +{ + int64_t interest; uint64_t valuein; + CCoinsViewCache &view = *pcoinsTip; + valuein = view.GetValueIn(height,&interest,tx,blocktime); + if ( valuein-tx.GetValueOut() > txfee ) + { + //fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee); + return false; + } + return true; +} // set additional 'unspendable' addr void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) @@ -668,4 +680,4 @@ bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector paramsNull,co return(false); //eval->Invalid("error in CClib_validate"); } return eval->Invalid("cclib CC must have evalcode between 16 and 127"); -} \ No newline at end of file +} diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 184c92d33..e0c4c8ada 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -192,7 +192,9 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) - return(eval->Invalid("negative values")); + return(eval->Invalid("negative values")); + if ( !CheckTxFee(tx, PAYMENTS_TXFEE, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); Paymentspk = GetUnspendable(cp,0); //fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() ); @@ -281,7 +283,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); return(eval->Invalid("vin is not paymentsCC type")); } //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str()); - } + } // check the chain depth vs locked blcoks requirement. CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if ( pblockindex->GetHeight() > ht-lockedblocks ) diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 65e32ee27..db64127e7 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -197,9 +197,6 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); - int64_t interest; uint64_t valuein; - CCoinsViewCache &view = *pcoinsTip; - valuein = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime); preventCCvins = preventCCvouts = -1; if ( numvouts < 1 ) return eval->Invalid("no vouts"); @@ -258,20 +255,17 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 ) return eval->Invalid("unexpected normal vin for unlock"); } - if ( valuein-tx.GetValueOut() > txfee ) + if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); + if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 && tx.vout[1].nValue == 10000 ) { - fprintf(stderr, "valueout.%li vs valuein.%li txfee.%li\n", tx.GetValueOut(), valuein, txfee); - return eval->Invalid("alright is stealing your money"); - } - if ( numvouts == 2 && numvins == 1 ) - { - if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("unlock recover tx vout.0 is not normal output"); + if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey ) + return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey"); else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey ) return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey"); else if ( tx.vout[0].nValue > vinTx.vout[0].nValue ) return eval->Invalid("unlock recover tx vout.0 mismatched amounts"); - else if ( tx.vout[1].nValue > 0 ) + else if ( tx.vout[2].nValue > 0 ) return eval->Invalid("unlock recover tx vout.1 nonz amount"); else return(true); } @@ -689,8 +683,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2 } else { - firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey)); - //CCerror = "cant find enough rewards inputs"; + firstmtx.vout.push_back(CTxOut(amount-txfee*2,scriptPubKey)); fprintf(stderr,"not enough rewards funds to payout %.8f, recover mode tx\n",(double)(reward+txfee)/COIN); return(FinalizeCCTx(-1LL,cp,firstmtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid))); } From 3a6db6cc718d9550b414dca6190775755f8cf6a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 01:59:56 -1100 Subject: [PATCH 016/385] Gamesiterate --- src/cc/dapps/dappstd.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 033633665..5c8fb0204 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -23,6 +23,9 @@ #include #include +extern struct games_state globalR; +void gamesiterate(struct games_state *rs); + char USERPASS[8192]; uint16_t GAMES_PORT; char Gametxidstr[67]; char *clonestr(char *str); @@ -960,6 +963,19 @@ char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) return(keystrokes); } +void games_exit() +{ + uint32_t counter; + resetltchars(); + if ( globalR.guiflag != 0 || globalR.sleeptime != 0 ) + exit(st); + else if ( counter++ < 10 ) + { + fprintf(stderr,"would have exit.(%d) sleeptime.%d\n",st,globalR.sleeptime); + globalR.replaydone = 1; + } +} + int32_t games_replay(uint64_t seed,int32_t sleeptime) { FILE *fp; char fname[1024]; char *keystrokes = 0; long fsize; int32_t i,num=0,counter = 0; struct games_state *rs; struct games_player P,*player = 0; @@ -981,7 +997,7 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) games_replay2(0,seed,keystrokes,num,player,sleeptime); mvaddstr(LINES - 2, 0, (char *)"replay completed"); endwin(); - my_exit(0); + games_exit(); } if ( keystrokes != 0 ) free(keystrokes); From 7604ee369749937957eb18958542dee377691973 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:01:32 -1100 Subject: [PATCH 017/385] Exit --- src/cc/dapps/dappstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 5c8fb0204..5f8821890 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -966,9 +966,9 @@ char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) void games_exit() { uint32_t counter; - resetltchars(); + //resetltchars(); if ( globalR.guiflag != 0 || globalR.sleeptime != 0 ) - exit(st); + exit(0); else if ( counter++ < 10 ) { fprintf(stderr,"would have exit.(%d) sleeptime.%d\n",st,globalR.sleeptime); From 62fc48877e96a4877de5d8ae12752221cdf4af30 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:05:19 -1100 Subject: [PATCH 018/385] -print --- src/cc/dapps/dappstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 5f8821890..b93e7b41d 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -971,7 +971,7 @@ void games_exit() exit(0); else if ( counter++ < 10 ) { - fprintf(stderr,"would have exit.(%d) sleeptime.%d\n",st,globalR.sleeptime); + fprintf(stderr,"would have exit sleeptime.%d\n",globalR.sleeptime); globalR.replaydone = 1; } } From 7b8adf33e196a8a3e3ba5d957796a980a13922cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:06:33 -1100 Subject: [PATCH 019/385] Gamesrngnext --- src/cc/gamescc.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index f62a8699c..367c8d96e 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -16,6 +16,21 @@ #include "gamescc.h" #include "tetris.c" // replace with game code + +uint64_t _games_rngnext(uint64_t initseed) +{ + uint16_t seeds[4]; int32_t i; + seeds[0] = initseed; + seeds[1] = (initseed >> 16); + seeds[2] = (initseed >> 32); + seeds[3] = (initseed >> 48); + seeds[0] = (seeds[0]*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[1] = ((seeds[0] ^ seeds[1])*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[2] = ((seeds[0] ^ seeds[1] ^ seeds[2])*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[3] = ((seeds[0] ^ seeds[1] ^ seeds[2] ^ seeds[3])*GAMES_RNGMULT + GAMES_RNGOFFSET); + return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); +} + #ifndef STANDALONE #include "tetris.cpp" // replace with game specific functions @@ -195,20 +210,6 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastf return(result); } -uint64_t _games_rngnext(uint64_t initseed) -{ - uint16_t seeds[4]; int32_t i; - seeds[0] = initseed; - seeds[1] = (initseed >> 16); - seeds[2] = (initseed >> 32); - seeds[3] = (initseed >> 48); - seeds[0] = (seeds[0]*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[1] = ((seeds[0] ^ seeds[1])*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[2] = ((seeds[0] ^ seeds[1] ^ seeds[2])*GAMES_RNGMULT + GAMES_RNGOFFSET); - seeds[3] = ((seeds[0] ^ seeds[1] ^ seeds[2] ^ seeds[3])*GAMES_RNGMULT + GAMES_RNGOFFSET); - return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); -} - UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result(UniValue::VOBJ); int32_t n; uint64_t seed; From fd3ded58bc46422389e95033d69f22779fa99ec9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:07:13 -1100 Subject: [PATCH 020/385] #define GAMES_RNGMULT 11109 #define GAMES_RNGOFFSET 13849 #define GAMES_MAXRNGS 10000 --- src/cc/gamescc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 07a1f8e65..6ec5dc9c4 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -3,6 +3,9 @@ #include #include +#define GAMES_RNGMULT 11109 +#define GAMES_RNGOFFSET 13849 +#define GAMES_MAXRNGS 10000 #ifndef STANDALONE @@ -22,9 +25,6 @@ std::string MYCCLIBNAME = (char *)"gamescc"; #define GAMES_REGISTRATIONSIZE (100 * 10000) #define GAMES_REGISTRATION 1 -#define GAMES_RNGMULT 11109 -#define GAMES_RNGOFFSET 13849 -#define GAMES_MAXRNGS 10000 #define MYCCNAME "games" From 4e9f443e4a20fa1cf635541c6f0b6886802c36fb Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Tue, 26 Mar 2019 21:09:24 +0800 Subject: [PATCH 021/385] fix minrelease recover transaction --- src/cc/rewards.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index db64127e7..2438b4035 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -257,9 +257,12 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t } if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) return eval->Invalid("txfee is too high"); + reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit); if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 && tx.vout[1].nValue == 10000 ) { - if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey ) + if ( reward == 0 ) + return eval->Invalid("unlock recover no rewards"); + else if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey ) return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey"); else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey ) return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey"); From 5330c2349980178a6236e6d32308ef4b4982573c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:23:50 -1100 Subject: [PATCH 022/385] Gamesiterate --- src/cc/tetris.c | 186 ++++++++++++++++++++++++------------------------ 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 1b039dc6f..1cc7962f5 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -638,13 +638,13 @@ void init_colors(void) */ #include "dapps/dappstd.c" -int32_t issue_games_events(struct games_state *rs,bits256 gametxid,uint32_t eventid,char c) +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,char c) { static FILE *fp; - char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; if ( fp == 0 ) fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c,gametxidstr,eventid); rs->buffered[rs->num++] = c; if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { @@ -685,15 +685,98 @@ char *clonestr(char *str) struct games_state globalR; +void gamesiterate(struct games_state *rs,tetris_game *tg) +{ + uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; + int32_t c,skipcount=0; uint32_t eventid = 0; + WINDOW *board, *next, *hold, *score; + // Create windows for each section of the interface. + board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); + next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); + hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); + score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); + while (running) + { + running = tg_tick(rs,tg, move); + display_board(board, tg); + display_piece(next, tg->next); + display_piece(hold, tg->stored); + display_score(score, tg); + if ( (counter++ % 5) == 0 ) + doupdate(); + sleep_milli(10); + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + if ( c < 0 || skipcount == 0x7f ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x80); + if ( c != -1 ) + issue_games_events(rs,Gametxidstr,eventid,c); + skipcount = 0; + } else skipcount++; + eventid++; + switch ( c ) + { + case 'h': + move = TM_LEFT; + break; + case 'l': + move = TM_RIGHT; + break; + case 'k': + move = TM_CLOCK; + break; + case 'j': + move = TM_DROP; + break; + case 'q': + running = false; + move = TM_NONE; + break; + /*case 'p': + wclear(board); + box(board, 0, 0); + wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); + wprintw(board, "PAUSED"); + wrefresh(board); + timeout(-1); + getch(); + timeout(0); + move = TM_NONE; + break; + case 's': + save(tg, board); + move = TM_NONE; + break;*/ + case ' ': + move = TM_HOLD; + break; + default: + move = TM_NONE; + } + } +} + int tetris(int argc, char **argv) { tetris_game *tg; - tetris_move move = TM_NONE; - bool running = true; - WINDOW *board, *next, *hold, *score; struct games_state *rs = &globalR; - int32_t c,skipcount=0; bits256 gametxid; uint32_t eventid = 0; - memset(&gametxid,0,sizeof(gametxid)); + int32_t c,skipcount=0; uint32_t eventid = 0; memset(rs,0,sizeof(*rs)); rs->guiflag = 1; rs->sleeptime = 1; // non-zero to allow refresh() @@ -741,88 +824,9 @@ int tetris(int argc, char **argv) curs_set(0); // set the cursor to invisible init_colors(); // setup tetris colors - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - int32_t counter = 0; // Game loop - while (running) { - running = tg_tick(rs,tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - if ( c < 0 || skipcount == 0x7f ) - { - if ( skipcount > 0 ) - issue_games_events(rs,gametxid,eventid-skipcount,skipcount | 0x80); - if ( c != -1 ) - issue_games_events(rs,gametxid,eventid,c); - skipcount = 0; - } else skipcount++; - eventid++; - switch ( c ) - { - case 'h': - move = TM_LEFT; - break; - case 'l': - move = TM_RIGHT; - break; - case 'k': - move = TM_CLOCK; - break; - case 'j': - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - /*case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break;*/ - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } - } - + gamesiterate(rs,tg); + games_bailout(rs); // Deinitialize NCurses wclear(stdscr); endwin(); @@ -835,9 +839,5 @@ int tetris(int argc, char **argv) return 0; } -void gamesiterate(struct games_state *rs) -{ - -} #endif From b0d0adb729531b32267a673e9a0f1a6dbd42eb04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:28:32 -1100 Subject: [PATCH 023/385] Gamesiterate --- src/cc/tetris.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 1cc7962f5..98e6a2fab 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -685,12 +685,13 @@ char *clonestr(char *str) struct games_state globalR; -void gamesiterate(struct games_state *rs,tetris_game *tg) +void gamesiterate(struct games_state *rs) { uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; - int32_t c,skipcount=0; uint32_t eventid = 0; + int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg; WINDOW *board, *next, *hold, *score; // Create windows for each section of the interface. + tg = tg_create(rs,22, 10); board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); @@ -774,7 +775,6 @@ void gamesiterate(struct games_state *rs,tetris_game *tg) int tetris(int argc, char **argv) { - tetris_game *tg; struct games_state *rs = &globalR; int32_t c,skipcount=0; uint32_t eventid = 0; memset(rs,0,sizeof(*rs)); @@ -813,7 +813,6 @@ int tetris(int argc, char **argv) // Otherwise create new game. tg = tg_create(rs,22, 10); }*/ - tg = tg_create(rs,22, 10); // NCURSES initialization: initscr(); // initialize curses @@ -825,7 +824,7 @@ int tetris(int argc, char **argv) init_colors(); // setup tetris colors // Game loop - gamesiterate(rs,tg); + gamesiterate(rs); games_bailout(rs); // Deinitialize NCurses wclear(stdscr); From a02e96bc3b1b1c62b6b1ec7006b7a2ae2f3ec0e9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:41:16 -1100 Subject: [PATCH 024/385] Free obj --- src/cc/dapps/dappstd.c | 15 ++++++++++----- src/cc/tetris.c | 21 +++++++++++---------- src/cc/tetris.h | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index b93e7b41d..1ab3e6427 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -24,7 +24,7 @@ #include extern struct games_state globalR; -void gamesiterate(struct games_state *rs); +void *gamesiterate(struct games_state *rs); char USERPASS[8192]; uint16_t GAMES_PORT; char Gametxidstr[67]; @@ -866,7 +866,7 @@ void games_bailout(struct games_state *rs) int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { - struct games_state *rs; FILE *fp; int32_t i,n; + struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; rs = (struct games_state *)calloc(1,sizeof(*rs)); rs->seed = seed; rs->keystrokes = keystrokes; @@ -882,7 +882,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu } globalR = *rs; uint32_t starttime = (uint32_t)time(NULL); - gamesiterate(rs); + ptr = gamesiterate(rs); if ( 0 ) { fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); @@ -909,8 +909,13 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu if ( newdata != 0 && rs->playersize > 0 ) memcpy(newdata,rs->playerdata,rs->playersize); }*/ - if ( newdata != 0 && rs->playersize > 0 ) - memcpy(newdata,rs->playerdata,rs->playersize); + if ( ptr != 0 ) + { + // extract data from ptr + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + free(ptr); + } n = rs->playersize; free(rs); return(n); diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 98e6a2fab..0f81971c4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -436,7 +436,7 @@ void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) // Initialization logic obj->rows = rows; obj->cols = cols; - obj->board = (char *)malloc(rows * cols); + //obj->board = (char *)malloc(rows * cols); memset(obj->board, TC_EMPTY, rows * cols); obj->points = 0; obj->level = 0; @@ -454,19 +454,19 @@ void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) tetris_game *tg_create(struct games_state *rs,int rows, int cols) { - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols); tg_init(rs,obj, rows, cols); return obj; } -void tg_destroy(tetris_game *obj) +/*void tg_destroy(tetris_game *obj) { // Cleanup logic free(obj->board); -} +}*/ void tg_delete(tetris_game *obj) { - tg_destroy(obj); + //tg_destroy(obj); free(obj); } @@ -591,7 +591,7 @@ void display_score(WINDOW *w, tetris_game *tg) /* Save and exit the game. - */ + void save(tetris_game *game, WINDOW *w) { FILE *f; @@ -614,7 +614,7 @@ void save(tetris_game *game, WINDOW *w) fprintf(stderr,"Game saved to \"tetris.save\".\n"); fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); exit(EXIT_SUCCESS); -} +}*/ /* Do the NCURSES initialization steps for color blocks. @@ -685,7 +685,7 @@ char *clonestr(char *str) struct games_state globalR; -void gamesiterate(struct games_state *rs) +void *gamesiterate(struct games_state *rs) { uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg; @@ -771,12 +771,13 @@ void gamesiterate(struct games_state *rs) move = TM_NONE; } } + return(tg); } int tetris(int argc, char **argv) { struct games_state *rs = &globalR; - int32_t c,skipcount=0; uint32_t eventid = 0; + int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0; memset(rs,0,sizeof(*rs)); rs->guiflag = 1; rs->sleeptime = 1; // non-zero to allow refresh() @@ -824,7 +825,7 @@ int tetris(int argc, char **argv) init_colors(); // setup tetris colors // Game loop - gamesiterate(rs); + tg = gamesiterate(rs); games_bailout(rs); // Deinitialize NCurses wclear(stdscr); diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 40a9c97cb..9fce377d7 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -97,7 +97,6 @@ typedef struct { */ int rows; int cols; - char *board; /* Scoring information: */ @@ -118,6 +117,7 @@ typedef struct { Number of lines until you advance to the next level. */ int lines_remaining; + char board[]; } tetris_game; /* From 44776662d087dd12d3e2d40a4f73adb0ff126ea3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:45:09 -1100 Subject: [PATCH 025/385] -load --- src/cc/tetris.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 0f81971c4..23d58e45c 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -472,7 +472,7 @@ void tg_delete(tetris_game *obj) { /* Load a game from a file. - */ + tetris_game *tg_load(FILE *f) { tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); @@ -494,18 +494,18 @@ tetris_game *tg_load(FILE *f) } } return obj; -} +}*/ /* Save a game to a file. - */ + void tg_save(tetris_game *obj, FILE *f) { if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) fprintf(stderr,"error writing tetrisgame\n"); else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) fprintf(stderr,"error writing board\n"); -} +}*/ /* Print a game board to a file. Really just for early debugging. From 6712caf91e3ae2cf1f013e689e419dc72cacdfa8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 02:46:10 -1100 Subject: [PATCH 026/385] Ptr --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 23d58e45c..305bf0c3b 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -825,7 +825,7 @@ int tetris(int argc, char **argv) init_colors(); // setup tetris colors // Game loop - tg = gamesiterate(rs); + tg = (tetris_game *)gamesiterate(rs); games_bailout(rs); // Deinitialize NCurses wclear(stdscr); From 6ba7bf538c81c86345fb41d70dfbed977b84aa69 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Tue, 26 Mar 2019 22:13:14 +0800 Subject: [PATCH 027/385] small fix --- src/cc/rewards.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 2438b4035..73f723453 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -258,10 +258,12 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) return eval->Invalid("txfee is too high"); reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit); - if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 && tx.vout[1].nValue == 10000 ) + if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) { if ( reward == 0 ) return eval->Invalid("unlock recover no rewards"); + else if ( tx.vout[1].nValue != 10000 ) + return eval->Invalid("wrong marker vour value"); else if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey ) return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey"); else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey ) From b7c8205870d3ada608abbf1d29acb67c43c0eb39 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:14:26 -1100 Subject: [PATCH 028/385] Origseed --- src/cc/dapps/dappstd.c | 65 ++++++++++++++++++++++++++++++--- src/cc/tetris.c | 82 +++++++++++++++++++++++++----------------- src/cc/tetris.h | 2 +- 3 files changed, 111 insertions(+), 38 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 1ab3e6427..f98a3af63 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -805,7 +805,7 @@ int32_t flushkeystrokes_local(struct games_state *rs,int32_t waitflag) #ifdef STANDALONE char fname[1024]; FILE *fp; int32_t i,retflag = -1; rs->counter++; - gamesfname(fname,rs->seed,rs->counter); + gamesfname(fname,rs->origseed,rs->counter); if ( (fp= fopen(fname,"wb")) != 0 ) { if ( fwrite(rs->buffered,1,rs->num,fp) == rs->num ) @@ -813,7 +813,7 @@ int32_t flushkeystrokes_local(struct games_state *rs,int32_t waitflag) rs->num = 0; retflag = 0; fclose(fp); - gamesfname(fname,rs->seed,rs->counter+1); + gamesfname(fname,rs->origseed,rs->counter+1); if ( (fp= fopen(fname,"wb")) != 0 ) // truncate next file fclose(fp); //fprintf(stderr,"savefile <- %s retflag.%d\n",fname,retflag); @@ -844,7 +844,7 @@ int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag) { if ( rs->num > 0 ) { - if ( games_progress(rs,waitflag,rs->seed,rs->buffered,rs->num) > 0 ) + if ( games_progress(rs,waitflag,rs->origseed,rs->buffered,rs->num) > 0 ) { flushkeystrokes_local(rs,waitflag); memset(rs->buffered,0,sizeof(rs->buffered)); @@ -868,7 +868,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; rs = (struct games_state *)calloc(1,sizeof(*rs)); - rs->seed = seed; + rs->seed = rs->origseed = seed; rs->keystrokes = keystrokes; rs->numkeys = num; rs->sleeptime = sleepmillis * 1000; @@ -891,7 +891,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu for (i=0; i<10000; i++) { memset(rs,0,sizeof(*rs)); - rs->seed = seed; + rs->seed = rs->origseed = seed; rs->keystrokes = keystrokes; rs->numkeys = num; rs->sleeptime = 0; @@ -1009,6 +1009,61 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) return(num); } +char games_readchar(struct rogue_state *rs) +{ + char c,ch = -1; + if ( rs != 0 && rs->guiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + c = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(c); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + if ( counter < 3 || (counter & 1) == 0 ) + return('y'); + else return(ESCAPE); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + ch = (char) getch(); + if (ch == 3) + { + _quit(); + return(27); + } + if ( rs != 0 && rs->guiflag != 0 ) + { + if ( rs->num < sizeof(rs->buffered) ) + { + rs->buffered[rs->num++] = ch; + if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) + { + rs->needflush = (uint32_t)time(NULL); + //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); + //sleep(3); + } + } else fprintf(stderr,"buffer filled without flushed\n"); + } + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) { char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 305bf0c3b..3047e0e55 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -696,40 +696,57 @@ void *gamesiterate(struct games_state *rs) next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - while (running) + while ( running != 0 ) { - running = tg_tick(rs,tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - c = getch(); - switch ( c ) + running = tg_tick(rs,tg,move); + if ( rs->guiflag != 0 ) { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; + display_board(board,tg); + display_piece(next,tg->next); + display_piece(hold,tg->stored); + display_score(score,tg); + if ( (counter++ % 5) == 0 ) + doupdate(); + sleep_milli(10); + c = games_readchar(rs); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + if ( c < 0 || skipcount == 0x7f ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x80); + if ( c != -1 ) + issue_games_events(rs,Gametxidstr,eventid,c); + skipcount = 0; + } else skipcount++; } - if ( c < 0 || skipcount == 0x7f ) + else { + if ( skipcount == 0 ) + { + c = games_readchar(rs); + if ( (c & 0x80) != 0 ) + { + skipcount = (c & 0x7f); + c = 'S'; + } + } if ( skipcount > 0 ) - issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x80); - if ( c != -1 ) - issue_games_events(rs,Gametxidstr,eventid,c); - skipcount = 0; - } else skipcount++; + skipcount--; + } eventid++; switch ( c ) { @@ -785,13 +802,14 @@ int tetris(int argc, char **argv) { #ifdef _WIN32 #ifdef _MSC_VER - rs->seed = _strtoui64(argv[1], NULL, 10); + rs->origseed = _strtoui64(argv[1], NULL, 10); #else - rs->seed = atol(argv[1]); // windows, but not MSVC + rs->origseed = atol(argv[1]); // windows, but not MSVC #endif // _MSC_VER #else - rs->seed = atol(argv[1]); // non-windows + rs->origseed = atol(argv[1]); // non-windows #endif // _WIN32 + rs->seed = rs->origseed; strcpy(Gametxidstr,argv[2]); fprintf(stderr,"setplayerdata\n"); if ( games_setplayerdata(rs,Gametxidstr) < 0 ) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 9fce377d7..317dad62b 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -182,7 +182,7 @@ struct games_player struct games_state { - uint64_t seed; + uint64_t seed,origseed; char *keystrokes,*keystrokeshex; uint32_t needflush,replaydone; int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; From 81263613bb334f39325a4c46bcae4b3cd8eceded Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:15:11 -1100 Subject: [PATCH 029/385] Games --- src/cc/dapps/dappstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index f98a3af63..714bcaf82 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -1009,7 +1009,7 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) return(num); } -char games_readchar(struct rogue_state *rs) +char games_readchar(struct games_state *rs) { char c,ch = -1; if ( rs != 0 && rs->guiflag == 0 ) From d223563eff2e4595e0fa11102d4b7c429b76ffa6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:16:36 -1100 Subject: [PATCH 030/385] Test --- src/cc/dapps/dappstd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 714bcaf82..0f3d8cc24 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -1035,16 +1035,14 @@ char games_readchar(struct games_state *rs) if ( rs->replaydone != 0 && counter++ < 3 ) fprintf(stderr,"replay finished but readchar called\n"); rs->replaydone = (uint32_t)time(NULL); - if ( counter < 3 || (counter & 1) == 0 ) - return('y'); - else return(ESCAPE); + return(0); } if ( rs == 0 || rs->guiflag != 0 ) { ch = (char) getch(); if (ch == 3) { - _quit(); + //_quit(); return(27); } if ( rs != 0 && rs->guiflag != 0 ) From 80085d9d390de918412418dff05e64121b55b8aa Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:38:25 -1100 Subject: [PATCH 031/385] Fund --- src/cc/gamescc.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/cc/gamescc.h | 2 ++ src/cc/tetris.c | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 367c8d96e..a361b43ba 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1443,5 +1443,42 @@ UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; std::vector opret; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049; + gamespk = GetUnspendable(cp,0); + mypk = pubkey2pk(Mypubkey()); + if ( amount > GAMES_TXFEE ) + { + if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) + { + mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,amount,gamespk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); + return(games_rawtxresult(result,rawtx,1)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","amount too small")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } + return(result); +} + #endif diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 6ec5dc9c4..a61b07564 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -33,6 +33,7 @@ std::string Games_pname; #define RPC_FUNCS \ { (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"rngnext", (char *)"seed", 1, 1, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"fund", (char *)"amount", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"players", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"games", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"pending", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ @@ -49,6 +50,7 @@ std::string Games_pname; bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 3047e0e55..fe042d28c 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -811,7 +811,7 @@ int tetris(int argc, char **argv) #endif // _WIN32 rs->seed = rs->origseed; strcpy(Gametxidstr,argv[2]); - fprintf(stderr,"setplayerdata\n"); + fprintf(stderr,"setplayerdata %s\n",Gametxidstr); if ( games_setplayerdata(rs,Gametxidstr) < 0 ) { fprintf(stderr,"invalid gametxid, or already started\n"); From 84023b1540678bd5bb3be354295ff6b2e58177b0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:40:55 -1100 Subject: [PATCH 032/385] Script --- src/cc/gamescc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index a361b43ba..41e571c15 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1446,8 +1446,8 @@ UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; std::vector opret; - if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; CScript opret; + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049; gamespk = GetUnspendable(cp,0); From e954ca48c7df58953263d5affaf1bd805686a795 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:42:56 -1100 Subject: [PATCH 033/385] Enable fund --- src/cc/gamescc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index a61b07564..e3bd15ea7 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -95,6 +95,8 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_extract(txfee,cp,params)); \ else if ( strcmp(method,"finish") == 0 ) \ return(games_finish(txfee,cp,params)); \ + else if ( strcmp(method,"fund") == 0 ) \ + return(games_fund(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 62731f9972a0a88c9b7702bbb7d4ca6bb833c6ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:44:39 -1100 Subject: [PATCH 034/385] params0 --- src/cc/gamescc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 41e571c15..9be6426ea 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1449,7 +1449,7 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; CScript opret; if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { - amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049; + amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; gamespk = GetUnspendable(cp,0); mypk = pubkey2pk(Mypubkey()); if ( amount > GAMES_TXFEE ) From fc3753d23b96782459aab4663a8543f6713b6a66 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:50:45 -1100 Subject: [PATCH 035/385] +print --- src/cc/gamescc.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 9be6426ea..5ac8fc5c7 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1457,6 +1457,11 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,amount,gamespk)); + { + char destaddr[64]; + GetScriptaddress(destaddr,mtx.vout[0].scriptPubKey); + fprintf(stderr,"destaddr.(%s) %d\n",destaddr,cp->evalcode); + } rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); return(games_rawtxresult(result,rawtx,1)); } From 00e6b83927e172ca8204778e800c4059d0bc9e8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:51:19 -1100 Subject: [PATCH 036/385] Fix --- src/cc/gamescc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 5ac8fc5c7..2f48a2c3c 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1456,7 +1456,8 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,amount,gamespk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); + if ( 0 ) { char destaddr[64]; GetScriptaddress(destaddr,mtx.vout[0].scriptPubKey); From f3c31104f7b62483bd1bfbe76e107a870128df34 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 03:51:35 -1100 Subject: [PATCH 037/385] Test --- src/cc/gamescc.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 2f48a2c3c..2f5c031c5 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1457,12 +1457,6 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); - if ( 0 ) - { - char destaddr[64]; - GetScriptaddress(destaddr,mtx.vout[0].scriptPubKey); - fprintf(stderr,"destaddr.(%s) %d\n",destaddr,cp->evalcode); - } rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); return(games_rawtxresult(result,rawtx,1)); } From 4b5da75d7da26636917cc757d3f01932505e96f4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:10:41 -1100 Subject: [PATCH 038/385] Fix gameloop --- src/cc/tetris.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index fe042d28c..d09116881 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -724,11 +724,11 @@ void *gamesiterate(struct games_state *rs) c = 'j'; break; } - if ( c < 0 || skipcount == 0x7f ) + if ( c >= 0 || skipcount == 0x7f ) { if ( skipcount > 0 ) issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x80); - if ( c != -1 ) + if ( c >= 0 ) issue_games_events(rs,Gametxidstr,eventid,c); skipcount = 0; } else skipcount++; From b4043bc6bb0c58cb6ee7d0cc33cdc1f2d5ac6bed Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:17:43 -1100 Subject: [PATCH 039/385] Scrub vals --- src/cc/dapps/dappstd.c | 15 +++++++++++++++ src/cc/tetris.c | 20 +++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 0f3d8cc24..267335b05 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -1040,6 +1040,21 @@ char games_readchar(struct games_state *rs) if ( rs == 0 || rs->guiflag != 0 ) { ch = (char) getch(); + switch ( ch ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } if (ch == 3) { //_quit(); diff --git a/src/cc/tetris.c b/src/cc/tetris.c index d09116881..5ddb10ca4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -299,9 +299,11 @@ static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move { switch (move) { case TM_LEFT: + fprintf(stderr,"LEFT "); tg_move(obj, -1); break; case TM_RIGHT: + fprintf(stderr,"RIGHT "); tg_move(obj, 1); break; case TM_DROP: @@ -644,8 +646,7 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; if ( fp == 0 ) fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c,gametxidstr,eventid); - rs->buffered[rs->num++] = c; + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -709,21 +710,6 @@ void *gamesiterate(struct games_state *rs) doupdate(); sleep_milli(10); c = games_readchar(rs); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } if ( c >= 0 || skipcount == 0x7f ) { if ( skipcount > 0 ) From 510689b9541daa870f0b136502ef663af755ab31 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:18:59 -1100 Subject: [PATCH 040/385] Necroses --- src/cc/dapps/dappstd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 267335b05..80b651b45 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -22,6 +22,7 @@ #include #include #include +#include extern struct games_state globalR; void *gamesiterate(struct games_state *rs); From aeba5e4b071ce0a470bd007f084a417d1572a607 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:20:20 -1100 Subject: [PATCH 041/385] Fetch --- src/cc/dapps/dappstd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 80b651b45..a5ef379db 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -22,7 +22,6 @@ #include #include #include -#include extern struct games_state globalR; void *gamesiterate(struct games_state *rs); @@ -1012,7 +1011,7 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) char games_readchar(struct games_state *rs) { - char c,ch = -1; + char ch = -1; int32_t c; if ( rs != 0 && rs->guiflag == 0 ) { static uint32_t counter; @@ -1040,8 +1039,8 @@ char games_readchar(struct games_state *rs) } if ( rs == 0 || rs->guiflag != 0 ) { - ch = (char) getch(); - switch ( ch ) + c = getch(); + switch ( c ) { case KEY_LEFT: c = 'h'; @@ -1056,6 +1055,7 @@ char games_readchar(struct games_state *rs) c = 'j'; break; } + ch = c; if (ch == 3) { //_quit(); @@ -1065,7 +1065,7 @@ char games_readchar(struct games_state *rs) { if ( rs->num < sizeof(rs->buffered) ) { - rs->buffered[rs->num++] = ch; + rs->buffered[rs->num++] = c; if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) { rs->needflush = (uint32_t)time(NULL); @@ -1075,7 +1075,7 @@ char games_readchar(struct games_state *rs) } else fprintf(stderr,"buffer filled without flushed\n"); } } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); + return(c); } int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) From e96b3bf96ae29acd188baa7f336313c8e48c9d9e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:34:08 -1100 Subject: [PATCH 042/385] Gamesevent --- src/cc/dapps/dappstd.c | 43 +++++++++++++++++++++++++----------------- src/cc/tetris.c | 18 +++++++++--------- src/cc/tetris.cpp | 6 +++--- src/cc/tetris.h | 8 +++++--- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index a5ef379db..05f4fe332 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -249,7 +249,7 @@ int32_t safecopy(char *dest,char *src,long len) //#endif int32_t games_replay(uint64_t seed,int32_t sleeptime); -char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter); +gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter); int GAMEMAIN(int argc, char **argv); @@ -735,9 +735,9 @@ int32_t games_sendrawtransaction(char *rawtx) return(retval); } -int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) +int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,gamesevent *keystrokes,int32_t num) { - char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx,*pastkeys,*keys; int32_t i,len,numpastkeys,retflag = -1; cJSON *retjson,*resobj; uint8_t *pastcmp; + char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx; int32_t i,len,retflag = -1; cJSON *retjson,*resobj; if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) { if ( rs->keystrokeshex != 0 ) @@ -757,9 +757,18 @@ int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,cha } free(rs->keystrokeshex), rs->keystrokeshex = 0; } + memset(hexstr,0,sizeof(hexstr)); for (i=0; iorigseed,rs->counter); if ( (fp= fopen(fname,"wb")) != 0 ) { - if ( fwrite(rs->buffered,1,rs->num,fp) == rs->num ) + if ( fwrite(rs->buffered,sizeof(*rs->buffered),rs->num,fp) == rs->num ) { rs->num = 0; retflag = 0; @@ -864,7 +873,7 @@ void games_bailout(struct games_state *rs) #endif #endif -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; rs = (struct games_state *)calloc(1,sizeof(*rs)); @@ -930,9 +939,9 @@ long get_filesize(FILE *fp) return(fsize); } -char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) +gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) { - char fname[1024],*keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; + char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; *numkeysp = 0; while ( 1 ) { @@ -946,7 +955,7 @@ char *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) //printf("fsize.%ld\n",fsize); break; } - if ( (keystrokes= (char *)realloc(keystrokes,num+fsize)) == 0 ) + if ( (keystrokes= (char *)realloc(keystrokes,sizeof(*keystrokes)*(num+fsize))) == 0 ) { fprintf(stderr,"error reallocating keystrokes\n"); fclose(fp); @@ -983,7 +992,7 @@ void games_exit() int32_t games_replay(uint64_t seed,int32_t sleeptime) { - FILE *fp; char fname[1024]; char *keystrokes = 0; long fsize; int32_t i,num=0,counter = 0; struct games_state *rs; struct games_player P,*player = 0; + FILE *fp; char fname[1024]; gamesevent *keystrokes = 0; long fsize; int32_t i,num=0,counter = 0; struct games_state *rs; struct games_player P,*player = 0; if ( seed == 0 ) seed = 777; keystrokes = games_keystrokesload(&num,seed,counter); @@ -1009,15 +1018,15 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) return(num); } -char games_readchar(struct games_state *rs) +gamesevent games_readevent(struct games_state *rs) { - char ch = -1; int32_t c; + gamesevent ch = -1; int32_t c; if ( rs != 0 && rs->guiflag == 0 ) { static uint32_t counter; if ( rs->ind < rs->numkeys ) { - c = rs->keystrokes[rs->ind++]; + ch = rs->keystrokes[rs->ind++]; if ( 0 ) { static FILE *fp; static int32_t counter; @@ -1030,7 +1039,7 @@ char games_readchar(struct games_state *rs) counter++; } } - return(c); + return(ch); } if ( rs->replaydone != 0 && counter++ < 3 ) fprintf(stderr,"replay finished but readchar called\n"); @@ -1065,7 +1074,7 @@ char games_readchar(struct games_state *rs) { if ( rs->num < sizeof(rs->buffered) ) { - rs->buffered[rs->num++] = c; + rs->buffered[rs->num++] = ch; if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) { rs->needflush = (uint32_t)time(NULL); @@ -1075,7 +1084,7 @@ char games_readchar(struct games_state *rs) } else fprintf(stderr,"buffer filled without flushed\n"); } } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(c); + return(ch); } int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 5ddb10ca4..048a701f5 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -640,13 +640,13 @@ void init_colors(void) */ #include "dapps/dappstd.c" -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,char c) +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,int16_t c) { static FILE *fp; char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; if ( fp == 0 ) fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -689,7 +689,7 @@ struct games_state globalR; void *gamesiterate(struct games_state *rs) { uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; - int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg; + gamesevent c; uint16_t skipcount=0; uint32_t eventid = 0; tetris_game *tg; WINDOW *board, *next, *hold, *score; // Create windows for each section of the interface. tg = tg_create(rs,22, 10); @@ -709,11 +709,11 @@ void *gamesiterate(struct games_state *rs) if ( (counter++ % 5) == 0 ) doupdate(); sleep_milli(10); - c = games_readchar(rs); - if ( c >= 0 || skipcount == 0x7f ) + c = games_readevent(rs); + if ( c >= 0 || skipcount == 0x3fff ) { if ( skipcount > 0 ) - issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x80); + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); if ( c >= 0 ) issue_games_events(rs,Gametxidstr,eventid,c); skipcount = 0; @@ -723,10 +723,10 @@ void *gamesiterate(struct games_state *rs) { if ( skipcount == 0 ) { - c = games_readchar(rs); - if ( (c & 0x80) != 0 ) + c = games_readevent(rs); + if ( (c & 0x4000) == 0x4000 ) { - skipcount = (c & 0x7f); + skipcount = (c & 0x3fff); c = 'S'; } } diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index f9e4e167a..a20652012 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -42,9 +42,9 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+33] << 8; eventid |= (uint32_t)payload[len+34] << 16; eventid |= (uint32_t)payload[len+35] << 24; - for (i=0; i Date: Tue, 26 Mar 2019 04:35:25 -1100 Subject: [PATCH 043/385] Gamesevent --- src/cc/dapps/dappstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 05f4fe332..55ffb33be 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -767,7 +767,7 @@ int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,gam else if ( sizeof(gamesevent) == 4 ) sprintf(&hexstr[i<<3],"%08x",keystrokes[i]&0xffffffff); else if ( sizeof(gamesevent) == 8 ) - sprintf(&hexstr[i<<4],"%016x",keystrokes[i]&0xffffffffffffffff); + sprintf(&hexstr[i<<4],"%016x",(long long)(keystrokes[i]&0xffffffffffffffffLL)); } static FILE *fp; if ( fp == 0 ) @@ -955,7 +955,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter //printf("fsize.%ld\n",fsize); break; } - if ( (keystrokes= (char *)realloc(keystrokes,sizeof(*keystrokes)*(num+fsize))) == 0 ) + if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*(num+fsize))) == 0 ) { fprintf(stderr,"error reallocating keystrokes\n"); fclose(fp); From 297794b25367e2140aa5700edc8c0bd2ded736d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:36:01 -1100 Subject: [PATCH 044/385] Llx --- src/cc/dapps/dappstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 55ffb33be..e120787bf 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -767,7 +767,7 @@ int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,gam else if ( sizeof(gamesevent) == 4 ) sprintf(&hexstr[i<<3],"%08x",keystrokes[i]&0xffffffff); else if ( sizeof(gamesevent) == 8 ) - sprintf(&hexstr[i<<4],"%016x",(long long)(keystrokes[i]&0xffffffffffffffffLL)); + sprintf(&hexstr[i<<4],"%016llx",(long long)(keystrokes[i]&0xffffffffffffffffLL)); } static FILE *fp; if ( fp == 0 ) From 4aed5b5b98c3a28924b7568d84cb803ee7c5a629 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 04:46:22 -1100 Subject: [PATCH 045/385] Uint check --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 048a701f5..6541d61e5 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -710,7 +710,7 @@ void *gamesiterate(struct games_state *rs) doupdate(); sleep_milli(10); c = games_readevent(rs); - if ( c >= 0 || skipcount == 0x3fff ) + if ( c <= 0x7f || skipcount == 0x3fff ) { if ( skipcount > 0 ) issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); From 0642013b11d5083ad953a88bfbecba447021fccc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:02:16 -1100 Subject: [PATCH 046/385] Skip -1 --- src/cc/dapps/dappstd.c | 4 ++-- src/cc/tetris.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index e120787bf..4bd116235 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -1070,7 +1070,7 @@ gamesevent games_readevent(struct games_state *rs) //_quit(); return(27); } - if ( rs != 0 && rs->guiflag != 0 ) + /*if ( rs != 0 && rs->guiflag != 0 ) { if ( rs->num < sizeof(rs->buffered) ) { @@ -1082,7 +1082,7 @@ gamesevent games_readevent(struct games_state *rs) //sleep(3); } } else fprintf(stderr,"buffer filled without flushed\n"); - } + }*/ } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); return(ch); } diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 6541d61e5..19aa0467b 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -640,13 +640,21 @@ void init_colors(void) */ #include "dapps/dappstd.c" -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,int16_t c) +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) { static FILE *fp; char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; if ( fp == 0 ) fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + rs->buffered[rs->num++] = c; + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) From bb97066b46ce6958b59a5df84eeced24070ded82 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:15:09 -1100 Subject: [PATCH 047/385] replay2 --- src/cc/dapps/dappstd.c | 57 ------------------------------------------ src/cc/gamescc.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ src/cc/tetris.cpp | 6 ++--- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 4bd116235..bac8cd50c 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -873,63 +873,6 @@ void games_bailout(struct games_state *rs) #endif #endif -int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) -{ - struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; - rs = (struct games_state *)calloc(1,sizeof(*rs)); - rs->seed = rs->origseed = seed; - rs->keystrokes = keystrokes; - rs->numkeys = num; - rs->sleeptime = sleepmillis * 1000; - if ( player != 0 ) - { - rs->P = *player; - rs->restoring = 1; - //fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints); - if ( rs->P.packsize > MAXPACK ) - rs->P.packsize = MAXPACK; - } - globalR = *rs; - uint32_t starttime = (uint32_t)time(NULL); - ptr = gamesiterate(rs); - if ( 0 ) - { - fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); - sleep(2); - starttime = (uint32_t)time(NULL); - for (i=0; i<10000; i++) - { - memset(rs,0,sizeof(*rs)); - rs->seed = rs->origseed = seed; - rs->keystrokes = keystrokes; - rs->numkeys = num; - rs->sleeptime = 0; - gamesiterate(rs); - } - fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime); - sleep(3); - } - // extract playerdata - - /*if ( (fp= fopen("checkfile","wb")) != 0 ) - { - //save_file(rs,fp,0); - //fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); - if ( newdata != 0 && rs->playersize > 0 ) - memcpy(newdata,rs->playerdata,rs->playersize); - }*/ - if ( ptr != 0 ) - { - // extract data from ptr - if ( newdata != 0 && rs->playersize > 0 ) - memcpy(newdata,rs->playerdata,rs->playersize); - free(ptr); - } - n = rs->playersize; - free(rs); - return(n); -} - long get_filesize(FILE *fp) { long fsize,fpos = ftell(fp); diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 2f5c031c5..31b33e2b5 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -31,6 +31,63 @@ uint64_t _games_rngnext(uint64_t initseed) return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); } +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) +{ + struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; + rs = (struct games_state *)calloc(1,sizeof(*rs)); + rs->seed = rs->origseed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = sleepmillis * 1000; + if ( player != 0 ) + { + rs->P = *player; + rs->restoring = 1; + //fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints); + if ( rs->P.packsize > MAXPACK ) + rs->P.packsize = MAXPACK; + } + globalR = *rs; + uint32_t starttime = (uint32_t)time(NULL); + ptr = gamesiterate(rs); + if ( 0 ) + { + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); + sleep(2); + starttime = (uint32_t)time(NULL); + for (i=0; i<10000; i++) + { + memset(rs,0,sizeof(*rs)); + rs->seed = rs->origseed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = 0; + gamesiterate(rs); + } + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime); + sleep(3); + } + // extract playerdata + + /*if ( (fp= fopen("checkfile","wb")) != 0 ) + { + //save_file(rs,fp,0); + //fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + }*/ + if ( ptr != 0 ) + { + // extract data from ptr + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + free(ptr); + } + n = rs->playersize; + free(rs); + return(n); +} + #ifndef STANDALONE #include "tetris.cpp" // replace with game specific functions diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index a20652012..6a1269099 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -20,15 +20,15 @@ uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 // game specific code for daemon -void games_packitemstr(char *packitemstr,struct games_packitem *item) +/*void games_packitemstr(char *packitemstr,struct games_packitem *item) { sprintf(packitemstr,"not yet"); } int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon { - return(-1); -} + return(0); +}*/ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { From 2ed6eccec62b8c459c88f0d3f3bedbf25dcfb9b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:16:46 -1100 Subject: [PATCH 048/385] Test --- src/cc/gamescc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 31b33e2b5..d5ec503c9 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -14,8 +14,6 @@ ******************************************************************************/ #include "gamescc.h" -#include "tetris.c" // replace with game code - uint64_t _games_rngnext(uint64_t initseed) { @@ -88,6 +86,9 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 return(n); } +#include "tetris.c" // replace with game code + + #ifndef STANDALONE #include "tetris.cpp" // replace with game specific functions From d61a4c44cf1f00a739dd5da7e74c4ee5ff571d86 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:17:56 -1100 Subject: [PATCH 049/385] Test --- src/cc/gamescc.cpp | 4 +--- src/cc/tetris.h | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index d5ec503c9..80f89332f 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -14,6 +14,7 @@ ******************************************************************************/ #include "gamescc.h" +#include "tetris.c" // replace with game code uint64_t _games_rngnext(uint64_t initseed) { @@ -86,9 +87,6 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 return(n); } -#include "tetris.c" // replace with game code - - #ifndef STANDALONE #include "tetris.cpp" // replace with game specific functions diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 3c246a3bd..b2f2fbe04 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -193,8 +193,10 @@ struct games_state gamesevent buffered[5000],*keystrokes; uint8_t playerdata[1024]; }; +extern struct games_state globalR; uint64_t _games_rngnext(uint64_t initseed); +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); #endif From 32851ac12aa85f2a599ac6b13791f75304051720 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:24:33 -1100 Subject: [PATCH 050/385] Baton support for games event --- src/cc/gamescc.cpp | 17 +++++++++++------ src/cc/tetris.h | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 80f89332f..227b3c5ae 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -848,9 +848,9 @@ int64_t games_registrationbaton(CMutableTransaction &mtx,uint256 gametxid,CTrans return(0); } -int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) +int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gamesevent **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) { - int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; + int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64]; gamesevent *keystrokes=0; batonvalue = numkeys = numplayers = batonht = 0; playertxid = batontxid = zeroid; if ( keystrokesp != 0 ) @@ -913,10 +913,15 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke uint256 g,b; CPubKey p; std::vector k; if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) { - keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); + keystrokes = (char *)realloc(keystrokes,sizeof(*keystrokes)*(numkeys + (int32_t)k.size())); for (i=0; i 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); char *method = (char *)"bailout"; - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index b2f2fbe04..94d56dbfc 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -194,7 +194,9 @@ struct games_state uint8_t playerdata[1024]; }; extern struct games_state globalR; +void *gamesiterate(struct games_state *rs); +void games_packitemstr(char *packitemstr,struct games_packitem *item); uint64_t _games_rngnext(uint64_t initseed); int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); From 985e8a71273f48f85a7f9246b11ef74f0c1263d7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:26:45 -1100 Subject: [PATCH 051/385] Test --- src/cc/gamescc.cpp | 1 + src/cc/tetris.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 227b3c5ae..7dc368d72 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -916,6 +916,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven keystrokes = (char *)realloc(keystrokes,sizeof(*keystrokes)*(numkeys + (int32_t)k.size())); for (i=0; i playerdata) } } -char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) +gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) { - CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; + CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64]; gamesevent *keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; gamespk = GetUnspendable(cp,0); *numkeysp = 0; seed = 0; @@ -110,7 +110,7 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto sprintf(fname,"%s.%llu.0",GAMENAME,(long long)seed); if ( (fp= fopen(fname,"wb")) != 0 ) { - if ( fwrite(keystrokes,1,numkeys,fp) != numkeys ) + if ( fwrite(keystrokes,sizeof(*keystrokes),numkeys,fp) != numkeys ) fprintf(stderr,"error writing %s\n",fname); fclose(fp); } From ce1a3197b2d933c7104dcfbf1abe7e617f82ebdf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:28:25 -1100 Subject: [PATCH 052/385] Test --- src/cc/tetris.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 2ef048364..216d4c4d0 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -14,7 +14,7 @@ * * ******************************************************************************/ -int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname); +int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gamesevent **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname); int32_t games_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0); uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr); @@ -169,7 +169,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; + char str[512],gamesaddr[64],str2[67],fname[64]; gamesevent *keystrokes; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; *cashoutp = 0; gamespk = GetUnspendable(cp,0); GetCCaddress1of2(cp,gamesaddr,gamespk,pk); From 6ce5d7f762bf9cc2115151b281695c42eb7ce9d2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:31:50 -1100 Subject: [PATCH 053/385] Hexer --- src/cc/gamescc.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 7dc368d72..0f261a184 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -913,7 +913,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven uint256 g,b; CPubKey p; std::vector k; if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) { - keystrokes = (char *)realloc(keystrokes,sizeof(*keystrokes)*(numkeys + (int32_t)k.size())); + keystrokes = (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*(numkeys + (int32_t)k.size())); for (i=0; i newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; + UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr; gamesevent *keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; pk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); result.push_back(Pair("name","games")); @@ -1263,10 +1263,25 @@ UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { result.push_back(Pair("status","success")); flag = 1; - hexstr = (char *)malloc(numkeys*2 + 1); + hexstr = (char *)calloc(1,sizeof(gamesevent)*numkeys*2 + 1); for (i=0; i Date: Tue, 26 Mar 2019 05:33:56 -1100 Subject: [PATCH 054/385] Link errors --- src/cc/tetris.c | 116 +++++++++++++++++++++++----------------------- src/cc/tetris.cpp | 4 +- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 19aa0467b..803d163fa 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -634,64 +634,6 @@ void init_colors(void) init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); } -#ifdef STANDALONE -/* - Main tetris game! - */ -#include "dapps/dappstd.c" - -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) -{ - static FILE *fp; - char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - rs->buffered[rs->num++] = c; - if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); - else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); - else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); - else if ( sizeof(c) == 8 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} - -char *clonestr(char *str) -{ - char *clone; int32_t len; - if ( str == 0 || str[0] == 0 ) - { - printf("warning cloning nullstr.%p\n",str); -#ifdef __APPLE__ - while ( 1 ) sleep(1); -#endif - str = (char *)""; - } - len = strlen(str); - clone = (char *)calloc(1,len+16); - strcpy(clone,str); - return(clone); -} - struct games_state globalR; void *gamesiterate(struct games_state *rs) @@ -785,6 +727,64 @@ void *gamesiterate(struct games_state *rs) return(tg); } +#ifdef STANDALONE +/* + Main tetris game! + */ +#include "dapps/dappstd.c" + +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); +} + +char *clonestr(char *str) +{ + char *clone; int32_t len; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + len = strlen(str); + clone = (char *)calloc(1,len+16); + strcpy(clone,str); + return(clone); +} + int tetris(int argc, char **argv) { struct games_state *rs = &globalR; diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 216d4c4d0..c2caaa8a9 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -19,12 +19,12 @@ int32_t games_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransa uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr); // game specific code for daemon - -/*void games_packitemstr(char *packitemstr,struct games_packitem *item) +void games_packitemstr(char *packitemstr,struct games_packitem *item) { sprintf(packitemstr,"not yet"); } +/* int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon { return(0); From a10f3988eeb975f9d7319e22e0fe812478bf89ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:35:58 -1100 Subject: [PATCH 055/385] Test --- src/cc/tetris.c | 71 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 803d163fa..f6a4974c4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -635,6 +635,43 @@ void init_colors(void) } struct games_state globalR; +gamesevent games_readevent(struct games_state *rs); +extern char Gametxidstr[]; + +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); +} void *gamesiterate(struct games_state *rs) { @@ -733,40 +770,6 @@ void *gamesiterate(struct games_state *rs) */ #include "dapps/dappstd.c" -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) -{ - static FILE *fp; - char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - rs->buffered[rs->num++] = c; - if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); - else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); - else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); - else if ( sizeof(c) == 8 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} char *clonestr(char *str) { From 38bf6a68951aaf878ad881eae0812c704a5cfd3e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:38:17 -1100 Subject: [PATCH 056/385] Fix --- src/cc/tetris.c | 74 +++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index f6a4974c4..3b330f5ca 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -635,43 +635,8 @@ void init_colors(void) } struct games_state globalR; -gamesevent games_readevent(struct games_state *rs); extern char Gametxidstr[]; - -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) -{ - static FILE *fp; - char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - rs->buffered[rs->num++] = c; - if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); - else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); - else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); - else if ( sizeof(c) == 8 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); void *gamesiterate(struct games_state *rs) { @@ -689,6 +654,7 @@ void *gamesiterate(struct games_state *rs) running = tg_tick(rs,tg,move); if ( rs->guiflag != 0 ) { +#ifdef STANDALONE display_board(board,tg); display_piece(next,tg->next); display_piece(hold,tg->stored); @@ -705,6 +671,7 @@ void *gamesiterate(struct games_state *rs) issue_games_events(rs,Gametxidstr,eventid,c); skipcount = 0; } else skipcount++; +#endif } else { @@ -788,6 +755,41 @@ char *clonestr(char *str) return(clone); } +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); +} + int tetris(int argc, char **argv) { struct games_state *rs = &globalR; From 82c132b6fbc6ea6f97f737626e7ea226ac362c24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:38:58 -1100 Subject: [PATCH 057/385] gamesevent games_readevent(struct games_state *rs) --- src/cc/tetris.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 3b330f5ca..487566ed4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -637,6 +637,7 @@ void init_colors(void) struct games_state globalR; extern char Gametxidstr[]; int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); +gamesevent games_readevent(struct games_state *rs); void *gamesiterate(struct games_state *rs) { From 8ba50f49c8d7981d7530a8d725305f6f8636c28c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:41:31 -1100 Subject: [PATCH 058/385] Test --- src/cc/dapps/dappstd.c | 69 ------------------------------------------ src/cc/gamescc.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index bac8cd50c..3992cb80e 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -961,75 +961,6 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) return(num); } -gamesevent games_readevent(struct games_state *rs) -{ - gamesevent ch = -1; int32_t c; - if ( rs != 0 && rs->guiflag == 0 ) - { - static uint32_t counter; - if ( rs->ind < rs->numkeys ) - { - ch = rs->keystrokes[rs->ind++]; - if ( 0 ) - { - static FILE *fp; static int32_t counter; - if ( fp == 0 ) - fp = fopen("log","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); - fflush(fp); - counter++; - } - } - return(ch); - } - if ( rs->replaydone != 0 && counter++ < 3 ) - fprintf(stderr,"replay finished but readchar called\n"); - rs->replaydone = (uint32_t)time(NULL); - return(0); - } - if ( rs == 0 || rs->guiflag != 0 ) - { - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - ch = c; - if (ch == 3) - { - //_quit(); - return(27); - } - /*if ( rs != 0 && rs->guiflag != 0 ) - { - if ( rs->num < sizeof(rs->buffered) ) - { - rs->buffered[rs->num++] = ch; - if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) - { - rs->needflush = (uint32_t)time(NULL); - //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); - //sleep(3); - } - } else fprintf(stderr,"buffer filled without flushed\n"); - }*/ - } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); -} - int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) { char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 0f261a184..b99c052ac 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -30,6 +30,75 @@ uint64_t _games_rngnext(uint64_t initseed) return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); } +gamesevent games_readevent(struct games_state *rs) +{ + gamesevent ch = -1; int32_t c; + if ( rs != 0 && rs->guiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + ch = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(ch); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + return(0); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + ch = c; + if (ch == 3) + { + //_quit(); + return(27); + } + /*if ( rs != 0 && rs->guiflag != 0 ) + { + if ( rs->num < sizeof(rs->buffered) ) + { + rs->buffered[rs->num++] = ch; + if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) + { + rs->needflush = (uint32_t)time(NULL); + //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); + //sleep(3); + } + } else fprintf(stderr,"buffer filled without flushed\n"); + }*/ + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; From e34fc6b5108521078b0c4d934044aafa91937129 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:43:30 -1100 Subject: [PATCH 059/385] Linker fix --- src/cc/gamescc.cpp | 138 ++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index b99c052ac..2746e8097 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -30,75 +30,6 @@ uint64_t _games_rngnext(uint64_t initseed) return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); } -gamesevent games_readevent(struct games_state *rs) -{ - gamesevent ch = -1; int32_t c; - if ( rs != 0 && rs->guiflag == 0 ) - { - static uint32_t counter; - if ( rs->ind < rs->numkeys ) - { - ch = rs->keystrokes[rs->ind++]; - if ( 0 ) - { - static FILE *fp; static int32_t counter; - if ( fp == 0 ) - fp = fopen("log","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); - fflush(fp); - counter++; - } - } - return(ch); - } - if ( rs->replaydone != 0 && counter++ < 3 ) - fprintf(stderr,"replay finished but readchar called\n"); - rs->replaydone = (uint32_t)time(NULL); - return(0); - } - if ( rs == 0 || rs->guiflag != 0 ) - { - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - ch = c; - if (ch == 3) - { - //_quit(); - return(27); - } - /*if ( rs != 0 && rs->guiflag != 0 ) - { - if ( rs->num < sizeof(rs->buffered) ) - { - rs->buffered[rs->num++] = ch; - if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) - { - rs->needflush = (uint32_t)time(NULL); - //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); - //sleep(3); - } - } else fprintf(stderr,"buffer filled without flushed\n"); - }*/ - } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); -} - int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; @@ -1628,3 +1559,72 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) #endif +gamesevent games_readevent(struct games_state *rs) +{ + gamesevent ch = -1; int32_t c; + if ( rs != 0 && rs->guiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + ch = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(ch); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + return(0); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + ch = c; + if (ch == 3) + { + //_quit(); + return(27); + } + /*if ( rs != 0 && rs->guiflag != 0 ) + { + if ( rs->num < sizeof(rs->buffered) ) + { + rs->buffered[rs->num++] = ch; + if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) + { + rs->needflush = (uint32_t)time(NULL); + //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); + //sleep(3); + } + } else fprintf(stderr,"buffer filled without flushed\n"); + }*/ + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + From e495123a5d5611b32d5cf7ed594e7a05f3ca9e81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:44:39 -1100 Subject: [PATCH 060/385] link --- src/cc/gamescc.cpp | 68 --------------------------------------------- src/cc/tetris.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 2746e8097..ad578400d 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1559,72 +1559,4 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) #endif -gamesevent games_readevent(struct games_state *rs) -{ - gamesevent ch = -1; int32_t c; - if ( rs != 0 && rs->guiflag == 0 ) - { - static uint32_t counter; - if ( rs->ind < rs->numkeys ) - { - ch = rs->keystrokes[rs->ind++]; - if ( 0 ) - { - static FILE *fp; static int32_t counter; - if ( fp == 0 ) - fp = fopen("log","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); - fflush(fp); - counter++; - } - } - return(ch); - } - if ( rs->replaydone != 0 && counter++ < 3 ) - fprintf(stderr,"replay finished but readchar called\n"); - rs->replaydone = (uint32_t)time(NULL); - return(0); - } - if ( rs == 0 || rs->guiflag != 0 ) - { - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - ch = c; - if (ch == 3) - { - //_quit(); - return(27); - } - /*if ( rs != 0 && rs->guiflag != 0 ) - { - if ( rs->num < sizeof(rs->buffered) ) - { - rs->buffered[rs->num++] = ch; - if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) - { - rs->needflush = (uint32_t)time(NULL); - //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); - //sleep(3); - } - } else fprintf(stderr,"buffer filled without flushed\n"); - }*/ - } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); -} diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 487566ed4..9808622f4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -732,6 +732,75 @@ void *gamesiterate(struct games_state *rs) return(tg); } +gamesevent games_readevent(struct games_state *rs) +{ + gamesevent ch = -1; int32_t c; + if ( rs != 0 && rs->guiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + ch = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(ch); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + return(0); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + ch = c; + if (ch == 3) + { + //_quit(); + return(27); + } + /*if ( rs != 0 && rs->guiflag != 0 ) + { + if ( rs->num < sizeof(rs->buffered) ) + { + rs->buffered[rs->num++] = ch; + if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) + { + rs->needflush = (uint32_t)time(NULL); + //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); + //sleep(3); + } + } else fprintf(stderr,"buffer filled without flushed\n"); + }*/ + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + #ifdef STANDALONE /* Main tetris game! From fd1ff16d471d38297bec4f0f23f217b20768a0f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:46:18 -1100 Subject: [PATCH 061/385] Test --- src/cc/rogue/cursesd.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cc/rogue/cursesd.h b/src/cc/rogue/cursesd.h index e3eec5d41..0b68bc307 100644 --- a/src/cc/rogue/cursesd.h +++ b/src/cc/rogue/cursesd.h @@ -16,6 +16,13 @@ #ifndef H_CURSESD_H #define H_CURSESD_H +#define KEY_OFFSET 0x100 +#define KEY_DOWN (KEY_OFFSET + 0x02) /* Down arrow key */ +#define KEY_UP (KEY_OFFSET + 0x03) /* Up arrow key */ +#define KEY_LEFT (KEY_OFFSET + 0x04) /* Left arrow key */ +#define KEY_RIGHT (KEY_OFFSET + 0x05) /* Right arrow key */ + + #define COLOR_BLACK 0 #ifdef PDC_RGB /* RGB */ From db01efa0221cd74add1802356ba7bdf514828d12 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:47:13 -1100 Subject: [PATCH 062/385] Readevent --- src/cc/gamescc.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++ src/cc/tetris.c | 69 ---------------------------------------------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index ad578400d..255866c86 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -30,6 +30,75 @@ uint64_t _games_rngnext(uint64_t initseed) return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); } +gamesevent games_readevent(struct games_state *rs) +{ + gamesevent ch = -1; int32_t c; + if ( rs != 0 && rs->guiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + ch = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(ch); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + return(0); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + ch = c; + if (ch == 3) + { + //_quit(); + return(27); + } + /*if ( rs != 0 && rs->guiflag != 0 ) + { + if ( rs->num < sizeof(rs->buffered) ) + { + rs->buffered[rs->num++] = ch; + if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) + { + rs->needflush = (uint32_t)time(NULL); + //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); + //sleep(3); + } + } else fprintf(stderr,"buffer filled without flushed\n"); + }*/ + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 9808622f4..487566ed4 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -732,75 +732,6 @@ void *gamesiterate(struct games_state *rs) return(tg); } -gamesevent games_readevent(struct games_state *rs) -{ - gamesevent ch = -1; int32_t c; - if ( rs != 0 && rs->guiflag == 0 ) - { - static uint32_t counter; - if ( rs->ind < rs->numkeys ) - { - ch = rs->keystrokes[rs->ind++]; - if ( 0 ) - { - static FILE *fp; static int32_t counter; - if ( fp == 0 ) - fp = fopen("log","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); - fflush(fp); - counter++; - } - } - return(ch); - } - if ( rs->replaydone != 0 && counter++ < 3 ) - fprintf(stderr,"replay finished but readchar called\n"); - rs->replaydone = (uint32_t)time(NULL); - return(0); - } - if ( rs == 0 || rs->guiflag != 0 ) - { - c = getch(); - switch ( c ) - { - case KEY_LEFT: - c = 'h'; - break; - case KEY_RIGHT: - c = 'l'; - break; - case KEY_UP: - c = 'k'; - break; - case KEY_DOWN: - c = 'j'; - break; - } - ch = c; - if (ch == 3) - { - //_quit(); - return(27); - } - /*if ( rs != 0 && rs->guiflag != 0 ) - { - if ( rs->num < sizeof(rs->buffered) ) - { - rs->buffered[rs->num++] = ch; - if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) - { - rs->needflush = (uint32_t)time(NULL); - //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); - //sleep(3); - } - } else fprintf(stderr,"buffer filled without flushed\n"); - }*/ - } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); - return(ch); -} - #ifdef STANDALONE /* Main tetris game! From 2fda05a5310a37b222e4f0c7731ddebbf5e511ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 05:57:58 -1100 Subject: [PATCH 063/385] Disable return0 --- src/cc/gamescc.cpp | 1 + src/cc/tetris.cpp | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 255866c86..442632c4e 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -102,6 +102,7 @@ gamesevent games_readevent(struct games_state *rs) int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; +return(0); rs = (struct games_state *)calloc(1,sizeof(*rs)); rs->seed = rs->origseed = seed; rs->keystrokes = keystrokes; diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index c2caaa8a9..1e0cb95d1 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -24,12 +24,6 @@ void games_packitemstr(char *packitemstr,struct games_packitem *item) sprintf(packitemstr,"not yet"); } -/* -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) // replay in daemon -{ - return(0); -}*/ - int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; From 21b50727bfe56f6e4ac43625046ccd6d965746f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:01:08 -1100 Subject: [PATCH 064/385] +print --- src/cc/gamescc.cpp | 18 +++++++++--------- src/cc/tetris.cpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 442632c4e..650c051b9 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -927,7 +927,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven *keystrokesp = 0; for (i=0; i= 0 ) { if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) @@ -946,17 +946,17 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven if ( matches == 1 ) { numvouts = matchtx.vout.size(); - //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); +fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); if ( games_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) { - //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); + fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); if ( tokenid != zeroid ) active = tokenid; else active = playertxid; if ( active == zeroid || games_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) { txid = matchtx.GetHash(); - //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); + fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); n = 0; while ( CCgettxout(txid,0,1,0) < 0 ) { @@ -973,7 +973,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven } } txid = spenttxid; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); if ( spentvini != 0 ) // game is over? { return(0); @@ -994,17 +994,17 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven } numkeys += (int32_t)k.size() / sizeof(gamesevent); (*keystrokesp) = keystrokes; - //fprintf(stderr,"updated keystrokes.%p[%d]\n",keystrokes,numkeys); + fprintf(stderr,"updated keystrokes.%p[%d]\n",keystrokes,numkeys); } } - //fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str()); + fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str()); if ( ++n >= GAMES_MAXITERATIONS ) { fprintf(stderr,"games_findbaton n.%d, seems something is wrong\n",n); return(-5); } } - //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); + fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); batontxid = txid; batonvout = 0; // not vini // how to detect timeout, bailedout, highlander @@ -1017,7 +1017,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven return(-4); else batonht = pindex->GetHeight(); batonvalue = batontx.vout[0].nValue; - //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); + printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); return(0); } else fprintf(stderr,"couldnt find baton\n"); } else fprintf(stderr,"error with playerdata\n"); diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 1e0cb95d1..a91157dde 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -90,7 +90,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: { UniValue obj; seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); + fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); memset(&P,0,sizeof(P)); if ( playerdata.size() > 0 ) { @@ -116,7 +116,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: fclose(fp); } } - //fprintf(stderr,"call replay2\n"); + fprintf(stderr,"call replay2\n"); num = games_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i no playerdata\n"); From 1c12ebcf34fe1d1046481122e944dd4e1ca2379f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:05:22 -1100 Subject: [PATCH 065/385] +print --- src/cc/gamescc.cpp | 19 ++++++++++--------- src/cc/tetris.cpp | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 650c051b9..8fa629b7f 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -927,7 +927,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven *keystrokesp = 0; for (i=0; i= 0 ) { if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) @@ -946,17 +946,17 @@ fprintf(stderr,"findbaton.%d of %d\n",i,maxplayers); if ( matches == 1 ) { numvouts = matchtx.vout.size(); -fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); +//fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); if ( games_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) { - fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); + //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); if ( tokenid != zeroid ) active = tokenid; else active = playertxid; if ( active == zeroid || games_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) { txid = matchtx.GetHash(); - fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); + //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); n = 0; while ( CCgettxout(txid,0,1,0) < 0 ) { @@ -973,9 +973,10 @@ fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex( } } txid = spenttxid; - fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); if ( spentvini != 0 ) // game is over? { + fprintf(stderr,"gameisover n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); return(0); } if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) @@ -994,17 +995,17 @@ fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex( } numkeys += (int32_t)k.size() / sizeof(gamesevent); (*keystrokesp) = keystrokes; - fprintf(stderr,"updated keystrokes.%p[%d]\n",keystrokes,numkeys); + //fprintf(stderr,"updated keystrokes.%p[%d]\n",keystrokes,numkeys); } } - fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str()); + //fprintf(stderr,"n.%d txid.%s\n",n,txid.GetHex().c_str()); if ( ++n >= GAMES_MAXITERATIONS ) { fprintf(stderr,"games_findbaton n.%d, seems something is wrong\n",n); return(-5); } } - fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); + //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); batontxid = txid; batonvout = 0; // not vini // how to detect timeout, bailedout, highlander @@ -1017,7 +1018,7 @@ fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex( return(-4); else batonht = pindex->GetHeight(); batonvalue = batontx.vout[0].nValue; - printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); + //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); return(0); } else fprintf(stderr,"couldnt find baton\n"); } else fprintf(stderr,"error with playerdata\n"); diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index a91157dde..1a55de005 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -89,6 +89,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) { UniValue obj; + fprintf(stderr,"got baton\n"); seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); memset(&P,0,sizeof(P)); From 33ba39090d1f82f9d11ffd2a999f6eded3732860 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:07:43 -1100 Subject: [PATCH 066/385] Test --- src/cc/gamescc.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 8fa629b7f..503eb17e3 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -984,18 +984,19 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven uint256 g,b; CPubKey p; std::vector k; if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) { - keystrokes = (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*(numkeys + (int32_t)k.size())); - for (i=0; i Date: Tue, 26 Mar 2019 06:14:00 -1100 Subject: [PATCH 067/385] Test --- src/cc/gamescc.cpp | 8 ++++---- src/cc/tetris.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 503eb17e3..1684e6a18 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -976,7 +976,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); if ( spentvini != 0 ) // game is over? { - fprintf(stderr,"gameisover n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); + //fprintf(stderr,"gameisover n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); return(0); } if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) @@ -984,7 +984,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gameseven uint256 g,b; CPubKey p; std::vector k; if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) { - fprintf(stderr,"update keystrokes.%p[%d]\n",keystrokes,numkeys); + //fprintf(stderr,"update keystrokes.%p[%d]\n",keystrokes,numkeys); keystrokes = (gamesevent *)realloc(keystrokes,(int32_t)(sizeof(*keystrokes)*numkeys + k.size())); for (i=0; i 0 ) { @@ -117,7 +117,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: fclose(fp); } } - fprintf(stderr,"call replay2\n"); + //fprintf(stderr,"call replay2\n"); num = games_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i no playerdata\n"); From 63cc12029754c0deac3f433a0af52404ad3cbf27 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:25:03 -1100 Subject: [PATCH 068/385] Replay --- src/cc/tetris.c | 25 ++++++++++++++----------- src/cc/tetris.cpp | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 487566ed4..6b63bb008 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -644,8 +644,19 @@ void *gamesiterate(struct games_state *rs) uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; gamesevent c; uint16_t skipcount=0; uint32_t eventid = 0; tetris_game *tg; WINDOW *board, *next, *hold, *score; - // Create windows for each section of the interface. + if ( rs->guiflag != 0 ) + { + // NCURSES initialization: + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + keypad(stdscr, TRUE); // allow arrow keys + timeout(0); // no blocking on getch() + curs_set(0); // set the cursor to invisible + init_colors(); // setup tetris colors + } tg = tg_create(rs,22, 10); + // Create windows for each section of the interface. board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); @@ -668,7 +679,7 @@ void *gamesiterate(struct games_state *rs) { if ( skipcount > 0 ) issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); - if ( c >= 0 ) + if ( c <= 0x7f ) issue_games_events(rs,Gametxidstr,eventid,c); skipcount = 0; } else skipcount++; @@ -679,6 +690,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); + fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); @@ -833,15 +845,6 @@ int tetris(int argc, char **argv) tg = tg_create(rs,22, 10); }*/ - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors - // Game loop tg = (tetris_game *)gamesiterate(rs); games_bailout(rs); diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 605c969ab..7f601bb56 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -91,7 +91,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: UniValue obj; //fprintf(stderr,"got baton\n"); seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); - fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); + //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); memset(&P,0,sizeof(P)); if ( playerdata.size() > 0 ) { From 73f31d4a2edf3b780088f2acff03ac356028b929 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:33:51 -1100 Subject: [PATCH 069/385] Keystrokes --- src/cc/dapps/dappstd.c | 10 +++++----- src/cc/tetris.c | 15 +++++++++------ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 3992cb80e..4f67f20e5 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -889,7 +889,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter while ( 1 ) { gamesfname(fname,seed,counter); - //printf("check (%s)\n",fname); + printf("check (%s)\n",fname); if ( (fp= fopen(fname,"rb")) == 0 ) break; if ( (fsize= get_filesize(fp)) <= 0 ) @@ -898,7 +898,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter //printf("fsize.%ld\n",fsize); break; } - if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*(num+fsize))) == 0 ) + if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*num+fsize))) == 0 ) { fprintf(stderr,"error reallocating keystrokes\n"); fclose(fp); @@ -912,9 +912,9 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter return(0); } fclose(fp); - num += fsize; + num += (int32_t)(fsize / sizeof(gamesevent)); counter++; - //fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); + fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); } *numkeysp = num; return(keystrokes); @@ -1097,7 +1097,7 @@ int main(int argc, char **argv) seed = atol(argv[1]); // non-windows #endif // _WIN32 - //fprintf(stderr,"replay %llu\n",(long long)seed); + fprintf(stderr,"replay %llu\n",(long long)seed); return(games_replay(seed,10)); } else diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 6b63bb008..5c3f742bb 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -810,7 +810,7 @@ int tetris(int argc, char **argv) memset(rs,0,sizeof(*rs)); rs->guiflag = 1; rs->sleeptime = 1; // non-zero to allow refresh() - if ( argc == 3 && strlen(argv[2]) == 64 ) + if ( argc >= 2 && strlen(argv[2]) == 64 ) { #ifdef _WIN32 #ifdef _MSC_VER @@ -822,12 +822,15 @@ int tetris(int argc, char **argv) rs->origseed = atol(argv[1]); // non-windows #endif // _WIN32 rs->seed = rs->origseed; - strcpy(Gametxidstr,argv[2]); - fprintf(stderr,"setplayerdata %s\n",Gametxidstr); - if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + if ( argc >= 3 ) { - fprintf(stderr,"invalid gametxid, or already started\n"); - return(-1); + strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata %s\n",Gametxidstr); + if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + { + fprintf(stderr,"invalid gametxid, or already started\n"); + return(-1); + } } } else rs->seed = 777; From 42b2c36f726b6f1941dc1a7fb320cf33cf04dd79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:34:30 -1100 Subject: [PATCH 070/385] Test --- src/cc/dapps/dappstd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 4f67f20e5..18f66ca58 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -898,7 +898,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter //printf("fsize.%ld\n",fsize); break; } - if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*num+fsize))) == 0 ) + if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*num+fsize)) == 0 ) { fprintf(stderr,"error reallocating keystrokes\n"); fclose(fp); From bd855221dfa67a79ac3b6c6c2545c355d5815684 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:36:47 -1100 Subject: [PATCH 071/385] Activate replay --- src/cc/dapps/dappstd.c | 5 +++-- src/cc/gamescc.cpp | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 18f66ca58..d8ed48b9b 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -886,10 +886,10 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter { char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; *numkeysp = 0; - while ( 1 ) + if ( 1 ) { gamesfname(fname,seed,counter); - printf("check (%s)\n",fname); + //printf("check (%s)\n",fname); if ( (fp= fopen(fname,"rb")) == 0 ) break; if ( (fsize= get_filesize(fp)) <= 0 ) @@ -939,6 +939,7 @@ int32_t games_replay(uint64_t seed,int32_t sleeptime) if ( seed == 0 ) seed = 777; keystrokes = games_keystrokesload(&num,seed,counter); + fprintf(stderr,"keystrokes.%p num.%d\n",keystrokes,num); if ( num > 0 ) { sprintf(fname,"%s.%llu.player",GAMENAME,(long long)seed); diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 1684e6a18..282b0051b 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -102,7 +102,6 @@ gamesevent games_readevent(struct games_state *rs) int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) { struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; -return(0); rs = (struct games_state *)calloc(1,sizeof(*rs)); rs->seed = rs->origseed = seed; rs->keystrokes = keystrokes; From 81170c2e29f845c254173ab83e7d9609665999ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:37:28 -1100 Subject: [PATCH 072/385] Break --- src/cc/dapps/dappstd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index d8ed48b9b..2b5900408 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -886,7 +886,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter { char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; *numkeysp = 0; - if ( 1 ) + while ( 1 ) { gamesfname(fname,seed,counter); //printf("check (%s)\n",fname); @@ -915,6 +915,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter num += (int32_t)(fsize / sizeof(gamesevent)); counter++; fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); + break; } *numkeysp = num; return(keystrokes); From b4a06f0cbc27d47eb441af5ac8791cfa0d4f2d0b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:39:26 -1100 Subject: [PATCH 073/385] Test --- src/cc/dapps/dappstd.c | 2 +- src/cc/rogue/cursesd.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 2b5900408..697e9f948 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -914,7 +914,7 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter fclose(fp); num += (int32_t)(fsize / sizeof(gamesevent)); counter++; - fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); + //fprintf(stderr,"loaded %ld from (%s) total %d\n",fsize,fname,num); break; } *numkeysp = num; diff --git a/src/cc/rogue/cursesd.h b/src/cc/rogue/cursesd.h index 0b68bc307..7dd83d435 100644 --- a/src/cc/rogue/cursesd.h +++ b/src/cc/rogue/cursesd.h @@ -175,6 +175,8 @@ char *unctrl(char c); #define leaveok(win,bf) 0 #define halfdelay(x) 0 #define nocbreak() 0 +#define cbreak() 0 +#define curs_set(x) 0 // for tetris #define init_pair(a,b,c) 0 From 5295446c978338d3eee62de4fabd001985b6d6cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 06:44:16 -1100 Subject: [PATCH 074/385] Revendian --- src/cc/dapps/dappstd.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 697e9f948..3653166cb 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -882,9 +882,21 @@ long get_filesize(FILE *fp) return(fsize); } +gamesevent revendian(gamesevent revx) +{ + gamesevent x = 0; + for (i=0; i>= 8; + } + return(x); +} + gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) { - char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t num = 0; + char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t i,num = 0; *numkeysp = 0; while ( 1 ) { @@ -911,6 +923,8 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter free(keystrokes); return(0); } + for (i=0; i Date: Tue, 26 Mar 2019 06:44:59 -1100 Subject: [PATCH 075/385] Switch --- src/cc/dapps/dappstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 3653166cb..9240c6404 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -884,11 +884,11 @@ long get_filesize(FILE *fp) gamesevent revendian(gamesevent revx) { - gamesevent x = 0; + int32_t i; gamesevent x = 0; for (i=0; i>= 8; } return(x); From 9df89f97fcccf72444b83e06bd6ea102572b9fd3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:01:15 -1100 Subject: [PATCH 076/385] +print --- src/cc/dapps/dappstd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 9240c6404..5961b5e7a 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -885,12 +885,10 @@ long get_filesize(FILE *fp) gamesevent revendian(gamesevent revx) { int32_t i; gamesevent x = 0; + fprintf(stderr,"%04x -> ",revx); for (i=0; i>= 8; - } + ((uint8_t *)&x)[i] = ((uint8_t *)&revx)[sizeof(gamesevent)-1-i]; + fprintf(stderr,"%04x\n",x); return(x); } From 15143c0129bb15824ab1c06f9b4d97319bf3617b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:02:35 -1100 Subject: [PATCH 077/385] Fix --- src/cc/dapps/dappstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 5961b5e7a..6ef4381e5 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -921,10 +921,10 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter free(keystrokes); return(0); } - for (i=0; i Date: Tue, 26 Mar 2019 07:09:02 -1100 Subject: [PATCH 078/385] display_board(board,tg); display_piece(next,tg->next); display_piece(hold,tg->stored); display_score(score,tg); if ( (counter++ % 5) == 0 ) doupdate(); --- src/cc/dapps/dappstd.c | 6 +++--- src/cc/tetris.c | 15 ++++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 6ef4381e5..eee51739b 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -885,10 +885,10 @@ long get_filesize(FILE *fp) gamesevent revendian(gamesevent revx) { int32_t i; gamesevent x = 0; - fprintf(stderr,"%04x -> ",revx); + //fprintf(stderr,"%04x -> ",revx); for (i=0; i 0 ) { sprintf(fname,"%s.%llu.player",GAMENAME,(long long)seed); diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 5c3f742bb..cb54ee261 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -299,11 +299,11 @@ static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move { switch (move) { case TM_LEFT: - fprintf(stderr,"LEFT "); + //fprintf(stderr,"LEFT "); tg_move(obj, -1); break; case TM_RIGHT: - fprintf(stderr,"RIGHT "); + //fprintf(stderr,"RIGHT "); tg_move(obj, 1); break; case TM_DROP: @@ -644,7 +644,7 @@ void *gamesiterate(struct games_state *rs) uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; gamesevent c; uint16_t skipcount=0; uint32_t eventid = 0; tetris_game *tg; WINDOW *board, *next, *hold, *score; - if ( rs->guiflag != 0 ) + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { // NCURSES initialization: initscr(); // initialize curses @@ -664,15 +664,18 @@ void *gamesiterate(struct games_state *rs) while ( running != 0 ) { running = tg_tick(rs,tg,move); - if ( rs->guiflag != 0 ) + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { -#ifdef STANDALONE display_board(board,tg); display_piece(next,tg->next); display_piece(hold,tg->stored); display_score(score,tg); if ( (counter++ % 5) == 0 ) doupdate(); + } + if ( rs->guiflag != 0 ) + { +#ifdef STANDALONE sleep_milli(10); c = games_readevent(rs); if ( c <= 0x7f || skipcount == 0x3fff ) @@ -687,6 +690,8 @@ void *gamesiterate(struct games_state *rs) } else { + if ( rs->sleeptime >= 1000 ) + sleep_milli(rs->sleeptime/1000); if ( skipcount == 0 ) { c = games_readevent(rs); From 140468d27dcba162144a60412f7015671ad2d7a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:10:36 -1100 Subject: [PATCH 079/385] -print --- src/cc/dapps/dappstd.c | 2 +- src/cc/tetris.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index eee51739b..9b44bc6a9 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -1112,7 +1112,7 @@ int main(int argc, char **argv) #endif // _WIN32 fprintf(stderr,"replay %llu\n",(long long)seed); - return(games_replay(seed,10)); + return(games_replay(seed,3)); } else { diff --git a/src/cc/tetris.c b/src/cc/tetris.c index cb54ee261..bd9a5526d 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -695,7 +695,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x\n",c); + //fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 2bcc183fb073c89dff6b9ca5e145ed0ba089a1ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:16:24 -1100 Subject: [PATCH 080/385] +print --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index bd9a5526d..cb54ee261 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -695,7 +695,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - //fprintf(stderr,"%04x\n",c); + fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From bd4bab770c09f227000b5641b03dcf07fd315dea Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:23:50 -1100 Subject: [PATCH 081/385] Dont flip --- src/cc/dapps/dappstd.c | 12 +----------- src/cc/gamescc.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 9b44bc6a9..764a569ac 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -882,16 +882,6 @@ long get_filesize(FILE *fp) return(fsize); } -gamesevent revendian(gamesevent revx) -{ - int32_t i; gamesevent x = 0; - //fprintf(stderr,"%04x -> ",revx); - for (i=0; i ",revx); + for (i=0; i Date: Tue, 26 Mar 2019 07:24:48 -1100 Subject: [PATCH 082/385] gamesevent games_revendian(gamesevent revx) --- src/cc/tetris.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 94d56dbfc..338eee3cb 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -199,6 +199,7 @@ void *gamesiterate(struct games_state *rs); void games_packitemstr(char *packitemstr,struct games_packitem *item); uint64_t _games_rngnext(uint64_t initseed); int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); +gamesevent games_revendian(gamesevent revx); #endif From 4799abb82dd0bcf86353a8eee3246599a458ce92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 07:27:08 -1100 Subject: [PATCH 083/385] -print --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index cb54ee261..bd9a5526d 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -695,7 +695,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x\n",c); + //fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 317b1a249829b6f4e400c295280c0af00731096e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:02:29 -1100 Subject: [PATCH 084/385] Tweaks --- src/cc/gamescc.cpp | 222 +++++++++++++++++++++++++++++++++++------ src/cc/gamescc.h | 12 ++- src/cc/rogue_rpc.cpp | 71 +++++++------ src/cc/tetris.c | 12 ++- src/cc/tetris.cpp | 232 ++++++------------------------------------- src/cc/tetris.h | 14 +-- 6 files changed, 288 insertions(+), 275 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index c01a89b69..063da9355 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -16,6 +16,9 @@ #include "gamescc.h" #include "tetris.c" // replace with game code +int32_t GAMEDATA(struct games_player *P,void *ptr); +void GAMEJSON(UniValue &obj,struct games_player *P); + uint64_t _games_rngnext(uint64_t initseed) { uint16_t seeds[4]; int32_t i; @@ -92,19 +95,6 @@ gamesevent games_readevent(struct games_state *rs) //_quit(); return(27); } - /*if ( rs != 0 && rs->guiflag != 0 ) - { - if ( rs->num < sizeof(rs->buffered) ) - { - rs->buffered[rs->num++] = ch; - if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 ) - { - rs->needflush = (uint32_t)time(NULL); - //fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered)); - //sleep(3); - } - } else fprintf(stderr,"buffer filled without flushed\n"); - }*/ } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); return(ch); } @@ -121,7 +111,6 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 { rs->P = *player; rs->restoring = 1; - //fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints); if ( rs->P.packsize > MAXPACK ) rs->P.packsize = MAXPACK; } @@ -150,14 +139,15 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 /*if ( (fp= fopen("checkfile","wb")) != 0 ) { //save_file(rs,fp,0); - //fprintf(stderr,"gold.%d hp.%d strength.%d/%d level.%d exp.%d dungeon.%d data[%d]\n",rs->P.gold,rs->P.hitpoints,rs->P.strength&0xffff,rs->P.strength>>16,rs->P.level,rs->P.experience,rs->P.dungeonlevel,rs->playersize); if ( newdata != 0 && rs->playersize > 0 ) memcpy(newdata,rs->playerdata,rs->playersize); }*/ if ( ptr != 0 ) { // extract data from ptr - if ( newdata != 0 && rs->playersize > 0 ) + if ( GAMEDATA(&rs->P,ptr) < 0 ) + memset(&rs->P,0,sizeof(rs->P)); + else if ( newdata != 0 && rs->playersize > 0 ) memcpy(newdata,rs->playerdata,rs->playersize); free(ptr); } @@ -695,7 +685,6 @@ UniValue games_playerobj(std::vector playerdata,uint256 playertxid,uint } datastr[i<<1] = 0; } - int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,pad; for (i=0; i playerdata,uint256 playertxid,uint free(datastr); } obj.push_back(Pair("pack",a)); - obj.push_back(Pair("packsize",(int64_t)P.packsize)); - obj.push_back(Pair("hitpoints",(int64_t)P.hitpoints)); - obj.push_back(Pair("strength",(int64_t)(P.strength&0xffff))); - obj.push_back(Pair("maxstrength",(int64_t)(P.strength>>16))); - obj.push_back(Pair("level",(int64_t)P.level)); - obj.push_back(Pair("experience",(int64_t)P.experience)); - obj.push_back(Pair("dungeonlevel",(int64_t)P.dungeonlevel)); + GAMEPLAYERJSON(obj,&P); obj.push_back(Pair("chain",symbol)); obj.push_back(Pair("pname",pname)); return(obj); @@ -834,6 +817,24 @@ int32_t games_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } +int64_t games_buyins(uint256 gametxid) +{ + int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + if ( spenttx.vout[0].nValue > GAMES_REGISTRATIONSIZE ) + buyins += (spenttx.vout[0].nValue - GAMES_REGISTRATIONSIZE); + } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"vout %d is unspent\n",vout); + } + return(buyins); +} + uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr) { CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; @@ -861,6 +862,7 @@ uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 obj.push_back(Pair("alive",games_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); obj.push_back(Pair("openslots",openslots)); obj.push_back(Pair("numplayers",numplayers)); + obj.push_back(Pair("buyins",ValueFromAmount(game_buyins(gametxid)))); } obj.push_back(Pair("maxplayers",maxplayers)); obj.push_back(Pair("buyin",ValueFromAmount(buyin))); @@ -885,6 +887,27 @@ UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } else return(cclib_error(result,"couldnt reparse params")); } +void disp_gamesplayerdata(std::vector playerdata) +{ + struct games_player P; int32_t i; char packitemstr[512],line[512]; + if ( playerdata.size() > 0 ) + { + for (i=0; i &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) +{ + CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64]; gamesevent *keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; + gamespk = GetUnspendable(cp,0); + *numkeysp = 0; + seed = 0; + num = numkeys = 0; + playertxid = zeroid; + str[0] = 0; + if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) + { + if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) + { + UniValue obj; + //fprintf(stderr,"got baton\n"); + seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); + //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); + memset(&P,0,sizeof(P)); + if ( playerdata.size() > 0 ) + { + for (i=0; i no playerdata\n"); + newdata.resize(0); + *numkeysp = numkeys; + return(keystrokes); + } + else + { + *numkeysp = numkeys; + return(keystrokes); + } + } else num = 0; + } + else + { + fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); + if ( keystrokes != 0 ) + free(keystrokes), keystrokes = 0; + } + } else fprintf(stderr,"extractgame: invalid game\n"); + //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); + return(0); +} + UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr; gamesevent *keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; @@ -1380,7 +1478,7 @@ UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) { //vin0 -> highlander vout from creategame TCBOO //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit @@ -1393,8 +1491,8 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // vout0 -> playerdata marker // vout0 -> 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); char *method = (char *)"bailout"; - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) @@ -1452,11 +1550,10 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) newdata[i] = player[i]; ((uint8_t *)&P)[i] = player[i]; } - if ( (P.gold <= 0 || P.hitpoints <= 0 || (P.strength&0xffff) <= 0 || P.level <= 0 || P.experience <= 0 || P.dungeonlevel <= 0) ) + if ( disp_gamesplayer(str,&P) < 0 ) { //fprintf(stderr,"zero value character was killed -> no playerdata\n"); newdata.resize(0); - //P.gold = (P.gold * 8) / 10; } else { @@ -1464,7 +1561,7 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); cashout = games_cashout(&P); - fprintf(stderr,"\nextracted $$$gold.%d -> %.8f GAME hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); + fprintf(stderr,"\ncashout %.8f extracted %s\n",(double)cashout/COIN,str); if ( funcid == 'H' && maxplayers > 1 ) { if ( P.amulet == 0 ) @@ -1474,7 +1571,7 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) else if ( games_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); } - cashout += numplayers * buyin; + cashout += games_buyins(gametxid);//numplayers * buyin; } if ( cashout > 0 ) { @@ -1516,6 +1613,16 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(games_finish(txfee,cp,params,"bailout")); +} + +UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(games_finish(txfee,cp,params,"highlander")); +} + UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey gamespk,mypk,pk; std::string symbol,pname; char coinaddr[64]; @@ -1638,6 +1745,59 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) +{ + static uint32_t good,bad; static uint256 prevgame; + char str[512],gamesaddr[64],str2[67],fname[64]; gamesevent *keystrokes; int32_t i,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; + *cashoutp = 0; + gamespk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,gamesaddr,gamespk,pk); + if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) + { + free(keystrokes); + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); + remove(fname); + for (i=0; ievalcode == EVAL_GAMES ) \ return(games_keystrokes(txfee,cp,params)); \ else if ( strcmp(method,"extract") == 0 ) \ return(games_extract(txfee,cp,params)); \ - else if ( strcmp(method,"finish") == 0 ) \ - return(games_finish(txfee,cp,params)); \ + else if ( strcmp(method,"bailout") == 0 ) \ + return(games_bailout(txfee,cp,params)); \ + else if ( strcmp(method,"highlander") == 0 ) \ + return(games_highlander(txfee,cp,params)); \ else if ( strcmp(method,"fund") == 0 ) \ return(games_fund(txfee,cp,params)); \ else \ diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index ee5f3d566..4b74e21b7 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -283,6 +283,24 @@ int32_t rogue_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } +int64_t rogue_buyins(uint256 gametxid) +{ + int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + if ( spenttx.vout[0].nValue > ROGUE_REGISTRATIONSIZE ) + buyins += (spenttx.vout[0].nValue - ROGUE_REGISTRATIONSIZE); + } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"vout %d is unspent\n",vout); + } + return(buyins); +} + int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) { uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey roguepk; uint64_t txfee = 10000; @@ -690,6 +708,7 @@ uint64_t rogue_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 obj.push_back(Pair("alive",rogue_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); obj.push_back(Pair("openslots",openslots)); obj.push_back(Pair("numplayers",numplayers)); + obj.push_back(Pair("buyins",ValueFromAmount(rogue_buyins(gametxid)))); } obj.push_back(Pair("maxplayers",maxplayers)); obj.push_back(Pair("buyin",ValueFromAmount(buyin))); @@ -1093,6 +1112,20 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +int64_t rogue_cashout(struct rogue_player *P) +{ + int32_t dungeonlevel; int64_t mult = 10; + if ( P->amulet != 0 ) + mult *= 5; + dungeonlevel = P->dungeonlevel; + if ( P->amulet != 0 && dungeonlevel < 26 ) + dungeonlevel = 26; + if ( dungeonlevel > 42 ) + dungeonlevel = 42; + cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; + return(cashout); +} + int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; @@ -1105,17 +1138,9 @@ int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct C free(keystrokes); sprintf(fname,"rogue.%llu.pack",(long long)seed); remove(fname); - for (i=0; i 42 ) - dungeonlevel = 42; - *cashoutp = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + *cashoutp = rogue_cashout(&P); if ( newdata == playerdata ) { if ( gametxid != prevgame ) @@ -1206,16 +1231,10 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param result.push_back(Pair("name","rogue")); result.push_back(Pair("method",method)); result.push_back(Pair("myrogueaddr",myrogueaddr)); + mult = 10; //100000; if ( strcmp(method,"bailout") == 0 ) - { funcid = 'Q'; - mult = 10; //100000; - } - else - { - funcid = 'H'; - mult = 20; //200000; - } + else funcid = 'H'; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n > 0 ) @@ -1264,13 +1283,10 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param cpTokens = CCinit(&tokensC, EVAL_TOKENS); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - if ( P.amulet != 0 ) - mult *= 5; - dungeonlevel = P.dungeonlevel; - if ( P.amulet != 0 && dungeonlevel < 26 ) - dungeonlevel = 26; - cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + cashout = rogue_cashout(&P); fprintf(stderr,"\nextracted $$$gold.%d -> %.8f ROGUE hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); + if ( komodo_nextheight() > 77777 && cashout > ROGUE_MAXCASHOUT ) + cashout = ROGUE_MAXCASHOUT; if ( funcid == 'H' && maxplayers > 1 ) { if ( P.amulet == 0 ) @@ -1280,12 +1296,11 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param else if ( rogue_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); } + cashout *= 2; cashout += numplayers * buyin; } if ( cashout > 0 ) { - if ( komodo_nextheight() > 77777 && cashout > ROGUE_MAXCASHOUT ) - cashout = ROGUE_MAXCASHOUT; if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,60,cp->unspendableCCaddr)) > cashout ) CCchange = (inputsum - cashout); else fprintf(stderr,"couldnt find enough utxos\n"); @@ -1598,13 +1613,13 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( enabled != 0 ) return eval->Invalid("mismatched playerdata"); } + if ( height > 777777 && cashout > ROGUE_MAXCASHOUT ) + cashout = ROGUE_MAXCASHOUT; if ( funcid == 'H' ) { cashout *= 2; - //cashout += numplayers * buyin; + cashout += rogue_buyins(gametxid); } - if ( height > 777777 && cashout > ROGUE_MAXCASHOUT ) - cashout = ROGUE_MAXCASHOUT; sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); if ( strcmp(laststr,cashstr) != 0 ) { diff --git a/src/cc/tetris.c b/src/cc/tetris.c index bd9a5526d..54ca3b953 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -7,12 +7,20 @@ also, the standalone game needs to support argv of seed gametxid, along with replay args */ -static int random_tetromino(struct games_state *rs) +int random_tetromino(struct games_state *rs) { rs->seed = _games_rngnext(rs->seed); return(rs->seed % NUM_TETROMINOS); } +int32_t tetrisdata(struct games_player *P,void *ptr) +{ + tetris_game *tg = ptr; + P->gold = tg->points; + P->dungeonlevel = tg->level; + return(0); +} + /***************************************************************************/ /** https://github.com/brenns10/tetris @file main.c @@ -676,7 +684,7 @@ void *gamesiterate(struct games_state *rs) if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep_milli(10); + sleep_milli(25); c = games_readevent(rs); if ( c <= 0x7f || skipcount == 0x3fff ) { diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 7f601bb56..e44b50925 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -14,14 +14,37 @@ * * ******************************************************************************/ -int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gamesevent **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname); -int32_t games_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0); -uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr); - // game specific code for daemon void games_packitemstr(char *packitemstr,struct games_packitem *item) { - sprintf(packitemstr,"not yet"); + sprintf(packitemstr,""); +} + +int64_t games_cashout(struct games_player *P) +{ + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; + cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; + return(cashout); +} + +void tetrisjson(UniValue &obj,struct games_player *P) +{ + obj.push_back(Pair("packsize",(int64_t)P->packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); + obj.push_back(Pair("level",(int64_t)P->level)); + obj.push_back(Pair("experience",(int64_t)P->experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); +} + +int32_t disp_gamesplayer(char *str,struct games_player *P) +{ + str[0] = 0; + if ( P->gold <= 0 || P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + return(-1); + sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); + return(0); } int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) @@ -43,205 +66,6 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay } else return(-1); } -int64_t games_cashout(struct games_player *P) -{ - int32_t dungeonlevel; int64_t mult=10,cashout = 0; - if ( P->amulet != 0 ) - mult *= 5; - dungeonlevel = P->dungeonlevel; - if ( P->amulet != 0 && dungeonlevel < 26 ) - dungeonlevel = 26; - cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; - return(cashout); -} - -void disp_gamesplayerdata(std::vector playerdata) -{ - struct games_player P; int32_t i; char packitemstr[512]; - if ( playerdata.size() > 0 ) - { - for (i=0; i>16,P.level,P.experience,P.dungeonlevel); - for (i=0; i &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) -{ - CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64]; gamesevent *keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; - gamespk = GetUnspendable(cp,0); - *numkeysp = 0; - seed = 0; - num = numkeys = 0; - playertxid = zeroid; - str[0] = 0; - if ( (err= games_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) - { - if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) - { - UniValue obj; - //fprintf(stderr,"got baton\n"); - seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i no playerdata\n"); - newdata.resize(0); - *numkeysp = numkeys; - return(keystrokes); - /* P.gold = (P.gold * 8) / 10; - if ( keystrokes != 0 ) - { - free(keystrokes); - keystrokes = 0; - *numkeysp = 0; - return(keystrokes); - }*/ - } - else - { - sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - //fprintf(stderr,"%s\n",str); - *numkeysp = numkeys; - return(keystrokes); - } - } else num = 0; - } - else - { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); - if ( keystrokes != 0 ) - free(keystrokes), keystrokes = 0; - } - } else fprintf(stderr,"extractgame: invalid game\n"); - //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); - return(0); -} - -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],gamesaddr[64],str2[67],fname[64]; gamesevent *keystrokes; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; - *cashoutp = 0; - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - free(keystrokes); - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - - for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); - } - *cashoutp = 0; - return(0); - } - } - if ( gametxid != prevgame ) - { - prevgame = gametxid; - bad++; - disp_gamesplayerdata(newdata); - disp_gamesplayerdata(playerdata); - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - } - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); - return(-1); -} - bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { return(true); diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 338eee3cb..79a1c2c3e 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -163,9 +163,12 @@ void tg_print(tetris_game *obj, FILE *f); * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ -#define GAMENAME "tetris" -#define GAMEMAIN tetris -#define CHAINNAME "GTEST" +#define GAMENAME "tetris" // name of executable +#define GAMEMAIN tetris // main program of game +#define GAMEJSON tetrisjson // displays game specific json +#define GAMEDATA tetrisdata // extracts data from game specific variables into games_state +#define CHAINNAME "GTEST" // -ac_name= +typedef uint16_t gamesevent; // can be 8, 16, 32, or 64 bits #define MAXPACK 23 struct games_packitem @@ -180,8 +183,6 @@ struct games_player struct games_packitem gamespack[MAXPACK]; }; -typedef uint16_t gamesevent; - struct games_state { uint64_t seed,origseed; @@ -191,7 +192,7 @@ struct games_state FILE *logfp; struct games_player P; gamesevent buffered[5000],*keystrokes; - uint8_t playerdata[1024]; + uint8_t playerdata[8192]; }; extern struct games_state globalR; void *gamesiterate(struct games_state *rs); @@ -200,6 +201,7 @@ void games_packitemstr(char *packitemstr,struct games_packitem *item); uint64_t _games_rngnext(uint64_t initseed); int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); gamesevent games_revendian(gamesevent revx); +int32_t disp_gamesplayer(char *str,struct games_player *P); #endif From ef1c722d2de8985d423c2ff17ca41ccd0c125490 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:04:11 -1100 Subject: [PATCH 085/385] Test --- src/cc/gamescc.cpp | 3 ++- src/cc/tetris.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 063da9355..6763b9033 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -17,7 +17,6 @@ #include "tetris.c" // replace with game code int32_t GAMEDATA(struct games_player *P,void *ptr); -void GAMEJSON(UniValue &obj,struct games_player *P); uint64_t _games_rngnext(uint64_t initseed) { @@ -160,6 +159,8 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 #include "tetris.cpp" // replace with game specific functions +void GAMEJSON(UniValue &obj,struct games_player *P); + /* ./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\" { diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 54ca3b953..dd142e036 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -15,7 +15,7 @@ int random_tetromino(struct games_state *rs) int32_t tetrisdata(struct games_player *P,void *ptr) { - tetris_game *tg = ptr; + tetris_game *tg = (tetris_game *)ptr; P->gold = tg->points; P->dungeonlevel = tg->level; return(0); From 1254c3ed5cbb7e3ad6e26c3d859956be2b723198 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:10:39 -1100 Subject: [PATCH 086/385] Test --- src/cc/gamescc.cpp | 14 +++++++------- src/cc/tetris.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 6763b9033..62d49c3dd 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -818,7 +818,7 @@ int32_t games_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } -int64_t games_buyins(uint256 gametxid) +int64_t games_buyins(uint256 gametxid,int32_t maxplayers) { int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; for (i=0; i playerdata) { - struct games_player P; int32_t i; char packitemstr[512],line[512]; + struct games_player P; int32_t i; char packitemstr[512],str[512]; if ( playerdata.size() > 0 ) { for (i=0; i 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64],str[512]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) @@ -1572,7 +1572,7 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,ch else if ( games_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); } - cashout += games_buyins(gametxid);//numplayers * buyin; + cashout += games_buyins(gametxid,maxplayers);//numplayers * buyin; } if ( cashout > 0 ) { @@ -1616,12 +1616,12 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,ch UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(games_finish(txfee,cp,params,"bailout")); + return(games_finish(txfee,cp,params,(char *)"bailout")); } UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(games_finish(txfee,cp,params,"highlander")); + return(games_finish(txfee,cp,params,(char *)"highlander")); } UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index e44b50925..a862e2a3f 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -17,7 +17,7 @@ // game specific code for daemon void games_packitemstr(char *packitemstr,struct games_packitem *item) { - sprintf(packitemstr,""); + strcpy(packitemstr,""); } int64_t games_cashout(struct games_player *P) From f1737210077500e3ebec693f8ab674fec799251c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:11:29 -1100 Subject: [PATCH 087/385] Test --- src/cc/tetris.cpp | 2 +- src/cc/tetris.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index a862e2a3f..a461d139e 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -27,7 +27,7 @@ int64_t games_cashout(struct games_player *P) return(cashout); } -void tetrisjson(UniValue &obj,struct games_player *P) +void tetrisplayerjson(UniValue &obj,struct games_player *P) { obj.push_back(Pair("packsize",(int64_t)P->packsize)); obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 79a1c2c3e..9d16a8e8b 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -165,7 +165,7 @@ void tg_print(tetris_game *obj, FILE *f); ******************************************************************************/ #define GAMENAME "tetris" // name of executable #define GAMEMAIN tetris // main program of game -#define GAMEJSON tetrisjson // displays game specific json +#define GAMEPLAYERJSON tetrisplayerjson // displays game specific json #define GAMEDATA tetrisdata // extracts data from game specific variables into games_state #define CHAINNAME "GTEST" // -ac_name= typedef uint16_t gamesevent; // can be 8, 16, 32, or 64 bits From 5abd8a92071773f5e85e7a33dfb2c587e0be71ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:19:43 -1100 Subject: [PATCH 088/385] test --- src/cc/tetris.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index dd142e036..3e2d4a24c 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -307,11 +307,11 @@ static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move { switch (move) { case TM_LEFT: - //fprintf(stderr,"LEFT "); + fprintf(stderr,"LEFT "); tg_move(obj, -1); break; case TM_RIGHT: - //fprintf(stderr,"RIGHT "); + fprintf(stderr,"RIGHT "); tg_move(obj, 1); break; case TM_DROP: @@ -459,7 +459,7 @@ void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) obj->stored.ori = 0; obj->stored.loc.row = 0; obj->next.loc.col = obj->cols/2 - 2; - printf("%d", obj->falling.loc.col); + //printf("%d", obj->falling.loc.col); } tetris_game *tg_create(struct games_state *rs,int rows, int cols) @@ -672,7 +672,7 @@ void *gamesiterate(struct games_state *rs) while ( running != 0 ) { running = tg_tick(rs,tg,move); - if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + if ( 0 && (rs->guiflag != 0 || rs->sleeptime != 0) ) { display_board(board,tg); display_piece(next,tg->next); @@ -703,7 +703,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - //fprintf(stderr,"%04x\n",c); + fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 701f7027f5c9252482850d68f25bfcd952c05cf6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:21:06 -1100 Subject: [PATCH 089/385] -flip --- src/cc/dapps/dappstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 764a569ac..925b8749a 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -913,8 +913,8 @@ gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter } fclose(fp); num += (int32_t)(fsize / sizeof(gamesevent)); - for (i=0; i Date: Tue, 26 Mar 2019 09:22:13 -1100 Subject: [PATCH 090/385] -print --- src/cc/tetris.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 3e2d4a24c..7db0e7fa0 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -307,11 +307,11 @@ static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move { switch (move) { case TM_LEFT: - fprintf(stderr,"LEFT "); + //fprintf(stderr,"LEFT "); tg_move(obj, -1); break; case TM_RIGHT: - fprintf(stderr,"RIGHT "); + //fprintf(stderr,"RIGHT "); tg_move(obj, 1); break; case TM_DROP: @@ -703,7 +703,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x\n",c); + //fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 250fe82e9c18dd63e433efad944c9e8ce81db9eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:23:50 -1100 Subject: [PATCH 091/385] Display --- src/cc/tetris.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 7db0e7fa0..e5a9be712 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -672,7 +672,7 @@ void *gamesiterate(struct games_state *rs) while ( running != 0 ) { running = tg_tick(rs,tg,move); - if ( 0 && (rs->guiflag != 0 || rs->sleeptime != 0) ) + if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) ) { display_board(board,tg); display_piece(next,tg->next); @@ -698,8 +698,8 @@ void *gamesiterate(struct games_state *rs) } else { - if ( rs->sleeptime >= 1000 ) - sleep_milli(rs->sleeptime/1000); + if ( rs->sleeptime != 0 ) + sleep_milli(1); if ( skipcount == 0 ) { c = games_readevent(rs); From 7c63b83176b25a0e14cdfae2ad5ebd6821fa69df Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:26:40 -1100 Subject: [PATCH 092/385] Test --- src/cc/tetris.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index e5a9be712..6308740e7 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -678,13 +678,13 @@ void *gamesiterate(struct games_state *rs) display_piece(next,tg->next); display_piece(hold,tg->stored); display_score(score,tg); - if ( (counter++ % 5) == 0 ) - doupdate(); } if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep_milli(25); + sleep_milli(15); + if ( (counter++ % 10) == 0 ) + doupdate(); c = games_readevent(rs); if ( c <= 0x7f || skipcount == 0x3fff ) { @@ -699,7 +699,11 @@ void *gamesiterate(struct games_state *rs) else { if ( rs->sleeptime != 0 ) + { sleep_milli(1); + if ( (counter++ % 20) == 0 ) + doupdate(); + } if ( skipcount == 0 ) { c = games_readevent(rs); From a29ad0f9bbbd478c15a296e8ef62ed2362061991 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:28:19 -1100 Subject: [PATCH 093/385] +print --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 6308740e7..852aecbc9 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -707,7 +707,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - //fprintf(stderr,"%04x\n",c); + fprintf(stderr,"%04x\n",c); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 0d7dbc3929e4462882aa1848dfea6860c96aed29 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:31:44 -1100 Subject: [PATCH 094/385] rs->replaydone --- src/cc/tetris.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 852aecbc9..3bf5b098a 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -698,6 +698,8 @@ void *gamesiterate(struct games_state *rs) } else { + if ( rs->replaydone != 0 ) + break; if ( rs->sleeptime != 0 ) { sleep_milli(1); @@ -707,7 +709,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x\n",c); + fprintf(stderr,"%04x score.%d level.%d\n",c,tg->score,tg->level); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From b8f944dfe9fa3dfdf03bde72e61f6a830b221682 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:32:24 -1100 Subject: [PATCH 095/385] Points --- src/cc/tetris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 3bf5b098a..97c35ecd9 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -709,7 +709,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x score.%d level.%d\n",c,tg->score,tg->level); + fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From d35bad65b5bc02bc60995acba09f88eb68ab079e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:35:18 -1100 Subject: [PATCH 096/385] Print --- src/cc/gamescc.cpp | 1 + src/cc/tetris.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 62d49c3dd..ce0b3e479 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -152,6 +152,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 } n = rs->playersize; free(rs); + fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); return(n); } diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 97c35ecd9..214145659 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -709,7 +709,7 @@ void *gamesiterate(struct games_state *rs) if ( skipcount == 0 ) { c = games_readevent(rs); - fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); + //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); if ( (c & 0x4000) == 0x4000 ) { skipcount = (c & 0x3fff); From 4b555126d5c5ca1163a15d2203cd10e2c54ca134 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:36:15 -1100 Subject: [PATCH 097/385] Test --- src/cc/gamescc.cpp | 1 - src/cc/tetris.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index ce0b3e479..62d49c3dd 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -152,7 +152,6 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 } n = rs->playersize; free(rs); - fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); return(n); } diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 214145659..0a613c0c9 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -18,6 +18,7 @@ int32_t tetrisdata(struct games_player *P,void *ptr) tetris_game *tg = (tetris_game *)ptr; P->gold = tg->points; P->dungeonlevel = tg->level; + fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); return(0); } From 91fcfefd16831bebce19239153294ed092222655 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:38:35 -1100 Subject: [PATCH 098/385] Test --- src/cc/tetris.c | 2 +- src/cc/tetris.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/tetris.c b/src/cc/tetris.c index 0a613c0c9..c507ec019 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -18,7 +18,7 @@ int32_t tetrisdata(struct games_player *P,void *ptr) tetris_game *tg = (tetris_game *)ptr; P->gold = tg->points; P->dungeonlevel = tg->level; - fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); + //fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); return(0); } diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index a461d139e..39e8f1a65 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -41,7 +41,7 @@ void tetrisplayerjson(UniValue &obj,struct games_player *P) int32_t disp_gamesplayer(char *str,struct games_player *P) { str[0] = 0; - if ( P->gold <= 0 || P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) return(-1); sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); return(0); From c2f90d6173669d602c7644c481508699b8695d5c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:41:47 -1100 Subject: [PATCH 099/385] Test --- src/cc/gamescc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 62d49c3dd..867c0a79b 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -151,6 +151,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 free(ptr); } n = rs->playersize; + fprintf(stderr,"gold.%d\n",rs->P.gold); sleep(3); free(rs); return(n); } @@ -1374,7 +1375,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: fclose(fp); } } - //fprintf(stderr,"call replay2\n"); + fprintf(stderr,"call replay2\n"); num = games_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i Date: Tue, 26 Mar 2019 09:44:32 -1100 Subject: [PATCH 100/385] Test --- src/cc/gamescc.cpp | 2 +- src/cc/tetris.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 867c0a79b..698890c57 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1375,7 +1375,6 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: fclose(fp); } } - fprintf(stderr,"call replay2\n"); num = games_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i no playerdata\n"); diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp index 39e8f1a65..8a52dcb37 100644 --- a/src/cc/tetris.cpp +++ b/src/cc/tetris.cpp @@ -41,8 +41,8 @@ void tetrisplayerjson(UniValue &obj,struct games_player *P) int32_t disp_gamesplayer(char *str,struct games_player *P) { str[0] = 0; - if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) - return(-1); + //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + // return(-1); sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); return(0); } From 67ba7536bdbed814b00041266fadaea2f3b7fb32 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:47:04 -1100 Subject: [PATCH 101/385] Test --- src/cc/gamescc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 698890c57..2c5668253 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -146,12 +146,13 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 // extract data from ptr if ( GAMEDATA(&rs->P,ptr) < 0 ) memset(&rs->P,0,sizeof(rs->P)); - else if ( newdata != 0 && rs->playersize > 0 ) + else rs->playersize = sizeof(rs->P); + if ( newdata != 0 && rs->playersize > 0 ) memcpy(newdata,rs->playerdata,rs->playersize); free(ptr); } n = rs->playersize; - fprintf(stderr,"gold.%d\n",rs->P.gold); sleep(3); + //fprintf(stderr,"gold.%d\n",rs->P.gold); sleep(3); free(rs); return(n); } From a43f0b65d4535cfd24f1db97547b7d954789d45b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:50:16 -1100 Subject: [PATCH 102/385] Test --- src/cc/dapps/dappstd.c | 2 +- src/cc/tetris.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 925b8749a..917045ed5 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -862,7 +862,7 @@ int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag) return(0); } -void games_bailout(struct games_state *rs) +void gamesbailout(struct games_state *rs) { flushkeystrokes(rs,1); } diff --git a/src/cc/tetris.c b/src/cc/tetris.c index c507ec019..cb89c0da0 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -651,7 +651,7 @@ gamesevent games_readevent(struct games_state *rs); void *gamesiterate(struct games_state *rs) { uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; - gamesevent c; uint16_t skipcount=0; uint32_t eventid = 0; tetris_game *tg; + gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg; WINDOW *board, *next, *hold, *score; if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { @@ -665,6 +665,7 @@ void *gamesiterate(struct games_state *rs) init_colors(); // setup tetris colors } tg = tg_create(rs,22, 10); + prevlevel = tg->level; // Create windows for each section of the interface. board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); @@ -693,6 +694,11 @@ void *gamesiterate(struct games_state *rs) issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); if ( c <= 0x7f ) issue_games_events(rs,Gametxidstr,eventid,c); + if ( tg->level != prevlevel ) + { + flushkeystrokes(rs,0); + prevlevel = tg->level; + } skipcount = 0; } else skipcount++; #endif @@ -870,7 +876,7 @@ int tetris(int argc, char **argv) // Game loop tg = (tetris_game *)gamesiterate(rs); - games_bailout(rs); + gamesbailout(rs); // Deinitialize NCurses wclear(stdscr); endwin(); From 8660a2eedc523474c9d47fe342c4389892b593b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:51:32 -1100 Subject: [PATCH 103/385] -print --- src/cc/gamescc.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 2c5668253..3e12a7010 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -146,9 +146,12 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 // extract data from ptr if ( GAMEDATA(&rs->P,ptr) < 0 ) memset(&rs->P,0,sizeof(rs->P)); - else rs->playersize = sizeof(rs->P); - if ( newdata != 0 && rs->playersize > 0 ) - memcpy(newdata,rs->playerdata,rs->playersize); + else + { + rs->playersize = sizeof(rs->P); + if ( newdata != 0 ) + memcpy(newdata,&rs->P,rs->playersize); + } free(ptr); } n = rs->playersize; @@ -1383,7 +1386,7 @@ gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std: newdata[i] = newplayer[i]; ((uint8_t *)&endP)[i] = newplayer[i]; } - fprintf(stderr,"newgold.%d\n",endP.gold); sleep(3); + //fprintf(stderr,"newgold.%d\n",endP.gold); sleep(3); if ( disp_gamesplayer(str,&endP) < 0 ) { sprintf(str,"zero value character -> no playerdata\n"); From 8a7a1da70f3773317c9e370d90e8957c0fc1e04b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 09:52:15 -1100 Subject: [PATCH 104/385] int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag) --- src/cc/tetris.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/tetris.h b/src/cc/tetris.h index 9d16a8e8b..c4cfb3b31 100644 --- a/src/cc/tetris.h +++ b/src/cc/tetris.h @@ -196,6 +196,7 @@ struct games_state }; extern struct games_state globalR; void *gamesiterate(struct games_state *rs); +int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag); void games_packitemstr(char *packitemstr,struct games_packitem *item); uint64_t _games_rngnext(uint64_t initseed); From 2e8573c0ec888a33a90abfd2a2cc72d311fde2d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 19:59:13 -1100 Subject: [PATCH 105/385] Fix rogue compile --- src/cc/gamescc.cpp | 13 +++---------- src/cc/rogue_rpc.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 3e12a7010..4e8660c18 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1510,15 +1510,8 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,ch result.push_back(Pair("method",method)); result.push_back(Pair("mygamesaddr",mygamesaddr)); if ( strcmp(method,"bailout") == 0 ) - { funcid = 'Q'; - //mult = 10; //100000; - } - else - { - funcid = 'H'; - //mult = 20; //200000; - } + else funcid = 'H'; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n > 0 ) @@ -1570,13 +1563,13 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,ch fprintf(stderr,"\ncashout %.8f extracted %s\n",(double)cashout/COIN,str); if ( funcid == 'H' && maxplayers > 1 ) { - if ( P.amulet == 0 ) + /*if ( P.amulet == 0 ) { if ( numplayers != maxplayers ) return(cclib_error(result,"numplayers != maxplayers")); else if ( games_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); - } + }*/ cashout += games_buyins(gametxid,maxplayers);//numplayers * buyin; } if ( cashout > 0 ) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 4b74e21b7..52323adbe 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -283,7 +283,7 @@ int32_t rogue_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } -int64_t rogue_buyins(uint256 gametxid) +int64_t rogue_buyins(uint256 gametxid,int32_t maxplayers) { int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; for (i=0; iamulet != 0 ) mult *= 5; dungeonlevel = P->dungeonlevel; @@ -1618,7 +1618,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( funcid == 'H' ) { cashout *= 2; - cashout += rogue_buyins(gametxid); + cashout += rogue_buyins(gametxid,maxplayers); } sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); if ( strcmp(laststr,cashstr) != 0 ) From 58215af9b0d138c1a0b87351958ec22541ae8ee4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:48:44 -1100 Subject: [PATCH 106/385] Make 4 cc libs --- src/cc/makecclib | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cc/makecclib b/src/cc/makecclib index adac757c3..3aded32e3 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,2 +1,8 @@ #!/bin/sh gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp + +gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp + +gcc -O3 -DBUILD_ROGUE -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o roguecc.so cclib.cpp + +gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp From 906cc5ccb4cd5e4aa9a059af87a78515ae5c683c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:49:59 -1100 Subject: [PATCH 107/385] -print --- src/cc/gamescc.cpp | 2 +- src/cc/tetris.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 4e8660c18..38396562e 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -546,7 +546,7 @@ void komodo_netevent(std::vector message) { if ( (rand() % 10) == 0 ) { - fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); + //fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); komodo_sendmessage(2,2,"events",message); } } diff --git a/src/cc/tetris.c b/src/cc/tetris.c index cb89c0da0..651b1018c 100644 --- a/src/cc/tetris.c +++ b/src/cc/tetris.c @@ -801,32 +801,35 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve if ( fp == 0 ) fp = fopen("events.log","wb"); rs->buffered[rs->num++] = c; - if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); - else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); - else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); - else if ( sizeof(c) == 8 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + if ( 0 ) { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + if ( (retjson= cJSON_Parse(retstr)) != 0 ) { - retval = 0; - if ( fp != 0 ) + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); + } else return(0); } int tetris(int argc, char **argv) From 3da4f521dc060c6a0275b4c9ff49f9aeeb74f5e8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:50:51 -1100 Subject: [PATCH 108/385] Add apps to makecclib --- src/cc/makecclib | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cc/makecclib b/src/cc/makecclib index 3aded32e3..d9a5f2a82 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -6,3 +6,6 @@ gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include gcc -O3 -DBUILD_ROGUE -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o roguecc.so cclib.cpp gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp + +./maketetris +make -f Makefile_rogue From 1e6630620c9db3ae2cd34cbf5fc6a721cba9b499 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:52:41 -1100 Subject: [PATCH 109/385] Fix --- src/cc/makecclib | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index d9a5f2a82..8db8514cd 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -8,4 +8,5 @@ gcc -O3 -DBUILD_ROGUE -std=c++11 -I../secp256k1/include -I../univalue/include -I gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp ./maketetris -make -f Makefile_rogue + +cd rogue; make; cd .. From 8a208a02c794571f8a65829c3c718a2626345b8b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:54:08 -1100 Subject: [PATCH 110/385] Make rogue --- src/cc/makecclib | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index 8db8514cd..e64934d31 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -8,5 +8,4 @@ gcc -O3 -DBUILD_ROGUE -std=c++11 -I../secp256k1/include -I../univalue/include -I gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp ./maketetris - -cd rogue; make; cd .. +./makerogue From 119decca6f464a9b4ecc22b8188593e4242338a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 21:56:35 -1100 Subject: [PATCH 111/385] Fix --- src/cc/makecclib | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index e64934d31..6a1908829 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,11 +1,12 @@ #!/bin/sh +rm *.so rogue/rogue tetris + gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp - -gcc -O3 -DBUILD_ROGUE -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o roguecc.so cclib.cpp +./maketetris gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp -./maketetris +make -f Makefile_rogue ./makerogue From 329b7437640fcb17908a861525c2bb075cca5693 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 22:02:53 -1100 Subject: [PATCH 112/385] +prints --- src/cc/makecclib | 9 +++++++-- src/cc/rogue_rpc.cpp | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index 6a1908829..35b4a9d8d 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,12 +1,17 @@ #!/bin/sh rm *.so rogue/rogue tetris +echo rogue +make -f Makefile_rogue +./makerogue + +echo sudoku/musig/dilithium gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp +echo games tetris gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp ./maketetris +echo customcc stub gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp -make -f Makefile_rogue -./makerogue diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 52323adbe..5040c34d3 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1341,12 +1341,12 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue rogue_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(rogue_finishgame(txfee,cp,params,"bailout")); + return(rogue_finishgame(txfee,cp,params,(char *)"bailout")); } UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(rogue_finishgame(txfee,cp,params,"highlander")); + return(rogue_finishgame(txfee,cp,params,(char *)"highlander")); } UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) From 3640e3c4fcb67981ca8c440fb72a9dc2ecc5608a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 22:28:18 -1100 Subject: [PATCH 113/385] Prices example --- src/cc/gamescc.cpp | 13 +- src/cc/makecclib | 4 + src/cc/prices.c | 896 +++++++++++++++++++++++++++++++++++++++++++++ src/cc/prices.cpp | 463 +++-------------------- src/cc/prices.h | 208 +++++++++++ 5 files changed, 1159 insertions(+), 425 deletions(-) create mode 100644 src/cc/prices.c create mode 100644 src/cc/prices.h diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 38396562e..f010ac282 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -14,7 +14,11 @@ ******************************************************************************/ #include "gamescc.h" -#include "tetris.c" // replace with game code +#ifdef BUILD_PRICES +#include "prices.c" +#elif +#include "tetris.c" +#endif int32_t GAMEDATA(struct games_player *P,void *ptr); @@ -161,8 +165,11 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 } #ifndef STANDALONE - -#include "tetris.cpp" // replace with game specific functions +#ifdef BUILD_PRICES +#include "prices.cpp" +#elif +#include "tetris.cpp" +#endif void GAMEJSON(UniValue &obj,struct games_player *P); diff --git a/src/cc/makecclib b/src/cc/makecclib index 35b4a9d8d..38634aa78 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -12,6 +12,10 @@ echo games tetris gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp ./maketetris +echo games prices +gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp +./makeprices + echo customcc stub gcc -O3 -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o customcc.so cclib.cpp diff --git a/src/cc/prices.c b/src/cc/prices.c new file mode 100644 index 000000000..651b1018c --- /dev/null +++ b/src/cc/prices.c @@ -0,0 +1,896 @@ + +#include "tetris.h" + +/* + In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. + + also, the standalone game needs to support argv of seed gametxid, along with replay args + */ + +int random_tetromino(struct games_state *rs) +{ + rs->seed = _games_rngnext(rs->seed); + return(rs->seed % NUM_TETROMINOS); +} + +int32_t tetrisdata(struct games_player *P,void *ptr) +{ + tetris_game *tg = (tetris_game *)ptr; + P->gold = tg->points; + P->dungeonlevel = tg->level; + //fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); + return(0); +} + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + + +#include // for FILE +#include // for bool +#include +#include +#include +#include +#include +#include + +#ifdef BUILD_GAMESCC +#include "rogue/cursesd.h" +#else +#include +#endif + + +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +/******************************************************************************* + Array Definitions + *******************************************************************************/ + +const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = +{ + // I + {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, + {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, + {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, + {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, + // J + {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, + {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, + // L + {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, + {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, + // O + {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, + // S + {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, + {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, + {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, + // T + {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, + // Z + {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, + {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, +}; + +const int GRAVITY_LEVEL[MAX_LEVEL+1] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 +}; + +/******************************************************************************* + Helper Functions for Blocks + *******************************************************************************/ + +void sleep_milli(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = milliseconds * 1000 * 1000; + nanosleep(&ts, NULL); +} + +/* + Return the block at the given row and column. + */ +char tg_get(tetris_game *obj, int row, int column) +{ + return obj->board[obj->cols * row + column]; +} + +/* + Set the block at the given row and column. + */ +static void tg_set(tetris_game *obj, int row, int column, char value) +{ + obj->board[obj->cols * row + column] = value; +} + +/* + Check whether a row and column are in bounds. + */ +bool tg_check(tetris_game *obj, int row, int col) +{ + return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; +} + +/* + Place a block onto the board. + */ +static void tg_put(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, + TYPE_TO_CELL(block.typ)); + } +} + +/* + Clear a block out of the board. + */ +static void tg_remove(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); + } +} + +/* + Check if a block can be placed on the board. + */ +static bool tg_fits(tetris_game *obj, tetris_block block) +{ + int i, r, c; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + r = block.loc.row + cell.row; + c = block.loc.col + cell.col; + if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { + return false; + } + } + return true; +} + +/* + Create a new falling block and populate the next falling block with a random + one. + */ +static void tg_new_falling(struct games_state *rs,tetris_game *obj) +{ + // Put in a new falling tetromino. + obj->falling = obj->next; + obj->next.typ = random_tetromino(rs); + obj->next.ori = 0; + obj->next.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; +} + +/******************************************************************************* + Game Turn Helpers + *******************************************************************************/ + +/* + Tick gravity, and move the block down if gravity should act. + */ +static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj) +{ + obj->ticks_till_gravity--; + if (obj->ticks_till_gravity <= 0) { + tg_remove(obj, obj->falling); + obj->falling.loc.row++; + if (tg_fits(obj, obj->falling)) { + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + } else { + obj->falling.loc.row--; + tg_put(obj, obj->falling); + + tg_new_falling(rs,obj); + } + tg_put(obj, obj->falling); + } +} + +/* + Move the falling tetris block left (-1) or right (+1). + */ +static void tg_move(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + obj->falling.loc.col += direction; + if (!tg_fits(obj, obj->falling)) { + obj->falling.loc.col -= direction; + } + tg_put(obj, obj->falling); +} + +/* + Send the falling tetris block to the bottom. + */ +static void tg_down(struct games_state *rs,tetris_game *obj) +{ + tg_remove(obj, obj->falling); + while (tg_fits(obj, obj->falling)) { + obj->falling.loc.row++; + } + obj->falling.loc.row--; + tg_put(obj, obj->falling); + tg_new_falling(rs,obj); +} + +/* + Rotate the falling block in either direction (+/-1). + */ +static void tg_rotate(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + + while (true) { + obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; + + // If the new orientation fits, we're done. + if (tg_fits(obj, obj->falling)) + break; + + // Otherwise, try moving left to make it fit. + obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) + break; + + // Finally, try moving right to make it fit. + obj->falling.loc.col += 2; + if (tg_fits(obj, obj->falling)) + break; + + // Put it back in its original location and try the next orientation. + obj->falling.loc.col--; + // Worst case, we come back to the original orientation and it fits, so this + // loop will terminate. + } + + tg_put(obj, obj->falling); +} + +/* + Swap the falling block with the block in the hold buffer. + */ +static void tg_hold(struct games_state *rs,tetris_game *obj) +{ + tg_remove(obj, obj->falling); + if (obj->stored.typ == -1) { + obj->stored = obj->falling; + tg_new_falling(rs,obj); + } else { + int typ = obj->falling.typ, ori = obj->falling.ori; + obj->falling.typ = obj->stored.typ; + obj->falling.ori = obj->stored.ori; + obj->stored.typ = typ; + obj->stored.ori = ori; + while (!tg_fits(obj, obj->falling)) { + obj->falling.loc.row--; + } + } + tg_put(obj, obj->falling); +} + +/* + Perform the action specified by the move. + */ +static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move) +{ + switch (move) { + case TM_LEFT: + //fprintf(stderr,"LEFT "); + tg_move(obj, -1); + break; + case TM_RIGHT: + //fprintf(stderr,"RIGHT "); + tg_move(obj, 1); + break; + case TM_DROP: + tg_down(rs,obj); + break; + case TM_CLOCK: + tg_rotate(obj, 1); + break; + case TM_COUNTER: + tg_rotate(obj, -1); + break; + case TM_HOLD: + tg_hold(rs,obj); + break; + default: + // pass + break; + } +} + +/* + Return true if line i is full. + */ +static bool tg_line_full(tetris_game *obj, int i) +{ + int j; + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) + return false; + } + return true; +} + +/* + Shift every row above r down one. + */ +static void tg_shift_lines(tetris_game *obj, int r) +{ + int i, j; + for (i = r-1; i >= 0; i--) { + for (j = 0; j < obj->cols; j++) { + tg_set(obj, i+1, j, tg_get(obj, i, j)); + tg_set(obj, i, j, TC_EMPTY); + } + } +} + +/* + Find rows that are filled, remove them, shift, and return the number of + cleared rows. + */ +static int tg_check_lines(tetris_game *obj) +{ + int i, nlines = 0; + tg_remove(obj, obj->falling); // don't want to mess up falling block + + for (i = obj->rows-1; i >= 0; i--) { + if (tg_line_full(obj, i)) { + tg_shift_lines(obj, i); + i++; // do this line over again since they're shifted + nlines++; + } + } + + tg_put(obj, obj->falling); // replace + return nlines; +} + +/* + Adjust the score for the game, given how many lines were just cleared. + */ +static void tg_adjust_score(tetris_game *obj, int lines_cleared) +{ + static int line_multiplier[] = {0, 40, 100, 300, 1200}; + obj->points += line_multiplier[lines_cleared] * (obj->level + 1); + if (lines_cleared >= obj->lines_remaining) { + obj->level = MIN(MAX_LEVEL, obj->level + 1); + lines_cleared -= obj->lines_remaining; + obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; + } else { + obj->lines_remaining -= lines_cleared; + } +} + +/* + Return true if the game is over. + */ +static bool tg_game_over(tetris_game *obj) +{ + int i, j; + bool over = false; + tg_remove(obj, obj->falling); + for (i = 0; i < 2; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + over = true; + } + } + } + tg_put(obj, obj->falling); + return over; +} + +/******************************************************************************* + Main Public Functions + *******************************************************************************/ + +/* + Do a single game tick: process gravity, user input, and score. Return true if + the game is still running, false if it is over. + */ +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) +{ + int lines_cleared; + // Handle gravity. + tg_do_gravity_tick(rs,obj); + + // Handle input. + tg_handle_move(rs,obj, move); + + // Check for cleared lines + lines_cleared = tg_check_lines(obj); + + tg_adjust_score(obj, lines_cleared); + + // Return whether the game will continue (NOT whether it's over) + return !tg_game_over(obj); +} + +void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) +{ + // Initialization logic + obj->rows = rows; + obj->cols = cols; + //obj->board = (char *)malloc(rows * cols); + memset(obj->board, TC_EMPTY, rows * cols); + obj->points = 0; + obj->level = 0; + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + obj->lines_remaining = LINES_PER_LEVEL; + //srand(time(NULL)); + tg_new_falling(rs,obj); + tg_new_falling(rs,obj); + obj->stored.typ = -1; + obj->stored.ori = 0; + obj->stored.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; + //printf("%d", obj->falling.loc.col); +} + +tetris_game *tg_create(struct games_state *rs,int rows, int cols) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols); + tg_init(rs,obj, rows, cols); + return obj; +} + +/*void tg_destroy(tetris_game *obj) +{ + // Cleanup logic + free(obj->board); +}*/ + +void tg_delete(tetris_game *obj) { + //tg_destroy(obj); + free(obj); +} + +/* + Load a game from a file. + +tetris_game *tg_load(FILE *f) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) + { + fprintf(stderr,"read game error\n"); + free(obj); + obj = 0; + } + else + { + obj->board = (char *)malloc(obj->rows * obj->cols); + if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + { + fprintf(stderr,"fread error\n"); + free(obj->board); + free(obj); + obj = 0; + } + } + return obj; +}*/ + +/* + Save a game to a file. + +void tg_save(tetris_game *obj, FILE *f) +{ + if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) + fprintf(stderr,"error writing tetrisgame\n"); + else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + fprintf(stderr,"error writing board\n"); +}*/ + +/* + Print a game board to a file. Really just for early debugging. + */ +void tg_print(tetris_game *obj, FILE *f) { + int i, j; + for (i = 0; i < obj->rows; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) { + fputs(TC_EMPTY_STR, f); + } else { + fputs(TC_BLOCK_STR, f); + } + } + fputc('\n', f); + } +} + +/* + 2 columns per cell makes the game much nicer. + */ +#define COLS_PER_CELL 2 +/* + Macro to print a cell of a specific type to a window. + */ +#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ +waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) +#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') + +/* + Print the tetris board onto the ncurses window. + */ +void display_board(WINDOW *w, tetris_game *obj) +{ + int i, j; + box(w, 0, 0); + for (i = 0; i < obj->rows; i++) { + wmove(w, 1 + i, 1); + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + ADD_BLOCK(w,tg_get(obj, i, j)); + } else { + ADD_EMPTY(w); + } + } + } + wnoutrefresh(w); +} + +/* + Display a tetris piece in a dedicated window. + */ +void display_piece(WINDOW *w, tetris_block block) +{ + int b; + tetris_location c; + wclear(w); + box(w, 0, 0); + if (block.typ == -1) { + wnoutrefresh(w); + return; + } + for (b = 0; b < TETRIS; b++) { + c = TETROMINOS[block.typ][block.ori][b]; + wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); + ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); + } + wnoutrefresh(w); +} + +/* + Display score information in a dedicated window. + */ +void display_score(WINDOW *w, tetris_game *tg) +{ + wclear(w); + box(w, 0, 0); + wprintw(w, (char *)"Score\n%d\n", tg->points); + wprintw(w, (char *)"Level\n%d\n", tg->level); + wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); + wnoutrefresh(w); +} + +/* + Save and exit the game. + +void save(tetris_game *game, WINDOW *w) +{ + FILE *f; + + wclear(w); + box(w, 0, 0); // return the border + wmove(w, 1, 1); + wprintw(w, (char *)"Save and exit? [Y/n] "); + wrefresh(w); + timeout(-1); + if (getch() == 'n') { + timeout(0); + return; + } + f = fopen("tetris.save", "w"); + tg_save(game, f); + fclose(f); + tg_delete(game); + endwin(); + fprintf(stderr,"Game saved to \"tetris.save\".\n"); + fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); + exit(EXIT_SUCCESS); +}*/ + +/* + Do the NCURSES initialization steps for color blocks. + */ +void init_colors(void) +{ + start_color(); + //init_color(COLOR_ORANGE, 1000, 647, 0); + init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); + init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); + init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); + init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); + init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); + init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); + init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); +} + +struct games_state globalR; +extern char Gametxidstr[]; +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); +gamesevent games_readevent(struct games_state *rs); + +void *gamesiterate(struct games_state *rs) +{ + uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; + gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg; + WINDOW *board, *next, *hold, *score; + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + // NCURSES initialization: + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + keypad(stdscr, TRUE); // allow arrow keys + timeout(0); // no blocking on getch() + curs_set(0); // set the cursor to invisible + init_colors(); // setup tetris colors + } + tg = tg_create(rs,22, 10); + prevlevel = tg->level; + // Create windows for each section of the interface. + board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); + next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); + hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); + score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); + while ( running != 0 ) + { + running = tg_tick(rs,tg,move); + if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) ) + { + display_board(board,tg); + display_piece(next,tg->next); + display_piece(hold,tg->stored); + display_score(score,tg); + } + if ( rs->guiflag != 0 ) + { +#ifdef STANDALONE + sleep_milli(15); + if ( (counter++ % 10) == 0 ) + doupdate(); + c = games_readevent(rs); + if ( c <= 0x7f || skipcount == 0x3fff ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); + if ( c <= 0x7f ) + issue_games_events(rs,Gametxidstr,eventid,c); + if ( tg->level != prevlevel ) + { + flushkeystrokes(rs,0); + prevlevel = tg->level; + } + skipcount = 0; + } else skipcount++; +#endif + } + else + { + if ( rs->replaydone != 0 ) + break; + if ( rs->sleeptime != 0 ) + { + sleep_milli(1); + if ( (counter++ % 20) == 0 ) + doupdate(); + } + if ( skipcount == 0 ) + { + c = games_readevent(rs); + //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); + if ( (c & 0x4000) == 0x4000 ) + { + skipcount = (c & 0x3fff); + c = 'S'; + } + } + if ( skipcount > 0 ) + skipcount--; + } + eventid++; + switch ( c ) + { + case 'h': + move = TM_LEFT; + break; + case 'l': + move = TM_RIGHT; + break; + case 'k': + move = TM_CLOCK; + break; + case 'j': + move = TM_DROP; + break; + case 'q': + running = false; + move = TM_NONE; + break; + /*case 'p': + wclear(board); + box(board, 0, 0); + wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); + wprintw(board, "PAUSED"); + wrefresh(board); + timeout(-1); + getch(); + timeout(0); + move = TM_NONE; + break; + case 's': + save(tg, board); + move = TM_NONE; + break;*/ + case ' ': + move = TM_HOLD; + break; + default: + move = TM_NONE; + } + } + return(tg); +} + +#ifdef STANDALONE +/* + Main tetris game! + */ +#include "dapps/dappstd.c" + + +char *clonestr(char *str) +{ + char *clone; int32_t len; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + len = strlen(str); + clone = (char *)calloc(1,len+16); + strcpy(clone,str); + return(clone); +} + +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( 0 ) + { + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); + } else return(0); +} + +int tetris(int argc, char **argv) +{ + struct games_state *rs = &globalR; + int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0; + memset(rs,0,sizeof(*rs)); + rs->guiflag = 1; + rs->sleeptime = 1; // non-zero to allow refresh() + if ( argc >= 2 && strlen(argv[2]) == 64 ) + { +#ifdef _WIN32 +#ifdef _MSC_VER + rs->origseed = _strtoui64(argv[1], NULL, 10); +#else + rs->origseed = atol(argv[1]); // windows, but not MSVC +#endif // _MSC_VER +#else + rs->origseed = atol(argv[1]); // non-windows +#endif // _WIN32 + rs->seed = rs->origseed; + if ( argc >= 3 ) + { + strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata %s\n",Gametxidstr); + if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + { + fprintf(stderr,"invalid gametxid, or already started\n"); + return(-1); + } + } + } else rs->seed = 777; + + /* Load file if given a filename. + if (argc >= 2) { + FILE *f = fopen(argv[1], "r"); + if (f == NULL) { + perror("tetris"); + exit(EXIT_FAILURE); + } + tg = tg_load(f); + fclose(f); + } else { + // Otherwise create new game. + tg = tg_create(rs,22, 10); + }*/ + + // Game loop + tg = (tetris_game *)gamesiterate(rs); + gamesbailout(rs); + // Deinitialize NCurses + wclear(stdscr); + endwin(); + // Output ending message. + printf("Game over!\n"); + printf("You finished with %d points on level %d.\n", tg->points, tg->level); + + // Deinitialize Tetris + tg_delete(tg); + return 0; +} + +#endif + diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index c53207562..8a52dcb37 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -1,3 +1,4 @@ + /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -13,442 +14,60 @@ * * ******************************************************************************/ -#include "CCassets.h" -#include "CCPrices.h" - -/* - Prices CC would best build on top of the oracles CC, ie. to combine payments for multiple oracles and to calculate a 51% protected price feed. - - We need to assume there is an oracle for a specific price. In the event there are more than one provider, the majority need to be within correlation distance to update a pricepoint. - - int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format); - - Using the above function, a consensus price can be obtained for a datasource. - - given an oracletxid, the marketaddr and format can be extracted to be used for future calls to OraclePrice. This allows to set a starting price and that in turn allows cash settled leveraged trading! - - Funds work like with dice, ie. there is a Prices plan that traders bet against. - - PricesFunding oracletxid, margin, priceaveraging, maxleverage, funding, longtoken, shorttoken, N [pubkeys] - - PricesBet -> oracletxid start with 'L', leverage, funding, direction - funds are locked into global CC address - it can be closed at anytime by the trader for cash settlement - the house account can close it if rekt - - Implementation Notes: - In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers. - - delta neutral balancing of riskexposure: fabs(long exposure - short exposure) - bet +B at leverage L - absval(sum(+BLi) - sum(-Bli)) - - validate: update riskexposure and it needs to be <= funds - - PricesProfits: limit withdraw to funds in excess of riskexposure - PricesFinish: payout (if winning) and update riskexposure - need long/short exposure assets - - funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address - pricebet -> user funds and exposure token to 1of2 address. - pricewin -> winnings from dealer funds, exposure token back to global address - priceloss -> exposuretoken back to global address - - exposure address, funds address - - - -*/ - -// start of consensus code - -int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vectorpubkeys,int32_t dir,int64_t amount,int32_t leverage) +// game specific code for daemon +void games_packitemstr(char *packitemstr,struct games_packitem *item) { - int64_t price; - // howto ensure price when block it confirms it not known - // get price from oracle + current chaintip - // normalize leveraged amount - if ( dir > 0 ) - rektprice = price * leverage / (leverage-1); - else rektprice = price * (leverage-1) / leverage; - return(price); + strcpy(packitemstr,""); } -CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector pubkeys,uint256 bettoken) +int64_t games_cashout(struct games_player *P) { - CScript opret; - fprintf(stderr,"implement EncodePricesFundingOpRet\n"); - return(opret); + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; + cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; + return(cashout); } -uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector &pubkeys,uint256 &bettoken) +void tetrisplayerjson(UniValue &obj,struct games_player *P) { - fprintf(stderr,"implement DecodePricesFundingOpRet\n"); + obj.push_back(Pair("packsize",(int64_t)P->packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); + obj.push_back(Pair("level",(int64_t)P->level)); + obj.push_back(Pair("experience",(int64_t)P->experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); +} + +int32_t disp_gamesplayer(char *str,struct games_player *P) +{ + str[0] = 0; + //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + // return(-1); + sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); return(0); } -bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - - return true; // TODO remove, for test dual-evals - - return eval->Invalid("no validation yet"); - std::vector > txids; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) - return eval->Invalid("no vouts"); - else + uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; + if ( (len= payload.size()) > 36 ) { - for (i=0; iInvalid("illegal normal vini"); - } - } - //fprintf(stderr,"check amounts\n"); - //if ( PricesExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Pricesget invalid amount\n"); - return false; - } - //else - { - txid = tx.GetHash(); - memcpy(hash,&txid,sizeof(hash)); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"Pricesget validated\n"); - else fprintf(stderr,"Pricesget invalid\n"); - return(retval); - } - } -} -// end of consensus code - -// helper functions for rpc calls in rpcwallet.cpp - -int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs) -{ - // add threshold check - int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; - std::vector > unspentOutputs; - SetCCunspents(unspentOutputs,destaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - // need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() ) - { - // need to verify assetid - if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; - } - } - } - return(totalinputs); + len -= 36; + for (i=0; i<32; i++) + ((uint8_t *)&gametxid)[i] = payload[len+i]; + eventid = (uint32_t)payload[len+32]; + eventid |= (uint32_t)payload[len+33] << 8; + eventid |= (uint32_t)payload[len+34] << 16; + eventid |= (uint32_t)payload[len+35] << 24; + //for (i=0; i > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vectorpubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx; - cp = CCinit(&C,EVAL_PRICES); - pricespk = GetUnspendable(cp,0); - SetCCtxids(addressIndex,cp->normaladdr); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - { - txid = it->first.txhash; - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) - { - if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) - { - result.push_back(uint256_str(str,txid)); - } - } - } - return(result); + return(true); } -// longtoken satoshis limits long exposure -// shorttoken satoshis limits short exposure -// both must be in the 1of2 CC address with its total supply -// bettoken -std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector pubkeys) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C; - if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 ) - { - CCerror = "invalid parameter error"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - return(""); - } - cp = CCinit(&C,EVAL_PRICES); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - pricespk = GetUnspendable(cp,0); - if ( (N= (int32_t)pubkeys.size()) || N > 15 ) - { - fprintf(stderr,"too many pubkeys N.%d\n",N); - return(""); - } - for (i=0; i 0 ) - { - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken))); - } - else - { - CCerror = "cant find enough inputs"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - } - return(""); -} - -UniValue PricesInfo(uint256 fundingtxid) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vectorpubkeys; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_PRICES); - pricespk = GetUnspendable(cp,0); - if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 ) - { - fprintf(stderr,"cant find fundingtxid\n"); - ERR_RESULT("cant find fundingtxid"); - return(result); - } - if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid))); - result.push_back(Pair("bettoken",uint256_str(str,bettoken))); - result.push_back(Pair("oracletxid",uint256_str(str,oracletxid))); - sprintf(numstr,"%.3f",(double)margin/1000); - result.push_back(Pair("profitmargin",numstr)); - result.push_back(Pair("maxleverage",maxleverage)); - result.push_back(Pair("mode",(int64_t)mode)); - for (i=0; ipubkeys; - if ( amount < 10000 ) - { - CCerror = "amount must be positive"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - return(""); - } - cp = CCinit(&C,EVAL_PRICES); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - pricespk = GetUnspendable(cp,0); - GetCCaddress(cp,myaddr,mypk); - if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) - { - fprintf(stderr,"cant find fundingtxid\n"); - return(""); - } - if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) - { - GetCCaddress1of2(cp,houseaddr,pricespk,planpk); - if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) - { - if ( (inputs= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,60)) >= amount ) - { - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG)); - if ( inputs > amount+txfee ) - CCchange = (inputs - amount); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk)); - // add addr2 - - std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys - return(FinalizeCCTx(0,cp,mtx,mypk,txfee, - EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty, - std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey()))))); - } - else - { - CCerror = "cant find enough bet inputs"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - } - } - else - { - CCerror = "cant find enough inputs"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - } - } - return(""); -} - -std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vectorpubkeys; - if ( amount < 0 ) - { - amount = -amount; - dir = -1; - } else dir = 1; - cp = CCinit(&C,EVAL_PRICES); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - pricespk = GetUnspendable(cp,0); - GetCCaddress(cp,myaddr,mypk); - if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) - { - fprintf(stderr,"cant find fundingtxid\n"); - return(""); - } - if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) - { - if ( leverage > maxleverage || leverage < 1 ) - { - fprintf(stderr,"illegal leverage\n"); - return(""); - } - GetCCaddress1of2(cp,houseaddr,pricespk,planpk); - GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk); - if ( dir < 0 ) - tokenid = shorttoken; - else tokenid = longtoken; - exposure = leverage * amount; - longexposure = CCtoken_balance(exposureaddr,longtoken); - shortexposure = CCtoken_balance(exposureaddr,shorttoken); - netexposure = (longexposure - shortexposure + exposure*dir); - if ( netexposure < 0 ) - netexposure = -netexposure; - balance = CCtoken_balance(myaddr,bettoken) / COIN; - if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction - { - fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure); - return(""); - } - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) - { - if ( (inputs= AddTokensInputs(cp,mtx,houseaddr,tokenid,exposure,30)) >= exposure ) - { - if ( (inputs2= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,30)) >= amount ) - { - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk)); - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,exposure,pricespk,pricespk)); - if ( inputs > exposure+txfee ) - CCchange = (inputs - exposure); - if ( inputs2 > amount+txfee ) - CCchange2 = (inputs2 - amount); - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,CCchange,pricespk,planpk)); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange2,mypk)); - // add addr2 and addr3 - //return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage))); - CScript opret; - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } - else - { - fprintf(stderr,"cant find enough bettoken inputs\n"); - return(""); - } - } - else - { - fprintf(stderr,"cant find enough exposure inputs\n"); - return(""); - } - } - else - { - CCerror = "cant find enough inputsB"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - } - } - return(""); -} - -UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) -{ - UniValue result(UniValue::VOBJ); - // get height of bettxid - // get price and rekt - // get current height and price - // what about if rekt in the past? - return(result); -} - -std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) -{ - return(""); -} - - - diff --git a/src/cc/prices.h b/src/cc/prices.h new file mode 100644 index 000000000..ae1c46821 --- /dev/null +++ b/src/cc/prices.h @@ -0,0 +1,208 @@ + +#ifndef H_PRICES_H +#define H_PRICES_H + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + +/* + Convert a tetromino type to its corresponding cell. + */ +#define TYPE_TO_CELL(x) ((x)+1) + +/* + Strings for how you would print a tetris board. + */ +#define TC_EMPTY_STR " " +#define TC_BLOCK_STR "\u2588" + +/* + Questions about a tetris cell. + */ +#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) +#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) + +/* + How many cells in a tetromino? + */ +#define TETRIS 4 +/* + How many tetrominos? + */ +#define NUM_TETROMINOS 7 +/* + How many orientations of a tetromino? + */ +#define NUM_ORIENTATIONS 4 + +/* + Level constants. + */ +#define MAX_LEVEL 19 +#define LINES_PER_LEVEL 10 + +/* + A "cell" is a 1x1 block within a tetris board. + */ +typedef enum { + TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ +} tetris_cell; + +/* + A "type" is a type/shape of a tetromino. Not including orientation. + */ +typedef enum { + TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z +} tetris_type; + +/* + A row,column pair. Negative numbers allowed, because we need them for + offsets. + */ +typedef struct { + int row; + int col; +} tetris_location; + +/* + A "block" is a struct that contains information about a tetromino. + Specifically, what type it is, what orientation it has, and where it is. + */ +typedef struct { + int typ; + int ori; + tetris_location loc; +} tetris_block; + +/* + All possible moves to give as input to the game. + */ +typedef enum { + TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE +} tetris_move; + +/* + A game object! + */ +typedef struct { + /* + Game board stuff: + */ + int rows; + int cols; + /* + Scoring information: + */ + int points; + int level; + /* + Falling block is the one currently going down. Next block is the one that + will be falling after this one. Stored is the block that you can swap out. + */ + tetris_block falling; + tetris_block next; + tetris_block stored; + /* + Number of game ticks until the block will move down. + */ + int ticks_till_gravity; + /* + Number of lines until you advance to the next level. + */ + int lines_remaining; + char board[]; +} tetris_game; + +/* + This array stores all necessary information about the cells that are filled by + each tetromino. The first index is the type of the tetromino (i.e. shape, + e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final + array contains 4 tetris_location objects, each mapping to an offset from a + point on the upper left that is the tetromino "origin". + */ +extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; + +/* + This array tells you how many ticks per gravity by level. Decreases as level + increases, to add difficulty. + */ +extern const int GRAVITY_LEVEL[MAX_LEVEL+1]; + +// Data structure manipulation. +void tg_init(tetris_game *obj, int rows, int cols); +tetris_game *tg_create(struct games_state *rs,int rows, int cols); +void tg_destroy(tetris_game *obj); +void tg_delete(tetris_game *obj); +tetris_game *tg_load(FILE *f); +void tg_save(tetris_game *obj, FILE *f); + +// Public methods not related to memory: +char tg_get(tetris_game *obj, int row, int col); +bool tg_check(tetris_game *obj, int row, int col); +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move); +void tg_print(tetris_game *obj, FILE *f); + +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +#define GAMENAME "prices" // name of executable +#define GAMEMAIN prices // main program of game +#define GAMEPLAYERJSON pricesplayerjson // displays game specific json +#define GAMEDATA pricesdata // extracts data from game specific variables into games_state +#define CHAINNAME "PRICES" // -ac_name= +typedef uint64_t gamesevent; // can be 8, 16, 32, or 64 bits + +#define MAXPACK 23 +struct games_packitem +{ + int32_t type,launch,count,which,hplus,dplus,arm,flags,group; + char damage[8],hurldmg[8]; +}; + +struct games_player +{ + int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; + struct games_packitem gamespack[MAXPACK]; +}; + +struct games_state +{ + uint64_t seed,origseed; + char *keystrokeshex; + uint32_t needflush,replaydone; + int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; + FILE *logfp; + struct games_player P; + gamesevent buffered[5000],*keystrokes; + uint8_t playerdata[8192]; +}; +extern struct games_state globalR; +void *gamesiterate(struct games_state *rs); +int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag); + +void games_packitemstr(char *packitemstr,struct games_packitem *item); +uint64_t _games_rngnext(uint64_t initseed); +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); +gamesevent games_revendian(gamesevent revx); +int32_t disp_gamesplayer(char *str,struct games_player *P); + +#endif + From 36fe43ff5876b0f161aaed3dc7b93999264a9ef0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 22:32:25 -1100 Subject: [PATCH 114/385] Make prices --- src/cc/gamescc.cpp | 4 ++-- src/cc/makeprices | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100755 src/cc/makeprices diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index f010ac282..ef9aa157b 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -16,7 +16,7 @@ #include "gamescc.h" #ifdef BUILD_PRICES #include "prices.c" -#elif +#else #include "tetris.c" #endif @@ -167,7 +167,7 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 #ifndef STANDALONE #ifdef BUILD_PRICES #include "prices.cpp" -#elif +#else #include "tetris.cpp" #endif diff --git a/src/cc/makeprices b/src/cc/makeprices new file mode 100755 index 000000000..012b8e157 --- /dev/null +++ b/src/cc/makeprices @@ -0,0 +1,3 @@ +gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES gamescc.cpp -lncurses -lcurl -o tetris + From 7b832d7124d72473ca58066589970a9c764e45d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:00:55 -1100 Subject: [PATCH 115/385] Games dir --- src/cc/{ => games}/prices.c | 6 +- src/cc/{tetris.cpp => games/prices.cpp} | 0 src/cc/{ => games}/prices.h | 0 src/cc/{ => games}/tetris.c | 0 src/cc/games/tetris.cpp | 73 ++++ src/cc/{ => games}/tetris.h | 0 src/cc/makeprices | 3 + src/cc/prices.cpp | 462 +++++++++++++++++++++--- 8 files changed, 500 insertions(+), 44 deletions(-) rename src/cc/{ => games}/prices.c (99%) rename src/cc/{tetris.cpp => games/prices.cpp} (100%) rename src/cc/{ => games}/prices.h (100%) rename src/cc/{ => games}/tetris.c (100%) create mode 100644 src/cc/games/tetris.cpp rename src/cc/{ => games}/tetris.h (100%) diff --git a/src/cc/prices.c b/src/cc/games/prices.c similarity index 99% rename from src/cc/prices.c rename to src/cc/games/prices.c index 651b1018c..02366fbc4 100644 --- a/src/cc/prices.c +++ b/src/cc/games/prices.c @@ -1,5 +1,5 @@ -#include "tetris.h" +#include "prices.h" /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. @@ -13,7 +13,7 @@ int random_tetromino(struct games_state *rs) return(rs->seed % NUM_TETROMINOS); } -int32_t tetrisdata(struct games_player *P,void *ptr) +int32_t pricesdata(struct games_player *P,void *ptr) { tetris_game *tg = (tetris_game *)ptr; P->gold = tg->points; @@ -832,7 +832,7 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve } else return(0); } -int tetris(int argc, char **argv) +int prices(int argc, char **argv) { struct games_state *rs = &globalR; int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0; diff --git a/src/cc/tetris.cpp b/src/cc/games/prices.cpp similarity index 100% rename from src/cc/tetris.cpp rename to src/cc/games/prices.cpp diff --git a/src/cc/prices.h b/src/cc/games/prices.h similarity index 100% rename from src/cc/prices.h rename to src/cc/games/prices.h diff --git a/src/cc/tetris.c b/src/cc/games/tetris.c similarity index 100% rename from src/cc/tetris.c rename to src/cc/games/tetris.c diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp new file mode 100644 index 000000000..8a52dcb37 --- /dev/null +++ b/src/cc/games/tetris.cpp @@ -0,0 +1,73 @@ + +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +// game specific code for daemon +void games_packitemstr(char *packitemstr,struct games_packitem *item) +{ + strcpy(packitemstr,""); +} + +int64_t games_cashout(struct games_player *P) +{ + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; + cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; + return(cashout); +} + +void tetrisplayerjson(UniValue &obj,struct games_player *P) +{ + obj.push_back(Pair("packsize",(int64_t)P->packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); + obj.push_back(Pair("level",(int64_t)P->level)); + obj.push_back(Pair("experience",(int64_t)P->experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); +} + +int32_t disp_gamesplayer(char *str,struct games_player *P) +{ + str[0] = 0; + //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + // return(-1); + sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); + return(0); +} + +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) +{ + uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; + if ( (len= payload.size()) > 36 ) + { + len -= 36; + for (i=0; i<32; i++) + ((uint8_t *)&gametxid)[i] = payload[len+i]; + eventid = (uint32_t)payload[len+32]; + eventid |= (uint32_t)payload[len+33] << 8; + eventid |= (uint32_t)payload[len+34] << 16; + eventid |= (uint32_t)payload[len+35] << 24; + //for (i=0; i oracletxid start with 'L', leverage, funding, direction + funds are locked into global CC address + it can be closed at anytime by the trader for cash settlement + the house account can close it if rekt + + Implementation Notes: + In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers. + + delta neutral balancing of riskexposure: fabs(long exposure - short exposure) + bet +B at leverage L + absval(sum(+BLi) - sum(-Bli)) + + validate: update riskexposure and it needs to be <= funds + + PricesProfits: limit withdraw to funds in excess of riskexposure + PricesFinish: payout (if winning) and update riskexposure + need long/short exposure assets + + funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address + pricebet -> user funds and exposure token to 1of2 address. + pricewin -> winnings from dealer funds, exposure token back to global address + priceloss -> exposuretoken back to global address + + exposure address, funds address + + + +*/ + +// start of consensus code + +int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vectorpubkeys,int32_t dir,int64_t amount,int32_t leverage) { - strcpy(packitemstr,""); + int64_t price; + // howto ensure price when block it confirms it not known + // get price from oracle + current chaintip + // normalize leveraged amount + if ( dir > 0 ) + rektprice = price * leverage / (leverage-1); + else rektprice = price * (leverage-1) / leverage; + return(price); } -int64_t games_cashout(struct games_player *P) +CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector pubkeys,uint256 bettoken) { - int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; - cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; - return(cashout); + CScript opret; + fprintf(stderr,"implement EncodePricesFundingOpRet\n"); + return(opret); } -void tetrisplayerjson(UniValue &obj,struct games_player *P) +uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector &pubkeys,uint256 &bettoken) { - obj.push_back(Pair("packsize",(int64_t)P->packsize)); - obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); - obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); - obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); - obj.push_back(Pair("level",(int64_t)P->level)); - obj.push_back(Pair("experience",(int64_t)P->experience)); - obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); -} - -int32_t disp_gamesplayer(char *str,struct games_player *P) -{ - str[0] = 0; - //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) - // return(-1); - sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); + fprintf(stderr,"implement DecodePricesFundingOpRet\n"); return(0); } -int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) +bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { - uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; - if ( (len= payload.size()) > 36 ) + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; + + return true; // TODO remove, for test dual-evals + + return eval->Invalid("no validation yet"); + std::vector > txids; + numvins = tx.vin.size(); + numvouts = tx.vout.size(); + preventCCvins = preventCCvouts = -1; + if ( numvouts < 1 ) + return eval->Invalid("no vouts"); + else { - len -= 36; - for (i=0; i<32; i++) - ((uint8_t *)&gametxid)[i] = payload[len+i]; - eventid = (uint32_t)payload[len+32]; - eventid |= (uint32_t)payload[len+33] << 8; - eventid |= (uint32_t)payload[len+34] << 16; - eventid |= (uint32_t)payload[len+35] << 24; - //for (i=0; iInvalid("illegal normal vini"); + } + } + //fprintf(stderr,"check amounts\n"); + //if ( PricesExactAmounts(cp,eval,tx,1,10000) == false ) + { + fprintf(stderr,"Pricesget invalid amount\n"); + return false; + } + //else + { + txid = tx.GetHash(); + memcpy(hash,&txid,sizeof(hash)); + retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); + if ( retval != 0 ) + fprintf(stderr,"Pricesget validated\n"); + else fprintf(stderr,"Pricesget invalid\n"); + return(retval); + } + } } +// end of consensus code -bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +// helper functions for rpc calls in rpcwallet.cpp + +int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs) { - return(true); + // add threshold check + int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + std::vector > unspentOutputs; + SetCCunspents(unspentOutputs,destaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + // need to prevent dup + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() ) + { + // need to verify assetid + if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) + { + if ( total != 0 && maxinputs != 0 ) + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + nValue = it->second.satoshis; + totalinputs += nValue; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + break; + } + } + } + return(totalinputs); } +UniValue PricesList() +{ + UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vectorpubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx; + cp = CCinit(&C,EVAL_PRICES); + pricespk = GetUnspendable(cp,0); + SetCCtxids(addressIndex,cp->normaladdr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + txid = it->first.txhash; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + { + if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) + { + result.push_back(uint256_str(str,txid)); + } + } + } + return(result); +} + +// longtoken satoshis limits long exposure +// shorttoken satoshis limits short exposure +// both must be in the 1of2 CC address with its total supply +// bettoken +std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector pubkeys) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C; + if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 ) + { + CCerror = "invalid parameter error"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + cp = CCinit(&C,EVAL_PRICES); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + if ( (N= (int32_t)pubkeys.size()) || N > 15 ) + { + fprintf(stderr,"too many pubkeys N.%d\n",N); + return(""); + } + for (i=0; i 0 ) + { + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken))); + } + else + { + CCerror = "cant find enough inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + return(""); +} + +UniValue PricesInfo(uint256 fundingtxid) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vectorpubkeys; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_PRICES); + pricespk = GetUnspendable(cp,0); + if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + ERR_RESULT("cant find fundingtxid"); + return(result); + } + if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid))); + result.push_back(Pair("bettoken",uint256_str(str,bettoken))); + result.push_back(Pair("oracletxid",uint256_str(str,oracletxid))); + sprintf(numstr,"%.3f",(double)margin/1000); + result.push_back(Pair("profitmargin",numstr)); + result.push_back(Pair("maxleverage",maxleverage)); + result.push_back(Pair("mode",(int64_t)mode)); + for (i=0; ipubkeys; + if ( amount < 10000 ) + { + CCerror = "amount must be positive"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + cp = CCinit(&C,EVAL_PRICES); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + GetCCaddress(cp,myaddr,mypk); + if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + return(""); + } + if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) + { + GetCCaddress1of2(cp,houseaddr,pricespk,planpk); + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) + { + if ( (inputs= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,60)) >= amount ) + { + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG)); + if ( inputs > amount+txfee ) + CCchange = (inputs - amount); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk)); + // add addr2 + + std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys + return(FinalizeCCTx(0,cp,mtx,mypk,txfee, + EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty, + std::make_pair(OPRETID_ASSETSDATA, EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey()))))); + } + else + { + CCerror = "cant find enough bet inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + else + { + CCerror = "cant find enough inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + return(""); +} + +std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vectorpubkeys; + if ( amount < 0 ) + { + amount = -amount; + dir = -1; + } else dir = 1; + cp = CCinit(&C,EVAL_PRICES); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + GetCCaddress(cp,myaddr,mypk); + if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + return(""); + } + if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) + { + if ( leverage > maxleverage || leverage < 1 ) + { + fprintf(stderr,"illegal leverage\n"); + return(""); + } + GetCCaddress1of2(cp,houseaddr,pricespk,planpk); + GetCCaddress1of2(cp,exposureaddr,pricespk,pricespk); + if ( dir < 0 ) + tokenid = shorttoken; + else tokenid = longtoken; + exposure = leverage * amount; + longexposure = CCtoken_balance(exposureaddr,longtoken); + shortexposure = CCtoken_balance(exposureaddr,shorttoken); + netexposure = (longexposure - shortexposure + exposure*dir); + if ( netexposure < 0 ) + netexposure = -netexposure; + balance = CCtoken_balance(myaddr,bettoken) / COIN; + if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction + { + fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure); + return(""); + } + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + { + if ( (inputs= AddTokensInputs(cp,mtx,houseaddr,tokenid,exposure,30)) >= exposure ) + { + if ( (inputs2= AddTokensInputs(cp,mtx,myaddr,bettoken,amount,30)) >= amount ) + { + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,amount,pricespk,planpk)); + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,exposure,pricespk,pricespk)); + if ( inputs > exposure+txfee ) + CCchange = (inputs - exposure); + if ( inputs2 > amount+txfee ) + CCchange2 = (inputs2 - amount); + mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,CCchange,pricespk,planpk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange2,mypk)); + // add addr2 and addr3 + //return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage))); + CScript opret; + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + } + else + { + fprintf(stderr,"cant find enough bettoken inputs\n"); + return(""); + } + } + else + { + fprintf(stderr,"cant find enough exposure inputs\n"); + return(""); + } + } + else + { + CCerror = "cant find enough inputsB"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + return(""); +} + +UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) +{ + UniValue result(UniValue::VOBJ); + // get height of bettxid + // get price and rekt + // get current height and price + // what about if rekt in the past? + return(result); +} + +std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) +{ + return(""); +} + + From 8f6561951e9fd0a9ad2646214f051edc96b3a7b2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:01:45 -1100 Subject: [PATCH 116/385] Games/ --- src/cc/gamescc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index ef9aa157b..6bcd17b09 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -15,9 +15,9 @@ #include "gamescc.h" #ifdef BUILD_PRICES -#include "prices.c" +#include "games/prices.c" #else -#include "tetris.c" +#include "games/tetris.c" #endif int32_t GAMEDATA(struct games_player *P,void *ptr); @@ -166,9 +166,9 @@ int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int3 #ifndef STANDALONE #ifdef BUILD_PRICES -#include "prices.cpp" +#include "games/prices.cpp" #else -#include "tetris.cpp" +#include "games/tetris.cpp" #endif void GAMEJSON(UniValue &obj,struct games_player *P); From f31b33355a64fb5d42b7bed6bef8f8a2b8a1d8b0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:03:15 -1100 Subject: [PATCH 117/385] Pricesplayerjson --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 8a52dcb37..cb2de54a1 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -27,7 +27,7 @@ int64_t games_cashout(struct games_player *P) return(cashout); } -void tetrisplayerjson(UniValue &obj,struct games_player *P) +void pricesplayerjson(UniValue &obj,struct games_player *P) { obj.push_back(Pair("packsize",(int64_t)P->packsize)); obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); From 6fca707153a3dde7826bf3798085fb30f61cb8ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:04:32 -1100 Subject: [PATCH 118/385] (uint8_t) --- src/cc/gamescc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 6bcd17b09..56fd13310 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1461,13 +1461,13 @@ UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) switch ( sizeof(gamesevent) ) { case 1: - sprintf(&hexstr[i<<1],"%02x",keystrokes[i]); + sprintf(&hexstr[i<<1],"%02x",(uint8_t)keystrokes[i]); break; case 2: - sprintf(&hexstr[i<<2],"%04x",keystrokes[i]); + sprintf(&hexstr[i<<2],"%04x",(uint16_t)keystrokes[i]); break; case 4: - sprintf(&hexstr[i<<3],"%08x",keystrokes[i]); + sprintf(&hexstr[i<<3],"%08x",(uint32_t)keystrokes[i]); break; case 8: sprintf(&hexstr[i<<4],"%016llxx",(long long)keystrokes[i]); From 5f2eeac994966f0b2629204e09eb753f0f472a44 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:08:20 -1100 Subject: [PATCH 119/385] Fixes --- src/cc/makeprices | 2 +- src/cc/maketetris | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cc/makeprices b/src/cc/makeprices index dc120deff..8bb98dd68 100755 --- a/src/cc/makeprices +++ b/src/cc/makeprices @@ -1,6 +1,6 @@ gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp cd games -gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES gamescc.cpp -lncurses -lcurl -o tetris +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o tetris cd .. diff --git a/src/cc/maketetris b/src/cc/maketetris index 9f0af354e..f11a4de9c 100755 --- a/src/cc/maketetris +++ b/src/cc/maketetris @@ -1,2 +1,4 @@ -gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE gamescc.cpp -lncurses -lcurl -o tetris +cd games +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris +cd .. From 7e1fc1ef0986d8564a30f9551f9865e42e28af62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:10:16 -1100 Subject: [PATCH 120/385] (uint8_t) --- src/cc/dapps/dappstd.c | 6 +++--- src/cc/makeprices | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c index 917045ed5..82366315c 100644 --- a/src/cc/dapps/dappstd.c +++ b/src/cc/dapps/dappstd.c @@ -761,11 +761,11 @@ int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,gam for (i=0; i Date: Tue, 26 Mar 2019 23:12:41 -1100 Subject: [PATCH 121/385] (uint8_t) --- src/cc/games/prices.c | 6 +++--- src/cc/games/tetris.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 02366fbc4..f35e8164b 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -804,11 +804,11 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve if ( 0 ) { if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid); else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid); else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid); else if ( sizeof(c) == 8 ) sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) diff --git a/src/cc/games/tetris.c b/src/cc/games/tetris.c index 651b1018c..254d324a8 100644 --- a/src/cc/games/tetris.c +++ b/src/cc/games/tetris.c @@ -804,11 +804,11 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve if ( 0 ) { if ( sizeof(c) == 1 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",c&0xff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid); else if ( sizeof(c) == 2 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",c&0xffff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid); else if ( sizeof(c) == 4 ) - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c&0xffffffff,gametxidstr,eventid); + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid); else if ( sizeof(c) == 8 ) sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) From 97460af39460d404315a4268c6689e46f948db5d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:21:34 -1100 Subject: [PATCH 122/385] Fix makecclib --- src/cc/makecclib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index 38634aa78..8179623ad 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -6,7 +6,7 @@ make -f Makefile_rogue ./makerogue echo sudoku/musig/dilithium -gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o sudokucc.so cclib.cpp echo games tetris gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp From eed57deaffa0ca4ccfde66a5ac5852459af1c2d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:36:34 -1100 Subject: [PATCH 123/385] Btcusd --- src/cc/games/prices.c | 777 +++++------------------------------------- 1 file changed, 83 insertions(+), 694 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index f35e8164b..cb475c763 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,5 +1,6 @@ #include "prices.h" +#include /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. @@ -22,90 +23,6 @@ int32_t pricesdata(struct games_player *P,void *ptr) return(0); } -/***************************************************************************/ -/** https://github.com/brenns10/tetris - @file main.c - @author Stephen Brennan - @date Created Wednesday, 10 June 2015 - @brief Main program for tetris. - @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised - BSD License. See LICENSE.txt for details. - *******************************************************************************/ - - -#include // for FILE -#include // for bool -#include -#include -#include -#include -#include -#include - -#ifdef BUILD_GAMESCC -#include "rogue/cursesd.h" -#else -#include -#endif - - -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -/******************************************************************************* - Array Definitions - *******************************************************************************/ - -const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = -{ - // I - {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, - // J - {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, - {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, - // L - {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, - {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, - // O - {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, - // S - {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, - {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, - {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, - // T - {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, - // Z - {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, - {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, -}; - -const int GRAVITY_LEVEL[MAX_LEVEL+1] = { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, - //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 -}; - -/******************************************************************************* - Helper Functions for Blocks - *******************************************************************************/ - void sleep_milli(int milliseconds) { struct timespec ts; @@ -114,578 +31,117 @@ void sleep_milli(int milliseconds) nanosleep(&ts, NULL); } -/* - Return the block at the given row and column. - */ -char tg_get(tetris_game *obj, int row, int column) +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) { - return obj->board[obj->cols * row + column]; -} - -/* - Set the block at the given row and column. - */ -static void tg_set(tetris_game *obj, int row, int column, char value) -{ - obj->board[obj->cols * row + column] = value; -} - -/* - Check whether a row and column are in bounds. - */ -bool tg_check(tetris_game *obj, int row, int col) -{ - return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; -} - -/* - Place a block onto the board. - */ -static void tg_put(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, - TYPE_TO_CELL(block.typ)); - } -} - -/* - Clear a block out of the board. - */ -static void tg_remove(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); - } -} - -/* - Check if a block can be placed on the board. - */ -static bool tg_fits(tetris_game *obj, tetris_block block) -{ - int i, r, c; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - r = block.loc.row + cell.row; - c = block.loc.col + cell.col; - if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { - return false; - } - } - return true; -} - -/* - Create a new falling block and populate the next falling block with a random - one. - */ -static void tg_new_falling(struct games_state *rs,tetris_game *obj) -{ - // Put in a new falling tetromino. - obj->falling = obj->next; - obj->next.typ = random_tetromino(rs); - obj->next.ori = 0; - obj->next.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; -} - -/******************************************************************************* - Game Turn Helpers - *******************************************************************************/ - -/* - Tick gravity, and move the block down if gravity should act. - */ -static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj) -{ - obj->ticks_till_gravity--; - if (obj->ticks_till_gravity <= 0) { - tg_remove(obj, obj->falling); - obj->falling.loc.row++; - if (tg_fits(obj, obj->falling)) { - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - } else { - obj->falling.loc.row--; - tg_put(obj, obj->falling); - - tg_new_falling(rs,obj); - } - tg_put(obj, obj->falling); - } -} - -/* - Move the falling tetris block left (-1) or right (+1). - */ -static void tg_move(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - obj->falling.loc.col += direction; - if (!tg_fits(obj, obj->falling)) { - obj->falling.loc.col -= direction; - } - tg_put(obj, obj->falling); -} - -/* - Send the falling tetris block to the bottom. - */ -static void tg_down(struct games_state *rs,tetris_game *obj) -{ - tg_remove(obj, obj->falling); - while (tg_fits(obj, obj->falling)) { - obj->falling.loc.row++; - } - obj->falling.loc.row--; - tg_put(obj, obj->falling); - tg_new_falling(rs,obj); -} - -/* - Rotate the falling block in either direction (+/-1). - */ -static void tg_rotate(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - - while (true) { - obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; - - // If the new orientation fits, we're done. - if (tg_fits(obj, obj->falling)) - break; - - // Otherwise, try moving left to make it fit. - obj->falling.loc.col--; - if (tg_fits(obj, obj->falling)) - break; - - // Finally, try moving right to make it fit. - obj->falling.loc.col += 2; - if (tg_fits(obj, obj->falling)) - break; - - // Put it back in its original location and try the next orientation. - obj->falling.loc.col--; - // Worst case, we come back to the original orientation and it fits, so this - // loop will terminate. - } - - tg_put(obj, obj->falling); -} - -/* - Swap the falling block with the block in the hold buffer. - */ -static void tg_hold(struct games_state *rs,tetris_game *obj) -{ - tg_remove(obj, obj->falling); - if (obj->stored.typ == -1) { - obj->stored = obj->falling; - tg_new_falling(rs,obj); - } else { - int typ = obj->falling.typ, ori = obj->falling.ori; - obj->falling.typ = obj->stored.typ; - obj->falling.ori = obj->stored.ori; - obj->stored.typ = typ; - obj->stored.ori = ori; - while (!tg_fits(obj, obj->falling)) { - obj->falling.loc.row--; - } - } - tg_put(obj, obj->falling); -} - -/* - Perform the action specified by the move. - */ -static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move) -{ - switch (move) { - case TM_LEFT: - //fprintf(stderr,"LEFT "); - tg_move(obj, -1); - break; - case TM_RIGHT: - //fprintf(stderr,"RIGHT "); - tg_move(obj, 1); - break; - case TM_DROP: - tg_down(rs,obj); - break; - case TM_CLOCK: - tg_rotate(obj, 1); - break; - case TM_COUNTER: - tg_rotate(obj, -1); - break; - case TM_HOLD: - tg_hold(rs,obj); - break; - default: - // pass - break; - } -} - -/* - Return true if line i is full. - */ -static bool tg_line_full(tetris_game *obj, int i) -{ - int j; - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) - return false; - } - return true; -} - -/* - Shift every row above r down one. - */ -static void tg_shift_lines(tetris_game *obj, int r) -{ - int i, j; - for (i = r-1; i >= 0; i--) { - for (j = 0; j < obj->cols; j++) { - tg_set(obj, i+1, j, tg_get(obj, i, j)); - tg_set(obj, i, j, TC_EMPTY); - } - } -} - -/* - Find rows that are filled, remove them, shift, and return the number of - cleared rows. - */ -static int tg_check_lines(tetris_game *obj) -{ - int i, nlines = 0; - tg_remove(obj, obj->falling); // don't want to mess up falling block - - for (i = obj->rows-1; i >= 0; i--) { - if (tg_line_full(obj, i)) { - tg_shift_lines(obj, i); - i++; // do this line over again since they're shifted - nlines++; - } - } - - tg_put(obj, obj->falling); // replace - return nlines; -} - -/* - Adjust the score for the game, given how many lines were just cleared. - */ -static void tg_adjust_score(tetris_game *obj, int lines_cleared) -{ - static int line_multiplier[] = {0, 40, 100, 300, 1200}; - obj->points += line_multiplier[lines_cleared] * (obj->level + 1); - if (lines_cleared >= obj->lines_remaining) { - obj->level = MIN(MAX_LEVEL, obj->level + 1); - lines_cleared -= obj->lines_remaining; - obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; - } else { - obj->lines_remaining -= lines_cleared; - } -} - -/* - Return true if the game is over. - */ -static bool tg_game_over(tetris_game *obj) -{ - int i, j; - bool over = false; - tg_remove(obj, obj->falling); - for (i = 0; i < 2; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - over = true; - } - } - } - tg_put(obj, obj->falling); - return over; -} - -/******************************************************************************* - Main Public Functions - *******************************************************************************/ - -/* - Do a single game tick: process gravity, user input, and score. Return true if - the game is still running, false if it is over. - */ -bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) -{ - int lines_cleared; - // Handle gravity. - tg_do_gravity_tick(rs,obj); - - // Handle input. - tg_handle_move(rs,obj, move); - - // Check for cleared lines - lines_cleared = tg_check_lines(obj); - - tg_adjust_score(obj, lines_cleared); - - // Return whether the game will continue (NOT whether it's over) - return !tg_game_over(obj); -} - -void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) -{ - // Initialization logic - obj->rows = rows; - obj->cols = cols; - //obj->board = (char *)malloc(rows * cols); - memset(obj->board, TC_EMPTY, rows * cols); - obj->points = 0; - obj->level = 0; - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - obj->lines_remaining = LINES_PER_LEVEL; - //srand(time(NULL)); - tg_new_falling(rs,obj); - tg_new_falling(rs,obj); - obj->stored.typ = -1; - obj->stored.ori = 0; - obj->stored.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; - //printf("%d", obj->falling.loc.col); -} - -tetris_game *tg_create(struct games_state *rs,int rows, int cols) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols); - tg_init(rs,obj, rows, cols); - return obj; -} - -/*void tg_destroy(tetris_game *obj) -{ - // Cleanup logic - free(obj->board); -}*/ - -void tg_delete(tetris_game *obj) { - //tg_destroy(obj); - free(obj); -} - -/* - Load a game from a file. - -tetris_game *tg_load(FILE *f) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) { - fprintf(stderr,"read game error\n"); - free(obj); - obj = 0; - } - else - { - obj->board = (char *)malloc(obj->rows * obj->cols); - if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) { - fprintf(stderr,"fread error\n"); - free(obj->board); - free(obj); - obj = 0; + fclose(fp); + *lenp = 0; + //printf("loadfile null size.(%s)\n",fname); + return(0); } - } - return obj; -}*/ - -/* - Save a game to a file. - -void tg_save(tetris_game *obj, FILE *f) -{ - if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) - fprintf(stderr,"error writing tetrisgame\n"); - else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - fprintf(stderr,"error writing board\n"); -}*/ - -/* - Print a game board to a file. Really just for early debugging. - */ -void tg_print(tetris_game *obj, FILE *f) { - int i, j; - for (i = 0; i < obj->rows; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) { - fputs(TC_EMPTY_STR, f); - } else { - fputs(TC_BLOCK_STR, f); - } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); } - fputc('\n', f); - } -} - -/* - 2 columns per cell makes the game much nicer. - */ -#define COLS_PER_CELL 2 -/* - Macro to print a cell of a specific type to a window. - */ -#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ -waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) -#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') - -/* - Print the tetris board onto the ncurses window. - */ -void display_board(WINDOW *w, tetris_game *obj) -{ - int i, j; - box(w, 0, 0); - for (i = 0; i < obj->rows; i++) { - wmove(w, 1 + i, 1); - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - ADD_BLOCK(w,tg_get(obj, i, j)); - } else { - ADD_EMPTY(w); - } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; } - } - wnoutrefresh(w); + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); } -/* - Display a tetris piece in a dedicated window. - */ -void display_piece(WINDOW *w, tetris_block block) +void *filestr(long *allocsizep,char *_fname) { - int b; - tetris_location c; - wclear(w); - box(w, 0, 0); - if (block.typ == -1) { - wnoutrefresh(w); - return; - } - for (b = 0; b < TETRIS; b++) { - c = TETROMINOS[block.typ][block.ori][b]; - wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); - ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); - } - wnoutrefresh(w); + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); } -/* - Display score information in a dedicated window. - */ -void display_score(WINDOW *w, tetris_game *tg) +char *send_curl(char *url,char *fname) { - wclear(w); - box(w, 0, 0); - wprintw(w, (char *)"Score\n%d\n", tg->points); - wprintw(w, (char *)"Level\n%d\n", tg->level); - wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); - wnoutrefresh(w); + long fsize; char curlstr[1024]; + sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + system(curlstr); + return(filestr(&fsize,fname)); } -/* - Save and exit the game. - -void save(tetris_game *game, WINDOW *w) +cJSON *get_urljson(char *url,char *fname) { - FILE *f; - - wclear(w); - box(w, 0, 0); // return the border - wmove(w, 1, 1); - wprintw(w, (char *)"Save and exit? [Y/n] "); - wrefresh(w); - timeout(-1); - if (getch() == 'n') { - timeout(0); - return; + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= send_curl(url,fname)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); } - f = fopen("tetris.save", "w"); - tg_save(game, f); - fclose(f); - tg_delete(game); - endwin(); - fprintf(stderr,"Game saved to \"tetris.save\".\n"); - fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); - exit(EXIT_SUCCESS); -}*/ + return(json); +} -/* - Do the NCURSES initialization steps for color blocks. - */ -void init_colors(void) +////////////////////////////////////////////// +// start of dapp +////////////////////////////////////////////// + +uint64_t get_btcusd() { - start_color(); - //init_color(COLOR_ORANGE, 1000, 647, 0); - init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); - init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); - init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); - init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); - init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); - init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); - init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); + cJSON *pjson,*bpi,*usd; uint64_t btcusd = 0; + if ( (pjson= get_urljson("http://api.coindesk.com/v1/bpi/currentprice.json","/tmp/oraclefeed.json")) != 0 ) + { + if ( (bpi= jobj(pjson,"bpi")) != 0 && (usd= jobj(bpi,"USD")) != 0 ) + { + btcusd = jdouble(usd,"rate_float") * SATOSHIDEN; + printf("BTC/USD %.4f\n",dstr(btcusd)); + } + free_json(pjson); + } + return(btcusd); } struct games_state globalR; extern char Gametxidstr[]; int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); -gamesevent games_readevent(struct games_state *rs); void *gamesiterate(struct games_state *rs) { - uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; - gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg; - WINDOW *board, *next, *hold, *score; + bool running = true; uint32_t eventid = 0; int64_t price; if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors } - tg = tg_create(rs,22, 10); - prevlevel = tg->level; - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); while ( running != 0 ) { - running = tg_tick(rs,tg,move); - if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) ) + //running = tg_tick(rs,tg,move); + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { - display_board(board,tg); - display_piece(next,tg->next); - display_piece(hold,tg->stored); - display_score(score,tg); } if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep_milli(15); - if ( (counter++ % 10) == 0 ) + sleep_milli(10000); + price = get_btcusd(); + fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/COIN); + /*if ( (counter++ % 10) == 0 ) doupdate(); c = games_readevent(rs); if ( c <= 0x7f || skipcount == 0x3fff ) @@ -700,7 +156,7 @@ void *gamesiterate(struct games_state *rs) prevlevel = tg->level; } skipcount = 0; - } else skipcount++; + } else skipcount++;*/ #endif } else @@ -713,7 +169,7 @@ void *gamesiterate(struct games_state *rs) if ( (counter++ % 20) == 0 ) doupdate(); } - if ( skipcount == 0 ) + /*if ( skipcount == 0 ) { c = games_readevent(rs); //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); @@ -724,56 +180,14 @@ void *gamesiterate(struct games_state *rs) } } if ( skipcount > 0 ) - skipcount--; + skipcount--;*/ } eventid++; - switch ( c ) - { - case 'h': - move = TM_LEFT; - break; - case 'l': - move = TM_RIGHT; - break; - case 'k': - move = TM_CLOCK; - break; - case 'j': - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - /*case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break;*/ - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } } - return(tg); + return(0); } #ifdef STANDALONE -/* - Main tetris game! - */ #include "dapps/dappstd.c" @@ -835,7 +249,7 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve int prices(int argc, char **argv) { struct games_state *rs = &globalR; - int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0; + int32_t c,skipcount=0; uint32_t eventid = 0; memset(rs,0,sizeof(*rs)); rs->guiflag = 1; rs->sleeptime = 1; // non-zero to allow refresh() @@ -862,33 +276,8 @@ int prices(int argc, char **argv) } } } else rs->seed = 777; - - /* Load file if given a filename. - if (argc >= 2) { - FILE *f = fopen(argv[1], "r"); - if (f == NULL) { - perror("tetris"); - exit(EXIT_FAILURE); - } - tg = tg_load(f); - fclose(f); - } else { - // Otherwise create new game. - tg = tg_create(rs,22, 10); - }*/ - - // Game loop - tg = (tetris_game *)gamesiterate(rs); - gamesbailout(rs); - // Deinitialize NCurses - wclear(stdscr); - endwin(); - // Output ending message. - printf("Game over!\n"); - printf("You finished with %d points on level %d.\n", tg->points, tg->level); - - // Deinitialize Tetris - tg_delete(tg); + gamesiterate(rs); + //gamesbailout(rs); return 0; } From 02e76e122bf1b71515e0707962d1f0f0b92fb834 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:40:09 -1100 Subject: [PATCH 124/385] syntax --- src/cc/games/prices.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index cb475c763..81f58521c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -31,6 +31,37 @@ void sleep_milli(int milliseconds) nanosleep(&ts, NULL); } +char *nonportable_path(char *str) +{ + int32_t i; + for (i=0; str[i]!=0; i++) + if ( str[i] == '/' ) + str[i] = '\\'; + return(str); +} + +char *portable_path(char *str) +{ +#ifdef _WIN32 + return(nonportable_path(str)); +#else +#ifdef __PNACL + /*int32_t i,n; + if ( str[0] == '/' ) + return(str); + else + { + n = (int32_t)strlen(str); + for (i=n; i>0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) { FILE *fp; @@ -73,7 +104,7 @@ void *filestr(long *allocsizep,char *_fname) { long filesize = 0; char *fname,*buf = 0; void *retptr; *allocsizep = 0; - fname = malloc(strlen(_fname)+1); + fname = (char *)malloc(strlen(_fname)+1); strcpy(fname,_fname); retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); free(fname); From 2821c37693fe66b4fafef0120cc9a6546abe1f81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:41:07 -1100 Subject: [PATCH 125/385] Ncurses --- src/cc/games/prices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 81f58521c..96506b41c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,6 +1,7 @@ #include "prices.h" #include +#include /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From 4d66ed85244123fa136689bf3e760c1aa12c8dd8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:43:26 -1100 Subject: [PATCH 126/385] -curses.h --- src/cc/games/prices.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 96506b41c..81f58521c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,7 +1,6 @@ #include "prices.h" #include -#include /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From 55b3b006edb1e99a85de8b60b9e00f89f20b8f71 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:44:12 -1100 Subject: [PATCH 127/385] Test --- src/cc/games/prices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 81f58521c..66cf54030 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -219,6 +219,7 @@ void *gamesiterate(struct games_state *rs) } #ifdef STANDALONE +#include #include "dapps/dappstd.c" From 20ff5d20d4182a17abf495ed0b9cbaab2419b0e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:46:06 -1100 Subject: [PATCH 128/385] syntax --- src/cc/games/prices.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 66cf54030..e125a1602 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -116,7 +116,7 @@ char *send_curl(char *url,char *fname) long fsize; char curlstr[1024]; sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); system(curlstr); - return(filestr(&fsize,fname)); + return((char *)filestr(&fsize,fname)); } cJSON *get_urljson(char *url,char *fname) @@ -138,11 +138,11 @@ cJSON *get_urljson(char *url,char *fname) uint64_t get_btcusd() { cJSON *pjson,*bpi,*usd; uint64_t btcusd = 0; - if ( (pjson= get_urljson("http://api.coindesk.com/v1/bpi/currentprice.json","/tmp/oraclefeed.json")) != 0 ) + if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json","/tmp/oraclefeed.json")) != 0 ) { - if ( (bpi= jobj(pjson,"bpi")) != 0 && (usd= jobj(bpi,"USD")) != 0 ) + if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { - btcusd = jdouble(usd,"rate_float") * SATOSHIDEN; + btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; printf("BTC/USD %.4f\n",dstr(btcusd)); } free_json(pjson); @@ -197,8 +197,6 @@ void *gamesiterate(struct games_state *rs) if ( rs->sleeptime != 0 ) { sleep_milli(1); - if ( (counter++ % 20) == 0 ) - doupdate(); } /*if ( skipcount == 0 ) { From eca3bda195239b325d1f71b350b3983c46b6bc13 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:48:03 -1100 Subject: [PATCH 129/385] Prints --- src/cc/games/prices.c | 2 +- src/cc/makeprices | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index e125a1602..057e8be7f 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -138,7 +138,7 @@ cJSON *get_urljson(char *url,char *fname) uint64_t get_btcusd() { cJSON *pjson,*bpi,*usd; uint64_t btcusd = 0; - if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json","/tmp/oraclefeed.json")) != 0 ) + if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 ) { if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { diff --git a/src/cc/makeprices b/src/cc/makeprices index ca8b80065..2779c1c5b 100755 --- a/src/cc/makeprices +++ b/src/cc/makeprices @@ -1,4 +1,6 @@ +echo pricescc.so gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp +echo prices cd games gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o prices cd .. From 382dd5021874f14230ac7e448517f00563de1eef Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:49:50 -1100 Subject: [PATCH 130/385] Test --- src/cc/games/prices.c | 142 +++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 057e8be7f..fa8749605 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -31,6 +31,77 @@ void sleep_milli(int milliseconds) nanosleep(&ts, NULL); } +struct games_state globalR; +extern char Gametxidstr[]; +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); +uint64_t get_btcusd(); + +void *gamesiterate(struct games_state *rs) +{ + bool running = true; uint32_t eventid = 0; int64_t price; + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + } + while ( running != 0 ) + { + //running = tg_tick(rs,tg,move); + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + } + if ( rs->guiflag != 0 ) + { +#ifdef STANDALONE + sleep_milli(10000); + price = get_btcusd(); + fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/COIN); + /*if ( (counter++ % 10) == 0 ) + doupdate(); + c = games_readevent(rs); + if ( c <= 0x7f || skipcount == 0x3fff ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); + if ( c <= 0x7f ) + issue_games_events(rs,Gametxidstr,eventid,c); + if ( tg->level != prevlevel ) + { + flushkeystrokes(rs,0); + prevlevel = tg->level; + } + skipcount = 0; + } else skipcount++;*/ +#endif + } + else + { + if ( rs->replaydone != 0 ) + break; + if ( rs->sleeptime != 0 ) + { + sleep_milli(1); + } + /*if ( skipcount == 0 ) + { + c = games_readevent(rs); + //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); + if ( (c & 0x4000) == 0x4000 ) + { + skipcount = (c & 0x3fff); + c = 'S'; + } + } + if ( skipcount > 0 ) + skipcount--;*/ + } + eventid++; + } + return(0); +} + +#ifdef STANDALONE +#include +#include "dapps/dappstd.c" + char *nonportable_path(char *str) { int32_t i; @@ -150,77 +221,6 @@ uint64_t get_btcusd() return(btcusd); } -struct games_state globalR; -extern char Gametxidstr[]; -int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); - -void *gamesiterate(struct games_state *rs) -{ - bool running = true; uint32_t eventid = 0; int64_t price; - if ( rs->guiflag != 0 || rs->sleeptime != 0 ) - { - } - while ( running != 0 ) - { - //running = tg_tick(rs,tg,move); - if ( rs->guiflag != 0 || rs->sleeptime != 0 ) - { - } - if ( rs->guiflag != 0 ) - { -#ifdef STANDALONE - sleep_milli(10000); - price = get_btcusd(); - fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/COIN); - /*if ( (counter++ % 10) == 0 ) - doupdate(); - c = games_readevent(rs); - if ( c <= 0x7f || skipcount == 0x3fff ) - { - if ( skipcount > 0 ) - issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); - if ( c <= 0x7f ) - issue_games_events(rs,Gametxidstr,eventid,c); - if ( tg->level != prevlevel ) - { - flushkeystrokes(rs,0); - prevlevel = tg->level; - } - skipcount = 0; - } else skipcount++;*/ -#endif - } - else - { - if ( rs->replaydone != 0 ) - break; - if ( rs->sleeptime != 0 ) - { - sleep_milli(1); - } - /*if ( skipcount == 0 ) - { - c = games_readevent(rs); - //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); - if ( (c & 0x4000) == 0x4000 ) - { - skipcount = (c & 0x3fff); - c = 'S'; - } - } - if ( skipcount > 0 ) - skipcount--;*/ - } - eventid++; - } - return(0); -} - -#ifdef STANDALONE -#include -#include "dapps/dappstd.c" - - char *clonestr(char *str) { char *clone; int32_t len; From 498c813b674b21fd1557004cc029f2e65c0bf42c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:53:59 -1100 Subject: [PATCH 131/385] #include "rogue/cursesd.c" --- src/cc/cclib.cpp | 2 +- src/cc/games/prices.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 95748def4..975b0735c 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -691,8 +691,8 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) #include "customcc.cpp" #elif BUILD_GAMESCC -#include "gamescc.cpp" #include "rogue/cursesd.c" +#include "gamescc.cpp" #else #include "sudoku.cpp" diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index fa8749605..b9da75fe2 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -53,7 +53,7 @@ void *gamesiterate(struct games_state *rs) #ifdef STANDALONE sleep_milli(10000); price = get_btcusd(); - fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/COIN); + fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/SATOSHIDEN); /*if ( (counter++ % 10) == 0 ) doupdate(); c = games_readevent(rs); @@ -184,9 +184,12 @@ void *filestr(long *allocsizep,char *_fname) char *send_curl(char *url,char *fname) { - long fsize; char curlstr[1024]; + long fsize; char curlstr[1024],*retstr,*retstr2; sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); - system(curlstr); + //retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,"","",""); + + if ( system(curlstr) != 0 ) + fprintf(stderr,"error doing system(%s)\n",curlstr); return((char *)filestr(&fsize,fname)); } From 75465c987cfbd6707f3a5438918ed12747a7ae1e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:55:08 -1100 Subject: [PATCH 132/385] SATOSHIDEN --- src/cc/games/prices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index b9da75fe2..3d72965fc 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,6 +1,7 @@ #include "prices.h" #include +#define SATOSHIDEN 100000000 /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From 9f42c31c2a81872822e9944dd8d5fd82be943072 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:55:38 -1100 Subject: [PATCH 133/385] #define SATOSHIDEN ((uint64_t)100000000L) --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 3d72965fc..0ac0844c2 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,7 +1,7 @@ #include "prices.h" #include -#define SATOSHIDEN 100000000 +#define SATOSHIDEN ((uint64_t)100000000L) /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From 73e6a1cb6bb803cf529f51b1a0f6cd8083b7903a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 26 Mar 2019 23:58:10 -1100 Subject: [PATCH 134/385] Fx --- src/cc/makecclib | 2 -- src/cc/maketetris | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/makecclib b/src/cc/makecclib index 8179623ad..81026e75a 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -9,11 +9,9 @@ echo sudoku/musig/dilithium gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o sudokucc.so cclib.cpp echo games tetris -gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp ./maketetris echo games prices -gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o pricescc.so cclib.cpp ./makeprices echo customcc stub diff --git a/src/cc/maketetris b/src/cc/maketetris index f11a4de9c..c39536229 100755 --- a/src/cc/maketetris +++ b/src/cc/maketetris @@ -1,3 +1,6 @@ +echo gamescc.so with tetris +gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp +echo tetris dapp cd games gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris cd .. From f49f901f4f12d73b47915be3b9adb0ab526d3f11 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:06:18 -1100 Subject: [PATCH 135/385] Change Tetris washout --- src/cc/games/tetris.cpp | 4 ++-- src/cc/makecclib | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp index 8a52dcb37..f1b6416ba 100644 --- a/src/cc/games/tetris.cpp +++ b/src/cc/games/tetris.cpp @@ -22,8 +22,8 @@ void games_packitemstr(char *packitemstr,struct games_packitem *item) int64_t games_cashout(struct games_player *P) { - int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; - cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=10000,cashout = 0; + cashout = (uint64_t)P->gold * mult; return(cashout); } diff --git a/src/cc/makecclib b/src/cc/makecclib index 81026e75a..b2f8e2ee1 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,5 +1,5 @@ #!/bin/sh -rm *.so rogue/rogue tetris +rm *.so rogue/rogue games/tetris games/prices echo rogue make -f Makefile_rogue From 58be59a00d8876b492faeef0b176a09478ec704c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:10:17 -1100 Subject: [PATCH 136/385] Test --- src/cc/games/prices.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 0ac0844c2..658ed2406 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -185,13 +185,14 @@ void *filestr(long *allocsizep,char *_fname) char *send_curl(char *url,char *fname) { - long fsize; char curlstr[1024],*retstr,*retstr2; - sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); - //retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,"","",""); - - if ( system(curlstr) != 0 ) - fprintf(stderr,"error doing system(%s)\n",curlstr); - return((char *)filestr(&fsize,fname)); + //long fsize; char curlstr[1024]; + //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + char *retstr=0,*retstr2; + retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,"","",""); + return(retstr2); + //if ( system(curlstr) != 0 ) + // fprintf(stderr,"error doing system(%s)\n",curlstr); + //return((char *)filestr(&fsize,fname)); } cJSON *get_urljson(char *url,char *fname) From 5bbe79b586a6ba832fd779806eed5ba8cc341d10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:11:07 -1100 Subject: [PATCH 137/385] Sleep --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 658ed2406..8798fa68f 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -52,7 +52,7 @@ void *gamesiterate(struct games_state *rs) if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep_milli(10000); + sleep(1); price = get_btcusd(); fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/SATOSHIDEN); /*if ( (counter++ % 10) == 0 ) From 73cc7ba642629343f8b7ef6e6553b3e19771c8b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:11:31 -1100 Subject: [PATCH 138/385] (char *) --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 8798fa68f..32e7e509c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -188,7 +188,7 @@ char *send_curl(char *url,char *fname) //long fsize; char curlstr[1024]; //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); char *retstr=0,*retstr2; - retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,"","",""); + retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,(char *)"",(char *)"",(char *)""); return(retstr2); //if ( system(curlstr) != 0 ) // fprintf(stderr,"error doing system(%s)\n",curlstr); From e7373723f4693bcfcef5900cf4a847a764048f0e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:12:38 -1100 Subject: [PATCH 139/385] Units --- src/cc/games/prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 32e7e509c..41ddb8fd7 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -1,6 +1,7 @@ #include "prices.h" #include +#include #define SATOSHIDEN ((uint64_t)100000000L) /* @@ -52,7 +53,7 @@ void *gamesiterate(struct games_state *rs) if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep(1); + sleep(10); price = get_btcusd(); fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/SATOSHIDEN); /*if ( (counter++ % 10) == 0 ) From e2527311f2bc8e8aa2d9bf6f18313b6556e1310f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:14:56 -1100 Subject: [PATCH 140/385] Test --- src/cc/games/prices.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 41ddb8fd7..339f3293c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -190,6 +190,10 @@ char *send_curl(char *url,char *fname) //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); char *retstr=0,*retstr2; retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,(char *)"",(char *)"",(char *)""); + if ( retstr2 != 0 ) + printf("retstr2 (%s)\n",retstr2); + if ( retstr != 0 ) + printf("retstr (%s)\n",retstr); return(retstr2); //if ( system(curlstr) != 0 ) // fprintf(stderr,"error doing system(%s)\n",curlstr); @@ -201,7 +205,7 @@ cJSON *get_urljson(char *url,char *fname) char *jsonstr; cJSON *json = 0; if ( (jsonstr= send_curl(url,fname)) != 0 ) { - //printf("(%s) -> (%s)\n",url,jsonstr); + printf("(%s) -> (%s)\n",url,jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } From 63a02c688ab238141847f2ad93a0c0b1bebe7db4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:17:23 -1100 Subject: [PATCH 141/385] issue_curl --- src/cc/games/prices.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 339f3293c..6d3694d30 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -188,13 +188,11 @@ char *send_curl(char *url,char *fname) { //long fsize; char curlstr[1024]; //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); - char *retstr=0,*retstr2; - retstr2 = bitcoind_RPC(&retstr,(char *)"prices",url,(char *)"",(char *)"",(char *)""); - if ( retstr2 != 0 ) - printf("retstr2 (%s)\n",retstr2); + char *retstr; + retstr = issue_curl(url,10); if ( retstr != 0 ) printf("retstr (%s)\n",retstr); - return(retstr2); + return(retstr); //if ( system(curlstr) != 0 ) // fprintf(stderr,"error doing system(%s)\n",curlstr); //return((char *)filestr(&fsize,fname)); From 7d251f6f240333f7727384dc7fdd5dd390df4ed7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:18:30 -1100 Subject: [PATCH 142/385] #define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0,0) --- src/cc/games/prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 6d3694d30..e45222c13 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -3,6 +3,7 @@ #include #include #define SATOSHIDEN ((uint64_t)100000000L) +#define issue_curl(cmdstr) bitcoind_RPC(0,"prices",cmdstr,0,0,0,0) /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. @@ -189,7 +190,7 @@ char *send_curl(char *url,char *fname) //long fsize; char curlstr[1024]; //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); char *retstr; - retstr = issue_curl(url,10); + retstr = issue_curl(url); if ( retstr != 0 ) printf("retstr (%s)\n",retstr); return(retstr); From 82850e26352730bfcbca46c608440764e65b4001 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:19:13 -1100 Subject: [PATCH 143/385] -0 --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index e45222c13..b5eca9c50 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -3,7 +3,7 @@ #include #include #define SATOSHIDEN ((uint64_t)100000000L) -#define issue_curl(cmdstr) bitcoind_RPC(0,"prices",cmdstr,0,0,0,0) +#define issue_curl(cmdstr) bitcoind_RPC(0,"prices",cmdstr,0,0,0) /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From a0667c2488b6c8bed921501b950623def355259d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:19:49 -1100 Subject: [PATCH 144/385] Char * --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index b5eca9c50..96b7b72e0 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -3,7 +3,7 @@ #include #include #define SATOSHIDEN ((uint64_t)100000000L) -#define issue_curl(cmdstr) bitcoind_RPC(0,"prices",cmdstr,0,0,0) +#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. From a13b601d779caac72f7f98b579706df11317cece Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:20:17 -1100 Subject: [PATCH 145/385] sleep(10); --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 96b7b72e0..ff98da774 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -54,9 +54,9 @@ void *gamesiterate(struct games_state *rs) if ( rs->guiflag != 0 ) { #ifdef STANDALONE - sleep(10); price = get_btcusd(); fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/SATOSHIDEN); + sleep(10); /*if ( (counter++ % 10) == 0 ) doupdate(); c = games_readevent(rs); From ba37ac2c088950769b6e8665e398f2174f14ec66 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:25:43 -1100 Subject: [PATCH 146/385] Encode price --- src/cc/games/prices.c | 98 ++++--------------------------------------- 1 file changed, 7 insertions(+), 91 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index ff98da774..4a95ef99e 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -55,7 +55,9 @@ void *gamesiterate(struct games_state *rs) { #ifdef STANDALONE price = get_btcusd(); - fprintf(stderr,"price %llu %.8f\n",(long long)price,(double)price/SATOSHIDEN); + fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); + issue_games_events(rs,Gametxidstr,eventid,price); + eventid++; sleep(10); /*if ( (counter++ % 10) == 0 ) doupdate(); @@ -105,98 +107,11 @@ void *gamesiterate(struct games_state *rs) #include #include "dapps/dappstd.c" -char *nonportable_path(char *str) -{ - int32_t i; - for (i=0; str[i]!=0; i++) - if ( str[i] == '/' ) - str[i] = '\\'; - return(str); -} - -char *portable_path(char *str) -{ -#ifdef _WIN32 - return(nonportable_path(str)); -#else -#ifdef __PNACL - /*int32_t i,n; - if ( str[0] == '/' ) - return(str); - else - { - n = (int32_t)strlen(str); - for (i=n; i>0; i--) - str[i] = str[i-1]; - str[0] = '/'; - str[n+1] = 0; - }*/ -#endif - return(str); -#endif -} - -void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) -{ - FILE *fp; - long filesize,buflen = *allocsizep; - uint8_t *buf = *bufp; - *lenp = 0; - if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) - { - fseek(fp,0,SEEK_END); - filesize = ftell(fp); - if ( filesize == 0 ) - { - fclose(fp); - *lenp = 0; - //printf("loadfile null size.(%s)\n",fname); - return(0); - } - if ( filesize > buflen ) - { - *allocsizep = filesize; - *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); - } - rewind(fp); - if ( buf == 0 ) - printf("Null buf ???\n"); - else - { - if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) - printf("error reading filesize.%ld\n",(long)filesize); - buf[filesize] = 0; - } - fclose(fp); - *lenp = filesize; - //printf("loaded.(%s)\n",buf); - } //else printf("OS_loadfile couldnt load.(%s)\n",fname); - return(buf); -} - -void *filestr(long *allocsizep,char *_fname) -{ - long filesize = 0; char *fname,*buf = 0; void *retptr; - *allocsizep = 0; - fname = (char *)malloc(strlen(_fname)+1); - strcpy(fname,_fname); - retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); - free(fname); - return(retptr); -} - char *send_curl(char *url,char *fname) { - //long fsize; char curlstr[1024]; - //sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); char *retstr; retstr = issue_curl(url); - if ( retstr != 0 ) - printf("retstr (%s)\n",retstr); return(retstr); - //if ( system(curlstr) != 0 ) - // fprintf(stderr,"error doing system(%s)\n",curlstr); - //return((char *)filestr(&fsize,fname)); } cJSON *get_urljson(char *url,char *fname) @@ -204,7 +119,7 @@ cJSON *get_urljson(char *url,char *fname) char *jsonstr; cJSON *json = 0; if ( (jsonstr= send_curl(url,fname)) != 0 ) { - printf("(%s) -> (%s)\n",url,jsonstr); + //printf("(%s) -> (%s)\n",url,jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } @@ -217,17 +132,18 @@ cJSON *get_urljson(char *url,char *fname) uint64_t get_btcusd() { - cJSON *pjson,*bpi,*usd; uint64_t btcusd = 0; + cJSON *pjson,*bpi,*usd; uint64_t x,btcusd = 0; if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 ) { if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; + x = ((uint64_t)time(NULL) << 32) | (btcusd / 10000); printf("BTC/USD %.4f\n",dstr(btcusd)); } free_json(pjson); } - return(btcusd); + return(x); } char *clonestr(char *str) From adcf1042a1699b1f3980d5806200a421d4b43681 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:27:54 -1100 Subject: [PATCH 147/385] Broadcast --- src/cc/games/prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 4a95ef99e..7987c45a0 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -139,7 +139,7 @@ uint64_t get_btcusd() { btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; x = ((uint64_t)time(NULL) << 32) | (btcusd / 10000); - printf("BTC/USD %.4f\n",dstr(btcusd)); + //printf("BTC/USD %.4f\n",dstr(btcusd)); } free_json(pjson); } @@ -170,7 +170,7 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve if ( fp == 0 ) fp = fopen("events.log","wb"); rs->buffered[rs->num++] = c; - if ( 0 ) + if ( 1 ) { if ( sizeof(c) == 1 ) sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid); From 9e878493e9a7a55fea2ca44c019f2629d47b75af Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 00:32:04 -1100 Subject: [PATCH 148/385] +print --- src/cc/games/prices.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index cb2de54a1..82e132c7f 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -59,9 +59,9 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+33] << 8; eventid |= (uint32_t)payload[len+34] << 16; eventid |= (uint32_t)payload[len+35] << 24; - //for (i=0; i Date: Wed, 27 Mar 2019 00:50:13 -1100 Subject: [PATCH 149/385] +prints --- src/cc/gamescc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 56fd13310..dc36cc757 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -553,14 +553,14 @@ void komodo_netevent(std::vector message) { if ( (rand() % 10) == 0 ) { - //fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); + fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); komodo_sendmessage(2,2,"events",message); } } } - //for (i=0; i Date: Wed, 27 Mar 2019 00:52:39 -1100 Subject: [PATCH 150/385] +print --- src/cc/gamescc.cpp | 4 +++- src/miner.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index dc36cc757..f04ffb22f 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -477,7 +477,9 @@ int32_t games_event(uint32_t timestamp,uint256 gametxid,int32_t eventid,std::vec games_payloadrecv(mypk,timestamp,payload); komodo_sendmessage(4,8,"events",vopret); return(0); - } else return(-1); + } + fprintf(stderr,"games_eventsign error\n"); + return(-1); } UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) diff --git a/src/miner.cpp b/src/miner.cpp index eaba96ee1..ca4ce8714 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -941,6 +941,7 @@ void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,st continue; if ( numsent < minpeers || (rand() % 10) == 0 ) { + fprintf(stderr,"pushmessage\n"); pnode->PushMessage(message,payload); if ( numsent++ > maxpeers ) break; From 2bb01b26340a0e018e1241c5d34e81a2e99f17f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:26:08 -1100 Subject: [PATCH 151/385] fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); --- src/cc/games/prices.cpp | 5 +++-- src/cc/gamescc.cpp | 6 +++--- src/miner.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 82e132c7f..4c9698593 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -49,7 +49,7 @@ int32_t disp_gamesplayer(char *str,struct games_player *P) int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) { - uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; + uint256 gametxid; int32_t i,len; char str[67]; int64_t price; uint32_t eventid = 0; if ( (len= payload.size()) > 36 ) { len -= 36; @@ -60,7 +60,8 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+34] << 16; eventid |= (uint32_t)payload[len+35] << 24; for (i=0; i t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); return(0); } else return(-1); diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index f04ffb22f..17b0d371b 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -555,13 +555,13 @@ void komodo_netevent(std::vector message) { if ( (rand() % 10) == 0 ) { - fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); + //fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); komodo_sendmessage(2,2,"events",message); } } } - for (i=0; iPushMessage(message,payload); if ( numsent++ > maxpeers ) break; From c9446180181a0d093e7af2ef9f319d0c611cc53b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:28:55 -1100 Subject: [PATCH 152/385] Test --- src/cc/games/prices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 4c9698593..3f71c786c 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -59,8 +59,8 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+33] << 8; eventid |= (uint32_t)payload[len+34] << 16; eventid |= (uint32_t)payload[len+35] << 24; - for (i=0; i t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); return(0); From c3e822b232a59a0255cbc8fc4856b3ffd5ff2197 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:37:10 -1100 Subject: [PATCH 153/385] prices_update --- src/cc/games/prices.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 3f71c786c..b9f9bfc76 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,6 +14,12 @@ * * ******************************************************************************/ + +void prices_update(uint32_t timestamp,uint32_t uprice) +{ + fprintf(stderr,"%t%u %.4f ",timstamp,uprice); +} + // game specific code for daemon void games_packitemstr(char *packitemstr,struct games_packitem *item) { @@ -61,8 +67,9 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+35] << 24; for (i=0; i t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); - fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); + prices_update((uint32_t)(price >> 32),(uint32_t)(price & 0xffffffff)/10000); + //fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); + //fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); return(0); } else return(-1); } From c428d5b8cb86f09cc4c0b6d074f0707b4d472dfe Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:39:18 -1100 Subject: [PATCH 154/385] Timestamp --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index b9f9bfc76..a103c5f70 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,7 +17,7 @@ void prices_update(uint32_t timestamp,uint32_t uprice) { - fprintf(stderr,"%t%u %.4f ",timstamp,uprice); + fprintf(stderr,"%t%u %.4f ",timestamp,uprice); } // game specific code for daemon From 1b86b9a1a36644bb5795dfb0cc7c172b5addfe21 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:39:54 -1100 Subject: [PATCH 155/385] Fix --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index a103c5f70..c57fd5c36 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,7 +17,7 @@ void prices_update(uint32_t timestamp,uint32_t uprice) { - fprintf(stderr,"%t%u %.4f ",timestamp,uprice); + fprintf(stderr,"%t%u %.4f\n",timestamp,(double)uprice/1000); } // game specific code for daemon From 837200f4eec248e53c87c9ec7f8e93edd17655bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:40:41 -1100 Subject: [PATCH 156/385] -% --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index c57fd5c36..f042b6b1f 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,7 +17,7 @@ void prices_update(uint32_t timestamp,uint32_t uprice) { - fprintf(stderr,"%t%u %.4f\n",timestamp,(double)uprice/1000); + fprintf(stderr,"t%u %.4f\n",timestamp,(double)uprice/1000); } // game specific code for daemon From 76bcf303657bec09079e52fa615a985bbd2a28e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:42:07 -1100 Subject: [PATCH 157/385] -/10000 --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index f042b6b1f..29ca9759e 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -67,7 +67,7 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+35] << 24; for (i=0; i> 32),(uint32_t)(price & 0xffffffff)/10000); + prices_update((uint32_t)(price >> 32),(uint32_t)(price & 0xffffffff)); //fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); //fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); return(0); From 1717fb6d87d5203149bfd239fc062a47d11b496b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:42:56 -1100 Subject: [PATCH 158/385] -print --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 7987c45a0..ed3dae051 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -55,7 +55,7 @@ void *gamesiterate(struct games_state *rs) { #ifdef STANDALONE price = get_btcusd(); - fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); + //fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); issue_games_events(rs,Gametxidstr,eventid,price); eventid++; sleep(10); From c993184197994d899a33073d3ef5b4b51c62168e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:45:39 -1100 Subject: [PATCH 159/385] 10000 --- src/cc/games/prices.c | 2 +- src/cc/games/prices.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index ed3dae051..67e66bfed 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -138,7 +138,7 @@ uint64_t get_btcusd() if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; - x = ((uint64_t)time(NULL) << 32) | (btcusd / 10000); + x = ((uint64_t)time(NULL) << 32) | ((btcusd / 10000) & 0xffffffff); //printf("BTC/USD %.4f\n",dstr(btcusd)); } free_json(pjson); diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 29ca9759e..7428dfb3b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,7 +17,7 @@ void prices_update(uint32_t timestamp,uint32_t uprice) { - fprintf(stderr,"t%u %.4f\n",timestamp,(double)uprice/1000); + fprintf(stderr,"t%u %.4f\n",timestamp,(double)uprice/10000); } // game specific code for daemon From a2d44907bd3009b333ba75bd37fd60a2b57afc4f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 01:48:14 -1100 Subject: [PATCH 160/385] Is mine --- src/cc/games/prices.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 7428dfb3b..d3f74a287 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -15,9 +15,9 @@ ******************************************************************************/ -void prices_update(uint32_t timestamp,uint32_t uprice) +void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) { - fprintf(stderr,"t%u %.4f\n",timestamp,(double)uprice/10000); + fprintf(stderr,"%s t%u %.4f\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000); } // game specific code for daemon @@ -67,7 +67,7 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay eventid |= (uint32_t)payload[len+35] << 24; for (i=0; i> 32),(uint32_t)(price & 0xffffffff)); + prices_update((uint32_t)(price >> 32),(uint32_t)(price & 0xffffffff),pk == pubkey2pk(Mypubkey())); //fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); //fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); return(0); From 3d425a23fd790bf83592471e1914ba16cf4ef4c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:07:01 -1100 Subject: [PATCH 161/385] Net_change --- src/cc/games/prices.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 67e66bfed..421fb8ff0 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -4,6 +4,7 @@ #include #define SATOSHIDEN ((uint64_t)100000000L) #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) +extern int64_t Net_change; /* In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. @@ -59,6 +60,11 @@ void *gamesiterate(struct games_state *rs) issue_games_events(rs,Gametxidstr,eventid,price); eventid++; sleep(10); + switch ( getch() ) + { + case '+': Net_change++; break; + case '-': Net_change--; break; + } /*if ( (counter++ % 10) == 0 ) doupdate(); c = games_readevent(rs); @@ -106,6 +112,7 @@ void *gamesiterate(struct games_state *rs) #ifdef STANDALONE #include #include "dapps/dappstd.c" +int64_t Net_change; char *send_curl(char *url,char *fname) { @@ -132,14 +139,16 @@ cJSON *get_urljson(char *url,char *fname) uint64_t get_btcusd() { - cJSON *pjson,*bpi,*usd; uint64_t x,btcusd = 0; + cJSON *pjson,*bpi,*usd; uint64_t x,newprice,mult,btcusd = 0; if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 ) { if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; - x = ((uint64_t)time(NULL) << 32) | ((btcusd / 10000) & 0xffffffff); - //printf("BTC/USD %.4f\n",dstr(btcusd)); + mult = SATOSHIDEN + Net_change*100000; + newprice = (btcusd * mult) / SATOSHIDEN; + x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); + printf("BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); } free_json(pjson); } From 9363ef04111d567bf316ee2def799a57ad5edce2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:10:14 -1100 Subject: [PATCH 162/385] cursesd --- src/cc/games/prices.c | 6 ++++++ src/cc/games/tetris.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 421fb8ff0..9d3014fdb 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -2,6 +2,12 @@ #include "prices.h" #include #include +#ifdef BUILD_GAMESCC +#include "../rogue/cursesd.h" +#else +#include +#endif + #define SATOSHIDEN ((uint64_t)100000000L) #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) extern int64_t Net_change; diff --git a/src/cc/games/tetris.c b/src/cc/games/tetris.c index 254d324a8..711170b0d 100644 --- a/src/cc/games/tetris.c +++ b/src/cc/games/tetris.c @@ -43,7 +43,7 @@ int32_t tetrisdata(struct games_player *P,void *ptr) #include #ifdef BUILD_GAMESCC -#include "rogue/cursesd.h" +#include "../rogue/cursesd.h" #else #include #endif From f3123a4d5b40a205fff13664dc188c02cddf52cc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:12:25 -1100 Subject: [PATCH 163/385] Test --- src/cc/games/prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 9d3014fdb..0856eaa32 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -151,8 +151,8 @@ uint64_t get_btcusd() if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) { btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; - mult = SATOSHIDEN + Net_change*100000; - newprice = (btcusd * mult) / SATOSHIDEN; + mult = 10000 + Net_change*10; + newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); printf("BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); } From 3da222eae80b71ed44de24f4f8e1deba536554b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:14:33 -1100 Subject: [PATCH 164/385] Activate curses --- src/cc/games/prices.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 0856eaa32..b0a16a3cc 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -51,6 +51,9 @@ void *gamesiterate(struct games_state *rs) bool running = true; uint32_t eventid = 0; int64_t price; if ( rs->guiflag != 0 || rs->sleeptime != 0 ) { + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen } while ( running != 0 ) { From 86491b25f022a553a27fdc371fdeb53f95fa7eb8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:18:33 -1100 Subject: [PATCH 165/385] Test --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index b0a16a3cc..7d3daef1f 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -157,7 +157,7 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - printf("BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); + fprintf(stderr,"BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); } free_json(pjson); } From d87dcb4d44d197b5feafebbc85c0a67291650053 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:25:14 -1100 Subject: [PATCH 166/385] Display --- src/cc/games/prices.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 7d3daef1f..b6bb6a640 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -148,7 +148,7 @@ cJSON *get_urljson(char *url,char *fname) uint64_t get_btcusd() { - cJSON *pjson,*bpi,*usd; uint64_t x,newprice,mult,btcusd = 0; + cJSON *pjson,*bpi,*usd; char str[512]; uint64_t x,newprice,mult,btcusd = 0; if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 ) { if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) @@ -157,7 +157,10 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - fprintf(stderr,"BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); + sprintf(str,"BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); + mvaddstr(0, 0, str); + clrtoeol(); + refresh(); } free_json(pjson); } From 829e9811647042f87441b4a2ea1c167f070c5c72 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:27:58 -1100 Subject: [PATCH 167/385] doupdate --- src/cc/games/prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index b6bb6a640..3ac7e76fe 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -68,6 +68,7 @@ void *gamesiterate(struct games_state *rs) //fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); issue_games_events(rs,Gametxidstr,eventid,price); eventid++; + doupdate(); sleep(10); switch ( getch() ) { @@ -160,7 +161,7 @@ uint64_t get_btcusd() sprintf(str,"BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); mvaddstr(0, 0, str); clrtoeol(); - refresh(); + doupdate(); } free_json(pjson); } From 6c14369eac9c83af9fab18b9527d1b542728193c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:44:28 -1100 Subject: [PATCH 168/385] timeout(0); --- src/cc/games/prices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 3ac7e76fe..97c617be7 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -54,6 +54,7 @@ void *gamesiterate(struct games_state *rs) initscr(); // initialize curses cbreak(); // pass key presses to program, but not signals noecho(); // don't echo key presses to screen + timeout(0); } while ( running != 0 ) { From 46bd37f80083ca7fb5ab27e6d87ff56585935d55 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 02:50:42 -1100 Subject: [PATCH 169/385] -print --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index d3f74a287..9db720907 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,7 +17,7 @@ void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) { - fprintf(stderr,"%s t%u %.4f\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000); + //fprintf(stderr,"%s t%u %.4f\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000); } // game specific code for daemon From 89913fa6ae498be1d9bbe96dcf86694182a0e579 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 03:46:03 -1100 Subject: [PATCH 170/385] pricedata --- src/cc/games/prices.c | 6 ------ src/cc/games/prices.cpp | 40 +++++++++++++++++++++++++++++++++++++++- src/cc/games/tetris.cpp | 6 ++++++ src/cc/gamescc.cpp | 2 +- src/cc/gamescc.h | 6 +++++- 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 97c617be7..3d4a65e14 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -12,12 +12,6 @@ #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) extern int64_t Net_change; -/* - In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. - - also, the standalone game needs to support argv of seed gametxid, along with replay args - */ - int random_tetromino(struct games_state *rs) { rs->seed = _games_rngnext(rs->seed); diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 9db720907..a903355e4 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,10 +14,48 @@ * * ******************************************************************************/ +UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t inputsum,price; CPubKey mypk; + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + { + if ( cclib_parsehash(&price,jitem(params,0),8) < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parsehash")); + } + mypk = pubkey2pk(Mypubkey()); + if ( amount > GAMES_TXFEE ) + { + if ( (inputsum= AddNormalinputs(mtx,mypk,GAMES_TXFEE,64)) >= GAMES_TXFEE ) + { + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); + return(games_rawtxresult(result,rawtx,1)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","amount too small")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } + return(result); +} void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) { - //fprintf(stderr,"%s t%u %.4f\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000); + fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)(timestamp<<32) | uprice); } // game specific code for daemon diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp index f1b6416ba..12c443e1e 100644 --- a/src/cc/games/tetris.cpp +++ b/src/cc/games/tetris.cpp @@ -66,6 +66,12 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay } else return(-1); } +UniValue games_oracledata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result; + return(result); +} + bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { return(true); diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 17b0d371b..77b463822 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1731,7 +1731,7 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); - return(games_rawtxresult(result,rawtx,1)); + return(games_rawtxresult(resulft,rawtx,1)); } else { diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 63d029b0a..19f3f66cf 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -46,6 +46,7 @@ std::string Games_pname; { (char *)MYCCNAME, (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"pricedata", (char *)"hexstr", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES }, bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); @@ -65,6 +66,7 @@ UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ @@ -100,7 +102,9 @@ if ( cp->evalcode == EVAL_GAMES ) \ else if ( strcmp(method,"highlander") == 0 ) \ return(games_highlander(txfee,cp,params)); \ else if ( strcmp(method,"fund") == 0 ) \ - return(games_fund(txfee,cp,params)); \ + return(games_fund(txfee,cp,params)); \ + else if ( strcmp(method,"pricedata") == 0 ) \ + return(games_pricedata(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 9e4f5663da07dcfcafbdf12b172da00263bc385c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 03:49:23 -1100 Subject: [PATCH 171/385] Test --- src/cc/games/prices.cpp | 22 ++++++++-------------- src/cc/gamescc.cpp | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index a903355e4..88fdab88a 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,35 +14,29 @@ * * ******************************************************************************/ +UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); + UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); std::string rawtx; int64_t inputsum,price; CPubKey mypk; if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { - if ( cclib_parsehash(&price,jitem(params,0),8) < 0 ) + if ( cclib_parsehash((uint8_t *)&price,jitem(params,0),8) < 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parsehash")); } mypk = pubkey2pk(Mypubkey()); - if ( amount > GAMES_TXFEE ) + if ( (inputsum= AddNormalinputs(mtx,mypk,GAMES_TXFEE,64)) >= GAMES_TXFEE ) { - if ( (inputsum= AddNormalinputs(mtx,mypk,GAMES_TXFEE,64)) >= GAMES_TXFEE ) - { - rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); - return(games_rawtxresult(result,rawtx,1)); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough funds")); - } + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); + return(games_rawtxresult(result,rawtx,1)); } else { result.push_back(Pair("result","error")); - result.push_back(Pair("error","amount too small")); + result.push_back(Pair("error","not enough funds")); } } else @@ -55,7 +49,7 @@ UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) { - fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)(timestamp<<32) | uprice); + fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice); } // game specific code for daemon diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp index 77b463822..17b0d371b 100644 --- a/src/cc/gamescc.cpp +++ b/src/cc/gamescc.cpp @@ -1731,7 +1731,7 @@ UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); - return(games_rawtxresult(resulft,rawtx,1)); + return(games_rawtxresult(result,rawtx,1)); } else { From c0798791e9d99b235d4efcf493a18bf9ee064d00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:05:10 -1100 Subject: [PATCH 172/385] Bet --- src/cc/games/prices.cpp | 11 +++++++---- src/cc/gamescc.h | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 88fdab88a..03fcff33a 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -19,17 +19,20 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastf UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t inputsum,price; CPubKey mypk; - if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey mypk; + if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { - if ( cclib_parsehash((uint8_t *)&price,jitem(params,0),8) < 0 ) + amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; + if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parsehash")); } mypk = pubkey2pk(Mypubkey()); - if ( (inputsum= AddNormalinputs(mtx,mypk,GAMES_TXFEE,64)) >= GAMES_TXFEE ) + gamespk = GetUnspendable(cp,0); + if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); return(games_rawtxresult(result,rawtx,1)); } diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 19f3f66cf..bfaf036d0 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -46,7 +46,7 @@ std::string Games_pname; { (char *)MYCCNAME, (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \ - { (char *)MYCCNAME, (char *)"pricedata", (char *)"hexstr", 1, 1, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"bet", (char *)"amount hexstr", 2, 2, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES }, bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); @@ -66,7 +66,7 @@ UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); -UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ @@ -103,8 +103,8 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_highlander(txfee,cp,params)); \ else if ( strcmp(method,"fund") == 0 ) \ return(games_fund(txfee,cp,params)); \ - else if ( strcmp(method,"pricedata") == 0 ) \ - return(games_pricedata(txfee,cp,params)); \ + else if ( strcmp(method,"bet") == 0 ) \ + return(games_bet(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 29fc5b9ea069e79f0477619c26fb587e79fa3caa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:05:50 -1100 Subject: [PATCH 173/385] Gamespk --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 03fcff33a..27d41ca9b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -19,7 +19,7 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastf UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey mypk; + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey gamespk,mypk; if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; From 8e4a613eb06e25db6e32d97edb67df763b7d36c3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:06:39 -1100 Subject: [PATCH 174/385] games_bet --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 27d41ca9b..e099d57af 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -16,7 +16,7 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); -UniValue games_pricedata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey gamespk,mypk; From 7c1c706f18a7062bae09d59df1754e8afae85a77 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:10:39 -1100 Subject: [PATCH 175/385] Test --- src/cc/games/prices.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index e099d57af..296d80a8c 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -28,6 +28,7 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parsehash")); } + fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) From 3de3e931bb5afee45f9cd1369676d3cbb6a9c648 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:12:41 -1100 Subject: [PATCH 176/385] Test --- src/cc/gamescc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index bfaf036d0..52627cd1c 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -109,7 +109,6 @@ if ( cp->evalcode == EVAL_GAMES ) \ { \ result.push_back(Pair("result","error")); \ result.push_back(Pair("error","invalid gamescc method")); \ - result.push_back(Pair("method",method)); \ return(result); \ } \ } From 2bf9af5f57333ddfb49df056d89e5a2dd8949dfc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:13:19 -1100 Subject: [PATCH 177/385] Test --- src/cc/gamescc.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 52627cd1c..af888ed05 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -71,6 +71,7 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ { \ + UniValue res; \ if ( strcmp(method,"rng") == 0 ) \ return(games_rng(txfee,cp,params)); \ else if ( strcmp(method,"rngnext") == 0 ) \ @@ -107,9 +108,9 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_bet(txfee,cp,params)); \ else \ { \ - result.push_back(Pair("result","error")); \ - result.push_back(Pair("error","invalid gamescc method")); \ - return(result); \ + res.push_back(Pair("result","error")); \ + res.push_back(Pair("error","invalid gamescc method")); \ + return(res); \ } \ } #endif From 2660c2b7f8d43f10c13ea003e73505258c8fc4de Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:50:17 -1100 Subject: [PATCH 178/385] issue_bet --- src/cc/games/prices.c | 34 ++++++++++++++++++++++++++++++---- src/cc/gamescc.h | 7 +++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 3d4a65e14..52ddc477c 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -10,7 +10,7 @@ #define SATOSHIDEN ((uint64_t)100000000L) #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) -extern int64_t Net_change; +extern int64_t Net_change,Betsize; int random_tetromino(struct games_state *rs) { @@ -39,6 +39,7 @@ struct games_state globalR; extern char Gametxidstr[]; int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); uint64_t get_btcusd(); +int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize); void *gamesiterate(struct games_state *rs) { @@ -61,7 +62,8 @@ void *gamesiterate(struct games_state *rs) #ifdef STANDALONE price = get_btcusd(); //fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); - issue_games_events(rs,Gametxidstr,eventid,price); + //issue_games_events(rs,Gametxidstr,eventid,price); + issue_bet(rs,price,Betsize); eventid++; doupdate(); sleep(10); @@ -69,6 +71,10 @@ void *gamesiterate(struct games_state *rs) { case '+': Net_change++; break; case '-': Net_change--; break; + case '0': Net_change = 0; break; + case '$': Betsize = SATOSHIDEN; break; + case '^': Betsize += (Betsize >> 3); break; + case '/': Betsize -= (Betsize >> 3); break; } /*if ( (counter++ % 10) == 0 ) doupdate(); @@ -117,7 +123,7 @@ void *gamesiterate(struct games_state *rs) #ifdef STANDALONE #include #include "dapps/dappstd.c" -int64_t Net_change; +int64_t Net_change,Betsize; char *send_curl(char *url,char *fname) { @@ -153,7 +159,7 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - sprintf(str,"BTC/USD %.4f Net_change %lld * 0.001 -> %.4f\n",dstr(btcusd),(long long)Net_change,dstr(newprice)); + sprintf(str,"BTC/USD %.4f Net_change %lld * 0.001 -> Betsize %.8f %.4f\n",dstr(btcusd),(long long)Net_change,dstr(Betsize),dstr(newprice)); mvaddstr(0, 0, str); clrtoeol(); doupdate(); @@ -218,6 +224,26 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve } else return(0); } +int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) +{ + char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(x),hexstr); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + fprintf(stderr,"%s\n",jprint(resobj,0)); + } + free_json(retjson); + } + free(retstr); + } + return(retval); +} + int prices(int argc, char **argv) { struct games_state *rs = &globalR; diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index af888ed05..52627cd1c 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -71,7 +71,6 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ { \ - UniValue res; \ if ( strcmp(method,"rng") == 0 ) \ return(games_rng(txfee,cp,params)); \ else if ( strcmp(method,"rngnext") == 0 ) \ @@ -108,9 +107,9 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_bet(txfee,cp,params)); \ else \ { \ - res.push_back(Pair("result","error")); \ - res.push_back(Pair("error","invalid gamescc method")); \ - return(res); \ + result.push_back(Pair("result","error")); \ + result.push_back(Pair("error","invalid gamescc method")); \ + return(result); \ } \ } #endif From 72922243f989904eb2cbe97bc60dce2d2bf52d0b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:53:38 -1100 Subject: [PATCH 179/385] Fix --- src/cc/games/prices.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 52ddc477c..93c89ab83 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -227,7 +227,13 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) { char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; - sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(x),hexstr); + memset(hexstr,0,sizeof(hexstr)); + for (i=0; i<8; i++) + { + sprintf(&hexstr[i<<1],"%02x",x & 0xff); + x >>= 8; + } + sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(betsize),hexstr); if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) From 251d6fb88f962c9b4fbaf165b42312d4138f778e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:54:29 -1100 Subject: [PATCH 180/385] I --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 93c89ab83..13b0c4934 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -226,7 +226,7 @@ int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eve int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) { - char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t i,retval = -1; memset(hexstr,0,sizeof(hexstr)); for (i=0; i<8; i++) { From 05b91ae06385927e506d040f330a5148057e2d79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 04:55:34 -1100 Subject: [PATCH 181/385] Test --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 13b0c4934..f33838c64 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -230,7 +230,7 @@ int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) memset(hexstr,0,sizeof(hexstr)); for (i=0; i<8; i++) { - sprintf(&hexstr[i<<1],"%02x",x & 0xff); + sprintf(&hexstr[i<<1],"%02x",(uint8_t)(x & 0xff)); x >>= 8; } sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(betsize),hexstr); From dbb8f0acc20634c44c6b5378f5ef5d35b349a9b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 06:02:13 -1100 Subject: [PATCH 182/385] Test --- src/cc/games/prices.c | 6 +++--- src/cc/games/prices.cpp | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index f33838c64..271271a67 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -123,7 +123,7 @@ void *gamesiterate(struct games_state *rs) #ifdef STANDALONE #include #include "dapps/dappstd.c" -int64_t Net_change,Betsize; +int64_t Net_change,Betsize = SATOSHIDEN; char *send_curl(char *url,char *fname) { @@ -159,7 +159,7 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - sprintf(str,"BTC/USD %.4f Net_change %lld * 0.001 -> Betsize %.8f %.4f\n",dstr(btcusd),(long long)Net_change,dstr(Betsize),dstr(newprice)); + sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice)); mvaddstr(0, 0, str); clrtoeol(); doupdate(); @@ -241,7 +241,7 @@ int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) { retval = 0; - fprintf(stderr,"%s\n",jprint(resobj,0)); + //fprintf(stderr,"%s\n",jprint(resobj,0)); } free_json(retjson); } diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 296d80a8c..a49fc1982 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -15,11 +15,18 @@ ******************************************************************************/ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); +extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey gamespk,mypk; + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey gamespk,mypk,acpk; + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error"," no -ac_pubkey for price reference")); + } + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; @@ -28,7 +35,9 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parsehash")); } - fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); + if ( mypk == acpk ) + amount = 0; // i am the reference price feed + //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) @@ -53,7 +62,7 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) { - fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice); + //fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice); } // game specific code for daemon From f18867055dddeea88e1ce5e880c8f75e292e73c4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 06:45:23 -1100 Subject: [PATCH 183/385] Test --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 271271a67..99b95f7c2 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -159,7 +159,7 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice)); + sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*mult/10000); mvaddstr(0, 0, str); clrtoeol(); doupdate(); From 2dfd8dacdb4f192f70523c5bc83ff8fb069adac6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 06:47:03 -1100 Subject: [PATCH 184/385] Display perc --- src/cc/games/prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.c b/src/cc/games/prices.c index 99b95f7c2..1bc62533e 100644 --- a/src/cc/games/prices.c +++ b/src/cc/games/prices.c @@ -159,7 +159,7 @@ uint64_t get_btcusd() mult = 10000 + Net_change*10; newprice = (btcusd * mult) / 10000; x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); - sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*mult/10000); + sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*(mult-10000)/10000); mvaddstr(0, 0, str); clrtoeol(); doupdate(); From 7596077f2a3fbe657dc6897906cf1d0d9c20cfc7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:10:30 -1100 Subject: [PATCH 185/385] Settle stub --- src/cc/games/prices.cpp | 7 +++++++ src/cc/games/tetris.cpp | 8 +++++++- src/cc/gamescc.h | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index a49fc1982..4098a3980 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -17,6 +17,13 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; + +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result; + return(result); +} + UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp index 12c443e1e..d1ca9c30b 100644 --- a/src/cc/games/tetris.cpp +++ b/src/cc/games/tetris.cpp @@ -66,7 +66,13 @@ int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector pay } else return(-1); } -UniValue games_oracledata(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result; + return(result); +} + +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result; return(result); diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 52627cd1c..7a6b7c66c 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -47,6 +47,7 @@ std::string Games_pname; { (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"bet", (char *)"amount hexstr", 2, 2, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"settle", (char *)"height", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES }, bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); @@ -67,6 +68,7 @@ UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ @@ -105,6 +107,8 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_fund(txfee,cp,params)); \ else if ( strcmp(method,"bet") == 0 ) \ return(games_bet(txfee,cp,params)); \ + else if ( strcmp(method,"settle") == 0 ) \ + return(games_settle(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 00eee20935f82635587776b527de745628a9dedb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:33:33 -1100 Subject: [PATCH 186/385] Settle stub --- src/cc/games/prices.cpp | 50 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 4098a3980..7bc540171 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,24 +14,69 @@ * * ******************************************************************************/ +#define PRICES_BETPERIOD 3 UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + { + height = juint(jitem(params,0),0); + result.push_back(Pair("height",(int64_t)height)); + if ( (pindex= komodo_chainactive(height)) != 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + { + n = pindex->block.vtx.size(); + for (i=0; i 1 ) + { + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + E_UNMARSHAL(vopret,ss >> pricebits); + fprintf(stderr,"i.%d %.8f %llx\n",i,(double)tx.vout[0].nValue/COIN,(long long)pricebits); + } + } + // display bets + if ( height <= nextheight-PRICES_BETPERIOD ) + { + // settle bets + } + result.push_back(Pair("result","success")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","cant load block at height")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","cant find block at height")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } return(result); } UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum,price; CPubKey gamespk,mypk,acpk; + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error"," no -ac_pubkey for price reference")); + return(result); } acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); if ( params != 0 && cJSON_GetArraySize(params) == 2 ) @@ -41,6 +86,7 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parsehash")); + return(result); } if ( mypk == acpk ) amount = 0; // i am the reference price feed From ed6a4160aa30c9fcc3d7d9ec0d6550cd1132a2b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:38:43 -1100 Subject: [PATCH 187/385] block.vtx --- src/cc/CCinclude.h | 1 + src/cc/games/prices.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 839fd2c95..12b4a6d12 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -197,6 +197,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector payload); int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t len); +int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets); diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 7bc540171..9909144f0 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -30,7 +30,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { if ( komodo_blockload(block,pindex) == 0 ) { - n = pindex->block.vtx.size(); + n = block.vtx.size(); for (i=0; i Date: Wed, 27 Mar 2019 07:51:09 -1100 Subject: [PATCH 188/385] +prints --- src/cc/games/prices.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 9909144f0..271470219 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -21,7 +21,7 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,pricebits; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); @@ -38,7 +38,9 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); E_UNMARSHAL(vopret,ss >> pricebits); - fprintf(stderr,"i.%d %.8f %llx\n",i,(double)tx.vout[0].nValue/COIN,(long long)pricebits); + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f\n",scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000); } } // display bets From 68802af3193756d5a4671f120f95893f630c079b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:51:56 -1100 Subject: [PATCH 189/385] Price --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 271470219..305d64f4e 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -21,7 +21,7 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,pricebits; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,uprice; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); From a26f3ea4a4c0eb4bfdae017c4c9883767475524c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:52:38 -1100 Subject: [PATCH 190/385] tx.vout[numvouts-1]. --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 305d64f4e..790f4a687 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -40,7 +40,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f\n",scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f\n",tx.vout[numvouts-1].scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000); } } // display bets From f003d0d8befcafd6010a47cf6e1fe7239af8f81d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:53:33 -1100 Subject: [PATCH 191/385] Test --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 790f4a687..de16a7f2b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -40,7 +40,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f\n",tx.vout[numvouts-1].scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d\n",tx.vout[numvouts-1].scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts); } } // display bets From a1a8014f057355d12e1580bc2b4988c4890583f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 07:54:17 -1100 Subject: [PATCH 192/385] scriptPubKey --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index de16a7f2b..ba78e8560 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -40,7 +40,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d\n",tx.vout[numvouts-1].scriptPubkey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts); } } // display bets From 4a998b2595fe111192bada2dff1a425d057ec14c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:01:21 -1100 Subject: [PATCH 193/385] +print --- src/cc/games/prices.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index ba78e8560..1171c3aba 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -34,7 +34,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) for (i=0; i 1 ) + if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) { GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); E_UNMARSHAL(vopret,ss >> pricebits); @@ -91,7 +91,10 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } if ( mypk == acpk ) + { amount = 0; // i am the reference price feed + fprintf(stderr,"i am the reference\n"); + } //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); From 03f663ea3795c3b146f54a819db3407ff1714950 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:04:06 -1100 Subject: [PATCH 194/385] Reorder --- src/cc/games/prices.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 1171c3aba..f5a866727 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -21,7 +21,10 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,uprice; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); @@ -80,6 +83,8 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("error"," no -ac_pubkey for price reference")); return(result); } + mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { @@ -93,11 +98,9 @@ UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) if ( mypk == acpk ) { amount = 0; // i am the reference price feed - fprintf(stderr,"i am the reference\n"); + //fprintf(stderr,"i am the reference\n"); } //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); From a28e03acdd52e6dec2c2b5b3ecdb646e3fbbb558 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:14:39 -1100 Subject: [PATCH 195/385] Test --- src/cc/games/prices.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index f5a866727..69c45f286 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -21,10 +21,11 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; int32_t i,n,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; char acaddr[64],destaddr[64]; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,height,nextheight = komodo_nextheight(); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); @@ -34,16 +35,24 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) if ( komodo_blockload(block,pindex) == 0 ) { n = block.vtx.size(); + vini = 0; for (i=0; i 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) + if ( myGetTransaction(tx.vin[vini].prevout.hash,vintx,hashBlock) == 0 ) + continue; + else if ( Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) + continue; + else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) { + prizefund += tx.vout[0].nValue; GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts); + if ( strcmp(acaddr,destaddr) == 0 ) + fprintf(stderr,"REF "); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); } } // display bets @@ -51,6 +60,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { // settle bets } + result.push_back(Pair("prizefund",ValueToAmount(prizefund))); result.push_back(Pair("result","success")); } else From d23d46d9534325fd2c4a149c2aab6845db73560c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:19:18 -1100 Subject: [PATCH 196/385] ValueFromAmount --- src/cc/games/prices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 69c45f286..64699dfe7 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -21,7 +21,7 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx; uint64_t pricebits; char acaddr[64],destaddr[64]; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char acaddr[64],destaddr[64]; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,height,nextheight = komodo_nextheight(); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); @@ -60,7 +60,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { // settle bets } - result.push_back(Pair("prizefund",ValueToAmount(prizefund))); + result.push_back(Pair("prizefund",ValueFromAmount(prizefund))); result.push_back(Pair("result","success")); } else From d2fbc97ee88f5f421c6bd04ca7af37a7abc3bcbd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:21:49 -1100 Subject: [PATCH 197/385] -print --- src/cc/games/prices.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 64699dfe7..146f6a926 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -50,9 +50,9 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - if ( strcmp(acaddr,destaddr) == 0 ) - fprintf(stderr,"REF "); - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); + //if ( strcmp(acaddr,destaddr) == 0 ) + // fprintf(stderr,"REF "); + //fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); } } // display bets From a5406418471059ca5594fbbf7c3d5ff7f6416221 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:30:19 -1100 Subject: [PATCH 198/385] Test --- src/cc/games/prices.cpp | 83 +++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 146f6a926..770cdfc8e 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -18,10 +18,41 @@ UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; +int64_t prices_blockinfo(int32_t height,char *acaddr) +{ + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts; + if ( (pindex= komodo_chainactive(height)) != 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + { + n = block.vtx.size(); + vini = 0; + for (i=0; i= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) + continue; + else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) + { + prizefund += tx.vout[0].nValue; + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + E_UNMARSHAL(vopret,ss >> pricebits); + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + //if ( strcmp(acaddr,destaddr) == 0 ) + // fprintf(stderr,"REF "); + //fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); + } + } + } else return(-2); + } else return(-1); +} UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char acaddr[64],destaddr[64]; uint32_t timestamp,uprice; CPubKey acpk,mypk,gamespk; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,height,nextheight = komodo_nextheight(); + UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); @@ -30,49 +61,21 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { height = juint(jitem(params,0),0); result.push_back(Pair("height",(int64_t)height)); - if ( (pindex= komodo_chainactive(height)) != 0 ) + if ( 1 || (prizefund= prices_blockinfo(height,acaddr)) < 0 ) { - if ( komodo_blockload(block,pindex) == 0 ) - { - n = block.vtx.size(); - vini = 0; - for (i=0; i 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) - { - prizefund += tx.vout[0].nValue; - GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - E_UNMARSHAL(vopret,ss >> pricebits); - timestamp = (uint32_t)(pricebits >> 32); - uprice = (uint32_t)pricebits; - //if ( strcmp(acaddr,destaddr) == 0 ) - // fprintf(stderr,"REF "); - //fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); - } - } - // display bets - if ( height <= nextheight-PRICES_BETPERIOD ) - { - // settle bets - } - result.push_back(Pair("prizefund",ValueFromAmount(prizefund))); - result.push_back(Pair("result","success")); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","cant load block at height")); - } + result.push_back(Pair("result","error")); + result.push_back(Pair("errorcode",prizefund)); + result.push_back(Pair("error","blockinfo error")); } else { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","cant find block at height")); + // display bets + if ( height <= nextheight-PRICES_BETPERIOD ) + { + // settle bets + } + result.push_back(Pair("prizefund",ValueFromAmount(prizefund))); + result.push_back(Pair("result","success")); } } else From 513731ea367a4a03eeae8a3561d7f4887eb949ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:32:55 -1100 Subject: [PATCH 199/385] Test --- src/cc/gamescc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 7a6b7c66c..efdd3b8e1 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -77,6 +77,8 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_rng(txfee,cp,params)); \ else if ( strcmp(method,"rngnext") == 0 ) \ return(games_rngnext(txfee,cp,params)); \ + else if ( strcmp(method,"settle") == 0 ) \ + return(games_settle(txfee,cp,params)); \ else if ( strcmp(method,"newgame") == 0 ) \ return(games_newgame(txfee,cp,params)); \ else if ( strcmp(method,"gameinfo") == 0 ) \ @@ -107,8 +109,6 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_fund(txfee,cp,params)); \ else if ( strcmp(method,"bet") == 0 ) \ return(games_bet(txfee,cp,params)); \ - else if ( strcmp(method,"settle") == 0 ) \ - return(games_settle(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 8de793c57bdc8159fb4f951151b7c452500333d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:35:06 -1100 Subject: [PATCH 200/385] Test --- src/cc/games/prices.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 770cdfc8e..ea5e28211 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -53,6 +53,8 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); + result.push_back(Pair("result","success")); + return(result); mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); From 0e1310dd8a3538b7cabc96072b493339be69a9c3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:42:44 -1100 Subject: [PATCH 201/385] Test --- src/cc/games/prices.cpp | 2 ++ src/cc/games/tetris.cpp | 2 ++ src/cc/gamescc.h | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index ea5e28211..275589b02 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,6 +14,8 @@ * * ******************************************************************************/ +std::string MYCCLIBNAME = (char *)"gamescc"; + #define PRICES_BETPERIOD 3 UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp index d1ca9c30b..cd609154d 100644 --- a/src/cc/games/tetris.cpp +++ b/src/cc/games/tetris.cpp @@ -14,6 +14,8 @@ * * ******************************************************************************/ +std::string MYCCLIBNAME = (char *)"gamescc"; + // game specific code for daemon void games_packitemstr(char *packitemstr,struct games_packitem *item) { diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index efdd3b8e1..b83276d8d 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -15,7 +15,6 @@ extern CWallet* pwalletMain; #include "CCinclude.h" #include "secp256k1.h" -std::string MYCCLIBNAME = (char *)"gamescc"; #define EVAL_GAMES (EVAL_FAUCET2+1) #define GAMES_TXFEE 10000 From aa24e63f86a17fee395204efa2edfa113b59ae1f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:46:03 -1100 Subject: [PATCH 202/385] Test --- src/cc/gamescc.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index b83276d8d..4d095ab12 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -24,6 +24,7 @@ extern CWallet* pwalletMain; #define GAMES_REGISTRATIONSIZE (100 * 10000) #define GAMES_REGISTRATION 1 +extern std::string MYCCLIBNAME; #define MYCCNAME "games" @@ -76,8 +77,6 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_rng(txfee,cp,params)); \ else if ( strcmp(method,"rngnext") == 0 ) \ return(games_rngnext(txfee,cp,params)); \ - else if ( strcmp(method,"settle") == 0 ) \ - return(games_settle(txfee,cp,params)); \ else if ( strcmp(method,"newgame") == 0 ) \ return(games_newgame(txfee,cp,params)); \ else if ( strcmp(method,"gameinfo") == 0 ) \ @@ -108,6 +107,8 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_fund(txfee,cp,params)); \ else if ( strcmp(method,"bet") == 0 ) \ return(games_bet(txfee,cp,params)); \ + else if ( strcmp(method,"settle") == 0 ) \ + return(games_settle(txfee,cp,params)); \ else \ { \ result.push_back(Pair("result","error")); \ From 1a413d246f0302cbb066d05c4d898c9dbec57756 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 08:58:40 -1100 Subject: [PATCH 203/385] Prices --- src/cc/cclib.cpp | 2 ++ src/cc/games/prices.cpp | 2 +- src/cc/gamescc.h | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 975b0735c..00a7c6fe0 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -52,6 +52,8 @@ std::string MYCCLIBNAME = (char *)"sudoku"; void komodo_netevent(std::vector payload) {} #endif +extern std::string MYCCLIBNAME; + char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); } struct CClib_rpcinfo diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 275589b02..7293a8de9 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,7 +14,7 @@ * * ******************************************************************************/ -std::string MYCCLIBNAME = (char *)"gamescc"; +std::string MYCCLIBNAME = (char *)"pricescc"; #define PRICES_BETPERIOD 3 UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 4d095ab12..b804216d7 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -24,7 +24,6 @@ extern CWallet* pwalletMain; #define GAMES_REGISTRATIONSIZE (100 * 10000) #define GAMES_REGISTRATION 1 -extern std::string MYCCLIBNAME; #define MYCCNAME "games" From 985386a7e31bde57567266305956f834051546aa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:00:40 -1100 Subject: [PATCH 204/385] Prices --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 7293a8de9..8624bc635 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -14,7 +14,7 @@ * * ******************************************************************************/ -std::string MYCCLIBNAME = (char *)"pricescc"; +std::string MYCCLIBNAME = (char *)"prices"; #define PRICES_BETPERIOD 3 UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); From 2102294650bf5f4c4bd59ff47575bcf5ee7642ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:04:14 -1100 Subject: [PATCH 205/385] Test --- src/cc/games/prices.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 8624bc635..4777e9de0 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -55,8 +55,12 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); - result.push_back(Pair("result","success")); - return(result); + if ( 1 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error"," no -ac_pubkey for price reference")); + return(result); + } mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); From 5e817c05acf57db0342d028958d475eb6a4ca786 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:06:30 -1100 Subject: [PATCH 206/385] Test --- src/cc/games/prices.cpp | 49 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 4777e9de0..91f4aa790 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -52,7 +52,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) } else return(-1); } -UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); if ( 1 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) @@ -93,6 +93,53 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } return(result); } +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error"," no -ac_pubkey for price reference")); + return(result); + } + mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + if ( params != 0 && cJSON_GetArraySize(params) == 2 ) + { + amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; + if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parsehash")); + return(result); + } + if ( mypk == acpk ) + { + amount = 0; // i am the reference price feed + //fprintf(stderr,"i am the reference\n"); + } + //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); + if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); + return(games_rawtxresult(result,rawtx,1)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } + return(result); +} UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { From dcfae63863f27e4dc82587d0da2a9e370df279b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:09:10 -1100 Subject: [PATCH 207/385] Test --- src/cc/games/prices.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 91f4aa790..112383554 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -106,7 +106,12 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); - if ( params != 0 && cJSON_GetArraySize(params) == 2 ) + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + { + height = juint(jitem(params,0),0); + result.push_back(Pair("height",(int64_t)height)); + } + /*if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 ) @@ -137,7 +142,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parse")); - } + }*/ return(result); } From 23e378493fa7b9f5ec01df6a8b78e4c69f837ce5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:10:02 -1100 Subject: [PATCH 208/385] Test --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 112383554..c9826fd9c 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -96,7 +96,7 @@ UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; int32_t height; if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) { result.push_back(Pair("result","error")); From d294ec1b93d9fdd5b0d258e111658db5c228ae51 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:12:22 -1100 Subject: [PATCH 209/385] Test --- src/cc/games/prices.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index c9826fd9c..a638a7016 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -93,6 +93,7 @@ UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } return(result); } + UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -106,10 +107,11 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + result.push_back(Pair("result","success")); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); - result.push_back(Pair("height",(int64_t)height)); + //result.push_back(Pair("height",(int64_t)height)); } /*if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { From 7b6ad019e63caadbc963b64627c7958f2635a8fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:13:48 -1100 Subject: [PATCH 210/385] Test --- src/cc/games/prices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index a638a7016..1ac7e3edb 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -110,8 +110,8 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("result","success")); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { - height = juint(jitem(params,0),0); - //result.push_back(Pair("height",(int64_t)height)); + //height = juint(jitem(params,0),0); + result.push_back(Pair("height",(int64_t)height)); } /*if ( params != 0 && cJSON_GetArraySize(params) == 2 ) { From ecd3a17c85b1b016aac8e971b61ca6f6545305cb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:16:03 -1100 Subject: [PATCH 211/385] Test --- src/cc/games/prices.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 1ac7e3edb..7f807954d 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -52,10 +52,10 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) } else return(-1); } -UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); - if ( 1 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error"," no -ac_pubkey for price reference")); @@ -64,6 +64,16 @@ UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *param mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + result.push_back(Pair("result","success")); + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + { + height = juint(jitem(params,0),0); + result.push_back(Pair("height",(int64_t)height)); + } + return(result); + /*mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { @@ -91,7 +101,7 @@ UniValue games_origsettle(uint64_t txfee,struct CCcontract_info *cp,cJSON *param result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parse")); } - return(result); + return(result);*/ } UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -110,7 +120,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("result","success")); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { - //height = juint(jitem(params,0),0); + height = juint(jitem(params,0),0); result.push_back(Pair("height",(int64_t)height)); } /*if ( params != 0 && cJSON_GetArraySize(params) == 2 ) From 42235ad98d80acd044f021e359f8f8c9bd752166 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:17:08 -1100 Subject: [PATCH 212/385] -2nd --- src/cc/games/prices.cpp | 54 ----------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 7f807954d..c88827fa2 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -104,60 +104,6 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result);*/ } -UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; int32_t height; - if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error"," no -ac_pubkey for price reference")); - return(result); - } - mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); - acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); - result.push_back(Pair("result","success")); - if ( params != 0 && cJSON_GetArraySize(params) == 1 ) - { - height = juint(jitem(params,0),0); - result.push_back(Pair("height",(int64_t)height)); - } - /*if ( params != 0 && cJSON_GetArraySize(params) == 2 ) - { - amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; - if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt parsehash")); - return(result); - } - if ( mypk == acpk ) - { - amount = 0; // i am the reference price feed - //fprintf(stderr,"i am the reference\n"); - } - //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); - if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); - return(games_rawtxresult(result,rawtx,1)); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","not enough funds")); - } - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt parse")); - }*/ - return(result); -} - UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); From e909810c76fc2c109ca8b71ea80dfaf0967d5466 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:18:29 -1100 Subject: [PATCH 213/385] Test --- src/cc/games/prices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index c88827fa2..142bc4c6b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -65,11 +65,11 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); result.push_back(Pair("result","success")); - if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + /*if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { height = juint(jitem(params,0),0); result.push_back(Pair("height",(int64_t)height)); - } + }*/ return(result); /*mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); From bdf32a01fb74f249bcf30807af3a75db4f5b256a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:19:27 -1100 Subject: [PATCH 214/385] Test --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 142bc4c6b..be85b92f1 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -63,7 +63,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); - acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + //acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); result.push_back(Pair("result","success")); /*if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { From a94d3bd0f753f395bbab32de8bd55f02ec28df07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:21:58 -1100 Subject: [PATCH 215/385] d'oh --- src/cc/games/prices.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index be85b92f1..7a43c8218 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -54,7 +54,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result; char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); + UniValue result(UniValue::VOBJ); char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) { result.push_back(Pair("result","error")); @@ -63,16 +63,6 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) } mypk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); - //acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); - result.push_back(Pair("result","success")); - /*if ( params != 0 && cJSON_GetArraySize(params) == 1 ) - { - height = juint(jitem(params,0),0); - result.push_back(Pair("height",(int64_t)height)); - }*/ - return(result); - /*mypk = pubkey2pk(Mypubkey()); - gamespk = GetUnspendable(cp,0); acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG); if ( params != 0 && cJSON_GetArraySize(params) == 1 ) @@ -101,7 +91,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt parse")); } - return(result);*/ + return(result); } UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) From 40174b32742b8d481c166ceea263d09977351087 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:23:55 -1100 Subject: [PATCH 216/385] Test --- src/cc/games/prices.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 7a43c8218..6385626fc 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -20,6 +20,8 @@ std::string MYCCLIBNAME = (char *)"prices"; UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; +// generate bars + int64_t prices_blockinfo(int32_t height,char *acaddr) { std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts; @@ -69,7 +71,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { height = juint(jitem(params,0),0); result.push_back(Pair("height",(int64_t)height)); - if ( 1 || (prizefund= prices_blockinfo(height,acaddr)) < 0 ) + if ( (prizefund= prices_blockinfo(height,acaddr)) < 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("errorcode",prizefund)); @@ -80,7 +82,7 @@ UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // display bets if ( height <= nextheight-PRICES_BETPERIOD ) { - // settle bets + // settle bets by first nonzero reference bar } result.push_back(Pair("prizefund",ValueFromAmount(prizefund))); result.push_back(Pair("result","success")); From 9c12a5523762798880c98b39a0cc0b4bfa111bab Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:25:35 -1100 Subject: [PATCH 217/385] Return prizefund --- src/cc/games/prices.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 6385626fc..177417c9b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -45,11 +45,12 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) E_UNMARSHAL(vopret,ss >> pricebits); timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; - //if ( strcmp(acaddr,destaddr) == 0 ) - // fprintf(stderr,"REF "); - //fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); + if ( strcmp(acaddr,destaddr) == 0 ) + fprintf(stderr,"REF "); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); } } + return(prizefund); } else return(-2); } else return(-1); } From 5a557264fa1c98ef90f8ce8cb8c4fb5c58532782 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 09:27:56 -1100 Subject: [PATCH 218/385] Test --- src/cc/games/prices.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 177417c9b..9178eb46b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -42,12 +42,15 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) { prizefund += tx.vout[0].nValue; GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - E_UNMARSHAL(vopret,ss >> pricebits); - timestamp = (uint32_t)(pricebits >> 32); - uprice = (uint32_t)pricebits; - if ( strcmp(acaddr,destaddr) == 0 ) - fprintf(stderr,"REF "); - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); + if ( vopret.size() == 8 ) + { + E_UNMARSHAL(vopret,ss >> pricebits); + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + if ( strcmp(acaddr,destaddr) == 0 ) + fprintf(stderr,"REF "); + fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); + } else return(-3); } } return(prizefund); From 0597306ea564fa640c7e91384421945e22804928 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 27 Mar 2019 19:31:39 -1100 Subject: [PATCH 219/385] 69522 exemption --- src/cc/rogue_rpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 5040c34d3..c5350a68d 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1521,7 +1521,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( (numvouts= tx.vout.size()) > 1 ) { txid = tx.GetHash(); - if ( txid == Parseuint256("1ae04dc0c5f2fca2053819a3a1b2efe5d355c34f58d6f16d59e5e2573e7baf7f") ) // osx rogue chain ht.50902 + if ( txid == Parseuint256("1ae04dc0c5f2fca2053819a3a1b2efe5d355c34f58d6f16d59e5e2573e7baf7f") || txid == Parseuint256("2a34b36cc1292aecfaabdad79b42cab9989fa6dcc87ac8ca88aa6162dab1e2c4") ) // osx rogue chain ht.50902, 69522 enabled = 0; scriptPubKey = tx.vout[numvouts-1].scriptPubKey; GetOpReturnData(scriptPubKey,vopret); From fab49cbf44440d7203bd48976b8ba24088c860cc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 00:52:17 -1100 Subject: [PATCH 220/385] prices_bar --- src/cc/games/prices.cpp | 88 ++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 9178eb46b..b5540650a 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -20,37 +20,87 @@ std::string MYCCLIBNAME = (char *)"prices"; UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; -// generate bars +#define bstr(x) ((double)((uint32_t)x) / 10000.) + +struct prices_bar +{ + uint64_t open,high,low,close,sum; + int32_t num; +}; + +int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) +{ + uint32_t uprice,timestamp; + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + bar->sum += uprice, bar->num++; + if ( bar->open == 0 ) + bar->open = bar->high = bar->low = pricebits; + if ( uprice > (uint32_t)bar->high ) + bar->high = pricebits; + else if ( uprice < (uint32_t)bar->low ) + bar->low = pricebits; + bar->close = pricebits; + return(0); +} + +int32_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) +{ + int32_t dist = 0; uint32_t uprice = (uint32_t)pricebits; + dist = (uprice - aveprice) * (uprice - aveprice); + return(dist); +} + +void prices_bardisp(struct prices_bar *bar) +{ + if ( bar->num == 0 ) + fprintf(stderr,"BAR null\n"); + else fprintf(stderr,"BAR ave %.4f (O %.4f, H %.4f, L %.4f, C %.4f)\n",bstr(bar->sum/bar->num),bstr(bar->open),bstr(bar->high),bstr(bar->low),bstr(bar->close)); +} int64_t prices_blockinfo(int32_t height,char *acaddr) { - std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts; + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,iter; struct bar_info refbar; if ( (pindex= komodo_chainactive(height)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) { n = block.vtx.size(); vini = 0; - for (i=0; i= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) - continue; - else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) + for (i=0; i= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) + continue; + else if ( iter == 0 != strcmp(acaddr,destaddr) != 0 ) + continue; + else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) { - E_UNMARSHAL(vopret,ss >> pricebits); - timestamp = (uint32_t)(pricebits >> 32); - uprice = (uint32_t)pricebits; - if ( strcmp(acaddr,destaddr) == 0 ) - fprintf(stderr,"REF "); - fprintf(stderr,"[%02x] i.%d %.8f %llx t%u %.4f numvouts.%d %s lag.%d\n",tx.vout[numvouts-1].scriptPubKey[0],i,(double)tx.vout[0].nValue/COIN,(long long)pricebits,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp)); - } else return(-3); + prizefund += tx.vout[0].nValue; + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + if ( vopret.size() == 8 ) + { + E_UNMARSHAL(vopret,ss >> pricebits); + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + if ( iter == 0 ) + prices_barupdate(&refbar,pricebits); + if ( strcmp(acaddr,destaddr) == 0 ) + fprintf(stderr,"REF "); + fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); + } else return(-3); + } + if ( iter == 0 ) + { + prices_bardisp(&refbar); + if ( refbar.num != 0 ) + aveprice = (uint32_t)refbar.sum / refbar.num; + } } } return(prizefund); From f970eb5c11009a639060215e7fb2690f6ef9135d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 00:53:02 -1100 Subject: [PATCH 221/385] prices_bar --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index b5540650a..1a599d390 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -60,7 +60,7 @@ void prices_bardisp(struct prices_bar *bar) int64_t prices_blockinfo(int32_t height,char *acaddr) { - std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,iter; struct bar_info refbar; + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,iter; struct prices_bar refbar; if ( (pindex= komodo_chainactive(height)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) From 3b880b21801208d59d1f14f6903f74dc72db3399 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 00:56:02 -1100 Subject: [PATCH 222/385] Fix skip condition --- src/cc/games/prices.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 1a599d390..40d747f65 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -47,7 +47,11 @@ int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) int32_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) { int32_t dist = 0; uint32_t uprice = (uint32_t)pricebits; - dist = (uprice - aveprice) * (uprice - aveprice); + if ( aveprice != 0 ) + { + dist = (uprice - aveprice); + dist *= dist; + } return(dist); } @@ -77,7 +81,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) continue; else if ( tx.vin[vini].prevout.n >= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) continue; - else if ( iter == 0 != strcmp(acaddr,destaddr) != 0 ) + else if ( iter != strcmp(acaddr,destaddr) ) continue; else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) { From 751156efa3be2e36db315340af7765b83597c608 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:09:08 -1100 Subject: [PATCH 223/385] Cleanup loop --- src/cc/games/prices.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 40d747f65..f6ee704ee 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -81,11 +81,8 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) continue; else if ( tx.vin[vini].prevout.n >= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) continue; - else if ( iter != strcmp(acaddr,destaddr) ) - continue; else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) { - prizefund += tx.vout[0].nValue; GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); if ( vopret.size() == 8 ) { @@ -93,18 +90,22 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) timestamp = (uint32_t)(pricebits >> 32); uprice = (uint32_t)pricebits; if ( iter == 0 ) - prices_barupdate(&refbar,pricebits); - if ( strcmp(acaddr,destaddr) == 0 ) - fprintf(stderr,"REF "); - fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); + { + prizefund += tx.vout[0].nValue; + if ( strcmp(acaddr,destaddr) == 0 ) + { + fprintf(stderr,"REF "); + prices_barupdate(&refbar,pricebits); + } + } else fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); } else return(-3); } - if ( iter == 0 ) - { - prices_bardisp(&refbar); - if ( refbar.num != 0 ) - aveprice = (uint32_t)refbar.sum / refbar.num; - } + } + if ( iter == 0 ) + { + prices_bardisp(&refbar); + if ( refbar.num != 0 ) + aveprice = (uint32_t)refbar.sum / refbar.num; } } return(prizefund); From 2f9c10cb73c366e5a1d38b2e05c6be6e35424f84 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:12:10 -1100 Subject: [PATCH 224/385] Test --- src/cc/games/prices.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index f6ee704ee..8c70750bf 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -51,6 +51,7 @@ int32_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebi { dist = (uprice - aveprice); dist *= dist; + fprintf(stderr,"dist.%d (u %u - ave %u) %d\n",dist,uprice,aveprice,uprice-aveprice); } return(dist); } @@ -97,7 +98,9 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) fprintf(stderr,"REF "); prices_barupdate(&refbar,pricebits); } - } else fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); + } + else if ( strcmp(acaddr,destaddr) != 0 ) + fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); } else return(-3); } } From 58ebf2262dede6fed26c0ace4bafa8a480c4c084 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:14:12 -1100 Subject: [PATCH 225/385] Int64 --- src/cc/games/prices.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 8c70750bf..d4a87ee39 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -44,14 +44,14 @@ int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) return(0); } -int32_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) +int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) { - int32_t dist = 0; uint32_t uprice = (uint32_t)pricebits; + int64_t dist = 0; uint32_t uprice = (uint32_t)pricebits; if ( aveprice != 0 ) { dist = (uprice - aveprice); dist *= dist; - fprintf(stderr,"dist.%d (u %u - ave %u) %d\n",dist,uprice,aveprice,uprice-aveprice); + fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); } @@ -100,7 +100,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) } } else if ( strcmp(acaddr,destaddr) != 0 ) - fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%d\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,prices_bardist(&refbar,aveprice,pricebits)); + fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)prices_bardist(&refbar,aveprice,pricebits)); } else return(-3); } } From 4414e5a5f47bcb08a7de59ab239f55d3900163b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:17:50 -1100 Subject: [PATCH 226/385] Test --- src/cc/games/prices.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index d4a87ee39..abcefed74 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -51,7 +51,7 @@ int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebi { dist = (uprice - aveprice); dist *= dist; - fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); + //fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); } @@ -99,8 +99,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) prices_barupdate(&refbar,pricebits); } } - else if ( strcmp(acaddr,destaddr) != 0 ) - fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)prices_bardist(&refbar,aveprice,pricebits)); + fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)prices_bardist(&refbar,aveprice,pricebits)); } else return(-3); } } From d7758d26c83b2060577805887e8a03a0313cbab9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:20:16 -1100 Subject: [PATCH 227/385] Test --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index abcefed74..f8f61085b 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -51,7 +51,7 @@ int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebi { dist = (uprice - aveprice); dist *= dist; - //fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); + fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); } From a3b757fdbd1fd06a915212c7e40a4f7c9a4d7ab4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:23:03 -1100 Subject: [PATCH 228/385] Test --- src/cc/games/prices.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index f8f61085b..ed5c285c3 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -49,8 +49,7 @@ int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebi int64_t dist = 0; uint32_t uprice = (uint32_t)pricebits; if ( aveprice != 0 ) { - dist = (uprice - aveprice); - dist *= dist; + dist = ((int64_t)(uprice - aveprice) * (uprice - aveprice)); fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); From fda7fa0ef1e4e78562cac5316dbd4991ae4316fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:25:38 -1100 Subject: [PATCH 229/385] Test --- src/cc/games/prices.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index ed5c285c3..28c882446 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -46,10 +46,13 @@ int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) { - int64_t dist = 0; uint32_t uprice = (uint32_t)pricebits; + int64_t a,b,dist = 0; uint32_t uprice = (uint32_t)pricebits; if ( aveprice != 0 ) { - dist = ((int64_t)(uprice - aveprice) * (uprice - aveprice)); + a = uprice; + b = aveprice; + dist = (a - b); + dist *= dist; fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); From b31363ad3cbbef4d6ad6c82140553c3b2c6fcfd2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:27:32 -1100 Subject: [PATCH 230/385] Test --- src/cc/games/prices.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 28c882446..9b36d6d80 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -46,14 +46,13 @@ int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) { - int64_t a,b,dist = 0; uint32_t uprice = (uint32_t)pricebits; + int64_t a,dist = 0; if ( aveprice != 0 ) { - a = uprice; - b = aveprice; - dist = (a - b); + a = (pricebits & 0xffffffff); + dist = (a - aveprice); dist *= dist; - fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); + //fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); } return(dist); } From 1dcca1c4c1cd1da615dabed613d45bedbb6341a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:32:09 -1100 Subject: [PATCH 231/385] Mini --- src/cc/games/prices.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 9b36d6d80..27d98b532 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -66,7 +66,7 @@ void prices_bardisp(struct prices_bar *bar) int64_t prices_blockinfo(int32_t height,char *acaddr) { - std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t prizefund = 0; int32_t i,n,vini,numvouts,iter; struct prices_bar refbar; + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,bestdist=0,prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; if ( (pindex= komodo_chainactive(height)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) @@ -96,11 +96,20 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) prizefund += tx.vout[0].nValue; if ( strcmp(acaddr,destaddr) == 0 ) { - fprintf(stderr,"REF "); + //fprintf(stderr,"REF "); prices_barupdate(&refbar,pricebits); } } - fprintf(stderr,"i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)prices_bardist(&refbar,aveprice,pricebits)); + else if ( strcmp(acaddr,destaddr) != 0 ) + { + dist = prices_bardist(&refbar,aveprice,pricebits); + if ( dist == 0 || dist < mindist ) + { + mindist = dist; + mini = i; + } + fprintf(stderr,"mini.%d i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",mini,i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)dist); + } } else return(-3); } } From 5191feefd4c543b4a02d965382cf70ba4b73627f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:32:46 -1100 Subject: [PATCH 232/385] Mindset --- src/cc/games/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 27d98b532..79e9d16c3 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -66,7 +66,7 @@ void prices_bardisp(struct prices_bar *bar) int64_t prices_blockinfo(int32_t height,char *acaddr) { - std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,bestdist=0,prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=0,prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; if ( (pindex= komodo_chainactive(height)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) From 1f36dbf75fb34899c7080e988a1f79b40ecaed5f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 01:34:24 -1100 Subject: [PATCH 233/385] Mindset --- src/cc/games/prices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp index 79e9d16c3..5c8437e5d 100644 --- a/src/cc/games/prices.cpp +++ b/src/cc/games/prices.cpp @@ -66,7 +66,7 @@ void prices_bardisp(struct prices_bar *bar) int64_t prices_blockinfo(int32_t height,char *acaddr) { - std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=0,prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=(1LL<<60),prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; if ( (pindex= komodo_chainactive(height)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) @@ -103,7 +103,7 @@ int64_t prices_blockinfo(int32_t height,char *acaddr) else if ( strcmp(acaddr,destaddr) != 0 ) { dist = prices_bardist(&refbar,aveprice,pricebits); - if ( dist == 0 || dist < mindist ) + if ( dist < mindist ) { mindist = dist; mini = i; From 21a8da86675b4e44fde97c69a7dc18605d8e80c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:11:59 -1100 Subject: [PATCH 234/385] Mineropret and cbopret --- src/bitcoind.cpp | 23 ++++++++++-- src/komodo_defs.h | 2 +- src/komodo_gateway.h | 87 ++++++++++++++++++++++++++++++++++++++++++++ src/komodo_globals.h | 3 +- src/komodo_utils.h | 24 +++++++++++- src/main.cpp | 9 +++++ src/miner.cpp | 8 +++- 7 files changed, 148 insertions(+), 8 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b2fa534a1..3c5cfe4d6 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -59,13 +59,16 @@ static bool fDaemon; #include "komodo_defs.h" #define KOMODO_ASSETCHAIN_MAXLEN 65 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +extern uint32_t ASSETCHAINS_BLOCKTIME; +extern uint64_t ASSETCHAINS_CBOPRET; void komodo_passport_iteration(); uint64_t komodo_interestsum(); int32_t komodo_longestchain(); +void komodo_cbopretupdate(); void WaitForShutdown(boost::thread_group* threadGroup) { - bool fShutdown = ShutdownRequested(); + int32_t i; bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. while (!fShutdown) { @@ -73,13 +76,27 @@ void WaitForShutdown(boost::thread_group* threadGroup) if ( ASSETCHAINS_SYMBOL[0] == 0 ) { komodo_passport_iteration(); - MilliSleep(10000); + for (i=0; i<10; i++) + { + fShutdown = ShutdownRequested(); + if ( fShutdown != 0 ) + break; + MilliSleep(1000); + } } else { //komodo_interestsum(); //komodo_longestchain(); - MilliSleep(20000); + if ( ASSETCHAINS_CBOPRET != 0 ) + komodo_cbopretupdate(); + for (i=0; i Mineropret; + +CScript komodo_mineropret(int32_t nHeight) +{ + CScript opret; + if ( Mineropret.size() != 0 ) + { + opret << OP_RETURN << Mineropret); + } + return(opret); +} + +int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) +{ + std::vector vopret; uint32_t pricebits[4]; int32_t i; + if ( ASSETCHAINS_CBOPRET != 0 ) + { + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() == sizeof(pricebits) ) + { + memcpy(pricebits,&Mineropret[0],sizeof(pricebits)); + fprintf(stderr,"ht.%d: t%u %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000) + return(0); + } + return(-1); + } + return(0); +} + +cJSON *get_urljson(char *url) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= issue_curl(url)) != 0 ) + { + fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +int32_t get_btcusd(uint32_t pricebits[4]) +{ + cJSON *pjson,*bpi,*obj; char str[512]; uint64_t btcusd = 0,btcgbp = 0,btceur = 0; + if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json")) != 0 ) + { + if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 ) + { + pricebits[0] = (uint32_t)time(NULL); + if ( (obj= jobj(bpi,(char *)"USD")) != 0 ) + { + btcusd = jdouble(obj,(char *)"rate_float") * SATOSHIDEN; + pricebits[1] = ((btcusd / 10000) & 0xffffffff); + } + if ( (obj= jobj(bpi,(char *)"GBP")) != 0 ) + { + btcgbp = jdouble(obj,(char *)"rate_float") * SATOSHIDEN; + pricebits[2] = ((btcgbp / 10000) & 0xffffffff); + } + if ( (obj= jobj(bpi,(char *)"EUR")) != 0 ) + { + btceur = jdouble(obj,(char *)"rate_float") * SATOSHIDEN; + pricebits[3] = ((btceur / 10000) & 0xffffffff); + } + } + free_json(pjson); + fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f\n",dstr(btcusd),dstr(btcgbp),dstr(btceur)); + return(0); + } + return(-1); +} + +void komodo_cbopretupdate() +{ + uint32_t pricebits[4]; + if ( (ASSETCHAINS_CBOPRET & 1) != 0 ) + { + if ( get_btcusd(pricebits) == 0 ) + { + Mineropret.resize(sizeof(pricebits)); + fprintf(stderr,"set pricebits\n"); + memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); + } + } +} + diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 69ad6b840..097d10da0 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -50,6 +50,7 @@ int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JU std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,WHITELIST_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB; uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,NUM_NOTARIES,ASSETCHAINS_MARMARA; bool VERUS_MINTBLOCKS; +std::vector Mineropret; char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096],NOTARYADDRS[64][36]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_BEAMPORT,ASSETCHAINS_CODAPORT; @@ -66,7 +67,7 @@ int64_t MAX_MONEY = 200000000 * 100000000LL; // spec will use an op_return with CLTV at front and anything after |OP_RETURN|PUSH of rest|OPRETTYPE_TIMELOCK|script| #define _ASSETCHAINS_TIMELOCKOFF 0xffffffffffffffff uint64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF; -uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0; +uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0,ASSETCHAINS_CBOPRET=0; uint64_t ASSETCHAINS_LASTERA = 1; uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS]; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index c1f488c5c..2702772f8 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1668,7 +1668,7 @@ extern int64_t MAX_MONEY; void komodo_args(char *argv0) { extern const char *Notaries_elected1[][2]; - std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256]; + std::string name,addn,hexstr; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256]; IS_KOMODO_NOTARY = GetBoolArg("-notary", false); IS_STAKED_NOTARY = GetArg("-stakednotary", -1); if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) { @@ -1810,6 +1810,16 @@ void komodo_args(char *argv0) ASSETCHAINS_BEAMPORT = GetArg("-ac_beam",0); ASSETCHAINS_CODAPORT = GetArg("-ac_coda",0); ASSETCHAINS_MARMARA = GetArg("-ac_marmara",0); + ASSETCHAINS_CBOPRET = GetArg("-ac_cbopret",0); + hexstr = GetArg("-ac_mineropret",""); + if ( hexstr.size() != 0 ) + { + Mineropret.resize(hexstr.size()/2) + decode_hex(&Mineropret,hexstr.size()/2,(char *)hexstr.c_str()); + for (i=0; i 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 ) + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 ) { fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size()); extraptr = extrabuf; @@ -2048,6 +2058,16 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_BLOCKTIME != 60 ) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_BLOCKTIME),(void *)&ASSETCHAINS_BLOCKTIME); + if ( ASSETCHAINS_CBOPRET != 0 ) + { + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_CBOPRET),(void *)&ASSETCHAINS_CBOPRET); + fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n"); + } + if ( Mineropret.size() != 0 ) + { + for (i=0; i 0 && (nHeight & 1) == 0 ) + { + + } + else if ( ASSETCHAINS_MINEROPRET != 0 ) + { + if ( komodo_opretvalidate(nHeight,tx.vout[1].scriptPubKey) < 0 ) + return(false); + } return(true); } diff --git a/src/miner.cpp b/src/miner.cpp index 48b8c5c62..af1f14ba3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -155,6 +155,7 @@ CScript MarmaraCoinbaseOpret(uint8_t funcid,int32_t height,CPubKey pk); uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector &NotarisationNotaries, uint32_t timestamp, int32_t height, uint8_t *script, int32_t len); int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *script, int32_t len); +CScript komodo_mineropret(int32_t nHeight); CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) { @@ -644,7 +645,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txNew.vout[1].nValue = 0; txNew.vout[1].scriptPubKey = MarmaraCoinbaseOpret('C',nHeight,pk); } - else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 ) + else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_MINEROPRET != 0 ||(ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0) ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); @@ -672,6 +673,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 ptr[34] = OP_CHECKSIG; //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); } + if ( ASSETCHAINS_MINEROPRET != 0 ) + { + txNew.vout.resize(txNew.size()+1); + txNew.vout[txNew.size()-1].scriptPubKey = komodo_mineropret(nHeight); + } //printf("autocreate commision vout\n"); } else if ( (uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE) From ca1ee9a8c1846fe6e7ce714785ec57793158ee68 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:18:06 -1100 Subject: [PATCH 235/385] syntax --- src/komodo_gateway.h | 6 ++---- src/komodo_utils.h | 4 ++-- src/main.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 46fc1d805..26443d41f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1554,9 +1554,7 @@ CScript komodo_mineropret(int32_t nHeight) { CScript opret; if ( Mineropret.size() != 0 ) - { - opret << OP_RETURN << Mineropret); - } + return(opret << OP_RETURN << Mineropret); return(opret); } @@ -1569,7 +1567,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( vopret.size() == sizeof(pricebits) ) { memcpy(pricebits,&Mineropret[0],sizeof(pricebits)); - fprintf(stderr,"ht.%d: t%u %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000) + fprintf(stderr,"ht.%d: t%u %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); return(0); } return(-1); diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 2702772f8..fa3278fda 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1814,8 +1814,8 @@ void komodo_args(char *argv0) hexstr = GetArg("-ac_mineropret",""); if ( hexstr.size() != 0 ) { - Mineropret.resize(hexstr.size()/2) - decode_hex(&Mineropret,hexstr.size()/2,(char *)hexstr.c_str()); + Mineropret.resize(hexstr.size()/2); + decode_hex(&Mineropret[0],hexstr.size()/2,(char *)hexstr.c_str()); for (i=0; i Date: Thu, 28 Mar 2019 03:20:00 -1100 Subject: [PATCH 236/385] issue_curl --- src/komodo_gateway.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 26443d41f..0e687c3d4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1575,6 +1575,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(0); } +#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) + cJSON *get_urljson(char *url) { char *jsonstr; cJSON *json = 0; From 99c55801a3b0006b93152364254e0815d1140ebd Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:23:14 -1100 Subject: [PATCH 237/385] vout.size() --- src/miner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index af1f14ba3..f79602d90 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -645,7 +645,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txNew.vout[1].nValue = 0; txNew.vout[1].scriptPubKey = MarmaraCoinbaseOpret('C',nHeight,pk); } - else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_MINEROPRET != 0 ||(ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0) ) + else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_CBOPRET != 0 ||(ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0) ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); @@ -673,10 +673,10 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 ptr[34] = OP_CHECKSIG; //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); } - if ( ASSETCHAINS_MINEROPRET != 0 ) + if ( ASSETCHAINS_CBOPRET != 0 ) { - txNew.vout.resize(txNew.size()+1); - txNew.vout[txNew.size()-1].scriptPubKey = komodo_mineropret(nHeight); + txNew.vout.resize(txNew.vout.size()+1); + txNew.vout[txNew.vout.size()-1].scriptPubKey = komodo_mineropret(nHeight); } //printf("autocreate commision vout\n"); } From f28b62c766e59259346ee41288647a9076a7ab3b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:42:23 -1100 Subject: [PATCH 238/385] Skop genesis --- src/komodo_gateway.h | 5 +++-- src/main.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0e687c3d4..12e7cc4c2 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1560,14 +1560,15 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t pricebits[4]; int32_t i; + std::vector vopret; uint32_t pricebits[4]; int32_t i,lag; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() == sizeof(pricebits) ) { memcpy(pricebits,&Mineropret[0],sizeof(pricebits)); - fprintf(stderr,"ht.%d: t%u %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); + lag = (int32_t)(time(NULL) - pricebits[0]); + fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); return(0); } return(-1); diff --git a/src/main.cpp b/src/main.cpp index d6993d203..b73a31856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1018,9 +1018,9 @@ bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeigh { } - else if ( ASSETCHAINS_CBOPRET != 0 ) + else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) { - if ( komodo_opretvalidate(nHeight,tx.vout[1].scriptPubKey) < 0 ) + if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) return(false); } return(true); From dd3704e2b06b4701e4c745e109d4b313556a831d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:45:21 -1100 Subject: [PATCH 239/385] -print --- src/komodo_gateway.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 12e7cc4c2..d6e308229 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1583,7 +1583,7 @@ cJSON *get_urljson(char *url) char *jsonstr; cJSON *json = 0; if ( (jsonstr= issue_curl(url)) != 0 ) { - fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); + //fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } @@ -1629,7 +1629,6 @@ void komodo_cbopretupdate() if ( get_btcusd(pricebits) == 0 ) { Mineropret.resize(sizeof(pricebits)); - fprintf(stderr,"set pricebits\n"); memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); } } From eab69d1d69175f23fa8ea141d80dcbbaca0e2c74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:49:25 -1100 Subject: [PATCH 240/385] Reorder coinbase opret checks --- src/main.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b73a31856..da1730696 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -980,7 +980,16 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight) { // if time locks are on, ensure that this coin base is time locked exactly as it should be - if (((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE) || + if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 ) + { + + } + else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) + { + if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) + return(false); + } + else if (((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE) || (((nHeight >= 31680) || strcmp(ASSETCHAINS_SYMBOL, "VRSC") != 0) && komodo_ac_block_subsidy(nHeight) >= ASSETCHAINS_TIMELOCKGTE)) { CScriptID scriptHash; @@ -1014,15 +1023,6 @@ bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeigh } return(false); } - else if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 ) - { - - } - else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) - { - if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) - return(false); - } return(true); } From c2a73508a8e1670e1440e3bdd841b5ae394d3563 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:53:23 -1100 Subject: [PATCH 241/385] +print --- src/komodo_gateway.h | 2 +- src/main.cpp | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d6e308229..4eee1a300 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1570,7 +1570,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) lag = (int32_t)(time(NULL) - pricebits[0]); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); return(0); - } + } else fprintf(stderr,"wrong size %d vs %d\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits)); return(-1); } return(0); diff --git a/src/main.cpp b/src/main.cpp index da1730696..b73a31856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -980,16 +980,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight) { // if time locks are on, ensure that this coin base is time locked exactly as it should be - if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 ) - { - - } - else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) - { - if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) - return(false); - } - else if (((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE) || + if (((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE) || (((nHeight >= 31680) || strcmp(ASSETCHAINS_SYMBOL, "VRSC") != 0) && komodo_ac_block_subsidy(nHeight) >= ASSETCHAINS_TIMELOCKGTE)) { CScriptID scriptHash; @@ -1023,6 +1014,15 @@ bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeigh } return(false); } + else if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 ) + { + + } + else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) + { + if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) + return(false); + } return(true); } From fb5b955a955e755890092066a47e293dd5aa6bea Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 03:57:28 -1100 Subject: [PATCH 242/385] +print --- src/komodo_gateway.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4eee1a300..a6aa1b6f8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1630,6 +1630,7 @@ void komodo_cbopretupdate() { Mineropret.resize(sizeof(pricebits)); memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); + fprintf(stderr,"set Mineropret[%d]\n",(int32_t)Mineropret.size()); } } } From 451af129c709cd3aefdc7f4403b1d1c46853c9b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:02:27 -1100 Subject: [PATCH 243/385] Est --- src/komodo_gateway.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a6aa1b6f8..4a81624ac 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1566,11 +1566,11 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() == sizeof(pricebits) ) { - memcpy(pricebits,&Mineropret[0],sizeof(pricebits)); + memcpy(pricebits,&vpopret[0],sizeof(pricebits)); lag = (int32_t)(time(NULL) - pricebits[0]); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); return(0); - } else fprintf(stderr,"wrong size %d vs %d\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits)); + } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits),(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); } return(0); @@ -1628,7 +1628,8 @@ void komodo_cbopretupdate() { if ( get_btcusd(pricebits) == 0 ) { - Mineropret.resize(sizeof(pricebits)); + if ( Mineropret.size() != sizeof(pricebits) ) + Mineropret.resize(sizeof(pricebits)); memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); fprintf(stderr,"set Mineropret[%d]\n",(int32_t)Mineropret.size()); } From 6dcc38b76545713979ca69eba7ae9595d322c8ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:03:44 -1100 Subject: [PATCH 244/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4a81624ac..2c78383df 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1566,7 +1566,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() == sizeof(pricebits) ) { - memcpy(pricebits,&vpopret[0],sizeof(pricebits)); + memcpy(pricebits,&vopret[0],sizeof(pricebits)); lag = (int32_t)(time(NULL) - pricebits[0]); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); return(0); From 54ab6c61a174c7dc19079e2972fe0fc9d0f586b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:05:15 -1100 Subject: [PATCH 245/385] Height --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2c78383df..7e6deb57d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1568,7 +1568,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { memcpy(pricebits,&vopret[0],sizeof(pricebits)); lag = (int32_t)(time(NULL) - pricebits[0]); - fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000); + fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1)); return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits),(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); From 3ba62bf865fca436f3165fb899dbaa4da4ca4512 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:07:39 -1100 Subject: [PATCH 246/385] Test --- src/komodo_gateway.h | 4 +++- src/komodo_utils.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7e6deb57d..9391406dc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1631,7 +1631,9 @@ void komodo_cbopretupdate() if ( Mineropret.size() != sizeof(pricebits) ) Mineropret.resize(sizeof(pricebits)); memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); - fprintf(stderr,"set Mineropret[%d]\n",(int32_t)Mineropret.size()); + int32_t i; for (i=0; i Date: Thu, 28 Mar 2019 04:08:51 -1100 Subject: [PATCH 247/385] +print --- src/komodo_gateway.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9391406dc..63ada8787 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1554,7 +1554,10 @@ CScript komodo_mineropret(int32_t nHeight) { CScript opret; if ( Mineropret.size() != 0 ) + { + fprintf(stderr,"use Mineropret[%d]\n",(int32_t)Mineropret.size()); return(opret << OP_RETURN << Mineropret); + } return(opret); } From 4b62adba68f5603fea7dd04a28e9f2faf7059d8b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:15:53 -1100 Subject: [PATCH 248/385] Test --- src/komodo_utils.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index d072f2dd5..a5a2eeb2c 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -2059,17 +2059,17 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_BLOCKTIME != 60 ) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_BLOCKTIME),(void *)&ASSETCHAINS_BLOCKTIME); + if ( Mineropret.size() != 0 ) + { + for (i=0; i Date: Thu, 28 Mar 2019 04:23:13 -1100 Subject: [PATCH 249/385] Fix miner --- src/komodo_utils.h | 2 +- src/miner.cpp | 48 +++++++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index a5a2eeb2c..1bc379f42 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -2067,7 +2067,7 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_CBOPRET != 0 ) { extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_CBOPRET),(void *)&ASSETCHAINS_CBOPRET); - komodo_cbopretupdate(); + komodo_cbopretupdate(); // will set Mineropret fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n"); } } diff --git a/src/miner.cpp b/src/miner.cpp index f79602d90..31a6b3f9d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -648,37 +648,41 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_CBOPRET != 0 ||(ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0) ) { int32_t i; uint8_t *ptr; - txNew.vout.resize(2); - txNew.vout[1].nValue = commission; - if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) + if ( commission != 0 ) { - //fprintf(stderr,"mine to -ac_script\n"); - //txNew.vout[1].scriptPubKey = CScript() << ParseHex(); - int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str()); - len >>= 1; - txNew.vout[1].scriptPubKey.resize(len); - ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; - decode_hex(ptr,len,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); - } - else - { - txNew.vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; - ptr[0] = 33; - for (i=0; i<33; i++) + fprintf(stderr,"nonzero commission %.8f\n",(double)commission/COIN); + txNew.vout.resize(2); + txNew.vout[1].nValue = commission; + if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) { - ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; - //fprintf(stderr,"%02x",ptr[i+1]); + //fprintf(stderr,"mine to -ac_script\n"); + //txNew.vout[1].scriptPubKey = CScript() << ParseHex(); + int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str()); + len >>= 1; + txNew.vout[1].scriptPubKey.resize(len); + ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; + decode_hex(ptr,len,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); + } + else + { + txNew.vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; + ptr[0] = 33; + for (i=0; i<33; i++) + { + ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; + //fprintf(stderr,"%02x",ptr[i+1]); + } + ptr[34] = OP_CHECKSIG; + //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); } - ptr[34] = OP_CHECKSIG; - //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); } if ( ASSETCHAINS_CBOPRET != 0 ) { txNew.vout.resize(txNew.vout.size()+1); txNew.vout[txNew.vout.size()-1].scriptPubKey = komodo_mineropret(nHeight); } - //printf("autocreate commision vout\n"); + printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); } else if ( (uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE) { From 99527844f38241a47a61043602cdc5671643b928 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:27:46 -1100 Subject: [PATCH 250/385] Fix miner --- src/miner.cpp | 62 ++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 31a6b3f9d..69580da7b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -645,44 +645,35 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txNew.vout[1].nValue = 0; txNew.vout[1].scriptPubKey = MarmaraCoinbaseOpret('C',nHeight,pk); } - else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_CBOPRET != 0 ||(ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0) ) + else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 ) { int32_t i; uint8_t *ptr; - if ( commission != 0 ) + txNew.vout.resize(2); + txNew.vout[1].nValue = commission; + if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) { - fprintf(stderr,"nonzero commission %.8f\n",(double)commission/COIN); - txNew.vout.resize(2); - txNew.vout[1].nValue = commission; - if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) - { - //fprintf(stderr,"mine to -ac_script\n"); - //txNew.vout[1].scriptPubKey = CScript() << ParseHex(); - int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str()); - len >>= 1; - txNew.vout[1].scriptPubKey.resize(len); - ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; - decode_hex(ptr,len,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); - } - else - { - txNew.vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; - ptr[0] = 33; - for (i=0; i<33; i++) - { - ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; - //fprintf(stderr,"%02x",ptr[i+1]); - } - ptr[34] = OP_CHECKSIG; - //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); - } + //fprintf(stderr,"mine to -ac_script\n"); + //txNew.vout[1].scriptPubKey = CScript() << ParseHex(); + int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str()); + len >>= 1; + txNew.vout[1].scriptPubKey.resize(len); + ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; + decode_hex(ptr,len,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); } - if ( ASSETCHAINS_CBOPRET != 0 ) + else { - txNew.vout.resize(txNew.vout.size()+1); - txNew.vout[txNew.vout.size()-1].scriptPubKey = komodo_mineropret(nHeight); + txNew.vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0]; + ptr[0] = 33; + for (i=0; i<33; i++) + { + ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; + //fprintf(stderr,"%02x",ptr[i+1]); + } + ptr[34] = OP_CHECKSIG; + //fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n"); } - printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); + //printf("autocreate commision vout\n"); } else if ( (uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE) { @@ -733,7 +724,12 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats); } else fprintf(stderr, "vout 2 of notarisation is not OP_RETURN scriptlen.%i\n", scriptlen); } - + if ( ASSETCHAINS_CBOPRET != 0 ) + { + txNew.vout.resize(txNew.vout.size()+1); + txNew.vout[txNew.vout.size()-1].scriptPubKey = komodo_mineropret(nHeight); + printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); + } pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; From 7ecb2d8b5daae27acbb8094de694956214080b95 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:32:07 -1100 Subject: [PATCH 251/385] Test --- src/komodo_gateway.h | 2 +- src/miner.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 63ada8787..2b9e7709d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1555,7 +1555,7 @@ CScript komodo_mineropret(int32_t nHeight) CScript opret; if ( Mineropret.size() != 0 ) { - fprintf(stderr,"use Mineropret[%d]\n",(int32_t)Mineropret.size()); + //fprintf(stderr,"use Mineropret[%d]\n",(int32_t)Mineropret.size()); return(opret << OP_RETURN << Mineropret); } return(opret); diff --git a/src/miner.cpp b/src/miner.cpp index 69580da7b..9246b7e6a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -726,8 +726,10 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 } if ( ASSETCHAINS_CBOPRET != 0 ) { - txNew.vout.resize(txNew.vout.size()+1); - txNew.vout[txNew.vout.size()-1].scriptPubKey = komodo_mineropret(nHeight); + int32_t numv = (int32_t)txNew.vout.size(); + txNew.vout.resize(numv+1); + txNew.vout[numv].nValue = 0; + txNew.vout[numv].scriptPubKey = komodo_mineropret(nHeight); printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); } pblock->vtx[0] = txNew; From eb58e86e18559b5b8f4bfed2ba6574560558d795 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:32:37 -1100 Subject: [PATCH 252/385] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 9246b7e6a..f131bc90e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -730,7 +730,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txNew.vout.resize(numv+1); txNew.vout[numv].nValue = 0; txNew.vout[numv].scriptPubKey = komodo_mineropret(nHeight); - printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); + //printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); } pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; From 71b0de3f217361465b2860a1f77eb3b763feba19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 04:34:58 -1100 Subject: [PATCH 253/385] -print --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2b9e7709d..e39470317 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1634,9 +1634,9 @@ void komodo_cbopretupdate() if ( Mineropret.size() != sizeof(pricebits) ) Mineropret.resize(sizeof(pricebits)); memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); - int32_t i; for (i=0; i Date: Thu, 28 Mar 2019 04:36:43 -1100 Subject: [PATCH 254/385] Test --- src/komodo_gateway.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e39470317..03816ee79 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1563,7 +1563,7 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t pricebits[4]; int32_t i,lag; + std::vector vopret; uint32_t pricebits[4]; int32_t i,lag,lag2; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); @@ -1571,7 +1571,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { memcpy(pricebits,&vopret[0],sizeof(pricebits)); lag = (int32_t)(time(NULL) - pricebits[0]); - fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1)); + lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); + fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits),(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); From 736a5cc15c42bb46090f5038352d6473410e23c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 05:42:16 -1100 Subject: [PATCH 255/385] Price bits --- src/komodo_gateway.h | 102 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 03816ee79..3a06d14b6 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1549,13 +1549,79 @@ void komodo_passport_iteration() } extern std::vector Mineropret; +#define PRICES_MAXCHANGE (COIN / 100) +#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) + +int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) +{ + CBlockIndex *pindex; CBlock block; int32_t numvouts; std::vector vopret; + if ( (pindex= komodo_chainactive(nHeight)) != 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + { + numvouts = (int32_t)block.vout[0].size(); + GetOpReturnData(block.vout[numvouts-1].scriptPubKey,vopret); + if ( vopret.size() == PRICES_SIZEBIT0 ) + { + memcpy(prevbits,&vopret[0],PRICES_SIZEBIT0); + return(0); + } + } + } + fprintf(stderr,"couldnt get pricebits for %d\n",nHeight); + return(-1); +} + +uint32_t komodo_pricenew(uint32_t price,uint32_t refprice,int64_t tolerance) +{ + uint32_t highprice,lowprice; + highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; + lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; + if ( price > highprice ) + return(highprice); + else if ( price < lowprice ) + return(lowprice); + else return(0); +} + +int32_t komodo_pricecmp(uint32_t pricebitsA[4],uint32_t pricebitsB[4],int64_t tolerance) +{ + int32_t i; + for (i=1; i<4; i++) + if ( komodo_pricenew(pricebitsA[i],pricebitsB[i],tolerance) != 0 ) + return(-1); + return(0); +} + +int32_t komodo_priceclamp(uint32_t pricebits[4],uint32_t refprices[4],int64_t tolerance) +{ + int32_t i; uint32_t newprice; + for (i=1; i<4; i++) + { + if ( (newprice= komodo_pricenew(pricebits[i],refprices[i],tolerance)) != 0 ) + { + fprintf(stderr,"priceclamp[%d] %u -> %u\n",i,pricebits[i],newprice); + pricebits[i] = newprice; + } + } + return(0); +} CScript komodo_mineropret(int32_t nHeight) { - CScript opret; - if ( Mineropret.size() != 0 ) + CScript opret; uint32_t pricebits[4],prevbits[4]; + if ( Mineropret.size() == PRICES_SIZEBIT0 ) { - //fprintf(stderr,"use Mineropret[%d]\n",(int32_t)Mineropret.size()); + if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) + { + memcpy(pricebits,&Mineropret[0],PRICES_SIZEBIT0); + if ( komodo_pricecmp(pricebit,prevbits,PRICES_MAXCHANGE) < 0 ) + { + komodo_priceclamp(pricebits,prevbits,PRICES_MAXCHANGE); + fprintf(stderr,"update Mineropret to clamped prices\n"); + memcpy(&Mineropret[0],pricebits,PRICES_SIZEBIT0); + } + } return(opret << OP_RETURN << Mineropret); } return(opret); @@ -1563,18 +1629,34 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t pricebits[4]; int32_t i,lag,lag2; + std::vector vopret; uint32_t pricebits[4],prevbits[4]; int32_t i,lag,lag2; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() == sizeof(pricebits) ) + if ( vopret.size() == PRICES_SIZEBIT0 ) { - memcpy(pricebits,&vopret[0],sizeof(pricebits)); + memcpy(pricebits,&vopret[0],PRICES_SIZEBIT0); lag = (int32_t)(time(NULL) - pricebits[0]); + if ( lag < 0 ) + lag = -lag; lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); + if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() == PRICES_SIZEBIT0 ) + { + memcpy(prevbits,&Mineropret[0],PRICES_SIZEBIT0); + if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + return(-1); + } + if ( nHeight > 1 ) + { + if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) + { + if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + return(-1); + } else return(-1); + } return(0); - } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)sizeof(pricebits),(int32_t)scriptPubKey.size(),scriptPubKey[0]); + } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)PRICES_SIZEBIT0,(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); } return(0); @@ -1632,9 +1714,9 @@ void komodo_cbopretupdate() { if ( get_btcusd(pricebits) == 0 ) { - if ( Mineropret.size() != sizeof(pricebits) ) - Mineropret.resize(sizeof(pricebits)); - memcpy(&Mineropret[0],pricebits,sizeof(pricebits)); + if ( Mineropret.size() != PRICES_SIZEBIT0 ) + Mineropret.resize(PRICES_SIZEBIT0); + memcpy(&Mineropret[0],pricebits,PRICES_SIZEBIT0); //int32_t i; for (i=0; i Date: Thu, 28 Mar 2019 05:44:49 -1100 Subject: [PATCH 256/385] fix --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3a06d14b6..664548c2c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1615,7 +1615,7 @@ CScript komodo_mineropret(int32_t nHeight) if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { memcpy(pricebits,&Mineropret[0],PRICES_SIZEBIT0); - if ( komodo_pricecmp(pricebit,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { komodo_priceclamp(pricebits,prevbits,PRICES_MAXCHANGE); fprintf(stderr,"update Mineropret to clamped prices\n"); From 66f7b96df6140864ad9c663d2ae6323702a7cad1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 05:46:14 -1100 Subject: [PATCH 257/385] Fix --- src/komodo_gateway.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 664548c2c..1e5aed8cf 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1554,13 +1554,14 @@ extern std::vector Mineropret; int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) { - CBlockIndex *pindex; CBlock block; int32_t numvouts; std::vector vopret; + CBlockIndex *pindex; CBlock block; CTransaction tx; int32_t numvouts; std::vector vopret; if ( (pindex= komodo_chainactive(nHeight)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) { - numvouts = (int32_t)block.vout[0].size(); - GetOpReturnData(block.vout[numvouts-1].scriptPubKey,vopret); + tx = block.vtx[0]; + numvouts = (int32_t)tx.vout[0].size(); + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); if ( vopret.size() == PRICES_SIZEBIT0 ) { memcpy(prevbits,&vopret[0],PRICES_SIZEBIT0); From 0698ed694afcf9ce65572583bb4efed583b9fc16 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 05:47:20 -1100 Subject: [PATCH 258/385] -tx --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1e5aed8cf..1b0664bb8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1560,7 +1560,7 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) if ( komodo_blockload(block,pindex) == 0 ) { tx = block.vtx[0]; - numvouts = (int32_t)tx.vout[0].size(); + numvouts = (int32_t)tx.vout.size(); GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); if ( vopret.size() == PRICES_SIZEBIT0 ) { From e9f398a93291935d076072c3ed5bb57a9e57bd36 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Thu, 28 Mar 2019 23:50:52 +0700 Subject: [PATCH 259/385] added tuis --- src/tui/LICENSE | 21 + src/tui/README.md | 58 + src/tui/lib/logo.txt | 39 + src/tui/lib/rpclib.py | 129 ++ src/tui/lib/tuilib.py | 1965 ++++++++++++++++++++++++++++++ src/tui/requirements.txt | 8 + src/tui/tui_assets.py | 67 + src/tui/tui_gateways_creation.py | 67 + src/tui/tui_gateways_usage.py | 96 ++ src/tui/tui_marmara.py | 68 ++ src/tui/tui_oracles.py | 67 + src/tui/tui_rogue.py | 116 ++ src/tui/tui_tetris.py | 96 ++ 13 files changed, 2797 insertions(+) create mode 100644 src/tui/LICENSE create mode 100644 src/tui/README.md create mode 100644 src/tui/lib/logo.txt create mode 100644 src/tui/lib/rpclib.py create mode 100755 src/tui/lib/tuilib.py create mode 100644 src/tui/requirements.txt create mode 100755 src/tui/tui_assets.py create mode 100755 src/tui/tui_gateways_creation.py create mode 100755 src/tui/tui_gateways_usage.py create mode 100755 src/tui/tui_marmara.py create mode 100755 src/tui/tui_oracles.py create mode 100755 src/tui/tui_rogue.py create mode 100755 src/tui/tui_tetris.py diff --git a/src/tui/LICENSE b/src/tui/LICENSE new file mode 100644 index 000000000..3300ef648 --- /dev/null +++ b/src/tui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Anton Lysakov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/tui/README.md b/src/tui/README.md new file mode 100644 index 000000000..61e733794 --- /dev/null +++ b/src/tui/README.md @@ -0,0 +1,58 @@ +# Komodo Cryptoconditons Terminal User Interfaces (aka TUIs) + +These tools creating for demonstration and partial automation of Komodo cryptoconditions modules testing. (RogueCC game, AssetsCC, OraclesCC, GatewaysCC, MarmaraCC, ...) + + +Developer installation (on Ubuntu 18.04) : + +Python3 required for execution: + +* `sudo apt-get install python3.6 python3-pip libgnutls28-dev` + +pip packages needed: + +* `pip3 install setuptools wheel slick-bitcoinrpc` +* or `pip3 install -r requirements.txt` + +Starting: + +# TUI for RogueCC + +If you're looking for player 3 in 1 (daemon + game + TUI) multiOS bundle - please check `releases` of this repo. + +`python3 rogue_tui.py` + +![alt text](https://i.imgur.com/gkcxMGt.png) + +# TUI for OraclesCC + +Have files uploader/downloader functionality - also there is a AWS branch for AWS certificates uploading demonstration + +`python3 oracles_cc_tui.py` + +![alt text](https://i.imgur.com/tfHwRqc.png) + +# TUI for GatewaysCC + +![alt text](https://i.imgur.com/c8DPfpp.png) + +`python3 gateways_creation_tui.py` + +`python3 gateways_usage_tui.py` + +At the moment raw version of manual gateway how-to guide can be found here: https://docs.komodoplatform.com/cc/contracts/gateways/scenarios/tutorial.html I advice to read it before you start use this tool to understand the flow. + +# TUI for MarmaraCC + +`python3 marmara_tui.py` + +![alt text](https://i.imgur.com/uonMWHl.png) + +# TUI for AssetsCC (not much finished) + +`python3 assets_cc_tui.py` + +Before execution be sure than daemon for needed AC up. + + + diff --git a/src/tui/lib/logo.txt b/src/tui/lib/logo.txt new file mode 100644 index 000000000..15ace1ad5 --- /dev/null +++ b/src/tui/lib/logo.txt @@ -0,0 +1,39 @@ +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xlc:ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xo:,........';lxOXNMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMWNKkoc,..................':ox0XWMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMWNKkdc;............................,:ok0NWMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMWNKOdl;'.....................................,cdkKNWMMMMMMMMMMMMMM +MMMMMMMMMMMMMW0c'..............................................';kNMMMMMMMMMMMMM +MMMMMMMMMMMMMK:......................';:c:'......................,kWMMMMMMMMMMMM +MMMMMMMMMMMMXl...................;cdkKNWWNXOdl;'..................;OWMMMMMMMMMMM +MMMMMMMMMMMNo...............,cok0XWMMMMMMMMMMWNKkdc;'..............:KMMMMMMMMMMM +MMMMMMMMMMWx'...........;ox0XWMMMMMMMMMMMMMMMMMMMMWNKko:............lXMMMMMMMMMM +MMMMMMMMMWk,...........lXWMMMMMMMMMMMMWWWWMMMMMMMMMMMMMNx'...........oNMMMMMMMMM +MMMMMMMMW0;...........cKMMMMMMMMMWNXOdl::cdkKNWMMMMMMMMMNo...........'xWMMMMMMMM +MMMMMMMMKc...........;0WMMMMMWN0xl:,........';ldOXWMMMMMMXl...........,OWMMMMMMM +MMMMMMMXl...........,kWMMMMMMKl..................;OWMMMMMMK:...........;0MMMMMMM +MMMMMMNd...........'xNMMMMMMXl....................:0WMMMMMWO;...........cKMMMMMM +MMMMMNx'...........oNMMMMMMNd......................cKMMMMMMWk'...........lXMMMMM +MMMMWO,...........lXMMMMMMWx'.......................oXMMMMMMNd'...........dNMMMM +MMMMXc...........,OWMMMMMMK:........................,kWMMMMMMKc...........;0MMMM +MMMMWx'...........oXMMMMMMNd........................cKMMMMMMWk,...........lXMMMM +MMMMMNd...........'dNMMMMMMXl......................:0MMMMMMWO;...........cKMMMMM +MMMMMMXl...........,kWMMMMMMKc....................,OWMMMMMM0:...........;0MMMMMM +MMMMMMMKc...........;OWMMMMMW0:..................,kWMMMMMMXc...........,OWMMMMMM +MMMMMMMM0;...........:KMMMMMMWKko:,..........';lx0WMMMMMMNo...........'xWMMMMMMM +MMMMMMMMWk,...........lXMMMMMMMMWWXOxl:,,;cdOKNWMMMMMMMMNx'...........dNMMMMMMMM +MMMMMMMMMWx'...........dNMMMMMMMMMMMMWNXXNWMMMMMMMMMMMMWk,...........lXMMMMMMMMM +MMMMMMMMMMNo............cx0XWMMMMMMMMMMMMMMMMMMMMMMWN0kl,...........cKMMMMMMMMMM +MMMMMMMMMMMXl..............,:ok0XWMMMMMMMMMMMMWNKkdc;..............;0WMMMMMMMMMM +MMMMMMMMMMMMK:..................,cokKNWMMWNKOdl;'.................,kWMMMMMMMMMMM +MMMMMMMMMMMMWO;......................;cool;'.....................'xNMMMMMMMMMMMM +MMMMMMMMMMMMMWk;................................................'dNMMMMMMMMMMMMM +MMMMMMMMMMMMMMWXOxl;'.......................................,cdkKWMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMWNKOdc;..............................,cok0NWMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMWNKkoc,....................,:ox0XWMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0ko:,..........':lx0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:,,;ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNNXNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM \ No newline at end of file diff --git a/src/tui/lib/rpclib.py b/src/tui/lib/rpclib.py new file mode 100644 index 000000000..a79fc73d4 --- /dev/null +++ b/src/tui/lib/rpclib.py @@ -0,0 +1,129 @@ +import http +from slickrpc import Proxy + + +# RPC connection +def rpc_connect(rpc_user, rpc_password, port): + try: + rpc_connection = Proxy("http://%s:%s@127.0.0.1:%d"%(rpc_user, rpc_password, port)) + except Exception: + raise Exception("Connection error! Probably no daemon on selected port.") + return rpc_connection + + +# Non CC calls +def getinfo(rpc_connection): + try: + getinfo = rpc_connection.getinfo() + except Exception: + raise Exception("Connection error!") + return getinfo + + +def sendrawtransaction(rpc_connection, hex): + tx_id = rpc_connection.sendrawtransaction(hex) + return tx_id + + +def gettransaction(rpc_connection, tx_id): + transaction_info = rpc_connection.gettransaction(tx_id) + return transaction_info + + +def getrawtransaction(rpc_connection, tx_id): + rawtransaction = rpc_connection.getrawtransaction(tx_id) + return rawtransaction + + +def getbalance(rpc_connection): + balance = rpc_connection.getbalance() + return balance + +# Token CC calls +def token_create(rpc_connection, name, supply, description): + token_hex = rpc_connection.tokencreate(name, supply, description) + return token_hex + + +def token_info(rpc_connection, token_id): + token_info = rpc_connection.tokeninfo(token_id) + return token_info + + +#TODO: have to add option with pubkey input +def token_balance(rpc_connection, token_id): + token_balance = rpc_connection.tokenbalance(token_id) + return token_balance + +def token_list(rpc_connection): + token_list = rpc_connection.tokenlist() + return token_list + + +def token_convert(rpc_connection, evalcode, token_id, pubkey, supply): + token_convert_hex = rpc_connection.tokenconvert(evalcode, token_id, pubkey, supply) + return token_convert_hex + +def get_rawmempool(rpc_connection): + mempool = rpc_connection.getrawmempool() + return mempool + +# Oracle CC calls +def oracles_create(rpc_connection, name, description, data_type): + oracles_hex = rpc_connection.oraclescreate(name, description, data_type) + return oracles_hex + + +def oracles_register(rpc_connection, oracle_id, data_fee): + oracles_register_hex = rpc_connection.oraclesregister(oracle_id, data_fee) + return oracles_register_hex + + +def oracles_subscribe(rpc_connection, oracle_id, publisher_id, data_fee): + oracles_subscribe_hex = rpc_connection.oraclessubscribe(oracle_id, publisher_id, data_fee) + return oracles_subscribe_hex + + +def oracles_info(rpc_connection, oracle_id): + oracles_info = rpc_connection.oraclesinfo(oracle_id) + return oracles_info + + +def oracles_data(rpc_connection, oracle_id, hex_string): + oracles_data = rpc_connection.oraclesdata(oracle_id, hex_string) + return oracles_data + + +def oracles_list(rpc_connection): + oracles_list = rpc_connection.oracleslist() + return oracles_list + + +def oracles_samples(rpc_connection, oracletxid, batonutxo, num): + oracles_sample = rpc_connection.oraclessamples(oracletxid, batonutxo, num) + return oracles_sample + + +# Gateways CC calls +# Arguments changing dynamically depends of M N, so supposed to wrap it this way +# token_id, oracle_id, coin_name, token_supply, M, N + pubkeys for each N +def gateways_bind(rpc_connection, *args): + gateways_bind_hex = rpc_connection.gatewaysbind(*args) + return gateways_bind_hex + + +def gateways_deposit(rpc_connection, gateway_id, height, coin_name,\ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount): + gateways_deposit_hex = rpc_connection.gatewaysdeposit(gateway_id, height, coin_name,\ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount) + return gateways_deposit_hex + + +def gateways_claim(rpc_connection, gateway_id, coin_name, deposit_txid, dest_pub, amount): + gateways_claim_hex = rpc_connection.gatewaysclaim(gateway_id, coin_name, deposit_txid, dest_pub, amount) + return gateways_claim_hex + + +def gateways_withdraw(rpc_connection, gateway_id, coin_name, withdraw_pub, amount): + gateways_withdraw_hex = rpc_connection.gatewayswithdraw(gateway_id, coin_name, withdraw_pub, amount) + return gateways_withdraw_hex diff --git a/src/tui/lib/tuilib.py b/src/tui/lib/tuilib.py new file mode 100755 index 000000000..da1d7658a --- /dev/null +++ b/src/tui/lib/tuilib.py @@ -0,0 +1,1965 @@ +from lib import rpclib +import json +import time +import re +import sys +import pickle +import platform +import os +import subprocess +import signal +from slickrpc import Proxy +from binascii import hexlify +from binascii import unhexlify +from functools import partial +from shutil import copy + + +operating_system = platform.system() +if operating_system != 'Win64' and operating_system != 'Windows': + import readline + + +def colorize(string, color): + + colors = { + 'blue': '\033[94m', + 'magenta': '\033[95m', + 'green': '\033[92m', + 'red': '\033[91m' + } + if color not in colors: + return string + else: + return colors[color] + string + '\033[0m' + + +def rpc_connection_tui(): + # TODO: possible to save multiply entries from successfull sessions and ask user to choose then + while True: + restore_choice = input("Do you want to use connection details from previous session? [y/n]: ") + if restore_choice == "y": + try: + with open("connection.json", "r") as file: + connection_json = json.load(file) + rpc_user = connection_json["rpc_user"] + rpc_password = connection_json["rpc_password"] + rpc_port = connection_json["rpc_port"] + rpc_connection = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + except FileNotFoundError: + print(colorize("You do not have cached connection details. Please select n for connection setup", "red")) + break + elif restore_choice == "n": + rpc_user = input("Input your rpc user: ") + rpc_password = input("Input your rpc password: ") + rpc_port = input("Input your rpc port: ") + connection_details = {"rpc_user": rpc_user, + "rpc_password": rpc_password, + "rpc_port": rpc_port} + connection_json = json.dumps(connection_details) + with open("connection.json", "w+") as file: + file.write(connection_json) + rpc_connection = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + break + else: + print(colorize("Please input y or n", "red")) + return rpc_connection + + +def def_credentials(chain): + rpcport =''; + operating_system = platform.system() + if operating_system == 'Darwin': + ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' + elif operating_system == 'Linux': + ac_dir = os.environ['HOME'] + '/.komodo' + elif operating_system == 'Win64' or operating_system == 'Windows': + ac_dir = '%s/komodo/' % os.environ['APPDATA'] + if chain == 'KMD': + coin_config_file = str(ac_dir + '/komodo.conf') + else: + coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') + with open(coin_config_file, 'r') as f: + for line in f: + l = line.rstrip() + if re.search('rpcuser', l): + rpcuser = l.replace('rpcuser=', '') + elif re.search('rpcpassword', l): + rpcpassword = l.replace('rpcpassword=', '') + elif re.search('rpcport', l): + rpcport = l.replace('rpcport=', '') + if len(rpcport) == 0: + if chain == 'KMD': + rpcport = 7771 + else: + print("rpcport not in conf file, exiting") + print("check "+coin_config_file) + exit(1) + + return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) + + +def getinfo_tui(rpc_connection): + + info_raw = rpclib.getinfo(rpc_connection) + if isinstance(info_raw, dict): + for key in info_raw: + print("{}: {}".format(key, info_raw[key])) + input("Press [Enter] to continue...") + else: + print("Error!\n") + print(info_raw) + input("\nPress [Enter] to continue...") + + +def token_create_tui(rpc_connection): + + while True: + try: + name = input("Set your token name: ") + supply = input("Set your token supply: ") + description = input("Set your token description: ") + except KeyboardInterrupt: + break + else: + token_hex = rpclib.token_create(rpc_connection, name, supply, description) + if token_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(token_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + token_txid = rpclib.sendrawtransaction(rpc_connection, + token_hex['hex']) + except KeyError: + print(token_txid) + print("Error") + input("Press [Enter] to continue...") + break + finally: + print(colorize("Token creation transaction broadcasted: " + token_txid, "green")) + file = open("tokens_list", "a") + file.writelines(token_txid + "\n") + file.close() + print(colorize("Entry added to tokens_list file!\n", "green")) + input("Press [Enter] to continue...") + break + + +def oracle_create_tui(rpc_connection): + + print(colorize("\nAvailiable data types:\n", "blue")) + oracles_data_types = ["Ihh -> height, blockhash, merkleroot\ns -> <256 char string\nS -> <65536 char string\nd -> <256 binary data\nD -> <65536 binary data", + "c -> 1 byte signed little endian number, C unsigned\nt -> 2 byte signed little endian number, T unsigned", + "i -> 4 byte signed little endian number, I unsigned\nl -> 8 byte signed little endian number, L unsigned", + "h -> 32 byte hash\n"] + for oracles_type in oracles_data_types: + print(str(oracles_type)) + while True: + try: + name = input("Set your oracle name: ") + description = input("Set your oracle description: ") + oracle_data_type = input("Set your oracle type (e.g. Ihh): ") + except KeyboardInterrupt: + break + else: + oracle_hex = rpclib.oracles_create(rpc_connection, name, description, oracle_data_type) + if oracle_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(oracle_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + oracle_txid = rpclib.sendrawtransaction(rpc_connection, oracle_hex['hex']) + except KeyError: + print(oracle_txid) + print("Error") + input("Press [Enter] to continue...") + break + finally: + print(colorize("Oracle creation transaction broadcasted: " + oracle_txid, "green")) + file = open("oracles_list", "a") + file.writelines(oracle_txid + "\n") + file.close() + print(colorize("Entry added to oracles_list file!\n", "green")) + input("Press [Enter] to continue...") + break + + +def oracle_register_tui(rpc_connection): + #TODO: have an idea since blackjoker new RPC call + #grab all list and printout only or which owner match with node pubkey + try: + print(colorize("Oracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + while True: + try: + oracle_id = input("Input txid of oracle you want to register to: ") + data_fee = input("Set publisher datafee (in satoshis): ") + except KeyboardInterrupt: + break + oracle_register_hex = rpclib.oracles_register(rpc_connection, oracle_id, data_fee) + if oracle_register_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(oracle_register_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex['hex']) + except KeyError: + print(oracle_register_hex) + print("Error") + input("Press [Enter] to continue...") + break + else: + print(colorize("Oracle registration transaction broadcasted: " + oracle_register_txid, "green")) + input("Press [Enter] to continue...") + break + + +def oracle_subscription_utxogen(rpc_connection): + # TODO: have an idea since blackjoker new RPC call + # grab all list and printout only or which owner match with node pubkey + try: + print(colorize("Oracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + while True: + try: + oracle_id = input("Input oracle ID you want to subscribe to: ") + #printout to fast copypaste publisher id + oracle_info = rpclib.oracles_info(rpc_connection, oracle_id) + publishers = 0 + print(colorize("\nPublishers registered for a selected oracle: \n", "blue")) + try: + for entry in oracle_info["registered"]: + publisher = entry["publisher"] + print(publisher + "\n") + publishers = publishers + 1 + print("Total publishers:{}".format(publishers)) + except (KeyError, ConnectionResetError): + print(colorize("Please re-check your input. Oracle txid seems not valid.", "red")) + pass + print(colorize('_' * 65, "blue")) + print("\n") + if publishers == 0: + print(colorize("This oracle have no publishers to subscribe.\n" + "Please register as an oracle publisher first and/or wait since registration transaciton mined!", "red")) + input("Press [Enter] to continue...") + break + publisher_id = input("Input oracle publisher id you want to subscribe to: ") + data_fee = input("Input subscription fee (in COINS!): ") + utxo_num = int(input("Input how many transactions you want to broadcast: ")) + except KeyboardInterrupt: + break + while utxo_num > 0: + while True: + oracle_subscription_hex = rpclib.oracles_subscribe(rpc_connection, oracle_id, publisher_id, data_fee) + oracle_subscription_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscription_hex['hex']) + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + break + else: + pass + print(colorize("Oracle subscription transaction broadcasted: " + oracle_subscription_txid, "green")) + utxo_num = utxo_num - 1 + input("Press [Enter] to continue...") + break + +def gateways_bind_tui(rpc_connection): + # main loop with keyboard interrupt handling + while True: + try: + while True: + try: + print(colorize("Tokens created from this instance by TUI: \n", "blue")) + with open("tokens_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + token_id = input("Input id of token you want to use in gw bind: ") + try: + token_name = rpclib.token_info(rpc_connection, token_id)["name"] + except KeyError: + print(colorize("Not valid tokenid. Please try again.", "red")) + input("Press [Enter] to continue...") + token_info = rpclib.token_info(rpc_connection, token_id) + print(colorize("\n{} token total supply: {}\n".format(token_id, token_info["supply"]), "blue")) + token_supply = input("Input supply for token binding: ") + try: + print(colorize("\nOracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + oracle_id = input("Input id of oracle you want to use in gw bind: ") + try: + oracle_name = rpclib.oracles_info(rpc_connection, oracle_id)["name"] + except KeyError: + print(colorize("Not valid oracleid. Please try again.", "red")) + input("Press [Enter] to continue...") + while True: + coin_name = input("Input external coin ticker (binded oracle and token need to have same name!): ") + if token_name == oracle_name and token_name == coin_name: + break + else: + print(colorize("Token name, oracle name and external coin ticker should match!", "red")) + while True: + M = input("Input minimal amount of pubkeys needed for transaction confirmation (1 for non-multisig gw): ") + N = input("Input maximal amount of pubkeys needed for transaction confirmation (1 for non-multisig gw): ") + if (int(N) >= int(M)): + break + else: + print("Maximal amount of pubkeys should be more or equal than minimal. Please try again.") + pubkeys = [] + for i in range(int(N)): + pubkeys.append(input("Input pubkey {}: ".format(i+1))) + pubtype = input("Input pubtype of external coin: ") + p2shtype = input("Input p2shtype of external coin: ") + wiftype = input("Input wiftype of external coin: ") + args = [rpc_connection, token_id, oracle_id, coin_name, token_supply, M, N] + new_args = [str(pubtype), str(p2shtype), wiftype] + args = args + pubkeys + new_args + # broadcasting block + try: + gateways_bind_hex = rpclib.gateways_bind(*args) + except Exception as e: + print(e) + input("Press [Enter] to continue...") + break + try: + gateways_bind_txid = rpclib.sendrawtransaction(rpc_connection, gateways_bind_hex["hex"]) + except Exception as e: + print(e) + print(gateways_bind_hex) + input("Press [Enter] to continue...") + break + else: + print(colorize("Gateway bind transaction broadcasted: " + gateways_bind_txid, "green")) + file = open("gateways_list", "a") + file.writelines(gateways_bind_txid + "\n") + file.close() + print(colorize("Entry added to gateways_list file!\n", "green")) + input("Press [Enter] to continue...") + break + break + except KeyboardInterrupt: + break + +# temporary :trollface: custom connection function solution +# to have connection to KMD daemon and cache it in separate file + + +def rpc_kmd_connection_tui(): + while True: + restore_choice = input("Do you want to use KMD daemon connection details from previous session? [y/n]: ") + if restore_choice == "y": + try: + with open("connection_kmd.json", "r") as file: + connection_json = json.load(file) + rpc_user = connection_json["rpc_user"] + rpc_password = connection_json["rpc_password"] + rpc_port = connection_json["rpc_port"] + rpc_connection_kmd = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + try: + print(rpc_connection_kmd.getinfo()) + print(colorize("Successfully connected!\n", "green")) + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print(colorize("NOT CONNECTED!\n", "red")) + input("Press [Enter] to continue...") + break + except FileNotFoundError: + print(colorize("You do not have cached KMD daemon connection details." + " Please select n for connection setup", "red")) + input("Press [Enter] to continue...") + elif restore_choice == "n": + rpc_user = input("Input your rpc user: ") + rpc_password = input("Input your rpc password: ") + rpc_port = input("Input your rpc port: ") + connection_details = {"rpc_user": rpc_user, + "rpc_password": rpc_password, + "rpc_port": rpc_port} + connection_json = json.dumps(connection_details) + with open("connection_kmd.json", "w+") as file: + file.write(connection_json) + rpc_connection_kmd = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + try: + print(rpc_connection_kmd.getinfo()) + print(colorize("Successfully connected!\n", "green")) + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print(colorize("NOT CONNECTED!\n", "red")) + input("Press [Enter] to continue...") + break + else: + print(colorize("Please input y or n", "red")) + return rpc_connection_kmd + + +def z_sendmany_twoaddresses(rpc_connection, sendaddress, recepient1, amount1, recepient2, amount2): + str_sending_block = "[{{\"address\":\"{}\",\"amount\":{}}},{{\"address\":\"{}\",\"amount\":{}}}]".format(recepient1, amount1, recepient2, amount2) + sending_block = json.loads(str_sending_block) + operation_id = rpc_connection.z_sendmany(sendaddress,sending_block) + return operation_id + + +def operationstatus_to_txid(rpc_connection, zstatus): + str_sending_block = "[\"{}\"]".format(zstatus) + sending_block = json.loads(str_sending_block) + operation_json = rpc_connection.z_getoperationstatus(sending_block) + operation_dump = json.dumps(operation_json) + operation_dict = json.loads(operation_dump)[0] + txid = operation_dict['result']['txid'] + return txid + + +def gateways_send_kmd(rpc_connection): + # TODO: have to handle CTRL+C on text input + print(colorize("Please be carefull when input wallet addresses and amounts since all transactions doing in real KMD!", "pink")) + print("Your addresses with balances: ") + list_address_groupings = rpc_connection.listaddressgroupings() + for address in list_address_groupings: + print(str(address) + "\n") + sendaddress = input("Input address from which you transfer KMD: ") + recepient1 = input("Input address which belongs to pubkey which will receive tokens: ") + amount1 = 0.0001 + recepient2 = input("Input gateway deposit address: ") + file = open("deposits_list", "a") + #have to show here deposit addresses for gateways created by user + amount2 = input("Input how many KMD you want to deposit on this gateway: ") + operation = z_sendmany_twoaddresses(rpc_connection, sendaddress, recepient1, amount1, recepient2, amount2) + print("Operation proceed! " + str(operation) + " Let's wait 2 seconds to get txid") + # trying to avoid pending status of operation + time.sleep(2) + txid = operationstatus_to_txid(rpc_connection, operation) + file.writelines(txid + "\n") + file.close() + print(colorize("KMD Transaction ID: " + str(txid) + " Entry added to deposits_list file", "green")) + input("Press [Enter] to continue...") + + +def gateways_deposit_tui(rpc_connection_assetchain, rpc_connection_komodo): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + coin_txid = input("Input your deposit txid: ") + dest_pub = input("Input pubkey which claim deposit: ") + amount = input("Input amount of your deposit: ") + height = rpc_connection_komodo.getrawtransaction(coin_txid, 1)["height"] + deposit_hex = rpc_connection_komodo.getrawtransaction(coin_txid, 1)["hex"] + claim_vout = "0" + proof_sending_block = "[\"{}\"]".format(coin_txid) + proof = rpc_connection_komodo.gettxoutproof(json.loads(proof_sending_block)) + deposit_hex = rpclib.gateways_deposit(rpc_connection_assetchain, bind_txid, str(height), coin_name, \ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount) + print(deposit_hex) + deposit_txid = rpclib.sendrawtransaction(rpc_connection_assetchain, deposit_hex["hex"]) + print("Done! Gateways deposit txid is: " + deposit_txid + " Please not forget to claim your deposit!") + input("Press [Enter] to continue...") + break + + +def gateways_claim_tui(rpc_connection): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + deposit_txid = input("Input your gatewaysdeposit txid: ") + dest_pub = input("Input pubkey which claim deposit: ") + amount = input("Input amount of your deposit: ") + claim_hex = rpclib.gateways_claim(rpc_connection, bind_txid, coin_name, deposit_txid, dest_pub, amount) + try: + claim_txid = rpclib.sendrawtransaction(rpc_connection, claim_hex["hex"]) + except Exception as e: + print(e) + print(claim_hex) + input("Press [Enter] to continue...") + break + else: + print("Succesfully claimed! Claim transaction id: " + claim_txid) + input("Press [Enter] to continue...") + break + + +def gateways_withdrawal_tui(rpc_connection): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + withdraw_pub = input("Input pubkey to which you want to withdraw: ") + amount = input("Input amount of withdrawal: ") + withdraw_hex = rpclib.gateways_withdraw(rpc_connection, bind_txid, coin_name, withdraw_pub, amount) + withdraw_txid = rpclib.sendrawtransaction(rpc_connection, withdraw_hex["hex"]) + print(withdraw_txid) + input("Press [Enter] to continue...") + break + + +def print_mempool(rpc_connection): + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + tx_counter = 0 + print(colorize("Transactions in mempool: \n", "magenta")) + for transaction in mempool: + print(transaction + "\n") + tx_counter = tx_counter + 1 + print("Total: " + str(tx_counter) + " transactions\n") + print("R + Enter to refresh list. E + Enter to exit menu." + "\n") + is_refresh = input("Choose your destiny: ") + if is_refresh == "R": + print("\n") + pass + elif is_refresh == "E": + print("\n") + break + else: + print("\nPlease choose R or E\n") + + +def print_tokens_list(rpc_connection): + # TODO: have to print it with tokeninfo to have sense + pass + + +def print_tokens_balances(rpc_connection): + # TODO: checking tokenbalance for each token from tokenlist and reflect non zero ones + pass + + +def hexdump(filename, chunk_size=1<<15): + data = "" + #add_spaces = partial(re.compile(b'(..)').sub, br'\1 ') + #write = getattr(sys.stdout, 'buffer', sys.stdout).write + with open(filename, 'rb') as file: + for chunk in iter(partial(file.read, chunk_size), b''): + data += str(hexlify(chunk).decode()) + return data + + +def convert_file_oracle_d(rpc_connection): + while True: + path = input("Input path to file you want to upload to oracle: ") + try: + hex_data = (hexdump(path, 1))[2:] + except Exception as e: + print(e) + print("Seems something goes wrong (I guess you've specified wrong path)!") + input("Press [Enter] to continue...") + break + else: + length = round(len(hex_data) / 2) + if length > 256: + print("Length: " + str(length) + " bytes") + print("File is too big for this app") + input("Press [Enter] to continue...") + break + else: + hex_length = format(length, '#04x')[2:] + data_for_oracle = str(hex_length) + hex_data + print("File hex representation: \n") + print(data_for_oracle + "\n") + print("Length: " + str(length) + " bytes") + print("File converted!") + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert", path, "d") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + time.sleep(0.5) + oracle_subscribe_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscribe_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscribe_hex["hex"]) + time.sleep(0.5) + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscribe_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + try: + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + except Exception as e: + print(oracles_data_hex) + print(e) + print("Oracle created: " + str(new_oracle_txid)) + print("Data published: " + str(oracle_data_txid)) + input("Press [Enter] to continue...") + break + + +def convert_file_oracle_D(rpc_connection): + while True: + path = input("Input path to file you want to upload to oracle: ") + try: + hex_data = (hexdump(path, 1)) + except Exception as e: + print(e) + print("Seems something goes wrong (I guess you've specified wrong path)!") + input("Press [Enter] to continue...") + break + else: + length = round(len(hex_data) / 2) + # if length > 800000: + # print("Too big file size to upload for this version of program. Maximum size is 800KB.") + # input("Press [Enter] to continue...") + # break + if length > 8000: + # if file is more than 8000 bytes - slicing it to <= 8000 bytes chunks (16000 symbols = 8000 bytes) + data = [hex_data[i:i + 16000] for i in range(0, len(hex_data), 16000)] + chunks_amount = len(data) + # TODO: have to create oracle but subscribe this time chunks amount times to send whole file in same block + # TODO: 2 - on some point file will not fit block - have to find this point + # TODO: 3 way how I want to implement it first will keep whole file in RAM - have to implement some way to stream chunks to oracle before whole file readed + # TODO: have to "optimise" registration fee + # Maybe just check size first by something like a du ? + print("Length: " + str(length) + " bytes.\n Chunks amount: " + str(chunks_amount)) + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert_" + str(chunks_amount), path, "D") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + # subscribe chunks_amount + 1 times, but lets limit our broadcasting 100 tx per block (800KB/block) + if chunks_amount > 100: + utxo_num = 101 + else: + utxo_num = chunks_amount + while utxo_num > 0: + while True: + oracle_subscription_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscription_txid = rpclib.sendrawtransaction(rpc_connection, + oracle_subscription_hex['hex']) + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + break + else: + pass + print(colorize("Oracle subscription transaction broadcasted: " + oracle_subscription_txid, "green")) + utxo_num = utxo_num - 1 + # waiting for last broadcasted subscribtion transaction to be mined to be sure that money are on oracle balance + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + print("Oracle preparation is finished. Oracle txid: " + new_oracle_txid) + # can publish data now + counter = 0 + for chunk in data: + hex_length_bigendian = format(round(len(chunk) / 2), '#06x')[2:] + # swap to get little endian length + a = hex_length_bigendian[2:] + b = hex_length_bigendian[:2] + hex_length = a + b + data_for_oracle = str(hex_length) + chunk + counter = counter + 1 + # print("Chunk number: " + str(counter) + "\n") + # print(data_for_oracle) + try: + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + except Exception as e: + print(data_for_oracle) + print(e) + input("Press [Enter] to continue...") + break + # on broadcasting ensuring that previous one reached mempool before blast next one + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + #time.sleep(0.1) + if oracle_data_txid in mempool: + break + else: + pass + # blasting not more than 100 at once (so maximum capacity per block can be changed here) + # but keep in mind that registration UTXOs amount needs to be changed too ! + if counter % 100 == 0 and chunks_amount > 100: + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_data_txid in mempool: + print("Waiting for previous data chunks to be mined before send new ones" + "\n") + print("Sent " + str(counter) + " chunks from " + str(chunks_amount)) + time.sleep(6) + pass + else: + break + + print("Last baton: " + oracle_data_txid) + input("Press [Enter] to continue...") + break + # if file suits single oraclesdata just broadcasting it straight without any slicing + else: + hex_length_bigendian = format(length, '#06x')[2:] + # swap to get little endian length + a = hex_length_bigendian[2:] + b = hex_length_bigendian[:2] + hex_length = a + b + data_for_oracle = str(hex_length) + hex_data + print("File hex representation: \n") + print(data_for_oracle + "\n") + print("Length: " + str(length) + " bytes") + print("File converted!") + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert_" + "1", path, "D") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + time.sleep(0.5) + oracle_subscribe_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscribe_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscribe_hex["hex"]) + time.sleep(0.5) + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscribe_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + try: + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + except Exception as e: + print(oracles_data_hex) + print(e) + input("Press [Enter] to continue...") + break + else: + print("Oracle created: " + str(new_oracle_txid)) + print("Data published: " + str(oracle_data_txid)) + input("Press [Enter] to continue...") + break + + +def get_files_list(rpc_connection): + + start_time = time.time() + oracles_list = rpclib.oracles_list(rpc_connection) + files_list = [] + for oracle_txid in oracles_list: + oraclesinfo_result = rpclib.oracles_info(rpc_connection, oracle_txid) + description = oraclesinfo_result['description'] + name = oraclesinfo_result['name'] + if name[0:12] == 'tonyconvert_': + new_file = '[' + name + ': ' + description + ']: ' + oracle_txid + files_list.append(new_file) + print("--- %s seconds ---" % (time.time() - start_time)) + return files_list + + +def display_files_list(rpc_connection): + print("Scanning oracles. Please wait...") + list_to_display = get_files_list(rpc_connection) + while True: + for file in list_to_display: + print(file + "\n") + input("Press [Enter] to continue...") + break + + +def files_downloader(rpc_connection): + while True: + display_files_list(rpc_connection) + print("\n") + oracle_id = input("Input oracle ID you want to download file from: ") + output_path = input("Input output path for downloaded file (name included) e.g. /home/test.txt: ") + oracle_info = rpclib.oracles_info(rpc_connection, oracle_id) + name = oracle_info['name'] + latest_baton_txid = oracle_info['registered'][0]['batontxid'] + if name[0:12] == 'tonyconvert_': + # downloading process here + chunks_amount = int(name[12:]) + data = rpclib.oracles_samples(rpc_connection, oracle_id, latest_baton_txid, str(chunks_amount))["samples"] + for chunk in reversed(data): + with open(output_path, 'ab+') as file: + file.write(unhexlify(chunk[0])) + print("I hope that file saved to " + output_path + "\n") + input("Press [Enter] to continue...") + break + + else: + print("I cant recognize file inside this oracle. I'm very sorry, boss.") + input("Press [Enter] to continue...") + break + + +def marmara_receive_tui(rpc_connection): + while True: + issuer_pubkey = input("Input pubkey of person who do you want to receive MARMARA from: ") + issuance_sum = input("Input amount of MARMARA you want to receive: ") + blocks_valid = input("Input amount of blocks for cheque matures: ") + try: + marmara_receive_txinfo = rpc_connection.marmarareceive(issuer_pubkey, issuance_sum, "MARMARA", blocks_valid) + marmara_receive_txid = rpc_connection.sendrawtransaction(marmara_receive_txinfo["hex"]) + print("Marmara receive txid broadcasted: " + marmara_receive_txid + "\n") + print(json.dumps(marmara_receive_txinfo, indent=4, sort_keys=True) + "\n") + with open("receive_txids.txt", 'a+') as file: + file.write(marmara_receive_txid + "\n") + file.write(json.dumps(marmara_receive_txinfo, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to receive_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_receive_txinfo) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_issue_tui(rpc_connection): + while True: + receiver_pubkey = input("Input pubkey of person who do you want to issue MARMARA: ") + issuance_sum = input("Input amount of MARMARA you want to issue: ") + maturing_block = input("Input number of block on which issuance mature: ") + approval_txid = input("Input receiving request transaction id: ") + try: + marmara_issue_txinfo = rpc_connection.marmaraissue(receiver_pubkey, issuance_sum, "MARMARA", maturing_block, approval_txid) + marmara_issue_txid = rpc_connection.sendrawtransaction(marmara_issue_txinfo["hex"]) + print("Marmara issuance txid broadcasted: " + marmara_issue_txid + "\n") + print(json.dumps(marmara_issue_txinfo, indent=4, sort_keys=True) + "\n") + with open("issue_txids.txt", "a+") as file: + file.write(marmara_issue_txid + "\n") + file.write(json.dumps(marmara_issue_txinfo, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to issue_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_issue_txinfo) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_creditloop_tui(rpc_connection): + while True: + loop_txid = input("Input transaction ID of credit loop you want to get info about: ") + try: + marmara_creditloop_info = rpc_connection.marmaracreditloop(loop_txid) + print(json.dumps(marmara_creditloop_info, indent=4, sort_keys=True) + "\n") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_creditloop_info) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_settlement_tui(rpc_connection): + while True: + loop_txid = input("Input transaction ID of credit loop to make settlement: ") + try: + marmara_settlement_info = rpc_connection.marmarasettlement(loop_txid) + marmara_settlement_txid = rpc_connection.sendrawtransaction(marmara_settlement_info["hex"]) + print("Loop " + loop_txid + " succesfully settled!\nSettlement txid: " + marmara_settlement_txid) + with open("settlement_txids.txt", "a+") as file: + file.write(marmara_settlement_txid + "\n") + file.write(json.dumps(marmara_settlement_info, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to settlement_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_settlement_info) + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def marmara_lock_tui(rpc_connection): + while True: + amount = input("Input amount of coins you want to lock for settlement and staking: ") + unlock_height = input("Input height on which coins should be unlocked: ") + try: + marmara_lock_info = rpc_connection.marmaralock(amount, unlock_height) + marmara_lock_txid = rpc_connection.sendrawtransaction(marmara_lock_info["hex"]) + with open("lock_txids.txt", "a+") as file: + file.write(marmara_lock_txid + "\n") + file.write(json.dumps(marmara_lock_info, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to lock_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def marmara_info_tui(rpc_connection): + while True: + firstheight = input("Input first height (default 0): ") + if not firstheight: + firstheight = "0" + lastheight = input("Input last height (default current (0) ): ") + if not lastheight: + lastheight = "0" + minamount = input("Input min amount (default 0): ") + if not minamount: + minamount = "0" + maxamount = input("Input max amount (default 0): ") + if not maxamount: + maxamount = "0" + issuerpk = input("Optional. Input issuer public key: ") + try: + if issuerpk: + marmara_info = rpc_connection.marmarainfo(firstheight, lastheight, minamount, maxamount, "MARMARA", issuerpk) + else: + marmara_info = rpc_connection.marmarainfo(firstheight, lastheight, minamount, maxamount) + print(json.dumps(marmara_info, indent=4, sort_keys=True) + "\n") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_info) + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def rogue_game_info(rpc_connection, game_txid): + game_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + game_info = rpc_connection.cclib("gameinfo", "17", game_info_arg) + return game_info + + +def rogue_game_register(rpc_connection, game_txid, player_txid = False): + if player_txid: + registration_info_arg = '"' + "[%22" + game_txid + "%22,%22" + player_txid + "%22]" + '"' + else: + registration_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + registration_info = rpc_connection.cclib("register", "17", registration_info_arg) + return registration_info + + +def rogue_pending(rpc_connection): + rogue_pending_list = rpc_connection.cclib("pending", "17") + return rogue_pending_list + + +def rogue_bailout(rpc_connection, game_txid): + bailout_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + bailout_info = rpc_connection.cclib("bailout", "17", bailout_info_arg) + return bailout_info + + +def rogue_highlander(rpc_connection, game_txid): + highlander_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + highlander_info = rpc_connection.cclib("highlander", "17", highlander_info_arg) + return highlander_info + + +def rogue_players_list(rpc_connection): + rogue_players_list = rpc_connection.cclib("players", "17") + return rogue_players_list + + +def rogue_player_info(rpc_connection, playertxid): + player_info_arg = '"' + "[%22" + playertxid + "%22]" + '"' + player_info = rpc_connection.cclib("playerinfo", "17", player_info_arg) + return player_info + + +def rogue_extract(rpc_connection, game_txid, pubkey): + extract_info_arg = '"' + "[%22" + game_txid + "%22,%22" + pubkey + "%22]" + '"' + extract_info = rpc_connection.cclib("extract", "17", extract_info_arg) + return extract_info + + +def rogue_keystrokes(rpc_connection, game_txid, keystroke): + rogue_keystrokes_arg = '"' + "[%22" + game_txid + "%22,%22" + keystroke + "%22]" + '"' + keystroke_info = rpc_connection.cclib("keystrokes", "17", rogue_keystrokes_arg) + return keystroke_info + + +def print_multiplayer_games_list(rpc_connection): + while True: + pending_list = rogue_pending(rpc_connection) + multiplayer_pending_list = [] + for game in pending_list["pending"]: + if rogue_game_info(rpc_connection, game)["maxplayers"] > 1: + multiplayer_pending_list.append(game) + print("Multiplayer games availiable to join: \n") + for active_multiplayer_game in multiplayer_pending_list: + game_info = rogue_game_info(rpc_connection, active_multiplayer_game) + print(colorize("\n================================\n", "green")) + print("Game txid: " + game_info["gametxid"]) + print("Game buyin: " + str(game_info["buyin"])) + print("Game height: " + str(game_info["gameheight"])) + print("Start height: " + str(game_info["start"])) + print("Alive players: " + str(game_info["alive"])) + print("Registered players: " + str(game_info["numplayers"])) + print("Max players: " + str(game_info["maxplayers"])) + print(colorize("\n***\n", "blue")) + print("Players in game:") + for player in game_info["players"]: + print("Slot: " + str(player["slot"])) + if "baton" in player.keys(): + print("Baton: " + str(player["baton"])) + if "tokenid" in player.keys(): + print("Tokenid: " + str(player["tokenid"])) + print("Is mine?: " + str(player["ismine"])) + print(colorize("\nR + Enter - refresh list.\nE + Enter - to the game choice.\nCTRL + C - back to main menu", "blue")) + is_refresh = input("Choose your destiny: ") + if is_refresh == "R": + print("\n") + pass + elif is_refresh == "E": + print("\n") + break + else: + print("\nPlease choose R or E\n") + + +def rogue_newgame_singleplayer(rpc_connection, is_game_a_rogue=True): + try: + new_game_txid = rpc_connection.cclib("newgame", "17", "[1]")["txid"] + print("New singleplayer training game succesfully created. txid: " + new_game_txid) + while True: + mempool = rpc_connection.getrawmempool() + if new_game_txid in mempool: + print(colorize("Waiting for game transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Game transaction is mined", "green")) + break + players_list = rogue_players_list(rpc_connection) + if len(players_list["playerdata"]) > 0: + print_players_list(rpc_connection) + while True: + is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") + if is_choice_needed == "y": + player_txid = input("Please input player txid: ") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid, player_txid)["txid"] + break + elif is_choice_needed == "n": + set_warriors_name(rpc_connection) + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + break + else: + print("Please choose y or n !") + else: + print("No players available to select") + input("Press [Enter] to continue...") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + while True: + mempool = rpc_connection.getrawmempool() + if newgame_regisration_txid in mempool: + print(colorize("Waiting for registration transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Registration transaction is mined", "green")) + break + game_info = rogue_game_info(rpc_connection, new_game_txid) + start_time = time.time() + while True: + if is_game_a_rogue: + subprocess.call(["../cc/rogue/rogue", str(game_info["seed"]), str(game_info["gametxid"])]) + else: + subprocess.call(["../cc/games/tetris", str(game_info["seed"]), str(game_info["gametxid"])]) + time_elapsed = time.time() - start_time + if time_elapsed > 1: + break + else: + print("Game less than 1 second. Trying to start again") + time.sleep(1) + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + #print("\nKeystrokes of this game:\n") + #time.sleep(0.5) + while True: + keystrokes_rpc_responses = find_game_keystrokes_in_log(new_game_txid)[1::2] + if len(keystrokes_rpc_responses) < 1: + print("No keystrokes broadcasted yet. Let's wait 5 seconds") + time.sleep(5) + else: + break + #print(keystrokes_rpc_responses) + for keystroke in keystrokes_rpc_responses: + json_keystroke = json.loads(keystroke)["result"] + if "status" in json_keystroke.keys() and json_keystroke["status"] == "error": + while True: + print("Trying to re-brodcast keystroke") + keystroke_rebroadcast = rogue_keystrokes(rpc_connection, json_keystroke["gametxid"], json_keystroke["keystrokes"]) + if "txid" in keystroke_rebroadcast.keys(): + print("Keystroke broadcasted! txid: " + keystroke_rebroadcast["txid"]) + break + else: + print("Let's try again in 5 seconds") + time.sleep(5) + # waiting for last keystroke confirmation here + last_keystroke_json = json.loads(keystrokes_rpc_responses[-1]) + while True: + while True: + try: + rpc_connection.sendrawtransaction(last_keystroke_json["result"]["hex"]) + except Exception as e: + pass + try: + confirmations_amount = rpc_connection.getrawtransaction(last_keystroke_json["result"]["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Let's wait a little bit more") + time.sleep(5) + pass + if confirmations_amount < 2: + print("Last keystroke not confirmed yet! Let's wait a little") + time.sleep(10) + else: + print("Last keystroke confirmed!") + break + while True: + print("\nExtraction info:\n") + extraction_info = rogue_extract(rpc_connection, new_game_txid, rpc_connection.getinfo()["pubkey"]) + if extraction_info["status"] == "error": + print(colorize("Your warrior died or no any information about game was saved on blockchain", "red")) + print("If warrior was alive - try to wait a little (choose n to wait for a next block). If he is dead - you can bailout now (choose y).") + else: + print("Current game state:") + print("Game txid: " + extraction_info["gametxid"]) + print("Information about game saved on chain: " + extraction_info["extracted"]) + print("\n") + is_bailout_needed = input("Do you want to make bailout now [y] or wait for one more block [n]? [y/n]: ") + if is_bailout_needed == "y": + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + while True: + try: + confirmations_amount = rpc_connection.getrawtransaction(bailout_info["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Bailout not on blockchain yet. Let's wait a little bit more") + time.sleep(20) + pass + break + elif is_bailout_needed == "n": + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + else: + print("Please choose y or n !") + print(bailout_info) + print("\nGame is finished!\n") + bailout_txid = bailout_info["txid"] + input("Press [Enter] to continue...") + except Exception as e: + print("Something went wrong.") + print(e) + input("Press [Enter] to continue...") + + +def play_multiplayer_game(rpc_connection): + # printing list of user active multiplayer games + active_games_list = rpc_connection.cclib("games", "17")["games"] + active_multiplayer_games_list = [] + for game in active_games_list: + gameinfo = rogue_game_info(rpc_connection, game) + if gameinfo["maxplayers"] > 1: + active_multiplayer_games_list.append(gameinfo) + games_counter = 0 + for active_multiplayer_game in active_multiplayer_games_list: + games_counter = games_counter + 1 + is_ready_to_start = False + try: + active_multiplayer_game["seed"] + is_ready_to_start = True + except Exception as e: + pass + print(colorize("\n================================\n", "green")) + print("Game txid: " + active_multiplayer_game["gametxid"]) + print("Game buyin: " + str(active_multiplayer_game["buyin"])) + if is_ready_to_start: + print(colorize("Ready for start!", "green")) + else: + print(colorize("Not ready for start yet, wait until start height!", "red")) + print("Game height: " + str(active_multiplayer_game["gameheight"])) + print("Start height: " + str(active_multiplayer_game["start"])) + print("Alive players: " + str(active_multiplayer_game["alive"])) + print("Registered players: " + str(active_multiplayer_game["numplayers"])) + print("Max players: " + str(active_multiplayer_game["maxplayers"])) + print(colorize("\n***\n", "blue")) + print("Players in game:") + for player in active_multiplayer_game["players"]: + print("Slot: " + str(player["slot"])) + print("Baton: " + str(player["baton"])) + print("Tokenid: " + str(player["tokenid"])) + print("Is mine?: " + str(player["ismine"])) + # asking user if he want to start any of them + while True: + start_game = input("\nDo you want to start any of your pendning multiplayer games?[y/n]: ") + if start_game == "y": + new_game_txid = input("Input txid of game which you want to start: ") + game_info = rogue_game_info(rpc_connection, new_game_txid) + try: + start_time = time.time() + while True: + subprocess.call(["cc/rogue/rogue", str(game_info["seed"]), str(game_info["gametxid"])]) + time_elapsed = time.time() - start_time + if time_elapsed > 1: + break + else: + print("Game less than 1 second. Trying to start again") + time.sleep(1) + except Exception as e: + print("Maybe game isn't ready for start yet or your input was not correct, sorry.") + input("Press [Enter] to continue...") + break + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout or highlander", "blue")) + time.sleep(5) + else: + break + while True: + keystrokes_rpc_responses = find_game_keystrokes_in_log(new_game_txid)[1::2] + if len(keystrokes_rpc_responses) < 1: + print("No keystrokes broadcasted yet. Let's wait 5 seconds") + time.sleep(5) + else: + break + for keystroke in keystrokes_rpc_responses: + json_keystroke = json.loads(keystroke)["result"] + if "status" in json_keystroke.keys() and json_keystroke["status"] == "error": + while True: + print("Trying to re-brodcast keystroke") + keystroke_rebroadcast = rogue_keystrokes(rpc_connection, json_keystroke["gametxid"], + json_keystroke["keystrokes"]) + if "txid" in keystroke_rebroadcast.keys(): + print("Keystroke broadcasted! txid: " + keystroke_rebroadcast["txid"]) + break + else: + print("Let's try again in 5 seconds") + time.sleep(5) + last_keystroke_json = json.loads(keystrokes_rpc_responses[-1]) + while True: + while True: + try: + confirmations_amount = rpc_connection.getrawtransaction(last_keystroke_json["result"]["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Let's wait a little bit more") + rpc_connection.sendrawtransaction(last_keystroke_json["result"]["hex"]) + time.sleep(5) + pass + if confirmations_amount < 2: + print("Last keystroke not confirmed yet! Let's wait a little") + time.sleep(10) + else: + print("Last keystroke confirmed!") + break + while True: + print("\nExtraction info:\n") + extraction_info = rogue_extract(rpc_connection, new_game_txid, rpc_connection.getinfo()["pubkey"]) + if extraction_info["status"] == "error": + print(colorize("Your warrior died or no any information about game was saved on blockchain", "red")) + print("If warrior was alive - try to wait a little (choose n to wait for a next block). If he is dead - you can bailout now (choose y).") + else: + print("Current game state:") + print("Game txid: " + extraction_info["gametxid"]) + print("Information about game saved on chain: " + extraction_info["extracted"]) + print("\n") + is_bailout_needed = input( + "Do you want to make bailout now [y] or wait for one more block [n]? [y/n]: ") + if is_bailout_needed == "y": + if game_info["alive"] > 1: + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + try: + bailout_txid = bailout_info["txid"] + print(bailout_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + except Exception: + highlander_info = rogue_highlander(rpc_connection, new_game_txid) + highlander_info = highlander_info["txid"] + print(highlander_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + else: + highlander_info = rogue_highlander(rpc_connection, new_game_txid) + if 'error' in highlander_info.keys() and highlander_info["error"] == 'numplayers != maxplayers': + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + print(bailout_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + else: + print(highlander_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + elif is_bailout_needed == "n": + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + break + break + if start_game == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def rogue_newgame_multiplayer(rpc_connection): + while True: + max_players = input("Input game max. players (>1): ") + if int(max_players) > 1: + break + else: + print("Please re-check your input") + input("Press [Enter] to continue...") + while True: + buyin = input("Input game buyin (>0.001): ") + if float(buyin) > 0.001: + break + else: + print("Please re-check your input") + input("Press [Enter] to continue...") + try: + new_game_txid = rpc_connection.cclib("newgame", "17", '"[' + max_players + "," + buyin + ']"')["txid"] + print(colorize("New multiplayer game succesfully created. txid: " + new_game_txid, "green")) + input("Press [Enter] to continue...") + except Exception as e: + print("Something went wrong.") + print(e) + input("Press [Enter] to continue...") + + +def rogue_join_multiplayer_game(rpc_connection): + while True: + try: + print_multiplayer_games_list(rpc_connection) + # TODO: optional player data txid (print players you have and ask if you want to choose one) + game_txid = input("Input txid of game you want to join: ") + try: + while True: + print_players_list(rpc_connection) + is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") + if is_choice_needed == "y": + player_txid = input("Please input player txid: ") + newgame_regisration_txid = rogue_game_register(rpc_connection, game_txid, player_txid)["txid"] + break + elif is_choice_needed == "n": + set_warriors_name(rpc_connection) + newgame_regisration_txid = rogue_game_register(rpc_connection, game_txid)["txid"] + break + else: + print("Please choose y or n !") + except Exception as e: + print("Something went wrong. Maybe you're trying to register on game twice or don't have enough funds to pay buyin.") + print(e) + input("Press [Enter] to continue...") + break + print(colorize("Succesfully registered.", "green")) + while True: + mempool = rpc_connection.getrawmempool() + if newgame_regisration_txid in mempool: + print(colorize("Waiting for registration transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Registration transaction is mined", "green")) + break + print(newgame_regisration_txid) + input("Press [Enter] to continue...") + break + except KeyboardInterrupt: + break + + +def print_players_list(rpc_connection): + players_list = rogue_players_list(rpc_connection) + print(colorize("\nYou own " + str(players_list["numplayerdata"]) + " warriors\n", "blue")) + warrior_counter = 0 + for player in players_list["playerdata"]: + warrior_counter = warrior_counter + 1 + player_data = rogue_player_info(rpc_connection, player)["player"] + print(colorize("\n================================\n","green")) + print("Warrior " + str(warrior_counter)) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n","blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + input("Press [Enter] to continue...") + + +def sell_warrior(rpc_connection): + print(colorize("Your brave warriors: \n", "blue")) + print_players_list(rpc_connection) + print("\n") + while True: + need_sell = input("Do you want to place order to sell any? [y/n]: ") + if need_sell == "y": + playertxid = input("Input playertxid of warrior you want to sell: ") + price = input("Input price (in ROGUE coins) you want to sell warrior for: ") + try: + tokenid = rogue_player_info(rpc_connection, playertxid)["player"]["tokenid"] + except Exception as e: + print(e) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + token_ask_raw = rpc_connection.tokenask("1", tokenid, price) + try: + token_ask_txid = rpc_connection.sendrawtransaction(token_ask_raw["hex"]) + except Exception as e: + print(e) + print(token_ask_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Ask succesfully placed. Ask txid is: " + token_ask_txid, "green")) + input("Press [Enter] to continue...") + break + if need_sell == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +#TODO: have to combine into single scanner with different cases +def is_warrior_alive(rpc_connection, warrior_txid): + warrior_alive = False + raw_transaction = rpc_connection.getrawtransaction(warrior_txid, 1) + for vout in raw_transaction["vout"]: + if vout["value"] == 0.00000001 and rpc_connection.gettxout(raw_transaction["txid"], vout["n"]): + warrior_alive = True + return warrior_alive + + +def warriors_scanner(rpc_connection): + start_time = time.time() + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + elif player_info["player"]["playertxid"] in my_warriors_list["playerdata"]: + pass + elif not is_warrior_alive(rpc_connection, player_info["player"]["playertxid"]): + pass + else: + warriors_list[token] = player_info["player"] + print("--- %s seconds ---" % (time.time() - start_time)) + return warriors_list + + +def warriors_scanner_for_rating(rpc_connection): + print("It can take some time") + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + actual_playerids = [] + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + else: + while True: + if "batontxid" in player_info["player"].keys(): + player_info = rogue_player_info(rpc_connection, player_info["player"]["batontxid"]) + else: + actual_playerids.append(player_info["player"]["playertxid"]) + break + for player_id in actual_playerids: + player_info = rogue_player_info(rpc_connection, player_id) + if not is_warrior_alive(rpc_connection, player_info["player"]["playertxid"]): + pass + else: + warriors_list[player_id] = player_info["player"] + return warriors_list + + +def warriors_scanner_for_dex(rpc_connection): + start_time = time.time() + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + elif player_info["player"]["tokenid"] in my_warriors_list["playerdata"]: + pass + else: + warriors_list[token] = player_info["player"] + print("--- %s seconds ---" % (time.time() - start_time)) + return warriors_list + + +def print_warrior_list(rpc_connection): + players_list = warriors_scanner(rpc_connection) + print(colorize("All warriors on ROGUE chain: \n", "blue")) + warrior_counter = 0 + for player in players_list: + warrior_counter = warrior_counter + 1 + player_data = rogue_player_info(rpc_connection, player)["player"] + print(colorize("\n================================\n","green")) + print("Warrior " + str(warrior_counter)) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n","blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + input("Press [Enter] to continue...") + + +def place_bid_on_warriror(rpc_connection): + warriors_list = print_warrior_list(rpc_connection) + # TODO: have to drop my warriors or at least print my warriors ids + while True: + need_buy = input("Do you want to place order to buy some warrior? [y/n]: ") + if need_buy == "y": + playertxid = input("Input playertxid of warrior you want to place bid for: ") + price = input("Input price (in ROGUE coins) you want to buy warrior for: ") + tokenid = rogue_player_info(rpc_connection, playertxid)["player"]["tokenid"] + token_bid_raw = rpc_connection.tokenbid("1", tokenid, price) + try: + token_bid_txid = rpc_connection.sendrawtransaction(token_bid_raw["hex"]) + except Exception as e: + print(e) + print(token_bid_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Bid succesfully placed. Bid txid is: " + token_bid_txid, "green")) + input("Press [Enter] to continue...") + break + if need_buy == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def check_incoming_bids(rpc_connection): + # TODO: have to scan for warriors which are in asks as well + players_list = rogue_players_list(rpc_connection) + incoming_orders = [] + for player in players_list["playerdata"]: + token_id = rogue_player_info(rpc_connection, player)["player"]["tokenid"] + orders = rpc_connection.tokenorders(token_id) + if len(orders) > 0: + for order in orders: + if order["funcid"] == "b": + incoming_orders.append(order) + return incoming_orders + + +def print_icoming_bids(rpc_connection): + incoming_bids = check_incoming_bids(rpc_connection) + for bid in incoming_bids: + print("Recieved bid for warrior " + bid["tokenid"]) + player_data = rogue_player_info(rpc_connection, bid["tokenid"])["player"] + print(colorize("\n================================\n", "green")) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "blue")) + print("Order info: \n") + print("Bid txid: " + bid["txid"]) + print("Price: " + str(bid["price"]) + "\n") + if len(incoming_bids) == 0: + print(colorize("There is no any incoming orders!", "blue")) + input("Press [Enter] to continue...") + else: + while True: + want_to_sell = input("Do you want to fill any incoming bid? [y/n]: ") + if want_to_sell == "y": + bid_txid = input("Input bid txid you want to fill: ") + for bid in incoming_bids: + if bid_txid == bid["txid"]: + tokenid = bid["tokenid"] + fill_sum = bid["totalrequired"] + fillbid_hex = rpc_connection.tokenfillbid(tokenid, bid_txid, str(fill_sum)) + try: + fillbid_txid = rpc_connection.sendrawtransaction(fillbid_hex["hex"]) + except Exception as e: + print(e) + print(fillbid_hex) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully sold. Txid is: " + fillbid_txid, "green")) + input("Press [Enter] to continue...") + break + if want_to_sell == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def find_warriors_asks(rpc_connection): + warriors_list = warriors_scanner_for_dex(rpc_connection) + warriors_asks = [] + for player in warriors_list: + orders = rpc_connection.tokenorders(player) + if len(orders) > 0: + for order in orders: + if order["funcid"] == "s": + warriors_asks.append(order) + for ask in warriors_asks: + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + ask["tokenid"]) + player_data = rogue_player_info(rpc_connection, ask["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("Order info: \n", "red")) + print("Ask txid: " + ask["txid"]) + print("Price: " + str(ask["price"]) + "\n") + while True: + want_to_buy = input("Do you want to buy any warrior? [y/n]: ") + if want_to_buy == "y": + ask_txid = input("Input asktxid which you want to fill: ") + for ask in warriors_asks: + if ask_txid == ask["txid"]: + tokenid = ask["tokenid"] + try: + fillask_raw = rpc_connection.tokenfillask(tokenid, ask_txid, "1") + except Exception as e: + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + try: + fillask_txid = rpc_connection.sendrawtransaction(fillask_raw["hex"]) + except Exception as e: + print(e) + print(fillask_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully bought. Txid is: " + fillask_txid, "green")) + input("Press [Enter] to continue...") + break + if want_to_buy == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def warriors_orders_check(rpc_connection): + my_orders_list = rpc_connection.mytokenorders("17") + warriors_orders = {} + for order in my_orders_list: + player_info = rogue_player_info(rpc_connection, order["tokenid"]) + if "status" in player_info and player_info["status"] == "error": + pass + else: + warriors_orders[order["tokenid"]] = order + bids_list = [] + asks_list = [] + for order in warriors_orders: + if warriors_orders[order]["funcid"] == "s": + asks_list.append(warriors_orders[order]) + else: + bids_list.append(order) + print(colorize("\nYour asks:\n", "blue")) + print(colorize("\n********************************\n", "red")) + for ask in asks_list: + print("txid: " + ask["txid"]) + print("Price: " + ask["price"]) + print("Warrior tokenid: " + ask["tokenid"]) + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + ask["tokenid"]) + player_data = rogue_player_info(rpc_connection, ask["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "green")) + print(colorize("\nYour bids:\n", "blue")) + print(colorize("\n********************************\n", "red")) + for bid in bids_list: + print("txid: " + bid["txid"]) + print("Price: " + bid["price"]) + print("Warrior tokenid: " + bid["tokenid"]) + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + bid["tokenid"]) + player_data = rogue_player_info(rpc_connection, bid["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "green")) + while True: + need_order_change = input("Do you want to cancel any of your orders? [y/n]: ") + if need_order_change == "y": + while True: + ask_or_bid = input("Do you want cancel ask or bid? [a/b]: ") + if ask_or_bid == "a": + ask_txid = input("Input txid of ask you want to cancel: ") + warrior_tokenid = input("Input warrior token id for this ask: ") + try: + ask_cancellation_hex = rpc_connection.tokencancelask(warrior_tokenid, ask_txid) + ask_cancellation_txid = rpc_connection.sendrawtransaction(ask_cancellation_hex["hex"]) + except Exception as e: + print(colorize("Please re-check your input!", "red")) + print(colorize("Ask succefully cancelled. Cancellation txid: " + ask_cancellation_txid, "green")) + break + if ask_or_bid == "b": + bid_txid = input("Input txid of bid you want to cancel: ") + warrior_tokenid = input("Input warrior token id for this bid: ") + try: + bid_cancellation_hex = rpc_connection.tokencancelbid(warrior_tokenid, bid_txid) + bid_cancellation_txid = rpc_connection.sendrawtransaction(bid_cancellation_hex["hex"]) + except Exception as e: + print(colorize("Please re-check your input!", "red")) + print(colorize("Bid succefully cancelled. Cancellation txid: " + bid_cancellation_txid, "green")) + break + else: + print(colorize("Choose a or b!", "red")) + input("Press [Enter] to continue...") + break + if need_order_change == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def set_warriors_name(rpc_connection): + warriors_name = input("What warrior name do you want for legends and tales about your brave adventures?: ") + warrior_name_arg = '"' + "[%22" + warriors_name + "%22]" + '"' + set_name_status = rpc_connection.cclib("setname", "17", warrior_name_arg) + print(colorize("Warrior name succesfully set", "green")) + print("Result: " + set_name_status["result"]) + print("Name: " + set_name_status["pname"]) + input("Press [Enter] to continue...") + + +def top_warriors_rating(rpc_connection): + start_time = time.time() + warriors_list = warriors_scanner_for_rating(rpc_connection) + warriors_exp = {} + for warrior in warriors_list: + warriors_exp[warrior] = warriors_list[warrior]["experience"] + warriors_exp_sorted = {} + temp = [(k, warriors_exp[k]) for k in sorted(warriors_exp, key=warriors_exp.get, reverse=True)] + for k,v in temp: + warriors_exp_sorted[k] = v + counter = 0 + for experienced_warrior in warriors_exp_sorted: + if counter < 20: + counter = counter + 1 + print("\n" + str(counter) + " place.") + print(colorize("\n================================\n", "blue")) + player_data = rogue_player_info(rpc_connection, experienced_warrior)["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print("--- %s seconds ---" % (time.time() - start_time)) + input("Press [Enter] to continue...") + + +def exit(): + sys.exit() + + +def warrior_trasnfer(rpc_connection): + print(colorize("Your brave warriors: \n", "blue")) + print_players_list(rpc_connection) + print("\n") + while True: + need_transfer = input("Do you want to transfer any warrior? [y/n]: ") + if need_transfer == "y": + warrior_tokenid = input("Input warrior tokenid: ") + recepient_pubkey = input("Input recepient pubkey: ") + try: + token_transfer_hex = rpc_connection.tokentransfer(warrior_tokenid, recepient_pubkey, "1") + token_transfer_txid = rpc_connection.sendrawtransaction(token_transfer_hex["hex"]) + except Exception as e: + print(e) + print("Something went wrong. Please be careful with your input next time!") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully transferred! Transfer txid: " + token_transfer_txid, "green")) + input("Press [Enter] to continue...") + break + if need_transfer == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def check_if_config_is_here(rpc_connection, assetchain_name): + config_name = assetchain_name + ".conf" + if os.path.exists(config_name): + print(colorize("Config is already in daemon folder", "green")) + else: + if operating_system == 'Darwin': + path_to_config = os.environ['HOME'] + '/Library/Application Support/Komodo/' + assetchain_name + '/' + config_name + elif operating_system == 'Linux': + path_to_config = os.environ['HOME'] + '/.komodo/' + assetchain_name + '/' + config_name + elif operating_system == 'Win64' or operating_system == 'Windows': + path_to_config = '%s/komodo/' + assetchain_name + '/' + config_name % os.environ['APPDATA'] + try: + copy(path_to_config, os.getcwd()) + except Exception as e: + print(e) + print("Can't copy config to current daemon directory automatically by some reason.") + print("Please copy it manually. It's locating here: " + path_to_config) + + +def find_game_keystrokes_in_log(gametxid): + + operating_system = platform.system() + if operating_system == 'Win64' or operating_system == 'Windows': + p1 = subprocess.Popen(["type", "keystrokes.log"], stdout=subprocess.PIPE, shell=True) + p2 = subprocess.Popen(["findstr", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE, shell=True) + else: + p1 = subprocess.Popen(["cat", "keystrokes.log"], stdout=subprocess.PIPE) + p2 = subprocess.Popen(["grep", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE) + p1.stdout.close() + output = p2.communicate()[0] + keystrokes_log_for_game = bytes.decode(output).split("\n") + return keystrokes_log_for_game + + +def check_if_tx_in_mempool(rpc_connection, txid): + while True: + mempool = rpc_connection.getrawmempool() + if txid in mempool: + print(colorize("Waiting for " + txid + " transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Transaction is mined", "green")) + break diff --git a/src/tui/requirements.txt b/src/tui/requirements.txt new file mode 100644 index 000000000..734da529c --- /dev/null +++ b/src/tui/requirements.txt @@ -0,0 +1,8 @@ +configobj==5.0.6 +pip==9.0.1 +pycurl==7.43.0.2 +setuptools==39.0.1 +six==1.12.0 +slick-bitcoinrpc==0.1.4 +ujson==1.35 +wheel==0.32.3 diff --git a/src/tui/tui_assets.py b/src/tui/tui_assets.py new file mode 100755 index 000000000..091484a40 --- /dev/null +++ b/src/tui/tui_assets.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + + +header = "\ + ___ _ _____ \n\ + / _ \ | | / __ \\\n\ +/ /_\ \ ___ ___ ___ | |_ ___ | / \/\n\ +| _ |/ __|/ __| / _ \| __|/ __|| | \n\ +| | | |\__ \\\__ \| __/| |_ \__ \| \__/\\\n\ +\_| |_/|___/|___/ \___| \__||___/ \____/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Print tokens list": tuilib.print_tokens_list}, + {"Check my tokens balances" : tuilib.print_tokens_balances}, + # transfer tokens (pre-print tokens balances) + {"Create token": tuilib.token_create_tui}, + # trading zone - pre-print token orders - possible to open order or fill existing one + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2 by Anton Lysakov\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() + diff --git a/src/tui/tui_gateways_creation.py b/src/tui/tui_gateways_creation.py new file mode 100755 index 000000000..7bb489c7f --- /dev/null +++ b/src/tui/tui_gateways_creation.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + +header = "\ + _____ _ _____ _____ \n\ +| __ \ | | / __ \/ __ \\\n\ +| | \/ __ _| |_ _____ ____ _ _ _ ___| / \/| / \/\n\ +| | __ / _` | __/ _ \ \ /\ / / _` | | | / __| | | | \n\ +| |_\ \ (_| | || __/\ V V / (_| | |_| \__ \ \__/\| \__/\\\n\ + \____/\__,_|\__\___| \_/\_/ \__,_|\__, |___/\____/ \____/\n\ + __/ | \n\ + |___/ \n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Create token": tuilib.token_create_tui}, + {"Create oracle": tuilib.oracle_create_tui}, + {"Register as publisher for oracle": tuilib.oracle_register_tui}, + {"Subscribe on oracle (+UTXO generator)": tuilib.oracle_subscription_utxogen}, + {"Bind Gateway": tuilib.gateways_bind_tui}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_gateways_usage.py b/src/tui/tui_gateways_usage.py new file mode 100755 index 000000000..0c989e3af --- /dev/null +++ b/src/tui/tui_gateways_usage.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os, time + +header = "\ + _____ _ _____ _____ \n\ +| __ \ | | / __ \/ __ \\\n\ +| | \/ __ _| |_ _____ ____ _ _ _ ___| / \/| / \/\n\ +| | __ / _` | __/ _ \ \ /\ / / _` | | | / __| | | | \n\ +| |_\ \ (_| | || __/\ V V / (_| | |_| \__ \ \__/\| \__/\\\n\ + \____/\__,_|\__\___| \_/\_/ \__,_|\__, |___/\____/ \____/\n\ + __/ | \n\ + |___/ \n" + +menuItems = [ + {"Check connection to assetchain": tuilib.getinfo_tui}, + {"Check assetchain mempool": tuilib.print_mempool}, + {"Check connection to KMD": tuilib.getinfo_tui}, + {"Connect to KMD daemon": tuilib.rpc_kmd_connection_tui}, + {"Send KMD gateway deposit transaction": tuilib.gateways_send_kmd}, + {"Execute gateways deposit": tuilib.gateways_deposit_tui}, + {"Execute gateways claim": tuilib.gateways_claim_tui}, + {"Execute gateways withdrawal": tuilib.gateways_withdrawal_tui}, + {"Exit": exit} +] + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + # We have to call KMD specific functions with connection to KMD daemon + elif list(menuItems[int(choice)].keys())[0] == "Connect to KMD daemon": + rpc_connection_kmd = list(menuItems[int(choice)].values())[0]() + elif list(menuItems[int(choice)].keys())[0] == "Check connection to KMD": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection_kmd) + break + except Exception as e: + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + elif list(menuItems[int(choice)].keys())[0] == "Send KMD gateway deposit transaction": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection_kmd) + break + except Exception as e: + print(e) + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + elif list(menuItems[int(choice)].keys())[0] == "Execute gateways deposit": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection, rpc_connection_kmd) + break + except Exception as e: + print(e) + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\nPlease provide RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_marmara.py b/src/tui/tui_marmara.py new file mode 100755 index 000000000..cfe628890 --- /dev/null +++ b/src/tui/tui_marmara.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + + +header = "\ +___ ___ _____ _ _ _____ \n\ +| \/ | |_ _| | | |_ _|\n\ +| . . | __ _ _ __ _ __ ___ __ _ _ __ __ _ | | | | | | | |\n\ +| |\/| |/ _` | '__| '_ ` _ \ / _` | '__/ _` | | | | | | | | |\n\ +| | | | (_| | | | | | | | | (_| | | | (_| | | | | |_| |_| |_\n\ +\_| |_/\__,_|_| |_| |_| |_|\__,_|_| \__,_| \_/ \___/ \___/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Check MARMARA info": tuilib.marmara_info_tui}, + {"Lock funds for MARMARA": tuilib.marmara_lock_tui}, + {"Request MARMARA cheque": tuilib.marmara_receive_tui}, + {"Issue MARMARA cheque": tuilib.marmara_issue_tui}, + {"Check credit loop status": tuilib.marmara_creditloop_tui}, + {"Settle MARMARA loop": tuilib.marmara_settlement_tui}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.1\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = input("Input assetchain name (-ac_name= value) you want to work with: ") + try: + print(tuilib.colorize("Welcome to the MarmaraCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_oracles.py b/src/tui/tui_oracles.py new file mode 100755 index 000000000..fec874d35 --- /dev/null +++ b/src/tui/tui_oracles.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + +header = "\ + _____ _ _____ _____ \n\ +| _ | | | / __ \/ __ \\\n\ +| | | | _ __ __ _ ___ | | ___ ___ | / \/| / \/\n\ +| | | || '__| / _` | / __|| | / _ \/ __|| | | |\n\ +\ \_/ /| | | (_| || (__ | || __/\__ \| \__/\| \__/\\\n\ + \___/ |_| \__,_| \___||_| \___||___/ \____/ \____/\n" + +menuItems = [ + # TODO: Have to implement here native oracle file uploader / reader, should be dope + # TODO: data publisher / converter for different types + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Create oracle": tuilib.oracle_create_tui}, + {"Register as publisher for oracle": tuilib.oracle_register_tui}, + {"Subscribe on oracle (+UTXO generator)": tuilib.oracle_subscription_utxogen}, + {"Upload file to oracle": tuilib.convert_file_oracle_D}, + {"Display list of files uploaded to this AC": tuilib.display_files_list}, + {"Download files from oracle": tuilib.files_downloader}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2 by Anton Lysakov\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_rogue.py b/src/tui/tui_rogue.py new file mode 100755 index 000000000..9942369e2 --- /dev/null +++ b/src/tui/tui_rogue.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time +import sys +import platform + +header = "\ +______ _____ _____ \n\ +| ___ \ / __ \/ __ \\\n\ +| |_/ /___ __ _ _ _ ___| / \/| / \/\n\ +| // _ \ / _` | | | |/ _ \ | | |\n\ +| |\ \ (_) | (_| | |_| | __/ \__/\| \__/\\\n\ +\_| \_\___/ \__, |\__,_|\___|\____/ \____/\n\ + __/ |\n\ + |___/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Check my warriors list": tuilib.print_players_list}, + {"Transfer warrior to other pubkey": tuilib.warrior_trasnfer}, + {"TOP-20 ROGUE Warriors": tuilib.top_warriors_rating}, + {"Set warriors name": tuilib.set_warriors_name}, + {"Start singleplayer training game (creating, registering and starting game)": tuilib.rogue_newgame_singleplayer}, + {"Create multiplayer game": tuilib.rogue_newgame_multiplayer}, + {"Join (register) multiplayer game": tuilib.rogue_join_multiplayer_game}, + {"Check my multiplayer games status / start": tuilib.play_multiplayer_game}, + {"Check if somebody wants to buy your warrior (incoming bids)": tuilib.print_icoming_bids}, + {"Place order to sell warrior": tuilib.sell_warrior}, + {"Place order to buy someones warrior": tuilib.place_bid_on_warriror}, + {"Check if somebody selling warrior": tuilib.find_warriors_asks}, + {"Check / cancel my warriors trade orders": tuilib.warriors_orders_check}, + # {"Manually exit the game (bailout)": "test"}, + # {"Manually claim ROGUE coins for game (highlander)": "test"}, + {"Exit": tuilib.exit} +] + +def main(): + while True: + operating_system = platform.system() + if operating_system != 'Win64' and operating_system != 'Windows': + os.system('clear') + else: + os.system('cls') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('TUI v0.0.3\n', 'green')) + menu_items_counter = 0 + for item in menuItems: + if menu_items_counter == 0: + print("\nUtility:\n") + menu_items_counter = menu_items_counter + 1 + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + if menu_items_counter == 6: + print("\nNew singleplayer game:\n") + if menu_items_counter == 7: + print("\nMultiplayer games:\n") + if menu_items_counter == 10: + print("\nDEX features:\n") + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = "ROGUE" + try: + print(tuilib.colorize("Welcome to the RogueCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + # waiting until chain is in sync + while True: + have_blocks = rpclib.getinfo(rpc_connection)["blocks"] + longest_chain = rpclib.getinfo(rpc_connection)["longestchain"] + if have_blocks != longest_chain: + print(tuilib.colorize("ROGUE not synced yet.", "red")) + print("Have " + str(have_blocks) + " from " + str(longest_chain) + " blocks") + time.sleep(5) + else: + print(tuilib.colorize("Chain is synced!", "green")) + break + # checking if pubkey is set and set valid if not + info = rpclib.getinfo(rpc_connection) + if "pubkey" in info.keys(): + print("Pubkey is already set") + else: + valid_address = rpc_connection.getaccountaddress("") + valid_pubkey = rpc_connection.validateaddress(valid_address)["pubkey"] + rpc_connection.setpubkey(valid_pubkey) + print(tuilib.colorize("Pubkey is succesfully set!", "green")) + # copy ROGUE config to current daemon directory if it's not here + tuilib.check_if_config_is_here(rpc_connection, "ROGUE") + except Exception: + print(tuilib.colorize("Cant connect to ROGUE daemon RPC! Please check if daemon is up.", "pink")) + tuilib.exit() + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_tetris.py b/src/tui/tui_tetris.py new file mode 100755 index 000000000..3c42d4daa --- /dev/null +++ b/src/tui/tui_tetris.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time +import sys +import platform + +header = "\ + _____ _ _ ______\n\ +|_ _| | | (_) | _ \n\ + | | ___| |_ _ __ _ ___| | | |__ _ _ __ _ __\n\ + | |/ _ \ __| '__| / __| | | / _` | '_ \| '_ \\\n\ + | | __/ |_| | | \__ \ |/ / (_| | |_) | |_) |\n\ + \_/\___|\__|_| |_|___/___/ \__,_| .__/| .__/\n\ + | | | |\n\ + |_| |_|" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Start singleplayer tetris game (creating, registering and starting game)": tuilib.rogue_newgame_singleplayer}, + {"Exit": tuilib.exit} +] + + +def main(): + while True: + operating_system = platform.system() + if operating_system != 'Win64' and operating_system != 'Windows': + os.system('clear') + else: + os.system('cls') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('TUI v0.0.3\n', 'green')) + menu_items_counter = 0 + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + elif list(menuItems[int(choice)].keys())[0] == "Start singleplayer tetris game (creating, registering and starting game)": + list(menuItems[int(choice)].values())[0](rpc_connection, False) + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = "GTEST" + try: + print(tuilib.colorize("Welcome to the Tetris TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + # waiting until chain is in sync + while True: + have_blocks = rpclib.getinfo(rpc_connection)["blocks"] + longest_chain = rpclib.getinfo(rpc_connection)["longestchain"] + if have_blocks != longest_chain: + print(tuilib.colorize("GTEST not synced yet.", "red")) + print("Have " + str(have_blocks) + " from " + str(longest_chain) + " blocks") + time.sleep(5) + else: + print(tuilib.colorize("Chain is synced!", "green")) + break + # checking if pubkey is set and set valid if not + info = rpclib.getinfo(rpc_connection) + if "pubkey" in info.keys(): + print("Pubkey is already set") + else: + valid_address = rpc_connection.getaccountaddress("") + valid_pubkey = rpc_connection.validateaddress(valid_address)["pubkey"] + rpc_connection.setpubkey(valid_pubkey) + print(tuilib.colorize("Pubkey is succesfully set!", "green")) + # copy ROGUE config to current daemon directory if it's not here + tuilib.check_if_config_is_here(rpc_connection, "GTEST") + except Exception: + print(tuilib.colorize("Cant connect to GTEST daemon RPC! Please check if daemon is up.", "pink")) + tuilib.exit() + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() From 7ca041ee23431d14862dc33b5ff8e918d099c9af Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 05:52:33 -1100 Subject: [PATCH 260/385] Test --- src/komodo_gateway.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1b0664bb8..4a17a1b3d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1578,6 +1578,7 @@ uint32_t komodo_pricenew(uint32_t price,uint32_t refprice,int64_t tolerance) uint32_t highprice,lowprice; highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; + fprintf(stderr,"%.4f -> (%.4f %.4f)\n",(double)price/10000,(double)lowprice/10000,(double)highprice/10000); if ( price > highprice ) return(highprice); else if ( price < lowprice ) From 10df98e580a9c3ac52c8c19379aecc3c0c51265f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 06:03:01 -1100 Subject: [PATCH 261/385] -print --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4a17a1b3d..58054feba 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1578,7 +1578,7 @@ uint32_t komodo_pricenew(uint32_t price,uint32_t refprice,int64_t tolerance) uint32_t highprice,lowprice; highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; - fprintf(stderr,"%.4f -> (%.4f %.4f)\n",(double)price/10000,(double)lowprice/10000,(double)highprice/10000); + //fprintf(stderr,"%.4f -> (%.4f %.4f)\n",(double)price/10000,(double)lowprice/10000,(double)highprice/10000); if ( price > highprice ) return(highprice); else if ( price < lowprice ) @@ -1602,7 +1602,7 @@ int32_t komodo_priceclamp(uint32_t pricebits[4],uint32_t refprices[4],int64_t to { if ( (newprice= komodo_pricenew(pricebits[i],refprices[i],tolerance)) != 0 ) { - fprintf(stderr,"priceclamp[%d] %u -> %u\n",i,pricebits[i],newprice); + fprintf(stderr,"priceclamped[%d] %u -> %u\n",i,pricebits[i],newprice); pricebits[i] = newprice; } } From 2f0c3c23fa69fb14c12f38d04d1f08645035c34a Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Fri, 29 Mar 2019 00:39:15 +0700 Subject: [PATCH 262/385] added komodoku gui --- src/gui/README.md | 27 +++ src/gui/Roboto-Light.ttf | Bin 0 -> 140276 bytes src/gui/Sudoku.py | 362 +++++++++++++++++++++++++++++++++++++++ src/gui/background.png | Bin 0 -> 308479 bytes src/gui/board.png | Bin 0 -> 5678 bytes src/gui/sudoku_kmdlib.py | 41 +++++ 6 files changed, 430 insertions(+) create mode 100644 src/gui/README.md create mode 100755 src/gui/Roboto-Light.ttf create mode 100644 src/gui/Sudoku.py create mode 100644 src/gui/background.png create mode 100644 src/gui/board.png create mode 100644 src/gui/sudoku_kmdlib.py diff --git a/src/gui/README.md b/src/gui/README.md new file mode 100644 index 000000000..8a3778ea0 --- /dev/null +++ b/src/gui/README.md @@ -0,0 +1,27 @@ +About +----- +Komodo SudokuCC GUI + +Just solve Sudoku and earn SUDOKU coins! + +![alt text](https://i.imgur.com/std99XW.png) + +To run you need up and running SUDOKU chain daemon built from latest https://github.com/jl777/komodo/tree/FSM and started with valid for your wallet pubkey in `-pubkey=` param. + +SUDOKU chain params: +```./komodod -ac_name=SUDOKU -ac_supply=1000000 -pubkey= -addnode=5.9.102.210 -gen -genproclimit=1 -ac_cclib=sudoku -ac_perc=10000000 -ac_reward=100000000 -ac_cc=60000 -ac_script=2ea22c80203d1579313abe7d8ea85f48c65ea66fc512c878c0d0e6f6d54036669de940febf8103120c008203000401cc &``` + +1) install dependencies: + +``` +$ sudo apt-get install python-pygame libgnutls28-dev +$ pip install requests wheel slick-bitcoinrpc pygame +``` + +2) and then start: + +``` +$ git clone https://github.com/tonymorony/Komodoku +$ cd Komodoku +$ python Sudoku.py +``` diff --git a/src/gui/Roboto-Light.ttf b/src/gui/Roboto-Light.ttf new file mode 100755 index 0000000000000000000000000000000000000000..664e1b2f9dbafbf6280305123d2df7fa0c66cee9 GIT binary patch literal 140276 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 literal 0 HcmV?d00001 diff --git a/src/gui/Sudoku.py b/src/gui/Sudoku.py new file mode 100644 index 000000000..7b46d93fc --- /dev/null +++ b/src/gui/Sudoku.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python + +# Copyright (C) 2010 Paul Bourke +# Copyright (C) 2019 Anton Lysakov +# +# 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 . + +import pygame +import sys +import random +import sudoku_kmdlib +import time + +class PyGameBoard(): + """Represents the game's frontend using pygame""" + + def __init__(self, engine, windowSize, gridValues, timestampValues): + pygame.init() + pygame.display.set_caption('Sudoku') + self.__engine = engine + self.__gridValues = gridValues + self.__timestampValues = timestampValues + self.__screen = pygame.display.set_mode(windowSize) + background = pygame.image.load(sys.path[0] + '/background.png').convert() + board = pygame.image.load(sys.path[0] + '/board.png') + boardX = boardY = 10 + self.__screen.blit(background, (0, 0)) + self.__screen.blit(board, (boardX, boardY)) + self.__tiles = self.__createTiles(boardX, boardY) + self.__drawUI() + self.__draw() + + def __draw(self): + """Handles events and updates display buffer""" + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + elif event.type == pygame.MOUSEBUTTONUP and event.button == 1: + self.__handleMouse(event.pos) + elif (event.type == pygame.KEYUP): + self.__handleKeyboard(event.key) + pygame.display.flip() + + def __drawUI(self): + '''Draws the text buttons along the right panel''' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 28) + font.set_underline(True) + self.__titleText = font.render('Sudoku', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 30 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 14) + self.__titleText = font.render('TonyL 2019', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 55 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__newGameText = font.render('-New Game-', 1, (0, 0, 0)) + self.__newGameTextRect = self.__newGameText.get_rect() + self.__newGameTextRect.centerx = 495 + self.__newGameTextRect.centery = 180 + self.__screen.blit(self.__newGameText, self.__newGameTextRect) + + self.__solveText = font.render('-Check Balance-', 1, (0, 0, 0)) + self.__solveTextRect = self.__solveText.get_rect() + self.__solveTextRect.centerx = 495 + self.__solveTextRect.centery = 220 + self.__screen.blit(self.__solveText, self.__solveTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__checkText = font.render('-Check Solution-', 1, (0, 0, 0)) + self.__checkTextRect = self.__checkText.get_rect() + self.__checkTextRect.centerx = 495 + self.__checkTextRect.centery = 260 + self.__screen.blit(self.__checkText, self.__checkTextRect) + + def __handleKeyboard(self, key): + """Get key pressed and update the game board""" + validKeys = {pygame.K_0: "0", pygame.K_1: "1", pygame.K_2: "2", + pygame.K_3: "3", pygame.K_4: "4", pygame.K_5: "5", + pygame.K_6: "6", pygame.K_7: "7", pygame.K_8: "8", + pygame.K_9: "9", pygame.K_BACKSPACE: "", pygame.K_DELETE: ""} + if key == pygame.K_ESCAPE: + sys.exit() + elif key in validKeys: + i = self.__currentTile.getGridLoc()[0] + j = self.__currentTile.getGridLoc()[1] + cell_num = 9 * i + (j + 1) + self.__currentTile.setFontColor(pygame.color.THECOLORS['blue']) + self.__currentTile.updateValue(validKeys[key]) + self.__gridValues[i][j] = self.__currentTile.getValue() + self.__timestampValues[cell_num] = int(round(time.time())) + + def __handleMouse(self, (x, y)): + for row in self.__tiles: + for tile in row: + if tile.getRect().collidepoint(x, y): + if not tile.isReadOnly(): + tile.highlight(pygame.color.THECOLORS['lightyellow']) + if self.__currentTile.isCorrect(): + self.__currentTile.unhighlight() + else: + self.__currentTile.highlight((255, 164, 164)) + self.__currentTile = tile + if self.__newGameTextRect.collidepoint(x, y): + self.__engine.startNewGame() + elif self.__solveTextRect.collidepoint(x, y): + self.__engine.getSolution() + elif self.__checkTextRect.collidepoint(x, y): + ret = self.__engine.checkSolution(self.__gridValues, self.__timestampValues) + + def __updateBoard(self, gridValues): + for i in range(9): + for j in range(9): + self.__tiles[i][j].updateValue(gridValues[i][j]) + + def __unhightlightBoard(self): + for i in range(9): + for j in range(9): + self.__tiles[i][j].unhighlight() + + def __createTiles(self, initX=0, initY=0): + """Set up a list of tiles corresponding to the grid, along with + each ones location coordinates on the board""" + square_size = 40 + tiles = list() + x = y = 0 + for i in range(0, 9): + row = list() + for j in range(0, 9): + if j in (0, 1, 2): + x = (j * 41) + (initX + 2) + if j in (3, 4, 5): + x = (j * 41) + (initX + 6) + if j in (6, 7, 8): + x = (j * 41) + (initX + 10) + if i in (0, 1, 2): + y = (i * 41) + (initY + 2) + if i in (3, 4, 5): + y = (i * 41) + (initY + 6) + if i in (6, 7, 8): + y = (i * 41) + (initY + 10) + tile = Tile(self.__gridValues[i][j], (x, y), (i, j), square_size) + row.append(tile) + tiles.append(row) + self.__currentTile = tiles[0][0] + return tiles + + +class Tile(): + """Represents a graphical tile on the board""" + + def __init__(self, value, coords, gridLoc, size): + xpos = coords[0] + ypos = coords[1] + self.__fontColor = pygame.color.THECOLORS["black"] + self.__readOnly = False + self.__colorSquare = pygame.Surface((size, size)).convert() + self.__colorSquare.fill(pygame.color.THECOLORS['white'], None, pygame.BLEND_RGB_ADD) + self.__colorSquareRect = self.__colorSquare.get_rect() + self.__colorSquareRect = self.__colorSquareRect.move(xpos + 1, ypos + 1) + self.__value = value + self.__gridLoc = gridLoc + self.__screen = pygame.display.get_surface() + self.__rect = pygame.Rect(xpos, ypos, size, size) + self.__isCorrect = True + if self.__value is not '-': + self.__readOnly = True + self.__draw() + + def updateValue(self, value): + self.__value = value + self.__draw() + + def isCorrect(self): + return self.__isCorrect + + def setCorrect(self, isCorrect): + self.__isCorrect = isCorrect + + def setFontColor(self, fontColor): + self.__fontColor = fontColor + + def getValue(self): + return self.__value + + def getRect(self): + return self.__rect + + def getGridLoc(self): + return self.__gridLoc + + def isReadOnly(self): + return self.__readOnly + + def highlight(self, color): + if self.__readOnly is True: + return + self.__colorSquare.fill(color) + self.__draw() + + def unhighlight(self): + self.__colorSquare.fill((255, 225, 255), None, pygame.BLEND_RGB_ADD) + self.__draw() + + def __draw(self): + value = self.__value + if self.__value == '-': + value = '' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + text = font.render(str(value), 1, self.__fontColor) + textpos = text.get_rect() + textpos.centerx = self.__rect.centerx + textpos.centery = self.__rect.centery + self.__screen.blit(self.__colorSquare, self.__colorSquareRect) + self.__screen.blit(text, textpos) + + +class Sudoku: + """Represents the game's backend and logic""" + + def __init__(self, puzzleFile, rpc_connection): + self.__puzzleFile = puzzleFile + self.__rpc_connection = rpc_connection + self.startNewGame() + + def startNewGame(self): + self.__linePuzzle = self.__loadPuzzle(self.__puzzleFile) + gridValues = self.lineToGrid(self.__linePuzzle) + # prefill 0 timestamps for already known numbers + timestampValues = self.prefill_timestamps(gridValues) + board = PyGameBoard(self, (600, 400), gridValues, timestampValues) + board.setValues(gridValues) + + def __loadPuzzle(self, listName): + self.__chosen_puzzle = random.choice(listName) + puzzle = self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["unsolved"] + print "Puzzle ID: " + self.__chosen_puzzle + print "Reward amount: " + str(self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["amount"]) + ret = [] + linePuzzle = str(puzzle) + for i in linePuzzle: + ret.append(i) + return ret + + def gridToLine(self, grid): + linePuzzle = '' + for i in range(9): + for j in range(9): + linePuzzle += grid[i][j] + return linePuzzle + + def lineToGrid(self, linePuzzle): + assert (len(linePuzzle) == 81) + grid = [] + for i in xrange(0, 81, 9): + grid.append(linePuzzle[i:i + 9]) + return grid + + def getSolution(self): + balance = self.__rpc_connection.cclibaddress("17")["mybalance"] + print "Your balance: " + str(balance) + + def __solve(self, linePuzzle): + linePuzzle = ''.join(linePuzzle) + i = linePuzzle.find('-') + if i == -1: + return linePuzzle + + excluded_numbers = set() + for j in range(81): + if self.sameRow(i, j) or self.sameCol(i, j) or self.sameBlock(i, j): + excluded_numbers.add(linePuzzle[j]) + + for m in '123456789': + if m not in excluded_numbers: + funcRet = self.__solve(linePuzzle[:i] + m + linePuzzle[i + 1:]) + if funcRet is not None: + return funcRet + + def prefill_timestamps(self, grid): + timestamps = {} + for i in range(9): + for j in range(9): + if grid[i][j] != '-': + cell_num = 9 * i + ( j + 1 ) + timestamps[cell_num] = 0 + return timestamps + + def sameRow(self, i, j): + return (i / 9 == j / 9) + + def sameCol(self, i, j): + return (i - j) % 9 == 0 + + def sameBlock(self, i, j): + return (i / 27 == j / 27 and i % 9 / 3 == j % 9 / 3) + + def checkSolution(self, attemptGrid, timestampValues): + # [%22%22,%22%22,t0,t1,t2,...] + attemptLine = self.gridToLine(attemptGrid) + + #print attemptLine + #print timestampValues + timestampsline = "" + for timestamp in timestampValues.values(): + timestampsline += "," + timestampsline += str(timestamp) + arg_line = "[%22"+self.__chosen_puzzle+"%22,%22"+attemptLine+"%22"+timestampsline+"]" + print arg_line + try: + solution_info = self.__rpc_connection.cclib("solution", "17", '"' + arg_line + '"') + print solution_info + solution_txid = self.__rpc_connection.sendrawtransaction(solution_info["hex"]) + print "Solution accepted!" + print solution_txid + except Exception as e: + print(e) + print(solution_info) + solution_txid = 'error' + return solution_txid + +def main(): + while True: + # Assetchain hardcoded here + chain = 'SUDOKU' + try: + print 'Welcome to the Komodo SudokuCC' + rpc_connection = sudoku_kmdlib.def_credentials(chain) + pending_puzzles = rpc_connection.cclib("pending", "17")["pending"] + puzzle_list = [] + for puzzle in pending_puzzles: + puzzle_list.append(puzzle["txid"]) + + except Exception as e: + #print rpc_connection + print e + print 'Cant connect to SUDOKU Daemon! Please re-check if it up' + sys.exit() + else: + print 'Succesfully connected!\n' + break + newGame = Sudoku(puzzle_list, rpc_connection) + +if __name__ == '__main__': + main() diff --git a/src/gui/background.png b/src/gui/background.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4844a0bfb7b2e023fb5b008c3ad35565277f6c GIT binary patch literal 308479 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%0DIMW)1ob#@zUwv~hUnR6cWAd1 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

@^0LcoFZ<}_-7$K_YTr&=5cC(gJyQ+M#*Z1%m% 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�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

+tP3Z)2P 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 literal 0 HcmV?d00001 diff --git a/src/gui/komodoku/Sudoku.py b/src/gui/komodoku/Sudoku.py new file mode 100644 index 000000000..7b46d93fc --- /dev/null +++ b/src/gui/komodoku/Sudoku.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python + +# Copyright (C) 2010 Paul Bourke +# Copyright (C) 2019 Anton Lysakov +# +# 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 . + +import pygame +import sys +import random +import sudoku_kmdlib +import time + +class PyGameBoard(): + """Represents the game's frontend using pygame""" + + def __init__(self, engine, windowSize, gridValues, timestampValues): + pygame.init() + pygame.display.set_caption('Sudoku') + self.__engine = engine + self.__gridValues = gridValues + self.__timestampValues = timestampValues + self.__screen = pygame.display.set_mode(windowSize) + background = pygame.image.load(sys.path[0] + '/background.png').convert() + board = pygame.image.load(sys.path[0] + '/board.png') + boardX = boardY = 10 + self.__screen.blit(background, (0, 0)) + self.__screen.blit(board, (boardX, boardY)) + self.__tiles = self.__createTiles(boardX, boardY) + self.__drawUI() + self.__draw() + + def __draw(self): + """Handles events and updates display buffer""" + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + elif event.type == pygame.MOUSEBUTTONUP and event.button == 1: + self.__handleMouse(event.pos) + elif (event.type == pygame.KEYUP): + self.__handleKeyboard(event.key) + pygame.display.flip() + + def __drawUI(self): + '''Draws the text buttons along the right panel''' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 28) + font.set_underline(True) + self.__titleText = font.render('Sudoku', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 30 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 14) + self.__titleText = font.render('TonyL 2019', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 55 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__newGameText = font.render('-New Game-', 1, (0, 0, 0)) + self.__newGameTextRect = self.__newGameText.get_rect() + self.__newGameTextRect.centerx = 495 + self.__newGameTextRect.centery = 180 + self.__screen.blit(self.__newGameText, self.__newGameTextRect) + + self.__solveText = font.render('-Check Balance-', 1, (0, 0, 0)) + self.__solveTextRect = self.__solveText.get_rect() + self.__solveTextRect.centerx = 495 + self.__solveTextRect.centery = 220 + self.__screen.blit(self.__solveText, self.__solveTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__checkText = font.render('-Check Solution-', 1, (0, 0, 0)) + self.__checkTextRect = self.__checkText.get_rect() + self.__checkTextRect.centerx = 495 + self.__checkTextRect.centery = 260 + self.__screen.blit(self.__checkText, self.__checkTextRect) + + def __handleKeyboard(self, key): + """Get key pressed and update the game board""" + validKeys = {pygame.K_0: "0", pygame.K_1: "1", pygame.K_2: "2", + pygame.K_3: "3", pygame.K_4: "4", pygame.K_5: "5", + pygame.K_6: "6", pygame.K_7: "7", pygame.K_8: "8", + pygame.K_9: "9", pygame.K_BACKSPACE: "", pygame.K_DELETE: ""} + if key == pygame.K_ESCAPE: + sys.exit() + elif key in validKeys: + i = self.__currentTile.getGridLoc()[0] + j = self.__currentTile.getGridLoc()[1] + cell_num = 9 * i + (j + 1) + self.__currentTile.setFontColor(pygame.color.THECOLORS['blue']) + self.__currentTile.updateValue(validKeys[key]) + self.__gridValues[i][j] = self.__currentTile.getValue() + self.__timestampValues[cell_num] = int(round(time.time())) + + def __handleMouse(self, (x, y)): + for row in self.__tiles: + for tile in row: + if tile.getRect().collidepoint(x, y): + if not tile.isReadOnly(): + tile.highlight(pygame.color.THECOLORS['lightyellow']) + if self.__currentTile.isCorrect(): + self.__currentTile.unhighlight() + else: + self.__currentTile.highlight((255, 164, 164)) + self.__currentTile = tile + if self.__newGameTextRect.collidepoint(x, y): + self.__engine.startNewGame() + elif self.__solveTextRect.collidepoint(x, y): + self.__engine.getSolution() + elif self.__checkTextRect.collidepoint(x, y): + ret = self.__engine.checkSolution(self.__gridValues, self.__timestampValues) + + def __updateBoard(self, gridValues): + for i in range(9): + for j in range(9): + self.__tiles[i][j].updateValue(gridValues[i][j]) + + def __unhightlightBoard(self): + for i in range(9): + for j in range(9): + self.__tiles[i][j].unhighlight() + + def __createTiles(self, initX=0, initY=0): + """Set up a list of tiles corresponding to the grid, along with + each ones location coordinates on the board""" + square_size = 40 + tiles = list() + x = y = 0 + for i in range(0, 9): + row = list() + for j in range(0, 9): + if j in (0, 1, 2): + x = (j * 41) + (initX + 2) + if j in (3, 4, 5): + x = (j * 41) + (initX + 6) + if j in (6, 7, 8): + x = (j * 41) + (initX + 10) + if i in (0, 1, 2): + y = (i * 41) + (initY + 2) + if i in (3, 4, 5): + y = (i * 41) + (initY + 6) + if i in (6, 7, 8): + y = (i * 41) + (initY + 10) + tile = Tile(self.__gridValues[i][j], (x, y), (i, j), square_size) + row.append(tile) + tiles.append(row) + self.__currentTile = tiles[0][0] + return tiles + + +class Tile(): + """Represents a graphical tile on the board""" + + def __init__(self, value, coords, gridLoc, size): + xpos = coords[0] + ypos = coords[1] + self.__fontColor = pygame.color.THECOLORS["black"] + self.__readOnly = False + self.__colorSquare = pygame.Surface((size, size)).convert() + self.__colorSquare.fill(pygame.color.THECOLORS['white'], None, pygame.BLEND_RGB_ADD) + self.__colorSquareRect = self.__colorSquare.get_rect() + self.__colorSquareRect = self.__colorSquareRect.move(xpos + 1, ypos + 1) + self.__value = value + self.__gridLoc = gridLoc + self.__screen = pygame.display.get_surface() + self.__rect = pygame.Rect(xpos, ypos, size, size) + self.__isCorrect = True + if self.__value is not '-': + self.__readOnly = True + self.__draw() + + def updateValue(self, value): + self.__value = value + self.__draw() + + def isCorrect(self): + return self.__isCorrect + + def setCorrect(self, isCorrect): + self.__isCorrect = isCorrect + + def setFontColor(self, fontColor): + self.__fontColor = fontColor + + def getValue(self): + return self.__value + + def getRect(self): + return self.__rect + + def getGridLoc(self): + return self.__gridLoc + + def isReadOnly(self): + return self.__readOnly + + def highlight(self, color): + if self.__readOnly is True: + return + self.__colorSquare.fill(color) + self.__draw() + + def unhighlight(self): + self.__colorSquare.fill((255, 225, 255), None, pygame.BLEND_RGB_ADD) + self.__draw() + + def __draw(self): + value = self.__value + if self.__value == '-': + value = '' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + text = font.render(str(value), 1, self.__fontColor) + textpos = text.get_rect() + textpos.centerx = self.__rect.centerx + textpos.centery = self.__rect.centery + self.__screen.blit(self.__colorSquare, self.__colorSquareRect) + self.__screen.blit(text, textpos) + + +class Sudoku: + """Represents the game's backend and logic""" + + def __init__(self, puzzleFile, rpc_connection): + self.__puzzleFile = puzzleFile + self.__rpc_connection = rpc_connection + self.startNewGame() + + def startNewGame(self): + self.__linePuzzle = self.__loadPuzzle(self.__puzzleFile) + gridValues = self.lineToGrid(self.__linePuzzle) + # prefill 0 timestamps for already known numbers + timestampValues = self.prefill_timestamps(gridValues) + board = PyGameBoard(self, (600, 400), gridValues, timestampValues) + board.setValues(gridValues) + + def __loadPuzzle(self, listName): + self.__chosen_puzzle = random.choice(listName) + puzzle = self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["unsolved"] + print "Puzzle ID: " + self.__chosen_puzzle + print "Reward amount: " + str(self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["amount"]) + ret = [] + linePuzzle = str(puzzle) + for i in linePuzzle: + ret.append(i) + return ret + + def gridToLine(self, grid): + linePuzzle = '' + for i in range(9): + for j in range(9): + linePuzzle += grid[i][j] + return linePuzzle + + def lineToGrid(self, linePuzzle): + assert (len(linePuzzle) == 81) + grid = [] + for i in xrange(0, 81, 9): + grid.append(linePuzzle[i:i + 9]) + return grid + + def getSolution(self): + balance = self.__rpc_connection.cclibaddress("17")["mybalance"] + print "Your balance: " + str(balance) + + def __solve(self, linePuzzle): + linePuzzle = ''.join(linePuzzle) + i = linePuzzle.find('-') + if i == -1: + return linePuzzle + + excluded_numbers = set() + for j in range(81): + if self.sameRow(i, j) or self.sameCol(i, j) or self.sameBlock(i, j): + excluded_numbers.add(linePuzzle[j]) + + for m in '123456789': + if m not in excluded_numbers: + funcRet = self.__solve(linePuzzle[:i] + m + linePuzzle[i + 1:]) + if funcRet is not None: + return funcRet + + def prefill_timestamps(self, grid): + timestamps = {} + for i in range(9): + for j in range(9): + if grid[i][j] != '-': + cell_num = 9 * i + ( j + 1 ) + timestamps[cell_num] = 0 + return timestamps + + def sameRow(self, i, j): + return (i / 9 == j / 9) + + def sameCol(self, i, j): + return (i - j) % 9 == 0 + + def sameBlock(self, i, j): + return (i / 27 == j / 27 and i % 9 / 3 == j % 9 / 3) + + def checkSolution(self, attemptGrid, timestampValues): + # [%22%22,%22%22,t0,t1,t2,...] + attemptLine = self.gridToLine(attemptGrid) + + #print attemptLine + #print timestampValues + timestampsline = "" + for timestamp in timestampValues.values(): + timestampsline += "," + timestampsline += str(timestamp) + arg_line = "[%22"+self.__chosen_puzzle+"%22,%22"+attemptLine+"%22"+timestampsline+"]" + print arg_line + try: + solution_info = self.__rpc_connection.cclib("solution", "17", '"' + arg_line + '"') + print solution_info + solution_txid = self.__rpc_connection.sendrawtransaction(solution_info["hex"]) + print "Solution accepted!" + print solution_txid + except Exception as e: + print(e) + print(solution_info) + solution_txid = 'error' + return solution_txid + +def main(): + while True: + # Assetchain hardcoded here + chain = 'SUDOKU' + try: + print 'Welcome to the Komodo SudokuCC' + rpc_connection = sudoku_kmdlib.def_credentials(chain) + pending_puzzles = rpc_connection.cclib("pending", "17")["pending"] + puzzle_list = [] + for puzzle in pending_puzzles: + puzzle_list.append(puzzle["txid"]) + + except Exception as e: + #print rpc_connection + print e + print 'Cant connect to SUDOKU Daemon! Please re-check if it up' + sys.exit() + else: + print 'Succesfully connected!\n' + break + newGame = Sudoku(puzzle_list, rpc_connection) + +if __name__ == '__main__': + main() diff --git a/src/gui/komodoku/background.png b/src/gui/komodoku/background.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4844a0bfb7b2e023fb5b008c3ad35565277f6c GIT binary patch literal 308479 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%0DIMW)1ob#@zUwv~hUnR6cWAd1 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

@^0LcoFZ<}_-7$K_YTr&=5cC(gJyQ+M#*Z1%m% zZ!oEFN`*sAiz{(Tln^f*BQ1B}t zwh*`bh(_{tk><-`FG#2yt{8(iJH9>QUF8UHbwM6|Gl=xZ@=A8Aj>K-=^-*%KPzgBBi z?us2>(0`AG|8}*>nfYw=eY2iZ)26|mrQ+QeIckj7Q($`qxy%BN^H}(fuh)*&x={t= zU6hv;V7BO-`_Zb&S0R<0=Q`>X^i>5-V`;$L#pqPz{kDJ?0y*3qxs5@IAJUk}C4SA> z)g+SESDFK((ar~TA`gbw3;mgZD-Cb|^!M@Qzx=DDR*m3khZSwj!mn04((C#T?F7N@ z#Z~p*mI7ICKDN0oQ z44s7CSC7upAF956bNQbu4;t`O)Pr1~MFkEYMvBH->Ky3=(Z zBHZ`i{qeA>kxq%Li|>-a-gbOr$4((c(~YcF0p#1$;SkJ%4jS-zHIB1hNT2hqvK@zo z9p&$`*7f!bEf;cj5ft<%NE@s1oTUBCE?S~c_xEH3ldSXT-~{^ zmw3N8{d)l6(zQ!xc_k9d;Xl#VMuvgr{Yz@SEjVQCV4vMIk!7P^(#DfVRiiZdVhE~& zf>_&(VArrX)tkJotK+ssjs7$vQ(LTFednzAkf?>ORv%iNoAiilj;Xy2#O%=$`aj3Z zlOpDQ91uQhXClp0IZu3gHGKW$9d0!E81UL($Z1nms8{#)L*LyMwGzdvCAAB8$z2RT zRrUI(aHnihXg$M(u0ZG4ST5QtI;UpOj^A^mEITRVuT4g)tR&8X$B~3S_z*GrK*|aG z+m7Mc;)fA``fuYU*V|&%A|p(>z^?CC8bvA2EC)ofwV^_RG$1nywq(E;x+nmK>aO9`u4Qi^*@DDG1_YeOkeD$~g2Kh0L zg19BLvmwTfdCf(~vjc(civr&}@!e?N@~tewZ~wjgnoI%c&lL5g>>clou#NXuU{5@1 zOu!slzbFIeUaR_Z;W{w<;)0*Ijkv6AqtFKn8irR?PYOV|{%(46jYXp?e9bkc2HY(c zP0l%NnT%64SJwqJR1K%M7CUk$+IupDfTNK5QM)Fo$Yp`twoSWDImG0E7Nkj>m_-6> zxfS>OU7^ucQtTIEq%|Rv7cPI-6~>gGv-7B9QKguG>8s1H1g%~r(fY8>VJgH|yP3SF z@6ZhLBUP+?7U6gS1JCDE|J}B2M23u+18qr;d^Hrb<4wKr&J%gt6crL@aa-vNuj@Dt zEsQPkeERN$ccWk77)b$VEePzWY>6c@2TU;*0CpTJ1Yh~Q*3zMrqG*Th24$>#7{~m% zQJ_4ytJQ}cZB~O!^xhYvL_30!(aCw9sveXzA?wGQ;94@Q6(DGV?4-Hi^!4ENd)P6% z<9Ln5=#Qh5wrDwTZAlM@hdN#A=%jS!Y(= zcXivgsRBYCw}yjO^>*dy9mlaCqqexRXtSl&a?Cy(`&>c@ih#-IxMr$$Q+&#q^Xb#4 zB~MaNXL&YK=u*Sy7t*uc+uOFOSV7J|DFme%lCxO82aTG`GWHJAl(Ayhu~mhfYgS=a z8&MVHvk?;Vo^LCEr=42J@4FWN)BKiE9lr2o%w)Meaxuf6lNZD{H32UCrPbNDvL~L>}XQdxa5H~3;&!mvIs)d$^^)1 zQ`G)Ej#*rpMnL{!GZifw7sJZevp$vT|MV#++mfcy0E+tGU` zf+WY&6l3_N9e8j=>hq2uOO_~#L|jxzp2vv;L#2*Bx2BK{=d9 za#YaQ9`OCg7ry@Tu0oO&J$fzE>DBH403ZNKL_t&tAuD%Hcx|0k(36*uaGuAKreHZh zHcI8X_vuo1sO zHr^qj)9iAkad?||$>NM;)X_FmwzJ5~S_0@=V5C_JJ^$?w`2HXK6hHn?{vDJy0HU7Z zJl9NGiLkK<)uOr=T1W_Jy{x0*))BbiDhwXjDU#fMBIv5M@|bP4FR?j(&b*7IC^Ze2 zokR)GQiKHiz9Z-O&JH5P`JHpRkwZW`r|MJ3{DA}-l~6w^JdfkR)tVs$>}nY65Ps_?zwu2U9i(!~b5=ybl4rG}3_&{(^^jpcf^>kbHN-%dQY}2@;ma7EE~IU{ z!Mljp{=(yNCr8*;(Z`yZrf{C~WR-uOXpIyg!|)KMtN7%QrIdi-*lZ9w^FEFPHxt1? zgkz_U+Lp^wYhjmh>iDWzgv(f}4^mQeG9AU}>PWlqJCmC!#JRW0nF}G%pJ9Yf4el<% zqQVi2G4N=!u$KsRjMw}r%YU&bjQkuyDdc%brz)ZXo1ZpDXX0jJa(n>%P~KEZRA__{ zDGF%N1rU5hZIx{<)(d$Z$*iL*JNBIiEniZjzsuyLaL=MjLURB0S|llQRtFz+1tB`L z=1>d4|H*LP?Cf7Y=hf3q%qp9)4fx!6%*ISC{z}53xE}I`oKGVFujZg3Odd_`&HSE~ zduNdt?~@X#oeLOnNXuA#yfe-AcE-7Keif+^z? zoz`_UeD0(eBvm;~Toe_d6Xmp4HJjQa**jR?qct}cii@0!T|=FRW(e!Jz7G^8>Qh6& zYDIQS2*2^0f9IRIIf>&E%{U?%w^)IVt)B(?Ds^~`C+Q3;a-QG760$2qMhgCQOy+Gm zhO-NYR7@*L*t!kpoSE$!4vwetEz%r@Qb1*6(5>jZTE@LIj4-u8x;G#@8a-|fK#TuC3`tDft%zECC zsv>Bps<@DAEQ8_MDXrzzj4|e@z@ReM5clOG{!Db1HI?m`fM4q)Wvx$wr+3@o@b=shW5AYY z0qbfLB3hGVYB&dSLL&OuWj4jrBqmIgP=^dP?Z8jni}WkNS8vV zNwqx1J&o0Y!=Qp;@jgyZsEyOBvZBb*#^Hwb5jKIS3 z9JRpyOtEH1(3bOSFMr`jNztd&4<6rL{q8DzFv@2XrL)aRlsiL}Y%D-<&cTI0M-uL7BJUCRZYGy853%(Ku;#tcRI>uh*iG)&iK5)!AzmUPc?9v$|~9tBew@0cea7l^xBkI;fj& zO3BMz5H4f!?@cU;xX1@{p|E7O^+`INq}x@IG0@;$TypE=GuX{@9aD%`ij|~Zlin># z(MHkFr4Gr%zjH@--Yw)$`i@=|lJaYoyldfYi$2JEl*2*0!rI{jJ5{q1sFk@PCsJa} zF3*!kYFN4rYkYVW6j&s~cE)S&*vX_>`r%~r(a>s#i-wTtpa!;Ab*DAWz1lBa-NGeT zuc0qR0jUy`ad+p=u2prK7M>S%tDSpPX^Yq-Fc0qp$jupqo(&z@!U#zoRB26^{$^I{VrEaIX2#_%4l z(Nq?}x;oBZ9nGyG&vwqX$g+sqL>%iodHOO!?hOM0Z?6KNA*YDaPUM)>=ggvxc2rk8 zy|X@Ozr0>ggs`cqY-vupX%Z!?MX}_(u>MffyU8txjzxr)3p6@71m&#)4jYfNglJ5t zJq)@Nl>cSLPfABHs!Zn`&UPa6KB=vt^#LElk_I3N0@8F{?JI0X>M{ZoWxBDmv1jTU zmh6@SJL>xx>LPCuT@`v*?=4oK+QQ2kAX|F^HL*=e^ZYE=tQq8{F*i^U@fH29@1mO0 zQLz8?|3Lb;{yN<7bT;wi=W3v8ebbiW@j}Rt$*akBXX#ukb((dzHWh%Eh&LU(rc4d~ z7>nEaHCSBUQQkJ1vY0bR-gxE^JVt^7i&3G_K7mSDai+ zsrs2^e(XH?W5_IhKMpkl+>Zl3(6bdDnv4%L$171$>jqyA;6f(^6kY_S(z9)yjO%Kn zSQ8q5vhPX|nKR4xqt`KHW?qiN9MR2!t0P1v%zKaIBVr`i>OMMW)CD!XETsU9AkiqL zEd+W|?O3$HS~KXlh7Wl-khB{E-bb|^5XX53{<~O`EYI0?{E>|)#k5iq2n0KpcPTam zq%P`;@=*tv*x)nr$TTjawHPB>ZG_Tv%DVL8M(r|kc%b)41+W-)nod~e{AA^^sX1U| z=zku%Tp*Flo_33HFuX!)b}D;=2?A;zt!JS5EFx5_5(70g!(*4ih)J>HW%GD^(7(Gi zF>CB9H>Y(I^peWl{g+x5p%Uaw2+)>uX9=P5oF!W3Jg16B5TC@)NwU)HIM9xBY*VqC z=gxocFF9;7t|LQ2pfrcqe&9#H@D(s~ZLtmgYjtV|yolo9&pXC_arE zZ;cl@B|MkMSk}Hk)K`{_`#C=;3drslUE*EXM0wDtgFaIvnY$tJ!Z~dB`!a%;j6o|} z68>GQP1ka%O_2&)%q*iY?~zi(dD1#uY<-OXn7osI$&<8Zu~sA_7pDu3+`o-Cqj0+5 z9cr0HiMX{(yo$u=c;n9~sFoF0DXI#f2x^q_A}Aq*vn$u9oJD<@ybp@JJsx*>USBCC z)K4#z-~S_|zx3zP*i^HRrecCp3hs}G7Kuxo)Mv7OT+7U}I0f4aesf@u;jXmKD@pEstbP6D^7UK1X4Ph{4nMSH*lanWQt`Pm0E(b|ek% zcmLqi*vku_ULGDDzxY)|t-xOBH>b#1ebM1O4t5ad#kwUd+WQ zmBty4y5_yGoj_|yG17dQJvPo#$SHV#;p?yOI8P$4k+XEic^)Q$!gE(y(0W16Jksg| zZUk0eFk!P+V0hGea$XvFi#&H4L*+=hfWZw^7tksYTtGhzsw_Npv?lRCG)Aom!QnV} zcn`$1X|^JDP+(Vfht|Ly%!wGK2oo23DkSM(V^qyW`m)`k!FJ0ACk2G!CT?X|nmxU`SekBqQ`bePHM?2e$2|Cab}F60kJ7 z1j)C|A$W&ry+mC||b>{(ilv0s$MCahy(Sbf1Znuq;kgchsF%>Z+ ztEPjvl4HChcXY``kx_r=XCUh=rYM$QaK0j@40NI-xIWlPn-Dj!xWK{l_&ri+oO7t< zWL{i>b8#WJd*?73jkYC$BF2C=8cN%6)C0HMKn^$be&Rf# z0}b^&u;n}5eK7*Pp?7M=2N$w5a+KWKrfVg>PJH|a{}^BX2mdB&bm+$k!~k@sxp>0a zZH*AtS}De7-*+@a%?ZKdJPyP_wlr{1f3VgnI`iiobKTw*PL7`87$kX7|KYJPAE1OS|MXMiDUp$v4?dg44N)37(XV~D5DbqI&Ndrv@z zn2k0*vyPMQHh2&B(|_`DlveO*A87T!R}YVvHhla2Cw%qgSBQ=r%zt=JB3vH>Id6Er zPO`3t$FURqd;j8w%ANhm9mSS2j2ZJD&>A_E-ye5;I-fkMqYCuH z;|A9X&ZFYFQ=zhL3ALU)tEb}bJP$l>5jjUaq&)(@|McYU-~%GN)VD(ZBUCV+xZOAW z{M!TfTgKxNQOX;>_~M4Qw+`nLabu!Kj1E6M4{SLTSw4CyZaS%4w%djQGSlqLC3<^% zBIO(4fOgU->BEN)c)q={T)8XHASUTvGTP{jeh^#<7twk{IV-;Y>MMNv-M7T$39~yV zSes_}F%q$LjEWdH9Q(l*2Az}3DbnG~FTdcbeceEA_`^oF*zdx`AQgnUz@W6Q<=xyM2bi|nPxZm;id?JK^@82jt@E3pdz~kZZ>G=^` z%y7dYW-9tpPB@MokH-UJbi7_WTZ%Xo9@X5o4Iw%l75MIlPx#r-eumfn#E-uI3R{fW z5*?;reE1U1g{cDVjS2fFZd=lBPLQA5%>yV3d*5z1JfAymw+GJSB=pWp$KE*)u%pz5 z7(FG)*Tx+@Nw-tXbZJL2@7q$ual9etgy-|gVbTrvZNq*PK)8&1!IpxmByYDwmwOr5 zwupT%xZgLty}c0N(HoOn^s03gX}|MU9LD8}T)rBOf$35L{z^RYYq*IV(G0 zlM!uBa!E1bIHdSv7w^2`s0AJlDR@-Q$$WczlG?j9+;V0CN@JhB2hb{l59BZpK|Pa_ zl+}yKIn+j%RjJbW4jde4tVYWX@R4mD_|Na>9OsqFp?*|Tl^7H=>zxd-H<17^^ z-w;wjFO3P-0i`|B0gMrlw~Z8$F_6;r_Rz6ahy&gyoCgJo=PfW7b0DXTvz*+3ctxS- z*dKHc)PmMIQ}QfmqMAzyDMyUj6`7@`(80TbIy$|xav~=x)P3;E4I;w4=e^E$0RxDc z?j`3tZrdHDFzOY7vkp@Kjf&fr=<_>jh{qU+F5n&$;4AZaJ=~`^{QST9NBDF9>EFW9 z$$0ei11@;PKn2>{+b7D5jY*A%KYo0}wq+f+iRA{NZ=O>j4%)}T0cdE$q1BF*SY*bg znCxJnYQ(`09QmL%owxqFMeKbS>K1F;wBXV#^c!T#3jSC{vS0eiB*p(ZRxSgUMgd4%CHXj1^ zqhJ$Df#@+>Wa1ok=-mupiy8Yt zl5`;!)_Ss2ImIs>z2mGbLg-Y$RBS*8QUEX{qYw(4w@wf+Wkzu~#{~Kq688O2Vt>vV zfAZb8XszHEe)J1C%044B1{HT|%8wNcl;Z4Z=E z>DlqY(`rN7L_I`83&$?qJ|r|wjCUUJj>bV-h-j6^zJs}6gW`p12aQ_$L;%R7mc}~6 za1~+Y2=iU8E)^Rv$1Q(s~))D?@GL_wZbFd zw%zFG_`pSJLGR)U?NCm@#f|`v;2d1=WW>n|#_7%E@qCKe>J)EKJ}T{TBJ4VPKCbh7 zppo&P{LtV~@#TjbZaKhVaFchVF4%kYUeE#5%1XBE;T=_hbS9DA2|$RL7}0`J{nzs# zafEQJKq_J9$s8ABU`r9tN-E-Vo>b^DbUsE$PFeHM;>O|bqj3>g;n}Fsc~2As=TMx( zaE_GT8ZE_++w475DxyY}31hne4-yqnMx|uKk_vpBnLM z1%LEy$9F&f9>4a>AMm3G71MAu-HJJ)RuYLMHll64p@J2i9XyH;cqBUKUauV~1w|NJ zBTuf!{V~NhjZBhLpjzPVtoZnR!^Z0MM@q=vBj*htfB2;IrjPv0#~64#ZfK*T?S&D$ z$n}5&QpTrGZ`ksNvz|yPpzfy%OrEbNZrcrSZ*Pbx<17X4?YnPBa2`EUMOMxV7r_Nh zq;X&CsC}r6yRqWVdy@P+A-xWU#xS%h^;|^NUJxTep*d!_K}FOgJ0?2(Ya_+nAn2{} zILm>G1P_N&PwLcC0+|mtI9ISAPuy;IoF|O}V)*$3(%sp2h_GYsU{i{D2RSFYx6T zAGlzk4rf13@hId%fW{ueVTjz7lUp;Za?w%CsUtz*WXR|4Zg7;LXJsEBm=zk+PM$x*)u=vha8Ldu>6_8sq z5&fw!bzr_C|NZdfN2E$outiEIh46OUbZkZAVCs||feJ)UZjJ;5&g1p0$oHV6Vj9;+ zj5gTAj!h^r-~#8E`N6LJ1KrUmYB0aD^+xB4Bd&j~4sa2l-U`0_;Mg3&qm2W>XVlWT zv!|wNuvZQ}V-_cX4*XIIaw6WNgw=*X@jtDe$l9Xu~U_S{}k6~c6%HCl@z9*l=#>LNhvNOJq=v~yCGb7OY z8aWquv|Q`Cm8aLWdLrfn6S~(CyLK{?Mq0!W3xS_sukB!-A`qT0?El06iuCXPYZx&g4u`@cJ@3E* z2uX2>%#rn6Bv*aEq-`5K+G{FQqUYu`(~tv!aF&W~`@nWdgwW9X6!91bNymW1d|ztp zJWWhoM{mH{H~7#I`ibVKj-YW`L*6oaa|=Hg&cSg5PmLp~7|(Gs|2xw191Z7jFfwZt zu%Nv&T4h>=gQKen4KxBzDWXS-YN8S87z43KRRh;{651O**Br$6$|0hbLL_=0u;ql; z{zCC`|4whpR!NB0$3Xa0nRshS42@&q(RU*7`QEvmzyrQV&w$ z6}paHc_@T)5V08pqc^Z48KQUSmBud)R4n)b)bk{x!&1>oMH`LA%*<=+Xb1x|_pXiP z-}OXbo=x_i{th=V{6I$|1O*ih73bM#T@4^?5ohm+Y0B@NBchXh?=}X4CzM7=-uvr7 ztqos&{Ug8=TI2$~H#mDq1S&crB zd_;;FR7su-%9M#n z8)85ogt!rEKzxSb8trjE06$R9gA3yZ_=e#cZjX(N4KdWEpjR5tfX@XgvVlM*AAiE*mJzTcI$%@|)ooO4v{Dc~9l)*?+|ot`N2912 zF=_U^DT4!|kGSOxt`FJ+KEQS2e!AWCG0yuxb`vHuA-VWp#ks_U6qfz6% zW%6F^tzh&5_zE97hO2aU`+?9KTx&=kNPfU|Myb4mM+bUC^gxaSg9R7SJM>bJ?-?#p z;p+lTD$?+1$ARcNk{d|Qq56vMDi9i6=!ly`*=YkQsDrH zKzP3yiT@A)1SZ>A6^{#UNsM1D_?vnmi4*bX0#rq5W7RZ{^Ps$U+|9a0_FT)D9#A~G z@xum_GJ@cPdIrfD$py9!rjxIIIsIp*Z#t6Rr$# z%DRp$yu+eK5(%!gau7c*Z$8^qA#*h)oGO^1(q1e3w%KE{W~|XDMd(!IoS65wE$hm2 zl!mARz4xeRVRX|mxi>Px&=^)H_ji%r&+jFbzLFIMH(F>@xZiRD#VKQk%2dY##kvV9lDcxzcj&RoY$EhrpK zM$v0iz69}boN^(o^@cn%c`icSh4Gpi>{mrOoE^2D814)F{vZ5+zw#HqKx@;t&%TpV z3t80|vt8>u){OkW^E*Qzj>x)3r)VX{Nb+~|Md?(zF%o6rRBTO0?8ZUrVrJYsKch~~ z!@j?$kYR2O*+&FLWazmJ6A;}Oj*Gi^!(GFeZC+$d3AI%C81&tW;;%P06fXNz|2E#I z(dlS+e;tbw4j|Et1gg_Ge4sZ@bTI2G1+Qrx;<#1l%f*bhs6GPQKH{i+|bdzL#+o~Z3v7sTI-Y6*iM4gxUE-sH8Qg)85Pti&e&d@lFx}W= zVy;Luu`AsaJARD~F=muVS^9{axQ-29plzB5VF zK5%j_59SaY?>v}nV57*WqjyW5QHqhEdvlQsnU^l*ZZ5K!d3KFxAvizrh@!p=ccpFu z7k6357t*OveHUwfA9Nwx2oZ5j7mub=3LcLKjbDww(IW3PQdLm_H8xGVCf8qc`D_kl zYYqF0GOMIGQIkxKnwS^yd7kRY)l8P4`WKnQ-FlALfKCaOmG4ZF{pnL>v-0eQu!f@& z6(xn3yu-J*x3w^F#Vs5CTBz7V#j&HZ6gi0t zo9Se{?ki`aX{Lvmc;3Zj&o;?EykvJ-N9}8)AnWnXQUF;)U>Wbz z_n+p-Vh>&-^nhyf`0S>&7%)EZ~?NTMIXg*;}?xxfW#fL zPNw}!T?|aG(L_>gNP%qkmUUZKMXoVarGlH3cxo`m^ z?^>MmTWd7AF=visLndP^s?9n-CsFsQ;cf63@QCq-Q7LxoyPy4U=w|Mr&y7*_gGN26C>= zw#24&IE0`4_HTVN&E$q2R-(*kjflrX4Zr$wv3j$}tXGic?HM#`vG?~u<1Xaagp(zq z$=65*JzPzIGc*oi&Bn7K)%LS?PIy;GX6MlAP_nHS9<5#sDuH1PC+DF$y|N@A*0CMK z5^!2i-dsbw;uyobyf%6M7Kx$1qfSl)<#lLBMAH57&Rmjmn=(PF?586^z_LNEDe>~$ zN-3n0jFI4ETj5_WX6wNtoT6>Zic)B-fGNuCLbhGAbuzaZh_T&YI#{b4h!d zT>XNq`Q0!VzYQ6dAYFC)KCQX#`wYZ2&Zeu0sC^F8kd^#etULU*D7RgbjUcj!4a@;* z8xkq7ZP>5v%3#8l=g$wy>k|{jlg%t`b8>BPY&44eBhStv&R5s;&mqzFLcGSD)Y>%7 zP!2Q^h1kpgirgt8%5hPeZ`cYj5(WmMZ*Z;&Yi$XRwZ(;fkJe0gEm)z7Tpt4B#e++D zA1Os%(_y)^Eb>3J_@Cj$Hj2m=-}3yVAR^u#S%c)1-^Bw-VW{swkPH6Y&aBDRi;D`z zYJAPemV?kRcQK!oKy^_+U(aS6x+|v1T4eQMT(oK5)zZ|WLOrldQ(~KZdk4)pq;+4B z5a3)cSNm+YTQ)gu9-(#||MU-#{>ooaRIL$N zQ4wZo(h0>DL*Ichnu^Dq**`GFs*Kmwt4`N3-_yomG$vBx`OBH9_W?y<{eGWf?qRG#eT^)d-i;`k!)JOuuta@qfs9azWFbH@{I&F%Yu`RUp6$vU&X{a zSR}(1K-UFr7rS-)4w|Aq%q0Ou6|Rfinu0a+^Xvg^yJH*XIS@iA0sM~5<*<&A|X?H9wd z8MWcmJ(&(%w-hioZTvdsg}aQWBz)F5Z(rjM=Ci5Gn&|8$LgOqNW9|EE=@KmBVBP#} z)RJuKecv@7(7H;?_pzfXDe|t}iH#{DV)j@X1bY$5=b+JeVgl*>y`y*X6|>o8mo9pY zwyY^ZgYA2R87+SBo91_P<$OzXq zK*2o-nA7j z^s&U}XmcVC;yEvcgTG`D&e)Yn1rd~v&~9#$a?<@OMWrZ$`)F!LY~9DHxJw+>v>MNP z=a-SM_BN}JoEmV(-%b;#3F`^XF)QpJG;N2Q)2+F7H-5Ql_eVbg>ByE|Av}5 z+Xh;YLI+ZA1{NsM{vH@d!4JRt&+zrX@~arpqwFVHOc+C2Z;V07w74@RVsM1lNktaN z+1Ry7=?;D|Sthy(`Q>>Yr^?wT?;`U=!WJ3c7|+`D7k%!%A}0FoDKz}_r~eRt`B(oX zocqA-{$sch(dxkH^<5eR*#;FBQF*eMU~mBgY@rmF?c5+zOd?_7^n!=>EhR6y(84rnX z6^&ZRtgJU8Skri_s#3>cEa;g%u;hT0U$+H=6j;vrrCOdbDnWg6TyV34tZm6&6Mmd* zKAUkRsxm1o>@&0c8BsavC1frY`ESc(lJ!uEjP~3D?-MG*Bvl@D#uyl_?28+F&Kb|= zb2%I>GPO9As~t#v7gh0ky_OEbJHaL8pa- z#DQGVJ6lxAnm-P*XSl{o*k;Lw7u$nvhS(NXG)h+KPt z!4XkohNWM)i8k6rP;~o#Y;L68AN7KG*kUY%ps2mgPqa;e9YfeI+9G>Pq>1^QeN;xt z$Q-k>a?t)hUAL^P?TpgcX2Bw`qztCdbZ}wYTF2w@V7rT|s#=x7NzYv1gP8dT!YL9M}WRqN27qv!9=$*V6ZByYx!0Y+ceP$E118#|ovq9z7ai2z>(6dUG zV8>X3vuV91%{;z3zuP@0qyFC8a+j1+FuaF5_P6026t%imeVR$;#<~&Nk(%OIf+7VD z4Iysq$-&+*;0!Rh5?17#h1>0Ale_Js>CW{#Gq%c=ETI`=il zZp`3qmoyJgksH^6;TL$;258G-8K8F~V`1t1EdR(J;>#G*;gmSLgg0fEZJDJa54@>3LnIK#l3vD^G3wMKaQ7?t-NXj{fZQCZd z5T1RG7>;)xIcDV@i2Rqve(QyKy|AwrnCuUW2HDHa^8f7m!Sw6q;BE;>Ez3KyjSH>q z*(})%v6RxxFLW|6!@D9@<7N2IOn%u=Zbs!Z#D>1wtTxMKun4Kmox2tuf_~faq&ye< zd8GT4#-_Fd7_=6*+eZ8(gZPnr+oP}=51-+x$sV>NLi_vHY&0zITH>EXu+ST&>vHj%C|6QViFokyMhY$2k&`P)RxeOG$-EQiI7BwW#Z z*WdANgHLFqa7Z;Zz+yOTi|exQy4OTJG92EaSCT9;hSRiy+9~mZ+~pZHk^@c-IeQt& zhs-%^E|6TZ2M2gMj=Tsy&kAnLSQrc8J)cify|D7YF2peg?)SSQFg93O!et}7$;$7y z`H0d9%ENlSUP}iv43T-?_vIq9!LQzQn6lW!Pe#Il<$K<4H>8v%r_3z2Ymp*{^!o@Fd_jn0A=^=cCBEzP3Ns`YSP6kr?8x)9m+lqex*n9a z5V*pnRvjwOK?u;orJBmK>C}tvmWxb2gFGAgJLJNZ0A<-^QUKVIjuO#FH;7(ckXw0n z_QJOZS!b0ck&IVjx+oVr$D>?xy@ZIbU6nyJ>_sgFop4N~fUpILMM8y;exAod?iT?; zG&yqg9HGUEh4qzNAfNX?I_;Fd7vG zif8H#J~|*c;!*{-AjGbELi=+? z`L$TpQBb3Cs1&ZU_PqC+b7`{%Ybh!gXuPMr_XxZOn|e%zg%%*9FIlhlv)a)w75ukJ zL}!|(jgZ+~;WDD9=lG~NXs zk0vbAIr5W|hmb~b*Ju2~KqS#YWpx{Q0IL5Pv!Jlq8d=)J+azz+xSI1skW zpXkdP@H#mB*vh5p=QJ(G#H4gw=C|_S&*xJwo6i1CD;H@cQwqA~5cmM|aIR@LW5-dJ zmmwR7LRZtmPgB!B9={S=lym{w!manQC`N=}ZAVD5$fe`5htpNTCuo61wJbs?Jc@3D ze(gbHVR}-xG=|ovwA^wdfk+|&!-Z#ok6QC=W5}D@R;AeC(EO|65!?H=*9-cqI1^PAeeC7 zJ{o8eEa?(KgPR*?HO`Uo;7q=%f4@CsMOBz{)})AmISsJ93|rjW!fg>`@L_KMk;_#6 zku|4WE-B2NLrR%*?qYsoDg8C4+47VIyQx}gt~i9b+H9* z&RMx;swNlC_i^Z$|8pp@<@{L@*XQhc$uEzW`6j0MAP1j@)IUOSPowfqb{cwSXXtOENU46wBeVcSd>De zL%9y*WPdJXXDi3Abt;17LY2Qu7LWWpD}lFb!*ZPDP?fc$V_D{y$w6p~4_jnW#Lfxl zDS#Plf@c+}*UM8jfE3em0q#3_?R@y~K`-rvoX_vn4U$uj0fZEnE_6|!7}bayD{(xf z#D}en@!X<*lp@6{HLpZ;3-Q~+%NC24`)J?UxEz{dyCO}3EgD4?MEnXY1*W{KTBp=~ zQCS*}X1#c5*}}o{9;k42x>jUgUeOFInYYSM+v(c^`O5XWHdof-LWMOUz=wg+%{haH zQ77S5f`9EHZpRF^sgSN&5D!}zTB{m;S1izxqU!3$lTy<7EX!jF94i$WQD}DTWB%T2 z2)o)S808qzJ>230wrv~WI%@6Mlq{W4$`d(D6qsY8wupH;hjJH^qYL^!pqH~fTS_U& z8(p&3QH~v%OEL9&y_SX}c(7A{SoY;{9C$n)`uA-)YHG#=1QO>=9wbl+o&)5GWbR`` zGd_2Ay;&vZ^yWK|Q_@0;_B4fBi^YR{Z=sVk^Ia|SL>37hIcXVa{lT zc-&Wow?V#C*vb$AoscJ|_wVZ)CI-xinjq~}&OzAco)-I-$D53i}Ulbj) zZ47gsaPaRX;_RPAqr{h5S6nxT?Z{QC+sJ1HP83l=IYqXJE#+LsVIibN1@n5n-pNdr z1PGCwMlEP0vS5-wI|U7!gO2>Fpw%|b>?y3$j*nzR*~80@b>zEVIc}2}PH`R~1iW4^ zh9Qvl%L z(YQq!tXfU}zf}#(`-U-(wPP1s;9N(=)u0sCqh^fv$hfRAJL<6wjO~gi{|*ZZqQrAn zS6UQCG7ZUti9&sYUlnQ=iCoYocEPsjlc0arB4XwtPGnw4w?TRQ|7H8MYa~Fws_SD39r60y5l% z)5`1TJkQlQm{DLMh+F=etR>5xS`bfyS`Z@92FN&dicpk<+~1=($8j1o4yJ%2^r!M! z;g~N)P%ekp_eztyTfLfy%GCgl3W3Nr+upKc^6`MzjY~XFsz z5ZEV8kS{Ock>*a(#+@w~hEdo$j!qKQFu3@>aywzTlil!Vr&0GbkF|)oMb+iAd6_au zQ)c$%$p+HW{8ACV`dNL}Zp0{B<=(XK+LG)kpu6h%O=IZH6OyiRK{4h9U~0TK1SAke ze&@4P_<5FBtmlzWXhT2=2lsk@KLpYiKOOO-x~ku-$(ZfZtdh*a>8q3S+_?52mxDEg zfNm~IJzzQSD6%TTE>3F^@Ht@IWjPfJ z0sFBdWy-@k&l5Rif)y$qu2b@K&tg)jVX*TwJ>KdL+gk4gd_VvQ25HnQ@N)r&wIEV_Ex;V+p zTC_ZyYuCK)o3W%5*h6%+3u*c;EsD2vrra?K+A=Tjz^=>vo!yBo8Z5Wr%0pPt2j`Z9 z->Tpij*Q_fSyYI|LUod5jpd2{9HY+Czo)K9XW=*-OQyFd&SDPAT$IWvdZ`s5P_r`S z{ate}Z9`zqM&~n23xau7X4}tn_1d|L9qb{#jNZqz4-hfMKwFG^J!ee%=qbjF5$m#- zdGQMR5xqG#{5z$t^|>S8He;{g=$x9*iz2}UVUlq4EpH1yQkn;m)mzhID@yU+a~uoa z`I}wWSmNU0x`u`1PUlQT%9|48Rk*=OixeRGIdu#tLD(~4KrdwDC1#t)>ty7L$fRw9 z9{~8-`4DK7b{zQjzy3$~@qhF;@$40w_i&M#cf0Szqe{Zl!AP_v0-gjOBlNEx^mQLQ1zq*mD$m4y|{D zpZxZ3ej~(iMUf0K+Dgamf$@Ak^|H7^bdwi^g_C11`72kYGmL79)wNa>HUN!2EKsWOUEl6xD==sL9~iJ zTfkn&d(x$@V;ahpq%lHMN8T%Es8)h=$qAi;mW3B_a$!+x#qDul_+G6w^fpP~l64mx z@qa8LQ)|WjeqXvD3;zmP`sB`4Mlrp0dwXaVnyk`*7MK)!N7o zgQ+>aceuAt-wyepdeH~JsFSWHcGuaX94z7marNsF^4}F6wZ+Y}p~w89e0Vs{({q?} zSn1d;nN<YiCGiW%T)|n54vWG2pZZg+1J?I?19~vYF-A>ERYQup-8HP1n}(OKnuq znu|~_c3Zeu6{HwH%4X2fOY4MSc~4`{gAl%sI=y6glgX&dj?u0#tTl<0F@o^d1i4h$ z-cdJ7lGlK|WxDW~za$4&sV_CyYqe`;m^A{OoG!0qeCH|7gd#%b=c~QX?nH`q7pQO> zgK{i6Ysy+hSbrf|DDMmZTi* z3%|g2k5?qaqQSPSw8-lf`MMsGQYb$j4}H&Kt|%!0Ycc_rk>S;>Q;7bSmt+ei%crp- z2TNKWV<55UVLjL>SY0dzti6bZ;U&UmwXc|_x#C^qq{HWNnYB)_=bd)$ek$quXp14G zJ*%#EAXh#}t^M8mum-G_D<&6|9Om+jt_9=OjMjdCEBUtqoSZYfie}Py#3r+&d&67qO2BBgE`gMsuyv`K*YyG@F{NAtD{D zqjW|z?fVAjGR8E$)d+ROGM-OqqUdmLaf2737o7(Mt&PRf#hwK+WuW`PFMDp~mBHMl zH!Z5kcB;U+4!D^P(kk(kWppk4Si6rOkB5p>>|Uk)=Jem$wMgr4p1ZXZpKL!)xQ{>l zd|1QA);mtFzE&sleu;0P%l|rR0aouO+Wf13gjK>=RKi{wQ+>u4z*yakWs%9Bw?>oJ zKf|iemME4{7ZsKLo>wxhMcZT(U0t?GRT*%*-O>6a*NLqBo-&GAOrp@US&o*AG99cB z^gb0*a=~}?{W^I}*iq^M=K^lqji1fu3_ty1kSK&ei%i&YpH=k;DOjHEaUAG_B&<10 z91C$Yj$`LSIOBG^F|vk*Pb9?^9lm_Pj*1);-adU=I7-dfQb>0ZP0T~%;(m0;JhZmv z*j)-@*;tk!PnUv>aT8L^DCIy*QxPj;Btb$Y`>U}bt0i7bl!c94`J6+!y=<-W=YGHA z?d@&(_kx1i5w5j?u#V`m7e0OZv=GZ@Q8tkoySFAM?OYBS+Z0?8Dt`$_l_o?GxCNDB zbW+y*EMTIV{9P|mi-1`rt}T?VoV36SrOYVpvG3TnO$}(TG=R%nfukMhZD<@!2odmW10kPhMP0}$#TMao4y`e4y?1OWzmv&Z%8Kq0H=Ww& z9w9{}{oV-g9h-H&H+7Ybu zQt;{T|IfJp+y5#`^tk1Ovo{2IEh^=6L7FmAFgA*MqV$mWV`%!{bk>PapIv|N{rZMx z?%FZC^@)o{L1@oF+g#aZ>h(IA_ZODtK_((o^}MRHEnUfu(JgmV8m?M9YCk9jr;%`@ z_3|zc`D(mun_gL4^u4d>I^!c}DV2OIW{LLVkPWx*J5pM$ z0j`&iMK-LD)|GoStLlR26B(c$`@$I^DeAd+4yl==`90#aObe#b%-jLah2>I)8J|H7 z@H%_|A}cm0$$PxJgs*dUa%+d0Y)TD@ zXcJ8}Tx$*6jm81Za`{C1YY* z%U&GqWlfU5Q(yRO_VQmXFYwM579nmS|zV@4uu{1n|J`W{*DhTrj+7&wHWP!eufPmSDAWm@WHdq zfGHe}VY4lw2gcF_*k>#*?KUV~ktj|F+4p@JpH7c7RzDwyCVjNl_^i+B^iPeYG)H48 z_>_Bf$;f=|yZSa}lNchO`}KOQA_GH(v3t^@bc^X|Olq@myWeS~I|e@f@BbIR_!s{o zd?Id98(ky1oHWcKAc$?n|IggJ_1czY*;#Ge=A3J-eJ&A^l`fZ@HV+tCmJmp`z+7a6 ziU-6?!GpygK{mYkckl-+A(;mXfrTHiWJ?$e1V{w}iL$E7c2;J_?VNq~T5Ha6>pb+! z9CPiHmns`@s7jF$vCrOX&&wEn^xoRn2K}t+Qk?_V^(G+HAdDuN44HAG4|+a-7~6U& z0DEKomX6Td@a%Z`=QdzN^Z+y-QnX8)rGq{eFXKK_tAJ!Bdv`4S_DLFqhspQL2Ywe6 zuAF6WDJ9#wMg-JW?BD4@WbC4jjf^mKLA7vwbSU?(-F`v}v%s-CvQQV?hmYUT2pKyT z9l8syn0N4A&A~O^_(mvLhlCcXjZfa%`Z~Xv{T-Oyo zXa*P;A?Ne?5McTk3Ouq*#$wAlLAjZbUE!rM?c(jdYb4@NA7t$3kbDrQ-7fefui68W zqNZRP0GC$WI2>3;G4e<&=Q4yqCm;ZM6E2V7FtpvSMGd#XkJ*bc1_VFZN!?r`R1d;@ z{vHL(e6coZE_ZBOHcb~7Fb&ITL5dMmnlVj_Xe}VulNZU_3SO>P1n-fAQ`H@#I>wP6 z>t@uZOr|?a)9F=al)hjibzIE^jA-DO=X5#`Cn4DQdmQlu(Ge)|T1Of>*4B-o6E8?L zD=604@2kbpJL>juNi^VKyCv!9gjCvzKq&(>L z3{w1#-@oI?iW|F-VX&AhYbF4wM1XhbwH-EJCM@T}ec!eX^Ac?%w!*d2tFB* zD+r9H*Tg zMxDtHKBL$_4x_X(8ozYi6`1R2=o-iLW9Oeoz9cR+$zbe;p+0Cp`HM zA^fNR*Kk?||8yACVN{0aAQR^^{ z4#xJnZU7osyRPdV1lx*zp3&t(4-dg{)I+Z}D%DQKxQ{k1R9Oh$+8XDd6=Z(jr7HsT zTCr_+5HU`HsG~t$F~TE?Ge8YnE;hmifK_PSHr^saE}5MUJ|W4xoFB+!9I7g1@ptu`x8YRyO~T1cmJK*<}f*B24sb1tNY zlv)R~Gw{YbhByudFHRz%ri?ba(AKKDrKb$pd%zwspz|Igt)^1Zzo@N#yK0K=t8Os#iP)49BGeT*l~ocogpn`*L6K`hsKcN z@!sm#uC;mypVb0%C7V!p9G!m7 zeOzlts~z*S0Oa^!A%>C1^nh`LIAjV+F{SUntr@au?YgETdP0fR{2XcFyuUv>4HygD z7y@eR7Mwgv5wxql=d>Qj_T{H4xN6oKFnd_agtWQ!lVNh54@e2&NWCg)A08WYEb z&FtDulehuhevlXsaARR*2g0_y3hmiy)qbuQP2=NOSM|Xo{hs%nqlxKyz2Y>@d&eei-S}V=*(H z$jA07UUk~`SQpE)YmK3&!-m9*sDD+_KIVFj-}6z3+=kpReR=c-nsy595M6ML?hvYW zW%22nGw$mhxAo4!mj;v!7D(HuBSa3|ZM`9jv+~i6VOd)k9a-K!W6os<#7cHnj0xxS z1=AD{-3;$MTGa~P5BL6c#v&IFdm!fJ@`T{Iqn6SP=K|(wu?>IQHX9#0=dmoOp}6;Q z0wvt<8*=8zC5<0Y@%XylQObsOWeRW;?G%9yF2Toxc3&x)18JG?j1RgIcFUQF} zkI#^^LW;K`<=%z;|MJsbxq@c_YW=p z-aBXR#mHj|0Xo_{sqoGa4(rw^FVF(Z^cJ4slC2Y#)0s7>)T|48WOE%OQ3yv((%88g zwS;~c;~Mg07zICm*28GC4aSCEvE}U`G&ZVx^ddoM=+q>Dy}SapjvY)}^W<60GBQk} zXRM{->2iT{9@|!A6c~`=EcA0{y4}a;_L1YJqG)CPO=&W%)?OevxDNR4fnJb8#(Mo8 z^XX#imJGFHxV}%lTcI;{kRLx6(QbSSK7tx|Y^amH<2hG}V{=2t zy@?4W8OV4vvuVNDT0Ok`Bh>rRGy{;yC`v7GvM1?5=6pVbdb47T8#vL5zVGUWKPPF?4q{5l5@}-KTv?tjF@?avTeGL+V%JL7iIgTZ6S{M1L2DiE`ww4}>K;^I z;$5^8H&bvm*%`y^+~Iy-51Y{#m^f|%WAXFI$r>x}&vlBtS4V(*MVuZTCE9_|(=qi9 zbUFlUa;{K0!0g;GGafgOF(i0w=Z>)#%3^vX&XQwH!#J*3?*%bAY}+bK7CDJG9zopi zE29d$$J@7WF-<3U?=Ynq>vp$?Q#V_Epw%LJI-TGHk3~cYA!2?(Mhqja=(t#`RfNWg zJ5b9!W11#BKR?TZuAh*Bie7 z{sY$SiZ9-Oh0Eo#TfQS9O*6LAvEEi`-zp51MrS}WKR3@a=6Obp6TI_>SR5xDCOyHoRMTe0TCQXv#-o*Aouw9iGHmL4@5*2r(9fLYoz>3j zj`-m4aUzDOs_Sgr&^IZLMm)<1#eE#VjL!j@Ko{M|b}N!#DWBum4$enymBKdq;4vtkK7m zhS3#%h%)jXHD}Y|Kq&lrtw&(+*sUB##z|=Jt7NYBUS%!iXM0(e;V_jBov%p1H-F=A z>c(1 z?@1aX?1-(9L!0FLrZiz&ZwIa99?j$cc$q2@2my@+MN@?`E)*z+~GT-j|SxH)B)mX8s`YL zRfOP>YvVD8u&qGAhY#OkU01w$^G@;#JxVK~OXxUI2XIC+`eP)p*oCc@Ek;ZrM zi^SdiitFtKpPpYZ&kLTOp0K`ri)lGwI=w~f4kh2Eqt>u)`$;bs?*8Sx3I{BsH|gd~ zOzzhrN}o%976Mb-ZG0IAacVvA#=K)^=;?Getz2ux?gjsImA8kxjo*I#HQv0vz{v@b zh4giYIS!U{r9kuN*`1aEkHPfa3V}O4^E}~tz47&g>cl*P14^v|$n%CO&=G$r*{t0C z;Qn>i$zp0Z4)DM&Z_MZ!z>uoBsI_pQFoBIR&LfHg(9-J%8od5H9d*YLF(uXpy5L2~ z!2CKb@c5u`GWhg7fKo za4;nSE7lWyRN3 z1nsTx``h@PR^tFbh%>uz6#}jA^Vn(Eb#ruO6A?V|wb(l6x|Ym(x_Msk)w?gTm5OOz z427W2m)*MI9v=QThQ_iR%s8Tj;Wdoxor^JwXrB-Ow01+y8=PNIOE!EyDG~5 zp@<3{w=$}Q*Q{xtBnNdU7`#WxMTFmbvDo^4hz)9>5UmrlnFx1D1JP?i#GN_kfYx!y z-3&3n<%;kB=HJ1)|L8BHd5`8h(0JV*yYecfkYz=>SS;qQrHWif3`X(}D6^`y1{Wea z6?q06Qk*cSWeAJsHF2INJ~$Q!s-CD8{&O4_$%4EPk~zmlep3t{t@8#r%@M78 zL?UB0DV#3|u7WoV)<#sZk_YdB4qPrzNE5r|o}WJ;7w#(cD)!OfFiYf2t_|n&1)>jz z^AM1#w=6|ot-OuS2Gl1kJzGyW@bVReJyxAS-~u_sU}3N!B@2GFuNM(9|JVjn_A-%m zKgC7?Ymw-ma6oTG+=dO8^BZ^{aY(r(CtvCYH(AF)1!+pELfhptq zXUH+9iDbiq3wBCYUK5KZd9+xI@QI}JT54l-37i-z7|`m(MRmKcNK=$eC8BnIZ__lf zU3qAqbJv460)odBC);p|I;YMT)_0|4;R3Wad`a-7mhGW`Y?mLrh3 zZD`Q7m_t33Rbv^M=m>@nmjF*(lTj7sTYURbE3}hldAD zd&osG92X&_7JHw_@xg_ooE&N{fD~umLy8S2g*OYYT?0HED)tl#I1)V<>plt1SX;c2 z&eloVwhcaL5yzujH3XfOvq=lM@L`@(y7TvY#bTF-g)RDjrhQ-@{1}$Y#smRyooMm*Lkti(~Bm~nS>%l&xKjl zv0wzKshU8S3^*S|&#VWaj@~%H*vBB_HDD{5yC|Kz?k;%nM<>MSqzM3)DAXnyzI-SM z0ABvfzlW#a`Zv)$fGGlnSxlXP)(NGS9j2>=Y~zkA19q!?{swpl3ITOvbBmXQ2s`8m zporERm=)^T9Tz7v>vS=}5CM7H5K_c#yA)5%ek z<(Axxk+MvT>vuk2YgslFCA{jQ%|Fn4cJeLJ4dXmk+lMq`T{n3+IhG~~1T=b&R#&dd z!Kd-O6-NKpik>slGE0%?fZEYh!1MD*oKA~S!yRJeVv2cPB1&}u-+lKT-oATl!nkD- zu2u-h8=p>7^q}SuQ#m=loF3Do3aO;P6mEbcp>-$=Kv zu=6aw!R4HAI&sz(cLM~Jwq^hhWn0l)!LrPlr`h0_0sNwQFKuHvo$M=>Xv~N=1+vAi z%WT~ZU+zGz%0CaSWP6N1S0L>NP>(LwU(DwraHNK}pGG#`+o3~*j+>thmoGVV|219 zIwAS8?xfRk!2Eut-BszlcpW4$^qt<)JG9~of;G`{11e`Ay zJb(I#^V0>l>s1_*4s)77t)sM#I3>iGu;rBl#cRcE?fHJ_elMrlMEIpN!;$pP?$o@o zOQ`0G5NCu4F&zYKxgd!SGl&&Brii?5sHGyNh)bsXVr+x}?cq?U0Oa>>pSqfAg>!l^ z<;|3!&{_$6o)!ipi+eIUc96BkW{lH(M$K%Mzi%6+(}a}RwMPhoxmYE0E})l=oC{*~ zCPH4$j6z{C_k#Pja#DtOSl4Zc3E{$lu@eogSA-;bBe2Bb>FEhRCQxsPG2ncDLQFG! zn61!ocGT;`sxlk^rNE-$KxkDBxbxkq$|l#~T;$D5V6Y^5N8Zpg9J*x%GCp9(b%bd4 zYdGoX>9gU%i6PUp7|p%5Y$4Uo@%X&eE*o?+6V+*EQn*ewMhA5i-D`K8=%Gd7+c$4P z-J?4~BjM}Gs5rEa=fC-P@#eSw62j?(wN*qpT*B?+>|Ptlcf>UFLEbyo9*fZ?CXe-Y zWyf&iwKX^=W7sAK&&&r8B21G*C3a{NakoB%#D~qq4UXQqp@B*wj&I2M20}-Q=V9u_ zMP*gzvh4M6K#IZg5O)&+*9b}CvSJ8GAsR}@$&TRVP;xq*E%+Q!BGzQzY3PV9;C{a% zrig9L2q7ZP6Jn45tzw?P2Rh*U?t?`LyN&!ANi2~qR;%%*1Qo=k3 zxK7BWBF=pJUhfQ=bKW5aZo8%wux^DHwc4?qPw)=da^=%~si>uzb-ByTl3K^p$;&;zQBZvPj}Y%OjAVi4!vkJj)#K=Gj9^&$#FOHG~<5X@bu;lT5I^( zPk)Mc@88=v(cD(Gz@I!?aoDzoH*Xe@%kV4fE(~-yB~VD%?i;>*{{-p<9swbqY$M_L z7hpL>gPn!ov77>y8F=?*Mu?8*zvOYt1@jaTgToRdyeAYyb1Se;DBzs5jbBmW&?=!c zLM_0yW=u0X6@zp`rYWNLie;H_y^)Y~oh%AKnxj~}f$Md}Jh5#$q`(h!&Kx*fD@x_@ z&hzsNzWnknq9f$iaK8(=IRrGYt}n#^ADxV9I%*{>b3_ag(REyN#grmqAWX?)P9C3b zH@tawLEhMM%pIkUd5)MPkHdm@aIT~DW%?D6-$TfgS+WX#1 zJHFz4o=rm$f=4M0%RKWlDILnw!W;KAMM(tcNRBYaU|El>!Dwhbo3mzHSNO<+{k#=% z`P~tx6TbcC1Kz*AV4eeR5`;}8=84{0iaef#R&lAKpMX#Z=9Lv14`r3 z{nOJ0tyXMBoj3v8{Vow60{xVtUCj_ac(}-nA%>dXO&8UBCfQYe+B+k$Be$MlR`??|qj}8&%mxkUQQgm>EH`x$80D5u-z#CeC83 zUGm*B2dX=VF5S@Dt8`GgD6hS7MxOAbf)q0j38favLW7NJW17%1yM22rs1z8JQ8GL# zYQEx>Cirv${ET%g5@1VK5c7y}PbYl!{s|vH-9ZS53ETmYLM^3;$vZR)u9E{G9Opg) zXfoysGX8Fz5X2l}h6B$q;od!BganE2!e(XyI^?q1VX+R_5$-y3;R@O8d5w1H=qRls z%C+%3H)!Ww$nn5WQm^<~(651yQ=)TP}bjOeyh{MYKC}ih%IM zY7nuiMx9t|$4Zq{2gm=|Uq%SF0`Z+GO(y`v80Qi*0WZ^j>6(sY2r*4~gi z>)1T8@u7*-1w+@ew1yP;o=ww)+wEpx-58ThMue`OCLa3*FC9G+NlKSaCm80+fRi1C z126o;DB9dbq!r=@jR~!jG?5%*lSJ&!`|pYn0~e`|@k+O?p!AAu-Qe!`jkrU@ZNY8Z zaCutfrtG3HlFo^7AQ`)PdemJ!?V;Y~NP*nGb$|7xJQQ3@sI_Nh`*Ck68kLxBDm5 z0%;*uwhqU6cWem!u6u_ioe?5|I%5?=;+xzgkIOk8?alK7505l)cgBPEHjuhCdP9{i z9&{WEXH_#-@tq$Y)zQeJMF2W+H>`@T$N3q-1J08WjXlU!?h?tIHaN#)9O+<{);YsW z)Obz!E!_E$c!bXRj=eX`Vwd(VqIKzL2~pVxj>_TArd*2@g`d!BTgseQdr;*){@m)jL<#L69;fB2hVw|>&9yhDlVr5 zwQ`rrIgby|6;tv!U(P7GU|kEkjPEYz6LMa$%oAGYh={TRy*z$(FHcZQe z6v-G>Nmx$KdwloZ_nfE@9OgOUu6PDAAQZ{Vs9aCKR zAb432f3*B^0Rfq6RP)2C;92fTOK@``Dm@#%WUG)=f( zujs_j9QB>_Ukj7&bH3qpUZnV~hAvUpU+@8O3OFUgyzu7z_RV{gRy<%DBLC8;ddLsuqA3&|)JV)g1j;A*ZKR+G#?)eHw4o^>KmSlH*YRj?*cq^0qfSVZ*M?<2VJj7FyW@wy^J9GT=YEK%_wVu28rIteq+mL|B-*9>eM4;>m&=)r z57K=tc|(;0k#|5!p7*HW`Puk%!*yHn?#%_QIZV;Hjwl7ecQ5^5)GqDHAwwEWJAP%GikH!CbMf+ycHlT>xT2^1LjV;sWo&UJyt- zoC}F6qWuc0&2sQs=NU5>D|-w9Yd>T$XQd%P4y|v1Qmd?w zi^39_X8;~P=mx=KF$mm^DaS$D=3Y*WU0jST-XtGHFdF!DB%{zOf@21kMl`ka3N+4# zz>F{hFgn%@IMKHZE{)Is<@VkTe{&i4Z?|LrJH7>)!mZaBox{koxY(_17v)%ZJQKZeBGTC5qCIJMYS`%eerK-@9#VvTuk?gd{gr4nQhf(VxZF zZx6t>c(lf%esn^Vca^nz9-X*L*5Q!6=$&TB4#}p@a_7fpRb^()PjubkhLzwU`@j`Almr-LuJCC{( zC%I{VP4vxGv2)uJ> zT?`05g1SQtkbfu1DXt;c2Kb2H2tFn>;)X&J?O1OO9uY(ZwH3G!vECa#+*W?4sl&Bi zh)?F(v;^MA!DU2dvxk#ZcH+&`hiD;@J8PxegLbC8 z<-^kftx!sqZds6cfYn$X^E9&%5`d#FHxA+?@s?Epu7wvyb)JR2kwu3K{pv67G8K7Aow!_s(WA#)MmXlh z%=1YKTCxr(h_G%e-^bRluA7Wv8EDHq9&wEkag0X_X83^c%7SOmU5d#B;yh~G3=^Wx z*;*TGjif6!TA(|1^AiMkGlXcQ2K)%B3`US9@PUMjgl5p&PArU`=b6XHB7BcQbx7s# zOfu!3JJdWfUb`t0+Bn;b&wtG&c6X(8z+fj z;%?+JFJ|T#89PN_vg)96&f(?LhXcxB57MoYw|L`&f_$GcLyZ)Jtd3 zjhfHCzwct67|jySd!RduOw-_Qh7%SIFeMBl&RYS}O4X&+9B1AW%i~hbLder~!e?|Pa|7A2sz%s$t4g|)O z@S%^#uOv}vYA{PNA=mm4a4z~z$CC$jFE>LGd3)YfzvoQz#n*pI3FIKAo*g5iqeLCw z>F3adjz%3-BmvBqns_~LU9Jg_+q{c{WE#TQ!|u4u;##hiOxNo};B_;oYrdPa9@J1u z+YihhKzFY~+gsD9I9@YbJ(2^sxloM~@6C11BKq}S5u-zH4Y!r>_4A8>wJTijnRs5w zfw_+a-D6UG7#?&SKICH%^doI{9{M5<0EK;{Ch(~UM;f>;YS-%(m&=8JKD;=0_P?eOQ8F(& ztyZMyk!4e0t_q6<+r}HHq9l52pdt57u>%}TtfXFVw&Oi?6NeDo6g2P7Sx(XjO>NW! z`nm8ZQMxoyK#iKht|tm*@ObZWyIqaRr93Nr2FCPpwYaL*WsE8@=$mMC*tO)v&F0Xd zFjcYb9_-!RE&ZeY)ejL*V_xHE1CEL5*sPrkydei(DAskAYq6T8eTPz#9Uw;HJL_M( zX&jv65$ZIj12un)xERw8MvTD7wo)#S<#u9#gerkL_*W28BOtrIh*lOBHxNm*ZAYp< z=audYp=NxZ&*y`!-%uycW11Gb=Hs<8V5XN1eYh_kaX-X3*0#*^Jmia!35mz&NJYkn zXbN*kq*?mVyi!n_2)XhpCiJ)~#Sg-x#8J>lr}g0;^Vhe5v^9hmY{i z;pxp=xF7%F9}pKE5ot=|rV^ppaMKh4ucIw3vc|${45fVxC;ePhiSlIjug5W9I`WCw zs#&GMQ+-7M?rdA*s00bcRGx-z==}9sspIhZAG;l|NX!HPI~{i~9D?z#w8K{W4s^WV zS1hLm9K_ynI-L;>zN*(ut^pbX!Xd5*016dx?NrRmEaLHnd?@p5ZH^MBb8n^ys_gof;KHJqrv{2 znjH47qGM*?P`vB2sn6s*&um-I8$P`}@4!^~JM#dg`wH$rOaeKsRl}o`VHKK~gCLzH zZyTSuwa1`k9|1YsI_%fgI9~cWB_#WPzYmA=VB~c@>;tgqsW8YGv}-fI6C*u+gjtUF zS0m=eqJM<{>bgrgdvOLLG@Z;5V{23|`IzJ~Qt8JCGySvUS~jkCTfV^|v6He^e7aVA z_j1E&nQ>n?xR>kq^zFCbVVX}^P8XD%@x{Bhho}r~-LhqKB=h!HC&a_)bNC=5?OZpn zam1%DtNuBovOnZI5wZ1DBUe-er(BmYrQH}%zhKk-9P4iUoq8_@O4IiAXvJj>K(i5J z>mANA2%DwUH*u>}v7qZIMO*UxeOdPrVnmkTjd>fZU9;f1yWnCFzLGQOVvOFxq;*s1 zq@w^bOY38>uxerUB5Du+-AAxR+!`!U*N0Mb0msM*{kuMl5Y;9o!pCUyBmmae|Gkw93^4XGUe;5+Qu+0o>iG2WJs1y2 z`W$I~ERX*Adn$E*%vaP5xiK7kUAY^s|68*Q_0Ix?QZt^PKMrwWI7}FrCzxb3r0EdB zo-LIR=;+;n7((ldgy4W$${}uQ%=ZiqGHNdN``z#NVWU01Z(}r7jLGkHU>QGFfla$12;N2J`9*Oj zs*72>Lpf)=XFCy}EK0{{@Uj;?CSSM^%n3!q+=%2L2Q+w}IM5m-pjaI4>toYlOorzZl$AUW;41!{K+5CmJ3R0I9;Cb{{4HzA>dZ^NF;<^$f%GD z#P;f;`9=Rc7GY!Di!L5*h=kCGfHfeKwW>93ojS8|7|N%`lza6vUT?7dRZ;cWeX*~k zW?j41nM4V$7 z+fG*JIdOUj&t{ilG|{Mbn>1>KHz_YRU)BUE&xgl(u=u1gF!*sStkDnpbvYL_ai@(M z5e+&XPXS{d*;ts@CR`Xe%VHyt6<9hh;*n(Ef6rg=?EU<1mPU8Fv2;XAZegfA2rR9oASmsxF7P#2ayFC5TICdyS8==rkPwcR^Zk6q;BXid9h-grI& z)h!iM+_i67s5a^Yia>4cazd}$9?;x?d0}*fog|?+g&EJ!&(el(Hjavdtxzq`*qzz+ zM6hRN91ZLi?rG3HiEgNptwG9@3enjjZzED+6glTuuOS?%u@fC*1VY5R-sE|7_Kw}J z&jqEfv^RvZ_Xfea<8_e7>cCf~b!qe#_mVAijvy1ME z!_s+8;p7e_YL{Bf{$A@4X@p^f+T9^s-4A15J$Tf%S?9~Ej%z4RrDhf@KX--+?D*Es zcrHa8+})nV$1wHYtBv4#YgR}&2h_qHHOnPc9U_qxb&p-=@q6n%9)GSDJa*q&!}j0& zPgwr_zXZ1=GzY{+a1-l-yA(B@IL!b$Dwk0n3%d7FActhL0jl*5>fH(jjlN?uQxc7# zK5x|~HTId|;A1c+JBFzPN!Qy+W+U~ET-uOourtuceMC)07^hMKC1)*IlXQwbX@mD# zl?tftjduA@Cv?gJm<}?6mftr7pffLR>?rHK(&Piqoeh?SITq@iCbGi21fqs}-f+8j zJl{72h;ih1{`dcxzWCxjbEc%#_k%CL!m^yCiVPgK=?Xv&Db1$kQEAmU3K}=H$A3T0 zoIf{;+gt5^(0%=qP4Y8Z=JC%x>cq6D88@zDC&Ue5v=GX;2&_H5(vZXuIZk9O%(^%M z9qe?A&TO%gH*DJq7YH74PcA27ySnEWhxJIjFzAD$@ed9T!B2+@pT}r^?<6%GX8k&L z@{-pvin$q8(Zr?F?4@d*Tlu}w@Mkord(TrF^UHL!rKj96lv9fi-9U&4>w3qsoJ4R; zCNc#$UoPh>Vo3050SUQiAFmv>M28o4DBgZqaixXI_#o}NEP<(dhg$CV_StnI^ zxj$&Uamy*$J1X8RXq7o!vA=L2G0)9(bP^cDmh% zJVUm1vmVbO1g3r0*7o3Q2jr~|ofl`&MZK0y%r(yK1)yG&Jv>+VZUlBd4u{1U6M{b$ zsye>r{JSX8B*3zq%!#M2I4y)M7d8Y0&qVQBl?Uc!WacHG&GASmGQ7n|_KuMA9p8Wd z9ky-5+qdsnZKi z1jD5jDRO09b?guve>Z1wS$o1kkOFEyWVt~Kq6bqM&+FbdcDiYl@URr8)ovYI%c69Q z{_#Fw%^Py>xZd~xRtbn-e)$!0F8C9F;!on`#BGm* zn}^69MC^~n)tFBIxT!sMn2uvB_j9^WKgXs2x$e`@P9HlXqcHJtR5rfkCX|z(!Hf2| zDM~j>Hb#4a0F*+94MbsPx_MqM7nD*CF0q=kIRkBc1Xv6a7c?ATtxierqfwW2p|m0> zq|e-w zxh@>S%HLO5LVf?;YOOZb(xQ9^gYHG7Zmi7u+I1uIJmY%3z8ZUF30)oww&WwWe76n0 z)QT`oc97HYS8K8$3NtL{jMM1}_xp{}2@;~L8xHH%R^-f`4AX{+gNeu=M6&$f%c0=c zZi5!p`t@Vth4*Yc8bhIVbe+VNXBdIrG0)spnbIVkZf~x_QKzJ%eOu>xN9{mLkkKAL z+w(lhW-McxwF6cRz^hv<|2L5cu<`2!8C)VJLpae~z9< z@6*IZ!Oh3ihp9#wn4HIAnf}zXge885o6crPkkK%4~SY|E48}kf( zfb$#?<3nQBl;|}1ev?Q+c>PS~0OiR7MeZWS6tLY^1Va{Zrx=Z}T+VP)M2`;eT%bfT z^Tf!8gwy%N*^9ak4(pfc(n63zn|7m0f>7C;8INpFl=WMK*|#lYo|C-4U9dhK4ndfe zdN783J&%YrBTyZeBgfJEL3a&;CvWFk;laB$BxjWHf#Sn|4Iv`B69t2k1nHMO}tF6 zHqWEOvA_C$uRCwB$eR88@d)YhXK05)#}~Eo+*gCANeZIi*%HpP>4s7{JMFNTbjh01 zF_7?C@R-R(M|-=qX@fIC^8T6k1#z^wkIymRVrlV$jG+T+7^kPYD34tR-6(g>-Y%lm zf4`5;=%BS3$Ar#%Y=Q*fe=oURzFL;p>wD!t`+WVg{A(YDcl_ax{|P=me=lLeUW^*s z;j?KWum4|4X6D$SKO1!rs>>>6*Hi5}!o83kwIE{=F}`ow(F)cDWE~e5z+~5)PyTA8 z$TprHI{{j#X$NgYs_dPHX5WWt;S8{4Hk!vYX;e(Kukn(Hs0R$~;3>X9^*_7LgAN@# zEh=<@+q)lCzIWdj?#g=2oHI_#38&?ZHn4X_F{^GqrbY5WAfJ34^@Pu`-iTVYc;3ab z<9o0l^t0FEux!jl=``pr50nvmaB|ylXc{@ zu+?im9ssp~Ypr5gPB@=0EcPxHX-bBxan4(pg}dh&Uw{1*IC$GoRa2_^%FnsdwVO8T zTgI;OSg7gxvMh@@3dJbWj>am>0QK@5gExFOaCy@qL1Lqrb>;0~s19XLV(?-_@do38 zQ}jlaP1X+priP z_h_{YhuCbb;$W+ETo^{NHy2;=@cGyo^Z9~s)CF~ezWQGv#&<)pL=Ub{_o}n!oU&f} zaR2B4?(CAe)J134hmC#IDD9#|ZFyIlRgdCi4pg3uw5{$$XoQLzv~$!LyFd`?e6$eT zqqyDwO2ySL7rp-in1k@VYAg8WXFtJxz2SCy!To;6>2$JSE&QOjE+TUO6f$&6Y=4 zTQ*FH{vO(m)OVVlvk)yAcW5A>;azwQDe8{zzgoC;T_~j(Fn44%G0Sf6MkW;Em77C^9~s zPW&9A+u_63rFQH15P%p1KK!k}k2nANpGQ3{n5UULGahIy zV_ok!oi1plqSb8LN|iOFd9i14kC1XES5TLJYnk;(M5g6K8}y!Db1|#Dr#v2;moupE z4H!;xXq;6kU~uO-VhzC~hKaASWFJ}Pt+Ug=FgTBnWFjD!ySdPV=K_x;+!=<8dhH^N zE}}yx1YR8IkONaO7GTqYQn+ECGf|D`1|22ph_Gfss8mjNdH%HWB%pP;+x?lwQ^Pmk ze2q`f-y!FUr^{PhE*D&$-XhHr>-~-p88pYPxpZ)eX%)#Ej4uBEFpk^X_W1cYb8D{VLB5QIm!I8Q*>TElRl|OHghu1=OqX%z}+mNBCxM zO!N-MArk`hgL5ScRi8R>=aYaKCng6Eor*n0elMO#Gz1}rSH=;2-;}0bM4!S%6@v=5 zjTcVpz%)+qg&Bd5~^A3uJSh>A(NPLmaUdIG#$&H^0X zaR|&`b1W8?xS(AVOUC|DNbw?p?^@LBsHx;)V-~_*$Sv~)VTyybzDc`3+t_|QB*n)JD@vf(8V|%qPXn0bR5T3#fV_Gey3=d&YwR{CeV(7aT;Cjizc0D(d8cXzSJaK zm_Vh&h224zTSN3f`3L_ePJiLgp(Kv>NnTx(KnM=E+lKRULM^*kJ&5dM%R6Vyd(Uvu z;0!*hQjR8?JDVtU0yW~)4+W%xtiYP41wKaPb(PN%QEC%p&_04w*+^>*aZZA1Na$cH zzc-yIS?8@+45PeiV)RZ$BKkb0v~WTiIZFv)J$pMCOKNQhE`VHxx9(Sf^XvjYunFC6 zK+wX<3lX5oyYgt5G0K4xi=Fe>T174uYvKRCmC7SR?}O#_@DI-T^!$ucxKe(4dV|yH zgr}#saKtVY>Oh*}VH`qw$&A1qKRYVqP{qru;^Lon!t+P5=l{I1;?El`{^G(54;&!8 za(Zcj^|*N-Sz>r-r+a%4e|bmm@oVUh-38nYuX@htgX>dVNxkhO5yC5)^tP=gZr7I= zy|UvfL|Oc~b$>*HK)MDjBK6K6K$8lG8R-tnV{5$Wf@R`1`p-+qhh z%LjC-*z$(!?RwDV1RpTZi|G)w6FSn4A)9Gxqbk*zdXrh^RLfSI$13`J)R^+_l zayg@vdeCvbd-oPysO&xjY`Jh;iBmpP2b^cxeT+j3pT`YVqDr{9XoqePZ^oPC(RtG- zQpbUt6+$rbxE3C4?&*RJnXLU^>uP8K@4e)e!HP2dZ>{x1N2pegB-$zOTriidABulv zF+D<;HLO_yuQ3K7cnON8rYTs5+53dI=L>%J5SHH1o99gc9Fv zqk9}{jomqo!O<}syZVBOmyL_3@(4NP){;3T!N#uLgxWTFkRqy!SwYu7-s~qSgd98M zT9xN3${`>~+!RO4Y$e;MYFSPQlEC03It3CNQ(Hp}(hck+(PF!FqL+&8fB9X!`HO!Z zIW%mw;obQi$a^@Epyd0VHMnslyTK!nSdk}0Fb$>i%#Ji(qQH=u2tSG0rh|xo zznCT~s1;4K-fxD=7(v|AG>dVh0mLaO3T&>mB25!&$$a=ELZg0gsZUcv%S8(0WGO4E zu^J~QpW}*=V31S?$Kv}c`N_`AL>S`VNa*l^B+y#qDV;-hZA~4GDVA9&W`UQj;I^?0 z$d$5^_iQ!S;^%sO5n^jK!Rqz;g5LR}y?OH%Kltj`a6X?8s(KK}ZgF$#VmM_wV1~dcB!Db?<_7V+O73F8Fl=o5^UnJ2^!z>Ji zx9VuL&~+Zx@z4=kkc9XVa7dCz);k^8Kl<+K2uH_O>QNMg7E1T2TVonjXF}CxWJMP zc-L|TTrO|y@UyP#;hqEBiR9vsPvgt-1V_O6bY`xdbE30)aA0eqCn+PY;@fY&wjx~* zP$Qd7yG_e-I&?jC!_((OpFhJdJUAkq?h7=8k-1&St(my5q!p58$Xc8(COcNXoPPA{%%OB1!Sl)C`NKzC&I_n_q-o)zA^3r=-f+9|p)Hq! zBN)kbmf}f{R z+@0QyVY&vKPV=F|UTa0^bV#pgt-*DIPZ7&_ts2ta ze9h6U~cH;rAKW3&}#$#n^|E=Vyl1wBm%vbjY? zO%q~D=#@t_>y~Z&*-7AxA~`6zh**1LfvRO%3az|16O8NTu3a=^0m%s(L^z$#!!r~y zO-VFOn?%X1RtY~Ozz&zw#tym|A6H?`%=qu+%iy&!^M4eLG>^3DybL_;YXK79Dj z3bC-46sTE;&h6uJrK^v{ERS5fX_v-ShS$a>cj)#X*Cu_*I|!Yr?@hWGr81ba zSIpDQhriyD(?pQ2hz9+7@3}jj zw<=-S@h~c--r)Z4Kg9em{s{id_n6`Y*BlUl>&quN*HLRmD;4L{#RTd58r%=*2elUA z$7MMnHPhp&22zW_ZIuK9an*kD#g{lgy_ZZst`e><&+zDCNXa6WSHns**maj6?x&}x zLpOO8nd>vOmOVy^JI&1G(`Ru!4Do?29+E6H8Aiv>%W1Ot@3w6cvL3_W2%G@(h+ zH9EIbnh`?;Ki2zLw~J(^Rt9f}=p@6nTmEFJ1#9id@Nl1Az9;T7CBzUd0;AQ2PtVU1 z2XaHH+kvIQ8!DLt<#bx`>%aaRnC25oDY94uqYXcf-ZZTDIGPK;60G!}|6;3s#zBce zwC-R1_s^5>!>_EF`c)m3(mejmpYWg6m+{|+k%vSQ$p4vctX0+;Twh)=FN*;8ytRWF zw8~n9MlvFi2nMRvsJ~;(N$?&dFPGDJjJQ*K#|?EP)Uz17$VkBrTD#-eb`%Y_)^J~0 zW2i6uGM@lA+-^5~eExv#e#gtpCw%e6S9tUG-4P5KoN1SK){&EuUOfV_3VH1MaB;@Wv0hi%(>phl02?-)U(oi!fI9EGU-xt(o%+C5!P zCmTt=ee(w2fB!wEQbflg0 zGcvM;_7RxsUsxlz7wkI#a(7R%21dIo!Mdim+s)R~GK5}F(}ZPN@YPp807#4s!wY zBQh=6UR+7+klTNeb-QDkCT3CrD0!8pKt|3R?)NLwB(7Crz_LX%`G9rH06H$0i)E~; zMoZR#0{}S7VF2(5 z|Jy%8_*ef0V46@vK8X|;yi?TU51BbU33%s1(9 z68_|`|Huw8>$+Nyv>q_eXD2&~^+PK$A^)J4e8y*J&fcCl}_o472q zbZk#n^m!!ACw?bE#A}Xd2j_Vb0|P`Gya!zq5qd2a)8s_X;Dbc@wJxCUj@wr8vfc6V zdWZWbKmJ|1T;3vth!oY@s|=TnmrtLtZFhWpX8sQ|dHk@rX~c_{(}=^L{xg3D=kpmU zOe_=|0%;##rUUG9a29_41oO)~Fn|264qj=PMorWoEpny4VtI`niYD1id|Fi}Nk5V;dT~HC7l-3Z=x5DBmp~QBEvE)K$g^k$mpn*+Nb`w}fP@ zq1_1$`fa@-Z!d5Fe46oedBZ=aR2jbnY}<;~x{Q#+L39{pb6-v;WZ|r=+ucrLL}IsY z5+NgzF?#*R7>dX4O3s;2yN-}cMQwc2<(D^sddKDIf|pM(NHL-`?bxw!cmx*e2FG*% zbP(!t!E;BNX4G5+V#{skZQCr5%~G*xWA{w!id^r>qM&fWPQ~cP;|#OgH;mTM zED{hCWkNHqClN_uoN<$$_sXXEle>&nQ$sU_h!kag5`12Ud)3K#p z47fTMSL(&Bv(}9B`4N}PNBGIZ6pdJVV7nY{WXQ>;q)Ov_J|oqLhx=F1%8*x>(QTyH zcvH7UUHiXf=NCqNwbK4f<`^jHQ!B3#*~8X#C6aq0yN_jA$l%u~eEaTe8hI%~t>nI? zoZ*e7Ttt30K7Rbr)~K9O_xJbs^2@I<&j+mQhNq_|;x222)BOqaG?S4u-y^Lx?jPRJ zh|*YCOFX3W)0qVr8tqW43@bQONZ@VoIkM`CSVU20cWJ(#ODm;F8 zM2s6w^8xemhzf<{>DXe`=y?roZ{N0!&ndF{$?WMSF-CF@fA-mDtdz8UtXPFBSDHJ% zQk0Q+4ObK{#K=A*w|o5UyLa$@!r^ejhx3B3-@ijB8S3f$vBnS)W5VGuH|VmNzUqqe z`HXG7(!xZ=<$OWR0qfFH3L(BJ;%;J|k9ht1HD15|42Q!BDMpIk2mx9F+Blk#11Lqo zSO?p}ZbyXYrNXJ;){jh7bKm8IH5M3X53*vi}PU+?==iKFcUoo--W5Sqt_(#!`a zmEiDNT0kWgEAkNAX3ZdIkjvvBoIlX`Dp1sl z1Y=Xzqo_cabax(K8}`Z)wUS7zOU@`V8!rX(G&MxbPZL5)t>A3MP$fi%3IQ5VrWlb+ z!8}h`uJk_27<~TOk2oqvBc;GyVrtTL*8GDjqgYeB}Ic6 zi;h{HBUhq__tKb@vJjaoCEqVsOuX5T5f8$NN-6VLqT(QY86HQ4xVDiaIaK#C=gjsE zl5g1gQBfe+S%`@4Ib?(U!sqwJLm)(|7CGl*eB&a8CG zc{h#_&nMw&$Tb?9$&G*4&bWJc4et-+w5`aodnZ6a85%s^QA=ePZ}C4WXbu923GpbXnMU{IY|civOioXX zYF25WO2N9Gab2!hmNU|}B5VQY^BL1L<8U}OTZf!8tTRZFg1_(YUg7Tk9-n>wCGPGY za6PX`DKh_$1O>#|_>GaWpJ4w1KS zKZE6rKdtN!AeE!#$f3Eq?m0}tFBxa{qPBQmz;$1uPw}JVK}y5nEzY-e@Rw%rsI|uX zZ{ERJ)5ZdO*(bWO9mf|)aVKVXVG9hMD)xr)xLlS&4X2>JqglN&aMQ#pJ1G=1N{(38 z6;>1fKq&=3O*lV2p)y=5BcQvxJ6yN5S#7NA!tU6_AGlu0QTgHi0sc5+TLZ^LOwDuU z@$nI-(}{g@G)kqY3o!Ea@$nI_?;kpeSkt&m)FSWSy~pu*Xu-VBdu;1U;lsxxLP)La zmm+HN9!Y|l1^sfakrPLfvg9x-rCU*RKA&;DUQj`%i}w$&@NoB<2%kz2mo(&tl~(MH zxox**u3a)t2?)3Atp|yJw-WaGcwOBnB>Vbp1kE9Puo?2*Lr{s z)ld51^`BGmcfDTQm{C51jFe=Q*2&LxHwKns!+Ve8@s9Y5sEBdn@$;dLTt!x`blDjq z=bWIi=g7^61E3tsz;UBwHT;Zs>k$zU$hbv}OvU+H3LY6*X*V-T~3l8&) z3kxAEb82L*(6gl}DhQp@@bK`^Z1tGY2><{f07*naR5){~)U-^8XZtHs#uj6<2JUO8uxb(Tv${d zld8U_s4|pUU4>XU8cPDEXf`-{qM`(zul zq9SvooW(rfA;pYRC1T0!6xgzFjGmh$D58QX=g4YMw7Np}3b8C{{Km>7{954s3@C+l zp{auc?L&ppNwH9=r9dly+i;|DxF zJz`r|gt#G>(8h|CW)6;NsBn%Phil;sBW>{J?PqxX<}CmXt4Z}hgv)}=QdXI3-`_o; z)=u>82Miw&jkFAu5_V%bc|TcTJrV|N-JcslbpVWB2AoWOKOAN#ZSd~f_iT+oGIH`! z3J8%l!kj7&2ND?=@0vf^;dlfpu&h)tS*vk*IwPfsZN0YKs;~vTdiBttb(!OT{q@&a z)(fj=A|4)Ikt&N#Ki|B5g=wB~xm>Y?6?bR(!!*X& z!k1%8q|oHzibjLLb-5y3ue_J604txr`s&A+=L7!W5B?CZ-@L&*v(<#66pfAd<#{?V zQkOB!Go$2*Y(O-yEGrI&1CL|LPJ?V7x_a|^y<$GhEEv(<)x451W#z`NuvujtRKc|r zc&%~yx+m_lrSO}uGRyX8GI3d(!kwT-SfcGCi;N81-1baK( z4!f`slsq3MSZnBk2@%FPEbH2C_D}!tkMQM}KPFERjxd0(+|5u&`0?XMyng+9M;I*3 z`H`;f);(Q1UHRDq6C5M z%bxv@YK_g|SGX&e%LSE*jn)`KT1o**#IOJIUt*q)RK4feM=m*|q=duqNUvoro4gqm z4qy#2BCabDeNRUsYM;-TCx`d%-(y)Wt=Kpok2^#`uHE^3ModziIn2`m+ZOQES3hpK zTG#Uhk53<9Cy&G7L<`$^oX?krfF2GcL#H5C?jA~E<a)T`SCrzZ~tao%^w!e^}}E5Utg&6T-|&7+M)(4g~ouF%Y_hD-7_dZe*DF??;8>ii!Z+T5vF;D=CLA?>K9mRNR<}o0A7{_(=-FnSgs4^d4e$xA3uJ? z>3BrgHvHz@Z;5lGDvk&G4A;xYovCe%5n;XJa=9S0GS4}OI*c%-(2_lCU01}o(f1B3 zHA;%m^)J5o0$+ah6TJQGb2vBQbUGrXzK3jUr2Us0HbIoAxC0W89_PvNdtG7egyVdq zKy4YntJ>%b!hwUT6g17AQ<^=q;+7haA$y#0b}-{MNXv?^|BpYzAN;3(6XwkW@uaMU z<8b*ZzIqUKCM8=4il;RgStJuo;=-!Nzum%$!{JCzQrd`W0*zE?GD1nxw#=%qhY9=^@4QH z(~&cPDOXo3hg{;bjO0;ONg0nIONP?v8OC^|L`vhrQ4&KYqF91G#v1~GPh?dEAh&8H*j!`7c0(TIho4#_UAacc1ctS0}krf@N z6}e^vey!_uX=BWht5a)*n$6pk52zW2JR7^wSE>DYz--M)j&9uFgD9gKXGx zkyRVNOoRt91;m)}#TQ>Oa`JDx;Q78{;`yH)En&akICgKe`a_GWA6kY9rK68Zet0q0 zzsK)Z0Dgy#_J!Y3xB9g2MHYKa^GR0r|1Y8&daoDm?B@n!O-`w@5 zX=+`(P!m#04OJ(zTpG1}`SwRxwhgadzs6^8zW{A{s-fM4sCRx2ajXhrNLa2H#K?$4 zOt@ao_~-xppJLtCwk&cfm<|W{X(B6yT5&p^keTOrIvw%tx8G86VT8Y>xbTVq$9b(x zwsy|pI8V4cp78k>U*X~P8}dCfa}%6s_J<2$0ZM_jQxoqftGkgU#}1W5Vd^PRtj#?6 zouRgZYE~%Qx;0K-7k*?qWoN*qw#N7+_uq+fl5!yo=0=2s7l9MQPV zT2B#X$f!^p!(^b)RojO5KPdo=vj}WGVXZ+mQQfBUa+_wWU*zem+T$uz|= ztbVo3p_}FjVGFDzu9*D9#XOsP8ij3Lp{wlSaVHkjTI2EY5#HN25|+YB>58YPGsSXQ zR`gj16p7O+P?{!Xf(+9hPQ@jOvU=e~BC*^|)Rkguputa#g4+X+yDen`l#1EWWJxkD z$sdgFK`4@sYFmDZ)=Q6|1KxnK*V z7AiH9b-iVowJ}^+(f{Odq>E=^l?N2CY%7e_EwLR+%)sbNgmuLTwc6G)m?T6wWafQU@?wdB;B!>fA{26t*tRPx z#wZqJT^E!RIN+6{U2-ls97)P+tU*pB%h!f{KFFKMlYHOWX5B#EGL+pn%|paMMT7Zk zrED-`3{ZerQu9^HOk7k@OZ#>VqlR=h4D0^Mv3h+wUA(I;EY9LUlwZ& zwh$;*L-ptt#g-8O@&2fw&m`v9R@~pe!eKtL%>CtZM*W}z{!_?H{Y0fwx{XFv{m-iJ zImn;=_U(I?oju3xK|j*OROLUVzU!M|a5Q5zk?K)n<7cSyKe38H7j%3#N;Q0-7e}n$ zgJ7xp@;$20-=`}4pgW9utLw#{g!4T?49$W-)V?oV*sApJPy!FxqyS2Z9C?zkZVQ%W z#bsS^y{j|ZlEW~#-2F`ng zxWF(U=;7ft?(bg#%mFJI(8j_VgA6Km2i9dQ6ekpcN@b_{o!?OY@_~(O0>o&gJ91&=_j^QYPfbSc9~#c>nkRAwK&% z|1s>_SD1`OJ!cFqWcV3>*i>l3hkE6^;$c$(7%tLLrp|XAG(WN@Pn8qfl$&2@?5ZhIJ#i z0&D2J=P6l3q5!hY;kc%hGg6E=-JMWMVAEuw^C%eOcx*46*G%4hCD55r6o80QfXO>R zRcu>^su~puZlblIwD=QNcx#}cC_b!Ys7gSHv5rJEY+s`-)k5CSxLy`KE@!Nf3*SoN zL;P&gh2c=JXZutsiNgrU0B=nJnqxvV2M9NAO{)@B+bhRztEfUmNOsO{{{{sNSMCb5 zkp3j+s}_VpGkWS|h{5meJxVQbMzeBcLrT|1Vj~ZoOr992Af>H4Jr^LQ4TTT>k~6Hg zjkwxKnBJnMiWnktA~j%%L}Yi?!MO?ZbVNk%j@N^Qg3`eCdd9=U1H-ViV8gaibb>Vu zw`!zRcobQoi(;Z`Wj;Y7415f5mQ16kqfWNmLHxo`ZV)9W_mE# z)p%QJ^fw>K1Lb_Z!WzSBLq`@L;tn1oz!4&)6chzmZBR>~!$&zN7)*|0En*@_T0+U2 zTfUIqtz|M}Woi3FvS&*OZce0bGKMl8*CimugwH?w3<{bGbM-^Sy1t z4v3Zd&Qk4#-+#FZ`F;RPRn!-_XfLGzRP{U5G>|=0NX0J%t(PALXsJ)2ZvWcAsP6U! zq`-^FrD9tbgmuN`azV@q=gS3$;{;VGgRz!^0EbcwPRApT^8uI36@T;xf0eCWMEq9~ zNNRHHNvr5yjB_o z8MP$jQuy~1ySrP&lAv|r$(81SdC!H&L?SnBppj4&bE*|c5m?AlMOzIGLp&=s8r5t$ zky7OSH!)I0{+a7W1t}FmEDS3>fPI=KYQhvLM~P~(@yJtR$U;K{3GgAH!C12VQCg$a z1g#uDju|Ce_{jmaaH#pzP-BX1v&bbu>j(|gEtQOJwG9cKMMS{yS*miTVZn!MK&l?s zb%FZz<5mwdjntMkV%-u_iioiwXPVzqm6=!tXJM?t^_uW-KLIsh@&?{0QUS6GsT7*| ziZrz}2W`bZOBGdV!~`rMVv7}%(OB2S9R(eB>vF~x61?*$xk71!xNdOH!uie{3pp@> z5{O}=&Lz|PTVoJY<^x=y%ZzQMMD;Z$9A=N2Bb?Dh2wy@&Lcpe%>-CXxv`WO`K=WKE zdT2DrJdt<^8?2%Ex^+bETNiTXb{@@)P8ZD%+m?#9lBwua3f?(-|3Wc4DaXcpSeGlT zBPd#FDxP}YnPTXhH+ho?x=ghHJLj;j>|0hVtRZy~lmmEtYMEw!$H$Ldsf>hN46HFgsqoI??sSK24L*PKmYczf6cSV+DhDafJybDtsMm~XKHz$} zw*1Y?99wc$XWJTWux?93rc=zwwR3VJ7b!6l5Rg)UG773F+@0>&W!dh9hZweY&Xtl_d1ndrDwR_aC|gjYf;?aqPzk{V(>O@1rl2%MlZ8NLtRmhh znM4)ddiIej$OZ5`ssnpaS=);q)QXrRD!afNV_FuZu2W0MkZeP7rx(?)(i$ZZf~soe zJ-l+7f^RBZ=g5;&>4X?67e$f(3~{X$$bsLwipQsqI35mgPWXmwU!q(KeizykB_EJk zYE_kyFV)0uPwRp$0c+f#{=uLA)0)-=F-4TBalE_3b-Cg&QBwNhaD>(h&e44L?*4>7 z{};c-o7b=KaPojkI2|3d$?%457D_?o!p3L~B+8lm!p>6O7h)e7fN7^w7GY zkSs&q6f&x`!E#NAX~XHr-bC6URI)3u*5RA4zsB3QpW)yYtamt{FU^x>T?6|h1sJO- zgcsDIv zq|}Ab!*{+c@XlfK8s2$qYe23Q_xJaBdU|SHt`KwM z&v}h)4dnTif9GLL!C}%URpH~u4Tpn6N`>tsDx4uY zKnm1EEo(%!7I7o4$o0BlV$O(Vp{}zQ#*tkHjV`F6di8KXT>_!MD44uK2rM?R7F$Tf zr!+(l*tUXsayVaBOx{8n)sT|NrnJs_q+BphmN^`Bm~0_32T$|Jy{nDHL7e=UXu5Sc zdW0<@#Y_sS!W^4gVVGm-n0%bso}i=(>olX@WJaouf}!&jS_4)$-$f*;kxgyBceMgq zQJz8{Y1C$s5hI&I ziNbG*Izsm+1eze^5~0}^Wtt|qX~w#3)Ib*!!o-wYgq2eKoeS~A{9$4wt^hURc$%@U zTUWP%5F2eO6?V#^ri9}>Bjv~uM4U@lK^z;9kKo~SkCaG(=~%7i6o8tVdQ!|>ttH!r z5EJc@flM;Rthcg1;S$JE{&*Dbl1I#B-C?ca;?W?46^RQQG5`GHUz~CI+2=6F2{k3e zZ39$=)f1d|O(=A{Kankx(g@o^f4@|uxFO|;!+b}Ccclq|M<$fX>ZSlR)<34&#rD;T*;tD7W%|Xv02564t(roFZm4~*h!%TwU zZ&2DnYfFZ(nx6M91e{JM^2y}UbFDyOYmkbH^Eu(;`3hJK^~+!VlUftVHwiRGDg}Iz z$<%Lh4z*+)?~g2>BujfaBjig_BcMLbH{fasyE(<~-q%o~m940bv^xmA!-FsgqET;#h*Er0wby|4yXoudx48Z zLJ=u(KIOv61dRNNg$ieI0;Eh%Dbu>F8LFD5J`#SSW}+9Nvij4wWWgX7WS zvp26%l*4bnS+J}$zPUeDUK~|K`QP@I= zB9;=M6sBn=L(jtsqKDVlGve@@%ZgfQ!lF%un`WGs!jmqVRvk}MQ}G`UM=JDVqJolh8LcHc&g>@Q zYgzi7N_FJciy#ZY(^DWj37$Z#>k97_`>TPim=sVGN+!CJ^N#GJw1qYmF&3nlalD&& zM5&r>g`YeW3JwRuqd|*h*-(-}VUH^}X&fhV&ev=%+8hnEs5gOJHdtq{EeVg8E2e{o zdjH|;x-3iEq_5X=i>-6Q~WJrt6fO%Ixv+13r9s2k%_V z@tQoT2sd6Rl96Vu#kyWt9$FZY3FJ~elN+t~9?SI#XeyxSX3=7ySOU|epJL?M+>p^z zzLnN6iU{e24;AkxtlQcHS_k)D$v?8jK!FOl$$O~ge%%d7o%bk}iX*MMx7L`+)xu9p z55Zj59!pd!btL4}O*d6!)+^gz7wH>F&ta$u#Ajn~w|;=VsoS zOKkQXHPVKXL5CEnOzmKvNe;@^I+81UPaC@$;(wU*KL+v^Q82XwrMA#w=SWQ8ooh@X z%ZOz6LQ&kI=axk8cx~mB$XJ!{l^9S)RwZ?ApQu78k5hyQwa}W)C8N}g-~8oopfzwj zoNzoGp$!#~-W`ZY$(~+SagihbN5j~zGO7Fd2u-~xT^n=QWc({Z!!1*;O`SNrxAeTO zQRc6PkjZD(0Rz!`*A&SnBBUhs9VGOM=2-nnCFC%Mdp>Ks-9H8uVhhb96!6yhdbq;R zU8*sJYf4ABYJ8WEk7Vz#ts9^Uwiqx^2OOpuUw!p^nA}9@mey?YSrE2}t zT4-OOBnCOt6y|Bd7AQ9}#t7%hqKO(rZUQ+VTWo_zQ7SeLz?ARXO$8IX z#M5RXHUn~fL=`vYr71;nRteRl!mqR?*70V0*%tem{uI(rGVQ9cO<)3Fp0p(}qdE@mxzgqIa?__82Qda4weX#cL zQSdxx)cl(pZTwpZrT<}GTzdo3aqqr0BHdpzg;ILhxzdD+lNVHB3zsV=Z)|K~^F$~I z?`?O-6MpiOp8(ooxn3A)uz0wC4Xr93A3x%BIyMds=>QBACw~zCroy|4&|3anZBOK` zU)0j_eM+GNHlsfuA%?~sCEvWB<{*2LP%fgN?86w6{P}XTtPxX9`ApWD-Cm-b>Rz#m z&2~3%LFRAbj>JEzyR|c#pNUc{u0p`OtB!CjLK^0(XK}J7`e}c zCTql$h5toR$Cs?ZJ1}*Ov1?-pulQ_m=h-Fo3IMC zLi2qCd#xdB0!29EmF{O^6)7h#7~7+bY9$L1H8NZ^M^#m}L_#|gV~RL$z-8Si3FX^& zzo}y0C=S<@pJp)6M~5r>3!c}QZ4u+S|wM83Cl7PZC}3!!ojQ%lnSSMXjls zMT(c(OOZFCK$Ojt-plT;B}uCjk6QIW#5T_k^OyXZM&n?y?f^dJ4!?J<7gzDUQ#+nz zk&Zc`5*yUABX5zwzpNd3_WC41?f$!e7PV853U6(E zX11_0qD4hk2oycDELRv!MUArtf9EVGEe&Bc^G>`RN1aii#ZvV2o?ypb$3Z z64F^y+4~OY-$5y9)?9lQO5NucDoKgpb((8wS*|HXMyRH?Kei^04_UB#xWw+r=aNFi z+MW+7`>nB#!Kxp3Y&a_4MGXoj}&3Z z3hf?DUK@fgXmREdcjZDAoGUBEdXNm+!%RWb*1|f6oHFOsm??g(Q6rj z;(R_gQ_yu;FwedfI%DxP7DY{EFmxeW_gtfKgO-IZKbHed9xTZ~6VyhEyYYQh%WTqQ zZNPt*;AKaWXZ{?rnR(|>GP$vj2ZbPJa&RA4u?#Jjt)osTxDa+Sd~yXGv!2 zwNMeM6s++(bgXg?l{h8K7T8Cs60813A`W2xb8(G&(OOcS`@t;7gV3+KR!nUzdwrT`;fq~!H`&} z77KE-zT~5PsyLK?*6rHdwXfGJYA$$sdc<+|ypJXPl|TApPOzvfji;u0xn40%^X?h2 z?3GA|KJT%RhT62B_d;vm0E>58Rb=i-9!RuDms*h60bVJM>-CDmVQ$5dd^g8b2H8U? zh&*z>WgMEp?v5^#f|62Ki8K8`KC3+cW8piZ>5{o$sT0tM+KWJb7A6~)e=69pH);s3_y`R81=UUv3F^1#e245_WrV|>76qHm*>Go_n z=Ne6<=K}XJBb}F>+&})3LY&^y??%;H8?yLd6{0bke9;EflAe)>B@~?36-61Sbvsv@ zJ4-c7q*Q`PD?6CtJ3@~odWOizs0AfwY+*wT^zh`G8Uffkn(=Pyb+>8D0_=zs^OCe3 zZnVreh(Jh(J6*_`1376C7>bC{eUZzkOJX3bB~Pc*>9h;8mFm70-5$PX$zRiMvl2DM zEe-*8MoUMthE4d&Lan_GIx$N`t&G zYw^R;z6Td*W6VJ>Fow;bVz((5;VhNXm0&|rLF zM@(|S2_jLEp_Ly(t?TY!{?zvxQK(wWuug`;u8Le>k4WZBX1C7}(yH5fk-bFTvyF9l zP0O`t`KCp+O?R|{cnJ-EUUXuYFW4yx=6g}C+X72I8{f~QxwHC;%$ZR$ZJrXX) z#5~x77(2AdPmMBuj2u9ZgF6zI)4 zw2TIV=^3?3qfe70r4?ePrrjvF1BqHFHfj@IDE8};`%9jj1wbb22lmWzj?AeG3-v6Y z$(J=_O9|&KkkP1giaFCPa$Q%>*E>9fHRqCB z=OTyxvMi{Xs>qbX;E_S9m_~{&1qQZ-nofQqH5vb%3L?8t(}Y|jN>bbr0nSf|VQm$& zknAgX&YXnMSmBJ_6XcafMuJje@n1N>yf)-UHZKDMsLF}&z%={T{fxyNYOmh4Ci0*% zjQ$u)gU;DEF+jcv@B(S#m{vI3BTGu5CoP56JAr3^@|}-5525&t3_5^FW5*OQ7Pg$!8LkjKWu;Cn=~bj8=w zHco`3-H)6(;nzt=D+rcw?C5^>gJx7}wzXgsD>ZG~w8*C|H}r5s&V-Ol{$E7k7yq1A z&|n`YAqUKeaJ6v=e}8RACNHCaJfdLCyBLw$$|OvYKr50Q4jE;`IFmOl`P?ZM_{lQ2 zvLMC;KOLB~T8Ht8-62L)_>%}hYwDh-c?LlKbrRf5qYV1onSIqvOHxXzQS$5W>3SVUp6-4#hi$V)nN1eU7jRC1NaQZbyYwaF>Aw zz>eO7wa2FmZa}I04AtvG6Wb5hhLm=MP?|rvZ-kWF-H7!T;UsfoI!Fwgg~kwwyv%k1 zclQrC9FJJ8SENMf@mOf)K-?(t$15eFVBe&SO_JD*jJ(Ufrlerdtw_J+Jjxjo0=ci# zq3Cvn^N4l|M^u_{=R87K+XzX{s}q1O%Z|NJHV-})0o06JGhwz-i8Rx&89aV@%q&Txeo7g9Nck=Sb5c}LAQogvz& zU4G(@kHyzP_MdIr+PyIJQ1`|_iSUX1q70j!YNMg7MAR9qYoupJqj_pkToWmeUflLqR@PG!#d|IK9z?2d-+cHo+sIH>XX#=$el2M(mt|>18_b^HXpA8X zD*nF4Xv7@xv?PR-$!_TH{k@<60wDKmpyKKL1ZzF!>Cn1kQRtA55q+SNBP%hMHacm% zB_0cnu(d$dE63JoLz@6CYTEQVl$qOuP)cp#$^a|uY9AMMrB-PVrQ~S|`jry#zyhN` z0z)>GDfjV+_oO^@Y=r*PYQOj1PVoO`nSKyn|^ zjj?N^!cRIqdXVJrOF`Tm|M{Vgp^G5e{i|rjq(J4PP-5g72};&RF+a{UE~rW`i2LpHRb&0kQwS}{Bmx!(&#Q5PNYBc)j_mE4<0ew!le6!D3m z&q-cE%k_f!aO9s8QJD}V;$$eU9`sPL5Q?HGz*m!kF!Mn`_ffZzBCVG=6j*FbdxPGH z^K)ji#c@qySbwzFNtZj066-Ju%54nW3mV;o9DA^1LGR*O7lq9x|Urqu{3#ttWf-$ zYril1h2k-oklj0tfqavkb&Yo=_ectTlQQ!E`)l~W_WKCA&}3+6`gFVYx^X%Cvt79X zp9VThY$`>$2BdDR!#>g1)QAF)iugWVP_V;Ztdwekv&Jj7o!-&+du~QcZk~wJJb4Bh zWRD|J8mS89v&ehhHuY_yz|S4nUPbB-X@*PQ2R%DSJX?AFe6x-k$Ie>hT6P>^D8Ly{ z!P+Tx!9~glk!@9;&hM+d__nRMJ3U~YPd89FAzU#8O0?GWAg|ZJML^hf0n$ClLXfeO zEcBc+0-IM#ham_~WJlzx3KQc9P4Rwe@i{ZgDMw@ix{pa@4CTEPSY;T8bmF$$7zs+2 zaien%HJ4pA3sAB;DM}oVVTf!l1%@m@#f785uwwwF9I60djo($^fP%5?a$ia-j^w&F zr|8ys=~n0|r2wjy4=x{_~S49X!iE^5Qh_;o;AZuv0d z$Y`g?@PQfdPEu;rYIz&N?x>uSyo6O^ToK?n&Ebb!04SxKS zpU|j@$F+hU>Sq0+Zn{&nQ9=d9Ks5=v6fid^QB&v&`o$i2w2nJhPYMEA$4Xv9DUKq! z;jD=pef@4O6bVZ@veJbVFMIIsi>Q}Sue?K|UV8tL3$icvu;YlxK{Jl;Z+UIw>&w0D z6pGrEfW4^6yW)t(RZF`MZF->yp)}TTGgVMkr(C3zxHuUo5QZ9Vquqg? zdr!WIy!Xhp9h*sO1qCHwWqgkjDeXb#s?{*`GYzdM7`r2G2}{bz1=vD@`Nc1O{tNjK z5BIO3wQVMs;HZwAB0hY02V-d=T`o_QF3y`T01mOtOAois&~H?vj3mwLqi{E;Z|ry?d0>Pm{36P zZMpNX)?k_rJ1&#b6hY%B@pVenc^3*&77sDGP9s-~(2P2CIeBMQFkZ*K6@y~eWX--N zwq@ScMiS&S^vM%nfDw&4ARQyh(^QXKh{-?WVJ;8Dc({(E!*Q%Rt_e8|9P{x?&hR{1 z8#yNJepZFjiq+ZzueIjS&rwG7+Nl)*qe!BmPux+Cs-Q-eWWTkM`!PPm@_nEv2Wun^ zzl7G+0iC-=%epTQZNj(7^2V?sr=o05;!O~&{*o&6cC15D5uMW`{J1`bwL6;<>KMtp zX8e2KeEklm(~;LDtuvABOPAXeOu4`+P4OR^jAd&nh?zFM*RNk8#fX|SIa9|-i2{j8 z(ctjbX3AQq$uj(`tP4xJ#fpRfe3R|x+z~K#Z~45(EHRj8Da5 zs&JUG+KuhUkyP)bh45bnJ{$&RXl)9)vC!!PiZLE%&t=;S0q{&IY6e8Htye*NhJ$cC z%w9suXx$|?)Fc$E)J%@ynwu_7f(qg5$=)gy3d(;?&HCmr&G6F%YYjJx@+^1Nu)Idj z8P*Mav6Odw!V#$&`GwMW-y((``FFeVm;9a_u7c#W^V#M{0h=EzTPdj z)mqDR8pA%BuG#5Gwr@YTD3@~FYvp^;dB{lveCCg0t>#HNoQw3jWC)vcEUnYp`0Lw)_tZ|dYH9FKRyh35raBCgj9k-ajj1j7iy_fCmidlNfO_hKLo9!Gs{ z-br(E;L_-Ae0WmpoMcSX6bGg&GUTSLk<@OoC`4V?57;uOlRDByH<j=hbnlcr2 z;~L4xpg=wIJ+j=z2?t9EnIkN`@7Po;HU+Y7C{Q6GL(Zv<3P-eSgxjSR9@Rf%LDSZT zpq!%!wcFIjz>|-Z2qOdWhW@LD~8PWas4K-7IO{9pIu8+P0 z8IX>fm9w@v&yPi29e7aPyNf%#W;$ATXsqOE5n(m&2<_@7g?Qxjb)=*Wj`D;OiHumB z^+#VVi83Pjv4Yl>ISSNqN;o!UnrRdyh&x%QM6)!NlBkCh^+sV?sVNjx)EZxIQHs^6X zo>~4slCf{qf#abvlF`R;@=N|;w<^xtXF=3bBbt2s`a zJqsrW48^5VP`VSKDRwKgL(^%Cd8Ps@7owS@+L49sNyP}W9Z;mKpN;V3`;D}O5k-~H zJ{Fc?+ZZL+yY(VY`M1W@f&|HHk?&nkACPBSfm01QPRD4CR5Gl0yXH<3K5EWPbs-|W zn>?RUypLY4xcu*bhSPufA0aCPuM`4GdsfElFbcS6pB1$tfe+Sc&V00uyVdq<=26qAG!HVL#mfTFRN6OHP{+Dc#L#Z;g`GnE)g60c~O1~FsM#^OW zV*c*m{qKG;`5BH4x@s-RHQ>XC_gI!|+wixzVT+XQ7h*sz?8a-T!xj&%Tr-@v2x%iy zp{G%mww4_2K}MR=@hGJ*&)xBMJhY^8yt}*WBPB;6oIUh6!cD$yY$K{A51?=}Zed5I z6b^@(-Czx@wwR}xx&%w<;7V(nrLs{O6^yPqtxwJq?5#DNbwHu)KgIU>3Kp6VqR|FI zau9{rQc3}IY2CWSX+S9?j+Ne_sOc|?+r^t9e$IelTU@7wCKxhRcfGhYe0ay!ru@KM6I|r?ZG&**7!lffuY}NQmdlGML#A~BH6NhyxUdFL= z_p_7DhL9VmLIJ&%NY3K-1_&Raiw8)iUl208__JM!xH^-^J@KEM_YJKYeRr%Qr)=jO zoOg|@Rd`euLS!V6MplIb(TU4}*4--R4EC`wjZeLSHx;<{2n%>{}v6faX`!)?>N z3a#pHf2v~#Ec^`3zCpY;Ye_BSyu}Eyj9s{AwD!!@(pR1a5B;!o+H_4Ru`>-Or3|@l;dm`N(6D+yvW4pS(=x5o}i5&N~Vdj zV1UZLo7!j;MSGjJhW$7djJq)e&jIs1p%w+B9cl(g&=^JoD;b&_2V*SzNvdYmKxWvg zH7X;8My!$A8Cx^aW;i6R)Jl)lBC`F2k)lrz0|T=dm>+lVib90XXh> zV~nIa;{tKylHH=DvT?|J$oq~ySt*gyG^esR%pAJkHg>o%;Tsi$f^3c^uNrDsD99$? zqCOf2j?{ePb!mrKDK`pD9>ZoFTDPE{!66nC77@qI@!xFjq{CoP-9sDPz)UUr?K z81h+0>88nJ+d>;9j6#Bu6SFMKGsLC2-QOTA!$6&r_+gZWc9AmtsHhQ^JR(*!%zhAOJ~3K~#I`e??C8y@Zy~$KMk&XXc7Sy3uAw?V!I>8fE4%&xDp+3)A-B z9{4VMt!eZR(+o)Ix+>UMu>7;X!0~VVl+Hd&xsJ8eraYI%Z={ht^TguklG_~Q*S_Y-l1uE@{x`_!&`}c@`k)@Ral;z2mfr>HJlp>bp z4C_qm#zys@j9A7>Uh?|rp)36Wtov?V4s(^#$3wsM3{rviaUR zu}g7fOyAH(x%WIz{O5b&#!fJ_xSV|fktsWmB`5_w5dYdkpUIz#B%ajOqwHPCsbI29 zAXY8ddUQD-1p=gwV*af*a7sav9Hhu919CH}4sl}va9e!loH<}OJ(K2+MD0Emyc`)R$+aqt4j@RQgr+yHw|LL&K1(ljN41S)MUMA)qy_AXm|>(mj&nzZ zd29wo*K9dN$0Bz;Y#WDBm0?3>0Z879FpM!U1F^Xkm4hwJD2N%OiPWcpXw=&%8?1^VI}SoQN8d79OQnrZWb6XXwiKmvSEWH1$B1Ne z5>X4eR@X{F;&KK|(?rIY#uj}sgVM;fo#m}Vg|#`9>cVa_Z5@_+e9`0;=HpChJ>R12!2$e3|7 zEcZdy$}O5V7A<0TBtnlEBcS*i6*bsD>^YtCce=-%@XXAf^!~!Hy(F%FIcr4{^XIKQMmAeE)wO|vjK+8bk_NA)y6H;OG(q&b(L$+vj}X~3_2)nT`7gHZidVq_ozi7Cq}#)S4A;&+{x}zxQSEuNQ4_zFG7|a^XUW$qSu-RLcE7&LpBL^ z9uFw$O!wVB-V?w>_82jf;?fsW!fpume+IQq+T>=y|yqi#&yl$9f zd)^nLSh7or!c1n=^4hYv+u@mM^BEufadtiy zMNRE7kk-cs%&>I^ZVsTaa2pRN!~7mvM;c0_72Cq6+VK&FqC`fOa;P5;hXL(GLqQq` zjmhhRs_g6)hS87QUt`9@L^ma&Zc=&827URNA?3IckK}dTI{*FHVC+}{I#`ICVRlv_ zT`*B^ECtF?FxlPfkEjc6&~aBZisES;4=XMfR(8^s=YNcOaW5Flj%#a_o0C8$?+kD0 zep0NFc$?AQ;&%5uF~MFo(zXU(Fzf7}g;73G^u)j9Bu{Xjp00VqQWZo|IgB*{gDn^!)JwGhVYY zJd=mRp%s850;5z#iruhSimP37DjC*{+{y??P@gRX;@b#E#yX^2TJ(w1^!J2Dp$&!e zDyX*i3)*f6p%sn2Y+F0>-6?p!dkZ%HmZ5w(!*&Xq83Q+K2m6p2;SH*)f>L#`Jrqi_WV)S3wftLWv4zwOSk>in zt|2abP+4{*O}jW8QM`;DqVQKnXrIs^^=xd@I7gb&s3-4`a@@til#-!fcipsB)PYHb zdRyS#9#ZATfm-}&6(ReFW<-h#qa;MY zq=+K0uaAOxM!4?>ERTYmgM!{|F0u||+*oC%TM?E*+$m2+@xpDlHj?j0<>6S+6Q{{> z=3j-;w~p_c)o<7Zl1fX)Rsz;q!06_mb}QviJRtz1K2-QRILo7U^f2W1eCtkW`2Xm7w^rTOEj{RI@1ghp zjXCGqd!>R#O~jxUDqaXyi3lMP0$zF}{sci#i8o2Cq*Ci|sW*an5ye9xf)yncN-0&b z)?RDQImXxfd-S3mdh316wP91W*P3&T@9X_NwDz>;U33n0`| zT~Q6puWyKd^#7pz&cBEhqK)c3iT~al`VrxYI(2uhocoQ5@e?7!fDiWTs>aK#wPINp z9wB35-w$lt#_u{t^TIs+qOLsI_wib|OojZp=;;B9`g(*~8v(O)y5(>B=2aUzfcGJv z#nq5e<+-WgBU3PMLe255{opLb5Yb!5b3gF?r|)c^sCzxaDX38OY#Tu91GNss|KvaY zkA8T0`H08%LCiV{Ijv|-ykq(VC|sobP3F}xWQ;NK^74?bc3e7Y64I_7ya>}$w+SpE z^&KYL5OKy?AI;{Vo`1!~({zVbl$SvW7OQjm^>_)Z&%^uh;lulUswJb;azge_VdO8W zTJ_QxoYpNSl|fM?QHXW%FaojZ8fV>cgut?LWI*f9$o~`~mduL@lg;~v^BVD^$o(jw zz+*cE)|4v|QAvvGxul%76OD?OXG$O$uk%4ffzU>`ZuRPZOwRQdHoDZ`$s6EQuav@h zl%+K5u02O7Q8Zo;gdiM3K=UI*DfV;`d-O&(>AJ4wU`@oHG{I$9G2e)lJFRt$37vtV z)N0)`bmSV+h1BVZ`9u-D4&!4~5r3TTI$_ehs9Num@q3Jm79_sGxbB~5?~&Z7UcmkY{UXI4nQGtiob!>CtthrIW1*9cOcBeHRJML?}|= zHAgk@h@jd|Od03JDE?%kk0Bw1#8w+^n3xEYKnOUh z2!lpr{`b-yeN_G4$G)tJ!w#Ii18THCS6 z9byqI6gY?)Bnc+GMursW+>{RtItln8Md0ngmp}P`@$%3AGeA6j*x)#go-5`}GEd{! z;HVx^vi!19Z}>jv!d3SxKbv7^1(BRCQPeJh+jUEB> zf;4}gC^F}5h4g2fdw~#>GX@R|YCDX7WoL0rtYHZODK99sA&C7$4hd1LXJ+K^=qio_ zZ4~Cy=7dOD?!g87(NDDaZ~f>0*$=G^eEs@WRAR|E7~1V=`njJI>r8jbL8gTZkJ5%+ zc8|x)S!svpI{D~c2rCI$B}Jwp;n))&@Eh=a?iX`1JtXf$TCH}+g+%$D@aO08z6jGQ zS_={XEVT3CD2QO)z4sjQL_;6+>F37m2eVoySX)J}oXZtsmifL0afS=oFD(pNx85!p zO$-~i%jM(UZ>N!AHHCe(OKCdjnLS?e#X(y6Nt!~h`3C|9SFt&!o;Ph)R7=rj$pE)!lQi`xY?Pmn$cl&A+jmHT!&x|Mddy?qMi%PP#)8*%sQfHO@->dILJ%7PS)l+$poBb|dFx?A8&zH+7A>BOT=A5YV?(U-rOyW*- z%y+qpdPW!$<_NO)!~8f7E_&qe`v@pqw<)pcqe|GY##qH);6Zv3$hkhUjkwOR*=v%+ zT}JL34P7gK?4*82cXLsH364qJ*!FrU)LLuU_g!pqA|Bi08yS69$8Uaj-B1E9$gk`C zyx>l6v3usGq7nX#`IdpIUD6U0!)H%7hxI=DMYwT~E%K9=(~E0dP?Wpdxt^c)?A0Hu z4Q$(sC6#yzhQ_!=vC9a7M5uyG>cpHttPMZ?@t@%P-~Ov8z401SI~e&6K3CT#T=3nJ zFNnVqy>~WzxD;_oof?Pw8U|{BwM%9D616D4yvj-q>V$*S^VfM{l3N#b&JLD#B3$*r<^f* zv+m3L{G458xhnn4$Lv(p_(R8!MZ6iFj)3nl^I2RsBT@Q`OAm?TsA7*H;*WT}kc{{! z76E$ET9lF-p?fu{zwoqJ(&pi=ob-i^M_asEp{^gVD)g@T-ql|D6n95uZ}#oKpRRfR z-`arqV)Wi{T#4fI!d>)Y82z*QE|vSH&*f#?E*)@d9G0tpP77Hd*`=4Yez*Jc_k~|| zo_3cI@^6G=+gP}9&SOpq9VeGh5B;37sUY;M^IXgOGqP;6+N{XeOXv_GgGU5(z4$$G zUn`#PsB6vq?P$Kski4fhtm|qtii>bSo`>ga4d>rhYmxEN<8q;Mv!>aPUfsq`mo|%x zysQ_&jeoEDfA@Vyh(VO2DqslcPMqW?6L;HI(KpH(kL@4Xg6z}K%|rSTO- zyKqSJ!Wn$8udf%RU9d?$O92$gE!4F##z6f1ir4?`ALFiy%32zak!SIZ@#Y@v|9&mAr>39)O&jo1p8Z4d?zC7Qsh&U|-_6d#RjvpzT zz;DKcF$DGfyMOm@|1d^3>jWh~-eXhPj-RX&EJv~NoJ#h`=$Jz!m=tYv#Of6uHwFo( z^bf6+V$d1`mzj9MFd8-}RN38a{;fh_H=}tAbV}qMYxNmufyrH`K;VJHjwKC7 zqD$gM%FCaZEAlyk5Es0??NYV#cjmFlX}8dNmri}!m?-B3`(8j45h%)gie?y>(qiM- zCI*!HUmZc#+H5pB!6t#N4+ncEBW(NV2z9lu^{|nq@1V~M`W`poBN_0`V(6Yn=*OK} zwEAMg3eHK6vv!g*{pF{lJC=aIcSW~C7Id-p@E6~CV4s2%ztNpFzVT&{49UadjW!vJn7>2Uqy!R z5x?eg!+b&Ei#*Q@^Il25OTP2u?&CIJ`1ve4?&#&c2bhQ4y{o^Pc3u+^w8-^JZvN~i z59)4Y>zi2rjPJ&&_lw9|rG&_1O_CsDHLBF_c~KvyjJLNpL+n-2dKuTwiK9Hlurki(kT0y5#bKSl9&+BEom?2%99??vP94Ga7Bd3(O`^3O#PKjq1uyvQkD zP}{r0Lkk4+c&eQ3>cvC=EcktK2?UniXJhKKSPn4&N5zNI(SPd`28clou{ZIyH$GHe z-}Tv0o^d&<`15u&UWu*iCYymG@Sn&7kioLBhO;A|DAF` z>lGoAG_8^+dP|`2oIc+;d4yU~Jn#7zRZTligJM2g%1v#}=-geEJmE!iO`ZeHpw;e> z$T`1#PSBtK`Jc|1BQ>yZL=wpjjde zL6>Zfi-@B^#uOe7Cn63q?V8!fB~(n=Y!4Kv@-Z?LvZ)4x zWwHS=>evY8lpWm2DW(K+9XrW8RBw+*u|@$G6fh+vOH1COlgOJXWlE^6Vsv&RKP1pwW0A~BUxK;)2yr+R$Zt+YNP~qa ztJk`|t1+gFJz)b(Z%1Hc)v0kuWC$l)m5j@NI6KKA5m6#%?pJ}wz3I^$t&}qxV_x#+ zPHu$H=K`I|H?KN6kq{o!>$3u`V;k-Gl_GFD^pnNFc=e$7yW?(~5A1ui$EE22@r462 zgZ8m;9kujjpehIqf^Ld)ORnO*}7V}R6rqNN@EHfG6 zKP1{HMmg_59MUU9X)ZK|a0%x*+sj)Y87tjTajX$IA=nC_T!E zP*v(Na>Ne({EFZF;s1_*>aYI}S`3)28-nG3raI6YlItie-YZh?!sbS3y07`Wl8rsN z$Zl9A6PS5`rwW!rz-SGvcQ)oG-!yl#FoL`1d@~fp$k+3?_|M6{C7Act==9F=$2U^G z0k|V`Y8j$@xH$+RPVD=B;b!aJ^iAa`hc&$_xS39zBIOny%PPjiCz4yn!~n6N=4_1uy(U6velw@GrpNOE0QgmjX?L6S8zh$B|O#M9aNyX9p;41}oC?bZ?H zVmbDw9mcIU^eJ5oO`r?B4pqi*DmtT0TzC!7$YXgj*_|)k%w0)h zpELwQlnZH2Af_N@eL#$vV>m=v3Q2q)&@mPxgOmbj0?*^XvOeTFH*wk~RB0Hx#QVgY zrXni85Mcje=X|XWa zjE^@Zn-T^e=sS3h-)jX1&}-uit4$NOaWm8^wyEnf?m5IphAKT z6EVu(2|$Pmn>0de&ghdPvSLmq;a4NuzaH50g`G>jrMNxrokEtQs<-hOUz@nl`!-*O^<*76N^;l2^TtyuF2X^Ss{# z>E&GvjKSj80i=+`O`g{cQwCs4GezNu0!9Z%5P>9I+C_%+GxkIUL>4`TV9kMMpYp{{ zz+kiG82B9$fOT2&kV>GNQ`wFVd|An_E-@Qpx zo5rVc!A-9COU6yAwQ38-=WUE8hN!Nww=wN#qB@lLmKe=lymek5^z&D|{$GEJ?|%DV z0LDa{gDEi!Cz&J}ucn33FaGbebd4wisHV+^m}e{3HpFNy0H;VSm^B6o=ZlC7_6ZU1 zNHZMc!sj_A_G339e7GwFMTC`dw%o}f1uunwqZAH#j}dc_)M`P-n_wlde0KeFy>-W1 z#09~+Gx&9ig-0k4@=V=9;z_39#f`E&`Aw zS5LdkDV>GQZkzH#l1ZSIVAke9z_k3qNx*0gFCSjSxqPs`r%zCl?5Nh!%YpSJqZSQV zW;N01O%53@*i%ZFs=Am!l=z((qJ*2W;;Qu_WYsfpl`CU`^Ti*DW$D>E2<xl9Wez_HYSsxH$^1^Um(h78+z%Ffh0VrAa(}57A$K5CQH7RAUx&oPw8Zm8JZ43 zbjU`7`(8|%OlmnY1`sA%t%#BT-6W2ZVZIq5W8sc#a8%TsBpy9MQtUgMQnrSa_|I~* z*h$3XScqvTj;eK3q8tPnDYY=tkpeWHEQ&=+RU=Cp`0>Zz;QQ~t=je&dh-|CFSgS)~ ze@>K&1W_EOBpS0z0VU%nL6-m^A=+mf;L9P&&pl<&1w%&by;u2u6H62hqo@&qftZ2T zm`1?eWxQ~DJerneOdA5LdSU?9^@R(87;%&W5UYV;nQbgAIgVWv&_j?)Mzi^RP_}Bc z;AWMtBWT8(#E1|#Z=7?+>t|x{znJrKQcy@1E5#^bKu&yFfM7^g5^iT8Ez}0Oa(=p6 zm2?0n|0FAaZ9sx=ixn2VbwirZth;20$;nqdk+x-7WlxZ($rcG5ZwQnur&jZBYc0q! z?yiMRcLz>yz9jEM6^zr%@5?UJ5pn&F{G7Uw>py&WvG3*;y@7}ukiq|Mbf!WC8_#lc zcN~YAN2in+-D`y#vN`O1Gdd096+X5HYOBafXNi!)mG6gT+03+6Ck8|sNh9JI$7ANG zu2s;lfmVm5l_(Of4NcA&={K)<{YQU{5C8VRjtVv{MPm=BYHB$}=&$~hhMdV>(7-6Xg9DF{bp-XD5*N22B}rATqw zPYWs8&k7o8vNXWsK8gX-Bbp}&lZr*v7l^}T<(bB}2gaMU=N7Tvzk}-+z zO9$r6YJJC@T5DJq{msE8Ksa9L&UKk z79T*wQ9*v=w6=?DGas5M$yjGf;TCu{%@;UV*HhryfGC~lw8#@v2uc(LQ51PN*#c%B z6~{NIKM&8r`2tUp6UB$ZX$!!RDIw-~dgTc6)y4lq4Mw?3u51iQferRXM@S1=+0k3Y z_E@t*>1jx_G*$UH+bCjv$oe-}+J#$P%KlYR{b?Hrt zkZE=w7~G+zxVQ+B&KF%yvR}I7G!8tr2j{|3L?08qRpcxj8o3~H=EDw?FNy&^IQOF< zQoypU7?ll!yV!Y507DR7Ca^cY-~ywdAqC7KqwyiOAle|sgxI;;ueF}BNEG<{63&3z z!D}W2_Ms!;8tFJ%N1ju1hS;pV6k$tq$af%D(V1%l7 zHpC@Fmt?_vW#F8OP+$a38-`0{m(t2Zgbw7C`=@&WlN*Eq7Am~GJ@I&KXtiTqRvx38 zR7`%ZaFc|canekr8N^*k6g+weMpef&bj=GR@TWhb|KI-v%kTaxm=y3VI})AdvrP+y zdGf3-hOq67>baBP0ic$GlrvtRZ#FK|(P1kU>$>sSP#UJdOPtk_&iuEv#_L%}Y=ZKb z*oz?hDp+yt719u~S_r|s9hK_@fX{q7W5cE(a$4M+RFyL>Yzkj8h6SKgy`Pd!oRXz) zwAL`g$tTlzwuL>9OhFvP25F9AUYBYQqZA>fEUDwd01*G50==O31u?xK%muvwA#4c9 zsQbid8B2aatsNoo?467KCV`hPZr0 zTsD**Fpv@Q2GD||c7(iOAfQbGLc~afqj$`d(FRb_K`Ehh04W18G4hfFkP?pGQ0KrD zvgF%wppJ=26Gv-kGvH_kW(+`#D7~Y%iBda@2msXDF+;%Y08NHnYa4?8P3xXxSkXnd zyvoH*ktNfu2x@?cUOSTbu+U)6OrU@O9yi9x8#W+de|sXw1sMGIX73VUoO#mF2U=yq z{;_vpFj{jQ1px^uE@*|(F;X}^^0=5Lcamr4pH71Qn5cz4-`JVHf+ArOP&?x|L_<3J zj6fN^69D?SL@@=1dqP zp*LQu{CoKCwK_$hz|Uk|7nGyOI_JX(Gt0kUk<)@&*#8J4gJwdj6ESkI^k{?>SM)Z4 zna~C>W<-b!CL&|4lo=%zZ=8gL)(AwIeZpn}z+#7x7W6@=4H%QJyjD9V*x)!urW+85 z5vIrm{ODr%N(sl_**^~neFTgd&`L){#Ha)sgjPD1m=HnO@`~fRqa8cK?3leG5zuSJ zV@U{@h?5X8(JPOz5)mT!oIxkhj2MH_x`>G|2SOhhwShV#aWpz;0$WTx;-U_OiL^#g z4%q9CHo2$|5jfg`(hf#NXrQBG#tBM<+8bsV08Jd7|K1o4F%u>YOmvjCOCT*b5FidT zP8paq0P09@in=yN+}+%$|TyTM@15p_D4(sB`>J+5m~jOs8oRBq+HeQyH~2^f9ok ztF5OlCZH6!DXXnx(B#1B5Ww{*i?T{<7~rCE$SSD4^TY%|Z39F+%H%|qfz~88FlO`) z(0}C>ude_aKD?~h>k}!G7~nCSp3;ir*iDs11msBQ12}3I zQ@9AkfY+~Iv8)SHOxT}KEGe0aVosK-hIN(9Hy*?6`;L@Xw9atkU-WNJ|cee^DD*-07V?N zB8CN@9t%cq=yT#XUv_LcOP3naTSbTo>#7-E46V1;vF~peRmJBoU+}VhK<`Z;Z-zYg zN=T6rsBKN`1r_yz7v&-ae0*6@L{c0CRoMH)vaBcv^8`ZVXJ2IuvL6L6FAt2${xDo5 z=|UZ*+?kk6X6%ClWW^wJ%!#9c7YQcP!uABMP5k=17X+DYk3bluV0*9 zV@0BYqZCvG9DBj{-~Spv|NI$5z<1w$!f_}8m%E$MC!%rzTVsPr@eJ!TU_TmSAgn8Q zqdCGz&r|$mh7b|=w~CM7eZ-fY%?=-1Mhb*D2hx%)#FZVSqp1GG9whOI_2t7V2#E1E zF=*iRIZ(%j=i3vXK16)?AUu|g<9KDB9&ra#3y*7y#41q=+$pz??>>DL->)eLBOfYR zI7o`(E(@z?dEYQMQYFxgDspk!TVoTv$cMVdrzn3l6038Rqtg4twtYme3}@#=pg6?u zDad8Z=-&QpHd5DE6+VzEhz34=ctI%#I-)}|xGR6YJ*C6TI1VPy=7kUNQX6wFQbYug z>uM=jADn(LIun~qVW;>M126_&_Z^SN3+AXuk>r3>3ljd>F+9+E#p97>lmg5dY^=aR zwZQZFhIL!9q{Sk#N;$CP#S$UL?8r&U_5qmT963mL%P3ewMldyJ7vy$=Y+S<=07k9( zT#6TU<7r30m*i|!kW?7zq@xVZ2n~qD7f-8QMr=Gj(WD3-C+WzfS^+U_R6=IEu%tyy zEqMf1>W*z&Y%IcAd(3GWvVJ+=ka?bL*sOx6W@u;~y0#`DNaE~#r;OP}QJqoC8wk_X z)G;JsT5;A}%8JU+DOl*tBM?P=!!aTA-D3w3M^Z68Br6vnx z<6-jDB3x`hlwQHSKNdq+_%^|8gw81ekGzxcX>-naeSHH6SXT~L4nKazkN@i*;V=A+ z-$iXqjfs;alzZCPkNLV{`5{F2ZCx$%QV~$4aAb)g(v$`zxvye_p$Q#|B(>IM1bHB- z3SUsIluj!X6)kywsUmh�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

+tP3Z)2P z4TRd5Qo-hD^7E?_j)lzHbmprDgPaq`1U{#JwcJg$@fq3MiI8&XpT%i345<4^waVP0 z5MmE)ZjHKovyNZT5iXIkHsi)FrjmAnkOX(y3VJ@Y(LYBBOzvIRmAOWZNq=gvsVIY! z`7!@&&qPf%2^AF*IS!pYQ26nFhD5zVzVRZ}d7s-V~r$(3>!xQ3){Wy5N$z`t3 zfC=G{a9EngbvoKq9*TC^_L3d$;bDqR;!!#O`MPe%`9uuyLq4A>Fj>_$^Hi>c=MJ@- zi(QKWy?C1S&XYm_O-H5U@LiVpBKF{sVZrTof9Wdi!B?c1(MwL_OLTAaTrtydT*V|- zIuE(@`Z{P#eAgOTk3|^>sLG;k3N3U@54m<(dE7xzv2VL2$NdN zT0&UfUP`BgBhyR9pzoyf+(+mHE*9gm;5hb9$nPrciWfuQo_S~@n_AWt))&%Vm~3Y z33V^GYh9najbpKqMAm|3GUZkzKE!Fib@Zk-Q5@$!%}_Jw-bAH}`j7t^Zhzs=p`zjO zcn6$A46B5+v!^4AVXUHE{3II$c#z490syu3LP*zkZKbPqy(46?*ioM6hZqkow_2iZva5@q?(n z(8-yhPoQ?WY3XqO2r4EFM1>cfC=1cBt(&+(2lJA%AZ-gTBtaf{kqtA$D$j#@Hw`RH zkmqCx!^3r+3HZ!W7+pr~C}Vf)CD;9mtd)bc@@EKEy3JN6JmOkopER&cRlj7F*e5675jelqHgJVd)J~&q7zca zah%wCLEBJE#J{OL7jA@>fTMiY)3HVUMGVY7#D%bw)8d9Rg$QI@^Uc#Dg5~*zYOxL?xDrFaPcTjPL&4e*> zKIg(vk0bPPt%{LGG*_L*!0Lmjo_9T-xp5ufFbbi;t@bD>v6aKc4-TU2wZ)Mg!;&a- zn@M-bsG{C;AZjv=VFhC@r8lmF#J?CGba@f4*#b}Phq4Ka*ElRikF9NvQ=G@|jhLYNFDfrv}`%f(;Rs%fVpQ1o0s0CQo6+{i6Kdtao;3y(z!k!M? zZ!5mNAKe5jdWYNFg5!B01lOIGi7K{0D1|p;@Bn!xuzvme#C=-;VkJsz8MSdypaG(_ z6|8H-moE>jYmm!{M~>^}P)ft?9Dn^;%M+I9*+|Q!kG%bUn9tCVFPUUi2cEc zz!se-5i)j>e4=IC-&Q8jfmkR|B|uX;cJ4F?x7#8dCoX1P@IWo7%?VG644`M}~Gf^a=j;cpQG zNycCWiHo&!!2A1w+wGGa{slx4HJ^xH_%5a5%n2d#v*!)5AlHQ4n8O!6a2z|m;yZyd{0WenAHG}8hC3cPCo1w79zuDuPYCmK9lSaBQ` zC_FN?NRIan`*C26Zyd$sz(te5IwcpR^T8Vx+(_s%YZaj2kj^R!umkH7WK=4MP+>Il zICiX}H1f`M&R`Xu8Cpg<4=gJaKZA=nj$NXFhIbi@Ci%bUpJvtF+Oq*_6h;2m>Qd?f5i5aJlvt0!f+=n$y_H6u5m!eJFfWGNLfa1p2p55e<( z;E_sz_ka%(=a~Uy1USGiIC8?uXl`uvn>gU{G1SI!sf?* zY6#9Dm4x63A$shBL=h2|z=d#28KnWvN1#=B2c(>OuIX_cxZUo^>4XEY1c!CKq2!8Z zdWzbNX(Rh_;I=M;nsYPkokM9FE#!?|z)*a$`jws9O96t5tZ+m@sg83!%gHt{KBDEq znW-o^_JrUUEMjX=NogexF$Cn45#j<*4M%!{DB`wlNGBH(&NEp&XXZ^7A#^ua!McV4 z4DiHdm64-Ik1SL*s_^fspjF-x&hvnCk%eTWd7=ECVk-E9|N8IX*Z<0IqunEFuBeTR zd>^9FO-gU(s82kKLG5ZU3`*95BA}Gid9;HsRfZ2;Iw#Z;sG!gQK|HlFsfGDqTF5Xz ziv?`nJ1jBsS`_|bk`xtg+T`;&2Nyif<3wE8C7%o66*(oKIjq}_3p;s+5Jj`2;Yja= zC#;1Phf4=M&jZUE@ykE_Lwx_;cL+|Dp~BHCrEn^UoC7)mNsk?km~+ipwgIO;+fw8` zc~DKPwiadUx_X>R?Qa_BAOG>$YHgAe#Rq&`J)Tbq$P6BYhWio(ogsvX&Oqw2N;Cnc zOjlBv7`>lGLMpk)N;%7c!aqBPfF#IFl@6xJLFZi*#EL6I9~k|5JfFDVH<06lwIqO? z#}ar`m&&TOuy~MJ1hr^xpTlt!QQr|tVUCs$?2S`P!LkH~j^!CZD()q+icWKfY8xZa zocS`3apCBRGf77&yaGTZ{S9Z9Jiy@kf{Q`qwV69Qat-@QaGrSM%Y5Ba5U1f$q3dRH z#D$v@QnM(vVu%10l*W$f>13(jLj8ZnryX&DgdT$McCJ6_ASnD&B4jp8JWMGQR)*&L^nE;j~5~ zl;G#F1?F?95;8jWSxINYvPGm)ahw@`;e(S&!40J(tdWb-k~5YV_~*8a+kM63{ek6n z!~RT26>xDu%D|oyoOigz75U7FOT@Rw6L2eHXegO4Hf~Jbal5a$ts8#&>49b0uq+O_ zGG}2wPQ2Z32){n}r zr+_bC{sh1Fr+;82+%sWaJ>Xf17Q+fq1~rF2{F9&X`TOs&c#myyIG+z}w-xC;k!ykv z0b69T#QRf6F`h4*%GL?W0Sb<-LA>+b!|c=jj&I+-Nzwv$+V9^EeE0nw=lQ_r&)?(m zIAjEo`HYf4Xh%j|(D@W1$7e)@DnYlVxUC4$H! z213ahwN!+~BY0v}^q#s}tkjI#5;@*Wc*2Zw@jU_uiOOoyEDZxs=Ll!v#+RJO^U3cw z5CQeX5o>MOY(h)3~GqZ?{!Q z>kh}ksB=yUAu5H%!}-t=-BS2Ib`m`AJr_$wCnn^3bQ#|-369XGIywzmqNwMD+Z*Eo zij1fS;ouQDpj$GO&TFh1kJgw#@BJ0Qm$U(JT+u-CD;fo!Udag2JI@8Am}ysy!;(U~ zfj^ITgocQeSO`$%F6H8Gq>pUtCIXjXPM%W1e!TM;93pDryECj&6xE)U{Ux&#gC|Y{ zc|5-~Fa9JsSMi-7cprt#mHT4%&SP0OPKz!X-fIRP!zdO z2{>I`%#Rw%8io!l5=(rY*!rV_ig2k65v>uo`0DPB+R%hVUb9HWQQ0maad0(3yo0=M zV>U@6aNd`rV2sc*oMTlM3DK4Frfz~XLA*c!mx@UW57^HgF>VNvP5GXWcODDCcP<3; z#X1#*M~5=HXvDmlp=KzEiPU zI9at57zOyYe+8&v^|2EwT?^cKO9#7d8}eEB9TFkehBG%TkxA~YR=hvnal3D587S3t zc{QP+5w9fzcLs5ZvY2&9J0j5v>z(K;EqrkrrwHZce#_!!YZ2(5K9L^iDr*v|t{ zFE!cNj?n$6h#Xv4fGlCAf*Sfrs4~85s4QpCKst+bSb0*Ia_mS$hyfuumRhqgn|Xev zzy+W*CM}1+UD>*Rk}(4l?Q`Bik|W74n1)Kz3&JSxzKY0UT{fgsvcDp59FK19+A16W zmByEflUSe_JdWo(7uLe_+HMw^7w;_hRsks8=B}>!e@qF)1 zqHojP{Cqr-(1g!KNC!Wk=%YM)=I2psNG;>- z?Nc|pRO-OnjYm#Lsvx((N5XOLA`Ias^UOfWt#cGhDaZv_)}`|ROU_v1#xf@zhl8-6 zYzxD843Cb#J$Br-1&%Uq%Zlf7$L;MVS*QgiHylSs3_Mn3jL75hJaF40yd!-5`VBw) z@B`{G?u7|45K?9;8B18?`wufqhtdh{`dP?u z*t%hxkm{k3Xep@hjG%}$NG%oQBzZiE+p`ZKKe7qCy+&pAoAR@q_keHH%zO|s#RN1i za74%zK*^J1d2tQrejs`#z85eb%aa3n8DpVgi+4W!s&cYC_O$ajNO(UngwCx?iTOS; zu5ckR=cP3y8G$$g78j9>-2h9*)!Yx=`I|Wv4di83FXEdZMVs1k?B|JXy9t@Mff}PO zAo*eBuy|HfLeSfk65sRF;DT_|S|`SXSP@rhLGXMaZ+9MlW>Fu77=V)DT$ID?E|7lc=p>;bmlLhKsIn~q zt5gY(C$Etz=5ozf=CXA%ZG#JA&veOl;~?!)@(`Ug38`&ERS6V9!Z{$BCH@g9KY_;M zpBM>89)_r1){&#Zne6I163$pDjL`W2UvrNh>Kr?9J%^~C_-C_%n8~-ij@NDLBzEN{ z5;z#$dB>kM6?iXZpRIMp>ly+VYcf*Gh52)>Hjq#X6zOiVY0mRR@RCdC9I|k>Vjwu- zCR){FmN+x!Kvpz(tig+y8JiE+#>(813rCA+sCC#_^wfBS+!|2Y(ZiUte8(aUKx?&! z78k#w=EVE47U2-fSd!Fg#e;;zU1~!JtB9JC7+Z5;TpFW&Aw*V|*NW0ObXk)E^sx0_ zavVzqkxX{-3DDpWI`2?r&q0J;?7djwiI9(z(HtUB^gJGy0?P-7B^UhD|K{)DU-&Ek z4o(n!tEe8#u_IQt9=Y_?OvZ(ck*pZlV3#LY4bc-vuMwMEI|(cY2&FMdbDRl_ACYQ$7B)E>b56pu zbvScI7GZ@GAAwBFc}zz_u9?pzzi{K`9q8B}jcpm45Lf|#`3DT&d64&LNT|s0Alcxf zC~$JvK!TH{R^HKi)zsYzQ{+bi|iOSFojBWVY-x zlyiZPTzI4`WOwHfV2UO}M+&((ROMiktf)GZ`0_CsuzAl&VJ;#tFeZXJAJ2#Ub3%Gl zQgKd&)pF{mWK@XVl(W=Pv=Q?}vhWi8!iI*eBsdpwX0H5W2tuT0D+*6RRH#mTSpekB zMKc;a5n5qHaepSP+f8f{7@hK6(l0L5xdDzs8cG&ZCqnKAgHA9XL^t@iJ#4hMLefM;1iE(#^e1PZlAt`a|=@k zoGN@gYTd;wRSoTi(4y6Xih^aiBjt=zPqsZl=!XF}0EAMQNPZj#Z|a`)HO8#`dvqK< z{J*?kC+{dGIG>2(2}aHXp5MO>w=IRqur6}3(G>l2M&ahY+)2Z4CiihRxLJ|FSrA`b zAmH40+_oFmb-|GfQehjAl;!d`P9x!0{U`O1Z#4F^Tb8Y_YYomu&2S;Wlf!W)DYm$< z@WCO;2q^dkpp4)b`Cb{dx?y`lY(T22!gTIE06pi-F6v^N5xhqR5MtobzbJA!tFCnN zEPp=cRgohxYj!-fp9GyaKDECt0y-8Kh z=~|KU!6fxcaB_}&gf5X+3J4Q@8%j!uA>jV$J2Xjl;Pcyy&?p(viZrfqSTdj)%Mg?< zhvzepy|J8fpAw%PoQxng84?%7zpwJ;7^S&(+@v4*WJFTzb6WMHwvDJ_uhJxni;Mr- zEdmCoNfe)Aqf?TGlmqL!^s#8JsgD+;0273Unll^%vY_KGcz98tLntTVsQCZ>tKY}J z_@DeX+NTXDY|Oj}d0NvnilCDkXS1xUoP`BBAMB*=S2n;U-zO9~F^7-oAgQmVbQ}nt zI)PsE14&5joUp*nQP?)Ia6sq&b`_gabV`Xn$poHZhai7ih23S!^J;~dq2~XQsH_4 zwe>xTGr{>F%Ho8Q6Ds&l&85Qs_22z3f7Bn^m3_$UH$`$dx`tLW&i&}oDLlrKJRZj! zr|3Pr1JF37nip~F;g*6+@s}fKj4d_Su1crcq{|xJfS0)~(1d(Vo%=MhjktK~YQ1VD z+Mdw@?>Y%COa9#R`Q*b-kO%e2a^6W~1Z2~oyW%oDQfL1VK@+OXhaEAR=348cJVon> zAE2hNaaGTo(QYk`l_j-_i!Gy4OJJkL znhT?MjeiDnbPCqU2SEs2G^19;u!u7{U!YMCD0Rn;J|OLh5BO5y8sHieRL}iHbP=tv zi6>R=MApDWT>|jw{>Ir>=ZQduBZP+iVD;U)t~e8ObsUKqX({j^JidOz8W#j2R=%_b z@_fN?#Lmfuvnb=7_rp`h6tZffxW zn;?B8RtmLb#3isntg6@=j2(;RYE}+H-&nz1avGU|@;;X(iaBLPh(Q`+Af*Ehg};ZV z9_>PoN$90!0D{&_ks1OM@ZS}I@SwN-$)NeMBa zw1QkR!m>=s0O-jG)M*o03d>p>eDsp|Q3WMxy`f~qaT-<#pq~2~oJY+Ci!{j0>E!3Z zD%IMZ+OL7c(KGKA)WpGjsMhvlXFjTUE(UY{E|OjnJ>O*{f~4TQ_#-+LSzjri?7^5b z@<041xc%mz#m?63tb`Pf(Xa&xo#xOQ+e^e{czBJtD`y(BI!1)V_t6?7N|po-v3&_~ z!Jd>-5W3}0jEhW45|+Sckb_2{HJK0*q9=Gy$R|&5I5EM4TH|{W5RXJgFN5R%uT^fq z6?Jl`NaqutfEYv}E}jE;L)Xn!xAFjgMdu7STGjkyF@uR zYUWX|Bgb_N8nzhaP9wNR2%aRTaYUB|34iv^f%g5;Y*?$Z^s9_`hNG=W##>|liE+qP zdHRrNl5rWXT`q6Eh3dt^>GZMtkaje~nMF-^&M&GoKvbExDQ+sbft&^}SEtXo9+^oLt|t zHRrV1YgQ(I4agn;Ie*WwZblHRB7sV*rOVp2W{|Al877UO+M6u9udK1)@KBollr;Q! zWMXQBMVib2?O5FU`CRk;_zbBpmK^E`-M#6YLkzxWW=_6N#^llNTYIipM{G6Pz3!8% z*{$^?y5^lu=Aq_Y^*tkoo2}9mhFnX93tXh;RJz&pHP0^R%;u3qSj3Ja#>mCISwG%O z%#2BIAVH*h79*LET+MwmMy=Cc@V@_DYf5Z=th%3(`WTvLYh!b+-bdQV*HRIeIJtXw zvNg3STCJyFEDIug)3C>2Kexd}J3JO1ao~JD5!OW-JlAb;T5E8R9e?z<{wMs}fACw_ zy~i3oa;xxgQ#NIfK@!h0wH2^#>f>Hm73I^|?ujdk@I z*@Omb`=cZ4Da+G)ZrZIAo))t)PDaMP0rei_BXUZe`l41ccAwZiiEea*>3q|l8KUds zO8ql?e@}+%#)Gc4#-m%ae*vJ1|76Y?{%`)xAAjt>s9W_@R|=@pX%z+BA~RWgK-tjB zZng#sA+ZmJenFiVTPNWj%!oOwuc69ft}^D5#BIjUJKEE_sp%*j^wl^M)_XNFV~D>^ z@f2PV4gKFCvRcgRy!eu|tq)yI_^h|aaF13K&f2?0dx7dRP*Xd5FzJG^Q3UN`zSh&o zO@Y)sLG;g5f-1%5h@2P&qW<}LCai1h8E^JGkFZzQV`*&xIU}CWy`wfZ zm+~6B;RsXlrjF>tXD3XB!R*>T7qB)w)E*YfNzkIu{ftw2treRXvf9{=Q!f1}2=`(N zeD#947UF7uVWW!X!fP0k5>d~Mv++1rA03-B7lQAeK`QdlV#PK=_LA0YLmO|ht}BmU zjIY>vvh%$y2Cw1s*1&f-IuFFanikqaTn$Avw(A-vc8yZe%g9DAS#w0&Tv$IR>%gv` zNB54+OP$v`8Jmmo9QE&MiosNPwZ@9WBS};ZK+Xtn$03}5DGwt1W{GTV6SJ5aOI>+i8^T!jlZ*2$iwHZXZyqP2%6t3V+5(7Al<$(4JN zVZj9_>bp_IjXgvnN+`K7XRKBx^S2_Y4(g*-ft2y(AN)gn{>?v+>Hh&ePXS=YEs#jdV_Wm&q1o|-?~eQFJXnSLeABHT2IYGS+L>kn&M_H-_SsKRTF1t6*n)8U?>go4c`qXs))33MruD#W zaw^*&UAr!9Rl|@JHrH60=kw7owf#)2x(ku#(EyKijN3YTJSIR=zy|3a=k9QzmABii zZ!qg}-4O@5eAP5hzw_1My7MW_MW>gzeUAMSluK#5ZSZ0oYol^l9=}W%Ue7qZpr2RN z)}jyg{q^q0cx%}LZm6zuZwTxj(!#Syc)F(0KOT>PQ1t`&^#ZitUoQ$9@uP*1t^+L$ zbj_ASSw<(i>*&1kgfoxX?R+TRQ!KGubu45XC080K0q z52I#p6w`v9l7x6W-;Gss9$BCx?{s|E{<#P*S&5|#4wDv!aR~#dlNb_PwCi`%bI_iX z-n*#?(}MH`?esiS3MK>edj4L~KRu(p=O(|D+m2{0>pnUutO^I zoFNKRQiEmw4*58+|D!*^r@!#$P`yXX%pL5i@ej^RzQ@XR|7bj#MNLH~kGL#7*2@;n z>$)PP#Qtp}x*$Cl|8m;Hmx~}tiW?auL5^S>#$)M9(DB1I~wi!8pnR*G; zqZdI+xtV~K(9L=^BU0DWb#gRvYTJ}=TuMPJe81XrBo`K4)mq_y_jmvLj}{i^4>U+~ zT6Dw-#;2EYn08vF)XTwuDgWy_LbHd8>l@c~(yIMAod~RfkZ3Q5o?7eMkq6mM-8d6l zepavaG2$_72Vmi6{Vw*!TLLgprBXi3=XV_*w|RBiNm?Yzb{#fy#C{$-x*Xj@=!>?Q zg`x^dcNsY;A$R0#<>~iod`pb6L++2q!(2eE7ifyAsQdgWNZeEaNP%)5hoGVrki%9F z0J~xKeeaivjjOS-3)i>?+lhHGgG(v*=cV7((a4pvpK+iog{8oOWb?x;CAJZ^Rd0%GjTyqhxVdyr6-X2U^ z5OHx8`}5N^t_M(+2E~Tya-rP1TecP?HXe!jowbW-6yerF-FB+B=uq_6HdW*7@n)nw z{{JAPdfRY~P~vny+-FmTRzk?Pm_I%OxGVKNV z-FlYTrX?uX%zRE;Fs7V(P`yQdfZ83wS!6Rurs(LUnOwSoO0zh~Uc{QxpcnD7u$4xS zkHHvK>6xa5j%}=T4Ik$*H8;I6G<%)>x)u`|n?X(4 zZYdk|TMOzoAvD)UwF(#6(`#<09k-G2AZ=l(>oKJ?O(yK#Y8NWQvabDi=qi#>H6q^hfFKRq_09W>iiu3+F$#tKia~H z9gV#xDMq)YDjb_GZY#Svh3h*Ncli4AN%&Y= zNIWG2jI@#!I1;9dv=;%ZB~Ce@+r%r=2fY}`(T=pnGZ}mhySa2Tase8;A>5QQPLMI1 z;UzVV7D`iKEUy zXMdk$csCHP7ZZJ%TTtXyD`sXt6hu6Ftr7&P{wKMxdd-XDK8qd*XFes$#=(Wq$4Pd4 zpa;l6CdcO0ZmN`mGbfO9l2*V)3y*-gyW=q`k2SPY*3Yh&8;>L%_(8EDl@mJ z>`)*{SgEcv9R*8%S8HqmpyPnSNr9v!X#U{f3HIVrOeUK)9K@>8Wnme=u9=j0l&fn? zVRt(!xA7A;z?BRB(u*n$K4qjfgIvX#4iRUYjpS8{Dd>+88qsn-9kz>#j=l7xnQX7i;3IN5S(qT6 zZ!A{h_o{^}!S%SQ&XF;wgylJ%>FA9O8vAeE?%RlVQTj)dxEQ#JKck=7(hM|*l*FKQ zT~?IB>!sw1C9ZvRr(?&FzsM;drItRH)TXyLA&nCW7`YQ=8?m2Wmd0X?5NA%8-k&-h z;Iqv{hkGV{69~`e4yqhUS2CMkuG`97R`1Z7Lny$PfAEj+`8WS8TnIQG4>VDomR50` ztfXDHjm1&5;y8}6Czr^L8bnaAENl^@qq{1jyUa$@S^(*HR5Xy}>{}w!eu9i1Ls+mZ z(eP;-S}Rk4xm}mGfwSo9JUMfn;^QT(xd=Dg1Fdvu@K%g))S?a%?X5z`z#X1irMx;M${}X?E+IuaPlDN zf@EDeHo7R-Ww>_4L`mwF3t%s}EAidJpO*Kb&bNcp;a*08I>)!fc73MDu}`7MEb&h8 zVd<{lJ^rMr#CeeP^zWo}^a8+!p;|tUKBN8lM04RKz|?m0i(LHKj0WrmvgA^GdF$GG zKA+u)REhIMz4VVZ>rD9!H?B^i? z-+m%B+iq89@FDu1i>AD>D!F}EC||$xYxdwk$YKybDHA~48hW&k76f_#*k@o5G+mdr zAsI!&tH7X(G7P!ec5Qag+mKT&{6mNmI!xVrt5xa;nWA5IRH}!Qb96b-26_D>)O@Vr zG&LP|57~Y0okv0K{GV>ka9lpI7DT zwW}u@9k=DiS#i;oOE(Z#KM~!TuQN~>Eey`I_kGzzyfKKtebk3y?g|-m_si0ci_4+s zb`o(B*N`XTHKRB*2}kUx=Srv_9G4`9yKO>hA@Mf4cCSd46joy`b3|In z6}6`BQ8+Ry%XE(Q##lI?DlXz?HK~g+7r43N+;>pqMzOSl+JsA33GR8~{rCSq?tkfD z1H}anKnZSAE~;p%=2;K}qT%;v0^DbGm%7^6Hdf2Bh!Syu|4%kyHhi4xjniRdM@`m{^Z9&s z6TofTdS}v%M7CZEkSm`>4Z4S)Xl62|>b*?MTA%#*UxeshvdVB>C&^8zHWAX)_N)Mfe1l7VwbOL$hD43_I>ZqTA#Na6Y09L zO0}ur@NOEN=z7%AtiI<>9P{-ev^*<4NNjj4Nzga@&CrDW*%6Gr^sk&W%Z<}Nv-{JI z#8jyojUeNyqEaMQpL;*gIFu2~vfwy&JfF|Wr%Ctgx~~0@PKno^j`OTKwj1*b`InKb zv0wQ29MgBO&5b=X^qF)LxLJpaUY+O34(Ni?>F?6tVGFy~I7&v>fv!J2s~53K(DAV4 zb2;a*?|Uy6?bt`xlD;cF)B5)&*Aa2sRM|ZnLg??$5~=lG(0C{<8oi_u*ydv9&CP4c zj=mw*9(JsL4YgLJmt$bc%P9HE4<1G1_&q#WDg9n!?=rRvNF}4`Bt`^6!84*2BKs+> z>xvK=wed0FDf_ZFy!$@ATZICLq zr%^!V+=I#EMd@urn6oL~?Pm=kbaB}=a9j6--W|IBNeJ+zvbBmf>6&bCJ%23#U`Ln} z8YxpEJ1tX0-OHp;?*x73wrQou<6E=RRqq^Xo#mHg_)dB`+5^1`aa|2Y?Lt?HJXedB z1WR4nh7140Zq#ktCiyobTBD=YjlPMZz$zM4&FI8?0|1VcX7!iMb!%&UVSA5YlzUej z1v?V83J1GD?LT9?2m5oB#H)NSOPbWf^GaNurK3(bUSbgt7X;UO+)DTAaba3aT8Z;! z8KiB7JZG}z6%i?gGYIv&?)%=!%Kb2v&wUz&m^}b&H)BbsdH@_UCVV^|xZm$)V-1AE zB3||x>8MICal2_O0s#qCEh@*Z+@*RkuPjxvvB0QDmdj4Z#QL*~Nqw)ah5_<+$m%%#PY^mwQD-uKQ+LmZ|U{e?d^t#3WTw zo+t-sn=VmX?Ag6-3BC5YUlmu^ccMHjI||bgsGe(D6fR4Ak;Y#+K(<4l$+>f5%m@&@ zpn#)OAIREuYLO%=MK8x*WJ^=5F=wnyZdkWlkF2?>P3<_-76tZaTl);V)=Cvssh9v; zic7=A2I8VR9R<1*UtcnXV(Ci1K5DHJF(w{|mJ@fi=>XUgr=FQJeBF#V1xc8wwV~!B z_f8cBVBiQH@8MiTc%1m<-})c%-CzETXv>0jW*m*PEN#IULqI;$q#*Snu<5s~I~}Rp zW=j9A15L%SMK}E6Z(e-N2 zAQpf%| zpX?)MP*mNMN3O%{_ZL6@-j7x~?!3nm!wV5o=a07Pvx{4is9>xB#$_@(E(>ofIoKX# zSF+(1F1MRq6=X`Zv|JZU8upgNOCz>t1j3*nChp=3GzyURLUf#zBZdrZW!x6Yx{?F+ z8S!FnlLdtR9Tv_UgykZnQ_g2BEsJj%yO?Xfmnx|21a zE)(bkKUG9E7x(kTH<$8%*WtVpI z+F=Y8S?X&+otw3Q3qp$ZDuI`xH^$gKSL`8vo}A&htV_Q@RZ?81=pkHGc9@8l_VRVk zi@B}5QwbVxrqQu}J{IP-JPKPB=^?9Vh@#W>lC|ruHy6gS*V+Q;;iJ|fyhaL+WA9@# z{hgLD`u6rV@jERU_=+xT=I52yXo~{t8)iS>hvPHMhx)M}aPXZ+p**PWFLd#Nv&fR# zh}ivXxfpteX@P5tLPZ8G-^CV^R#;>Ay)8JbNI_Mu_VQ8=n!WI2<$T>i`2cTb$BSBtof+vV^ar9+IsQ z&aV%&|M!=;{VTtLEKQ0F0gEWFJJOaoH9+^;5~HZbF;Ow}+!^C|xlfI{vb(6evBr{E zK-9uTqZXwxuH2~0S;zt(KdGW^V{X@y<+EBpN;_fc^c&1VAH5^=uI)-%A3KPn#j;wa z1iy5Y-_jDUg}DA}S(a|TI|{jglul#$(U8uwD@N_~B$q1aWrgdu^yaY7B_r1|Eh0M) zx6uA|25!fMdMORG%L@|WJABHd$F;oE$ zLQNH}c~BuFPNqdA;LN#8rBw|&xE!WBKnrwS^@ks+o3 z8Oz>7AFJ_*CL@;uIG~_1(X`dBcCj$_D0H;bhCxz;aBv2}TE_vZda-hUh4X`3;95X% zKr1H#{A8MG4`?O(YsP3w8Ku;IVZ^u~t_yB&ceubV$7eoK8b@_J_6Ks!D6RBDm%Bvv z`?}xna@JJr`-yeE;YbHkNq8PlG>s(?0(&YMab5VCRd6(t^C-2UN?^L~14X=_$KC}2 zD#{oK)UCCKPoF+b=bp6`(EqKYeQTwl|9jt=l&o}d;}UY>?-toW zR4(rK_jfb$Uqr4?;$Tl8H;W=hQ!5cwiX6E%sarXefz^hs67IK8y-6M(cDajqS_QUc z<)%;aEfq;o`w(5fF~+`zSjEmnbLR;aOrQoy%u}7m>56#kJ6M;Eb444+iM7f(d+97a z1%uHJ|3Y!#gbeuBGP-r)Mcxt^_w;ENa& zQ_2IMQ3bVTJohJjYk1}pr8%GgA#P{|I1i3*((jgY#q&sTVL@0{9GPS2w0XA{JGLPz zrQkSE_GI!7E(U~UVF&)AcLES7Ah>|Itdi}@=-+Yd$hmUtP$RVFQ7iMyVq7L;XzP<1 zWt^|~o1O0HpV{-)HGrz5qkypWHQk1#RPY^rJ@ym(^8^}4Sb4WhK9YLZ@B5C-*>@i{ zKU%~NKBFc`FyD+vlL?go7Xz9jR08&N0w}|U;5eSmR&iBAGr7thJPQpf)q}#yV67|a z)q_a8aYc=aF<-mNjdNx)yn0tO$)VF*RpHj?JuA-){B9-Bid$b`*i;&o&QKhtsR`d~UMek6qV+s9x-@bhVInErjYF1W3jWrS_dO}SqZLw!N zxvO82B_yk1V~6pbJUR<960kkqW=NW-%+q5*EV_Z zT*u<}kkoh6(OEY<#B{w~xi2Kylvfmcd~Y|9oShW>Omg=NoD<2Ea0w)4V`Nv!#&pV-M>{QIQ4?>>QH{eZLkJ|Mcn8 zgyNN&%+x^ls1wC1pRa6OIwk^E{c7F*?RT|&#Ewye**d~a>)U=l+qhVS%LYde`&1FAL7CB9I|<&G9XEETcY2S9f=7oH=)3Zc^IVk%YqBt;3AN#=b-D zDNV*<_Rt%%cuO`MqmN=X_($GcS9j|xS=KHP{f@Q((t|@^v~~;k`+eH@77U8W5=r1zLelcko<=d+x#k7UahTEE?HePqH&*AO6BNZpdRRUD$o%XNJ* ze}ezJ?JljCmMWy2OH2~29CXZt(b>Gw`XNo66%!v)O2OOP8+-_&4qbZDWaFlKciCo7 z9`8N2ZJR^@j7|@yZ_BHgUE5Cya&G33%m~4~7RpN zv@E^Bj@7SRL|tQ7HD~Q3Y=^hEH*x)@VO*R!_mlhro_smU>2%2Xgrnh&XD_T?&`U}N z33|x?jPMfsXXJgmZMU9G(EWmpicP)pEb6D9UC|~x<+$JP6L(D4{JL&k-McOu7c!0C z)p;hATqin)ZGLT|cjd)>6eXmMiT;^#1l1EssRP&e6wU=?TaQ|*F=B3=pJ_?+t+IVb z60WmVZStj`I}M|~?|A$_{}kK5{2Lu`u#JLsH`m5Oi{T_7hMN1@6qBo=uti59`Lu-D z4yd&TAAI+z%qh=&X$2r8O3#`uU(us6K?twrpyp1$o?%LkXHPdTLVzsAFJ~o|T&BIK z4R}Y&%(DyLgQN&_;Cf+rz!6Hzoxnc!DovD)Wm!4sJ*8QUx&T#**b7rJs%uJIRFFAr6b)n%N zU1`VXJOP&ojG6m$c20vX2>mYB0a(YnIVEI?7GTe;j2O1=6J^l|EiP?`sFHE#NQ|Q@ zL-7WU(Q$!QBz~kEyYgcO55rGnaXVkP*^P0H-8`~)hK6^i!2Q`Ao(a9*FOAEtIxrt!NqVpavd<*?t@9*zY$TKo>f4ld0 z5o6?WD(d7y-&#Y>94%yxLu<NrYhO684O;$hqZ@ScERdI4Qoa z@gT1P7MhSo+mI=;Nff$`jRx66&?*uEN?aC1Pd%N$s+kp~=|7t)N;X-it|Ith>X_!mKabL)@bKa1tCCJ!jcV5_|^aL z_wd7i_-}P@yesl(sXKPE$cQccF^%XgD#Rq@(p zlkeYG^J05;S}Pz0D)daU&9=1?>1#+ppW)-Eb|1y0snClG*{&Hm?)hCeOvNXoy?I(Y z+=#R(f{wX-WkLxp=lVDj{4aj-dp}xOt(lk^M?->Zc|$gW!4lmqbZ*J0*8pQJu57rd z77O|kS%&L+LiMBqld3|0cQK1jU%1Un)51%uZF{(0FEoo@DTJ-_SW7mwnSoay4YkR) zCWKxAgXftw^{*LfjWnC zaxQx72xhG^V(?x}_yme3_Y&Z3M~$-y?KKu;pl!AbwQjtMw%C7Zk!h8n`niWOZh0Ye zeiYQJ?^h+aHUmw6*OiZ^NJBSz6uW~}6t5k*kRtOszUWZ698lNd)Q-kx)7!aWm=25X zSl%YIN8gE#xa^ogm0yF8!-2cO6Iwe#E}}I?I*S=$+SnXh80dJ?lKEM#{r|J|ZauSY z+f`T_w>hi6wf8o*z(}A-j!>ikA>@Tb0mM@t!+%K>kfX#A2mVg}20Y{`4=5Li6cby< z#`f_(XYch@)tuv&hu-@bZOmHd<(#wD`s%BiH7>ok-Y#n2KzV^BPgSNp`&!H5gl|RM zwrvAl{Qmpzk+lf2B4OWlHLb+byfIQfef6eE=NRq5FZp;$x@IB4#=2L<`Tc$$(NL^9 z<4Xs9?L3INX-IJjn2H)710%|& zwTA6>LnS&9Hxqo0?zbBplkTa3zS@I)%S*8X$oU)%C*Tl#R21nwyHe2pwV5${rrtZE zkBczNaya?y*!LY(O@N`+KF`+^-pzdg9hVvfsPYyRWGJitIDcpI5g}5mx42AGzkwBRfzJgN)-}u?RrV6Lw2R{ z9y_%2VrSmPDqZg5g5#Vy3njM2Vh1}berl}?()9J~S8Urp4sk=buK8ON6^O$D+c<3< z(izs)m7t5^mf!7jmnw#FdZC+}dOqt=k2vqqszVR5;BsjwwV^wQ+JNKCs7)l-xrhhN z^C>E>2lH_p4*tqHll4b_VVFpFPB)OL)tG97wp4zRlNy! zr4EjWchjYK5WUGi>pBi9rQoKa=c90QiokTa=qD-~7T8)El^Ne;M00LLc-`3HX{NHK zN;1e=iqSwZ5rGcf8DU|Wb9Q-{7uXV=q_z^T^NA2W&RoZ3dgTI|+~4?y=UFuT_l~0D z5^+n%BIe-3lRssAEuz$l=Sw10YOg9#Se1{hcCji65nV~TLyqmC!VJF{ z&kjVONz?XmzYm)ki@Um_*DP*fV^JN&v1{sG52X>|y3^!}z zr<{kL*-@L?HjwZTg(Fn*ftbvXY%2DWCK=e-dv#EsyhMx!?EZ0+fZezXt5|J&%|YbC z*$R68bM|*M4wZ$rr!6VRw~2Bu_;CgV?}t50t&{%2(Pb${R2>zH^Zy5YjOYk(0mwgp zqW=3I;eO|@YGW=6?GV%OVPjzuQyH9J^D|kL#)?w!JOTo?v>}BcYd}Rzawa)VlyC@E z?6)rHRI_ARiwJW#kJtFUSJPkqZ>H^VL&|l?H2|H9-ryYWx0@KOda+fi`dx@;Sw}7> zj`M|%rapP10<|;GywGg?d;QKk+FO{t_YUQ(!)J2e(y$@uBeqW+6bxm2y&jz(Tybhuzy#6AR(F6zA9P@{P;#YL^e$kafiXx42o9z(oC-KW!#^E`2!Cw}-k~3J(+4Tn?_&D;UO#NcKBU7Mp+|8Vouf)r5Ia=Ex z$DfTMVS7D85xC&k_k9@KuK9kmFlSXOk6O56TSg3BFNxl}cz-5+P!4fSI_7mnS` zCG(5JKQ|a$Tr9#1r%KO@pAx^9YmoW3&_*@|Wq#8@i@RQOy^R9cgb}RX8={lN@w*R) zZWEC(iZTvbgkhjL5v#iFZAPz|N5rIb9(P$_uJM;_O~mMM9H$~Nec{r`XNb%G@Xn*T zvLKDUcT_?E<-N5rHk{++GJFK>JLA{5ie0{yXmK^vw4YCE7r%aWh`0l^``{+&b0H4n% zV%i3ZY&Jz)fQS?OA)LC4X)livB^NcqbvKG621>XY9_w4xkT!;PG$y->ZfxzmUaw&b z(@4GF^fh?gcD*CpWqQSAc@qbW>50d}nPT5UwpZD=`@%)$yJ{pI)GDe~`kqBN)=>*l zJlq_Uvj{E5h%;vqWBk*9`cHoGcs%fUJQg#r>+I4<&4w7*n`cy@xArEx7P*<|Dfe$Eq zF7t4HH|XTimc6zaEAr-MzSW#r%f&tC-3|L~m8*)uW*P3@*Dzr>;AJ&~jg$MYN{c{Be-iZA}<&jJXR_;k6PPXUs%hoS+#U99*c2%>@ew_;=YR;}H#WX}DWr#Oi89 zIXPW&X@?Nd%DexPUAF9NWaGZ;h7W3fYh*|3lK3JXWA9~@90#eF4>c<^mdUUz?c3+E8S8gUA^&`%f@O?Rvz0qa=ieiFONv; zyPB?-TrZ)*?#)|i9L$DN_O_f`e9;OA%r7WF&@uQGslJ{SjK=bKkgW@*l?awGy`63E z=TjI3_&j61jG;n8aALi&>A$hd3xq&1;>v0$GfKyr(;}|hFANHIU=6Vz#2a0nlg!h ztaGNK=)ZYBpG$$0E?!JCP&!UBJsMK3__KfgZ}I)#`A-Iy@#FphT>S5>nXxnjv*EF3 zjGyn-s%9cmL33BjqL^m>bQq|zn1kC|3QBHYEn_Bqhkf99M9xLLjq41g;TnSLg6k-K zD6fm;Gs<0@bfOX$Z?x&xA)%k;) z@&`+bwNnVUU4k^Q}Nc zL*--S)CC&NMMg@!0)F?}0buYTX6Kn`tQVK}+*-$ZzJ^+bl~z}76~n<-_wsA8&L*$i z5!u?XgXF5x;-ZijK9ed#2&kPyaQ&Mq?puikyf*mHI8H(iPXDHSoQ0o%LyhG3uKS1! z*g4*?f@MWpnMi%*ZE>*_f*;&LdEL6Y+tX)U*Yql9ADy3%Z=*W?tQ=3oF++?Z@bB=H zz4$GsfBU^$&@n02E}NUF0W}&X=R+?sk@jC3o~pmo3RHOyQwYE@Ew$F6Y_#`hXg!Z% znEWfx!`4+_M&MUll-}iB7zlB#aQb=enM(d2#4Y?{bjd|3kJYHNA3yuUTaHudhi?x)&KVtg<=L61DxuB?szy8GMzx>zu?jQd{ zI4|O?rj!vmLSYW zydt93K=2s|Ma8OezuE<1aw=@IHE(Bo?;Tzp=ealt3C~RX~M*x#_iMNZM7o@%C<8>l!Y3aIb zyv9(qSAQT@%3ViQroOZ6qrnw8U!$mOy(vMvE0SND}QA{2!opAu5x28q^|rIRx>i{aE)X!!lpcrwLs;9gb{_DGrV(1 z+cuO?T*w3;E<%LFe6Ks-PHQ zGhZ5e?a{SwGs>sc)tgE(;KH)!tx;k{vi%+_!mfoKdpljdvE;o(-N%!gXWTe0{=JWH zb{_M!?DK4zY=H4z8D(RHi5tCB3p8^Mw=>BY2=Lp`cL!2s^4KcE3&&4~hDJj;fqCZl^hGDJX7qo_(uxk@H_fODtj49`L za6^?X;l^$VJ~$KdTVdp@+E2bGBSSOtH8{go>_(6F`NZr0{rC9zJAXsWPrcXzFtuVf zs$v^p4OTN60{Q}4T#;VyL~K$@UPKquf~d{Vda@{*LGgC)lPS5Sq;Ny;JvPeHOxreW znCuQ1$j>EI-3Kr4Q-KB!Y3FmLwpq}3N?~9y#wHhr{9eb7tBEp(wahXeZy0+)0Gu@o zlW8%vR)qiIzyI%kv2VM0Uz`~+D*vTdwCWVL6<@5{BnvR6sF17>$2&T*nc-=MnmJ3-i9Qi$zay`||PdImHKGBsR+|g8a5B)Py$iR6xCCQ&T zi-dVgDCI=-euR6r+K2xOS`#DL4!G{*yQodqq1b{%?}4UBO>j7~6t3r)v86OjL37U7 zHITS>hu3)^Zb4L#aBy7+?AsHB!(!ehg!{YQ0XNz*D?^JmqunwDmNE_i4cm# zP9>LfaK*fL@X@0dIY*+7Rz(q&5u%WUTNmTnZQqn@Xq>4k-$M|y%waa^fm~hy5_+u& zn?r-_7a6TJ%}5hxc^Rd*Ifn2-*Py8;)jKRVaXVK3&`*6r2-uGS{#D&yv68)}Y(g5codS@M~2yM2fms{Y-WROp=}XK3Bp zKmY(B07*naR8CbfO&qT1Hck@yg!-B4`RTmaC6sFZZC&pVufe~9ei_Qsx_llhNK9R4 zDGzarIF1*bx4kIo0OCO=qw)}gt`*IJ4H7$-YtehMDneFJ8`Lbj;H<*qu|VS98y?RG zQfDFHJ*$6V+zd#6<6coTVKIE}&*Hcb3CezXK!V`=kNX zK#V(_d3bqo_lNEgK<=xiB=-N%J{lRO+@IDPu%rqYU@hkmpeVT1|K67wLo_s zHCKJUSrouNz>)Al{>+n^bXSo;LrOQG*?BKXFEwXL5>NwU39)u+pCM#*?*JcVuZ1M% zR!jk|RYVmobgjVs-+%OD7xYIRww*_W zMA#fh!IzH@IM+sHTGhv+RgvyW#b#U}S#ajc z>E}AoQIS-tn)4|x$uS`x1tF+Kgp*AR$os3M4*4!RRBb00ZE#*C`R3=<^m1z0(hcYh zXURxWJXTWg<8=fsb|^8SwG6bTR{cc_RgV~@km%Q%7MrL`o}2 ziHuD{8ikXgBegcPoN?QC@!2UE4jy{0EIgq$#tiblYip>kBW-DzTgDg>y~BBA?6)0f zDafT@k4a_b(=olPprGcA`~4;X(`e|eBA1GNyNQE!>+m`rFqi6@Pi)&wgPaAfuCBsI ziMzi4lif zQ1W$~LAcHZwCa?^T_M3o0VPj@Y6Z}%W_$+aGzE|6H&L-2=$7pL*2GAdDh7LYu z$Kej%Q3c(xu@pK|h;V&2Owi)qxiGu)HUrHE%Ht!>QUEVwqx-(07L9&s8O{Z@CODOs z+i{#3DQ>9F$tC7QrR5NDo-)3T+AOA&5S^erF$R=sX$U~cSqdR_QAd-pku&r`v-3o7 zBAvV-me6&X<==NX6U|_GK@go#Cx*ec^XRqfb8`AV%CMM8NzSjVcR)%3jts7I$=H(c zW|MlsIe4TH09VjmghND%0ksv$AN4^0)lYc*tAB&v_{aYMtrz6h;2N-PVeCsOnB+4% zMdG(T;W#rwl4t0Yv*{g>k5l&+lpfGgQB;{&5re~?HlR&G!M5#6C4ua_B$g<>m9gGs zopgkd;JZC{xx?kG^8;*f#@DTDh+2b9h z3J0#_GU!1uL;$WpQNLAuw&6)8g}R;-t-&FU2CUXHRI-*&+tfm);)N6ieRCG+=H#vt z>9~Ry-QhS3eCTlh>%aPS|L)_4=Swzm0}wwVO3lbeQ|E5L_c)Y!IT!5r8@_(NaKCMG zU<5&r&Mb3mbl}UE@9@iC{t`JK`0c;?+c=L?I=u!o_rzcN{s**HaJ&xmRuQ+`AV@wR z4>cZ@4Zq(uv|5pKL$1K>wkgcov2QzomsI7!<2+8pB*gbGw;NK7`0l$e`26{2AZ+-J z-~287!5{nye*S!+Lo)F`ZVAp+Y|$h5j>jwGcDv*2*9Tgc0M0!)R8*uSq~?83_;NSs zv*YcPn^70MX?Fe!X7kF5oy$e0+SU)q}^rN1SJYLqINa;Cz=3q!8ry zTL0C6GiQVV-0nMSsd9*`?^RU8&aclCpI<-m@$m&QZpddw3>^-_wX3z_SHJoR*?Xit z;XGexRXUE}{EZK^4%}`Z`1P-TLM_t;_-H}eqid^`~%a2}_26oO3p-0|^o$F?Wz zyO2TeySP~Y_~TDFN&$R?L&yE&V{q|GF4`S+pjRm*wjF!g2G`C|os5px>%i^4i=s3a z{N``m@%ee+@q{7+K=cj)4rz;cJ~Co-@LR-@1$8V{!&V`m**n08hVyiAz2S=i5G+eOa)cnFG;^!>|v5L=0_Ka1be4}a+c-8H!0kpT~)h+Z{1TerGNf zog#kZ0-a=S1R+;X7vnyxApnQ_ZHMz7$MF;+%TtP587T=*u@wi~?b zsK^LG3LLrk0N0uv_O**Mb8EP#O)N!HKq-pE!efgb=qFyeqV*4;S0wGMOFbo^yJ8&P z(YT#HBg9QUmzQx$L_lc|!~pabQEEi-P7$Xvikf;>eB5rxS;DMSbZGt%{>)1ve0r}y zmEznCRAWkb<$@HylgrOFq*(Czs~5if@B>ncIP()*a5%Fc`DkXEyQP4fMS_02ZxT=) zHZfTgz)6}0@|=>QCJrG`sa5S95-J2i=`|y!h+HaauSnLN!=dYCk8a`)8RuOWI0f^836=Ew4B-3>xIw~zW?q6RZT0csT8Cw;I{8lw8n&5`xwQwTGfNd zDsDk2(DUFQZQBm?j^-t|vo}Erhbp=X3ZB$E$yBAm3|F04E7Xz^lOUOAKH0#BA-&c+tkB(X{6DV#!;oPO~GqnF3qXM&^cF7sz+-A419dK4*}BlIFSGM-$(n0 ze;d0OyOV~l4R#~`S{Q{wh#neFgjTBN@pc3kaFi2WkJT+k@sf)PC>_oxgy__B(xJMB zQj0!i9rdEC=aV$`Iaie05qv`_r^f$u#I(tor42&sby%KQk-qOcYOcz2lw4T!rYg)+ zxu$Y&Mi=3H1k9=31Eo9>lpDA2!gYGRo`Oh)s2nthJ*5$sS4#m@3~}aDig`uVL$nca zmUZGI(1ZRyrQ3vnv!3X+2^#CB0KYdaGE0GT0U?Qf((C+$d!5gImO?Xgg%w){pz63P z3(Zgv=bb%r)Fv=oP!y|cXPRbj`Kha9{ZM%OO{~HTH&H}eNKxo?_~s1h`0y&ZL(m!)9&2k*FS$9sprCl z5eaWoDZcO)ym$dAm!=rcj10|6lMcQ0fV3s#a!#n*rGZe?+O@-#?#zDId1moM@d7&w zzbc^ML<|w$>7m+no}!(9R6axuf;v7vAK21O#uM<$o6~Vw3~2R0a6;I0I!3KUH(83J zV)P!hRcs+(i$Q$2I#7F+G2n43dA&>*|0?jfjPQW-tmu%#dP`2nP<^00!6!I0Rjx=_ zY3stp3Fyg>j?3*8v;`FP@XOL(0fXRElSgjO?ZIYqwgOoo{>&biJctza@ANoX3INp72}0 z`GH^l#m^`;p%m#d@An&=YlE{HlLRjB%2}!HMC(AwO}=|=WWM{@(0jqpp9h@ZkWcAK zeRQLdJ8HrA-+zx@3u5r1zUmRJIsE!pzsC39f6;MGCo@lvTrzS4IwGWQt@!TCj@YH4 z72i4shlZaYf(E9P@Kh;!Q&*apJT|o?K<)5BkoxXCjziGRl8cVFq_LM1;_x*`yA(mJ*+;>&HrnG2q;6ZhL4 zX-oM0`V~P@;@9hekB<+W`2bo%+5((wNL#|=^NDRwBY1sFNiKG6nvY!2mFM#DWykCJ z#D3rL`1-)MZ}_<1@q8T`P1A9n1froe23#WP>vUT+~9-99`1B^G}E36KBn|3Lh2{vPh=2x-Gl&jVfyS1Bd}e*NpOh;hSr zUv4N_zE=c~$Mb~{BDPI9fwz4_P{i`_c;J5jP-;)bSsT85e8KbcD{fnYzB*z|`01xl zI0xK6cKJ@u1HC#tpD!RfeEHb1Z*eq#y&mGLmC{%@c2A`!cc(H=wSbm2?L$OXH~dmE zKEB+L^NC(Na_Oj51slO5Bst5ylhG}@$NjEk^eUsrnk!;}sQ$D7`uMox_0otrFL&dYgew|3FjL=_B-;K(YnJ?GPWdv@~w6)XaTe=YX}+c$j>e# zIe{AQ`yK5()vLrKp9S0Q;X@i#akIFSCPA*wD>UnrByeH9QR1#GvnXL#uKa z<@3;LHmk{6RNopmxED^-)Xy_Z0b#E9!zO=vK<(S6oGiIuQ{41@IW6dl@CzC_)GF^K zQ|@9^&Oxpx?zbDtnHBC8?v!M!#X;1T94bLadMi4@3fQ*|uh&!I>>@l4KgoI>4x5i^ zq?bk|-V~;PK3~|j1n;BfZYfH6$;OgRRdCyH_1+RTNQ-CB>Qgg)bi; zYD@{Z7}Xdv%=|YraWXfOda0=03G!p3=qe%u)Tx}z<mJPtWKGTFa4+lG>VnYMuF zWNmK&$W1sitrwtHROc!GEh72=F93+3Kv5+44MDxS3c7c22#8M9iD^sdRm?tb+lMxu zWsF81M@H}st}DsdCm9>YO^li~v#}N-6PKECybgpAA)uH?h?^Ku))#6~ML1L;9vxZ{ z?pbXG=W*ixag#zj+gSn)@Girkw5mz7-^3EYJ1Oc~175FFO(k^_;2hG{(OpFf>R0Ci zdNZ+zM>*uYY~9Rx9a?k31JntF0%CZ4KCs_+HK+}Ed>-QUb)K?5RY+vX1X&S5uSS<9 z#M*TPUCu1R66M(5Z<~(J9rBUY5Y^)p<_8?)Zr%3{$N571@z+TI=8tjy!@q^^LqzEv zpRFUmUbyW^1D1jA0=kaNddb2G^d6@Y-CLi@8Yu?E;FUKf=Dhp%fye8Bj}cL@4}8t4 zFboMXZg@VQA{40w9UUp$aGWQ)Z@BLf$LopPw&6U>K(L{P*OHGb_rsSjUxugHSqd7( z{^v1*N4Kd z)~0FULi}SZfb$eGt|`h|6|=a8CRnBi&_o>)^&+WynVF(b`aYRtO`slmIf(pN)Db;HLWS3 zS(RfmUZkTL@&%~laUZD#Q584#Z-U<>;1yHKA9S2xL}f#R4GoMj;`w?h-%AL;cA#4! z=MKwrO=(+N;Ox{5r6HvuL4 zc5SZIEOJX@Ew5HBaf~Iq7W^V6&`i?c2bx>7;c%LD*$Tsr z^|`ap(1j1=y^z(7bbPzr#X-9P+rFcmSY@(+HW4=vi9|q8hR8+9-(PTX{#C^Z`mJ5$=_o5ou32|KLx6fA^=j|D(T)*1I&9 zPR>0+@THLsF$_Pu!NnxCrE#Z?|Cue!JZ&PZQKEQLE|tu7yg2OF`MPH2YH?R^au+7` z#2P+Xecm_D6qlkPSc2VSN;-LPx(CIt&PIArp%AueE@K(^^2M;NScVZ^TOeI2%pzIUq5$t zL^g>bd(p_Esf&r>>SKgAqt2^Y8(Sfm+%qLn0$HYz-2FnZ{Q2jvxZSl=gn5_fgHXEM zG`a)|TOI5DfCAbZuY;oLQI>-xEPU5ubm@85!>yYfi*_ppt?%#EDVZZ?!%avUkT!!rD= z5bYP+1u?*Os;Y6rrodi*6c}UwOqXio;IVAmSPfF7Ob;4UEg2fP?>ow{cqqg0*4B>k zq*6+9NYyHYZT$>Z6i#RUX=QP>Az_0&_RcbiI~#Pe-_h!^#U42wj@;G@S!`T`yZJM- ziR;z4lYMR2dV~!>XYjRfbFR@R{F%66ahP6KQ^IflH$@dpm|PNdj5pc16`$-PZEMrk zoxLafZfmPraJb>xFGOHbI3_jgEoHjz=bZ6;K5@I<#y*tSF7tBLv98x*9%v&$V_2OG zRjr;krNC2e<+p53j3h4w@QTv%KD1PXtC6&v)f-|o8-%8W>oDvKoK7G_(H0l~yphLF zHa!+7%oaCSKRwR&G_=ILzOJ5erk-nEty!9qoO?rW+BgR_bX7YII|HPVS%acmtBY+z zN@<8)u6N?}AC!V9{rRu)`hWfq>A(70Xh9|pJy%su`Xv{W{TA8chd&obUCl6hRlVD} z(!^%LQ#72}1M&V9)N^`ZvB58bM^y_ZyPMck&zk?7&jEZGx7#=El*kXVbU8;QAba}N z*}t*o-mB@c6?Tj5jCUg@uQxvm-TVD6?^*MVtJws_AhZw5adZ$$2Ra<$c=jCy4skKr z9&4^Q9LI_9yTAKSf3c-)__}a1^zg*#>tSdAZ4SS<7<_SvGy4eHML(hhG_%P}6}zed zy_a#6>!RE;Q^}mm62ia=R=9zZ6VX7}{&ue{-Q?2kG=^DI-HG zk_vE|MdooynWqQ)nb^U}9zEBXh{d6~*U>!*UuZ34Ie?ZAA+yrp157T#sp=RG(tUcn z7=I(ipoL2x2COqEG%iI9n~bt~Cp+@8)BE_WPHh1-YUMe>3<3iZR#_azB^u=>(ped$ARn}4;nO^dprIbc7DQjRQOK+3B@7VmEF>0tMmqBOZhOyx0ldj4e5MmtXs8 zfXc>>kH=#ae*C`qwd`{LRxFPhgl^l0UJEuYuB>P}j+c_PyQO|Au`Io6rGq;5wjB3!b%*D15*rnkGM(86#7^tN*0Lc0oQl8*mc3s#^X1@P zw)f!uyM$6-LYcY9l6a_E-0LM(Y_FWT$C1fxX%SG$qqo7Z0Z~C(1)~ zUM{U~x!ZFwXf`S0ATB7T5Vf(mmOBUJ+SL{%{|_bZQI|aWVIx4OCe&7(Xu&3}44kkzZ0}9bu|7>;SI^O zG=ylAE#-vGI$@1uvhlu%2s}mXxh0`u+_QlAS*aJL4^9H*i!??}$K1Auw{06%5xsZK za$mDntGePl?*OYew62iML@b8EX1LzFQ!a1T$fr2?znsVGycfmrKl^9@%P+V}eed+u ziIw6Q_`(!ey^Uyq;kHd^_M91;cOUIm|{rLN9vt08*cek)R)I`E(IhX#IvAGGXlemU@4!jstRv9*NV|!YgmJ@yZYG-xEG_l z4^P3Ll zT~#-a=T~~4VRZED7A&vbsDtdwXJr?19y1F}e+gEm?~vCcqkhR`$VzBE&Mbz%F$m|0 zM$s}JDa+^M|M1v#X_V+9=Zk&e)Lpvars|+MdRRlWxv0D5mNNRlh5bNZXtXCLr}2_8 zxfVdL*Xzv<{yNsIbtX`7A;j?^HWt6Wj_~x-((PMOXs8vV3XJ&j8nd{ts+JUe{9U`` zoLcfl9b@b3=q#xHK?t*HnrD!h;(GN)vI5H*0!Dh69$`F2@!0cY+%0Cqlws(?QixjE zubdTO{Eph{7@>ve$NG1Q=T?ewx}w&zxosmLc{Bu6B-=>vnx|=JkTu`4a1&c1Qve%+ zDZhJ~@5<}PHI_^FFh@S|o*o4_p{l$VXV#uRhsO)}`a=4Tej8^M!BnsY`O+-#clE81 zW~Nc_xKIQuliJ{P6z0@{e=R`kTOKK6L)PGM;suD#AUwe^#;Ep#!TZsmU%896zxeEF zx))tnpT*urbHT3gks7v>-k06+b{6NHRhbz^o}r-bb@+T5k}UbXf^ayX{Ko(QAOJ~3 zK~%|k;|8E{Jxk3jIQ-u4{ZGH(t|f*@UFdXYmyO!=gSbJsy`lo+FySE45R^<8)YZM> zwhO^Gc!Bzav}cC}=lay)p04dbwtag;M%t1owc7OCWi5r^NkxOIp7da{oVM#IhQnJK zDjgD(?iP*=BQ>`0ISlvf*RRWboU`+Igfb!duw;dK^*yR}WJ8O~Bm2Cp1FDYE zLQJC2%I9(^8}H1b8q78TSkbR=F~K-+I|_otv-8{^wSVBNkC zZipakjWOB(noBmLm%1WfvQDbHU3VR^_SOf}tk$w{KR5%Ifx^_3Y9J#Q zR5xozEay(G4JpVdy(@|-JP|>#Ymqn-lgBeEJNP;j@e*T1+Qgh#*6cbS=aBGHW&>(! zF?3bz!r_M>e$XhSj8b%@Its%u_EpY@qS!{J);(Ye6jYGf8N%zu;%9opFolGU@~n`s zWu`G)WI5w@*KqXU)S9IZ4kbrvaU@!;MYP4OFU5v5?P~_1HK6wFYi;@--O6cl zeu?dAt)c()3IFp8?yvu4xxYeGm26vzPO(=}_kAifZO&#qjbv0WEgwW-iP4CdjgO%DrkJ(@t6HOQ0RilJaie6R>vm>AlPg51=7z!b96via zq*3`?P1a>m4zgDze{X#hksN9-DFvtSdUJVp zgSnZ%z%Xyn%a%J!Mk2T?<@u>ejhl8dJnQ#p>UqTBt+?=-jHEgLo)2rgFoO3ubQ4^8 zCS2Uu1^awH@$vCNo2D)Ve};KESC50E`J%UHWiYQ1+L!l8gkk1J*$iHkmi;ZkoVyUq z?6Ti!8_W(A?%C7hG5h zP429%#f#KrbL^xN00TcX1LDiN*#n3@p zL(Ca81Y_HF{hbmCA_&AB=N!+MA}2GtrZp^Ux+$SFl3I`paoz`p7BiWg#S8X+8Kva) zbtUt|t>eOuJ_xeh$YdH9UjuHrvE$C&vJ077!0+Sw^PE>{>niCegx78lQap_F#Cvqj zkIQnCq4kdAbq+#%*6++{0M~I5BXP3l!@}Eoe~#Nf`p@w?4s8U|+nFg&?Lxku z9JKaE__t=oz9$o>Iggbx;T)PGx4dVaM!zxo!vKVh23tE2!wtDqgrEg|5wywn6rVTT zkcW^IL6qh~1SL`|v6$j2Xb`n;8sX6PJ@U^8Nj@)v9ouu3jmnv$Lp7q~PZo|bPrCHB zPzhMbl}nWoAuEWukQf`ExDU&lrl8i9ur|kxW;aks*&|=1bRK-Dni9_*z_v}q!wrMW zHbxenAi+itoVi%sIddmzh}G?OTi{dc)~sWCn+NNAW*B{Lb_}G9t6AoE%$c@d3K~1y znYX~5vHg4FZr$(qCHU036}}Moa9@>UarivdQU{sc4wu1^Qj|=HgMLODjfHJWrdgo! zA%6WH?4V>$1s6sJkIOm>gG6tNDgI8Zz~W}WUdz5?=FKddqLiVIv7Zx^Ns5QR_=~>~ zr+t0D_B{4|UoI@$tYdEPMQ+aON-HcSXn9*M2JW;Con&>>Muo9i4Ok#AuPJdeUen;M zi=Cgh1FoVLQJsm&Y8pjtAa&BUQL;-w@&MyN9YN}0;lLd5&SBejY5)Y)vqFdiyLsfp zs1#qA!>&UwciVIJ9k5!N3$CluaW;>B2Kid?-R9`e#`laoFk*Avn;``J^wUrH`1qKT za1sY_gJYMdHM6z`7#a6;2HVf~OK`ZCS&rt>$+`6T_{6>m!fM%p*P`8C^Ez@LMR#vh zps#cb8+)>X+}^*Tgg^cC(>M?B_mA;i#u)MS>sOqo&?-tfhbobSrL73C=fR_6<`D5^ zX6yXQcjL?7QUz?U+IwO#6Q5hQ2l;o~Yl#vNnqk_6 zTx_$rFtb1=1lni6-|y5hx;Op-KLb%?Xn1Mq+7W5Sl@d_-`#0lSUf5SP>opC16n+}# zU>j84yTHDTFubd0`tmHt`m194XcxE~UT%y_0P4 z-~*g3LwJlnRal)4o-lYutTJOxfvsaX7@aD4J7U<;py+BZ1HIeRhT|yeSJkv=c5lkX zMrR0*CsOf7oh_KIDL)=@k=CuWcKdgyR{HdGz&w1KOdlU0q^f5+$( z^S{2O?zH#xd_Liv!^g*mj)Ve4n>ss8k-q8Nw&*1;)mk59V zZ^H$ThNiistId(+?)IjQl&h-9+m`Rfo|6??vOYb|d@NjG@5DRsYJtMY+|?Fk7CQ~j zSDdGq1Bc{L@`+lebSC2c^K&szawrhEqF zShs1!RD-K!Yyz>zC%>bhW_^4q7;!nqs99%uf$F%(i#j@Bk~(|Su#Xh;A^6V*H-Z+_ zwUDvDH*SF);H}NkoNabKWcd(dnBF#Mx+tyebD8}BcWxgaA4~VcmKogjUten$v|Uo{ z$KP>cIg@6+##m^$DkeEMrAWxnw)}4H%(*aRJ{XVlxT|;0;q`h9^TvI@sj*}mep~E4 z##{j_{`iu$zvnL1pmjzDhY*xV?Xd5glAE{XaJ6UX$e8oW3A5L~ zl5!Wm#lfD%3zpW_}x7aSplRU?t+gZkqL+>58eV4Fc6+tlaG43B9(0=-gEd%&#zolMn z4rmRZpP%C{wGm{|6a-mIl8|AZg;$iu_DzfuAtijo`FzFjxsI_J11CIgoW7EEoIU4x zqEyM<4Iv_*2cEB|=A>qP_x<h#QzA$)V7B#N5+r7q%@~KAd(clcy@#!-Z6$g z(7d@)H*l(fpB)AUyLpS;(Esf;$4y9kGA~vAyLz^$qbeOV&WYo!cVg^miXq!vyttTa zV_YU)+$>R-%drjRko~u*jo1^5zw}8YUJoLc(q6l>(IEz?LE1`^<%5Jt%XZM)n5x!> z;Jc8+^*tWviKuy4`LGe~Hjos)>@7FycDucG4Ew%oh7*w0?<@E)9o@ax{5?P9tPIK8 z?>W!Bm?kn(wjSyd<-kzC)jeFWZQDLB5nFqv47CGD{(efDM{%O&b+uL{D@t*2yWQ}7 zK9`HtE`qCpAvXfn^}q|aX#UyC6)1&y5T*p1WX|!OmxAxUd|9|a)yzwMAeU|bHfFI* z(JPd0-Ty2$EivAY*E95u$8|o0;WFR56=I2G%=04h&Pj|>oc7=ujvTN1+ie`DkSwvNZ+ti@nPhDw!zB^x_@W5EsrGaxv`jmkz~0f zPk0~Iy}XVf;c=FEZAR);>;}!Hv?km3yNsLmArRr_(4Lj>x5R7g>MwXT0cGA1qxhCY zz#~tI0&AmLH}di*pmdxMhXoB6Vse?$Erx=2QJvdoG{u?-ILHD=UCYHWUH0^u4@GkO zA{a9#^3}JnE$3nXcYlKVCx3yDfAn8SBiR~`T9ATTUBsZm8d0~IFJEf~`)x-)>o@si z%!w8E^|o00*gaV_KwI4LcX2jvT_U@-4ao;|H_r@H0tyj54S|o)N75p&Fmq=!$o1aT zlUT<6@@!^dTa|Bk^=-4J(Ju|OAKXttMvYeCm+`*D&6yH&*C~VsMt6DtA*c;ZYqEay z43(NBjOKMB{uS^Jr2wv!vm1d;9#WG)W;B$V#|R>Y_*QKv_1|H5`Kn~&?u`!_CZaKN z!=sr~A#fg9Fey|HjHrj(y7_qI!iO4jRE(%;n}kP)a?qcb_umHZhdXX2OEcHuYBE_a zCUJIX%3%!Tl97VAJTq*5mCaw#uYo2if2^xo%|QyH)*80By@?nY{x<~-OJv!5X^=?O z7fXD%^diQpBDJ-|2fZO6*Gq=SidSCWYICvrl1Xuy7xZlMhr(j`XX+Fl1Nq>UhZIn9 zU6g^0R#;)Sk?M-yFLS4I&hP;gCxe0LtOmGsC|~C9YfItj^|D=jSRCM^L#uA6V6S5j z?z*my_e_}QwK)sMpjH>>!rw6xDgV42j>6pueyaa?yfQ|=ml2eGPbSzH-(M>l8xv8g z5~6*2BZpf=jJ#~aw#Sh{H%5>bg8aDX%lYPsX3or9&^Pk28@xZbg&2F~l+{|bKz}Tw zH~tQ|NZ{`Wcy}tdi`kx&Q7GhRx}s3?y&Pv*#%J7=@mQ1#(1G@$YNADib8YzGncWD` zapn{Ic2~tTmN9vH^E&Hqq8p~3SYaj?*t@YZ(@?%erC|OdbKc})51eDU@?H~hWF8=xW#OwIP=i@6$;p0Le zA5cG4y>`G}{i3eCB39mAiRWw#_jo*(;^Fmrjjm;Orx-KRIT~@xX5y;Z-uLZx8=J)5 zhrz`2ef2lX1sl)sJR0y~QhDa#L@!*duH&1y5F+`K-BcQFQ4romJf4qnU@!h37l}T* z5qt0P<;xee-f`xPTq|Nqcs-wpG2!FOm$A5OtplOqVwVrHs}Ub>$g3mx)$y14PyDPH zLAnx|SvAC$78lGsRGv^I#;XK8#A^4=B$Z1iu^19+kFg9hj?{(Xf-Ys5@f+f18 zw2EBIh@2^{;5@UAUnSp=5j++Y*>g5Al$`^%-b@fut30!9Q!0iQiYY~TMjhC1Iu=V2 zN68}wY<_PTXQO~j^4wG0kaIg1Dmtp`!Y^|`_k!B$3sc0jgTvqlQvWWFXkvCe^aq`^(|xA+7L13Ce43W-&A$%0d*zz8`5OKoMtysOIwWk zuE-}77{6sKH=d&-ltOyi@wyf|+-9F)vO1{dVl z+(8}_o@W`C1S>Dk^F*KvZ6X1JcA3&=c6BQ`w$qrEQAtiG5N|ShFC{lP-!yjOws0sU zTs))XrUgb7M{l><5HPoFMv+7Wj|EYaU)6 z%y;9WQNH^`dsCYa@5Y{xw1uw83+wJ9_((w zTT+Fsa|=nI`Fd^fe-jt!fRE%z;svymHkp4>R^;r`v9qWtnlq`&u{BA0^LfI~x( z?W~ZqJW*aL+tl<$pu*@WBZcRA4CHOb<#h>m)`GsaDttiYo|%u@p#*s=pyjiukr_>) zB%gOB%6FwA2~acdWAFTk$CLlB2HtV{fO)UqPYhy6>m6M4E63J3lwL;6pHY{5Ta!|p zbLf8lT&aSn#_oqP`arw4wA2-{My$D4WUNZQaW-)3cYpVv{K9*OGrxvBGeq&dki*ld zTz)M?%=>2$R5hdPTNe~VgG?O0dP;HeG`%(a(ur}Gz=snuAoIX9)&mz=QQwb^!sT+TgP#~< z_$K*#9FjyBy?Qb+eIVzIR^_~r%(k+aFb+lNC|HYj+8!Rlmzk!*eNo_!bD-750>I7| z_PP^J)87=BzM?&e1mt!g%}4`Uj+;7 zsz0((zmc@S=Q9(Gx!7?*yu*A5D7Bzl!UE-e#+Yy_zsPvNQ7`on{NSuYIDc*qtgfXX|M`#bxuE^_Z^#~S9#v!J)`XHq{HGatvvPyW!rf&6!j$jU z@O5?4ALgFU;XK890Zt5M?K~>AEWg7W`liU)v-Jh|g|Ew(Medx`wJ6u(?xnNjnmMyiJ9#u!n1TbeTicI-W! z=Q)g)LyR(N%=yu4tN8inuc)t^ z61Jsm*HYmw9#HIJ?I6y^(8v%bh_m!w4zxBdHRCB5$+81>4 z)f%dZQgIwF{Q6fv;xGS|zl;z!yp98Roxg9}K3u^W5v-aP9%GolSHCZNKY$b0aqXB# zh_?^RC_+A4c{8Hr5!5yM;_8ge1>h`_+b|cs-)}<{aV5VS_rQv;@4x?H97Ljol!G>E z6vFHElA;N2prW($t~v&j??W!{x*Ux5zlX9dy5Vx&E>eD0rPz1Z`x??cd|SRT^6PG* zVsm_1$yGlr{3_YUe!%VXfC#!joL&ywjKi?(zYv6da|zd;nSgZ^($;`kR0^ZN=GC%-UM+ zG}cy;s2LiZL~WKQ3KmdXR&q1v#TknB8WCb{+zo-^h1^h@ng5=T!X3-`6w4Odb4Fm+ zacNhJ4H?&o$Y|a>t2dJf5+Z6B3W?Jqpp-m(6GfOKyuW?l5dhSG`$zccKl~}a{|A3} zIEp*(aF#rs`&&cs0UM#ia&Ng+!m>*W$ z4*^{^#ou;EZF90wa>mDfN7r;189OFqjrQujNx`Rt`Du?M&p#x;#1n}aOMU-x9!UhX zTOf3SdmTS_%jz3lZgayEV;rhmSok0o<f~S~8R@KzDlm^f4l`&iFh|^>JCpgDEAPCBMo3J%v@$l? z8zpcG0efCuxpY^TdloZX(O^amoO5_Q9t)po7+A*lVCvxfQeX&gjvA}+`{nc4`M}wl z-1s>U9d&qkJ5w*55km~vi;4@K>qy6nExR0NjEo;fklxQ=a5EaMdSO~JLEO?1r7+R| zivEirK!h{hCRpsmV`(1f&YuwGEz{Og;AIE_d=DB&h-SBuk23pAW zJTXZay+c?`I$65EDnkj?a?s`phOr1LxsW7$(M|N|YvUgbb^g=s1pH8{>mU zlf`Y=E|pTGQ1_G8VU`^n_cYM^{8do)@Ox~;$3Y-(pRPOo=SRL3sT5n6najALm z(HK}o!{imF!2mTlY6az*cTAgAa7eKebXjF59Z7IWciv&P8}lg`p`9Or0I zLre(2`@8?+FM^luJ@{zZi4$tojeeZ33#rSE+(IK2_YQcCiSZ%eECq2?(q#~0TWfeJ z@z#YPO2ltCHZvk(Gvf0+2bq-pZEP_!nVKC}r@;$*Gc&?{-%-xIj7ptz2q_FRPp-3d-kksdAOJ~3K~$g_ntmsvyJ5?~ zB8AuSlJ8pQ6lTk&rScPn26INZy-hl=`TSCVU@22Y4 zzN>2@gzz1q=tuk}2Z{?G7AV*VlP||Hvb43JTq36?!YNAOXa&jD$L;E`#U5R?$^MX{ zRf;UzU$(vhL5rNxJbwL03o_S#d$Sy7wta!V`Zrxpj` zz?2FrZmm;%J|BzgI&)}wxWwrA|MOc*u3bBmHn39dJ6 zYULDTKr03L$S7LOZZV>j3a3i(Oz}>B+zow&9IMHLkV;&5J+_I4^Kq$o9fzdBQ>GP@x1Dn+TBPvC zHSZo)!kD2YcdJ%pt#0b8^}cyyFuAgKQ7!O+Xxtl{w|nQ`;spk5PlkK@wkw31*XV+j z7IcfNZ+iyw;?ytk%t%|(?k&89Z<+T!v>Gn&WYw9ffu6sQ;`DjlW*Z3hJP zJ(I%_0jTEJb+Oc{|Fd#9d*6Bqo9@UcRgKdU^GvJgd?n9Sa1{9Nt#n-jK;|IYJ; z`~71TC&0!};mx)o1RD|Vl--8WNZ9XqS6qfc*q3}fMO!M~jAgS5RrnIL@0NK<%Ni%- zh}Xq6XVN-a8{1#Gj8}^kANm+A4=aV%m*SjB;8qZ_y@Y-LiOh|yU@N7-1#!a`vu5Q5 zwrRt`pWEE^d2D!9LE}wo?r`R!%CLtPAi_&AzaTqvs`84mD!0?V4X18KBHUt9i#3>- z3d6PN(sTwVg~+~%V$;T|lX$+`bBy)Tfzs<}SnWc0L;~l}&F7GeLe=oNGTJDl=xYHi z2vuH+A12f<_CspStE>neB?_6^)_!mO%_W@CR=#|_^XN`Evn5xJ9%I3k@SM7i+kNji z|IhyqF?htk^*cC^6K5^L2a8eFhNK4Wt5u7MiEN4xq96R>Va_Q-TpX{wpz3T@Gn?hA zw1=>`!Cw*37$fRg;5}5dOmOFWl#LYv_)+}2E`3A}MU2Jz&b7I?f+m;4} z#C$TvpR5i7y&rLOwyZnq1qm|_;)skJ!Ps#@^{uh7=GY4OT!fC2OGEg*-}|3`vFV(C zD9f}nfCFNRh$$ctf!4xAv-%J%hoJXJF(4_#{N0z2$>}f^5FIj%%9vLNcZfNk3&H#9 ziDhV3t!+U@uDOY0)O1m`En_Gj7J~Gs%txTHlFZeHK}HEvs&5AMvP1Lvd@5qr z@qE5UC(&vfLB2DBMbh2}T$`0#i+9_E)c{qy<6N=r+sH^9N)3wKv1~$HxDr;~lt3Jo z3&nrK`zBI$TI(Ip$74}g@#1AQ8IOo~Y`}z9KJ@IuXTPp`0F^*$zaiLPqY#WM#93Sx z!@xf)=u<~6^)1kRn99W&;yq1F+Zg{@A!1exwXE;ezAO9u9KgzJ=jsQ>#*5P+FOP%( z>z+)#$v#%=xHT+AtMM0%Sh|dd^!u~|?n+>{?{|F9(2+-XZ^+IydWWAooAC0!wt|e& z0v0l`EsH%PE3oatX2Sa@G^r>A9CFFH@3-O7%n0U6Twlq$c0SlM8Y4};h_iAyhXBN_ z$leSyZi{$@qm+hfR*S3{(^Pq3uGV@>S>^hQF zwnGwOY=w=Du?&bHAZQXnhd1CU91sq$G2klRfrp?AFF=D1FF*q~e33AvI;zXrd$09p z=A3g(8sjoY=GssSMM>xEz1II{&dV6z_%6qB0Mfu^FFuLW(A7J;-^uNa(8y>N8n;v~ zd?GKf(*1_W=eMVDnDTuL31eq9Tmyz(7hs7l+mrU=6;TkeN^QNyKH$TE99YIuiJgrjYw6{*Wt9!W# zpM||5LH=B^Mz?iQ-gaqvS1juW63(jf0;eE@Yy!sg19kczCj3dV*Us}mYxRSF745wNuIrf)FwLo_GP}lra!6sLLUvT>~2erWDzoJw%rHhHjgK zzd#h;1FJ1sfywz4`gB|t!Z&)bg06KD4m6F`8HT_mIiMIW z=7&DyW%9wzF)yVQ)K(eBj)8NR`e|fsme)4qyrR_uDG>Uo=wqOiS4V2kMnvWLH;;%? zD8S%g;1rW}(UhhI!Eu}-8W?D8j_lTT;m<8Uv-K{H`@uGkZZ4I5rx+$02pKEUm_+pB ziGd+dJ-Z}>hN<$@fKrj1VB;U=1K7-758pvpmcsrv)B%vapLt0G)B{>$>x5p%$(01`ioB^H)8=YRk%^nrkOcIFw;^gm)^bifcbs&Yimd$;kiHAfjVb-Z)Bw8Wm(Y&t3XK_q#@+_MJ#&u}K6W=#>=A;M^5M}Qm1Rkvo z!k{L?2o~xr+ltZa1z`@6zZ2Ush*7ebH;b~WZ)xLAl+Uym3g-uHJg z?Ia=Z4kNE$e5qOmA@U1s4LJdOJMegHc>nS)gnRxD%d+uBnxj%4eoTb!i1Ck(8VX!JBN5mfS{`PK?+YkeC2^N%HTf-t9pK>*{$V4orK2tu& zvT#?jABSC#IR?30zT)NaiM>-WJIq=e=R&3^st7`ee3@4|SUDlyJDmnH@TL8a$t@yOi8$u z1+5cONC=^WLdKR~P&%Qfh8`07Sy4*D(N0$G0LYO!Cfo%UJDe323xUI`NmNm6!k08} zT1E~4(2N(;d*x2CR^*bcx^11q+*8i1uoAW4;$lihP;TGK;qP5Tsyp(MnWsb5I&$+p z%hAGg2PGgzv0UITI%7zIej)@d*dI9RA!t*OMrKFK9HzUJ1;@dSTNPQkWpRda;WIt= zC$_v;mf#SDlBR7(3);?zNjY^iIaT4o%`3=aLP}Jj&x~JcLnsyq5>3L~nkareVFZ)g zcL^e&xrL0@@&$94VJR2q!-_?X3W3-^aB%xm)Yu6*6{Hk^2(;rwJK3c4@%oAp2LdsH zJjR5*o=C*&nePX_h%qAeV@HgfBNxSgto4SYo_I*J+$tB52te=E#@K_x%=@GP8XYlA z>yz_5u)e<7{^7IwWOXMn$AAIM*}*{Vf>J~V1+rK?3^#7Ku=$)!G1j`v$;|~cI*#)& zMOuhl)P$7K>LJe?rs^Ev;PFl;&VTl&c&QQL-~H=2&L?sY=t}}dmAg?WFtuYT4<7d& zPvp$O&@lk=>ZDj4h$C8#tny+>Y#rEw;Sl3&=FuJJ$@e66

d7@`p2QLizj&|rCuF{#nA?9x>vkR6mGm#}d0|}og~a^> z4z%siuGQ`VFaD&yS1wau_4~_L)bAH{O-y{FV8E{47bj$W*yq5&{ja~#?e#-RNBX>< znQ^h#o`G!U=jwIZa$PPZ;;b*r(pNV?Vtbp)0FfZ`96FS7S? za+x|Hduj&`;y< z^3ZnniOO&#Q<7T^O(;j{psBl}Xlsiv@g%I1Pk4^KPzdBG-S;)LRPIScn@ zWG_;GROirn`0kw-^sIU6&lD@{)L!Z(^&(#fg>hKI%GjTvZys04v0zHXRXA}gk(P)^ zv?-8h79(B=4Wv4x;v^y~5ToT8PP3d=I!QxK-JOt^{Blsm>7Rlsa9xJgk~)wjXp^h& zz}Ei~PGQUJ9a-qizSHIxY%cGUI3#rx)9qO@bAywMn%8N8=dlrQCbA246Y9rzoRR)! zcANe~yLGl#Qs%E&q+X6mj_ln%dP9#E?eXn3aw{En_R}$$5zR_jG*We46b)C8*T>?3#fjq}F*6OL? zSdn8|*I;ZcmH@p{dyV^hNf2^r#Mb(_Hh<-Bc^2W^Aqpe>eN|Tx=^_e}R!zll{ z>D^j1Z0}|8>K)O%U)RCCyY%nM^|^FiqQuwlNW?&lG}?l9D=f7(4{+_s17*WqkYD5#HWbqPNgAZIktpC17oznD8w-&R!5? zu&jC#31Bs14+=J5WFzTPHD`jFLJKC)-IZ@kuS;!G)i>zzR9gO`4bRU2Jx^u1?1=6? zjLQc=MJ~q{=X_coeN0o_GnuVnmvonL&xg2YyLL}QFvNzSPpq8a>sZgwFLakh%ohLE z1!sYCWX=FI{FUt>M+lGEBB&HiM9h{iy{E5lkp9ZhT~^deF^>x2zxt1`->Q8QHhxPR z+ge0&H1Cz>I~2XwycO1JpvlRV8$2d=J8oHke^mP;xXo`#f)9r{r*&6PU$(h^&KSp- zyzxoPqu>rVFZsA|TBanwxSZR6aO?KwKXhLL-afGF0zqF6_->kLQ*=$6t(x!IM2W@9 zf<6LoC0v)WZmcBzN7YQFAMY?bDt+=X)jjV8(DBY9mPKEa8dzu+v40!Bfwcy&<>s=i zGRwUwY7fd+61d_EY@&Uw$=aukb{g(W^;WbC!g8stB0ObL6hp$rv<*-A-6?To!3O=H znSIClL45WdJicd}S6W8d%@Oo6kZq$$x=Wyit5sEOn??)T>P*mrkPi~iQR9AI&~uF& zhRX+s`hrIx;TfN>8d~~4dwNA^#xkp3TKB%>$i|JvBO5juGsb6($;=u%HdCIu@$~79 z*_%$D+%#_CqV(*six-at?al|k?jiW~6hF?dr_dw;$4>ZIPJ!o!Q~cjGY%BIt@uf>U zs;3{ZBfx9*Jg9{W@8ZwAFP@nSo!U-&7SDWuFD2GIBUrVV7kFkRVht;F?}_(+E}r>F znv22KV=mRLoo}r%ms(rq5+fPvR4G+{1$lD*Jlf@Eu>-|w7H$U;H^IxfT>W2{qhd{` z&1x1!(F=tRJUYP=`xakSfNsaXD#2Q_#zV%ZESWQ9Ez4r;v%O_k7tU-`AFEkd(Sou4 zCT^KjvzlemCzIobj-Z?PS}`{uHUM+M72g;vvW&Md#9p2af)X@OkVKTFZ3$5;|n z9)J%*zA8x*Vcc4K5s~O;lOb;vyyHP#?)X4>Fe!#g#5n zXYwre+iB)Px=!kh|D+6ab|`r)UB)-U9bxg9WCs{B)S)^A#B-(~8YsRc$v+~jr*tSy zQ}-p(0d!!Zx{szMs@v6Ed`ogX9o9=N6dQFzBF*5Rdj)$zUhF~S#eN5$L?|+)sw43> z*`7j0;5um&E5MQRX=T)!{F?-Gz84VOgzq9OyT;-qxF96ENY~)@BTt+~j5)j9vPAmr9pcS}1ICtK8ug_obPQ z!xi&}*abbb{MzWK+#CJ=*ep_P+qcd8rr+)P52wDW#a2ic%{2m-uKPo3Gp{}|XFdW(lx#s9tBdYFVgqjo z`-3yM8unWwJ-LI^-i?PKtXIpM{B$C&hRpc}wPPk?l$s8K(3XYgX>nS7c{8qh37Qvm z&H3oS$`dnb)~&n&$HIdfZRqsYI(6;roF3EH$*n%Tvt!NpPkRnf@2=anJ31&eplQzV zQPg+I&@cK7nS7uCG=v@7gbzUIVceg|6RX^U#OGqDmSQ6Rviw@>reE*afAY?!RGB?%N&W<; zyM1a_X~Q<>CSAF0b~#!;Ccj;D>(a`uY3CZKmAOUprIpJMIx{vg*DEt^;Ou?t3XUZ$ zUcWfiNm+g@W6Y?mKW~oqJNM|d<^vOYjvm*R2CjZ{!X z?&B}~TVVF^$RP}7?J|NN*~Vo=z1_9wDfAIO-(gAV!nv&vN2*V#50)6?V>%qA7EM-a zotdpZ`nW>A?3Db=;|hJC0*_p$eko4&2O%=ugwazkz+ug4Kz zv6q1F6jLH|*O#%z%W2eWx(sN>=vY&!QE@PM-QPaR!V07=#u6 z&Qp2Zx^+fO;?UH=sR&*tjEd?xbkykaIh|fp=)4B~qY=Zt)~= z>*Fpzt>rOoFVCGdH>r8^=;pKy%c3N4>%BODlzfF;F&*^R#;@kE}ez1yf3-+mH zO8h+sP}8b4`C=OrHvZpo0J(SUpK}21E%EJ~=KCi7b9h^S!aR52@PCSL*M$x?7IMJ@ zw%R{^5ksiqob?)nx^FaKb(kT*0GA?M5ic!7ZYN|4|~1BIX8I&bA=mMdgJEDg*-LIod3N(vzpeNl12H_H z#3Dm|JVLhk)OSnuJ-*H=FE2-m9zA}vd3P$yYdXFu!$)*D-k_V)zd-+v_yUkXhz<4E zD5O-b)+GL=Ulm4poxy$VK{mV>30^#_z|x1#CeyU?@@dkLPUAb7-Pk*w$9HBw@wUs= zZt@SnNgaIeTC^=Bs)iGr;Du(jirZ|0*rJP=lQ#KXh*4n4EeMn67`~L*6<@RTO8#Nj znt(Vz7uU9415+w5@-U`riCt@g zTLropI@V1Zv10C9c?~cbPK+Ff>>^JNz!;swTiNXAQ`@JHseF!^0o$qSXMG@SPao*a zt1Z2^S+OjTtf5~U`dT2tIe1{f%8oF3Si+|s{~v2#0w2@a{XfrLW)dWsB(hi{8;L!L zBt>f}s@7Oa?SdwDL1`w0pq5f9wxVilRqZAtlu}DeH%b((mbQvoT18*9Mdr!>d!9RY za<8TD^8542&D>cs&vKr#e$P3G9R=gG7%SO9eKEpZF-HSb3Gp*?ns#(F1#3_kg;G*O z!^m4BepFIVG@*d>R9jThivDw3-{hxRwVQ3IlYwM`yk`lR~tP&wZ(z+7fY39 z?a+dx4)bB{%lIPGH^aTQtj$NcW%J>G|H6-5;&&nI`eH32v5!=rtpO}yF-?=KGl5!! z7Dx*~Dy+}~iH}-kp?3I{6COps1XAq`K^a%YNMX>&6_QiTplCSj3QZ*0sJD3}qXxM& zYG@Qa6^ru_pv$YS^@W67aJEsSZ*o1D;1y5Re`e2=*UvU;_I&4^K%^9BLu0Wk}ek^H@nfjA?9 z>du;ZmFh+M2Rt46V*i2y4eVU59>C6b2Hs)2mj099Xh#i_-HazPUTR#oFGF z2Th8+K5L>i86LjQW*b=F9YL)6jaLI<{=!B_kqu)32I!LpK8n2wp=cxdr)-bO{@YlfE`ncls$;;Wq=22t8UVHMVU&|S<=~{*UeBq zOehECP3cuGTPcElQk?<=&X@KcvluJOYACo>{;{N1Es zmnQ9sqAII!gsue@A%O39h9R+ z;-aviH8dtY=0kclCvDg@vDnsqN<>wk5O zT5Ch#&p*SVO5gFivQ_#Lx?=#YcZgI%T@zAB*j%pOso=@q}FWNA5Zk|-73C* zV%4fi$zsmExPz?$e+;HLYA~Qq`u7<5AWS2#7aRT^EeM>#dOhDRE-|WZczC7Ob=wWd z=<{^iQ<2F*{#}C0_2}5@wIuQPGnAWBvHAo4ek|%LSfJhrkPRvIKvluggS`P6iDIL{ zq*e~(~iTtG+Ucg`&spi?qf$jmmJh>+{ovFC6g>OluL4` zdIPcG(w2B6;>$Hec~);I%o_u9B6x@I6Tv&wqlk@{DI^vzy*gjwXGTkr)8)GvvU&rt zF)LGW6?qSmWfy;&ohe=`_5~=%aAbYztK{_6A2kiL_}YD=eCzl&_3h}J<~z!FvTvU6 zYTwep&xmgg!TiE>pCgvg7`NQj?dgUubZPWV*XL_QR;pI5Qe=$_4cfPFkkYnoO1UbP z%STkM44QKLEBkn;S_GO35q#A<3ReJ1dtvoZrkaQL+b~Jl#~S1PtCjtHt?Jg^4;Y(w zL0kby@5K8PtR zJN@GtGXG_(TUk5t5Ad#c)o?k%x*U(lw}u>ie4mzU?p?X2rE_ibY^!YBZ2N60sz@2Egc3w1|`DP1q{x+$P68(@g|Mgibb;@zdQ;hEf8jq-X<#tZTk9uTit}@Lrd(_MXak0w&FkR6Dh2^BZtJC zD5@DN3KYajZ(4c1iBjkoDKtk#`6pUe(1Hv!l|?Dz*|XBf&KG~*6ff85z(@oxRT3Fv zDhzLA%DMXCQjn|8QvupE)SSYZH0qLd>Qb^k1@&b7jFXoX4M~%Zx$AXBhWQ)m>9RdT zw(7N;sD^_Lma!PmzmHf#Ko~1>3ICi%roUzteUhcrD4|n^sJum~jlb`Q9%+xxS2tZu zw4f4yG0p}4CY%HcQYJB$gkLr$?dPF#kD@?HaTm$EimprSN9l??H=~dAmejjXhU)$l z>)iuqq#wRJ1o7i|bXpVNZ*nzx)!Lx4LahxV?Zs8Pl!zkW+{4ioWb$6X$wdAPLx~b+ z7!58l3b86nbS&!c$3_vrAvzI$(Lj=u1Od`w2#JAm81;5-$@lPL$-w|e`-n9M5XhmN z{_F2k6TkiI&ofN9!;fG2l^;KNkR|+z{NBC%$D*aTKRNKP+XoNbk_Quw=3rjFm{&Qy zdW^}&2!}x&t{+l8ZZD?p1)7GI2_khplx9o#Zlh@>9E)Ujz^hvpDr{_EoJCXJ!{B6; z?pwG2=-@wG&%VYlInHdeX0s!b@AZ$RI_|aCls#+s=tf!7^d7tN)WteY%`|9CTtKj2^2 z8JpgdJ@@rEwDs-F*YL~ZPVn75)1k*8pB=qbJ3teoeqCbFCW}L?xNd&vaB}fBJ&TZN z#^B6#`3Dl#%vC}BqLS0$rdSmS%9JG}d_puik?Nkpw1}R^S0;a*RHsZ>Kwwy%3LSg< zC2bu0@!7M7#;i~Bcjv5FIc{l<>PyG2T%|NDIy1P7qV(}A)n{wG`|3g z@NmO0GFs~}fy^EVW6?&qQb2O`$pG@iGd%?p=olqQop=2_r0?uSe}9>_yRqZ$`X%$0 zygq4Dt?eV%xVF7LPd)tYhV=Jp#eXsT^PihF<*K@K>n-<~yjMrP=bBOUS?jKw7tPs0 zJg+A2FY=a3>vdO5yD1o;zMFzUkt^3%_GIHEGK>%SYUB;ct#bHi2OpKgsw0gFM&vL2 zS+-B9P;@#MAR$klr#Pq8(c`UzZuG+`s6+oIofVN8Y0TbJL|oq$ss;7KMKM4_q5%$t zG0F+b0ee)ud7+ec;0bLe$$E}xoXF6SLgWJX4H>7Pt>*iL>zbI`%Ia%6_ zO|I3d;7wJ@trK2VxKYCs3NpiU!==#${lYWDNk1S|roln(lEVcE_Hih1XH|QCR0+}H z)=7*37(^`zzzpL~M99h;%7se>#iQbejmaD^{Nmvqf2-1n9n+R9o&VPE-K$n@T)JQv zg5dnGornKq)%w3$DJHkWf>j%4SbL2d)4g}bOX)+?#=Y9#`t~}~LtFDv@(S#6G*ARo zz1Hh1)i+t-{%Ojr5}gzyriZrLRKOHSW6hq!&_e)Gf+Ii^9{?u>rLg$uBzXlNJ8?+f z+~=mwVvBm!YCOE%3mrc?oHd(uk=-p+XKOAm|8@Mh`6CAnSRVUgxxp=-diwaXu`F@} zTcZ-t5&5K`eTr%Pr}@z2Or<&Lob12Nhu)Tzj{*XdbCy>@#NvarVP9W+a7?ND;oI36 zMSp4WJlQe>{M9aSa#U$!rbai9cX9e_E>3^wn#eCL*yg|ApL9)sXqd2O1P2C(&oJWIKs2)H?l48Gk`qaN}ojUzT z(GBUXP4B+5QF_arvH2bReoSMBmuFIEhu$P#0jmi0v>OF zgQLr_wms9?if5v_wk%cMuKGV!Hfv%W8&au#qF@nO_NMW5^qrhmi-b`k0>I>5Wnvbv9 z?;2&UW)xRSFeher)*{_b=Nn!I^6=>_DNLUdn(y7k`2FX7iEk_v$8<#J z9`MtBz4`5NQ#!QaK+nA~dZc4ezH`C0vBUcU<2`Q#wTww1tA$lxP{rSRa=Os-^M9qPNGtN9-I#KYF!BPUO* zorEzZ#@DC12A;YAA$sj3`TK*THa_KG?CwX$FF97OSowDKw_aYcMpOmp*w+2M{Fm>q zOo1`@0I1?StNHHk>AxM)Xeg7X%O^xE(6go{*)I|U^-=46n!u*v+8}0a%<8Ua0-|G0 z4M{`r+agn_goDSEW?DZ;dd7JP^^@M2vd($vqa}0M;$F3y4DXTtd+|M`!x5Kt+A_YY zy6e~Az>LBD7R9_6-oI(1My0}8_{HkiSfZ{^3cQbQ&C?HAwcvSU3@)`p#~+zN%1Hrpfwx` z3}nIYyuR*Dsd3WOx(!bJ@a1_x-`9S15GH3H3w&*2@ut6d;az5tdSVQcWi*db{V|4c zaM|vn>YY~u(7)TXM_#7^z0I45PbztsK*10m$j47)!6I?kQziit1ilrSzyU%ldTZo_ zy7R59)C;F0+oeh*+pmfvv-C?Os(^ng{L=%tSvTpM`j^i#X z?SVN|MYg?=7p8qP zB|Vq$HjtqRq2mM^g+K7-1eZo^0Ot~;2X2}qCuq?s*@!=A4gvv%HXa|3sY>eV(&xKK zZ_J;(G<(UEym?ZW=chJLJ#u)8t7^6U$)A4Np@q`$HGVViV6o-kSFAEWhZANwIFAL+ z!U?;>k4~97bqcG0XA@%+#5tP|SvUncVtM5Ack&_uOpq4u>RW^(Su`7TDM6wK5~4 zg+C-)-2;D!r@pk1kGjDiwno44Vxb@-jgjIIQk=j4E8n zWfI4CtCSoXRw|}!ozyD)ii2N@?~o7@RVpkrsZ!VR_4ie_R#v{v8SG!CuUe{MSN9_K z2C0WMv}?msYTq*cgL8PdQKQ5@JO$iz70_5H{Mhgf5EnBMmhKf6uZZ$A#M+UrZInP2 zNGoxb@*@NwH-!tYqj|(clE}BJ^bZ&tK;dIku6S>GB{Pe)y0r`}=4rkWQORX^C~1-aq#bUWRZOV4h@#b~j^8*VykaE?clB!5D;3wY`Dju)=Scf64Lxz}i2 zFFt=<*NbP;+v|NV>RT*63D_^PB1aiCW_`zWPotnsUG}<|FD2YlEEu}80jUJUYrfGX z352FGkdI^vgY}3BmLyX|%aR0V6%^OtV0u~@@yZ1@;+F?Smv{yDvEaZ1e^slpZBbyD zT#1b+*s*gvYVEK5^`nn|#b%!5ZTZr4WGLrJ3sHMN=fm04J-B(mn0+XA9R#$=WNm&X z&#%rbT$TXg-$iB=b-^phwai1tp=gHZO0^*54tWHr1jr=X^(k6cNs8N>(nDw;4dh9{ z1;Y`>d{NflFlAEKy>mqX^O-C*;_`iX#3~{rkR=z;Gn(f8-l6jrDkhKIV{@{LcDh1CFjB$I z$+ZpDQd#Cc-h0QOn|B@CclY0oLW`}$k@~S*g_GC$K(=D{>I&uDjlJh-FJC2atlnBb zLdNP8W(w+=R6Tvb#>j~iDBn^Dd+VWU_^t$!8pVk*w7pqaM1+BPGzI0oRZQgR zZioD!CKZ$u1X)NcWjfV5X%oXS*a0rdSI9!ijHP-cD+q8*;gOBS1Mik9k?t~V_?7z) zF7t}=aC*FB`}Q3m*Xuv-+50ngGRnO;f7Yv8Nhf}uuTo#b`23$RKHVI2mZUWx6blJw zz*B0W7bk!Sn1sQi1>s?BP@XC=8K;X{OGt3_2S%&8nGd!N^&8OT9ea5>_U)oo0W?57rJJbgc!3UZfB>s9WKW0a4Lns2#I2xsPcgbGZ6Nou`6}vAaxf?FhT1{8AjW- zm)2%&-~mge2=1H5j^t-;VMp?~k5p-?^ntsz__-w=K&`=r;-{(GuFVfMY?Xn~o4o#5 z;eyp?p;HP{=BpADESIn|wOqe)ndM}#`*Ij`0xm{A_dob!jUD{FC>`O=_e96wl|@4_ zD)6tgn>}Gp9zS>OD}EC7+`iki|C=vA+qUiF-3RwAKb0w2S^1;an4eO2#I_pot{I>F zaOQ}0&aU!(?r=e~yA-jDNf6MO3I-(fnVLVed4;0fC(41VanVn2{c z6Np|S*orX4f$EvmWkv+c2{0Z5z<6b73#2bp!}pSZDnPGPYWiN2=gn)XgXtPe$C(44 zBvnA|263WXaJb(H_TTh3E3Ge&V(Wb(qOD4XCaiMitRBX6;c7Ip=a4q;c6kB7uD##s^icqkTIiS&vm zMqViji^wZk&d4^GQz`%?-Vv?X{;rT+9{Txq)`9t!&yM(kF<$(G^Cw=+Ea%Is75VOa z_xT5>PqS9{@3Gc}{7BLB%;)q;=EMIyd79sscWHaQldn-nVvYUC?@t`qRMJORd`;XQ z{zTxMP^tiDotikC*}h1l0q`d<8tD^_q^!BVBOW07a({=Uw!Z%XZ^-%y8ruRITY~Qm zws`76nmE5O$MucYY1PTq(SumJUmQRzrsi-#nOJ(K#m8!rwz*a zLO&H42W!ZBNo7&L{fpJ$r~h?>UqsQVZ}#oG>V8{#>FU0H-^kajr%}gu760{j6o^^# z_c?3+Ar^P7e@4}7tm?s?(8<1q-TpcBfDm{c-hPbEXfh;pq7{ry*VbHqn)-;m+N7KUft3elP-a>5@v9pXjArzj^c$HH>g=!?PyGIheR1z)NbM+1KfTd65nbo{*&7 znzIqCpX)#`{s)rO1OB0vRf-!~lJ54Mp48Eb^i?R;N)wQtA1p^tmqL@0AP%%1Y0;S& z#Fc<$l}Ru*w023Nd>gskP1XkjWLjx4q1rPo2|F?R!W7nX9-8Z3VS63CCtJt&ez3n_ zHOr8)57wND36?rc3evA`xy^=Lh;7~l#3!#(h`KyL=A#&?s|ACDAxXKG8 zy0JVVIbBR?_YCc-JxLN+@f3KKMb-gg(C{#aK|}N8KqCk$bv)tb_s@Js!GNEaOzbNu z+wzy6M%my`2Cn~T--h-3_RIg`w@yW06S62<>W+r@EI_-vLuXTDaZQFVs{K$kQqm*19RQuG^}f zA}?OMrb@IHV~^gz=6-oTz1Pqw-|pt`v0gJ4E}n+p3A6K-FXg`~4d>@|nN+dtygmz; zv48O~g9r2+`jXVYPyar|C*H**8e{xsY^OeUT@2IFH&|oDD}{2`*!_b;S}va~s)aux z_Bn}vth5#D;kEAs=h6S7&UsAs65vuW>!D!4mE#p@B;xS3Ci@ASn?i;YsT#1O$e#-l z^J=$@(m_)0DBqDqCx`g5IlgIarEYv!`taZHvYACScpui7f6U&MI-KGcdduk;Cj%W? z)FO;CjH>&Q4kXToK1x$KP_P&M74M4BXH2$}?o)FGN&-_F2o8#h{RRC3GXnv4G%O!k zPiV_dMhg-^F-?HO%8)+jv7X{h<`dw$-{v{y@lo?-c7TtZ&j!wSEMNl{^5N{DyZ{}V z%FvH0)s%dB6?T?>+<&@HtF#{sz0YsR?+8pwe{G&s3C5z&MrW4!24|70T%gCEdb08K zc=U>HEfJXiAFL$`vdeD_=s9S}#ShotgRQi2%ABQh7ryu28@V%HA4hF+eqFb_P%fW3 zDW=lY0gK*$f4Mbn+SvZX1`Hn9r{}0wdRnJ%Tq)+Z7PNa7duXKUd!g@NvH^RRa#=s=sp7qV6dGn@;QvvY}e__ z^1s`4fk2qVrlizM4h)pfIe7A7XAP;!$bn+HPV!m&V}4;6`vI+21)pTZC)Fe|4o}}q zu_O98Oy|w(*rg*TmR6TvUZemp{NNcdM__Hy-c=!YgRpe9q-p7vm2Fz&u=0$qystHD z#d>)Gws9ycS}f9so zAk!z8TFOwn-GX^Ot9-DX21D5kIu>SweAeOK?I5ecvwam9;ZF6jnX%3K*d99^3PMXI zm@@CzL~CCmr4IIFLW|}B4S7N8^J;Kc%%s;;tl!1t~La}sJLwPk{MIFa;)9?6bPcE zvl2y^f(TR#rbO^evKpnNDulj8exC@`CPkY-shLMVOzIh%72CVP?qgr=YS5>0R+S#f zyN)VZOBSYdC|5BxY2o4`mbb88hlmR8>Mxovm8DLk0Uvaly>CTM>o_J1Y5*K3QLq@0io`XF>B;Zm6}qaOB7M{A23 z=Sh-;h=zb(>1es2#fhU?uP=XoQ4tE}guF>MQ*vat>Zv;$WnT|i`(QEid2eOLnX9xSiasPXL!t&{on*6KyerqdypVWChx(TVIa_pVdi6cET7R zwZZjKn!sJUDlfM5|CbFOr4Kht8>{pHJTsq0i%|z^qjl3lVof1y27@w2CYenm|R7`q;9`Pc3%gAFP+d$$7aFwO2F>dFI2oq*oM8ZR8 zPt6NWj1IOAF*;rQLLP2XG!Vs-I(F-DNxl8fsr&a%ZM~{W!{5(Yy+xLJC3Znlx5!st zb66K2;m3Zh{u@7bVzYJHTi3U#>FUNy*ng}i?C)UAgZdSFu;3ZBf zvKG2D1s{n)!CFB~gpBCqL`s0bk&Lm*`3~~vPGj~_0e_ zPa@X7{KgKxr*|&A5783X+lY+88}WtltO=01J*PbjDN1W1$QP2uH|6DeB%RB|^zb zXp<_n=3j}1Y^(F48=;y+%W^OF*IKjf-tAzC%1OReG-xYB6=4RbrKXIN{?t0PDJL_2 z`ib}uvy8-f`d*wT4@Ss@PSZ6-wu;Rbt4)W> zy}$;So_@5enD{ne2t@mW`2I#5Qw=o}z>!)k;G4TeI zny=4COiowk4N-i=QXY!jBZm541@9}89-aK*i4&NNP^ns3D>Q^v`YbWYatRUW(8V{4f>nn};m zIhvS{J~^Z9=>*sU2`t7MeI9*_TriB*o3C~76`FSQ;8TiOgB-+p-3+-g1ir~A6Q)m( zs0gh}zY(gxexuu0VoZ~}4f5!sg!HoxIh+4Ve$CoDvbLRe zEOO+ooUnA_gk=bQ{&w<*VMB%t`{AS#^5C~sn>Vj2`K^r~eRtK1n2dS+y3S*=S;hGE zSN{KwU%hx_?a+6s)m%I5ox@qvhL3r}F)MTAERb-E!^isd?c49zVQH_s#rzd3=9m1Y z@k_-QLDxT9%Zal&R-(*SvG^$xV2%>6`a@BOI5u~i&#Nm}VUH(Pkh7u}F{;Z&IAq$Z;3$CNu;YPsKgmHtj z-zWy7>`q|+0C%V?jw@Wvi28@wVhQRdg#ZesgTWGYxR|E1bVSwQ>bI{ld$2Sr{EJ=t zuSh}e8v+zIN(YVcdk84iieaIw|DQiucO2knu2jxQ7tk;dY%JZ~fZ|K2FAkcV1{oNy zuYs7UiSqOtp&jUJpw|L3$_E!f0VMAOAy!0f70u&n2#V4E8#Ekeq$o}bU#*b+fU!Ix z9<_3#T3Ko-o*bHqtkQ#0x4!nYUw#k$E!c5hM}B{kM~a^LL%k1OzQ+$NT=Zf-zY)^1 z;5V&DbIcW91}9Jga@L|8#1c?_eNRO@Au9C^_j)WI@ymJ{h{Y(+OxlPpu*JxAHQ#0R z@zkTt4=I5z6FphQnZngyc!Zx|?(leZVG3CvHsh(gmWcw1zD# zZ7xU#UV#_|ypFhP^Aaia(T|-Mc8N7(otZCf(L%9Z^Z6N=D21NgIw)mB*Z1t1wr}p4 z+OE<3;N?~?W8WfRcX_hL1S#oTCB(XZz;)P$n38}s;}w^$pQyZ!vOl1CuxI081}FuR zy%Oz|IgFWz9Ogu948!RT!5$Idi4ceJl!Qw8!_g}*ewWTWD#Lkd+IJTnZ*5#t%3)i# zahX&(m<@DSWjSB(lh(R>e{_;hV>$0lx4VZ*%S+E#3uj>&sj-kvVs6ytwj!jfac=tF zndWBNA+JZlr>vM8s=8oqFrtl$a2P$~j1Y4($I{3Kqq$MuP^`#M^-e8>B?d>Y{QiWM ze<;7rKRo`uW5Md?rLt^o-pOM-%ieR}|K#hB*i|0RK05KqCu^tMd1ZE?)bzEVNSzt% zGsLNZaRs;vxhK^u^R;s(PLsZ0f+6cS`q3BrWpZ}vnT_I=7|5;|+DTim;MKqu;cVIL zq?aKOYBzX4QQiSCyeRQ%oY15Vb-BUYq94Df$daNxPEOH|BdtxU92)Y-{_b3}AUml( zuZmi>WyCgPGauPxWyWgS^Yle^-8~Vz?v3r1s8+7^2==-%vO7HMVoFMh#T;YxjW_Y1 z$8Nk>7k!b?b1ar*7_c3_hP6O>B+#}V9zWS3-(ihg{Wno8!3(}c_^%#d- z&||hf$U;c6e5lb$O)No8oiqf6>wa+kTpMk0S8Vy3H0js`V>JSoHAXB&O}nvan6swc zS+CGpFQKX5xX= z*rI~{wU5`9sQOv$$l3|Do77hNIFm>w)g!pS2udrlT7Ehe#uNukGb{;5E&${xev+bB zNjrCj$#W*Yv4CIrzIm@s!<*FVy=cL_rrS;&IXrFJ!Cl*(d_P<1DWvB7a>vLm)#J9$ z{OC-xCe8YXy%@c?@9=T&&U$OnpanB>mSr%-Q)x}I^u?MEx0V%adR1FfA-r_55(KBO zsc=^k;{?~R8K?$;Y(sRxRWnuy<(dh`^>hW)5Ni+iqAhEfaS64>Jzwuuz0!S}MqBFH z>qXUjc$rJyV;|i#_|f9%j>W$9MuiC3h?q?-=@0!(nR7u(=+4ervC!M$Wb&INQy(TZc zwq8}&UnAMepifwoNzh)CWnNTiY{BXQv^So#;1uc z%~GdHnf`u#)KX2m7g6V93H8E8E0?W=1xe6zlTC}D#|uc$fP_UuY^2v1v+E?AY`TS?|A;CH3c*w=NBym=m~st02>DZwF>M$}Zi;uSnPP zvV$GjfjN2CZ{En87&u{kaCY8JtTWYdnSfpid&S&}Gpl)PcMEe8k6QAC^-)T+F2$ss_0b}-)wah)JiCLW!vdf z8?BB-a2csh=^VeD+ z^8IC1>ixkw_rdpfZeGQ{r-uE}sZVDw|F}Of0#5bc?vHB~?Nnx6;5unjwC!0%k232+qWlMY;%XK`9!Jxr z;8g$H{lIE#UJx>zp12>wt#2Rxbj^tOYSdUe{GG#xR#=BmBj;Y$8!r!=Hf`9Om8S4J z4O_Rzexx#cCXasVnb(zPB=y^){N}N5`{CcW$5`OeZ?PZmFXK1gTDM~Uojdbatb2~*RtBLQ>Up@`PqNt zU`Eb9U!ZIPF1wuGlS8P&V zP~;M&n~n?oCY-6ivj}u4{`RB&SFY^ufEJ{^?5rm%^*i}b@1M0g55s?Y6W&wObf?!F~*r$AOCdk^p-0qma=}rI_I|atuesffvm=lR0>6SI8iEP zZxP0ZgnH!CH-`Tz*y8kuVGrS~o4;T*s;vr~WK~jB@slXyUTTK0IRD|pnLqQNl30~< z{Kpg)dt}-ltV%=ZsLsv(Hu8M-#-_fT*z8Sdo7iC9b5q}qq;D0ys~ji}Q2zvdqYgEU zWx3>p;;V4b&=Ebv9XyKhk!qs}Uk=}c&*Z9M#oeqS&=YG~TxIN#poqm8K1j-t$osPU5SBdm{hcUB(rzSoYcGh^9}j!$&u>I?~Ko=6x6KKimn)&d#qZUKW*&~ z46={K)0vxLG+{RP*x8L6sOP57$*xWBdmr!1)ZZtgq%TGupAwI8pKs8Zy{^_4yw2x- z8GeYpt8Rm*nA(&!L5-h&mP|`7{ySetaK4n_91AgPSZ+|Pu`ajs1reBg!Jgl{WLl)- zy+po$T=Rz;p08Qx9BX&hr)z$W;rXWvoh|J7?Mj}Z!N!rMs>hQ<9==B=#Xr9O@caMW z{lkB+s8~`)^-CMANQ3Lvt5=)-BB`U((#9y#kUEL=YIhQM^djyO_}8XecX!iA-CZSR zbXxz>D!sXG9ex?N{lslT{knCY5qD!$X$bBTl-t(SL4#7QH5xXk$$ztU7>vg?8#JuJ zeM=s@@0C2}m#iH#GCJZt4Qi_8_0K-}{UC3P&;4r1cOHz`kYe!#E|)yQm4L0PN@d*< zt%^x-R!nflCpZ!AL1|PvXeOISuzCc)pw*&ycd#5EoQMjOYDg8Fxg?dPR0*@H%!USQ za=e@p%))|gGOtm3e7}|r%4DZKCsp!8bEtI>#`z&Lucy3RV$E7q;l)MZu?JeRxEg_r zntdww3tar{;ivui7Q{#2@dwmnH4iM4GoV!?y0ESGWi7(;i{1!a*79@dlEj{C$xjzu zl=z-jtOn+%$MOb>Sl&=gJ_*l|&TUNzzE2L{3DCJWd{^ebjo{%_{s$2}WOZg!1P_Vl z+qV~O@x<>W%H>k>AY<*=8xJl^SkC$!bZ(6P-M(4UUs-Bvc7LbpWCQT`SHVzwMqT*O z-+x5@{`21_&opIyJmdb}A;o8DIA+#^#=nPOQCfqhLM<DA*wk zK%50^g|T!7^btdp1hd08qw-!^NiS?d;j3sWYkrFPvE*OBv$A!Y+3jyni7MyrKlso5 z(nbEIBK3H%|LQe274@KX;J4*X@HT`P#%ZD5_DA`#h1c!&hFrIF0{RrBBQr$F}Y6dl(x2 zG0P6nLm`G-)`U*dPpGg3^cyd65IfbqUasI$qHeCI)t0Lt_1iL*4`xa*8CB355K5<* ztFMHD0T?R%7c~PA6I2$VHTKOV{JGv4^Ru$%XAESM5KU<6woBXj1y;%39(RLTdB~lm z81p+Aa}!LUtX{X(gm)2ReuUs2Kjwmd!I{Cp@n;6-1`~iEgD;pDyeb#~{(nCQC{dm{ zfK6f!etaF9vyyLboAFw9_G=mKSTsNzf4U3Vts6JA)_Z^a!Omm+oe&=xiZ!=eJSYuQ zl+WZuHLbZG(scPqo=BLhA5spqyn|eydB{jGL3t48GtR<~k$W42L!$;xlrmkZ$8oGY z{_`vzD)s+NdS<5NUMEeL-jKGqyMUd$2S_Vb6n2Rgxh08+Pu9V@+o4?vnJUJuFSQuA ze)I3fEm9@4B#QrO$kK&%*?g4b`%pFv%I)b54k;Z5YmGWIwgXseKg$$t%wl9ZNt@`~ z6t?%$x225mSnKs^wxMDJtl6I)TdM{~)Ue>#V6y`ioCT;6T6`jX6rOon?&OZ69+X+K zB5lsNzmr-|Vz3xD_^3*GD}FleLyTKrUK5Q!Vcgoev>@jQ+eNu5G;-vsKrJRxrwPo% z*GOZ?{r6uCJ4|XNRpu{fSu9=IFN2C|X_+iyy|?q5HtK&9PIag#cnMx%0(%L?g&dId ziZ^a;2^6juU^UEMXIevJ%rnds7yvClhE>x7D?e^9G3yOlwST$!L)<#vSpOe9+X|o+ zbO6-f_l(`-6wnW#7`x!+6sfh?MNuX(cH(mwa)7~iiXf9&zQE3Xb3Ha z9c9l?GK?01ROnr`OP+C+lWUV&6JJ~CXrXpz^+IQLlsoe@bcUz|Y&KFNOcdGhC}=Gu z1rm@p2o6gL;S4~agQ%FGR>~+uT|8u8=jT>-<5&3h2ZycF(p}8|d}6;E^H-g5xqf)n z(QsNDcjsjb$4^@_C3j)@*x0CO_Bu;A##v`oO5?vAEkr8vhqcn2xt>a5h@VmbRUr8(wwfq=YBy6| z*2LswWpbA#&!$Xn`3?GNEwc8V{K@;3TSkt|dT-Xu4PD#UN>5pp(fP%+%yjE>sbwlw zh>Bt@|7`yiE3HcXPOeBj!v8K^rv0^fLl55J4-OB`{jQzAKRYmN(U-dxjGX#eN`r&o zGqHS)bvVvzpk5Ke#2-zv$a`|ZFN`@lNX-Fk%vg*Wb_SrxqKqWu4E4+`sTcyNd#1dD zcPXhG(k4CqL4}gaA&6HYN9qR7VSwHT!^HbcVP4&#Ogzk>?NPcAJo?5l0q=)MfS>Md zC;dqq8Yv-^U(8zbQ_>-RUQeNtPp79B<&`8+F^gW$B!YU#6Z;ZDW?hz;LP%o7#2i8- zQ8g*VT*MiGA_ONitTwW#ym2Gp=R|}EV}eSjl{o2_^i;;Lj%-Jd7q@35*B_`CItlPm z{<_Ns57Ek}d!#~FwddF(AW<-9SPW5`qgUgo%5X}NSWEEaJ z1GdviuqR6Vdg4$M<Fh(xdetFqxewR>MJ9jtj{l~v*A zWt%@`g^9k($^y`zH!n?$Mqg9!88oSHR*OicN1sIlpG9GBS~YU0crZ)|QUCxl1}5`bAB799Fh%4a`U;@M{XDg|gB>lx^hS z4_)>XzxHfOj|T1JPSt;e(tP%N_!IsHAM5}=7y)FZXO1R7vv-a`77>1d;{?%9c%2OZ z2|@s4j!zDo5u*c(15cx_>Dpe<1Vc$IV1hEXB#esFORgjQcIL|&&6<@j-uT%ixAO7I zQ7fNHd}dFc=ma}{T?ngrxnAg7IUR=te|pc*4OVu0I=>Q)@8Cz3^+MMeqMb)!Q|Yv0 zig1`3&4{@Mc~lS~#`POrz;B0!jc)dstiJ)|C>WYzG!2C!C-i7(IC}dgUek?3{%KZL zz7#)8lA|Q39G49SVjI{pqoh1iPcesgU?*M{ItO@)M|=z7(@&>Rk@OoA>|D>T*j`rl z!(hwW2`OfwLZm=AnH3Bi4e0t(oiBdhc_4b}3`zR&!+q2od{dqzbqoIC$W+cN_lemt zcFTHik8q4_ucr@on5CVzzGC6@^)4wuM*11KNukzd5ih9rUeHNnuyqGBw{OsGHLdh)z&cy+sjB5G|Dup#Za0J zrxHT~s|i7U9^yEjsyw7`2G=57T^yy=NGP$Vh z-|At$gnz%DpW)Nl3oL$Iue+>%^W+{+b-4dJd-``Z={&zeeDgK*9W7E)#hCxczN1=4 z9`o=i>R^B)U^aSM;1l|eN|mYa=-qvvU6P7SjKn=-osvp@N3Zf@1}0J@>r8}M#(*!D z1`nyIueyn>g`EX4z8&TKuN$n&;%A#Y7UK&YwC(&zRu;i{Gr%U|V zi#K@jS9|y^RT{l_$(o(p^Rv~KYDORTAJWBBAOGm76S!l&)>mN+A1AQp6)k9JNK#NI z?d@ez1ii*%2Zj~<$C31v+(|T&*5BXa{OE`Lre`Dvw-1$%se}5sZ~9z1df=z;zOc^T zwSI2FhC%2RSRTB9{BCiU%`p~B96Pn5g~i5}qu(L^;q^eA#|%(%oaJg&@%lS6#Ou@O zbJmnO()MjFm^kQ1Vnv#WZhc$)OHu~wnj18FzbnK8`5~JlwawLzq0zI#pWIl8xZA8T3sCZ4XD4=dbXf|FSqf}EHU{=of=?aUg^m0_J zq7J3(I%XDMv$jX>T8t%8uNy2_gP!A~lZT*{ zf9eiT4a*Gc=?aPzb?`l{;j#7x-32F7v==F6Hh~CeM;?oap=caF)Bf7rz77-+-b0hoHOyi|sy~yN`z)x;nULP;?;VRATW} z^;7I;O}$>6&}?)$C6b0fSw^1XQY#8A2c->+o)4G|#w7_+C}qeMQ;psWf+Jjf3Bt7m zgBe1r5#-%#u^Q63g|qjs-{IQ1pD$yBZn|gZzWfp!{9@iZg~dj_5>r`H?tGZH%El(n zT%ED_%~uy>eDY!L?rN2{PDyD3<1S; zd8g|w#UZW7wUV&PSCHw5ytET?LGvcViQ=u^?M)tN_i&>&V{t zl6gy?v&N~DXDd?W$`fK@nDXP=$+_xe$4Tkf5d&A z@LyPkYxif2pP6MH5Xi5yFuy9VwwylW?etZzd@E^s>e8|&8k_2cqv04j|=iV z&_ZR)%Z7E*X+cL6lt>E@KdFYOpCNW!Te>QqrF(dahWcAB&lK^&*e6ZVOBX3#x`>bx z<$0K3{jf5xI*Qp(Z_a#eF+VD?dY^oqmX_YLTPd2MEqp*?TA!imXi+vIef8oVlcOt4 zO&d@~%!kyGjKL)eZu~Fd1k0hqa18jn?ZM znHW?#Ds)8k&;tXNV;a|riF}2a)}Q+pziV@UcIZMFg;sP=Y6y_6z*UN?KmDrLVSMCiktEu1UIk^Z21#nEV-L;CdxfEXWmBiDEF|P}=CV zGELE*`FWVMc9!MVJbmfL2CU}j3~3fi?>>D#cyiP@;z#GV&Rc0k-uH5JI{s=Hy9@v6 zQFkQfc*NCXe>%(A-0k|`m?7q~ANv!B{fV$l)#hW`A5+6jaf1JY&2m);6TR~)Bou6` zu)hL4?ER2gU65O09z9N=EbE`Vsn&*5NNT|2w~>NN(SgcZHjD%h$(_oQdUxOAwN`g2 zq;dRd+Q6JWy-CDidaQ+eAgqoq5}ZA>cW+|v%3<#!^ty54cQX{{qJW2+X8lf@BRzi>~1Eo&b(!c9M?aW!EH!JzLz_ zy%!T~k>%OmSTS{Nd)aS11U5(r`%T~3j|P?OEX{Wo^x^riL!$MFy$Ls=YewXyH{i0# zP&OPjR|QeTQFsFa(VxVN)|TKA4)Q1tLcS;xOb}Ef_-p98rd6Bgb^YS{^)J@%R9J=Z ztP17O73+@>)(3P5LBjgRSLqua%fCCz|NfDGC+&Er^Y)h}FY9>bvbIm-P%GjS_&1_~ z{}CHt3bqO_FX;e=Gv%`SiAbwCP!ACZ#Rfb9<3m%dlBy6I-drHlqz*I2$$q8B`uQtI z-#h2NeWLekHDYRyZ@G5;&W_U9K@BE6)#Bx(m1|kUi`6f%hEb9IDn#)6&g%L6o;KEK z=qnL8Kjm~ySWu3xuL!>d9hpa6ng}Hr5c#fvP)fz5V=p|Jk2wcYWw%?I>@JeDLjc8t zlrJ0t8-jZoMFAQI`(l``V`=BRdGS?c8ED=-KAqLD8J4}gU^B!;gH5c zjre)XqP0HceRWU6_&!?Kd3zr=ZdK|}ztQN3Mi+oaFMvj?qZ+E%YZDH!DuFd=uZ{Xm zc$5HTgeMs5xw_?!{F*2jNV@Id;kSDye8lIDZ98uVc`oqxsZ?4-TwRa^_lSH}0+wLbPG ziUgq@@d@iot?FkrgHBNDDCXG)ipmP#1H#qO5bw8TP z+WZfK=tze$FfMY;su(DwJ;D|g$49&~ns;>YHf*PZIpq^Y3G#^{>=iy6Q^fbb0BloT ze19;yx{LKOg}qI2dy`LCETax{^0IzfU|q*FMOa`x8JiBGouk$648lO8^?`Z@O93IJ zE^nF5Ut}BTC!6izE%B4aR;SA&2hqp}6)g~BUm#VKRQVv{;J}K?r3eFxBPsBv!h@K! zApM1|>GUJ}cSuj~&@6SpfK==^;{MW4s8$nav4;QxV6iha_|u+O26>;4*Pf@>hF z_r(W4*HOmQ0o@L_yu*s*P1qG5OF4M9!?E{BJ4<4TS6SI1{5uvuM2h1%Y(g+KUSpPY zy#KEE{Z{e*MD!_+W$8m$JpXP8D=Tl}(}UsFgj zyhd}#7J~pyNS5|e9l1Sdq7-;5D(s*;77>CjbX=2F=x(>@(v&WCx>!{qZxEs?Q?g}b zgyBfYg)W~mTAIFwh++^XgvgGkRQteqoAmC+jU#vkg`J&%l=Dn$xZJ+i#~-(oX1ZTv zze#n(xtJimF8!{4h%-IQA_{t7L?$&{98u^Lt|$~Gc5S0eWFYL|{dB>jF|JHp3VsT_ z87PgR*T=Y;(B&q*K94SVghUUz;7^Qp-J(ZK5fLy%ceUCf2K5x13>a@JfmwI;?UT&1SWk$;mZ?519yO}kl%k%D|at!u?_+uR*&)?GclPOxG2jyKs z0Z2g!2*4;Z>CyxjDwt=|Lur9cojH;E6%a)4rb{L+6w@-6c?lO~1JKjnpe|@tUnl_s zd0?o_N9k`Y47tyUWhX&@O^SzwD1O8d^y&pvFbqFz9!sn(v!X7go_mg+K4Cq4(00nT zXRj=en&p@{AMiocsAX%|&4^(iH%(6uxa^3?Seuc5^xE;Q)kD2((DF3JfjMswZlNRe{iC3n8hRxVQ@=aiZ||xRk1U27X7LHr+St1lRRSQY zz;}ZRcLu~q#wWzfeNgT$-FlzrUs+x`zDWTbdKNLfPXCDT!YM}zR9DX+Wff`>;3^nP(p$~y&f1iIKa+g?gnS9 z&!}>T#o7ag+Jmot7N3FA3JPIb)M=P|1ZLmB@{DD=#n~{y`LxECM7F1HOX#{VWqW${ zJi4)q6whD-ZvrB>yy=#zX+Q~%_L5Ikdwzo99ntpuNoJ9R z@GudD2kN4N=Ss6BW!~8Al`9Je zpTfFTfX3{Jftx@Z;yl4}01!feHqd$7ctFCa5UnY34Qatft^qru3OI#ov%>!e11E{P z)ac5JWTTY`_DmVwRgnk~BB=zRWxZt4C zWy?w||I5vJFdldG?!M|HrBuzq!{*H3t)%DOLZ8`%WQe-z$A|~ifpr;c$yQ^F-O#rK z)K`l`5#cCd2SgK<3tdswDa%ywmo#~a(j5FH08vy=KNyq8)vKmL;j}=L2^TKIVA1o4 z+QEsME5JR#KM42}+@tmqdT^E{o*9plN+bmmgYlmlh2b#-oqXTAI`KX0^L;m2w{~ys zzPz-}N;X*yWqdMNCm$n~L%rPh-B;KtUXz__DaN`O{Y~;<-&0>E&sc>3*4dvoe&jC; z$&2(VXjVan0Ri?MYPf~AYM^)We1m$a50fZD8m(1|PGKa)q66dNl;9Wl_WPb6W6i%f z&Z69wl)3HuefT2JYcsc@R5AJWzA24Z>#G-7D*y6I0^gO?;OWM4^=1wDZ>&=NXGrgy zRD9RkNOf7_*_W0$X$F43f(SHOE+^zv%+P4#V5fwQGaR2epdP?`j~3sP7KzW~dp>ij zz^5c&s>KOJ)RvazAn8XK66R?jDnBo-=oLg#PwerJI!n%_8H$nW0%cHAdP3gh49to$tQP~L_OAFIE2=QH@3 zb9ea{Ea=M{%-*-N;%2e!?tfMMX}5uMFK%Cao@UQ1TZ{dag`jyGq70<-kx&&H1{Tm% zXd7Zdp~DOl3q%{OEOfX_JLF$(Tc5f2iS=Fax0>+V%5wazGE_xC*8Y}$W?%=1Vj|G@ zp!IIIYcn;2^>o0h{%r`=w5lSNLQs?0}~w8`RoWXlBD zQorKNmIJ>{vW(Ywk>I%csTKBvkyoLr28D=9uVBrgAi89&E__f5x|9>m*?zr$ zbmyJtpTARZ?B3sB?YR4V>$^LT+{@awa_0{b<$v0-%6V_{)-~JDMaFzzuxcy2dyaqY z-nh}tYM<+HjwKYY-@y5abKCypyGB+Y!FSxr&%eW-8&iEOdls$cS@G+2O^|CJ4Z!Kj>wCEE{09?hM(vrt`JrKO??1h8P_SH3TJh@GZDKU3;-J1 zNDG9K-kUux&IXPyKk=2!gq&tAo2K_{)~soEU7tERO`mnq}7s(q8HNOtU8A z>)NzeMmB8GbbKATTZ;}Xyk6~c9iAK4vVFOl^}|_eOa7yHvQBua_GEGx>(~-!Z?R>W z{H<~bc3TIFE1(Qk&mIsJfYq}HAXOYHx!o`ka1K}>uovxRu&TI>b|MlFX$%$C2#p{& z7mUbg89YOdr>4`vIQ79{(v55U+(vfH{nz3~6ECyq4Ln&=-+o%&G?X77%5T@WFqG9D z%F5M%d|HDXyi4*OWC4+Uozc|N;4Sd~*NThWFX$day@HvRr`{0}3(_O-+4=bFkK(gY zkk2Kb{qu33RWOr|xOj9BcwK-wal+3Q0Q99e`X)2BgeeG<6U5>tCW|(sC|pJr_XI=w zI*q-}Gt&4#xdQ(N{lWS7tXixUwFBMp?rPGvQdHNj?(^=SyLBV}H@7&Q#pAmk=aaO> zqIw34@6xJ%M)HZ1D5nUThs7^70$B&+ERzrgoMD-5dBd{6 z@+PZbAwxt?$Z@`s5H8lK4gB$KAYEPaJHvjTn}^HdIk>c3gi8|{oFdQed{wBE*j>~M zC?(X%NrfnF=eiXIng?#XP9c?4=?XKf&{d2w=5#J<6gpelosA2fPurbMbk;&QV+x%k z3!Os?ozE6Jo7kN%7dkTwox=*9%?q7v?9R6OTV1Jb2?)>@f336K*}l-(*6z$GbPgzV z_APXF5bqsS=p0z+>{sYa#ZX?MJ$MD=TZoJE6}$5VJoy3}z0>l7{e`F(gs_29KvB#1)ks7Bo?As*YR*clj5NL2<^f1I9Pi_EVOUUHYMVyVt6bk zPfi~^d2&X^l;(TWGiz3@lRTt1pVqc%(>86MZPG^mu=mhTy@pt&7n18$O}Tey^dYtC zXPJMGU`dD6>nu65sQ09LNr?$+Aq#c)f`Q%}!nRb&^q2gwHIhY)-LPRSzqp}j=Y|?p<7!KCo3Y~Gy{EKqkq=d^8Xv_^7EQWe6moBp z_6tWDC%(7)wC!7;0nn8y!DfmBU58m*QI$Z7QZz0WKU_j8kek_8R#6jB>$n#4|A>1J z_^gVhfBfw3d7g(9NPrNkB=k-?RRt14uOcGd0D(k80!e_#MX;bKh}gXXp(A`kfi_XJl+9o^n>ZR|p&T7%=@-dg(df8>cjLZR9>7!fqo^t-wyJ|++(d%HN3uMT$>`wMNtQWxB zNX8jk>u#=Q_Sd@)t|OkoJnP#E(Vn&HU^ItxsUX?n)ln9iM36#QZ&04}{|uQXrd$iR z`<`o^+nf#8A!qu`^@t69zvhXWYH`YGD96YF#5aLcf-N-?G{w>md!mU)gWr*Xyiq=D z5vDK73(AJ@ZpJt2O_u1$!}nG^b9c=mrR>gMIk!6}AAC@B5LX<{hn`)DIYkua=k=jy z%?U9P8&JHl05+*_D=b;p5f+a?2uE9qm1o+7g!EfHgE0AH?5I<(o%sIS6R&+&archx zcippn`&}{%(e}qh8jfAe#eeC}i_T{W?|=8*`_9ep{`iAAiy*o7-{P0Ren^lxr?Z+4pwArxDxTKCQdajmuc)j1=8)b~xq9aOXZOKxA|J>*gfKE*nRbV6K+hX8oNKh&rVUY z@nq?>-grWTM!k}HP3uc?c&$^3bn{C9Spg+w!^KVbrso^${)IB|>KHlxiHs)Qwi|;#@KY){l!zic5(b z5H~h%W?XQ36+5-7ydwz@#>FPZro^h!>c<JhFE$GwjBA|KIHj?gevmc~uf$Dt zE%pspZvja4CG_VwJwBd@yDj*0FfK7EF(r}U6H5|T;%5Jr#JyxN*OIM#oc>$_IC458 zfhksv&T#2Fc>Ij_&-nHX#lIzo-zLAG{B1Jcl4VRiOnctEv7#|EmZmVBkUFeaV(-LW zS@N(9Zd`Tc#*mygW!8*ov!@R}`|=*0du30}?Y*W)r#^wI;MDT+slfqb$DJ+Yh*{J7 z^^6-fTZoxLoCWiTc>1AyEEEJ!ldWrrr}4~FT>g@y2Uo_ekJ}Q5Bid`pU0;X4$aBdI z9uRAnRnahEy=I-6^E8i)rS1VytZV&Bpe6A{WB9v5|A@4-mMX2k}E$T zo_G<2om{thJ5dHk`HT#1x^i_T5^znMHDgBcT(uJ+bHT}_rIUkaj~RQ`(*b15MjguR zkL6FnLs&s;Wj#zzia6aDXzD>NCy&$LkXL$CTqr3-iM^2YRUO}dDz-Kj?J+a9Bz9#i z+G8&!B5tohz!GL8)hqF5|EaiIOkxhsj4O#-8Aotv?Sr~=;pr6SHq|R>f`jQxBc9YG zx+NYwp7?&^w~3Hu{N}am!Q;)}Z~kp_yhVTDV;@58I^q8vGJ3OchdQ!wLyNF*|0I__ zb8M*;^$TB`cxJD%&TV@RoY+5gS*Nxs_Lso}2ZCR}l|A)*DbMawf6zQ3CP|suMe{}- z5AFkRnpvZWH&MEM|C%SnuPB%LaJyACbl;)HG_k!inqt!hd3=p5Hj#!<=gJ?%=rgAe z4U}JXP7X+X=%L`(p>pTZ`~#~&%sux6zn=CP_%qA?SUrRM zOH}?4TK0?uf3Qahr{1$$3usNoB?t@NkefK3oLgu~k3#^8N{UK}8W6>0X9P5FL`JBc zxUgJ=SI;Z-O4T*XWe~1&| z{ut%za~q14gzj4sy1H5?rYiRF*yFM9$9@|dSX4ceRLoeYnCeqT&m_1liN2VSl#r4z zAYp96%!EJei|sn~&cOUKaL2XlcLwE**+m8OE?@kJM0{xQ!Yfx728W$LWk~d^Iv2sM z_Ce7r*c3LzU&Y|`&Oj2;TPF?cyfiT2PU6-_+(f>SXtaZw)xEFn8VI&j`?g-^OWY; ze6_y$7QE7zQvY_b>Uwb$7)o=xzEzCU+*(Pghc=sYH} zuef2|#r2)XPT#ue?;B6s>o#nhy5@`~8}ln~mq|`;SyA3nd**_|`4_;ZSXp}tdu%GP zo;Fn1?ayr6s(8I@=5x`|vRT9v{;)R#6`KIKq z&9^=J$cD{#ibcT(j)Jz|Pd8TMebQGQE!im^jbquPsqv#zq9b#bkYsX_49sJZ z5}}~x0lDS$7piGZo*X8-JALNZ>++pKv>DOz81rMnU-Sr^*h(RiaM|cgDM{oB-P{UR_af zrFdkGbdqI5dA)32^BI`;FIhiO^J2|jv)7pV%q-9sa6PSmIEw6xSU&1NvYsK5vFBXd;t+{!L@Pg>52e18FPTVpY)9zq5&@^+yqr{USbW5V=A##8RF0h zgA*?uON7O{XFJafR#e`pKK`vt-78OzhnMB_0MOyeD29a_%IDSO0 zKO3KgJ6;TQetzSm^RuY;#v3AL>63TvKJ@sVcRns&c*{90?6>}PQUsjePKy195AXls z;Nd6l*K}QP{~dJE8J;Hh9Y!U+AcJ%2vl~aJb?m|QcyH9-5dz?^-$?mf&pmtG$1T-kARr&U|RBo5pk z4{eLS;!7)B9c{HF-4A8z%hP~NE_x<0#rE^89eOPM(z4iM|tTY7)cY`a9|@ zsc^1P7u%hGJ85^$*E(|(`p~y*G_{b6JvERy26M>aIEATk(nz;Vk2t6AyUh*y#w^UChl74h$ zoF-Gyj97`MnGV~QI07M~F&%_J%kWqN*4>Wh}CCD5BU4IO&A2((d~Vtw9j0)J~)%h>cBHt6~^!zb>v9d@slcUyVH5_Z?}+y5CS5rY1gBmmbM%}qoe0{_nC|dYwbQw9-Sv>) z?VlHSuf2WOmW}J~TPOqne(b5QFI&2HO|A9JA?F*&@RPS~seb6*wW|5%6<2M)V|DPZ z4_|+5-hu9&9$fL{yKg=bTwAs6mfLRB?cM|J-U9WnXQk#{6td0ukLVIHX&f*zmWmgr~=5W=yY2{mUEGinnTG!1#k<10kBeDK~|0vVYiH zWDK7aPV+vj0qXHC-2YTj{^YqAzPoSxm*`d-mS29;+N-v0yL|a&moB_%p$xvgt?C6e z`MkC5lCLeStiESkaNg>bg^Nq(EXtp?eA%qvHG5%ULMCaf_z8W0;^j@|n1~V3>sZp} z5m2W1ZCo-1gA{6sbVJqkVz_T`Wl3LP5gUVv8z`@uzV}{5&D~Oty`<)GaV*$U6y!UI zejK3&o_<@dmT;UziiIDm=VaCkfi$U0tsM=cB+3GLS@* z*XqXl1>y&N`%q!UMh3JsZj645IFsJJ%sR&asbgMwH7c}zu)M0~gKlYmo4)(Gr(fLt z9=Lt;@*CE!K~9L)(vs_noYD?Gl{&Vs`ju^!!O((>ZdkkG#t{?>3I47|eGYOz=wzM$ z2cxE&nUHj`@3^b#1_`W-v0Xl<0d0NsTT4~g1{rB4`NEgol~1i9+SB<&#xzALr<`Hy z`#0~qXw2G&(r%x>|L{lqt3F5ailS{Tw1ox4-bq5z*&~ zf7cwJIg`5BoCJ+c$sy%dU;6x(e~mss$U? z?!2c&27Y?wkq>UY(kYShn`!clTaHazea8bEf(K8ZJXrDb-<^Imky6$|@V^TDZwgyA z#XZfCvkd*NfA@%LLjAi3`gaeS(e+5_QO8PEEqjnu#r0rg6=tA6&j@miMV?*f>&dYD za72{0{uE1b-|J)kh__v_jN|@ zCTh9kjkRvAUAc=G-9ia`gm5UO+78iOgwP=jG(zY)&|)J^GEBX&U)WtEY>Z%PQd-be z2nPM|ihI+yO+Rq_qy5#N|M+0`x}3!Ri^nglOy2&t6R`@rJQ2UZ29{<|`OWr?pz_3xfuDIylfXttJ?v(uL)0Ztff8vz$N6wxt zgWD=rZIC1T&1jyOH*~?W#l^t^<3ztEJzad_EIXsk`2&{Ua`VO& zy8?3d+=+8$&YU=5N`jan4$u5H@eHZfFJE@ug89Kv&M<7=n9;K<__`K#`I`Geo8V8zDJaH>aY~%*RoFGL%eh$>T-JW^$V;!g z>&jL4K5@~Ql7=PcO`bnpb#K&gQheOv8FRa5TwPJR{;t(;th(D-bY^rG(B-^LJhy1EUY<;usjYe%(d$uV3JtDSOMOwtRGS<;tf-;(Tm& zrmyO^pa&Tskk{&C2&;evUk}$p;T-jrNk1ajW4SkHOb_W_B zZ^+-!Cd|ev8fe0g;Oc)l(8v>`2acSw=dv~TO&yyv=Ju5p+s-W?Ke?h}%7jHNW)B-T zuW;b{JGn%)YJE(Zsvf}Lgmd$6JHLtYP=`iS=a|UIP86)oNH#GOmGl#)=q&~R_ ze0bH!&NSax<8r~3oqblA>}qeU*-xw3h_G;noG=XSJZKw!#Du=?kP{9|i5zlnn7X9h zf&o`;yleI4dmgwty)Z4I>%;-0FH9(zFzLb>V=tUIw`=!n7ME_^edVc(D;qXEzfl9x zu}{}d)0bR0Y}5>0r|W8egr4bc)%6v+b@IF@6yFr4kvv#FeaekPBcvYs5#zywqA|!+ z%%1h@_wKp&y1fe)<>eJG%)4NrXnA#I<<(!U-m+!2m{C+T z$SsGh%kN?6sg9#RV--#G=`IC-{Np)Fhc8EdP_s$S(HjaBVr%BhQNfManHG;I1FXkj z^NpP{FzO}yJ^PehYhy7sj@D~enm?u0TWs2CN{=(~Xa87xrj6E0LRfHBc)KFPK3lje zu~qfFJG}N5Xh97HLxl9Km2HLIJ~LY!yHp*WSuu6sfXR~w44gVRqkX&d^mgqtf*XTR zy*Oy{#W zX`InS(P}VOZ^hr{-tp3zHJ461XRUpW=-b43V%<~EU(Iqo4z})jh4d z(2_*C+R5h>QQL^I#y2nWCPX+V(#(k{Lbvg8{QVE7M2(Q16cX$OEa^GX@$vFV&5qu^ zuUPodC-1(yANdjI?^?TK+xF|%-qc3ksLm*<`FC1xrE0B{?>N6ab2ND4rXvsSI68R> z^K}>M(v#;9kzWmcv?9hDdCSNf`X=>VIA;56XFjy($j3h(dB*uo zw7&DA18p9^<%Yd?1&+2&o|WAC^b41cnc;l@<{QrEqPqx)lGEbsnhh&v&wu&*Pwv?J zI_f3h)wa}qXrst6$E}qsEj;Fg+XxFP5J)K%qS+fYqP+m>zPCQ>6tgtC^S_=w{kgg^ zFv9t~<}qi@vSp%7P7*;Z^I_~c(;1<@$9^3;Lu<5kla`5Y@LP0qgV{NLoiajni?2#K zUX>ED*N9%`xZQMrTuxFBhHn4rZ^L?=Zlz(0f44?;>r~oOUfsT44oNdMV)yk`1Y37U zgdb6T(Q`?5;-CoG$M$2m)YZ@`A%LY4- zWZhT%)DN|fyy`eVyfwOVSYpl<1()sZaA4!Q`|la|?n?)!&k^-sJt2~ue>%T96Kb3< zl3M4tX(dBf&RX))+n?XD^=&jI>IBc1`jvfNjotOOKU}}6w%q)t{qpbtT7*W2UE0sDG2ctwb zQR{jhzV6Al-#)VLP->4Qc?C;qx>RmndB+(oHeJ1Wi|BP*HS&2jp_HH18%5um4{JUa zwMV}C?EbO$)H=Vt#Cwa@+Iu9<6Oln{6F;ZPe#mXK1a;4B!a{P{Z>e8MjwU1ig5P|9p`N)iS_G$)bHC5`b`6EmoUo8x-sy z?YTr}(k2FOXyXeu(#R{Ey}kBV+O*lZ^6IooV5D|v0% zeeg~~gSi^Es_S^UgN@y@6nvgy+Mec1gjSYD!ncYY z=vFrJ_sqm<+I_JqU}IMf?KjjgNghm@com1k0VZDAkuVt^%m(XSF`Zx<;F!M%Jn0_H zR_j$UkznHL!UR2-0_#3;9;D#D`T^jyj#rVD!4BLX%dXcgetERfntDIc>p1@Jy?f|_PvX+Vuai&8p&UCWu$;_`# znqSuUF28Vsf&Ny*5Wh4`nW%F4RR@OnrC~N$4{LtK+jU@w7aFF(x=!;VK0v1>#OuA8 zAg{Kz_GeHto#`UC7TU3PgQg3?k1kyZp^+&eqD#Y+S?6iG>V;vjTrYcuh%ODYp?0>W zD`+c&r}iztOb-!V8m6GOkEW|$0A<15RYmF2m@ekmsSvd}wl#pRt)iLR=3YIQV+{Q? z)CVy5h-k;&pmLInRw~-1UBhI0FlFMDC?=TXx-i2$m<`siqLg4-+jZ~^^ zlT;U`r3X`By(H$7TqOs9rz)8;7`gSMdC-H*_uhu~Gd15Esd_H$8ix3;Vamj>n(v8q zVTkV9@xXp4)C{ownXWQ%uQ-S5Szm=* zy5_+yJQny6Fgcobob=b4V7lAQBVpe4V9LY=h)M=bYF(J`4NTD5FuxT+^bBY$Y)9y_ zzVl$VUXVaADZhuIK1cKft%89~i0i2#;HgU0DbYzEF|J@IkEYGmGsqeT$Sk6%Dl5LK zzsCm+>(x=bX1#`}WAyueieUTkyb6B@(igy;=j5sv>@mPii+|Mbr*OYVo;r1$c{SAV z>VW1|vhDFx!w|1DOqnRtylP(;hImCV;MEG|Roj5Z!o1RWhz}a3U;^`@eF!jB?U5o# z(^~r!Fmw+*4>%+q+^S_&v%Di=$2Jb8v=j8^LnA*_4&=PMcxd23s`txsLxxMBQ6g3ng+b_ zVk-Jgv%m*{8Lw$a8=gTht-`cxn0GvwGO-$SH^3yW;~t$i<&E{hUjYXI;3~G>5F?28SQ>vdjPA=10!H`K z;yFfm|Kqo-12 zx-wjco)I3Njl$MrWZSy*{L7`YM+5V$cTw)SgzsZTbFmKUwhNM5u)D_+X- z(kAHBdD>8CxX)-j^*ub5;tD;E{*E5fn;K80 z7zRH&@Fe^2I2HC}mOIcx@+F|l&?l!k`_*xlJABLUf3nWRdtEN^74V>KqxFL3Ys0WT zr}^-MS1z6A!sD%ve#*7{Vu<9f3**^f{ifxmUD!S;L4SWeKyo+Sz+9^3rDs^5X*?4= zJewddJE)Ew>f$-=;n{?7WR&iKuHNU|&o72Zel1%((b%7Uv zW#wY$1j^mw^j9BpT}GStZJgKfejnr`6nq~zdos>4>nzcNa7Kscr(3{7J2VY2h!#e< zWvK5h%){{9=aAFi4sp4_!{z>s@n7cj7wx%Rd`s_Zf8_ThmmWOnNkKb5jGlD;6=)vj z8Ok5dJmc~K+cvCIIs7?Nr~2?(mEv&CZnP=(^KkySdx4A2By#IgDVobl(w7>~ zCTMxqm&sv0r}13i;n{|WjZ(6-u&E4|R+3Ix3ARCQ8DB8U!?(@)33`)Y$-a$*MSgAj zIJYUbDwF(*J9L|NMrIGAhrwHUKkF?-*szShtJ}1RjROm{o_GXpdOWZfWdaYk-2!gA zi<|*+E4L}WWf}k4c?&e^a%o)Cxn zxonqp4QMQy9{6`Ecsv3g=&+^YPM+r#IKxyW^8w%T`@yxpfe$mCPJVdw-zCnIcwgXj z^~2+RL+2>LbA8EP({ygMp40Z4uP&NS;+v*(<6P!jcR!syoGkK#0;ZQ~uL9>d@OO05 zygyIBw@x^e&%cK=-Vcv@Ax?ndN6T$tc)SlWAE06F^`TUaAMZ9=kBBLx7wd=Z zmX7d&t`4?kQ~-syHM{3d3^27ZMYRa820fsF|`6MdVWN@N6&q> zBBL&kuT9C1q2-kE@c63n6kCoSUmMrOL*uK)Q;gG8czkVQEK8K7>7nsef%ma?KaGRl%lZ5s$zFnAvW-P)Uob9bWS*ef3;)!hR1qjb71G7o{oQ8(|bIWV*!5BFmFqaw_C2plQ>80Y`ww+pA4j&1% z$!f!&QOHO~FrJ>T{U`X0J@K-mxQk%KiQ0v=i=d&a4>d((Q4->0t5fK%mLq1lZT>gk zxO?AF&Vwi?C{B$080)LmRtyRlM}Ly>hZ-OK2in!18i4I5b}`-A*3)_}7aO+yGz{uy zV8|cCb@Q!XXqaz381l!k4cQ>P4x(XBc`&568WE3t>lYg4uz?|;O=FVUc(STIkG)HG zu!Dz-bi@RL{DZX%#!2?ArXN1cU*T~`u&P_wNGb#84bmjwFE3pXPgXj^D8B;W@8rI} zR9wVk7_FHfVqV>Cc(v8#l_yUchIpl6%ESzpS9M^BR|JFcwU9X#Z={mjMdKkpXqbYt z4IhBT$A{XZz|f6p+N)`*EzmUi)-7nJ!2U@(Qv~IewddAzS1qW#+L!UmY4Y(g49zRj zbo&K8`=}N)$!-CnNtabn8-yPaJm-4LE(EE5Wo5uWe{N(1!-kR%f*K zZlPgbH87C9`R%B7Y{B|{n7jv+e6QjmL-()R2KTL5Xc&yq2Bu6rplvbVnuUgeon>G) zScmnz|93F(s~VUB%=_50%Hwb3ng!V+Edp-<7PEBLR_pUnfv~dotfJgC!dSnM|2)?IPv8XD|kMG|VPzEvy8zU57d_0phKOsT89$ zo;KmR+DfOVjhrAFhUYocoM)gLiJyJA&+aiaY|?d%_iTmQYoI4OaNpN@Vry+j-SD1iUD;utBiDxAKJXr3s&rl0IsmU48|k3>I=v}J24MElSb+ISl=BMS z--fYZ7R`S|HNK^Fp<3dy>oL)7>hz`j6&i-VwZ33K40srR&+~!y>K%7J;BL1z<8vKY z$W&HMebm$SWl(!eCA-7uS*%n3e!PJ{2)QOS4A)_?O9#FsnbSIYqxGyFJ6x%wu@F2O z7$M*9`3D$=WlqCvvbJcM`<;%4AI;#|hB3G+X;+rZst)mp&UNiks#625 z)BW5oWgKINt&5s0R%G1zJb> z=F$wqeT`s()`kl1XoOB(-1_%B&6`S1^eY#=`Y zU|^$ho5V8x!yp?+1K;TPME?c6T3p|+2lTi>W3?WCw&MI@UXN=Mp2KSx_-qVJF+34$ zA^YZk8s@YIv&nj1`(qNrJ_UvecJyF2i#G65pxs&$Oys;x!@?h9%G@S8X@ATg%*8fg z{6HQB4a<6P1@jc%y};wFUmoGM*?_eL?zt_LH%HRr+*kOP#yPZ2K@;kG^-VMY<7GmG&sS+n#dfI zuRCiI^$(gcuL+Fi_g&5V@%$chK5-y89`N1F`#i?qA3lX&`F&b~#`8DEe>3p3=J)+I zyz?5vpO12n^ZNsU2R(n+^i;u*ab}QweA>RatG0ga0~8C8K-=(Ah!qQ5yV6e23?BekPeAUr~^JMfe^3v>)PU%*FAHzjhTr z_oL_kDvpP7{fF~$T0dMC>;^t#FvB>1rzl5Rkno;%Gk3l@zxEsTNw6zmv<|pabgg|; z!+5^F%}$Vw>-iKb1_*1sMlERD@dF4ub_{EGkLcE?HzWc#jh z-0CfCtT^bkZ~Dto6%4-}d};|FNf5RN@s0ho@CgRV?~CW{&IRgK{=J-^vD%>y^D`t5 ze0>NsodrI-a#m2=3<8MWn-KEk%pEJ3Hip%-6~HAz+9?EWLE6b(muDK77odT8I$ZOD zeZ{~Ax^z8>7le!Weim#HaHDzHhl6$P;N&2|JgZ@3p@!*hcXr!`brpZq{1*sA!YeS41{eDA9tosZsm%Xv5;i=BJ!eNE&qy|v$&kMG#^%CGx_ zH$1Yby!ggGXFk7c&x>!r61?knC=~F!PJjNd`V;&%Y9IGSNDpuk&+F&{`y1vfdNtah zOl;MBZ5;M%^hG~=j@J&~Vwg?V+uFD3i~IPWbQrfE(}DIgbog}|(RGT;IH}9Pb|(|Z z;ra6b^EDPu&*K7Z7eAwSyw~tri4A%hTI0u3*EROX+oc|e!8t1@i&fVjN{_+AI za!mPmP>?@C9XE-Gk-Ep1UrKM7z%j-_4(I0+nEXjAWy;cn7s|k|x4-k<_itDK)0Xr1 zuH3V0=eVmb3f}UpNcpDg*CO?myMvc){P&|>AOD5x$UarpK~Ny5Ge!ippP#3MdBW=* z;0bi#pTv||JMi7v>?i%4c~xe8rTwJQVV%qC7R;N8jQd_d()wtStP$ux%!>chSg~5p zk)1`ET8~1mPSteL_%WI3Di9s@_z@Yc#r5QIIn)ZU=oM5?#Iv4H{EG7C zvzF!;)sy%|FjxGpp5=D7g|&4>o_KE!o431#*LGIg{lyy$V*|$Ig>+%KQ}E>m$~ku%m#dOdis0mZ-cK1C$V4$!m>c4a{qLUf4A(=gH0%`#m0; zVgG^7?TBkppkbb~MID3ubNm~n?84b?5hUz4x80Vf3DO6Tlbvj`Z+<5_f)zWnSy*Y>}sBJ~kX@%)0S^h-20I zlH^6}%WRa+{USCTi@Y3tCyI6Wex~mtCl?FuWHUX(&u4(%mqKS@KGB5vyUWhd>o*Cs z=0H|9?S(-VQ8!E%Y@`_hY@&u$$E{9e1vR5}C2UcwYVE;Jbw<`Z8+w@6;K84%wzk2R zJ0qjI!^U9V)BC_I#y!oMV9#c~_XhD(REjON2T|r6=Ulbj9*H`BW!`7i-jDaI0PlpXW^Q#|7j4M1IfxkNJT9hwr1o1*={;qml!uInao(jBwC zHTqWI?P(sbzBDk4^?21P(7?6P>f%iX58q?FkX6XMFW%DAoAWR(9t+fHxh1{%NAZ@7 zhxC-jjyns zP513Bz@__kF*2Z>ssqD#*#6ge3anaP=Z3uY8e#uyd{k$`2ig#ZiyAi!p~NZ|611@m z$n|C2h_?CjJr!(=QQL5w4RHQREH>jLJ5e;|HuY>cfoZ>2ra&9xcjoa|V!W0Iip6mw z>BHahIuyR8dW=hDNRIz@A%Sxn&P9EO$J>t#&euc{L3ZT+(b2!QzYzWHRj$Wx8s}h^ zv5w3e7ZNzxj^}pMc6>2nMY!FX20dFvkKq*SKx25&Djv#_4lV@OLC*(BRyCdiYnLml z{wQyT)%d90G`>HJ2iG`BPimaoL@ynmkVN(m#VCbkTH~bn1i~4@8F$t2zJNDLH2;i* zh0SQ+$};wj;p5Ai)@BqJO*%gu_fQObVKa}zKWaWEv5YkfQ7gKT;N!#4o8REfl#bSi z^(?EC)eXKXZg+8$#(f6w-$DFEm}c0j0qAFZ^DFvlCu@yuEoW8ev^82p9 zJAuFd#^CMD?~|RQ5q8LK8?pzy^PHm*cF1lUx(x4=S%+h7!szgw_DQVbLJ#=X#94O- zmjH(JU&z{N=fk1{jBoFc#~#QB}|Qs;mf{KY2K} zhjG%LK|fBKE82a62RxkH{}Shq9?ospYt>8BX>dl=9dsV_aBiFTa|E4U-KiZp#-<(G zw-eUCutyTS=k_GtGY|B*!);6J0MtH^PVA{-NO}Tf#NH~+)8{-|w_5)Y?Bn*L4#H~_ zy4}}!v~DfrvBYbq0e+s=i}i5cVZASwQLQ|jbV>|}AvxrBqVh?Wg5r(^eF@UTd1eGo zidjSbVIOY+&f$NBGt|Jtxn)7UzrdN`;oJ((9XB}v6tnL^HRi~g5CE0Ry6oG&3QUvPr+{cQuc>yyNLR+ zwu^S!2i$(_#UQXf&;6L@_0*3mbU*g(OVfDLJv>{jDzgW(?j8-S<@271ptZG(_vf|q z$0HG*^&!#+Ob_(IQ(7N1qFBMIMt*%j_RTr0511~%UX7e8kP6=GKx1#%z8Ma@lS8Bv zG~OMs+gK;?URcsIo=&i0A#2B3ClKDC*zq^k3A}%s2Ar2^!~i7bnLe zlVuXdNwkh+ouF}U{|lUxL!=Wl&TZEHS|@lo!#Y8?3+V)nbK5f32_BtXd$c{v1nUIg z1YX_;EJ!CnHmIljVy9V7SSJ7{>4X(pCqP;VGGY(mF>vR{5XnwAEf;F4mK|SQ&8_(5 zNRVQc*BBUg4cqJv1bt88fbZ!%)&URZRlC)6jwij%c}b*lO#DdmK9yy8x$~s`DbKe^ zIZ!=*t*rr`sm`Nt{?nX!ym@~u$J;Ik?>`OETvLy`JMAB^YZA5b#n7-_7hJ5r1#foR z*XVU#-(EqDhiqiV11misW|6#k(J!4neMR`@28&#Lkj+YDpdwgWyRX9j-Y~4j`>=<1 zhxIe!V*$&1imO`t|ScJ<;h zko%DEB%>}GPqr8h&mr)1tc!>CoN7GT?w-?*b@33dHJ+V;c){@}b@8w~YCN7i{ti!y zhi5A?l$=BKbP30(=z4wY(c|q)?c(E)b2M-|I7Q>({&bqhT;lPYHs-oi7k;n%(=O+5 zMBMLg``@(=`riiFif^!OImy6}U_86P+Xq=s^wv7SuGMQZpo^V+t$EipJv}OX&zeBF#BTLA`~JV_YFMlP?pA%ExKwS zR;#*rNM~p~6!Xdcsn&Jzkp9zncG~~c^{R`9^`FM$)$4b7XzbK@wpyR-u`|i8Q?GYC zdc1h{Her7a+9j9~?4|K=dwuS6E_uoYsjorH3a?$23_7}f3 ztvqj1i)nA- zfVK!`UWq?i7anpd11-7DvEoI(O1la7(H%~u-G$p6Ya;Ys!7fFc6Z~+7?`q)D5O{w( z;QKK=c2Y5XCcp22_x`;kmEs3}pXyYqdl~+F4KH*oOMk#0V*GlZTd5vo_;kR(#qfHb zTPaWQ`+EWZ6T@Rp&*h?g&{GWf8ixN-zn4FI@V7?5>o^C3-y8woo8cb@{!R>kkH%xI z;K|Rv&WF_!af1=A%9QB+(c-7M;@x@9)i~E0Ju4tl z|3qt*u0J=LTYo;1%6)K?XtCC1gXsw z2`W0pe>xD(7s1hbRiWe6jrlMKlWoh0CLe5;(Ny3(RN3g*(trG8DfY^pdRm^fTGs58 zSIBGSy)_f;O>_6`nd>Z(n*%j{YuaFGNWeD7`4$*U60vKSiREgzJmm_y!-~t`I(3rq zG)OdvXl+!1&${?uRzVzCQ?Yw@g&6ESvO?T&jdaF}ch%K0uI4-YhT zG^GCbXL5rYv30l+9R`HsNa%>VP7o*@3RENxuXTFt`8>E();#I-Tq{?rE~j6c8&mVO zY-!I`G+!0&dK_X7r~34PD?7ipLMYiPWz6$VB%lX3?W_N2%Id)}IO-NVZyI7=8K9(c zOqI~*Rb{BIKUMtn4`d^b= z`~->2&oI66kLVr!pV8a?MKR+V=XvM(YsHM?&pG$6Lv=b_>)d}#{NmITFE|zXNcz{j1L!Ze*ybpqnxPS?v&&G19DH`Tjb^*BCe{k=FT06 z@tnqYowbw#Hyz=X~ zT`1SGT4VP!j~2KGP3B&}N0wynB}(mP?iKd*rJH-(2NQr!9AVxE@%{pHAF`6IB6A;w zH5fYeh5i=ji(XOFr=ioJb6xDd0z7Dl7$zQ7S1auPaaxQ zGOs8u&2hX|Mr|+vLL6Rw6LtaFt0cnSn^BD z%Swtz70%8tF3X>jytsHyera-fL4NX}g?Y1aF~4+AcIim(nOaa@zOY|P%F?Avd*(4z z&yv!4DMcDbS<0y4Ik{sd|OYC05#8A4Cp*y@qgRzPrvDBux4OGc|N`> z12&>9871|^f2mw%Chq!s6l6qT>k&bLpRz(=OXj+j19KkgnvWFuMB9A4FR|w0ub;}E z5l@l75O)?}v7i876W((C&0{(>H;DFfyeHa;BePLfF`n~LYBG3I%%zv&z8pA+n}fjZ zJizIv$Zxvi_qzN@2R~A|UCQxgKcoszv6k|`p1>2v)e|(7q8(Du4t_ey@MaX!^5kH{ z=ooA;%|)oW#_4a*aBHHMOHvfjl^25eKlq;=4`n3*g#^FQEFt#1L_@R0!sewt3h@{l z8bP-tAhJFYF;(OPXn`3~E38YjhIUJauc9qhR@x)87J1S;BePIfXu9qottZIU;+6r8 zn}s;`-c}z(%=LpHoN1k9osE6;1Hr^>RA?|NGX#w{4AmO}Ykw4SL5;D-BCp7Jh{^=) z@|XyAPQuAUld&E<75lZPTQjVg(2;qFa$JQNxJTjB`5b5PT#GpGO6yLI3wZ6khaF_KXcH94iSg-4>Z()!96YCjU5$Ev$R=K|s0c1%FS|3^; z!HZfCBgH-uW$hHv@cG4x`p7sCXPvY@u->-*0nPe8;)dT7@uHzqEaLY{*;B45lE^F#r16I>|fiz2Z=6pIqE zP%MHExJ;Cb#bOEe%2$Ys#4_io^(7ICZiJFJflVx!oE8TMwe1rg8N#CEX*zWh6o7iyQ-E$&2g z`Q73k~tg97{_5Yk%_XYY$lt_7P6&m zCC`wpWs*#mZDd>7PPUgFWJlRac9vaaSJ_Q=mpx=p>mHdRQ>`y#noO4&*xCFHJg9r1 z-e=29^!n$Zs*YiQz)RRq^@8;xROYMJaqDGR2=fpHbpjbQ3lNEPAr#GgsK+9!SY|=} zEP^^BRlXR?ZV6OWg|!R=%ipYvt>xBAYlU?QvJZT1JtTYK7@j_|FY=1_w`wd$o+;0g zXJdq~6_y+*2gz)iBL~Y|IRxjt50k^?2su)YlB2C(tbfZfa;zLD$IEl%1bMEUD9@9V znX>z)pA!o`9WS*QQXXCh(d^uOnlLfL+UMT0wBDp{o%M!UzE|R6POqR>V za*13jE96CTnf#kvE-#iVcnGd7JgH+#ol~O|sJZ)cQ@RR`5kbyA&G7u8jDQ{7b$)l;RYRF$UERfft`S*n-nt@^0G zs-Nnw&Qxcqv(*4KPz_SqDn|`gxoU_Ss)niIIBs&J8l^_7F>0(Dr^c&u)C6^|nyAiG zlhpZYvYMi%s%dJvnxST@3sjz(rDm%+Dqqc2^HhN*stR?HTBiP{maB`^3bj&QqApdJsms+Wb%nZ8tyWj5tJNB{R$ZgkscY4Gb)C9i z-Jot%H>sP|E$UYFcXgZEpf;*a3O-D=MQv5v)ONK)-LCFXJJl|=TivPdQg^F+)V*qt z+N-M6K2@#mQ~T8cbx_@}9#9Xeht$LB5%s8gOdV2>t0&Zx>aaSZj;g2B)9RRdMm?*Z zQ_rgx)QjpRbzHryUQw^A6Y4efx_U#MRBx)c)Z6MG>K*m2dQZKtK2RU3kJQKN6ZNV3 zOnt7tP+zLA)Ys~t>Kk=ReXG7x->ZMAAJmWPC-t-XMg3d-s(w?aRgH2~Ew)GrECwqC z=LE3GAA*x23JX{<$RSf7i!E_>yxkBBA&n6*-^5O|ezu!hwmoLzs8PWMd9zDPiW@A< zFD)#Y1Bp*0 z|4!t;i|KD@adBa4dPeU++3bR)dHQKcM%290ye0XtqGv_r&0but@5&2{=J1_eP*O6V zK{HZ^)SFXMJ}bYdWNDzhq`0K4{+vRPQwGzUo}%)KOUm<$@(c3mSXI8E1QaJsqn;%jEAe$GtIG|zp_b&$Dco9hsLP1ATX(+qr?!IRe8{NBf0&3EY; z`Z?XeryKZm1D|f-(@nYQrrdP*`yBKAU~|niS3^&Rp(n%CBg2%JVam%e0H`CzFG;4$YztmD$^r*V~lW+u-YM@bxzMdK-Mb4Zhw6UmsJCKBgXh4E{a_e;$!zh}F@8~$XQa{cf>BE)V6<4MMSFR_nOb4z^2d+#9u1p86Ob4z^2d>%m*{M-B zy99&5tfKmh7DMrt<}ZO?C4UadWO{14!Pz@As<>=14CxQ9r6mlS zW{OWs(`2Qk^@_@eGi5#XdVVV zDjEY&>}+_Pir|l-hj{-(QU2WW823ea;p_&ph!NiKRi7W}D;nVRkKQQPcy?jw?8OV_ z7UfrXA2bTTbHDO|c|)b|org|i_dpu@cu|T`t2{qAh^rgS)|VW88LTh4`Z7dchU&{O zeHpGVBlKmYzKqhB(fTq*U&iXoczroXUnc0wx%x6uU(VB)NqmXs)@9BIC+i=k@I^Nb zwHG%H-;^&c@qa|`qUM$?F4Z59Xz*RVvcd{|LmyDA;d?GQ z&8V%k)ND|Y2P-l-hcBUAQwF@MWLySwbs715iOz+Mr#o^$E?%&_oRF$LlK;BfAk!9u=-h8xPEoS5?An({); zo#BSYLVb-M?vXEtkC25I#*7Ffj=3;=A3M@VNh~P}SB1fBC5ssLCS77j`F@Hm@;wAc zX?7Ix#U6!%?IQdMj?v#2>+i?-K8Y>%Jp{+-?~64%i}Mzil$Dp3EG)#r~(zMAP_-^)+TvnA(`7zWd3(`-{T&!6~}l%lHyK#S@+A zW!`OQP%i%(%FEZ>8CzDAS5~0!OMLgb!)x7_TV9~G1oeEriy6d2gt_Oh`96M7m>lyX zGl=gS407jM{HV1D-^PU%2|w4*nVmleV`Uyc#pL=5)8zB}_}n^$HOP%9AZEDlyWu_} zhu8gXc;t6u!ZgQ>_2C%n!!foFj+n9Gj~a}P#5d80W1LTUiR*y4SP zRR1`Xdx8FnX-H4yhlYMt%5UO*DpY@~b*KK;XioEk52;a_{6kz=WAbynPhs+lhJH<{ zacK>yfA#A}^J}3glz_&(OCH1k84+tIAe_;sTQWoAC} ziAB6mf$^{LKF!518cdFqc&)+sr?{~G;^&wt;cCRetX=@8(X65}{w;bC`Cr(B6Pv3Y zC;U(^7bYwFb%vAiN_S|ELK=7V!$co&^jLDQ@cV}3p>ZkWHvule&c?JOWJ<87;6b4T zn~(=a<}F;9Cr2-qV-{n;<1*Aa1tscSICD%fDyN_@mVjNJ=1)jX{PU)20qKY z&ob|`-1o+PkY%R#S!PAWw?@MxZc}5_cq+wgN!q2km3Fy z(~3C;e~!VQV_GrC{65(HZk(Q(#_5?k*tE)EQ;)%>bp{*y1{?YYoAL*n@&}t%8f@w} z*w8cBl$UGD&o%gS4gOq%KiA;THTZK)eREBHb4_`D+{k5Fq+0Sn~%bXQFdx|R98uYvDtp0#-4 zd((}z7^Y_SG2ffHWM*GxGw3vQ^<}o;*?iZ>)T587hZZl;Vcu(T!n65Kizl94`i*+j z-3s&?IPJDf&C+W;h)>Hx5D%8t5vN1BH{&?6FB(xcgDp9D$f$EII4sMH5usyKun!;v zF5!E8IX}O&*lM8vGA_brbDWU0qO;z&gqlWQh&xkXPklXD9jcdBk$MS23)-jG3pL1U zo7FabVdjZcTyfVvbxriJ=x5V!N?(}zkJPG+Rat{mXT)TteVLY!-a2MU?AG)VX$h(0 z>fe&Sr2Y>XpQbNq&>$_L!MMyuX%*@1(<&M~8@E4xd&5f_wN78ssC}cJ3Ew6@+jM_g zLbE;1_P5y6;^S6JTJ1igW5(ARUnlj+YMb<8^5Yq++B#HnT2K1h?il^nVMfQ~j(a-A zcKS49S?8jRPkY|e`IauH(-OKb>%PC|nx1RY5_-Jb^8&iVeMS0+)PJNe>3L6D0ur?? z%RG^JBE5CSGODZo*YowBpQkiPX_nGDB{gMA%EFY(Qf^9lDCO~#*Hhk44W_mNAKIti zlvWY(Po~$?|A;F6kKqWmefmQEFKaOP;`^80+WZ@l?*3bnz65x`^!`Ig2mJ$%dVsC- zpIZ`Lb(^HNrGH-eBk&#nmpYFAp_S;Lp@y!hRat}6mr$G0Kk%j=<7y8|(dOy(QfJU} z<_Y~abxrzBS%cBWZSmEJ^dSIocDo*0rS8Ns~-h+l*BipX%TEcdCDDddKww#6P=j@EtF_0~Lec^PpXL0r^4BtE7uAzo3PGd?BhqHD(2nT<3Dvk)0C?nK{;Lfme{ zh?u!Qj+m<(FGo>w6d^a7W8%(5Je(U1H{H4lkxTa=_Gb^`da5WE3K38T5zqD@@~BYc z)8mMQI)aF(rx6SE45EQv{D1A;d7NEEnLqwI_jGqUou#uc7!Y@MFd$$65l{&ri-2Jf zL6F5^5fuf2VG|Hh7z_xwj3chYFbaH?K|x5^nkCSf1u~N9kcH0e+sRGe+v&70I^_J` zRh=dsU~p!B^ZoC8@9T4`&beo)<*BDW^_;5nq&Ywf%>{}xfEIgi(I3rZTVhVzi(#2r zZ7ah|alTBP`C?XGx4Cg^%#w>U>DGsr&EENQoK+KN`DB@O`@=WReA{Z{ytW<9XFI?g zwK&UcV2;@>W_;aYu2-DnH88(xaCTRm+x23aTUGvFnO8M9t7_9+syEJ|dY}1I+nYOO z-c)Q}rCm$Al|Ha>F4KNyEPd2$rGv~=I?Vi}Bh5{kWnR+p<|LiC*=(fGnTd3^IY$?o zZ*+;dMpu-sG`r{;Gm8f26@A;BqM@^L{@RS3QRd)`OLK4DZ060tyqlr3ZsMGq!5KGk zp3Oey*bL6FiF0cPX4V{GPEDLmbHba>p^5Wn24>I188a8ZZl+9}A@jdKH|Do*IWOi} zvtSl&Hru7kJeM_Tj?3WOmN=(ngSjjX4b5hz?rDDN2hCI6D@^i+x(TIHm{htpj4ORh zcs;BSlkyyzV6QMP-v{=E{cO()6LMZr@@23BUJ9I9nCqH_vBlQf$>?HI7z6L}X5Ae& zykZvXgm6IdV)$sWCVUJIgoD8Q0>e>obWsk+6syCrMa8>@D`B>MH^Z&={mM1&0`EBv zzw_Ut!pGoo|2^xv3!%?;QLM>^7j4-D;iRIHZ6VwWb`BG=-GzGy4-mR-LM+gKo!1O-r%>6I-Yty2$F_m(US z;myKZgtrR6EBv1D`@$ax|6ce*;Xep}B)m=dW8qJPKNbE=_zU;A9qxc%!kyr~>G`kW z9=IPKfI09GJObn~e;l5KdGHK83-e*2@_G&y!yjP@bij+ST%J}!C#)gITZi3?=fj>w zr#GTi!(PSG@T~2H#q-(3qBGlBxCh)GMwd#(($WRR^Q8;nVz{=bmcC`*^{~EJn&;32 z+ZNB~dwJ8}KCmzBXWy)%Ge1$d3|7EPu%>vvq1pYmkb=9VV6D5)clW#9{cd+(>+W~E z``zw5-<|Jv=eyncZg-vUuJhe>zPrwM*ZJ;xw>!;ur?u`h-<{^W(|mWD?@o8S(|oh! zcPM(o9z{>K0g9rh6d;4c;1akDu7E4yYPiN*0Jnezu*kUw;{{_dgE8jbPcScj9Q{(E zUn=xVB^(4t!AWM~&lcVc_rjy_81zAr^hAZ8sL&A=`k_KUROp8a{ZPry2xGiubxg+B zpH)3$va`b&?YyF$SG4nrc3#oWE81v98?9)g6>YSljaIbLiZ)u&Ml0HAMH{VXqZMtm zqK#Ix(TX-!(RM1@O>8rj{D3ef{|L;4BW=@%+Db*csAv}zZ6daT3K^}C(Fz%@kkJYm zt&q_Q8Lg1f3OTHh!wNa9kim*|10N+%AA#AH=<+>`@Rk^Opbycpba$S|{ zs$5s)x+>RID=$7F#S`2qVj@g}$uI>@fm7jhN6Q7>R;9zLbWfGuscPp{?Yyd;SGDu1 zc3#!atJ-;0+pb#qF}k=)FLzb;H*gMo5xx}nk?bnTu9EC3$*z*@D#@;r>?+BwlI$wU zu9EC3$*z*@D#@;r>?+BwS|!p@tP8{8*rHF5*r(^~3+syhY*Nveol&ggr(|7rCY%Ll z7whyQeR`2T8oZCT?xThKXy85?xGz7TSeJhUX2LPHPlC(f3b+!M!%FCMj~U@Tezyfz z2)lx#!nff&a3{>Q%H0WS#Ha6TbA3h z+?M6GEVpI3Ez50LZp(68mfN!2mgTlAw`I94%WYY1%W_+`is)T>l^MlCdVLX2)rnJe zhPhTOFD@41O`TZ=wd5vaVxoOm%DbkYY&fT8^eos?Q<*bb1Ut0EA4YDIc=BI zb~$aA({?#+m(zARZI{b-xonrqcDZYpvv#>@my33(ZUODam+E$@ zZkOtIscx6*cByWc>UOMnu61Fh(56?VqvAT+qJuW>pp83dQ7jHe3Xihy z7`^ea#R{!|1x?*SQ+MFQOKIy4+F(VvPY-y%ntj0W58}Ubitg|b&(RMTU9@=zZQkLI zFNMdQ^F;A%c&d0V%q#vaR2*N0wV;iLI`l%Hj+Bj3$7T}JD!pmkT|2a6wRKV3-cuF$J>=+!!C-xYec z4n12(exCon0vEX6g|;siUgrNR;7Yj0f8VtK7jQe=0l$Ph;coaf+ynPJ?*W(t55Xhw z7(5P7`hOlg1JBx?FI*@u&%t8&BP@XqcoCMn?@H(dvXZX`a?wBr8gghP6X)xn__KkJ zlDLn-fp8EU1;==wvfPr~4w73Zxpk6TBe`{w+d*2ZT0|>JT}@K!B(+XbJ4kAcq;`?S zI;pFZwhq!(CvA0-Rwre35>_W+brM$B4=&LUF3}Gz(GM=s4=y2fby8O+b#+o#Cv|nw zRU=(B(p4i}HPY2Vx_Dgk-!`xv>;OB#E-)Q-1NS6db<$NQU3Jn`CtYz8W zH4;=KK{XQ8L4xX}r$%x*NKTE^)JRR8q|`}D2T7@ukPZ^kksnYj(JwF2FE1e}byCtn zO6sJfPD(mRNu89`Nk*MibdZV;Qqe&o>Lj90BI+cfP9o|gqD~^}B%)3t>T12N*6V7$ zuEy(Xyr#x$YP_b#Yihiv#%pT4rp7zec!wJA(Em3Sx2f6N!c6+)n4(urwyDWBHQ1~6 z+SFc8>J=YWi*3amwbmP+RQi*Qk~)d7F0$7}_IT)kZD2dt0d|62U^?su zu0zJU$XFK{>mp-aWUPxEb&;Dca??d-y2wWt+2|r0UF4#RTy&9(F0#-?7P`nn7g^{c z3teQPi!5}Jg)XwtMHafqLKj)+A`4ymqc$U^OO2jJ8a<6v4x2_zGi}F_(uf|S4MdEJLdtI0}sI?@EEX)sqamrzh`Y50p`nHcO`VH zvr*xAwRb{dBP+t{Vr}ULm<=}>uTO_l;9R&Cdf-ovJ(awSATJ}x%O)${OxpvNyl(Qc zhMWvo?xMABfT64-BLfz@C!(g%rsmP}gBH69MK?Jau+&8>-RmuMXON@M!I^LtoUKk< zShL<}Y3n8f-DIGf40Mx$Zgu}Zvz(pc+*9H7qFcSMQSaUAyjz_|D_6HVU!%U)sOJ&t zd4zf%p`O>M;{nUoCM#CA`i)ksZgsjwJN;{xrEYcFtxmhuX}3DuhO^7)3?kE zyBmk>iI2Kk8jl>#d-V};Bpi#=9#29(CH!6Dw+q6vj$a6i9lwMuF2#RWI=|xh)sC$S z*Fp{I&e$YN3W}F2FSxcBW{J^8EQkPC3g1vun_G;VtjNtmO?V{O;ec1=ysQPXqO?o(=T znVMRwmTGE=CBK-XmX@iZIoaOyMy!=t#d0NHQ{puxJVy!7QNnYSZscG!B{)Z^)s$3C zDbr!m1U_clY=fY&_xEi$Uv9z z^ExunrS5yAysYkHTkciIUFxz+J$9+X*tUDsVQk;M>aIt<^{BHR^;J<xTVTOw52+}H5?B^k;Mqnh zY$Fv%T22olQk$67F)KI ziV|C%O%_gtw}B@iN^m)wN<|4SPpxo*z`wvVB^Dz>{} zHLQUutOfVY72shMVAKxD~z!KY$;? zkKo7fQ@GDHeh&}ATzD98H};|mdr^hGsKQ=UVK1uW>XY;=BR$JV&oa`pJhkS!Ft+G* z#qx%xFs5M`G?R_#VX8Km;K$%rE*$MQ_sEFNiPEX64$!;szZ6&*{uhS^8S1FUl zRwY&@hpkGjoHuwsVUrLqCX1~D+Qq*8?DKYXr5Ae%J%oLy+CCl3dCD(!{N?a9xT;u1 z25A`kzXjJh=6bjRX2VTzGu#T_gCD>T;YaXe_$e%Nj}`C|B(3B+HP@}XZm)2iu-`it zS=Y%|t6C|WskJ*h)(j=Q7n|j?;`7B93ZGB*%T?h8+e?gBdyG5+?5t1U0}j{Ef0B)| z1Q!%9k*Sx+)JtTlQz=E;Wwcv%lBrcnr;|)|E18$b)G8$tpOSTwr&Z)>6?y6=Pu=9H zn>?)|Ppk6lu8t1OHzrR>TrdBl!D^|-vC#l+9N@t|huax>usb4AeE3}MG zsqajwXML4}HF6O9x|MRUQVwFuS4#OxDPJk2gQ;98l`(bEn%eog)OAW-r_`;HqLotA zDMg)9)G0-4JQu;Vm1Uo@Tq7m%Zk~^0%O#A@vsZUp<8Et|Q=fA3ZWL{Z?ME5KHn&FE z^eLM@dGC|=K6&qRr#150=UM;Z`tc*+NH|`rdO%o#ZoTGe+g0(kP=h-3!aD!07h(z6 zS`AyPVQaN4gGSndts16P!=P#yQw?LP={@V% zQVmqGc^w(FQGOgVwWwxde5iur>KN{r}f2XK(#{f0I>h;Q4+%{K&X?lyUJW zGhFIQyoXJxhfS%+tg}(!AYruXA0^ymOX&$W+rAf~E#*<+W6)jPq5a=wY}~`v)I$&4 zHDGl&?wz8ZJ^Rk4v6E~i+#L=8*Jpp~$v*Cw!{BJ~GuTQ#2WP@ra5nr`Y%6+Kvs>z= zM$p5Slyph2SQ-v3p1+TPkuVBI!<$+12kkCfJLjG7Zg{U_w}I`zGk-R)9yYKZHn1Kx zu%42g976fN@Gt4-G<0gFjM&qg~;&k#Gz zDC6@{#^#~PAk+CYpe?$7nxf)*xLg~dVkq%3O~JzmeI| zFiVfy;@zerU?hx!(ePf_2DXD8U?U${Dbl z)am^7$zsy2H;6r1k7r()B!Yq*=ws z)3ta`OubaUYxTQUziaioR_uxTU8~=<`n~w-4!z2qbo@p=ABJbQ6o0gLoxSVqT}S(` z%kDR8?)Pl94-`*ibBnoN+;@wsJwS_P^v=R`oz41-(Bgz>f)3VrtWxL$8&E{46UUGWxM_v?Yo#Ik2q+QU*THSxH)?mhg!qVrM;Yw0de zY|K|(TIw+^^5L0Vv_8jtCms6G>r2GHt!&d{*rvzCtC04A9BsNvEQ9B1`QwV8N%d^U zjCV|*T=#A)!I+c16`1{w&KY&PV>Y^ ztC;8hKVnn(gezUlel*Y3ma;3XGyeLD@z*@%cewOjrk#osW=A7uO^fGC@TWkKceNl>^ zx4lx%J_)xweoi`Spww0?m)|*WwR_b!vfniuEnd|mwQHm$GK^Ty@kxv)0G{j6*2R;` zuh-n(ql@L2n#x9q-U#qoC!e7K+EiP1Zmq_hp?*3gV zUZMuCP=nu9gO@0&->Ajgl>Of-`|m6Jvz2{WZJs4pH!8tjsnv_sYO9i*o$NZXjo*#~ z-BH}9KJHT=_mQ>xJQI3Ay+m!W)~t$d_Sh*(eTqCiCr@=xDA#VR|K;g<@>66&KS~zH z$wRkv|Eu);tF$bVmc`Q2CM{jOgpK0OFZNf9)BQJZ58X;Vmg{hJ_NZ(8!8M*GPhGCD zj0`OxLsfNooAVbKvmRZXqx7!}XT3T%T(semaM^|jl>YWg{}3rXSxRqE`mJHkhKkaE zdw68SDy9Fi@Wh5VOXRrl)P`5XybUiX{Ueorqm)0W^bZQ%8#XBY@lxTU?KUNy|R{FnG`V*D@-b#P8l%A>d50c}NQoC=q&xT$(ekhx{p{DfTuk=q+`YlSo zQR;V*`)J=du6S5V+ob9qcmG#+yw4qe?G6jw;YnAG^%={q(^Z~vm1ms&w6kmKtfJ1! z>TE!lG%Njyn8ZXS*6FNO($T5ZUQ%i+m0D+bcW92WJJMyda9GQC)-R><`I(%(%Eo=&>xDRUO) zY13a&_hy%ouYZ=-c4>WDTAwCgPm`@avQ-PEVc(?JLd&t^wlntIGKAvh;v2=YMO#rV z9yK%ezws$%{WlKY?9k#HgPU|~DEbSQ>*Ak^-xog-e^z@Rs}+wUOMmsF6|hLcQ=1=3 zBmI>R-uGYr=ud`x(mnYYB2VeV;<52le7{(&US9XnazljAgu%b$w>%jCPr`9S_YbC) zObvX-ij9pa@fka?Yw(xk{QvkAv`Nb0Yq^s8ZW6okQ~dO`*h8N7r*w$n?{QB)w$YwlNyVDoz$zI*k{871sj{KJqIsS{GZ~6;)lgeaGlcd z26Jc)V~QUazbhWoHbQY}@wa~88_y`F6l02d@tYL?mtrBk8t}Ny?ps7##E=gS=3{=@ zYo9{@7VCRsosS;;V`KdeZieFO7}d9K_DSg{OL$29q_c}P=~}T4$I`JIKQU#4AFblI zJX8G<9w!H5X^L^`d|dH@HoJ20C|BK)o(RP=g|XU3DU93kei1|DtzggFblw|dwDN!Y z(ObO5XHZVx>=5;w&Sh_U-6!tfyyRbZz*}y<@p_vMe-o+N^k>ko{trJG-+%fkdIzri z#;Yei66G}MgEzUx=50R7(2(22_7G<^`W>=&v#1`;r?`2uof|je{odrBZ+7VG_QjmM zF*mO}=nb32hl(AFj}*JY`$*I<2Mp8a4=WBSzEpg@xY0FRi;-IPMe)=Pr`TSAr3F3U zW}gk(B-R^n>hvK;sr@9Weys)vdVu2R#q8oidiX&tJU+7+_-qV4r4M=;8hXPy@sHx# zjsI^9-nxV~>A<096&DWO+B|NS>c-E24jbHZ=YA~j0zI+582cKIPmlI3(O_eYl-_0b zZv+1c)BUr%XSd^$tB0wq8V4F59PGO#p9n{qQ-8GYJ6Yk5bVb@Dpn>KN@~+J?4So7uIAR6#mh=%tONM)@B|S{;70C>4mxV{IRcZdmR`1^ z@Q>c1K0KIFm5&PD)^D~3Ys>O+VNG1e8LHl){*KV&o$2ohuXtnn4&g7}l)hV*#rL9T z%~ovgleJj2xoL&JXJlK%x1DG2wO;ew zY@6JA&1`!sHZRV0v}*IpY^V4>^XvoGYyL~NhqsUaHv5cqmXBvAd$;(r*|}C#F37%M zW#yvmi&j^5W?%9K@viKv)>d|B7g}GrCc7xEvCJ;^2Jt^-mw0#hzh_s(w})q6^Y-u! z*;UqCma?m@xopV3?%m{Gr|wV@OE zHHocgyjJu}?d?~-B`d1$l&ZUYOQ~H=P3>w@YFFb^yV^3ft6`~KMc*JV$jcJnty1e6 zmRi@a)Vj7zt!vBFy562z*A}UDjZdv>Ypv_g>?D8j9iQ6R)~Stco!VGQ8=DX&^Dr{e z*lv>cHdTAu#*y1*+lFbpiEJ0%p4#5<)b@s_wl^`gy|?rA@i!XnIa*+rT40u1U}I{5 zBdxpcQIoZ-#`aXt`a%;=7O#Y1yjZ+y6t$t0g=YRMXemA{hFe$L!Uj5l|BBIJqINsp z3fl=<@8syMB24A4;_actXT{cze1|8yCB7@(DgG``cuRa(yj%P|C9=Vn#d}@neI;6t zPm68Dw=Hcez8yO%pHaL$W@({Wj(3Gml|JQaCzMVQ|8(io;wP3)6z8`>{N&Qf(tJwk6eaW7 z(r3j_EuAWUTIn?L)9I$kNjFVNx@k(%O;eI?8kuy{$fTP_Cf(GWbW?NEP0dL+H7DKF zoODxj(oLi3CUYwIw75|*ur`#p7;%74Z5umv9$yE)iA6^QGZ} z`~vyaTll>szeKJtH6vmxUNJ6n$IJ7}#jo&;XetjGUlYI5{N1T~lyA7swfVKKbG;c7 zC4Msg&K++sQ=-IQ#<#_1n=w)1H{(X}oAR5)zmtDQ{AM#KO8jWtB7Uox6ea#NzAOGc zGb&2_YJ6Y(2WD23_}BP*@gJIDQQ~LgAH;uTrbUUr4PzcYH-0Ssll&**KQ;5B#Q(<6 z#DAXuT&{oNdB{Y*IQ~)mcF#p7^2zZ};&*sHGLdhNe-{6x=Oh#P==hcRot~FW*O{P*GyUYUgJmHjTu zmyvggxxe_QpJk+DwF|Gv}yO}&0dy?(Pke;fO^^=(eQen`Fk7W({M?2kQtbL!~> z4!W!OZoYw!un*{iW8XhK_5CfW?;nx+{*kHgpPc&sQK|2rf{*U+tjGZJ!~lZ+|3GP< z=^H!;JV^ZDaG3bvJc%_X9?+C{K%*ywNBKAM=)kwwC-vF0d;=e2$H-@7)~%iy9A{5t z3DXiwXiY3(4Bumy+kb^`GapmYUiEF?W=|YvyXK92js?D>zGKhLz70H+@i)%{*{!bp zUECrJ;TFvsxy9W)Rt3*0?{)ldeM4d!t?3OeA#sjIKF%Jo|4~me8`#I@z^?X52D z;?MdH=jZ7U?mORiEY82ce)Em(U&Lw|5=WVw-u4pklouQmnaafE%`EU|wiK6o(K}y4 z;wX)*oYAfo#{tv40fs#xRJ{kL(KFN@Jjr|)@pZl-@t6j0hgok=zwZS8)m|3o>B+y5 z*)%3*6TCO(Kg4;9vcK?cz;yy1tHqHJmvn|E9@{G5EPqv-xiDQ)E*)G}p z#iwV}-JSn6@egDlaOCcu0ypr)wufW(%sy=Ye%XGG**_z7iCs1D#`ZDsIKFA*k&VCY^;%beF ztA)hX8WUG*PF$@iakb{e)tVAlYffCPsdPr^Y}YxbbPmq+`O@dHpL0v+ihrT>1@SMI zz9{~s(wD@~E1f6)<*8^o+QPS)S&fMij^yL) zo30so;i$w5TN5uFm3ZNl#0$qHUN|N3!ZC>#PD#9QO!S53+*?YwDAij_J>r8*QF~7u zu{m+XQPJC&J%db9drus33XWLt_8oa)GhSE{kBo3sVuX_uBMgZVj^c}K7$(%5Yww92 zHu6i>B0eG?foYA**^3fiY~rVEw0In6M}K8w#K-1i9TUggO?;P)7oUJThQu9{_cHOw z9VfoV9p7zFWQxtvinTrzsKdr$uG}p{*4^8IdRa2#6d?T4%(W3CjX3oBL|(FM-DnIanLY?gXZ}r4w~nm z!$Cvhpbh!ixt5ZcXhUM6lk><#r{!PBzhwV;`FYaz<^0RyU&+5B9vNzL9vNyApKV_i zztF6ghWw)ZBJs#sn{qzf93MIB#Kc)!6K9>6IBRR-tP>MwZROqVD(vv;{A#TF>-pE6 zbxnSayF@NKIdR!(yuNuJ#`D{^!dTwluET~mvD1Eqz3-&o)VvDK2ifecTbBylRqQgp0|rf2HeE&9mc}< z-F*8a8*bqPZ=qHkIdKbLc+ZJHpJOk4;+dz;FCJ?*-*|r%e<6QCd`Z4U{NHj<`}b>LTTwRmLM!}-^% z+7o&9d@ok+uv|zUL!q9hpz84qt@vhHdf|9K! z{I7-eY}5XX3O4%20^^Fw(I;~f6J`zkp8YpxoE%Qv_{*D2I5ql|38#J`{+>DT8~x*i zFKqlhZNmd4+v^gB%Y#_18SYnapUVq;6= z{*ALz-dLH8KFXn;7k!L((Z~50eS(M4=wmc`8I68M2Rx0o^ELV`Z==!Q zX!JN5eU3)2ql@?*eU9hR=lLFu-bbVV(ddCR`XG&7NTVOp=!rD?B8}ciqd(H+Jd#GA zq$^7=`F1AHq|rBNnRn9YpEP^ay_7~jrE5#yB@N@1@Y_hkyNu*ojNfLm7$0nO zwH=SmR~pw{?faoL8rqjH;afdzcqn^3>=z{=%uKe+gR?S=;m5Jfy~7Q--yz}0rNc@m zvHG8kgFS?IeU*j&VivB&TK6hrl>w=24q0g-d5g04tL)!~NZ!Iw{=Xu5zj}jz*?%BuD!vIl4N@(XC02ewO6u-Xup)COLX0$&vY) zNsEyqSC4Y!{mI#lWcm=Xj3h@ro#cz&Xi0vspWws#Uk5x+M{m=Pjps)B-|W~o(>spM fQws>G1!SoO#Cs0hgHCntc;ACI+qZ4nckllP8pbT8 diff --git a/src/gui/Sudoku.py b/src/gui/Sudoku.py deleted file mode 100644 index 7b46d93fc..000000000 --- a/src/gui/Sudoku.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2010 Paul Bourke -# Copyright (C) 2019 Anton Lysakov -# -# 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 . - -import pygame -import sys -import random -import sudoku_kmdlib -import time - -class PyGameBoard(): - """Represents the game's frontend using pygame""" - - def __init__(self, engine, windowSize, gridValues, timestampValues): - pygame.init() - pygame.display.set_caption('Sudoku') - self.__engine = engine - self.__gridValues = gridValues - self.__timestampValues = timestampValues - self.__screen = pygame.display.set_mode(windowSize) - background = pygame.image.load(sys.path[0] + '/background.png').convert() - board = pygame.image.load(sys.path[0] + '/board.png') - boardX = boardY = 10 - self.__screen.blit(background, (0, 0)) - self.__screen.blit(board, (boardX, boardY)) - self.__tiles = self.__createTiles(boardX, boardY) - self.__drawUI() - self.__draw() - - def __draw(self): - """Handles events and updates display buffer""" - while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - sys.exit() - elif event.type == pygame.MOUSEBUTTONUP and event.button == 1: - self.__handleMouse(event.pos) - elif (event.type == pygame.KEYUP): - self.__handleKeyboard(event.key) - pygame.display.flip() - - def __drawUI(self): - '''Draws the text buttons along the right panel''' - font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 28) - font.set_underline(True) - self.__titleText = font.render('Sudoku', 1, (0, 0, 0)) - self.__titleTextRect = self.__titleText.get_rect() - self.__titleTextRect.centerx = 445 - self.__titleTextRect.centery = 30 - self.__screen.blit(self.__titleText, self.__titleTextRect) - - font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 14) - self.__titleText = font.render('TonyL 2019', 1, (0, 0, 0)) - self.__titleTextRect = self.__titleText.get_rect() - self.__titleTextRect.centerx = 445 - self.__titleTextRect.centery = 55 - self.__screen.blit(self.__titleText, self.__titleTextRect) - - font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) - self.__newGameText = font.render('-New Game-', 1, (0, 0, 0)) - self.__newGameTextRect = self.__newGameText.get_rect() - self.__newGameTextRect.centerx = 495 - self.__newGameTextRect.centery = 180 - self.__screen.blit(self.__newGameText, self.__newGameTextRect) - - self.__solveText = font.render('-Check Balance-', 1, (0, 0, 0)) - self.__solveTextRect = self.__solveText.get_rect() - self.__solveTextRect.centerx = 495 - self.__solveTextRect.centery = 220 - self.__screen.blit(self.__solveText, self.__solveTextRect) - - font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) - self.__checkText = font.render('-Check Solution-', 1, (0, 0, 0)) - self.__checkTextRect = self.__checkText.get_rect() - self.__checkTextRect.centerx = 495 - self.__checkTextRect.centery = 260 - self.__screen.blit(self.__checkText, self.__checkTextRect) - - def __handleKeyboard(self, key): - """Get key pressed and update the game board""" - validKeys = {pygame.K_0: "0", pygame.K_1: "1", pygame.K_2: "2", - pygame.K_3: "3", pygame.K_4: "4", pygame.K_5: "5", - pygame.K_6: "6", pygame.K_7: "7", pygame.K_8: "8", - pygame.K_9: "9", pygame.K_BACKSPACE: "", pygame.K_DELETE: ""} - if key == pygame.K_ESCAPE: - sys.exit() - elif key in validKeys: - i = self.__currentTile.getGridLoc()[0] - j = self.__currentTile.getGridLoc()[1] - cell_num = 9 * i + (j + 1) - self.__currentTile.setFontColor(pygame.color.THECOLORS['blue']) - self.__currentTile.updateValue(validKeys[key]) - self.__gridValues[i][j] = self.__currentTile.getValue() - self.__timestampValues[cell_num] = int(round(time.time())) - - def __handleMouse(self, (x, y)): - for row in self.__tiles: - for tile in row: - if tile.getRect().collidepoint(x, y): - if not tile.isReadOnly(): - tile.highlight(pygame.color.THECOLORS['lightyellow']) - if self.__currentTile.isCorrect(): - self.__currentTile.unhighlight() - else: - self.__currentTile.highlight((255, 164, 164)) - self.__currentTile = tile - if self.__newGameTextRect.collidepoint(x, y): - self.__engine.startNewGame() - elif self.__solveTextRect.collidepoint(x, y): - self.__engine.getSolution() - elif self.__checkTextRect.collidepoint(x, y): - ret = self.__engine.checkSolution(self.__gridValues, self.__timestampValues) - - def __updateBoard(self, gridValues): - for i in range(9): - for j in range(9): - self.__tiles[i][j].updateValue(gridValues[i][j]) - - def __unhightlightBoard(self): - for i in range(9): - for j in range(9): - self.__tiles[i][j].unhighlight() - - def __createTiles(self, initX=0, initY=0): - """Set up a list of tiles corresponding to the grid, along with - each ones location coordinates on the board""" - square_size = 40 - tiles = list() - x = y = 0 - for i in range(0, 9): - row = list() - for j in range(0, 9): - if j in (0, 1, 2): - x = (j * 41) + (initX + 2) - if j in (3, 4, 5): - x = (j * 41) + (initX + 6) - if j in (6, 7, 8): - x = (j * 41) + (initX + 10) - if i in (0, 1, 2): - y = (i * 41) + (initY + 2) - if i in (3, 4, 5): - y = (i * 41) + (initY + 6) - if i in (6, 7, 8): - y = (i * 41) + (initY + 10) - tile = Tile(self.__gridValues[i][j], (x, y), (i, j), square_size) - row.append(tile) - tiles.append(row) - self.__currentTile = tiles[0][0] - return tiles - - -class Tile(): - """Represents a graphical tile on the board""" - - def __init__(self, value, coords, gridLoc, size): - xpos = coords[0] - ypos = coords[1] - self.__fontColor = pygame.color.THECOLORS["black"] - self.__readOnly = False - self.__colorSquare = pygame.Surface((size, size)).convert() - self.__colorSquare.fill(pygame.color.THECOLORS['white'], None, pygame.BLEND_RGB_ADD) - self.__colorSquareRect = self.__colorSquare.get_rect() - self.__colorSquareRect = self.__colorSquareRect.move(xpos + 1, ypos + 1) - self.__value = value - self.__gridLoc = gridLoc - self.__screen = pygame.display.get_surface() - self.__rect = pygame.Rect(xpos, ypos, size, size) - self.__isCorrect = True - if self.__value is not '-': - self.__readOnly = True - self.__draw() - - def updateValue(self, value): - self.__value = value - self.__draw() - - def isCorrect(self): - return self.__isCorrect - - def setCorrect(self, isCorrect): - self.__isCorrect = isCorrect - - def setFontColor(self, fontColor): - self.__fontColor = fontColor - - def getValue(self): - return self.__value - - def getRect(self): - return self.__rect - - def getGridLoc(self): - return self.__gridLoc - - def isReadOnly(self): - return self.__readOnly - - def highlight(self, color): - if self.__readOnly is True: - return - self.__colorSquare.fill(color) - self.__draw() - - def unhighlight(self): - self.__colorSquare.fill((255, 225, 255), None, pygame.BLEND_RGB_ADD) - self.__draw() - - def __draw(self): - value = self.__value - if self.__value == '-': - value = '' - font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) - text = font.render(str(value), 1, self.__fontColor) - textpos = text.get_rect() - textpos.centerx = self.__rect.centerx - textpos.centery = self.__rect.centery - self.__screen.blit(self.__colorSquare, self.__colorSquareRect) - self.__screen.blit(text, textpos) - - -class Sudoku: - """Represents the game's backend and logic""" - - def __init__(self, puzzleFile, rpc_connection): - self.__puzzleFile = puzzleFile - self.__rpc_connection = rpc_connection - self.startNewGame() - - def startNewGame(self): - self.__linePuzzle = self.__loadPuzzle(self.__puzzleFile) - gridValues = self.lineToGrid(self.__linePuzzle) - # prefill 0 timestamps for already known numbers - timestampValues = self.prefill_timestamps(gridValues) - board = PyGameBoard(self, (600, 400), gridValues, timestampValues) - board.setValues(gridValues) - - def __loadPuzzle(self, listName): - self.__chosen_puzzle = random.choice(listName) - puzzle = self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["unsolved"] - print "Puzzle ID: " + self.__chosen_puzzle - print "Reward amount: " + str(self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["amount"]) - ret = [] - linePuzzle = str(puzzle) - for i in linePuzzle: - ret.append(i) - return ret - - def gridToLine(self, grid): - linePuzzle = '' - for i in range(9): - for j in range(9): - linePuzzle += grid[i][j] - return linePuzzle - - def lineToGrid(self, linePuzzle): - assert (len(linePuzzle) == 81) - grid = [] - for i in xrange(0, 81, 9): - grid.append(linePuzzle[i:i + 9]) - return grid - - def getSolution(self): - balance = self.__rpc_connection.cclibaddress("17")["mybalance"] - print "Your balance: " + str(balance) - - def __solve(self, linePuzzle): - linePuzzle = ''.join(linePuzzle) - i = linePuzzle.find('-') - if i == -1: - return linePuzzle - - excluded_numbers = set() - for j in range(81): - if self.sameRow(i, j) or self.sameCol(i, j) or self.sameBlock(i, j): - excluded_numbers.add(linePuzzle[j]) - - for m in '123456789': - if m not in excluded_numbers: - funcRet = self.__solve(linePuzzle[:i] + m + linePuzzle[i + 1:]) - if funcRet is not None: - return funcRet - - def prefill_timestamps(self, grid): - timestamps = {} - for i in range(9): - for j in range(9): - if grid[i][j] != '-': - cell_num = 9 * i + ( j + 1 ) - timestamps[cell_num] = 0 - return timestamps - - def sameRow(self, i, j): - return (i / 9 == j / 9) - - def sameCol(self, i, j): - return (i - j) % 9 == 0 - - def sameBlock(self, i, j): - return (i / 27 == j / 27 and i % 9 / 3 == j % 9 / 3) - - def checkSolution(self, attemptGrid, timestampValues): - # [%22%22,%22%22,t0,t1,t2,...] - attemptLine = self.gridToLine(attemptGrid) - - #print attemptLine - #print timestampValues - timestampsline = "" - for timestamp in timestampValues.values(): - timestampsline += "," - timestampsline += str(timestamp) - arg_line = "[%22"+self.__chosen_puzzle+"%22,%22"+attemptLine+"%22"+timestampsline+"]" - print arg_line - try: - solution_info = self.__rpc_connection.cclib("solution", "17", '"' + arg_line + '"') - print solution_info - solution_txid = self.__rpc_connection.sendrawtransaction(solution_info["hex"]) - print "Solution accepted!" - print solution_txid - except Exception as e: - print(e) - print(solution_info) - solution_txid = 'error' - return solution_txid - -def main(): - while True: - # Assetchain hardcoded here - chain = 'SUDOKU' - try: - print 'Welcome to the Komodo SudokuCC' - rpc_connection = sudoku_kmdlib.def_credentials(chain) - pending_puzzles = rpc_connection.cclib("pending", "17")["pending"] - puzzle_list = [] - for puzzle in pending_puzzles: - puzzle_list.append(puzzle["txid"]) - - except Exception as e: - #print rpc_connection - print e - print 'Cant connect to SUDOKU Daemon! Please re-check if it up' - sys.exit() - else: - print 'Succesfully connected!\n' - break - newGame = Sudoku(puzzle_list, rpc_connection) - -if __name__ == '__main__': - main() diff --git a/src/gui/background.png b/src/gui/background.png deleted file mode 100644 index dc4844a0bfb7b2e023fb5b008c3ad35565277f6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 308479 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%0DIMW)1ob#@zUwv~hUnR6cWAd1 z9dC3~!qe%5P)&u>uwAcG3{U%G9;vz+WE(?xt#I?Pfts3zG$Jpx6eL~OO_eu-JdM6a zjL4V`hw&4l@nB4Gq^PRzd_~3xmH^N(ohqFynjj zc-E#CF-A!_m<$;09A@Lry+{GEp0Wx)qN0{Ti=6JmR%`L`RfrYG-kZUg;7;mNEEUa# zEjY@CySuyL?9L$$_6{}zMkpd;LO?A6A;?*2X0v=|H#cM+bMT__aoMiO?l3Eu?0##` zOCGH@m|igoSi0Y!tj|h*Pg;Dxen$JoA0q#qzb@xHfMv~!+Lpn6e&4HPYgVIt6z4Y0 zd|KwA`k70`G7E9?B2$;-QFh|d6;n{Y;^O<8K?L7d`g<;yN383~BdCmSQ`NK1Gfmq; zoNNrK5WTPq2(@6}4&)``_rLiK{LlZ(|AZEIL^Pap#%awspE4FjPHU?u6*y`^t6c$T zJU?X(qP2is<8&^&iN^xgx?tb0It>dr_JWH}qJ(u& zugwZ4CUkR#nDk%Wyswd?xNmUn;I7ww;G-BP#$>-7T*_lPhRm4&C>MipTF&Qt9EUm0 z9tssMgR*awpsNe;x;i=6jpS%!@_5CdP>FegtIT8rk0yjRv(M8Z&Qjw!f6dT~9&)|= z=VBvGhUVYqkZoP2!|5sGK!@J#vz_wEyC=Iej$`XQHCnvVRV5{E233dlFk`-CT~(-s zk{uST*x^k#%ken@U=GU;8aI=38h9TDQO}0A%pr0$pS>q?OrP@`XPbbcnOFu(J2ysA zqwRWeQt75+?>Vu47_q40X&zUZQ#!kLhm;(tgAs?1ecB6E#+L)ZI1D_fK2nXIw`rq` zoRaei%jtHH``@lIFW^ zy=g;ng>M(ubo4l-jJ;eCnvUga>8{;z!K+uFqP89Hyz?$%)v*;wbPuoocP+d+YFtkx zRNTgkQh@Fro^E61sGfNtr9SS|X2sOjX3^4PZiKF}Z&#uhi5ow%j4y}Z->h-naXR1W zIZ<%EKI3=3@h|X4fAo7;a>c{C;(Y&rhlhLIo$qlvtyq_{f4)|O{;=Q$WkYk%%TgPz z+ZE53E1sX9@!6yN^XYQM^L59Uzx-AFM}PZ2#`$!I>t3-eXXIr?K*X_Mu8?U7f-l-?-4ilJ};MxJ0=6w_ZG*V97?92#Tbkb zSiwGc=BYt2ub-`GK~z9SzRO@Gl5>_UH#$pNYgo=_M;v(Fz0H#;%sziwEP{}Upz%Ol zoST1^6;>7?J%nF}=%d1+c?vcHCFHD{*H16r8p?oD4F$o}nD(_G{IODs6R52Tx$c`Z z1Emgh0zR`tjEIiDbTdg0A}11e4N}PPyDoK?coqo1^EfJ@(Z)3_h>9*rQDRwul3#lq zSDa2~9J}}+t?Sag@KQo(@B*t(KEz@{V#AV*5%XveYkO`!Tl_q>rr6YY>Z@k^gKb-E z>S6`gP7@A}HtUAlV`#cGJCYH~jr4jsu>JGjL;IDVmmp)yK~-Nvdq<5>{gf6j>=@zq z^{mznfsB7$fMJ3l0BKopY?~Bmns+#lh3(w75gn>$M+>Bhz z4%_GRc|-sSxio~yi%CNAc#P+0NK_sZl8?-SDiiq`M3sy~$2(?;VyNPwsDpRcZRAck z`JUd@tnRZ5W-R>Ugpx@{rgP4MnI^^oJ(GQ}CX=LK6a*^_)+-Ht#O@;)wH0w<`-FTO z+JHI*+t!Abw3!X@hV#ki$Knl;jGeeq=7Qm92k!45uw9G0!Z!#9s(Hl7LTf}a1QDxb z%c%ioHE|FG(Ym`6^eG^twqy9LA(;OXCS<639L#YP9~U#%&0OFs(Oqo($Kr=X#fKqS ziAJOLXJ@3>?0ynWf)4lSs!l!dJWQn@3_R9P-{6zq{FnIPAO2l+RD&9BcOb&}$uR=k zxlbIz; z0TyD!zF$P7MEkP=19z+(2fqLPzeEVYiEmwxGQ;hh(s$GWU|^YmJi9>mSR6!BGr zj;^=kKzMrmr13>2o3?YB(K+dho;q7oMOZSxDj3K6;3>Oe>}!Wv&LEPHp= zTkC{Zc~D7Rh>cKOTmk4*27Q@1XXItUzHRdFViZHSZ66SnI*bvrhdMF|*bX{FxOleS z4`cWxh{gg3uLTThjAGPEnhB|8^mn34e(7t67gb0@X+10<^K9Ib-tvb}3sE_I@WmZ~-TZILPXOu&X9{xb)y%~Hi?L{v!8d13t!#?5HGkAM&5)1^V#XX+an18xH!#Q0Z?EZYBXdzQ0G zO$5T@!!X%Ru;&j)VzCi12b{C(ywy2pdmw=fxhKn!r_?cf=0L8a6O*7My>5o=hK zoj-FVSWF3JKd_!o?%(B24MiQ9C@2QGoU0c6Hde9XtGm9FYRe;cio2?tBCjcl-kMpF zx2yd{z_1?BfTN5SAz|Q6sVONvcR>G6&ZtMZv5jDaEGVjNV;n;`_%co@VJ{m_=X>m1 zanVq%yDQu{RJV^}g~VTuN}u~se>zgz&LCGO(hhz9Z2y1Ao1tC|fBc7BwubBiK6jtzhD-EZUl z_dciZM#k~&*m2!96hr6N)klvhWwaO&TGT>wSBlRCAAR%@Vp>&Tm+_UaensxX?Sjko z8J~Xg1AO-S6+V0X45eiJ^`HMmynOjSo*!T1`SBHE&N!Xco`ivj8l+*pZU@qb|Kry` zG+sv^AzcP;O;h7IJ2;~HNFCee2$Y#_z0I4Y`U`@S!z>JXcCfZFjv+|KoiYNWn0Qrk zA%~iKEy!73_M(QOu*zH^!Vn{_&lk_~>*Vz6U7F+wHVgf$Lf zP@fc(R*@Ge2%8>c@?IFNggU6_9%H3sUFTOV3l=Sejrh;1*-EGwiz;kSFoI=c_GHL} z$6JhCL>{U0xSz)qJSJp6H@9k0Zp?Z*d4XZd!($gw%V`x-@RFkzSfXGn<_9W8DuG!gUb>Pp|}2Atu>0P}5O(!o@awHp+#tD?B(+CD|1uzi9A9$)=p zJ=AEC$B?qVR#8pGqz&qr7{DB)neG6}M=YvvmVMWQgk!XEdlF@`?p=;ix^7q8-QVN+ zazU$26x@0q8;Zi#JA>h++7ocI&4$JHjFxqE^s0|@dmbJ)THCg{3YO1)D~Q&0@yHr$ zOpUYaEk%1In7N0W;&NG5=T>za8ZDwU(6|L@2I7(xG3z3-WK`PItsd<@(P4X;nnKb*P2J;2x_k5b+xLPsVF%w*f!yHEk+B`QDNZCq;?Ve zwxiX8?|<|?EK7DTKq=q?_CpBxrR-SOjJxv*(Bd+*D#DI(py2>e@#f8^`1I2sU_YL4 zT%K?`uQ;y@-hcOfq>zweL#Rc$WfB7YHO#DOs0T18CIhtj>8V#Cdtgg2`kZj$9Dqqh~?c121nmL&~p z9#+`!p=h1kqERy2b;G(Yez|PhrV6|TrEcmhEgf$P5qpttHe|_%I;%p8{ZIr-v|`9y zs*`q%<>nBxQJ6f7q{u+j!X&7Ra2iI60|y|&{g!6+g=f*3=hu{1#uwupF~S`v^nh=g z|7Hiqx@1Rt_>h(&+u}8Z2T~x!?c=hk1Y3#={yglrGOMr{rD6CvPKN>e^LP=Z$f*63 z3$4R)s7ljrHQbPu`$$fp-@&^`PHtQ`%{yD~x*t%MIHRb=S~XKY^NO1SiJ3E(9I+F= z)U3#LGI=RLt;iPPGac0I>BJ(3ZZcXlKeCH1JapLubGb+`WNE)Cf*7SW(FKoz7!_mg zN2PJ06`f`~A-qkw;CJF@F^bE^upq-hyO3?aTb^i~xMe(coH;FyqJ`0oT!_n*g{OIg z!MRpJ3#{aZqNNr4PHt8(^%4qt1z0M zTI6ACgx?3aeMJ9!@H3ppux9s z4>E>~LqRu_^ckJC&mhXPw3cZ ze20gJmw0%1N0i#3pq2x#UcC~8Dz8}A6H;98{PcvfUyzp|u{*BDl?c3Nt#@jTNMHZ@ z*FI#pmk)Z|Xv?yy19-a`i7YCQE`&6342XDAt#0dJ-Ib`-Mrl8f5Bj(QI^&e+ket;Q z#T6LAJySwph&;HP_qwczSrf|jz)uACODC~-CZZHOQ02neZ5%+)rNh2atqnRPK1Auz zp>NSJy+DcN{(5*u9H*S~VZ$6BE55AYnhg|X(+3Y#%j!*vq+wa<7H$@CvmdE)GnLShUddJ0R56` zj+_k^0lLmie!p#-TP2v;WL0mPIXjNIG=YM;jUW`KaZ5~TECQ%Fh|}7ipCK1K@*Rq2 zKFT;V4dhrO(vRb!pwS@thJVBY241f`9%PP}b?zSVVGhxHAz3sQ7tie6&tn=c+=K(O z>Bvh)zQ-<u zJ^~*tEym`=&K};IL!d8-QbLfXoOlo&D|pB{D1=+C5hFXKhon&7b+ zBT6hjYJ`||W8-pzd|E?NiXaY#+z#VUbh10IK}P-}jRgUqnKG1A>Ar8Zcr^Qzx#>0H zHy5#t+I9dUdt>5}UpWJh7hM17+qnCyKdG@ma#n0KRhjvp&d*y`wA#FgH6EN59JV*) zyea;DB-Nt1-xOLC&#fkTd}7tGJBz89*vAB2zKXexcXiB1_+gon?o8JZs9a}2qM zqZw!($kOan#PJUnS##_cy!!YfY}*BKS%4PQF}J8UQt|^>Mx;u-jdIwB28Xn-*DD?# z9;PC?3@Dm;crhX}3m9hJ*^JiB1viTxLeh(=^cbU=gl}q4UK{*QiaK2v=W7T@sVQQ* zseQ(JI(e7IVdk@6QX+2|M!GCUX%LZ2qKinM%Rb|>$~c$Tx4A%fBi>^u^14?X6+d=S zYe&m#kU@@_JdvU!H5uKc7`ydGs}R0#ax>as zrjvfIHAe+NX%YTBC<4sSFC`%hH!-+%gZ>cp-x|Hf5IPlO$PZLyy8SFGw(7KB7||Ls z>Ov>npY*->p4YQgkdFm<$phJ&&%NIKjE?jsK;SjUXJ2a#pMLr&Uc7kGM|&v@RuXI{ zVvW(7-Fxo)U!15b06AD^rWX9XkXZIH) zi-r)oqrFhWs!}H8jI#Gs>oKSvjT>i(TB3=^t5+Xm->-;i)yV~VKCPKV2cQNKBDJQY zyCe?(>w1UNS;&dn5 z@>V<^=K0ou@aFZ$%@%ryP3xXCjQa#pdQvr4cdL$=(VV`>xM+~E6P!nomt}YvERp3! zBh|P)aEl;G&b_)*^T>V?L~`pDH|0Y+OhY{)!doTJOvoP$H5G;g$(&OXsr^s6$jQ~TM^qMdCHB^U(kFx<6X$2?^0${^)xahFKUo!ZtsSG1pqBZ ztT_O+pq7dn6Ux!1fZyuew!t0z5O1ja^I3}Ml#!Pn6U35fE{fQsHci3d91P9{h5hrO z4r_K8cZ5#oBS|wUlZ`3Od7KOdJvjg}PPDmw%t^lr=001BWNklm!+?tb*Uu->C1XqR-WxZKSOBF!TE7CYU3bJ3l%x({FNT)pluO+>W-^VM1}e z_H}A&XWtLyhE>lZ#H9M&yusYLUxuXK5vp|cvNK_jW z{!|SxPx}1t#CLH?ZW$r>+@>ih=uIi4u=#)g)xShqGVUJU$GWUN(=mo2PuHCa@+wVQ z&f;06b;M~sEBahCSbFjAwrMl<=IMf`%M%hBe)NOS;gkYWUMFs}pm5$)+XM|#5N>-# z`ucDD;}6lg{e4h%n-g)>TPkQ*ep*&U%gq?aG&~8n7ab7hff38m|f)}d>7*{g_|rf;qo-Re)R*~ zpE5#N5Y>fzmhtjvjEeIm^DPRW9d6 zN2(10wwHxC9VS1p!>e)muM~2p)tuK=*+$Vn_RdXK&jH`F86+bg_I>S8GuiS%J|{fl zvI{Qi%__=TRUnb_)JgO-X0t$QL+V6XA_r4fHujL}pzN5OvJ)7KujzvnnqiRVi&1Iy z)B^TyaY;3+<|yPj+6b*Sl(G*jjw1#ZKDiBr%iA$havY7eHqRL zUUzdMLWt6pigdAK&jfkL9@<{*yQ;)TV6f-Ig%7+|nP{humkHyR;!Y^g>>e9HZ5T#-}>Vb$j zAmpz43K4l(C5{CF=aXDoHlCKweH50Yl<@fYI22e+nXm%Ol)^Cv9ObH!G0m+nY>nH` zw(lHMcx#At&KcWvyE)tDn5Q0vHU{1AYU{!Nj36V~^>lJ{u?ww6z9a_sbhuK`Oq@#< zU$UGfJ)za8oWDM`K?rEi8=n98JGlG#pZ55nS-tJNRcmmnjLGCPb%9!pKsh8{Cg^!1 zHa87<&4LCQA1efuvSC?I-ZWWcmBbx&fdVUmYm;U*Ym>?&<S@_R${ zeAiy^~b(mPl z2bhnbXk@}x0ag&UHXh`FEYOF$JJA7!1>4b(lN6~l>3^{NpA;?jOi!m(RcUNwIg*_% z#(>?FgApa^MayM5cJ-Ev#+}{1A5MI?V#=WHxA|Ey8fD*MKA7gv=*|yV2G@GFEEp01 zCgr3@nGD4K?wMlnxcv?*zWHL7j=9T&5duE?=p(%I@?9se+F|KNdNj(ct-2rD+oFOv zzD3sA<|-_EhKmx=QLA|4_~+WyIw5+|XE83vzB%V7s5eckZQ#xsV!$>h^IDrPBmSOj z7Rc||e2s{(LI_Irj7URP8P%+{;?Uy9_Y0`(p9EU=36^ ztJ1Q5=1mJZblXEnWy(3=F?&YRAm5k=j5mwyb&LQ=KNwXONTVt(u4BTY$ z&$IOzD6pFgL2kN*>$}JpNjyG`~KfwK8`ziVP)|j;Bb`cWUWrCB`Ee@iL z;ZLWNs4s0~R@=Y_GhZ|VQUrx6Jx*xy*JEDrAav5RLKK9>&t^ln_fl0|9o_iW>WMZ* zKrPGSqd^vrlzPQCzxlgTM5%>D(t=S6rL1V^3Gcjo7cXAC<3_hJEgI{S#0fu$h()~h zk~bjseYWiaw1VsPf^r;q@7;H?#svt(t!`o-+)y3tk@bE^ifn5*N=5qG*Z%tt8-j!e zN1EeKi?{6J17h%C)>*M#N<7{(u8v*wo@t~CC_x(5fj?4-8^v)s4)@16jAj-h7tXOP z)>#-T#fSjIzC6EQ^m{!&KkL8W0EqG>gx~?mLqtTasQWI8jF7SI4fUvl`f!e9;e*Ri z1}2D$s^N^{MM-zC&gv)}LcmoKMBXq^Ik7D|nd#@j#aRx7;$xi7-#YxCb9B$F7PJHM zbUF<@8!j5p=kwr2#Tkv9$2fC{_;MZ)6dGUIXSN(XR{L1SRU!g6TXL9G-3qLC-+g!J zgqYW1VX8LHU6x5r$L66yZ0uZWthGofqQY^bRej%0vl@-?Dg2U%Wl37p?+5|7JU=1l z)$;*s6+*T>+p4CdbJP+muj~@ImC57A2E#8FLYJ&qlny=&s9&8TZrFFo_LYyo^=F#O z@laW~6}Pk9z^t5Q{>U6TWarAD2&4TsDrUR6tQavuO+Fi9%*bich@OIV&3;)H4NkUf zwve)i^t!2|x`hTvtO;602qN_sRbat-T9I-Tgh?}`Q|iIutSq#VV^ABCfIelI8(GW$ z>n4hkMyP$<9w3*l@o8$S-SdeOB778RJRvpD<^3x~g-kW_y2_bLaWK5*_*`Gt#hXV9 z4v&Ojjd^?BGm&W=+>BXs6Ls{%P2fV!C>K_Yu5-!+7m%Re1L9uszIq$)taE4EP#jt| zX3o(O6de$XDXNNzaNTfvv*Y-&cd@Le0qJ++RE>~HSwtb0Q`nlEzedM+dVbVE^aYJZ zma^YV549&%Dx=yAT(EV~Aac>iR9hMDI-8ip7y*y+X)0Qa9yrYuBah-sGL@;VqLeGX z`K^DAv?PQSQ4VSDRz*~oWyQ;v@8JIa1=jV9Wm&y&mz05k6c$CTbN8rI)jwL&>{u}{ zuXV?^UC~0r7eDwhL3l%vajMxe#Doy)FhLR2)6SNJ^tG@3cOS+Ov94J;DBW*^6(1?~ zEVyzULkc%9+Sz2#7NLxf#sh#a)ts|?dCVr7feI-5cO1*Y9k6{_`)r0N9LIsvy5hUv z{Vv{n@4cJOk2f^*z%w#&mxXupRks;PK&t_l{Xhy?6=KH?fs~2b>@{S+(>Nxllg5_l z%eU`m#itz{=es)}iTQ%IlyvG;4VmJ1!4?vx*p$&uaWZ%*7>pKsXS=w0TUSkvJPCVV z=B>ot=M;I6W`6e%_@=j-6XWOTNBoynB3j>tQP<>S~Y^RBD{lIvv>cPjP&A- zt%!>$^!N5ijM#ZE=73I|G~W^5pD-u}fia!=^vW zm*(8j%h);(A;dPe^ovl11CeqQOQ~MuJCaDG+@?Ng96j>33yXyk9>T6fSk9B1-Ph;! z$5t5UyE`X>59W=U*B3o{MNr*<z;-Mg>3V96ShfZ#D&7z@s{UZdN zbluG=aof*^gxc89&VMf6SYd1^)v|Ok$LzK*0vkQEs*HYZGJ&THwmCLD9JTtXY*vT-h={GuYmLRLBL`wl44_1F)0^PMdo%)Q#kzkSXx zT$9=wzVxLp4S})dj+}GyQJ0`4c9}2ga=q*5EDp+#QYyBxVa+E10mptBlw3R_~mVgfOx0~hr|-eeRO7WX&S9{{?eibqgA2Xei=VKJ@taIiE&`k>^I9# zV>0v{(IT5Rco?sdaXE{T3Ggi2x63vVDrTSG(%}s)yq+^*`C6RbMuGd(M--6 zIf)Vzt#eQ~YcN<*(5mN@F%7`>y1g?-KO>nunxB}3r<)S<*!MBKTLZW`3_K`Gf4;jD z$@yExpS3mY&(FG7wV68t&gVNV=9JTQXg=O`lTJA&MS_x_b(T+B+aVmPB5SAYho)mx z@$S=RNK9`>9#(VQp^X>ND9V$|QO{Q^MC^QXb=`zonh?O!E-B5{RYNTkJY*^@hcltL}aPjpKq8YLV&%P97n!L+mKtxAGYH33u&Pv5rn~tEye`f^z zlRETU@VS%JwTP+2ue1WvIGf{`65jOjNPe&}GJ%Uy7MKpv$F_Ai3yysk-jsgN7$S~Z zv7AS z61M$W&b-=sL{9B?DFAS~I|H@&T0oPqdx_8@8c+;4YC((*r@K4c-#_5Zn^*Yc;~(Jh z@d-=%1o!t3IN#mjbUNei?jB1%;o<%Pd0DY65h*P=ogcK;$jE7>{XwxgE-VUI^6G%k zx~xbsqqPKt10l$nW86-s9qD9aS8jC987LK54vXZMnRFmo`5=o!zsIo=aXsCP_vB(| zLj(;M8LT{F`vg;S@Q8-z+Ev|+Pc~ANQvvm;H^`NFSv@~LVO`H!*&bMyvvbQh8&N)2 zR7FL9u`UmYDPg-_hp3#H55tP54%b#9i%Zws zpVjWqH>jGYn}^EgY<>x{n{rTcZt%mKQ9bVrwZbnA*e)ucM|#Y+C$|dsWL-tccRrtoLoQKa!G*%efzHhi(u07Bi@SHX@InZlq%AYz=%kJi$#wR-8-}|VA1p%``Y|a|R zQ*1xyy6Zjhy?WDv zw^CEA*n9EtFyvY?%|(njr9djJqH4oozy+sV$k`mQs1dl?%Ura->;gL*g4mh#L!Ch*gJ`Ys-CXW8nADc-+Oes zj~I|cmY=x;U;L3D!@gf|K0inr$$7=GU$Do3%hMyS&yTn}Kj8JNk7ezJj290N*tZ>7 zEnol(}xKfg7p|I4Aq_d_hU=pWw#Um8YJRalG%m~OlhGIDK&l86 zyS@Ytg|*MnVd>Q`QSl5aPQ>Qf`Iv=RT_sRTyXo|q7sj0kdw#tQisrEsUkc0voBdT7 zS>WHDhVe@oMnCg^cpSp;u)PQCI9qE<9Gs#sYQF$G6pot=x0#@BV-G_)=4a!Vr9#FQ zqHCX*tp=>XsFa6ghj^*Y<3kL7w!-c5{Mv?$8fVfN_6=C^qP8J^9=Ts8qU%LOJUvr*sabV4Dd#~Taf`|vxP zd2;OREj)+iEeQaly^4zi6u}g7aHkRYXkVKL8!I!RdG^%f@ODP!xDeqBXC9Suux(1v zhz=?8a!RO2bJutu-U`AP3{y zDye;Pu^wV6~o!@GivXl-Y6omi;@ia2D&G$mO6>qdsJ<_I+ zoO{5%*k0_~fcN!#yZUPgfk4S)Kle~3T%)BjJ#gh76;@VkVQx-5$rf0~;3eD1tl zQbY+#HP00 z_Z^qZCaEZBNdM>`{kI>+7>KOb$eF#7YM>vGDGBeRhK8e7R6wMYfD=JEB47>@wM$|i z^SOV8UK;zpt73vdy?~U{4GB-YnUX92%%j6dcKow#kz41@Dl=PzAqXeP#vknE#PfD0 zigSUuuIo(*vW*V8n|T`%enxv(lG};vVIXqyXqEW|25kr8dvW1mWc6pYt>B`r)o#Vm z{i^ct_gR_6&$6}RmjE9=j8@FWs6AWzonorjl%JJ`BH(hl+*n>1qE{(0hsoP~_?Svm z4u7&VAOy&s0h8rJ2w06%G8rUV;HQ~Z+Fo&4FQEjE3Xs!uA_UTTMvDCK;mbuxrN|*h z4hGbKx@cSfJi_NBfP=j0SmJJB(9GMi(Tf#4?#Gj}8zQEhU4rcjHVu%qXA&@ue!aoa zJ!0eZk$W-{;R`7;hiDv1YcQ*gbzQx{ml3O+M`uO)YL`e63ZhC7g@X12bGu@SD zsz#rGSHS3>C+OwksUoMKAE>?rw^%t?PpCeCIE)EGzP| z;Cw!NpmP^`1vj}CPH3d}b@-^#a(9EK!<2GGUJ@Q3Kf~qvgx7CA#;2cthR?nKdE~qx zC7=~xyF5#VXo{0FfQ*q%L1})4>7V?QU;D6BNzgu>S0!W`HzU!Z)xD3*UcaJB$Zbj< zY@1^r_3#*kRf1d$FrvZZ4cmxCXYl^eH4UCeZe3kiCxt_GG>QuuE)cqBQ}D|ogy#IC zbzKJ;?zU~t>u>_LUNG*LLdBI8QFi&w945ZF8F}C?)DW(yoB(lUPELMY^|_9t!8#ZY z&hagF2-u;4$xK}9!z{!XO6wO*JVmc5g*4qcH;M-FwiZ|I`^?}o@2 z^27y^e+J#)EGtelVuGgE^WRyNFT#iXzHb9>$-k31vWIT8H@Z2iqE$CuBz4S;f(|1u ziq7Cplb_uj)6>XBdAzVYQJGDBS-fHeJxh(}5jHmkjHcRJGUHh<@agwk9Bd%|haoT= zn%kze$L`ryY=I1d-}cTqX2bTT{qN?5mQuLM2MriAKINI=W(;lL-->u^IJ__?gqnTa z#ON^NayhW=8}9B_0Ec$r(Vg#`DoM?$of8%;__+_-CbYsXJB&f>LVSyQ$Ou%N!2lGj}0p}zVw2m&?`LJ!<%{^csffah?)f<%W z{1B&~{VKM7N7S(-s~(x-%*Mw9a!aT(kL{hecvM97g^Jn?9?d2TLT@OwBG4$m!K@sD zli67{=xC~ndmNh7#av4_D~F%$#m#VypXX}W)_{<(o-+ROyWjJ5Yu{D)($zsBSL$mL zgc*zq2$D3fIC_yDYSnP)L-H2)1N*Tfr4!zN|3`5;ttiKaloMj8ICdG=*4B$%G00x@ z9*}ydq9N@2n^ukkwN-4}j`Qi%iGEFaGSR$vtT>S*?6imnkBsxG8kUWn*~L zVyIoI73aINtBvxq097Qv)`gk5BOh|62r{*s5OuS1-xin39{X{ly0JVe-?-*AqX_4E zIw1zV+;Z$L)LKv+dr`9S;juTXu3uBCv838i5HV5YxC|}uylCejS$L;qL`i!O<>;o5 z$05j~5I==8CmEjQt>&r2$UqAbRx9yn*FL9-B4UgZT|(V77v@%!8yY(!5&V6EX5m#u zHY||VY))bbcz%9%w09nd8{)+AQ?qqQQY2NY0=0aOKH6YPK&9e|UA7xJvU6ea{QNvv zxEvJW#lAzr?+Gq|u?sh)?1r^@StO4w2&cqCXuEZSq7_l>HVnaX)N}IoGt#tk1M7m* zX+dpQw6Y_{wWGOK=%Dlh3gSjzr{`gRhkuu$prsb1kX%XS&1Gm>#8w^0$!O5unKwMD zoUDzA@*?JGC_u5eus(r63^<+coZxFo6D&@!ePvCsSaewAh*(z09^FalTKz(|pkf|n z0ktP}7`Ia+j;uH}zS{Y``qX4u#CFA%xawWS$fKL~mNKMqY}fgrm<$}^09v<#-y>7$wz#A~-ZP~uY zq&hTLe*qm7O+2k)KpH3-Cu&%^XH4q9(?S>Os(zFmAeB2)A2?%_DL-6r`RHBwUDC7$ zRWX`#fcR>Kmeho{;MHfJ;@|$;Z~6MTUN8C?blj-i#PxJSR9lJ|n2wQBD_Tgnzk3fKeDGxeSx3Daj`9rDg8d>C4QN4MbPd~DIZDIR)1#oJU;p*5eQ0d@ ztO~Q3GKw9#(V|~Q=s2pGS+e}C2AtN@;D5qZew{`m*XwoYP;FepY7FZj7DAh{`k=_= zL^JEOsDFh*!bn19HA6<@=P(@U=t=Nm%1G5Yi(izDkL2gBE=}JyF(FH;M&SaHRf=<0 zF?Jp&KX_!kAjKXlWCS5Q>xC{#zvCFWS7DI!_e*XLi?(9d9lce;zbM?=YDG>GZM5W7 zN5qS&4x20K%*w&STeTk6*)|YUz;RTU;`RX1G>stDBS^dFs)3!!U|biS73a8c;IKvD zOh{+ml_9Z4JD9C97BZHt)Xce+O6;An z1m0Fx5OqG59F)OD9o^*A-r41P5!I9Buqpjup9)zU9lL30kV32+J5mgYLFfy|cBsK- zMTMeQr7Dj|QTbZbQX~xVQ3|m+|I22r79j1HN&rRW1Tu2L>b zv#_xyaNi2n(-|oQ=L6P>pE`?}&^<`apT-LHkmK~(=PcaEsxb^rSYdYIy zL;c2DA&o0wUp61|RIaqJKm1+fSpT?NgRw0hxY1@Hd4!zo0>EUN8D3j(M`&D^PR#ZtB z*Rz+JcZi&u#iaE)XOPu|c8D;Pn{om|a#Y7gDj{??KgN~}79cvt28~iV2zdy$r8PYZXV`GGkAM#^vVb1o`~3VY zURZ-{UY}DM`CNvY@|gq`NHo1*XojWgsLp3iDdX~d6;v>4tWAxcTi7g5O~*7GEri$= zkv1wdB-xSv5PIIK7FlibaWGQ6*kgquW3o;G#32M6+jc_`4y_I*$x$y8j+8+YZtff? zJ%o^x5$sHjV6g>rlXxxK=+Mq%o`kS>RjtAsYqhC~ZzRrc9!c`r^vN11q&Oz31(Cve z0yF!sbp#I6y6kgaF{M|;P(@;{0)PFC$N%e_SpLp0$YrgKCMpJc$}AR}pLbEzNJJM_ zga;?bTY=A_G$XPPJja+uaZU(biA{SpP`LJ-=3z}>tyTDrwcEAGvkP7%*;=jMD2M}l zQ`6&bed~8n>qXt+CEmx@l)d|OI=iaUYLbAApbGt<=FoXPBSv+g&-eK1m;VYo-4x`LHoGZCDPF$aRP{(bXE z;SQb08O(j)O=+l#RpPbU1#Jd#MG0_u-~gm0`_H^QU)0Yf48>I`#mRhfaa>7(5vTmV z9umr*xlzvD+X~H|nU=hJNIAJw{B%0G{y$*BJ#PiI!sFjn-kAXB~yARb|M=ALnp85Ol)JE)9Iw&FWjh#{QVgk zNf){i?`=I8(VV{v|7X=MvX+8CDph;deJmLC{X>zC({#Tt&4qynb+=GD0hR} z%?s9O*^-7Z&?vt9FI9y@+fdvdJ|aBS^tZmzz`@>C?O)1>Y z<2Z1beFyPKS$WRNX1mxt3v>!f=RM)(rZH%7CCLxh>lKfWk3$LuJBV-kJvd&+UF^vx zj8&|B=J6dm3rNH#X&b%#6d|$m!|Wl-wqt+&h*Qd_+m6(P$iNMHPeoa75I#Fsd5RK3 z(;UnyQ-K(Ks$;xWdB#ya+6>9>2z)pFKD^-oq2sKu&N(C7nG-wec|MF?3W)WvGz~B86g5=Fc zZLn&<7k}g{Na@rk7O-&MGDPw*kJZn660126_1AvwAAe}SoE3I{zTDJ%i#gybHU?8XmWXH z^rw%K+R%L&VS9EhH(ppL*rtJ>V5Gh9p`gjSnzD9DMP*8wAC))d)@k{g(1T}84_{6pJEov>Vo zapp{dhMOAZ8#D}r5E!CoqXbho@~Ef#0~w-gdm{K*SKlIU?;up^aT{*a&<5l&(jJI} z@ENtCQPBhSx)L!^)qrUkOPXCt(F=+VKZ8;TEEkjcdvmtwEYUYk%?(-zvu&X9n8t?) zPs(KTxcT{#$+-6QOlV!!m@YQvWQ37XD?87Q<8V~g_BNm0v)up}Ud*H9LXQ8AtwR$y zyv@}=(4Ox9zIiq;7v8sS>}7D7pEi*uuYN1u29q_mhdd?vLEutkdXqrY?u%n z?F&=KZ!=d`H8B*}!w-vRuFV`IE9e*v<8dG#uw&KF(HmXPEEiFA&d?19tak22%8SRB z_-EE^G?DQ3S+x}kDP^3`CodX}KyQWD-QB&9RT_0VJl-5fLjlW@hw9!oTHo*^0+OAT^E#kxa@o;NV~}?fMY)h1uM$K3XbTQBBYNen#;r) zg)<(D#7e9Pp}4idppqj8W9D$QHgfw~0~U3PetLQu4`>S@R!)g=2cS;U)|s23UQB^T zypfb*<5*0L{d&=Dkry_q*|y!s(rp@_vB%WD@9sOrow}_jE7EOD&jIJN>$w#Gb0ieU z4katnlAJO;4&v_I_9`RAP7L7y+iv}E@&ie%N%V^qT63l^u?EGsy8Y{?h+ ziSi!jxGdu!iBtG8yt_W;Idt4)xrxFXDaTGEb5(h!-kkOLjo|ywk+0Z!QbkiHJZ>aK z)Y9mA$j6L?h;?#(^thegAhjFON}xu-)O7BVH5DrZipugttGh(LPYjc1-rppLpL}7+?=qD-E1$?=%T(}H>4aXLPpWn$7j@!K0*E~Uq(v_OUejJ zQ<)X;ET9?2*VJS|Z81bt&^#X?gzo=l{N~z3^cG_9I43E{gEt(2G^y77SgJx!3Be{V z^bl-)mSa-^M(pOgts#)olhIhX16=65!4TCSYsLHTy@$*7QT?uj_q8k;DMm!idrb&9 zuPaVD15t7?bBb6`i#7%)q;$rYzw{G&=Ql5oLjanZEQi>q6Mi=51$h}o2Ze=iZ(e`g z7*=EifiF3PdXv?3&dU%PGXGr;K%6DOydcbr$y}z5YqFDpq8;M)=hzR#E~o4D8S6PC zV)68PJM=kbAw(drD_Yq})*aEBTmqkc_8KqWx%UDr(1FY-m2GxYY}IO))ZzRoyU-b# zGf0;?CG0sgM)8yZ%5EC)xh!|m1!Ax+k;;f64I`EwBHM=XH2;Umrz29>2AJGj_^mlOj@m6QCg*TA zrH#sQQT^{Q&Wa%+<_xsr{6BlP?6cL1@hwE9_wex2i~q61l}m3|m7a}*hR&QWCRp?waaWlt;gWZ&h{!ZMZnI2b?quGzP!xl#0xDe z;^^XJ_x0Jlm+enx-rYPZ9YUnvf^3*di}#bfmwIDC!8{s4zQw%wI1ZfDz>v9Nd@dSF zx9__bvz9Ar=99Cr@{FRnTeqnbz5Wq(S4h1GoBfoAb>d@qDY|MK%}Jeq)oy=3Vjy%; z&!~D3N`xDGgQIMCe0)@)$D)DKX&Q&?8L)^uzNz)xszrrU{A_Ge;YC$yh+z~MF|{EY zdIIwSV-$YOwq@nroPk=LP5_`4KgYP(w>@h2R$u>Z2zzGFHsh)GjN5{|oPh@H`!n|M z{s8HZ{}QMF;OEg!3sNaKj*8lXHdt4`+bm7Nk$hF|G7`oVpy#buqGZh=#d1{CO%#Tbt!bHoS=WnL;%t}K zc>Vf^A|zQ7w(USt8cwMVr&Vf%qe=Fx{QQiUFW<%a{H}&V%kOC+NUT>VXl+L*1+`V| z$93Sz@_Y4rw*+kbyq}+5HGTn1jvENb?HEFQPwR^9a=i(VWuwIT;^36+u=S8t`rlD5n(@EkHq9{>a zn#_WP7#vzZ_T9Vx!BEzefbL}kKd^F2xGKkGE>bZSp|is@7jPB=D@0sT(8@ZL*em0X z9i+e<#yrX=skP$n?(W7?!oKgO{5@NP#*Hw*M7%M)n^PI!8J)CofwP$djD2!{4GT(@I* zhK8uE8jaS^`$T0XAph?y(&_huL^C%3ea6F^MLz669%lD_y*E0Y!MK6R-yMkDY}G+^ zdye4IaMtA8`6J&g;_2yWqG_ly`qS5V{o8+l_y686;m8qDeV$@6PUCUo*v`CXLt55# z?Sd(L9;S3Xj^VsBo@pas!p7g0sc8yLw2J*u)F>w3JE37f=uLc)pc%T1*pfm~{+!)M zl26!L5TQ{EZexNF(L&X*a?M{10ihKjNaD=%^OJlo1Sy;dNp8WAbP?Tn6cobXEhpz< zL8(^+&4R7%82H0%oNmp^aR9rjTaQu@F3+DeLwdMSVp+Hf&~K{nHFYG%;L`K?>C9^OH|L=|R&ffoJa}IkXy5%wFuqm{6)n z+ZjQ#uFSqKiy>w&wbSX;eR%Y}mr`(de=o?f61F*9ytXz(=NJNI{6iiM%N{M>FLd+x8%PbuG(+H@YuI z4&m5|v*DwyG0RrtXJwHqb6k;~QH&h3VQN$AfzYcO@{$J6rGJ+ZFQ)_qa?CdaNE z%OV7PcL49M?|zwPF^qI#JMo)j;u26pMQq`%$ePnAlnjqXU_)p)%Asg*(mcDYn@EHc zcK%zzE|dvDqxR#1WjzlKb5`enMz3TYWw%3-=PKuvg;>v%k;~v4rw%T2qIT2S}6WU%sYPt)bLoKt4hU2=&$> z{cY-rSsKfo@gReqLOS0Do13W^cjd=XbQE!MUn!aQH|KlwklY})0VyG%ASN}3v~f|+ zsB{1`N%&AhJ}y?6z@Ha0X{~M*V73Yd_0RSRIcGOCt^q8SZWf)^b zqUUSx)h;(ym=*M>lvbsh&jh>2DYq_8zC_jurU}Wk&oiSZPLxD(UO^-Ho6(^ziIolB zm8HUOvUPVlov>{eB1q$=aO-@*=rjKq7d6aXoSbOSb>BAm-PVQetJzF<9z$O)@@yU+9vq1Ss;UXk?$mEx zoyS)3Xn>G1L$bo;=FWvrAfzR*(v6BJURTGyJA%hTfLVFW%1e6=h7R!A#UndLUjcYz z$#Lu+E^Neh8JQL{td?ej_R<{h#N%Q|oE>dRXccOH+r03K6AESMml1zEI+e(_L6L~i z)O@ijXDwljuyh8y8ko`q_2)&3r%ikTEdfN< zP?fs_Ks$<$>O?)+aFjMEMZ2irHu1wQMfofTQp_~kPGlUd%_^A%^P1)iQJ$vo{^D`A z+Y6Lk@0r87V~n2i7+?NfbQ_7Bv+og810RR&&7^-$@5Go8KYqkV|NI;H;P3rSlvBnU zB1&j()6iORN)1zSY^*ms%g^7Nd1RadVLV!}abPgV00desF8#JV zuHF>{FIwb<7CrQv{@LB5Yg%hqPbXJ#S;%Ih5ep-PtW*SmVj;0A$%ba`S@**kaY2dO zo%fW-cpf4y&wMN9P>r07g45~TRjVoDa=Bt%yZywrOQO4RI4m!ceXd3UfTCJdOtKG8 zC#mWjWT3o&B5U|YBm>YR+HLVGrt)dYcQ$3O#32Esx&U{7@_2*fG;5qpB+961@$sw z#qZeG6RV1Sygixwj!`eo3oDMcF(oS(DYX`LykC4&XayT{cFZcI){4{lgnE?0R>Cf? zTBS%ccX9+#RR%*Hsd;OZAL_k!6XWNo(I2IC6r-7uZ?NF#UK~{;fm?B+JggomGuk=4 zJuq0F=eA!Fs?=h}B}*w|J>R1i<*_<{G&+ghI8aN@%J(x<*y6^SgCerF!S`$ovv1_z z*Ib;zXN#Rn$s3sB+{w8~Wb|-Af|a!0RM{!WY8i?$ri+M&T)Mr^TOA|3Xx(=KlPLKt z-!6oJcvNiP`yrNp?~4dIAyf$hH&bl058C&``BY2~Vah=!E16|k2CD&}iJLn`Sv94j zjJ7eAM!s2uV1dLmgF3zoC1lhb@VU=_9;FsZ6lg^az3Co`5e+t?4W5ZC8WIs)AQ<;A zK@yOg*{3>3TxT}uKVke&XtyO-2r?o!T2SYLRm6bqdlsbuviE1tR#0zM-)i*LzVFgh zwz{?J^%)In;2D;IWX*h-K!ww~u80^9^x7Ks(j!sq@M9>|$f${m30ri$LA*;ntv69R zfu!}UK;f|x%hjEbN_l2gi>|1uDpSCiksOaD&2bx(+R?hzLS9RQdpFq&@aQx7LA&^- zY^r!kS>^J&kY;1iKB|+?E@~wy6b|K#ariPc8pTFMb2zROmGzz3Wxgznj~AJ5vhP<% z5hRW%4?o9{N*mX(*ujXChD31SH_x-r=QE99iWVYe5DLu5=Ik%U2v3{Bj^{D8tB2gN zc#)10Mb-|&U|7d7P|QVh9*FWIBr0dj1&pzK-kABOIY-;)W6v}m<$6#u7yddn&r<+3 zCbXH~_x${rU&oNYAJp1-49@EuPCE%dW(Jt2hZ>)Q}ni__Wn9ryS5 zg691HbiG@zZP|7n^!3{qbFRJX*bb2*3rBgyan(5|D5tix5o0vCO&F-fPY|`mOQMF1?Mhww;vDIaRyXnsbbPY3*y@WpeZr zXpMG=Xqm{0Lc4cG!7D<{f`AiJ*xe3d@kMh*&(DWNWAxImLR>4)5u?w9>yHVLSbmNAqGxT znNpC&Uw*+){?|Xkcfa+YfRL~uqKAoycxpb_reG=7Q%ZPyd;4HmY)zw3Qn=aIh!}~f zK@i>;S>b*vd_%x!&MJh4ghK~SAxCny6pORPUSz#BQ|Di&L95x)e9i$H!KFo7;Yrf$t1kFVdK zFNF86zn~b`hZ$pjhz{^h?I%B;KrTu_co)vhQ;RA6=N<|!E;hxh%~bkt7iP&HRA5_L zsKWYeOTKOi-EOqyJ7_P}^_-6>&ay1spXPRJzAl&XfG0p}q(GBHF$nj9E|O?3F%L1H zMhQG3ISlpdeV&M!{_^6q3`X%7vSwa}UQXs;bW!&W=f>*~n&2RIgSs7QdP(Vr6wVX( z``d}koLvaCzkK~+mYgx9FC4ClA&-ECKsFlj2A1CF(iiX7Xc#}j_PheWF3i4wSpC#{ z$DodV+l`NO&D2yM8lUZl5HRaYxGPaYRFgB~8-@@m%BJ0t=OlU_qYv^PUjF=zux!sM zAs4W!W{_UEqVMKf4EyMdZ>dDDMtlDAedHzLgf#gA|LW}R_Xhze(jEE&^;+2Z0)FLi z>S%~g>c^`QWjEh12s)VnsH=GTVB+a*HI|F{2BINn%J~^78mJe9at^g=V3I8it@7^I ztm2cv^C*$00Fu~D=zt`+^Gmr);$$ira!fMLr%_h2LWwTv4yVRso};O_OK*~6$njoE zz$dXm7_Bd>3V9#Xts_IhBhxmX$LoV_LJIM;Z?A>IHGuw!6dIHFn3ZbNaz0>k9-%JUIjKNI5%y%PP-Z z&{i3#`vTAmDWPUqi9+XFkuQ26UghDrWbu#M9M>w^A@%9gr_&{9Va8)D z>9o6mg7=fsTsJ)kE<{yd=$taqv|CpmjJwzrdevv3qn;QensmGV!YE>RdNq{v7p)>0 z(RE~ho>K6N^!azAD2)F5N+zx*;pfX<4>Rq^a?aTH%?e&07JGGA_gnx|__(ptwLsEh zsx@q~1Jl~VA0K5f*iYF7Pw-e1YX{kopa)KW%q zdhn~ewV_5AZ#K@;?5DBmHHXjJR7AH&9*>8uVJ}qCal5Iu$_9LQTMKYcAm2}9KQkpzJC463P|g^59dcVPJ6)Cjf3Kq99?V04?q0yVb6G8tu~^kzZAnoi`tt%3eEs@G)(#W?OW7rUjlKAE&*-_TIjOz36S&~- z)vav!^3$KoKFyM^d$#q^f6sCl9ly$pM5aTQ^>^_8|@xb9~32sRAVa zg&`(9pHG?kh`F^=FKo1}0wPhm#%z-%T`x3AK4%hOf`@>-7K4S8`&?Taaid#=8w)O$ zNvP7F)?X7LOey517?+ZuwG)^FQO4?8Q>a6|-I+Q7Wk8z036dh(?rrB(uVd0skFS(- z;R=wZb=aPm?8i6@9wg@tw1}G_MH>-$60|N(Lm*;0!MwUK^pdm%;T&2GajD}}c)%WP zIJw9BD4tU^fsMPG9W1ISTUlS>Lq3)MEN{N(eMWo$sJ8~t?$mfH+8NLA0l}P8Hif9* z%w^cg%ryrJZUN3YF`dNQx_jxkgFC=|L2IAs!b=JCwPI^tr~uzcuHPaG0g z*qJ4TvsCbx;MrdUj>i#}(&U0bdVY^xhVB5-LjD|s6F(5&?eZ}v{~L%V+Ng#K_{b(L zls#H_LR~Q}ibhH9eoeD-Xme`IDCqGp4=exqHbK@j3rxE{%^4$a@t~FxY7*-BLsv@; zUts#qUP-t*($(*KeSRm2@^D4Bv`@@kNBLL+|0odrwE?{evN@ z|7^?GjteFJc`B>lzKNLWT4rP6yA(@9lxFE-aTBbdV&uxJ;*y;~p1Y>J7SBQLIFJI5 zcJfw0Q`jeVzR37b_jQsr0FM7q4&pl3&gYemUA$$%GRay_+%zXT$L}JSZRH(K<`J>) zT#}JoIz8to1=vEBU0}1DHgMh{J|I`V$?&M9CuI}SiF4}xx`=rE?;F8kCfer-fffft zc(E20lM;q_C#pOA7}F4Ey@SSBacVxRS3k?^^+YMzvRUUCD7l>Ov-&4L#`xoZgSWr; zw{T3t1{NZ1+wBrFMaGfyBYtf%{D`)ca-Pb}A@1qS(d(lzzjVkQbmF^B_Fv35yX(nK zb!af>2q7&bFve4~8AQCmqLPnsVKHTi@QIRY07TckEt=2-C_BrTm9wa>0eoMCljj@% zPB$qrs|Xo~+gUbc3rx`L%n3{da~@|-tAHF`p8a7lUu^yJIx5oN|NH;#_n$w1cFx;p zl^IqM!6&Gu| zcoAKdaaZy-x%WaA5iv~-qX?K1-qrd-$)dGZ?6=#=H|bW<7A=$ zUMs^o^dw$t=lG&?CY2wf#=spX5l)4m9=JTpE~u49!5S*8qBB@ z;&u6Tk=a8mSo|EmtLnoOdRjJ9eqGnXhtOc*$_4qIF)pIK=WzO;?;YvY3+swvdS~~P zRzig5K>A|Ya~oF?wrYi|DXJf#Xny5!R2dO+W}v#gUyV)?*5Q4QbCIy{*_{mtY#)0b zmlqISM{*oUFI>ME%%MD{D8a^QDWRtZ>Jmolh|-8yWYioIAGV4sb(Qtc#hSLb&Z1Rl z&665Y--#7t41>vfO{aT6(He~tBbVgid1K_()G3{S&gRb7=It5}bmeD8;{~t4WqogU z7K?9La0s`Z9oqaz@urOs7pEiwnsQP}w^pT5Sb&1=Q$<%(iZ+^K&Qmli4&&E?km~^b z^aqr``s-*!NCZp?713xY-*6{OsTfWn9-SxP3Ssu@yCOtnqK-!Dn3!Lk7&@Q_WM+GQL_-|*Aq_#AHV%`i8z zKubk%WaRgy8eHSRV1d$ecJ{p#h9ZLJm9NQFYaNrsc87RWtW+5@KelEp;&>g*Gy8+z z|K0DO&nI@_EvX~;QhxwBC$xSDi(V8>rGOAHCQF9B=F=+2)(64I33>0 zML4=Kl~*ol;SP6rCu-vL7MxSh42=RCl#g~i+{iWrVJXgot;WFry zG_T4;Rz>ngXL4vVnX@ORS0TX9i(is{hAW@QL-1=f(=kS~yfHJPoMZ=lF6@02L;4U; za?N+sXa=t&;)7#a5vj(ECO4LXyI?|RKZBnp^gqPJ>}%H$lu{d@4=&qOi~jZ^~e8m%tAP-`8d4+|Pr z&WNrt?_{m+>%O4$UO`uqG#A&=`L&f3DrqCC7(p?hjSd>(xzz`&nXPy$7L0rx_2dTc z-=Ff{e50`<$T(Pfhby!&Yt>eM(@nT0CHlZK?CSj@j<3F*RU2eW2wS zt#kr0sj+u((K;|cxB$YO%?*ka(G+gu9QMPs0MoNf8xf5L0tru(YyfD*c0fd+fE*Lr znAS|E-}}9P_`P;LoS(*B`<%nzzag%)a}EUOzqH~J+9?$F8c)NWRI&wEO8F2fdv($E z>JFcorx&$;hBXRX0k`IbB0f}}(CwYwy>d!t_|rks3o%GWQ1*XbIW^vGp7}J+B+xDw z`atIOVSU$2)X2**8UY=r$ewAROI0kI^W{xgJptH=;Bt|9PoOrMZ6NQ!dQnYw2DD2p%n;=-`Y=^z9V zp3kQge@n9L-fxWK=b!p>OZjs}jZL>5Rk)gdOvzb!yTzyI`Q`blS8pQE7rO=> z^Z8OR`fzq3@q-1%)ny(Ui$c?KlLxOm%&t0jo-Z^s{-V>L2!5&|N68$59VAqn#9?PHVz7MsMu_oVr=Vhzld4Y@Xr)TauQ(;c- z%%@rw66!Ok(B}7T<&=do>W&ns{0L_J$KX2gnfWB}4j8cjxf63klQem{cx5o1q zMLen;_Hd?j9_n3+Cpr<=7wIn=e5qvG-ntR|t}j|USnX!@XDF%OAB;Y$&mU%L+?JgM zfGMNgq568gmQ%XqNNM-m#Zg@spC>36=XrCLyZU@JC05SKW5G>K43(5RT_^7gI^RuX zg-mtaAtR&V#+&{!JzmENvGJqOYrdiS|L7+6ToB*=DYUH@m=_#e-OFwB%3S}N4X2ym zUncrl^y1-BAmn0Zx8Hf`cGd0JBLIiU_OF~8&lftWB*k?e4wBAg$4xwZVo28g_>0oR z?_&%c$I1ZHHSR4&blqs-M3;!CYbU10yMABzpKZKH8GHEPWnZuW;6mKG+B0HXO8yWl z6H`Q$-=V+D6MDV6OF19@o%UXhyQCfTH9qMYx1&V)eczYL=^FvWy7tt*KtD5|FHt&X zR^n-%-8J6m6!+npFFjwL&*!N)@!|qM-qm8z3vXg%#NmFs*}hORzMe5DB~!KPI?~@A zW0b;uSyt%Z_Xqjo@xYvf=i|A!bMkrf#f(`^L?M!YZkCyMqWO{7I;1kT}f2H1A)+t{q3OMdFfN<@lyPiL@ZDka=*H@lB~7U$LcR`-+s<)3%X z*=Q86ukYAPLCFOnu>X`6Qu=#!&FC4WX2M?0ssbfO>LCCCbLP}}-8VbB2lPzPDTh&5 z+?r7|-NM!{&Eb?08ZOf#FT^mLqS3hso=i3eO+=c&=v=7GAt?orcidJW_v}dGhQKy+ zYpkoL;{Yrz0u)SSaLswuv(LXT&u{ZZ>ZF0zx$d~%?-nxtdc7Di{lkCs``_~-ik9-; zJ45o(GRl&1v-lvLPN}oF2R@B_S;!~jQg}YjRXOB49IsaVR`|4DqNnbZ=BWtLgH8|B zZ;@{OL%SjiaOy=JSNZeAA5uPmmS4;nvDySl^WRk$UAzR?T9@gZapwimQLade$$86U z3qoC%3X6B*FNSOJ#bd|?-Rk1;7pyOieYdO->eY!{ovJ-=!gJpg#q^nu`gm2f_)YXp zF7B(^=gKeg9sZf{8kRAfK0A@*Pnrg&Gly!aBXwMUbp_YLILaFGK0j)3c#TxK8XS7X zs7C<5RZMB|a`pXMYC+)#eZx@J7h`MeB&66&2)ObtdJjEAM@i~*!A4d!q`Uv`8c0#+tB6W*~vUDX`t`d;Qm_%NUhdi;`35!!k=LVkr?G5G!u33_E02&|z1vhB zmoqzjtGxn8mo+O0!Z)~u%E!{*?X3p<82($06Wkf+(Nsf2I9Yzn|{KYY@9f#C@aTxn`P%0R$UwFV0mm(ae}ll!QfZzhw`i z&n#zYy66(V?V240J>>ldf^f8)H<<*58*fjN1D>Lq=6EOwDn+IoRMSvZ8Ya7kyTt8; zWyq@|=@{&MSBi>%c2WJ@uCymnKE^DQnV2+N97FEz+8WaD{LVl4eq}@j>E?qi?rq!T z&~5+$x7+>n0IE&5M^m4q(XyTiJx2o*0G2+DY$tI-xeLv6A3Fi<~ zl@PlEL-{2^0&@}g(k3Z9n4FsyiF9=1tW3v|@o0-Tn2a$9Ig*K;+a~^0Dj!##i713P zbe2rTV*Vs!p!JS9_)^fKecLvr5!lFfIL_AVI56a5HnM1nCPOxZJT+(}=3pi5(u6S2 z#Rm-jH-4MI+J`{P$}d_6G%kj@(;6V}L&b+%GLDiK=@9qt(L0YfCKpsGv!ZL;cXJ+| zmx!usQ=>u@b%ZB}`dke-{n^mF_qoAogz`ELlzn4Yd*j}$@guo$y6)js^qt4fy2q3= z;!#)S@(q`v=8H!y#5|(LmqHgi7;#}21>Q}pY;?42q8wG43188VB~`)JdPjHT)2la_ z7vU%x6GL<;TeEX+DVT@tsURcwsUuGUhqt>JBt;oah3L*#Eo_5JC-Fs=7Vd;)!C;M3 z%5LpWhgNs??K^#sZu`k78Dm=ER<>eDwjb5{M$ucn=;teCyP%@50Ai+b%+u)gT4avN zioT|M>@s@wnSTmQZ2PuijsT?09M$RGXOgqR?^!*=vZ^Ceso{YPPAXD(NlHx0i4m*-3>wHH>e_C*Py*Q?RmXkGx$Ldl zqD?Vjk{7`dXb$wz#W;Bi8W&Bdk=zJ;)f(8lYl;^T|gR3GlkGRCRgS|i04G? z*D}>$Od?SFU<1O|J6E(ZVPc4)F9Pz?#{{0wCtqYi5kN`nmc_@1dp94A0KVvSQ5sjn z6(2ze?MwvU(A%;O;C!ehN#C|jiaSQS#!$shz?j1zezxc!$;DzdNQ?Q=3;%Oc8vxe~bVo*JQtL2R?C0}=ZM!*Azl;SCt+=yd$MHL_1nH%0 zU1Em8Ap=hj*`)v$K$DiYzSvjUQlNr+5{r_oPiKZMRI#0$^nl%*FV^Oi3;?>X@x}kuu2U$ju%QUC#9YzitDasF;t+SzDVjS?+fuUhk+0} zdfv7oNDbe)X#)A@?-+miF9MUJk@kJFLd{QGc>K$vl#&w$O@tJH2=v*}M#IEJ*FwK! zP=J{hlTW^gOL2^#MeI@&#u&tmb08v^z$u8rUadE3t^8g^J;+FJM@YP`X^=JBF+@=n z7KFrS1CJ*sa=wYnd=ip*M$kw&=T(qbNdb=Hz`#jPH#sAx1Wu1jJfJ8< z1CT;MJq`g|*oUh%oh(dK91fXu5QhBRZ1+UyuLn(Gz1PN&bC&KwRdFE(%+}3wMLAWJ zr&al54kOL#taB5mUmYK)T$LYYSjj$ zmbV&W{y+|=;r))JlS;w(2E&cNf*eF75g6({mm64KFY#gOH)h%un`7k3Gc-xfkT&G?mYJDsOi zN(sI86Bi_gfR1hSXye4Ik+I41rEt}8D;otzb}3gBN1kKMF1t>~w6$xo(y`@& z*Xt#*Qc)~tI>zJzJBBD;b1zX@NAn+xs@`*cM9OoG&gAu51ouUDX4!a5#iDZOkRmE9 zb+nJkiBUs*%OV-ezZ)b=&``H_2qKX|(u64|Q!j6#f!bb3`6ddtWbZ8{LE)V6=ueaGxw6#T(>fFZCU^tOBdxcMPr zp|vK(t?XZY22v2+@AuQFQNLp}@c>Si4(W$?eEp~YJ3jwczX_UURLc4K>xv=1J5wE3WO(;9tFSY#~ zgh_D;&CEd`;vB#Z0x7UJmyI*EsEX-B#8C{{knj)#XbhW1c!aXgW)z6%!lip}CK_YA zogj$nLVhW9U`q3q0_JEg)SB;$oDz;U(EC7b9qGUO?f>EXSQ5TIpO_(Fgo$Gg#4TgS z0QOWRq;10hq0__+K-xBB+A%9(^nlqTO1go1z-&N70nLa#-;q;7NgHO93Y`*4`Gnbk zl5WUpL!=Bs#^?-b_eQwyZ|F53h7Az~_x&?(o_NFP{O@8W)MFxrf-wS8C1M zXn-I7Ae1cTq?1RVqYqAY4*|0`LI3KvSyx3j8O0U9boY>MjwOI1qP2PLX3c{fwHk33}VEPuws^hCyXJU z(SlAQM(geoSA0?*1Gz9-NkrK4W*${mgvr<{D8SC$b+LduMK=CZNL=Ok?9!nbP;Q+)OM;PDcJHqm%)OVv1}D_?|O zLUcjkiUc{;*5okUIy$<1-=>IJViawVD#!R4>{6&)6hSmDm+2?9V-rX-TtstB_FPW>D~_N*54 zyq~)j%=&%3X|aa2dtpwD5qKWx|JRR^|JrYW6bTA}!4EJGX+olW2zHk6d9v~7>J&-E z7A{QbAZw7k_)Hu1QW!~!2q&MpQVPC&`GVW+jyZW;o=UOo-XRE_ofTdF_vE4qB1&Nt zuSo$X_AX!^HDMqG62OG4(bVv5E~eDgpdrx2oQ>aSm}1+&=n@~J6EQOh{&_r1ov8L3 zYNuqh9chdaCZ4YcVggbQlGV&-P9IX-2iW-pY36F{@-D?&>+9Di#Tbmh-s%e>IF+A3 z-|eN5AncIdY2rm4kHcHh*1iGR6v+Qu5aR7 zB8N(hXswD#S(XLO&~I%W+a^2JCOzFamU%dz<^wI(x6?5$goWxi>xBE_>!h&sXdG3+xc;q+%e|Cz{R$rB$H|@>~Gvp8DX{B7`YWw%1xa1>%rl@iUe_E!lAuWh~$BQZR1!MbzYw| z?e7&q8KNL)JjP#V@xE`IFp;A8heCs2fqnw{37kqh_j%@A`Zly5GMp4k7&IK$BR4clr)~?iTln6kiy5z<>6xJ?d>MW2s1Z%^t6kyAs5C$ zOyKka+DgXP_XnHCksQvEp??xHw^9n?Y>Y076Zy2uPh|J|E|;j7#3o)BYOu(GqjEWn z#{9Iw1aXTmaUH4_D?A@x&crDvw92NEwKkDg2eitEo0=I;DNHHoc(UOA^~C+Qp^uK) znULQ{HIapmC%hr+l%iT|fHe-|?=|~CDSQxD@iEF<;k9l4KM}JxY{Cyy$@$~`fqi52 zs*gn;4dOc&0Oo|qMa73z!0on+nr)ifJo8Y35rv!ZzP6G9Ui{MprOYL1Cr@+V`Ac)p%!qvE#TRzyvRGA14- z65;RGQCq{NNYl0%r?1tDs4C1kEV!NP2o4-4EcNf0Q(}hHe#7}K$;e(`V2T{SF~>BH zToyhZr10lvOvfbLq`bYo0g>0azApsAoWYD9d4KZAfkWH7iD!=2z^D5gCUt4D0*DeO zfZM*wsG3ob<2bnaflB2&QYtoYCc7-OQ<3SgYHcWPuC5E<#|gd77v4RZzz3CL)z zV$6Y0Z=VD;BSQfB;!Ea5lvTxM2DohYxb3`tvl$2n^Gu2X!X1|IUoa=uJo=)T9S5dp zP#}ra;+4#c1QfbqZlG0K1Ox6lKy?Hgtv%uf^)ySBz>9e}NHBu~jjcuzp9 zjn6Hi$>{zdg3uy>lz9ZIg(VS(ZL?}NS`-bxC-DswC1LCQ9a3S$HU{2Htu-e8tFiCk z`%WAFl`pvXjtK0I-rKNIZx(vTl!mO^zn^8&L1>*L(YX0wkV3g{eXdbI&55$*)x3&- zUvICA_$`zfcw6<*rx^@VJ91Hp!EAk-*5CmEboCH34142aW1N-g1e2e4)jycJT z1xn`28{mWEXw{sDa|t%{-L?(yU%w*8gl*p}@N&$_FggLFiz(v(fCG~_gn9~uTB}I* zLo#RE6sAa>T?p^&XuUJJP}M<5Cns(*G3*0~!HBkp#D(bQ(&#S)MtRg!u(u#ciY_u% zUM%%aF~hVz*oO>3#P{XV8M%7E}e!uhcX^g5dM89HeT5qCw3rPEp zqjr?Mp|#E#Yp94JqcxG@Zvpki&*y%>NjJ!ayK$n_O}Mfua%knODH$oqANulbf9jh8Tg@aqz`dcBGu} zdR56XJH#zM3r8ojC}9M2st6^bRu*@(*0660NywUffbvB-C@@+a2#@DGwrxip%T)LM z>kIpB=L3tlNQ$~oLjqyQXGv02SG?VCvL_koXpM{;S=$S@+YN_E=Z6#oV>G;36jH*g z9?XA}y$b-3=M%Tv9i0Lm&j-quxhNSEVVun#TW`p>yKpYMTzJ6k#!mdt#}jXNR#3&< zrQiau2@vui#2key$QQ}y`zJh~4~)^V?ZW*DjB3`Snnzv?5p_hozd!LSKl+T`o_POS z@!gNU!|VAKArNl+hLkvw;dNA$oN?PC9*=|1y=^xq_Blno1ODCs3l+9~7eh`yks})J z_d9<0;R`FHOU9f9G%DV11%n7}fawddaUw}1nk?!VI>1dx#0Dx z*fJyMJY8TE>-FSlmB-_Wec$ku4A(h^6j)+_Nd(M}@9rDEyg#ws-Vmu9URLYC{eHva zRhdtkqacS&V&C_I(GI-bZ+Jc)c>DYb&ljH;F-2@!!e~4~+HW^JUJntBY@Df=w&ko8|GXlw>f5%0(|=XhF|>r=P3DxqZ3}ofnWLVGwSP!EoZ#yflr@5qtAi&=M$|r z+{#_X{L`!sN)GHdW_K6wzfO~ts1iH-d>sH0KHYcJ*MY4tDSb+Fd%Tzn^rQC|{`8;y zZ}F)6Jc>;SI0VgC#J#qT890M6f-?a>fBq3SP;&1)U+ke4hJ466T+O>w}NA^prN;hC=)83{HVH}X$e#6q<~N# zKafflpU)>+Yxw-5?*szQi#HKyL9T)2@L@1yJw#EGOGckOs$f|&FRD_qK=gcgjXtoY z-I5qcF45YDb?hoN*F!l98IMPh9eu3XHX~$k`DMdwCdL@p1rZ2Bl6$+q8DTExv=*SE zH#E(aeY?FeSuG_LBI~k;j7^aFknOdhY^)+mMO>zZ32!4baa3mXfsiTjNHls5O|-Fu z+GgzcyQnIGDw|+$52~IA|HmR6fF=_nXc06-9_KGa3{4Vog!vJ0z#f#$Xbu)M_;)7J_z!&A3CV1QT|F@JyN^ zSW0T2g6>Rl3D!{%`v!GK4o)(fn9SAb9DC84pmDXLY>cEdwKIqb0|Z3gWHCfUnrOl+ z0Vy)YuzAUwg>d&VWh@gdgA8F{j)|?@&>N3dig0K)DHbUKDe#78LTBKvb_`4mlpL+; z0RmHp#zZIPIv}yaYz`ZIuv|EbwSwf`-EKRALyA;=IHeO)k2{SG3Yen$;x1L30gYhG z2V_G|n{=Rz25tL>Fqb!;%HWUV9eFFK(bSwP-bJ0EoAKc`9>F;>Hc2K}Z4ISFBlxN< z#*E|SKQ$*IhV4XX*HLbkMy^&ymj(il?uBQ=)B_gFL>aw=5HNzo`XC?$rgF`|u^B|e z&VV(x5L=A^3|h|8$BP5iHR7gEwLeLQSn61VgoHfAI8;X`DHgn5Ur{pi&q~>aqzs`+ z>=^Tj6z{^#(IEB2mw|Zw9hDnrjZaI7FIEIXJ9tc#(o$RWmKi?8wm@5T_^%vry&9G!#TB$a^Haq>x_O zz?#&8N0jgrKmws12ezG+pFA5<&%rq1Q(tRrVS`C5&{Dd zb2LN*v_7q950`-U6;wSC;s(OO=nN@unGDg5qC}@aCtDO2Tkse%$~iiTkRublQ;ImA zFH>Ig{$Z<=03MyIZ`JG73?SI|9q$iTg7fnoAA;Wr>~z4BPGV%f!DtFA?I1b3rzDn5 z%nQ~`Sau1J26U)Z&Oq$}w|&Fx&5+Pn9oPgR9DSg+da`>`b#3hvDFr-VFN8<^LUZy# zrL)8?j@O5H&&)AE0eJiLNqAO?M-Z(sVHte5KA$h#G9xk+n7p=cJ11Wg;kI*?yXAs0 zI7VVC8GXoQC&7z6!xlfPTFuao?E^AiuWI3^N=^?k*n^nh11Ss4?fDg3+AwBwIZ$jT zvE6piSnlc&zn~@yBj$`iOzh4nn@jlO(BO1sTG4j>_ij$ZAYua{AOZI z?4P2x2!Xj&QKa9Kra-1#sP-ZMJO(Lb8qb5p?@9fbp2t^gWykDOiim_Ug9UEpt>F21 zAb`iL%5fQenBs&lg#nt8q2?r9C3yy8OqA{B{6nU>6>Ffc&cbudX3of?rk6dxA-nbRX8mm&yPPSX+6ID}WWp}soXJruG7 zQ_1mZMB~MbskSl89C)d|R_k1eZQkuFT20XCc*}Tyf3S1_Z_EIPJ=DPhM^IE&Ng zI-0FQmj+8kDG@{wZFJUlv{!8$?40)qID%UN5l)SrJA#Wgex*b1v?j#Cs?Ly$Zdg z?2?h#cpNu7!jFHB$G`j&{OaHR+n`*~Mne$KsFT+nfZm3zH=ab@Zab(?^f~No(V%Z_ zbhdp5CLwg7YzY(wsPj;aN&*cCL7zuukM{@eZ+8??VfWtAo&($cCIW|IQ8USW*m$2z z3a8kc7y<%Kgv{ru@+eabn4%(nJl=)RM&_&4`>?aWivs_4DQONymS++n)Yn%^DdHve z3F>WBTa`n<3Na4OseK}XgC|1>Xrl?qj8UsOCbli(b-bkG4K@nXIGH)Rxvy%d^O%eV zeEISP+rBedJ8!HOh&+EM1VKlFm`G09FkKFHuH;Ebt^w+6l@LNg3?$O_rCMQ>J9q$+$CE8at2Dm;gBE;P6QV)Y0W)=Z)OEl7$xxDQ)O-iA8Wo2O}bVbT(jx z8qzT$Gz6g|BZ4P!uFXz1D@LdxVzxE=UW8*lXf2W=W>atg5nJBa+e!omj1(p$aQ8}> zrl`u1J*-k;`FaQu6TESvC~$Hv{Cq;-k*ekb3jc#uj3k9tmo+3o-ywp+ltnyES;*+; zG!>wt5IQ>tl)NpfGFhYi&Xe&~vUuw-w=Igd6vO&$G_=8%BUOdQb_^s0 zR<;mXo_W1D+-|#!A_JzZ*&)bshzV`*ch5ouZml5`qiUsa(Lx|}3{jCq5jRu>WFt27 z&s%7Y%C=*Qm|eIUljH*9!;%rN<^Lp}1IDqNG!aOVK^Ck`1Vo_{zzDb#BTS5X2ql6M zubi@TuIDvU@{ZQ|^4B6$ZCu8f4#k?L-tvLekc(_evD`;vh4;ojJvn_6e$haP#EB%L zQj4OVBw2T3ik*h|;#p3neg=z167yL}2S_omEV=3JW1~pu#WDj^RGkyz3V=yLNXOIh z>jFY#&S;e98syw%fJ4t;0u^q;*btYwlZkYi(b=F<3GgBeDP`m4ModXr9X3T7J;XRT zSy(&ufk?~HIK~JH2~E!V2;ev>w%g9&LtoZ1!z@v9l~tQ5ad>s$=}QnRob)~MB{^%Dtd@BlFU-joY>Ep~v(ZCbo+`$;r_~v!QiRyr zOa-@$FmKY$4uK}wg2)_|<-xtAQX~wtK9FMu1%_g4Yq&{{+i26GXVmxUcDu0x&MEhD zg1~|iqcQQFJ1~GSP_`T1zq~VqSc;%kFCNDbD+!duNC4Ux5+5Msz)8rP`XRYYJ2AAI zbDDBN<>a$-x7rmY5kD+bS&V32N36`52yrsECKqv#k9Jv>l7(MEK;T(=t5u9nBa&>g zZQCq+5K)^Pb);n_(U?P!CCP>qS^0h|65A1wLK4Jon!7O*5lK)=_CQi{KFbLun7R#- zod;e^0T%hA#)3Qo?gHyWT%*o0$LYxji}^4?#1Y4fkw^<7mpveg-7!@$8!%_U>o|~8K}0|i@U9+J zKzhq-L6IEG!4O`T)T>(5soDuKm^;Zu=(A|AJ}|8!EDLxM9m1`s;-l zgYeFnZ#SKTxFRUGw435IMBd*oO=aiuDEOh)K7<^VB*v$%rl zMYICSH8u%E{5iJFTtXQgPju|tCyY@ssUwCPQY!XLxgle8iG)iR#f&)RPoPJ|Shx3vjTI%g@+BU-OA`ix>4%I- zH^c#m6a)oYG!s?1jY$?_uHup7`4Z{_H+|f2aw5Rd7zGam%-)x?w@_bV$~ayx%bcx} zH=D$n9%Et%563c7nY_zmCiQ<(hj=kBRy1?`>Cf=|SN|5D{?30ag$GxtU7QQDI5k zHe|`bVfEnz3B9D&!|t0XW4z($Jbf@Hc~Y=Kbo9aFc90d!>b;i|6Y%-$S((UY1lxx+ zhf4)Kwcrz5m)G-wn3vb0*-}`JDT%895Yr~qmKFcjMTxH?d?G@xFSO3*a(F&|pk)&; zn_Rj`MVzkj7y1iSGOOm6Aq1=Je2$#=X3-8+?fdoT`1lW>EbsHjRz6TPWs!wDi+W(X zbZ`A!J{PLZCVY;LxBDBbwFDi}&)r(X7B?G5>GxQEBK?%(r!Oyw37`+ZRvY~gge&B1 z2-Fo;eO!hS)W<19P|5PwtgaP96NTUxP63tIcW0Sbr_k(a(taPV>@yZM+w1!GSFR+? zJ$e0^XwqBd?d^I05K)oLdy2a`R-e{W1cv{;$ujnsf1nCB%K&s70ga?k8MKWwVz3dV zj)r^=WQqZVB#3R1!V7r4p1jt!&Bnj_98KYpSy9$In@pz2{1*QCWZ|U#yUei+0e#My z%AL1;Lp`dk2{n{Gj>8#D2IC%@Re>w&bswslO2f8&7MhyTo-#RY7|8{EDjB2m*se7` z_z^hV^zH4%9-_#m9YnOsJk?t>+^k{VQV57uhu<&WYC|nXw7F5iialQ}kFQ#*jl_Mt)HU~T+WESSGc_h)lGg&x~Sy5$Texeq3kbP(c zGmRyP5;t+3+Nh^6B%>)mOHdK&|f##9RsZ)Fo)0jKAv(jxeG zc3W?(UWfS!uFT4@?2h#A$s5y7dY7Q)h=HYSRo+%WT4(I2CmR``IjZkL_xZ`P$CV&c{avCl+WtF8|N6Vj4~@WY<mh$(3)_duQ|4vf1bx8e@ZSD$e}+*6-%myI0J;M78B(Ui==hyiVnYxyv;; zYYIJ3eBiB)0{rLj>q*xVi!$OVTTlx^A6l*d_jo+)e2FoNx+^dra7=OaW@On%w)l7C z3;QTPzm&p}R4E}jgG@cIvJ1twf_-*5k6^*mKGga7eB#rmPxiaJjd6Iq=!3}BG*Sy3 zEmrh1_+V>w#qUn4p7VAJrB}yn{jSGxh>>d%Vav4hHUz%py-}nuz;&PLd)CXu7e|&a z7~^Rz>K?0AedFdOeENLJ=^Ek-hKtRiUVm=C>3Y)NW%;+4VjePuun4FCgc&X#bE~27 z`HlWupiN?fqGvUf?F`{`ThF!Bzlt2rK?ar!o3Yj#^JSv~#k^B|1}8 zJ~N{sXfYM^)=uj~?~VDVKf~+){5SaSKl>Z#LOIC7bvvou#M4QgH2Cur3=s_R8i>Z_ z^i6FNp-0x{S`!Hzh+^lG6g<{gNTHRpaL%$ex^3Bs$e&N8u-~Pio^wu6WHFD~eaN}w z_ZGjeZ1>VppQq-=_KoI$0w?oYABe4cQ3KMgFi#1y^|LFyaCCz;t$f~0=+BI3?dh6$ znN$s?d%VA%;*~{6fA9yt`@Iqx)#wcFL9Z&<^Fihbq0!4fx^CHKl8)f#<7j-Bte2^& z-|~8>9)<8-oiAYY((_1_c9V3uFqB8KOx-$0XQ{7w9}O}EPjoK3KGD6khW&OsMLhUR zD++(2l)?mgxXdphuhS$8&*iv`!@OOJWC{9!UH=~RcliRI)~XT2d7LlY8`seI=c*TJYYn&C&3>OA zUd&UYOVkTKL<0H7&7PCXfzt~%T+kRkkgGL`dMUBb5XrlaVgQ>?g{}Yo`n+Rwp4oIL`5MOw6p zVa^{+=nxUirJX&;m}95w-->1_>bh$@*aoD3`|k5uj&kPsgaW!0aO=M7#!u4-FkJ@_ zGu!xVc>Va#aQ~~n!L4~96d`;2ro;9mErg#(R@I%IQ^aA%X>w$sfh&3s@%r}NVt$u?pe43F9N`JAa^5BLV!L}zT*US{Rvu=n@8l0NUqsYeKe%5TIavyu zbLSpTU6B7`{-IwlB;O^&jq1$jDd$sF?Kiu2kL1Q-T6Ac!qkr!>4y3KHleKueuyTil zw=~w}H0SA%$~l`{+mGpNW6q;RNAc#{?dYN-5bT;zyAFVDsU*%TavI@aLFFB^ZL`krDsi z{eSv#ip{&-$auxVWY||MWX9;fYJOSC1T* z=>}2nTu1SKf9X2*>tW?vb|dx|Q9k;yv`1@o4=G*Xx(}z2!VyUh;N?@}3t%k_bQEfe zMVGs0h0vw=9%BG08Cs`};BM!aL{owJhFUcEJ=4Xfu8C$zjo=#^wZpVQ4d5ieyhui200ID=kF%U;v;%U%%_0C1*k^2-$2h z?j{@k?^5vaI#kL6H?^lTa`3wF(+a%@^>a^A{_4zA-|6%9LTwFiZ*R7CqAOnf^U68O zd33&Cd}B0!{8Rk=pZy>Bwg2)raf|^(LYicsSqm{$!UqwP@$Z7EEHwn0pYtZvioVvD z@T<>($GlE73hR2-=%3?)a+-jF-&MPut?S;FV;ffFqL90i{z(DW3 z{?i}+qu>8tFCULWX-B*+wvXMjqDa20>uyx%gKsTk$sr9sl$a3=I7DooF2vI)!-X8{ zWs)x4qh3bCEpSC|_hz6@fVbKLKbN1MqEAs+VeB?@J#M~XtCn?a-N@|?_c3wKZ4P} z6zS0g?qge2b!3jm4teq88DA`Gm#p8@^Z4}LdnAUl6IbD6oIVY7mO?|JCUx8n0;cq?IOvB3-+cDNL+IE9{kxCCrC$g*OA*A z|7Cj?+qN0!BfIftYyH%~YD1!pl2SKxS?PtRb`$y@buIe~n#3hug)F{#_DF*N^S=35 zIc?F-7LU;BzHDy9rHbGXBj=V%5HS3||B z(VD|rt27Q$kjgu`B4Fei4Sj!#NNM9SCll|)94het>>&CpZmBlEm(?JG{qQE zBqD0M{m2xN!_L*$>#&pzKb7)(L5nngw+RRdh(L}R3~Vn2_>cl!(;0@0&y{@61)djc zkootW1M11pIpu-*GgD1tgZg#JUe|pJK|s~q`?lX)nEg5Qo)r+PV$BGT_g@lUNbQ7r z80;I9gd{FQ%mDd97?@*S$W@>-AK>cep;t1cpP4eu+HA(Hm39p0?vOi;aq6CYVPPGQ z5T2p&89K6YqcQs#VdWqhDrbewFvGGdS@p^hTNj+0@v7$$k>ypb->uyMODJhhv{tc; z_Y?m)HVD)Wu^{b!8sVm#(Azv6qSw)#nLWxgu#o~0x0-DS_o2pK~5Nk$I%8XGJ!S@yOL8*wSeq>9A3e3k{cr6Mk&!OGaeq z=M_0*Wv^VOLL$~;+F#oKGkN}73<-nS7jB4G+P>cnIq?OW6&g;o;Q5hbj1w|tV?kHw z>1S`VIfKwFHWNI?)C=`o7{Sg5EinDqbkEtEp61Z0;(X3X_6UgZd_Ayj1*K%fnJiOt z{oHmM*D1D%n{JX1~{T ze|p-1FT#95o^!!*aO_de8^)~68%hopjOEmb>7~iVR9dMD;vSF7IqjRt}n86 zy#}{$eFNYp2+8eV<{v0-jTL=p1JOfws&O@IbnpPCU9~QotP-9e;$Qw_>5sev+ zEYh*^2AM~j&?2xX%ORIK;x{Z9?7hXCGvW!g@|U_-k6uaaNgS~KnW4m6|N9x;U|+tRSQ*8^ z3uNbrN5?%6^zH5Kj8^Dc7c|Oq7CrAI>PW(wm2QGSB?;m7g^x#k{Kcm4Q{P2O8AUF6 zj|_MUgh%UrGvf;keZE?7UPVP(Ecjw%&S|4pe@6S?H!gx3|IEDbg`;{nT)sH|AWhD< zWxuq1Q64LY2x3mkf*Hv3jq!|jeT!1y5nH2_$Y<>?=-$8c<@6n`LAmnhJi6==IvdA} zHx}D|B;zgV&r%`E7z1zj`w4;0#`g+#HYmM7K@I>&Z6dwD5dPhN2W?IiF=&Q_X%`{T z>ljc;_xznUv{p~+#-nQf+^S+@vbxE`(?!MrwRW2*XF>VL+S(P&$1I=bxh;y z#*htFRI83ILWY<)+ZK{78AC$r6)CR>zAEckz4&ymCYjpw*2J!76_JdNLM)Erhq3!f z1m*yRrAS|Zi`G1ymSs`;z2Ezt?=`93UwEGMrCn}HnZ0tP(||?}3^r?12-KrFzVNyJ z?+=`+7)~P!kGSXy((&E(a=&tThzL#MVy*HY_?s;OnW)kXu_u>ezMD!zN zeQ&)F3q$qmNd`DO*kCTh z8eQo6o8K5|On1rq-}RDI0NtnCwn@a)u-~f}f!}k<@szF{Dv#X4UB0bpY!IDBO8kC; z2?zWIe;&obE=B*l{NDF;0KL5Q0=FDa;|e9Tc6{@9=|27zPjeN8;l#Vui&BZ({`~eA zwnqnZ&IrnN&DqdfFS^l-$kt1a7LCQJ0=qz}os zaQOSfk6(R5$7pXf!iSERckyFfg(KfnzF1okYahRZ#>TY9UT5?DiTYr6iiG<2uvCo2RF3?f z#jjF)34^3->Ruv8TF;x%d;l|vMTi)ZH>&xv{O>~wv0+74@0=Y7&pC5}csEJ2W zyli)kiLwRVUJJ8$8GHF+ZJ`Nd2coZ<747hc*$QzEAJlaUy?PSt6?M_itlyVtoYKR6 z(UD8Bs0dYK(d?&jioZDdyDYxd>dxlrvf_WnMtS~X^kYK*tgi^pAbdkLdPeWAqXI8* zxQ>u~p{hkzbV@H39VpMnkHGXW*2C@E*?VQ@6{_~ccvI2HA?nx0wNqVOooJCQgdq7~ zXEo3VGPQMdES%63jyWa=M9ZJ+VrHmDf9nEZo{hKQxPE7Uke&1O)+kw(z+B|V(|E-5 z*{UlT?Y+*WI8sE$uOEHJCn9Xj7_-TN6vcROVBgQ)RbDvbk!$a9)g>s^7i0i9-esO` z0%9&Q-kcVJrTi%UjvkruetG^Zu<>DQ#{01*L4AyjFWE6P|8mkAdCv9zmyHdbP#{&a zDspb;M&9f)@F>j{3BHOQJgTpkzmC7OaQ2oF9tqMlrp1JM*?{JNta8gnek@1xL`RohB5S)FD z%X`$Kdr>a3@o|!i^kR_^48a1$6aU9IaC7kV=QLT7X#rDHf}M5D#g%jMRWbhTr#SxT zPw=C^`!_LTz9uv2H zH?J%oXssLpEeial=D7jh0%H=Bf=~7fDW3{~eZM*NN&0ZPdj!Xi%&x|YUMztNJiKk2 z6`@yU)73h{BQ?IDRw=kwwtB^jsy35DGW}(ud;uk)w>AX9VG?#djt_^?nX{#9T7MVN zjs^trDw1cR>mvkxMoSgQF6RZsb-KRW&CdK%*N7@zQYkV-UyyT1op+yY8YTjN=393$-a6f`B8=bpI4LF2>9aL<$ZCyigGxUO8+~&jes8P z{*Yhx2;)>7CqbpB^Uz^h#5fuKs(~(Bc? zr@p|tzrCHfMc$)s?ag^I-u0Kr6^-!L35Kv-L@xev^g@@LJH>nroM99 z$zRcPE>+E?y0Jx>T%=?z3jG=2g&8MatqU~1a!Hlj>n9=pJip!VhUg?k!Gyo5&w@$m zOVHHn5FfY2#WHJ;t*m4YRbhH@l#a5EM$wGVwoTxdfBb*r?LT0fhMW>&mc)UR;2@Zq z&D6a zHWb692&8}T+yDLd>ZM@?M1X}Pb9{qb9KG=eR6asXmf4gthqnd^A4YIlezOA<%%qT= z&BN(K@c|B*zX!S0J{k=&+9FP`(uMRf%o|4ugt!z$0PKLfa{gB(91&qG?d|B;qVf$3?R-W^3rZVova-Z|MUcxkk#}(C4w=Zis>N z8gt1ADN1A$7jMzUOZbAxE@(#wU@xg~LWVu+=L;ZDhV?wUr1^j{THQ(kiN_F$)xnta z|EKF+TW;I7^q{9-$DDKR%c)Z#(Mq5yF{z3HC5j&u2@x@fhz381_&3B#>T-%~|B?zq zLKFoF91SRFNg~9eN-4`ar}ky7cg`_JzxknEdh6p|wc&8iS$nN_%{fNDwDz>;qFlF0 z;C*i(dmS&?2EnFH$SRPrgqZ${C}M!}&no8t*5>i?<4*BUqfji3K@$T9uwR7%^U`tb z;O-Zdq%?{akrm!o;ZZr{{joE)pdsSIog%4J^?3%*XOUY**NzojB&Ok_aWo8$a*+g| z#yOgEyh9h6^W;-SMd6*zQQ2JB0UjQu7V{jYx{VOjVo zeweK{%E{z>*a2uX7L=Fg)QY10@Co}r`8|B`*MAkg0u{h$gM}yu-3MG?c#fG8bVUq} z?S#Ri_Y$FHxnY(IY0)VeXOsOx=Ugxxc@Ed>k*S}emH5a=E3mIFJyw#vFn?*XITOrwo;M7!a zszAyz%eCl&!0&d%Bo(zKYhEF8+ofGQv?aUDRMj$SvL0H(le(Jkr4*IdVK=G0_~a0! zpKIeX29Fx6IdGvtmDf?&)t`iXWaydIi>-znT*8%G`EFBAFTOt4LPXH7t7pztGT-=O zw)`neo|bCe?up_0q!et*#CV-Fv( zGO@(>F(_syrOce4&fYCSi*+%|qw&MOD1GEJ5eJgre+Wq1M&m2nRr1=9{dpy=S{n~L zZn32uu&@*4ojFd7;X_TdE&RVe&up?Zn5VRwz&lSbu zLM}9venG1A|9{4IMmaNZ?@T|X0i!b`>T{g_Rn4HYNeztky#Z>9Dx55R2hN+I`7vXH zq!lrZuO)}~-jRpH_zt>vYEdq_ zp-B|O_)S{iK+hKWEUisI$Os<@6yo|pOk=4cW@Pnbz`!XAeO1@@-cedd_^sdkyWd=u zTm9m;PMtR1sSvItYw5!5Tvx+R7u0IyvRD$Ug{+^?=TceQaog3+_iCUhki3xlQcBqO z-T27(1+KOkhB9}z2$)r%T)R_Sc+x>S{ds0lm=+?oRNp#wGm5o^?`HTJ*89mCtH}sc zf|@OvSY)KS$T&RJ&fDcemuF}

@^0LcoFZ<}_-7$K_YTr&=5cC(gJyQ+M#*Z1%m% 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�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

+tP3Z)2P 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

Jq5C-aTifz(E5Kg}P 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⋙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 LNkvXXu0mjfL3yYq diff --git a/src/gui/board.png b/src/gui/board.png deleted file mode 100644 index bd77ca419999b45f31af1dc6e91aedd4b0f53a9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5678 zcmeAS@N?(olHy`uVBq!ia0y~yV5|jU4mP03i^?5=K#C>Z(btiI;o6NW{t-q%zGR7O zL`iUdT1k0gQ7VIDN`6wRf@f}GdTLN=VoGJ<$y6H#2GIkaE{-7;w~|s45`LUF;Bq^t zA;G#h!G)oLAxVn2DG(xJ$)L~>k~F@M{Q-MU|kN+74koMTY6Tl7ztmwLMJ)o!OKl^U$ z_Acp(KNlC;OMPGb(5mQ>955ZVmqSZM7DiyHsQbko(uWx3jfTYH1W+nSVtMp`@j+w+V|BDHrVGdyBIgycp zse|>{kN^MeA1_$HP(t!Qe_1)7sJYT-Q19TK`{B|jM{I$qitjzNR2=QlI_X`4raI^*LDqz40|2~awwXxSpWxo89ZJ6T-G@yGywpilHk$+ diff --git a/src/gui/sudoku_kmdlib.py b/src/gui/sudoku_kmdlib.py deleted file mode 100644 index a2b2aa239..000000000 --- a/src/gui/sudoku_kmdlib.py +++ /dev/null @@ -1,41 +0,0 @@ -import platform -import os -import re -import random -from slickrpc import Proxy - - -# define function that fetchs rpc creds from .conf -def def_credentials(chain): - rpcport =''; - operating_system = platform.system() - if operating_system == 'Darwin': - ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' - elif operating_system == 'Linux': - ac_dir = os.environ['HOME'] + '/.komodo' - elif operating_system == 'Windows': - ac_dir = '%s/komodo/' % os.environ['APPDATA'] - if chain == 'KMD': - coin_config_file = str(ac_dir + '/komodo.conf') - else: - coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') - with open(coin_config_file, 'r') as f: - for line in f: - l = line.rstrip() - if re.search('rpcuser', l): - rpcuser = l.replace('rpcuser=', '') - elif re.search('rpcpassword', l): - rpcpassword = l.replace('rpcpassword=', '') - elif re.search('rpcport', l): - rpcport = l.replace('rpcport=', '') - if len(rpcport) == 0: - if chain == 'KMD': - rpcport = 7771 - else: - print("rpcport not in conf file, exiting") - print("check "+coin_config_file) - exit(1) - - return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) - - From c8fcf61bb781174e2cc5f960a304570f9ed08df4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 09:49:47 -1100 Subject: [PATCH 265/385] +comments --- src/komodo_gateway.h | 88 +++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 58054feba..3669f29c0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1548,10 +1548,11 @@ void komodo_passport_iteration() } } -extern std::vector Mineropret; -#define PRICES_MAXCHANGE (COIN / 100) -#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) +extern std::vector Mineropret; // opreturn data set by the data gathering code +#define PRICES_MAXCHANGE (COIN / 100) // maximum acceptable change, set at 1% +#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) // 4 uint32_t unixtimestamp, BTCUSD, BTCGBP and BTCEUR +// komodo_heightpricebits() extracts the price data in the coinbase for nHeight int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) { CBlockIndex *pindex; CBlock block; CTransaction tx; int32_t numvouts; std::vector vopret; @@ -1562,7 +1563,7 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) tx = block.vtx[0]; numvouts = (int32_t)tx.vout.size(); GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - if ( vopret.size() == PRICES_SIZEBIT0 ) + if ( vopret.size() >= PRICES_SIZEBIT0 ) { memcpy(prevbits,&vopret[0],PRICES_SIZEBIT0); return(0); @@ -1573,34 +1574,47 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) return(-1); } -uint32_t komodo_pricenew(uint32_t price,uint32_t refprice,int64_t tolerance) +/* + komodo_pricenew() is passed in a reference price, the change tolerance and the proposed price. it needs to return a clipped price if it is too big and also set a flag if it is at or above the limit + */ +uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) { uint32_t highprice,lowprice; - highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; - lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; - //fprintf(stderr,"%.4f -> (%.4f %.4f)\n",(double)price/10000,(double)lowprice/10000,(double)highprice/10000); - if ( price > highprice ) - return(highprice); - else if ( price < lowprice ) - return(lowprice); + highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; // calc highest acceptable price + lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest + if ( price >= highprice ) + { + *maxflagp = 1; + if ( price > highprice ) // return non-zero only if we violate the tolerance + return(highprice); + } + else if ( price <= lowprice ) + { + *maxflagp = 1; + if ( price < lowprice ) + return(lowprice); + } else return(0); } -int32_t komodo_pricecmp(uint32_t pricebitsA[4],uint32_t pricebitsB[4],int64_t tolerance) +// komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance +int32_t komodo_pricecmp(int32_t *maxflagp,uint32_t pricebitsA[4],uint32_t pricebitsB[4],int64_t tolerance) { int32_t i; + *maxflagp = 0; for (i=1; i<4; i++) - if ( komodo_pricenew(pricebitsA[i],pricebitsB[i],tolerance) != 0 ) + if ( komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance) != 0 ) return(-1); return(0); } +// komodo_priceclamp() clamps any price that is beyond tolerance int32_t komodo_priceclamp(uint32_t pricebits[4],uint32_t refprices[4],int64_t tolerance) { - int32_t i; uint32_t newprice; + int32_t i,maxflag = 0; uint32_t newprice; for (i=1; i<4; i++) { - if ( (newprice= komodo_pricenew(pricebits[i],refprices[i],tolerance)) != 0 ) + if ( (newprice= komodo_pricenew(&maxflagp,pricebits[i],refprices[i],tolerance)) != 0 ) { fprintf(stderr,"priceclamped[%d] %u -> %u\n",i,pricebits[i],newprice); pricebits[i] = newprice; @@ -1609,16 +1623,18 @@ int32_t komodo_priceclamp(uint32_t pricebits[4],uint32_t refprices[4],int64_t to return(0); } +// komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight CScript komodo_mineropret(int32_t nHeight) { - CScript opret; uint32_t pricebits[4],prevbits[4]; - if ( Mineropret.size() == PRICES_SIZEBIT0 ) + CScript opret; uint32_t pricebits[4],prevbits[4]; int32_t maxflag; + if ( Mineropret.size() >= PRICES_SIZEBIT0 ) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { memcpy(pricebits,&Mineropret[0],PRICES_SIZEBIT0); - if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { + // if the new prices are not within tolerance, update Mineropret with clipped prices komodo_priceclamp(pricebits,prevbits,PRICES_MAXCHANGE); fprintf(stderr,"update Mineropret to clamped prices\n"); memcpy(&Mineropret[0],pricebits,PRICES_SIZEBIT0); @@ -1629,13 +1645,21 @@ CScript komodo_mineropret(int32_t nHeight) return(opret); } +/* + komodo_opretvalidate() is the entire price validation! + it prints out some useful info for debugging, like the lag from current time and prev block and the prices encoded in the opreturn. + + The only way komodo_opretvalidate() doesnt return an error is if maxflag is set or it is within tolerance of both the prior block and the local data. The local data validation only happens if it is a recent block and not a block from the past as the local node is only getting the current price data. + + */ + int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t pricebits[4],prevbits[4]; int32_t i,lag,lag2; + std::vector vopret; uint32_t pricebits[4],prevbits[4]; int32_t i,lag,lag2,maxflag=0; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() == PRICES_SIZEBIT0 ) + if ( vopret.size() >= PRICES_SIZEBIT0 ) { memcpy(pricebits,&vopret[0],PRICES_SIZEBIT0); lag = (int32_t)(time(NULL) - pricebits[0]); @@ -1643,20 +1667,20 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) lag = -lag; lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); - if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() == PRICES_SIZEBIT0 ) - { - memcpy(prevbits,&Mineropret[0],PRICES_SIZEBIT0); - if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) - return(-1); - } if ( nHeight > 1 ) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - if ( komodo_pricecmp(pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) return(-1); } else return(-1); } + if ( maxflag == 0 && lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) + { + memcpy(prevbits,&Mineropret[0],PRICES_SIZEBIT0); + if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + return(-1); + } return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)PRICES_SIZEBIT0,(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); @@ -1664,6 +1688,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(0); } +// get_urljson just returns the JSON returned by the URL using issue_curl + #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) cJSON *get_urljson(char *url) @@ -1678,6 +1704,8 @@ cJSON *get_urljson(char *url) return(json); } +// parse the coindesk specific data. yes, if this changes, it will require an update. However, regardless if the format from the data source changes, then the code that extracts it must be changed. One way to mitigate this is to have a large variety of data sources so that there is only a very remote chance that all of them are not available. Certainly the data gathering needs to be made more robust, but it doesnt really affect the proof of concept for the decentralized trustless oracle. The trustlessness is achieved by having all nodes get the oracle data. + int32_t get_btcusd(uint32_t pricebits[4]) { cJSON *pjson,*bpi,*obj; char str[512]; uint64_t btcusd = 0,btcgbp = 0,btceur = 0; @@ -1709,6 +1737,7 @@ int32_t get_btcusd(uint32_t pricebits[4]) return(-1); } +// komodo_cbopretupdate() obtains the external price data and encodes it into Mineropret, which will then be used by the miner and validation void komodo_cbopretupdate() { uint32_t pricebits[4]; @@ -1716,7 +1745,7 @@ void komodo_cbopretupdate() { if ( get_btcusd(pricebits) == 0 ) { - if ( Mineropret.size() != PRICES_SIZEBIT0 ) + if ( Mineropret.size() < PRICES_SIZEBIT0 ) Mineropret.resize(PRICES_SIZEBIT0); memcpy(&Mineropret[0],pricebits,PRICES_SIZEBIT0); //int32_t i; for (i=0; i Date: Thu, 28 Mar 2019 09:51:08 -1100 Subject: [PATCH 266/385] Maxflag --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3669f29c0..b7bfa9bd5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1614,7 +1614,7 @@ int32_t komodo_priceclamp(uint32_t pricebits[4],uint32_t refprices[4],int64_t to int32_t i,maxflag = 0; uint32_t newprice; for (i=1; i<4; i++) { - if ( (newprice= komodo_pricenew(&maxflagp,pricebits[i],refprices[i],tolerance)) != 0 ) + if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],refprices[i],tolerance)) != 0 ) { fprintf(stderr,"priceclamped[%d] %u -> %u\n",i,pricebits[i],newprice); pricebits[i] = newprice; From b7f15dd8b3365907d944b4cc4dfdb73cefc39bc4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 10:22:29 -1100 Subject: [PATCH 267/385] Local validation of limit move --- src/komodo_gateway.h | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b7bfa9bd5..868c639d8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1590,7 +1590,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 } else if ( price <= lowprice ) { - *maxflagp = 1; + *maxflagp = -1; if ( price < lowprice ) return(lowprice); } @@ -1655,7 +1655,7 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t pricebits[4],prevbits[4]; int32_t i,lag,lag2,maxflag=0; + std::vector vopret; uint32_t localbits[4],pricebits[4],prevbits[4],newprice; int32_t i,lag,lag2,maxflag=0; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); @@ -1675,11 +1675,29 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(-1); } else return(-1); } - if ( maxflag == 0 && lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) + if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { - memcpy(prevbits,&Mineropret[0],PRICES_SIZEBIT0); - if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) - return(-1); + memcpy(localbits,&Mineropret[0],PRICES_SIZEBIT0); + if ( maxflag == 0 ) + { + if ( komodo_pricecmp(&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) + return(-1); + } + else + { + for (i=1; i<4; i++) + { + maxflag = 0; + if ( (newprice= komodo_pricenew(maxflag,pricebits[i],prevbits[i],PRICES_MAXCHANGE)) != 0 ) // proposed price is clamped + { + // make sure local price is beyond clamped + if ( maxflag > 0 && localbits[i] < pricebits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > pricebits[i] ) + return(-1); + } + } + } } return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)PRICES_SIZEBIT0,(int32_t)scriptPubKey.size(),scriptPubKey[0]); From c7a0e8562d134b90697722b8bba473422cd5c101 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Mar 2019 10:23:24 -1100 Subject: [PATCH 268/385] & --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 868c639d8..6a9afd473 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1688,7 +1688,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) for (i=1; i<4; i++) { maxflag = 0; - if ( (newprice= komodo_pricenew(maxflag,pricebits[i],prevbits[i],PRICES_MAXCHANGE)) != 0 ) // proposed price is clamped + if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],prevbits[i],PRICES_MAXCHANGE)) != 0 ) // proposed price is clamped { // make sure local price is beyond clamped if ( maxflag > 0 && localbits[i] < pricebits[i] ) From a3bbaaef9b57a74e42500e275e016bdabfd220e4 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Fri, 29 Mar 2019 07:44:41 +0700 Subject: [PATCH 269/385] tetris tweaks --- src/tui/lib/tuilib.py | 79 ++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/src/tui/lib/tuilib.py b/src/tui/lib/tuilib.py index da1d7658a..9a2fed639 100755 --- a/src/tui/lib/tuilib.py +++ b/src/tui/lib/tuilib.py @@ -7,6 +7,7 @@ import pickle import platform import os import subprocess +import random import signal from slickrpc import Proxy from binascii import hexlify @@ -1044,34 +1045,41 @@ def print_multiplayer_games_list(rpc_connection): def rogue_newgame_singleplayer(rpc_connection, is_game_a_rogue=True): try: - new_game_txid = rpc_connection.cclib("newgame", "17", "[1]")["txid"] - print("New singleplayer training game succesfully created. txid: " + new_game_txid) - while True: - mempool = rpc_connection.getrawmempool() - if new_game_txid in mempool: - print(colorize("Waiting for game transaction to be mined", "blue")) - time.sleep(5) - else: - print(colorize("Game transaction is mined", "green")) - break - players_list = rogue_players_list(rpc_connection) - if len(players_list["playerdata"]) > 0: - print_players_list(rpc_connection) + if is_game_a_rogue: + new_game_txid = rpc_connection.cclib("newgame", "17", "[1]")["txid"] + print("New singleplayer training game succesfully created. txid: " + new_game_txid) while True: - is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") - if is_choice_needed == "y": - player_txid = input("Please input player txid: ") - newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid, player_txid)["txid"] - break - elif is_choice_needed == "n": - set_warriors_name(rpc_connection) - newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] - break + mempool = rpc_connection.getrawmempool() + if new_game_txid in mempool: + print(colorize("Waiting for game transaction to be mined", "blue")) + time.sleep(5) else: - print("Please choose y or n !") + print(colorize("Game transaction is mined", "green")) + break + else: + pending_games = rpc_connection.cclib("pending", "17")["pending"] + new_game_txid = random.choice(pending_games) + if is_game_a_rogue: + players_list = rogue_players_list(rpc_connection) + if len(players_list["playerdata"]) > 0: + print_players_list(rpc_connection) + while True: + is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") + if is_choice_needed == "y": + player_txid = input("Please input player txid: ") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid, player_txid)["txid"] + break + elif is_choice_needed == "n": + set_warriors_name(rpc_connection) + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + break + else: + print("Please choose y or n !") + else: + print("No players available to select") + input("Press [Enter] to continue...") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] else: - print("No players available to select") - input("Press [Enter] to continue...") newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] while True: mempool = rpc_connection.getrawmempool() @@ -1143,7 +1151,7 @@ def rogue_newgame_singleplayer(rpc_connection, is_game_a_rogue=True): print("Let's wait a little bit more") time.sleep(5) pass - if confirmations_amount < 2: + if confirmations_amount < 1: print("Last keystroke not confirmed yet! Let's wait a little") time.sleep(10) else: @@ -1163,15 +1171,16 @@ def rogue_newgame_singleplayer(rpc_connection, is_game_a_rogue=True): is_bailout_needed = input("Do you want to make bailout now [y] or wait for one more block [n]? [y/n]: ") if is_bailout_needed == "y": bailout_info = rogue_bailout(rpc_connection, new_game_txid) - while True: - try: - confirmations_amount = rpc_connection.getrawtransaction(bailout_info["txid"], 1)["confirmations"] - break - except Exception as e: - print(e) - print("Bailout not on blockchain yet. Let's wait a little bit more") - time.sleep(20) - pass + if is_game_a_rogue: + while True: + try: + confirmations_amount = rpc_connection.getrawtransaction(bailout_info["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Bailout not on blockchain yet. Let's wait a little bit more") + time.sleep(20) + pass break elif is_bailout_needed == "n": game_end_height = int(rpc_connection.getinfo()["blocks"]) From aee4b6ec2b7dafc2a44de1fd31ae852d9e3c1130 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:25:55 -1100 Subject: [PATCH 270/385] alphadvantage api --- src/komodo_gateway.h | 101 +++++++++++++++++++++++++++++++++++++++++-- src/komodo_utils.h | 2 +- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 6a9afd473..5f235ee63 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1631,13 +1631,13 @@ CScript komodo_mineropret(int32_t nHeight) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - memcpy(pricebits,&Mineropret[0],PRICES_SIZEBIT0); + memcpy(pricebits,Mineropret.data(),PRICES_SIZEBIT0); if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { // if the new prices are not within tolerance, update Mineropret with clipped prices komodo_priceclamp(pricebits,prevbits,PRICES_MAXCHANGE); fprintf(stderr,"update Mineropret to clamped prices\n"); - memcpy(&Mineropret[0],pricebits,PRICES_SIZEBIT0); + memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); } } return(opret << OP_RETURN << Mineropret); @@ -1677,7 +1677,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) } if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { - memcpy(localbits,&Mineropret[0],PRICES_SIZEBIT0); + memcpy(localbits,Mineropret.data(),PRICES_SIZEBIT0); if ( maxflag == 0 ) { if ( komodo_pricecmp(&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -1709,6 +1709,19 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) // get_urljson just returns the JSON returned by the URL using issue_curl #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) +char *Cryptos[] = { "KMD", "BTC", "ETH", "LTC", "BCH", "XMR", "IOTA", "DASH", "XTZ", "XEM", "ZEC", "WAVES", "DOGE", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "DGB", "STEEM", "ENJ", "STRAT", "VEO" }; + +char *ForexMajor[] = { "USD", "EUR", "JPY", "GBP", "AUD", "CHF", "CNY", "RUB" }; + +char *ForexMinor[] = { "CAD", "NZD", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", "UAH", "AED", "SAR" }; + +char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; + +char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; + +char *Techstocks[] = +{ "AAPL","ADBE","ADSK","AKAM","AMD","AMZN","ATVI","BB","CDW","CRM","CSCO","CYBR","DBX","EA","FB","GDDY","GOOG","GRMN","GSAT","HPQ","IBM","INFY","INTC","INTU","JNPR","MSFT","MSI","MU","MXL","NATI","NCR","NFLX","NTAP","NVDA","ORCL","PANW","PYPL","QCOM","RHT","S","SHOP","SNAP","SPOT","SYMC","SYNA","T","TRIP","TWTR","TXN","VMW","VOD","VRSN","VZ","WDC","XRX","YELP","YNDX","ZEN" +}; cJSON *get_urljson(char *url) { @@ -1722,6 +1735,61 @@ cJSON *get_urljson(char *url) return(json); } +uint32_t get_stockprice(char *symbol) +{ + char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0; + sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + if ( (json= get_urljson(url)) != 0 ) + { + if ( (obj= jobj(jitem(json,"Time Series (15min)"),0)) != 0 ) + { + high = jdouble(jitem(obj,0),"2. high")*10000 + 0.000049; + low = jdouble(jitem(obj,0),"3. low")*10000 + 0.000049; + price = (high + low) / 2; + } + free_json(json); + } + return(price); +} + +uint32_t get_currencyprice(char *symbol) +{ + char url[512]; cJSON *json,*obj; uint32_t price = 0; + sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + if ( (json= get_urljson(url)) != 0 ) + { + if ( (obj= jobj(jitem(json,0),0)) != 0 ) + price = jdouble(obj,"5. Exchange Rate")*10000 + 0.000049; + free_json(json); + } + return(price); +} + +int32_t get_currencies(char *list[],int32_t n) +{ + int32_t i,errs=0; uint32_t price; + for (i=0; i Date: Fri, 29 Mar 2019 01:27:32 -1100 Subject: [PATCH 271/385] Test --- src/komodo_gateway.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 5f235ee63..d37927af2 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1741,10 +1741,10 @@ uint32_t get_stockprice(char *symbol) sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); if ( (json= get_urljson(url)) != 0 ) { - if ( (obj= jobj(jitem(json,"Time Series (15min)"),0)) != 0 ) + if ( (obj= jobj(jitem(json,(char *)"Time Series (15min)"),0)) != 0 ) { - high = jdouble(jitem(obj,0),"2. high")*10000 + 0.000049; - low = jdouble(jitem(obj,0),"3. low")*10000 + 0.000049; + high = jdouble(jitem(obj,0),(char *)"2. high")*10000 + 0.000049; + low = jdouble(jitem(obj,0),(char *)"3. low")*10000 + 0.000049; price = (high + low) / 2; } free_json(json); @@ -1759,7 +1759,7 @@ uint32_t get_currencyprice(char *symbol) if ( (json= get_urljson(url)) != 0 ) { if ( (obj= jobj(jitem(json,0),0)) != 0 ) - price = jdouble(obj,"5. Exchange Rate")*10000 + 0.000049; + price = jdouble(obj,(char *)"5. Exchange Rate")*10000 + 0.000049; free_json(json); } return(price); @@ -1839,6 +1839,7 @@ void komodo_cbopretupdate() // fprintf(stderr,"%02x",Mineropret[i]); //fprintf(stderr," <- set Mineropret[%d]\n",(int32_t)Mineropret.size()); } +ASSETCHAINS_CBOPRET = 0xff; if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { get_currencies(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); From 888282a9f9e676954184bc273f4a2899ba23ab13 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:28:40 -1100 Subject: [PATCH 272/385] const --- src/komodo_gateway.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d37927af2..18f54c961 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1709,17 +1709,17 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) // get_urljson just returns the JSON returned by the URL using issue_curl #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) -char *Cryptos[] = { "KMD", "BTC", "ETH", "LTC", "BCH", "XMR", "IOTA", "DASH", "XTZ", "XEM", "ZEC", "WAVES", "DOGE", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "DGB", "STEEM", "ENJ", "STRAT", "VEO" }; +const char *Cryptos[] = { "KMD", "BTC", "ETH", "LTC", "BCH", "XMR", "IOTA", "DASH", "XTZ", "XEM", "ZEC", "WAVES", "DOGE", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "DGB", "STEEM", "ENJ", "STRAT", "VEO" }; -char *ForexMajor[] = { "USD", "EUR", "JPY", "GBP", "AUD", "CHF", "CNY", "RUB" }; +const char *ForexMajor[] = { "USD", "EUR", "JPY", "GBP", "AUD", "CHF", "CNY", "RUB" }; -char *ForexMinor[] = { "CAD", "NZD", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", "UAH", "AED", "SAR" }; +const char *ForexMinor[] = { "CAD", "NZD", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", "UAH", "AED", "SAR" }; -char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; +const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; -char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; +const char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; -char *Techstocks[] = +const char *Techstocks[] = { "AAPL","ADBE","ADSK","AKAM","AMD","AMZN","ATVI","BB","CDW","CRM","CSCO","CYBR","DBX","EA","FB","GDDY","GOOG","GRMN","GSAT","HPQ","IBM","INFY","INTC","INTU","JNPR","MSFT","MSI","MU","MXL","NATI","NCR","NFLX","NTAP","NVDA","ORCL","PANW","PYPL","QCOM","RHT","S","SHOP","SNAP","SPOT","SYMC","SYNA","T","TRIP","TWTR","TXN","VMW","VOD","VRSN","VZ","WDC","XRX","YELP","YNDX","ZEN" }; From 338c0392744e438fad6eecf91f35b562f80b18c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:30:16 -1100 Subject: [PATCH 273/385] Obj Derek --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 18f54c961..673774be7 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1741,7 +1741,7 @@ uint32_t get_stockprice(char *symbol) sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); if ( (json= get_urljson(url)) != 0 ) { - if ( (obj= jobj(jitem(json,(char *)"Time Series (15min)"),0)) != 0 ) + if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 ) { high = jdouble(jitem(obj,0),(char *)"2. high")*10000 + 0.000049; low = jdouble(jitem(obj,0),(char *)"3. low")*10000 + 0.000049; From 8cfcf57ae3de24ece5c5573a5f6135312bf82e52 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:31:12 -1100 Subject: [PATCH 274/385] Const --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 673774be7..328df66dc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1765,7 +1765,7 @@ uint32_t get_currencyprice(char *symbol) return(price); } -int32_t get_currencies(char *list[],int32_t n) +int32_t get_currencies(const char *list[],int32_t n) { int32_t i,errs=0; uint32_t price; for (i=0; i Date: Fri, 29 Mar 2019 01:32:07 -1100 Subject: [PATCH 275/385] Const --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 328df66dc..b26d8bb9b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1735,7 +1735,7 @@ cJSON *get_urljson(char *url) return(json); } -uint32_t get_stockprice(char *symbol) +uint32_t get_stockprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0; sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); @@ -1752,7 +1752,7 @@ uint32_t get_stockprice(char *symbol) return(price); } -uint32_t get_currencyprice(char *symbol) +uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); From 8d6cc79729ebd57f8c62d30df03a36db4aedb344 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:34:19 -1100 Subject: [PATCH 276/385] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b26d8bb9b..265458e4d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1728,7 +1728,7 @@ cJSON *get_urljson(char *url) char *jsonstr; cJSON *json = 0; if ( (jsonstr= issue_curl(url)) != 0 ) { - //fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); + fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } @@ -1839,7 +1839,7 @@ void komodo_cbopretupdate() // fprintf(stderr,"%02x",Mineropret[i]); //fprintf(stderr," <- set Mineropret[%d]\n",(int32_t)Mineropret.size()); } -ASSETCHAINS_CBOPRET = 0xff; +ASSETCHAINS_CBOPRET = 5; if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { get_currencies(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); From b2fade3af5114e9cf786db056d47f06ee283a55b Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:36:54 -1100 Subject: [PATCH 277/385] +print --- src/komodo_gateway.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 265458e4d..8777eb602 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1738,7 +1738,7 @@ cJSON *get_urljson(char *url) uint32_t get_stockprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0; - sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + sprintf(url,"http://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); if ( (json= get_urljson(url)) != 0 ) { if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 ) @@ -1755,7 +1755,8 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + fprintf(stderr,"issue (%s)\n",url); if ( (json= get_urljson(url)) != 0 ) { if ( (obj= jobj(jitem(json,0),0)) != 0 ) From 99f2cd9bd9388f5bb288b1c591b439d6bf5a9f00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:39:19 -1100 Subject: [PATCH 278/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8777eb602..b0eed88b0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1755,7 +1755,7 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); fprintf(stderr,"issue (%s)\n",url); if ( (json= get_urljson(url)) != 0 ) { From 751251b1f110ccaaacfe1ff57a6e5cd8841fbfc1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:41:12 -1100 Subject: [PATCH 279/385] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b0eed88b0..a0eac269b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1738,7 +1738,7 @@ cJSON *get_urljson(char *url) uint32_t get_stockprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0; - sprintf(url,"http://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); if ( (json= get_urljson(url)) != 0 ) { if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 ) @@ -1755,7 +1755,7 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); + sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); fprintf(stderr,"issue (%s)\n",url); if ( (json= get_urljson(url)) != 0 ) { From d5d5169310a7d37a390efc575916d4f48cda5982 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:45:28 -1100 Subject: [PATCH 280/385] Test --- src/komodo_bitcoind.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e76da09ec..5834a1f5e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -182,6 +182,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) specialcase = 1; else specialcase = 0; +specialcase = 1; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7876/nxt"); if ( specialcase != 0 && 0 ) @@ -247,13 +248,13 @@ try_again: numretries++; if ( specialcase != 0 ) { - printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); + fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); free(s.ptr); return(0); } else if ( numretries >= 1 ) { - //printf("Maximum number of retries exceeded!\n"); + fprintf(stderr,"Maximum number of retries exceeded!\n"); free(s.ptr); return(0); } From 10de70008ce9b644cf40a45bbf8ec81633c687c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:51:52 -1100 Subject: [PATCH 281/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a0eac269b..5d3326efb 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1755,7 +1755,7 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); + sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); fprintf(stderr,"issue (%s)\n",url); if ( (json= get_urljson(url)) != 0 ) { From b8e28e6e7d7f64d76dfa112cb3beab4506df15ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:55:57 -1100 Subject: [PATCH 282/385] Useragent --- src/komodo_bitcoind.h | 2 +- src/komodo_gateway.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 5834a1f5e..6fd5767a2 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -195,7 +195,7 @@ try_again: init_string(&s); headers = curl_slist_append(0,"Expect:"); - curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"Mozilla/4.0 (compatible; )");//"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 5d3326efb..a0eac269b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1755,7 +1755,7 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"http://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); + sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); fprintf(stderr,"issue (%s)\n",url); if ( (json= get_urljson(url)) != 0 ) { From 2420161fc83dd232c50ad0ccfb1a35df835e323b Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 01:58:57 -1100 Subject: [PATCH 283/385] Test --- src/komodo_bitcoind.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6fd5767a2..20062c588 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -195,8 +195,9 @@ try_again: init_string(&s); headers = curl_slist_append(0,"Expect:"); - curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"Mozilla/4.0 (compatible; )");//"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + if ( headers != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback From cdd520ef6095f99505f751ce38c23e86f04baf1e Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:03:10 -1100 Subject: [PATCH 284/385] curl_easy_setopt --- src/komodo_bitcoind.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 20062c588..a16d6d7ed 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -203,6 +203,8 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); From cd66407853ff4f685d2a8402b6fbc757a3dc675f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:04:42 -1100 Subject: [PATCH 285/385] curl_easy_setopt --- src/komodo_bitcoind.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index a16d6d7ed..aa757f47e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -203,7 +203,8 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + //curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 3); if ( strncmp(url,"https",5) == 0 ) { From aa21c5314967e3d2f0b802441e671d40a24b085d Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:07:13 -1100 Subject: [PATCH 286/385] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index aa757f47e..300a33a63 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -204,7 +204,7 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback //curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 3); + curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 1); if ( strncmp(url,"https",5) == 0 ) { From b793b800276084eee6b67fa2462535873992c290 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:08:42 -1100 Subject: [PATCH 287/385] V2 --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 300a33a63..e4c6139de 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -204,7 +204,7 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback //curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 1); + curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 2); if ( strncmp(url,"https",5) == 0 ) { From cd196766ca70b3695052a7c3a640aab0442ae5d2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:10:49 -1100 Subject: [PATCH 288/385] Test --- src/komodo_bitcoind.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e4c6139de..b5bc7d634 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -196,15 +196,14 @@ try_again: headers = curl_slist_append(0,"Expect:"); curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - if ( headers != 0 ) - curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + //curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback //curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 2); + //curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 2); if ( strncmp(url,"https",5) == 0 ) { From cd78a331b83a30d86f68ca058186ab2a60a13c2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:21:39 -1100 Subject: [PATCH 289/385] Test --- src/komodo_bitcoind.h | 3 +- src/komodo_gateway.h | 93 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index b5bc7d634..38f9041c1 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -182,7 +182,6 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) specialcase = 1; else specialcase = 0; -specialcase = 1; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7876/nxt"); if ( specialcase != 0 && 0 ) @@ -196,7 +195,7 @@ try_again: headers = curl_slist_append(0,"Expect:"); curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - //curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a0eac269b..7a002abbe 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1706,6 +1706,94 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(0); } +char *nonportable_path(char *str) +{ + int32_t i; + for (i=0; str[i]!=0; i++) + if ( str[i] == '/' ) + str[i] = '\\'; + return(str); +} + +char *portable_path(char *str) +{ +#ifdef _WIN32 + return(nonportable_path(str)); +#else +#ifdef __PNACL + /*int32_t i,n; + if ( str[0] == '/' ) + return(str); + else + { + n = (int32_t)strlen(str); + for (i=n; i>0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) +{ + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) + { + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) + { + fclose(fp); + *lenp = 0; + //printf("loadfile null size.(%s)\n",fname); + return(0); + } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +void *filestr(long *allocsizep,char *_fname) +{ + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); +} + +char *send_curl(char *url,char *fname) +{ + long fsize; char curlstr[1024]; + sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + system(curlstr); + return(filestr(&fsize,fname)); +} + // get_urljson just returns the JSON returned by the URL using issue_curl #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) @@ -1755,9 +1843,8 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; - sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,"D0185MGYVTIW0G6H");//NOTARY_PUBKEY.data()+50); - fprintf(stderr,"issue (%s)\n",url); - if ( (json= get_urljson(url)) != 0 ) + sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + if ( (json= send_curl(url,"curldata")) != 0 )//get_urljson(url)) != 0 ) { if ( (obj= jobj(jitem(json,0),0)) != 0 ) price = jdouble(obj,(char *)"5. Exchange Rate")*10000 + 0.000049; From 5e0ab6bf2ab852e608771f06866fb6c50337df85 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:24:21 -1100 Subject: [PATCH 290/385] Test --- src/komodo_gateway.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7a002abbe..e019a9d68 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1779,19 +1779,26 @@ void *filestr(long *allocsizep,char *_fname) { long filesize = 0; char *fname,*buf = 0; void *retptr; *allocsizep = 0; - fname = malloc(strlen(_fname)+1); + fname = (char *)malloc(strlen(_fname)+1); strcpy(fname,_fname); retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); free(fname); return(retptr); } -char *send_curl(char *url,char *fname) +cJSON *send_curl(char *url,char *fname) { - long fsize; char curlstr[1024]; + long fsize; char curlstr[1024],*jsonstr; cJSON *json=0; sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); - system(curlstr); - return(filestr(&fsize,fname)); + if ( system(curlstr) == 0 ) + { + if ( (jsonstr= filestr((void *)&fsize,fname)) != 0 ) + { + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + } + return(json); } // get_urljson just returns the JSON returned by the URL using issue_curl From 894593a1c9928eb97ac84b1faf033f58001c1c9d Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:26:01 -1100 Subject: [PATCH 291/385] Curl data --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e019a9d68..ca924a770 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1792,7 +1792,7 @@ cJSON *send_curl(char *url,char *fname) sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); if ( system(curlstr) == 0 ) { - if ( (jsonstr= filestr((void *)&fsize,fname)) != 0 ) + if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) { json = cJSON_Parse(jsonstr); free(jsonstr); @@ -1851,7 +1851,7 @@ uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; sprintf(url,"https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=%s&to_currency=USD&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); - if ( (json= send_curl(url,"curldata")) != 0 )//get_urljson(url)) != 0 ) + if ( (json= send_curl(url,(char *)"curldata")) != 0 )//get_urljson(url)) != 0 ) { if ( (obj= jobj(jitem(json,0),0)) != 0 ) price = jdouble(obj,(char *)"5. Exchange Rate")*10000 + 0.000049; From 10f6aa68908bb106cdf1096f51107c1a381fc5b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 02:38:08 -1100 Subject: [PATCH 292/385] get_dailyfx --- src/komodo_gateway.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ca924a770..4dcefd217 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1847,6 +1847,17 @@ uint32_t get_stockprice(const char *symbol) return(price); } +uint32_t get_dailyfx() +{ + char url[512]; cJSON *json; uint32_t datenum=0,price = 0; + sprintf(url,"https://api.exchangeratesapi.io/latest"); + if ( (json= get_urljson(url)) != 0 ) + { + free_json(json); + } + return(datenum); +} + uint32_t get_currencyprice(const char *symbol) { char url[512]; cJSON *json,*obj; uint32_t price = 0; @@ -1934,7 +1945,7 @@ void komodo_cbopretupdate() // fprintf(stderr,"%02x",Mineropret[i]); //fprintf(stderr," <- set Mineropret[%d]\n",(int32_t)Mineropret.size()); } -ASSETCHAINS_CBOPRET = 5; + get_dailyfx(); if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { get_currencies(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); From 9547e334a15de98b64b50892d00830c5a4cd6681 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:07:06 -1100 Subject: [PATCH 293/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4dcefd217..61c04c34b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1850,7 +1850,7 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_dailyfx() { char url[512]; cJSON *json; uint32_t datenum=0,price = 0; - sprintf(url,"https://api.exchangeratesapi.io/latest"); + sprintf(url,"http://api.openrates.io/latest");//http://api.exchangeratesapi.io/latest"); if ( (json= get_urljson(url)) != 0 ) { free_json(json); From 829c399f1ff33f0e55c5251b2ca8b78f6afbc1af Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:09:50 -1100 Subject: [PATCH 294/385] Test --- src/komodo_gateway.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 61c04c34b..8952e7df7 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1850,8 +1850,9 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_dailyfx() { char url[512]; cJSON *json; uint32_t datenum=0,price = 0; - sprintf(url,"http://api.openrates.io/latest");//http://api.exchangeratesapi.io/latest"); - if ( (json= get_urljson(url)) != 0 ) + sprintf(url,"http://api.openrates.io/latest"); + if ( (json= send_curl(url,(char *)"curldata")) != 0 )//get_urljson(url)) != 0 ) + //if ( (json= get_urljson(url)) != 0 ) { free_json(json); } From 76f2e11e4734778239ce7be3ba8da2b1c7af85da Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:12:09 -1100 Subject: [PATCH 295/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8952e7df7..9b72327f5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1789,7 +1789,7 @@ void *filestr(long *allocsizep,char *_fname) cJSON *send_curl(char *url,char *fname) { long fsize; char curlstr[1024],*jsonstr; cJSON *json=0; - sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + sprintf(curlstr,"wget \"%s\" > %s",url,fname); if ( system(curlstr) == 0 ) { if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) From b4d66481d86b2282ec2c4a738acb561a2b26095f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:16:04 -1100 Subject: [PATCH 296/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9b72327f5..163e680d3 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1789,7 +1789,7 @@ void *filestr(long *allocsizep,char *_fname) cJSON *send_curl(char *url,char *fname) { long fsize; char curlstr[1024],*jsonstr; cJSON *json=0; - sprintf(curlstr,"wget \"%s\" > %s",url,fname); + sprintf(curlstr,"wget -q \"%s\" -O %s",url,fname); if ( system(curlstr) == 0 ) { if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) From 7d9ed2dcf12ea52a9b14d2228f78966f03c3ea23 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:34:48 -1100 Subject: [PATCH 297/385] Test --- src/komodo_gateway.h | 49 +++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 163e680d3..05ea4ba05 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1850,15 +1850,39 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_dailyfx() { char url[512]; cJSON *json; uint32_t datenum=0,price = 0; - sprintf(url,"http://api.openrates.io/latest"); - if ( (json= send_curl(url,(char *)"curldata")) != 0 )//get_urljson(url)) != 0 ) - //if ( (json= get_urljson(url)) != 0 ) + sprintf(url,"http://api.openrates.io/latest?base=USD"); + if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { free_json(json); } return(datenum); } +uint32_t get_binanceprice(const char *symbol) +{ + char url[512]; cJSON *json; uint32_t price = 0; + sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); + if ( (json= get_urljson(url)) != 0 ) + { + price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; + free_json(json); + } + return(price); +} + +int32_t get_cryptoprices(const char *list[],int32_t n) +{ + int32_t i,errs=0; uint32_t price; + for (i=0; i Date: Fri, 29 Mar 2019 03:35:52 -1100 Subject: [PATCH 298/385] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 05ea4ba05..2a1b6fdeb 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1961,7 +1961,7 @@ void komodo_cbopretupdate() get_cryptoprices(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); if ( (counter % 300) == 0 ) get_dailyfx(); - if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) + /*if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { get_currencies(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); } @@ -1984,7 +1984,7 @@ void komodo_cbopretupdate() if ( (ASSETCHAINS_CBOPRET & 64) != 0 ) { get_stocks(Techstocks,(int32_t)(sizeof(Techstocks)/sizeof(*Techstocks))); - } + }*/ } counter++; } From cfcfea00e44152ba21e07c0266d57d25f779abde Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:38:25 -1100 Subject: [PATCH 299/385] Test --- src/komodo_gateway.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2a1b6fdeb..a50b79819 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1862,11 +1862,12 @@ uint32_t get_binanceprice(const char *symbol) { char url[512]; cJSON *json; uint32_t price = 0; sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); - if ( (json= get_urljson(url)) != 0 ) + if ( (json= issue_curl(url,(char *)"bnbprice")) != 0 ) { price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; free_json(json); } + usleep(100000); return(price); } From de144ec34e57dc93da79481967f61a5e5c7a28e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:39:15 -1100 Subject: [PATCH 300/385] send_curl --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a50b79819..d0ccf4f5f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1862,7 +1862,7 @@ uint32_t get_binanceprice(const char *symbol) { char url[512]; cJSON *json; uint32_t price = 0; sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); - if ( (json= issue_curl(url,(char *)"bnbprice")) != 0 ) + if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) { price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; free_json(json); From 5511751b6a9eca8b8ba6a4101fb36cb27f870aac Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:41:26 -1100 Subject: [PATCH 301/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d0ccf4f5f..f95551407 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1878,7 +1878,7 @@ int32_t get_cryptoprices(const char *list[],int32_t n) { if ( (price= get_binanceprice(list[i])) == 0 ) errs++; - else fprintf(stderr,"(%s %.4f) ",list[i],(double)price/10000); + fprintf(stderr,"(%s %.8f) ",list[i],(double)price/SATOSHIDEN); } fprintf(stderr," errs.%d\n",errs); return(-errs); From 3dacf07fe3069a67f2dbe7deb7116a644a9871b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:46:14 -1100 Subject: [PATCH 302/385] Test --- src/komodo_gateway.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f95551407..d60bc037f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1804,11 +1804,7 @@ cJSON *send_curl(char *url,char *fname) // get_urljson just returns the JSON returned by the URL using issue_curl #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) -const char *Cryptos[] = { "KMD", "BTC", "ETH", "LTC", "BCH", "XMR", "IOTA", "DASH", "XTZ", "XEM", "ZEC", "WAVES", "DOGE", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "DGB", "STEEM", "ENJ", "STRAT", "VEO" }; - -const char *ForexMajor[] = { "USD", "EUR", "JPY", "GBP", "AUD", "CHF", "CNY", "RUB" }; - -const char *ForexMinor[] = { "CAD", "NZD", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", "UAH", "AED", "SAR" }; +const char *Cryptos[] = { "KMD", "ETH", "LTC", "BCHABC", "XMR", "IOTA", "DASH", "XEM", "ZEC", "WAVES", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "STEEM", "ENJ", "STRAT" }; const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; From fea8ac8afd96a77e78eb6b24173f96d1ed43bcd9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:46:40 -1100 Subject: [PATCH 303/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d60bc037f..898477215 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1819,7 +1819,7 @@ cJSON *get_urljson(char *url) char *jsonstr; cJSON *json = 0; if ( (jsonstr= issue_curl(url)) != 0 ) { - fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); + //fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } From de3d5538f3580cfce086ffbe6378e91693543990 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 03:53:47 -1100 Subject: [PATCH 304/385] Test --- src/komodo_gateway.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 898477215..704084221 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1845,10 +1845,22 @@ uint32_t get_stockprice(const char *symbol) uint32_t get_dailyfx() { - char url[512]; cJSON *json; uint32_t datenum=0,price = 0; + //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} + char url[512],*datestr; cJSON *json,*rates; int32_t i,n; uint32_t datenum=0,price = 0; sprintf(url,"http://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { + if ( (rates= jobj(json,"rates")) != 0 && (n= cJSON_GetObjectSize()) > 0 ) + { + for (i=0; i Date: Fri, 29 Mar 2019 03:54:59 -1100 Subject: [PATCH 305/385] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 704084221..774450c72 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1850,7 +1850,7 @@ uint32_t get_dailyfx() sprintf(url,"http://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { - if ( (rates= jobj(json,"rates")) != 0 && (n= cJSON_GetObjectSize()) > 0 ) + if ( (rates= jobj(json,(char *)"rates")) != 0 && (n= cJSON_GetArraySize()) > 0 ) { for (i=0; i Date: Fri, 29 Mar 2019 03:55:54 -1100 Subject: [PATCH 306/385] Rates --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 774450c72..17e971535 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1850,7 +1850,7 @@ uint32_t get_dailyfx() sprintf(url,"http://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { - if ( (rates= jobj(json,(char *)"rates")) != 0 && (n= cJSON_GetArraySize()) > 0 ) + if ( (rates= jobj(json,(char *)"rates")) != 0 && (n= cJSON_GetArraySize(rates)) > 0 ) { for (i=0; i Date: Fri, 29 Mar 2019 03:59:08 -1100 Subject: [PATCH 307/385] +print --- src/komodo_gateway.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 17e971535..d2d98d91e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1794,6 +1794,7 @@ cJSON *send_curl(char *url,char *fname) { if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) { + fprintf(stderr,"[%s]\n",jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } @@ -1848,8 +1849,10 @@ uint32_t get_dailyfx() //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} char url[512],*datestr; cJSON *json,*rates; int32_t i,n; uint32_t datenum=0,price = 0; sprintf(url,"http://api.openrates.io/latest?base=USD"); + fprintf(stderr,"dailfx\n"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { + fprintf(stderr,"(%s)\n",jprint(json,0)); if ( (rates= jobj(json,(char *)"rates")) != 0 && (n= cJSON_GetArraySize(rates)) > 0 ) { for (i=0; i Date: Fri, 29 Mar 2019 04:03:14 -1100 Subject: [PATCH 308/385] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d2d98d91e..1a5a9a3ea 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1970,8 +1970,8 @@ void komodo_cbopretupdate() // fprintf(stderr,"%02x",Mineropret[i]); //fprintf(stderr," <- set Mineropret[%d]\n",(int32_t)Mineropret.size()); } - get_cryptoprices(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); - if ( (counter % 300) == 0 ) + //get_cryptoprices(Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); + //if ( (counter % 300) == 0 ) get_dailyfx(); /*if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { From 7051bf44a8227e9e7d6b1483108e2e7d8e07cbd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 04:06:42 -1100 Subject: [PATCH 309/385] Https --- src/komodo_gateway.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1a5a9a3ea..dbee7f803 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1848,8 +1848,7 @@ uint32_t get_dailyfx() { //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} char url[512],*datestr; cJSON *json,*rates; int32_t i,n; uint32_t datenum=0,price = 0; - sprintf(url,"http://api.openrates.io/latest?base=USD"); - fprintf(stderr,"dailfx\n"); + sprintf(url,"https://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { fprintf(stderr,"(%s)\n",jprint(json,0)); From 9645cf2e19bc9888c7c3360eab607551ab80db86 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 04:14:37 -1100 Subject: [PATCH 310/385] Test --- src/komodo_gateway.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index dbee7f803..719b3894e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1794,7 +1794,6 @@ cJSON *send_curl(char *url,char *fname) { if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) { - fprintf(stderr,"[%s]\n",jsonstr); json = cJSON_Parse(jsonstr); free(jsonstr); } @@ -1811,6 +1810,10 @@ const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; const char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; +const char *Forex[] = +{ "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR" +}; + const char *Techstocks[] = { "AAPL","ADBE","ADSK","AKAM","AMD","AMZN","ATVI","BB","CDW","CRM","CSCO","CYBR","DBX","EA","FB","GDDY","GOOG","GRMN","GSAT","HPQ","IBM","INFY","INTC","INTU","JNPR","MSFT","MSI","MU","MXL","NATI","NCR","NFLX","NTAP","NVDA","ORCL","PANW","PYPL","QCOM","RHT","S","SHOP","SNAP","SPOT","SYMC","SYNA","T","TRIP","TWTR","TXN","VMW","VOD","VRSN","VZ","WDC","XRX","YELP","YNDX","ZEN" }; @@ -1851,18 +1854,17 @@ uint32_t get_dailyfx() sprintf(url,"https://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { - fprintf(stderr,"(%s)\n",jprint(json,0)); - if ( (rates= jobj(json,(char *)"rates")) != 0 && (n= cJSON_GetArraySize(rates)) > 0 ) + if ( (rates= jobj(json,(char *)"rates")) != 0 ) { - for (i=0; i Date: Fri, 29 Mar 2019 04:15:58 -1100 Subject: [PATCH 311/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 719b3894e..0c0e9314f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1858,7 +1858,7 @@ uint32_t get_dailyfx() { for (i=0; i Date: Fri, 29 Mar 2019 22:54:27 +0700 Subject: [PATCH 312/385] moving vertically also if block not fit game field on swap --- src/cc/games/tetris.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/games/tetris.c b/src/cc/games/tetris.c index 711170b0d..a0fd0615c 100644 --- a/src/cc/games/tetris.c +++ b/src/cc/games/tetris.c @@ -296,6 +296,7 @@ static void tg_hold(struct games_state *rs,tetris_game *obj) obj->stored.ori = ori; while (!tg_fits(obj, obj->falling)) { obj->falling.loc.row--; + obj->falling.loc.col--; } } tg_put(obj, obj->falling); From e1bfe06bf51cce1c2a4ff805eaefb04f57c2daf1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 05:41:08 -1100 Subject: [PATCH 313/385] Cleanup --- src/komodo_gateway.h | 48 +++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0c0e9314f..262e73ce0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1804,19 +1804,21 @@ cJSON *send_curl(char *url,char *fname) // get_urljson just returns the JSON returned by the URL using issue_curl #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) + const char *Cryptos[] = { "KMD", "ETH", "LTC", "BCHABC", "XMR", "IOTA", "DASH", "XEM", "ZEC", "WAVES", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "STEEM", "ENJ", "STRAT" }; -const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; - -const char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; - const char *Forex[] = { "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR" }; +/* const char *Techstocks[] = { "AAPL","ADBE","ADSK","AKAM","AMD","AMZN","ATVI","BB","CDW","CRM","CSCO","CYBR","DBX","EA","FB","GDDY","GOOG","GRMN","GSAT","HPQ","IBM","INFY","INTC","INTU","JNPR","MSFT","MSI","MU","MXL","NATI","NCR","NFLX","NTAP","NVDA","ORCL","PANW","PYPL","QCOM","RHT","S","SHOP","SNAP","SPOT","SYMC","SYNA","T","TRIP","TWTR","TXN","VMW","VOD","VRSN","VZ","WDC","XRX","YELP","YNDX","ZEN" }; +const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; + +const char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; +*/ cJSON *get_urljson(char *url) { @@ -1847,10 +1849,10 @@ uint32_t get_stockprice(const char *symbol) return(price); } -uint32_t get_dailyfx() +uint32_t get_dailyfx(uint32_t *prices) { //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} - char url[512],*datestr; cJSON *json,*rates; int32_t i,n; uint32_t datenum=0,price = 0; + char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0; sprintf(url,"https://api.openrates.io/latest?base=USD"); if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { @@ -1858,13 +1860,14 @@ uint32_t get_dailyfx() { for (i=0; i Date: Fri, 29 Mar 2019 06:05:13 -1100 Subject: [PATCH 314/385] Test --- src/komodo_gateway.h | 71 ++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 262e73ce0..e1a32ea05 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1565,7 +1565,7 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) { - memcpy(prevbits,&vopret[0],PRICES_SIZEBIT0); + memcpy(prevbits,vopret.data(),vopret.size()); return(0); } } @@ -1598,21 +1598,21 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 } // komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance -int32_t komodo_pricecmp(int32_t *maxflagp,uint32_t pricebitsA[4],uint32_t pricebitsB[4],int64_t tolerance) +int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { int32_t i; *maxflagp = 0; - for (i=1; i<4; i++) + for (i=1; i= PRICES_SIZEBIT0 ) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - memcpy(pricebits,Mineropret.data(),PRICES_SIZEBIT0); - if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + memcpy(pricebits,Mineropret.data(),Mineropret.size()); + n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); + if ( komodo_pricecmp(n,&maxflag,pricebits,prevbits,Mineropret.size()) < 0 ) { // if the new prices are not within tolerance, update Mineropret with clipped prices - komodo_priceclamp(pricebits,prevbits,PRICES_MAXCHANGE); + komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE); fprintf(stderr,"update Mineropret to clamped prices\n"); - memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); + memcpy(Mineropret.data(),pricebits,Mineropret.size()); } } + int32_t i; + for (i=0; i vopret; uint32_t localbits[4],pricebits[4],prevbits[4],newprice; int32_t i,lag,lag2,maxflag=0; + std::vector vopret; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) { - memcpy(pricebits,&vopret[0],PRICES_SIZEBIT0); + n = (int32_t)(vopret.size() / sizeof(uint32_t)); + memcpy(pricebits,vopret.data(),Mineropret.size()); lag = (int32_t)(time(NULL) - pricebits[0]); if ( lag < 0 ) lag = -lag; @@ -1671,21 +1677,21 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - if ( komodo_pricecmp(&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) return(-1); } else return(-1); } if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { - memcpy(localbits,Mineropret.data(),PRICES_SIZEBIT0); + memcpy(localbits,Mineropret.data(),Mineropret.size()); if ( maxflag == 0 ) { - if ( komodo_pricecmp(&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(n,&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) return(-1); } else { - for (i=1; i<4; i++) + for (i=1; i Date: Fri, 29 Mar 2019 06:11:08 -1100 Subject: [PATCH 315/385] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index a91dae1e8..44b1192a4 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -2067,7 +2067,7 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_CBOPRET != 0 ) { extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_CBOPRET),(void *)&ASSETCHAINS_CBOPRET); - komodo_cbopretupdate(); // will set Mineropret + //komodo_cbopretupdate(); // will set Mineropret fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n"); } } From 2b8eac7ca17485a2581fbefdf90093fb0dccdbc1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 06:14:33 -1100 Subject: [PATCH 316/385] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e1a32ea05..271362c4b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1985,9 +1985,9 @@ void komodo_cbopretupdate() if ( get_btcusd(pricebits) == 0 ) { memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); - //int32_t i; for (i=0; i Date: Sat, 30 Mar 2019 00:15:48 +0700 Subject: [PATCH 317/385] fixing fit from both ends --- src/cc/games/tetris.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cc/games/tetris.c b/src/cc/games/tetris.c index a0fd0615c..8e7642837 100644 --- a/src/cc/games/tetris.c +++ b/src/cc/games/tetris.c @@ -296,7 +296,14 @@ static void tg_hold(struct games_state *rs,tetris_game *obj) obj->stored.ori = ori; while (!tg_fits(obj, obj->falling)) { obj->falling.loc.row--; + if (tg_fits(obj, obj->falling)) { + break; + } obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) { + break; + } + obj->falling.loc.col += 2; } } tg_put(obj, obj->falling); From b7cf1a57e9ae788fad86cc1e31e736072895e6fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 06:17:03 -1100 Subject: [PATCH 318/385] 333 --- src/komodo_gateway.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 271362c4b..c71f7c4f2 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1974,6 +1974,8 @@ void komodo_cbopretupdate() int32_t size; if ( (ASSETCHAINS_CBOPRET & 1) != 0 ) { + if ( komodo_nextheight() > 333 ) + ASSETCHAINS_CBOPRET = 7; size = PRICES_SIZEBIT0; if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) size += sizeof(forexprices); From 3b4a6191f9759df2bd440f257f9c3636830e0f02 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 06:19:33 -1100 Subject: [PATCH 319/385] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c71f7c4f2..0612caa80 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1987,9 +1987,6 @@ void komodo_cbopretupdate() if ( get_btcusd(pricebits) == 0 ) { memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); - int32_t i; for (i=0; i Date: Fri, 29 Mar 2019 06:38:55 -1100 Subject: [PATCH 320/385] Test --- src/komodo_gateway.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0612caa80..fbdda445c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1603,8 +1603,13 @@ int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_ int32_t i; *maxflagp = 0; for (i=1; i %u out of tolerance maxflag.%d\n",i,pricebitsB[i],pricebitsA[i],*maxflagp); return(-1); + } + } return(0); } @@ -1697,6 +1702,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],prevbits[i],PRICES_MAXCHANGE)) != 0 ) // proposed price is clamped { // make sure local price is beyond clamped + fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u\n",maxflag,i,localbits[i],pricebits[i]); if ( maxflag > 0 && localbits[i] < pricebits[i] ) return(-1); else if ( maxflag < 0 && localbits[i] > pricebits[i] ) @@ -2003,9 +2009,9 @@ void komodo_cbopretupdate() memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices)); size += sizeof(cryptoprices); } - int32_t i; for (i=0; i Date: Fri, 29 Mar 2019 07:01:56 -1100 Subject: [PATCH 321/385] +prints --- src/komodo_gateway.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index fbdda445c..94d5928a9 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1584,12 +1584,14 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest if ( price >= highprice ) { + fprintf(stderr,"high %u vs h%u l%u\n",price,highprice,lowprice); *maxflagp = 1; if ( price > highprice ) // return non-zero only if we violate the tolerance return(highprice); } else if ( price <= lowprice ) { + fprintf(stderr,"low %u vs h%u l%u\n",price,highprice,lowprice); *maxflagp = -1; if ( price < lowprice ) return(lowprice); @@ -1606,7 +1608,7 @@ int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_ { if ( komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance) != 0 ) { - fprintf(stderr,"i.%d %u -> %u out of tolerance maxflag.%d\n",i,pricebitsB[i],pricebitsA[i],*maxflagp); + fprintf(stderr,"i.%d/%d %u -> %u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],*maxflagp); return(-1); } } @@ -1621,7 +1623,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 { if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],refprices[i],tolerance)) != 0 ) { - fprintf(stderr,"priceclamped[%d] %u -> %u\n",i,pricebits[i],newprice); + fprintf(stderr,"priceclamped[%d of %d] %u -> %u\n",i,n,pricebits[i],newprice); pricebits[i] = newprice; } } From 3af96cfe61f9492d23ea6bf2219ff6e93868f181 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:03:48 -1100 Subject: [PATCH 322/385] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 94d5928a9..b60399329 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1602,13 +1602,13 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 // komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { - int32_t i; + int32_t i; uint32_t newprice; *maxflagp = 0; for (i=1; i %u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],*maxflagp); + fprintf(stderr,"i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); } } @@ -1623,7 +1623,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 { if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],refprices[i],tolerance)) != 0 ) { - fprintf(stderr,"priceclamped[%d of %d] %u -> %u\n",i,n,pricebits[i],newprice); + fprintf(stderr,"priceclamped[%d of %d] %u vs %u -> %u\n",i,n,refprices[i],pricebits[i],newprice); pricebits[i] = newprice; } } From ec1c7ffcc7dd2535f9772ca7e5ba8862c02a1bc9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:10:46 -1100 Subject: [PATCH 323/385] Int64 --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b60399329..7a12f21bd 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1579,19 +1579,19 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) */ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) { - uint32_t highprice,lowprice; + uint64_t highprice,lowprice; highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; // calc highest acceptable price lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest if ( price >= highprice ) { - fprintf(stderr,"high %u vs h%u l%u\n",price,highprice,lowprice); + fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = 1; if ( price > highprice ) // return non-zero only if we violate the tolerance return(highprice); } else if ( price <= lowprice ) { - fprintf(stderr,"low %u vs h%u l%u\n",price,highprice,lowprice); + fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = -1; if ( price < lowprice ) return(lowprice); From c12368a75c7fefe97453cfa2169ac02d88cf7a8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:18:47 -1100 Subject: [PATCH 324/385] Print --- src/komodo_gateway.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7a12f21bd..adf71c070 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1582,6 +1582,8 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 uint64_t highprice,lowprice; highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; // calc highest acceptable price lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest + fprintf(stderr,"ref.%u * %llu -> %llu -> highprice %llu\n",refprice,(long long)(COIN+tolerance),(long long)((uint64_t)refprice * (COIN + tolerance)),(long long)highprice); + fprintf(stderr,"ref.%u * %llu -> %llu -> lowprice %llu\n",refprice,(long long)(COIN-tolerance),(long long)((uint64_t)refprice * (COIN - tolerance)),(long long)lowprice); if ( price >= highprice ) { fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); From 5f9d3a95528174ef97161511dbda0ab407d6f27e Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:27:33 -1100 Subject: [PATCH 325/385] Test --- src/komodo_gateway.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index adf71c070..6ef0739e9 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1635,14 +1635,24 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 // komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight CScript komodo_mineropret(int32_t nHeight) { - CScript opret; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,n; + CScript opret; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,n,numzero=0; if ( Mineropret.size() >= PRICES_SIZEBIT0 ) { + n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); + numzero = 1; + while ( numzero > 0 ) + { + memcpy(pricebits,Mineropret.data(),Mineropret.size()); + for (i=numzero=0; i Date: Fri, 29 Mar 2019 07:28:47 -1100 Subject: [PATCH 326/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 6ef0739e9..8400289ef 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1635,7 +1635,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 // komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight CScript komodo_mineropret(int32_t nHeight) { - CScript opret; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,n,numzero=0; + CScript opret; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,i,n,numzero=0; if ( Mineropret.size() >= PRICES_SIZEBIT0 ) { n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); From 92f0ec2616b71cf5fbbb4d5070e83e0ab961287c Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:34:46 -1100 Subject: [PATCH 327/385] Make sure highprice and lowprice != refprice --- src/komodo_gateway.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8400289ef..cb0bc761b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1580,20 +1580,24 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) { uint64_t highprice,lowprice; + if ( refprice < 2 ) + return(0); highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; // calc highest acceptable price lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest - fprintf(stderr,"ref.%u * %llu -> %llu -> highprice %llu\n",refprice,(long long)(COIN+tolerance),(long long)((uint64_t)refprice * (COIN + tolerance)),(long long)highprice); - fprintf(stderr,"ref.%u * %llu -> %llu -> lowprice %llu\n",refprice,(long long)(COIN-tolerance),(long long)((uint64_t)refprice * (COIN - tolerance)),(long long)lowprice); + if ( highprice == refprice ) + highprice++; + if ( lowprice == refprice ) + lowprice--; if ( price >= highprice ) { - fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + //fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = 1; if ( price > highprice ) // return non-zero only if we violate the tolerance return(highprice); } else if ( price <= lowprice ) { - fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + //fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = -1; if ( price < lowprice ) return(lowprice); From e955d862fb9e652e83865549a9f9732683a57150 Mon Sep 17 00:00:00 2001 From: "Anton \"TonyL\" Lysakov" Date: Sat, 30 Mar 2019 01:45:33 +0700 Subject: [PATCH 328/385] looking for keystrokes.log in the right place --- src/tui/lib/tuilib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tui/lib/tuilib.py b/src/tui/lib/tuilib.py index 9a2fed639..b46030af8 100755 --- a/src/tui/lib/tuilib.py +++ b/src/tui/lib/tuilib.py @@ -1952,10 +1952,10 @@ def find_game_keystrokes_in_log(gametxid): operating_system = platform.system() if operating_system == 'Win64' or operating_system == 'Windows': - p1 = subprocess.Popen(["type", "keystrokes.log"], stdout=subprocess.PIPE, shell=True) + p1 = subprocess.Popen(["type", "../keystrokes.log"], stdout=subprocess.PIPE, shell=True) p2 = subprocess.Popen(["findstr", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE, shell=True) else: - p1 = subprocess.Popen(["cat", "keystrokes.log"], stdout=subprocess.PIPE) + p1 = subprocess.Popen(["cat", "../keystrokes.log"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["grep", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() output = p2.communicate()[0] From 6c9eb0e0f9c4836159d337bf0ff2f7bbdef16e28 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:46:06 -1100 Subject: [PATCH 329/385] Dailyfx every 5 hours -> on average -> 2 hours ave delay --- src/komodo_gateway.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index cb0bc761b..94f85531a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1993,7 +1993,7 @@ int32_t get_btcusd(uint32_t pricebits[4]) void komodo_cbopretupdate() { - static uint32_t counter; + static uint32_t lasttime; static uint32_t pricebits[4],cryptoprices[sizeof(Cryptos)/sizeof(*Cryptos)],forexprices[sizeof(Forex)/sizeof(*Forex)]; int32_t size; if ( (ASSETCHAINS_CBOPRET & 1) != 0 ) @@ -2014,10 +2014,11 @@ void komodo_cbopretupdate() } if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { - if ( (counter % 300) == 0 || forexprices[0] == 0 ) + if ( time(NULL) > lasttime+3600*5 || forexprices[0] == 0 ) { get_dailyfx(forexprices); memcpy(&Mineropret.data()[size],forexprices,sizeof(forexprices)); + lasttime = (uint32_t)time(NULL); } size += sizeof(forexprices); } From 6053dc843dbd4e9cd110fa8ac1201f43a63efee7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:48:51 -1100 Subject: [PATCH 330/385] -counter --- src/komodo_gateway.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 94f85531a..43c9981f2 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2045,5 +2045,4 @@ void komodo_cbopretupdate() get_stocks(Techstocks,(int32_t)(sizeof(Techstocks)/sizeof(*Techstocks))); }*/ } - counter++; } From 1976dcbfdb128ba924e437d3ef7a75fe3344e349 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:55:23 -1100 Subject: [PATCH 331/385] test --- src/komodo_gateway.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 43c9981f2..16a64f86b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1701,7 +1701,10 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + { + fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); return(-1); + } } else return(-1); } if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) @@ -1710,7 +1713,10 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( maxflag == 0 ) { if ( komodo_pricecmp(n,&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) + { + fprintf(stderr,"maxflag.0 cmp error\n"); return(-1); + } } else { From e24193c7a8774b9a5d911d89660499554c4b8c83 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 07:59:47 -1100 Subject: [PATCH 332/385] Return 0 in all fall through cases for pricecmp --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 16a64f86b..3614ec4cc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1602,7 +1602,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 if ( price < lowprice ) return(lowprice); } - else return(0); + return(0); } // komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance From eb4c6419fd0da61ff3887fc779d11f48bd77dfc2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 08:24:28 -1100 Subject: [PATCH 333/385] Edge case of no local prices yet --- src/komodo_gateway.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3614ec4cc..bf07218eb 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1609,10 +1609,10 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { int32_t i; uint32_t newprice; - *maxflagp = 0; for (i=1; i newprice.%u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); @@ -1624,9 +1624,10 @@ int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_ // komodo_priceclamp() clamps any price that is beyond tolerance int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int64_t tolerance) { - int32_t i,maxflag = 0; uint32_t newprice; + int32_t i,maxflag; uint32_t newprice; for (i=1; i %u\n",i,n,refprices[i],pricebits[i],newprice); From 78dd8ae93776ee9fcf5735977c282a2f7d39020b Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 08:27:16 -1100 Subject: [PATCH 334/385] Only skip check if localbits is 0 --- src/komodo_gateway.h | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index bf07218eb..26fbeda02 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1612,7 +1612,7 @@ int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_ for (i=1; i newprice.%u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); @@ -1711,27 +1711,33 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { memcpy(localbits,Mineropret.data(),Mineropret.size()); - if ( maxflag == 0 ) + for (i=0; i 0 && localbits[i] < pricebits[i] ) - return(-1); - else if ( maxflag < 0 && localbits[i] > pricebits[i] ) - return(-1); + fprintf(stderr,"maxflag.0 cmp error\n"); + return(-1); + } + } + else + { + for (i=1; i 0 && localbits[i] < pricebits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > pricebits[i] ) + return(-1); + } } } } From 78564c9b3b3c02c8724239fa7c55be217fefbb0e Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 08:28:21 -1100 Subject: [PATCH 335/385] Handle partial 0 --- src/komodo_gateway.h | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 26fbeda02..63c210d6a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1713,31 +1713,28 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) memcpy(localbits,Mineropret.data(),Mineropret.size()); for (i=0; i 0 && localbits[i] < pricebits[i] ) - return(-1); - else if ( maxflag < 0 && localbits[i] > pricebits[i] ) - return(-1); - } + // make sure local price is beyond clamped + fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u\n",maxflag,i,localbits[i],pricebits[i]); + if ( maxflag > 0 && localbits[i] < pricebits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > pricebits[i] ) + return(-1); } } } From 67352a31b59499e452c8564af14eda31850e2ac5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 08:35:02 -1100 Subject: [PATCH 336/385] Fix --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 63c210d6a..1306696f0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1609,9 +1609,9 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { int32_t i; uint32_t newprice; + *maxflagp = 0; for (i=1; i newprice.%u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); From 725ac7114718704719a807465add337d49919261 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 08:52:12 -1100 Subject: [PATCH 337/385] +print --- src/komodo_gateway.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1306696f0..225524eaf 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1590,14 +1590,14 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 lowprice--; if ( price >= highprice ) { - //fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = 1; if ( price > highprice ) // return non-zero only if we violate the tolerance return(highprice); } else if ( price <= lowprice ) { - //fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); *maxflagp = -1; if ( price < lowprice ) return(lowprice); @@ -1606,7 +1606,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 } // komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance -int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) +int32_t komodo_pricecmp(int32_t nHeight,int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { int32_t i; uint32_t newprice; *maxflagp = 0; @@ -1614,7 +1614,7 @@ int32_t komodo_pricecmp(int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_ { if ( (newprice= komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance)) != 0 ) { - fprintf(stderr,"i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); + fprintf(stderr,"ht.%d i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); } } @@ -1657,7 +1657,7 @@ CScript komodo_mineropret(int32_t nHeight) if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { memcpy(pricebits,Mineropret.data(),Mineropret.size()); - if ( komodo_pricecmp(n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(0,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { // if the new prices are not within tolerance, update Mineropret with clipped prices komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE); @@ -1701,7 +1701,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - if ( komodo_pricecmp(n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); return(-1); @@ -1716,7 +1716,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) localbits[i] = prevbits[i]; if ( maxflag == 0 ) { - if ( komodo_pricecmp(n,&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(nHeight,n,&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) { fprintf(stderr,"maxflag.0 cmp error\n"); return(-1); From d605780e576e1f1952c8158cb693003a73559d26 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Mar 2019 09:04:39 -1100 Subject: [PATCH 338/385] +print --- src/komodo_gateway.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 225524eaf..d82cb47e8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1591,16 +1591,22 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 if ( price >= highprice ) { fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); - *maxflagp = 1; if ( price > highprice ) // return non-zero only if we violate the tolerance + { + *maxflagp = 2; return(highprice); + } + *maxflagp = 1; } else if ( price <= lowprice ) { fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); - *maxflagp = -1; if ( price < lowprice ) + { + *maxflagp = -2; return(lowprice); + } + *maxflagp = -1; } return(0); } From d3ff021e338f09f7d7acd997df32d8621aedef10 Mon Sep 17 00:00:00 2001 From: "Anton \"TonyL\" Lysakov" Date: Sun, 31 Mar 2019 05:42:13 +0700 Subject: [PATCH 339/385] Update tuilib.py Discovered that `keystrokes.log` creating in folder from which game calling, not especially daemon folder. So before changed from correct to not correct :/ --- src/tui/lib/tuilib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tui/lib/tuilib.py b/src/tui/lib/tuilib.py index b46030af8..9a2fed639 100755 --- a/src/tui/lib/tuilib.py +++ b/src/tui/lib/tuilib.py @@ -1952,10 +1952,10 @@ def find_game_keystrokes_in_log(gametxid): operating_system = platform.system() if operating_system == 'Win64' or operating_system == 'Windows': - p1 = subprocess.Popen(["type", "../keystrokes.log"], stdout=subprocess.PIPE, shell=True) + p1 = subprocess.Popen(["type", "keystrokes.log"], stdout=subprocess.PIPE, shell=True) p2 = subprocess.Popen(["findstr", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE, shell=True) else: - p1 = subprocess.Popen(["cat", "../keystrokes.log"], stdout=subprocess.PIPE) + p1 = subprocess.Popen(["cat", "keystrokes.log"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["grep", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() output = p2.communicate()[0] From b0edb6718cdd5528742537e9f8a8aff60338686f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 04:19:43 -1100 Subject: [PATCH 340/385] Fix cmp bug --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d82cb47e8..bec86a439 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1722,7 +1722,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) localbits[i] = prevbits[i]; if ( maxflag == 0 ) { - if ( komodo_pricecmp(nHeight,n,&maxflag,localbits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,localbits,PRICES_MAXCHANGE) < 0 ) { fprintf(stderr,"maxflag.0 cmp error\n"); return(-1); From c85b4db249d1c027be04e08744312d93caa82e07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 04:42:11 -1100 Subject: [PATCH 341/385] Test --- src/bitcoind.cpp | 2 +- src/komodo_gateway.h | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 3c5cfe4d6..0afb47894 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -90,7 +90,7 @@ void WaitForShutdown(boost::thread_group* threadGroup) //komodo_longestchain(); if ( ASSETCHAINS_CBOPRET != 0 ) komodo_cbopretupdate(); - for (i=0; i vopret; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; + std::vector vopret; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); @@ -1698,9 +1698,13 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { n = (int32_t)(vopret.size() / sizeof(uint32_t)); memcpy(pricebits,vopret.data(),Mineropret.size()); - lag = (int32_t)(time(NULL) - pricebits[0]); + lag = (int32_t)(now - pricebits[0]); + if ( lag > 60 ) // blocks from future not so good to have + return(-1); if ( lag < 0 ) lag = -lag; + if ( lag > ASSETCHAINS_BLOCKTIME ) + return(-1); lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( nHeight > 1 ) @@ -1735,11 +1739,11 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) maxflag = 0; if ( (newprice= komodo_pricenew(&maxflag,pricebits[i],prevbits[i],PRICES_MAXCHANGE)) != 0 ) // proposed price is clamped { - // make sure local price is beyond clamped + // make sure local price is moving in right direction fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u\n",maxflag,i,localbits[i],pricebits[i]); - if ( maxflag > 0 && localbits[i] < pricebits[i] ) + if ( maxflag > 0 && localbits[i] < prevbits[i] ) return(-1); - else if ( maxflag < 0 && localbits[i] > pricebits[i] ) + else if ( maxflag < 0 && localbits[i] > prevbits[i] ) return(-1); } } @@ -2009,9 +2013,9 @@ int32_t get_btcusd(uint32_t pricebits[4]) void komodo_cbopretupdate() { - static uint32_t lasttime; + static uint32_t lasttime,lastcrypto,lastbtc; static uint32_t pricebits[4],cryptoprices[sizeof(Cryptos)/sizeof(*Cryptos)],forexprices[sizeof(Forex)/sizeof(*Forex)]; - int32_t size; + int32_t size; uint32_t now = (uint32_t)time(NULL); if ( (ASSETCHAINS_CBOPRET & 1) != 0 ) { if ( komodo_nextheight() > 333 ) @@ -2024,13 +2028,14 @@ void komodo_cbopretupdate() if ( Mineropret.size() < size ) Mineropret.resize(size); size = PRICES_SIZEBIT0; - if ( get_btcusd(pricebits) == 0 ) + if ( now > lastbtc+30 && get_btcusd(pricebits) == 0 ) { memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); + lastbtc = (uint32_t)time(NULL); } if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) { - if ( time(NULL) > lasttime+3600*5 || forexprices[0] == 0 ) + if ( now > lasttime+3600*5 || forexprices[0] == 0 ) { get_dailyfx(forexprices); memcpy(&Mineropret.data()[size],forexprices,sizeof(forexprices)); @@ -2040,8 +2045,12 @@ void komodo_cbopretupdate() } if ( (ASSETCHAINS_CBOPRET & 4) != 0 ) { - get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); - memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices)); + if ( now > lastcrypto+60 ) + { + get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); + memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices)); + lastcrypto = (uint32_t)time(NULL); + } size += sizeof(cryptoprices); } //int32_t i; for (i=0; i Date: Sun, 31 Mar 2019 04:50:02 -1100 Subject: [PATCH 342/385] Test --- src/komodo_gateway.h | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 66fff3984..74ba9a779 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1698,17 +1698,17 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { n = (int32_t)(vopret.size() / sizeof(uint32_t)); memcpy(pricebits,vopret.data(),Mineropret.size()); - lag = (int32_t)(now - pricebits[0]); - if ( lag > 60 ) // blocks from future not so good to have - return(-1); - if ( lag < 0 ) - lag = -lag; - if ( lag > ASSETCHAINS_BLOCKTIME ) - return(-1); - lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); - fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( nHeight > 1 ) { + lag = (int32_t)(now - pricebits[0]); + if ( lag > 60 ) // blocks from future not so good to have + return(-1); + if ( lag < 0 ) + lag = -lag; + if ( lag > ASSETCHAINS_BLOCKTIME ) + return(-1); + lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); + fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -1717,34 +1717,34 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(-1); } } else return(-1); - } - if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) - { - memcpy(localbits,Mineropret.data(),Mineropret.size()); - for (i=0; i= PRICES_SIZEBIT0 ) { - if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,localbits,PRICES_MAXCHANGE) < 0 ) + memcpy(localbits,Mineropret.data(),Mineropret.size()); + for (i=0; i 0 && localbits[i] < prevbits[i] ) - return(-1); - else if ( maxflag < 0 && localbits[i] > prevbits[i] ) - return(-1); + fprintf(stderr,"maxflag.0 cmp error\n"); + return(-1); + } + } + else + { + for (i=1; i 0 && localbits[i] < prevbits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > prevbits[i] ) + return(-1); + } } } } From eb23d9e3c46e858419b5d63820c5cdf3accfe6cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 04:52:29 -1100 Subject: [PATCH 343/385] Fix lag calc --- src/komodo_gateway.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 74ba9a779..c8219fc08 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1701,12 +1701,18 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( nHeight > 1 ) { lag = (int32_t)(now - pricebits[0]); - if ( lag > 60 ) // blocks from future not so good to have + if ( lag > ASSETCHAINS_BLOCKTIME ) + { + fprintf(stderr,"now.%u - pricebits[0] %u -> lag.%d\n",now,pricebits[0],lag); return(-1); + } if ( lag < 0 ) lag = -lag; - if ( lag > ASSETCHAINS_BLOCKTIME ) + if ( lag > 60 ) // avoid data from future + { + fprintf(stderr,"now.%u - pricebits[0] %u -> lag.%d\n",now,pricebits[0],lag); return(-1); + } lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) From 275e78667c9c8957bf6f6f8eed9db845dd79bd73 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 04:56:26 -1100 Subject: [PATCH 344/385] Use lag2 --- src/komodo_gateway.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c8219fc08..f989594ff 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1701,19 +1701,19 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( nHeight > 1 ) { lag = (int32_t)(now - pricebits[0]); - if ( lag > ASSETCHAINS_BLOCKTIME ) - { - fprintf(stderr,"now.%u - pricebits[0] %u -> lag.%d\n",now,pricebits[0],lag); - return(-1); - } if ( lag < 0 ) lag = -lag; - if ( lag > 60 ) // avoid data from future + lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); + if ( lag2 > 60 ) { - fprintf(stderr,"now.%u - pricebits[0] %u -> lag.%d\n",now,pricebits[0],lag); + fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); + return(-1); + } + if ( lag2 < -ASSETCHAINS_BLOCKTIME-60 ) // avoid data from future + { + fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); return(-1); } - lag2 = (int32_t)(pricebits[0] - komodo_heightstamp(nHeight-1)); fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { From c171940c3f563ffe4cfa36477deda946869ab034 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 05:00:04 -1100 Subject: [PATCH 345/385] Test --- src/komodo_gateway.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f989594ff..e3ab02086 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1701,15 +1701,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( nHeight > 1 ) { lag = (int32_t)(now - pricebits[0]); - if ( lag < 0 ) - lag = -lag; lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); - if ( lag2 > 60 ) - { - fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); - return(-1); - } - if ( lag2 < -ASSETCHAINS_BLOCKTIME-60 ) // avoid data from future + if ( lag < -60 ) // avoid data from future { fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); return(-1); From 14943d68064c143acc7bcbb92c8a80eba1780579 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 08:54:17 -1100 Subject: [PATCH 346/385] Test --- src/komodo_gateway.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e3ab02086..64b11bafe 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1707,9 +1707,13 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); return(-1); } + // else need to check against current blocktime to prevent pricebits[0] games fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { + for (i=1; i Date: Sun, 31 Mar 2019 08:56:54 -1100 Subject: [PATCH 347/385] Test --- src/komodo_gateway.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 64b11bafe..25dc6d0bd 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,6 +1711,9 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { + for (i=1; i Date: Sun, 31 Mar 2019 09:03:21 -1100 Subject: [PATCH 348/385] Retry prev block error (most likely due to unfleshed data) --- src/komodo_gateway.h | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 25dc6d0bd..4e49d59d0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,16 +1711,23 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - for (i=1; i= PRICES_SIZEBIT0 ) From 98977bb947924964ec1c0e5e1796d7c0fa8a4131 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:24:02 -1100 Subject: [PATCH 349/385] Add some forex calc --- src/komodo_gateway.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4e49d59d0..b7e1ec8f9 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1690,7 +1690,7 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); + std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 ) { GetOpReturnData(scriptPubKey,vopret); @@ -1708,7 +1708,10 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) return(-1); } // else need to check against current blocktime to prevent pricebits[0] games - fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR htstamp.%d [%d]\n",nHeight,pricebits[0],lag,(double)pricebits[1]/10000,(double)pricebits[2]/10000,(double)pricebits[3]/10000,komodo_heightstamp(nHeight-1),lag2); + btcusd = (double)pricebits[1]/10000; + btcgbp = (double)pricebits[2]/10000; + btceur = (double)pricebits[3]/10000; + fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.7f, EURGBP %.6f htstamp.%d [%d]\n",nHeight,pricebits[0],lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,komodo_heightstamp(nHeight-1),lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -1720,6 +1723,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"%.4f ",(double)pricebits[i]/10000); fprintf(stderr," newprices.%d\n",nHeight); sleep(3); + memcpy(pricebits,vopret.data(),Mineropret.size()); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) From 7a2cdcb8c57578e0fb441408c14fd820d09fd159 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:24:52 -1100 Subject: [PATCH 350/385] -timestamp prints --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b7e1ec8f9..47d84e6df 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,7 +1711,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcusd = (double)pricebits[1]/10000; btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; - fprintf(stderr,"ht.%d: t%u lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.7f, EURGBP %.6f htstamp.%d [%d]\n",nHeight,pricebits[0],lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,komodo_heightstamp(nHeight-1),lag2); + fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.7f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) From 9beb02477d82a8ab322204c45a83b7b85dc438e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:29:55 -1100 Subject: [PATCH 351/385] +prints --- src/komodo_gateway.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 47d84e6df..3995dadf1 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,7 +1711,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcusd = (double)pricebits[1]/10000; btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; - fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.7f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,lag2); + fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -1997,7 +1997,7 @@ int32_t get_stocks(const char *list[],int32_t n) int32_t get_btcusd(uint32_t pricebits[4]) { - cJSON *pjson,*bpi,*obj; char str[512]; uint64_t btcusd = 0,btcgbp = 0,btceur = 0; + cJSON *pjson,*bpi,*obj; char str[512]; double dbtcgbp,dbtcusd,dbtceur; uint64_t btcusd = 0,btcgbp = 0,btceur = 0; if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json")) != 0 ) { if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 ) @@ -2020,7 +2020,10 @@ int32_t get_btcusd(uint32_t pricebits[4]) } } free_json(pjson); - fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f\n",dstr(btcusd),dstr(btcgbp),dstr(btceur)); + dbtcusd = (double)pricebits[1]/10000; + dbtcgbp = (double)pricebits[2]/10000; + dbtceur = (double)pricebits[3]/10000; + fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f GBPUSD %.6f, EURUSD %.6f EURGBP %.6f\n",dbtcusd,dbtcgbp,dbtceur,dbtcgbp/dbtcusd,dbtceur/dbtcusd,dbtceur/dbtcgbp); return(0); } return(-1); From 8a520ea4399f415accc7e33bf9af5d4b9658f085 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:32:33 -1100 Subject: [PATCH 352/385] Invert forex calc --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3995dadf1..12a980d78 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,7 +1711,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcusd = (double)pricebits[1]/10000; btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; - fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcgbp/btcusd,btceur/btcusd,btceur/btcgbp,lag2); + fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcgbp/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -2023,7 +2023,7 @@ int32_t get_btcusd(uint32_t pricebits[4]) dbtcusd = (double)pricebits[1]/10000; dbtcgbp = (double)pricebits[2]/10000; dbtceur = (double)pricebits[3]/10000; - fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f GBPUSD %.6f, EURUSD %.6f EURGBP %.6f\n",dbtcusd,dbtcgbp,dbtceur,dbtcgbp/dbtcusd,dbtceur/dbtcusd,dbtceur/dbtcgbp); + fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f GBPUSD %.6f, EURUSD %.6f EURGBP %.6f\n",dbtcusd,dbtcgbp,dbtceur,dbtcusd/dbtcgbp,dbtcgbp/dbtceur,dbtcgbp/dbtceur); return(0); } return(-1); From 3e48426eb56ad0dd748eef821ed7e2139086a4ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:35:06 -1100 Subject: [PATCH 353/385] Fix eurusd --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 12a980d78..d04bb9fc4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1711,7 +1711,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcusd = (double)pricebits[1]/10000; btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; - fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcgbp/btceur,btcgbp/btceur,lag2); + fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) @@ -2023,7 +2023,7 @@ int32_t get_btcusd(uint32_t pricebits[4]) dbtcusd = (double)pricebits[1]/10000; dbtcgbp = (double)pricebits[2]/10000; dbtceur = (double)pricebits[3]/10000; - fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f GBPUSD %.6f, EURUSD %.6f EURGBP %.6f\n",dbtcusd,dbtcgbp,dbtceur,dbtcusd/dbtcgbp,dbtcgbp/dbtceur,dbtcgbp/dbtceur); + fprintf(stderr,"BTC/USD %.4f, BTC/GBP %.4f, BTC/EUR %.4f GBPUSD %.6f, EURUSD %.6f EURGBP %.6f\n",dbtcusd,dbtcgbp,dbtceur,dbtcusd/dbtcgbp,dbtcusd/dbtceur,dbtcgbp/dbtceur); return(0); } return(-1); From b025dd2eaf8068b2068e09112dbbfab478197127 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 09:43:53 -1100 Subject: [PATCH 354/385] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d04bb9fc4..c1e5dcdcb 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1590,7 +1590,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 lowprice--; if ( price >= highprice ) { - fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + //fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); if ( price > highprice ) // return non-zero only if we violate the tolerance { *maxflagp = 2; @@ -1600,7 +1600,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 } else if ( price <= lowprice ) { - fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + //fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); if ( price < lowprice ) { *maxflagp = -2; @@ -2048,7 +2048,7 @@ void komodo_cbopretupdate() if ( Mineropret.size() < size ) Mineropret.resize(size); size = PRICES_SIZEBIT0; - if ( now > lastbtc+30 && get_btcusd(pricebits) == 0 ) + if ( now > lastbtc+120 && get_btcusd(pricebits) == 0 ) { memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); lastbtc = (uint32_t)time(NULL); @@ -2065,7 +2065,7 @@ void komodo_cbopretupdate() } if ( (ASSETCHAINS_CBOPRET & 4) != 0 ) { - if ( now > lastcrypto+60 ) + if ( now > lastcrypto+100 ) { get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices)); From c6fca9511810429d79e49fd2ae194064b28c90e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 21:26:51 -1100 Subject: [PATCH 355/385] Fix strange data bug --- src/komodo_gateway.h | 17 ++++++----------- src/komodo_utils.h | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c1e5dcdcb..d863c8a27 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1665,7 +1665,7 @@ CScript komodo_mineropret(int32_t nHeight) memcpy(pricebits,Mineropret.data(),Mineropret.size()); if ( komodo_pricecmp(0,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { - // if the new prices are not within tolerance, update Mineropret with clipped prices + // if the new prices are outside tolerance, update Mineropret with clamped prices komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE); fprintf(stderr,"update Mineropret to clamped prices\n"); memcpy(Mineropret.data(),pricebits,Mineropret.size()); @@ -1722,17 +1722,10 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) for (i=1; i= PRICES_SIZEBIT0 ) { @@ -2030,6 +2023,8 @@ int32_t get_btcusd(uint32_t pricebits[4]) } // komodo_cbopretupdate() obtains the external price data and encodes it into Mineropret, which will then be used by the miner and validation +// save history, use new data to approve past rejection, where is the auto-reconsiderblock? +// 51% correlation, smoothing void komodo_cbopretupdate() { diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 44b1192a4..a91dae1e8 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -2067,7 +2067,7 @@ void komodo_args(char *argv0) if ( ASSETCHAINS_CBOPRET != 0 ) { extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_CBOPRET),(void *)&ASSETCHAINS_CBOPRET); - //komodo_cbopretupdate(); // will set Mineropret + komodo_cbopretupdate(); // will set Mineropret fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n"); } } From 7f81f5f6ffd44e01b30007c6882eb81b7d6cb16a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 21:44:27 -1100 Subject: [PATCH 356/385] Allow 0 price for earlyblocks --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d863c8a27..2eac0e7f4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1618,7 +1618,7 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,int32_t *maxflagp,uint32_t *pr *maxflagp = 0; for (i=1; i newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); From dc1b504b980b606e5a60f158335aab71db618466 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 21:48:54 -1100 Subject: [PATCH 357/385] Latch prevbits if new is 0 --- src/komodo_gateway.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2eac0e7f4..1cc899f1a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1714,6 +1714,9 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { + for (i=0; i Date: Sun, 31 Mar 2019 21:53:31 -1100 Subject: [PATCH 358/385] +print --- src/komodo_gateway.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1cc899f1a..4d84fa19f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1590,7 +1590,7 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 lowprice--; if ( price >= highprice ) { - //fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); if ( price > highprice ) // return non-zero only if we violate the tolerance { *maxflagp = 2; @@ -1618,7 +1618,7 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,int32_t *maxflagp,uint32_t *pr *maxflagp = 0; for (i=1; i= 500 || pricebitsB[i] != 0) && (newprice= komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance)) != 0 ) { fprintf(stderr,"ht.%d i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); @@ -1714,9 +1714,12 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - for (i=0; i Date: Sun, 31 Mar 2019 21:56:44 -1100 Subject: [PATCH 359/385] 339 exemption --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4d84fa19f..8fad25202 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1720,7 +1720,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( pricebits[i] == 0 ) pricebits[i] = prevbits[i]; } - if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( nHeight != 339 && komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { for (i=1; i Date: Sun, 31 Mar 2019 21:58:47 -1100 Subject: [PATCH 360/385] 340 --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8fad25202..4aab886b5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1720,7 +1720,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( pricebits[i] == 0 ) pricebits[i] = prevbits[i]; } - if ( nHeight != 339 && komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( nHeight != 340 && komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { for (i=1; i Date: Sun, 31 Mar 2019 22:02:28 -1100 Subject: [PATCH 361/385] Skip first 500 --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4aab886b5..c8a3d3c9f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1720,7 +1720,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( pricebits[i] == 0 ) pricebits[i] = prevbits[i]; } - if ( nHeight != 340 && komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( nHeight < 500 && komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { for (i=1; i Date: Sun, 31 Mar 2019 22:06:51 -1100 Subject: [PATCH 362/385] 500 --- src/komodo_gateway.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c8a3d3c9f..26bf2fcc3 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1618,7 +1618,7 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,int32_t *maxflagp,uint32_t *pr *maxflagp = 0; for (i=1; i= 500 || pricebitsB[i] != 0) && (newprice= komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance)) != 0 ) + if ( (newprice= komodo_pricenew(maxflagp,pricebitsA[i],pricebitsB[i],tolerance)) != 0 ) { fprintf(stderr,"ht.%d i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); @@ -1693,6 +1693,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 ) { + if ( nHeight < 500 ) + return(0); GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) { @@ -1714,13 +1716,13 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - if ( nHeight < 500 ) + /*if ( nHeight < 500 ) { for (i=0; i Date: Sun, 31 Mar 2019 22:09:36 -1100 Subject: [PATCH 363/385] 600 --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 26bf2fcc3..66a6f2515 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1693,7 +1693,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 ) { - if ( nHeight < 500 ) + if ( nHeight < 600 ) return(0); GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) From 6e25432673f5cd2a9f8a00c64ec0ea9aef7e8a80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:13:44 -1100 Subject: [PATCH 364/385] Fetch data first --- src/komodo_gateway.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 66a6f2515..e71b8cd4d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1691,9 +1691,11 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); - if ( ASSETCHAINS_CBOPRET != 0 ) + if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) { - if ( nHeight < 600 ) + if ( komodo_heightpricebits(prevbits,nHeight-1) < 0 ) + return(-1); + if ( nHeight < 350 ) return(0); GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) @@ -1714,7 +1716,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); - if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) + //if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { /*if ( nHeight < 500 ) { @@ -1734,7 +1736,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); return(-1); } // else this is the good case we hope to happen - } else return(-1); + } //else return(-1); if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { memcpy(localbits,Mineropret.data(),Mineropret.size()); From 6d7828d809f684ac31ad5c8c2a5f4c42bbe86682 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:17:45 -1100 Subject: [PATCH 365/385] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e71b8cd4d..65487219d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1693,10 +1693,6 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) { - if ( komodo_heightpricebits(prevbits,nHeight-1) < 0 ) - return(-1); - if ( nHeight < 350 ) - return(0); GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() >= PRICES_SIZEBIT0 ) { @@ -1704,6 +1700,10 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) memcpy(pricebits,vopret.data(),Mineropret.size()); if ( nHeight > 1 ) { + if ( komodo_heightpricebits(prevbits,nHeight-1) < 0 ) + return(-1); + if ( nHeight < 350 ) + return(0); lag = (int32_t)(now - pricebits[0]); lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); if ( lag < -60 ) // avoid data from future From 5479c8ae392e69d861a23b2494a548c97dd51311 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:25:10 -1100 Subject: [PATCH 366/385] Test --- src/komodo_gateway.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 65487219d..fc410d5ad 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1698,12 +1698,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { n = (int32_t)(vopret.size() / sizeof(uint32_t)); memcpy(pricebits,vopret.data(),Mineropret.size()); - if ( nHeight > 1 ) + if ( nHeight > 1 && vopret.size() == Mineropret.size() ) { - if ( komodo_heightpricebits(prevbits,nHeight-1) < 0 ) - return(-1); - if ( nHeight < 350 ) - return(0); lag = (int32_t)(now - pricebits[0]); lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); if ( lag < -60 ) // avoid data from future @@ -1769,6 +1765,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) } } } + else if ( nHeight > 500 ) + return(-1); return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)Mineropret.size(),(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); From 0cba720dbd3fec82618add4880adaa6b0a0b6ac7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:28:30 -1100 Subject: [PATCH 367/385] Test --- src/komodo_gateway.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index fc410d5ad..f5149d473 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1698,7 +1698,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { n = (int32_t)(vopret.size() / sizeof(uint32_t)); memcpy(pricebits,vopret.data(),Mineropret.size()); - if ( nHeight > 1 && vopret.size() == Mineropret.size() ) + if ( nHeight > 1 ) { lag = (int32_t)(now - pricebits[0]); lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); @@ -1712,14 +1712,14 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) btcgbp = (double)pricebits[2]/10000; btceur = (double)pricebits[3]/10000; fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); - //if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) + if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - /*if ( nHeight < 500 ) + if ( nHeight < 500 ) { for (i=0; i 500 ) - return(-1); return(0); } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)Mineropret.size(),(int32_t)scriptPubKey.size(),scriptPubKey[0]); return(-1); From 485376098a763386dab77d14039412d2f8623f85 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:32:03 -1100 Subject: [PATCH 368/385] Test --- src/komodo_gateway.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f5149d473..06ed31474 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1730,7 +1730,8 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr," newprices.%d\n",nHeight); fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); - return(-1); + if ( nHeight != 339 ) + return(-1); } // else this is the good case we hope to happen } //else return(-1); if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) From dd851e864413a33986ef3b3b8dda7dd7bdbcfeee Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:37:49 -1100 Subject: [PATCH 369/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 06ed31474..86d1ab541 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1730,7 +1730,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr," newprices.%d\n",nHeight); fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); - if ( nHeight != 339 ) + if ( nHeight != 339 && nHeight != 340 ) return(-1); } // else this is the good case we hope to happen } //else return(-1); From 46d59bf1d71ee46449971b469b0a3896d53f8cd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:39:42 -1100 Subject: [PATCH 370/385] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 86d1ab541..79b6642e5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1730,7 +1730,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr," newprices.%d\n",nHeight); fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); - if ( nHeight != 339 && nHeight != 340 ) + if ( nHeight != 339 && nHeight != 340 && nHeight != 341 ) return(-1); } // else this is the good case we hope to happen } //else return(-1); From 7291a4fc73eef6d59654ca875d7b261c7b718c75 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:41:25 -1100 Subject: [PATCH 371/385] 500 --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 79b6642e5..5f8c6d134 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1730,7 +1730,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr," newprices.%d\n",nHeight); fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); - if ( nHeight != 339 && nHeight != 340 && nHeight != 341 ) + if ( nHeight > 500 ) return(-1); } // else this is the good case we hope to happen } //else return(-1); From 1ee8042e98fb12215121fcb5b61edeb5ac69965e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:43:38 -1100 Subject: [PATCH 372/385] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 5f8c6d134..be262b24f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1714,12 +1714,12 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - if ( nHeight < 500 ) + /*if ( nHeight < 500 ) { for (i=0; i 500 ) + //if ( nHeight > 500 ) return(-1); } // else this is the good case we hope to happen } //else return(-1); From 0792e959c86a4cf3f635c5af02d20346685cb0c3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:54:42 -1100 Subject: [PATCH 373/385] CBOPRET reconsider --- src/main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index b73a31856..bac0def5d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4120,7 +4120,14 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) + { InvalidBlockFound(pindexNew, state); + if ( ASSETCHAINS_CBOPRET != 0 ) + { + pindex->nStatus &= ~BLOCK_FAILED_MASK; + fprinf(stderr,"reconsiderblock %d\n",(int32_t)pindex->nHeight); + } + } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } mapBlockSource.erase(pindexNew->GetBlockHash()); @@ -5211,7 +5218,7 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat miSelf->second = pindex = AddToBlockIndex(block); if (ppindex) *ppindex = pindex; - if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK ) + if ( pindex != 0 && (pindex->nStatus & BLOCK_FAILED_MASK) != 0 ) { if ( ASSETCHAINS_CC == 0 )//&& (ASSETCHAINS_PRIVATE == 0 || KOMODO_INSYNC >= Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight) ) return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); From f7a881d1b3a0b411cf522951a9e4b14fb4609093 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:55:46 -1100 Subject: [PATCH 374/385] pindexNew --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bac0def5d..8a139c247 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4124,8 +4124,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * InvalidBlockFound(pindexNew, state); if ( ASSETCHAINS_CBOPRET != 0 ) { - pindex->nStatus &= ~BLOCK_FAILED_MASK; - fprinf(stderr,"reconsiderblock %d\n",(int32_t)pindex->nHeight); + pindexNew->nStatus &= ~BLOCK_FAILED_MASK; + fprinf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->nHeight); } } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); From baacd254e3abef202f9c8674b8363f6407f3412c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:56:55 -1100 Subject: [PATCH 375/385] fprinTf --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 8a139c247..e8e1e554c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4125,7 +4125,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * if ( ASSETCHAINS_CBOPRET != 0 ) { pindexNew->nStatus &= ~BLOCK_FAILED_MASK; - fprinf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->nHeight); + fprintf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->nHeight); } } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); From 1af4f989ac9c1fa7f91198bf1685d208d1fa6940 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 22:58:52 -1100 Subject: [PATCH 376/385] GetHeight() --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index e8e1e554c..be516c25d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4125,7 +4125,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * if ( ASSETCHAINS_CBOPRET != 0 ) { pindexNew->nStatus &= ~BLOCK_FAILED_MASK; - fprintf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->nHeight); + fprintf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->GetHeight()); } } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); From 6b7f7d91aeb6a51d716f6aee0fcb39728d81bd5d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 23:01:10 -1100 Subject: [PATCH 377/385] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index be516c25d..1036670d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4122,11 +4122,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); - if ( ASSETCHAINS_CBOPRET != 0 ) + /*if ( ASSETCHAINS_CBOPRET != 0 ) { pindexNew->nStatus &= ~BLOCK_FAILED_MASK; fprintf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->GetHeight()); - } + }*/ } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } From 7a739655e4b616ae4436559c5bf35718e6c35855 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 31 Mar 2019 23:07:55 -1100 Subject: [PATCH 378/385] Test --- src/komodo_gateway.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index be262b24f..60bf83006 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1687,6 +1687,10 @@ CScript komodo_mineropret(int32_t nHeight) The only way komodo_opretvalidate() doesnt return an error is if maxflag is set or it is within tolerance of both the prior block and the local data. The local data validation only happens if it is a recent block and not a block from the past as the local node is only getting the current price data. */ +// reconsiderblock 002aca768b09dfcf36bd934ab34b23983148b116e12cb0b6e1a3f895d1db63aa +// and +// reconsiderblock 0034cf582018eacc0b4ae001491ce460113514cb1a3f217567ef4a2207de361a +// are needed to sync past initial blocks with different data set int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { @@ -1714,12 +1718,12 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { - /*if ( nHeight < 500 ) + if ( nHeight < 500 ) { for (i=0; i 500 ) - return(-1); + return(-1); } // else this is the good case we hope to happen } //else return(-1); if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) From 31580754dbd6b13c1c1bdfac909061ff33bb2674 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 02:30:27 -1100 Subject: [PATCH 379/385] Always do the clamp check --- src/komodo_gateway.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 60bf83006..c964f19ee 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1577,7 +1577,7 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) /* komodo_pricenew() is passed in a reference price, the change tolerance and the proposed price. it needs to return a clipped price if it is too big and also set a flag if it is at or above the limit */ -uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) +uint32_t komodo_pricenew(char *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) { uint64_t highprice,lowprice; if ( refprice < 2 ) @@ -1612,13 +1612,12 @@ uint32_t komodo_pricenew(int32_t *maxflagp,uint32_t price,uint32_t refprice,int6 } // komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance -int32_t komodo_pricecmp(int32_t nHeight,int32_t n,int32_t *maxflagp,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) +int32_t komodo_pricecmp(int32_t nHeight,int32_t n,char *maxflags,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) { int32_t i; uint32_t newprice; - *maxflagp = 0; for (i=1; i newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); return(-1); @@ -1646,7 +1645,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 // komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight CScript komodo_mineropret(int32_t nHeight) { - CScript opret; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,i,n,numzero=0; + CScript opret; char maxflags[8192]; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,i,n,numzero=0; if ( Mineropret.size() >= PRICES_SIZEBIT0 ) { n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); @@ -1663,7 +1662,8 @@ CScript komodo_mineropret(int32_t nHeight) if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) { memcpy(pricebits,Mineropret.data(),Mineropret.size()); - if ( komodo_pricecmp(0,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + memset(maxflags,0,sizeof(maxflags)); + if ( komodo_pricecmp(0,n,maxflags,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { // if the new prices are outside tolerance, update Mineropret with clamped prices komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE); @@ -1690,11 +1690,12 @@ CScript komodo_mineropret(int32_t nHeight) // reconsiderblock 002aca768b09dfcf36bd934ab34b23983148b116e12cb0b6e1a3f895d1db63aa // and // reconsiderblock 0034cf582018eacc0b4ae001491ce460113514cb1a3f217567ef4a2207de361a +// reconsiderbloc 000abf51c023b64af327c50c1b060797b8cb281c696d30ab92fd002a8b8c9aea // are needed to sync past initial blocks with different data set int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n,maxflag=0; uint32_t now = (uint32_t)time(NULL); + std::vector vopret; char maxflags[8192]; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) { GetOpReturnData(scriptPubKey,vopret); @@ -1702,6 +1703,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { n = (int32_t)(vopret.size() / sizeof(uint32_t)); memcpy(pricebits,vopret.data(),Mineropret.size()); + memset(maxflags,0,sizeof(maxflags)); if ( nHeight > 1 ) { lag = (int32_t)(now - pricebits[0]); @@ -1724,7 +1726,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( pricebits[i] == 0 ) pricebits[i] = prevbits[i]; } - if ( komodo_pricecmp(nHeight,n,&maxflag,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(nHeight,n,maxflags,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) { for (i=1; i Date: Mon, 1 Apr 2019 02:32:20 -1100 Subject: [PATCH 380/385] Maxflag --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c964f19ee..d90016ee4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1619,7 +1619,7 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,char *maxflags,uint32_t *price { if ( (newprice= komodo_pricenew(&maxflags[i],pricebitsA[i],pricebitsB[i],tolerance)) != 0 ) { - fprintf(stderr,"ht.%d i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,*maxflagp); + fprintf(stderr,"ht.%d i.%d/%d %u vs %u -> newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,maxflags[i]); return(-1); } } @@ -1695,7 +1695,7 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; char maxflags[8192]; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); + std::vector vopret; char maxflags[8192]; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,maxflag,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) { GetOpReturnData(scriptPubKey,vopret); From a3c6ea84f9e14db1be10281f124d2f822f8b7525 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 02:34:02 -1100 Subject: [PATCH 381/385] 2048 --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d90016ee4..0b94ccda4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1629,10 +1629,10 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,char *maxflags,uint32_t *price // komodo_priceclamp() clamps any price that is beyond tolerance int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int64_t tolerance) { - int32_t i,maxflag; uint32_t newprice; + int32_t i; uint32_t newprice; char maxflags[2048]; + memset(maxflags,0,sizeof(maxflags)); for (i=1; i %u\n",i,n,refprices[i],pricebits[i],newprice); @@ -1645,7 +1645,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 // komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight CScript komodo_mineropret(int32_t nHeight) { - CScript opret; char maxflags[8192]; uint32_t pricebits[8192],prevbits[8192]; int32_t maxflag,i,n,numzero=0; + CScript opret; char maxflags[2048]; uint32_t pricebits[2048],prevbits[2048]; int32_t maxflag,i,n,numzero=0; if ( Mineropret.size() >= PRICES_SIZEBIT0 ) { n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); @@ -1695,7 +1695,7 @@ CScript komodo_mineropret(int32_t nHeight) int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { - std::vector vopret; char maxflags[8192]; double btcusd,btcgbp,btceur; uint32_t localbits[8192],pricebits[8192],prevbits[8192],newprice; int32_t i,maxflag,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); + std::vector vopret; char maxflags[2048]; double btcusd,btcgbp,btceur; uint32_t localbits[2048],pricebits[2048],prevbits[2048],newprice; int32_t i,maxflag,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) { GetOpReturnData(scriptPubKey,vopret); From 32c65f4686d999b11a419cf9a37ff6b25de90b04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 02:35:07 -1100 Subject: [PATCH 382/385] &maxflags[I] --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0b94ccda4..22952230e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1633,7 +1633,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6 memset(maxflags,0,sizeof(maxflags)); for (i=1; i %u\n",i,n,refprices[i],pricebits[i],newprice); pricebits[i] = newprice; From 16eddc774c639f755a0f58497ddee700557958ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 03:06:38 -1100 Subject: [PATCH 383/385] Cleanup code --- src/komodo_gateway.h | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 22952230e..2f5dfc5c5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1738,36 +1738,26 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) fprintf(stderr,"vs prev maxflag.%d cmp error\n",maxflag); return(-1); } // else this is the good case we hope to happen - } //else return(-1); + } else return(-1); if ( lag < ASSETCHAINS_BLOCKTIME && Mineropret.size() >= PRICES_SIZEBIT0 ) { memcpy(localbits,Mineropret.data(),Mineropret.size()); - for (i=0; i 0 && localbits[i] < prevbits[i] ) - return(-1); - else if ( maxflag < 0 && localbits[i] > prevbits[i] ) - return(-1); - } + // make sure local price is moving in right direction + fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u\n",maxflag,i,localbits[i],pricebits[i]); + if ( maxflag > 0 && localbits[i] < prevbits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > prevbits[i] ) + return(-1); } } } From 19f067493995ba4e8f864de7ac52dc03c62df9b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 04:22:00 -1100 Subject: [PATCH 384/385] Tweak print --- src/komodo_gateway.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2f5dfc5c5..932efd051 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1692,6 +1692,8 @@ CScript komodo_mineropret(int32_t nHeight) // reconsiderblock 0034cf582018eacc0b4ae001491ce460113514cb1a3f217567ef4a2207de361a // reconsiderbloc 000abf51c023b64af327c50c1b060797b8cb281c696d30ab92fd002a8b8c9aea // are needed to sync past initial blocks with different data set +// pass in blockhash and nTime, latch if it is rejected due to local price, then if localprice changes in a way that would validate then issue reconsiderblock +// add rpc call for extracting rawprices int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) { @@ -1753,7 +1755,7 @@ int32_t komodo_opretvalidate(int32_t nHeight,CScript scriptPubKey) if ( (maxflag= maxflags[i]) != 0 ) { // make sure local price is moving in right direction - fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u\n",maxflag,i,localbits[i],pricebits[i]); + fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u prevbits.%u\n",maxflag,i,localbits[i],pricebits[i],prevbits[i]); if ( maxflag > 0 && localbits[i] < prevbits[i] ) return(-1); else if ( maxflag < 0 && localbits[i] > prevbits[i] ) From cf38e77da5fa12dc252f0f34ed930d2deae0a443 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 1 Apr 2019 05:36:21 -1100 Subject: [PATCH 385/385] Change to 150000 activation --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 38f9041c1..eefccd32a 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1237,7 +1237,7 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) n = pblock->vtx[i].vout.size(); for (j=0; j 100000 && ASSETCHAINS_STAKED != 0 && txn_count > 1 && i == txn_count-1 && j == n-1 ) + if ( height > 150000 && ASSETCHAINS_STAKED != 0 && txn_count > 1 && i == txn_count-1 && j == n-1 ) break; //fprintf(stderr,"(%d %.8f).%d ",i,dstr(pblock->vtx[i].vout[j].nValue),j); if ( i != 0 || j != 1 )

Jq5C-aTifz(E5Kg}P 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⋙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 LNkvXXu0mjfL3yYq literal 0 HcmV?d00001 diff --git a/src/gui/komodoku/board.png b/src/gui/komodoku/board.png new file mode 100644 index 0000000000000000000000000000000000000000..bd77ca419999b45f31af1dc6e91aedd4b0f53a9f GIT binary patch literal 5678 zcmeAS@N?(olHy`uVBq!ia0y~yV5|jU4mP03i^?5=K#C>Z(btiI;o6NW{t-q%zGR7O zL`iUdT1k0gQ7VIDN`6wRf@f}GdTLN=VoGJ<$y6H#2GIkaE{-7;w~|s45`LUF;Bq^t zA;G#h!G)oLAxVn2DG(xJ$)L~>k~F@M{Q-MU|kN+74koMTY6Tl7ztmwLMJ)o!OKl^U$ z_Acp(KNlC;OMPGb(5mQ>955ZVmqSZM7DiyHsQbko(uWx3jfTYH1W+nSVtMp`@j+w+V|BDHrVGdyBIgycp zse|>{kN^MeA1_$HP(t!Qe_1)7sJYT-Q19TK`{B|jM{I$qitjzNR2=QlI_X`4raI^*LDqz40|2~awwXxSpWxo89ZJ6T-G@yGywpilHk$+ literal 0 HcmV?d00001 diff --git a/src/gui/komodoku/sudoku_kmdlib.py b/src/gui/komodoku/sudoku_kmdlib.py new file mode 100644 index 000000000..a2b2aa239 --- /dev/null +++ b/src/gui/komodoku/sudoku_kmdlib.py @@ -0,0 +1,41 @@ +import platform +import os +import re +import random +from slickrpc import Proxy + + +# define function that fetchs rpc creds from .conf +def def_credentials(chain): + rpcport =''; + operating_system = platform.system() + if operating_system == 'Darwin': + ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' + elif operating_system == 'Linux': + ac_dir = os.environ['HOME'] + '/.komodo' + elif operating_system == 'Windows': + ac_dir = '%s/komodo/' % os.environ['APPDATA'] + if chain == 'KMD': + coin_config_file = str(ac_dir + '/komodo.conf') + else: + coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') + with open(coin_config_file, 'r') as f: + for line in f: + l = line.rstrip() + if re.search('rpcuser', l): + rpcuser = l.replace('rpcuser=', '') + elif re.search('rpcpassword', l): + rpcpassword = l.replace('rpcpassword=', '') + elif re.search('rpcport', l): + rpcport = l.replace('rpcport=', '') + if len(rpcport) == 0: + if chain == 'KMD': + rpcport = 7771 + else: + print("rpcport not in conf file, exiting") + print("check "+coin_config_file) + exit(1) + + return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) + + From 6c49bda16bb1aefda799bd2ef6585985202cd906 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Fri, 29 Mar 2019 00:42:43 +0700 Subject: [PATCH 264/385] moved to subfolder --- src/gui/README.md | 27 --- src/gui/Roboto-Light.ttf | Bin 140276 -> 0 bytes src/gui/Sudoku.py | 362 --------------------------------------- src/gui/background.png | Bin 308479 -> 0 bytes src/gui/board.png | Bin 5678 -> 0 bytes src/gui/sudoku_kmdlib.py | 41 ----- 6 files changed, 430 deletions(-) delete mode 100644 src/gui/README.md delete mode 100755 src/gui/Roboto-Light.ttf delete mode 100644 src/gui/Sudoku.py delete mode 100644 src/gui/background.png delete mode 100644 src/gui/board.png delete mode 100644 src/gui/sudoku_kmdlib.py diff --git a/src/gui/README.md b/src/gui/README.md deleted file mode 100644 index 8a3778ea0..000000000 --- a/src/gui/README.md +++ /dev/null @@ -1,27 +0,0 @@ -About ------ -Komodo SudokuCC GUI - -Just solve Sudoku and earn SUDOKU coins! - -![alt text](https://i.imgur.com/std99XW.png) - -To run you need up and running SUDOKU chain daemon built from latest https://github.com/jl777/komodo/tree/FSM and started with valid for your wallet pubkey in `-pubkey=` param. - -SUDOKU chain params: -```./komodod -ac_name=SUDOKU -ac_supply=1000000 -pubkey= -addnode=5.9.102.210 -gen -genproclimit=1 -ac_cclib=sudoku -ac_perc=10000000 -ac_reward=100000000 -ac_cc=60000 -ac_script=2ea22c80203d1579313abe7d8ea85f48c65ea66fc512c878c0d0e6f6d54036669de940febf8103120c008203000401cc &``` - -1) install dependencies: - -``` -$ sudo apt-get install python-pygame libgnutls28-dev -$ pip install requests wheel slick-bitcoinrpc pygame -``` - -2) and then start: - -``` -$ git clone https://github.com/tonymorony/Komodoku -$ cd Komodoku -$ python Sudoku.py -``` diff --git a/src/gui/Roboto-Light.ttf b/src/gui/Roboto-Light.ttf deleted file mode 100755 index 664e1b2f9dbafbf6280305123d2df7fa0c66cee9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140276 zcmbrn2V4}#`#(N2ySGQ@=ql0$6hTlx)TlAW78`cKE(#h%K}E$9d+)tbR8+uzoQO4Q zj2dGSL;RS;Bqk<)j4_EV#x&)Y|9j?GxHHN3`~AKChqJr0ZRUCAnWxW6C?UiR8<`k7 z_e$)0yL75b==(Pa>HAaXzWv+Zu6s9|Fu(JJC~@8U_3d&k^+h}(?k(_uXJX&zW+x}p zU_$6tyk*3w@guXQADFR|5by4U*tHuqH9N45KRZiE&@5b!Ny{2DKKfqI1BCdm#4~5c zjGUZB?1%^2yMpUZV=|_vJ#<}gmykvkgic#JHg)9a-_jfMd+XzR^RYPLu-EQK)cc{{ zVC?wp9JlmYuc7`YA%=DtnWILIdYfHFdk4{e@c5BASxOuB4A*mTf8d0X<5PEq-8K=r zD+&GImX$dfO-ju=*6;OL+}Z`t#1f7hlwlF`J{s=Y`ZrS74krk? z_{6OV-(U0mu+eiT^QZQab}6XZ6UNWthiB|k%%5Ug^xR1uY8NNoWVt4`vVot$b_?+) z!-=l?x(mT8XeE(Qm*fRB5?6?ByAC~~0hYb=2}$G4XiX9FEn!u?NZ??c4CF8GoS8WW zJLf8Mbsth#<3K`pB=Qzp>5RB5kTCj`-;4KR&kO5L=E%R3*X2x-t^0{gkROo2bO_02 zbID4!lDJE$#7|yGy3wViFY8L0(jQ5&6h-{y{bUKAIfIgpG76<5%085>C_PX{qa;%k z*-p!Gj}OkxB%9<=GD|8XJ@q}w7`ciB%D<6wx*)Pp*N&W%^HB0ppH9~6O2|1DLB5d3 zkRH1FIG;eyDUWgOFiHxUCI5>3C^Ade0e$$G442;~QMzHISbj_b^%10{e4o4`-y%Ws z6*8RuOm<7*BnEpT^&>r`Y(m)^WT@N&eaI&H=+j8-Gvxp>gzX~ju z>5@X$$Zbh~>2)#{a7=@pR!V0{ zhW-uWCdZJW9B=Yja$Gi&Ey_iVOEJc8CFugV2g`HFF5N;>mtG+y@<383M-m_AM(XLd zlX4ETemdSWnhXOzidjL`CEX^nLY_ee>m~#DCo$GHs#bD5N?By5)PXFOMv@iu2a*ri z4}f+DOS1rrjx1(t$O%HspnUUALMo47KOTGV81tJZBokdkA4o8lYzrZ@&=9z2k<)XS{^tl`GMd-f3{Ni;K z=^GNG`w;zKje2`BK}jZilyPK-&Vhs|4EJ?G=}fYedDtg`)~8f`kNO1VGtxl0i)W@( zJ>l=s*CPj&&7kGZRsYq8k(;_-f%A_*%PmM6 zLC@#OROKlN(Y-?abUn!-IgM<^zC>{#jpP$me~NdsAceZ!;1{3?-8S-;{0dnr=aNaH ztRnTKu9zR2NO$E`l-ndz=}lsFVWbIYB1L9oqW%nNuVj%}{RiMhd1SNv3t1-D0X>$G zAe}Gfau>2*_5}BD#HFNV5B@-y192FHb9z@MPtr&~;n$^vp6^EHxYfcNq; z5@kH;%0`pH>`j#3!0{OH==r1{+f3F=y8wR>IitS@el?P0prlHhNn7yM9?~%I4Dc0Y z1vx1bp>rpjls#lNcw~mYKN+uFB4g#9WR$KwIShQiDz7Db z@p$$L&QBq8q%<-S{a!1LAa8-U86`qy%d1E)v~>piV(C}Nwgl2z zK1b%GK32eWfMg1O$mK3%DdbfLUI1$lmtU-ecnX=w<>EgSE+>VI@NeCuS33hV}C_iN4}7bfuBGR;j)eEB3vK9*p}iRzCVZke7=__%O<{cR6j2K=HxXW37$-Y*jR4RnnEb#I}euxeVe>?=qZA9Fq)|JOa& zpSTXgX+(@$wH}4zL0q4*-gBLT>ku06m)BQ46ot=0KA-=s@Hx)sw^ae|FM+wr+>N+q!7H#HuaPF6S%OMevxam1uiobzj_gf2?@UHqLjn!g-HY zZ2HIfkXAT9vMwAi8h^5eq54?xD-MswuQ<;_vAc-(VBY9R)icG3xUtocIaA3ix^`8Y zbiGLuORF-9c?Er1%nyu{rbBa@eOY(rG$MEa^kmLA#4*>Qpf`!RVbPazg$`($+l3hS zNVIbb*K;}j^1Z_KBt9RZr*ZnkocTh$uUc>CZF60yrf>W{+|TEQ=o99m;8R?u<2pU( zalCI_f9E`c&vUNxSlSc1I;TmLX8fAamoPUl2M=M)_Hlik>r4C|jgDX5YjiE_9N0fn z9(2S>q&=VCT>kQY30=RMPw7&sdMgh}d%Xv2gX+F({Sx{o^u=l&NM|>U47Tr%`3+r= z>u(xQt8O!r{tT)*STFY`ieJ_(!xK21;2o~d~+=P$sE;4gfy@f5DxLnqU8GaYnH zt_Sil;5hl)9=fT_^+)KW3fCKfcY#~jHah6BTTUG@RD;5l`uTD2>7&Z4ebqX|PWeez-0k6nD}ll!j7IH&Ka*2oBeai>{W7 zeqz^*Hn8X2z;ofz!L%uLapGu&<3@)r(U6f(UFw$9yH*^-twq;E8yohGuj{qZxqVcJQdDg;cWTwYqTzY)R+Il@e`-4 zH+%>!KR)*S?;n2+fIa>fRTq?jzhE&y9yBZ%e-xC$$s#JsSN#3s8|sHg)&7a6qd`;A z6oZI?iSn}iY919}TWYvcbD9R@XQ=@>_yq=9-6^QC=H3{v9xw zLg$o%pFOqr6>V6m*rLBaK$gI@1>?5cnj5PRIJPZ#)wWGBX)J#nqfRwH?MXliQUnNr zVv^%@RHH`XB6?%F$%ocK?_mbQ{1K%-;WeW46244A>JwRs!-;RmT%wR+#F+$<*<>d< zNDh&6Piizb0By-yBONY}jbT*ws*VA3pNT1Lu=F1XTGCRZGWAC%C*{>3n zB*|WKl|rQD(n<;Tuw;}@O6R2arEAi4=`%T0j+Q&hiE@gZDNmOd%h%-3{KBP-1}%zMoj%}30;&4uQC^H%dBylqTX8o$G= zL!nijDxX*W0q;;b%He8HQ9hpEh_V*-&V+p5?R&?&r|&+zn|Sx;@i`1PraRaJLC3< z+Z}F4-H!O`vcoml;u{gi;BGMzgHz*2i>M^&RtZ z-*)W^%|i{54hF9mYl6}i$2>boS_mENa6(x2$h z^Z|WH=Fq$JPx=>qPG8VUYR3GWM^(%W<%IeHjE8tBgks9hK*z?Y!n;KQsJdtOV+U|Y$}_^a@b5Zi{7I@&_~RkZDgC+ zX10Y*X4z~yn?d%G{p>M(%1_uY>?!9b>@W75yKB{P#FOl4KVD^n^_Vv?97!KWyb zGIC7PNs6SG?7%@BBuB{!_PmSa3Xik1)JyUr*CcQ9vE(Dwk?KnIFnd2C*QNSWZ^@7R zNAf2(qyQ<9d@2Qz&&cQGrW7ps!aooqHIPE3FezMWC^aHqlCPu)sWCX)59B`iQHmr# zk)O!}L`@!&N8ol(q$cDSDO!plPo<{hSE-rQM~Wq?6i2G0c&WLRAhnhPY7#oX@E3PN|ur!^FqN5sPr7XB^=zP5si>4B{S5CNa;7}cWIC` zSo%S_4?)pHQl%;guo&q_=_hcZW;B+@(RkWi8X^sqewH3c!=&M|oop{XlpfIp+Cq9P zJ)tdWEBcD`7i~@3NPkFwN+YC^QVMNLUzHVEPutPgWF||}FVa(4mUXl}eO=0s#!C~V zOess6NITGu(y!7pX|c3~cA}l7rP4ClL3X5Fq~)@cv_e`*N7Gc#6@h1V`*FoUeA*2BbC1E6-G$f5k1ZhknNfc>9qT%IiN}7>a5=Y`mbCN(> zkd~wsd4;qlZAe@4DrrYvBkjrSqyy*hC&_=CnLZQFdyk-`U~cx8M9Bu%+q1kDa?*JFem27oS6$VFjwZr z+%XHiFb};UGkh@r>hc*#Cy-2%LPn7>;6_u(0y3VwN#~Hsu!>iaIhfbWNfupA*N{|_ zO&8H6bTN5{t{~}TIyr`!y@bpr@FLS?WCL9ZxiyZ=pp)o#;1)k4CW-mTM~RN38Ia3k z$zr;e`Lk7YD#k0DPT^xlGvU8|la8m8!Cjt$$NUPZ_8a}3{z0E{{sIX9;+%!5WI5Rm z={SMpk$l(^(;z2zkX$2)>}Is@l~hXU>f{r&YLRiFU#Yz`d{~r`Mg|6Ue6xd*j)*d{ zNF$91iZV)(ft`#}Xs13&A<2Qu1DC%sdU;@{z_BAo8|6^3$A#48$W|(>LR-Z8l|vaNxhSdb36DN+jU6x z4GIeEXguF5$#}klZ%}e_lu@baBl`N*n{_O`)khkYh$y3-F_TrYXjO zPBvxn&0M~z;F~}Pnr(X32}i^EW)9y(JKR58ooKgH&uKS;6$hJC#LWxrtl}G zm|R`>vwZWIZvtF!-*CQJ!#5xEO%>m~>Vlgy`R1H~H)O!M9ejgow#n6i3pj^2yW?sV z-+b(j3yFLa&8yL#*u2U&bFd-cFKOTeV<8RqLwo)VJkCoULA>Nv#1nCPFL@O)K*BgG zb^gZxA`z92peG0$+^O%nM;AoRaeC| z&UK~h4TEfGZAdZ9FccWB81A~+xh;2l;@-}Ej|cO}@Ob3e+%wJdu;-s%o?eT+D!l7^ z&-cFP6Xvtk=TV)wI-~2HsLSehtvkQ&#k#lZ`PUm!Z)v@!z9W1u)NfF~L;WXy{(fct z&7h|a2~Yy+2Mh_=9&j+=Y`~qs=7A#urv{n=F9tb4?~V!T8ZsC($j(5GSj!m`57hdYIL4d2s{HC);#uu)p0dl9`N${Ra1&T3p3DMvPs92>bh zvLy0OlzUW%sO+c{Q58}5qnrnjtU)uh#) zSCm&~z4D;-kk*G=KWWph&E~dB+qrGeyh>i}@~Y|8N9|(TWwa}Q&F-}kukC5?(0*(C z2d^i+e&Y3SJH&M;>FC|DPsfsu4>~pPw6IfIr*AvwbS~@sdzU6%a=Ki7BlwN9H?DSV z(RFnpdEHqj|@P~!ex-n|z0de(bb@1Oci>RZ3>t$w}w znfg8J->QGf0Pg|!1|Cdmo%C69!{n*S2a_)+KOf{WD0p!F!7B$p8q#6Ni6Qrg))|^H z^!%`T!)6ToY5?&g7IbJ zuaAE+!EQqR32_s;Pna~plxfI}%xsa_CCeo%EURr+pRBxzY~t!k^(Sqg+3l1)n7p5<~v4|{cy(oRr*~Kjuk6pZT@lQ*)znpISKV3NX?4!(vuhfxS-a-)+SzNLuN%Ft zWW8a19sC8ZU%dXohJG8iZnWE2Z)4=fwi|nGOxrkXzo}%?sZAel`exI!&C2FFntgZ96 zZrob5^~BbzTW@WBw2f?Y-_~$jt8Lx44cnHrZT_~6+jed{xb5t=ifwncJ=?Bqud_X3 zd+Y68wh!8#v3>6L_1pJsFW-J;`&TW$0F1Jtau-x?AS-Goox91k+ zp2@wQdnfm4o}A~M7o685uU%fBys>#R@>b>*41>Y1r+d+0X z?eO0bv!nfveml~4%-XSf$Icz59T#_ew&VVe=R2Kt`tNM9v(L`4J7?@%xwBxWap%RI zU+#RmQ{83Q6}&5MSC?Ibc4h3Ey=&vHqFpC;UEOtS*P}vK=vf$6*rKp!;fTUXg$oPU z78Vwk6<#j9S@=_70ZPsN@)d!Fr8_PXzFus3FJ`@Q}4rtQtyyL#`Qy~e#4 z_TJcgfA8}mry~ENh@$32?TdOA4Jt}2np8BqXme3PQBl$1qVl4%MVE`N6@6CpP0_ug zM@7FEsl`fh{o-cD9f}7Ok1d{2yuNsQabfZPVpH*z;#B}FBNOD>jt zSaPG}Udf;P$UeJ$hJAJRMeJ*~uhqWx`?~Jyvv1J8lzr*@CheQCZ{@y?`||cZ*!OH- z<$lBd;QbN%o9*wizt{eh{n`5$@87zA|Nb-kukXLV|M>x@1O5k^A83D|=YbIiCLLIK zVDo{(1BVZsKk(s!TL&H;BnRCOHaHl0Fz#U2gCh=R9Lzbm@Zj2mc?U}l8V{a0c>dt^ zgLe-;IH(>n911(s>QMVbT@MX8G~v*~Lt76WK6LTWmxmr5CWqY*H$2?>aG%3zhbJ7K zdU)mGorlX0Up;*5@S`L0kvd139O-am(2)s8mL4fQa`?!pBNvWbJM!g`dqWOiHG2J-VxY4-Zc-DBs_){q<^(>7jZCl!}bZqJD()Fb!rDsd8mVQ=xzx27u$>eW} zGj%nMFlC#Tn+i;2rYojzOwW!gN9!DIa5Uy<>!V$c4mz4~bpFw;M-Lypc=XGoPs)_C z`en_^x|9tn%P5;&wzjOWtgP&E+0C-MWlzc~kJ%locP#Q)+he_sr5wvXw)oiAWBZSt zId3b{LXjfs>8H^4U zF-<+Bkc9YHA1TBmKK6c47b)#=P!~B>*G_#=_03K71!Z61wRrFA@cHk6Ug8UDDa-O+ zXS~Z@L++toC>eJDLSg6>pB8KHI_igSNZr02jq zA=yVR@D%LF}UW5hL*R47)l%0-U1}Vg@uQO#m6-8aVVIjeam#4Rn zx3`z4qW21k4+~33i1qZ2ZPr{`w6?tB%9Vp@N6s@TYv7j|(1>|Rhni)dr3XaT+i@Ffi~VW@<0TsVYD9Bzl`Qa8pyvrq!yu2Wkz1z2th zh&F~9N~3Bo7y}HYakW*DXPKlviG{mTjv};Jg3L(Lx*N3&6<_eBWd>Rq{QK`?- z6QR@xdQ5Tk6}}@8aeU_-7r}QfmTPX7YjrI@TKT|^daGjz#b^bqgnF=+!n4^IQ>WTrGm!Yj(> z9pagH1kb8x!JiB)$(&;e65t$5FeqDI1TxM>lwUj8e4G zIU2VbNP>@#!rZ(J?f^TCxUHn#2b6m2Zr)s1PdTJMVBP6B)-HvXKw7VyLgL$QON->{TH;H%pvA3kI;GZt=6A2m-FoH%*&aN^aMdxS}lb!hyi#9nq zGaQ-VAm%6Z6()NpeuDE%N6rsJ6LeCn6zZe%&`VM{eN!z9q}}DQcCt`qMjE^g4f6UllPMat0j2K#X#9t$c}T8Y%<|bxrTnahkjO zfcg~U{-&%IJXkw0YupK-gr}#5F>oFqAH)o55WUS>r2=KRA9JmSFyd zRP(l1EF2f|;9}!9BK_yIZ)0Gr0*?9507F z`{L#w&%XHL_Z(w!@!`^%eo@pa`LBhjYegbp=DV`FqRlB^NJBQcal)SfhXMF@a=4aUFl#BZ5uc}cEp%;1N}O{YyE}=S{p4yuni6^m4&WBqf1#WEJj6WPL35OJLbrd z0ae7A&u6GhVm`y)ALJIUm&V+^JI&mm?O0&WV17z0{WMiwOS3vim6f4VTZSZjj`w|- z8+PbR02yuR2?eUDhIbcKT=>kO2835?X0pl7h4Pl|qM_26bOCm}0xi#j>w2Z$wKp2= z45jsJt6=6rui@EJyI39`L+7z`;;^C^lZ&Sy4wvXs-`c(!Jq@M7wN>D^nYWKVOsHdC%|YxI05BQih(|CqGYcPx z3u8;Vt#297GOK6dr>##-ym+>yPZ$T?!6N3G}c0XkO1@>eDYi zSMSqEs-u~ew5@sj>`~)BdHVg{BXAW`#1)7b8z)331T>BSz)^!nqY|T|?JOmn78sNC zAqfbFfaA(`51vOj<~T-ByDux>kxuKns`t(3)MYc^{bvKI9)Vejj0WzUfjb{q6w%~O zOM6~u&r54hkSM3hD0?qH-cgu?QG5B1!k4=r7ESZ+DBv|*!jb1(kq`lWg28Z|UdJyY>X<*Ma}4lQ3(xLfKxyLjiKdAYfu znPl*t@2hF1rv+*on@6LWQc~M%lipJZalI|UIKMHd>j_Ro*H#TJ| zbfPI*!SLVao8e-k$5Eyp7jE;TXuh%M8>;9zCBW{}RT$-pvJg2|W)qEi1GiD_E6O76 zTidgVpas2`4}zZYD8U&SEUogA^a^WVU#YJ?n@wkqq%&r7p2f%}S|oig9RStp5uL;9 zrN(6j8c5kt6Oytfa%N@4FHHvCS8RrIE!xUtMT1=VL6JVMJS(;5MS3mW{30DN&muFB zWl{|@qY{Ui;XT6{2aRuT^Nl?=+=7MmO8^ME!*Gv;E143<5I?$&4Ri@W4*1JLbg??z zqnEg{2ZqR@ji(9m;j^S3l}A}lMuyaXrn-2fx@Z=4_f`A=Z%<6nE`mn=5ls-IX(PpJ zq+>l_E}D(?q9MTR@uPnh;Pu2^kcEDlN&!@Go?I;jp#;}Ra~Kb>%46wt8Zk6u)Y92g zAwrn+S<%rC7R_kuYgn;@Zd@>?f7X`lxht1VQTCp_dT_}nlj4VrP&0TY1S4bASCsp@ zm58gpj)Ny}TwH>O;P}et z4xe4?`KDWZUfP1C9zG9BhE3|oq-GAi5?1eZbXSe)X7z1#h?@sOqrH>L+6J_{He6k( zj_`1&pVDcF!!CPq!q9KTfK_ocIfc+L%KDJL4egrOPHeing7T=F<=txD;DTe?~!F51VTRChV0fu)9+-V3(evX zDAoKmwew#n6-?M7P%7-KuqInvMcfMm{UL+~(Gck)bL!?Og~y2;M94kuU0 zWkc;*K92)xt1(Su-GVFzuSGSZs0xY=t=0=>5S*jXB7q3xw`P(>+Gz#c*mLrC8;ZxEMEaQC|L;kcMx;T50QNV!@tQ|?$Cn7 z^{DNbQMPsT0F{1R2Ky)wY6Qk4iESox8x^_(gL?xc*gQer&pgye_kLABqY=N}rv?v} zRpuRx1-h;;d})&(&fcZSX#(DOUy{)mN8~)z(wU|+XgZ3?LFPUXc#2HX4j6kYtB_;Q zid%CYZAF)yN4r5~v=r%A^XpPbWtz09@(z2Oy<^^!sxzjUzpn1b2!WGoJ@y}G0#s%} z{C3b??C8+40J~^AFyll!IqqR)aZKOlBVdhnJ`C1oMoiNnAQ?6dCcay&{NuFBi_@k_t*5a9bBfMr?q^APqvQ(^ zVsG?M!t50dYt8^s(Yhqw7E62Qt1DZlr;+I!D=>{94Vh@AW&`##=6DQSmgEUL#TRX+O+pr znOrxz!SKS z{r{gIimNSLu<%`Y9QR6DGvsd^)@ASlKakJ{xM@tuy|3{=)sV<11F46u64i zxd2xl$l9y!hXIqspiz;gJDMbW1LuwgL#a>g4CPj*4VR>z4Bqijq2m1;;>M>w@2md# z%7QNcg1tTJUwt2R`^(Soe?%ereg-(K&>ex#Eku)w|A<3Dd+vbB-4>x%UI>!|5mq$t zYU_-s!7I0(d3?wV`h|#=)Z#gI8h!ZF^TjikObZO15$b;^R~<{oTq-|yTwTuAn$-}xcKES@uakJM z8*)eg&hu>eyCxQ25-DyL9|)MX#gpVFpH#p8=?C>r&aKk2J33=!=%Y&WL+Pu^&{H2= zJuQitErotTZ{mZNn#pn?#$NB8tiz;!ItmZ=;jJsE6kg9smP$9^li*hxfoI z!P1ZL5Iy*LEPXptNuY5PX1l&wI&3 zw{3d?&Vivte_sJEjHoyw7gw}xqZQlqR~rLyn;z7x=hSSk7n&9vsv=}!lsHWr72a9& z4Bg}ZVp%rLU8mNk&(^5@)dB11Gu3yU)SgW+H#7UQ`R3W|4!b7$6NLVpLVxU#S^W3@ zh*mX}Y5g$~nfppC4RX;I%QEP@E6fk4nSWWqmPm~%N1GooUkL#x%u&359NurQS${UK z)YJ%Td2PbVK+Y}oHjWUJz0T5T0)%-ycZzsDlHPjpOd14t;U}r7L*z$k1JT}Y^$LBc z%*EUZCq{iV4+r5zR*o^Q%UijL0R`kDSCZ+&>(|wC+EuCdmuH&(1l|=>wLsFL?;?i7 zEdBsZ{eo8nCTPqQHe!m-_!ri9;C_O(yNR|N0GH7S1D49Qd<3%C+M^rO6bfTdJhTMb zO+EIX|0r|+?2@Kn(FJ^}>BMG_YVw^QLVvQSwXt<|oQso+HVk!@QQGBcA6n$5B z5t+FS0TKtxG=~Q?Y9c*lJLDrW8(Quv2VkL-G?XJ$N{FTJPWgpx$HQ3TD|{@_W3R|P z!3!Fbd6pj31xeS12TycI(||=q;{qm0;gMyNb6sJXAv78743#p_ImQ{jxw~LmofTt}GJyif+>qw^)FAq zGCh>pxFd587Z>$fI$ha(l}0~`ctB&WA5iA!{`Gdm`9B4&Gts~QRO5PtrH2Be8mO~QyIHvg~t`2&W~pkFWEA3KCr4x0ju3pj=Vjtbz}8#L3;3J$I7 z+PpD265+sh1e>z;P=Wnft2por*${~?SU6QgR!fj2K*ZgQ63E0S2s4AleW3nI9nZdZ z*DPNs$SP|)BKMA-nLbrcHJcN2itW1tIl#7X%C`5 ziU79{zO=;SaGb_%@a_Q);PEmfMh}CvwFoQ5G=lp(p72c;%x~`b7+Mx>_bNBgWB7@k z{Djf&Jol3jJ35Jn^sHQWoKqsF%NxuRBNUJM&f~x}fii9#{&w`}?hQd5LR{;_2B(ar zOjV_uDFwSt4)&uI{j98llu9fwIp(r20zF^CRR&cweVeM=OWzNSBG;fxk)t? z`1Pg9B?&I6KV0i+Y#-2Wb?<^*2_;$Yex0)uv=|Y-WqLuOg%(qX9C~r%lc!-psewV| zg-iP+)8MD?{+K?L{yr>6t+eP21rQ@&Vs3dL`X?|T^rwHESvFiu7)KlfL=yH80CKVh z2>yLehEOR)FwJ7IdN(i2IdD8@#f+JI!(p_}8<}zAwmFsM8@J6HXXf0LVU-Y}4RBRv1=&k_)aJK_IljH2maNw0Q}}ylR!&jW)*nT>){I ze}GuLQhUG9k}&2rCa1f>=vLd78*htRyffOUxrqoy18q9;J>u?hX-(l*+&qZWm`*j zp0*@NCC9i!IkSozG(9%|(3zZ7vsY|&r_^E5X7;=Xy~&2|W00yliVd;u71=F7jss0mI1i3p(a`9ft84TI)t>*0I3=Uf@L zbBrsUZak5*V(#o6AvtoZw?~iv{H}RCTYqZ%q6uba-XqS(c)nmA^ojdhII*K zqwUg{tYw>IBab+Q4G2to#Ec1K9*-cyz8Ah8s6jWspo;q9=9lX8oU{9j&z&zRIm@CR z^CY9kK~LcPY5L?$70`1g=p<*jJoyzmk~%`xpqx*{ ztiY!G%Q}+o);p69G|x$OZGHecQqG=&>081Y^UgnQ=UzQ9?;X2YaDo-9_ z{xdo4!Mg&MOm&2Gtr`|<9YpKC4Z?*EqQRn3_y4;N0%;K9##P&Y&_Obbn>&r2mQXZ7 z=pb3!A{%X)tmz;_2kdwr#+oGd<2uOCsRNmN@7=Jw%2>1DSMw;ka25fWDl zdu#WFlb;+s{+W(tZkfAa!Nh&ty1H4Ms7OMqzaFtS(&w5 z!L|xfL3c1B@yU}jJy^RT7Wa(^C&LEfI*}V4^ypEKc76#B-2DeMo;2t5X~_wBk{o6V!^0vG$0}6wZ7JPR%&#=TKR7){JGzg_odpk z1V^=7h%_qBm~-Gl&XQS63j=e~ONWoS|BOvGuef}0#yE++xD32Sg15elzS#PfwB~JO zp=MPI-x96yEz#>C3O@HTOHCc2j-Ewb=gg5BzqoASlN9TziS8mQw*DpU{Wc;=_?NUR z|5yJ~Y=TFu2l~Rj3EYMkq3tD&l-PS??!_rlmu9J#(w;;sF%QP5muJ!8@4UmlGKXHi z%)WYYncY2o+FW0Blwwslk;-uFsQJNc=*Om?njfcj=){;faQnfe2=@{UZ|;LJ*^}x> zjg@N&i>gCctLy0OmFkD;hpXuvb=@j9m!2{|G=D)qQe#;-^RUd@5a`NR1@5ZzMr|0L z4Z6fYf%}=LohKT$*50|CMl^*A`lwcygg@?+FokwrtVTpEp6Aut#leNozoX{wU7&1#Z~$ajVfWtEikPrfL2 zuJRCDXtg`4+C3i6 z)p#VD!489P70GAZea_xGo;z{s)QP#r>&=-mc<9i<)8?uf2@m(*nXzo_;+c03JWfb# zbal<$35B8IyT{*Ib14FSFsVi;d&R9(^8e)o1@`lefR< zvv;($9cj}0c#A%JAS0(bDGt^mA0O`OkM+We5Z-nBIXS~djT$y(PQCKHtZCD-a*wNL zA}+1DlU3Ltq;TThweL4dOn7|Y?u;d4m(94d|6u~}!x~yF|0sFj+X&5w$=)05c)V?y z8=`DZ(VVdxYRw0}Os6iA?vbp=ogS7X$Z(6LSMBcjv2c3Qx}7!j2ly~jkGInkX^pJJxavA_y;WkACxSYj$6)XeT>Bi4dcGV8C8zbJ$%161li7F;@Pltk;uWdEo(=mqk;QN zutf$Mwlzz6j9y}`61JW-+#i*CSh!>;^{d55tye`X$zd2K_m|e}aNkOoY31XXd}CA2 z*^jQhom23EB-MIXmR)fF?_D1n{#C>mG`!BOuiQS&uko@_u@)-^@t0stcenAdYwXs> z2WnSg3R3tCHwM9(7X%qS9GkK^L2H5#B(@448J#PPL1JZ=r&xi7OjjGX1@!@OaaV9G z=r0@sOcFy~Bd3wWOPA?mn@F^>uS2I!`j0DfJNBP

Jq5C-aTifz(E5Kg}P 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⋙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 LNkvXXu0mjfL3yYq literal 0 HcmV?d00001 diff --git a/src/gui/board.png b/src/gui/board.png new file mode 100644 index 0000000000000000000000000000000000000000..bd77ca419999b45f31af1dc6e91aedd4b0f53a9f GIT binary patch literal 5678 zcmeAS@N?(olHy`uVBq!ia0y~yV5|jU4mP03i^?5=K#C>Z(btiI;o6NW{t-q%zGR7O zL`iUdT1k0gQ7VIDN`6wRf@f}GdTLN=VoGJ<$y6H#2GIkaE{-7;w~|s45`LUF;Bq^t zA;G#h!G)oLAxVn2DG(xJ$)L~>k~F@M{Q-MU|kN+74koMTY6Tl7ztmwLMJ)o!OKl^U$ z_Acp(KNlC;OMPGb(5mQ>955ZVmqSZM7DiyHsQbko(uWx3jfTYH1W+nSVtMp`@j+w+V|BDHrVGdyBIgycp zse|>{kN^MeA1_$HP(t!Qe_1)7sJYT-Q19TK`{B|jM{I$qitjzNR2=QlI_X`4raI^*LDqz40|2~awwXxSpWxo89ZJ6T-G@yGywpilHk$+ literal 0 HcmV?d00001 diff --git a/src/gui/sudoku_kmdlib.py b/src/gui/sudoku_kmdlib.py new file mode 100644 index 000000000..a2b2aa239 --- /dev/null +++ b/src/gui/sudoku_kmdlib.py @@ -0,0 +1,41 @@ +import platform +import os +import re +import random +from slickrpc import Proxy + + +# define function that fetchs rpc creds from .conf +def def_credentials(chain): + rpcport =''; + operating_system = platform.system() + if operating_system == 'Darwin': + ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' + elif operating_system == 'Linux': + ac_dir = os.environ['HOME'] + '/.komodo' + elif operating_system == 'Windows': + ac_dir = '%s/komodo/' % os.environ['APPDATA'] + if chain == 'KMD': + coin_config_file = str(ac_dir + '/komodo.conf') + else: + coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') + with open(coin_config_file, 'r') as f: + for line in f: + l = line.rstrip() + if re.search('rpcuser', l): + rpcuser = l.replace('rpcuser=', '') + elif re.search('rpcpassword', l): + rpcpassword = l.replace('rpcpassword=', '') + elif re.search('rpcport', l): + rpcport = l.replace('rpcport=', '') + if len(rpcport) == 0: + if chain == 'KMD': + rpcport = 7771 + else: + print("rpcport not in conf file, exiting") + print("check "+coin_config_file) + exit(1) + + return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) + + From f4150ce014a22d6b5b24ed1a951b81c8f1c5f6a9 Mon Sep 17 00:00:00 2001 From: Anton Lysakov Date: Fri, 29 Mar 2019 00:40:19 +0700 Subject: [PATCH 263/385] fixed path --- src/gui/komodoku/README.md | 27 +++ src/gui/komodoku/Roboto-Light.ttf | Bin 0 -> 140276 bytes src/gui/komodoku/Sudoku.py | 362 ++++++++++++++++++++++++++++++ src/gui/komodoku/background.png | Bin 0 -> 308479 bytes src/gui/komodoku/board.png | Bin 0 -> 5678 bytes src/gui/komodoku/sudoku_kmdlib.py | 41 ++++ 6 files changed, 430 insertions(+) create mode 100644 src/gui/komodoku/README.md create mode 100755 src/gui/komodoku/Roboto-Light.ttf create mode 100644 src/gui/komodoku/Sudoku.py create mode 100644 src/gui/komodoku/background.png create mode 100644 src/gui/komodoku/board.png create mode 100644 src/gui/komodoku/sudoku_kmdlib.py diff --git a/src/gui/komodoku/README.md b/src/gui/komodoku/README.md new file mode 100644 index 000000000..8a3778ea0 --- /dev/null +++ b/src/gui/komodoku/README.md @@ -0,0 +1,27 @@ +About +----- +Komodo SudokuCC GUI + +Just solve Sudoku and earn SUDOKU coins! + +![alt text](https://i.imgur.com/std99XW.png) + +To run you need up and running SUDOKU chain daemon built from latest https://github.com/jl777/komodo/tree/FSM and started with valid for your wallet pubkey in `-pubkey=` param. + +SUDOKU chain params: +```./komodod -ac_name=SUDOKU -ac_supply=1000000 -pubkey= -addnode=5.9.102.210 -gen -genproclimit=1 -ac_cclib=sudoku -ac_perc=10000000 -ac_reward=100000000 -ac_cc=60000 -ac_script=2ea22c80203d1579313abe7d8ea85f48c65ea66fc512c878c0d0e6f6d54036669de940febf8103120c008203000401cc &``` + +1) install dependencies: + +``` +$ sudo apt-get install python-pygame libgnutls28-dev +$ pip install requests wheel slick-bitcoinrpc pygame +``` + +2) and then start: + +``` +$ git clone https://github.com/tonymorony/Komodoku +$ cd Komodoku +$ python Sudoku.py +``` diff --git a/src/gui/komodoku/Roboto-Light.ttf b/src/gui/komodoku/Roboto-Light.ttf new file mode 100755 index 0000000000000000000000000000000000000000..664e1b2f9dbafbf6280305123d2df7fa0c66cee9 GIT binary patch literal 140276 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