2017-07-23 16:05:46 +02:00
|
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
|
|
let
|
2024-02-21 16:13:30 -06:00
|
|
|
|
# Similar to lib.escapeShellArg but escapes "s instead of 's, to allow for parameter expansion in shells
|
|
|
|
|
escapeDoubleQuote = arg: ''"${replaceStrings ["\""] ["\"\\\"\""] (toString arg)}"'';
|
|
|
|
|
|
2019-01-02 21:13:45 +01:00
|
|
|
|
cfg = config.system.checks;
|
|
|
|
|
|
2025-01-12 00:39:05 +00:00
|
|
|
|
macOSVersion = ''
|
2025-01-30 12:46:25 -03:00
|
|
|
|
IFS=. read -ra osVersion <<<"$(sw_vers -productVersion)"
|
2025-01-12 00:39:05 +00:00
|
|
|
|
if (( osVersion[0] < 11 || (osVersion[0] == 11 && osVersion[1] < 3) )); then
|
|
|
|
|
printf >&2 '\e[1;31merror: macOS version is less than 11.3, aborting activation\e[0m\n'
|
|
|
|
|
printf >&2 'Nixpkgs 25.05 requires macOS Big Sur 11.3 or newer, and 25.11 will\n'
|
|
|
|
|
printf >&2 'require macOS Sonoma 14.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'For more information on your options going forward, see the 25.05\n'
|
|
|
|
|
printf >&2 'release notes:\n'
|
|
|
|
|
printf >&2 '<https://nixos.org/manual/nixos/unstable/release-notes#sec-release-25.05>\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'Nixpkgs 24.11 and nix-darwin 24.11 continue to support down to macOS\n'
|
|
|
|
|
printf >&2 'Sierra 10.12, and will be supported through June 2025.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'You can override this check by setting:\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 ' system.checks.verifyMacOSVersion = false;\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'However, we are unable to provide support if you do so.\n'
|
2025-01-29 15:48:57 +00:00
|
|
|
|
exit 2
|
2025-01-12 00:39:05 +00:00
|
|
|
|
fi
|
|
|
|
|
'';
|
|
|
|
|
|
2025-01-29 15:48:54 +00:00
|
|
|
|
determinate = ''
|
|
|
|
|
if [[ -e /usr/local/bin/determinate-nixd ]]; then
|
|
|
|
|
printf >&2 '\e[1;31merror: Determinate detected, aborting activation\e[0m\n'
|
|
|
|
|
printf >&2 'Determinate uses its own daemon to manage the Nix installation that\n'
|
|
|
|
|
printf >&2 'conflicts with nix-darwin’s native Nix management.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'To turn off nix-darwin’s management of the Nix installation, set:\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 ' nix.enable = false;\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'This will allow you to use nix-darwin with Determinate. Some nix-darwin\n'
|
|
|
|
|
printf >&2 'functionality that relies on managing the Nix installation, like the\n'
|
|
|
|
|
printf >&2 '`nix.*` options to adjust Nix settings or configure a Linux builder,\n'
|
|
|
|
|
printf >&2 'will be unavailable.\n'
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
2024-10-29 00:09:37 +11:00
|
|
|
|
|
2024-09-10 16:17:57 +01:00
|
|
|
|
preSequoiaBuildUsers = ''
|
|
|
|
|
firstBuildUserID=$(dscl . -read /Users/_nixbld1 UniqueID | awk '{print $2}')
|
2025-01-28 19:30:20 +00:00
|
|
|
|
if
|
|
|
|
|
# Don’t complain when we’re about to migrate old‐style build users…
|
|
|
|
|
[[ $firstBuildUserID != ${toString (config.ids.uids.nixbld + 1)} ]] \
|
|
|
|
|
&& ! dscl . -list /Users | grep -q '^nixbld'
|
|
|
|
|
then
|
2024-09-10 16:17:57 +01:00
|
|
|
|
printf >&2 '\e[1;31merror: Build users have unexpected UIDs, aborting activation\e[0m\n'
|
|
|
|
|
printf >&2 'The default Nix build user ID range has been adjusted for\n'
|
|
|
|
|
printf >&2 'compatibility with macOS Sequoia 15. Your _nixbld1 user currently has\n'
|
|
|
|
|
printf >&2 'UID %d rather than the new default of 351.\n' "$firstBuildUserID"
|
|
|
|
|
printf >&2 '\n'
|
2024-09-15 21:07:10 +01:00
|
|
|
|
printf >&2 'You can automatically migrate the users with the following command:\n'
|
2024-09-10 16:17:57 +01:00
|
|
|
|
printf >&2 '\n'
|
2024-09-15 21:07:10 +01:00
|
|
|
|
if [[ -e /nix/receipt.json ]]; then
|
|
|
|
|
if
|
|
|
|
|
${pkgs.jq}/bin/jq --exit-status \
|
|
|
|
|
'try(.planner.settings | has("enable_flakes"))' \
|
|
|
|
|
/nix/receipt.json \
|
|
|
|
|
>/dev/null
|
|
|
|
|
then
|
|
|
|
|
installerUrl="https://install.lix.systems/lix"
|
|
|
|
|
else
|
|
|
|
|
installerUrl="https://install.determinate.systems/nix"
|
|
|
|
|
fi
|
|
|
|
|
printf >&2 " curl --proto '=https' --tlsv1.2 -sSf -L %s | sh -s -- repair sequoia --move-existing-users\n" \
|
|
|
|
|
"$installerUrl"
|
|
|
|
|
else
|
|
|
|
|
printf >&2 " curl --proto '=https' --tlsv1.2 -sSf -L https://github.com/NixOS/nix/raw/master/scripts/sequoia-nixbld-user-migration.sh | bash -\n"
|
|
|
|
|
fi
|
2024-09-10 16:17:57 +01:00
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'If you have no intention of upgrading to macOS Sequoia 15, or already\n'
|
|
|
|
|
printf >&2 'have a custom UID range that you know is compatible with Sequoia, you\n'
|
|
|
|
|
printf >&2 'can disable this check by setting:\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 ' ids.uids.nixbld = %d;\n' "$((firstBuildUserID - 1))"
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
exit 2
|
2021-02-17 21:58:03 +01:00
|
|
|
|
fi
|
2017-07-23 17:23:09 +02:00
|
|
|
|
'';
|
|
|
|
|
|
2024-09-10 16:17:57 +01:00
|
|
|
|
buildGroupID = ''
|
|
|
|
|
buildGroupID=$(dscl . -read /Groups/nixbld PrimaryGroupID | awk '{print $2}')
|
|
|
|
|
expectedBuildGroupID=${toString config.ids.gids.nixbld}
|
2024-10-29 00:09:37 +11:00
|
|
|
|
if [[ $buildGroupID != "$expectedBuildGroupID" ]]; then
|
2024-09-10 16:17:57 +01:00
|
|
|
|
printf >&2 '\e[1;31merror: Build user group has mismatching GID, aborting activation\e[0m\n'
|
|
|
|
|
printf >&2 'The default Nix build user group ID was changed from 30000 to 350.\n'
|
|
|
|
|
printf >&2 'You are currently managing Nix build users with nix-darwin, but your\n'
|
|
|
|
|
printf >&2 'nixbld group has GID %d, whereas we expected %d.\n' \
|
|
|
|
|
"$buildGroupID" "$expectedBuildGroupID"
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'Possible causes include setting up a new Nix installation with an\n'
|
|
|
|
|
printf >&2 'existing nix-darwin configuration, setting up a new nix-darwin\n'
|
|
|
|
|
printf >&2 'installation with an existing Nix installation, or manually increasing\n'
|
|
|
|
|
printf >&2 'your `system.stateVersion` setting.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'You can set the configured group ID to match the actual value:\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 ' ids.gids.nixbld = %d;\n' "$buildGroupID"
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'We do not recommend trying to change the group ID with macOS user\n'
|
|
|
|
|
printf >&2 'management tools without a complete uninstallation and reinstallation\n'
|
|
|
|
|
printf >&2 'of Nix.\n'
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
|
|
|
|
|
2025-01-28 19:30:20 +00:00
|
|
|
|
nixDaemon = ''
|
|
|
|
|
if [[ "$(stat --format='%u' /nix)" != 0 ]]; then
|
|
|
|
|
printf >&2 '[1;31merror: single‐user install detected, aborting activation[0m\n'
|
|
|
|
|
printf >&2 'nix-darwin now only supports managing multi‐user daemon installations\n'
|
|
|
|
|
printf >&2 'of Nix. You can uninstall nix-darwin and Nix and then reinstall both to\n'
|
|
|
|
|
printf >&2 'fix this.\n'
|
2024-11-11 20:23:06 +11:00
|
|
|
|
printf >&2 '\n'
|
2025-01-28 19:30:20 +00:00
|
|
|
|
printf >&2 'If you don’t want to do that, you can disable management of the Nix\n'
|
|
|
|
|
printf >&2 'installation with:\n'
|
2024-11-11 20:23:06 +11:00
|
|
|
|
printf >&2 '\n'
|
2025-01-28 19:30:20 +00:00
|
|
|
|
printf >&2 ' nix.enable = false;\n'
|
2024-11-11 20:23:06 +11:00
|
|
|
|
printf >&2 '\n'
|
2025-01-28 19:30:20 +00:00
|
|
|
|
printf >&2 'See the `nix.enable` option documentation for caveats.\n'
|
2024-11-11 20:23:06 +11:00
|
|
|
|
exit 2
|
|
|
|
|
fi
|
2017-09-06 23:55:14 +02:00
|
|
|
|
'';
|
|
|
|
|
|
2018-01-13 19:44:26 +01:00
|
|
|
|
nixInstaller = ''
|
|
|
|
|
if grep -q 'etc/profile.d/nix-daemon.sh' /etc/profile; then
|
|
|
|
|
echo "[1;31merror: Found nix-daemon.sh reference in /etc/profile, aborting activation[0m" >&2
|
|
|
|
|
echo "This will override options like nix.nixPath because it runs later," >&2
|
|
|
|
|
echo "remove this snippet from /etc/profile:" >&2
|
|
|
|
|
echo >&2
|
|
|
|
|
echo " # Nix" >&2
|
|
|
|
|
echo " if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then" >&2
|
|
|
|
|
echo " . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'" >&2
|
|
|
|
|
echo " fi" >&2
|
|
|
|
|
echo " # End Nix" >&2
|
|
|
|
|
echo >&2
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
|
|
|
|
|
2017-07-23 18:56:37 +02:00
|
|
|
|
nixPath = ''
|
2024-02-21 16:13:30 -06:00
|
|
|
|
nixPath=${concatMapStringsSep ":" escapeDoubleQuote config.nix.nixPath}:$HOME/.nix-defexpr/channels
|
2022-08-14 14:04:20 -07:00
|
|
|
|
|
|
|
|
|
darwinConfig=$(NIX_PATH=$nixPath nix-instantiate --find-file darwin-config) || true
|
2017-07-23 17:49:38 +02:00
|
|
|
|
if ! test -e "$darwinConfig"; then
|
2017-07-23 17:28:58 +02:00
|
|
|
|
echo "[1;31merror: Changed <darwin-config> but target does not exist, aborting activation[0m" >&2
|
2025-01-13 23:21:04 +00:00
|
|
|
|
echo "Create ''${darwinConfig:-/etc/nix-darwin/configuration.nix} or set environment.darwinConfig:" >&2
|
2018-08-26 14:47:40 +02:00
|
|
|
|
echo >&2
|
2019-02-24 22:27:41 +01:00
|
|
|
|
echo " environment.darwinConfig = \"$(nix-instantiate --find-file darwin-config 2> /dev/null || echo '***')\";" >&2
|
2018-08-26 14:47:40 +02:00
|
|
|
|
echo >&2
|
|
|
|
|
echo "And rebuild using (only required once)" >&2
|
2019-02-24 22:27:41 +01:00
|
|
|
|
echo "$ darwin-rebuild switch -I \"darwin-config=$(nix-instantiate --find-file darwin-config 2> /dev/null || echo '***')\"" >&2
|
2017-07-23 17:28:58 +02:00
|
|
|
|
echo >&2
|
|
|
|
|
echo >&2
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
|
2022-08-14 14:04:20 -07:00
|
|
|
|
darwinPath=$(NIX_PATH=$nixPath nix-instantiate --find-file darwin) || true
|
2017-07-23 17:49:38 +02:00
|
|
|
|
if ! test -e "$darwinPath"; then
|
2017-07-23 17:23:09 +02:00
|
|
|
|
echo "[1;31merror: Changed <darwin> but target does not exist, aborting activation[0m" >&2
|
2017-08-07 20:09:59 +02:00
|
|
|
|
echo "Add the darwin repo as a channel or set nix.nixPath:" >&2
|
2025-01-14 01:18:53 +00:00
|
|
|
|
echo "$ sudo nix-channel --add https://github.com/LnL7/nix-darwin/archive/master.tar.gz darwin" >&2
|
|
|
|
|
echo "$ sudo nix-channel --update" >&2
|
2017-07-23 17:23:09 +02:00
|
|
|
|
echo >&2
|
|
|
|
|
echo "or set" >&2
|
|
|
|
|
echo >&2
|
2019-02-24 22:27:41 +01:00
|
|
|
|
echo " nix.nixPath = [ \"darwin=$(nix-instantiate --find-file darwin 2> /dev/null || echo '***')\" ];" >&2
|
2017-07-23 17:23:09 +02:00
|
|
|
|
echo >&2
|
2017-07-23 16:05:46 +02:00
|
|
|
|
exit 2
|
|
|
|
|
fi
|
2017-07-23 17:49:38 +02:00
|
|
|
|
|
2022-08-14 14:04:20 -07:00
|
|
|
|
nixpkgsPath=$(NIX_PATH=$nixPath nix-instantiate --find-file nixpkgs) || true
|
2017-07-23 17:49:38 +02:00
|
|
|
|
if ! test -e "$nixpkgsPath"; then
|
|
|
|
|
echo "[1;31merror: Changed <nixpkgs> but target does not exist, aborting activation[0m" >&2
|
2017-08-07 20:09:59 +02:00
|
|
|
|
echo "Add a nixpkgs channel or set nix.nixPath:" >&2
|
2025-01-14 01:18:53 +00:00
|
|
|
|
echo "$ sudo nix-channel --add http://nixos.org/channels/nixpkgs-unstable nixpkgs" >&2
|
|
|
|
|
echo "$ sudo nix-channel --update" >&2
|
2017-07-23 17:49:38 +02:00
|
|
|
|
echo >&2
|
|
|
|
|
echo "or set" >&2
|
|
|
|
|
echo >&2
|
2019-02-24 22:27:41 +01:00
|
|
|
|
echo " nix.nixPath = [ \"nixpkgs=$(nix-instantiate --find-file nixpkgs 2> /dev/null || echo '***')\" ];" >&2
|
2017-07-23 17:49:38 +02:00
|
|
|
|
echo >&2
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
2017-07-23 16:05:46 +02:00
|
|
|
|
'';
|
2018-01-18 00:12:38 +01:00
|
|
|
|
|
2023-07-16 16:59:43 +01:00
|
|
|
|
# TODO: Remove this a couple years down the line when we can assume
|
|
|
|
|
# that anyone who cares about security has upgraded.
|
|
|
|
|
oldSshAuthorizedKeysDirectory = ''
|
|
|
|
|
if [[ -d /etc/ssh/authorized_keys.d ]]; then
|
|
|
|
|
printf >&2 '\e[1;31merror: /etc/ssh/authorized_keys.d exists, aborting activation\e[0m\n'
|
|
|
|
|
printf >&2 'SECURITY NOTICE: The previous implementation of the\n'
|
|
|
|
|
printf >&2 '`users.users.<name>.openssh.authorizedKeys.*` options would not delete\n'
|
|
|
|
|
printf >&2 'authorized keys files when the setting for a given user was removed.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 "This means that if you previously stopped managing a user's authorized\n"
|
|
|
|
|
printf >&2 'SSH keys with nix-darwin, or intended to revoke their access by\n'
|
|
|
|
|
printf >&2 'removing the option, the previous set of keys could still be used to\n'
|
|
|
|
|
printf >&2 'log in as that user.\n'
|
|
|
|
|
printf >&2 '\n'
|
|
|
|
|
printf >&2 'You can check the /etc/ssh/authorized_keys.d directory to see which\n'
|
|
|
|
|
printf >&2 'keys were permitted; afterwards, please remove the directory and\n'
|
|
|
|
|
printf >&2 're-run activation. The options continue to be supported and will now\n'
|
|
|
|
|
printf >&2 'correctly permit only the keys in your current system configuration.\n'
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
2024-05-31 15:52:23 +05:30
|
|
|
|
|
|
|
|
|
homebrewInstalled = ''
|
2024-11-17 14:20:32 +00:00
|
|
|
|
if [[ ! -f ${escapeShellArg config.homebrew.brewPrefix}/brew && -z "''${INSTALLING_HOMEBREW:-}" ]]; then
|
2024-05-31 15:52:23 +05:30
|
|
|
|
echo "[1;31merror: Using the homebrew module requires homebrew installed, aborting activation[0m" >&2
|
|
|
|
|
echo "Homebrew doesn't seem to be installed. Please install homebrew separately." >&2
|
|
|
|
|
echo "You can install homebrew using the following command:" >&2
|
|
|
|
|
echo >&2
|
|
|
|
|
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' >&2
|
|
|
|
|
echo >&2
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
2024-12-29 12:13:54 +01:00
|
|
|
|
|
|
|
|
|
# some mac devices, notably notebook do not support restartAfterPowerFailure option
|
|
|
|
|
restartAfterPowerFailureIsSupported = ''
|
|
|
|
|
if sudo /usr/sbin/systemsetup -getRestartPowerFailure | grep -q "Not supported"; then
|
2025-01-04 14:35:53 +01:00
|
|
|
|
printf >&2 "\e[1;31merror: restarting after power failure is not supported on your machine\e[0m\n" >&2
|
|
|
|
|
printf >&2 "Please ensure that \`power.restartAfterPowerFailure\` is not set.\n" >&2
|
2024-12-29 12:13:54 +01:00
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
'';
|
2017-07-23 16:05:46 +02:00
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
{
|
2025-01-29 15:19:46 +00:00
|
|
|
|
imports = [
|
|
|
|
|
(mkRemovedOptionModule [ "system" "checks" "verifyNixChannels" ] "This check has been removed.")
|
|
|
|
|
];
|
|
|
|
|
|
2017-07-23 16:05:46 +02:00
|
|
|
|
options = {
|
2019-01-02 21:13:45 +01:00
|
|
|
|
system.checks.verifyNixPath = mkOption {
|
|
|
|
|
type = types.bool;
|
2025-01-28 18:40:29 +00:00
|
|
|
|
default = config.nix.enable;
|
2024-04-14 23:02:32 +02:00
|
|
|
|
description = "Whether to run the NIX_PATH validation checks.";
|
2019-01-02 21:13:45 +01:00
|
|
|
|
};
|
|
|
|
|
|
2023-06-05 18:27:58 -07:00
|
|
|
|
system.checks.verifyBuildUsers = mkOption {
|
|
|
|
|
type = types.bool;
|
2024-09-10 21:32:06 +01:00
|
|
|
|
default =
|
2025-01-28 19:30:20 +00:00
|
|
|
|
config.nix.enable && !(config.nix.settings.auto-allocate-uids or false);
|
2024-04-14 23:02:32 +02:00
|
|
|
|
description = "Whether to run the Nix build users validation checks.";
|
2023-06-05 18:27:58 -07:00
|
|
|
|
};
|
|
|
|
|
|
2025-01-12 00:39:05 +00:00
|
|
|
|
system.checks.verifyMacOSVersion = mkOption {
|
|
|
|
|
type = types.bool;
|
|
|
|
|
default = true;
|
|
|
|
|
description = "Whether to run the macOS version check.";
|
|
|
|
|
};
|
|
|
|
|
|
2019-01-02 21:13:45 +01:00
|
|
|
|
system.checks.text = mkOption {
|
|
|
|
|
internal = true;
|
|
|
|
|
type = types.lines;
|
|
|
|
|
default = "";
|
|
|
|
|
};
|
2017-07-23 16:05:46 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config = {
|
|
|
|
|
|
2019-01-02 21:13:45 +01:00
|
|
|
|
system.checks.text = mkMerge [
|
2025-01-12 00:39:05 +00:00
|
|
|
|
(mkIf cfg.verifyMacOSVersion macOSVersion)
|
2025-01-29 15:48:54 +00:00
|
|
|
|
(mkIf config.nix.enable determinate)
|
2024-09-10 16:17:57 +01:00
|
|
|
|
(mkIf cfg.verifyBuildUsers preSequoiaBuildUsers)
|
2025-01-28 19:30:20 +00:00
|
|
|
|
(mkIf cfg.verifyBuildUsers buildGroupID)
|
2025-01-28 18:40:29 +00:00
|
|
|
|
(mkIf config.nix.enable nixDaemon)
|
2019-01-02 21:13:45 +01:00
|
|
|
|
nixInstaller
|
|
|
|
|
(mkIf cfg.verifyNixPath nixPath)
|
2023-07-16 16:59:43 +01:00
|
|
|
|
oldSshAuthorizedKeysDirectory
|
2024-05-31 15:52:23 +05:30
|
|
|
|
(mkIf config.homebrew.enable homebrewInstalled)
|
2024-12-29 12:13:54 +01:00
|
|
|
|
(mkIf (config.power.restartAfterPowerFailure != null) restartAfterPowerFailureIsSupported)
|
2019-01-02 21:13:45 +01:00
|
|
|
|
];
|
|
|
|
|
|
2017-07-23 16:05:46 +02:00
|
|
|
|
system.activationScripts.checks.text = ''
|
2019-01-02 21:13:45 +01:00
|
|
|
|
${cfg.text}
|
2017-07-23 18:02:08 +02:00
|
|
|
|
|
2024-10-29 00:09:37 +11:00
|
|
|
|
if [[ "''${checkActivation:-0}" -eq 1 ]]; then
|
2017-07-23 18:02:08 +02:00
|
|
|
|
echo "ok" >&2
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
2017-07-23 16:05:46 +02:00
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
}
|