From 3a5fd263ae5a0011d62b335e3c924f27d3c06c6a Mon Sep 17 00:00:00 2001 From: IgorA Date: Wed, 2 Dec 2015 12:25:32 +0000 Subject: [PATCH] add multi select vertices & average coordinates: x,y,z git-svn-id: svn://kolibrios.org@5944 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/info3ds/info3ds.asm | 41 ++- programs/develop/info3ds/info3ds.ini | 11 +- programs/develop/info3ds/info_menu.inc | 2 +- programs/develop/info3ds/info_wnd_coords.inc | 320 ++++++++++++++++++- programs/develop/info3ds/objects.png | Bin 2412 -> 3036 bytes 5 files changed, 350 insertions(+), 24 deletions(-) diff --git a/programs/develop/info3ds/info3ds.asm b/programs/develop/info3ds/info3ds.asm index 70cf8a50bc..8f56765c84 100644 --- a/programs/develop/info3ds/info3ds.asm +++ b/programs/develop/info3ds/info3ds.asm @@ -13,6 +13,8 @@ include 'lang.inc' include 'info_fun_float.inc' include 'info_menu.inc' +offs_zbuf_pbuf equ 24 ;const. from 'zbuffer.inc' + debug equ 0 @use_library_mem mem.Alloc,mem.Free,mem.ReAlloc,dll.Load @@ -44,7 +46,7 @@ image_data_toolbar dd 0 TREE_ICON_SYS16_BMP_SIZE equ IMAGE_TOOLBAR_ICON_SIZE*11+54 ;размер bmp файла с системными иконками icon_tl_sys dd 0 ;указатеель на память для хранения системных иконок icon_toolbar dd 0 ;указатеель на память для хранения иконок объектов -TOOLBAR_ICON_BMP_SIZE equ IMAGE_TOOLBAR_ICON_SIZE*8+54 ;размер bmp файла с иконками объектов +TOOLBAR_ICON_BMP_SIZE equ IMAGE_TOOLBAR_ICON_SIZE*10+54 ;размер bmp файла с иконками объектов ; IMAGE_FILE1_SIZE equ 128*144*3+54 ;размер файла с изображением @@ -94,6 +96,8 @@ offs_last_timer dd 0 ; ID_ICON_CHUNK_MAIN equ 0 ;иконка главного блока ID_ICON_CHUNK_NOT_FOUND equ 1 ;иконка не известного блока ID_ICON_DATA equ 2 ;иконка для данных блока, не определенной структуры +ID_ICON_POINT equ 8 +ID_ICON_POINT_SEL equ 9 FILE_ERROR_CHUNK_SIZE equ -3 ;ошибка в размере блока @@ -149,10 +153,27 @@ start: stdcall [ksubmenu_add], [main_menu_view], eax stdcall [kmenuitem_new], KMENUITEM_SEPARATOR, 0, 0 stdcall [ksubmenu_add], [main_menu_view], eax - stdcall [kmenuitem_new], KMENUITEM_SUBMENU, sz_main_menu_View, [main_menu_view] - stdcall [ksubmenu_add], [main_menu], eax stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Reset, 9 stdcall [ksubmenu_add], [main_menu_view], eax + stdcall [kmenuitem_new], KMENUITEM_SUBMENU, sz_main_menu_View, [main_menu_view] + stdcall [ksubmenu_add], [main_menu], eax + + stdcall [ksubmenu_new] + mov [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Vertexes_Select, 10 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Vertexes_Deselect, 11 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_SEPARATOR, 0, 0 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Average_x, 12 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Average_y, 13 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Average_z, 14 + stdcall [ksubmenu_add], [main_menu_vertexes], eax + stdcall [kmenuitem_new], KMENUITEM_SUBMENU, sz_main_menu_Vertexes, [main_menu_vertexes] + stdcall [ksubmenu_add], [main_menu], eax mov dword[w_scr_t1.type],1 stdcall dword[tl_data_init], tree1 @@ -216,6 +237,8 @@ start: mov [color_vert],eax stdcall dword[ini_get_color],file_name,ini_sec_w3d,key_face,0x808080 mov [color_face],eax + stdcall dword[ini_get_color],file_name,ini_sec_w3d,key_select,0xffff00 + mov [color_select],eax finit fild dword[color_bk+8] fdiv dword[fl255] @@ -1480,6 +1503,13 @@ buf_0: dd 0 ;ука .color: dd 0xffffd0 ;+16 color db 24 ;+20 bit in pixel +align 4 +buf_ogl: + dd 0 ;указатель на буфер изображения + dw 3d_wnd_l,3d_wnd_t ;+4 left,top + dd 3d_wnd_w,3d_wnd_h ;+8 w,h + dd 0,24 ;+16 color,bit in pixel + align 4 buf_1: dd 0 ;указатель на буфер изображения @@ -1512,9 +1542,9 @@ white_light dd 0.8, 0.8, 0.8, 1.0 ; lmodel_ambient dd 0.3, 0.3, 0.3, 1.0 ; Параметры фонового освещения if lang eq ru -capt db 'info 3ds версия 29.11.15',0 ;подпись окна +capt db 'info 3ds версия 02.12.15',0 ;подпись окна else -capt db 'info 3ds version 29.11.15',0 ;window caption +capt db 'info 3ds version 02.12.15',0 ;window caption end if align 16 @@ -1532,6 +1562,7 @@ i_end: color_bk rd 3 color_vert rd 1 color_face rd 1 + color_select rd 1 rb 2048 align 16 thread_coords: diff --git a/programs/develop/info3ds/info3ds.ini b/programs/develop/info3ds/info3ds.ini index 19939bb370..5f2afe1614 100644 --- a/programs/develop/info3ds/info3ds.ini +++ b/programs/develop/info3ds/info3ds.ini @@ -1,11 +1,12 @@ [Window 3d] draw_vertices=1 draw_faces=1 -draw_faces_fill=0 -draw_light=0 +draw_faces_fill=0 ;заливка граней (0-выкл., 1-вкл.) +draw_light=0 ;освещение (0-выкл., 1-вкл.) col_ox=255,0,0 col_oy=0,0,255 col_oz=0,255,0 -col_bkgnd=0,32,64 -col_vertices=255,255,255 -col_faces=128,192,192 +col_bkgnd=0,32,64 ;цвет фона +col_vertices=255,255,255 ;цвет вершин +col_faces=128,192,192 ;цвет граней +col_select=255,255,0 ;цвет выделенных точек diff --git a/programs/develop/info3ds/info_menu.inc b/programs/develop/info3ds/info_menu.inc index b1b20448b3..7d339eaec6 100644 --- a/programs/develop/info3ds/info_menu.inc +++ b/programs/develop/info3ds/info_menu.inc @@ -1 +1 @@ - if lang eq ru sz_main_menu_View db 'Вид', 0 sz_main_menu_Veiw_Vertexes db 'Вершины вкл./выкл.', 0 sz_main_menu_Veiw_Faces db 'Грани вкл./выкл.', 0 sz_main_menu_Veiw_Faces_Fill db 'Заливка граней вкл./выкл.', 0 sz_main_menu_Veiw_Light db 'Свет вкл./выкл.', 0 sz_main_menu_Veiw_Reset db 'Сброс настроек', 0 else sz_main_menu_View db 'View', 0 sz_main_menu_Veiw_Vertexes db 'Vertexes on/off', 0 sz_main_menu_Veiw_Faces db 'Faces on/off', 0 sz_main_menu_Veiw_Faces_Fill db 'Faces fill on/off', 0 sz_main_menu_Veiw_Light db 'Light on/off', 0 sz_main_menu_Veiw_Reset db 'Reset settings', 0 end if main_menu dd 0 main_menu_file dd 0 main_menu_view dd 0 KMENUITEM_NORMAL equ 0 KMENUITEM_SUBMENU equ 1 KMENUITEM_SEPARATOR equ 2 \ No newline at end of file + if lang eq ru sz_main_menu_View db 'Вид', 0 sz_main_menu_Veiw_Vertexes db 'Вершины вкл./выкл.', 0 sz_main_menu_Veiw_Faces db 'Грани вкл./выкл.', 0 sz_main_menu_Veiw_Faces_Fill db 'Заливка граней вкл./выкл.', 0 sz_main_menu_Veiw_Light db 'Свет вкл./выкл.', 0 sz_main_menu_Veiw_Reset db 'Сброс настроек', 0 sz_main_menu_Vertexes db 'Вершины', 0 sz_main_menu_Vertexes_Select db 'Выделить вершину', 0 sz_main_menu_Vertexes_Deselect db 'Отменить всё выделение', 0 sz_main_menu_Average_x db 'Среднее x',0 sz_main_menu_Average_y db 'Среднее y',0 sz_main_menu_Average_z db 'Среднее z',0 else sz_main_menu_View db 'View', 0 sz_main_menu_Veiw_Vertexes db 'Vertexes on/off', 0 sz_main_menu_Veiw_Faces db 'Faces on/off', 0 sz_main_menu_Veiw_Faces_Fill db 'Faces fill on/off', 0 sz_main_menu_Veiw_Light db 'Light on/off', 0 sz_main_menu_Veiw_Reset db 'Reset settings', 0 sz_main_menu_Vertexes db 'Vertexes', 0 sz_main_menu_Vertexes_Select db 'Select vertex', 0 sz_main_menu_Vertexes_Deselect db 'Deselect all', 0 sz_main_menu_Average_x db 'Average x',0 sz_main_menu_Average_y db 'Average y',0 sz_main_menu_Average_z db 'Average z',0 end if main_menu dd 0 main_menu_file dd 0 main_menu_view dd 0 main_menu_vertexes dd 0 KMENUITEM_NORMAL equ 0 KMENUITEM_SUBMENU equ 1 KMENUITEM_SEPARATOR equ 2 \ No newline at end of file diff --git a/programs/develop/info3ds/info_wnd_coords.inc b/programs/develop/info3ds/info_wnd_coords.inc index 64c5de2a05..83d673db71 100644 --- a/programs/develop/info3ds/info_wnd_coords.inc +++ b/programs/develop/info3ds/info_wnd_coords.inc @@ -29,6 +29,7 @@ key_oz db 'col_oz',0 key_bk db 'col_bkgnd',0 key_vert db 'col_vertices',0 key_face db 'col_faces',0 +key_select db 'col_select',0 prop_wnd_run db 0 ;переменная следящая за тем что-бы не запускать больше 1-го окна со свойствами одновременно @@ -45,7 +46,13 @@ obj_point: ; .text: rb MAX_OBJECT_SIZE - +if lang eq ru +txt_select_vert: db 'Выбрано: ' +else +txt_select_vert: db 'Select: ' +end if +.count: +dq 0,0 ;даное окно (процесс) вызываеться функцией but_wnd_coords align 4 @@ -67,7 +74,7 @@ pushad cmp word[ebx],CHUNK_OBJBLOCK jne .end_oblo mov dword[capt_p],txt_4000 - call found_block_data + stdcall found_block_data, tree1 cmp eax,0 je .no_points mov esi,eax @@ -90,7 +97,7 @@ pushad cmp word[ebx],CHUNK_TRIMESH jne .end_trim mov dword[capt_p],txt_4100 - call found_block_data + stdcall found_block_data, tree1 cmp eax,0 je .no_points mov esi,eax @@ -117,7 +124,7 @@ pushad movzx edx,word[ebx+6] ;колличество точек add ebx,8 ;поиск данных для треугольков - call found_block_data + stdcall found_block_data, tree1 cmp eax,0 je .set_points mov esi,eax @@ -198,7 +205,7 @@ pushad stdcall str_cat, obj_point.text,esi stdcall str_cat, obj_point.text,Data_String loop @b - stdcall dword[tl_node_add], tree3,(ID_ICON_DATA shl 16),obj_point + stdcall dword[tl_node_add], tree3,(ID_ICON_POINT shl 16),obj_point stdcall dword[tl_cur_next], tree3 dec edx cmp edx,0 @@ -228,6 +235,11 @@ pushad and ebx,0x3f3f3f add eax,ebx mov [edit3.color],eax + + mov eax,dword[ctx1] ;eax -> TinyGLContext.GLContext + mov eax,[eax] ;eax -> ZBuffer + mov eax,[eax+offs_zbuf_pbuf] ;eax -> ZBuffer.pbuf + mov dword[buf_ogl],eax popad call prop_red_win @@ -318,6 +330,7 @@ prop_wnd_clear_param: ;обнуление указателей на данные объектов mov dword[obj_poi_data],0 mov dword[obj_poi_count],0 + mov dword[obj_poi_sel_c],0 mov dword[obj_tri_data],0 mov dword[obj_tri_count],0 ret @@ -328,24 +341,24 @@ prop_wnd_clear_param: ;output: ;eax - структура текущего узла (или 0 при неудаче) align 4 -found_block_data: -push ebx ecx +proc found_block_data uses ebx ecx edx, tlist:dword + mov edx,[tlist] mov ecx,eax - stdcall [tl_node_poi_get_info], tree1,0 + stdcall [tl_node_poi_get_info], edx,0 @@: mov ebx,eax - stdcall [tl_node_poi_get_data], tree1,ebx + stdcall [tl_node_poi_get_data], edx,ebx cmp eax,ecx je @f ;если попали на выбранный узел - stdcall [tl_node_poi_get_next_info], tree1,ebx + stdcall [tl_node_poi_get_next_info], edx,ebx cmp eax,0 jne @b jmp .end @@: mov eax,ebx .end: -pop ecx ebx ret +endp ;установка размеров объекта align 4 @@ -549,7 +562,7 @@ draw_3d: stdcall [glEnd] .end_points: - ;рисование выделенной точки + ;рисование активной точки stdcall [tl_node_get_data],tree3 cmp eax,0 je @f @@ -568,13 +581,38 @@ draw_3d: stdcall [glVertex3f], [eax],[eax+4],[obj_z_max] stdcall [glEnd] - stdcall [glColor3f], 1.0, 1.0, 0.0 + stdcall [glColor3ub],[color_select+2],[color_select+1],[color_select] stdcall [glPushMatrix] stdcall [glTranslatef], [eax],[eax+4],[eax+8] stdcall [gluSphere], [qObj], [sph_radius], 8,8 stdcall [glPopMatrix] @@: + ;рисование выделенных точек + cmp dword[obj_poi_sel_c],0 + je .end_select + mov ecx,dword[obj_poi_sel_c] + stdcall [glColor3ub],[color_select+2],[color_select+1],[color_select] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel + stdcall [tl_node_poi_get_data], tree3,ebx + mov eax,[eax] + stdcall [glPushMatrix] + stdcall [glTranslatef], [eax],[eax+4],[eax+8] + stdcall [gluSphere], [qObj], [sph_radius], 4,4 + stdcall [glPopMatrix] + dec ecx + jz .end_select + .next_sel: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + .end_select: + ;рисование граней bt dword[draw_mode],bit_faces jnc .end_triangles @@ -614,6 +652,10 @@ draw_3d: .end_triangles: stdcall [glPopMatrix] + cmp dword[obj_poi_sel_c],0 + je @f + stdcall [buf2d_draw_text], buf_ogl, buf_1,txt_select_vert,5,3,[color_select] + @@: stdcall [kosglSwapBuffers] .end_f: ret @@ -849,6 +891,7 @@ prop_button: stdcall str_cat, obj_point.text,esi stdcall str_cat, obj_point.text,Data_String loop .coord + mov byte[obj_point.text],'*' ;отмечаем что вершина изменялась stdcall dword[tl_node_set_data], tree3,obj_point stdcall dword[tl_draw], tree3 mov byte[can_save],1 ;для показа кнопки 'Сохранить' @@ -883,6 +926,31 @@ prop_button: call mnu_reset_settings jmp prop_still.end @@: + cmp ah,10 + jne @f + call mnu_vertexes_select + jmp prop_still.end + @@: + cmp ah,11 + jne @f + call mnu_vertexes_deselect + jmp prop_still.end + @@: + cmp ah,12 + jne @f + call mnu_reset_average_x + jmp prop_still.end + @@: + cmp ah,13 + jne @f + call mnu_reset_average_y + jmp prop_still.end + @@: + cmp ah,14 + jne @f + call mnu_reset_average_z + jmp prop_still.end + @@: cmp ah,1 jne prop_still.end @@ -967,6 +1035,231 @@ mnu_reset_settings: m2m dword[draw_mode],dword[def_dr_mode] ret +align 4 +proc mnu_vertexes_select uses eax ebx + stdcall [tl_node_get_data],tree3 + cmp eax,0 + je .no_points + stdcall found_block_data,tree3 + cmp eax,0 + je .no_points + mov bx,word[eax] + cmp bx,ID_ICON_POINT_SEL + je @f + mov word[eax],ID_ICON_POINT_SEL + inc dword[obj_poi_sel_c] + jmp .change + @@: + mov word[eax],ID_ICON_POINT + dec dword[obj_poi_sel_c] + .change: + mov eax,[obj_poi_sel_c] + stdcall convert_int_to_str, txt_select_vert.count,16 + .no_points: + ret +endp + +align 4 +proc mnu_vertexes_deselect uses eax + cmp dword[obj_poi_sel_c],0 + je .no_points + mov dword[obj_poi_sel_c],0 + stdcall [tl_node_poi_get_info], tree3,0 + cmp eax,0 + je .no_points + @@: + mov word[eax],ID_ICON_POINT + stdcall [tl_node_poi_get_next_info], tree3,eax + cmp eax,0 + jne @b + .no_points: + ret +endp + +align 4 +proc mnu_reset_average_x uses eax ebx ecx edx edi + cmp dword[obj_poi_sel_c],2 + jl .end_select + finit + fldz + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel0 + stdcall [tl_node_poi_get_data], tree3,ebx + mov eax,[eax] + fadd dword[eax] + dec ecx + jz @f + .next_sel0: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + fidiv dword[obj_poi_sel_c] + fstp dword[eax] + mov edx,[eax] + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel1 + stdcall [tl_node_poi_get_data], tree3,ebx + mov edi,eax + mov eax,[eax] + mov [eax],edx + stdcall update_tree, edi + dec ecx + jz @f + .next_sel1: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + .end_select: + ret +endp + +align 4 +proc mnu_reset_average_y uses eax ebx ecx edx edi + cmp dword[obj_poi_sel_c],2 + jl .end_select + finit + fldz + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel0 + stdcall [tl_node_poi_get_data], tree3,ebx + mov eax,[eax] + fadd dword[eax+4] + dec ecx + jz @f + .next_sel0: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + fidiv dword[obj_poi_sel_c] + fstp dword[eax+4] + mov edx,[eax+4] + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel1 + stdcall [tl_node_poi_get_data], tree3,ebx + mov edi,eax + mov eax,[eax] + mov [eax+4],edx + stdcall update_tree, edi + dec ecx + jz @f + .next_sel1: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + .end_select: + ret +endp + +align 4 +proc mnu_reset_average_z uses eax ebx ecx edx edi + cmp dword[obj_poi_sel_c],2 + jl .end_select + finit + fldz + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel0 + stdcall [tl_node_poi_get_data], tree3,ebx + mov eax,[eax] + fadd dword[eax+8] + dec ecx + jz @f + .next_sel0: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + fidiv dword[obj_poi_sel_c] + fstp dword[eax+8] + mov edx,[eax+8] + mov ecx,dword[obj_poi_sel_c] + stdcall dword[tl_node_poi_get_info], tree3,0 + @@: + cmp eax,0 + je .end_select + mov ebx,eax + cmp word[ebx],ID_ICON_POINT_SEL + jne .next_sel1 + stdcall [tl_node_poi_get_data], tree3,ebx + mov edi,eax + mov eax,[eax] + mov [eax+8],edx + stdcall update_tree, edi + dec ecx + jz @f + .next_sel1: + stdcall dword[tl_node_poi_get_next_info], tree3,ebx + jmp @b + @@: + .end_select: + ret +endp + +align 4 +proc update_tree h_mem:dword +pushad + mov edi,[h_mem] + mov ebx,[edi] + finit + + ;обновление измененного узла в списке tree3 и главного окна (по таймеру) + mov word[NumberSymbolsAD],5 + mov dword[obj_point.text],0 + cld + mov ecx,3 + .coord: + fld dword[ebx] + fstp qword[Data_Double] + call DoubleFloat_to_String + add ebx,4 + stdcall str_len, Data_String + mov esi,txt_space + add esi,eax + cmp esi,txt_space.end + jl .normal_size + mov esi,txt_space.end-1 ;минимум 1 пробел нужно добавить, что-бы цифры не слипались + .normal_size: + stdcall str_cat, obj_point.text,esi + stdcall str_cat, obj_point.text,Data_String + loop .coord + mov esi,obj_point.text + mov byte[esi],'*' ;отмечаем что вершина изменялась + mov byte[can_save],1 ;для показа кнопки 'Сохранить' + add edi,4 + mov ecx,MAX_OBJECT_SIZE-4 + rep movsb +popad + ret +endp + align 4 def_dr_mode dd 0 ;режим рисования по умолчанию delt_size dd 3.0 ;изменение углов при поворотах с кливиатуры @@ -979,6 +1272,7 @@ angle_dym dd 1.3335 ;~ 3d_wnd_h/180 draw_mode dd 0 ;режим рисования объекта obj_poi_data dd 0 ;указатель на координаты вершин obj_poi_count dd 0 ;колличество вершин +obj_poi_sel_c dd 0 ;колличество выделенных вершин obj_tri_data dd 0 ;указатель на данные треугольников obj_tri_count dd 0 ;колличество треугольников cursor_last_draw dd 0 ;положение курсора при последней прорисовке 3d окна diff --git a/programs/develop/info3ds/objects.png b/programs/develop/info3ds/objects.png index ee77879da7c817c5b5fac52422455aa9c7dbf95a..e35b9e8264d47e1928fd31db2a17b5ecac8498e8 100644 GIT binary patch delta 3028 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 RFB<>=002ovPDHLkV1o0~q|pEX