2023-11-03 01:37:37 +01:00
{ pkgs , config , lib , . . . }:
2023-10-28 22:09:36 +02:00
{
2023-11-22 14:05:48 +01:00
config = lib . mkIf config . frogeye . desktop . xorg {
2023-12-02 18:05:33 +01:00
frogeye . shellAliases = {
noise = '' ${ pkgs . sox } / b i n / p l a y - c 2 - n s y n t h $' ' + '' { 1 } noise'' ;
beep = '' ${ pkgs . sox } / b i n / p l a y - n s y n t h s i n e E 5 s i n e A 4 r e m i x 1 - 2 f a d e 0 . 5 1 . 2 0 . 5 2 > / d e v / n u l l '' ;
# 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)
# n = "$HOME/.config/i3/terminal & disown"; # Not used anymore since alacritty daemon mode doesn't preserve environment variables
x = " s t a r t x ${ config . xdg . configHome } / x i n i t r c ; l o g o u t " ;
nx = " n v i d i a - x r u n ${ config . xdg . configHome } / x i n i t r c ; s u d o s y s t e m c t l s t a r t n v i d i a - x r u n - p m ; l o g o u t " ;
# 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?
} ;
2023-11-22 14:05:48 +01:00
xsession = {
enable = true ;
windowManager = {
i3 = {
enable = true ;
config =
let
# lockColors = with config.lib.stylix.colors.withHashtag; { a = base00; b = base01; d = base00; }; # Black or White, depending on current theme
# lockColors = with config.lib.stylix.colors.withHashtag; { a = base0A; b = base0B; d = base00; }; # Green + Yellow
lockColors = { a = " # 8 2 a 4 0 1 " ; b = " # 4 6 6 c 0 1 " ; d = " # 6 4 8 9 0 1 " ; } ; # Old
lockSvg = pkgs . writeText " l o c k . s v g " " < s v g x m l n s = \" h t t p : / / w w w . w 3 . o r g / 2 0 0 0 / s v g \" v i e w B o x = \" 0 0 5 0 5 0 \" h e i g h t = \" 5 0 \" w i d t h = \" 5 0 \" > < p a t h f i l l = \" ${ lockColors . a } \" d = \" M 0 5 0 h 5 0 V 0 H 0 z \" / > < p a t h d = \" M 0 0 l 5 0 5 0 H 2 5 L 0 2 5 z m 5 0 0 v 2 5 L 2 5 0 z \" f i l l = \" ${ lockColors . d } \" / > < / s v g > " ;
lockPng = pkgs . runCommand " l o c k . p n g " { } " ${ pkgs . imagemagick } / b i n / c o n v e r t ${ lockSvg } $ o u t " ;
locker = pkgs . writeShellScript " i 3 - l o c k e r "
''
# Remove SSH and GPG keys from keystores
$ { pkgs . openssh } /bin/ssh-add - D
echo RELOADAGENT | $ { pkgs . gnupg } /bin/gpg-connect-agent
$ { pkgs . coreutils } /bin/rm - rf " / t m p / c a c h e d _ p a s s _ $ U I D "
2023-11-03 18:18:38 +01:00
2023-11-22 14:05:48 +01:00
$ { pkgs . lightdm } /bin/dm-tool lock
# TODO Does that work for all DMs?
if [ $ ? - ne 0 ] ; then
if [ - d $ { config . xdg . cacheHome } /lockpatterns ]
then
pattern = $ ( $ { pkgs . findutils } $ { config . xdg . cacheHome } /lockpatterns | sort - R | head -1 )
else
pattern = $ { lockPng }
fi
revert ( ) {
$ { pkgs . xorg . xset } /bin/xset dpms 0 0 0
}
trap revert SIGHUP SIGINT SIGTERM
$ { pkgs . xorg . xset } /bin/xset dpms 5 5 5
$ { pkgs . i3lock } /bin/i3lock - - nofork - - color $ { builtins . substring 1 6 lockColors . d } - - image = $ pattern - - tiling - - ignore-empty-password
revert
fi
'' ;
focus = " e x e c ${ pkgs . writeShellScript " i 3 - f o c u s - w i n d o w "
2023-11-03 18:18:38 +01:00
''
WINDOW = ` $ { pkgs . xdotool } /bin/xdotool getwindowfocus `
eval ` $ { pkgs . xdotool } /bin/xdotool getwindowgeometry - - shell $ WINDOW ` # this brings in variables WIDTH and HEIGHT
TX = ` $ { pkgs . coreutils } /bin/expr $ WIDTH / 2 `
TY = ` $ { pkgs . coreutils } /bin/expr $ HEIGHT / 2 `
$ { pkgs . xdotool } /bin/xdotool mousemove - window $ WINDOW $ TX $ TY
''
} " ;
2023-11-22 14:05:48 +01:00
mode_system = " [ L ] V é r o u i l l a g e [ E ] D é c o n n e x i o n [ S ] V e i l l e [ H ] H i b e r n a t i o n [ R ] R e d é m a r r a g e [ P ] E x t i n c t i o n " ;
mode_resize = " R e s i z e " ;
mode_pres_main = " P r e s e n t a t i o n ( m a i n d i s p l a y ) " ;
mode_pres_sec = " P r e s e n t a t i o n ( s e c o n d a r y d i s p l a y ) " ;
mode_screen = " S c r e e n s e t u p [ A ] A u t o [ L ] L o a d [ S ] S a v e [ R ] R e m o v e [ D ] D e f a u l t " ;
mode_temp = " T e m p e r a t u r e [ R ] R e d [ D ] D u s t s t o r m [ C ] C a m p f i r e [ O ] N o r m a l [ A ] A l l n i g h t e r [ B ] B l u e " ;
in
{
modifier = " M o d 1 " ; # FIXME Mod1 for VM, Mod4 for not VM
terminal = " a l a c r i t t y " ;
2023-12-01 22:19:52 +01:00
bars = [ ] ; # Using frobar
2023-11-22 14:05:48 +01:00
colors = let ignore = " # f f 0 0 f f " ; in
with config . lib . stylix . colors . withHashtag ; lib . mkForce {
focused = { border = base0B ; background = base0B ; text = base00 ; indicator = base00 ; childBorder = base0B ; } ;
focusedInactive = { border = base02 ; background = base02 ; text = base05 ; indicator = base02 ; childBorder = base02 ; } ;
unfocused = { border = base05 ; background = base04 ; text = base00 ; indicator = base04 ; childBorder = base00 ; } ;
urgent = { border = base0F ; background = base08 ; text = base00 ; indicator = base08 ; childBorder = base0F ; } ;
placeholder = { border = ignore ; background = base00 ; text = base05 ; indicator = ignore ; childBorder = base00 ; } ;
background = base07 ;
# I set the color of the active tab as the the background color of the terminal so they merge together.
} ;
focus . followMouse = false ;
keybindings =
let
mod = config . xsession . windowManager . i3 . config . modifier ;
rofi = " e x e c - - n o - s t a r t u p - i d ${ config . programs . rofi . package } / b i n / r o f i " ;
pactl = " e x e c ${ pkgs . pulseaudio } / b i n / p a c t l " ; # TODO Use NixOS package if using NixOS
scrot = " ${ pkgs . scrot } / b i n / s c r o t - - e x e c ' ${ pkgs . coreutils } / b i n / m v $ f ~ / S c r e e n s h o t s / & & ${ pkgs . optipng } / b i n / o p t i p n g ~ / S c r e e n s h o t s / $ f ' " ;
# TODO nix path and create directory?
in
{
# Compatibility layer for people coming from other backgrounds
# "Mod1+Tab" = "${rofi} -modi window -show window"; # FIXME When no longer using a VM
" M o d 1 + F 2 " = " ${ rofi } - m o d i d r u n - s h o w d r u n " ;
# "Mod1+F4" = "kill"; # FIXME When no longer using a VM
# kill focused window
" ${ mod } + z " = " k i l l " ;
button2 = " k i l l " ;
# Rofi
" ${ mod } + c " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . rofi-pass } / b i n / r o f i - p a s s - - l a s t - u s e d " ;
# TODO Try autopass.cr
# 23.11 config.programs.rofi.pass.package
" ${ mod } + i " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . rofimoji } / b i n / r o f i m o j i " ;
" ${ mod } + p l u s " = " ${ rofi } - m o d i s s h - s h o w s s h " ;
" ${ mod } + ù " = " ${ rofi } - m o d i s s h - s h o w s s h - s s h - c o m m a n d ' { t e r m i n a l } - e { s s h - c l i e n t } { h o s t } - t \" s u d o - s - E \" ' " ;
# TODO In which keyboard layout?
" ${ mod } + T a b " = " ${ rofi } - m o d i w i n d o w - s h o w w i n d o w " ;
# start program launcher
" ${ mod } + d " = " ${ rofi } - m o d i r u n - s h o w r u n " ;
" ${ mod } + S h i f t + d " = " ${ rofi } - m o d i d r u n - s h o w d r u n " ;
# Start Applications
" ${ mod } + R e t u r n " = " e x e c ${
2023-11-03 01:37:37 +01:00
pkgs . writeShellScript " t e r m i n a l " " ${ config . programs . alacritty . package } / b i n / a l a c r i t t y m s g c r e a t e - w i n d o w | | e x e c ${ config . programs . alacritty . package } / b i n / a l a c r i t t y - e z s h "
2023-11-03 18:18:38 +01:00
# -e zsh is for systems where I can't configure my user's shell
# TODO Is a shell script even required?
2023-11-03 01:37:37 +01:00
} " ;
2023-11-22 14:05:48 +01:00
" ${ mod } + S h i f t + R e t u r n " = " e x e c ${ config . programs . urxvt . package } / b i n / u r x v t " ;
" ${ mod } + p " = " e x e c ${ pkgs . xfce . thunar } / b i n / t h u n a r " ;
" ${ mod } + m " = " e x e c ${ config . programs . qutebrowser . package } / b i n / q u t e b r o w s e r - - o v e r r i d e - r e s t o r e - - b a c k e n d = w e b e n g i n e " ;
# TODO --backend not useful anymore
# Volume control
" X F 8 6 A u d i o R a i s e V o l u m e " = " ${ pactl } s e t - s i n k - m u t e @ D E F A U L T _ S I N K @ f a l s e ; ${ pactl } s e t - s i n k - v o l u m e @ D E F A U L T _ S I N K @ + 5 % " ;
" X F 8 6 A u d i o L o w e r V o l u m e " = " ${ pactl } s e t - s i n k - m u t e @ D E F A U L T _ S I N K @ f a l s e ; ${ pactl } s e t - s i n k - v o l u m e @ D E F A U L T _ S I N K @ - 5 % " ;
" X F 8 6 A u d i o M u t e " = " ${ pactl } s e t - s i n k - m u t e @ D E F A U L T _ S I N K @ t r u e " ;
" ${ mod } + F 7 " = " ${ pactl } s u s p e n d - s i n k @ D E F A U L T _ S I N K @ 1 ; ${ pactl } s u s p e n d - s i n k @ D E F A U L T _ S I N K @ 0 " ; # Re-synchronize bluetooth headset
" ${ mod } + F 1 1 " = " e x e c ${ pkgs . pavucontrol } / b i n / p a v u c o n t r o l " ;
" ${ mod } + F 1 2 " = " e x e c ${ pkgs . pavucontrol } / b i n / p a v u c o n t r o l " ;
# TODO Find pacmixer?
# Media control
" X F 8 6 A u d i o P r e v " = " e x e c ${ pkgs . mpc-cli } / b i n / m p c p r e v " ;
" X F 8 6 A u d i o P l a y " = " e x e c ${ pkgs . mpc-cli } / b i n / m p c t o g g l e " ;
" X F 8 6 A u d i o N e x t " = " e x e c ${ pkgs . mpc-cli } / b i n / m p c n e x t " ;
# Misc
" ${ mod } + F 1 0 " = " e x e c ${ pkgs . writeShellScript " s h o w - k e y b o a r d - l a y o u t "
2023-11-03 18:18:38 +01:00
''
layout = ` $ { pkgs . xorg . setxkbmap } /bin/setxkbmap - query | $ { pkgs . gnugrep } /bin/grep ^ layout : | $ { pkgs . gawk } /bin/awk ' { print $ 2 } ' `
$ { pkgs . libgnomekbd } /bin/gkbd-keyboard-display - l $ layout
''
} " ;
2023-11-22 14:05:48 +01:00
# Screenshots
" P r i n t " = " e x e c ${ scrot } - - f o c u s e d " ;
" ${ mod } + P r i n t " = " e x e c ${ scrot } " ; # FIXME Doesn't work at least in the VM
" C t r l + P r i n t " = " e x e c ${ pkgs . coreutils } / b i n / s l e e p 1 & & ${ scrot } - - s e l e c t " ;
# TODO Try using bindsym --release instead of sleep
# change focus
" ${ mod } + h " = " f o c u s l e f t ; ${ focus } " ;
" ${ mod } + j " = " f o c u s d o w n ; ${ focus } " ;
" ${ mod } + k " = " f o c u s u p ; ${ focus } " ;
" ${ mod } + l " = " f o c u s r i g h t ; ${ focus } " ;
# move focused window
" ${ mod } + S h i f t + h " = " m o v e l e f t ; ${ focus } " ;
" ${ mod } + S h i f t + j " = " m o v e d o w n ; ${ focus } " ;
" ${ mod } + S h i f t + k " = " m o v e u p ; ${ focus } " ;
" ${ mod } + S h i f t + l " = " m o v e r i g h t ; ${ focus } " ;
# workspace back and forth (with/without active container)
" ${ mod } + b " = " w o r k s p a c e b a c k _ a n d _ f o r t h ; ${ focus } " ;
" ${ mod } + S h i f t + b " = " m o v e c o n t a i n e r t o w o r k s p a c e b a c k _ a n d _ f o r t h ; w o r k s p a c e b a c k _ a n d _ f o r t h ; ${ focus } " ;
# Change container layout
" ${ mod } + g " = " s p l i t h ; ${ focus } " ;
" ${ mod } + v " = " s p l i t v ; ${ focus } " ;
" ${ mod } + f " = " f u l l s c r e e n t o g g l e ; ${ focus } " ;
" ${ mod } + s " = " l a y o u t s t a c k i n g ; ${ focus } " ;
" ${ mod } + w " = " l a y o u t t a b b e d ; ${ focus } " ;
" ${ mod } + e " = " l a y o u t t o g g l e s p l i t ; ${ focus } " ;
" ${ mod } + S h i f t + s p a c e " = " f l o a t i n g t o g g l e ; ${ focus } " ;
# Focus container
" ${ mod } + s p a c e " = " f o c u s m o d e _ t o g g l e ; ${ focus } " ;
" ${ mod } + a " = " f o c u s p a r e n t ; ${ focus } " ;
" ${ mod } + q " = " f o c u s c h i l d ; ${ focus } " ;
# Switch to workspace
" ${ mod } + 1 " = " w o r k s p a c e 1 ; ${ focus } " ;
" ${ mod } + 2 " = " w o r k s p a c e 2 ; ${ focus } " ;
" ${ mod } + 3 " = " w o r k s p a c e 3 ; ${ focus } " ;
" ${ mod } + 4 " = " w o r k s p a c e 4 ; ${ focus } " ;
" ${ mod } + 5 " = " w o r k s p a c e 5 ; ${ focus } " ;
" ${ mod } + 6 " = " w o r k s p a c e 6 ; ${ focus } " ;
" ${ mod } + 7 " = " w o r k s p a c e 7 ; ${ focus } " ;
" ${ mod } + 8 " = " w o r k s p a c e 8 ; ${ focus } " ;
" ${ mod } + 9 " = " w o r k s p a c e 9 ; ${ focus } " ;
" ${ mod } + 0 " = " w o r k s p a c e 1 0 ; ${ focus } " ;
# TODO Prevent repetitions, see workspace assignation for example
#navigate workspaces next / previous
" ${ mod } + C t r l + h " = " w o r k s p a c e p r e v _ o n _ o u t p u t ; ${ focus } " ;
" ${ mod } + C t r l + l " = " w o r k s p a c e n e x t _ o n _ o u t p u t ; ${ focus } " ;
" ${ mod } + C t r l + j " = " w o r k s p a c e p r e v ; ${ focus } " ;
" ${ mod } + C t r l + k " = " w o r k s p a c e n e x t ; ${ focus } " ;
# Move to workspace next / previous with focused container
" ${ mod } + C t r l + S h i f t + h " = " m o v e c o n t a i n e r t o w o r k s p a c e p r e v _ o n _ o u t p u t ; w o r k s p a c e p r e v _ o n _ o u t p u t ; ${ focus } " ;
" ${ mod } + C t r l + S h i f t + l " = " m o v e c o n t a i n e r t o w o r k s p a c e n e x t _ o n _ o u t p u t ; w o r k s p a c e n e x t _ o n _ o u t p u t ; ${ focus } " ;
" ${ mod } + C t r l + S h i f t + j " = " m o v e c o n t a i n e r t o w o r k s p a c e p r e v ; w o r k s p a c e p r e v ; ${ focus } " ;
" ${ mod } + C t r l + S h i f t + k " = " m o v e c o n t a i n e r t o w o r k s p a c e n e x t ; w o r k s p a c e n e x t ; ${ focus } " ;
# move focused container to workspace
" ${ mod } + c t r l + 1 " = " m o v e c o n t a i n e r t o w o r k s p a c e 1 ; ${ focus } " ;
" ${ mod } + c t r l + 2 " = " m o v e c o n t a i n e r t o w o r k s p a c e 2 ; ${ focus } " ;
" ${ mod } + c t r l + 3 " = " m o v e c o n t a i n e r t o w o r k s p a c e 3 ; ${ focus } " ;
" ${ mod } + c t r l + 4 " = " m o v e c o n t a i n e r t o w o r k s p a c e 4 ; ${ focus } " ;
" ${ mod } + c t r l + 5 " = " m o v e c o n t a i n e r t o w o r k s p a c e 5 ; ${ focus } " ;
" ${ mod } + c t r l + 6 " = " m o v e c o n t a i n e r t o w o r k s p a c e 6 ; ${ focus } " ;
" ${ mod } + c t r l + 7 " = " m o v e c o n t a i n e r t o w o r k s p a c e 7 ; ${ focus } " ;
" ${ mod } + c t r l + 8 " = " m o v e c o n t a i n e r t o w o r k s p a c e 8 ; ${ focus } " ;
" ${ mod } + c t r l + 9 " = " m o v e c o n t a i n e r t o w o r k s p a c e 9 ; ${ focus } " ;
" ${ mod } + c t r l + 0 " = " m o v e c o n t a i n e r t o w o r k s p a c e 1 0 ; ${ focus } " ;
# move to workspace with focused container
" ${ mod } + s h i f t + 1 " = " m o v e c o n t a i n e r t o w o r k s p a c e 1 ; w o r k s p a c e 1 ; ${ focus } " ;
" ${ mod } + s h i f t + 2 " = " m o v e c o n t a i n e r t o w o r k s p a c e 2 ; w o r k s p a c e 2 ; ${ focus } " ;
" ${ mod } + s h i f t + 3 " = " m o v e c o n t a i n e r t o w o r k s p a c e 3 ; w o r k s p a c e 3 ; ${ focus } " ;
" ${ mod } + s h i f t + 4 " = " m o v e c o n t a i n e r t o w o r k s p a c e 4 ; w o r k s p a c e 4 ; ${ focus } " ;
" ${ mod } + s h i f t + 5 " = " m o v e c o n t a i n e r t o w o r k s p a c e 5 ; w o r k s p a c e 5 ; ${ focus } " ;
" ${ mod } + s h i f t + 6 " = " m o v e c o n t a i n e r t o w o r k s p a c e 6 ; w o r k s p a c e 6 ; ${ focus } " ;
" ${ mod } + s h i f t + 7 " = " m o v e c o n t a i n e r t o w o r k s p a c e 7 ; w o r k s p a c e 7 ; ${ focus } " ;
" ${ mod } + s h i f t + 8 " = " m o v e c o n t a i n e r t o w o r k s p a c e 8 ; w o r k s p a c e 8 ; ${ focus } " ;
" ${ mod } + s h i f t + 9 " = " m o v e c o n t a i n e r t o w o r k s p a c e 9 ; w o r k s p a c e 9 ; ${ focus } " ;
" ${ mod } + s h i f t + 0 " = " m o v e c o n t a i n e r t o w o r k s p a c e 1 0 ; w o r k s p a c e 1 0 ; ${ focus } " ;
# move workspaces to screen (arrow keys)
" ${ mod } + c t r l + s h i f t + R i g h t " = " m o v e w o r k s p a c e t o o u t p u t r i g h t ; ${ focus } " ;
" ${ mod } + c t r l + s h i f t + L e f t " = " m o v e w o r k s p a c e t o o u t p u t l e f t ; ${ focus } " ;
" ${ mod } + C t r l + S h i f t + U p " = " m o v e w o r k s p a c e t o o u t p u t a b o v e ; ${ focus } " ;
" ${ mod } + C t r l + S h i f t + D o w n " = " m o v e w o r k s p a c e t o o u t p u t b e l o w ; ${ focus } " ;
# i3 control
" ${ mod } + S h i f t + c " = " r e l o a d " ;
" ${ mod } + S h i f t + r " = " r e s t a r t " ;
" ${ mod } + S h i f t + e " = " e x i t " ;
# Screen off commands
" ${ mod } + F 1 " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . bash } / b i n / s h - c \" ${ pkgs . coreutils } / b i n / s l e e p . 2 5 & & ${ pkgs . xorg . xset } / b i n / x s e t d p m s f o r c e o f f \" " ;
# TODO --release?
" ${ mod } + F 4 " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . xautolock } / b i n / x a u t o l o c k - d i s a b l e " ;
" ${ mod } + F 5 " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . xautolock } / b i n / x a u t o l o c k - e n a b l e " ;
# Modes
" ${ mod } + E s c a p e " = " m o d e ${ mode_system } " ;
" ${ mod } + r " = " m o d e ${ mode_resize } " ;
" ${ mod } + S h i f t + p " = " m o d e ${ mode_pres_main } " ;
" ${ mod } + t " = " m o d e ${ mode_screen } " ;
" ${ mod } + y " = " m o d e ${ mode_temp } " ;
2023-11-05 21:32:31 +01:00
} ;
2023-11-22 14:05:48 +01:00
modes = let return_bindings = {
" R e t u r n " = " m o d e d e f a u l t " ;
" E s c a p e " = " m o d e d e f a u l t " ;
} ; in
{
" ${ mode_system } " = {
" l " = " e x e c - - n o - s t a r t u p - i d e x e c ${ locker } , m o d e d e f a u l t " ;
" e " = " e x i t , m o d e d e f a u l t " ;
2023-11-23 22:54:11 +01:00
" s " = " e x e c - - n o - s t a r t u p - i d e x e c ${ locker } & ${ pkgs . systemd } / b i n / s y s t e m c t l s u s p e n d - - c h e c k - i n h i b i t o r s = n o , m o d e d e f a u l t " ;
2023-11-22 14:05:48 +01:00
" h " = " e x e c - - n o - s t a r t u p - i d e x e c ${ locker } & ${ pkgs . systemd } / b i n / s y s t e m c t l h i b e r n a t e , m o d e d e f a u l t " ;
" r " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . systemd } / b i n / s y s t e m c t l r e b o o t , m o d e d e f a u l t " ;
" p " = " e x e c - - n o - s t a r t u p - i d ${ pkgs . systemd } / b i n / s y s t e m c t l p o w e r o f f - i , m o d e d e f a u l t " ;
} // return_bindings ;
" ${ mode_resize } " = {
" h " = " r e s i z e s h r i n k w i d t h 1 0 p x o r 1 0 p p t ; ${ focus } " ;
" j " = " r e s i z e g r o w h e i g h t 1 0 p x o r 1 0 p p t ; ${ focus } " ;
" k " = " r e s i z e s h r i n k h e i g h t 1 0 p x o r 1 0 p p t ; ${ focus } " ;
" l " = " r e s i z e g r o w w i d t h 1 0 p x o r 1 0 p p t ; ${ focus } " ;
2023-11-05 21:32:31 +01:00
} // return_bindings ;
2023-11-22 14:05:48 +01:00
" ${ mode_pres_main } " = {
" b " = " w o r k s p a c e 3 , w o r k s p a c e 4 , m o d e ${ mode_pres_sec } " ;
" q " = " m o d e d e f a u l t " ;
" R e t u r n " = " m o d e d e f a u l t " ;
} ;
" ${ mode_pres_sec } " = {
" b " = " w o r k s p a c e 1 , w o r k s p a c e 2 , m o d e ${ mode_pres_main } " ;
" q " = " m o d e d e f a u l t " ;
" R e t u r n " = " m o d e d e f a u l t " ;
} ;
" ${ mode_screen } " =
let
builtin_configs = [ " o f f " " c o m m o n " " c l o n e - l a r g e s t " " h o r i z o n t a l " " v e r t i c a l " " h o r i z o n t a l - r e v e r s e " " v e r t i c a l - r e v e r s e " ] ;
autorandrmenu = { title , option , builtin ? false }: pkgs . writeShellScript " a u t o r a n d r m e n u "
''
shopt - s nullglob globstar
profiles = " ${ if builtin then lib . strings . concatLines builtin_configs else " " } $ ( ${ pkgs . autorandr } / b i n / a u t o r a n d r | ${ pkgs . gawk } / b i n / a w k ' { p r i n t $ 1 } ' ) "
profile = " $ ( e c h o " $ profiles " | ${ config . programs . rofi . package } / b i n / r o f i - d m e n u - p " $ { title } " ) "
[ [ - n " $ p r o f i l e " ] ] || exit
$ { pkgs . autorandr } /bin/autorandr $ { option } " $ p r o f i l e "
'' ;
in
{
" a " = " e x e c ${ pkgs . autorandr } / b i n / a u t o r a n d r - - c h a n g e - - f o r c e , m o d e d e f a u l t " ;
" l " = " e x e c ${ autorandrmenu { title = " L o a d p r o f i l e " ; option = " - - l o a d " ; builtin = true ; } } , m o d e d e f a u l t " ;
" s " = " e x e c ${ autorandrmenu { title = " S a v e p r o f i l e " ; option = " - - s a v e " ; } } , m o d e d e f a u l t " ;
" r " = " e x e c ${ autorandrmenu { title = " R e m o v e p r o f i l e " ; option = " - - r e m o v e " ; } } , m o d e d e f a u l t " ;
" d " = " e x e c ${ autorandrmenu { title = " D e f a u l t p r o f i l e " ; option = " - - d e f a u l t " ; builtin = true ; } } , m o d e d e f a u l t " ;
} // return_bindings ;
" ${ mode_temp } " = {
# "r" = "exec ${pkgs.sct}/bin/sct 1000";
# "d" = "exec ${pkgs.sct}/bin/sct 2000";
# "c" = "exec ${pkgs.sct}/bin/sct 4500";
# "o" = "exec ${pkgs.sct}/bin/sct";
# "a" = "exec ${pkgs.sct}/bin/sct 8000";
# "b" = "exec ${pkgs.sct}/bin/sct 10000";
# FIXME Not on aarch64
} // return_bindings ;
} ;
window = {
hideEdgeBorders = " b o t h " ;
titlebar = false ; # So that single-container screens are basically almost fullscreen
commands = [
# Open specific applications in floating mode
{ criteria = { class = " F i r e f o x " ; } ; command = " l a y o u t t a b b e d " ; } # Doesn't seem to work anymore
{ criteria = { class = " q u t e b r o w s e r " ; } ; command = " l a y o u t t a b b e d " ; }
{ criteria = { title = " ^ p d f p c . * " ; window_role = " p r e s e n t e r " ; } ; command = " m o v e t o o u t p u t l e f t , f u l l s c r e e n " ; }
{ criteria = { title = " ^ p d f p c . * " ; window_role = " p r e s e n t a t i o n " ; } ; command = " m o v e t o o u t p u t r i g h t , f u l l s c r e e n " ; }
# switch to workspace with urgent window automatically
{ criteria = { urgent = " l a t e s t " ; } ; command = " f o c u s " ; }
] ;
2023-11-05 21:32:31 +01:00
} ;
2023-11-22 14:05:48 +01:00
floating = {
criteria = [
{ title = " p a c m i x e r " ; }
{ window_role = " p o p - u p " ; }
{ window_role = " t a s k _ d i a l o g " ; }
] ;
} ;
startup = [
# Lock screen after 10 minutes
{ notification = false ; command = " ${ pkgs . xautolock } / b i n / x a u t o l o c k - t i m e 1 0 - l o c k e r ' ${ pkgs . xorg . xset } / b i n / x s e t d p m s f o r c e s t a n d b y ' - k i l l t i m e 1 - k i l l e r ${ locker } " ; }
{
notification = false ;
command = " ${ pkgs . writeShellApplication {
2023-11-05 14:32:01 +01:00
name = " b a t t e r y N o t i f y " ;
runtimeInputs = with pkgs ; [ coreutils libnotify ] ;
text = builtins . readFile ./batteryNotify.sh ;
# TODO Use batsignal instead?
# TODO Only on computers with battery
} } /bin/batteryNotify " ;
2023-11-22 14:05:48 +01:00
}
# TODO There's a services.screen-locker.xautolock but not sure it can match the above command
] ;
workspaceLayout = " t a b b e d " ;
focus . mouseWarping = true ; # i3 only supports warping to workspace, hence ${focus}
workspaceOutputAssign =
let
x11_screens = [ " H D M I - 1 - 0 " " e D P 1 " ] ; # FIXME Per computer thing
workspaces = map ( i : { name = toString i ; key = toString ( lib . mod i 10 ) ; } ) ( lib . lists . range 1 10 ) ;
forEachWorkspace = f : map ( w : f { w = w ; workspace = ( ( builtins . elemAt workspaces w ) ) ; } ) ( lib . lists . range 0 ( ( builtins . length workspaces ) - 1 ) ) ;
in
forEachWorkspace ( { w , workspace }: { output = builtins . elemAt x11_screens ( lib . mod w ( builtins . length x11_screens ) ) ; workspace = workspace . name ; } ) ;
} ;
} ;
2023-11-03 18:18:38 +01:00
} ;
2023-11-22 14:05:48 +01:00
numlock . enable = true ; # FIXME Only on computers with a separate one
2023-11-05 21:32:31 +01:00
} ;
2023-10-29 00:49:22 +02:00
2023-11-22 14:05:48 +01:00
programs = {
# Browser
qutebrowser = {
enable = true ;
keyBindings = {
normal = {
# Match tab behaviour to i3. Not that I use them.
" H " = " t a b - p r e v " ;
" J " = " b a c k " ;
" K " = " f o r w a r d " ;
" L " = " t a b - n e x t " ;
# "T" = null;
" a f " = " s p a w n - - u s e r s c r i p t f r e s h r s s " ; # TODO Broken?
" a s " = " s p a w n - - u s e r s c r i p t s h a a r l i " ; # TODO I don't use shaarli anymore
# "d" = null;
" u " = " u n d o - - w i n d o w " ;
# TODO Unbind d and T (?)
} ;
2023-11-19 23:09:10 +01:00
} ;
2023-12-01 22:19:52 +01:00
loadAutoconfig = true ;
2023-11-22 14:05:48 +01:00
searchEngines = rec {
DEFAULT = ecosia ;
2023-12-01 22:19:52 +01:00
alpinep = " h t t p s : / / p k g s . a l p i n e l i n u x . o r g / p a c k a g e s ? n a m e = { } & b r a n c h = e d g e " ;
2023-11-22 14:05:48 +01:00
ampwhat = " h t t p : / / w w w . a m p - w h a t . c o m / u n i c o d e / s e a r c h / { } " ;
2023-12-01 22:19:52 +01:00
arch = " h t t p s : / / w i k i . a r c h l i n u x . o r g / ? s e a r c h = { } " ;
archp = " h t t p s : / / w w w . a r c h l i n u x . o r g / p a c k a g e s / ? q = { } " ;
aur = " h t t p s : / / a u r . a r c h l i n u x . o r g / p a c k a g e s / ? K = { } " ;
2023-11-22 14:05:48 +01:00
aw = ampwhat ;
ddg = duckduckgo ;
2023-12-01 22:19:52 +01:00
dockerhub = " h t t p s : / / h u b . d o c k e r . c o m / s e a r c h / ? i s A u t o m a t e d = 0 & i s O f f i c i a l = 0 & p a g e = 1 & p u l l C o u n t = 0 & q = { } & s t a r C o u n t = 0 " ;
2023-11-22 14:05:48 +01:00
duckduckgo = " h t t p s : / / d u c k d u c k g o . c o m / ? q = { } & i a = w e b " ;
ecosia = " h t t p s : / / w w w . e c o s i a . o r g / s e a r c h ? q = { } " ;
2023-12-01 22:19:52 +01:00
gfr = " h t t p s : / / w w w . g o o g l e . f r / s e a r c h ? h l = f r & q = { } " ;
g = google ;
gh = github ;
gi = " h t t p : / / i m a g e s . g o o g l e . c o m / s e a r c h ? q = { } " ;
giphy = " h t t p s : / / g i p h y . c o m / s e a r c h / { } " ;
2023-11-22 14:05:48 +01:00
github = " h t t p s : / / g i t h u b . c o m / s e a r c h ? q = { } " ;
google = " h t t p s : / / w w w . g o o g l e . f r / s e a r c h ? q = { } " ;
2023-12-01 22:19:52 +01:00
invidious = " h t t p s : / / i n v i d i o u s . f r o g e y e . f r / s e a r c h ? q = { } " ;
inv = invidious ;
2023-11-22 14:05:48 +01:00
npm = " h t t p s : / / w w w . n p m j s . c o m / s e a r c h ? q = { } " ;
q = qwant ;
qwant = " h t t p s : / / w w w . q w a n t . c o m / ? t = w e b & q = { } " ;
wolfram = " h t t p s : / / w w w . w o l f r a m a l p h a . c o m / i n p u t / ? i = { } " ;
youtube = " h t t p s : / / w w w . y o u t u b e . c o m / r e s u l t s ? s e a r c h _ q u e r y = { } " ;
yt = youtube ;
2023-11-19 23:09:10 +01:00
} ;
2023-11-22 14:05:48 +01:00
settings = {
downloads . location . prompt = false ;
tabs = {
show = " n e v e r " ;
tabs_are_windows = true ;
} ;
2023-12-01 22:19:52 +01:00
url = rec {
2023-11-22 14:05:48 +01:00
open_base_url = true ;
2023-12-01 22:19:52 +01:00
start_pages = lib . mkDefault " h t t p s : / / g e o f f r e y . f r o g e y e . f r / b l a n k . h t m l " ;
default_page = start_pages ;
2023-11-22 14:05:48 +01:00
} ;
content = {
# I had this setting below, not sure if it did something special
# config.set("content.cookies.accept", "no-3rdparty", "chrome://*/*")
cookies . accept = " n o - 3 r d p a r t y " ;
prefers_reduced_motion = true ;
2023-12-01 22:19:52 +01:00
headers . accept_language = " f r - F R , f r ; q = 0 . 9 , e n - G B ; q = 0 . 8 , e n - U S ; q = 0 . 7 , e n ; q = 0 . 6 " ;
tls . certificate_errors = " a s k - b l o c k - t h i r d p a r t y " ;
2023-11-22 14:05:48 +01:00
} ;
2023-12-01 22:19:52 +01:00
editor . command = [ " ${ pkgs . neovide } / b i n / n e o v i d e " " - - " " - f " " { f i l e } " " - c " " n o r m a l { l i n e } G { c o l u m n 0 } l " ] ;
# TODO Doesn't work on Arch. Does it even load the right profile on Nix?
# TODO spellcheck.languages = ["fr-FR" "en-GB" "en-US"];
2023-11-19 23:09:10 +01:00
} ;
} ;
2023-10-29 00:49:22 +02:00
2023-11-22 14:05:48 +01:00
# Terminal
alacritty = {
# FIXME Emojis
enable = true ;
settings = {
bell = {
animation = " E a s e O u t E x p o " ;
color = " # 0 0 0 0 0 0 " ;
command = { program = " ${ pkgs . sox } / b i n / p l a y " ; args = [ " - n " " s y n t h " " s i n e " " C 5 " " s i n e " " E 4 " " r e m i x " " 1 - 2 " " f a d e " " 0 . 1 " " 0 . 2 " " 0 . 1 " ] ; } ;
duration = 100 ;
} ;
cursor = { vi_mode_style = " U n d e r l i n e " ; } ;
hints = {
enabled = [
{
binding = { mods = " C o n t r o l | A l t " ; key = " F " ; } ;
command = " ${ pkgs . xdg-utils } / b i n / x d g - o p e n " ;
mouse = { enabled = true ; mods = " C o n t r o l " ; } ;
post_processing = true ;
regex = " ( m a i l t o : | g e m i n i : | g o p h e r : | h t t p s : | h t t p : | n e w s : | f i l e : | g i t : | s s h : | f t p : ) [ ^ \\ u 0 0 0 0 - \\ u 0 0 1 F \\ u 0 0 7 F - \\ u 0 0 9 F < > \" \\ \\ s { - } \\ \\ ^ ⟨ ⟩ ` ] + " ;
}
] ;
} ;
key_bindings = [
{ mode = " ~ S e a r c h " ; mods = " A l t | C o n t r o l " ; key = " S p a c e " ; action = " T o g g l e V i M o d e " ; }
{ mode = " V i | ~ S e a r c h " ; mods = " C o n t r o l " ; key = " K " ; action = " S c r o l l H a l f P a g e U p " ; }
{ mode = " V i | ~ S e a r c h " ; mods = " C o n t r o l " ; key = " J " ; action = " S c r o l l H a l f P a g e D o w n " ; }
{ mode = " ~ V i " ; mods = " C o n t r o l | A l t " ; key = " V " ; action = " P a s t e " ; }
{ mods = " C o n t r o l | A l t " ; key = " C " ; action = " C o p y " ; }
{ mode = " ~ S e a r c h " ; mods = " C o n t r o l | A l t " ; key = " F " ; action = " S e a r c h F o r w a r d " ; }
{ mode = " ~ S e a r c h " ; mods = " C o n t r o l | A l t " ; key = " B " ; action = " S e a r c h B a c k w a r d " ; }
{ mode = " V i | ~ S e a r c h " ; mods = " C o n t r o l | A l t " ; key = " C " ; action = " C l e a r S e l e c t i o n " ; }
2023-11-02 21:57:06 +01:00
] ;
2023-11-22 14:05:48 +01:00
window = {
dynamic_padding = false ;
dynamic_title = true ;
} ;
2023-11-02 21:57:06 +01:00
} ;
} ;
2023-11-22 14:05:48 +01:00
# Backup terminal
urxvt = {
enable = true ;
package = pkgs . rxvt-unicode-emoji ;
scroll = {
bar . enable = false ;
} ;
iso14755 = false ; # Disable Ctrl+Shift default bindings
keybindings = {
" S h i f t - C o n t r o l - C " = " e v a l : s e l e c t i o n _ t o _ c l i p b o a r d " ;
" S h i f t - C o n t r o l - V " = " e v a l : p a s t e _ c l i p b o a r d " ;
# TODO Not sure resizing works, Nix doesn't have the package (urxvt-resize-font-git on Arch)
" C o n t r o l - K P _ S u b t r a c t " = " r e s i z e - f o n t : s m a l l e r " ;
" C o n t r o l - K P _ A d d " = " r e s i z e - f o n t : b i g g e r " ;
} ;
extraConfig = {
" l e t t e r S p a c e " = 0 ;
" p e r l - e x t - c o m m o n " = " r e s i z e - f o n t , b e l l - c o m m a n d , r e a d l i n e , s e l e c t i o n " ;
" b e l l - c o m m a n d " = " ${ pkgs . sox } / b i n / p l a y - n s y n t h s i n e C 5 s i n e E 4 r e m i x 1 - 2 f a d e 0 . 1 0 . 2 0 . 1 & > / d e v / n u l l " ;
} ;
2023-11-19 23:19:03 +01:00
} ;
2023-11-22 14:05:48 +01:00
rofi = {
2023-12-01 22:19:52 +01:00
# TODO This theme template, that was used for Arch, looks much better:
# https://gitlab.com/jordiorlando/base16-rofi/-/blob/master/templates/default.mustache
2023-11-22 14:05:48 +01:00
enable = true ;
pass . enable = true ;
extraConfig = {
lazy-grab = false ;
matching = " r e g e x " ;
} ;
2023-11-19 21:48:35 +01:00
} ;
2023-11-26 23:47:15 +01:00
autorandr = {
enable = true ;
hooks . postswitch =
let
frobar = ( pkgs . callPackage ( import ./frobar ) { } ) ;
in
{
" b a c k g r o u n d " = " ${ pkgs . feh } / b i n / f e h - - n o - f e h b g - - b g - f i l l ${ config . stylix . image } " ;
" f r o b a r " = " ${ pkgs . i3 } / b i n / i 3 - m s g e x e c ${ frobar } / b i n / f r o b a r _ l a u n c h e r " ;
} ;
} ;
2023-11-22 14:05:48 +01:00
mpv = {
enable = true ;
config = {
audio-display = false ;
save-position-on-quit = true ;
osc = false ; # # Required by thumbnail script
} ;
scripts = with pkgs . mpvScripts ; [ thumbnail ] ;
scriptOpts = {
mpv_thumbnail_script = {
cache_directory = " / t m p / m p v _ t h u m b s _ ${ config . home . username } " ;
} ;
2023-11-19 21:48:35 +01:00
} ;
} ;
} ;
2023-11-05 14:32:01 +01:00
2023-11-22 14:05:48 +01:00
xdg = {
mimeApps = {
enable = true ;
associations . added = {
" t e x t / h t m l " = " o r g . q u t e b r o w s e r . q u t e b r o w s e r . d e s k t o p " ;
" x - s c h e m e - h a n d l e r / h t t p " = " o r g . q u t e b r o w s e r . q u t e b r o w s e r . d e s k t o p " ;
" x - s c h e m e - h a n d l e r / h t t p s " = " o r g . q u t e b r o w s e r . q u t e b r o w s e r . d e s k t o p " ;
" x - s c h e m e - h a n d l e r / a b o u t " = " o r g . q u t e b r o w s e r . q u t e b r o w s e r . d e s k t o p " ;
" x - s c h e m e - h a n d l e r / u n k n o w n " = " o r g . q u t e b r o w s e r . q u t e b r o w s e r . d e s k t o p " ;
} ;
2023-11-19 21:28:42 +01:00
} ;
2023-11-22 14:05:48 +01:00
userDirs = {
enable = true ; # TODO Which ones do we want?
createDirectories = true ;
# French, because then it there's a different initial for each, making navigation easier
desktop = null ;
download = " ${ config . home . homeDirectory } / T é l é c h a r g e m e n t s " ;
music = " ${ config . home . homeDirectory } / M u s i q u e s " ;
pictures = " ${ config . home . homeDirectory } / I m a g e s " ;
publicShare = null ;
templates = null ;
videos = " ${ config . home . homeDirectory } / V i d é o s " ;
extraConfig = {
XDG_SCREENSHOTS_DIR = " ${ config . home . homeDirectory } / S c r e e n s h o t s " ;
} ;
2023-11-19 22:41:09 +01:00
} ;
2023-11-22 14:05:48 +01:00
configFile = {
" p u l s e / c l i e n t . c o n f " = {
text = '' c o o k i e - f i l e = . c o n f i g / p u l s e / p u l s e - c o o k i e '' ;
} ;
" x i n i t r c " =
let
nixgl = import
( builtins . fetchGit {
url = " h t t p s : / / g i t h u b . c o m / n i x - c o m m u n i t y / n i x G L " ;
rev = " 4 8 9 d 6 b 0 9 5 a b 9 d 2 8 9 f e 1 1 a f 0 2 1 9 a 9 f f 0 0 f e 8 7 c 7 c 5 " ;
} )
{ } ;
nixGLIntelPrefix = " ${ nixgl . nixVulkanIntel } / b i n / n i x V u l k a n I n t e l ${ nixgl . nixGLIntel } / b i n / n i x G L I n t e l " ;
wmPrefix = " ${ lib . optionalString config . frogeye . desktop . nixGLIntel nixGLIntelPrefix } " ;
in
{
source = pkgs . writeShellScript " x i n i t r c " ''
$ { pkgs . xorg . xrdb } /bin/xrdb $ { config . xresources . path }
$ { wmPrefix } $ { config . xsession . windowManager . command }
'' ;
} ;
" r o f i m o j i . r c " = {
text = ''
skin-tone = neutral
files = [ emojis , math ]
action = clipboard
2023-11-19 22:41:09 +01:00
'' ;
} ;
2023-11-26 22:45:07 +01:00
" v i m p c / v i m p c r c " = {
text = ''
map FF : browse <C-M> gg /
map à : set add next <C-M> a:set add end <C-M>
map @ : set add next <C-M> a:set add end <C-M> : next <C-M>
map ° D:browse <C-M> A:shuffle <C-M> : play <C-M> : playlist <C-M>
set songformat { % a - % b : % t } | { % f } $ E $ R $ H [ $ H % l $ H ] $ H
set libraryformat % n \ | { % t } | { % f } $ E $ R $ H [ $ H % l $ H ] $ H
set ignorecase
set sort library
'' ;
} ;
2023-11-19 23:19:03 +01:00
} ;
2023-11-19 22:41:09 +01:00
} ;
2023-11-22 14:05:48 +01:00
services = {
unclutter . enable = true ;
dunst =
{
enable = true ;
settings =
# TODO Change dmenu for rofi, so we can use context
with config . lib . stylix . colors . withHashtag ; {
global = {
separator_color = lib . mkForce base05 ;
idle_threshold = 120 ;
markup = " f u l l " ;
max_icon_size = 48 ;
# TODO Those shortcuts don't seem to work, maybe try:
# > define shortcuts inside your window manager and bind them to dunstctl(1) commands
close_all = " c t r l + m o d 4 + n " ;
close = " m o d 4 + n " ;
context = " m o d 1 + m o d 4 + n " ;
history = " s h i f t + m o d 4 + n " ;
} ;
2023-11-05 15:52:09 +01:00
2023-11-22 14:05:48 +01:00
urgency_low = {
background = lib . mkForce base01 ;
foreground = lib . mkForce base03 ;
frame_color = lib . mkForce base05 ;
} ;
urgency_normal = {
background = lib . mkForce base02 ;
foreground = lib . mkForce base05 ;
frame_color = lib . mkForce base05 ;
} ;
urgency_critical = {
background = lib . mkForce base08 ;
foreground = lib . mkForce base06 ;
frame_color = lib . mkForce base05 ;
} ;
2023-11-05 15:52:09 +01:00
} ;
2023-11-22 14:05:48 +01:00
} ;
mpd = {
enable = true ;
network = {
listenAddress = " 0 . 0 . 0 . 0 " ; # So it can be controlled from home
# TODO ... and whoever is the Wi-Fi network I'm using, which, not great
port = 8601 ; # FIXME Chose a different one for testing, should revert
startWhenNeeded = true ;
} ;
extraConfig = ''
restore_paused " y e s "
'' ;
2023-11-19 21:28:42 +01:00
} ;
2023-11-22 14:05:48 +01:00
autorandr . enable = true ;
2023-11-19 21:28:42 +01:00
} ;
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
home = {
packages = with pkgs ; [
# remote
tigervnc
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# music
mpc-cli
ashuffle
vimpc
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# multimedia common
gimp
inkscape
libreoffice
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# data management
freefilesync
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# browsers
firefox
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# fonts
dejavu_fonts
twemoji-color-font
gnome . gedit
feh
zbar
zathura
meld
python3Packages . magic
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# x11-exclusive
numlockx
simplescreenrecorder
trayer
xclip
keynav
xorg . xinit
xorg . xbacklight
# TODO Make this clean. Service?
2023-10-28 22:09:36 +02:00
2023-11-22 14:05:48 +01:00
# organisation
pass
thunderbird
] ;
sessionVariables = {
MPD_PORT = " ${ toString config . services . mpd . network . port } " ;
} ;
2023-11-19 21:28:42 +01:00
} ;
2023-11-05 21:32:31 +01:00
} ;
2023-10-28 22:09:36 +02:00
}