From e25f2e74dc663302a6cec1d43fed37a40ba778da Mon Sep 17 00:00:00 2001 From: Arignir Date: Fri, 15 Dec 2023 19:31:13 +0100 Subject: [PATCH] WIP. --- .github/workflows/accuracy.yml | 70 ++++++++++ .github/workflows/{main.yml => build.yml} | 12 +- .gitignore | 5 + accuracy/__init__.py | 0 accuracy/check.py | 152 ++++++++++++++++++++++ accuracy/expected/ags_01.png | Bin 0 -> 32486 bytes accuracy/expected/arm.png | Bin 0 -> 1974 bytes accuracy/expected/dma_start_delay.png | Bin 0 -> 2926 bytes accuracy/expected/openbus_bios.png | Bin 0 -> 3434 bytes accuracy/expected/thumb.png | Bin 0 -> 1974 bytes accuracy/expected/timer_basic.png | Bin 0 -> 3653 bytes accuracy/suite.py | 68 ++++++++++ source/app/config.c | 2 +- source/app/dbg/lang/lexer.c | 3 +- 14 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/accuracy.yml rename .github/workflows/{main.yml => build.yml} (96%) create mode 100644 accuracy/__init__.py create mode 100755 accuracy/check.py create mode 100644 accuracy/expected/ags_01.png create mode 100644 accuracy/expected/arm.png create mode 100644 accuracy/expected/dma_start_delay.png create mode 100644 accuracy/expected/openbus_bios.png create mode 100644 accuracy/expected/thumb.png create mode 100644 accuracy/expected/timer_basic.png create mode 100644 accuracy/suite.py diff --git a/.github/workflows/accuracy.yml b/.github/workflows/accuracy.yml new file mode 100644 index 00000000..1aeb0881 --- /dev/null +++ b/.github/workflows/accuracy.yml @@ -0,0 +1,70 @@ +name: Accuracy + +on: [push, pull_request, workflow_dispatch] + +jobs: + linux: + runs-on: ubuntu-latest + steps: + - name: Fetch Source Code + uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y meson ninja-build libsdl2-dev libglew-dev libgtk-3-dev libreadline-dev libedit-dev libcapstone-dev + - name: Build Hades w/ Debugger + run: | + meson build --werror -Dwith_debugger=true + cd build + ninja + - name: Download Test Roms + run: | + # Download BIOS + echo "$BIOS_DATA" | base64 -d | gpg --pinentry-mode loopback --passphrase "$BIOS_KEY" -d -o ./bios.bin + + # Create ROMs directory + mkdir roms + cd roms + + # Download AGS + declare ags_url="$(echo "$AGS_URL" | base64 -d | gpg --pinentry-mode loopback --passphrase "$AGS_KEY" -d)" + wget "$ags_url" -O ags.zip + unzip ags.zip + shred -u ags.zip + mv AGB_*.gba ags.gba + + # Download the remaining testing ROMs + wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/arm/arm.gba + wget https://raw.githubusercontent.com/jsmolka/gba-tests/master/thumb/thumb.gba + wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/dma-start-delay.gba + wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/openbus-bios.gba + wget https://raw.githubusercontent.com/Arignir/Hades-Tests/master/roms/timer-basic.gba + env: + BIOS_DATA: ${{ secrets.BIOS_DATA }} + BIOS_KEY: ${{ secrets.BIOS_KEY }} + AGS_URL: ${{ secrets.AGS_URL }} + AGS_KEY: ${{ secrets.AGS_KEY }} + - name: Check Accuracy + run: | + python3 ./accuracy/check.py --binary ./build/hades --roms ./roms/ -v + - name: Collect Screenshots + uses: actions/upload-artifact@v3 + if: always() + with: + name: tests-screenshots + path: './.tests_screenshots/' + if-no-files-found: error + - name: Cleanup + if: always() + run: | + if [[ -f ./bios.bin ]]; then + shred -u ./bios.bin + echo "BIOS deleted" + fi + + if [[ -f ./roms/ags.gba ]]; then + shred -u ./roms/ags.gba + echo "AGS deleted" + fi diff --git a/.github/workflows/main.yml b/.github/workflows/build.yml similarity index 96% rename from .github/workflows/main.yml rename to .github/workflows/build.yml index dbae5ce3..54ed21d6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/build.yml @@ -9,10 +9,10 @@ jobs: run: shell: msys2 {0} steps: - - name: 'Sync source code' + - name: Fetch Source Code uses: actions/checkout@v4 with: - submodules: 'recursive' + submodules: recursive - name: Install Dependencies uses: msys2/setup-msys2@v2 with: @@ -35,10 +35,10 @@ jobs: mac-os: runs-on: macos-latest steps: - - name: 'Sync source code' + - name: Fetch Source Code uses: actions/checkout@v4 with: - submodules: 'recursive' + submodules: recursive - name: Install Dependencies run: | brew install meson ninja sdl2 glew create-dmg @@ -130,10 +130,10 @@ jobs: linux: runs-on: ubuntu-latest steps: - - name: 'Sync source code' + - name: Fetch Source Code uses: actions/checkout@v4 with: - submodules: 'recursive' + submodules: recursive - name: Install Dependencies run: | sudo apt-get update diff --git a/.gitignore b/.gitignore index 22743602..32238b38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,12 @@ /screenshots /build /build.* +/build-* /games /demos *.gba *.bin +config.json +.hades-dbg.history +__pycache__ + diff --git a/accuracy/__init__.py b/accuracy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/accuracy/check.py b/accuracy/check.py new file mode 100755 index 00000000..5513b7da --- /dev/null +++ b/accuracy/check.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 + +import os +import shutil +import filecmp +import textwrap +import argparse +import subprocess +import tempfile +from enum import Enum +from pathlib import Path + + +GREEN = '\033[32m' +YELLOW = '\033[33m' +RED = '\033[31m' +BOLD = '\033[1m' +RESET = '\033[0m' + + +class TestResult(Enum): + PASS = 0 + SKIP = 1 + FAIL = 2 + + +class Test(): + def __init__(self, name: str, rom: str, code: str, screenshot: str, skip: bool = False): + self.name = name + + self.rom = rom + self.code = textwrap.dedent(code) + self.screenshot = screenshot + self.skip = skip + + def run(self, hades_path: Path, rom_directory: Path, config_path: Path, tests_screenshots_directory: Path, verbose: bool): + module_path = Path(os.path.realpath(__file__)).parent + + subprocess.run( + [hades_path, rom_directory / self.rom, '--without-gui', '--config', config_path], + input=self.code, + stdout=None if verbose else subprocess.DEVNULL, + stderr=None if verbose else subprocess.DEVNULL, + text=True, + encoding='utf-8', + check=True, + ) + + if not filecmp.cmp(tests_screenshots_directory / self.screenshot, module_path / 'expected' / self.screenshot, shallow=False): + raise RuntimeError("The screenshot taken during the test doesn't match the expected one.") + + +def main(): + from suite import TESTS_SUITE + + exit_code = 0 + + parser = argparse.ArgumentParser( + prog='Hades Accuracy Checker', + description='Tests the accuracy of Hades, a Gameboy Advance Emulator', + ) + + parser.add_argument( + '--binary', + nargs='?', + default='./hades', + help="Path to Hades' binary", + ) + + parser.add_argument( + '--roms', + nargs='?', + default='./roms', + help="Path to the test ROMS folder", + ) + + parser.add_argument( + '--verbose', + '-v', + action='store_true', + help="Show subcommands output", + ) + + args = parser.parse_args() + + hades_binary = Path(os.getcwd()) / args.binary + rom_directory = Path(os.getcwd()) / args.roms + + config = tempfile.NamedTemporaryFile() + config.write(textwrap.dedent(''' + { + "file": { + "bios": "./bios.bin" + }, + "emulation": { + "skip_bios": true, + "speed": 0, + "unbounded": false, + "backup_storage": { + "autodetect": true, + "type": 0 + }, + "rtc": { + "autodetect": true, + "enabled": true + } + } + } + ''').encode('utf-8')) + config.flush() + + tests_screenshots_directory = Path(os.getcwd()) / '.tests_screenshots' + if tests_screenshots_directory.exists(): + shutil.rmtree(tests_screenshots_directory) + os.mkdir(tests_screenshots_directory) + + print(f"┏━{'━' * 30}━┳━━━━━━┓") + print(f"┃ {'Name':30s} ┃ Res. ┃") + print(f"┣━{'━' * 30}━╋━━━━━━┫") + + for test in TESTS_SUITE: + result = TestResult.FAIL + + try: + if test.skip: + result = TestResult.SKIP + continue + + test.run(hades_binary, rom_directory, config.name, tests_screenshots_directory, args.verbose) + result = TestResult.PASS + except Exception as e: + if args.verbose: + print(f"Error: {e}") + result = TestResult.FAIL + finally: + if result == TestResult.PASS: + pretty_result = f'{BOLD}{GREEN}PASS{RESET}' + elif result == TestResult.SKIP: + pretty_result = f'{BOLD}{YELLOW}SKIP{RESET}' + else: + pretty_result = f'{BOLD}{RED}FAIL{RESET}' + exit_code = 1 + + print(f"┃ {test.name:30s} ┃ {pretty_result} ┃") + + print(f"┗━{'━' * 30}━┻━━━━━━┛") + + exit(exit_code) + + +if __name__ == '__main__': + main() diff --git a/accuracy/expected/ags_01.png b/accuracy/expected/ags_01.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef7357bbd31e4caedbef0ec5933baa93b064bf0 GIT binary patch literal 32486 zcmWJsXIK+i8%;7KLr9~OKp>%mQbHA!GNFs05m}6gk|1CxixdkWLJCz{P!?&c0YO30 zFV+QXLQsQ%MrB!8VGTvZj*3VT{P;05KkuFAdGC48d(OEfjIDtb2j_@L+C7?2x_%RnN$sM6aymbZWVLDIvl8 z>Im&GR>meT2cK1nd{(A&FMl-O_UD%Z!mX_8hu-Z8T(&j~2j`P&8O`UzPY?H0t`}%D zSkvd#gGIDW!oRCxyj<@qoPNq}MXXO2f!^+`1_Pyo7`SeviiP!!_pGawYGO&+GPHa^ zyr27QwkaB`@h9&oJ0algCapcVd-1yMRUz#wJt%9hqqB>Z)mE~9avsFtTMzH(`?&CP zbKe5x(v2%cuxD$_p8;b%vbD5Ff)B3r3>~I9S=~6pK)~v@wFxC}yu&n!H{;K1RP9rv z9)*^yao%CywI;n|Ci9$~!t7OQ0{|@z#M#jM&jx9OKHLc}TF11>px@cwv?`d(CFR7q z`r5E>?H}*)f?1stm7@#b;=b#W77y2w`T%{~Q-QuLXBE_bRody>KYn?Gir>kN>LA}* z1Y=@@elAEQvq0}h1ayS}!PRk^sNM|d?=)(!@q3^S=_mja@nz*UC|ArB-t0DOnx8Km z8J=?xy)`%QtQzpW365ZyMAkPT#PF7PmFzVbMl~s&Ot%d21bMTlB7?!?Jl9M+W%xs3oh2;PN&cl`0M|KMX@|#H)-DSt^Wg*~H(S^JZufJybT?K8 znElhFp&-Q^)cvJ7X*ab{&>o0CV!?!Uo89+CLdTUQs_W2rvPdOeDFf8r?XJ}qx&;}g z=LIQ+8rhBfwGls-V`Zyqmm_2QwSP?&4wMC{8rN`+8YVm z=$5%S6Mi1&>^YO3U*;D&PEpU?D#r_t^;=!~6FVn^5%v#et zkv}=TnI(bG)`8z>SM@VZc#(xh&~V4NIt#YJleOw|u4+tG6C{;JwWW#7IkDfWWJuXw zJZf+n9}Z6+j!9Z!Wq7;(5)3vi10x@YyOHi6RNMXWda<_^V_=3shXrqcP}>i-l*%<9 zXnN!cp3qNzi||Ylz5ugtu~?AGeOMUTq{#c;^&+FsGilsVdz)kyo7YHj6Q*y>-kAT^ zx1HB?iG$kOwvDw!FXZD`5}cd3dSj=f+Ng)fD04?6Jn7#!Xx_QF+{j8k&mWc_?p~Nd zzn2kEcesGH>G)SYw_+9&G3YEF3$mCzp4?b7nX1>nO`bL@;8GMHx$Tc;309-Lcw)4Dt4zwHz)gPp7Lt*J)f zqzampOXv74Ro~Mjqg*44*!&IYnbacqkTY_NZxEXsN=T1{^$MJ5!TYiVu2$Z|8>9s4pXH`&ELeZ)pK4c13v|rukopM!T zQWTXwsb(^#YGz?oCDZWyMlB)@kGYMOX`&z(`KJY5HG~w-$v*I3R>rE@9ifQ|J`+4j zDDIb8bvt41XL*jA3J)PE^$2}HPbo1<_f|MkhCLarWX3h24C@)C2=$-0OxLF$-gL`I zNDiX(f0oCK8j8pd#ixH+nS^Wl>B^E;;7=#@bWH{&y;}#`vO$bEBM@-^QOq^%Ckj(C z%PSw)WV-pRl-b^;-sS?fHuQ9Po#xn$&I!Ufe7unyOGNdtuYlJGWkw5FY_SKf+IMRU zQ7V^8xa*~p!3uA&^KWj7kGw8)Am7q@5*k|owpf=Bl&3m)G@Y()<-y9e48PFqhpu0w9#N|4&9zNQG%MsWWH}O7Ho!Bb zOS%#51;84lMP;ziNmJt2l6Wv2tLr-av)Bk!)@y9ZIcx9>ZaZ#z+o0iqGzB`TlxWz| ze#Bso;+?&XA9<%|ib`b*!`(Wu77?4$9vGaEF=?7Zgu!5KcO17H+f%d))vTlQhF_k! z>P5P|Jxtvgwa=pDd8&Bv|5mf=%lN*I(2?JHQKu33ATZd;^?L>1_|L9Y1-Dph3CoHq~^?EKM#O z6}-r)U2RwCe`LH(u>yUgvx9H0aMBjXI3(avmldjdZqrV5(poPlq&R#65^Bs|2Z>2FkH49%~P zdA3cS8#6blro|L`{S%3b58hkKFLLbv^$(AY+%idXn3@Hy(CdX5?XYfw(W=C)NT*gw zE7-czQHWNCaulQXnHnJYj$v?3j11=(zgx%F9MA4MO5okE^#C zqs6UtKFOh~rHq4XR77uRVNnXXN~~h9T-S7)UBD$f=w`)wdMoPN<*WYxYzui0oNA~7 z;HOr4RJ6eg3rnlXZby4LS>3?1LecPPWAsm&DHjLp(>z%8A!(C}h+t z#9lN2d?(Sl2UocRFP%!5E5oHAP6~6X8a!#glY>kzb@qcJf{Uq=*QnXHA0P@9{3p$ra1f5v`r| zH}`g6onZ?f0#gD69S`TRY9N2xcWP^3 z%!F2)(ZZ%dq^Oh2u01P3BEe6L!Z>QwjeiNrBxJ8g^3oN5$y)Vm%YXAu9YiU^mVuNb z0!J5{efyjMi^>%H{@>+GSGx3eoras!jLAZeWCgxqJ-a|72p{Y9B(fMd+9XJ}DEy_E z&^kYYRlSy0;B@8N>ou&4CYvn7?=sj_1lMtW@O`~@LfN)W!8tLTqp4Yp0Oa?#^wsYA zTrLnrb@5IO*T%}zxaUyOIg&YE604RZwwNO@Vz^7#t^?dC6ZIV%sUZHQUvP+%{*X$* z|Nf+(?H@)^c3?edHp;MaitF%}lTv9FvNrWJG{{bUUsj%lyF)!U}Zc+-3L zgVp*wwFs^p;DR}H1DUO*ZbxtiBPOX0+uA)k&}s*oo6G0Ae}X4>`Wb{4_MR;}C zGgZ5CodzYc#*6xLeZID6=geL&pVD2ha_-Crr&+^?eQ1;cJu=7K)w-^h(c34LLb}{8 z_?WG?u)d4su86Yih{j-GQO*kU&VGTr=J}&(e$Ek3joTlj+SiTq){h%6gGqPbAD6%I zQf(`ey>2x~6AFWl?88J)@zG;OId6fT`Ye$PRXuOGn`9T@w^2&kAM{q&OKm_}@@_ZN zgNwl5eJIsU!z%nLjpC^{XhmF8)zXdCa^q?kgvQmoU$O9O16ZF51MRHRx>0voHz=La z5{ZPn)rn;hTbm`HUX}b~V`5<}`w%BdZeE4Hn%X2^`4_~b9$aSSwD8N|*2zSgiP{XR zg-*Y7m_DiQxhIwS00+2orvmWgFU9N6PNWk&a`R|3_3M<8(4HPbxaVj}<~iX2Eg9Tp%oWfEIOs>94jgRqJWkFX7kNpVyus?vm**6Fyl$mMG zDn{N<$tT^8)j-VA*bS4RhiDs2toaW}>7(p#6wt_=GCa9M5KkG!PlY_W+U z)*-e5^@Xq3#~y7;KDgF(2pw$LAmLScPl-9*foe`HgXn!dorBGmhifNQgdRO~KNH`r z(AuJ*ma)F6=P9qoxJt{oKmA}J&&l(;kh(6- z_anEiJc^ULHYP+>9oL*qt!zdiuHIKVDvFidTZSW^SQVIc9dX2JO6u29n#d|q8OV+K z2qgG^0mCxYABSVZRcJpp36T$6si6yzar86H0YFodhKGyO8c^gKUmD@ za5|0m>&A2=&g`jP5)3Pg4tYZFsz#>#C|ft2ZCxLmw=W+a>Cdx&p{4b()-oO1q87Vh z1+xEGb?hl`la~yAO10c^p26Uf8VF5|nj^KTiLUYndHfOg+G z{{G{8C-J08O z`EEN)yDJ}(40jHF|0Ox~gv1E!%A=k)zphVmA820I8tV4l_Dg)dqVWlISmNjqWVHKE z%$We6boFBNWDHJ088+33cL#vP^3qS#oYVe?oo}iJdbJC9@MUL2HdV6hz~SM4AVV6V ziC9ThEp4=<&*(Z!P+;p(mX^OB1jpZMCYJ#2pM;aJ2PDp6{s8?+595J6?I8qT;6198 zzXdPqFh`GnIxyE+v}o|pLnL!}Vzg7n8#*ML&gEpLDYtmjTom+(7#V!`oo1UU?g8uk zzg-nVSZ-{|M7U0#IwgEi34ewWRFgaOF{CD2=4jMU- z6Z2wSgcCh}MREX<&X@fG6W7^pewZ6I_5JpV*iUZ?76VT3SME`rRNsQ_#hX@=GZa1-EOgR_$Hdh(bvNEjFtv8YlHcNME=%FC zfkt@)nq_Y2nw6Sw{I<&PMWx*~+6$_?y61^B6lxH#T3G7W z`bL$P@G%1RWkG%;ujB>?Q62OTXw~be|rr zs0sTP2t|^PzpuvE8bxWS9x%#arFntCTUg)}58K^P%z~HwZ@!=lRT-Is#<*)VXJWUU z%dZoVbH#E~_it=WB!bo9-br??QnQeJb;2CkW#guZZBdW=1fgEix*tw9i;1`9%-lOKzRf?Y%oZ zMNi@S8!hGTo$ANE15WPq>dzJ$idXJ*{w%tB<`g_brA~ACnU;lg_O&Rbut!W7$mvLc z@6_j7?UTLjZ+WckWbPR!2LzPsF9`|9 zeXTQvH?>SGu{oQUK=cjUe!HniM0Ea7Xq!+ak&5Efo;|Xg73%D>yxlzQ!+G<+(5gu> zVbAkb7E6S=%%74;P3uNCahz(4+uFdC~t&ewrRBO@hC@WH`e`&WT{6iwTW68r!a%J&V|(opaDpZEei>vI{jSW?b2Fn-=~f( zjD7)Z5ve-ZnZsINH{Ei#N}-y(*mnr*S|S$1-1-9uo5Cim8I9`44a)dj?oMc0niw0U zLmF0%{ndPaU-BiK2YXv`E%l$s*VpaZuNa_1@u zLC5wuuUCz;h^o^(;|rxYh30G}rE{lq)3QOsFQF60&eZ|Vx4o+BPrX-m-2RHfgm!Y z;Tk_fS;K!0ze>y3NT-?HMz?(SR3PY_Lihvpop=iq(|uc(ho5h}IR}d_G3OpM(!Kg; zk68>;$sIJgHh$X7(dSB*in~ZLV9|0K?kUqu1tb14b%$L%205`YgKP~f2J~V75bzOb z&;Dl^)hQocb3pyVE^&cI)t92bjiR~;y&?QB#SgHxzu0x(-EFSrF7Vu=aL+4itgpm9 zr_3Jz0n*;4LhJX2y8^+@d^fE7eTf=;_$~PaAB!DK`O~CGZ#pa()n-qm>Yi1xtAPS* z0=Ej?wA3RDp`AtR9iM&Vy_NmZPOJBnH({TbX*bP~(0XU!1`tLo_Q-gKX~%Q{siZFt z>jw)~Lj+$wB7N^X7qV@uG3+{Q>Mu&rm+waHZ!!O)F%Sf!X6!58ql{A)Dn+qu) zKj7#Hcm2i6*K*D1?N7Bzv4}-Qk|lio>Swd_+p8R%vx!w<*BmAF&t^zEu~s)H6NFCo z{V`iP76Ip~$PeJxf$Azc8=v?(xY_VqzJ0Fng~ly!_7bsj&+;!y_ybu@SWH7OKfz*c zw-*a``6ODH2T(eMk~r6)kV^Aw<7&j%j6C&qEsFjJ=T0*$ET;COOkg*~67xdMT#o5Y z*2UQZotm-|C!^Fh|I5G82VPM)NOKv1d8v48a@c8Ia~I}{?xpw#5oaAG*BpS(#XjCf zX8yq8&fUC+_lr(#bTcW|YKGKnVbIIyD{(Q&3F^AuH20`4#Uo%mH=7H;absJuZCRge z#zikZf85a^db;Nn6CIz3Z(CnAsb?`KfXB@lPP^9Dd8f+vZDLdQ*xG~%2YmGQQIYEM zAQc&$qjy}tEsMA$?(#UVqM>ut1Jobe*=)i&lK8Y8c7y74>{N@4TOChi)h%wSQJwP3WQHLo4Cr*5J>jw6 zh~gu!Ns2+1YZLn(Z(aT+4ALFGdw-N>-`?n0dyl|>EwMW=w{PpUR45Mnh~GKTvfZPPGwqAk!G$(XwYQv)l+lJS(`@)WhczotG?eX zt&UMQ9AmHgKf|o2Nl#$0a?|^?LvoVtwH$v}*ag5{Ms+zlUZ+z(DG6o1iNjLn1EhSM zN65r={PK$AP4j2o-@LNHsN?O^8yQBi-$5#Gpscm}Q zOqq>mO?7tf1Y~88{@M(Wwf_2GOzEcb5WGbUiqd?V%bx4^ZG%bV$?`S*KJA&K!&R@S zWK>kVaml`G6i+9<9^%ZXK1ti6eSCf9r~)5B3hR8|+a zV2mz%O9a8{_g7gk7i%f$G(4ig6wuWS4aeY!+yk{_PZeAe(qfMoRadt-M>j z8+}PcT3{+XQTUk1<8%-%Bsa`xpKb~gpmopHZDM_QTkn(IgNh7-a`031NV}kW(n>UP&Tvx}szc*6J3h$Vf4gFiOqK)`sN?#PzT z#MVZ0^BSyRi){$GMq_;O7g%wRP~Sl7Hy`>$83tBYGf-u9e=UD*N~|(O|5MSn-JMsl zi1)0}3%khI9>1`wX&!byI+wcbDeML}2@-mlQp{J~ zSuc2?7a36azkUY41*^hcLZg$(vGq%WQo>9%1(7j zqPI||5kf>%W%yj&lI*hHawh$N8Su=>#_h7OTi1;6eo|JiU>)Vgb8nf*Q-C;*P@kc- zh!m?wB^|092Tzznb)@`Lk$V9AP2X;CYLKF`4nNga*hZ)3lv^ZCn({R%_CVle zPlx`Z5dto-b5SAnh`q)xz{w-$=o@PD82y&jCrFIHvi=KvERrXq%<{Trh|{|?ngkxd z0ZCuibfC`{eg2jug}0fqP4A0x&4X0eI8TB5&2+r`BtPVJzLxqXMe`XrDb*y+jl_U= zoLfmjzFjjM?T2&8sF*GHp7KZ<&dB`HcV(=}bTTKeoeZ*=?yE-d5h{unWa$DTLR zJ}s$AP*{1Uvg+ZcT9fiE;yL(JN#_zwtUnJrv%8)7WC_pSk2DL!W~8?NbUli_;aEOKW7d^0Z6 zPd1@e?I3KBQscxSs%P0Z)&=3~%E>=wz7)j$Z3=jNb7akLVt-oX`QxV^5||g#8Ma9( z+@dH-?w?>je z&x<;O-4ZJHE3Mx3WuSEe7rFJrRe7Cu3*s`?Gfsk*#BqU^otLo|ubAsGxtf@mx zByd&DV+o2uEY1}}Mu*lztYuLSJCf5LO%{OS7zL#lw z(QdOp`TTf8XenDDTc6n8t>2Zsz-#=;`gTDgZ6%0ub<8qM%JRRs3sDzYE8(oa46Bob z7hnsIJs7tufDEz#uwAMGDa~~_BN4Ar&Ms_x=_Vp!*P+s<2{SN*%wF?wiq)lw z{t$1PULv=f;u?hM6VJ{r!EMzcObCml$#H1YEqq|wMg{&Nvl2<_rB2W^^{>73+b2H> z26?0K-G@uGRcGF6>JErI-#~W#!nr1FOqxk6ICZd_`@p1@N7SW;Vb?_2)0vywcU_6| z3UhL^X%>%^Y6Q)YNYM`iwx+76Z5ZZiI=HO6Nz1;95kxe&MMe*TN&Vs(9RvA~IePSG$Jry^V>bKwYXe}`C1FAHsEXyle(s^#eoiZ7o zP>eaZarFp|UCQF&S;Px(bgXc^`^G{sPV2$IS_*X}QoI+~h|uW&z$cq94$VGD64 zcYncqZwhC)#S;e&EwA4PTcl{9Pi`M#pM82<={Kjdz1gU}0QN-08814KaHYVuVu7yv zkW}DJRF?WcpHMDa=oszsWfksM(Vg;-2YV@sx$;JoaKwtV2=;syJvN%62#*RM9f#p|zWlS7zbb`-NTMqQ#&R)$4wQD5|h_dm7G6N+$GOV_j5S z{B3Twut2Z>Jvj)i^;qSReenP<=m2e>;s#F!POGQhf(&tMPAu7+`w6kZITuO_4rs#k_#IIJ@Diz%Yrrb;NWDV`^v>+PGwmqSHDVfaWhvMja%*sBOe}Xu z#K@Yu+b*A$>Q4J|@H3B*eiHt+14?d3K#asST+J2Rg)Td4r_-YC{1t=QR=Y{`HXlxb z4y-y-85U)t<}5;FRuq&8 zWtV%A4QQ8Iz}EEaQ9^|3+1PH1a1Qwb^X?Jf(e8sbAO&$UY^zEL^9$VyRZnhPw(<7TJK48LBr_K^m zpbT^lgpSRJ&C>+#hFQU=WMB{*b@7B-lfEh+Hoj3IzC9KV_enHFQuKWO+bWaySYra7MJ{DE@16qq5-Tp&}(5bmuHHN=RXhjve z*J{~@vs*Pg!p+RDIVcg{ikKRnGnZ_g`X|GQeHsZ`f%RQ->jED9&>jajKO$rsHcPhb zFY(S*x&lM{kvbY8Zs6EgRKkDKrFN_p-rq2azgvplj1niPEQA}K@K%1oyAZ}oSy`N& zsIFt}yrNk*6XjR2uhy6S_AO|#gWnJSeOg?ml2m81pA>}k ziA`Q8R4%zshPh@#6m@diEn(-POz>58zaA7lPkGKRD8iqoV zZ`ec@@(oJOHA%%PWX@r!Wi=o54aWlOUXW$4?;KWe$K*L!cZ-!>8-V! z7$^e$l9dRd=yp|z5y_xNe>@TAs9Dod1zux)DIKMtO5r6Gr88piyJ1x!gjDY|fE_YT z|5&uiXrF-R*ep9);aCQr%XSv88>D4&-|`n1Ni$H(CW=xLkyIl2XzJ3K;g267?3 zdX2HWJC$A;b*=kJIHJAhUbT8N=;aB76>DpV5^>}%Nu$aWXXd#C;hzPzlc}tPv)zss z{ecnh#h-T~|DK@U7}lLI{ol$13&Kl#tlE~Suj2lT#c@sE@|@aN;d%K3q;|}~1>7*)s5ahbH0(GlV2~s`tck|~zzY_+%+~q0!^I_e=+EeH7Zf|`* znjQA_x*YoRMC^YA?0RcyiAs=U*=gp+J3=jiwn4Zry1hrjwKZ*OQJ=bL9fktl0{g=` z!;&O*6siMB&AuS}t%2Y0H&%Ggesm+gIIm39FhJk3jy;gVc{2agR!wezb1lEs5;ZtvBloIaEA1+K1zF$5k?kDhkRDB(W}-~sZ59vz z+73^~+Pq;oXhmG?uD?$;_og|nA1qQ-quN8=iHxM*^2do82NcPuEp6UHFc|umH4x2I z2K)3+C?yAJ*~YMmeHTO5q!Olu|9`s#v7S*F%d2-8u9x9~u|FhOXlN^^5s1K={6)ML^9+5<8UYX_$>-CBGI(S`uK8F z=-7{^8qG6oc!u{{pkzrtE1rht%IV7mbT&M3g*U*RAFKK(AZ%<#nxs3CV<}HstBbQs z;qNb{4r|)3mCL;v1a5I&&L z_eIfvXZ+{?2Mc3JuNzyk@HW#YPXw@*wmYu73innuvm0h9jtnxhew~KDkGc>)=UAw> zTceJ6w+@pyaWC+y*2^nyqT}$0zUB>Q={KCL`dMFR##A!(VBwo3pgA=KtP)4)C124_ zzks}!2Yof4cGh%eb8)-?we;SS^NdHDvd$wC4@ki4|`sGW~!y0n4nY6OKFJ-rO(H=EvTQK_alw!aP|M-sl zs~jj4FBdVc=LM>vm=9n3-GEJ@&^FtT97|9aP)~$0GYqCe7!QwqAs@1Jf8unR8&BQv zi$2d&0~m#{Vvc%Zb^_p_9S8&*p?&ts>jD#_FQEk@ zfd9^8=lOE`G1NMkdg(XmHxo%vIX>WzqD8I4Gp-$Ct`2pkWc0CW^Dm;9D;-jC5&T>1u_N8qQPaJd^5Z?KfhVl?|%Yx8PM&TK2Z^asKfGnCCOba1nC zuX?za3lXPWf`!pl9SL4)<-a#mhW-mUtetM*KTo}9`a4vS?{D$sUO%Cqe(pz*E;WFs zVNG_wLKER^ct3kf!kf_(!y))m>=c$~d)DO4l7x$-?vKjMQ!Cxbw3uW;By0hP=Z?^? zB8DDrv#7mKcTT1v|H%!H`TY4o*8S8ko~YUKZyd{Lexin3r@{+pde+b>&S-}Uyg(Z#;O+a2W~J8n z=VuvK*M|`8;395uFbGA4y~---a#HBJi1r%bihYjBF^;p%F;Y6cDKT^cCWHX$a~@mum{_t zoFJeSUb`0V?qNLQ#girArxlnEpBl>1;9b8zzlfRQYlhmM*hpt)E7t&tQL1#GV{8;3 zRV)qh6#@(^MHV@X7+anMo6%UiS?J=D7frJJq;jF)-0uoiXSWdHbBpUmkGPG8g_ElL zwDoQG$Qm@rOwIMK4#II!P(XqvZwDESrK04hIJJ)RnvOKdGBAwy05+f9_Cn%O7$O)n zwoI>m@hpJ}v0@|I*o`wNx=U(IADt#sbfc&3ViRVSYq@}jg&LWiyfpy_9y%zp@MhKm z*Q_ypcUW&$xz~NzX#(4d)VP>~U*1UaQ7?Zz=8|>2sU=^L^4}HaXQ@xAdWS{7`4`iv zGtak+P_wvPNeH2@N38N>7N~05?wZ2&C~vglt%5EcEF{LwS#e6_Un$!rDgo zOcOOvd;W{(1e6;rK}zoN2~ML~bUfsa@W{_*sw%8Po2=2g4&KyObCZ~=o%RmY3ocuO z5D#3JFc=z#NR#|TXuV-UU&&SiY5^=;k9QJ&Xs^y?ZC$0jkX~K@;=l`@oCE{AlF_I_ zbUK9NEy68U0c*Id2ioF{tU|1SAb4jgAi=uHe_a@j#&tB#4y~{u>^4%}%Hiaq-V5q* zt>b5ZV#%|D5%$hPuHJQM1*CBKE=i&~>|xa45$0D|E2eEk^uT#`1R)0LCxkdPkppfH zp;H|oAt5duR{8vV2|gB8X_UZ8q?aCI{TFamQ_~MZ3;$%jXb9O1Z1_xnA%`c!WgC zjk?h7qhftYnncaHSS_A16?@^CcolstC4E2l$N}Zne58t{C4iC)c@$dnA8k5ehc{bW z5T_Y%*z!)v&$aA`jLhjqmYSN!2uDQD_zQot#tWlLS6~$}+qkAVSXP$3mhyQlk0;M?x156A_@;k>2!F1|UHJ0e&0+6AD z)CKVrBKm1X%TD#1p;{NnduvTd{JmFrU%`&QVZld)DJZ~A+I+@@?}5No@F~R+IyMCU zZaXM#A(Ar{^@JOq{*!CoO(|{w+!Tm4Z|iY;k+-_WDzHTz?X$zfW849%j}`yvO!J&s z31`}>JuQV$VP2@0`HkDEo}+qn9U$7Q!?1?o9D5&GD$=Alh&SmU9eh+sNRuP)b%eut7^!Z9%o)`gBU(s{RmfkP)+$i5m{ zUGRcltCvO*iIOc+-n3VdkvIJG5&y$(KvAKhK~LM z?Vnir?Jgq2Q9tIfde=+X;eWxl6=qUIz88v-DIIjA7FYr*YbNL{4P2MS3s>zP-5fF< z2O-3Ktvgh7qH4?~M2{g~5{7TVyAO1)GvB%v)#a=bn4^f-+rcZMw0!ab>J9lZ*3@%y z)VJoiy;JeJHjmw}gp5lPcQeuRKqOga_>^lX@jzCF)S6TE-#N@yXtm8#6wh^9&wMr1 zO`~n1dac6oWaTi*X3??nMT5Oq5_#fHvB+?B7u z;J*+V0avphmV3DQr}|)v>Pn&-1Q=gVqtpX+4bfHlPzB>Hj8DC_3jd~^Us&*xa9shM zS`Z6lc~nB_FD}83SI^*UDyB_<=6RmIL%!|^E05}8=vK7{dxUxca2vl@SS--h7zHn% zh7+3MTXrjM=y-cU&Vtd3(I|oav=Um-sS&bUz1tuu=MxJJR7;ThUjbVYL?U_aID3RH zF{goMjnKHc>IHn2quOxA=V2{c5Z-IzDXgUEvp01hTsT_!xviq`)I3>i;Si+doRCwL zybjD7_xvyz$T2}YSQntr)yF-@ZS!V0%+9Ix_cqRKG)5bcHwAsEc>cqGNXBzj_HyxD z-KG(^orh?MKZ-gIFp^Zlp{5`1^fdf8rNXuiJ4W62Vurf7wwyzY-65D<#H3G`kQX&S_ub!h*Q--W3!qQ0cKGcM+}(6}x? zSWgfn+&X6#02RB3`}uX>od-1kQuZvt6J9x{YiTnXTs3b79r5m@VC4tA-4$7+W1}KO z6!GBZc=n59WY#A7D%??_W}M1?gho4|T15MyD?nHqG<~0U!_4XqH-Puhmih%e1l$^t zg!iKxwjxk4w`<3W9ugFG!~en;Afi=$m7@mO(a>E|pG1#h9*hZhX0%fO$91%iRj4gS z1aRDZ#(->}H^eD8t`yaLta?uSA*i1SfKcgDHSNa&q#Ia1VK!TDb+ zb_RBRPJLQ;INdMSMcgV7xAH};#bUZy?b7d$PLLq9p@#%j&SDnQ=id;V`?fn;w7D(u zTy>v*5ZmM?EM505vI7Dn!aYD%$!_S-0k>U(qe#Q?B~2O~Bf< zvkADHaUQp=Xl9bd{X14UZ4#tjNdM%272B_JJ^0YU>WnLbNBt3WBX&b z@g_*Fg$O(aA4D49#WgwKR7mR6*t*c9p6(sdPxv|&6$x;_Vf}#)8HKdJ0@eSLCPKuLC|r zw~jpSLAY&zfoPF86d~&;Goqou_*cHSHCVUvL`5_J2)>VT^+a6P{cnIbO~^FzGx~zO z!u!pp&A!xQpM+=on*A0bar6#y&!nl#VLx`z5wF&|bgbPn7@M!5?~r;_(p4&ewfL*p1ZnJ<^`MBDaBCDjP@sqEE=-?JA%~$xjXt5&VYIEgt<43TFr>54k>5-4c zx}C=Go9=Kkq^r?j4p4JKbk3Z!Y}08tM?KPRLE5kYE!n>#Yk`R#hyU!t!^ zyT(T1o&O`T)}NH52o??N)ue)dnSqleqVVZP#D05b5C11}5HK)Dy%dnQ%xdPt*TeKY z7}q4p%=o~DoAhnNRGH$RMUz%v@gC|o*1$1Flj>&Bo5*VLQ^!wmFBY{@geRf5NbUdZ zy&$diJa?urlIbQme+D|&yrw4MFi)a_fV0$A+Fe>+4iwxVUUiqF8|6l?{eB>Ug%Iaz zADnrU15LE^{F;R&EWN{;8qfmAtjVOH1$)tZlQDCLRa_9a2Y(1 zYU6OW(h9aEPZ4C%`Ol+XSf$F=wrINZ2R}lr9`^^1;bWpTy-j!@+Jd1k8Vz;B7J;ETl}&3AEB=x{1glbG9oyX5Ap8#7VQa~- zwMmhDDXC7a+D&0CE7_{;f4Z~Ak-BfV;d((lm0*ys=rNH?xF;lRBozp;kF;3D+cvVl zpikFv_2K$%{5ZAY6CuKlYYFRMfOZ~DwT3NfoVIRST+3&h3IJrHgJoj$X#u=_3xG4o zJm+6;v0TwOpGzg&qRX)LSyf{Xco7$+S2y;%v-IC>ZJ7xeF@JzadYGzgGs&Y-b6`fS zap=Npp(DA&7a#UnWsDELjClk*q;V4p48~xGm!6Bm^cEdsnVSnHw$J4ko@R1+>tNTg z)?bC-%g6&6;R zwsv5mmL7S2IMEJ2nERXa!7b+LOuIdpk$c6zm)nLI=CtZMf03dJpj^Zv;65(Ua_sbn zg_lJ^un}>tS&pXz1Kshu;yEE;eVH4Q$bh+_(|wYtjBmQJ)?iJ%ceq}5D0;n;J}uh$ zAC{v8`>`#4C0E}pfh`?~Iw0Ym6HTI~&9we**nYo4p0fr_I*WK~)vDz?@~z`N6L!od zcr$y?PQ2NX?#L$U53$4%0PE@ULhc|J>yrudw1gIB;%VwI`8)Q&o7R`j8YB{Nym;l# zGpusVSW|tE*n*mDFnMSuH>&dwML&P$Y@ic2k)?p4I^tnELE;q&^{8>^o~d*p55CXa zeh?9KX>BMQt|Sk@E`(OCs06bj>Wf$Um41SnV)`CXSf%X7C%UA+a3XGmRQrU~8?*J8 zNDi+Xe}ekVQ4fgSh^{H2|G%R%4M-||+cxi)(IZW@=8MS!3&9S);8iT2xwERyvcVW@cq(Wx3aT{x6^TaCi>S^W4jI{q7{m z;yLNuQn?EZ?P5F%z>`s{qFQOgVdoU?-ZlMmzz1vgC&Hs&p>;Jt*m$0iFj?Qt)9fDM zT7u(c{h4)yBLR=F^l$X-02*Cds-bb1R)i#+&=v+eCfyBc*N8uWX!uDcbBETJE_D@e zeQN&BrnZ<-4{W#_!wRH~W8E(M@-@X{rW_GmbB8bq#<_@3$J($&2+eCkn#aF{BZWgP zk3oBZ)d993;3*ZbUYjB$BR~Jm>yMT^^OMR2zghT6mc$%fC%k+;`-=X5Sj(0^cq`z3 z%9Z{skm1A&``rHgjsJp-U;)$~D(b^JR^K^AjAlKt%~*@0GUOR_!M_H9t-w}>GUNd3 zKq7R?O<~>0&7{ol*t7ysg?E6lrV&H5CN7Wg z?u+6q3*N?Xt`_t^4w$lPB9u2FJ(!y)@=wTSC1uQ-bFrkln=Dz@&`gQ@!qH z8YJH?aZ4t62mg@l;;CjC|3G#_nXmL8Bz?;YHxSs-`dtWr_-b9K~;`AWj9=td1Dyi@ap zme?H=^J2KeNz?rX)#bU;e4}gi+p{ZcJ?i3JCW`G&KbFJysH&nB zU50z#D~Ue-6Y`da@*WKbhRLCX$$J9OL%$EYMvBvXWJo@H21d~gLl!9@S7`N7kkIQ( z!UQ(x{)^5Fal2sntDM4}c!QG#X$}Y8EgpjOIUBM*!fZ9hoy+un=r@?sC&Nr- zjPHf}ni^~1iD+O&@aGXRgG!J+{KQ0R9SrA`X`EkA=EEe*kd3hyPvZ19#=Ef_6z}3F zWcDBVP>(LVnhN_kCA@{*g#LT|9diw*EKgFBwf${w`em)Bjmw)7Y5Lc!s1}%36R)F9 zT?XCMPgl#jVNU`4KDIJoT|)p+ zqFa>&qM_r`QYAuB7)fchgY-fX!stRN5Q$gfG2zV|WP%p|EPBtsU@WP64qV__e-gih zpZ`wJgsq87C)34$5E9{qPY59!r0O7g{~G@HhQz}x)I&^nYDVo!4%3-ybQrS&;YZJj zs4s*Zx6(u&0>4@^Km2ng+ad0_5e6vm6li0&ZPiG+E!wtG7Gc#AGiF6&CU|MD|6Q_~ z_tcwVIH=E$7A5_WSS$bLyh$5laTZMWUuz(h1%|sa_A)F9jDuV}{h^b>Iv(Z#yJ!Ua z9SI-mgx!9J&G-t1AXM|eHcOmkkefePSXLlA1P-cG?+M8Y(Td*b>B4SL@z#~n8qLHu zsyF|>uxJYh{z#}-AZ^3_u(RK7j-uN?ZQ2D%I7P>w^mdo*u!FjrimkyDkTwyQ)j5r^ zVX@-xxH69c9zyCUar zC^l{Dr=r_f#N;Yg>=QBR&e2;3;YFF1h(Dg2dPUWjuIC7|w);{KO}=gXu(d6#J!e z#ylHyIsxegzx_mGjnf4=yaOI4p&J!m&VrxtkiLQvT9V|8$%kASdEE#}@04T;6RhzM zP125ZXhhy~f098QhgrI%k)?GjeBh>qr1n6#4rlxX6su`$p&Q+X73lU|26xxeTi??09=}xW(@;0pP$Ev9@0AS)5)#Zl!9s@g(*XRcn_Gd=|AOHIVLX3m2_+w zf!)jp7rO_#6TninQpa`R7kEgxnR8H}7Y!j0Zm=9Q*e8v=Ht~8c(gtEyM8~Gf4X z&j?mVu^Z9EH?-dM0R5gk-Jlr_uj>)^Zw9u&EB1xk_iSxW6h5;U78M+UTZ83m#-JPE zm!SS1&L7yoFVm#zhc|gO%ko&eKVMg?Bbo`WXtPo z=r<%GQ-4%N zt0#9LgQxP+r6?>^xUW}Bzp41o+0t&!xQ zXWz_s(5TdtzPLQWLQMS%@UBP;Hy&SWPekjX)Lyg`3NqtXUc*nGHYOd}o#ubq(0i}c zeOJVfOi`L`OFiqHyW+f1P|y4J!H=sSd)`vGylL##X|AVYsdR^{XpY*_iisp`7)zYW zYj7vD{R!k;2hy6*_2S-#LK}xWv0*Mn6XL&8Ia4B(8^-Jocin5gS$(g~nRI$Q*zylk z0+9rwF4U3TvGP9T1~yfqkF#0FJsts$R5YZ>Z?k%Y+{VwnQ~0m%k4~pxfe)HXbj>11 zt^Uo^vVb?~O*NLX8YBBuV<{q$Ha6I%yqwhavEmXZ}=j z#@7vh>W1#WCks{^#0~H3bklj|dPMMn37w7(e0j`yq1SLgDnUJhOJ6;gv1a-v2@`y6 z4!(YjOJRS2edPf@FkhR->Px#F<;5)y++wY>`8|S{t3~by zd3P00P+26GORL&DLo8&fdFtO5C%X^i?z_SpPy>_pR(J8(`1SPpjK7TfNeDl`CY z{#gM5Wl~^&*`X(4XE5z{6Y&ofuM*-YH1vQ)TKfoKqqr0a3K)+ zn^HuROnD;;CZG~S>BHhK1lJ6P@;)HEOKQGNQuj=_uLR;Ok684-4*l{_Fz(a7U-4~B zN3xDU)Zv^#Cc$REEAsUiRGt^cFa^pPc{4!$AXq||V2ULnEr%Gx=;7Ws0^+45F6dQ` zef8UD;02^IRN6a?fvgcmixe#fS2Sl0un+O|#OBWVSF+Lt;DSNS1ZgZI?@1M~mTu6l z&Npw<1L_1XXM(~vQ#m3)KbY?KOMb+Q7db5x*5^mV#QEGBfl{x>pGfRi*w>~@`yRv2 zyZ3Fgk}>ZEo1gEhxzEbvx-}|Ju+r%m;0aDcss=R@$M!y!wN?nhg8V~y!hS7opA;#~KXA4&# zW$tZKk>1B;x$L7`SFzT)@=J4$_%eau~S2b8b>a3cabC zS0DT>>nQ3wF4#Z}toqs|Xx(Svr7*)d+pl9{$F`2$_EuADmLp^%y$UzT!}Jd+;~Ac5 zB0$ysPl1P~Abc2R z>5_b-iYX&l%5^*@47U)g8@dE51g@6+E68;^2j6PB?Sv$HvOMAFeyKU5e(wYtjKxj{ zW*tU4X1o(PaD|D2XP4+E_HV@Bklj4#4C%YI^<{Hz?mL0o8<1Ca+f6HX(kU_!yo;w3 z7Zif*tD56*zSeI98+W@nIdPI2O{sy8ZszEj{p}n=Ot<(WrVNq1{N!`u%1Ra9q#)`c zdy_Eb!#i(-F2RX7`HysZb<;!fR(C|!7>|X2ctKrbws{9VyO!D<2Cv#=y?15KE@p+Ue62P0~qrDqb!L@rO@YfWsI0|I7g(AOeL*LGfCZ_F1 zJ!ol1=smw#5T6#Bu3zn6d5Wq;-}t!tiIl>oWWjyYU|fo^RsT-ZAnt*^de5#(yMwj2 zM4ZSPaQUFW@SGGf8O;~M`}6-{FMKXO`Ef5u#6 zS#Sm#^GqYX4`AF6nG%Cfo?u-=4IZ~?Eqd7|$cI}uqc9IzM9ehXX!0?IU$0Wr_Q0Lk zFTOdNggpqci_W#1$lGPwNyIcLM#W@4H3O==Tk1+1iVx8{FwL|))>oOzOvcpSVW&#s zavaJo=$}Rh+h$O-zU`z=oDuu$UUb5x(Z5nS(siXTOAC%NCMRUBbukwn*Q!6mW?(sgOAz9WTW&&RXQ z7U=G-Hqo1+*4`)7oRplF=-P#14zO|cc$Qu=pLoLAYh)<4v`3SiZJ0pmHOsm_!sW_q zzJNbeN&n6UOU|^>YsOtejlIia?yqk@Bjnam=Bxgw&6H$Md{qal>K{{kGlUJSk>qB1 zr_K_zjTmWW`Ig+;zvStK^8T{gU0rU(O(L^hF>&{rJR4bQb4l@`_K5B9hw6rjEgJVT z-2Rdui#D@^TWU#HvHgs0oh3#VM3m$f658Zj^<`zt40FX0GTOF4D1`g;rPAYJS+*6; zv|O^uCc?7XEc794G@{yQ#c*z5=@T)U!V6Y?e(ZB5pK44PHhRbVP1pXE+1`NRp4Dh{ zmd`Q}B2kSWWj&!b$f68ouko5liMv|7R;DyC2?qaABrMC~qd2DUhmF${qv6wL?8I;aG)-3|WLcdQ$0*|TW#c&=2% z+y5J{PSXo6UqhM>KuzLTUGp3(861iv=oy2{~Bw#Rg9F4#c>{K%>A0 zhd5i^HSj%u(mC?Nn7$(N)+uDzlaPSWjH6}Xw3wDfAxFK%{z6EZ($sit;@S$u+1>o z_a}PK?+*liPTZ$r`vQlE*rBpc*m|j~tXEp4k*8Rl#62&S=;AYkNE?4pSa86X;fUd` z2w7_>$;+!rmPRKZwB#rOlzrkk^tC#pYIW}hfdGXJB{rzJ&Slk7$?l$)0+wI+C)~YGb^MMNPvSM5yR!US zMddAGBCvE5t#%#J&)5E_@F>d-y-M-Qb9rqo)!q_kd+d?S) zEe_x&v;A+8Zs`$nuOk7S;k-!#f&xD`2rd-u#dcSJn>Dp(uSXhf5?T6>S&0Aa?3$hEuSM++{XDcod5E=*D~hMc)bz zdC)G?K_6TP``2FJ^`~ywH-o`<>K%cO`rIUmt7V$2epHs}yZBOloLVab-`geCXB{yB zR+R;K0cjG|1@MvsrT2}2?Wd+)(K2JssG--J^x;a(4OEiv?fOdg`om#P(NujV`wq{Q zH2!-vfuIv;Oz{5{EAYnLkQ?1@0lavr{^d8|UBpBRU2QMf#zvreQYW-wNx>?ep8d_6 zfQO!(f09$_=myCiy$gSOw&bgEM~;Z$u{D$v8xGO+qYr>*BO(>GhWE)fI zYhfd~qFY^daa=rZIL*uL4J>eIHN`m9v=xo&R6AFEF7mbGXyT9r_XF4;&k^z5k%a(mQIpG;4S@611^l5grLWXell|21b!=9xdC1B!j0xfdhozNkNs5|YAI;T3Uo9XUe7WXAxa9N6z498OSs zItqH0gmn?EUbyTCOxl_J|F9e8)pbXqBY)ejO88#i6<(F2MZ2oUZ3+w%9Rn{#q&kWO zyYJSN^lGAWP&Fv>L!$%RRZr9;YK%IGmBdBar``1rujPKHa*`mjV4}4_B&2wx z^e)W<=P;Y^c1FSI$4gFR_YG;LI|1FN{MbX~o+>COmUS36>spjY0;<2Nm<)652_kfh z{;}3o@F)dw-S9sv_{5k=qRM0POcon9ywbhT_^?SUIeQLD;pO$W85P2zlBz{hVqwLc zzpG2y0av+uqxBXGUwiRrbhug$w#=6_v?!9f1xsIy_r=8+eeW7v$`8?lV!X}cfsQw| zQRKKJ?ac)N8_el@Te>U*Q8`^OB9M69{}H3z8)UpO+tXRfUHVww%2@zxM^d@AVDC_X z`k>8MPSwApHj&1dMRbbbF(B4!w2u|9(i`7FY=#xIMl7g?y{zmhl=@=D$2j3?BDils zYqfvb6klS^xONLVVs~hTh&D_NLvo1Ef5&+2S9ma_Zm`P#s@oUN^@gGc3+%3#-NUEV zgZBx&r4NPAXHaMFdFXV58sK5S87+TDY-&7L^4mo5iUglDbl_&-3VvG->rul*a=RBB zV``mtfg%#Z_Xp=?7YX4J_+>eP8MjE`CRO$;CIin@E|X$UJ&eV>#yPW}YHUNtgZpMl zlRpFYd9FnlypXF;6kgZ!F&F14C>n{{ljX*9?v^s2n_!T7^C`KDMsff=@jv5*G9tkO zHuE2$@~WuDK=hJY`t}uFvT8aQ$8Awet=M|_SmSeUU28U=L>^e&!Wtj_mxMREiM)sp{)cvOzp-z2 zlNjlxOWz|p?Dt~pU3#|Wbs>CZLC^2>i+L{#Zy(g!Hm7uPbo}MYO*Ie2-kKKJs-kM8 z7djEP$iJM4dG}=u*3Qg=g0>sgb%gBQroWgft#vK_C$uZj~aR-V&VO0dxphw`J7v4P)K7%P%$l zJDmdJ#(vsf5MgNE_li5lbS7~eX}}w}<#y#cCV!nPBhl>B=6n>)KEUkr=Ac)j=!bkr z!bd--#(%Axl__;-U-g-_1Dt>JpPx}LfE02w zv7xxnh4Jzbn0kMQr7TqzUnQGn?W1{QOAe|(o~%^q9RC%O6ek^;TbN`ltFuYpLXDwv z%&kp=Y;>UbD=O_s1rTzQxaphOu9Sf`y7aMGqCoM-WBHbhKmfX5eVm@;Y!;)j-uQbra0Ndq$9|x!uaS~U3OAT#=a3O zNVNaCC~Vf>ViHAOlJoRACi)eiJO7XwB>szm8di8r?RNTKSB5nu=uX_%qc1hIAO31|8sQ^S#bLZI!@zm?so2{!``DMw;vlk&nxJFEl(JY z8LsG}g@y;4cq=orjV{T=D-x#tHEkml$`uz3#^c*wVo3YZ6Dyt2p;YqGuOgKr|mC+U?lNT=d9MEu+JPwX zNbccEZg4LWGO{@z;m5q!S`}O`5o7ncO3!w6%M*)%Obz(LZX_WKmgNi|c!3RK{`0kQ z(nHkpOXv~=Xm2~*z^gp(*|K7I`DX9iJn3y_3*{E+J=Jc^^&+@_yH>EiIN$iv-rMRI z$C@hAQ=1A=X@T??SV)CXqUwEW)*crRZd*pbHQxr`X9w(tZPvuNpgJ~LKi`ym6*#;a zXAw$F8%x#GvdL9FfdJjQ?Ub@+Vn+utszl#w;JOxLb>DY0S{?9kjIqc%Ao0%npB7(l zm#G1#eXH?=18;gL6xya^xny(*;}QoIpVd|b`)POZ8&$G@vt_0Jgn0H_QwM6>0{BQekxXp!wYB!Rm&TCp@Dc@SrnL)y0IDBIRkcWI zH15%Rd-s4>jCyn!(lsJ}S0V4mmYBym>#X!`FKK-y$V=*_jd3~!2jPCeS(ul9&%%|f;5)@eTGsI9LHW*S4#Zo2eES`DQV^M!w3rE#7#QHkDbep|U>Dj4Db zbjJ#>m%yVwHd=43^^^bbcL=fdYAq5jKZg5Ya7n9eT*Z(4{Y}V-SytmhZP(_xOGa~tt*5% zm_7FpcO~MF@q0(h``(bZ`$-^DqvL%|zpS$Ias8Pn+@*T*xa+iy+g&uAn0T@TNarGM zX@ro>;Ys<&~X3Tavsg8FE{){ZkfP_*#67x{-n5YmFq-=2)Co zPlfC#z{aXdgB<_tyV$v+al+C^y)`-Y8}uu*)@sd-9%H{e6~`n};X?iD&f4NhjQ>=K zvxyI*Qiqn)&fspue*>-smgsd%Bg2yq4s{D^(0xP27YOt+Or#a!c7bm!2w>X}`zKfjQ<7K*SP<}vqpYB{s?KZ3KE{^lN%zPO^&u%fC z`w`l5oV!G0E}>ivJEnQy#*#R14!UMU@*VP&)(NS9n|8ajHF z$ZAUE@w@cfbn6ot2v@w9vjSn#tZ7vqXAN9tO3K{LC|Z^)Uusya92Pi{ zz;B8HyNg*vWs~8xCK-MZ(%s#@()_79C1jWQs>%$$783W8u93!lC8M+~@59xXdR2N} zKFjhW@4b4L$}i||s|RPHsR=jH!S6TvI}~8--O^A@vJHY>*w~*;Z85)2S9vwYG=ygI zdQ|LeJ!?~xy|FLWm-y$yGBkM*=GJ*z9HSkpzmhu$r!M`xp!ccPQk6&^)@; zlF0rYq5lp{s&BN^BO<=cyupklc1~NXE8;r+3brTKVf$x0$9H7hiA{ITvAX-gj@V{p zk4f5S>{T8yqv|)^l?3q`aapxHd%N>aTV@>6{;GQ|i{**`v*H#S9i-QvN|S11KK>=N zR~&~G6~*!2iyaCTGiFaG#v8xzMoMC=wyqP6NsfO}=Wy#Zrl`_+HN0YSb1gHiIrf_) zroWVySZtE)gh@J7%+4CE4tbOpS`O}Wx|}YzxW!R%4fS z4mpiae_6T(FpoFk_!pAo0ylqi^e&h##Z*Qp^yZ5jKC{2N6p6=d|6GN{`xy!2SWWZ2>a?A-9%^P^>3cHx(X+%SkV1c1SuG*re7@P@*tv4BT zny9OT+fH(!i3QXK3Yy9$5Rf7BtwA1DWXx^8FqoM(Ab)vRI39wo-7onR@Z_HaONxb6>E_VvX5|T%hpoM(; z1!>7JVhJ6Fm36+5CZq^y93e1$Su@C zV=5G8OgXjqF(taN{+Nu_viP{_>ANxL>onP*xS_T3*_*?7iQ$2K_;bFh$}4qzGlD`% zo+a5A>m)f}z7gT#10;^_vTU`woPbkIFf-eBe% zi<=BKumlZfry(0z$Mk64QssRiZ)p9fyb z@1>ShDUdQ!Fl6QzJtMZWLP;;W`x5#=w8L$N+zO+sI(9}XUI&%! zbkH(>m-Y+hQ~Gs3){i%QpnFGFmjCxOY2oS=(-3C_yZ`IRFcIxd>_n6HfOR4Px8Ym*Cb4mW{UeKeW0R+XTieaW{$fP38 zPBt{@4*lWRt3z~jtyCFoYvA)4Y~*y8gZ(3Nu4FgljzhX2avD;HIeXS`sxQdzBB9%a z=8&Rxt^FpCoPuE7hT28k91v&rV<r7R_zf-%H zkvc?=eOP+D?^qx*3^w56(QQ1Ow*dXS;M!9#N(Fm^-q=Fv0+f3zh!5xMo34blHd_4hzOz(5@ zzIZ@jiA7&{%0;@mrbUBKeK44EhBAUHZL#v#TuUQgqS(?UDrA>KA`Y`_Qxj^X2WiBv zi#M+99}e?Yr%jyp{(4g{lvuzUPY3b1EQI*_BBll=m=^}XuC6JY@*E?G9=}#+^0{IB zEDc&U{~Z{YM+?kbefjnO-f?sqeMOV{D>ZAfbJtH&+jQ5_-o9n{$(`tY90uUQ+Av+o z-Z{e`z?4Pd>qMe|X6)07sRRpm2%2$!f^KWED0$Y@4aAl)rS!BNsNHw3HDQkLNG@Lx z>Pho-G;{nF_1S$o`k2U=kjKrkb=~mo%c7K5q!~4O6>MigjNlw*5eUhH9)U2y%bSe4 zc^|bc(ELA4tmgWBiadBhqz?Q=01gNMa=hFvq>9ibwt`x?7=r&Lq zu#XAkj3JB)I4N0mb4S3+o7i*WE_@_Y>-f*azU5zBclaH zeWRh|6S9?;u98j<(_JqrsSkyxk^cJoAKfo{hQ9y#m*QaGtVk>S{;yvY?gBRlOakj$ z>)?^32h-{#UW%v$-V-O^91{Qxdzqgx`Z8EHX)0NDVG39v9s7?pD*9~tvn#>#@Vq(~ zJb#}xl5cl_mmqkF!N^M0s0C3ycC5&YOMZjP*uRI+m{u+-%5;b~!kkNwR`RVjPP zmAku`p@oyU8g^pC*_g^+>>@?(tl0aSAY7s4IHOHfHP zdqAk;<}tgbX%PQa_cA%Hsq>v*Mml2&YA5!>fb*!Y3SPds2^R_|JzpLKm+4+(O2Xj5 z0T<&O5zvJ?{EM4{*ox2%`GM(nfQVu)qy($R1NrCa%H4jEjSpEd4tWjPys1%nq_$$H z)C8kG(B@V_Enw{Dzjc<(+nnm1{(ZkJi8jb@*~7i+1OVeO;-hsX)CG=^(xcWbtKo3L!y;<4Src3A7{&}aM~zb z*J-0C%QuQd!Jh&y243Nkd4_A{5H7|4RGmuT&;&hTQShTqb+QDdUVTh<#+9uUOH0;)*0gIn-)IwPlie)QMIS;!5=a2zOg$nQsk-$Q<1WlkUq=2unM|0 zy+n7D_@ba|l*EZ1w&w_QB;PciM14-yW+99V zQAhIJRlRH74w%#gCf!|Y_T8bij$}6 zkL>AaT-4mgq;C#ZE4o?IF45&Yy>r@UFk7518*$(32cB|kGw`|!q$i+B7kdPxy z%SQGk-aNHy9p{XHrt6w7g>m!+qD`DDFFE51>i{&RW3oGLpzk~cB0FIvAV`A8)|I>} z4W8Ay6bk;4V!m2y7bpnBN*^~8kw;skLW}4gCw6np!?=l4Eizf>7CzlNw^^=;_qBIc zEQPD1{XfVGMo8X+z;_bKou}JKC`oa2{7zNpuXL+0-4z|@r&`izqWnM9w!yT~oWs>fBDbT_IuqM8 zSmmRj4(3axgS>{^XIy@MlOkUK5v<_)isdLzSLY7mNvc~HyC53&ZNYj;b zJ^z_n)~ylV1T|Oxi>l*NKHl5c2~Vf5=H)_tyYs&*o(6+Qn7uCU*WXCOu1o#v*IL$1na=qJ}8!?gUQCgXy)dQ`U>Br*+nc~CZvS^FU`jVb%f_hv5m z#D7z#(hM2mUzp!RYB@B*L#2CG86DD!_~@bqFLEvv1OKolQXhkH%u!cekBh~(Beh~3 zX?=z9 zyW_uTi9P6A!&0njT;CgB?#&cx3)Gc`$&OV_)?#tD)_{f!I&px9H)!9M+K%@k@Djv{ zar@;7f*JEV1uG%pr!WC+|A;p_pkr-c$?Np&*Rd>xJMV)a-ziNlaPdgvyur88I6B&)gq@;M zx{F!sIpBRz1q|xUZFhk0W$ZiEP8%dpEAbm93GIJhVr`I;b5${<9H!ZE_=}2W(l{}B z1nr6MF^SIY+NBR1g*mRCo;QkfcYcrgOSiaa13C%e{lj#THuN}a77%wMQ3(5QO@Hm- zJT;8sLU{B4LIx1J$v;TlnLg_rJihgIVH0*pj!eggW$Lq!1ERCU6E#`7<4-O|)YLFTZ?iqWDcEKlkD3Bt{CT`9&v{Lj29HM85#=awM zc?aS(2cl`N+1v{p8F3hp-MK^hV?FEbnaOdIBfhWAKeu*Q&knu&&L%ow+{TI zn{B5Tc9GiJ1)r)_QPZj!UYOr>Hh19JO2$56B2+iBIUfui4skf)Av`^+a*6 z=pOfN=qu_nR-;g@yUY*H!8%-ii-bM1l5F|RI&H@fWJhY5VKhPpmhVYLIvHW+U%eNW z-w_ChtF*4tJ?7Ff?8ki%k?docrn8Rbg{pMvHtx7`lxXn_UXL3QA7Oh6yWxX(g>HLo zU{^`wPEgBdMlPBS#eKx|6XF(GDFuJwq`~Z3!Q@Y(CPqTNesVYkea-;2OpDW38#C^R=A?5#KFMZkIM<>&v+*kg(DMfNS*In$ z$Vt7J5|k`1x^`YB!ayrgzM)x-xbYFwW{EmXkS-5bVLuSF-sg9j`CIDS%dm5}+d*0# z&4Ih#*o87C6_F28=^I$WvBsb95bP$O>&CM}++^1`8bO@`50Zah^dtMibiGP7pZqjA zr*Al}o;eO$H4FZA>LM?W$c!$_w{Q<22Y z(qU+wz^S}J%}C4@-N|t2(*8u^9in|Gm?`dLx!J^umS*846hi23Sc1vGLGT~33(Dq{ zK!s@`PI|O3LygqY?Z<^bS&pzN@sL~&bN#qj3%mN# z6TNSSXzoBucIf?rX|js{aQhBDZzqqwJ$g#m^9$zi0%tt zVw5%zRT+AzbE59ITscxrF$~i0F(ua-Y;lgR-BC(%&KJ` zK1yv_{g-4hlly(Z4B1i$e2B_$RlxCjV=(9Uu?Wi!9GU{hzlk*LFKVOwbJK?ptA(BGPe4LJ32Jb7hSr7>|M z;^_=vt7@`NsolyM?_60?!|(f3(2$)PA9x@M%<26U6j3pjn{|XTZbdG;Pyjs3m&uVh zv5w`1``8CQRWdf_Lt#9JT{Z*X1i)hrs63djam7qU%g{{3UqEZ!hlMcHpuq_dw#-v zY=|`{AZAk>Y2Z)rceUI ztsGt_NMP7UGbL*&2XN>u#=zw;G6QZ8@+c?a7`a_Vbzkog%7xZ33^%H{NEgOO6VVN@ zO<@9rZvV0TXEj>iwCch2+qBTn=nOGfiFY-rk@2qT3>=hq!XFgL2xUERNG?7uTEebH z(p_0SNu2woBO9bFn_0hr74jiqZ?)A;+D|dOKVumT$6)dnsGR1(&P@hZuKzlix8T?mMU2dj;CU|6`OF0 z1t<*OMg>1Ayk{i%z`6*B2ANzjYM=-mkg{|^66-5{8Ip~~5!)@{ZU)ubiXQ>@Y{3Oh zcP~f^e2(^BS$H;o?&;JVVP+XWQ; zj_2rjJuO;;T##G%3}hZNa{)0^jX27f2fGZn=aO=XaNbz)1)2~>qvdk{w8qT8#kBRq zP(C&U)-yt~OtWT=H!c*R^xbHZQNRMdVFQ>d$zivTt|TjtuIgPQn+tqYDk~*y_(u0j z2d~%D{}C#&Pmq}B|Mn7aQ8O26Dpxnrr;w&4-g|4{jP=_ND&t`2{Ox zNh0}2f?-c~!VR=Qk7N+pWz$?$BL@1GfI_=|=f{mW%{Z%;C{&ks+F8>1`w=(M8E=-~ z`7s`yy=zFbIqh@q-Egt-gnPSBgVrIlT|2TgVNZyAvEHqS`GJ*8=!CB~*kmqTvcnlO zvVJ0TLWcVirKZvpEb|TEF4$u#neXkK1umXJtPs(p6yq8NID#&zc&8re!5QbF&b`Y! zy*V6>o^ivBinm3vH^`Ng=PO4#tImLHdHIC)J+P~=WMuCZXuPNfCA`hzez9e-vR@;n z6|YaFN#B$7pWFLME8#DIcfn*R4F@Z=c6a#O~BS$yb)kzi>e zstzhfu&%mc#UV{61C~zN6ft0(1!XqkJv*fd?9C_-GUR4&c_u#?*%CF7p=0?72fLpxu|7RX)Cfjb7%{Mloz}MG{})!ZszC zY{#I<>d#W;`$bG1Tph1tb4#Ft)yzu164jcrDR@?%N#a=n%_-7r4_Yx30%K5g}BvI=AOWvQP{(|I^B1V|KyH?yEz|8gB24ovY!sgCM$M0f_MZm z(F{3{>nH^uGwA887{;C0D@J3PiSeC+3%@Y^k^G*oKt6IWFk`9yne}bd{iK{#Y^b}p2Q_QJ< zy!mRLMqLtEBhctEZxr5+=>oJP5Zpb7UQ#-P)(}0$FkGe~j4;O(M+LL-sgD@EOw*V%=uL{X_o vmlJwdTF(Z}(z^fP^qh_gQVOmU^b@RM`bZlvfRvgAgFb75!UHe)b4C9LD8A70 literal 0 HcmV?d00001 diff --git a/accuracy/expected/arm.png b/accuracy/expected/arm.png new file mode 100644 index 0000000000000000000000000000000000000000..512904da1a99b3877d1815abce2dee6ea653dee1 GIT binary patch literal 1974 zcmeAS@N?(olHy`uVBq!ia0vp^AAooP2OE$yy8SSffq}i&)5S5QA};w4KMT*|1QQlF z=LC;7hRYdydfN_UaPZs}kT`o_@yc=&76~`w4;e}lyp0zHBpL)H);79NzMH|(bM3(5 zOt7|w#4T)czATFs4WyWsv>eC~t}@x%12h9j^MYs&gC4Vm?!pIwdJv)F!|XBlm!~Z3^s^akZG~$hm2j)Kx?Hcpavn?xkNxB*QsA^2GC7FdKt)V zK$U7=GNd35g$ZgZ8r))+^L-68w8c5Wgt=esK2RypXArk1C^#j6Twe~9k79NS>5o+u)wyoj?`X5of2o%0sDzwQSni!Q|jMpC(3_!*xZVhVrju%flWf1cDc z;mcJHVa@lv79RO~Vy*NH*(tN^gD!pTICX$I^mUVv^1d|LT{0c~hhD5@jq$AxI;(D8 zsJxr~X05{K33uIA{r=d>TlDN$s{OVP(q|7GHeg|^{wx{J$b5RiiBCI>jJIVh4zV}% zWSo9Gai;XNl^d^aII@d>zATTj2r&1t2OfERddiP1i=;gcE9<_b>FuiA(9^Y!FS^Zj z{lbY~4}DpD{lkka2{%Ry7K#6pgQoCbbU1wV$S->b<%>6jl$GZN7Uh`o+ig!iE$|}H z-D}I@cKK~74d;7X?)dlom*703Bp~f}SoeN^2aiouM6ejsk(37)4diA(vZhUwq5+ds zrn8x7kKR%lV9p!OiKAr*u#g@s*_{66Hn75DP?zJ B{xARl literal 0 HcmV?d00001 diff --git a/accuracy/expected/dma_start_delay.png b/accuracy/expected/dma_start_delay.png new file mode 100644 index 0000000000000000000000000000000000000000..75c961d0e41d444433d868b5bd2d8e423f7d909d GIT binary patch literal 2926 zcmd5;YgAKL8oha#Tpp1qiXlKAJfc*B0TL9&0Evc&fEX#Fs1vZE;USfX4=AlfAi$9D z5Q+#s2~r)!qJje`8VJ^~0811BMOsh>(T<3MEW}6W+<;0~f6bad^W)yL);Z^X=R14v zZ+|x{DA1c=NH&BZh~Vq9MhM1H@SKEk;O*QyAci0#j_(?;;QiZoRJU!PI)Q?70C2DK&JJPy8ay5)wh?Wr_A5j!U(Ri#0c7$k)#;r=Bpc zZ9;FR`VdwgU@uh4)e=}Fhm5XxqQsOS#+>l+2Zoyhd~?+|yZxa1>;0FaH(SwfD7!jU znZQ_)Vt?M0cfl(OZ2U7(M8CHoE!wWw zz0$?G{%U?0f#oKQ4)S}Q%Xpz9k}`>+#!cCCe`eTnmv25rxF$24CvikQ=uDu8*qGnT%G^S>wEv^pZfv z-ooM#j)h$%o)@>+^{4=^5oDv1_Zb0d%CFG2^$@NBw8J<*{N zQ)g~vh7#nKYdim~DeFGk6D^F0j!Nc?I?WHcs_Yt6-JIt{_pBk4dSTXuHk>e_tzZ5HYBExS;9ys^L z+oekacU;3!2#)~T1k{uqx+_V^MW{CJBa+(Hsg)P~U356zoAPqtcVE`8hjceU>k zRm*-hcC<@P^9{8opBZ8?Rhf6VthzXx(?gVz^nQt1`F5DthZo%L)V{CQX=#pFIQ=)t zWKM;xlqX8?7?sqU6J&Ht^b+r9mYVo7+!gYoZN_1{EgI~7vfebyohrBB3nxv6CU#&0 z9oz)XSqxR(PBu1=51lqp9v#p=&!C%h(iZy+D$>v85;mqXFB467HV^YhvJVw3(7vY9 z|1dS>s(b+{9ehy-^K`j*$jVrk%T!rk&CYu#nNK00j&fK|Ui>Ag^zL0f(ecR~n*VCI z8V_lE<}cLde`v(Gx(}Dh$MBT)L^g~%6fFuJx_LOuK+NTtXC7@^_e&vaw}<1tM`P6b zhZl8;{W|}Ea5(Q_8iSGA*qPUBSs^|ze1KR#|TJay{MGJLv;l;Le+!F#3W zE03RI5Qc7Y)$;tS2t{6w$s@N8CuY91krHw$JJerl!j!i$xkK*cG<8+4iGSPxKend{ zP|x9BN29lm^bEU?N-8Q?*s9wY&HN{xoQ#&&rcOr=1K#c8G*7rZ&RdBe6}g9+=hvQk zd=kI$hG|`uSEPyA@`Dd$%ih5)xs2a*M70@OHKtZQjbLNtyI|vU@71?Jp?SMJhK*$5 zm#L(>16e%gvYJ!&9(&T`>#0&wqp_^S`+8Ny56=rE zo`ao5A(Bn=SKE`B(3T2@FnZ+F9V=4%cNi*K6Y0T{?!>h^3{LzQHIJ#q#Pk@F!SP4L zY;0A!8iA%BR6bC&zv|+0y^SXDMQluN#jn5(fEC;YUIB{T6VyGyy<`NCjF>xmpASd^?>hf6{F9m0N@hw0hBVo2v$Y z6EFt%=9OkKVL`zph_DiyNonQ<_6*l>l9bArbyia$?owy8rg7F_Vpx{y)awyMO| zn=fLeL#>|d1NbkX4kKgYiNXsQ?t4{B5*v%N#ts+BbTP}NrKg&^Dzvh!UxRP`%WP{v z64J*;fL8_sPe@}#-uS|m!^#~f&=lR*w)dCgY~AKGNu*W;S>t@P>Mg+P5!gFGByG#$ zAkM9a5iwPQOa{wz%Z6q@BFn zis>{zPUeIAeAln5=7JWy0*kbVSKyX9U(z$fM(;~1~ecd@5&v$6hsBI*!NRBf=jL^SPO5}@nrAR~b4{~~%M;tanZE5Q#| zOn{(M)9L^)v;c!gP@N$lbGp+0)O2T+nQgkh=QiqluAYVecX0tbL0EVLiWot4nl;Qk zy;$lkfRa8@J?k%{oQNoqQ4EywS4Ga6v7%*4puoCfe84f(DO KTyudZI`|*V5T)_} literal 0 HcmV?d00001 diff --git a/accuracy/expected/openbus_bios.png b/accuracy/expected/openbus_bios.png new file mode 100644 index 0000000000000000000000000000000000000000..627975105b2340527d467e4c94f4b321ba0f6cea GIT binary patch literal 3434 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 literal 0 HcmV?d00001 diff --git a/accuracy/expected/thumb.png b/accuracy/expected/thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..512904da1a99b3877d1815abce2dee6ea653dee1 GIT binary patch literal 1974 zcmeAS@N?(olHy`uVBq!ia0vp^AAooP2OE$yy8SSffq}i&)5S5QA};w4KMT*|1QQlF z=LC;7hRYdydfN_UaPZs}kT`o_@yc=&76~`w4;e}lyp0zHBpL)H);79NzMH|(bM3(5 zOt7|w#4T)czATFs4WyWsv>eC~t}@x%12h9j^MYs&gC4Vm?!pIwdJv)F!|XBlm!~Z3^s^akZG~$hm2j)Kx?Hcpavn?xkNxB*QsA^2GC7FdKt)V zK$U7=GNd35g$ZgZ8r))+^L-68w8c5Wgt=esK2RypXArk1C^#j6Twe~9k79NS>5o+u)wyoj?`X5of2o%0sDzwQSni!Q|jMpC(3_!*xZVhVrju%flWf1cDc z;mcJHVa@lv79RO~Vy*NH*(tN^gD!pTICX$I^mUVv^1d|LT{0c~hhD5@jq$AxI;(D8 zsJxr~X05{K33uIA{r=d>TlDN$s{OVP(q|7GHeg|^{wx{J$b5RiiBCI>jJIVh4zV}% zWSo9Gai;XNl^d^aII@d>zATTj2r&1t2OfERddiP1i=;gcE9<_b>FuiA(9^Y!FS^Zj z{lbY~4}DpD{lkka2{%Ry7K#6pgQoCbbU1wV$S->b<%>6jl$GZN7Uh`o+ig!iE$|}H z-D}I@cKK~74d;7X?)dlom*703Bp~f}SoeN^2aiouM6ejsk(37)4diA(vZhUwq5+ds zrn8x7kKR%lV9p!OiKAr*u#g@s*_{66Hn75DP?zJ B{xARl literal 0 HcmV?d00001 diff --git a/accuracy/expected/timer_basic.png b/accuracy/expected/timer_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..f19b9e164e03e971a037ace03a886c80c67388af GIT binary patch literal 3653 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.speed = (int)d; - app->emulation.speed = max(1, min(app->emulation.speed, 5)); + app->emulation.speed = max(0, min(app->emulation.speed, 5)); } if (mjson_get_bool(data, data_len, "$.emulation.backup_storage.autodetect", &b)) { diff --git a/source/app/dbg/lang/lexer.c b/source/app/dbg/lang/lexer.c index 567677c5..75c81bfc 100644 --- a/source/app/dbg/lang/lexer.c +++ b/source/app/dbg/lang/lexer.c @@ -66,6 +66,7 @@ debugger_lang_lexe( while (input[i]) { switch (input[i]) { case '.': + case '_': case 'a' ... 'z': case 'A' ... 'Z': { /* Lexe the whole identifier */ @@ -73,7 +74,7 @@ debugger_lang_lexe( size_t j; j = 0; - while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '/') { + while (isalnum(input[i + j]) || input[i + j] == '.' || input[i + j] == '_' || input[i + j] == '/') { ++j; }