2021-01-22 12:25:31 +01:00
{ lib , stdenv
2020-09-24 12:25:27 +02:00
, fetchurl , perl , gcc
2021-07-04 20:30:39 +02:00
, ncurses5
2021-07-04 21:26:53 +02:00
, ncurses6 , gmp , libiconv , numactl
2020-09-24 12:25:27 +02:00
, llvmPackages
2020-11-03 10:18:21 +01:00
# minimal = true; will remove files that aren't strictly necessary for
# regular builds and GHC bootstrapping.
# This is "useful" for staying within hydra's output limits for at least the
# aarch64-linux architecture.
, minimal ? false
2020-09-24 12:25:27 +02:00
} :
# Prebuilt only does native
assert stdenv . targetPlatform == stdenv . hostPlatform ;
let
2021-07-04 20:11:47 +02:00
downloadsUrl = " h t t p s : / / d o w n l o a d s . h a s k e l l . o r g / g h c " ;
version = " 8 . 1 0 . 2 " ;
# Information about available bindists that we use in the build.
2021-07-04 21:11:42 +02:00
#
# # Bindist library checking
#
# The field `archSpecificLibraries` also provides a way for us get notified
# early when the upstream bindist changes its dependencies (e.g. because a
# newer Debian version is used that uses a new `ncurses` version).
#
# Usage:
#
# * You can find the `fileToCheckFor` of libraries by running `readelf -d`
# on the compiler binary (`exePathForLibraryCheck`).
# * To skip library checking for an architecture,
# set `exePathForLibraryCheck = null`.
# * To skip file checking for a specific arch specfic library,
# set `fileToCheckFor = null`.
2021-07-04 20:11:47 +02:00
ghcBinDists = {
2021-07-05 17:08:58 +02:00
# Binary distributions for the default libc (e.g. glibc, or libSystem on Darwin)
# nixpkgs uses for the respective system.
defaultLibc = {
i686-linux = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - i 3 8 6 - d e b 9 - l i n u x . t a r . x z " ;
sha256 = " 0 b v w i s l 4 w 0 z 5 z 8 z 0 d a 1 0 m 9 s v 0 m h m 9 n a 2 q m 4 3 q x r 8 z l 2 3 m n 3 2 m b l x " ;
} ;
exePathForLibraryCheck = " g h c / s t a g e 2 / b u i l d / t m p / g h c - s t a g e 2 " ;
archSpecificLibraries = [
# The i686-linux bindist provided by GHC HQ is currently built on Debian 9,
# which link it against `libtinfo.so.5` (ncurses 5).
# Other bindists are linked `libtinfo.so.6` (ncurses 6).
{ nixPackage = ncurses5 ; fileToCheckFor = " l i b t i n f o . s o . 5 " ; }
] ;
2021-07-04 20:11:47 +02:00
} ;
2021-07-05 17:08:58 +02:00
x86_64-linux = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - x 8 6 _ 6 4 - d e b 1 0 - l i n u x . t a r . x z " ;
sha256 = " 0 c h n z y 9 j 2 3 b 2 w a 8 c l x 5 a r w z 8 w n j f x y j m z 9 q k j 5 4 8 z 1 4 c q f 1 3 s l c l " ;
} ;
exePathForLibraryCheck = " g h c / s t a g e 2 / b u i l d / t m p / g h c - s t a g e 2 " ;
archSpecificLibraries = [
{ nixPackage = ncurses6 ; fileToCheckFor = " l i b t i n f o . s o . 6 " ; }
] ;
2021-07-04 20:11:47 +02:00
} ;
2021-07-05 17:08:58 +02:00
armv7l-linux = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - a r m v 7 - d e b 1 0 - l i n u x . t a r . x z " ;
sha256 = " 1 j 4 1 c q 5 d 3 r m l g z 7 h z w 8 f 9 0 8 f s 7 9 g c 5 m n 3 q 5 w z 2 7 7 l k 8 z d f 1 9 g 7 5 v " ;
} ;
exePathForLibraryCheck = " g h c / s t a g e 2 / b u i l d / t m p / g h c - s t a g e 2 " ;
archSpecificLibraries = [
{ nixPackage = ncurses6 ; fileToCheckFor = " l i b t i n f o . s o . 6 " ; }
] ;
} ;
aarch64-linux = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - a a r c h 6 4 - d e b 1 0 - l i n u x . t a r . x z " ;
sha256 = " 1 4 s m w l 3 7 4 1 i x n b g i 0 l 5 1 a 7 k h 7 x j k i a n n f q x 1 5 b 7 2 s v k y 0 y 4 l 3 w j w " ;
} ;
exePathForLibraryCheck = " g h c / s t a g e 2 / b u i l d / t m p / g h c - s t a g e 2 " ;
archSpecificLibraries = [
{ nixPackage = ncurses6 ; fileToCheckFor = " l i b t i n f o . s o . 6 " ; }
{ nixPackage = numactl ; fileToCheckFor = null ; }
] ;
} ;
x86_64-darwin = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - x 8 6 _ 6 4 - a p p l e - d a r w i n . t a r . x z " ;
sha256 = " 1 h n g y q 1 4 l 4 f 9 5 0 h z h h 2 d 2 0 4 c a 2 g f c 9 8 p c 9 x d a s x i h z q d 1 j q 7 5 d z d " ;
} ;
exePathForLibraryCheck = null ; # we don't have a library check for darwin yet
archSpecificLibraries = [
{ nixPackage = ncurses6 ; fileToCheckFor = null ; }
{ nixPackage = libiconv ; fileToCheckFor = null ; }
] ;
2021-07-04 20:11:47 +02:00
} ;
} ;
2021-07-05 17:08:58 +02:00
# Binary distributions for the musl libc for the respective system.
musl = {
x86_64-linux = {
src = {
url = " ${ downloadsUrl } / ${ version } / g h c - ${ version } - x 8 6 _ 6 4 - a l p i n e 3 . 1 0 - l i n u x - i n t e g e r - s i m p l e . t a r . x z " ;
sha256 = " 0 x p c b y a x q y h b l 6 f 0 i 3 s 4 r p 2 j m 6 7 n q p k f h 2 q l b j 3 i 2 f i a i x 8 9 m l 0 l " ;
} ;
exePathForLibraryCheck = " b i n / g h c " ;
archSpecificLibraries = [
# In contrast to glibc builds, the musl-bindist uses `libncursesw.so.*`
# instead of `libtinfo.so.*.`
{ nixPackage = ncurses6 ; fileToCheckFor = " l i b n c u r s e s w . s o . 6 " ; }
] ;
2021-07-04 20:11:47 +02:00
} ;
} ;
} ;
2021-07-05 17:08:58 +02:00
distSetName = if stdenv . hostPlatform . isMusl then " m u s l " else " d e f a u l t L i b c " ;
binDistUsed = ghcBinDists . ${ distSetName } . ${ stdenv . hostPlatform . system }
or ( throw " c a n n o t b o o t s t r a p G H C o n t h i s p l a t f o r m ( ' ${ stdenv . hostPlatform . system } ' w i t h l i b c ' ${ distSetName } ' ) " ) ;
2021-07-04 20:11:47 +02:00
2020-09-24 12:25:27 +02:00
useLLVM = ! stdenv . targetPlatform . isx86 ;
2021-07-04 21:11:42 +02:00
libPath =
lib . makeLibraryPath (
[
gmp
]
# Add arch-specific libraries.
++ map ( { nixPackage , . . . }: nixPackage ) binDistUsed . archSpecificLibraries
) ;
2020-09-24 12:25:27 +02:00
2021-01-22 12:25:31 +01:00
libEnvVar = lib . optionalString stdenv . hostPlatform . isDarwin " D Y "
2020-09-24 12:25:27 +02:00
+ " L D _ L I B R A R Y _ P A T H " ;
in
stdenv . mkDerivation rec {
2021-07-04 20:11:47 +02:00
inherit version ;
2020-09-24 12:25:27 +02:00
name = " g h c - ${ version } - b i n a r y " ;
2021-07-04 20:11:47 +02:00
src = fetchurl binDistUsed . src ;
2020-09-24 12:25:27 +02:00
nativeBuildInputs = [ perl ] ;
2021-07-04 21:26:53 +02:00
propagatedBuildInputs =
lib . optionals useLLVM [ llvmPackages . llvm ]
# Because musl bindists currently provide no way to tell where
# libgmp is (see not [musl bindists have no .buildinfo]), we need
# to propagate `gmp`, otherwise programs built by this ghc will
# fail linking with `cannot find -lgmp` errors.
# Also, as of writing, the release pages of musl bindists claim
# that they use `integer-simple` and do not require `gmp`; however
# that is incorrect, so `gmp` is required until a release has been
# made that includes https://gitlab.haskell.org/ghc/ghc/-/issues/20059.
# (Note that for packaging the `-binary` compiler, nixpkgs does not care
# about whether or not `gmp` is used; this comment is just here to explain
# why the `gmp` dependency exists despite what the release page says.)
++ lib . optionals stdenv . hostPlatform . isMusl [ gmp ] ; # musl bindist needs this
2020-09-24 12:25:27 +02:00
2021-07-04 19:24:10 +02:00
# Set LD_LIBRARY_PATH or equivalent so that the programs running as part
# of the bindist installer can find the libraries they expect.
2020-09-24 12:25:27 +02:00
# Cannot patchelf beforehand due to relative RPATHs that anticipate
2021-07-04 19:24:10 +02:00
# the final install location.
2020-09-24 12:25:27 +02:00
$ { libEnvVar } = libPath ;
postUnpack =
2021-07-04 21:11:42 +02:00
# Verify our assumptions of which `libtinfo.so` (ncurses) version is used,
# so that we know when ghc bindists upgrade that and we need to update the
# version used in `libPath`.
lib . optionalString
( binDistUsed . exePathForLibraryCheck != null )
# Note the `*` glob because some GHCs have a suffix when unpacked, e.g.
# the musl bindist has dir `ghc-VERSION-x86_64-unknown-linux/`.
# As a result, don't shell-quote this glob when splicing the string.
( let buildExeGlob = '' g h c - ${ version } * / " ${ binDistUsed . exePathForLibraryCheck } " '' ; in
lib . concatStringsSep " \n " [
( ''
echo " C h e c k i n g t h a t g h c b i n a r y e x i s t s i n b i n d i s t a t ${ buildExeGlob } "
if ! test - e $ { buildExeGlob } ; then
echo > & 2 " G H C b i n a r y ${ binDistUsed . exePathForLibraryCheck } c o u l d n o t b e f o u n d i n t h e b i n d i s t b u i l d d i r e c t o r y ( a t ${ buildExeGlob } ) f o r a r c h ${ stdenv . hostPlatform . system } , p l e a s e c h e c k t h a t g h c B i n D i s t s c o r r e c t l y r e f l e c t t h e b i n d i s t d e p e n d e n c i e s ! " ; exit 1 ;
fi
'' )
( lib . concatMapStringsSep
" \n "
( { fileToCheckFor , nixPackage }:
lib . optionalString ( fileToCheckFor != null ) ''
echo " C h e c k i n g b i n d i s t f o r ${ fileToCheckFor } t o e n s u r e t h a t i s s t i l l u s e d "
if ! readelf - d $ { buildExeGlob } | grep " ${ fileToCheckFor } " ; then
echo > & 2 " F i l e ${ fileToCheckFor } c o u l d n o t b e f o u n d i n ${ binDistUsed . exePathForLibraryCheck } f o r a r c h ${ stdenv . hostPlatform . system } , p l e a s e c h e c k t h a t g h c B i n D i s t s c o r r e c t l y r e f l e c t t h e b i n d i s t d e p e n d e n c i e s ! " ; exit 1 ;
fi
echo " C h e c k i n g t h a t t h e n i x p a c k a g e ${ nixPackage } c o n t a i n s ${ fileToCheckFor } "
if ! test - e " ${ lib . getLib nixPackage } / l i b / ${ fileToCheckFor } " ; then
echo > & 2 " N i x p a c k a g e ${ nixPackage } d i d n o t c o n t a i n ${ fileToCheckFor } f o r a r c h ${ stdenv . hostPlatform . system } , p l e a s e c h e c k t h a t g h c B i n D i s t s c o r r e c t l y r e f l e c t t h e b i n d i s t d e p e n d e n c i e s ! " ; exit 1 ;
fi
''
)
binDistUsed . archSpecificLibraries
)
] )
2020-09-24 12:25:27 +02:00
# GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib
# during linking
2021-07-04 21:11:42 +02:00
+ lib . optionalString stdenv . isDarwin ''
2020-09-24 12:25:27 +02:00
export NIX_LDFLAGS + = " - n o _ d t r a c e _ d o f "
# not enough room in the object files for the full path to libiconv :(
for exe in $ ( find . - type f - executable ) ; do
isScript $ exe && continue
ln - fs $ { libiconv } /lib/libiconv.dylib $ ( dirname $ exe ) /libiconv.dylib
install_name_tool - change /usr/lib/libiconv.2.dylib @ executable_path/libiconv.dylib - change /usr/local/lib/gcc/6/libgcc_s.1.dylib $ { gcc . cc . lib } /lib/libgcc_s.1.dylib $ exe
done
'' +
# Some scripts used during the build need to have their shebangs patched
''
patchShebangs ghc- $ { version } /utils /
patchShebangs ghc- $ { version } /configure
'' +
# We have to patch the GMP paths for the integer-gmp package.
2021-07-04 21:26:53 +02:00
# Note [musl bindists have no .buildinfo]
# Note that musl bindists do not contain them; unclear if that's intended;
# see: https://gitlab.haskell.org/ghc/ghc/-/issues/20073#note_363231
2020-09-24 12:25:27 +02:00
''
find . - name integer-gmp . buildinfo \
- exec sed - i " s @ e x t r a - l i b - d i r s : @ e x t r a - l i b - d i r s : ${ gmp . out } / l i b @ " { } \ ;
2021-01-22 12:25:31 +01:00
'' + l i b . o p t i o n a l S t r i n g s t d e n v . i s D a r w i n ''
2020-09-24 12:25:27 +02:00
find . - name base . buildinfo \
- exec sed - i " s @ e x t r a - l i b - d i r s : @ e x t r a - l i b - d i r s : ${ libiconv } / l i b @ " { } \ ;
'' +
2020-10-19 20:32:49 +02:00
# aarch64 does HAVE_NUMA so -lnuma requires it in library-dirs in rts/package.conf.in
# FFI_LIB_DIR is a good indication of places it must be needed.
2021-01-22 12:25:31 +01:00
lib . optionalString stdenv . hostPlatform . isAarch64 ''
2020-10-19 20:32:49 +02:00
find . - name package . conf . in \
- exec sed - i " s @ F F I _ L I B _ D I R @ F F I _ L I B _ D I R ${ numactl . out } / l i b @ g " { } \ ;
'' +
2020-09-24 12:25:27 +02:00
# Rename needed libraries and binaries, fix interpreter
2021-01-22 12:25:31 +01:00
lib . optionalString stdenv . isLinux ''
2021-07-04 23:42:15 +02:00
find . - type f - executable - exec patchelf \
2021-07-04 21:26:53 +02:00
- - interpreter $ { stdenv . cc . bintools . dynamicLinker } { } \ ;
2020-09-24 12:25:27 +02:00
'' ;
# fix for `configure: error: Your linker is affected by binutils #16177`
2021-01-22 12:25:31 +01:00
preConfigure = lib . optionalString
2020-09-24 12:25:27 +02:00
stdenv . targetPlatform . isAarch32
" L D = l d . g o l d " ;
configurePlatforms = [ ] ;
configureFlags = [
2021-01-22 12:25:31 +01:00
" - - w i t h - g m p - i n c l u d e s = ${ lib . getDev gmp } / i n c l u d e "
2021-07-05 19:01:00 +02:00
# Note `--with-gmp-libraries` does nothing for GHC bindists:
# https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6124
2021-01-22 12:25:31 +01:00
] ++ lib . optional stdenv . isDarwin " - - w i t h - g c c = ${ ./gcc-clang-wrapper.sh } "
2021-07-04 19:24:10 +02:00
# From: https://github.com/NixOS/nixpkgs/pull/43369/commits
2021-01-22 12:25:31 +01:00
++ lib . optional stdenv . hostPlatform . isMusl " - - d i s a b l e - l d - o v e r r i d e " ;
2020-09-24 12:25:27 +02:00
# No building is necessary, but calling make without flags ironically
# calls install-strip ...
dontBuild = true ;
2021-07-04 21:26:53 +02:00
# Apparently necessary for the ghc Alpine (musl) bindist:
# When we strip, and then run the
# patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p
# below, running ghc (e.g. during `installCheckPhase)` gives some apparently
# corrupted rpath or whatever makes the loader work on nonsensical strings:
# running install tests
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: : symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: ir6zf6c9f86pfx8sr30n2vjy-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/../lib/x86_64-linux-ghc-8.10.5/libHSexceptions-0.10.4-ghc8.10.5.so: symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: y/lib/ghc-8.10.5/bin/../lib/x86_64-linux-ghc-8.10.5/libHStemplate-haskell-2.16.0.0-ghc8.10.5.so: symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: 8.10.5/libHStemplate-haskell-2.16.0.0-ghc8.10.5.so: symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: <20> : symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: <20> ?: symbol not found
# Error relocating /nix/store/...-ghc-8.10.2-binary/lib/ghc-8.10.5/bin/ghc: 64-linux-ghc-8.10.5/libHSexceptions-0.10.4-ghc8.10.5.so: symbol not found
# This is extremely bogus and should be investigated.
dontStrip = if stdenv . hostPlatform . isMusl then true else false ; # `if` for explicitness
2020-09-24 12:25:27 +02:00
# On Linux, use patchelf to modify the executables so that they can
# find editline/gmp.
2021-01-22 12:25:31 +01:00
postFixup = lib . optionalString stdenv . isLinux
2020-10-19 20:32:49 +02:00
( if stdenv . hostPlatform . isAarch64 then
# Keep rpath as small as possible on aarch64 for patchelf#244. All Elfs
# are 2 directories deep from $out/lib, so pooling symlinks there makes
# a short rpath.
''
( cd $ out/lib ; ln - s $ { ncurses6 . out } /lib/libtinfo.so.6 )
( cd $ out/lib ; ln - s $ { gmp . out } /lib/libgmp.so.10 )
( cd $ out/lib ; ln - s $ { numactl . out } /lib/libnuma.so.1 )
for p in $ ( find " $ o u t / l i b " - type f - name " * \. s o * " ) ; do
( cd $ out/lib ; ln - s $ p )
done
for p in $ ( find " $ o u t / l i b " - type f - executable ) ; do
if isELF " $ p " ; then
echo " P a t c h e l f i n g $ p "
patchelf - - set-rpath " \$ O R I G I N : \$ O R I G I N / . . / . . " $ p
fi
done
''
else
''
for p in $ ( find " $ o u t " - type f - executable ) ; do
if isELF " $ p " ; then
echo " P a t c h e l f i n g $ p "
patchelf - - set-rpath " ${ libPath } : $ ( p a t c h e l f - - p r i n t - r p a t h $ p ) " $ p
fi
done
2021-01-22 12:25:31 +01:00
'' ) + l i b . o p t i o n a l S t r i n g s t d e n v . i s D a r w i n ''
2020-09-24 12:25:27 +02:00
# not enough room in the object files for the full path to libiconv :(
for exe in $ ( find " $ o u t " - type f - executable ) ; do
isScript $ exe && continue
ln - fs $ { libiconv } /lib/libiconv.dylib $ ( dirname $ exe ) /libiconv.dylib
install_name_tool - change /usr/lib/libiconv.2.dylib @ executable_path/libiconv.dylib - change /usr/local/lib/gcc/6/libgcc_s.1.dylib $ { gcc . cc . lib } /lib/libgcc_s.1.dylib $ exe
done
for file in $ ( find " $ o u t " - name setup-config ) ; do
substituteInPlace $ file - - replace /usr/bin/ranlib " $ ( t y p e - P r a n l i b ) "
done
2020-11-03 10:18:21 +01:00
'' +
2021-01-22 12:25:31 +01:00
lib . optionalString minimal ''
2020-11-04 21:40:14 +01:00
# Remove profiling files
2020-11-03 10:18:21 +01:00
find $ out - type f - name ' * . p_o' - delete
2020-11-04 21:40:14 +01:00
find $ out - type f - name ' * . p_hi' - delete
find $ out - type f - name ' * _p . a' - delete
2021-07-04 21:26:53 +02:00
# `-f` because e.g. musl bindist does not have this file.
rm - f $ out/lib/ghc- * /bin/ghc-iserv-prof
2020-11-04 21:40:14 +01:00
# Hydra will redistribute this derivation, so we have to keep the docs for
# legal reasons (retaining the legal notices etc)
# As a last resort we could unpack the docs separately and symlink them in.
# They're in $out/share/{doc,man}.
2020-09-24 12:25:27 +02:00
'' ;
2021-07-04 21:26:53 +02:00
# In nixpkgs, musl based builds currently enable `pie` hardening by default
# (see `defaultHardeningFlags` in `make-derivation.nix`).
# But GHC cannot currently produce outputs that are ready for `-pie` linking.
# Thus, disable `pie` hardening, otherwise `recompile with -fPIE` errors appear.
# See:
# * https://github.com/NixOS/nixpkgs/issues/129247
# * https://gitlab.haskell.org/ghc/ghc/-/issues/19580
hardeningDisable = lib . optional stdenv . targetPlatform . isMusl " p i e " ;
2020-09-24 12:25:27 +02:00
doInstallCheck = true ;
installCheckPhase = ''
unset $ { libEnvVar }
# Sanity check, can ghc create executables?
cd $ TMP
mkdir test-ghc ; cd test-ghc
cat > main . hs < < EOF
{ - # LANGUAGE TemplateHaskell #-}
module Main where
main = putStrLn \ $ ( [ | " y e s " | ] )
EOF
$ out/bin/ghc - - make main . hs || exit 1
echo compilation ok
[ $ ( ./main ) == " y e s " ]
'' ;
passthru = {
targetPrefix = " " ;
enableShared = true ;
2021-05-31 00:26:03 +02:00
# Our Cabal compiler name
haskellCompilerName = " g h c - ${ version } " ;
2020-09-24 12:25:27 +02:00
} ;
2021-05-07 15:09:08 +02:00
meta = rec {
2020-10-19 20:32:49 +02:00
homepage = " h t t p : / / h a s k e l l . o r g / g h c " ;
description = " T h e G l a s g o w H a s k e l l C o m p i l e r " ;
2021-01-22 12:25:31 +01:00
license = lib . licenses . bsd3 ;
2021-07-05 17:08:58 +02:00
# HACK: since we can't encode the libc / abi in platforms, we need
# to make the platform list dependent on the evaluation platform
# in order to avoid eval errors with musl which supports less
# platforms than the default libcs (i. e. glibc / libSystem).
# This is done for the benefit of Hydra, so `packagePlatforms`
# won't return any platforms that would cause an evaluation
# failure for `pkgsMusl.haskell.compiler.ghc8102Binary`, as
# long as the evaluator runs on a platform that supports
# `pkgsMusl`.
platforms = builtins . attrNames ghcBinDists . ${ distSetName } ;
2021-05-07 15:09:08 +02:00
hydraPlatforms = builtins . filter ( p : minimal || p != " a a r c h 6 4 - l i n u x " ) platforms ;
2021-05-31 09:04:54 +02:00
maintainers = with lib . maintainers ; [ lostnet guibou ] ;
2020-10-19 20:32:49 +02:00
} ;
2020-09-24 12:25:27 +02:00
}