mirror of
https://gitee.com/gfdgd-xi/deep-wine-runner
synced 2025-01-13 01:58:27 +08:00
初步实现对吾爱专版的实现
This commit is contained in:
parent
932ff67008
commit
b6e0e203f8
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import pyquery
|
import pyquery
|
||||||
import requests
|
import req as requests
|
||||||
import urllib.parse as parse
|
import urllib.parse as parse
|
||||||
|
|
||||||
def CleanTerminal():
|
def CleanTerminal():
|
||||||
@ -57,6 +57,7 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
apiReturn = json.loads(requests.get(f"https://s.pcmgr.qq.com/tapi/web/searchcgi.php?type=search&callback=searchCallback&keyword={parse.quote(search)}&page=1&pernum=30").text[:-2][15:])
|
apiReturn = json.loads(requests.get(f"https://s.pcmgr.qq.com/tapi/web/searchcgi.php?type=search&callback=searchCallback&keyword={parse.quote(search)}&page=1&pernum=30").text[:-2][15:])
|
||||||
except:
|
except:
|
||||||
|
#traceback.print_exc()
|
||||||
input("无法连接服务器,按回车键继续")
|
input("无法连接服务器,按回车键继续")
|
||||||
CleanTerminal()
|
CleanTerminal()
|
||||||
continue
|
continue
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
import PyQt5.QtWidgets as QtWidgets
|
import PyQt5.QtWidgets as QtWidgets
|
||||||
from UI.AutoConfig import *
|
from UI.AutoConfig import *
|
||||||
from Model import *
|
from Model import *
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
def exit():
|
def exit():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
input("按回车键退出")
|
input("按回车键退出")
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import req as requests
|
||||||
homePath = os.path.expanduser('~')
|
homePath = os.path.expanduser('~')
|
||||||
try:
|
try:
|
||||||
fontList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/fonts/list.json").text)
|
fontList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/fonts/list.json").text)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
msxmlList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/msxml/list.json").text)
|
msxmlList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/msxml/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/net/list.json").text)
|
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/net/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
|
|
||||||
if "--help" in sys.argv:
|
if "--help" in sys.argv:
|
||||||
print("作者:gfdgd xi、为什么您不喜欢熊出没和阿布呢")
|
print("作者:gfdgd xi、为什么您不喜欢熊出没和阿布呢")
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/vscpp/list.json").text)
|
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/vscpp/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Package: spark-deepin-wine-runner
|
Package: spark-deepin-wine-runner
|
||||||
Version: 2.2.0-Alpha3
|
Version: 2.2.0-Alpha4
|
||||||
Maintainer: gfdgd xi <3025613752@qq.com>, 为什么您不喜欢熊出没和阿布呢
|
Maintainer: gfdgd xi <3025613752@qq.com>, 为什么您不喜欢熊出没和阿布呢
|
||||||
Homepage: https://gitee.com/gfdgd-xi/deep-wine-runner, https://github.com/gfdgd-xi/deep-wine-runner, https://gitlink.org.cn/gfdgd_xi/deep-wine-runner
|
Homepage: https://gitee.com/gfdgd-xi/deep-wine-runner, https://github.com/gfdgd-xi/deep-wine-runner, https://gitlink.org.cn/gfdgd_xi/deep-wine-runner
|
||||||
Architecture: all
|
Architecture: all
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import pyquery
|
import pyquery
|
||||||
import requests
|
import req as requests
|
||||||
import urllib.parse as parse
|
import urllib.parse as parse
|
||||||
|
|
||||||
def CleanTerminal():
|
def CleanTerminal():
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
import PyQt5.QtWidgets as QtWidgets
|
import PyQt5.QtWidgets as QtWidgets
|
||||||
from UI.AutoConfig import *
|
from UI.AutoConfig import *
|
||||||
from Model import *
|
from Model import *
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
def exit():
|
def exit():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
input("按回车键退出")
|
input("按回车键退出")
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import req as requests
|
||||||
homePath = os.path.expanduser('~')
|
homePath = os.path.expanduser('~')
|
||||||
try:
|
try:
|
||||||
fontList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/fonts/list.json").text)
|
fontList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/fonts/list.json").text)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
msxmlList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/msxml/list.json").text)
|
msxmlList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/msxml/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/net/list.json").text)
|
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/net/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
|
|
||||||
if "--help" in sys.argv:
|
if "--help" in sys.argv:
|
||||||
print("作者:gfdgd xi、为什么您不喜欢熊出没和阿布呢")
|
print("作者:gfdgd xi、为什么您不喜欢熊出没和阿布呢")
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import req as requests
|
||||||
try:
|
try:
|
||||||
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/vscpp/list.json").text)
|
netList = json.loads(requests.get("https://code.gitlink.org.cn/gfdgd_xi/wine-runner-list/raw/branch/master/vscpp/list.json").text)
|
||||||
except:
|
except:
|
||||||
|
@ -14,7 +14,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
def exit():
|
def exit():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
input("按回车键退出")
|
input("按回车键退出")
|
||||||
|
@ -18,7 +18,7 @@ import base64
|
|||||||
import shutil
|
import shutil
|
||||||
import hashlib
|
import hashlib
|
||||||
import platform
|
import platform
|
||||||
import requests
|
import req as requests
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
import requests
|
import req as requests
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import urllib.parse as parse
|
import urllib.parse as parse
|
||||||
|
@ -14,7 +14,7 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
# UI 布局(自动生成)
|
# UI 布局(自动生成)
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import base64
|
import base64
|
||||||
import requests
|
import req as requests
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import urllib.parse as parse
|
import urllib.parse as parse
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"Version": "2.2.0",
|
"Version": "2.2.0-Alpha4",
|
||||||
"Thank": [
|
"Thank": [
|
||||||
"感谢 @a2035274 @虚幻的早晨 https://bbs.deepin.org/post/238301",
|
"感谢 @a2035274 @虚幻的早晨 https://bbs.deepin.org/post/238301",
|
||||||
"感谢 @zhangs https://bbs.deepin.org/post/227948",
|
"感谢 @zhangs https://bbs.deepin.org/post/227948",
|
||||||
|
@ -16,7 +16,7 @@ import time
|
|||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import easygui
|
import easygui
|
||||||
import requests
|
import req as requests
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import ttkthemes
|
import ttkthemes
|
||||||
|
@ -16,7 +16,7 @@ import time
|
|||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import easygui
|
import easygui
|
||||||
import requests
|
import req as requests
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import ttkthemes
|
import ttkthemes
|
||||||
|
@ -18,11 +18,11 @@ import base64
|
|||||||
import shutil
|
import shutil
|
||||||
import hashlib
|
import hashlib
|
||||||
import platform
|
import platform
|
||||||
import requests
|
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import req as requests
|
||||||
import urllib.parse as parse
|
import urllib.parse as parse
|
||||||
import PyQt5.QtGui as QtGui
|
import PyQt5.QtGui as QtGui
|
||||||
import PyQt5.QtCore as QtCore
|
import PyQt5.QtCore as QtCore
|
||||||
@ -1174,6 +1174,7 @@ class ProgramRunStatusShow():
|
|||||||
return
|
return
|
||||||
if choose == 1:
|
if choose == 1:
|
||||||
ProgramRunStatusUpload.ShowWindow(sha)
|
ProgramRunStatusUpload.ShowWindow(sha)
|
||||||
|
return
|
||||||
if choose == 2:
|
if choose == 2:
|
||||||
try:
|
try:
|
||||||
lists = [0, 0, 0, 0, 0, 0, 0, 0]
|
lists = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
@ -1184,8 +1185,7 @@ class ProgramRunStatusShow():
|
|||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
QtWidgets.QMessageBox.critical(window, "错误", "无法获取预测数值")
|
QtWidgets.QMessageBox.critical(window, "错误", "无法获取预测数值")
|
||||||
# QtWidgets.QMessageBox.information(None, "提示", "必须选择一个选项!否则无法进入程序!")
|
return
|
||||||
# sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
informationList = [
|
informationList = [
|
||||||
@ -1198,10 +1198,11 @@ class ProgramRunStatusShow():
|
|||||||
"含有不良内容,不宜安装",
|
"含有不良内容,不宜安装",
|
||||||
"含有病毒、木马等对计算机有害的软件"
|
"含有病毒、木马等对计算机有害的软件"
|
||||||
]
|
]
|
||||||
|
try:
|
||||||
if title.lower() == "null":
|
if title.lower() == "null":
|
||||||
title = "未知应用"
|
title = "未知应用"
|
||||||
|
except:
|
||||||
|
title = "未知应用"
|
||||||
maxHead = lists.index(max(lists))
|
maxHead = lists.index(max(lists))
|
||||||
ProgramRunStatusShow.msgWindow = QtWidgets.QMainWindow()
|
ProgramRunStatusShow.msgWindow = QtWidgets.QMainWindow()
|
||||||
msgWidget = QtWidgets.QWidget()
|
msgWidget = QtWidgets.QWidget()
|
||||||
@ -1594,7 +1595,7 @@ try:
|
|||||||
canUseWine = []
|
canUseWine = []
|
||||||
if os.path.exists("/opt/deepin-box86/box86"):
|
if os.path.exists("/opt/deepin-box86/box86"):
|
||||||
canUseWine.append("基于 box86 的 deepin-wine6-stable")
|
canUseWine.append("基于 box86 的 deepin-wine6-stable")
|
||||||
if not os.path.exists("/opt/exagear/bin/ubt_x64a64_al"):
|
if os.path.exists("/opt/exagear/bin/ubt_x64a64_al"):
|
||||||
canUseWine.append("基于 exagear 的 deepin-wine6-stable")
|
canUseWine.append("基于 exagear 的 deepin-wine6-stable")
|
||||||
for i in wine.keys():
|
for i in wine.keys():
|
||||||
if not os.system(f"which '{wine[i]}'"):
|
if not os.system(f"which '{wine[i]}'"):
|
||||||
@ -1708,6 +1709,10 @@ def GetVersion():
|
|||||||
fileName = file.read().splitlines()
|
fileName = file.read().splitlines()
|
||||||
package = False
|
package = False
|
||||||
for i in range(0, len(fileName)):
|
for i in range(0, len(fileName)):
|
||||||
|
if fileName[i] == "Package: spark-deepin-wine-runner-52":
|
||||||
|
programVersionType = "吾爱专版"
|
||||||
|
window.setWindowTitle(f"{title} 吾爱专版")
|
||||||
|
break
|
||||||
if fileName[i] == "Package: spark-deepin-wine-runner":
|
if fileName[i] == "Package: spark-deepin-wine-runner":
|
||||||
package = True
|
package = True
|
||||||
continue
|
continue
|
||||||
@ -1795,7 +1800,7 @@ updateThingsString = '''※1、Dll 提取工具支持 NT 6.X 及以上版本的
|
|||||||
'''
|
'''
|
||||||
for i in information["Thank"]:
|
for i in information["Thank"]:
|
||||||
thankText += f"{i}\n"
|
thankText += f"{i}\n"
|
||||||
updateTime = "2022年09月11日"
|
updateTime = "2022年09月22日"
|
||||||
about = f'''<h1>关于</h1>
|
about = f'''<h1>关于</h1>
|
||||||
<p>一个能让Linux用户更加方便运行Windows应用的程序,内置了对wine图形化的支持和各种Wine工具和自制Wine程序打包器、运行库安装工具等等</p>
|
<p>一个能让Linux用户更加方便运行Windows应用的程序,内置了对wine图形化的支持和各种Wine工具和自制Wine程序打包器、运行库安装工具等等</p>
|
||||||
<p>同时也内置了基于VirtualBox制作的小白Windows虚拟机安装工具,可以做到只需要用户下载系统镜像并点击安装即可,无需顾及虚拟机安装、创建、虚拟机的分区等等</p>
|
<p>同时也内置了基于VirtualBox制作的小白Windows虚拟机安装工具,可以做到只需要用户下载系统镜像并点击安装即可,无需顾及虚拟机安装、创建、虚拟机的分区等等</p>
|
||||||
@ -1849,8 +1854,6 @@ iconList = [
|
|||||||
for i in iconListUnBuild:
|
for i in iconListUnBuild:
|
||||||
iconList.append(i)
|
iconList.append(i)
|
||||||
print(iconList)
|
print(iconList)
|
||||||
# 异同步获取信息
|
|
||||||
threading.Thread(target=GetVersion).start()
|
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# 窗口创建
|
# 窗口创建
|
||||||
@ -1864,6 +1867,9 @@ if not get_now_lang() == "zh_CN.UTF-8":
|
|||||||
trans.load(f"{programPath}/LANG/deepin-wine-runner-en_US.qm")
|
trans.load(f"{programPath}/LANG/deepin-wine-runner-en_US.qm")
|
||||||
app.installTranslator(trans)
|
app.installTranslator(trans)
|
||||||
window = QtWidgets.QMainWindow()
|
window = QtWidgets.QMainWindow()
|
||||||
|
window.setWindowTitle(title)
|
||||||
|
# 异同步获取信息
|
||||||
|
threading.Thread(target=GetVersion).start()
|
||||||
widget = QtWidgets.QWidget()
|
widget = QtWidgets.QWidget()
|
||||||
window.setCentralWidget(widget)
|
window.setCentralWidget(widget)
|
||||||
mainLayout = QtWidgets.QGridLayout()
|
mainLayout = QtWidgets.QGridLayout()
|
||||||
@ -2250,7 +2256,6 @@ hm1_1.triggered.connect(lambda: webbrowser.open_new_tab("https://gitee.com/gfdgd
|
|||||||
# 窗口设置
|
# 窗口设置
|
||||||
window.resize(widget.frameGeometry().width() * 2, widget.frameGeometry().height())
|
window.resize(widget.frameGeometry().width() * 2, widget.frameGeometry().height())
|
||||||
widget.setLayout(mainLayout)
|
widget.setLayout(mainLayout)
|
||||||
window.setWindowTitle(title)
|
|
||||||
window.setWindowIcon(QtGui.QIcon(f"{programPath}/deepin-wine-runner.svg"))
|
window.setWindowIcon(QtGui.QIcon(f"{programPath}/deepin-wine-runner.svg"))
|
||||||
widget.show()
|
widget.show()
|
||||||
window.show()
|
window.show()
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"Version": "2.2.0"
|
"Version": "2.2.0-Alpha4"
|
||||||
}
|
}
|
||||||
|
33
req/__init__.py
Normal file
33
req/__init__.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# 此库用于实现 52 版不连接程序服务器
|
||||||
|
import req as requests
|
||||||
|
|
||||||
|
unConnect = False
|
||||||
|
with open("/var/lib/dpkg/status", "r") as i:
|
||||||
|
unConnect = "Package: spark-deepin-wine-runner-52" in open("/var/lib/dpkg/status", "r").read()
|
||||||
|
if unConnect:
|
||||||
|
print("52专版,将会无法连接服务器")
|
||||||
|
|
||||||
|
badUrl = [
|
||||||
|
"http://120.25.153.144",
|
||||||
|
"https://304626p927.goho.co",
|
||||||
|
"https://30x46269h2.goho.co"
|
||||||
|
]
|
||||||
|
|
||||||
|
class Respon:
|
||||||
|
text = ""
|
||||||
|
|
||||||
|
def get(url): # -> requests.Response:
|
||||||
|
if unConnect:
|
||||||
|
# 筛选 Url,只有特定的 url 才会被拦截
|
||||||
|
for i in badUrl:
|
||||||
|
if i in url:
|
||||||
|
raise Exception("52专版不支持连接作者服务器")
|
||||||
|
return requests.get(url)
|
||||||
|
|
||||||
|
def post(url, data):
|
||||||
|
if unConnect:
|
||||||
|
# 筛选 Url,只有特定的 url 才会被拦截
|
||||||
|
for i in badUrl:
|
||||||
|
if i in url:
|
||||||
|
raise Exception("52专版不支持连接作者服务器")
|
||||||
|
return requests.post(url, data)
|
BIN
req/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
req/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
@ -14,7 +14,7 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import requests
|
import req as requests
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
# UI 布局(自动生成)
|
# UI 布局(自动生成)
|
||||||
|
Loading…
Reference in New Issue
Block a user