forked from KolibriOS/kolibrios
TinyHashView:
- Now uses (kolibri-libc) libc.obj. - Resize 12kb -> 6kb git-svn-id: svn://kolibrios.org@8707 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
8797117c1d
commit
d093f70049
@ -1,2 +0,0 @@
|
|||||||
#SHS
|
|
||||||
/kolibrios/develop/tcc/tcc thashview.c -o thashview -lck -lcryptal -ldialog -lbox
|
|
@ -1,4 +1,5 @@
|
|||||||
KTCC_DIR=../../develop/ktcc/trunk
|
KTCC_DIR=../../develop/ktcc/trunk
|
||||||
|
KLIBC_DIR = ../../develop/libraries/kolibri-libc
|
||||||
|
|
||||||
NAME=thashview
|
NAME=thashview
|
||||||
|
|
||||||
@ -6,11 +7,13 @@ KTCC=$(KTCC_DIR)/bin/kos32-tcc
|
|||||||
KPACK=kpack
|
KPACK=kpack
|
||||||
|
|
||||||
SRC=thashview.c
|
SRC=thashview.c
|
||||||
CFLAGS=-I $(KTCC_DIR)/libc/include
|
|
||||||
LIBS = -lck -lcryptal -ldialog -lbox
|
CFLAGS= -I$(KLIBC_DIR)/include -I$(KTCC_DIR)/libc/include
|
||||||
|
LFLAGS= -nobss -nostdlib -L $(KLIBC_DIR)/lib $(KLIBC_DIR)/lib/crt0.o
|
||||||
|
LIBS = -lbox -ldialog -lcryptal -lc.obj
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(KTCC) $(CFLAGS) $(SRC) $(LIBS) -o $(NAME)
|
$(KTCC) $(CFLAGS) $(SRC) $(LFLAGS) $(LIBS) -o $(NAME)
|
||||||
$(KPACK) $(NAME)
|
$(KPACK) $(NAME)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -2,9 +2,9 @@ if tup.getconfig("NO_TCC") ~= "" then return end
|
|||||||
|
|
||||||
TCC="kos32-tcc"
|
TCC="kos32-tcc"
|
||||||
|
|
||||||
CFLAGS = "-I../../develop/ktcc/trunk/libc/include"
|
CFLAGS = "-I../../develop/libraries/kolibri-libc/include -I../../develop/ktcc/trunk/libc/include"
|
||||||
LDFLAGS = "-nostdlib ../../develop/ktcc/trunk/bin/lib/start.o -L../../develop/ktcc/trunk/bin/lib"
|
LDFLAGS = "-nostdlib ../../develop/libraries/kolibri-libc/lib/crt0.o -L../../develop/libraries/kolibri-libc/lib -L../../develop/ktcc/trunk/bin/lib"
|
||||||
LIBS = "-lck -lcryptal -ldialog -lbox"
|
LIBS = "-lcryptal -ldialog -lbox -lc.obj"
|
||||||
|
|
||||||
COMMAND=string.format("%s %s %s %s %s ", TCC, CFLAGS, "%f -o %o", LDFLAGS, LIBS)
|
COMMAND=string.format("%s %s %s %s %s ", TCC, CFLAGS, "%f -o %o", LDFLAGS, LIBS)
|
||||||
tup.rule("thashview.c", COMMAND .. tup.getconfig("KPACK_CMD"), "thashview")
|
tup.rule("thashview.c", COMMAND .. tup.getconfig("KPACK_CMD"), "thashview")
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* Copyright (C) 2019-2021 Logaev Maxim (turbocat2001), GPLv2 */
|
/* Copyright (C) 2019-2021 Logaev Maxim (turbocat2001), GPLv2 */
|
||||||
|
|
||||||
|
#include <sys/ksys.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <kos32sys1.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cryptal/md5.h>
|
#include <cryptal/md5.h>
|
||||||
#include <cryptal/sha1.h>
|
#include <cryptal/sha1.h>
|
||||||
@ -17,8 +17,9 @@
|
|||||||
#define WINDOW_W 665
|
#define WINDOW_W 665
|
||||||
#define VERSION "%s - thashview 2.6.1"
|
#define VERSION "%s - thashview 2.6.1"
|
||||||
#define EDIT_TEXT_SIZE 0x10000000
|
#define EDIT_TEXT_SIZE 0x10000000
|
||||||
|
#define DATA(type, addr, offset) *((type*)((uint8_t*)addr+offset))
|
||||||
|
|
||||||
struct kolibri_system_colors sys_color_table;
|
ksys_colors_table_t sys_color_table;
|
||||||
|
|
||||||
char hash_str_md5[MAX_HASH_LEN]= "Click the 'MD5:' button to show the md5-checksum!"; //‚뢮¤ MD5
|
char hash_str_md5[MAX_HASH_LEN]= "Click the 'MD5:' button to show the md5-checksum!"; //‚뢮¤ MD5
|
||||||
char hash_str_sha1[MAX_HASH_LEN]= "Click the 'SHA1:' button to show the sha1-checksum!"; //‚뢮¤ SHA1
|
char hash_str_sha1[MAX_HASH_LEN]= "Click the 'SHA1:' button to show the sha1-checksum!"; //‚뢮¤ SHA1
|
||||||
@ -54,7 +55,7 @@ enum BUTTONS //
|
|||||||
|
|
||||||
void notify_show(char *text)
|
void notify_show(char *text)
|
||||||
{
|
{
|
||||||
start_app("/sys/@notify", text);
|
_ksys_exec("/sys/@notify", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* safe_malloc(size_t size) // <20>¥§®¯ áë© malloc. <20>®ª §ë¢ ¥â 㢥¤®¬«¥¨¥ ®¡ ®è¨¡ª¥ ¨ § ªàë¢ ¥â ¯à®£à ¬¬ã ¥á«¨ ¯ ¬ïâì ¥ ¡ë« ¢ë¤¥«¥
|
void* safe_malloc(size_t size) // <20>¥§®¯ áë© malloc. <20>®ª §ë¢ ¥â 㢥¤®¬«¥¨¥ ®¡ ®è¨¡ª¥ ¨ § ªàë¢ ¥â ¯à®£à ¬¬ã ¥á«¨ ¯ ¬ïâì ¥ ¡ë« ¢ë¤¥«¥
|
||||||
@ -160,51 +161,51 @@ void sprint_hash(BYTE *hash, char* hash_str, int hash_size) //
|
|||||||
void redraw_window() //<2F>¨á㥬 ®ª®
|
void redraw_window() //<2F>¨á㥬 ®ª®
|
||||||
{
|
{
|
||||||
sprintf(title,VERSION, filename); // “áâ ¢«¨¢ ¥¬ § £®«®¢®ª ®ª
|
sprintf(title,VERSION, filename); // “áâ ¢«¨¢ ¥¬ § £®«®¢®ª ®ª
|
||||||
pos_t win_pos = get_mouse_pos(0); // <20>®«ãç ¥¬ ª®®à¤¨ âë ªãàá®à
|
ksys_pos_t win_pos = _ksys_get_mouse_pos(KSYS_MOUSE_SCREEN_POS); // <20>®«ãç ¥¬ ª®®à¤¨ âë ªãàá®à
|
||||||
begin_draw(); //<2F> ç¨ ¥¬ à¨á®¢ ¨¥ ¨â¥à䥩á )
|
_ksys_start_draw(); //<2F> ç¨ ¥¬ à¨á®¢ ¨¥ ¨â¥à䥩á )
|
||||||
sys_create_window(win_pos.x, win_pos.y, WINDOW_W, 150, title, sys_color_table.work_area, 0x14); // ‘®§¤ ñ¬ ®ª®.
|
_ksys_create_window(win_pos.x, win_pos.y, WINDOW_W, 150, title, sys_color_table.work_area, 0x14); // ‘®§¤ ñ¬ ®ª®.
|
||||||
|
|
||||||
edit_box_draw(&hash_edit_box); // <20>¨á㥬 edit_box
|
edit_box_draw(&hash_edit_box); // <20>¨á㥬 edit_box
|
||||||
|
|
||||||
define_button(X_W(10,60), Y_H(30,20), BTN_MD5, GREEN); // Ž¯à¥¤¥«ï¥¬ ª®¯ªã md5
|
_ksys_define_button(10, 30, 60, 20, BTN_MD5, GREEN); // Ž¯à¥¤¥«ï¥¬ ª®¯ªã md5
|
||||||
define_button(X_W(10,60), Y_H(60,20), BTN_SHA1, GREEN);// Ž¯à¥¤¥«ï¥¬ ª®¯ªã sha1
|
_ksys_define_button(10, 60, 60, 20, BTN_SHA1, GREEN);// Ž¯à¥¤¥«ï¥¬ ª®¯ªã sha1
|
||||||
define_button(X_W(10,60), Y_H(90,20), BTN_SHA256, GREEN);// Ž¯à¥¤¥«ï¥¬ ª®¯ªã sha256
|
_ksys_define_button(10, 90, 60, 20, BTN_SHA256, GREEN);// Ž¯à¥¤¥«ï¥¬ ª®¯ªã sha256
|
||||||
|
|
||||||
draw_text_sys("MD5:", 15, 34, 0, 0x90000000 | sys_color_table.work_button_text); // <20>¨é¥¬ ⥪áâ ª®¯ª å
|
_ksys_draw_text("MD5:", 15, 34, 0, 0x90000000 | sys_color_table.work_button_text); // <20>¨é¥¬ ⥪áâ ª®¯ª å
|
||||||
draw_text_sys("SHA1:", 15, 64, 0, 0x90000000 | sys_color_table.work_button_text);
|
_ksys_draw_text("SHA1:", 15, 64, 0, 0x90000000 | sys_color_table.work_button_text);
|
||||||
draw_text_sys("SHA256:", 15,94, 0, 0x90000000 | sys_color_table.work_button_text);
|
_ksys_draw_text("SHA256:", 15,94, 0, 0x90000000 | sys_color_table.work_button_text);
|
||||||
|
|
||||||
draw_text_sys(hash_str_md5, 80, 34, 0, 0x90000000 | sys_color_table.work_text); // ‚뢮¤¨¬ ª®â஫ìë¥ áã¬¬ë ¢ ®ª®
|
_ksys_draw_text(hash_str_md5, 80, 34, 0, 0x90000000 | sys_color_table.work_text); // ‚뢮¤¨¬ ª®â஫ìë¥ áã¬¬ë ¢ ®ª®
|
||||||
draw_text_sys(hash_str_sha1, 80, 64, 0, 0x90000000 | sys_color_table.work_text);
|
_ksys_draw_text(hash_str_sha1, 80, 64, 0, 0x90000000 | sys_color_table.work_text);
|
||||||
draw_text_sys(hash_str_sha256, 80, 94, 0, 0x90000000| sys_color_table.work_text);
|
_ksys_draw_text(hash_str_sha256, 80, 94, 0, 0x90000000| sys_color_table.work_text);
|
||||||
|
|
||||||
define_button(X_W(610,42), Y_H(30, 20), BTN_COPY_MD5, sys_color_table.work_button); // Ž¯à¥¤¥«ï¥¬ ª®¯ª¨ ¤«ï ª®¯¨à®¢ ¨ï
|
|
||||||
define_button(X_W(610,42), Y_H(60, 20), BTN_COPY_SHA1, sys_color_table.work_button);
|
_ksys_define_button(610, 30, 42, 20, BTN_COPY_MD5, sys_color_table.work_button); // Ž¯à¥¤¥«ï¥¬ ª®¯ª¨ ¤«ï ª®¯¨à®¢ ¨ï
|
||||||
define_button(X_W(610,42), Y_H(90, 20), BTN_COPY_SHA256, sys_color_table.work_button);
|
_ksys_define_button(610, 60, 42, 20, BTN_COPY_MD5, sys_color_table.work_button);
|
||||||
|
_ksys_define_button(610, 90, 42, 20, BTN_COPY_MD5, sys_color_table.work_button);
|
||||||
|
|
||||||
draw_text_sys("Copy", 615, 34, 0, 0x90000000 | sys_color_table.work_button_text); // <20>¨è¥¬ copy ¢á¥å ª®¯ª å ¤«ï ª®¯¨à®¢ ¨ï
|
_ksys_draw_text("Copy", 615, 34, 0, 0x90000000 | sys_color_table.work_button_text); // <20>¨è¥¬ copy ¢á¥å ª®¯ª å ¤«ï ª®¯¨à®¢ ¨ï
|
||||||
draw_text_sys("Copy", 615, 64, 0, 0x90000000 | sys_color_table.work_button_text);
|
_ksys_draw_text("Copy", 615, 64, 0, 0x90000000 | sys_color_table.work_button_text);
|
||||||
draw_text_sys("Copy", 615, 94, 0, 0x90000000 | sys_color_table.work_button_text);
|
_ksys_draw_text("Copy", 615, 94, 0, 0x90000000 | sys_color_table.work_button_text);
|
||||||
|
|
||||||
define_button(X_W(592,60), Y_H(120,20), BTN_CMP, GREEN); // Ž¯à¥¤¥«ï¥¬ ª®¯ªã ¤«ï áà ¢¥¨ï ª®â®«ìëå á㬬
|
_ksys_define_button(592, 120, 60, 20, BTN_CMP, GREEN); // Ž¯à¥¤¥«ï¥¬ ª®¯ªã ¤«ï áà ¢¥¨ï ª®â®«ìëå á㬬
|
||||||
draw_text_sys("Compare", 595, 124 , 0,0x90000000 | sys_color_table.work_button_text); // <20>¨è¥¬ â¥ªá ª®¯ª¥.
|
_ksys_draw_text("Compare", 595, 124 , 0,0x90000000 | sys_color_table.work_button_text); // <20>¨è¥¬ â¥ªá ª®¯ª¥.
|
||||||
define_button(X_W(540, 45), Y_H(120,20), BTN_PASTE, sys_color_table.work_button); //Š®¯ª ¤«ï ¢áâ ¢ª¨ (¥à ¡®â ¥â)
|
_ksys_define_button(540, 120, 45, 20, BTN_PASTE, sys_color_table.work_button); //Š®¯ª ¤«ï ¢áâ ¢ª¨ (¥à ¡®â ¥â)
|
||||||
draw_text_sys("Paste", 543, 124 , 0,0x90000000 | sys_color_table.work_button_text); // ’¥ªáâ paste ª®¯ª¥
|
_ksys_draw_text("Paste", 543, 124 , 0,0x90000000 | sys_color_table.work_button_text); // ’¥ªáâ paste ª®¯ª¥
|
||||||
end_draw();
|
_ksys_end_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void paste_to_edit_buffer() // ‚áâ ¢¨âì ¨§ ¡ãää¥à ®¡¬¥
|
void paste_to_edit_buffer() // ‚áâ ¢¨âì ¨§ ¡ãää¥à ®¡¬¥
|
||||||
{
|
{
|
||||||
char *temp_buff=NULL;
|
char *temp_buff=NULL;
|
||||||
if(kol_clip_num()>0){
|
if(_ksys_clip_num()>0){
|
||||||
temp_buff=kol_clip_get(kol_clip_num()-1);
|
temp_buff=_ksys_clip_get(_ksys_clip_num()-1);
|
||||||
memset(edit_box_buff,0,MAX_HASH_LEN);
|
memset(edit_box_buff,0,MAX_HASH_LEN);
|
||||||
if(DATA(int, temp_buff,0)>0 && DATA(int,temp_buff,4)==CLIP_TEXT && DATA(int,temp_buff,8)==CLIP_CP866){
|
if(DATA(int, temp_buff,0)>0 && DATA(int,temp_buff,4)==KSYS_CLIP_TEXT && DATA(int,temp_buff,8)==KSYS_CLIP_CP866){
|
||||||
strncpy(edit_box_buff,temp_buff+12, MAX_HASH_LEN-1);
|
strncpy(edit_box_buff,temp_buff+12, MAX_HASH_LEN-1);
|
||||||
edit_box_set_text(&hash_edit_box,edit_box_buff);
|
edit_box_set_text(&hash_edit_box,edit_box_buff);
|
||||||
notify_show("'Pasted from clipboard!' -I");
|
notify_show("'Pasted from clipboard!' -I");
|
||||||
hash_edit_box.text_color = BLACK;
|
hash_edit_box.text_color = BLACK;
|
||||||
user_free(temp_buff);
|
free(temp_buff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,10 +219,10 @@ void copy_to_clipboard(char *text) //
|
|||||||
{
|
{
|
||||||
char *temp_buffer=safe_malloc(MAX_HASH_LEN+12); // ‚뤥«ï¥¬ ¯ ¬ïâì ¤«ï ¢à¥¬®£® ¡ãä¥à
|
char *temp_buffer=safe_malloc(MAX_HASH_LEN+12); // ‚뤥«ï¥¬ ¯ ¬ïâì ¤«ï ¢à¥¬®£® ¡ãä¥à
|
||||||
memset(temp_buffer, 0, MAX_HASH_LEN); // ‡ ã«ï¥¬ ¡ãä¥à
|
memset(temp_buffer, 0, MAX_HASH_LEN); // ‡ ã«ï¥¬ ¡ãä¥à
|
||||||
DATA(char,temp_buffer,4)=CLIP_TEXT; // “áâ ¢«¨¢ ¥¬ TEXT ¤«ï ¡ãä¥à (‘¬¥é¥¨¥ 4 ¡ ©â )
|
DATA(char,temp_buffer,4)=KSYS_CLIP_TEXT; // “áâ ¢«¨¢ ¥¬ TEXT ¤«ï ¡ãä¥à (‘¬¥é¥¨¥ 4 ¡ ©â )
|
||||||
DATA(char,temp_buffer,8)=CLIP_CP866; // “áâ ¢«¨¢ ¥¬ ª®¤¨à®¢ªã CP866(‘¬¥é¥¨¥ 8 ¡ ©â)
|
DATA(char,temp_buffer,8)=KSYS_CLIP_CP866; // “áâ ¢«¨¢ ¥¬ ª®¤¨à®¢ªã CP866(‘¬¥é¥¨¥ 8 ¡ ©â)
|
||||||
strncpy(temp_buffer+12, text, MAX_HASH_LEN-1); // Š®¯¨à㥬 ¤ ë¥ ¨§ text ¢® ¢à¥¬¥ë© ¡ãä¥à(‘¬¥é¥¨¥ 12 ¡ ©â)
|
strncpy(temp_buffer+12, text, MAX_HASH_LEN-1); // Š®¯¨à㥬 ¤ ë¥ ¨§ text ¢® ¢à¥¬¥ë© ¡ãä¥à(‘¬¥é¥¨¥ 12 ¡ ©â)
|
||||||
kol_clip_set(strlen(text)+12, temp_buffer); // ‚믮«ï¥¬ á¨áâ¥¬ë© ¢ë§®¢ ¨ ¯¥à¥¬¥é ¥¬ ¤ ë¥ ¨§ ¢à¥¬¥®£® ¡ãä¥à ¢ ¡ãä¥à ®¡¬¥
|
_ksys_clip_set(strlen(text)+12, temp_buffer); // ‚믮«ï¥¬ á¨áâ¥¬ë© ¢ë§®¢ ¨ ¯¥à¥¬¥é ¥¬ ¤ ë¥ ¨§ ¢à¥¬¥®£® ¡ãä¥à ¢ ¡ãä¥à ®¡¬¥
|
||||||
notify_show("'Copied to clipboard!' -I");
|
notify_show("'Copied to clipboard!' -I");
|
||||||
free(temp_buffer); // Žá¢®¡®¦ ¥¬ ¢à¥¬¥ë© ¡ãä¥à.
|
free(temp_buffer); // Žá¢®¡®¦ ¥¬ ¢à¥¬¥ë© ¡ãä¥à.
|
||||||
}
|
}
|
||||||
@ -296,36 +297,35 @@ int main(int argc, char** argv)
|
|||||||
notify_show("'File not found!' -E");
|
notify_show("'File not found!' -E");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
if(_ksys_screen_size().x<WINDOW_W){
|
||||||
if(GetScreenSize()/65536<WINDOW_W){
|
|
||||||
notify_show("'Low screen resolution! Program will not display correctrly!' -W");
|
notify_show("'Low screen resolution! Program will not display correctrly!' -W");
|
||||||
}
|
}
|
||||||
|
|
||||||
int gui_event; // <20>¥à¥¬¥ ï ¤«ï åà ¥¨ï ᮡëâ¨ï
|
int gui_event; // <20>¥à¥¬¥ ï ¤«ï åà ¥¨ï ᮡëâ¨ï
|
||||||
uint32_t pressed_button = 0; // Š®¤ ¦ ⮩ ª®¯ª¨ ¢ ®ª¥
|
uint32_t pressed_button = 0; // Š®¤ ¦ ⮩ ª®¯ª¨ ¢ ®ª¥
|
||||||
|
|
||||||
get_system_colors(&sys_color_table);
|
_ksys_get_system_colors(&sys_color_table);
|
||||||
hash_edit_box.shift_color=sys_color_table.work_button;
|
hash_edit_box.shift_color=sys_color_table.work_button;
|
||||||
|
|
||||||
set_event_mask(0xC0000027);// “áâ ¢«¨¢ ¥¬ ¬ áªã ᮡë⨩
|
_ksys_set_event_mask(0xC0000027);// “áâ ¢«¨¢ ¥¬ ¬ áªã ᮡë⨩
|
||||||
do // –¨ª« ®¡à ¡®âª¨ ᮡë⨩
|
do // –¨ª« ®¡à ¡®âª¨ ᮡë⨩
|
||||||
{
|
{
|
||||||
gui_event = get_os_event(); // <20>®«ãç ¥¬ ᮡë⨥
|
gui_event = _ksys_get_event(); // <20>®«ãç ¥¬ ᮡë⨥
|
||||||
switch(gui_event){ // Ž¡à ¡ âë¢ ¥¬ ᮡëâ¨ï
|
switch(gui_event){ // Ž¡à ¡ âë¢ ¥¬ ᮡëâ¨ï
|
||||||
case KOLIBRI_EVENT_NONE:
|
case KSYS_EVENT_NONE:
|
||||||
break;
|
break;
|
||||||
case KOLIBRI_EVENT_REDRAW:
|
case KSYS_EVENT_REDRAW:
|
||||||
redraw_window();
|
redraw_window();
|
||||||
break;
|
break;
|
||||||
case KOLIBRI_EVENT_MOUSE:
|
case KSYS_EVENT_MOUSE:
|
||||||
edit_box_mouse(&hash_edit_box);
|
edit_box_mouse(&hash_edit_box);
|
||||||
break;
|
break;
|
||||||
case KOLIBRI_EVENT_KEY:
|
case KSYS_EVENT_KEY:
|
||||||
hash_edit_box.text_color = BLACK;
|
hash_edit_box.text_color = BLACK;
|
||||||
edit_box_key(&hash_edit_box,get_key().val);
|
edit_box_key(&hash_edit_box, _ksys_get_key().val);
|
||||||
break;
|
break;
|
||||||
case KOLIBRI_EVENT_BUTTON: // ‘®¡ë⨥ ®¡à ¡®âª¨ ª®¯®ª
|
case KSYS_EVENT_BUTTON: // ‘®¡ë⨥ ®¡à ¡®âª¨ ª®¯®ª
|
||||||
pressed_button = get_os_button(); // <20>®«ã票¥ ª®¤ ¦ ⮩ ª®¯ª¨.
|
pressed_button = _ksys_get_button(); // <20>®«ã票¥ ª®¤ ¦ ⮩ ª®¯ª¨.
|
||||||
switch (pressed_button){ // <20>஢¥àª ª ª ï ª®¯ª ¡ë« ¦ â
|
switch (pressed_button){ // <20>஢¥àª ª ª ï ª®¯ª ¡ë« ¦ â
|
||||||
case BTN_MD5:
|
case BTN_MD5:
|
||||||
print_pending_calc(hash_str_md5);
|
print_pending_calc(hash_str_md5);
|
||||||
|
Loading…
Reference in New Issue
Block a user