From d323bb28fc602b3a699bc3c195e835f36b53a282 Mon Sep 17 00:00:00 2001 From: MaddoScientisto Date: Thu, 9 Apr 2026 00:32:12 +0200 Subject: [PATCH] more work done --- .../idata/01/~00000015.db/change.data.gbf | Bin 147456 -> 147456 bytes .../idata/01/~00000015.db/change.map.gbf | Bin 32768 -> 32768 bytes .../01/~00000015.db/{db.85.gbf => db.95.gbf} | Bin 24461312 -> 24461312 bytes .../01/~00000015.db/{db.86.gbf => db.96.gbf} | Bin 24461312 -> 24461312 bytes Crusader.rep/projectState | 2 + .../00/~00000008.db/{db.52.gbf => db.54.gbf} | Bin 81920 -> 81920 bytes .../00/~0000000d.db/{db.5.gbf => db.7.gbf} | Bin 163840 -> 163840 bytes docs/entity-dispatch-entry-class-layout.md | 20 ++++++- ...entity-vm-runtime-owner-resource-layout.md | 27 +++++---- docs/presentation-callback-broker-layout.md | 20 +++++++ docs/remorse-class-candidate-inventory.md | 52 ++++++++++++++++++ docs/remorse-class-lift-index.md | 43 +++++++++++++++ docs/sprite-node-class-layout.md | 51 +++++++++++++++-- docs/usecode-debugger-break-state-layout.md | 7 ++- plan-mid.md | 14 ++++- scripts/_tmp_apply_broker_slot08.py | 14 +++++ scripts/_tmp_apply_cache_backend_methods.py | 38 +++++++++++++ scripts/_tmp_apply_cache_backend_setter.py | 20 +++++++ .../_tmp_apply_owner_resource_accessors.py | 39 +++++++++++++ ..._tmp_apply_presentation_callback_broker.py | 39 +++++++++++++ .../_tmp_apply_vm_class_types.py | 0 .../_tmp_changer_ir_dump.py | 0 scripts/_tmp_comment_broker_slot0c_callers.py | 21 +++++++ .../_tmp_comment_watch_controller_mapping.py | 22 ++++++++ ...mp_create_entity_vm_slot_entry_datatype.py | 0 scripts/_tmp_create_sprite_node_datatypes.py | 32 +++++++++++ ..._tmp_decompile_entity_dispatch_periodic.py | 8 +++ ...compile_entity_dispatch_periodic_extras.py | 9 +++ .../_tmp_disasm_entity_dispatch_word_list.py | 22 ++++++++ .../_tmp_entity_vm_context_this_type.py | 0 .../_tmp_find_text_section.py | 0 .../_tmp_fix_entity_vm_runtime_create.py | 0 ..._tmp_fix_entity_vm_runtime_create_typed.py | 0 .../_tmp_fix_probably_some_alloc_1000_42e2.py | 0 ..._inspect_entity_vm_runtime_create_frame.py | 0 .../_tmp_inspect_psx_banks.js | 0 .../_tmp_map248_observers.js | 0 .../_tmp_parse_combat_dat.py | 0 scripts/_tmp_probe_broker_slot08.py | 11 ++++ scripts/_tmp_probe_cache_backend_object.py | 9 +++ .../_tmp_probe_cache_backend_object_callee.py | 23 ++++++++ ...tmp_probe_cache_backend_object_reanchor.py | 9 +++ .../_tmp_probe_debugger_formatter_helpers.py | 9 +++ .../_tmp_probe_entity_dispatch_entry_live.py | 30 ++++++++++ ...mp_probe_entity_dispatch_word_list_head.py | 9 +++ ...robe_entity_dispatch_word_list_reanchor.py | 9 +++ scripts/_tmp_probe_owner_resource_live.py | 38 +++++++++++++ .../_tmp_probe_psx_section16.js | 0 .../_tmp_probe_sections.js | 0 ..._probe_sprite_get_or_traverse_candidate.py | 9 +++ .../_tmp_probe_sprite_get_or_traverse_lead.py | 9 +++ scripts/_tmp_probe_sprite_node_followups.py | 9 +++ scripts/_tmp_probe_sprite_node_live.py | 9 +++ scripts/_tmp_probe_sprite_node_reanchor.py | 9 +++ scripts/_tmp_probe_tier2_candidates.py | 11 ++++ .../_tmp_psx_gpu_search.py | 0 .../_tmp_psx_mode1_live_row0_batch.py | 0 .../_tmp_rebind_entity_vm_runtime_create.py | 0 .../_tmp_scene_link_scan.ps1 | 0 .../_tmp_scummvm_attack_process.cpp | 0 .../_tmp_scummvm_combat_dat.h | 0 .../_tmp_spawner_compare.js | 0 .../_tmp_spawner_truth_pass.js | 0 _tmp_targets.py => scripts/_tmp_targets.py | 0 scripts/_tmp_update_sprite_create_comment.py | 15 +++++ .../_tmp_update_sprite_dispatch_comment.py | 15 +++++ .../_tmp_valuebox_cache_scan.py | 0 .../_tmp_valuebox_cache_scan_output.txt | 0 68 files changed, 714 insertions(+), 19 deletions(-) rename Crusader.rep/idata/01/~00000015.db/{db.85.gbf => db.95.gbf} (98%) rename Crusader.rep/idata/01/~00000015.db/{db.86.gbf => db.96.gbf} (99%) rename Crusader.rep/user/00/~00000008.db/{db.52.gbf => db.54.gbf} (99%) rename Crusader.rep/user/00/~0000000d.db/{db.5.gbf => db.7.gbf} (99%) create mode 100644 scripts/_tmp_apply_broker_slot08.py create mode 100644 scripts/_tmp_apply_cache_backend_methods.py create mode 100644 scripts/_tmp_apply_cache_backend_setter.py create mode 100644 scripts/_tmp_apply_owner_resource_accessors.py create mode 100644 scripts/_tmp_apply_presentation_callback_broker.py rename _tmp_apply_vm_class_types.py => scripts/_tmp_apply_vm_class_types.py (100%) rename _tmp_changer_ir_dump.py => scripts/_tmp_changer_ir_dump.py (100%) create mode 100644 scripts/_tmp_comment_broker_slot0c_callers.py create mode 100644 scripts/_tmp_comment_watch_controller_mapping.py rename _tmp_create_entity_vm_slot_entry_datatype.py => scripts/_tmp_create_entity_vm_slot_entry_datatype.py (100%) create mode 100644 scripts/_tmp_create_sprite_node_datatypes.py create mode 100644 scripts/_tmp_decompile_entity_dispatch_periodic.py create mode 100644 scripts/_tmp_decompile_entity_dispatch_periodic_extras.py create mode 100644 scripts/_tmp_disasm_entity_dispatch_word_list.py rename _tmp_entity_vm_context_this_type.py => scripts/_tmp_entity_vm_context_this_type.py (100%) rename _tmp_find_text_section.py => scripts/_tmp_find_text_section.py (100%) rename _tmp_fix_entity_vm_runtime_create.py => scripts/_tmp_fix_entity_vm_runtime_create.py (100%) rename _tmp_fix_entity_vm_runtime_create_typed.py => scripts/_tmp_fix_entity_vm_runtime_create_typed.py (100%) rename _tmp_fix_probably_some_alloc_1000_42e2.py => scripts/_tmp_fix_probably_some_alloc_1000_42e2.py (100%) rename _tmp_inspect_entity_vm_runtime_create_frame.py => scripts/_tmp_inspect_entity_vm_runtime_create_frame.py (100%) rename _tmp_inspect_psx_banks.js => scripts/_tmp_inspect_psx_banks.js (100%) rename _tmp_map248_observers.js => scripts/_tmp_map248_observers.js (100%) rename _tmp_parse_combat_dat.py => scripts/_tmp_parse_combat_dat.py (100%) create mode 100644 scripts/_tmp_probe_broker_slot08.py create mode 100644 scripts/_tmp_probe_cache_backend_object.py create mode 100644 scripts/_tmp_probe_cache_backend_object_callee.py create mode 100644 scripts/_tmp_probe_cache_backend_object_reanchor.py create mode 100644 scripts/_tmp_probe_debugger_formatter_helpers.py create mode 100644 scripts/_tmp_probe_entity_dispatch_entry_live.py create mode 100644 scripts/_tmp_probe_entity_dispatch_word_list_head.py create mode 100644 scripts/_tmp_probe_entity_dispatch_word_list_reanchor.py create mode 100644 scripts/_tmp_probe_owner_resource_live.py rename _tmp_probe_psx_section16.js => scripts/_tmp_probe_psx_section16.js (100%) rename _tmp_probe_sections.js => scripts/_tmp_probe_sections.js (100%) create mode 100644 scripts/_tmp_probe_sprite_get_or_traverse_candidate.py create mode 100644 scripts/_tmp_probe_sprite_get_or_traverse_lead.py create mode 100644 scripts/_tmp_probe_sprite_node_followups.py create mode 100644 scripts/_tmp_probe_sprite_node_live.py create mode 100644 scripts/_tmp_probe_sprite_node_reanchor.py create mode 100644 scripts/_tmp_probe_tier2_candidates.py rename _tmp_psx_gpu_search.py => scripts/_tmp_psx_gpu_search.py (100%) rename _tmp_psx_mode1_live_row0_batch.py => scripts/_tmp_psx_mode1_live_row0_batch.py (100%) rename _tmp_rebind_entity_vm_runtime_create.py => scripts/_tmp_rebind_entity_vm_runtime_create.py (100%) rename _tmp_scene_link_scan.ps1 => scripts/_tmp_scene_link_scan.ps1 (100%) rename _tmp_scummvm_attack_process.cpp => scripts/_tmp_scummvm_attack_process.cpp (100%) rename _tmp_scummvm_combat_dat.h => scripts/_tmp_scummvm_combat_dat.h (100%) rename _tmp_spawner_compare.js => scripts/_tmp_spawner_compare.js (100%) rename _tmp_spawner_truth_pass.js => scripts/_tmp_spawner_truth_pass.js (100%) rename _tmp_targets.py => scripts/_tmp_targets.py (100%) create mode 100644 scripts/_tmp_update_sprite_create_comment.py create mode 100644 scripts/_tmp_update_sprite_dispatch_comment.py rename _tmp_valuebox_cache_scan.py => scripts/_tmp_valuebox_cache_scan.py (100%) rename _tmp_valuebox_cache_scan_output.txt => scripts/_tmp_valuebox_cache_scan_output.txt (100%) diff --git a/Crusader.rep/idata/01/~00000015.db/change.data.gbf b/Crusader.rep/idata/01/~00000015.db/change.data.gbf index b761a34189d3de7b95265f080ded974c357d2387..cd9f537a1d2d4bd86914f443bc0c2b74478bee83 100644 GIT binary patch literal 147456 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 diff --git a/Crusader.rep/idata/01/~00000015.db/change.map.gbf b/Crusader.rep/idata/01/~00000015.db/change.map.gbf index 773701a1b2e4a609f5d91b2aa785e79bb77c9b6c..af7724f2bdb6c2967d86b077542a27d2f50a3296 100644 GIT binary patch delta 100 zcmV-q0Gt1SfC7Mk0uV1SF)TDGEGpVy0e232-UX2mA_PY=F|Ls|RRmM$x^=OS@ zzV`Aewi6K#J61p}uf7%#^;Ja0-sS)O&g@(gUVWeU_q_jkGT-cHXLfe_?9T4&_4d9o zxED6A&{mXJnv<8CIrYeC7i3TTMAI}~)2cMD-uvYj6Wm*4>VqB(s|sz>D>m)DEp=1T z?P+2waZ~&4`%I(YyW+tU?#K_&FWJ<2SE*jV=?sk3=?PF5{^fjAqeZ1Y&t7#!?HpTBeRX_UR@|~BQ7u4py@RoJQCg`vMuz|2auqN1G z*bvxI*f7{Zu!CWTzz&5S1{)3=0UHS$1se?;0~-rF9Cie39Be#n0&F5|5^OST3T!H@ z8P)=u2Ad9>0c(ZLgw2A@hRuP^g&hf-2b&LD;665?aF9OTJ*cYiYS-_Y8L5xj8$49g zDxX#`9B{pYbii^21%PP^7HHb&3I*2zGztGekXpq;0|EwVTKN$L!vNbP9MCiuD9oV1 zH#M#7Jqe#Ogt9UNOlvi*^q_>JbSWJz;U_}Ll>(xzSQ1G&Z3IXX7stEaKNjQm+w@*T~fNTj12_szw1Wg1u07!rI z!k}588HQ8XGQe;NwLB=d)qudInwI^A0YPn=mi2=Hrd~jug4;AL^F{;0=4+ZY-hd$w zXj=My1ERjvw6x!h2rc1>(&kF14ua(_1(N}nNmxY}^C1bn0xBh3L`XFXVgn)NQ|Yo< zzyt**xEL9{Sw0>2OM}^Fv(;6W+8hpZ-D-1()6wa0u5dJ%+Z!7@9bM)I zM@yI8+~{m?HMcacaF~lq%59al(sIWbv(wQC-%A{w=7wfx*J^WTm%YnjUb)24W^Qvh z8XOII@KWF2+R@zwKlb|i?$+)Wcxf=#wRg8QbmmRQft?-pu6l;iwZviW?r2~T*tI0j zY;SAe&NlN(d&@HEUcaQdr6IqixosH&>FloSayr~|&MAy>>Bat(l-TQv|8FTNFi$a} zal#5mTbH@j-qC4xh|T);21Ko>u(+_au%ghms>lW@rj$~OY&LUyTUWcwyrRoq*WxgD zwzPM3nn&7J*-8tk6+-K&IFu^(7m58vVt;Yz7?E}cDN=5>w{*4}i53Yqw~1IVKL+HN zv%R}%iJ4x?kQ+ENPh3)Ju5&cDJ00fsj;`kRHhYV?)6vqHuiT63%}Wpx^03JhnLSgF zaV?+Z=c5&(kN29&Fr3+cw*45nR zXpzCRx3$Qa$wV$-H`_ZpTACf51;_e~`<$YtP}lu^^|!=c z{(q~#V{jU$(L#7`qdE3Zxr|sVGp+>ryu#knjFyJ#VP4{B>2Nr6WkQ%qs6)l02ejzs zPGn^ls-@FmZ&>XKA5*KxVHnVQ`^CA!_J57Dzr>u~MyDZqk($O9dlPyKQJE1Dqh2C| zm#`|zKBmYVgsNHMUS8A`<2uwAjpFkE)QO?s+yAW-L;LP>cGq{cJM%lcR-*~C^Fdi7 z0_fbZ+vu8XtIBLec2tH=htb&cP-`4^XM?OZO)c$psF02A_1&EVD_PePk%1_e_LZoi z&0VamIFc z4rhLgXo~Zv6*l2a=JvX!h)}25iEx$Fgk`h4Jsl_y>+gbhj<$70nHf_QKB9on4MrQPbN3x;s2yztW~Bxz9MO z@E+Iq|3g+7$@}x1C`CbEkgdGDr7Iqx$c-RTvTY9P*1NGaygL|v4 zvwGjSwd$8xi&G5~yoSUrUdwUZux{6mD%gpzlVB&qPJulEb}H9A+Oo(a1Mb}?)XY%Q!Ewhp!)mT_`; zckO7LHbtL&^`NGCE|a(ljqKHM!!zb11sMRh0^Em<;oSu;ZF{v7aL3kZK-e7Iq{(aA z$lkDv0rL7ivUjir5MX#4@)&O4TPXMi4#8@mt#0?{DpT_VAEL%-tyF@%adI1|4Favw6Ek{+NjDpdubW&3~<9#!wb-^)ioFlx}5DC zTWjjY7|KB&<71<}wHc#BTl-23R(4#Y7z1X#z188g=XW^U>m8lwUBxk?8?F==1vT=j zfJ2({BL_@g9r!PXjEf!7Hx}157~N|r5 z(qJ}nY@h<~s)^ZRK!n$C4 zVb{Q(2fG&beAo+MFN9qOdlBr#u$RDI3VRvs<*--4u7}+KdnN2f*iEok!Cnn}4Xhh> zGwijn*TG&7djsqi*c)Lzuv=kog1s5`Z?Lz(-U@pg?Cr33z}^Xa7wp}z_rTr@`*+y; zVDE?B2KxZ)gRl?5J`DQ^tQYoC*zK^7!R~;49Cjz{6R@%>>!afK4 zJnU}oW#_(d?i&5MhX=oC3U;BOwHy;9`)kTOl&2_nQFxu2J&%I%K+F1qf|*J!i?t?; zU3Au+6wH5WS(j3JD6N#ml-U#vELs*iH7yHOQOgQ~WMW{|GT-5dlKB!hAE)q~nVTt? z+tM;wcQR`!Gbxo629t^Et!3&ED<<+Z>pv;%tgR1IZl<7j)vSz+wVA^DZ=FoBQIaW` zn$=txKSDDwTxuEnC{IxCrZ65E7f_s(8p;d`larB2L7US=!$@b&q%-r0ywxA1H??95m8)QnpgoQW_~3+qASiN;t&w4do3A3&O(o zZaJ4?r%a(Rw=7JjnGrNIWb=cRYbdKZ2W>u+n-eH$6xM~*Pbn;yR19XE+k|vcFjQ)( zEQnNQVJfVa!bqn)M`2w^xs1|IIfYV2iGw8nN_n61B;^*0V;yxVg=L(~(n)5vCNV#F ziKHblGm|z^SP)5bDD;=aTu5XMNPLBI4~3O5k>MpWw-Q-x6GOa5Ltjjd@>&yLj2#x? z=)h3d-Nxj=Wc=YR&3W<6u}b9spe~2!e7;YE^(dNh($F zFd#<3BS`Rf3cLUr9QL4=B>F?!4)7=FF-$A}qK?@CKuzZPVbCrUwu&tXDrG{g0<@F_ z))--YfB*%%G%fyF1t{zITNOM7V3QK&X@En)Gk_BmJPUAH6`^Xyn-n~cN$-yp>;}NE zG%o;dRq!I<0tKkZajZ4MybOp`@QS95_@{zb0Z6dnhyYHD>wi+S;0X-qJj@`De*Y~=Z8Vtj@}`*ARhrPRe(Z>K10DL zfRPIRg=Y-EDnL&X^^$_m0M{!x3|OY%bHEq{M*xH6`LXK@+;sd?Iia;j-mTy(fImx) z0@&n*`5M4JM;J7&2*gR6Zvj39XeSYF1>XbM%?k4a(jQT#=tn#aftBVb0Q)Xseg>>i z@C#sp0^~q=xq{yS!xj9F$0yJV?2b zaxtZgQbS=UXJK(#c&vq0$ov%rC)Ui&1#JSeM;0Y$DIQ7)t` zq*PLvtK)y5Fhj?)T*hBbIh%4CWi%xoGVW)}+m!8;YbmQKr%^^z;vr*yrnugwZl_#J zSxq^OGMW+(8S^vcZOV4awUpJA1(ea01V||kEOp+KAWt3V9TZL^Hr0_EegDPa)3fEFlelD$$8B%D16da;3{sn)hTti`PFF1|D0xZa; zL_+d0>S_7(oWGvZNMRx7Gx~WyP*_>>SO$3vDvxE5w~)d*lQ$eP()AIQ**fxO%0-l= zlrl)}uasvftP8ozDT^p*E?RCDg^|hmn6iiR2!*vGhkbU=bV?c|n;Dh;A>|$l3n#mo z^)LHmZVEpk*vew{%zA;cjdB5H7Nvy33X#dQ%l?{SWnN5KMwv=s24sdothi>-tjq=L z;}n*QmHy=IVkNdlT2sleTE@GSCnzlKj9!YJGM*}>)ruwv50JUP?$y=`)1ob zN(Ci}0;?5%MA=PY#uaX$bWs+vBnroJ(@Y716nsi~nQ}knD#|JfQ&mt!$)JQn^1r6M zLD^2(LSZ52J1C-Na)8NaeaT}B%zK-%lX4TpmB*6KYo^Sk6j5R!BY&p6M|qNRD}`k~ zvXwH2!rD4A9+LYz<0^%CV#3Zs?1k#Y`&3CZT^vL{eRQbtfrkSvyS);p9JC}^bayDr%Kw(B}j z#ySc+!i>`?6DfHV9-k2iNk2+qJxOQzq%#8Pw@@}w&Z8`+)KX?sSc%gaN_ql?WroRa z2=glKMaq4w1ZgbhwAGY4%E^>c3ae2XD~9EB$}1FhR2DadiMG^GW>Cr~Y}A%;i1}v< z`#1BelZ?5L%7)mB35|YYZDD@M{e#%bD?G%=4YA1yyl{(4oTemmO z^(3}a?x3*SOX;PsG~|2*^C2ad!VWMc0FwMAWeUp5^WX?XQgw=;?4rbi7s&(9`O*b-eb@ z9{mW8+kbnQ=Yfke^-i~WP}LxB;q?7?q_~eY?YFt#TC)FF?+?xUtwX$7EB3GGb{`o1 z`4IQZzrUL0-TV3e%GdeGaM$bCTfOCTb*~qSFbO|>6^U=etdng z9?-MIZTtE48v}Zlxp)2i`mBJSrfYto$3}O=FRxz_(Bp7#5WIBV)?Z$SeFOGQ*tcN+ z0sA)WJFx%sZvExm<_q+--a)KKk1% z+s&bY=kR>`OyA&LL-b37w`E+H;jX>=gOD&bLIxM>1>PPUW<)k9`jH1d$Ql%8Bt9s{ zYkvHL!+`?=@Ya6*!H6LL5i#D5uReHQ_a74LwSE1;2cdfOg};38$S(&5P1S!yy*PM5 zgm-WC!5fDJ^qkRRq-^VZfLv}L*uh^V1)UV%QA9T$xS zZ85J`Yyvg_&QO3ZF|S+!`nWu{OBxIMn~_K4wq`-sG4go@R|7UHKua9SHb`S}qnjC7 zDM7Qq&&XH>*P>Hq-$r9WJIsAaZj0&9+}jk~02fvGmMwrYmCKEQQ3^bOC&iNwq`-ZGG7trr;``No|1;M%$Z$sTeF~t&YZ0Pr_W@UNn_aoFv)Gr@;JJ@ z0}9YFTj45<c@}_* zC*e6jn*!9njA;r`z8M(`UcjJt%m9}K!*PC=Z6 zv0&^@K`oT<6~L|FD8Q-UYrsqeE;NUfY(N}z)8Ft{UIgt2@NKtqs#j7q*r!H8c36mB8K;@8t#3VkbAP9h7Ub>h7&9eR>1Y~I96y+2GNL3Ju>3+mrn6xke>ZgQ3 zfcq5;23)FO2%u5HP{2e5!vIMN!a4Vk>=Py}0)#dqArf$}f+)a63Zen^3St1`6~qGK z6%5DRKMGKov=M+k3Q#ZO?otqs{P#aSNJ{|JDyKxi7zK!P9D)=k4dpljl}JJgV5b7) z+K9~x%z#b>7Qie8D7X>GBN|Mpp;Gp?VlI*G5!iv26#{TD+k=EU=(15f(n4YTt@>?AB0J(#3O=T z3Xp}-XDb*Bs8TQvkcj*jCJn_H^@D;5fPD(80QV@s8Kc@1OakC!!m!VbLKTpJx*Ykv zf)fCbDL@uRo}=JIq(5?@qLbi+!Vrc}U?cn?ph-tOr(8}3T%}+Jz+W9vz!4}JVbW#; zhAF7VQ-Lr00XEIBksG{`8xG!|E=|PHU_H?ERN>Si?)$Gg80#MY;K3oD z>Tf&rkP*@;c+=*i@D~sgB>ZdVx%asbrmVBwd(dmU_rte0>YH(0d#E|oz4oL-F7q3| zPP0XR8i3-WF@?T4`t=vEVVn#PMFXZC+7=Xk!;Zg4Z{;!(n&8L156nDtFd+QSbK9e9 zO}%2L7JRjPWA&kl;R&Z~#110>tLA;J`p_Cv_>J3~k)N7wl3s^}dQVw!=#(Mehw2X9 z7`$#{^C8%eU_XZa1omIBpTd6T-Pn9MWv+YIk*Z<5NlA4d82kAcVuJfX?n?>o+Lil; zx~u;9GQqv!*H31y+qLtsch}C(r=6$wB9TX~)l*9rrAHo!i;?FIIyS$g>2TzMm|qS4 z(R=g6BWnV~AFI1R@<0M=J>T8F&O5R%{MJ8qVTY0OS@XS<<{x=7$Qyn7k=}stP3tU?pXz@z4hZ&c zJoCtMJ^Z90XUd1o+&^o9H(>FRaS7{YuQ~$zg?ILI zSf$`Rz(NIU0Tl|)2gE730Q1^EDYy{ul7e-Bixpf1Xa+F-nuguurim@cC4k`yFszJK zJ%e@`;7#RnIY6~U?FvAba#;_Ur(grXC|ymv5_9C=Di>tMF+&lRArF27#^2Jv#_zchabbSOZY%S#9%|8YQ>zgV^b;8&Ul z04Q5&9t5;0cnDCY;9)?lf=BQi;ClsLfIqZH0ZWw2c0ig@|1=FlM9CY9=73{;z@KFV? z0d^_a57?mKbwI5GWNx8N!J7cN&GLT>bH@l@ntuScDtH^vq2L`rm4bf)A{4xf`D8>x z8Wci4T7@+41C}fJ05DO(0YIecf3$;`%Yc;zO*(Izfsqk-7quPwqYiUjS}W@Fifmg0BEo3XTH86?~0p2_#;c zZvbeE(x9Q`T%h1PmphJphoTTmmr@@tcAmz`F`efX5XC18z_d z0_Xt@<_###_Alfo*;jwM*HRU=l$VChp$haE3Z zxm21a_zv%RRY&&)sWZvF+8ypwPB{8?_>RBd-S2{Cp?lKQqx-_s_K8I&(&wyG-BBkV zomg0Z5~`zyET@@qZj|d@cAF?RnvCC~diSCO_w(;w=ZQxxq2aeI{63~CV3qKMOJVQE z*+(NR-hkyt|Coh}q6I$1Dlr@vNv|*(GPJ}PT<3HcK_$lGTI6E|@Hzf;1tV}-u}481 zpjtsZE)jMpNC0FgNW^IGkl@l1lQ53&RZhu(MG8_dB)_O26);_a8Ds4y3M_#06r^Dc zJ)$5T(54^*gX2*JR=`?-=qD00K_SX13!~np3bFy=3UV;EZSofCo107Om}M}dU=gq| zY`igIxpIwI*^8wBTnAQMiv3d-pei*sV;R}NCC*)TCzkKZ1-@+#wb;1@wYtD_@QzMB zwh1jyOYCG!P;HY!EDBembTEb>%ZzjLkn|9CD} zO22cVO$#HcgIF`mmFI1aRb4fWc4tSI6RwLVi;n};FR?dcg{85|yTjh>^e+cBR;pud zBiGsb)9Gl)$0`xAqS9Cm-C1Dn@f<=kh@Q>Di#K9YhVAJh9-7vI|HH7B)6q~;<|A(u$rMPs`Q6s+UP*ci^Jr$!3mOeW=unI`T*!biF7FZj{z!k@s@qGhkTdT)* zXQ!U*itKl$N&U_gH}Fj2t!;EkrN!`b>M8P_Eh9wX#uc%J;{3?AhQ7k$3M3;!D7ZGG zfa)xc)x^J^*hNRE=aHG!qVP0>}{GWmtG^=>e`)H^MraJR;<@yZ8g_Y ziQutQEz57J!Gdix!5Z~V2QKMyt~M(48CZs2YSS0>i^s5j@kqc`63rUeSbhj&b%&#d zpIvCNudXSw*OWBE;llZCSk>Cz!u8Cp%?%ALT)5oC6dKFK?e)%fT*s&ga0L^-xUj;G zmtNYsu!eh?1GNHcs9JKG>zljGEV~x2AQr3O3)NETPJGg!%ZxQ=U081I$-kvjA2Ado zn>JL%*Yoz}o%%I;nWy85PW>wUH?8l~&o!~oB0M*4=+sj^w_{HeT*5(@;Qw{}FMJFV zKFpqJS9a<(=YM_vH|KwQ{&(kpfBp~W|M<{PVZHi^cnbYfO<|b4e9&gi_w3r3qL1*d zzVD~i!RrDZ`3d%C*k53O^#(lh+pL+cbvQE(C-q9%f6+wXYPOpfU&OdH3hkV2LQbI(;`NK zE>}*tPbplYpa8%N9GVE+Sr!@_Fz&rz75z|1(SYaYCq>UV;;AGr(eym^yV3&fK0Dtk%0<2IjvjKAy zR0B|&!bD(iZis?YaOv|Qfq5A*7qnA3A!a$770d^8Dp&x($%KhO-sGsOr-+3Be*-%W zx2hi~Zz!JZ#}u3axLU!PfDScF6oD!tUQ?uN#9{z@Et-fLfWOk!;_mcau^%pWfLB2s zV55S1K&yfV0J2<|2#mj3XjT%MG|l^b$nTC+_rLb<9p+t-_51vxw&+vj2SJR{X|5P= z;lJQub0Fpj=F;rJz=7V-hKWkjj5i_EEM|uA`jIJgr0_Xq6Qdmig%S zDSxNHkvCBgGpf6y~>l4S6)Tk|0IDQw~v{r_f)~CJIknG?S7= z35M9dpfD@M#GZ}$ZM%@tM43w&#WrOd!A<6EA%iYt*2ot^ujCe6Yax?eSVc*N6#PPY zi}EmK1Eqt)7FRHa5)aA$jPeYHS)I?b=kx6Otm64>k@@09SJC6;G3|LwQ{EMnc1ks+ zh{F6H`7PxQ$~Fr9iHWq4Jm*My$z>XHAEVqvVOHm!MxmG71V|41*BsWwoEusHGe9mxWxCAtESGF7rR%9|9%BXuK%WtYnOlFE3b zvH(+~y-64RaV*~Rt8nwB-xDuS(z^n^Ww-yaJtQK;xB-T5nBc2DU%xp? zw|XP)`{Q|iMg*7Y_wOyGuaE}(52YJt_~bql`=My=o7%j}(QpEgn;17C|VP7&<=`LRFV3^0$F+T7MKzm4}7O^yb7nzVXaLy=8-8y4zW zb8D3zx9+2ze|SIIdCVH1@4%ap$BqWGaAA6;pa9v2(e#`Em@l`r9#pTiOa-XCmR}U0 ziSkt_VS1(kSkq~GP;?g7O`4vQ0j$R~Ju?8TRx~{`QMtwYy@Jp)m|3|5pt72s3ed#O zlNF$#&BGO(g7Q9~03BB9RSGZ!r6RV%^dK=QhZQUU+^4{GDu~U4rU&&i#Vj@f=n|4y z-DrAF2V5(+wVpEoZ0_fi61H_ z_(?olL4Ch>YU&r$;L;eCW&u(!FAw)X6%Wo4w=SNW+QJJ zTO6y5{2Ns|nlb+K?yFxYZ&V*MvzkOz2edGl!hyjQm)A3x8SVCd9pF@a)N`i2t+^2& zlfxkcLc7z9Jux=@Y6g}gaYd#z;O0g-(Z9@gW-&v z-?nT%I^xFW7Dr8y46jr~tS=}>-%^`?5!zo}#ekyF$uOYAfvLl{aTqDj+?Z}X+ST^= zTk~W&$dZVfY{v&iC*doOn7^7WzW#3 zuC{eYE|9*5JaAl0>hV!i_#QBekMR1%WZjWYd93L+9-H7lldTLNFT=6^nd9S+JJUFB zS}zZb>vtf&>WBmT2I2vy8!QhCYCG;Id>htt?AvHPZfe`Q&$st4i9vm{&Bw*z^X(!q zytTx@#>*(!Q39o9^`13J-Fj>#K1SMV@50PwXT7tzgU{qJGle$Ri3zQNpL_ak}W1Mhl|8thu8+p!C9IcoqZ9uBmn6Za%sWE`8zPu|gso?of5Z~J4fy|G|_oMZ^14+Yhuy)I-G8Fv?LrLf#jUq?AtX?j76AhQ|YSCNj0B?5DSs!;b)<32YBYC(Z~*jAC*C z6mc0Xhp_$+nU9M?+%NLbxN{kW37)a{SL>-Rqqd69${`<5V;DaLZE=aCp<7%__fJRM zK_ieD22!Zf!BLFU+LJIP&V39OH9&r!bb>MrDy6WM~DRi4Rum zBSg>iZwF5)KK|hAYOx0T$Cfp#Nhx1JBz(*x@o*QMZf-B{iLnKZ)!888v!blJX)SmJJM6WXSN(rf2mJKN98Q z=;(BR{l~F5W?PnLeao48g8Qt`j)f!hvifD-0y>+KRL)m1$r+;AmzJUfFCHbD{hv&5 z!C(JqO#4`dAe&?6RC|MGxp$c!ZDFlB?pANWal5=I&zvp#S33sv>fXUS_Fbx*hwad> z(<6f2_ng`gdVP*ZkGnK-tL}ro0_a8*h6cA~di1UVC2Gza8p(;|*Q! z4e~kO(e?KRuP^>Y*C7GAulSQdeZGCRx-$w-#@KL39;=1p#yb0H1*w3)DKG=pDzE_R z6{GWvG;js@-m z8yWt5&sOX}u=9L-vGG3E9nSS_T^OP-yj2f(mU94B2zy|Bv1G03P5oMT1`c5+d-36x8 z4HyNOp?MEKHDYOwE28gmLv}9mXsJQ?$GbZosO}8$VCS`?`?R-u#61aqFhl)U7xnNv ztS`_>cqIsX{Dwh}gk_Lc3?Zy(u5MRx>A^KebEP^T#mO8HrOC`_Xa+QS!Bdp1BPmK0epEE?? zJ}EdLit*bSzCd3*$lLm2TxX0pi)$2n4P5EusKX3av+&AY)d0ofdvZ9i-0*Kz(J(mU zI8Hx~x!wlGrIi^6SPTz}&Bw8N146m0w-gj7ALl>mI99LJDF5=M7u>n29sZXMj0nXY z7r=<)c=&Ow-fL0esW(p)`(HaS!WS!bgv7A0kuktO2+5&ys77f#D1KfMBXbkoITr*6M6PxS9YKQ5Na7u*k z3#*OP^#l5w=*FV-??bP-c=$x`#IW;g;(Z3X}sl z+y@Nk;91AH&peK29LFaQ{d=Cx(D0OV)r*bC-U6bc2SBqY{zVXKx9TKbi8h;$F-*S;& z?Hk-XLVq^M^$+;Xdxr85%<&Sk%qn@Jf?fz@&j zQJ$u7(9H2rE~TJP*K!#19L)G>IkPEM6h=WlFo@<>5X6=JJv93h%3GA(lN2-bE~Yps^C;sf1r!!Z<}ir$cghjp%@>Z)XQ%qiw~f&M6{KI``|7R{ zdPqR@Ao((oaUDyq+WK$r8KL{Wy(dl|K36|$=b(6fXmB24B_4^u2QEbr_Aze3%tEX) zUy<8*kruGYH#s<7pD*qu|HDKW#{wF8=&VUWx^9Z-dn@%%CT^tvfk#C3y|UVGf?9u-26I~m`iU$+C z(U*1*M+b%*Zy(Fu+M}M=K1$GU3ZI-kj?;p2uc^)F{5V0khlJOTx`GpYa(Bog-)lz_ z^n*d+7bkS%{bJUA7*mkvsjn0CC&P`4PPsQc$#>p23Hs5%^#MO7=#WH864L%-vL1S| z?m<72qMtX|g)3w&@!Aepsb*rOyTK9422A5 zuQ2>U$`zEQloKg2o)<1l(X+;}F~>6UF+Wq@q%bFAn1Yxt3VXAdVoEq9`T&I)5xv=$ ze|d_&JlK2T?EUq6;-9oA_=3TU-oNgB^C{miSEuMFhQ&wx$s`YanZi8P?k@dR@6prt zA2j*CxHUyjK3)HM=ipR*SD5Fei@Wq<-|u0m`i&``V_B)X&2xQrs=f+8l3;JHi}sb| zr0Tt)K3`F){#&r``3jJ}er{!|?wea_*1aa&mkq8m>+L2_|`hcn}h;*%74Y?$(y z@kiWxgYq23OSyw`E#(r*S(HY~9LjjgNDBMXktRs)H8q#QIOvn zVtHoYPGNf#w~IrvSvlpnGSj_!-S8~ei`bEMKjj7rd;Tn*E32Nu?A zC~Uo4@NaxMi5--MeS-Y3GYivl4dns~!?M^Z)s%6R0t$n&Fssc>oSBI;vx1v(TLYYsQL}8LrlPF=3 zlpiSUzEbv5c2e%5EOk?vH7Uy}izzIp6lQRWl@bL>K1N|mlHaC0M|qI4m2x?Stu(ob zGLJHm!u&{PwM`CnhwpwZ&UGiYlbDA|YbhO+MHH55(kMy>B@&Xz>`VNd@(;?hlm{pt z%4L+*lt#*2N);ual0XT8Bz#9XNO_g@Jz)no@1U?=B%DWSr?7SWCUyGh|ef*Ql6&VPuW7bgtC&-Kw$+RF`hD#5=Sv1{o3$vC?8N>rfjF&M%hH^ zrLgkwg)-!xJc+b?ELVZPx%=!sKM-Emqo^nzY{xeuK{@rpSl)HcP zbuKmQwYu-aWoG^7FwYm=X8k$evn$N{lo#|~T;o~v3xixCr=f*C4F5DCNUnLk+}1)+ z2C1(rK*bQ>Ul-mM0WMN5ive{CY5-#u)B=Vpu%j6rRRI4fFA`W7A;_Z?Rx%pC>*D{0 zc?fD#GOHR*2&#B8Ya2}n8d)+c98Jg)0P7r0NHc)djwWO&fHjXMWEmRO0kH{a0X!zo zPbU<1600Ch2x?#wYavYtnne;TB27pKfOU~3WI0;b5V@^|IMGl(QP2t4rJxJok3u(E z!U5%i3gU`q6QBt}wT<^j0ZEJZM`1N8KddkzXQ2+GFeID}C|A$}@Mq&WsHh8+%eerX z0%W=WBi|vWUR+N7yv@=&)WbPTldCpxsor-xqJKV#Kgp(khNN$jkUuq|et^yRg*o}t zVFhOVZe70dqa=MlC^qm%>eO1DPX3U}fZyhH@y9v&gML`e(rKQ8lRMj27aEUh3kS?1 zk5O+=;FnPPe(p{E;vZhz#~*(w>(71wu3tjb&%iZfKEB!R>h}|H{$J%R6u$;%{16h?;cN-qDIXkgns18%T{Y$byLl@ci6r$~mw`^uq8@>SJ`MS%ZCk(+W zE&1FPiQlu5yN0%Xf!}zOyENTnsjkuE-OI-|t@BLyVu3ysN0cSgnJ>YpK#qKA5xejz ziwfj$m3FDRHG?lYW>aeE17KGJ*(V%W6lt{E1<={t9loA@y1u}+F$*Uv1^9P z)W-PyZ9D^ z+O_sjps_2_zw5(q_;?C{c zwb|Ge)3?hmcg6hLx2ux7`0P^d;?vF!w`Cdbz?0scu7`Wl-=40kRtmRee(yyNi=G(v z+4Pg;9?t=nMNi`4mh}f}ExPYOZJM6*fqn?r5b1hIkf&%$x^BkjHct=rtj1=xdzKe7 z;@h#g+w;=RUHV|(4JV}Qv4cGOW~b}5?g`)3g!-mc!!_KqZ*jW5!QJ6m7`i^bHeH8g z=)U+`tA6-KyAMYp9RaW~8OMC5VE0qu!^H1L1j@ZxdA_v9O#Rb%{WZ+d zWa`#1_sFoS?|s%wGWF+DJ;!d()aUs=zcW+6Y^cY3W0zj*JLJvOvjaRM9?R6v_uLNM z;F-K5Q_om`DHM`L$)@B`aw#Jzd6axg0i}>)(|wojDALb;Mt{mTsJB?J2@T`rC(Nw* zzPgKw_1KK{>+UJmee3Qi(I>^ZaP=ch2(F|2UuOtejQjY5%B2QytAbhpE@XrW!FANg zECmQD*MHSf54cXbAOgAYDhw~9auXFaqGR=cc7fMXIa`#|62N=~xQ@#4U$@}&*-t1J zTt{WEP=M8{~<}L-ejuLafU;j{FDKamr>$lw*qh(Wkm#q2_c+{P2be#O7#3xPw~ek zdbICm=%JvTe|z=X44*Mo5Mks(l~T-l`tCnmqPulh+@HQIh<63eIG}F^a@J%%-JWL5 zN(T3H{F4uH8?G}D0*pNL{EhPmA-EapP&x)rcCNqUNQn+9rIhKuJC2m=y>Git7Dw{x zAJv5IhK6?txo^vD{KydCCI!a;r~<-Rp}B<$(BN{7ZOw{yCYB^{hcyUrv+`yFpqPZQ z@|EtKNs2-MLluOgntZAt4Dhr96eE5)LmKNa04lXG)^NZ$1(5(;ok$m?OnjD_WQ_(q zBOUOu&KS@pNt!hlfOaK}bvPhL!3b2K?-U^1OrHXbXPK8MNC2o7VMPy7k!O%1UXBNiV4zMcdz}>Mw4al|OPbe2O zn&JL-h>1*^X(K&6P-rGOvnjzFY@v2F&S5=lVGaqY2$>j1$DuE&=zUr~S(3CGEVu_AZF z+ZEghKzATrJb-8gTk-nT2NF)wtY|gE{3*H_fKnI6`Zs_-OKt^3Dwo^vS%LTZ!LUsC zzEQ8l`>I|YrH@NW@AoLXR{9E%|Ku~>_wcz(ch$as#99aZc+j7D<;Aqevmj27O&`?v zLgt_OR znBYwtPSkL@ue_Y+jy$k;#QLi~AEiSoD5G`XRi9Vt-LH#R9>?g{CWPNnSj(5YaUhH- z%y;uUWAvLNhsmJi-i%*;la7qh1N33?+oW=@<#OMoFUIJTL)Sn2{TLlGR`)&p{WyKz zbp2G%psMlu=PrJ!vv{>;#sQHBVru{s6+8 zbb$hX?lV7Idi#_S${TM0KhrsKJptc;6_3cVY7_+Ehf;HXQ-Cz*gc!h&fo7K&z>jie z)f!+*#HGvM6x@U^VxNSg2vWn zUFJ`e=z7y+*ijJ-E=`6V6-Thhu%pZb{A?EgM`a5rGC)57mk0v_&?&i6zcDCqEXL_K z6rcg6-e*A2V!%cP&jY#*FrmXsT`0lE6Q$fQ0hx&5^9u=80#1-{5+QMm0@or?jiLsC z%;Bh$_)`uE-zygsSi)Npsu@E3d;|E3LR^OddEd~S@045j^JQxrup@ZI{nQQ>8cT+~^qF~=cXN=dknOxid`X{$XSJoBP zmlWW~uUlF=&40ak%`B&Z&HTie86T;!;q~s7&G?*N|LHoc=;%T?`0fm*_{u6O%ynYn zTc!FgQyzRf@EMwwnDE6+Ba(y)o zzrT&8yol@Z3%fA!+l+M;1z6@HK71pmAzRv;n(Hxn$vMo`=H|X{@NjAoX(*}?GtQWM z=F*Bh_`@6{W+Roe%{Wqi#mR+F;$TGx;*HNCVK%yj-%^8*_U@)7{$EMAn@jV>mw&qK zO@&OB!zpLN>)Sh;ji3=F{BC=GXLkp_po8RyUrWb4KIgqLNoq`^k1Q=vj~V2DcW+UX z$+g43_Msg?;PVmnSeJt7a^y&Uom}gNAAxUa;Wo0L&m0QO^W~4BBUihfoP9UaCBDNX zKZ=DA21crpi>8r1m?m#9cd|sVXv5wzR(u%IfjRd^dv}WpNP3ew!(W5%%fUjK%_4(4 z#gD+d_Wc(rP!XT%z;E6o+w7S8mkSn+XDP;qwfa{+`Fr&uAtLccp>!U#xRh71@kf z$$BBv(JP8s%NH3rG$j|NJ zXX&xLXmn*+IaV!-@~SZctC2CU;R6==tM(1Z_SO!pmUP0W)5(g%&oPOwG2!D=DEFpT z7GtZU%Z_D)cAUZG6u~oenH2HFM0_@DU=G+;729MLHBN7qr_VFX2Rwbxcf|9P2IK?R zZRX2w3>M;)OWGUqMW!MBSQUl3k0N);X2WX4a0`vnkp5cmn8$b`CBnz?`*c5apP>FIgRhPzofAd`<)Ifn?r~VHO&oqqPJpex5$tznjC2zh z4t9x>GdeI1NaI)8j3-L{Dp*l@Um_Z@>RI(mf0>9~eTitmy2<|`&z+9C?q)m(#nZ#q z4y-9N`U+GbjB;osc(m1)FG`&if!T}(GNut9k&uPaj{ZV+aoao{3^5jH*ms4mSACv@)ku1Nnp6^WXJu|lM3B`?23SJ>7i>lH2`8uMil z2uG~5<{Jg#V~A$<07dMTIvt*gG0A$Y>-v7_z)IWyobTf8h5y*Q_LaTLe0DDX*2SRH zXBnL3818I0+J|WRg~sc0)3_;#omFhy)RYL3CRk8Ht( zM!zWYTy#ao@Gm+?SzFk-ux>A~RphJ6Em~+tx9mjGx@BVRZ5)i6(F^oXs%lwGCeGL1 z(cOZfRh|-OFmnH!zQmPcb+KHknlG{fS%gROypAq5nr3FqOy*; zlt13gHOrN_K(XPOKQ6tU^3=Rou-U{y-kNExE__9{8PS@DpI>&OPrw(1WqkRzgb`VO zc@+sa-T;s>EM#9NH_>&-70`XHg+J!(%$IKfu)?9b*;|~rbY6{W*VTWN_sl{a40Rpp z%Y_oGjXo|H9AcgHUuFVVQ~x)a;BRCDvj92J@+Vo)xzdgs8n(&*&*?V`{?mR*#!_xv z{m2i6qsY}u7z3Iji<@h{|C^NdeGpfsz$iL(nS@?tv397YJJ9$ZJ$%V^#Y|ROJ=Tb`eYCi>V!0wT@3t zV8VG|Lrg11|Q{Vx0lPZJj>zl zZ$&v56o@*|SO1uW;;zo~u5-NJ?s~wVvU*2j-G7&|Qh5BYQ&z~E6f`nid*kM#6&0~x zv>Qs88Z|ni37~7^ihI#j4M-7_Q7me0sffP2Be}`BerM-+9Wp`p?d+`5hYoW+!`T*? zpr7!8!b{|~7W6Y9f)K!V1)%^n?`{eMOjIs|0N6p} z(oC2nD|t(jW*P$UC>RQ8QZNi~q5?b$Dale0ff?XK3NW8ve5V3Tj21f;UM>06#_Q@q;N2P^i4cV|Muq1qlHEF_`DI*_BHYz@PABfRS*` zge)xFC(aMQrc}^2b&wfwr2-3Jxq>vn90losA_W=ve#H+8tbiQ~G6B5`kZT1eD9A?o z3s4%um~t=?zDGeWKs|&pjRY)IE_r|o1*kju$QEHtnETB8NdYn{?+FDq!1)Rg<-7(1 zT&7~s6y=1u_&g*;7*i=ANI@Cq;$Kuy4iGb-*kKw4=uj?**vM)HqX9UxFs4dCgn}`6 zv0^WQ`ESCUw*RFa(>Q=b`5O=LSM>>)=KoN+Q~@yWFN_HVoU>BFBmj<+E|UTNG$5H` zy(gVaCJqz%Za+!_vXP&PJ*(Mh2kWHv#nTW11CbXK&3&K!No@k<^%kVU;&^- zxtt2{SJZ|7ue0+2kD^-p_?#rW3xVuH2uKTA2P zh7|+qC1PR00u~UkAVnAi6-BUKD_+5JMZKb;*Q;I&-~WHkyh*_FeBXDTC;!ZE&Y9Vn zQ{FS>opS)KB_=cmZ!t~?jRm|Wa1mgOz&OAPfr|n21jYl-5tsnT6_^NUEr14@ctT(j z;0X=Le;4vSu}Y$*02)dU^&rtBG1KrOMb{aua7_nnmY5lU*#a{G4Fxd^?^}M87$oWX zumJLg^RJrncg+Fee06Zm1vIp&O1z3`Xj3>!|I?Ce9^h^PSUEq=N(WaB01eYXEg(i< zKHkKTa0Qw)4LZ=-PbrS%;tb^-jKtrZ31N4`eTL9ez>hRX-3xVZ;h9g}8xK(1X z&=D0}2iI+Y5-jTScij%^C{cgId#nEntOUF#P!HH4a0lQ{fmMLZ1hBTlSb@6$B?71} z9hAU5cqO*e)ISvEYEZ+8hXH3wx;21kfwg#b)^M)(0vgWsKET70?0&$F0uKOY383iD z7%H$H=dZt4h>Dgd7?O5}1Re%#6nF%H!qCCB0We1ZN!pbOJPODX*aV0XK)Y>w z+<}m53+RwUJqFk)@Hk+Z0L(>$cZlmrK$*mB1!M_41&9&YhSz_`1-1hY3G4uDBryM7 zJ3-4N3hg^?j=(NJnZRy9mVgb25!i!Qi^m0?0UQ$83)m>I53o$&S->1q|8NM;fyyN6 zc|exHen5=C3wRHCTmXh7_K?5{+3MhW6Hp`Y7NAJrZM-=BO@QN3_&yMN7tml*-vi8& zn8Sd4f%ox(^%sGE02&S(d-AT5m?MAz0!IO@1U|$|S?mNM{MfQmr9aYaF=!?jS}`^J zIacoJ+A!L%9}$gnkDB?!rei)*`}JE&RYYv&9}PjQw`us?fB0y6!1l%v0O8-(l&V0e z^}chlNZ zRT>*=jvLz1cre|sma+Jtpc7-^cB^MGyXyNcgjAe=V1AU6y(I;@y2U5*orv!(WCY4^wD3UYhn2!aLYfMph4*_?IG<9tBn$8zI9 z3+CrS7;Qn1zTj-2hhaEnm}h4z7*__fRpo7F5?R@ZksX|j9QL~b1^tL^9HGVR;dy7& zmSSfYNCI=xF#KPW(f|C2XdJV_Y&`+(R`7a+x=xt>n3bSpoGdP9$VKYia zn})Zw^2nfHq50kRao7cd+4cfw5?|Ri&az+KTB?3jnZMt|fIL68YnX~RJq4D^>Tx@TjkL#L3XM>YC`chJ zoK?79&p`)|%XjAiMPzF%CLUR8@c@+}M zMfdJZ6>t%kdQq4QfnO=KlYxB{bk$bi1`2I#fM*=&L*eNJypSB`TMms}4o@Tpy|$He zGlg5^jG}OhoOntkB>Qc4hS`r(uBXhS@N}~KQMy2~exkfVd4hsVFEejv)_Ghipqv58 zWV%ckZ7UO9sFfL}TuEWhXY%AShfughCNng%89U>QV_3{U$7W@0rZBrQYAHP647O)I zrcnA1SkmtN>CB4sYbX~|f|M4Jw4;<4D0fmSC_Lk|RuD5v1A0R%btC0QN{E%qjP#Sl zr5H%chZOE6g=Q>eCFOF;R7x?$Phnk4W@#t0LL@&)Sw&eu;o&FqWRu%Ll76PVN3kia z_eqOc|I9cGtUgK6knYDRtQ*}~F5UU--4{~Mr?9lU^JLA)2|S&|brdE^98JlmFiE$s zDX&m?B4#jzMO-SU42FcdB|^KNps>Moy@fKFl1*_z{I63UqFg~?ru$1M?I8)jQ9hv@ zps)}Vc+d%pDU&EeDBNE{9Ha{mwF?imONm|bTz~aZ2m6yF{ng<}`yU_oSJNXC{>1)c z3j|lQa6gROQyTw=*3(H7WnY0bA4GLLbqGci>+6jFvEe;Qb5+}9EP7ddZ3q0xkgiM+ z8NT$({%TaB^ekA1;AUMtb(PCwA3)01D*QxUsp@FA`KrI_>*?xr+Y`v3dreuYl-N&ER9`>O#Sb>6NPXQ~kqqsAkmU^sE}_h#TtF$MWK!CPyX=d{d~s_5`8QGKQ>Ia95Atch z^3y2oD6}$ptkHRIQ+87}Q0ghyQ!b@&2l`QAULP)HQCLcO%^}8IzR#t-l#LdSCHD?4 z(hB5OP)1YwQ@C+%Gf3cL$}8a&S5Lx7;xu)E*%T%X44~vvXb$x=LSsN#m2=*p@W=EM z!kjf+s-w^jwoI!CzvcIJqp*%-!VRF_^B3oV7Z4~~nF}eIDjF<^w5*7;eHk=G89d5RMjNOZ zDCZF_-A-9dnL=Tvr1N0X^C{gaZ7DpRv>zy+QQoB-pzznzHc;-N+(Ka{r&UpCV$#l~ zoJk4l7*@hGRtz}r!rJ~w`J6(-Xa>)DnoAogt0~O%)FqU8lu4BHC@jC!0tz!Pl{ufv zLQnaL@&)BEDJ+uY|5CWaWS)ES3zVlQ zcTsMn)KVr=22xn9lH)0?zDe9cQue>7ti(x&C~OKzG|NeAD9k@Dsy)mxqIgzjgm zUz>&U@%D%xXJZuhN%Jv>N%e%k7*5@p7!&(J@Xdi_{n_S!HmEzcaqH4G8-@!pKzous zB@lpJ2pq0X{}*P}MHnu8 zp~I|r2%d|~|KY;pPUDO1h{}O#ctotlCWA1X&57Z`aQ}IT32EaCmWZg6I=X>f1{*o* zw0I|hZ0};DLTF$%ho;P$+{k!j#){Oq!g8@@HsuzlvYtDqNqh_&a1-`Mp2nyCpw%kI ziPw3JwyQfW?!d`>-S;)+zct+e=~te{cb>)%p31sU#wrd!$iU~b44T=f_>7jJApxyS z6ZZCU*eQMMin+6J4g(h6;_hcU-f` z&H5(8k6i+gmj%XiJFZz2>`=jI%fv)gqRZPO0Hcs+{PyEo@mTUQO-y@2?$rV~?!ZqD zD74$aa}Gp>(15eQbI1jI0>k9TwsGy__M!d#-GR0n0e3lY28?4?r31Vv$&?@J2?LsW zv5Dbctc)idXn6z%d9uJiVfWtC5Q_7+{02ts4ks!GHYe$Jfr|moiTh(Fzyv)eG0(x+ z81MWzzqbTen%$fj@0YlwZ0SI&tvDOwG#}@0^&Tz`KXzhT!^$U&Gd}on{?_OMy1e5= z#V!Dx??ButJg`2;fwqNs-h518KHx?NIH+#t9D&7nj_l-*pOfiy-0sA1tf!7n2K)Kw zyF+M{6BUnMqP^r6hrGhbOw7VKe>@7}jL#hCat5H20}0*n0CcPa{!(0E9x#xK4Xw6a z4WNLq8=Ncu1uPswo3#$8VQ6--&WY=x9b=t+7jdK3)h1n$>V!uvL4kz;m%uidYUfvr zB4C1itDKmKV!#XsBHIB{43u)$F-~R;DUCpOw|Kybiol7txWWM!x~UdU@t4v#v&~eP@iQ|K%y|-lo=W^}+amuPmnGM64OkN0gs2tAd8xnWt zTJ0Xi`HRgEGjx&GUSMuE@Y$mqlsJdcqeZ(<fUC&_~4un~o;#PlprB zOdQaBxbU9(8)@=!0fyr^qalNPOohwDDH(j09`&cuDg1wt$8-m;p?6y_mo64T?Pw7U zB3sM{A8y?2#^cQK>_IMPH)EC{+Yg23A*b7zoc`Ug2PT_Cf1J(mZo&{kQ!%(r zy3Ard0iXKOx1L@rdY*00*5H&#;}?dR+EYhn-qzK?Y}7bNuVLfuHo?V;l4hT1Ri;ix z6g)J76Iy4%HMDYmHNMGlJmmeH8Cv|N96uTH#R>$&ug&bE+Kv^sXwJ)|9RU54&7))O zWJ6~>{rN{0{MYdjjrjK)@BDIp;R5F!T}0Jc`cnk>G{ZZs95p6<0`7VpMnC!gIJn8? zgCsO8xV5ngo`=tl^nUtl7i1h&IMAUCa}Dvcl*XT&YL3LOkA!u{G(G=J%z*>~GqXshq^1%0CZRyV%%#6N7TAsqtg>?7To;VOAiR1^;C; z2o;JN6}@sUnt1rixBJ6H`BQU)xkV+IGHgm3oUZUy4x6tTyh?vKfr^0jv_<^V165gm zV}1?4bHR+-Q#src9j_WbI)H!NObn!jkAvnfaHa{@pJACA&GQoH*%_!>xq)JCi9Ers zvT$DhOeioOvGJ)#(?ELW6qoR6LJi#g;5n6xqvTjz7$gi6)?fl~$CS;T zI-lb~)wL=rQ;^}xZdEiw-Ff{FD_nt{zm{;u07upXbIRV5Q7e|=Sm?j;1U7c?)2;-fUB#Lp9ES1 z_6WoR)(Er#lncZG`U$iJbQNd^PzFMl_Y6#N`=La&2RtLt0kBp87Y@bc0_c#7Qv^B# zoU41wi)*-|V-nK^fJ-+Wya@pGuLk@8-a6y_k=I)bwPzpd^ z>fr4M@Ce{GH1C+enSd<c3f4QB-IHhz|vk$}Sj=Kyw^`iDb6T?||!QRe}s2;fFpKS?8d zF94tx>fjxPCt(d0bu{25iMbH)h`<=YT!FCw9H0)~i*Ww#{58Vz4ECy^8 zfF(*@CU6A+r>KJ$J54PUSOUlrKtt0nV94I9a2q=AxI|qIIwXK2OW7!JEnu0zQotO6 z>i`WUem(AEf0mdV0DJ94`$wqZ37e|CJ{6M_i>va1{GzyVQd2*Ya|}qcm3hs6&!X>k zaGl-x-y<+QZSc<~0p_+Gtk2n2zgz!k^_FU`3!hB%srRz~_=SVs5X0p)-Eh>7Nt^Av zejTAIuTm)(>20LCT!q#nMd6JU)Fi8r&8Co*tI!20U}Y*eNZCZWm4dRj3efnh0@eWS zPh6m|6#Rs;pYkw;xfw)Fvw~>qRuHz<3Zk@^ep>lx-G%r6pVk!3<%JYM^&T)V=43Rl%142DQF5-=6DKsZRS&HhNX;uQ1(&oqpUrV1%8A5?o3|Z-Iu$cB83tDTM|#g(Z|SkkSH@9D0q)0@UuT$;=w< zzMAakQUoOFEy^y+{S;Uji^DD9SvbWD>CUX~zJs!wausD7r5`1pf6BIw zKWnW29SSqg{{ST9XBqo>I)1hgJ!X5t_gG5!fWo~daIXnVDQu$&11QOmF27RVr94il zr|>Adlu~#$@jpY>ED@l9?r1Nh)oz86Foq3*SNOirAjiWR3w$oP>W`C!Z zl)04iC_zdGh?zjc<`R>1oNK>%?MSsc&i?Suk!rNNO_Lc|5REW=RQQ$$CaWBK%G!~t zd-Q}q_kl6#T`v4@^f+=>vI7038;g_93SaxkNcC=q-&tl8@9h;Hvtgt<)c$k_C1>;K zaN@?1s;u)LJytPETE*CNm_&8`(_sxwLeItFujh@xTrn>{I#SKS6ib*#6Hl8V;;-z?B!34R0AUt|6-aPv%}#R+7~@FSv{`muH810at`HO%6XLYDHkaF z+HIrMSucdpyGQoM6eQ>4IXGHIAJh=nBlzDEdqd0a{S&@sxdi_|#s7=(|4qcBlj{w8 zPS^I{*I@gh_zz1Q6^;MpVC<(iszcNg{4d3Sw5HxUSlv+_C+P?NM40y*{-^ zTsc~;?rBHv8m*S8@I9YRRY~<9*srvxdwBO~Wk0<8LN&3U`es*)G3wr^w&z%Alx#nV zF_3QGQr-^liW;Nh?IX|)@!_g&V^pV8bRyOihrc>fs|FAd} z!N^Izz;WKzbdeY@^&wL9MWQO{C;PdeY+PJMo?yxI|mrb2Ozd zr6Z(-NlIvSO75b}q_C{@-E&DKmWpXpi(jIBF5bw+I?6%{DxFnaO39|Qh7^5Cpi zcp%;XL;0tVdYr;?>b}XI5j9%{{NYc!&sGWHPoZ7HZJ=$#TcAndDrn1aT+(cHEIHnJ zq>owIt7hOm%mh7vK1K_gz=x*T9m6*JMhF>X~tqQ|)?}pI}Z-2d3W!cM%XRBJ(w&iK_S#yi^w(5z)XCz+J@FmTN zxszGx8D6%td(BoZr8l{lv%dis{n-pcLJPc%Y7G`PmiM#g+8Un z9)WuRYXnvUmI#Ca69v`)N(I&ec=inLdts?RHOrP8O|9^Gf%^gL41_E;NAmpvfFY$1GoTd8Qgnu{<#GPEcZTi zJTy2AZrIwuA+v0`p95Sk@H~KKi^07gy%D<_2KNg9l$j3h7Xjl0kOMg}0xzMDdfkDL z`ydDztAiWAm_0!NhFag)lijZX+!BNA$of>^H2{uD2RHVcwNBs-z*2#~1EvYQ3CJQa z|J`q)&-N@8&W|0nSra97-{Mz9@7}%h zQLeN7k5{N6k=eiRR`pgBW1U88=9Z6s=7kY$u+Cn*wL(3w(qjfstsPN)el;fH!N4wN z3z>`9Y_Z*$pE!Ipp|7eK)x4~{diH>s)wK&vV(C6j;w4U(>TVM0ai%PCRxPn~FzMfa z=!!~o!ArtR{C(98BgAjoB$e4uO;VW=)!DUV`plTqeER(cW`@!g5c)-;P$zy z&Ct+w=Ep7HTv+bu0+oQl0#$$%fq4LrKs7A#F@YMuet}xRdV%?X>jW+VOc%HmrXe_3 zXaOKaU?IRGa2X8uF#$Bk{QUxp0qX@W2V5s`1z@@Wey8E3ly3-z|Xm1nK~*1Yi*Y$S@szXzBXH7n1K*K(UFie76BQ2;7eD;wPGB2H)R6 z@0w-Hw-T^j0GB*Ds|4-7k4)j0obq}9O} zM${sKHGqo*)&hD8+zaR=fDF}lVPqf7Rn}gKc>sWNZT90>Uy1of9F zT=Haf6L=U9A@B%#AN005_%;BL)WAjn%GSW6fSCfD0A~qo2BZmW0W>Et|9y|4U;134 z9tXTA@C4u?fhPes2y6w+6u>2qzE>pswgJ*4W;;45^b$Jwb^vgI26h52m9EkEG^me6 z?E<(2cB3mgC}0DmBk}D4oGUTU0P+O(0%8UBplf9emFtYMQ`) zz#su!@@V&UvhPKJTVl|~rF<&z65x3O9CFG!fkS|$Te`l|Wz*)AO63jye|);bd&Wnp zxF}9HUw62mQrU+Ks#JEg`WcVGs#LwFzUWY!R`pXM_J@P3R3M_hZ_b!zcG}P?^;z5c z%58^QHIWI#5tP1^97+PkM>+WvWOF^XUR8RwD(z^$cv+R|=W?OUU6=0ijZ(M9*lU+n zsgv&A^;K%6yMzvi44!d*C}(vdfyerxaitI)JQw-#zX^{CFTbZst?Sq@CH5sc0cMoZ z=`GKEJFvP6^AqDHZuxyxYH3_ZdQVRklXBWFC+Wh|xYDrnot_%Q(mi_SI=sZv!86CO z^l_dF!*WOHS)#c`!!4qx+HSS2O8uakkJ3A^Jd0NEsNxgL%j{AttW(h(rkcUCIDB+x zm3pg0UQ>EPeynbsb=6YD8=xD8e#cqaOxjT5kYCO902)d-&P;a9Q4z#7E( zy!?Xf;*9Lf=C9>7|9fwxMbk8;X_ffn{oWSKcdeh!H#t^C4ENdAsM3G5Dp`8u)ug2b zYm@a<)1{NverhVlwk6v-tjqCIQl)`V?ITYD9(y`l%)a<1zxA!;IV58aFu5AzSQSFzScJ?*3)3jOb zw^i?K@1+JTU9)SFslTTA4OkkxyPrC`?Y`X$9`zaf{dV7Zw^}PiFGO!dA4C%(ANND_ zM{I-`fEb9_7%>Pj7%>Df6fq1j9I**v1Y#s&6k;@D3}P%|9AZ<%c*F$6M8qUSGol4C z88HPh714^AhM10ML(D+TM9f0WM$AFXb=+#57ogfY0xI*C*{^G6ls^23FDj+{U6Clr za*-6sB#~T5Cy^D95JSGiUbN<;J>nIhY0W&l{?aQLQfK6x;bzTZJmUSiUDHZ08g`yp zrR_apnuFd^Z%93JN;(^Il~TM)mnKYWMOQtdUVt1n#9z-zHzbr&Xg4H=Qt-JUcC&6d zhS@0jj~S9r$@|)nGF=J{sifpSVMu36&KX0hbZKTte@gZukNC8KOcUu2xf_D=H|gJK zJj`ljRr5(%vkVzS$vkGrWL+{v&_^>H8#0qQ8N&^!q1bjBGGCW4Ll#rg#~AV)CC%-r zljk%O>_tzON`;IQ`BT%Zo3*KX7hz&j4S=3eM(GhW~iDT5mc}wQKGAj=;AF%+j5U~ic7_kJg6tNj%8Dew9a>N#hEfFga zTOqb~y)vtEl(%}>6T|A@)Y>gLoHWU&MZh{SgNs4n({g@gBrMh=UP_ zAXXy|MI44W9B~BVNY~+aMwPc$ZI=a%?qlz#S8Z60h9TXuR0RF7h0%t{X%2CDavJr- z%;OY!0`iDQ0xgh^9%;N2VhpUXn#jwTpt3zVQSWP7*%gn(zKdbltc%z_Ohb|tw+3R& z6=5~;A3(NyHjDoR@{Gu5kg0~~W3J?5kEjsLR(E*B`x#6_o&xEkv9OJiW7mgcfidNV zJ*VA|8R`Ke>p8FQFek0^h&O5>&zR!Eo@+D+qC7c47cnOt^+*IZ%iZLWNE@WaBXRQ} zy$xB#agnngg7Sy0V%_H$Gf&v6pr0USW4m?SE_x2$g>b*P715zzO6qP zIdvL#VBO^ruQwr64AJL+)B_$-3p6dYxyWLaKgH9v_A8V&#nWf@tBsh|RvFtJ;R{)e zwI=LHBQ%la3r|j9E#z^JG#(Ba>5(Ss5MvbzI}(jq-~6{HC$<3co=41yXaV!H9!tec zm{j1A=08A&xMq5felX7Y-cXC0>&y=rq|DC0A8e%_#7cgM3yqZ9s@az!ML9v|XFfiV-Uw8 zjzb)eI05lq#EFQL5GNzvhd2dsD&jQ6>4-BB??;@8_yFRAhz}voLVOtU5kxy;4dQIX zM-k^BK883K@o~g?i1QJjKwN!Od>U~H;!?zC5SJl7i|9an4ski+ z3dH9TUqD=m_#&bcaTVff#Fr3XMtlWv4dSbaYZ2EWzJ~ZZ;(Ejlh;JZnMBIe98F35Z zR>Ws-;yC+)Y|0fxfJz z`2f~miBrVK1m`a68iEI7#ojgR1Y!Wukzfb4nhEx7d+IeX^+)13@h-vRNPV7|PfRC< z5iCw>OCp270Mk-gGbt=i3Tr0i0O2BDAuu~=DUT31Z`4xy6CH>`B8f+s(ilkoo51v; zB_AW+B9;@gh#^EbFsCZYT~pUPEgU#li;_G!4tm@aIe}kSPfUs;=fZ>q-$Qnft7)- z@{9wAq5_oPEdV@ymJc^zfAAhI69V(0;NpTMfu z!yAxEBIt4n>|J`;1PK?}jFKMJ#SWsW;}=TSRtTF#58EK!MBao%h-^niu=4eQj@9(I z2>NN$hP`3%G;P@1+mMC=p}pcxu(Rml9T;0s54#{Wp0u_bQYo?r;w9q7JA`jV>L3l( z_%4K9Mh|Gm*pVW8Ass}}8Ds5Mu@7J-kq_~P<9m^P5ab$RKV*#vI)BVu5wu9mNRf{r z1tJIWj^$U8Par6+5e}jJ(VP|Za2PU9DPC^<=bPDpM3*;SiSmbX^3lUz$chxXqG=&$CnI3LA&-e*f(+>^at%@{avc&S@{gtkV~<9-0r_0y zCgd%T*tJ`*XFaCyH+Y5!EV!=-hFx%}h&Lok1XE_vUm_;R=OVt4w?zCP&x-g%W@u(j zb4>1bpw#u$tCwyxa_#MRAj~f)wuxsW&E%zAzqu}j`OiB#>Hy-$hzAiraUC6XsO&5C zo-45OaE`D2K|CRovrJ|+(VJkUW;Q3X2+rA=Aq0zT^C1MF4ZyGu=-~0fW0kyPE1YbRk&$XxF2(+|GL@%NpkxfJqXcEneZl_r> zvNS7Z56${6fmJ}WayQn61gp_HnqUoDTN51c)-VE5OTA2Bglnmv5Ujk^^?dcz6~q(7 zOoF>f?MrkZiis2=oM4%Z)0@*w9U^uRuM*D?vk4X{Wgx-5q~sG#311)?15Qi+hEqr~ zYczQ)v67fiOeF>rT?igRauN{$SpFo=5FZn75vz%(2o6xoFoMl#;d3qQLKZ*3%ojGZ z7R-FEIhTiSUPCM)SRdvI!~mirQAC)DMAzBQhqI#{?jeUGy(VkU`k)x~gL~&h7r8KdU9BE}#7E5eROHw{N@qiL4y@*009BASj)at z_z1z7sjwBnLKJ!f1*ZtsRKarudu_o`qMYEd<<}D@h&qD3G@q58-<3!wynsCJDv!sO z_X5H8%R_zGwY)?mbN?aE5c`Nt#8P4k!3NB2Lu3-1Fmuij>j;)1hmDxS!_Nr;ve{X) z*#_C%RW{oo`#yqwCOZ$vx#sM0c85UeQMb>ahpjbnS17{UH$<2E)k!S0#Yv0H1Y0|GIq@LTk7%ZO z|BhO7U!OAUQ2lfd0XYa)g412TUm*gZ105f0)Zf{m8hjz}li zxEYs;V}y%%o zCLsNHf{l{CpKv+W%{}t9{UxOT^=Se}VQOb0kBB4q>=X{RlvBh3f>mj(v`d(pO-v?O z+LZ1@1;PHD!o8&U1Id38=LptR@(zv-W4UFEBy$`jR}syLWP&YjVH;Y$BHkf5y;$ZF zEV2c2jAkh(QixE%%#m+q1DZc2b`fg{9mf0Q@BtF)iEoJA1p8#de1iK< z7)J~s?jTq){R0RqkHN~$Vtta}#@6wgt9t&CZzG(49`sV(T`#RX5+3P3i0@{1HJUeg z*Ads?U7v24qfX&8_vitO(^Te}oan=)uFP9y>U;wvoft`!{j~ zUp^k{%DsHN%HOr<%JC}YxODaSV#lJtk5@WQ{e3*tar5uvHI7Bsj)%_Mczn=cme_qJ7)2@(fXRdcpzoVwl&JA_e+!d`V zU5l&EzS!8&YS7tG*Wf{C&v-eyS0g#G`fPHVox_pAvIsNx+eTWm)Iy#SSqzyZ@-&3= z9fJkq0ACjy!Gbx2JyZ|;z%J`+5%l=14I=2?SsXeH76-Sixa}hpTV*UqVy!@4xVjia2PRIFqP@k zsV*-=IMj7{1#+**8c1^y%%B+@@(dQt54OujTC=Q!aH?alyavJZ^k8`%QiCMQk1UKy z+uckdSl)o78)?mg89|?P^_{F*Gz?RuwS~xgkSLM8SV6dWFj(G)95m9JyaO6oLcPgXI_m{my8A%W>E&BS*7*2H~8~VEG(UXr%cipOzdX@+ET5i+lw^ z9qGYx0>Z_B!SXfY14df2pqE?vh@6Dv8T}6_Oaqnx$vTZS?0bdoufp{D>6~h1Ua*-=4Hl>?dSBA#wpSLIib~)LP^sBu?ZPEQWuIpcNBQ z|9Y@s3?{A@sfRo+f{v6pRK)%ptfkoRkZ6%Vuwo)t4}6=RfG%LjUyyYoS0Hmlu0jTj z{0(U?at#t8avh&w;{XxRr7Zuz& z56RvT36ln~3 zPy{_T?k*ARDK1|m1Y*Y%^^lBF6Z?Y*N)!98NI2vLktUG)MNpx!y+k4*IU-RI9J(Ho z(WEixpN7Oh_K3uy{$rMlpTh!4a+6-k0@5HUmMiC7@R zM9_NC$YsE1MydEj9Q{}i$?1^&A~wh~A}CtaK#^QXxkw(Qp&C)Uk>5y80ptylLdZ-J zv~Og42+EJh73rLG6%WtLd*iGt?~QLyEK$$k#PZx&|Bx-I4~3nH!0f`{bHy>G^SK&l_>W2z zxY~6&SL5UKzMxc%t9SQv)n3ka7nQ1VrSv>E+2kzxmFeI6o>PsTBd#eG>iT2YxfgvC z>t9`d3%l|hdJ1|?M5X^hefOH*1jpvP&n7x9-F-IHk$cZsoL`SUhxi@h_lQ3r{)l)U z@h8{Du@}60JF6##sp4lJ`ZV29Hx4+H`Ei`1`uk*WNZ4YrI{(J6t@|XvpZuE@9`5*T;vEreR~+{1tXyy=**U@*Os&?*aHl zkNXW9v&%Q^yw`e#g=j2b2M#U+nE;;e{r>) zd1;TI36rw-8^#65ar3S(D;DyENF1b_2>M7N=3qU9Vm&Af5=p=ZP@X}og<=*g_(XD&Aa976Aqx$` zmu*-O3NS_Jf%8N`o=6G=HDTmnamc?cVug4bTnkNujFlWL8~I&Cux#XKh#;YV)GMOEiLW~8;yTu5&b99SNTsE5#ee8?r^FSG!%S8}kt=%0(xLore0 zJ|H>85SjHuvAX0o%=)2NUUFsD55@A5BeQ-eCgPkr*#nlBoaaTbyyVOfX#wdeg5@Qr zq03Z2a3-UNP^>Q5--@(G`Lof*jjT#!Jtu6w6B%n$r+GnuWQ;5KK9lvYLl>gETZh4lHwt zY}NyEuSgXHFQ$i3)J-Njlp($FM)f9>Z2wR+aK=}91_bSs@umot^^97PzL0Su{U9i> z9zy#=%pwEuuJyXeK*;AJcSE*_+yi;a=zn7!r*W>Ym$S{JE~<%Y>`>MlOxrj{`w4E`5?xkn*#v0uJMkH@ftW+^m|LK`YAx6!T5xcb|3PrO^0$a*h^ef^a@JRQ zEYSQXf<3SKTw)Y~A)qzKRHc<&BfccwAs!=8DOy=65d<{*mS9~rdybe$^d)i#9!KdJ zf}51q0QOQeg;vUAElnj5wUSfB`^3w{Lj*dZR>IZ6Cxb#PBw7KtE8s{fc#n9N;Aqt6 z;DS=7*nau9h;zhYViU1~U_tWPSM%EwmB3Lt7m{YVY9+v*`S|&Hi{D9!gWzHfnJ879_!1$8k6Q)=d z84HOKL=pR624BR+>M|}wc%G?g1ovReC0PCGzY#20`db8hSo(tmk2jrNDBVmb09Q@| zJfbw#d>Wf6trx+HN{a;aFRbj=BTTZ=t+m7yq94HxtsG*h*9dNx${I~&5mToU-HA*h z3`qHf*iURE*g`2hz?5pDBf-v;5)CB(LwwKvm;4d&3c*82W@9C@v67n+F@!f@`JP}s z8sG4<0xT?;g&SMSh$z7PC&BH^tZ(yjf*s#nO>jV)*>q-fmwYXW2a?1FOxgn!ECU!4 zwn8QuX)R$Jgw3J3;^*GH73-*9`L&Ol;VhV%qY|8zzfV+tULiA_p$WrOs#nN#=g?_6 zMq-?UY6j^DQ5OmSAfQK=%F@h97=Kv%c7Zcg)YeYNxEF)!z|HI;Z5^WE;7uJ3l= zvU;ic_$>Way|3%%A6CYPxT5;Ld7!cD%(u5PR;pj$38+!7K=+pM!D^=0I~j}AjzAUk z&e7#6$@j^yRmzR1t|qCw-2rtpqho~{Y1No~bg9|f3{yJD=b`s8!O%VYk|g#`xc7DUQyE?uT}?J?tC97NJeM8T zDY6zaUjz%5Di_&+oN12FzWbm^O>;E*{)28!J-3Z**7hN*v24ddFwJq__a8*L>#O|K zA}`0Gsv~CSp5A`=hUgNQ@67GP^kCAF+w(}MbEE#iDV@Q0`KcP`i=f$gh-t^AC3ya# zzIdkl5O_qnH}>~a_pDW2b_e>a>4C1AJ6hIl&-i8@bMY6yuK4pHaK^Ok?F20_Xy$PBr~g}x z9-AEJUNtOSwf3*wG(KDbO_Y1n_y{$ykD82vM5x$cchR8;RTJRsJ$ZtvayR)365@RM ze1vkkd;JulJ`HjfU5QY6iTg%pe};BRLqsUtrT_5^hO|Db`q}>D~LG+XD?&9>C99yVJ5gHWL+V?B{-R7?I2zv zo+73bLx@g99uZG)uFSkZ9Oe3w$)ziE9pNAzC-~${u4I{a5giEbAro_=mhl^LmN-Q4 z$TN5rmhl3yka&dP^q5gi^d#C6MFhu{ekF!IgL9sZC9$0+IPmqab8PQ0#nE9~Nh~5} z5@QJN(AI|FI%KmDTx8O35x)>$67Lh62u>X7EL{41#63hOmM*=Jz!apV`vYme6D(cY zL4wtqwwhp*q}@vlBDxV3L^jcs2mq{C-7h^Jt$HLmH!rSIAjU z>(T16s{Lz2v~vHoAx1Unt!C^Fh*d$p*}ZT8eerQE>ppHE(VQ?7>{AK-h^|D1yPa>W zy36c5nb1o;5gFED;dYvX@Ca<8M?kGG=TkKpkqW7KAhrdTyD z-dQ|7O;x&IxhGZ)4z3L!AFJHqgq?|D7eFv+&bGhBsdwE?evea^y&d0< zy!dpj_mwyWG$rDd+xtp_@_Rz9#HdJAj|SQ!@jU%Ihs4jAVy8}=MX(AI*>)U!;@Nrh5BK#C_2a{#O|KH{C{5obxLs5ItiLH*!uW)~ zDLX~n&jeO^Esotgjy*fBBf(J-=Lf`|B-m?Xml0EmDuOFUY#^XtWgg>ZioG$0o5Zji z#iRhy?7GpXfmYEUGRe*#y@VJ|@a3X2fT)|qVd8b-abh@;PXs$ZdMZ(+R}?`aLxG6j ziBE}*#1q5>q6-lRG+|veIZ90eq5|DH3lr6SzQs9d)o=v%K!hA?wf?ukQ*ZN>YRy&C zeR^D+c8aj?5ZDd?5xTC%bG-$Fi`!uJ1_}rv*QS^QE;Dbl%#egIzP50 zshKLsU6zrgoc=1_eXt-&`T4o;UX`Y31W8&ogvJwe4VJ3S_ z=Jy0^E7Pq{p=<_Y_T+9dClWj&W8&nrt$#p}$r&nx&78p_%J`b#!k)2>SV_zyI71ni zCv)b_;0`j(L@;1uk!%+T_FVhFE>dQ3Y>SCU2)40}Gl{J;QA(r{QG_p$&UR1#f%u%@ zSV~_{I0%-;m@Wr1bth3y*a+?=-P;bPT_nCBxCi5!dx^~i>%+Q$m_e{ztUZaAL^^>%jBmFUlBx9sM^EY@VmGmYc%I;HQXe43 z5NzJmjzj^GK(KjJ{w8=ZDV%vycrYnj2q&?Sc!(HFa4#u#HW5Fy*HSD*2#|b(_?h^M z;BJgdmbs85vxSmbZ^`T_$%6>iZE_1DlZYk!0m~JFEyQoF^>5}i3%d(1qtGl*v;SFY znB=}J_YijwWkd$SeOVd-W|q#l*y;#V?+~vNONkodUV?qb+=*b1!rCE{yhKe3%)H;btyW)WkFzC=4BpZzZ;fyn?Mn!PppJK|Gf53!zjj+jeKA%+m_ z^U=+TG@=QCXna+x-}Mx=kNPIDnpi|UM2sQs0_;(3nam^N3HJ2Jzld`LdwS$<;&sA7 zJVx9{3??{UBFhLX5e`J$A}$hN5g!uU8o+~zV5LMn?Ed8rv)beDY~9DKlH7;E4Uz8G z#+mUhUH#*}I^L}O0@QWqrRiq%g<9x-bB0;n^^xk2voDK!+-HleD*oAKt$k|0tF|cj zch$+tdRkpXW{UFjajOwS)v89DdUi`uUhXZEhbn(xcg9^Qs(*lEva`Q`ZESUl0#cPb zw%V#L{28+GWK8%G6DtzIbjs<~m*;l9!1qF&shwhRB3d#kO??)tzQVaynzA->EPVDLmly4nQ{sL+W)eyW#n_sAcQ=QE=6spkLd7yjVh9cEA#?Jo0;5P^hcWWc9 z`Jr{P*boeU*aW{sUIQKF5VM0y6ZlpE8 zi4cw|2ER!V93X>T^P3FwG@Ry#zM01PfWZ#~CT)$8*8HYI=89lyNkc*O;5Qw@am3&^ z1B>I2Mq2Z`AHspe;5QS}P;-=ic+}nT!y=WF6c^Qd()5WVhP0b7a_E#U)3|GS#C_lQ zMe3?gR(QvuBSuzDnKXRl)Tu+-O&K|K+DJ1ti>L%V!KA!QPrNoP*1hCHk#Z=DW=00S z+g;YMftT|A*JF_m_m{V#qK%C>C+LBDxffpw*DkwQq<~_gM7ft;ELBUtvUl-pmiiCc zJ4WONTJ<}Tn-I4Mx>4o|k67_ne~U}EdO_MR7-`KK3|XgX&QR~x%4D~OK<7wa7=#lO15a`ETg-Gp z2eEOU)dll*IwvPxA|bDcL_yHI^k7AC^piH46*ZNPlIVfA8>Df1Z@rV@-qo2Yt*NVQJ zx>L4Ghs+hRL3)a0KyVm(;4N(W#qTt07DUFeH5(#>-^RDj*$1?5$wv0(!8v!P(YH z5iD-z*F@Su8V;d71l>>%R_w}*E?@`_Ea^)TY?9Q_F*-vqAsL%>fuQgRXn!l}Bk_0L zAXpI-8|ofIGVxK#=?1|u>A~6^5+u?CXH^Zais>)mWywKXB}^3Q1!*pVQIml2$Nq;` z?Ss>*k0t9a$TK2+A%jHvLC`t$VC|1{sLLV)ATE)CkjF*thG36+u-*ef$1?=GjkEtK zhG7@?p2!f$N|9>FC=m>eICKF$ScgIUMTX;C>I;z(kaZ#>ArFXPPq7WvI2z@T#e|>- z4wRU0M8-lI_Am}IRdTT6#GwB5z~88d!9Xws4IF(z1of_;fYEusQ8b>X2P+nwXipjN z9ttZ?w2x%rMWRlNOoKG^h3SxGl7p@og__WV6-A3e4>#mNNVLd9IH&qnWENzb$iom; ziQfL!M_}jzdf-oQL?(&UVEs5JG8?i-WDaDx$YT)HkshpQ`UsBgUuGas@; z8m7IcaJAb_dD242`yz`V*i;Yvk}Mou(vZavi^$XXXzn+W zC6K)$OHux?hOUl87}`k>R#bIZrO2}oUl9ks+CM7t9OMlVR7WU^s0Zr`2*$4=&qJDs zynydrPI$!5_u3)bCF?~9j$IGDXEpGYntQxh2ugU;RA3r-n!gGTzq%!lV&Q&5i#I+q?^f#c*mLIE1_zH6O z>|I_eHGG7xmzSSsXPQ3}-p+dSSQXo71h3_ryF2`#BW&i$NN1nF+NX~$JRd@$NV zEst|=JJCX|4%;;1Vhg3*(|&28+W5Qv98zEJS3CVi3k9@P?&&uw)H7{W2WLQKEA_KI zatOXx_hX^8urrY#;9CRZ7xs)R?h0*2PCc@_&l zip`&?OE{mR;K%9Dehn4W7$6}H9w^TscC8H3b% z%E+o_7EVgc_!D03joQcAkRhhoIKTMEkTJ;CQu}zsI~S7f5#KS)0Go(hJ>5`RUs6{OM13bcI$KpBE#mq5#j`TT7lIKWQ>Eb!kb(F+K#tt@95`Hjb zhc2xQsiVX{t4nhDep=H@M%I3R^cj3~Va8+O`~A_inr?EyXzZ=N|}0jUIe%Kx7W{xrr-c4oJ=| z2xfCVn84CDBFYZ4h6Q-QvO_Jje z!KAMTQzJ;j4gw&a9oTW%D~5f;9vVX$_7DWQU-l3TY1l&uq?zP|VygIEBnv`Al7;itf`&arL-cL9Sq!ALY!-_t1y!yGQyiq>IZYur zX)to)Aw5MBAb6gUlZct8;SMMh>Lc%6$udJ$i=cV(W{V_4hKitv=Cu(?g`hF?V6tK! z`&c9mqK_LqU_zmD?~)uF%Abp4*Mlho^WABYOvo!DS&%Uz*^tg6IS`u&hJ6lNT@R)_ z%y)-G@*%R0n+hP)JUMn#A*_#VR|F{*K_WXsqy#fzL*Fcgtdbn`gRB~nGDx*Zb4aB~ zIm9f|0&ix|P}sI6%+r~#(-2G*km*KRGqr-CRC+L>>GdyoX{JiZJNn}gG=l#1gr3tD z(p_>eZ#3MUXKIf*`%B5`09j-7KkT6+Y^r2+g5a3+U_w>vcR$ngpMq?t)UKGp9mZCg z=?=)%}M{DZA)D7=ZW%@ATz|xLNP7lud&xlnaYnlkUY+4_YUXWsu-jE0pY|?Ps zoeAB_+As+4zQj69HtPpz=&1c67Rj*>fGM$oSU1j!pfvh##?ejpKvql6AjoWy!H}UM zLm+KLsv#B;Y?7)(Fb$-J-3zOhtceheSv{C0L3~9fW9>UAf+@zlL1YR9Q4c0` zB>iG7nrRvY^Nt=&=-5eLiOhi58yf6>Si>G>LNI2HCq00r^mma5Aq|B@!NJHH}3W<`OIasDoh&%>)Nn|bro9cn*PVvJ; z=0Vzu%!ee4JOS}C1nbWNEbRv*>q*EGk*6RHRk9G$OL7)L3Po!1F87+qVo1Z0J`H(E zaL&Jr2nKuX0g>k*uZt{)ED%`%87J~Qq^rma zkT8*zcxU`E>R%707hyO;L!1zdb3;}^;zU;C&2U3mQMBlWvc3%2DVx0lSs}6p@}S78 zkbxp=QU2(1v31Cb6L}5qlTV7EoKd?))24s-PMo5LoCP;$FX1syE z;SsxO3+$w1ZH4R>*#=oD@+RbAk?oK{BIwMK6(TN3g2)cM(Y_&qffjL6WG7@dh4pWG z2ewkOc0nE%!8Q?tMD{=`MBI=BkvhB|zajE2`%Z`)fi#Sq zPa$I^=P0C9abdenrGGlvuumgEn~Z&ut~ ze@2y`RJZ<&wTE`La@Mb^RQb(rdqQF9aN`MH6YxrU;7hDMSaUtR%4>qJ84oex+;nW3 ziZl+V%Gi$7xBd8`1@1>zSE@nb_Kg6d7g0}o#%Oa=6{}7IMnWWLAm+P^F+@Ld7dX4nZ_%4mEi#OfZHu3 zpO5`##|0zxO8VbTezITV#y`*Va0ej9^?#o@w8)H|{qJr;d7^O#p*->B+g~t0Ki_yB zGCYAbJfyOi&Dg(j#afK)zstn2)ADB)=eK=en*M#4@hUM9*pD7~fKTsDvb#Tg zt5W%TS}BK{ao30sQYGA^ z1hbh|vVmAYj3K%b>;%UBBN1%Y;y>ZVm;$t7Ze9EsF^=d?G$VMzR)pzDE5dB974e{p zrV<=5McD+Wy~00;0|b^ut#A&(<|r&AynzBtJX!%K)&i{1n!Vs5CWjD}gp~*Y@_!~U z>uLE|PPF`0#8bp%f>oB^ibx}Z0OLof_>8)bd6W&51}L_X2T@*v0HzcGBD$ z;%=gZhyrqcCAgt+0}1Op=K+G-Nl(YX?SrYyCNK%h7wT)oKrE;58)^chrkiyn5uGMle#nwo< zpWv~jv?DTz5Wu)1>ushM5q*g)!15P?Ra<|zqS-C1GfPLpOn3q2GsK6)27U z%v5_Kli-mjafeCY5L<{^Vj{sKPl^EWe@FoCFL5Qo3N@~8Eq9lH&{lmL>%8<&kxF#< z?7X?w9ecX1I_2H;|M2ZQo`&Ez!u`j$ZPhq$XUz|7RfYQ`__dGo)1TX_L}%#5wyL-L z2{2eS4R1ek*!0oU@0~oPplB$T(8A^g#x6qcb*`?(N8j!(zqD1Y{oE0MwpI6gyFa?x zR<-d{J$47SQ$4)wth161L@|*{gaO4jiHii!6N+&Tr4_$LtRfZ=(}`;0PNIxRAy{Qa zHwccxqA!Sd3HG<5WyIrzerc}pGm2g4r3Cj-#9m!^g*ZhVBwWNg!a;Bkg&cN;Y%u+% z<3jeyLiUfsD4^gUg2P9@z1aA*#aF0L5%&Z30`}#CZiJ2S2K2j!^S@?lAHmL=&!L|G zB*Ew9k05#y>;d|{!}*+d@_hi~{x-gF-ls$z!SS8Pu93%A&wGd%hoPb64Inxb&4@H2 z9LT*zuwUgKB6bq566~zGj}Sck+>Qi0Yi=-*^Bcj#&-sYp;pgy$bEXn}p&a(u?2DY5 zviCCi95IS$O|SutTM^h|#&xvqn93&jWMksG%oO`a=EuY?;tk?Of}R+D&XE*ajJkiP;1jKVvx2hhQ(xU>C|rCpZP` z7i-wAA!YlS;0V^Q*|6+bSlXCLSeNNj5gG?Jk0KYh%0E*guTl^$S2Morju! zp7?_Jkl0GRM6iX@xj*B2+iIqI5Jf~X(HO9&T?Nxl5^Sur?Zj$=doZrIoyOEiqA$^j z;9%1)57Ix@O7nsm^YAIA*c#Ry#2SLTva-tfC9!55Ox#J74z7DF=9&|;2c!Ex?!?|iBAwKptA9|aI{MXxGzs;}Q z=0Du#_H(yAaNsuIaGNi_&8Pm?TipDwmsj8BZT{=_=0E-Sf#&;e^S!tE+qe0a+kE|P zzUIGP_UC`xu9fZi&jVW7w%dH|Z9eKY?|GZ|xXnA<=8^yQQk)|P{QCi{1tQ)-jok%(fLX!# zqBz1FT#oa#k)E93i#Rds;gQg{aN_m8$O%ZAN5Y2Td<*ws+V!Ig!xEF!)RPrH6K7lw zkMJszgl9YwiC&SADKZ@&q<-R&C=L5!<;t`!IeX(SQ9Q9=R{s7tH5kE8-E;un` zM-gM%cGo|3)@3pt(c+#kawhxsf+V_s@$RO4{oH*<$ElZm9Pg$@HFX9Dc2h4o-C5o6 zJE{K+v8Z{D$%Ro(+`GT(s(h8Zd1yCvNx9!>(oN;1I8*PosNZVC%DUkO(X#HiLA0!g zdVaorEME#C*atr|k!Pf}VAMd%KSg{YT-+Ff{UFa9X)V|v@{mX)2s)}Bf&(CNB7yj^ ziEAQ_At<*Vf`iaJEq03Gq^!jXkr2q;BB2nBT|ESc;dd#%6A6dBFVX}uS0n;5QX~@6 zK?JQ>ZZ*WN1*5~2nx8kAvh5qVtgu+ z1lb~DhRlF)cxu5GSYM_Pf|DUAydHSXP_r*ZFdCYz7O_Im&-4(S2H^=4LvT8#)_;t& z7L1Wn+E9iJ$Rf$fgiO?5pHD&oO3?%L5S$Ik70H31WsDp=T5?GQ-KE4Of>BuF5GjCE zixfgCMR1fQW|3l)zr-V2FjB>5B&!rsC(;bEN(6(txJCq{v$$HM98xLL0%8`y`cUji zYrz#*Q_gtI9^496=ds|{kjF(TA)`dvKst)Fg`mpy5Zn%{QoTrf$Ptkakj)}^a^Yf; zPLRnI)_-tkSe0a9eJIQq=?V!IL5C}-7r7I1M5G&Jvq*Qy43QoXREr*ht03schV;aH zuxm#D!y#ab$;UKoWc7x;EYb%uN8~QZaFMU>tJJ-y$O*yF~0G zVGV--t(}9m)kE-T2*#ozV<284m@^xG@hNy5WR2vEhhS4Z1W$mVX$?U!vuz?1A^y7H zrGqEoG~#2)nhaSaavuckq=(=skO&c!GxH0PX^<5n(;*LvpdVzSyXztNeuyWn1<%Ck z%3ja>qXjfXL}o+o z6nPYKPqrBPn60tMV|d$lQDiRUpa_mKeS^q6NJERyhm=ds6AA0~M(iM-Cr|}i3HqQ`f=NIt!7Qwm1OUaq5bUzW+lXfgRJc}*9;6%HXVHF`eL`3b24H?fRBztjruAhLis5T|mo!m8c;w(zN^{z@8rm=G`E^Az0^mXmTx&9Wu{KuynbXiBE~G#7cr)DHokr z%f+;y<+dQ20y)=+lf?T34?l;8uU~(Z!%mk|Kq!4m?@SBFMW!D-<05g0V299u zu{(nuA_J43=Ra$(qHKQ>+^daKi)}T*y&C`Xpo%FTs;vo-&c;b+Z#|5|VYI&EqlGYAZG0s%{kIM+>E-=WQy1Sq1tBijoQ~Ua!e#-s&p8l%3 z4S&pG0N#k@a%>y7!E<^^W@{#YOY9>y5FAs+D7oAHwa);xIl1_7VsTA*z-8l4YoBny9Yh z^S+@fI>6m?+#PCWsQa}6L)A=^W8;#c{HEPf)XZk*~}Y3G=);P|WHn6Jnpf&t?{Z`CoyQQQ)zM_NlXnbtCcFaa$- zCte^PB6<>NNv#}RLo4TGTh6gnj^3e_b5<))Be?tKr-(XEW6f7FiC(8QN0-x@-$|4b zi9i|KtLz)%0I`OcO`z{-W$0L18TV>@7mdECHQP^cyJmdhW<2s{ES&LUhT%w+ULm+s zd+EDOt|BH8=($>HJb^~gN`4^TBi0g65#tHYq$P1c@!!O8;%#C9QBCmJ^skYOZ;-x% z7VRLG6SIh(D8E*eM{uGwz9{;dDL1i-c$nx%aPlf_1QeVlc;p2u3D%qO50SVC;IlQH zB(Q?>-zU})tP111o{mhhYV*ChjOKA)#y{QSapj@AX?fiV4*1-^i7yE5CYQU(ttMI$ zp+L@e1RFZ%IbtNymSFW{pCL99d@gR)0NNAmYFYN1eP|e6zDSb-apm7J~84ip9f~KVHE!bmHg3GEFZ60a*11= z7Zu~4*u!5QdCUZLUk_Y;70#B@gX!M22Yr$9W~V{u7`XPJKl-{i zI|6;bT-jx~X(BHT3vakw%rx1(6??7nb{9^Vpniz7b6_y|E2b^o(J4%@?D%w9b>~`zmCW2*z4zjmSDkwa9Cb zN|Dzg9Ip(%>oI+wGt!#x2FPBKHz0FFFmaV|K|=ZQBn(ddKQ8LB8Pb?31m7)~>Mt5; z&37y0pvX4J1`&)q{bB>U?{-Kl$$1NsDB{9;fX<=^-yM+m_1A~{z72a!vQX7U?M2>! zq>Ai<_=xPrvhkhB9?1J5ZV2ZY2H!eJJ`xPR?_wP}ZKO5d_fUTQ&8nV-n$j;h&;`3H z=qKBK0O9(|;QJv~n1))|2jL9N;JY7EV5Bu)%zAl0h#Y{Rf9k>aW5_)ovHN0Id0cZC zd_Te3^OKR*d=Ei5cQW`MhAcMHn(q#O?eF_J zY?5Ss0Vx&v5)viy6&AO@L{32PJU#egWzT+A%Ce<*=5Y&76Xpt+BT#>6-IkBl8eE)`Q6uAbuSL8aRp=11mHPq+}Q8=I* zuvM}hh9_?EcfH&xV|Rl4^H(OQ4MFZ_<65gLjqw9B6Zk7L_wrX}CaQ1R*)b*QA!H(^ zjQJwyN&01u^pMGr&XRK<#3nKY;x954v&4CkX^{OQ(;@3bWA?~5#eyaK^-p@yG?VgGsvc?!}(WFbVl zRtUOZKKg*MSuJFz$YRI}k*6W3Fg=7UfeaK`3Mm(P1`?;gJ{}2KhAHftWIYQxA%cOD zw^QUf$O@6=kOxKZXu}*B@;oG7a$dj`hTf`&kd=^cL|#Psb9ae3k%evb5V8s~OJp_V z9ucg``UyTg1T#c#yyT!lb7bg+tby#6oL3>(R1YC*A#*%p4?#2L4416eAnimjaC1^b zuqJ0;5ZM4ZAo2zTo9ZD112=nt$R@}*k!ZNrRsLF7%y0g>&H z*G1lfED*uOmNiaf2c)aW+mJ93w4(k`ThBxDvHAM$-L$%>O7lfVS_d+ZDDG` zND!p62($lHQP9{%23KC4M^c+g5)$bLvNKfr1k?jdDBaqAYw#lAlekQDRPq_ zhDoncPcR26ddwK6X?!DamKECH@VP->(HTEH2<;+CfICOV4)CaX15~#1(R!bHj zk1?g2#S0iCIt5zG=-POXNmUY0!-gs2tqIO=7;fseZ#^ru53fs?M1+`QcqBI_twa&3y zF;2GTJa~8_MK67h%afRoYbB(PP>9wO}KK427RZe9nDo;{>Ku Ij&0M;zmZIct^fc4 diff --git a/Crusader.rep/idata/01/~00000015.db/db.86.gbf b/Crusader.rep/idata/01/~00000015.db/db.96.gbf similarity index 99% rename from Crusader.rep/idata/01/~00000015.db/db.86.gbf rename to Crusader.rep/idata/01/~00000015.db/db.96.gbf index b70c39ae748c631a4267f712e2249a0c43497464..1c04aa461e778cdbd55884f531e1e9e007691237 100644 GIT binary patch delta 44807 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 delta 26025 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 diff --git a/Crusader.rep/projectState b/Crusader.rep/projectState index 6244408..877ece6 100644 --- a/Crusader.rep/projectState +++ b/Crusader.rep/projectState @@ -3,6 +3,8 @@ + + diff --git a/Crusader.rep/user/00/~00000008.db/db.52.gbf b/Crusader.rep/user/00/~00000008.db/db.54.gbf similarity index 99% rename from Crusader.rep/user/00/~00000008.db/db.52.gbf rename to Crusader.rep/user/00/~00000008.db/db.54.gbf index 83c418da06a48a6a322b60c4c236738fd1c32528..b2eb540a9d8ebc517aa14cbdc6422a517210370d 100644 GIT binary patch delta 350 zcmZo@U~On%70@>@)G^W2(VD&gv;D`mNf#OgrV23fGMa8w^tG9uZNqqedZP`aG!xUx z>4~2Bd)RNMoypYO*RJY93oD`q@=@0bAFyFmKs8f4$TcK1 z$S*!5GQd?y0Yus=6_*rc=A|nsggN?z0=cDmDXD3hd8sK7gC^QD8dL^*y8Af-H4@aL z5L%FuSd!|Pm*SFHT##6joS^|X&q$#l5$K6{LmdSSF(XYS1${eSE*pKH#Nv{8m|yGw D+qZM; delta 301 zcmZo@U~On%70@>@)G^W2(b9{${Dv|*HHVwyjFo(-cjyMcw3fq{|X^o6#JmK-KXJc;SQfI_k!jzRGO{=rHLA&~*D zwn~|KB}ximjy|D4wy`ltm&9}+=9%U)FQo{{A93=dM>GHiKRIu zE^w*owRVi*Tp^zRe(|n;AwiMT8-Zp(Z8k6fn<(ew>E{~n7wU`6RznMjt>N~J23#Tj m-mZS}A+8Z2AY;Vk)Y40=L0CyaALv&beV@eQl6W7eTkHUTuUPH? diff --git a/Crusader.rep/user/00/~0000000d.db/db.5.gbf b/Crusader.rep/user/00/~0000000d.db/db.7.gbf similarity index 99% rename from Crusader.rep/user/00/~0000000d.db/db.5.gbf rename to Crusader.rep/user/00/~0000000d.db/db.7.gbf index 5e2d55c9dba6b46415148e21a6f72bd9b92af644..4a45395a3850a8ecd15e5dff899f92d8aa5ad92d 100644 GIT binary patch delta 214 zcmZo@;A&{#63{m=)G^W2(aQ7Z@LaboE3{FdRe*7;028kRB;sb*G-Gdx`<9+;{9YZ|*{TLXSSf`iNGP$stnOhi|OkYsPBr*MJEt4{WFF9ST zjwzcZA}BR&`s6w$dtEan1${eSE(IX4aSRG_j8yP*^mVmWig)(+4TukL4DnD>2#E{; xie%=MfK6l$a&?>jzK%(W)yUK|$pT_aVLg+afQ`OSVsS~lPkwS@NoIbY9RS>xJplj! delta 224 zcmZo@;A&{#63{m=)G^W2(K>f;d4`LUAw#1;s{rFx0VZAt#-NRgHn!8FYMEN5r`9n^ zP2W+=Bs+ah9aD~wTWMZ$NoIatP-;nOQC>)8LF#m#dM5knyX%-FS=>VXoTtmyF)4vH za0j`Dga-M=heQUrPM=rHB+glymy(*6nU|U}eQzz3#Pmz`Omfo?*D?ul279{uIRX_! z)Y-$;DHIe}#3v^vXQalL0IiBoEGmglNi9w;$}A|!FVfIdQqZ^K<+9QDNh~gj_sLIA I1UbzP0G6^$5&!@I diff --git a/docs/entity-dispatch-entry-class-layout.md b/docs/entity-dispatch-entry-class-layout.md index faf41e9..0adeb2e 100644 --- a/docs/entity-dispatch-entry-class-layout.md +++ b/docs/entity-dispatch-entry-class-layout.md @@ -279,10 +279,28 @@ That is no longer true after the next live pass on 2026-04-07. - `+0x46/+0x48 = owned_buffer_a` - `+0x4a/+0x4c = owned_buffer_b` - Those two runtime-state methods now carry provisional `EntityDispatchEntryRuntimeState * this` signatures and in-session comments tying them back to the older `000d:` evidence, which is enough to treat the runtime-state lane as class-authored rather than only documented. +- The next derived-family step is now landed too for the periodic/timed branch in the live `11e0:` substrate segment. Six more methods are re-anchored from the older `0008:` note cluster by preserved offset delta from `0008:ba00 -> 11e0:0000` and now live under `Remorse::EntityDispatchEntry` with short provenance comments: + - `11e0:14fb Process_Create_0x36byte` -> `ConstructVtable3AD2` (older note anchor `0008:cefb`) + - `11e0:1814 Process_Init0x40ByteProc` -> `ConstructVtable3AA6` (older note anchor `0008:d214`) + - `11e0:187e Process_Set_MaybeTimesPerSecond` -> `SetUpdatePeriodAndReschedule` (older note anchor `0008:d27e`) + - `11e0:1913 FUN_11e0_1913` -> `TickPeriodic` (older note anchor `0008:d313`) + - `11e0:19e6 Process_11e0_19e6` -> `EnableActiveCounters` (older note anchor `0008:d3e6`) + - `11e0:1a33 Process_11e0_1a33` -> `DisableActiveCounters` (older note anchor `0008:d433`) +- The earlier word-list blocker is now closed too, but by re-anchoring rather than by `11e0:` boundary repair. The expected live `11e0:2000..25a1` window is not code in the current database; the actual word-list-owned subtype lives in the `11e8:` `MList_*` cluster, with the root at `11e8:0000` carrying explicit old `0008:da00` segment metadata in the decompiler. That full batch now also lives under `Remorse::EntityDispatchEntry` with short provenance comments: + - `11e8:0000 MList_11e8_0000` -> `SetWordList0408Terminated` (older note anchor `0008:da00`) + - `11e8:01a3 MList_11e8_01a3` -> `FreeWordList` (older note anchor `0008:dba3`) + - `11e8:01ec MList_11e8_01ec` -> `Destroy` (older note anchor `0008:dbec`) + - `11e8:0238 FUN_11e8_0238` -> `EnsureWordListContains` (older note anchor `0008:dc38`) + - `11e8:02ab MList_11e8_02ab` -> `AppendUniqueWord` (older note anchor `0008:dcab`) + - `11e8:03af MList_11e8_03af` -> `RemoveWordValue` (older note anchor `0008:ddaf`) + - `11e8:04ea MList_GetInt16` -> `GetWordAt` (older note anchor `0008:deea`) + - `11e8:051b MList_11e8_051b` -> `SetWordAt` (older note anchor `0008:df1b`) + - `11e8:05a1 FUN_11e8_05a1` -> `FindUnflaggedWordById10` (older note anchor `0008:dfa1`) +- That correction matters more than the names alone. The pilot family is no longer blocked on a missing word-list method surface; the remaining uncertainty is now about how explicitly the word-list-owned subtype should be split in datatypes and eventual C++ modeling, not about whether those methods exist in live `CRUSADER.EXE`. ## Questions To Close Later -- the remaining live `CRUSADER.EXE` method mapping for the note's old `0008:` / `000d:` anchors after the first `11e0:` base-method port and the `1440:` runtime-state port, especially `entity_word_list_destroy` and the timed/periodic constructors around old `0008:cefb` / `0008:d214` +- whether the live `11e8:` word-list-owned subtype should stay modeled as a method batch under `EntityDispatchEntry` alone or be split further into an explicit derived/overlay class once a safe instance-size boundary is chosen - whether `+0x00` should be modeled as a literal `kind` field in all variants or only in some factory-built subtypes - exact ownership split between the base object and the embedded surfaces at `+0x1e` and `+0x28` - whether the seg126 startup/display subtype is truly part of the same inheritance family or only shares a lower-level dispatch-entry substrate diff --git a/docs/entity-vm-runtime-owner-resource-layout.md b/docs/entity-vm-runtime-owner-resource-layout.md index 9a1c502..aa1927c 100644 --- a/docs/entity-vm-runtime-owner-resource-layout.md +++ b/docs/entity-vm-runtime-owner-resource-layout.md @@ -72,17 +72,18 @@ Strong anchors: Best current helper shape: -- compact file-backed helper object -- helper-owned count at `+0x14` -- far-pointer table at `+0x10` -- paired 16-bit table at `+0x18` -- helper vtable `+0x04` acts as size query -- helper vtable `+0x0c` materializes the `0x0d`-stride owner rows later consumed by contexts +- compact `0x14`-byte file-backed wrapper object +- first `0x08` bytes are the embedded file-handle base initialized by `File_MallocOrInit8Bytes` +- helper vtable/dispatch pointer lives at `+0x08` +- materialized owner-row table far pointer lives at `+0x0c` +- helper vtable `+0x04` acts as the current best size/query callback +- helper vtable `+0x0c` materializes owner data; the thin wrapper now asserts if the first output byte is `0xff` Current safest interpretation: - this is the most bounded class-lift target in the VM lane - it looks like a real helper object with a compact stable layout and a clear owner relationship to `EntityVmRuntime` +- the earlier `+0x14` / `+0x18` count-and-table claims belong to the downstream materialized loader data, not to the outer `0x14`-byte wrapper itself ### seg070 loader contract @@ -172,9 +173,9 @@ Verified first batch landed in the live `CRUSADER.EXE` session on 2026-04-05. - Created namespace `Remorse` and class owners `Remorse::EntityVmOwnerResource`, `Remorse::EntityVmRuntime`, and `Remorse::EntityVmContext`. - Created provisional datatype `/Remorse/EntityVmOwnerResource` with current stable anchors: - - `+0x10 owner_row_table` - - `+0x14 entry_count` - - `+0x18 entry_word_table` + - first `0x08` bytes reserved for the embedded file base + - `+0x08 helper_vtable` + - `+0x0c owner_row_table` - Created provisional datatype `/Remorse/EntityVmRuntime` with size `0x1319` and only the currently stable tail anchors around the owner-resource attachment lane. - Created provisional datatype `/Remorse/EntityVmSlotEntry` with size `0x26` and only the currently stable tail buffer fields named: - `+0x1e owner_buffer_offset` @@ -296,6 +297,11 @@ Verified first batch landed in the live `CRUSADER.EXE` session on 2026-04-05. - `1420:1601 Remorse::EntityVmRuntime::Destroy` -> `byte __cdecl16far Destroy(EntityVmRuntime * this, word destroy_flags)` - `1420:10b6/10da/1162/118f/1278 Remorse::EntityVmContext::{FreeBuffer, SyncGlobalValueAndDispatch, Destroy, Save, Load}` now all carry explicit `EntityVmContext *32 this` - That leaves `CreateFromSlotIndex` as the one clearly still-complex VM signature in this family cluster: the body still shows a far `this`, but the remaining argument pack needs a dedicated caller-side recovery pass rather than another pointer-only rewrite. +- Verified sixteenth live batch landed on 2026-04-08. +- Re-read `1430:0000 Remorse::EntityVmOwnerResource::Create` and `1430:00fd Destroy` against the live decompiler and corrected the outer-wrapper model: the object itself is only `0x14` bytes, with the first `0x08` bytes acting as the embedded file base, the helper vtable pointer at `+0x08`, and the materialized owner-row table far pointer at `+0x0c`. +- Moved `1430:014c` under `Remorse::EntityVmOwnerResource` as `MaterializeChecked` after confirming from `InitSlotOwnerBuffers` and `EnsureSlotChunkLoaded` that it is the thin wrapper over helper vtable slot `+0x0c` used to materialize owner data and assert on `0xff` sentinel failure. +- Moved `1430:0195` under `Remorse::EntityVmOwnerResource` as `QueryMaterializationSize` after confirming it is the adjacent thin wrapper over helper vtable slot `+0x04`, with the current safest read still being the same size/query callback already seen from the `Create` path. +- Added short decompiler comments at `1430:014c` and `1430:0195` so the callback-slot evidence remains visible in-session without pretending the full seg069/070 helper contract is closed. - Verified fifteenth live batch landed on 2026-04-06. - Recovered the mixed caller pack on `1420:0eec Remorse::EntityVmContext::CreateFromSlotIndex` far enough to replace the old anonymous split arguments with caller-backed names: - `dword owner_source_farptr` @@ -317,6 +323,7 @@ Verified first batch landed in the live `CRUSADER.EXE` session on 2026-04-05. Current live datatype state: - `/Remorse/EntityVmOwnerResource` is the cleanest landed class in this lane so far. +- Its current stable outer-wrapper model is now tighter too: embedded file base at `+0x00..+0x07`, helper vtable at `+0x08`, and materialized owner-row table far pointer at `+0x0c`. - `/Remorse/EntityVmRuntime` currently only freezes the stable tail fields and helper pointer, not the full slot-entry schema. - `/Remorse/EntityVmSlotEntry` now exists both as a bounded helper datatype and as a live `Remorse` class owner. Its current authored surface is intentionally small: one constructor/clear method plus the stable `match_key_farptr`, `owner_chunk_count`, `owner_data_base`, and owner-buffer / chunk-state pointer anchors. - `/Remorse/EntityVmLoadedChunkRecord` now exists as the shared cleanup/iteration record for the chunk-release and conditional-unload lane, with the currently stable next-link, saved-owner-buffer, slot-index, and chunk-index fields named. @@ -335,7 +342,7 @@ Current live datatype state: Current scope of that batch stayed intentionally conservative: - no final source-format schema naming for the owner rows -- no speculative promotion of additional seg069/070 helper callbacks into owned methods yet +- no speculative promotion of additional seg069/070 helper callbacks beyond `QueryMaterializationSize` and `MaterializeChecked` - no speculative promotion of the masked-create wrapper ladder into `EntityVmContext` methods - no speculative typing yet for the entity-like pointer parameter on `AcquireSlotForEntity` - no attempt yet to force slot-entry field names beyond the stable `+0x1e..+0x24` tail region and the current conservative helper prototypes diff --git a/docs/presentation-callback-broker-layout.md b/docs/presentation-callback-broker-layout.md index 623328f..8bf0d81 100644 --- a/docs/presentation-callback-broker-layout.md +++ b/docs/presentation-callback-broker-layout.md @@ -200,6 +200,26 @@ Why not first: 3. decide whether `0x45a6` is an owned buffer, fallback object, or adapter scratch lane 4. tighten the constructor/installation provenance in the live NE program, not only the raw notes +## Live Ghidra Authoring Status + +Verified first live `PresentationCallbackBroker` batch landed on 2026-04-08. + +- Created class owner `Remorse::PresentationCallbackBroker` in the active `CRUSADER.EXE` database. +- Re-anchored the global install/teardown pair into live `12d0:` helpers by direct access to the `0x4588/0x458c/0x4590/0x4594/0x4595/0x45a6` broker globals: + - `12d0:0513` -> `InitOnce` + - `12d0:0656` -> `TeardownOnce` +- Added short decompiler comments to both methods so the current `0x4588` lifecycle remains visible in-session: + - `InitOnce` now records the `0x4594` guard, state snapshot into `0x458c/0x4590`, broker install at `0x4588`, and fallback-buffer allocation at `0x45a6`. + - `TeardownOnce` now records the `0x4595` guard, broker clear, conditional slot `+0x0c` emit when `0x4590 != 0x458c`, slot `+0x04` release, and final cleanup path. +- Re-anchored the finalize-phase caller as well: `1288:0fc3` is now `allocator_phase_finalize_pass` in the live database with a comment recording that it exercises broker slot `+0x08` twice before sweeping allocator heads. +- Preserved two verified live slot `+0x0c` callers with decompiler comments instead of forcing premature renames: + - `1278:0616 Vport_1278_0616` uses the installed broker callback when the local vport path takes its fallback branch with `param_2 == 0`. + - `1320:1588 Dispatch_ModalGump` emits the broker callback before and after modal dispatch when the requested state pair differs from the current mode snapshot. +- This remains intentionally conservative live authoring: + - no forced `this` typing yet for the broker pointer parameter on `InitOnce` + - no live promotion yet of `allocator_phase_finalize_pass` under the class owner itself, because it is a broker caller rather than a broker method + - no attempt yet to rename the wider subsystem beyond the existing `PresentationCallbackBroker` placeholder + ## Bottom Line The `0x4588` family is now documented well enough to be treated as a real object candidate. diff --git a/docs/remorse-class-candidate-inventory.md b/docs/remorse-class-candidate-inventory.md index e3170a1..a68ea18 100644 --- a/docs/remorse-class-candidate-inventory.md +++ b/docs/remorse-class-candidate-inventory.md @@ -60,6 +60,58 @@ If the goal is to make later class-authoring work fast and low-risk, the best or This order prioritizes bounded families with visible constructors, derived variants, or explicit method tables before the larger gameplay and VM surfaces. +## Broad Sweep Priorities + +The earlier class-lift lane focused on proving a few pilot families end to end. After the recent live authoring batches, the next useful broader sweep is smaller and more structured than the raw inventory table alone suggests. + +### Tier 1: Ready Or Already Started + +These families now have enough evidence or live foothold that they can be treated as the main near-term queue rather than as speculative future ideas. + +1. `EntityVmOwnerResource` + +- Why it is next-ready: bounded helper object, explicit create/destroy pair, stable callback slots at `+0x04` and `+0x0c`, and already-strong loader/table layout evidence. +- Why it broadens coverage well: it adds a non-UI, non-dispatch, non-debugger object family with a compact file-backed contract. + +2. `CacheBackendObject` + +- Why it stays in Tier 1: it is still a compact object with a concrete `0x20` size and explicit method-table state. +- Current live status: the constructor shell is now started in `CRUSADER.EXE` as `Remorse::CacheBackendObject::Create` at live `1250:0000`, backed by the decompiler's explicit old `0009:5600` segment metadata. + +3. `SpriteNode` + +- Why it stays active even in a broader sweep: its core live surface is now materially landed, but the constructor-wrapper split, deeper slot semantics, and subtype boundary questions remain open. +- Current live status: class owner plus first method batch and first datatypes already exist in-session, so future broader work can deepen it selectively instead of rediscovering it. + +### Tier 2: Good Broader Identification Targets + +These families are strong enough to be promoted intentionally in a wider identification pass, but they still benefit from one more bounded evidence sweep before heavy datatype work. + +1. `WatchEntityController` + +- Why it stands out: global object ownership is clear, create-global and direct create paths are already named, and vtable dispatch at `+0x24`, `+0x2c`, and `+0x30` is explicit. +- Main current caution: the wider subsystem label is still weaker than the local object mechanics. + +2. `DialogMenuObject` + +- Why it stands out: small UI/dialog object with one stable vtable (`0x28b5`) and multiple event-notify wrappers that already behave like owned methods. +- Main current caution: destructor and richer layout evidence still trail the create/event surface. + +3. `PresentationCallbackBroker` + +- Why it still belongs in the broader class map: object lifecycle and vtable-slot surface are real, and it gives the broader sweep one presentation-side callback family. +- Main current caution: subsystem naming is intentionally conservative and should probably remain that way until installation provenance tightens further. + +### Tier 3: High-Value But Bigger Families + +These are absolutely class-worthy, but they are better treated as longer arcs than as quick additions to a broad identification pass. + +1. `Entity` +2. `EntityVmRuntime` +3. `EntityVmContext` + +The common pattern here is that they are already clearly object-shaped, but each carries enough subtype, caller, or schema breadth that broad identification alone is not the main problem anymore. + ## First Pilot Candidates ### Best pilot: `EntityDispatchEntryBase` diff --git a/docs/remorse-class-lift-index.md b/docs/remorse-class-lift-index.md index b9845c7..457cbd5 100644 --- a/docs/remorse-class-lift-index.md +++ b/docs/remorse-class-lift-index.md @@ -1,3 +1,19 @@ + +That `aux_farptr` lane also survived one more direct caller pass without widening. `CallstackPushFrame` still has only the retail `1418:051d Interpreter_NextUsecodeOp` caller, that caller still pushes literal zero for the trailing field, and the current seg109 consumers still read only `+0x09` and `+0x0d`, so the field remains intentionally neutral rather than weakly renamed. + +That first `SpriteNode` batch now includes datatype authoring too. `/Remorse/SpriteNodeBase` and `/Remorse/SpriteNodeVtable` both exist live with the current safest base offsets and event-slot anchors, so the family is no longer just a method-owner shell. + +The constructor side has now started too. `1360:036a` lives as `Remorse::SpriteNode::Create` with an explicit comment that preserves the remaining caveat: this is the current safest constructor-style anchor because it allocates `0x34` bytes, stamps the `0x501a` vtable, and initializes the core node lanes, but it may still prove to be a higher derived/UI wrapper once more subtype evidence lands. The main remaining `SpriteNode` gap is therefore the live `GetOrTraverse` anchor, not whether the family has any constructor surface at all. + +That traversal gap is now closed too. `1360:0955` is live as `Remorse::SpriteNode::GetOrTraverse`, with a comment recording that it recurses through the child-linked subtree, adjusts query coordinates by the local offsets, and returns either the matched child node or the default sentinel through the out pointer. The remaining `SpriteNode` questions are now the constructor-wrapper split and the deeper slot/layout story rather than missing core method anchors. + +The next bounded family after `SpriteNode` is started too. `Remorse::CacheBackendObject` now exists live with `1250:0000` promoted as `Create`, backed by the decompiler's explicit old `0009:5600` segment metadata and a comment recording the `0x20`-byte object allocation plus file-handle/method-table initialization path. That family is still only at its constructor shell, but it is no longer inventory-only. + +That broader Tier 1 sweep is now complete too. `EntityVmOwnerResource` is no longer just a create/destroy shell: the outer wrapper model is corrected to a `0x14`-byte file-backed object with helper vtable at `+0x08` and materialized owner-row table at `+0x0c`, and the two adjacent `1430:` wrappers now live under the class as `QueryMaterializationSize` and `MaterializeChecked`. `CacheBackendObject` also moved beyond its constructor shell: `1250:026c` is now `LoadEntryTableFromManifest`, `1250:0749` is now `InitFixedEntryTable`, and the live decompiler now supports a tighter `0x20`-byte layout read around the `+0x10/+0x14/+0x16/+0x18/+0x1c` entry-table lanes. `SpriteNode` slot work tightened as well: `DispatchEvent` now maps event codes `1/2/4/8/0x10/0x20/0x40/0x100` onto concrete vtable offsets instead of the earlier generic `A/B/C/D` placeholders. + +The next broader shortlist is now partially started as well. `PresentationCallbackBroker` has its first live foothold in `CRUSADER.EXE`: `12d0:0513` and `12d0:0656` now live under `Remorse::PresentationCallbackBroker::{InitOnce,TeardownOnce}` with comments tied to the `0x4588` lifecycle globals. The same pass also clarified what is *not* ready yet: first-pass live searches for `WatchEntityController` (`0x2c2b`, `0x2be4`, `0x39ca`, `0x0219`) and `DialogMenuObject` (`0x28b5`, `0x27ca`, `0x2843`) hit camera/process and controller-save false positives rather than safe reanchors, so those two families remain documented candidates but not yet live-authored classes. + +That next-pass follow-up is now tighter too. The raw `WatchEntityController` lane no longer needs to stay completely abstract: its `0007:ba00/ba45` create pair maps onto the live `Camera_Init` / `Camera_CreateProcess` cluster at `1180:0000/0045`, and those functions now carry provenance comments instead of forcing a weaker duplicate rename over the clearer camera-process naming. `DialogMenuObject` remains the one compact family in this batch that still lacks a safe live re-anchor: second-pass searches on the obvious `0x28b5/0x27ca/0x2843` leads still landed on unrelated process/save helpers, so that family stays note-backed but not yet live-authored. `PresentationCallbackBroker` also has its first non-method live adjunct now: `1288:0fc3` is renamed `allocator_phase_finalize_pass` with a comment recording the two broker slot `+0x08` calls before allocator-head sweep, and two slot `+0x0c` caller sites (`1278:0616`, `1320:1588`) now carry caller-evidence comments in-session. `CacheBackendObject` advanced another bounded step as well: `1250:0910` now lives under the class as `SetEntryNameAndTag`, and the latest `SpriteNode` caller pass supports treating `Create` as the compact shared node constructor used by the larger `GumpCreate_*` wrapper family. # Remorse Class-Lift Work Index ## Purpose @@ -88,6 +104,25 @@ The future MCP endpoint sequence should follow the spec note rather than ad hoc 3. Add one more dedicated note for the callback/object lane around `0x4588` only if later caller evidence supports a stronger subsystem name than `PresentationCallbackBroker`. 4. Turn the first-class-authoring checklist into a completed execution log once the first real MCP batch lands. +## Broader Sweep Shortlist + +The broader class-identification pass is now narrow enough to be explicit. + +Current best near-term shortlist after the recent live authoring work: + +1. `WatchEntityController` +2. `DialogMenuObject` +3. `PresentationCallbackBroker` +4. deeper `CacheBackendObject` follow-up around `1250:0910` +5. `SpriteNode` subtype/layout follow-up beyond the recovered event-slot map +6. broader `Entity` family partitioning + +That ordering is deliberate: + +- the old Tier 1 set is now complete, and the next pass already resolved part of the follow-up list +- `PresentationCallbackBroker` still belongs on the map, but its subsystem label remains weaker than its mechanics even after the first live reanchor +- the last two items stay in view because they now have live footholds and cleaner remaining follow-up than they did before + ## Current Live Authoring Snapshot The live `CRUSADER.EXE` class-authoring lane is no longer just a plan. @@ -106,6 +141,12 @@ The next planned pilot family is no longer purely preparatory either. `Remorse:: That family also has its first derived slice now. The old `000d:7e00/8078` runtime-state pair is re-anchored in the live `1440:` fade/palette cluster as `InitRuntimeState` and `ReleaseRuntimeState`, and `/Remorse/EntityDispatchEntryRuntimeState` now exists as a provisional overlay datatype with the recovered `+0x40..+0x4c` runtime-state tail fields. That is a meaningful pause point because the pilot family now has a class owner, a base datatype, a vtable shell, a first base-method batch, and one concrete derived/runtime-state batch rather than just one isolated constructor lane. +That pause point has moved again. The timed/periodic derived branch is now partially lifted in-session too: `ConstructVtable3AD2`, `ConstructVtable3AA6`, `SetUpdatePeriodAndReschedule`, `TickPeriodic`, `EnableActiveCounters`, and `DisableActiveCounters` are now owned by `Remorse::EntityDispatchEntry` in the live `11e0:` substrate segment with short `0008:` provenance comments preserved. + +The earlier word-list blocker on that same family is now closed by a re-anchor correction rather than by local boundary repair. The old `0008:da00..dfa1` word-list lane does not live in the dead `11e0:2000..25a1` window after all; it reappears as the live `11e8:` `MList_*` cluster, and that full batch is now also owned under `Remorse::EntityDispatchEntry`: `SetWordList0408Terminated`, `FreeWordList`, `Destroy`, `EnsureWordListContains`, `AppendUniqueWord`, `RemoveWordValue`, `GetWordAt`, `SetWordAt`, and `FindUnflaggedWordById10`. The main remaining `EntityDispatchEntry` question is therefore no longer "where did the word-list methods go," but whether that `11e8:` subtype should eventually become its own explicit derived/overlay class in the datatype model. + +The next family switch has now started for real too. `Remorse::SpriteNode` exists live in `CRUSADER.EXE`, and its first bounded `1360:` batch is no longer just a note: `Destroy`, `IsDirty`, `MarkDirty`, `DispatchEvent`, and `UpdateAndDispatch` are now class-owned with short `000b:` provenance comments. That shifts the `SpriteNode` family from note-only planning into the same live-authoring lane as the earlier Remorse pilots, while still keeping the constructor side and `GetOrTraverse` mapping deliberately open. + The latest signature-recovery pass also tightened two of those runtime methods materially: - `GetSlotChunkPtrAtOffset(runtime_farptr, slot_index, chunk_index, intra_chunk_offset)` now reads as a real slot-chunk accessor instead of a five-word anonymous wrapper. @@ -123,6 +164,8 @@ The next debugger pass tightened the bounded helper and callback edges too. `140 The follow-up seg109 consumer pass is also done now. `13a0:0291` and its local helper `13a0:045c` are documented in-session as the first concrete consumers of the current callstack entry's trailing payload: they read entry `+0x09` as a descriptor/source-stream cursor and entry `+0x0d` as the current-frame payload context while formatting debugger dump/watch text. That cursor name is now promoted into the live `/Remorse/UsecodeDebuggerCallstackEntry` datatype and the `CallstackPushFrame` signature too, which means the remaining open callstack question is mostly the unused `aux_farptr` lane rather than the first two dwords. +That formatter consumer lane is no longer just comment-backed either. The two seg109 helpers now have stable live names in `CRUSADER.EXE`: `13a0:0291` is `usecode_debugger_format_expression_to_shared_buffer`, and `13a0:045c` is `usecode_debugger_format_descriptor_expression`. That keeps the debugger-family residue focused where it belongs now: mainly the still-neutral `aux_farptr` lane and any later evidence for non-retail callback behavior, not anonymous formatter plumbing. + The VM lane also advanced one more selective step without overpromoting inheritance: `Remorse::EntityVmContext::CreateFromSlotIndex` now has a caller-backed mixed parameter pack (`owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, `ucparamsize`) and an explicit far return restored in `AX:DX`, even though the current live endpoint still textualizes that repaired signature conservatively as plain `dword __cdecl`. ## Bottom Line diff --git a/docs/sprite-node-class-layout.md b/docs/sprite-node-class-layout.md index 9aa6822..6d272eb 100644 --- a/docs/sprite-node-class-layout.md +++ b/docs/sprite-node-class-layout.md @@ -109,14 +109,19 @@ So the safe future modeling strategy is: ## Candidate Virtual Slot Map -The currently verified slots are already good enough for a first typed vtable. +`DispatchEvent` now gives a materially tighter slot map than the earlier placeholder `A/B/C/D` read. | Slot offset | Current best role | Evidence | |---|---|---| -| `+0x14` | event handler A | `sprite_node_dispatch_event` dispatches here for one event class | -| `+0x18` | event handler B | same dispatcher | -| `+0x20` | event handler C | same dispatcher | -| `+0x24` | event handler D | same dispatcher | +| `+0x04` | event `1` handler | `DispatchEvent` routes event code `1` here directly | +| `+0x08` | event `2` handler | same dispatcher | +| `+0x0c` | event `4` handler | same dispatcher | +| `+0x10` | event `8` handler | same dispatcher | +| `+0x14` | event `0x10` handler | same dispatcher | +| `+0x18` | event `0x20` handler | same dispatcher | +| `+0x1c` | event `0x40` self handler | called after the dispatcher walks child nodes for the same event | +| `+0x24` | event `0x100` handler | same dispatcher | +| `+0x34` | child-broadcast event `0x40` slot | used on child nodes during the `0x40` walk, not on the root dispatch object itself | The seg091 default-slot helpers are also useful evidence: @@ -153,11 +158,45 @@ When class authoring begins, the safest sequence for this family is: 4. create provisional vtable with slots `+0x14`, `+0x18`, `+0x20`, `+0x24` 5. keep recursive tree helpers outside the class until decompiler output shows they benefit from becoming methods +## Live Ghidra Authoring Status + +Verified first live `SpriteNode` batch landed on 2026-04-08. + +- Created class owner `Remorse::SpriteNode` in the active `CRUSADER.EXE` database. +- Re-anchored the strongest old `000b:` method batch into the live `1360:` segment by preserved offset delta from `000b:326e -> 1360:046e`. +- Created minimal live datatypes `/Remorse/SpriteNodeBase` and `/Remorse/SpriteNodeVtable` from the current safest note anchors. +- `/Remorse/SpriteNodeBase` currently names only the bounded field block that is directly supported by the live method batch: + - `+0x19 = child_or_next_farptr` + - `+0x21 = local_x_offset` + - `+0x23 = local_y_offset` + - `+0x29 = dirty_flags` +- `/Remorse/SpriteNodeVtable` is still the earlier minimal shell in-session, but the live `DispatchEvent` read now supports a deeper slot map than the first authoring batch encoded: + - direct self dispatch uses `+0x04`, `+0x08`, `+0x0c`, `+0x10`, `+0x14`, `+0x18`, `+0x1c`, and `+0x24` + - child broadcast during event `0x40` uses child slot `+0x34` +- Moved the first bounded method set under the class owner with short provenance comments: + - `1360:036a` -> `Create` (best current constructor-style anchor; still keep the higher-wrapper caveat visible) + - `1360:046e` -> `Destroy` (older note anchor `000b:326e`) + - `1360:0580` -> `IsDirty` (older note anchor `000b:3380`) + - `1360:05a6` -> `MarkDirty` (older note anchor `000b:33a6`) + - `1360:0955` -> `GetOrTraverse` (best current live anchor for older note anchor `000a:b988`) + - `1360:0cb2` -> `DispatchEvent` (older note anchor `000b:3ab2`) + - `1360:12ee` -> `UpdateAndDispatch` (older note anchor `000b:40ee`) +- The live decompiler now makes the core family surface much easier to navigate directly in-session: + - `Create` now exists live as the current safest constructor-style anchor: it allocates `0x34` bytes when `this` is null, stamps the `0x501a` SpriteNode vtable, initializes the child-link/core offset fields, and links the incoming parent/child lane. + - Direct callers now narrow the subtype story materially: the current call set is dominated by `GumpCreate_*` and adjacent UI wrapper constructors, which supports treating `Create` as the compact shared base-node constructor used by higher-level gump/display objects rather than as a one-off derived leaf. + - `Destroy` restores the `0x501a` base vtable, clears the global focus pointer when `this` owns it, releases child linkage, and optionally frees self. + - `IsDirty` and `MarkDirty` read and mutate the `+0x29` dirty-state lane exactly as the note predicted. + - `GetOrTraverse` now exists live as the best current `000a:b988` re-anchor: it recursively walks the child-linked subtree, adjusts the incoming query coordinates by the local offsets, and returns either the matched child node or the default sentinel through the out pointer. + - `DispatchEvent` updates the global focus pointer at `0x4fd0:0x4fd2` and now ties concrete event codes to concrete slot offsets: `1/2/4/8 -> +0x04/+0x08/+0x0c/+0x10`, `0x10/0x20 -> +0x14/+0x18`, `0x40 -> child +0x34 then optional self +0x1c`, and `0x100 -> +0x24`. + - `UpdateAndDispatch` now clearly shows the `IsDirty` / `MarkDirty` / recompute / child-walk sequence instead of staying as an anonymous seg1360 helper. +- The `SpriteNode` family is therefore no longer note-only. What remains open is narrower now: chiefly whether `Create` should remain the family's public constructor-style entry or later be split into a higher derived/UI wrapper and a smaller base-node constructor once more callers and subtype evidence land, plus the deeper vtable-slot and subtype-layout questions. + ## Open Questions +- whether the current `Create` signature itself can be cleaned up further now that its caller set points to a shared compact base-node constructor used by higher-level gump wrappers - exact root vtable address or addresses for the main SpriteNode family - whether the `+0x17e` redraw flag belongs to a derived display node rather than the compact base node -- which event-code cases map to which slot semantically beyond the current `A/B/C/D` placeholder naming +- whether the recovered event-code map can now be promoted from raw event-code labels to prettier semantic slot names without overfitting UI behavior too early - whether `sprite_tree_accumulate_pos` should become a class method, a static helper, or a separate geometry utility ## Immediate Follow-Up Value diff --git a/docs/usecode-debugger-break-state-layout.md b/docs/usecode-debugger-break-state-layout.md index af4292e..6faab63 100644 --- a/docs/usecode-debugger-break-state-layout.md +++ b/docs/usecode-debugger-break-state-layout.md @@ -204,11 +204,16 @@ Verified first live class batch landed on 2026-04-06. - `13a0:045c FUN_13a0_045c` now also carries a decompiler comment recording the same split from the consumer side: it reads descriptor bytes and inline strings directly from the `+0x09` lane and dereferences the `+0x0d` lane as the evaluation context while formatting debugger dump/watch text into the shared output buffer at `0x45a6`. - The `CallstackPushFrame` comment in seg1408 was updated to reflect that narrower live read: `+0x09` is no longer just a generic source-derived far pointer, but a real source-stream cursor used by the seg109 formatter path. - That naming decision is now applied live too. `/Remorse/UsecodeDebuggerCallstackEntry` now exposes `source_stream_cursor_farptr` at offset `+0x09` with a matching field comment in the datatype manager, and `CallstackPushFrame` now uses `source_stream_cursor_farptr` in its parameter list instead of the older `source_stream_target_farptr` wording. +- The seg109 consumer helpers are now named live as stable free functions rather than left comment-only: + - `13a0:0291` -> `usecode_debugger_format_expression_to_shared_buffer` + - `13a0:045c` -> `usecode_debugger_format_descriptor_expression` +- Those names are still intentionally conservative. They record the verified behavior now visible in both producer-side and consumer-side comments: `13a0:0291` resolves the current debugger callstack entry and writes the formatted result into the shared output buffer, while `13a0:045c` interprets the descriptor/source-stream cursor plus frame payload context rather than merely dumping raw bytes. - Added decompiler comments on the breakpoint and callstack helpers so the recovered inline-record layout is visible in-session even before every field is formally typed. - Added decompiler comments on the only verified `Interpreter_NextUsecodeOp` caller of `CallstackPushFrame`, which confirms the current live read of the three trailing callstack dwords: - `source_stream_target_farptr` is source-stream-derived from the interpreter `+0xd6/+0xd8` lane plus one fetched word - `current_frame_payload_farptr` is current-frame-derived from the `frame_base + 0x04` lane - `aux_farptr` is still zero in the only verified caller +- A second caller pass on 2026-04-08 still did not widen that lane: `get_callers(1408:02f5)` still reports only `1418:051d Interpreter_NextUsecodeOp`, and the live `CallstackPushFrame` comment now records that the trailing `aux_farptr` slot remains literal zero in retail while the current seg109 consumers still only read `+0x09` and `+0x0d`. ## Current Cautions @@ -221,7 +226,7 @@ Verified first live class batch landed on 2026-04-06. 1. Cross-check the seg1408 class note against the interpreter callback site at `1418:04b5` so the dormant-orphan lifecycle remains explicit in the live notes now that slot 0 is confirmed to land on an inert retail stub. 2. Decide whether `aux_farptr` should remain neutral or can be promoted after one more caller or consumer pass. -3. Decide whether `13a0:0291` and `13a0:045c` are ready for stable debugger-UI names or should remain comment-backed until another direct caller or string anchor lands. +3. If the debugger family is revisited again, prioritize non-retail callback behavior or instantiation evidence before spending more time on the already-stable retail formatter lane. 4. If the debugger family stalls there, switch to the next planned class-lift family instead of overworking this orphaned subsystem. ## Bottom Line diff --git a/plan-mid.md b/plan-mid.md index b1561be..f677c2e 100644 --- a/plan-mid.md +++ b/plan-mid.md @@ -85,9 +85,21 @@ Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-renderi - The latest debugger class-lift pass closed two more bounded gaps without overpromoting semantics: `1408:0230` now lives under `Remorse::UsecodeDebuggerBreakState::BreakpointFindFirstForUnitAtOrAfterLine` as the breakpoint-table lower-bound helper for `(unit_name, line_number)` queries, and the retail vtable root at `1478:65ab` is now resolved enough to show that `MaybeBreakOnCurrentLine` dispatches slot 0 into a shipped no-op stub while slot 1 currently returns zero through a second inert method. - The next debugger follow-up also closed the planned seg109 consumer pass: `13a0:0291` plus its helper `13a0:045c` now show that the current callstack entry's `+0x09` lane is a real source-stream cursor consumed byte-by-byte by the debugger formatter and that `+0x0d` is the paired current-frame payload context used for expression/watch rendering. The remaining open tail-field question is now mostly `aux_farptr`, not the first two dwords. - That naming decision is now landed live rather than only in notes: `/Remorse/UsecodeDebuggerCallstackEntry` now names offset `+0x09` as `source_stream_cursor_farptr` with an in-session field comment, and `CallstackPushFrame` now carries the same parameter name in its signature. The debugger-family residue is therefore narrower again: mainly `aux_farptr`, plus whether the seg109 formatter helpers deserve stable names. +- That last formatter-helper hesitation is now closed too. The seg109 consumer pair is no longer anonymous in-session: `13a0:0291` now lives as `usecode_debugger_format_expression_to_shared_buffer`, and `13a0:045c` now lives as `usecode_debugger_format_descriptor_expression`. The debugger-family residue is therefore narrower again: mainly `aux_farptr`, plus any future evidence that the retail-stub callback slots ever had non-retail behavior. +- The follow-up retail caller pass did not widen `aux_farptr` either. `get_callers(1408:02f5)` still reports only `1418:051d Interpreter_NextUsecodeOp`, that caller still pushes literal zero for the trailing field, and the current seg109 formatter consumers still read only `+0x09` and `+0x0d`. For now the right live result is to keep `aux_farptr` intentionally neutral rather than invent a prettier but weak name. +- The next bounded class-family step landed too. `Remorse::SpriteNode` now exists live in `CRUSADER.EXE`, and the first strong `000b:` batch is re-anchored into live `1360:` by preserved offset delta from `000b:326e -> 1360:046e`: `Destroy` (`1360:046e`), `IsDirty` (`1360:0580`), `MarkDirty` (`1360:05a6`), `DispatchEvent` (`1360:0cb2`), and `UpdateAndDispatch` (`1360:12ee`) are now class-owned with in-session provenance comments. The remaining `SpriteNode` work is narrower and safer than before: mainly the constructor side, the exact live anchor for `GetOrTraverse`, and later vtable/datatype authoring rather than basic family existence. +- That same `SpriteNode` pass also moved beyond method ownership into datatype work: `/Remorse/SpriteNodeBase` now names `child_or_next_farptr`, `local_x_offset`, `local_y_offset`, and `dirty_flags`, and `/Remorse/SpriteNodeVtable` now exists as a provisional slot shell exposing `+0x14`, `+0x18`, `+0x20`, and `+0x24`. +- The constructor side is now started too: `1360:036a` lives as `Remorse::SpriteNode::Create` with an in-session caveat comment that preserves the remaining wrapper uncertainty. The live search for the old `000a:b988 GetOrTraverse` anchor is still open, but the family no longer lacks a constructor-style entry outright. +- That remaining traversal gap is now closed too. `1360:0955` now lives as `Remorse::SpriteNode::GetOrTraverse`, and the decompiler comment records the currently safest read of the helper: recurse over child-linked nodes, adjust the incoming query coordinates by the local offsets, and return either the matched node or the default sentinel through the out pointer. The main `SpriteNode` residue is therefore structural again: constructor-wrapper split, deeper slot naming, and subtype layout boundaries. +- The next bounded-family start is now landed too. `Remorse::CacheBackendObject` exists live with `1250:0000` promoted as `Create`; the decompiler itself carries explicit old `0009:5600` segment metadata on that body, and the current comment records the `0x20`-byte allocation plus file-handle/method-table initialization path. That family is still only at its constructor shell, but it is now a live class-lift lane instead of a pure inventory entry. +- The broader Tier 1 Remorse class sweep is now closed too. `EntityVmOwnerResource` gained two real accessor wrappers in-session (`QueryMaterializationSize` and `MaterializeChecked`) plus a corrected outer-wrapper layout (`0x14` bytes total, embedded file base at `+0x00..+0x07`, helper vtable at `+0x08`, owner-row table at `+0x0c`); `CacheBackendObject` gained the first two non-constructor class methods (`LoadEntryTableFromManifest` and `InitFixedEntryTable`) plus a tighter live layout read around `+0x10/+0x14/+0x16/+0x18/+0x1c`; and `SpriteNode::DispatchEvent` now ties concrete event codes to concrete vtable slots instead of generic placeholder slot names. +- The next broader Remorse batch also has its first post-Tier-1 live foothold now. `PresentationCallbackBroker` is no longer note-only: `12d0:0513` and `12d0:0656` are now live as `Remorse::PresentationCallbackBroker::{InitOnce, TeardownOnce}` with comments tied directly to the `0x4588/0x458c/0x4590/0x4594/0x4595/0x45a6` lifecycle cluster. The same pass also clarified that `WatchEntityController` and `DialogMenuObject` still need a second re-anchor pass before any live authoring: first-pass searches on the obvious type/vtable/callback constants hit unrelated camera/process and controller-save functions rather than safe class-family matches. +- That second pass is now partly closed. The old `WatchEntityController` create lane maps onto the live `Camera_Init` / `Camera_CreateProcess` cluster at `1180:0000/0045`, so those functions now carry provenance comments instead of a weaker forced rename; `DialogMenuObject` still lacks a safe live re-anchor after a second search on the obvious `0x28b5/0x27ca/0x2843` leads; `PresentationCallbackBroker` now has its raw `0009:b1c3` finalize-phase caller re-anchored live as `allocator_phase_finalize_pass` plus two preserved live slot `+0x0c` callers at `1278:0616` and `1320:1588`; `CacheBackendObject` gained `SetEntryNameAndTag` at `1250:0910`; and the widened `SpriteNode::Create` caller map now shows that the `0x34` allocation path is the compact shared node constructor used by many `GumpCreate_*` wrappers. - The next planned pilot family also started for real: `Remorse::EntityDispatchEntry` now exists in-session with provisional `/Remorse/EntityDispatchEntryBase` and `/Remorse/EntityDispatchEntryVtable` datatypes, so this family is no longer just a note cluster. The remaining blocker is now concrete rather than vague: the current source note still points at older `0008:` / `000d:` anchors that are not yet ported back onto the live `CRUSADER.EXE` method objects, so the first base-method ownership move has to wait on that mapping step instead of being guessed. - That mapping step is now partially closed too. The older `0008:ba00` base cluster ports into live `11e0:` by offset, and the first base-method batch now lives under `Remorse::EntityDispatchEntry`: `InitBase`, `SetSourceType`, `SetEventTypeChecked`, `SetGroupId`, `Unlink`, and `IncrementGroupId`. The next blocker on this family is therefore narrower again: not whether the pilot can move methods at all, but which live segments carry the remaining word-list, timed/periodic, and runtime-state methods from the older `0008:` / `000d:` notes. - The runtime-state follow-up is now partially closed too. `FadeProcess_Create` is explicitly tagged by the decompiler as old `000d:7e00`, `FUN_1440_0278` matches the old `000d:8078` release path by both offset delta and behavior, and both now live under `Remorse::EntityDispatchEntry` as `InitRuntimeState` and `ReleaseRuntimeState` with a new `/Remorse/EntityDispatchEntryRuntimeState` overlay datatype. That leaves the remaining `EntityDispatchEntry` pilot work in a narrower end-of-day state: mainly the word-list destroy lane and the timed/periodic constructor cluster, not the core base or runtime-state surfaces. +- That pilot moved one more bounded step in-session too. The periodic/timed branch from the old `0008:` note cluster is now re-anchored live onto `11e0:` well enough to move six more methods under `Remorse::EntityDispatchEntry`: `ConstructVtable3AD2` (`11e0:14fb`), `ConstructVtable3AA6` (`11e0:1814`), `SetUpdatePeriodAndReschedule` (`11e0:187e`), `TickPeriodic` (`11e0:1913`), `EnableActiveCounters` (`11e0:19e6`), and `DisableActiveCounters` (`11e0:1a33`). Each now has an in-session provenance comment tying it back to the old `0008:` anchor, so the remaining `EntityDispatchEntry` blocker is narrower again: the word-list-owned subtype still has no live function objects in the expected `11e0:2000..25a1` window, and a bounded boundary scan did not yet yield safe entries to promote. +- That remaining `EntityDispatchEntry` blocker is now closed by a re-anchor correction. The expected `11e0:2000..25a1` window is not code in the current live database; the old `0008:da00..dfa1` word-list-owned subtype actually lives in the `11e8:` `MList_*` cluster, with `11e8:0000` carrying explicit old `0008:da00` segment metadata in the decompiler. That full batch now also lives under `Remorse::EntityDispatchEntry`: `SetWordList0408Terminated`, `FreeWordList`, `Destroy`, `EnsureWordListContains`, `AppendUniqueWord`, `RemoveWordValue`, `GetWordAt`, `SetWordAt`, and `FindUnflaggedWordById10`, each with an in-session provenance comment. The remaining question on this pilot family is therefore modeling depth rather than location: whether the `11e8:` word-list branch deserves its own explicit derived/overlay datatype instead of remaining a method cluster under the shared class owner. - `CreateFromSlotIndex` is no longer a raw anonymous pack either: the live signature now separates `owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, and `ucparamsize`, with explicit `AX:DX` return storage restored even though the endpoint still textualizes the function conservatively as plain `dword __cdecl`. ### Areas That Are No Longer Live Priorities @@ -124,7 +136,7 @@ Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-renderi 5. Tighten the seg006 masked-helper caller chains so the local state-selector/value family can be tied to concrete gameplay subsystems. 6. Classify the paired seg070 loops behind `entity_vm_runtime_owner_resource_create`, especially which temporary buffers and record schemas each family populates. 7. Stay on the Remorse VM class-lift batch while the repaired runtime lane is warm: use the now-recovered `CreateFromSlotIndex` caller pack to decide whether any remaining scalar positions deserve stronger typedefs, but keep the return semantically conservative until the base-process inheritance model is explicit enough to justify a prettier live return type. -8. Continue the `UsecodeDebuggerBreakState` family from the now-landed live array layout, callback-map pass, seg109 consumer pass, and live datatype promotion only if the last `aux_farptr` lane can be closed cheaply; otherwise resume from the current `EntityDispatchEntry` stopping point and map the remaining old `0008:` method groups onto live `CRUSADER.EXE` segments, especially the word-list destroy lane and the timed/periodic constructor cluster. +8. The current broader Remorse follow-up batch is now materially tighter: `WatchEntityController` is effectively re-identified as the live camera-process create lane, `DialogMenuObject` is the last compact family here without a safe live re-anchor, `PresentationCallbackBroker` now has install/teardown plus both slot `+0x08` and preserved slot `+0x0c` caller evidence, `CacheBackendObject` has its indexed entry writer, and `SpriteNode::Create` now looks like the shared compact node constructor for `GumpCreate_*` wrappers. The clearest next unresolved items are therefore: a safer live reanchor for `DialogMenuObject`, a decision on whether the camera-process lane should stay under the stronger live `Camera_*` naming or also receive a class-owner layer, deeper slot `+0x0c` payload classification in the broker lane, and higher-level subtype/layout work above the compact `SpriteNode` base. 8. In the local GhidraMCP upgrade lane, add support for dual POST body decoding (`application/json` plus form-urlencoded) and a constrained live write-side PyGhidra endpoint family so future custom-storage/type repairs can stay inside the active MCP session when Python is enabled. 9. Promote additional ledger rows directly from already-verified docs and live comments, especially where segments already deserve `Foothold`, `Partial`, or `Deep`; the new seg029 step-aware sweep batch, seg031 queue-release batch, and seg090 movement-helper batch should be the immediate template. 10. If the VM lane stalls, revisit `000e:ffb0` from the now-better-constrained video/audio caller windows and try to recover an adjacent non-overlapped helper before attempting broad boundary repair. diff --git a/scripts/_tmp_apply_broker_slot08.py b/scripts/_tmp_apply_broker_slot08.py new file mode 100644 index 0000000..c89551e --- /dev/null +++ b/scripts/_tmp_apply_broker_slot08.py @@ -0,0 +1,14 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +print(bridge.rename_function_by_address("1288:0fc3", "allocator_phase_finalize_pass")) +print( + bridge.set_decompiler_comment( + "1288:0fc3", + "Live re-anchor for raw 0009:b1c3. Calls PresentationCallbackBroker vtable slot +0x08 twice through the installed 0x4588 broker pointer, then sweeps allocator heads for finalize cleanup.", + ) +) +print(bridge.get_function_by_address("1288:0fc3")) \ No newline at end of file diff --git a/scripts/_tmp_apply_cache_backend_methods.py b/scripts/_tmp_apply_cache_backend_methods.py new file mode 100644 index 0000000..fd09185 --- /dev/null +++ b/scripts/_tmp_apply_cache_backend_methods.py @@ -0,0 +1,38 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +updates = [ + { + "address": "1250:026c", + "name": "LoadEntryTableFromManifest", + "comment": ( + "Constructor-selected cache-backend branch. Fetches a manifest-style buffer through the " + "object callback table, allocates the +0x10/+0x18 entry tables, and copies parsed entry " + "records into backend-owned storage." + ), + }, + { + "address": "1250:0749", + "name": "InitFixedEntryTable", + "comment": ( + "Constructor-selected cache-backend fallback branch. Uses the current entry count and a " + "caller-supplied fixed record size to allocate default entry records and seed the +0x10/+0x18 tables." + ), + }, +] + +for update in updates: + print(f"=== {update['address']} -> {update['name']} ===") + print( + bridge.set_function_class( + function_address=update["address"], + class_path="Remorse::CacheBackendObject", + method_name=update["name"], + ) + ) + print(bridge.set_decompiler_comment(update["address"], update["comment"])) + print(bridge.get_function_by_address(update["address"])) + print() \ No newline at end of file diff --git a/scripts/_tmp_apply_cache_backend_setter.py b/scripts/_tmp_apply_cache_backend_setter.py new file mode 100644 index 0000000..da2c4de --- /dev/null +++ b/scripts/_tmp_apply_cache_backend_setter.py @@ -0,0 +1,20 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +print( + bridge.set_function_class( + function_address="1250:0910", + class_path="Remorse::CacheBackendObject", + method_name="SetEntryNameAndTag", + ) +) +print( + bridge.set_decompiler_comment( + "1250:0910", + "Indexed CacheBackendObject writer. Resolves the logical entry id through the +0x18 remap table, ensures the +0x10 entry buffer exists and is large enough, stores a 4-byte tag/header, and copies the caller-supplied name string at offset +4.", + ) +) +print(bridge.get_function_by_address("1250:0910")) \ No newline at end of file diff --git a/scripts/_tmp_apply_owner_resource_accessors.py b/scripts/_tmp_apply_owner_resource_accessors.py new file mode 100644 index 0000000..61f99ae --- /dev/null +++ b/scripts/_tmp_apply_owner_resource_accessors.py @@ -0,0 +1,39 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +updates = [ + { + "address": "1430:014c", + "name": "MaterializeChecked", + "comment": ( + "Owner-resource wrapper over helper vtable slot +0x0c. " + "Called by InitSlotOwnerBuffers and EnsureSlotChunkLoaded to materialize owner data " + "and assert if the first output byte is 0xff." + ), + }, + { + "address": "1430:0195", + "name": "QueryMaterializationSize", + "comment": ( + "Owner-resource wrapper over helper vtable slot +0x04. " + "Current best read from the 1430:0000 create path is a size-query callback used ahead " + "of owner-data materialization." + ), + }, +] + +for update in updates: + print(f"=== {update['address']} -> {update['name']} ===") + print( + bridge.set_function_class( + function_address=update["address"], + class_path="Remorse::EntityVmOwnerResource", + method_name=update["name"], + ) + ) + print(bridge.set_decompiler_comment(update["address"], update["comment"])) + print(bridge.get_function_by_address(update["address"])) + print() \ No newline at end of file diff --git a/scripts/_tmp_apply_presentation_callback_broker.py b/scripts/_tmp_apply_presentation_callback_broker.py new file mode 100644 index 0000000..d79255b --- /dev/null +++ b/scripts/_tmp_apply_presentation_callback_broker.py @@ -0,0 +1,39 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +updates = [ + { + "address": "12d0:0513", + "name": "InitOnce", + "comment": ( + "Live re-anchor for the 0x4588 presentation-callback broker install path. " + "Guards on 0x4594, snapshots current video/system state into 0x458c/0x4590, installs " + "the nullable broker pointer at 0x4588, and ensures the fallback buffer at 0x45a6 exists." + ), + }, + { + "address": "12d0:0656", + "name": "TeardownOnce", + "comment": ( + "Live re-anchor for the 0x4588 presentation-callback broker teardown path. " + "Guards on 0x4595, clears the installed broker pointer, conditionally emits broker slot +0x0c " + "when 0x4590 != 0x458c, then calls broker slot +0x04 before final video/system cleanup." + ), + }, +] + +for update in updates: + print(f"=== {update['address']} -> {update['name']} ===") + print( + bridge.set_function_class( + function_address=update["address"], + class_path="Remorse::PresentationCallbackBroker", + method_name=update["name"], + ) + ) + print(bridge.set_decompiler_comment(update["address"], update["comment"])) + print(bridge.get_function_by_address(update["address"])) + print() \ No newline at end of file diff --git a/_tmp_apply_vm_class_types.py b/scripts/_tmp_apply_vm_class_types.py similarity index 100% rename from _tmp_apply_vm_class_types.py rename to scripts/_tmp_apply_vm_class_types.py diff --git a/_tmp_changer_ir_dump.py b/scripts/_tmp_changer_ir_dump.py similarity index 100% rename from _tmp_changer_ir_dump.py rename to scripts/_tmp_changer_ir_dump.py diff --git a/scripts/_tmp_comment_broker_slot0c_callers.py b/scripts/_tmp_comment_broker_slot0c_callers.py new file mode 100644 index 0000000..76190cb --- /dev/null +++ b/scripts/_tmp_comment_broker_slot0c_callers.py @@ -0,0 +1,21 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +comments = { + "1278:0616": ( + "Verified live caller of PresentationCallbackBroker slot +0x0c through the installed 0x4588 broker pointer. " + "When the local vport state takes the fallback path and param_2 == 0, this function emits the broker callback instead of the normal direct graphics path." + ), + "1320:1588": ( + "Verified live caller of PresentationCallbackBroker slot +0x0c through the installed 0x4588 broker pointer. " + "Dispatch_ModalGump emits the broker callback before and after modal dispatch when the requested state pair differs from the current SuperVGA mode snapshot." + ), +} + +for address, comment in comments.items(): + print(bridge.set_decompiler_comment(address, comment)) + print(bridge.get_function_by_address(address)) + print() \ No newline at end of file diff --git a/scripts/_tmp_comment_watch_controller_mapping.py b/scripts/_tmp_comment_watch_controller_mapping.py new file mode 100644 index 0000000..4c157b4 --- /dev/null +++ b/scripts/_tmp_comment_watch_controller_mapping.py @@ -0,0 +1,22 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +comments = { + "1180:0000": ( + "Live re-anchor for raw 0007:ba00 watch_entity_controller_create_global. " + "The current live NE build exposes this family more concretely as Camera_Init / Camera_CreateProcess " + "rather than under the older watch-entity-controller label." + ), + "1180:0045": ( + "Live re-anchor for raw 0007:ba45 watch_entity_controller_create. " + "This family now reads as the camera-process create path: allocates the process object, stores the global at 0x2bd8, and seeds the process-name row at 0x2be4." + ), +} + +for address, comment in comments.items(): + print(bridge.set_decompiler_comment(address, comment)) + print(bridge.get_function_by_address(address)) + print() \ No newline at end of file diff --git a/_tmp_create_entity_vm_slot_entry_datatype.py b/scripts/_tmp_create_entity_vm_slot_entry_datatype.py similarity index 100% rename from _tmp_create_entity_vm_slot_entry_datatype.py rename to scripts/_tmp_create_entity_vm_slot_entry_datatype.py diff --git a/scripts/_tmp_create_sprite_node_datatypes.py b/scripts/_tmp_create_sprite_node_datatypes.py new file mode 100644 index 0000000..9d4f16c --- /dev/null +++ b/scripts/_tmp_create_sprite_node_datatypes.py @@ -0,0 +1,32 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +struct_result = bridge.create_or_update_struct( + name="SpriteNodeBase", + category_path="/Remorse", + size=0x2b, + fields=[ + {"offset": 25, "name": "child_or_next_farptr", "datatype": "undefined4", "comment": "Child-chain pointer pair used by traversal and accumulated-position helpers.", "confidence": "high"}, + {"offset": 33, "name": "local_x_offset", "datatype": "undefined2", "comment": "Summed by the live SpriteNode offset-accumulation helpers.", "confidence": "high"}, + {"offset": 35, "name": "local_y_offset", "datatype": "undefined2", "comment": "Summed by the live SpriteNode offset-accumulation helpers.", "confidence": "high"}, + {"offset": 41, "name": "dirty_flags", "datatype": "undefined2", "comment": "Checked by IsDirty and updated by MarkDirty.", "confidence": "high"}, + ], +) +print("=== struct ===") +print(struct_result) +print() + +vtable_result = bridge.create_or_update_struct( + name="SpriteNodeVtable", + category_path="/Remorse", + size=40, + fields=[ + {"offset": 20, "name": "event_handler_slot14", "datatype": "undefined4", "comment": "Verified DispatchEvent target for one event class.", "confidence": "high"}, + {"offset": 24, "name": "event_handler_slot18", "datatype": "undefined4", "comment": "Verified DispatchEvent target for one event class.", "confidence": "high"}, + {"offset": 32, "name": "event_handler_slot20", "datatype": "undefined4", "comment": "Verified DispatchEvent target for one event class.", "confidence": "high"}, + {"offset": 36, "name": "event_handler_slot24", "datatype": "undefined4", "comment": "Verified DispatchEvent target for one event class.", "confidence": "high"}, + ], +) +print("=== vtable ===") +print(vtable_result) diff --git a/scripts/_tmp_decompile_entity_dispatch_periodic.py b/scripts/_tmp_decompile_entity_dispatch_periodic.py new file mode 100644 index 0000000..5d17673 --- /dev/null +++ b/scripts/_tmp_decompile_entity_dispatch_periodic.py @@ -0,0 +1,8 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["11e0:14fb", "11e0:1814", "11e0:1913", "11e0:19e6", "11e0:1a33"]: + print(f"=== {address} ===") + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_decompile_entity_dispatch_periodic_extras.py b/scripts/_tmp_decompile_entity_dispatch_periodic_extras.py new file mode 100644 index 0000000..5acab7f --- /dev/null +++ b/scripts/_tmp_decompile_entity_dispatch_periodic_extras.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["11e0:17a4", "11e0:17dc", "11e0:187e"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_disasm_entity_dispatch_word_list.py b/scripts/_tmp_disasm_entity_dispatch_word_list.py new file mode 100644 index 0000000..0fc8027 --- /dev/null +++ b/scripts/_tmp_disasm_entity_dispatch_word_list.py @@ -0,0 +1,22 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +RANGES = [ + ("11e0:1ff0", "11e0:2090"), + ("11e0:2190", "11e0:2260"), + ("11e0:2290", "11e0:22f0"), + ("11e0:2390", "11e0:23f0"), + ("11e0:24d0", "11e0:2520"), + ("11e0:2580", "11e0:25d0"), +] + +for start, end in RANGES: + print(f"=== {start} .. {end} ===") + result = bridge.disassemble_region(start, end) + if isinstance(result, list): + for line in result: + print(line) + else: + print(result) + print() diff --git a/_tmp_entity_vm_context_this_type.py b/scripts/_tmp_entity_vm_context_this_type.py similarity index 100% rename from _tmp_entity_vm_context_this_type.py rename to scripts/_tmp_entity_vm_context_this_type.py diff --git a/_tmp_find_text_section.py b/scripts/_tmp_find_text_section.py similarity index 100% rename from _tmp_find_text_section.py rename to scripts/_tmp_find_text_section.py diff --git a/_tmp_fix_entity_vm_runtime_create.py b/scripts/_tmp_fix_entity_vm_runtime_create.py similarity index 100% rename from _tmp_fix_entity_vm_runtime_create.py rename to scripts/_tmp_fix_entity_vm_runtime_create.py diff --git a/_tmp_fix_entity_vm_runtime_create_typed.py b/scripts/_tmp_fix_entity_vm_runtime_create_typed.py similarity index 100% rename from _tmp_fix_entity_vm_runtime_create_typed.py rename to scripts/_tmp_fix_entity_vm_runtime_create_typed.py diff --git a/_tmp_fix_probably_some_alloc_1000_42e2.py b/scripts/_tmp_fix_probably_some_alloc_1000_42e2.py similarity index 100% rename from _tmp_fix_probably_some_alloc_1000_42e2.py rename to scripts/_tmp_fix_probably_some_alloc_1000_42e2.py diff --git a/_tmp_inspect_entity_vm_runtime_create_frame.py b/scripts/_tmp_inspect_entity_vm_runtime_create_frame.py similarity index 100% rename from _tmp_inspect_entity_vm_runtime_create_frame.py rename to scripts/_tmp_inspect_entity_vm_runtime_create_frame.py diff --git a/_tmp_inspect_psx_banks.js b/scripts/_tmp_inspect_psx_banks.js similarity index 100% rename from _tmp_inspect_psx_banks.js rename to scripts/_tmp_inspect_psx_banks.js diff --git a/_tmp_map248_observers.js b/scripts/_tmp_map248_observers.js similarity index 100% rename from _tmp_map248_observers.js rename to scripts/_tmp_map248_observers.js diff --git a/_tmp_parse_combat_dat.py b/scripts/_tmp_parse_combat_dat.py similarity index 100% rename from _tmp_parse_combat_dat.py rename to scripts/_tmp_parse_combat_dat.py diff --git a/scripts/_tmp_probe_broker_slot08.py b/scripts/_tmp_probe_broker_slot08.py new file mode 100644 index 0000000..93ed482 --- /dev/null +++ b/scripts/_tmp_probe_broker_slot08.py @@ -0,0 +1,11 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +for address in ["1288:0fd1", "1278:06b1", "1320:15e9"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() \ No newline at end of file diff --git a/scripts/_tmp_probe_cache_backend_object.py b/scripts/_tmp_probe_cache_backend_object.py new file mode 100644 index 0000000..d2728dc --- /dev/null +++ b/scripts/_tmp_probe_cache_backend_object.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["0009:5600", "0009:5601"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_cache_backend_object_callee.py b/scripts/_tmp_probe_cache_backend_object_callee.py new file mode 100644 index 0000000..47204cf --- /dev/null +++ b/scripts/_tmp_probe_cache_backend_object_callee.py @@ -0,0 +1,23 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["1250:0000", "1250:0001"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() + +for address in ["1250:026c", "1250:0749"]: + print(f"=== helper {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print(bridge.get_xrefs_to(address)) + print() + +for address in ["1250:0910"]: + print(f"=== helper {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print(bridge.get_xrefs_to(address)) + print() diff --git a/scripts/_tmp_probe_cache_backend_object_reanchor.py b/scripts/_tmp_probe_cache_backend_object_reanchor.py new file mode 100644 index 0000000..6bb3a47 --- /dev/null +++ b/scripts/_tmp_probe_cache_backend_object_reanchor.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["12d8:03b4", "12d8:03d6", "12d8:0451"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_debugger_formatter_helpers.py b/scripts/_tmp_probe_debugger_formatter_helpers.py new file mode 100644 index 0000000..c99669f --- /dev/null +++ b/scripts/_tmp_probe_debugger_formatter_helpers.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["13a0:0291", "13a0:045c"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_entity_dispatch_entry_live.py b/scripts/_tmp_probe_entity_dispatch_entry_live.py new file mode 100644 index 0000000..dc08a6c --- /dev/null +++ b/scripts/_tmp_probe_entity_dispatch_entry_live.py @@ -0,0 +1,30 @@ +from pathlib import Path +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +ADDRESSES = [ + "11e0:14fb", + "11e0:1814", + "11e0:1913", + "11e0:19e6", + "11e0:1a33", + "11e0:2000", + "11e0:21a3", + "11e0:21ec", + "11e0:2238", + "11e0:22ab", + "11e0:23af", + "11e0:24ea", + "11e0:251b", + "11e0:25a1", +] + +for address in ADDRESSES: + print(f"=== {address} ===") + try: + print(bridge.get_function_containing(address)) + except Exception as exc: + print(f"get_function_containing failed: {exc}") + print() diff --git a/scripts/_tmp_probe_entity_dispatch_word_list_head.py b/scripts/_tmp_probe_entity_dispatch_word_list_head.py new file mode 100644 index 0000000..2de53b7 --- /dev/null +++ b/scripts/_tmp_probe_entity_dispatch_word_list_head.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["11e8:0000", "11e8:01a3"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_entity_dispatch_word_list_reanchor.py b/scripts/_tmp_probe_entity_dispatch_word_list_reanchor.py new file mode 100644 index 0000000..9d02917 --- /dev/null +++ b/scripts/_tmp_probe_entity_dispatch_word_list_reanchor.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["11e8:01fa", "11e8:0246", "11e8:02b9", "11e8:03bd", "11e8:04f8", "11e8:0529", "11e8:05af"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_owner_resource_live.py b/scripts/_tmp_probe_owner_resource_live.py new file mode 100644 index 0000000..66aabd7 --- /dev/null +++ b/scripts/_tmp_probe_owner_resource_live.py @@ -0,0 +1,38 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +for address in ["1430:0000", "1430:00fd"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() + +for address in ["1220:0000", "1478:67b6", "1478:1228"]: + print(f"=== symbol {address} ===") + if hasattr(bridge, "get_symbol_at"): + print(bridge.get_symbol_at(address)) + else: + print(bridge.get_function_by_address(address)) + print() + +for address in ["1220:0000"]: + print(f"=== decompile {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() + +for address in ["1420:1866", "1420:19fd"]: + print(f"=== runtime {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() + +for address in ["1430:014c", "1430:0195"]: + print(f"=== owner helper {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print(bridge.get_xrefs_to(address)) + print() \ No newline at end of file diff --git a/_tmp_probe_psx_section16.js b/scripts/_tmp_probe_psx_section16.js similarity index 100% rename from _tmp_probe_psx_section16.js rename to scripts/_tmp_probe_psx_section16.js diff --git a/_tmp_probe_sections.js b/scripts/_tmp_probe_sections.js similarity index 100% rename from _tmp_probe_sections.js rename to scripts/_tmp_probe_sections.js diff --git a/scripts/_tmp_probe_sprite_get_or_traverse_candidate.py b/scripts/_tmp_probe_sprite_get_or_traverse_candidate.py new file mode 100644 index 0000000..f9bebb1 --- /dev/null +++ b/scripts/_tmp_probe_sprite_get_or_traverse_candidate.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["1320:0b18", "1320:0b29", "1320:0b44"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_sprite_get_or_traverse_lead.py b/scripts/_tmp_probe_sprite_get_or_traverse_lead.py new file mode 100644 index 0000000..a46cd33 --- /dev/null +++ b/scripts/_tmp_probe_sprite_get_or_traverse_lead.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["1360:0955", "1360:0790", "1360:10d8"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_sprite_node_followups.py b/scripts/_tmp_probe_sprite_node_followups.py new file mode 100644 index 0000000..9f173ff --- /dev/null +++ b/scripts/_tmp_probe_sprite_node_followups.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["1360:0580", "1360:05a6", "1360:0cb2", "1360:12ee"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_sprite_node_live.py b/scripts/_tmp_probe_sprite_node_live.py new file mode 100644 index 0000000..47ec5b0 --- /dev/null +++ b/scripts/_tmp_probe_sprite_node_live.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["000a:b988", "000b:326e", "000b:3380", "000b:33a6", "000b:3ab2", "000b:40ee"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_sprite_node_reanchor.py b/scripts/_tmp_probe_sprite_node_reanchor.py new file mode 100644 index 0000000..ce14d6a --- /dev/null +++ b/scripts/_tmp_probe_sprite_node_reanchor.py @@ -0,0 +1,9 @@ +import sys +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + +for address in ["1360:0380", "1360:03af", "1360:0483", "1360:0cd7", "1360:0d79"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() diff --git a/scripts/_tmp_probe_tier2_candidates.py b/scripts/_tmp_probe_tier2_candidates.py new file mode 100644 index 0000000..7fdee23 --- /dev/null +++ b/scripts/_tmp_probe_tier2_candidates.py @@ -0,0 +1,11 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +for address in ["1180:000f", "1180:00a8", "1130:3038", "1130:31cc", "1130:3269", "12d0:0516", "12d0:0668"]: + print(f"=== {address} ===") + print(bridge.get_function_containing(address)) + print(bridge.decompile_function_by_address(address)) + print() \ No newline at end of file diff --git a/_tmp_psx_gpu_search.py b/scripts/_tmp_psx_gpu_search.py similarity index 100% rename from _tmp_psx_gpu_search.py rename to scripts/_tmp_psx_gpu_search.py diff --git a/_tmp_psx_mode1_live_row0_batch.py b/scripts/_tmp_psx_mode1_live_row0_batch.py similarity index 100% rename from _tmp_psx_mode1_live_row0_batch.py rename to scripts/_tmp_psx_mode1_live_row0_batch.py diff --git a/_tmp_rebind_entity_vm_runtime_create.py b/scripts/_tmp_rebind_entity_vm_runtime_create.py similarity index 100% rename from _tmp_rebind_entity_vm_runtime_create.py rename to scripts/_tmp_rebind_entity_vm_runtime_create.py diff --git a/_tmp_scene_link_scan.ps1 b/scripts/_tmp_scene_link_scan.ps1 similarity index 100% rename from _tmp_scene_link_scan.ps1 rename to scripts/_tmp_scene_link_scan.ps1 diff --git a/_tmp_scummvm_attack_process.cpp b/scripts/_tmp_scummvm_attack_process.cpp similarity index 100% rename from _tmp_scummvm_attack_process.cpp rename to scripts/_tmp_scummvm_attack_process.cpp diff --git a/_tmp_scummvm_combat_dat.h b/scripts/_tmp_scummvm_combat_dat.h similarity index 100% rename from _tmp_scummvm_combat_dat.h rename to scripts/_tmp_scummvm_combat_dat.h diff --git a/_tmp_spawner_compare.js b/scripts/_tmp_spawner_compare.js similarity index 100% rename from _tmp_spawner_compare.js rename to scripts/_tmp_spawner_compare.js diff --git a/_tmp_spawner_truth_pass.js b/scripts/_tmp_spawner_truth_pass.js similarity index 100% rename from _tmp_spawner_truth_pass.js rename to scripts/_tmp_spawner_truth_pass.js diff --git a/_tmp_targets.py b/scripts/_tmp_targets.py similarity index 100% rename from _tmp_targets.py rename to scripts/_tmp_targets.py diff --git a/scripts/_tmp_update_sprite_create_comment.py b/scripts/_tmp_update_sprite_create_comment.py new file mode 100644 index 0000000..436dc8a --- /dev/null +++ b/scripts/_tmp_update_sprite_create_comment.py @@ -0,0 +1,15 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +comment = ( + "Current best live read: compact shared SpriteNode constructor. " + "The body allocates 0x34 bytes, stamps the 0x501a node vtable, and initializes the core link/offset lanes; " + "current direct callers are overwhelmingly GumpCreate_* wrappers, which supports treating this as the base node " + "constructor used by higher-level UI/gump objects rather than a one-off derived leaf." +) + +print(bridge.set_decompiler_comment("1360:036a", comment)) +print(bridge.get_function_by_address("1360:036a")) \ No newline at end of file diff --git a/scripts/_tmp_update_sprite_dispatch_comment.py b/scripts/_tmp_update_sprite_dispatch_comment.py new file mode 100644 index 0000000..89078ed --- /dev/null +++ b/scripts/_tmp_update_sprite_dispatch_comment.py @@ -0,0 +1,15 @@ +import sys + +sys.path.insert(0, r"k:\mcp\GhidraMCP") +import bridge_mcp_ghidra as bridge + + +comment = ( + "Old 000b:3ab2 by preserved offset delta from live 1360:046e. " + "DispatchEvent maps event codes 1/2/4/8/0x10/0x20/0x40/0x100 onto vtable slots " + "+0x04/+0x08/+0x0c/+0x10/+0x14/+0x18/+0x1c/+0x24; the 0x40 path also walks child nodes " + "and dispatches through child slot +0x34 before optional self-slot +0x1c handling." +) + +print(bridge.set_decompiler_comment("1360:0cb2", comment)) +print(bridge.get_function_by_address("1360:0cb2")) \ No newline at end of file diff --git a/_tmp_valuebox_cache_scan.py b/scripts/_tmp_valuebox_cache_scan.py similarity index 100% rename from _tmp_valuebox_cache_scan.py rename to scripts/_tmp_valuebox_cache_scan.py diff --git a/_tmp_valuebox_cache_scan_output.txt b/scripts/_tmp_valuebox_cache_scan_output.txt similarity index 100% rename from _tmp_valuebox_cache_scan_output.txt rename to scripts/_tmp_valuebox_cache_scan_output.txt