init: public
This commit is contained in:
34
modules/virt/types/app.nix
Normal file
34
modules/virt/types/app.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
renderer = lib.mkOption {
|
||||
description = "Specify the renderer to use";
|
||||
default = "auto";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
cursorPollInterval = lib.mkOption {
|
||||
description = "How often to check for a cursor update in microseconds";
|
||||
default = 1000;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
|
||||
framePollInterval = lib.mkOption {
|
||||
description = "How often to check for a frame update in microseconds";
|
||||
default = 1000;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
|
||||
allowDMA = lib.mkOption {
|
||||
description = "Allow DMA transfers if supported";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
shmFile = lib.mkOption {
|
||||
description = "Path to the shared memory file or kvmfr device";
|
||||
default = "/dev/kvmfr0";
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
}
|
||||
32
modules/virt/types/audio.nix
Normal file
32
modules/virt/types/audio.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
periodSize = lib.mkOption {
|
||||
description = "Requested audio device period size in samples";
|
||||
default = 2048;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
|
||||
bufferLatency = lib.mkOption {
|
||||
description = "Additional buffer latency in milliseconds";
|
||||
default = 13;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
|
||||
micDefault = lib.mkOption {
|
||||
description = "Default action when an application opens the microphone";
|
||||
default = "prompt";
|
||||
type = lib.types.enum [
|
||||
"prompt"
|
||||
"allow"
|
||||
"deny"
|
||||
];
|
||||
};
|
||||
|
||||
micShowIndicator = lib.mkOption {
|
||||
description = "Display microphone usage indicator";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
52
modules/virt/types/default.nix
Normal file
52
modules/virt/types/default.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
app = lib.mkOption {
|
||||
description = "Application-wide configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./app.nix;
|
||||
};
|
||||
|
||||
win = lib.mkOption {
|
||||
description = "Window configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./win.nix;
|
||||
};
|
||||
|
||||
input = lib.mkOption {
|
||||
description = "Input configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./input.nix;
|
||||
};
|
||||
|
||||
spice = lib.mkOption {
|
||||
description = "Spice agent configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./spice.nix;
|
||||
};
|
||||
|
||||
audio = lib.mkOption {
|
||||
description = "Audio configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./audio.nix;
|
||||
};
|
||||
|
||||
egl = lib.mkOption {
|
||||
description = "EGL configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./egl.nix;
|
||||
};
|
||||
|
||||
opengl = lib.mkOption {
|
||||
description = "OpenGL configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./opengl.nix;
|
||||
};
|
||||
|
||||
wayland = lib.mkOption {
|
||||
description = "Wayland configuration";
|
||||
default = { };
|
||||
type = lib.types.submodule ./wayland.nix;
|
||||
};
|
||||
};
|
||||
}
|
||||
70
modules/virt/types/egl.nix
Normal file
70
modules/virt/types/egl.nix
Normal file
@@ -0,0 +1,70 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
vsync = lib.mkOption {
|
||||
description = "Enable vsync";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
doubleBuffer = lib.mkOption {
|
||||
description = "Enable double buffering";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
multiSample = lib.mkOption {
|
||||
description = "Enable multisampling";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
nvGainMax = lib.mkOption {
|
||||
description = "The maximum night vision gain";
|
||||
default = 1;
|
||||
type = lib.types.int;
|
||||
};
|
||||
|
||||
nvGain = lib.mkOption {
|
||||
description = "The initial night vision gain at startup";
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
};
|
||||
|
||||
cbMode = lib.mkOption {
|
||||
description = "Color Blind Mode (0 = Off, 1 = Protanope, 2 = Deuteranope, 3 = Tritanope)";
|
||||
default = 0;
|
||||
type = lib.types.addCheck lib.types.int (x: x >= 0 && x <= 3);
|
||||
};
|
||||
|
||||
scale = lib.mkOption {
|
||||
description = "Set the scale algorithm (0 = auto, 1 = nearest, 2 = linear)";
|
||||
default = 0;
|
||||
type = lib.types.addCheck lib.types.int (x: x >= 0 && x <= 2);
|
||||
};
|
||||
|
||||
debug = lib.mkOption {
|
||||
description = "Enable debug output";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
noBufferAge = lib.mkOption {
|
||||
description = "Disable partial rendering based on buffer age";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
noSwapDamage = lib.mkOption {
|
||||
description = "Disable swapping with damage";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
scalePointer = lib.mkOption {
|
||||
description = "Keep the pointer size 1:1 when downscaling";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
84
modules/virt/types/input.nix
Normal file
84
modules/virt/types/input.nix
Normal file
@@ -0,0 +1,84 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
grabKeyboard = lib.mkOption {
|
||||
description = "Grab the keybaord in capture mode";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
grabKeyboardOnFocus = lib.mkOption {
|
||||
description = "Grab the keyboard when focused";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
releaseKeysOnFocusLoss = lib.mkOption {
|
||||
description = "On focus loss, send key up events to guest for all held keys";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
escapeKey = lib.mkOption {
|
||||
description = "Specify the escape/menu key to use";
|
||||
default = "KEY_SCROLLLOCK";
|
||||
type = import ./keys.nix {
|
||||
inherit lib;
|
||||
};
|
||||
};
|
||||
|
||||
ignoreWindowsKeys = lib.mkOption {
|
||||
description = "Do not pass events for the windows keys to the guest";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
hideCursor = lib.mkOption {
|
||||
description = "Hide the local mouse cursor";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
mouseSens = lib.mkOption {
|
||||
description = "Initial mouse sensitivity when in capture mode (-9 to 9)";
|
||||
default = 0;
|
||||
type = lib.types.addCheck lib.types.int (x: x >= -9 && x <= 9);
|
||||
};
|
||||
|
||||
mouseSmoothing = lib.mkOption {
|
||||
description = "Apply simple mouse smoothing when rawMouse is not in use";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
rawMouse = lib.mkOption {
|
||||
description = "Use RAW mouse input when in capture mode (good for gaming)";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
mouseRedraw = lib.mkOption {
|
||||
description = "Mouse movements trigger redraws (ignore FPS minimum)";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
autoCapture = lib.mkOption {
|
||||
description = "Try to keep the mouse captured when needed";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
captureOnly = lib.mkOption {
|
||||
description = "Only enable input via SPICE if in capture mode";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
helpMenuDelay = lib.mkOption {
|
||||
description = "Show help menu after holding down the escape key for this many milliseconds";
|
||||
default = 200;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
};
|
||||
}
|
||||
129
modules/virt/types/keys.nix
Normal file
129
modules/virt/types/keys.nix
Normal file
@@ -0,0 +1,129 @@
|
||||
{ lib, ... }:
|
||||
lib.types.enum [
|
||||
"KEY_RESERVED"
|
||||
"KEY_ESC"
|
||||
"KEY_1"
|
||||
"KEY_2"
|
||||
"KEY_3"
|
||||
"KEY_4"
|
||||
"KEY_5"
|
||||
"KEY_6"
|
||||
"KEY_7"
|
||||
"KEY_8"
|
||||
"KEY_9"
|
||||
"KEY_0"
|
||||
"KEY_MINUS"
|
||||
"KEY_EQUAL"
|
||||
"KEY_BACKSPACE"
|
||||
"KEY_TAB"
|
||||
"KEY_Q"
|
||||
"KEY_W"
|
||||
"KEY_E"
|
||||
"KEY_R"
|
||||
"KEY_T"
|
||||
"KEY_Y"
|
||||
"KEY_U"
|
||||
"KEY_I"
|
||||
"KEY_O"
|
||||
"KEY_P"
|
||||
"KEY_LEFTBRACE"
|
||||
"KEY_RIGHTBRACE"
|
||||
"KEY_ENTER"
|
||||
"KEY_LEFTCTRL"
|
||||
"KEY_A"
|
||||
"KEY_S"
|
||||
"KEY_D"
|
||||
"KEY_F"
|
||||
"KEY_G"
|
||||
"KEY_H"
|
||||
"KEY_J"
|
||||
"KEY_K"
|
||||
"KEY_L"
|
||||
"KEY_SEMICOLON"
|
||||
"KEY_APOSTROPHE"
|
||||
"KEY_GRAVE"
|
||||
"KEY_LEFTSHIFT"
|
||||
"KEY_BACKSLASH"
|
||||
"KEY_Z"
|
||||
"KEY_X"
|
||||
"KEY_C"
|
||||
"KEY_V"
|
||||
"KEY_B"
|
||||
"KEY_N"
|
||||
"KEY_M"
|
||||
"KEY_COMMA"
|
||||
"KEY_DOT"
|
||||
"KEY_SLASH"
|
||||
"KEY_RIGHTSHIFT"
|
||||
"KEY_KPASTERISK"
|
||||
"KEY_LEFTALT"
|
||||
"KEY_SPACE"
|
||||
"KEY_CAPSLOCK"
|
||||
"KEY_F1"
|
||||
"KEY_F2"
|
||||
"KEY_F3"
|
||||
"KEY_F4"
|
||||
"KEY_F5"
|
||||
"KEY_F6"
|
||||
"KEY_F7"
|
||||
"KEY_F8"
|
||||
"KEY_F9"
|
||||
"KEY_F10"
|
||||
"KEY_NUMLOCK"
|
||||
"KEY_SCROLLLOCK"
|
||||
"KEY_KP7"
|
||||
"KEY_KP8"
|
||||
"KEY_KP9"
|
||||
"KEY_KPMINUS"
|
||||
"KEY_KP4"
|
||||
"KEY_KP5"
|
||||
"KEY_KP6"
|
||||
"KEY_KPPLUS"
|
||||
"KEY_KP1"
|
||||
"KEY_KP2"
|
||||
"KEY_KP3"
|
||||
"KEY_KP0"
|
||||
"KEY_KPDOT"
|
||||
"KEY_102ND"
|
||||
"KEY_F11"
|
||||
"KEY_F12"
|
||||
"KEY_RO"
|
||||
"KEY_HENKAN"
|
||||
"KEY_KATAKANAHIRAGANA"
|
||||
"KEY_MUHENKAN"
|
||||
"KEY_KPENTER"
|
||||
"KEY_RIGHTCTRL"
|
||||
"KEY_KPSLASH"
|
||||
"KEY_SYSRQ"
|
||||
"KEY_RIGHTALT"
|
||||
"KEY_HOME"
|
||||
"KEY_UP"
|
||||
"KEY_PAGEUP"
|
||||
"KEY_LEFT"
|
||||
"KEY_RIGHT"
|
||||
"KEY_END"
|
||||
"KEY_DOWN"
|
||||
"KEY_PAGEDOWN"
|
||||
"KEY_INSERT"
|
||||
"KEY_DELETE"
|
||||
"KEY_MUTE"
|
||||
"KEY_VOLUMEDOWN"
|
||||
"KEY_VOLUMEUP"
|
||||
"KEY_KPEQUAL"
|
||||
"KEY_PAUSE"
|
||||
"KEY_KPCOMMA"
|
||||
"KEY_HANGEUL"
|
||||
"KEY_HANJA"
|
||||
"KEY_YEN"
|
||||
"KEY_LEFTMETA"
|
||||
"KEY_RIGHTMETA"
|
||||
"KEY_COMPOSE"
|
||||
"KEY_NEXTSONG"
|
||||
"KEY_PLAYPAUSE"
|
||||
"KEY_PREVIOUSSONG"
|
||||
"KEY_STOPCD"
|
||||
"KEY_F13"
|
||||
"KEY_F14"
|
||||
"KEY_F15"
|
||||
"KEY_PRINT"
|
||||
]
|
||||
28
modules/virt/types/opengl.nix
Normal file
28
modules/virt/types/opengl.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
mipmap = lib.mkOption {
|
||||
description = "Enable mipmapping";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
vsync = lib.mkOption {
|
||||
description = "Enable vsync";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
preventBuffer = lib.mkOption {
|
||||
description = "Prevent the driver from buffering frames";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
amdPinnedMem = lib.mkOption {
|
||||
description = "Use GL_AMD_pinned_memory if it is available";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
76
modules/virt/types/spice.nix
Normal file
76
modules/virt/types/spice.nix
Normal file
@@ -0,0 +1,76 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
description = "Enable the built-in SPICE client for input and/or clipboard support";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
host = lib.mkOption {
|
||||
description = "The SPICE server host or UNIX socket";
|
||||
default = "127.0.0.1";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
description = "The SPICE server port (0 = unix socket)";
|
||||
default = 5900;
|
||||
type = lib.types.port;
|
||||
};
|
||||
|
||||
input = lib.mkOption {
|
||||
description = "Use SPICE to send keyboard and mouse input events to the guest";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
clipboard = lib.mkOption {
|
||||
description = "Use SPICE to synchronize the clipboard contents with the guest";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
clipboardToVM = lib.mkOption {
|
||||
description = "Allow the clipboard to be synchronized TO the VM";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
clipboardToLocal = lib.mkOption {
|
||||
description = "Allow the clipbaord to be synchronized FROM the VM";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
audio = lib.mkOption {
|
||||
description = "Enable SPICE audio support";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
scaleCursor = lib.mkOption {
|
||||
description = "Scale cursor input position to screen size when up/down scaled";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
captureOnStart = lib.mkOption {
|
||||
description = "Capture mouse and keybaord on start";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
alwaysShowCursor = lib.mkOption {
|
||||
description = "Always show host cursor";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
showCursorDot = lib.mkOption {
|
||||
description = "Use a 'dot' cursor when the window does not have focus";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
16
modules/virt/types/wayland.nix
Normal file
16
modules/virt/types/wayland.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
warpSupport = lib.mkOption {
|
||||
description = "Enable cursor warping";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
fractionScale = lib.mkOption {
|
||||
description = "Enable fractional scale";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
160
modules/virt/types/win.nix
Normal file
160
modules/virt/types/win.nix
Normal file
@@ -0,0 +1,160 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options = {
|
||||
title = lib.mkOption {
|
||||
description = "Window Title";
|
||||
default = "Looking Glass (client)";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
position = lib.mkOption {
|
||||
description = "Initial window position at startup";
|
||||
default = "center";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
size = lib.mkOption {
|
||||
description = "Initial window size at startup";
|
||||
default = "1024x768";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
autoResize = lib.mkOption {
|
||||
description = "Auto resize the window to the guest";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
allowResize = lib.mkOption {
|
||||
description = "Allow the window to be resized manually";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
keepAspect = lib.mkOption {
|
||||
description = "Maintain correct aspect ratio";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
forceAspect = lib.mkOption {
|
||||
description = "Force the window to maintain the aspect ratio";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
dontUpscale = lib.mkOption {
|
||||
description = "Never try to upscale the window";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
intUpscale = lib.mkOption {
|
||||
description = "Allow only integer upscaling";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
shrinkOnUpscale = lib.mkOption {
|
||||
description = "Limit the window dimensions when dontUpscale is enabled";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
borderless = lib.mkOption {
|
||||
description = "Borderless mode";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
fullScreen = lib.mkOption {
|
||||
description = "Launch in fullscreen borderless mode";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
maximize = lib.mkOption {
|
||||
description = "Launch window maximized";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
minimizeOnFocusLoss = lib.mkOption {
|
||||
description = "Minimize window on focus loss";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
fpsMin = lib.mkOption {
|
||||
description = "Frame rate minimum (0 = disabled - not recommended, -1 = auto-detect)";
|
||||
default = -1;
|
||||
type = lib.types.addCheck lib.types.int (x: x == -1 || x >= 0);
|
||||
};
|
||||
|
||||
ignoreQuit = lib.mkOption {
|
||||
description = "Ignore requests to quit (i.e. Alt+F4)";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
noScreensaver = lib.mkOption {
|
||||
description = "Prevent the screensaver from starting";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
autoScreensaver = lib.mkOption {
|
||||
description = "Prevent the screensaver from starting when the guest requests it";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
alerts = lib.mkOption {
|
||||
description = "Show on screen alert messages";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
quickSplash = lib.mkOption {
|
||||
description = "Skip fading out the splash screen when a connection is established";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
overlayDimsDesktop = lib.mkOption {
|
||||
description = "Dim the desktop when in interactive overlay mode";
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
rotate = lib.mkOption {
|
||||
description = "Rotate the displayed image (0, 90, 180, 270)";
|
||||
default = 0;
|
||||
type = lib.types.int;
|
||||
};
|
||||
|
||||
uiFont = lib.mkOption {
|
||||
description = "The font to use when rendering on-screen UI";
|
||||
default = "DejaVu Sans Mono";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
uiSize = lib.mkOption {
|
||||
description = "The font size to use when rendering on-screen UI";
|
||||
default = 14;
|
||||
type = lib.types.ints.positive;
|
||||
};
|
||||
|
||||
jitRender = lib.mkOption {
|
||||
description = "Enable just-in-time rendering";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
showFPS = lib.mkOption {
|
||||
description = "Enable the FPS and UPS display";
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user