Publish curated LumaOps source from c85ee9ef8f1454f5c305398902afbb9e6738de40
Managed validation / full (push) Failing after 8s
Managed validation / full (push) Failing after 8s
This commit is contained in:
1 parent
91f8b3e3c1
commit
def7920856
2271 files changed
+501225
-501178
No files matched your search
@@ -1,136 +1,136 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| main_FreeBSD_Linux_MacOS.cpp |
|
||||
| |
|
||||
| Entry point for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "cli.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "NetworkServer.h"
|
||||
#include "LogManager.h"
|
||||
#include "startup.h"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#ifdef _MACOSX_X86_X64
|
||||
#include "macUSPCIOAccess.h"
|
||||
io_connect_t macUSPCIO_driver_connection;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "macutils.h"
|
||||
#endif
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
volatile std::sig_atomic_t headless_shutdown_requested = 0;
|
||||
|
||||
void HeadlessSignalHandler(int)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Keep the handler async-signal-safe. The normal |
|
||||
| application thread performs the actual server stop. |
|
||||
\*-----------------------------------------------------*/
|
||||
headless_shutdown_requested = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| WaitWhileServerOnline |
|
||||
| |
|
||||
| Wait while NetworkServer is online and return only when |
|
||||
| it has shut down |
|
||||
\*---------------------------------------------------------*/
|
||||
void WaitWhileServerOnline(NetworkServer* srv)
|
||||
{
|
||||
while(srv->GetOnline() && !headless_shutdown_requested)
|
||||
{
|
||||
std::this_thread::sleep_for(1s);
|
||||
};
|
||||
|
||||
if(headless_shutdown_requested && srv->GetOnline())
|
||||
{
|
||||
srv->StopServer();
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| main |
|
||||
| |
|
||||
| Entry point, calls the startup processing |
|
||||
\*---------------------------------------------------------*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Mac x86/x64 only - Install SMBus Driver macUSPCIO |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _MACOSX_X86_X64
|
||||
InitMacUSPCIODriver();
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform CLI pre-detection processing to get return |
|
||||
| flags |
|
||||
\*-----------------------------------------------------*/
|
||||
unsigned int ret_flags = cli_pre_detection(argc, argv);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Install POSIX handlers for headless server mode. |
|
||||
| GUI mode installs its Qt-aware handlers in startup(). |
|
||||
\*-----------------------------------------------------*/
|
||||
if((ret_flags & RET_FLAG_START_SERVER) && !(ret_flags & RET_FLAG_START_GUI))
|
||||
{
|
||||
std::signal(SIGINT, HeadlessSignalHandler);
|
||||
std::signal(SIGTERM, HeadlessSignalHandler);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Initialize ResourceManager |
|
||||
\*-----------------------------------------------------*/
|
||||
ResourceManager::get()->Initialize(
|
||||
!(ret_flags & RET_FLAG_NO_AUTO_CONNECT),
|
||||
!(ret_flags & RET_FLAG_NO_DETECT),
|
||||
ret_flags & RET_FLAG_START_SERVER,
|
||||
ret_flags & RET_FLAG_CLI_POST_DETECTION);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform application startup and run the application. |
|
||||
| This call returns only when the GUI application is |
|
||||
| closing or if not running the GUI. |
|
||||
\*-----------------------------------------------------*/
|
||||
int exitval = startup(argc, argv, ret_flags);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| If started in headless server mode, wait until server |
|
||||
| shuts down before closing application. |
|
||||
\*-----------------------------------------------------*/
|
||||
if((ret_flags & RET_FLAG_START_SERVER) && !(ret_flags & RET_FLAG_START_GUI))
|
||||
{
|
||||
NetworkServer* server = ResourceManager::get()->GetServer();
|
||||
if(server)
|
||||
{
|
||||
WaitWhileServerOnline(server);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform ResourceManager cleanup before exiting |
|
||||
\*-----------------------------------------------------*/
|
||||
ResourceManager::get()->Cleanup();
|
||||
|
||||
LOG_TRACE("OpenRGB finishing with exit code %d", exitval);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Mac x86/x64 only - Uninstall SMBus Driver macUSPCIO |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _MACOSX_X86_X64
|
||||
CloseMacUSPCIODriver();
|
||||
#endif
|
||||
|
||||
return exitval;
|
||||
}
|
||||
/*---------------------------------------------------------*\
|
||||
| main_FreeBSD_Linux_MacOS.cpp |
|
||||
| |
|
||||
| Entry point for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "cli.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "NetworkServer.h"
|
||||
#include "LogManager.h"
|
||||
#include "startup.h"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#ifdef _MACOSX_X86_X64
|
||||
#include "macUSPCIOAccess.h"
|
||||
io_connect_t macUSPCIO_driver_connection;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "macutils.h"
|
||||
#endif
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
volatile std::sig_atomic_t headless_shutdown_requested = 0;
|
||||
|
||||
void HeadlessSignalHandler(int)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Keep the handler async-signal-safe. The normal |
|
||||
| application thread performs the actual server stop. |
|
||||
\*-----------------------------------------------------*/
|
||||
headless_shutdown_requested = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| WaitWhileServerOnline |
|
||||
| |
|
||||
| Wait while NetworkServer is online and return only when |
|
||||
| it has shut down |
|
||||
\*---------------------------------------------------------*/
|
||||
void WaitWhileServerOnline(NetworkServer* srv)
|
||||
{
|
||||
while(srv->GetOnline() && !headless_shutdown_requested)
|
||||
{
|
||||
std::this_thread::sleep_for(1s);
|
||||
};
|
||||
|
||||
if(headless_shutdown_requested && srv->GetOnline())
|
||||
{
|
||||
srv->StopServer();
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| main |
|
||||
| |
|
||||
| Entry point, calls the startup processing |
|
||||
\*---------------------------------------------------------*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Mac x86/x64 only - Install SMBus Driver macUSPCIO |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _MACOSX_X86_X64
|
||||
InitMacUSPCIODriver();
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform CLI pre-detection processing to get return |
|
||||
| flags |
|
||||
\*-----------------------------------------------------*/
|
||||
unsigned int ret_flags = cli_pre_detection(argc, argv);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Install POSIX handlers for headless server mode. |
|
||||
| GUI mode installs its Qt-aware handlers in startup(). |
|
||||
\*-----------------------------------------------------*/
|
||||
if((ret_flags & RET_FLAG_START_SERVER) && !(ret_flags & RET_FLAG_START_GUI))
|
||||
{
|
||||
std::signal(SIGINT, HeadlessSignalHandler);
|
||||
std::signal(SIGTERM, HeadlessSignalHandler);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Initialize ResourceManager |
|
||||
\*-----------------------------------------------------*/
|
||||
ResourceManager::get()->Initialize(
|
||||
!(ret_flags & RET_FLAG_NO_AUTO_CONNECT),
|
||||
!(ret_flags & RET_FLAG_NO_DETECT),
|
||||
ret_flags & RET_FLAG_START_SERVER,
|
||||
ret_flags & RET_FLAG_CLI_POST_DETECTION);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform application startup and run the application. |
|
||||
| This call returns only when the GUI application is |
|
||||
| closing or if not running the GUI. |
|
||||
\*-----------------------------------------------------*/
|
||||
int exitval = startup(argc, argv, ret_flags);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| If started in headless server mode, wait until server |
|
||||
| shuts down before closing application. |
|
||||
\*-----------------------------------------------------*/
|
||||
if((ret_flags & RET_FLAG_START_SERVER) && !(ret_flags & RET_FLAG_START_GUI))
|
||||
{
|
||||
NetworkServer* server = ResourceManager::get()->GetServer();
|
||||
if(server)
|
||||
{
|
||||
WaitWhileServerOnline(server);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Perform ResourceManager cleanup before exiting |
|
||||
\*-----------------------------------------------------*/
|
||||
ResourceManager::get()->Cleanup();
|
||||
|
||||
LOG_TRACE("OpenRGB finishing with exit code %d", exitval);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Mac x86/x64 only - Uninstall SMBus Driver macUSPCIO |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _MACOSX_X86_X64
|
||||
CloseMacUSPCIODriver();
|
||||
#endif
|
||||
|
||||
return exitval;
|
||||
}
|
||||
+635
-635
File diff suppressed because it is too large.
Load diff
+159
-159
@@ -1,159 +1,159 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| startup.cpp |
|
||||
| |
|
||||
| Startup for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "cli.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "NetworkServer.h"
|
||||
#include "startup.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "OpenRGBDialog.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "macutils.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* Linux signal handler *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
#ifdef __linux__
|
||||
void sigHandler(int s)
|
||||
{
|
||||
std::signal(s, SIG_DFL);
|
||||
qApp->quit();
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* startup *
|
||||
* *
|
||||
* Opens the main windows or starts the server *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
int startup(int argc, char* argv[], unsigned int ret_flags)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Initialize exit value, which will be returned on exit |
|
||||
| in main() |
|
||||
\*-----------------------------------------------------*/
|
||||
int exitval = EXIT_SUCCESS;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| If the command line parser indicates that the GUI |
|
||||
| should run, or if there were no command line |
|
||||
| arguments, start the GUI. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(ret_flags & RET_FLAG_START_GUI)
|
||||
{
|
||||
LOG_TRACE("[main] initializing GUI");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Enable high DPI scaling support (Qt5 only) |
|
||||
\*-------------------------------------------------*/
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Enable high DPI fractional scaling support on |
|
||||
| Windows |
|
||||
\*-------------------------------------------------*/
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined(Q_OS_WIN)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Create Qt application |
|
||||
\*-------------------------------------------------*/
|
||||
QApplication a(argc, argv);
|
||||
QGuiApplication::setDesktopFileName("org.openrgb.OpenRGB");
|
||||
LOG_TRACE("[startup] QApplication created");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Main UI widget |
|
||||
\*-------------------------------------------------*/
|
||||
OpenRGBDialog dlg;
|
||||
LOG_TRACE("[startup] Dialog created");
|
||||
|
||||
if(ret_flags & RET_FLAG_I2C_TOOLS)
|
||||
{
|
||||
dlg.AddI2CToolsPage();
|
||||
}
|
||||
|
||||
dlg.AddClientTab();
|
||||
|
||||
if(ret_flags & RET_FLAG_START_MINIMIZED)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*---------------------------------------------*\
|
||||
| Show the window always, even if it will |
|
||||
| immediately be hidden. On Windows, events |
|
||||
| are not delivered to nativeEventFilter (for |
|
||||
| SuspendResume) until the window has been |
|
||||
| shown once. |
|
||||
| |
|
||||
| TODO Try using |
|
||||
| RegisterSuspendResumeNotification instead, |
|
||||
| that should work in headless mode too |
|
||||
\*---------------------------------------------*/
|
||||
dlg.showMinimized();
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
MacUtils::ToggleApplicationDocklessState(false);
|
||||
#endif
|
||||
dlg.hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
LOG_TRACE("[main] Ready to exec() the dialog");
|
||||
|
||||
#ifdef __linux__
|
||||
std::signal(SIGINT, sigHandler);
|
||||
std::signal(SIGTERM, sigHandler);
|
||||
#endif
|
||||
|
||||
exitval = a.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| If no GUI is needed, we let the background |
|
||||
| threads run as long as they need, but we need to |
|
||||
| AT LEAST wait for initialization to finish |
|
||||
\*-------------------------------------------------*/
|
||||
ResourceManager::get()->WaitForInitialization();
|
||||
|
||||
if(ret_flags & RET_FLAG_START_SERVER)
|
||||
{
|
||||
NetworkServer* server = ResourceManager::get()->GetServer();
|
||||
if(server)
|
||||
{
|
||||
exitval = !server->GetOnline();
|
||||
}
|
||||
else
|
||||
{
|
||||
exitval = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(exitval);
|
||||
}
|
||||
/*---------------------------------------------------------*\
|
||||
| startup.cpp |
|
||||
| |
|
||||
| Startup for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "cli.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "NetworkServer.h"
|
||||
#include "startup.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "OpenRGBDialog.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "macutils.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* Linux signal handler *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
#ifdef __linux__
|
||||
void sigHandler(int s)
|
||||
{
|
||||
std::signal(s, SIG_DFL);
|
||||
qApp->quit();
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* startup *
|
||||
* *
|
||||
* Opens the main windows or starts the server *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
int startup(int argc, char* argv[], unsigned int ret_flags)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Initialize exit value, which will be returned on exit |
|
||||
| in main() |
|
||||
\*-----------------------------------------------------*/
|
||||
int exitval = EXIT_SUCCESS;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| If the command line parser indicates that the GUI |
|
||||
| should run, or if there were no command line |
|
||||
| arguments, start the GUI. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(ret_flags & RET_FLAG_START_GUI)
|
||||
{
|
||||
LOG_TRACE("[main] initializing GUI");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Enable high DPI scaling support (Qt5 only) |
|
||||
\*-------------------------------------------------*/
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Enable high DPI fractional scaling support on |
|
||||
| Windows |
|
||||
\*-------------------------------------------------*/
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) && defined(Q_OS_WIN)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Create Qt application |
|
||||
\*-------------------------------------------------*/
|
||||
QApplication a(argc, argv);
|
||||
QGuiApplication::setDesktopFileName("org.openrgb.OpenRGB");
|
||||
LOG_TRACE("[startup] QApplication created");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Main UI widget |
|
||||
\*-------------------------------------------------*/
|
||||
OpenRGBDialog dlg;
|
||||
LOG_TRACE("[startup] Dialog created");
|
||||
|
||||
if(ret_flags & RET_FLAG_I2C_TOOLS)
|
||||
{
|
||||
dlg.AddI2CToolsPage();
|
||||
}
|
||||
|
||||
dlg.AddClientTab();
|
||||
|
||||
if(ret_flags & RET_FLAG_START_MINIMIZED)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*---------------------------------------------*\
|
||||
| Show the window always, even if it will |
|
||||
| immediately be hidden. On Windows, events |
|
||||
| are not delivered to nativeEventFilter (for |
|
||||
| SuspendResume) until the window has been |
|
||||
| shown once. |
|
||||
| |
|
||||
| TODO Try using |
|
||||
| RegisterSuspendResumeNotification instead, |
|
||||
| that should work in headless mode too |
|
||||
\*---------------------------------------------*/
|
||||
dlg.showMinimized();
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
MacUtils::ToggleApplicationDocklessState(false);
|
||||
#endif
|
||||
dlg.hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
LOG_TRACE("[main] Ready to exec() the dialog");
|
||||
|
||||
#ifdef __linux__
|
||||
std::signal(SIGINT, sigHandler);
|
||||
std::signal(SIGTERM, sigHandler);
|
||||
#endif
|
||||
|
||||
exitval = a.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| If no GUI is needed, we let the background |
|
||||
| threads run as long as they need, but we need to |
|
||||
| AT LEAST wait for initialization to finish |
|
||||
\*-------------------------------------------------*/
|
||||
ResourceManager::get()->WaitForInitialization();
|
||||
|
||||
if(ret_flags & RET_FLAG_START_SERVER)
|
||||
{
|
||||
NetworkServer* server = ResourceManager::get()->GetServer();
|
||||
if(server)
|
||||
{
|
||||
exitval = !server->GetOnline();
|
||||
}
|
||||
else
|
||||
{
|
||||
exitval = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(exitval);
|
||||
}
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| startup.h |
|
||||
| |
|
||||
| Startup for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int startup(int argc, char* argv[], unsigned int ret_flags);
|
||||
/*---------------------------------------------------------*\
|
||||
| startup.h |
|
||||
| |
|
||||
| Startup for the OpenRGB application |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int startup(int argc, char* argv[], unsigned int ret_flags);
|
||||
Reference in new issue
Block a user