From 822ee5d4111928b6192b994cb209dac2a80a732a Mon Sep 17 00:00:00 2001 From: niart120 <38847256+niart120@users.noreply.github.com> Date: Sat, 18 Dec 2021 00:02:39 +0900 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .gitignore | 114 +++++++++++++++++++++++++ LICENSE | 21 +++++ README.md | 2 + munchlax/eye.png | Bin 0 -> 2570 bytes src/calc.py | 187 ++++++++++++++++++++++++++++++++++++++++++ src/debug/expr.py | 21 +++++ src/debug/naetoru.png | Bin 0 -> 17129 bytes src/debug/test.py | 63 ++++++++++++++ src/rngtool.py | 168 +++++++++++++++++++++++++++++++++++++ src/tidsid.py | 121 +++++++++++++++++++++++++++ trainer/eye.png | Bin 0 -> 1941 bytes 12 files changed, 699 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 munchlax/eye.png create mode 100644 src/calc.py create mode 100644 src/debug/expr.py create mode 100644 src/debug/naetoru.png create mode 100644 src/debug/test.py create mode 100644 src/rngtool.py create mode 100644 src/tidsid.py create mode 100644 trainer/eye.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..510c73d --- /dev/null +++ b/.gitignore @@ -0,0 +1,114 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5980aef --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 niart120 + +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/README.md b/README.md new file mode 100644 index 0000000..42a5dec --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Project_Xs + diff --git a/munchlax/eye.png b/munchlax/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..6ff3025f22156eefc2f5f2b355e370ab3990071b GIT binary patch literal 2570 zcmV+l3ib7gP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGxhX4Q_hXIe}@nrx237<(sK~zXfg_Va_ zT3Z%}`RC?oVk}WnX~x8q$xBS04a5pkL^>kUBz6=;P>d~_7+YeG9Z?YhF(`-~HBQ28 zyyiZ}ajm!3=UE4Z-?z`+=OTv0HxYTp-@v||DCofd1}Eyo3d~quM%GpwK?@!HVLe-_}O9HH@%(C|cPcp+|k zQ)SLlz9(1r!uqzVBSUI>CTfGiQ&`$$W)lD!BG-Tf!Z|PmZd({e0@sA+cO>)8ARr1% zkNB-=<=UsbrZ-Z3q0*!@4z~<^GYv19$5su43-w)J#SPs>indomZ7RDSOAi4iLb)C- z`kw_*b*{RbYx+_%u+TlVHDcMDwjV9H&u1McW2<{z<7?GD(*>HYbZ&DJqu~w#zPuF( z7vQdkN#q+L{RvM?QFn?>BZje+;RVOqmhb!i<-u9-Fc92732yHORyX&)%-I^uLv)4V z1-mAdQHy74NgSBAk;H?vwj053&27P-QX^YG+%RGpvH92cE`7(pj?aT9mp6cB_uy*N z6BwMeDceUWa#K2|i3oG%=t<=U;&ss&97m7xTLU99JQcQPRkd?k23tl}r)+-r{?$<+ zcoqm={`i}V%i!r*aR2DnvdwE4m@QRzyyC+!v;?*`bZg67K@$?Bl<5G}f#c{v@Tat$ ztskxZygF(>wfTbwf#Ai@|4BzV`w_H%KkNBw$X2wO<3CLE(NbY(g4aI|8QSS^r_ ztcZieZh9$brq}f}eqJ11al5?d2PeNSFM?NBL0JEv^UL7Q-sRYwQ)L*UNc2ybbp(1H zf!z#^x)ETR&4>VTfFM(5l66geSlP9Df9xIqI)U=fL!1Zh0Q%)OQFix^6A^0-RnL6d3p3VvDiu>4q8VncQ2?!1je{DFAKTWQ) ztIg>Q4I;p^TkvIiOfo#;*CdqI$J6WZ<+|)jLzS*?V!`hDehBGDhnFWO{{cXAHz!a; z(6N2;WoDDBHoYiSl1fwrMg!a>7>d zfQREK=-LTP%scq+%!mM2T8D@01cD@HV=}Wog;AGWqDd}RKjk!*s7$Q`lUB#Rckk4{ zA3z-dGz8fI5DmW%HSqcbAedQl^EB-sAQmfA=(RTjETcXN(o1WTimR~&3J@@B-ggYo zA%X+{IU+#t`Oe^2(7K(S1Gn1`E4)1LUmhO(bh^)Gmv^8=Pib-xB$w2{(*WN~n8ear zETq$GK#-U(2LZRCr+<9e=JG?_Ey1qm$mR6T&RE7qX9hogU0hgqI`$3^e)xSq?9QX< z#ch_n^+}P8P$Y+bq?AJG4R;6xO?|`PHnw(-(Egx6?Q2$NyQx>9sFPNxKMstouetpD z7v8;#4f_GifL@_ZE2sbgq$Sa7LxOmEO#-b3OM914sC<|wOD}5x!RYLU!+iuNfKWID zm|zcVyY@lQs(&w$sDuLf(C10p#?G$iWY-h0Zg_{rtu#qfYQE%d!NYucEV%*%B5nW3 z%=)IwkK7_ihhe}T>5p~Qq1Ty3LWO`Y1HtCzchC1@&(7(x)$?I!p-@;y$`hjk`1b$; zO#)q$NYlhnt76E~GsCcdgb00yx2k42Wm&I4G17{czCL>ceuCb^TPa^ zV{6yD7jQWbXXfoqrh#0Jl0f030_Y7Uo>mPc(yHSMs-p9xIOaRL#@su)Xt8;>-G^Rp z0Ln+wVE_Ph3EBeDa1=;~B7DApZF6^Md|A=-{x6mSM-iqJ%CJRBEWH{^zY!#qsN;*| zG1N*dO-+^Qjs27J7WbCJ=kbJ^gQP<=fN1P?53+|dZEfu>E^qaGoD!+^FN-CJAfZs6 zSfUOI9+oJ9c$x~<2lHv+@~>2L@VQ$wrmH4M(rEZSY}Lx_N0BfuU39FPtxJO|6G z&d%O3o=W$EUV)QKiYn@=S@Y#ymPUWwASbkP970 zK}~Q7nD+A0=ESt6QP*9-RT9Z%DHK7tAiAgu6I~z&Vha^YQ8J=pUMFG;}j6-~F4$O(HYn zDCN-<0Zb9OEC6UQ5PgdW`7#hBP^B-K?}VCmbJy_D=arbJS=^YOSs5Ie z(wTZWV%1A3gP2o-&1J-pIUs;3q7K;H2%vD32UKZfo+K()f~Cse@|%VA{o1ba-r>2i z*|o3VtYdTQ{gW$gpC(mpeYC2&XGNU&Od3Q#AoK5$#rN|n5CQ7I+=NmpP~c7f$`#(r z7ABBokBgPL+y<`FplUSNxAxSubZA;S70sQ3cltb@{8<4zEw2=s6P;Uz3J?dX!GuR6 zz&k=Gpj5<=D`RpcN%>WeY0B3u^9C1{RBsyChlO>GLpjy g6cvQmdOuh6U(AhgVoaGg6951J07*qoM6N<$g8KKw+yDRo literal 0 HcmV?d00001 diff --git a/src/calc.py b/src/calc.py new file mode 100644 index 0000000..f9c82a4 --- /dev/null +++ b/src/calc.py @@ -0,0 +1,187 @@ +import numpy as np +from functools import reduce +from bisect import bisect + +def getZero(size=32): + return np.zeros((size,size),dtype="uint8") + +def getI(size=32): + return np.identity(size,dtype="uint8") + +def getShift(n,size=32): + return np.eye(size,k=n,dtype="uint8") + +def getTrans(): + t11,t12,t13,t14 = getZero(),getI(),getZero(),getZero() + t21,t22,t23,t24 = getZero(),getZero(),getI(),getZero() + t31,t32,t33,t34 = getZero(),getZero(),getZero(),getI() + t41,t42,t43,t44 = (getI()^getShift(-8))@(getI()^getShift(11))%2,getZero(),getZero(),getI()^getShift(-19) + + + trans = np.block([ + [t11,t12,t13,t14], + [t21,t22,t23,t24], + [t31,t32,t33,t34], + [t41,t42,t43,t44], + ]) + + return trans + +def getS(intervals): + intervals = intervals[:32] + t = getTrans() + t_ = getTrans() + + s = np.zeros((128,128),"uint8") + for i in range(32): + s[4*i:4*(i+1)] = t[-4:] + for j in range(intervals[i]): + t = t@t_%2 + return s + +def getS_munchlax(intervals): + intervals = intervals[::-1] + section = [0, 3.4333333333333336, 3.795832327504833, 3.995832327504833, 4.358332394560066, 4.558332394560066, 4.9208324616153, 5.120832461615299, 5.483332528670533, 5.683332528670532, 6.045832595725767, 6.2458325957257665, 6.608332662781, 6.808332662780999, 7.170832729836233, 7.370832729836232, 7.733332796891467, 7.933332796891467, 8.2958328639467, 8.4958328639467, 8.858332931001934, 9.058332931001933, 9.420832998057167, 9.620832998057166, 9.9833330651124, 10.1833330651124, 10.545833132167635, 10.745833132167634, 11.108333199222866, 11.308333199222865, 11.6708332662781, 11.8708332662781, 12.233333333333334,] + t = getTrans() + t_ = getTrans() + + s = np.zeros((128,128),"uint8") + safe_intervals = [] + for i in range(32): + #intervals[-1]を挿入した際のインデックスが奇数だと危険な値の可能性がある + is_carriable = bisect(section,intervals[-1])%2==1 + + while is_carriable: + #スキップする + t = t@t_%2 + #危険な値を除外 + intervals.pop() + is_carriable = bisect(section,intervals[-1])%2==1 + s[4*i:4*(i+1)] = t[105:109] + t = t@t_%2 + safe_intervals.append(intervals.pop()) + return s, safe_intervals + +def gauss_jordan(mat,observed:list): + r,c = mat.shape + assert r==c + + n = r + bitmat = [list2bitvec(mat[i]) for i in range(r)] + + res = [d for d in observed] + #forward elimination + pivot = 0 + for i in range(n): + isfound = False + for j in range(i,n): + if isfound: + check = 1<<(n-i-1) + if bitmat[j]&check==check: + bitmat[j] ^= bitmat[pivot] + res[j] ^= res[pivot] + else: + check = 1<<(n-i-1) + if bitmat[j]&check==check: + isfound = True + bitmat[j],bitmat[pivot] = bitmat[pivot],bitmat[j] + res[j],res[pivot] = res[pivot],res[j] + if isfound: + pivot += 1 + + #backward assignment + for i in range(1,n)[::-1]: + check = 1<<(n-i-1) + for j in range(i)[::-1]: + if bitmat[j]&check==check: + bitmat[j] ^= bitmat[i] + res[j] ^= res[i] + return res + +def getInverse(mat): + r,c = mat.shape + assert r==c + n = r + + res = [(1<>i)%2 for i in range(size)] + return np.array(lst[::-1]) + +def list2bitvec(lst): + bitvec = reduce(lambda p,q: (int(p)<<1)|int(q),lst) + return bitvec + +def reverseStates(rawblinks:list, intervals:list)->int: + blinks = [] + for b in rawblinks: + blinks.extend([0,0,0]) + blinks.append(b) + blinks = blinks[:128] + #print(blinks) + s = getS(intervals) + lst_result = gauss_jordan(s, blinks) + bitvec_result = list2bitvec(lst_result) + + result = [] + for i in range(4): + result.append(bitvec_result&0xFFFFFFFF) + bitvec_result>>=32 + + result = result[::-1]#reverse order + return result + +def reverseFloatRange(f:float,mi:float,ma:float): + norm_f = (ma-f)/(ma-mi) + norm_i = int(norm_f*8388607.0) + return int(norm_f*8388607.0)&0x7fffff + +def reverseStatesByMunchlax(intervals:list)->int: + s, safe_intervals = getS_munchlax(intervals) + bitvectorized_intervals = [reverseFloatRange(30.0*f,100,370)>>19 for f in safe_intervals] + bitlst_intervals = [] + for b in bitvectorized_intervals[::-1]: + for i in range(4): + bitlst_intervals.append(b&1) + b >>= 1 + bitlst_intervals = bitlst_intervals[::-1] + + bitvec_result = list2bitvec(gauss_jordan(s, bitlst_intervals)) + result = [] + for i in range(4): + result.append(bitvec_result&0xFFFFFFFF) + bitvec_result>>=32 + + result = result[::-1]#reverse order + return result \ No newline at end of file diff --git a/src/debug/expr.py b/src/debug/expr.py new file mode 100644 index 0000000..21107ec --- /dev/null +++ b/src/debug/expr.py @@ -0,0 +1,21 @@ +from xorshift import Xorshift +import secrets +import time +import calc + +def splitstate(state:int): + result = [] + for i in range(4): + result.append(state&0xFFFFFFFF) + state>>=32 + return result[::-1] + + +def main(): + prng = Xorshift(0x12,0x34,0x56,0x00) + for i in range(10): + print(*list(map(hex,prng.getState()))) + prng.prev() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/debug/naetoru.png b/src/debug/naetoru.png new file mode 100644 index 0000000000000000000000000000000000000000..bda544428253b05820fa384ea3139d675f52686a GIT binary patch literal 17129 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 literal 0 HcmV?d00001 diff --git a/src/debug/test.py b/src/debug/test.py new file mode 100644 index 0000000..35e2b03 --- /dev/null +++ b/src/debug/test.py @@ -0,0 +1,63 @@ +import cv2 +import time + +def main(): + eye = cv2.imread("E:/documents/VSCodeWorkspace/Project_Xs/src/debug/naetoru.png",cv2.IMREAD_GRAYSCALE) + #video = cv2.VideoCapture("E:/documents/VSCodeWorkspace/Project_Xs/src/debug/naetoru_blink.mp4") + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + + IDLE = 0xFF + CLOSING = 0x0F + state = IDLE + intervals = [] + prev_time = 0 + + offset_time = 0 + fc = 0 + prev_fc = 0 + + prev_roi = None + + # 瞬きの観測 + while len(intervals)<3000: + ret, frame = video.read() + if not ret:break + + time_counter = time.perf_counter() + unix_time = time.time() + x,y = 830,460 + box_w,box_h = 120, 160 + roi = cv2.cvtColor(frame[y:y+box_h,x:x+box_w],cv2.COLOR_RGB2GRAY) + if (roi==prev_roi).all():continue + prev_roi = roi + fc += 1 + + res = cv2.matchTemplate(roi,eye,cv2.TM_CCOEFF_NORMED) + _, match, _, _ = cv2.minMaxLoc(res) + + if 0.40.5: + state = IDLE + if time_counter - prev_time>0.5: + state = IDLE + + cv2.destroyAllWindows() + print(intervals) +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/rngtool.py b/src/rngtool.py new file mode 100644 index 0000000..249b811 --- /dev/null +++ b/src/rngtool.py @@ -0,0 +1,168 @@ +from typing import List, Tuple +import time +import cv2 +from xorshift import Xorshift +import calc + +def randrange(r,mi,ma): + t = (r & 0x7fffff) / 8388607.0 + return t * mi + (1.0 - t) * ma + +def tracking_blink(roi_x=905, roi_y=750, roi_w=55, roi_h=55)->Tuple[List[int],List[int],float]: + """measuring the type and interval of player's blinks + + Returns: + blinks:List[int],intervals:list[int],offset_time:float: [description] + """ + IDLE = 0xFF + CLOSING = 0x0F + + eye = cv2.imread("./trainer/eye.png",cv2.IMREAD_GRAYSCALE) + + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + video.set(cv2.CAP_PROP_BUFFERSIZE,1) + + state = IDLE + blinks = [] + intervals = [] + prev_match = 0 + prev_time = 0 + + offset_time = 0 + + # 瞬きの観測 + while len(blinks)<40 or state==CLOSING: + ret, frame = video.read() + time_counter = time.perf_counter() + unix_time = time.time() + roi = cv2.cvtColor(frame[roi_y:roi_y+roi_h,roi_x:roi_x+roi_w],cv2.COLOR_RGB2GRAY) + res = cv2.matchTemplate(roi,eye,cv2.TM_CCOEFF_NORMED) + _, match, _, _ = cv2.minMaxLoc(res) + + delta = match - prev_match + prev_match = match + #cv2.imshow("",roi) + cv2.waitKey(1) + if 0.080.7: + state = IDLE + cv2.destroyAllWindows() + return (blinks, intervals, offset_time) + +def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[int],List[int],float]: + """measuring the type and interval of pokemon's blinks + + Returns: + intervals:list[int],offset_time:float: [description] + """ + IDLE = 0xFF + CLOSING = 0x0F + + eye = img + + video = cv2.VideoCapture(0,cv2.CAP_DSHOW) + video.set(cv2.CAP_PROP_FRAME_WIDTH,1920) + video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080) + video.set(cv2.CAP_PROP_BUFFERSIZE,1) + + state = IDLE + + intervals = [] + prev_roi = None + prev_time = time.perf_counter() + + offset_time = 0 + + # 瞬きの観測 + while len(intervals)0.7: + state = IDLE + if state==CLOSING and time_counter - prev_time>0.7: + state = IDLE + cv2.destroyAllWindows() + video.release() + return (intervals, offset_time) + +def recov(blinks:List[int],intervals:List[int])->Xorshift: + """ + Recover the xorshift from the type and interval of blinks. + + Args: + blinks (List[int]): + intervals (List[int]): + + Returns: + List[int]: internalstate + """ + advanced_frame = sum(intervals[1:]) + states = calc.reverseStates(blinks, intervals[1:]) + prng = Xorshift(*states) + states = prng.getState() + + #validation check + expected_blinks = [r&0xF for r in prng.getNextRandSequence(advanced_frame) if r&0b1110==0] + assert all([o==e for (o,e) in zip(blinks,expected_blinks)]) + + result = Xorshift(*states) + result.getNextRandSequence(len(rawintervals)) + return result + +def recovByMunchlax(rawintervals:List[float])->Xorshift: + advances = len(rawintervals) + intervals = [interval+0.048 for interval in rawintervals]#観測結果のずれを補正 + intervals = intervals[1:]#最初の観測結果はノイズなのでそれ以降を使う + states = calc.reverseStatesByMunchlax(intervals) + + prng = Xorshift(*states) + states = prng.getState() + + #validation check + expected_intervals = [randrange(r,100,370)/30 for r in prng.getNextRandSequence(advances)] + + paired = list(zip(intervals,expected_intervals)) + #print(paired) + + assert all([abs(o-e)<0.1 for o,e in paired]) + result = Xorshift(*states) + result.getNextRandSequence(len(intervals)) + return result \ No newline at end of file diff --git a/src/tidsid.py b/src/tidsid.py new file mode 100644 index 0000000..0a67bcc --- /dev/null +++ b/src/tidsid.py @@ -0,0 +1,121 @@ +import rngtool +import calc +import cv2 +import time +from xorshift import Xorshift + +def randrange(r,mi,ma): + t = (r & 0x7fffff) / 8388607.0 + return t * mi + (1.0 - t) * ma + +def getids(r): + g7tid = ((r%0xFFFFFFFF+0x80000000)&0xFFFFFFFF)%1000000 + tid,sid = r&0xFFFF, r>>16 + return g7tid, tid, sid + +def generate_dangerintervals_list(k): + lst = [] + for b in range(1<>16 + if g7tid==playerid: + print(f"backwarding {i},", hex(tid),hex(sid)) + break + + randlist = prng.getPrevRandSequence(100) + expected_intervals = [randrange(r,100.0,370.0)/30.0 for r in randlist] + + print(f"observed:{gombe_intervals[::-1]}") + print(f"expected:{expected_intervals}") + +def main(): + blinks, intervals, offset = rngtool.tracking_blink() + prng = rngtool.recov(blinks,intervals) + print(f"state:{prng.getState()}") + print("input trainer ID") + playerid = int(input()) + + for i in range(10000): + r = prng.prev() + g7tid = ((r%0xffffffff+0x80000000)&0xFFFFFFFF)%1000000 + tid,sid = r&0xFFFFFFFF, r>>16 + if g7tid==playerid: + print(f"backwarding {i},", hex(tid),hex(sid)) + break + randlist = prng.getPrevRandSequence(100) + expected_intervals = [randrange(r,100.0,370.0)/30.0 for r in randlist] + + print(f"expected:{expected_intervals}") + +if __name__ == "__main__": + expr() \ No newline at end of file diff --git a/trainer/eye.png b/trainer/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..1b9f95537d408a43c6898d19a666b31edd51a1a9 GIT binary patch literal 1941 zcmV;G2Wt3Px#1ZP1_K>z@;j|==^1poj532;bRa{vGxh5!H^h5=oo6M+B#2P#QKK~z{rwU}FO z1i1}G>(O3T{sRO7g8V0o$QEV;*-ExI?nlnK6szQN`(p+(G-yf`C6QN@O6v80|NZ5) zuIsX_uVs0?mUY{fWszUY^YuVNPuidt?N|AHJySl(wwFU87$MrO z3m9!{NsTAo_R?)QJj;}^zjE8``@Y<6x9~QV<()C*+YLQ!A0Ox}e|!kZ6K6mO-yEVm)!Q{iQN;^;_cwH(`Umrlj+bHx13u+NWFC| zkslOp^rc78!?vKC$-({zn#Ue&A~|g~CS#fB zx+cqu(d^JH%?^c!1JOO1PJR^6{k8pxt_aS^Zr!g3`pyr)<798gm=u4Qa08JQ#C8}- z%t{^6&eQyrdaVTA8OL+4$Z2g-)_GXu7v(!rhco4^kvByzLO}_%9wPS0(mg2KZuzu5 z`yNLP6f~Gzd9X=7c4nN)VEFv$x+BY>DasMCtKEpmcln9#X*LvM+SIuYnshh!9Q(nL zb(V>$^>Y3s=k#0qCa0Q`M?qvDmt~vk7w&vZ9oya@X-j?R2YO|5A~_RIjfSkb)jpMt z%1DViIYf@2c*-dk!a9=3o3U?XE62)CIvgF2g_y&6Dyv*Ra!NFe&}P{XO$05>>7kY-`O@&L(XKs;<0(AzH|9Xev}z-2#FSqg%*yE;-n$c;!LEqkZ`;IZql);(M=b5h+5zYyf zK4a1$i!9d~%=FH&aiSMWQtgxm^Q4NhBJO4AN&8hiQ`fuCT$kphywdi3e&U4pn33G% z7~ z=dP5lHdo?AzjNv5M$K8ZzJ6ubeS#RM8Knl1(^rs9un)e;*c3X-oH|Te2;I=9zxLE; zgh+xf^_dQ&@~s1rlm|D>D9GkXm>lVIr)B>ZkX*vE&Mn*WV+Y*hgp+??T}w`_k53RX ze{h7Tvh$D|SKLCQkm-DK$K{ukl+CHC-*CWRO+Ij92bv@`^O4fgSFXv`7N>PW#7+!6 z5`5u$^DHS^M{W(o-sO}eIwjA@=iN5zT7RXUqstOb-E--e7xHN#zs#ux^m23Z49hFo ze5$C9TuZK;IoCNwP7HpRGfvE^(BA11tun#WPjo~kFWuwCTj$n^Sjm~@s2hz`a4$JX^=1lOVUF&}~ bEzAD_LG(ZSUB~8100000NkvXXu0mjfL5|uV literal 0 HcmV?d00001