From ef7362c5d9482a606a7d15df55658b866057b047 Mon Sep 17 00:00:00 2001 From: Julia <145168563+julia-aph@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:06:14 -0500 Subject: [PATCH] windows window --- source/fumotris.h | 3 +- source/game/tetr.c | 8 +- source/game/tetr.h | 2 +- source/io/ctrl.c | 25 ++--- source/io/ctrl.h | 13 +-- source/io/input.c | 16 +--- source/io/instance.c | 16 ++++ source/io/instance.h | 17 ++++ source/io/platforms/win.c | 7 +- source/io/platforms/winhandler.c | 79 +++++++++++----- source/io/platforms/winhandler.h | 4 +- source/main.c | 152 ++++++++++++++++++------------- source/{io => term}/term.c | 30 ++---- source/{io => term}/term.h | 2 +- test.exe | Bin 80992 -> 81044 bytes 15 files changed, 213 insertions(+), 161 deletions(-) create mode 100644 source/io/instance.c create mode 100644 source/io/instance.h rename source/{io => term}/term.c (83%) rename source/{io => term}/term.h (84%) diff --git a/source/fumotris.h b/source/fumotris.h index ad30993..e747a8a 100644 --- a/source/fumotris.h +++ b/source/fumotris.h @@ -13,5 +13,4 @@ typedef uint32_t u32; typedef uint_fast32_t u32f; typedef uint64_t u64; -typedef uint_fast64_t u64f; - +typedef uint_fast64_t u64f; \ No newline at end of file diff --git a/source/game/tetr.c b/source/game/tetr.c index 6fe475e..c774601 100644 --- a/source/game/tetr.c +++ b/source/game/tetr.c @@ -21,11 +21,15 @@ struct TetrMap { u8 *blks; }; -struct TetrMap NewTetrMap(size_t wid, size_t hgt) +struct TetrMap NewTetrMap(u8 *blks, size_t wid, size_t hgt) { + size_t area = wid * hgt; + memset(blks, 0, area); + return (struct TetrMap) { - wid, hgt, wid * hgt, + wid, hgt, area, 0, 0, 0, + blks }; } diff --git a/source/game/tetr.h b/source/game/tetr.h index 5efe26f..7b5fd45 100644 --- a/source/game/tetr.h +++ b/source/game/tetr.h @@ -21,7 +21,7 @@ struct TetrMap { u8 *blks; }; -struct TetrMap NewTetrMap(size_t wid, size_t hgt); +struct TetrMap NewTetrMap(u8 *blks, size_t wid, size_t hgt); void TetrMapToTermBuf(struct TetrMap *map, struct TermBuf *term); diff --git a/source/io/ctrl.c b/source/io/ctrl.c index f85ed17..f1548db 100644 --- a/source/io/ctrl.c +++ b/source/io/ctrl.c @@ -16,7 +16,6 @@ enum CtrlType { KEY, AXIS, JOYSTICK, - WINDOW, ESCAPE }; @@ -122,26 +121,19 @@ struct Ctrl { }; typedef struct Ctrl Ctrl; -Ctrl NewCtrl(struct bkt *codes, struct Axis *axes, size_t c, struct bkt *binds, size_t b) +Ctrl NewCtrl(struct dict *codes, struct dict *binds, struct Axis *axes) { - memset(codes, 0, sizeof(struct bkt) * c); - memset(axes, 0, sizeof(struct Axis) * c); - memset(binds, 0, sizeof(struct bkt) * b); + memset(codes->bkts, 0, sizeof(struct bkt) * codes->capacity); + memset(binds->bkts, 0, sizeof(struct bkt) * binds->capacity); + memset(axes, 0, sizeof(struct Axis) * codes->capacity); - for (size_t i = 0; i < c; i++) { - codes[i].axis = &axes[i]; + for (size_t i = 0; i < codes->capacity; i++) { + codes->bkts[i].axis = &axes[i]; } Ctrl ctrl; - - ctrl.codes.capacity = c; - ctrl.codes.filled = 0; - ctrl.codes.bkts = codes; - - ctrl.binds.capacity = b; - ctrl.binds.filled = 0; - ctrl.binds.bkts = binds; - + ctrl.codes = *codes; + ctrl.binds = *binds; ctrl.mutex = PTHREAD_MUTEX_INITIALIZER; return ctrl; @@ -295,7 +287,6 @@ bool CtrlPoll(Ctrl *ctrl, struct RecordBuffer *buf) update_axis(axis, rec); break; case JOYSTICK: - case WINDOW: update_joystick(axis, rec); break; default: diff --git a/source/io/ctrl.h b/source/io/ctrl.h index e363640..f3851ab 100644 --- a/source/io/ctrl.h +++ b/source/io/ctrl.h @@ -16,7 +16,6 @@ enum CtrlType { KEY, AXIS, JOYSTICK, - WINDOW, ESCAPE }; @@ -107,17 +106,7 @@ struct Ctrl { }; typedef struct Ctrl Ctrl; -#define NEW_CTRL(CTRL, CODES, BINDS) \ - struct bkt NEW_CTRL_CODES[CODES]; \ - struct bkt NEW_CTRL_BINDS[BINDS]; \ - struct Axis NEW_CTRL_AXES[CODES]; \ - CTRL = NewCtrl( \ - NEW_CTRL_CODES, \ - NEW_CTRL_AXES, CODES, \ - NEW_CTRL_BINDS, BINDS \ - ); \ - -Ctrl NewCtrl(struct bkt *codes, struct Axis *axes, size_t c, struct bkt *binds, size_t b); +Ctrl NewCtrl(struct dict *codes, struct dict *binds, struct Axis *axes); bool CtrlMap(Ctrl *ctrl, u16f code, u16f bind, u8f type); diff --git a/source/io/input.c b/source/io/input.c index c9b5f59..472ac92 100644 --- a/source/io/input.c +++ b/source/io/input.c @@ -12,17 +12,9 @@ #include "win.h" #endif -struct input_args { - Ctrl *ctrl; - struct RecordBuffer *buf; -}; - void *block_input(void *args_ptr) { - struct input_args *args = args_ptr; - Ctrl *ctrl = args->ctrl; - struct RecordBuffer *buf = args->buf; - free(args_ptr); + struct RecordBuffer *buf = args_ptr; while (true) { bool success; @@ -42,11 +34,7 @@ void *block_input(void *args_ptr) void StartInput(Ctrl *ctrl, struct RecordBuffer *buf) { - struct input_args *args = malloc(sizeof(struct input_args)); - args->ctrl = ctrl; - args->buf = buf; - - pthread_create(&ctrl->thread, nullptr, block_input, args); + pthread_create(&ctrl->thread, nullptr, block_input, buf); } void JoinInput(Ctrl *ctrl) diff --git a/source/io/instance.c b/source/io/instance.c new file mode 100644 index 0000000..26b7d58 --- /dev/null +++ b/source/io/instance.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fumotris.h" + +struct Window { + size_t x; + size_t y; + + u16f fps; +}; \ No newline at end of file diff --git a/source/io/instance.h b/source/io/instance.h new file mode 100644 index 0000000..5ace3ff --- /dev/null +++ b/source/io/instance.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#include "fumotris.h" + +struct Window { + size_t x; + size_t y; + + u16f fps; +}; \ No newline at end of file diff --git a/source/io/platforms/win.c b/source/io/platforms/win.c index 29e9f96..a4fa385 100644 --- a/source/io/platforms/win.c +++ b/source/io/platforms/win.c @@ -5,9 +5,10 @@ #include #include "input.h" +#include "instance.h" #include "winhandler.h" -bool WindowsInit() +bool WindowsInit(struct Window *window) { if (!WinInitInputHandle()) return false; @@ -15,9 +16,11 @@ bool WindowsInit() if (!WinInitTimer()) return false; - if(!WinInitConsole()) + if (!WinInitConsole()) return false; + + return true; } diff --git a/source/io/platforms/winhandler.c b/source/io/platforms/winhandler.c index 43f996e..a59f809 100644 --- a/source/io/platforms/winhandler.c +++ b/source/io/platforms/winhandler.c @@ -10,26 +10,37 @@ #include "fumotris.h" #include "gametime.h" #include "input.h" +#include "instance.h" struct Windows { HANDLE input_handle; - HANDLE timer; + HANDLE draw_handles[2]; }; static struct Windows windows; -bool WinInitInputHandle() +bool WinInitHandles() { windows.input_handle = GetStdHandle(STD_INPUT_HANDLE); if (windows.input_handle == INVALID_HANDLE_VALUE) return false; - return true; -} -bool WinInitTimer() -{ - windows.timer = CreateWaitableTimer(NULL, TRUE, NULL); - if (!windows.timer) + windows.draw_handles[0] = CreateWaitableTimer( + NULL, // Timer attributes + TRUE, // Manual reset + NULL // Name + ); + if (!windows.draw_handles[0]) return false; + + windows.draw_handles[1] = CreateEvent( + NULL, // Event attributes + FALSE, // Manual reset + FALSE, // Initial state + NULL // Name + ); + if (!windows.draw_handles[1]) + return false; + return true; } @@ -43,6 +54,20 @@ bool WinInitConsole() return SetConsoleMode(windows.input_handle, mode); } +bool WinGetRefreshRate(struct Window *window) +{ + LPDEVMODE mode; + if(!EnumDisplaySettingsA( + NULL, // Device name (null for current) + ENUM_CURRENT_SETTINGS, // Mode + &mode // Out + )) + return false; + + window->fps = mode->dmDisplayFrequency; + return true; +} + void set_key_record(struct CtrlRecord *record, KEY_EVENT_RECORD win_key) { record->type = KEY; @@ -78,24 +103,17 @@ bool set_mouse_record(struct CtrlRecord *record, MOUSE_EVENT_RECORD win_mouse) return true; } -void set_window_record(struct CtrlRecord *record, WINDOW_BUFFER_SIZE_RECORD win_resize) -{ - record->type = WINDOW; - record->data.joystick.x = win_resize.dwSize.X; - record->data.joystick.y = win_resize.dwSize.Y; -} - bool dispatch_record(struct CtrlRecord *record, INPUT_RECORD win_record) { switch (win_record.EventType) { case KEY_EVENT: set_key_record(record, win_record.Event.KeyEvent); - return true; + break; case MOUSE_EVENT: return set_mouse_record(record, win_record.Event.MouseEvent); case WINDOW_BUFFER_SIZE_EVENT: set_window_record(record, win_record.Event.WindowBufferSizeEvent); - return true; + break; default: record->type = ESCAPE; } @@ -108,7 +126,12 @@ bool WinBlockInput(struct RecordBuffer *buf) INPUT_RECORD win_buf[win_size]; DWORD count; - if (!ReadConsoleInput(windows.input_handle, win_buf, win_size, &count)) + if (!ReadConsoleInput( + windows.input_handle, // Input handle + win_buf, // Record buffer + win_size, // Record buffer length + &count // Out number of records + )) return false; struct timespec now; @@ -132,14 +155,28 @@ bool WinBlockInput(struct RecordBuffer *buf) return true; } -bool WinWait(double seconds) +bool WinWait(struct timespec duration) { LARGE_INTEGER duration; duration.QuadPart = (u64)(-10000000.0 * seconds); - if (!SetWaitableTimer(windows.timer, &duration, 0, NULL, NULL, FALSE)) + + + if (!SetWaitableTimer( + windows.draw_handles[0], // Timer + &duration, // Duration + 0, // Period + NULL, // Completion coroutine + NULL, // Completion coroutine arg + FALSE // Resume + )) return false; - DWORD result = WaitForSingleObject(windows.timer, INFINITE); + DWORD result = WaitForMultipleObjects( + 2, // Handle count + windows.draw_handles, // Handles + FALSE, // Wait for all + INFINITE // Timeout + ); if (result != WAIT_OBJECT_0) return false; diff --git a/source/io/platforms/winhandler.h b/source/io/platforms/winhandler.h index 09b75ef..5eaf3c3 100644 --- a/source/io/platforms/winhandler.h +++ b/source/io/platforms/winhandler.h @@ -7,9 +7,7 @@ #include "fumotris.h" -bool WinInitInputHandle(); - -bool WinInitTimer(); +bool WinInitHandles(); bool WinInitConsole(); diff --git a/source/main.c b/source/main.c index 956e572..9923c95 100644 --- a/source/main.c +++ b/source/main.c @@ -15,69 +15,89 @@ #include "win.h" #endif -const size_t code_count = 12; - -const enum CtrlCode codes[12] = { - LEFT, - RIGHT, - SOFT_DROP, - HARD_DROP, - ROTATE_CCW, - ROTATE_CW, - ROTATE_180, - SWAP, - ESC, - - VSCROLL, - HSCROLL, - - MOUSE -}; - -const u16f binds[12] = { - 0x25, - 0x27, - 0x28, - 0x20, - 'Z', - 'X', - 'A', - 'C', - 0x1B, - - 0, - 1, - - 0 -}; - -u8 I[16] = { +const u8 I[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 }; +const u8 O[4] = { + 1, 1, + 1, 1 +}; + +const u8 T[9] = { + 0, 1, 0, + 1, 1, 1, + 0, 0, 0 +}; + +const u8 S[9] = { + 0, 1, 1, + 1, 1, 0, + 0, 0, 0 +}; + +const u8 Z[9] = { + 1, 1, 0, + 0, 1, 1, + 0, 0, 0 +}; + +const u8 J[9] = { + 1, 0, 0, + 1, 1, 1, + 0, 0, 0 +}; + +const u8 L[9] = { + 0, 0, 1, + 1, 1, 1, + 0, 0, 0 +}; + +struct CtrlBind { + enum CtrlCode code; + u16 bind; + u8 type; +}; + +const size_t code_count = 12; +const struct CtrlBind ctrl_binds[12] = { + { LEFT, 0x25, KEY }, + { RIGHT, 0x27, KEY }, + { SOFT_DROP, 0x28, KEY }, + { HARD_DROP, 0x20, KEY }, + { ROTATE_CCW, 'Z', KEY }, + { ROTATE_CW, 'X', KEY }, + { ROTATE_180, 'A', KEY }, + { SWAP, 'C', KEY }, + { ESC, 0x1B, KEY }, + { VSCROLL, 0, AXIS }, + { HSCROLL, 1, AXIS }, + { MOUSE, 0, JOYSTICK } +}; + +void Update(Ctrl *ctrl) +{ + +} + void Loop(Ctrl *ctrl, struct RecordBuffer *in_buf) { - struct TermBuf term = NewTermBuf(20, 20); - struct CharBlk4 term_blks[term.area]; - memset(term_blks, 0, sizeof(struct CharBlk4) * term.area); - term.blks = term_blks; + struct CharBlk4 term_blks[20 * 20]; + struct TermBuf term = NewTermBuf(term_blks, 20, 20); size_t out_max = TermMaxChars(&term); char out[out_max]; - memset(out, 0, out_max); - struct TetrMap board = NewTetrMap(10, 20); - u8 board_blks[board.area]; - memset(board_blks, 0, board.area); - board.blks = board_blks; + u8 board_blks[10 * 20]; + struct TetrMap board = NewTetrMap(board_blks, 10, 20); - struct TetrMap falling = NewTetrMap(4, 4); - u8 falling_blks[falling.area]; + u8 falling_blks[4 * 4]; + struct TetrMap falling = NewTetrMap(falling_blks, 4, 4); memcpy(falling_blks, I, falling.area); - falling.blks = falling_blks; for (int i = 0; i < 7779997; i++) { CtrlPoll(ctrl, in_buf); @@ -88,27 +108,36 @@ void Loop(Ctrl *ctrl, struct RecordBuffer *in_buf) TermBufToChars(&term, out, out_max); puts(out); - WindowsWait(0.5); + WindowsWait(1.0/30); } } int main() { - WindowsInit(); + #ifdef _WIN32 + if(!WindowsInit()) + exit(1); + #endif - Ctrl ctrl; - NEW_CTRL(ctrl, 13, 13); + struct bkt code_bkts[code_count]; + struct dict codes = { + .capacity = code_count, + .filled = 0, + .bkts = code_bkts + }; + struct bkt bind_bkts[code_count]; + struct dict binds = { + .capacity = code_count, + .filled = 0, + .bkts = bind_bkts + }; + struct Axis axes[code_count]; + Ctrl ctrl = NewCtrl(&codes, &binds, axes); for (size_t i = 0; i < code_count; i++) { - CtrlMap(&ctrl, key_binds[i], key_codes[i], KEY); + const struct CtrlBind *bind = &ctrl_binds[i]; + CtrlMap(&ctrl, bind->code, bind->bind, bind->type); } - for (size_t i = 0; i < 2; i++) { - CtrlMap(&ctrl, axis_codes[i], axis_binds[i], AXIS); - } - CtrlMap(&ctrl, 0, MOUSE, JOYSTICK); - CtrlMap(&ctrl, 0, 0, WINDOW); - - printf("set controls\n"); struct RecordBuffer in_buf = { .count = 0, @@ -117,7 +146,6 @@ int main() StartInput(&ctrl, &in_buf); Loop(&ctrl, &in_buf); - JoinInput(&ctrl); return 0; diff --git a/source/io/term.c b/source/term/term.c similarity index 83% rename from source/io/term.c rename to source/term/term.c index 2871b56..8ea2659 100644 --- a/source/io/term.c +++ b/source/term/term.c @@ -21,10 +21,13 @@ struct TermBuf { struct CharBlk4 *blks; }; -struct TermBuf NewTermBuf(size_t wid, size_t hgt) +struct TermBuf NewTermBuf(struct CharBlk4 *blks, size_t wid, size_t hgt) { + size_t area = wid * hgt; + memset(blks, 0, sizeof(struct CharBlk4) * area); + return (struct TermBuf) { - wid, hgt, wid * hgt + wid, hgt, area, blks }; } @@ -104,25 +107,4 @@ size_t TermBufToChars(struct TermBuf *term, char *buf, size_t max_chars) } buf[filled] = 0; return filled; -} - -/*int main() -{ - struct TermBuf term; - term.wid = 20; - term.hgt = 10; - term.area = 20 * 10; - struct CharBlk4 blks[term.area]; - memset(&blks, 0, sizeof(struct CharBlk4) * term.area); - term.blks = blks; - - size_t out_max = TermMaxChars(&term); - char out[out_max]; - memset(out, 0, out_max); - - TermBufToChars(&term, out, out_max); - - puts(out); - - return 0; -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/source/io/term.h b/source/term/term.h similarity index 84% rename from source/io/term.h rename to source/term/term.h index 8892b03..d8c9daa 100644 --- a/source/io/term.h +++ b/source/term/term.h @@ -22,7 +22,7 @@ struct TermBuf { struct CharBlk4 *blks; }; -struct TermBuf NewTermBuf(size_t wid, size_t hgt); +struct TermBuf NewTermBuf(struct CharBlk4 *blks, size_t wid, size_t hgt); size_t TermMaxChars(struct TermBuf *term); diff --git a/test.exe b/test.exe index 48bd297330a22c30d739e001620415a48ccf7342..ceedd7aa5f5fb214ba568488f621fafbed12a42f 100644 GIT binary patch delta 17227 zcmeHudw5gTw(nZ2Nna^6^krYrvo$)JSrRR*`+ON+ z$)@n5d6BK-yYn`75Pv=F0{<}ojdzCdX-GlZJdSg6YkU<^2L+Dfn%&tPcO~*5PrMU+ z^R-bNCpzQLkY0?#*nC=+w<~f-3-#;sipkFER(@GDq~qun9rew(v!_FoIvtRFIP?$i zkyK0OvHhX__yg>_&&_qO?*PPC<5q;rzsJTHrV9F@-scS?d3%G7BHV4M#5_euRUwIv=Sn2f zBs$&`tJXA8SJiWr^_+uo5OQkiFHLnpB6Z0c5I-f+vBpZHoif21uD;B}WF~>DebHil zvrepU(lx(00D!&6QL$>A#e^OjX(FYn+$OPVs!{P3>Gw5D?(?9pG3Ouz#6f>4jxp5d zoLYmijT0P=NO{e4xhH=pvbAO;DdKZ!HU5ZBd4A3{g*v;e^OdUK4^Z+$Z@q%6zu9| zLS$?I-RO>FO&!jz3`()z?DwY=$)ZTB*3=;QNzOI0R3*)*>N!f` zWJkTf7B1?cd2CGyK>A#nhk249R>i$ffLNt}bQ%cXh?!fd0}l*H^nSZ7bX@d)pCTWy z>7oxb_$4P7eE`)h1(55g&ynjc1doWgS~AbeQywM>3FL1!Ems)oC>UE_ufb?O|;7R5C4ZQg0IyLcVN>Ae-#l_wPr^`w(dB!uR)8G}RG-A8g_ z)o4M|YCS1yVYHFuB*dj;1)G>joyT%pDaI>V?Ae6G0?Cb(f%=O&suSnbERp}4G||<$ ztvte(;u@CQTK=}^q|^bM5{|^xAfvUSGY6T?MIlW_EJ_!ips6sGV`R4y9!XtC>8aAc zeMH$7iL1x9Rn6AjwufKn%}E@<^I6`Cq+xvO7qWWQBt`u-i6iv|?09l&>X)*@ z)PTav0fqjIPwChBqO1@ZPBIDq&4$p zQB5vqV>(~4Kha%_RzR+$O$JMAQ>qRt>MuO2RCr`Xsx#CYES-n?+T5R`_vik+x`ltj zSMeQEvTy=LQr{e#f$IPnY)3M-q1f0YbB$2>8vDbX98-2%&W$u9{SzBmPs`w#A9wiSNiv+f zkv(YX6>Ws%oO%lZLe;R-`9HBE3Fmv!P_WzTo-FAUFM zC%ZQZ`RVM9%7l1#YX?vG^W6x<0v$BEdb8)14UGQuzRNMa%B{UblKQEz?owM1`rx>4w@T+FV}t+JpuMJU}1^>-7$ z+K0zcFG{dJhaKwCg}=x?@6nY%#Q2^`{8pCIGu<@sLR%ZvhE=`hIrXrErRQLNHv7EiKz;~|?p0e7fy=#9Cy1MH_xYXf^n7Dm6RP(V z-GNc!S0+RFN)c=jZYaV)2%$8D)Ve`PSA--8BNZVELh&fpulIDJ^C;%%y^O!c+ImkC zsvYb>Yf1-OqBtzqSUyd3c6fx4)X>C9PW`>aCa~B0q~V@>s!tzdjN}yu$sagKoE^Sq z{re^|SHIAR7SS=r1mqBq!Tgi>dmCHTwlqR0o#=TsZg3V}1y>FpidVt6250hV?90L5c5n<* zi(sXypyyjQ0`bq@7SYK0)=b z6I7*tD4=|Z)n|3?PcoJvQhLrWZAO$(8WvE>lP&s>Gq|{eMGx!7cV|O}<^1KXm5Srv zo+ZbU4Ndi1o%&iRQO=PVGW}R!%(K!MnA{>kDA@57vJjH)_OO9<})3$esLkmNM#g{#7=A)ZM~eec7Q=ukyRtoa~`|IeQ^{ zi6HdxMveA`@HOnzm~q0wOcpz~SI=wG;f83Mv75rE{<&D3I7le*>xd_};Hy~4*cJBK z|A}+O)zBRfk!qpEQc=R!{bTQ34Y|EGRhStgfp zlV5J})0=+kxn0&b`R#F&WjV`FANSLZGG!KT94phkzJB7|bynR2JU--Fp?G5ah(Dk} zhb)t}Ji;$aL;boE2^zp2I~u>v8fou}4)TIa94DaRso+A;OlUf^nP_^n>1d&7IcQ;M zxT#b<2O)*Au@m65ALv zr(TAd#xmdSxWrECu5%6Iu$i=HeQLgQ`v2}N*VawTj=f8L> ztIkjBWVC5DJnZBA2cmkL$_Mu_^&i-GKwm4noImb=fd9$I|MPOtQ5AZP4=fQFU-*)} zB$49|)o>iqVR*t%g13Q|pfwQ=dJye<@I=p{wSsQ~tw_bju~(*-I&+*6JkdCOBb^G~ z1X_uf37+U>v@GyM%_fc;w-?`45wk9x%YeJ6bdNN>C@-P4L*m zxq*X`3GhVo(Zanlb%Qs8_kg~OOLr=G-w>?-aR^xu8bNLNV%Y|sXc}H3CV?mVGum|U zM6*Y5++6TP8?rHb@I*^TWA@<7K+mDA1y59GLw3L$K?jaO0N`z)7tnTl?J~0!XIw2h zh~|vL?7)3?D#fhRg&g z=eT&ZChx~{@8bt^cglAPeJ3OUjj~KMB0NMNewQwUhpM782>3+OVMX(1bzajcB!YjQ z6Rf1d$A+zm4KeTqoX#3jD3r05dFkwn1yQU=Nfi5ReiZ9G{}7w8AdyWjv7%Yn%94B7 zsK10WeaT4g7bR&SZ!>f(eiPfg+%xY_ORy9|Ks)K&z*0oz*TQ_apv6anQm1%5wmD_IIZrX0$ zZrh%}y>Pqt$yHDBe9Oz7Dh0m98}oRt7?A7@7lC=xH%=4y0p23rTK>(yUKiMamrSAm zfJti@D}1p_=oN}aV)Y>i*2k*fO2bcmh*|>K))y0mLRqyGs7Xd|z4$mT7&)Fa{UvD- zxX@?;resT9!L~@t`eM?H%U5Acrtk-xD;=LN5>n=!sP2?2!A`PKb+)ksV?CSJ{4S-9`Ck> z@*UWkm#3tcgj1cEIDzY1QM|kYfj5TAl@r1*&~aQcd(aopqP9h{i93g~f_K9Vh0s9& zTnOLFst+aM+nuXh&1~~Fi@^w6a*yPgeY4FX*bM96N$!(ZTyf8WMa5i+LGgBP(E@VD z9Sk6fe;b?firMcmn{Q%=U&%uTe%O`5D&LHVZ0BOqs}`Zjz_NFBVXjwoxfM~0eX{)+ z;xEIhNHGz>Jp<%Y2SrEm*d)b3Ga3X{A!x?gf{tg`wq~%I+bw*V6h!{Z;f9)aQGBr7 zBAB8PMY3HiT3SM$Dx(!IB-Oz0NaK6*oyAurTI%rOYaCkN{&s^>?z0dBRDQ0ILG+1%&{{M-|&3A z(`=v@ncx~q+-2ciY}79Ez_Yjr$+@B6qV+iJ@e`!Bc3qMVdD#V>&>$~T?Fv>rdfSs( z*|u=uth}&UuUQQFTA#*i82d*X4h8<<1&jO6;h5{SIKh@gRo1gB{5~D$sC)0ooN>-*z z$Q&RmG)OrGqCp-55{CPrnzr>o>NUtVAU8C~z9E1%;0h@ZyLZ82>0#Z|MM0D~HcBB< zwzpzLd{DM6Z210I)^B?lcBn7*n0X!JYs{>sE|Mi|i(&K#wP;h&Ed$S~ob!s}@74^ohAmTl(60fZALvx%40N(v@eDky}b=q?1)n8{2>>5 zEkdP*HaO<-hT~D)={4h9o}8U#*5bA3Z_@l(_5MV*he+F&LA;2DFjox-hyw1Vk% zX8g^?UmN2O+URiPeQa-?*^mmCay_I{J+Rg~9F914f+MlLZDA7+Ti8vcfA`xKLt(rA zn{QhLUpGp5r+H=N#W)W*UpId;SkB>CHvLfY`hz+2km<9?Um*Wq9m&hbV9&l|#tDv#lzs{17H}yMO8qvn-`+8=KWJfN-n9svj+MMiYvO!2&ycT)DvAB{ z?hqWleSGHhbN&1o2rPb?gkTo@2E?jkKb%gGX1L2|;n%W{e0c^>khS#sQG(GLNW-i3 z7DG!=H*QPpTD^r-lu|dcp+}@BR~@k!Jb`tMVw2xZ5(@RK;mCM{4QE^M(hhiUCT3Fg zo_Xkn0ZP1-$(gt|Y#kV!rKLb}1}Qp9W^C-A?@2!U9<}IqOKW>|_ifDjS~z>?sKwxF z=kA@O7Qr^yKdA`$8LkdzU%nsdP7dW0Sj$eGp{d=N^7rL2_2Z#uF<7w^1<#<{2U0if zwr?QBLwGk-&yd4FrVa^4J^_+~S3_0jUqBXWkT7icZ)=cbAoH_=NA(2qf(FS;02DP$ zQBpJ1_JNr##^duwLn-8@boa~WEs(NrM=SoQl!{!wQI>u_uXW} z#nR%~3cQnRoV^msJX^Z-p-%L1k83*XVPRtcQEJ%3rhH;%e`$aWOZkhu2qn-&MML^Nc#iQ zihsE9s@UlYomthN<*|oOmj>jbraX4XnbIKbmNQ~(BEG_r3WDo9x2U2Blam8jd{$(S zeijkg4*veE3tzP>4!i-LjQh@&vdr^JV6#6L*{cDm36kXtrEk`Gk!=k~=OLNCRQhIq zA+jw2=`5tU3rgR#FGaTAFL{~qVgyUNlH#9g<5#6PMdZken!K@Pe=@O&7ew~VMa5zR zq^PeIY5YZzJtaxi7Z)+*4f#%FEB;BE>%LpaS|yGae!xFP_E588p$5{;fYi5HWaXEXzTJ?TuP9Q_OCp>1 zy&~CP=)?hy1tP4B#u%e+;Fice^Ms($Bj}p>t~Y4`ste_MX=GW5kN?L`Hv#o*Q(h3=|`84 zuY^NS#`T{{Re&t~?dMW9;1@-|v{hs^0qHWNzP~DcCBKMlcR>0MQqSM0FXz{VY=^{= z|BJthtlKSROyO@L+ZK?%gp~2S(s%zYk$D2rIY?dpQ2M6-F0#!5=`^I|HtOsD$3nJA z;>g!0e~8Z|@XDC{Hu1R)0qMgw(H+Ap;&YRD(d|;jzwu&h)4yL8x5z`c5Z^e32k#8- z4|v`sv;^hSeMI0(RRqa&|22d!b=T?m7%?gTymj9|3U zOEF$L!1;@%`m@paX_mgi!q;Bz8KFGxnC_LKe4akjh8kt{2ht4rK^x}}Es1VJ7;lgD z_(3`mIBo)7K3d!_hGBTVyFQGcVb7xB=#l$BL;rIB%w^;<5K9z;cy{Sk;6c;5Tfet3hCg3mkR%+cwFN- z`$Sy(SHOBTmjDd#YOnmQWG$}PE6Ni z<8>f((^A8G2ME523i8tk#H1;m3qY(Iogan(a%oZ)jcdD0<18JBRiiV^ont^+<^5Sn z>o};1C?++g0wDRwmt0|G%PN+_Iai{YTN!j(0`sT-jpPn-%ZXl8R9d=Z4i-ZSiF_4| zz3ZNW$@murw`Wi?+bkyhPM<6cB8S*d94q3*vpVOG`3d9o# zsA%>Q)B=8{)0EzL($P380@4ITE?5k}|KUREX&$1NfXD%v$^AW~h0k&{dDz{OjKmV+ z9@UXgvG2hc`lvg_Q6S4T(R@TYnjNPN$XU&-;&7T2LQP%M{y;J{a~KK4B#kopvop~S zs3njLjOS(msnJYy0T8_T1g!=A!#IzoII4kYEBXKs6F@bfkAPTkM9FJ9M|yg(P??&D zXw@q*M$L01km;IyWB|$1%&Z>}3R*3f5kNd}FC!Dd(PsymYI%MfH;ALRVs%&r4MUu& z(t031n8r%`lUC=BF!J5)^b4{Iegd_^z{6QEXUU>POXe0gVUSwpUqi>HshAcZCQaPG z6JiUtY=}pInjq7FWR8PrHSXI188xO0fY3+Pc?5`06ZBK=8%7*78_`jV8LO(V1F>MR zx_Ivc(HC#(>V! z1@jjdm12|9I4gpVRf9YT#D}b?me;y*wT!o$G-`i^+73-jdw?w0AV+~{*X8d(DiM;J zql-W|&1?ny^3z%sRO@M5g8oUa`q>1`h(g{>InNC76Bx(w-FOcaPJEN&!kREk! zy9>zL5FAgc`*J{{6r;&Mk4hju%>umyWQPWMlMv0!P69a_2zpWRBI&yiqh{0@=qyJ} zcGbNOzZy{*)m4lI0y{xbX96(+Q4gA-Kx#Cj@_=ZsI8%Yp^$kh#Ps|QvEd{OKexGqW z;`qV#7tmwW#6HTKIuS~SUQ15&F=R7dKlfYU738&6EKDuhel1Q#scxcrJAO6LIN|Li9Wiq zahuR6Hd5rcAyA?^QDe^o(yE#9Ody*yNGX}t+=;4z6l$j71tNdnWAgiYC&hg}fzPo2 z9X%zQlm03YBcf1C=2sxLz;-c#LdB;LO^rP|6-%k{nE|9$6X^gTR*X{9l0B1#0aEwN zdx3na*;AebvIApOXIp@@2EI_laBe3MQy@e_eC{*1VUe$)qcM>9c@LK_s3=D40fbar zq0^*^J*G3BEzKgEfLJw)+z&{LW`4Oq=%ZHJ19m|9nup=R|DyCbkhL0TZXm6is@nxb z`66E~mIFWHJRjaT8x~;Nx`utUh86uB*7VE?ex*@57ti$GY>g4)n|9O~QehJ^5vPa9 delta 16987 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 V9V2O+tj63fyU@kmHdc80e*v3r6uSTb