Add host modules and home options; update README
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
{
|
||||
pkgs,
|
||||
username,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
programs.anki = {
|
||||
options.anki.enable = lib.mkEnableOption "Anki";
|
||||
|
||||
config.programs.anki = lib.mkIf config.anki.enable {
|
||||
enable = true;
|
||||
package = pkgs.anki;
|
||||
language = "pl_PL";
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
programs.btop = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.btop.enable = lib.mkEnableOption "Btop";
|
||||
|
||||
config.programs.btop = lib.mkIf config.btop.enable {
|
||||
enable = true;
|
||||
package = pkgs.btop.override {
|
||||
rocmSupport = true;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
_: {
|
||||
programs.cava = {
|
||||
enable = false;
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.cava.enable = lib.mkEnableOption "Cava";
|
||||
|
||||
config.programs.cava = lib.mkIf config.cava.enable {
|
||||
enable = true;
|
||||
settings = {
|
||||
general = {
|
||||
bar_spacing = 1;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
programs.chromium = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.ungoogled-chromium.enable = lib.mkEnableOption "Ungoogled Chromium";
|
||||
|
||||
config.programs.chromium = lib.mkIf config.ungoogled-chromium.enable {
|
||||
enable = true;
|
||||
package = pkgs.ungoogled-chromium;
|
||||
# commandLineArgs = [ ];
|
||||
|
||||
@@ -1,184 +1,17 @@
|
||||
{
|
||||
programs.fastfetch = {
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.fastfetch.enable = lib.mkEnableOption "FastFetch";
|
||||
|
||||
config.programs.fastfetch = lib.mkIf config.fastfetch.enable {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
display = {
|
||||
color = {
|
||||
keys = "35";
|
||||
output = "90";
|
||||
};
|
||||
separator = " ➜ ";
|
||||
};
|
||||
|
||||
logo = {
|
||||
source = ./garandos.png;
|
||||
type = "kitty-direct";
|
||||
height = 15;
|
||||
width = 30;
|
||||
padding = {
|
||||
top = 3;
|
||||
left = 3;
|
||||
};
|
||||
};
|
||||
|
||||
modules = [
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌─────────────────────────────────Hardware────────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "host";
|
||||
format = "{5} {1} Type {2}";
|
||||
key = "│ PC";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "cpu";
|
||||
format = "{1} ({3}) @ {7} GHz";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "gpu";
|
||||
format = "{1} {2} @ {12} GHz";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "memory";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "swap";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "disk";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "monitor";
|
||||
key = "│ └ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌─────────────────────────────────Software─────────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "os";
|
||||
key = "│ OS";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
text = "echo GarandOS v$" + "{GARANDOS_VERSION}";
|
||||
}
|
||||
{
|
||||
type = "kernel";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "packages";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "shell";
|
||||
key = "│ └ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "wm";
|
||||
key = "│ WM";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "wmtheme";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "icons";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "cursor";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "terminal";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "terminalfont";
|
||||
key = "│ └ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌───────────────────────────────Age / Uptime───────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ IN";
|
||||
text =
|
||||
#bash
|
||||
''
|
||||
birth_install=$(stat -c %W /)
|
||||
if [ "$birth_install" -gt 0 ]; then
|
||||
echo "Installed $(date -d @"$birth_install" +"%Y-%m-%d")"
|
||||
else
|
||||
echo "Installation date unknown"
|
||||
fi
|
||||
'';
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ ├ ";
|
||||
text =
|
||||
#bash
|
||||
''
|
||||
birth_install=$(stat -c %W /)
|
||||
current=$(date +%s)
|
||||
delta=$((current - birth_install))
|
||||
delta_days=$((delta / 86400))
|
||||
echo $delta_days days
|
||||
'';
|
||||
}
|
||||
{
|
||||
type = "uptime";
|
||||
key = "│ └ ";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
"break"
|
||||
];
|
||||
};
|
||||
package = pkgs.fastfetch;
|
||||
};
|
||||
|
||||
imports = [
|
||||
./settings
|
||||
];
|
||||
}
|
||||
|
||||
7
modules/home/fastfetch/settings/default.nix
Normal file
7
modules/home/fastfetch/settings/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
_: {
|
||||
imports = [
|
||||
./display.nix
|
||||
./logo.nix
|
||||
./modules.nix
|
||||
];
|
||||
}
|
||||
9
modules/home/fastfetch/settings/display.nix
Normal file
9
modules/home/fastfetch/settings/display.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
_: {
|
||||
programs.fastfetch.settings.display = {
|
||||
color = {
|
||||
keys = "35";
|
||||
output = "90";
|
||||
};
|
||||
separator = " ➜ ";
|
||||
};
|
||||
}
|
||||
12
modules/home/fastfetch/settings/logo.nix
Normal file
12
modules/home/fastfetch/settings/logo.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
_: {
|
||||
programs.fastfetch.settings.logo = {
|
||||
source = ../garandos.png;
|
||||
type = "kitty-direct";
|
||||
height = 15;
|
||||
width = 30;
|
||||
padding = {
|
||||
top = 3;
|
||||
left = 3;
|
||||
};
|
||||
};
|
||||
}
|
||||
159
modules/home/fastfetch/settings/modules.nix
Normal file
159
modules/home/fastfetch/settings/modules.nix
Normal file
@@ -0,0 +1,159 @@
|
||||
_: {
|
||||
programs.fastfetch.settings.modules = [
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌─────────────────────────────────Hardware────────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "host";
|
||||
format = "{5} {1} Type {2}";
|
||||
key = "│ PC";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "cpu";
|
||||
format = "{1} ({3}) @ {7} GHz";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "gpu";
|
||||
format = "{1} {2} @ {12} GHz";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "memory";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "swap";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "disk";
|
||||
key = "│ ├ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "monitor";
|
||||
key = "│ └ ";
|
||||
keyColor = "33";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌─────────────────────────────────Software─────────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "os";
|
||||
key = "│ OS";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
text = "echo GarandOS v$" + "{GARANDOS_VERSION}";
|
||||
}
|
||||
{
|
||||
type = "kernel";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "packages";
|
||||
key = "│ ├ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "shell";
|
||||
key = "│ └ ";
|
||||
keyColor = "31";
|
||||
}
|
||||
{
|
||||
type = "wm";
|
||||
key = "│ WM";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "wmtheme";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "icons";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "cursor";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "terminal";
|
||||
key = "│ ├ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "terminalfont";
|
||||
key = "│ └ ";
|
||||
keyColor = "32";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
|
||||
"break"
|
||||
{
|
||||
type = "custom";
|
||||
format = "┌───────────────────────────────Age / Uptime───────────────────────────────┐";
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ IN";
|
||||
text =
|
||||
#bash
|
||||
''
|
||||
birth_install=$(stat -c %W /)
|
||||
if [ "$birth_install" -gt 0 ]; then
|
||||
echo "Installed $(date -d @"$birth_install" +"%Y-%m-%d")"
|
||||
else
|
||||
echo "Installation date unknown"
|
||||
fi
|
||||
'';
|
||||
}
|
||||
{
|
||||
type = "command";
|
||||
key = "│ ├ ";
|
||||
text =
|
||||
#bash
|
||||
''
|
||||
birth_install=$(stat -c %W /)
|
||||
current=$(date +%s)
|
||||
delta=$((current - birth_install))
|
||||
delta_days=$((delta / 86400))
|
||||
echo $delta_days days
|
||||
'';
|
||||
}
|
||||
{
|
||||
type = "uptime";
|
||||
key = "│ └ ";
|
||||
}
|
||||
{
|
||||
type = "custom";
|
||||
format = "└──────────────────────────────────────────────────────────────────────────┘";
|
||||
}
|
||||
"break"
|
||||
];
|
||||
}
|
||||
@@ -12,14 +12,19 @@ in {
|
||||
# APLIKACJE - GŁÓWNE
|
||||
# =============================================================================
|
||||
"$modifier, A, exec, anki"
|
||||
"$modifier, B, exec, bitwarden"
|
||||
"$modifier, C, exec, chromium"
|
||||
"$modifier, D, exec, vesktop"
|
||||
"$modifier, G, exec, affinity-v3"
|
||||
"$modifier, I, exec, iotas"
|
||||
"$modifier, L, exec, logseq"
|
||||
"$modifier, M, exec, plexamp"
|
||||
"$modifier, N, exec, dex ${desktopEntriesPath}/garandcloud.desktop"
|
||||
"$modifier, O, exec, obs"
|
||||
"$modifier, Return, exec, ${terminal}"
|
||||
"$modifier, S, exec, steam"
|
||||
"$modifier, T, exec, thunar"
|
||||
"$modifier, V, exec, codium"
|
||||
"$modifier, W, exec, ${browser}"
|
||||
"$modifier, Z, exec, zeditor"
|
||||
|
||||
@@ -42,11 +47,12 @@ in {
|
||||
"$modifier ALT, G, exec, dex ${desktopEntriesPath}/glance.desktop"
|
||||
"$modifier ALT, M, exec, dex ${desktopEntriesPath}/mastodon.desktop"
|
||||
"$modifier ALT, S, exec, slack"
|
||||
"$modifier ALT, T, exec, gnome-text-editor"
|
||||
"$modifier ALT, T, exec, gedit"
|
||||
|
||||
# =============================================================================
|
||||
# APLIKACJE - Z CONTROL
|
||||
# =============================================================================
|
||||
"$modifier CONTROL, G, exec, gimp"
|
||||
"$modifier CONTROL, M, exec, mattermost-desktop"
|
||||
|
||||
# =============================================================================
|
||||
@@ -142,12 +148,6 @@ in {
|
||||
# =============================================================================
|
||||
# NIEUŻYWANE KEYBINDY
|
||||
# =============================================================================
|
||||
# "$modifier, B, exec, bitwarden"
|
||||
# "$modifier, G, exec, affinity-v3"
|
||||
# "$modifier, L, exec, logseq"
|
||||
# "$modifier, O, exec, obs"
|
||||
# "$modifier, V, exec, codium"
|
||||
|
||||
# "$modifier SHIFT, N, exec, swaync-client -rs"
|
||||
# "$modifier, P, pseudo,"
|
||||
# "$modifier SHIFT,F, togglefloating,"
|
||||
|
||||
@@ -54,7 +54,7 @@ _: {
|
||||
"float, tag:settings*"
|
||||
"float, class:^([Ff]erdium)$"
|
||||
"float, title:^(Picture-in-Picture)$"
|
||||
"float, class:^(mpv|com.github.rafostar.Clapper)$"
|
||||
"float, class:^(mpv)$"
|
||||
"float, title:^(Authentication Required)$"
|
||||
"float, title:^(War in Tunnels)$"
|
||||
"float, class:(codium|codium-url-handler|VSCodium), title:negative:(.*codium.*|.*VSCodium.*)"
|
||||
@@ -71,6 +71,7 @@ _: {
|
||||
"size 70% 60%, initialTitle:(Add Folder to Workspace)"
|
||||
"size 70% 70%, tag:settings*"
|
||||
"size 60% 70%, class:^([Ff]erdium)$"
|
||||
"size 70% 70%, class:^(mpv)$"
|
||||
|
||||
# Tile rules
|
||||
"tile, class:^(affinity.exe)$"
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
services.kdeconnect = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.kdeconnect.enable = lib.mkEnableOption "KDE Connect";
|
||||
|
||||
config.services.kdeconnect = lib.mkIf config.kdeconnect.enable {
|
||||
enable = true;
|
||||
indicator = true;
|
||||
package = pkgs.kdePackages.kdeconnect-kde;
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
{pkgs, ...}: {
|
||||
programs = {
|
||||
librewolf = {
|
||||
enable = true;
|
||||
package = pkgs.librewolf;
|
||||
# nativeMessagingHosts = [pkgs.firefoxpwa];
|
||||
languagePacks = [
|
||||
"pl"
|
||||
"en-US"
|
||||
];
|
||||
settings = {
|
||||
# LibreWolf settings
|
||||
"network.http.referer.XOriginPolicy" = 2;
|
||||
"privacy.resistFingerprinting.letterboxing" = true;
|
||||
"privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts" = true;
|
||||
};
|
||||
policies = {
|
||||
# Policies (about:policies#documentation)
|
||||
};
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.librewolf.enable = lib.mkEnableOption "LibreWolf";
|
||||
|
||||
config.programs.librewolf = lib.mkIf config.librewolf.enable {
|
||||
enable = true;
|
||||
package = pkgs.librewolf;
|
||||
# nativeMessagingHosts = [pkgs.firefoxpwa];
|
||||
languagePacks = [
|
||||
"pl"
|
||||
"en-US"
|
||||
];
|
||||
settings = {
|
||||
# LibreWolf settings
|
||||
"network.http.referer.XOriginPolicy" = 2;
|
||||
"privacy.resistFingerprinting.letterboxing" = true;
|
||||
"privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts" = true;
|
||||
};
|
||||
policies = {
|
||||
# Policies (about:policies#documentation)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
{
|
||||
pkgs,
|
||||
osConfig,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
programs.lutris = {
|
||||
enable = false;
|
||||
options.lutris.enable = lib.mkEnableOption "Lutris";
|
||||
|
||||
config.programs.lutris = lib.mkIf config.lutris.enable {
|
||||
enable = true;
|
||||
package = pkgs.lutris;
|
||||
protonPackages = [pkgs.proton-ge-bin];
|
||||
winePackages = [pkgs.wineWowPackages.waylandFull];
|
||||
defaultWinePackage = pkgs.wineWowPackages.waylandFull;
|
||||
steamPackage = osConfig.programs.steam.package;
|
||||
steamPackage = pkgs.steam;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
services.nextcloud-client = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.nextcloud-client.enable = lib.mkEnableOption "Nextcloud Client";
|
||||
|
||||
config.services.nextcloud-client = lib.mkIf config.nextcloud-client.enable {
|
||||
enable = true;
|
||||
startInBackground = true;
|
||||
package = pkgs.nextcloud-client;
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
{pkgs, ...}: {
|
||||
programs.obs-studio = {
|
||||
enable = false;
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.obs-studio.enable = lib.mkEnableOption "OBS Studio";
|
||||
|
||||
config.programs.obs-studio = lib.mkIf config.obs-studio.enable {
|
||||
enable = true;
|
||||
plugins = with pkgs.obs-studio-plugins; [
|
||||
wlrobs
|
||||
obs-pipewire-audio-capture
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
programs.onlyoffice = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.onlyoffice.enable = lib.mkEnableOption "OnlyOffice";
|
||||
|
||||
config.programs.onlyoffice = lib.mkIf config.onlyoffice.enable {
|
||||
enable = true;
|
||||
package = pkgs.onlyoffice-desktopeditors;
|
||||
settings = {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vesktop = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.vesktop.enable = lib.mkEnableOption "Vesktop";
|
||||
|
||||
config.programs.vesktop = lib.mkIf config.vesktop.enable {
|
||||
enable = true;
|
||||
package = pkgs.vesktop;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
enable = false;
|
||||
package = pkgs.vscodium;
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.vscodium.enable = lib.mkEnableOption "VsCodium";
|
||||
|
||||
config = {
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
programs.vscode = lib.mkIf config.vscodium.enable {
|
||||
enable = true;
|
||||
package = pkgs.vscodium;
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
{pkgs, ...}: {
|
||||
programs.zed-editor = {
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.zed-editor = {
|
||||
enable = lib.mkEnableOption "Zed Editor";
|
||||
remote-server = lib.mkEnableOption "Zed Editor Remote Server";
|
||||
};
|
||||
|
||||
config.programs.zed-editor = lib.mkIf config.zed-editor.enable {
|
||||
enable = true;
|
||||
package = pkgs.zed-editor;
|
||||
installRemoteServer = true;
|
||||
installRemoteServer = lib.mkIf config.zed-editor.remote-server true;
|
||||
};
|
||||
|
||||
imports = [
|
||||
./user-settings
|
||||
./extensions.nix
|
||||
|
||||
Reference in New Issue
Block a user