nix: Make nix the root
Which means now I'll have to think about real prefixes in commit names.
This commit is contained in:
parent
550eed06e0
commit
ee178b7d57
190 changed files with 5 additions and 6 deletions
514
hm/common.nix
Normal file
514
hm/common.nix
Normal file
|
@ -0,0 +1,514 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
let
|
||||
direnv = {
|
||||
# Environment variables making programs stay out of $HOME, but also needing we create a directory for them
|
||||
CARGOHOME = "${config.xdg.cacheHome}/cargo"; # There are config in there that we can version if one want
|
||||
CCACHE_DIR = "${config.xdg.cacheHome}/ccache"; # The config file alone seems to be not enough
|
||||
DASHT_DOCSETS_DIR = "${config.xdg.cacheHome}/dash_docsets";
|
||||
GOPATH = "${config.xdg.cacheHome}/go";
|
||||
GRADLE_USER_HOME = "${config.xdg.cacheHome}/gradle";
|
||||
MIX_ARCHIVES = "${config.xdg.cacheHome}/mix/archives";
|
||||
MONO_GAC_PREFIX = "${config.xdg.cacheHome}/mono";
|
||||
npm_config_cache = "${config.xdg.cacheHome}/npm";
|
||||
PARALLEL_HOME = "${config.xdg.cacheHome}/parallel";
|
||||
TERMINFO = "${config.xdg.configHome}/terminfo";
|
||||
WINEPREFIX = "${config.xdg.stateHome}/wineprefix/default";
|
||||
YARN_CACHE_FOLDER = "${config.xdg.cacheHome}/yarn";
|
||||
# TODO Some of that stuff is not really relavant any more
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
programs =
|
||||
let
|
||||
commonRc = lib.strings.concatLines ([
|
||||
''
|
||||
# Colored ls
|
||||
# TODO Doesn't allow completion. Check out lsd instead
|
||||
_colored_ls() {
|
||||
\ls -lh --color=always $@ | awk '
|
||||
BEGIN {
|
||||
FPAT = "([[:space:]]*[^[:space:]]+)";
|
||||
OFS = "";
|
||||
}
|
||||
{
|
||||
$1 = "\033[36m" $1 "\033[0m";
|
||||
$2 = "\033[31m" $2 "\033[0m";
|
||||
$3 = "\033[32m" $3 "\033[0m";
|
||||
$4 = "\033[32m" $4 "\033[0m";
|
||||
$5 = "\033[31m" $5 "\033[0m";
|
||||
$6 = "\033[34m" $6 "\033[0m";
|
||||
$7 = "\033[34m" $7 "\033[0m";
|
||||
print
|
||||
}
|
||||
'
|
||||
}
|
||||
alias ll="_colored_ls"
|
||||
alias la="_colored_ls -a"
|
||||
''
|
||||
] ++ map (d: "mkdir -p ${d}") (builtins.attrValues direnv));
|
||||
# TODO Those directory creations should probably done on home-manager activation
|
||||
commonSessionVariables = {
|
||||
TIME_STYLE = "+%Y-%m-%d %H:%M:%S";
|
||||
# Less colors
|
||||
LESS = "-R";
|
||||
LESS_TERMCAP_mb = "$'\E[1;31m'"; # begin blink
|
||||
LESS_TERMCAP_md = "$'\E[1;36m'"; # begin bold
|
||||
LESS_TERMCAP_me = "$'\E[0m'"; # reset bold/blink
|
||||
LESS_TERMCAP_so = "$'\E[01;44;33m'"; # begin reverse video
|
||||
LESS_TERMCAP_se = "$'\E[0m'"; # reset reverse video
|
||||
LESS_TERMCAP_us = "$'\E[1;32m'"; # begin underline
|
||||
LESS_TERMCAP_ue = "$'\E[0m'"; # reset underline
|
||||
# Fzf
|
||||
FZF_COMPLETION_OPTS = "${lib.strings.concatStringsSep " " config.programs.fzf.fileWidgetOptions}";
|
||||
};
|
||||
treatsHomeAsJunk = [
|
||||
# Programs that think $HOME is a reasonable place to put their junk
|
||||
# and don't allow the user to change those questionable choices
|
||||
"adb"
|
||||
"audacity"
|
||||
"binwalk" # Should use .config according to the GitHub code though
|
||||
"cabal" # TODO May have options but last time I tried it it crashed
|
||||
"cmake"
|
||||
"ddd"
|
||||
"ghidra"
|
||||
"itch"
|
||||
"simplescreenrecorder" # Easy fix https://github.com/MaartenBaert/ssr/blob/1556ae456e833992fb6d39d40f7c7d7c337a4160/src/Main.cpp#L252
|
||||
"vd"
|
||||
"wpa_cli"
|
||||
# TODO Maybe we can do something about node-gyp
|
||||
];
|
||||
commonShellAliases = {
|
||||
# Completion for existing commands
|
||||
ls = "ls -h --color=auto";
|
||||
mkdir = "mkdir -v";
|
||||
# cp = "cp -i"; # Disabled because conflicts with the ZSH/Bash one. This separation is confusing I swear.
|
||||
mv = "mv -iv";
|
||||
free = "free -h";
|
||||
df = "df -h";
|
||||
ffmpeg = "ffmpeg -hide_banner";
|
||||
ffprobe = "ffprobe -hide_banner";
|
||||
ffplay = "ffplay -hide_banner";
|
||||
# TODO Add ipython --no-confirm-exit --pdb
|
||||
|
||||
# Frequent mistakes
|
||||
sl = "ls";
|
||||
al = "la";
|
||||
mdkir = "mkdir";
|
||||
systemclt = "systemctl";
|
||||
please = "sudo";
|
||||
|
||||
# Shortcuts for commonly used commands
|
||||
# ll = "ls -l"; # Disabled because would overwrite the colored one
|
||||
# la = "ls -la"; # Eh maybe it's not that bad, but for now let's keep compatibility
|
||||
s = "sudo -s -E";
|
||||
# n = "$HOME/.config/i3/terminal & disown"; # Not used anymore since alacritty daemon mode doesn't preserve environment variables
|
||||
x = "startx ${config.xdg.configHome}/xinitrc; logout";
|
||||
nx = "nvidia-xrun ${config.xdg.configHome}/xinitrc; sudo systemctl start nvidia-xrun-pm; logout";
|
||||
# TODO Put in display.nix
|
||||
# Was also thinking of not storing the config in .config and use nix-store instead,
|
||||
# but maybe it's a bad idea as home-manager switch doesn't replace aliases in running shells
|
||||
# FIXME Is it still relevant with NixOS?
|
||||
|
||||
|
||||
# Give additional config to those programs, and not have them in my path
|
||||
bower = "bower --config.storage.packages=${config.xdg.cacheHome}/bower/packages --config.storage.registry=${config.xdg.cacheHome}/bower/registry --config.storage.links=${config.xdg.cacheHome}/bower/links";
|
||||
gdb = "gdb -x ${config.xdg.configHome}/gdbinit";
|
||||
iftop = "iftop -c ${config.xdg.configHome}/iftoprc";
|
||||
lmms = "lmms --config ${config.xdg.configHome}/lmmsrc.xml";
|
||||
|
||||
# Preference
|
||||
vi = "nvim";
|
||||
vim = "nvim";
|
||||
wol = "wakeonlan"; # TODO Really, isn't wol better? Also wtf Arch aliases to pass because neither is installed anyways x)
|
||||
mutt = "neomutt";
|
||||
|
||||
# Bash/Zsh only
|
||||
cp = "cp -i --reflink=auto";
|
||||
grep = "grep --color=auto";
|
||||
dd = "dd status=progress";
|
||||
rm = "rm -v --one-file-system";
|
||||
# free = "free -m"; # Disabled because... no? Why?
|
||||
diff = "diff --color=auto";
|
||||
dmesg = "dmesg --ctime";
|
||||
wget = "wget --hsts-file ${config.xdg.cacheHome}/wget-hsts";
|
||||
|
||||
# Imported from scripts
|
||||
rms = ''${pkgs.findutils}/bin/find . -name "*.sync-conflict-*" -delete''; # Remove syncthing conflict files
|
||||
pw = ''${pkgs.pwgen}/bin/pwgen 32 -y''; # Generate passwords. ln((26*2+10)**32)/ln(2) ≅ 190 bits of entropy
|
||||
newestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | tail'';
|
||||
oldestFile = ''${pkgs.findutils}/bin/find -type f -printf '%T+ %p\n' | sort | head'';
|
||||
tracefiles = ''${pkgs.strace}/bin/strace -f -t -e trace=file'';
|
||||
} // lib.optionalAttrs config.frogeye.desktop.xorg {
|
||||
noise = ''${pkgs.sox}/bin/play -c 2 -n synth $'' + ''{1}noise'';
|
||||
beep = ''${pkgs.sox}/bin/play -n synth sine E5 sine A4 remix 1-2 fade 0.5 1.2 0.5 2> /dev/null'';
|
||||
# FIXME ALSA lib dlmisc.c:337:(snd_dlobj_cache_get0) Cannot open shared library libasound_module_pcm_pulse.so (/nix/store/9b06fxbvm07iy9f9dvi5vk2iy9pk8hyz-alsa-lib-1.2.8/lib/alsa-lib/libasound_module_pcm_pulse.so: cannot open shared object file: No such file or directory)
|
||||
|
||||
} // lib.attrsets.mergeAttrsList (map (p: { "${p}" = "HOME=${config.xdg.cacheHome}/junkhome ${p}"; }) treatsHomeAsJunk);
|
||||
# TODO Maybe make nixpkg wrapper instead? So it also works from dmenu
|
||||
# Could also accept my fate... Home-manager doesn't necessarily make it easy to put things out of the home directory
|
||||
historySize = 100000;
|
||||
historyFile = "${config.xdg.cacheHome}/shell_history";
|
||||
in
|
||||
{
|
||||
home-manager.enable = true;
|
||||
bash = {
|
||||
enable = true;
|
||||
bashrcExtra = lib.strings.concatLines [
|
||||
commonRc
|
||||
''
|
||||
shopt -s expand_aliases
|
||||
shopt -s histappend
|
||||
''
|
||||
];
|
||||
sessionVariables = commonSessionVariables;
|
||||
historySize = historySize;
|
||||
historyFile = historyFile;
|
||||
historyFileSize = historySize;
|
||||
historyControl = [ "erasedups" "ignoredups" "ignorespace" ];
|
||||
shellAliases = commonShellAliases;
|
||||
};
|
||||
zsh = {
|
||||
enable = true;
|
||||
enableAutosuggestions = true;
|
||||
enableCompletion = true;
|
||||
enableSyntaxHighlighting = true;
|
||||
# syntaxHighlighting.enable = true; # 23.11 syntax
|
||||
historySubstringSearch.enable = true;
|
||||
initExtra = lib.strings.concatLines [
|
||||
commonRc
|
||||
(builtins.readFile ./zshrc.sh)
|
||||
];
|
||||
defaultKeymap = "viins";
|
||||
history = {
|
||||
size = historySize;
|
||||
save = historySize;
|
||||
path = historyFile;
|
||||
expireDuplicatesFirst = true;
|
||||
};
|
||||
sessionVariables = commonSessionVariables;
|
||||
shellAliases = commonShellAliases;
|
||||
};
|
||||
dircolors = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
# UPST This thing put stuff in .dircolors when it actually doesn't have to
|
||||
};
|
||||
powerline-go = {
|
||||
enable = true;
|
||||
modules = [ "user" "host" "venv" "cwd" "perms" "git" ];
|
||||
modulesRight = [ "jobs" "exit" "duration" "load" ];
|
||||
settings = {
|
||||
colorize-hostname = true;
|
||||
max-width = 25;
|
||||
cwd-max-dir-size = 10;
|
||||
duration = "$( test -n \"$__TIMER\" && echo $(( $EPOCHREALTIME - $\{__TIMER:-EPOCHREALTIME})) || echo 0 )";
|
||||
# UPST Implement this properly in home-manager, would allow for bash support
|
||||
};
|
||||
extraUpdatePS1 = ''unset __TIMER'';
|
||||
};
|
||||
# neovim = {
|
||||
# enable = true;
|
||||
# defaultEditor = true;
|
||||
# vimAlias = true;
|
||||
# viAlias = true;
|
||||
# vimdiffAlias = true;
|
||||
# };
|
||||
# FIXME Still want this despite using nixvim
|
||||
gpg = {
|
||||
enable = true;
|
||||
homedir = "${config.xdg.stateHome}/gnupg";
|
||||
settings = {
|
||||
# Remove fluff
|
||||
no-greeting = true;
|
||||
no-emit-version = true;
|
||||
no-comments = true;
|
||||
# Output format that I prefer
|
||||
keyid-format = "0xlong";
|
||||
# Show fingerprints
|
||||
with-fingerprint = true;
|
||||
# Make sure to show if key is invalid
|
||||
# (should be default on most platform,
|
||||
# but just to be sure)
|
||||
list-options = "show-uid-validity";
|
||||
verify-options = "show-uid-validity";
|
||||
# Stronger algorithm (https://wiki.archlinux.org/title/GnuPG#Different_algorithm)
|
||||
personal-digest-preferences = "SHA512";
|
||||
cert-digest-algo = "SHA512";
|
||||
default-preference-list = "SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed";
|
||||
personal-cipher-preferences = "TWOFISH CAMELLIA256 AES 3DES";
|
||||
};
|
||||
publicKeys = [{
|
||||
source = builtins.fetchurl {
|
||||
url = "https://keys.openpgp.org/vks/v1/by-fingerprint/4FBA930D314A03215E2CDB0A8312C8CAC1BAC289";
|
||||
sha256 = "sha256:10y9xqcy1vyk2p8baay14p3vwdnlwynk0fvfbika65hz2z8yw2cm";
|
||||
};
|
||||
trust = "ultimate";
|
||||
}];
|
||||
};
|
||||
fzf = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
defaultOptions = [ "--height 40%" "--layout=default" ];
|
||||
fileWidgetOptions = [ "--preview '[[ -d {} ]] && ${pkgs.coreutils}/bin/ls -l --color=always {} || [[ \$(${pkgs.file}/bin/file --mime {}) =~ binary ]] && ${pkgs.file}/bin/file --brief {} || (${pkgs.highlight}/bin/highlight -O ansi -l {} || coderay {} || rougify {} || ${pkgs.coreutils}/bin/cat {}) 2> /dev/null | head -500'" ];
|
||||
# file and friends are not in PATH by default... so here we want aboslute paths, which means those won't get reloaded. Meh.
|
||||
};
|
||||
# TODO highlight or bat
|
||||
nix-index = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
};
|
||||
less.enable = true;
|
||||
git = {
|
||||
enable = true;
|
||||
aliases = {
|
||||
"git" = "!exec git"; # In case I write one too many git
|
||||
};
|
||||
ignores = [
|
||||
"*.swp"
|
||||
"*.swo"
|
||||
"*.ycm_extra_conf.py"
|
||||
"tags"
|
||||
".mypy_cache"
|
||||
];
|
||||
lfs.enable = true;
|
||||
signing = {
|
||||
key = "0x8312C8CAC1BAC289"; # FIXME Only in extension
|
||||
# TODO signByDefault?
|
||||
};
|
||||
userEmail = "geoffrey@frogeye.fr";
|
||||
userName = "Geoffrey “Frogeye” Preud'homme";
|
||||
extraConfig = {
|
||||
core = {
|
||||
editor = "nvim";
|
||||
};
|
||||
push = {
|
||||
default = "matching";
|
||||
};
|
||||
pull = {
|
||||
ff = "only";
|
||||
};
|
||||
} // lib.optionalAttrs config.frogeye.desktop.xorg {
|
||||
diff.tool = "meld";
|
||||
difftool.prompt = false;
|
||||
"difftool \"meld\"".cmd = "${pkgs.meld}/bin/meld \"$LOCAL\" \"$REMOTE\"";
|
||||
# This escapes quotes, which isn't the case in the original, hoping this isn't an issue.
|
||||
};
|
||||
# TODO Delta syntax highlighter... and other cool-looking options?
|
||||
};
|
||||
readline = {
|
||||
enable = true;
|
||||
variables = {
|
||||
"bell-style" = "none";
|
||||
"colored-completion-prefix" = true;
|
||||
"colored-stats" = true;
|
||||
"completion-ignore-case" = true;
|
||||
"completion-query-items" = 200;
|
||||
"editing-mode" = "vi";
|
||||
"history-preserve-point" = true;
|
||||
"history-size" = 10000;
|
||||
"horizontal-scroll-mode" = false;
|
||||
"mark-directories" = true;
|
||||
"mark-modified-lines" = false;
|
||||
"mark-symlinked-directories" = true;
|
||||
"match-hidden-files" = true;
|
||||
"menu-complete-display-prefix" = true;
|
||||
"page-completions" = true;
|
||||
"print-completions-horizontally" = false;
|
||||
"revert-all-at-newline" = false;
|
||||
"show-all-if-ambiguous" = true;
|
||||
"show-all-if-unmodified" = true;
|
||||
"show-mode-in-prompt" = true;
|
||||
"skip-completed-text" = true;
|
||||
"visible-stats" = false;
|
||||
};
|
||||
extraConfig = builtins.readFile ./inputrc;
|
||||
};
|
||||
tmux =
|
||||
let
|
||||
themepack = pkgs.tmuxPlugins.mkTmuxPlugin
|
||||
rec {
|
||||
pluginName = "tmux-themepack";
|
||||
version = "1.1.0";
|
||||
rtpFilePath = "themepack.tmux";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "jimeh";
|
||||
repo = "tmux-themepack";
|
||||
rev = "${version}";
|
||||
sha256 = "f6y92kYsKDFanNx5ATx4BkaB/E7UrmyIHU/5Z01otQE=";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
mouse = false;
|
||||
clock24 = true;
|
||||
# TODO Vim mode?
|
||||
plugins = with pkgs.tmuxPlugins; [
|
||||
sensible
|
||||
];
|
||||
extraConfig = builtins.readFile ./tmux.conf + "source-file ${themepack}/share/tmux-plugins/tmux-themepack/powerline/default/green.tmuxtheme\n";
|
||||
};
|
||||
};
|
||||
services = {
|
||||
gpg-agent = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
enableSshSupport = true;
|
||||
pinentryFlavor = "gtk2"; # Falls back to curses when needed
|
||||
sshKeys = [ "72A5F2913026776593947CF00DFF330E820E731D" ]; # TODO This seems to prevent other keys from being added?
|
||||
# FIXME For g extension, as base is not supposed to have private keys
|
||||
};
|
||||
};
|
||||
xdg = {
|
||||
configFile = {
|
||||
"ccache.conf" = {
|
||||
text = "ccache_dir = ${config.xdg.cacheHome}/ccache";
|
||||
};
|
||||
"gdbinit" = {
|
||||
text = ''
|
||||
define hook-quit
|
||||
set confirm off
|
||||
end
|
||||
'';
|
||||
};
|
||||
"iftoprc" = {
|
||||
text = ''
|
||||
port-resolution: no
|
||||
promiscuous: no
|
||||
port-display: on
|
||||
link-local: yes
|
||||
use-bytes: yes
|
||||
show-totals: yes
|
||||
log-scale: yes
|
||||
'';
|
||||
};
|
||||
"pythonstartup.py" = {
|
||||
text = (builtins.readFile ./pythonstartup.py);
|
||||
};
|
||||
"screenrc" = {
|
||||
text = (builtins.readFile ./screenrc);
|
||||
};
|
||||
};
|
||||
};
|
||||
home = {
|
||||
stateVersion = "23.05";
|
||||
language = {
|
||||
base = "en_US.UTF-8";
|
||||
# time = "en_DK.UTF-8"; # FIXME Disabled because complaints during nixos-rebuild switch
|
||||
};
|
||||
packages = with pkgs; [
|
||||
# dotfiles dependencies
|
||||
coreutils
|
||||
bash
|
||||
gnugrep
|
||||
gnused
|
||||
gnutar
|
||||
openssl
|
||||
wget
|
||||
curl
|
||||
python3Packages.pip
|
||||
rename
|
||||
|
||||
# shell
|
||||
zsh-completions
|
||||
nix-zsh-completions
|
||||
zsh-history-substring-search
|
||||
powerline-go
|
||||
|
||||
# terminal essentials
|
||||
moreutils
|
||||
man
|
||||
# nodePackages.insect # FIXME Don't install on aarch64
|
||||
# TODO Use whatever replaces insect
|
||||
translate-shell
|
||||
unzip
|
||||
unrar
|
||||
p7zip
|
||||
|
||||
# remote
|
||||
openssh
|
||||
rsync
|
||||
borgbackup
|
||||
|
||||
# cleanup
|
||||
ncdu
|
||||
jdupes
|
||||
duperemove
|
||||
|
||||
# local monitoring
|
||||
htop
|
||||
iotop
|
||||
iftop
|
||||
lsof
|
||||
strace
|
||||
pv
|
||||
progress
|
||||
speedtest-cli
|
||||
|
||||
# multimedia toolbox
|
||||
sox
|
||||
imagemagick
|
||||
|
||||
# password
|
||||
pass
|
||||
pwgen
|
||||
|
||||
# Mail
|
||||
isync
|
||||
msmtp
|
||||
notmuch
|
||||
neomutt
|
||||
lynx
|
||||
|
||||
# Organisation
|
||||
vdirsyncer
|
||||
khard
|
||||
khal
|
||||
todoman
|
||||
syncthing
|
||||
|
||||
# TODO Lots of redundancy with other way things are defined here
|
||||
|
||||
];
|
||||
sessionVariables = {
|
||||
# Favourite commands
|
||||
PAGER = "${pkgs.coreutils}/bin/less";
|
||||
EDITOR = "${pkgs.neovim}/bin/nvim";
|
||||
|
||||
# Extra config
|
||||
BOOT9_PATH = "${config.xdg.dataHome}/citra-emu/sysdata/boot9.bin";
|
||||
CCACHE_CONFIGPATH = "${config.xdg.configHome}/ccache.conf";
|
||||
# INPUTRC = "${config.xdg.configHome}/inputrc"; # UPST Will use programs.readline, but doesn't allow path setting
|
||||
LESSHISTFILE = "${config.xdg.stateHome}/lesshst";
|
||||
NODE_REPL_HISTORY = "${config.xdg.cacheHome}/node_repl_history";
|
||||
PYTHONSTARTUP = "${config.xdg.configHome}/pythonstartup.py";
|
||||
# TODO I think we're not using the urxvt daemon on purpose?
|
||||
# TODO this should be desktop only, as a few things are too.
|
||||
SCREENRC = "${config.xdg.configHome}/screenrc";
|
||||
SQLITE_HISTFILE = "${config.xdg.stateHome}/sqlite_history";
|
||||
YARN_DISABLE_SELF_UPDATE_CHECK = "true"; # This also disable the creation of a ~/.yarnrc file
|
||||
} // lib.optionalAttrs config.frogeye.desktop.xorg {
|
||||
# Favourite commands
|
||||
VISUAL = "${pkgs.neovim}/bin/nvim";
|
||||
BROWSER = "${config.programs.qutebrowser.package}/bin/qutebrowser";
|
||||
|
||||
# Extra config
|
||||
RXVT_SOCKET = "${config.xdg.stateHome}/urxvtd"; # Used to want -$HOME suffix, hopefullt this isn't needed
|
||||
# XAUTHORITY = "${config.xdg.configHome}/Xauthority"; # Disabled as this causes lock-ups with DMs
|
||||
} // direnv;
|
||||
# TODO Session variables only get reloaded on login I think.
|
||||
sessionPath = [
|
||||
"${config.home.homeDirectory}/.local/bin"
|
||||
"${config.home.sessionVariables.GOPATH}"
|
||||
"${config.frogeye.dotfiles.path}/scripts"
|
||||
];
|
||||
file = {
|
||||
".face" = {
|
||||
source = pkgs.runCommand "face.png" { } "${pkgs.inkscape}/bin/inkscape ${./face.svg} -w 1024 -o $out";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue