From f82b861bcdffa9d3df69bd29c7c88be2a30c9ba5 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Thu, 3 Jul 2025 19:48:33 -0400 Subject: [PATCH] Fix Issue #74: Add missing Grid.grid_y property Added individual grid_x and grid_y getter properties to the Grid class to complement the existing grid_size property. This allows direct access to grid dimensions and fixes error messages that referenced these properties before they existed. closes #74 --- debug_immediate.png | Bin 0 -> 30555 bytes debug_multi_0.png | Bin 0 -> 30555 bytes debug_multi_1.png | Bin 0 -> 30555 bytes debug_multi_2.png | Bin 0 -> 30555 bytes grid_none_texture_test_197.png | Bin 0 -> 31717 bytes issue78_fixed_1658.png | Bin 0 -> 31744 bytes screenshot_opaque_fix_20250703_174829.png | Bin 0 -> 30555 bytes src/UIGrid.cpp | 10 ++ src/UIGrid.h | 2 + temp_test.py | 120 ++++++++++++++++++ tests/issue74_grid_xy_properties_test.py | 60 +++++++++ timer_success_1086.png | Bin 0 -> 31733 bytes validate_screenshot_basic_20250703_174532.png | Bin 0 -> 30555 bytes validate_screenshot_final_20250703_174532.png | Bin 0 -> 30555 bytes ...screenshot_with_spaces 20250703_174532.png | Bin 0 -> 30555 bytes 15 files changed, 192 insertions(+) create mode 100644 debug_immediate.png create mode 100644 debug_multi_0.png create mode 100644 debug_multi_1.png create mode 100644 debug_multi_2.png create mode 100644 grid_none_texture_test_197.png create mode 100644 issue78_fixed_1658.png create mode 100644 screenshot_opaque_fix_20250703_174829.png create mode 100644 temp_test.py create mode 100644 tests/issue74_grid_xy_properties_test.py create mode 100644 timer_success_1086.png create mode 100644 validate_screenshot_basic_20250703_174532.png create mode 100644 validate_screenshot_final_20250703_174532.png create mode 100644 validate_screenshot_with_spaces 20250703_174532.png diff --git a/debug_immediate.png b/debug_immediate.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/debug_multi_0.png b/debug_multi_0.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/debug_multi_1.png b/debug_multi_1.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/debug_multi_2.png b/debug_multi_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/grid_none_texture_test_197.png b/grid_none_texture_test_197.png new file mode 100644 index 0000000000000000000000000000000000000000..fe3210d989bdc61b0b157380cbad1c55f73427fa GIT binary patch literal 31717 zcmeI5&ubGw6vroNtV`OIcqoKmtU>VNB}fjX6s>Jd&B5X?@T4s0q24OwP*E@ysfeo{ zJlRtrP!OaCk39txMDP;&7gRwkco8r5pg5a0blKg^zQfF0(|#}8EDPJ2ec$()@4Wpn zPcO~RWYYPx5F%5(FnvXcl>FHztbX}teSJ71#QnF`>2uc>Zr&Qd`{l#KrOTy!vQg}^ zsac7EfoHAxW0}QPHn)p%weWLN^K{-{KvQ?W2%NY{R$zPEtEr{I3 zzOL=uJMg}ks$3V&>et9KCW@soQCj{yqi*4poqF8-E}CTe`auFGAJV*`|{eU*W{ z0m{{&G+e!>9`=r1_c)OyaCF&^9HV*-2%at2R({c_CPti zB;m^0B?(u~?k>pAj~pAIoIP*g%GvVgIlCm` z%Guoo+4+%U6EDi0iL-x4o^Pq8+djHkNH$K1%GKXdA69qj*_`WpzjfY0=(^-VQhxMa zey#oW%c!rlTkQx$0dUv0vy+w_{R9bCxeIV3JNe#VfA2D%+1 z)7-^f?kLxF*?m8MR4$#8uD5FA|1%|fA~ry|8k7cxS)g1EN&|TVl&e9h-<|^H>NS}R zOdWu7pgd&3Jp&_{eq7KS36ulnAqz{!DM|e^CZHTB2g*AY#!VDhG|iac%Hhhx?m*}t l!3<2|$&EyTB?=b_@$N_Z&q{Leo?O0LRL{>&uT9#I{sFb}FopmC literal 0 HcmV?d00001 diff --git a/issue78_fixed_1658.png b/issue78_fixed_1658.png new file mode 100644 index 0000000000000000000000000000000000000000..1e7680a09ccf7b7ce6464a25bd94fb1192032efe GIT binary patch literal 31744 zcmeI5Pe>F|9LJyQR^#T{dN7tH%T16Vh`|;qi72&I4@ra&6vcuD+s%W8REITWL)i3S z7d<5d(#dmp8W55wkj+zg3PH?6B}o(=wl}NGjLh)n3Gcnd^?Mly2ITkN@Ap2x@B6(! zJASLLI~tT3kwZlLY^)4c3tluc`z`TO8r^ZL&?rmBFKJZ zA8Y!n_dn8FE^D$MKTnM2t1|iitFeF)*BOuIreN|INlyJ`|3CV*j^yS>^O0!S=kYZX zFwT?Y%9ihc%tWG%Bzkk5Z6W;{=tvEdRAPG4ui2VbZ1$kQW{Wp+gP7@|aS zCO>?IZDB0HpB%(fQbI`X!^q6TbN{vqg@Q3Y>`cmUPX=s1Yx(Y* zA*W#Ek z`!W)}U!~7XaJ0*`Qef*DKP6F5l?09H56_*A_oVo>qC9E&C9c^)Iz|K=NoCfGk8CSS zrXea~8i?_2q%xXaM&DQxIKfiCr8Iwv3d|#By8ZMa3rX?50WR1KlE5@;4pm)>WLHYC zKP<+J$zg7dZ6W=-j}#@GlHx-WC}%rdLP&}aAfVh+_}Cg!{I~(im5&>soUM6*a^)cj zlq(NOpqxDo6CaWiBoI)peB7YGqI%pwl|z-=QxN-2doRD_eLV}#zO(Ly!8Im6 zcQFCw?A$E@7u;F^!dAI&fO6C*JeHxkDOpZja2p9#4pk0SUb>PEH&S_Q!E)9<_?d=H zAkKbsix+O?2b8-z&)K#7At}Dn09CHsH&EqJkrU%AL~D z9q~}*%GCu_x$2OVFk^x$S3Yila@FGowQ|(TQ7cEST=+H{pd2XoSa=aX8Ihp;xQ#@C z#Xa40hP?#eK$Sz4qgIYuIcnuB^m1n~?v?oRqMX!B)E6$^`@Kqk*_-s<=bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/src/UIGrid.cpp b/src/UIGrid.cpp index 64e928b..0d08328 100644 --- a/src/UIGrid.cpp +++ b/src/UIGrid.cpp @@ -269,6 +269,14 @@ PyObject* UIGrid::get_grid_size(PyUIGridObject* self, void* closure) { return Py_BuildValue("(ii)", self->data->grid_x, self->data->grid_y); } +PyObject* UIGrid::get_grid_x(PyUIGridObject* self, void* closure) { + return PyLong_FromLong(self->data->grid_x); +} + +PyObject* UIGrid::get_grid_y(PyUIGridObject* self, void* closure) { + return PyLong_FromLong(self->data->grid_y); +} + PyObject* UIGrid::get_position(PyUIGridObject* self, void* closure) { auto& box = self->data->box; return Py_BuildValue("(ff)", box.getPosition().x, box.getPosition().y); @@ -431,6 +439,8 @@ PyGetSetDef UIGrid::getsetters[] = { // TODO - refactor into get_vector_member with field identifier values `(void*)n` {"grid_size", (getter)UIGrid::get_grid_size, NULL, "Grid dimensions (grid_x, grid_y)", NULL}, + {"grid_x", (getter)UIGrid::get_grid_x, NULL, "Grid x dimension", NULL}, + {"grid_y", (getter)UIGrid::get_grid_y, NULL, "Grid y dimension", NULL}, {"position", (getter)UIGrid::get_position, (setter)UIGrid::set_position, "Position of the grid (x, y)", NULL}, {"size", (getter)UIGrid::get_size, (setter)UIGrid::set_size, "Size of the grid (width, height)", NULL}, {"center", (getter)UIGrid::get_center, (setter)UIGrid::set_center, "Grid coordinate at the center of the Grid's view (pan)", NULL}, diff --git a/src/UIGrid.h b/src/UIGrid.h index 300c2f5..0e041a2 100644 --- a/src/UIGrid.h +++ b/src/UIGrid.h @@ -48,6 +48,8 @@ public: static int init(PyUIGridObject* self, PyObject* args, PyObject* kwds); static PyObject* get_grid_size(PyUIGridObject* self, void* closure); + static PyObject* get_grid_x(PyUIGridObject* self, void* closure); + static PyObject* get_grid_y(PyUIGridObject* self, void* closure); static PyObject* get_position(PyUIGridObject* self, void* closure); static int set_position(PyUIGridObject* self, PyObject* value, void* closure); static PyObject* get_size(PyUIGridObject* self, void* closure); diff --git a/temp_test.py b/temp_test.py new file mode 100644 index 0000000..41b65b4 --- /dev/null +++ b/temp_test.py @@ -0,0 +1,120 @@ +import sys; sys.path.insert(0, '.') +#!/usr/bin/env python3 +"""Test for UICollection - Related to issue #69 (Sequence Protocol)""" +import mcrfpy +from mcrfpy import automation +from datetime import datetime + +def test_UICollection(): + """Test UICollection sequence protocol compliance""" + # Create test scene + mcrfpy.createScene("collection_test") + mcrfpy.setScene("collection_test") + ui = mcrfpy.sceneUI("collection_test") + + # Add various UI elements + frame = mcrfpy.Frame(10, 10, 100, 100) + caption = mcrfpy.Caption(mcrfpy.Vector(120, 10), text="Test") + sprite = mcrfpy.Sprite(10, 120) + + ui.append(frame) + ui.append(caption) + ui.append(sprite) + + print("Testing UICollection sequence protocol (Issue #69)...") + + # Test len() + try: + length = len(ui) + print(f"✓ len() works: {length} items") + except Exception as e: + print(f"✗ len() failed: {e}") + + # Test indexing + try: + item0 = ui[0] + item1 = ui[1] + item2 = ui[2] + print(f"✓ Indexing works: [{type(item0).__name__}, {type(item1).__name__}, {type(item2).__name__}]") + + # Test negative indexing + last_item = ui[-1] + print(f"✓ Negative indexing works: ui[-1] = {type(last_item).__name__}") + except Exception as e: + print(f"✗ Indexing failed: {e}") + + # Test slicing (if implemented) + try: + slice_items = ui[0:2] + print(f"✓ Slicing works: got {len(slice_items)} items") + except Exception as e: + print(f"✗ Slicing not implemented (Issue #69): {e}") + + # Test iteration + try: + types = [] + for item in ui: + types.append(type(item).__name__) + print(f"✓ Iteration works: {types}") + except Exception as e: + print(f"✗ Iteration failed: {e}") + + # Test contains + try: + if frame in ui: + print("✓ 'in' operator works") + else: + print("✗ 'in' operator returned False for existing item") + except Exception as e: + print(f"✗ 'in' operator not implemented (Issue #69): {e}") + + # Test remove + try: + ui.remove(1) # Remove caption + print(f"✓ remove() works, now {len(ui)} items") + except Exception as e: + print(f"✗ remove() failed: {e}") + + # Test type preservation (Issue #76) + try: + # Add a frame with children to test nested collections + parent_frame = mcrfpy.Frame(250, 10, 200, 200, + fill_color=mcrfpy.Color(200, 200, 200)) + child_caption = mcrfpy.Caption(mcrfpy.Vector(10, 10), text="Child") + parent_frame.children.append(child_caption) + ui.append(parent_frame) + + # Check if type is preserved when retrieving + retrieved = ui[-1] + if type(retrieved).__name__ == "Frame": + print("✓ Type preservation works") + else: + print(f"✗ Type not preserved (Issue #76): got {type(retrieved).__name__}") + except Exception as e: + print(f"✗ Type preservation test failed: {e}") + + # Test find by name (Issue #41 - not yet implemented) + try: + found = ui.find("Test") + print(f"✓ find() method works: {type(found).__name__}") + except AttributeError: + print("✗ find() method not implemented (Issue #41)") + except Exception as e: + print(f"✗ find() method error: {e}") + + # Take screenshot + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"test_UICollection_issue69_{timestamp}.png" + automation.screenshot(filename) + print(f"Screenshot saved: {filename}") + print("PASS") + +# Set up timer to run test +mcrfpy.setTimer("test", test_UICollection, 1000) + +# Cancel timer after running once +def cleanup(): + mcrfpy.delTimer("test") + mcrfpy.delTimer("cleanup") + +mcrfpy.setTimer("cleanup", cleanup, 1100) \ No newline at end of file diff --git a/tests/issue74_grid_xy_properties_test.py b/tests/issue74_grid_xy_properties_test.py new file mode 100644 index 0000000..590c14e --- /dev/null +++ b/tests/issue74_grid_xy_properties_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +""" +Test for Issue #74: Add missing Grid.grid_y property + +Verifies that Grid objects expose grid_x and grid_y properties correctly. +""" + +def test_grid_xy_properties(timer_name): + """Test that Grid has grid_x and grid_y properties""" + import mcrfpy + + # Test was run + print("Issue #74 test: Grid.grid_x and Grid.grid_y properties") + + # Test with texture + texture = mcrfpy.Texture("assets/kenney_ice.png", 16, 16) + grid = mcrfpy.Grid(20, 15, texture, (0, 0), (800, 600)) + + # Test grid_x property + assert hasattr(grid, 'grid_x'), "Grid should have grid_x property" + assert grid.grid_x == 20, f"Expected grid_x=20, got {grid.grid_x}" + print(f"✓ grid.grid_x = {grid.grid_x}") + + # Test grid_y property + assert hasattr(grid, 'grid_y'), "Grid should have grid_y property" + assert grid.grid_y == 15, f"Expected grid_y=15, got {grid.grid_y}" + print(f"✓ grid.grid_y = {grid.grid_y}") + + # Test grid_size still works + assert hasattr(grid, 'grid_size'), "Grid should still have grid_size property" + assert grid.grid_size == (20, 15), f"Expected grid_size=(20, 15), got {grid.grid_size}" + print(f"✓ grid.grid_size = {grid.grid_size}") + + # Test without texture + grid2 = mcrfpy.Grid(30, 25, None, (10, 10), (480, 400)) + assert grid2.grid_x == 30, f"Expected grid_x=30, got {grid2.grid_x}" + assert grid2.grid_y == 25, f"Expected grid_y=25, got {grid2.grid_y}" + assert grid2.grid_size == (30, 25), f"Expected grid_size=(30, 25), got {grid2.grid_size}" + print("✓ Grid without texture also has correct grid_x and grid_y") + + # Test using in error message context (original issue) + try: + grid.at((-1, 0)) # Should raise error + except ValueError as e: + error_msg = str(e) + assert "Grid.grid_x" in error_msg, f"Error message should reference Grid.grid_x: {error_msg}" + print(f"✓ Error message correctly references Grid.grid_x: {error_msg}") + + try: + grid.at((0, -1)) # Should raise error + except ValueError as e: + error_msg = str(e) + assert "Grid.grid_y" in error_msg, f"Error message should reference Grid.grid_y: {error_msg}" + print(f"✓ Error message correctly references Grid.grid_y: {error_msg}") + + print("\n✅ Issue #74 test PASSED - Grid.grid_x and Grid.grid_y properties work correctly") + +# Execute the test after a short delay to ensure window is ready +import mcrfpy +mcrfpy.setTimer("test_timer", test_grid_xy_properties, 100) \ No newline at end of file diff --git a/timer_success_1086.png b/timer_success_1086.png new file mode 100644 index 0000000000000000000000000000000000000000..a09f8d516757c3ac44e5a34c7b207a144d12d473 GIT binary patch literal 31733 zcmeI5PiPZC6vijpSeIbhh!oObt5NadWzif;C{ml6nuA58U=fss_7HD9L};;KE0QAA zKcFb~Xh87No0s4rA}E3&u@t-r6`@p6tawqR#L3dIbh6G&VP->{@3P&=!ZMrp=J&q$ z_Dy>0+|Xb+6blhT!kIGz=LreY(-va3(m%ywN0^XnFERtCh9@qMj@kC__f{yKvJ*l6 zA%E4hZomGKHRtjr{$Z_srW}|q51)(~g}B8z96lIK?*dcdX2=Hz^_0}$lIkZ3l=DHU!GVBszOK@+Zh&$=DAmhTpj?pQ0OfwWWb>kY zBt1I0oLa6_Dur?_l};st(az4n(Q&Vo{obsjuZ|@7Hrk@T`eaxi4^8Gezh_^baBe(I zv*N!WvKPDRGV*wblY;O2#t#+rs`NTS*yVqh2)n*3L4;l3T~Zns(zZbc<@>q;%6(rq z$e{RANE#Q?VHOz_GAOUNMd~A%v`aQ`1||81aa-61Ca~CJxQo?sB(|C zkw&_thA<111LZ(@t)&ayMyfI<6j)GT@o3T15WyOlF`>Ys3Kvl2zT-lA-2mmj+Xkv! znJN!FERS@L#n&p8>;nO<@?PL^A2xl~XIjR3 zPjO``@l4pmZqXeJ9i)(vxodSV!qH#MwCaa}xK&-h?*>IXD}uBkmNw-dKcMo_8#c-6 z#*aj;QH58>*iRcssKt}rJL0jo;+CpyQ{9~s7OgP4WoOT9Bzh@e&EIJdv7S zo_B9h^i@2VzCgDweW~XIz1d z-Bkyad%2DKnR*8T%K4y_$Az?QfO0-4HONz-oC*HSP`ws_Di`d(mBxj%ZGdv1+(TJu zh+xt#36%TplIm>(lmq2%3gVurk6;>bAw5Z`a;S2T-y>?IO9JJ-yQDNOq-_IL?z;p6 z%6(rqD6lXU6=o=n3+Z?RRSs3|YH{~WeFT$sNez_-pd2WNDzClwM+b}GcSNPbEL1sE zIcnv#7A|zK2!2OYS^`0pLzTN)+&zOTXA)v&C>^+^SE7bwq>+Ly3kobKu&CaW3X}uot`>LCpvoB;&J3Z- z1?vU{7RF3EpLVB0l1C!SuJ*WT9 On`BN84J`EAH~s+?tQRx@ literal 0 HcmV?d00001 diff --git a/validate_screenshot_basic_20250703_174532.png b/validate_screenshot_basic_20250703_174532.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/validate_screenshot_final_20250703_174532.png b/validate_screenshot_final_20250703_174532.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001 diff --git a/validate_screenshot_with_spaces 20250703_174532.png b/validate_screenshot_with_spaces 20250703_174532.png new file mode 100644 index 0000000000000000000000000000000000000000..a61c9299ac664f9ec25a16f29bacf72832222a8c GIT binary patch literal 30555 zcmeI*F%H216b9gjR-{QsiFD%xCOay0X++E-=^>bH&SAIfDNHWlB6A7#AQ~M%j5ObOwz}6Ui1|i*aK&P0uqvtgd`*( z2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUF zBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex zl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Ex{v+Xfkwp5A S-shElyQjHPZR+y5I^TYP&0XRE literal 0 HcmV?d00001