From 0221d5913ea26fde9493dadfbb265f2ff103124f Mon Sep 17 00:00:00 2001 From: Azat Bahawi Date: Sat, 30 Sep 2023 15:21:49 +0300 Subject: 2023-09-30 --- flake.lock | 60 +++++++++++----------- flake.nix | 4 +- modules/common/common/nix/default.nix | 4 +- .../common/nix/patches/tdesktop-no-ads.patch | 45 ---------------- .../nix/patches/telegram-desktop-no-ads.patch | 45 ++++++++++++++++ modules/common/emacs/default.nix | 2 +- modules/nixos/emacs.nix | 1 + modules/nixos/profiles/headful.nix | 2 +- modules/nixos/throttled.nix | 14 +---- nixosConfigurations/eonwe/default.nix | 1 + nixosConfigurations/melian/default.nix | 9 +--- packages/bruh.nix | 25 ++++++--- packages/mpv-autosub.nix | 20 ++++++-- packages/myip.nix | 10 ++++ packages/nixfiles.nix | 46 ++++++++++++----- packages/throttled.nix | 36 ------------- 16 files changed, 163 insertions(+), 161 deletions(-) delete mode 100644 modules/common/common/nix/patches/tdesktop-no-ads.patch create mode 100644 modules/common/common/nix/patches/telegram-desktop-no-ads.patch delete mode 100644 packages/throttled.nix diff --git a/flake.lock b/flake.lock index 7aa25b1..d1ecf4c 100644 --- a/flake.lock +++ b/flake.lock @@ -147,11 +147,11 @@ ] }, "locked": { - "lastModified": 1695686713, - "narHash": "sha256-rJATx5B/nwlBpt7CJUf85LV27qWPbul5UVV8fu6ABPg=", + "lastModified": 1696043447, + "narHash": "sha256-VbJ1dY5pVH2fX1bS+cT2+4+BYEk4lMHRP0+udu9G6tk=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "e236a1e598a9a59265897948ac9874c364b9555f", + "rev": "792c2e01347cb1b2e7ec84a1ef73453ca86537d8", "type": "github" }, "original": { @@ -287,11 +287,11 @@ ] }, "locked": { - "lastModified": 1695738267, - "narHash": "sha256-LTNAbTQ96xSj17xBfsFrFS9i56U2BMLpD0BduhrsVkU=", + "lastModified": 1696063111, + "narHash": "sha256-F2IJEbyH3xG0eqyAYn9JoV+niqNz+xb4HICYNkkviNI=", "owner": "nix-community", "repo": "home-manager", - "rev": "0f4e5b4999fd6a42ece5da8a3a2439a50e48e486", + "rev": "ae896c810f501bf0c3a2fd7fc2de094dd0addf01", "type": "github" }, "original": { @@ -346,11 +346,11 @@ ] }, "locked": { - "lastModified": 1695777360, - "narHash": "sha256-dU1Baq0ae2JRCLwg7puSZ8+4lfd401gnQEVHKA4QYH8=", + "lastModified": 1696036450, + "narHash": "sha256-h8Bm29mgi84ExURlvXS1BGctts2FKmbtLHK9/H0dq0E=", "owner": "Infinidoge", "repo": "nix-minecraft", - "rev": "769afc9e3338697d0ff129ef096a7fde6db3d696", + "rev": "1c3622d8b71d32deaaa5d27220703fbe2dc3d900", "type": "github" }, "original": { @@ -373,11 +373,11 @@ ] }, "locked": { - "lastModified": 1695777563, - "narHash": "sha256-eRYVpsEgU61yjBRdwEm+fvmwbl1had2GSULpAaB8KWI=", + "lastModified": 1696036838, + "narHash": "sha256-GmzS2RWWG98Lw/NsXlBpVxBfH9deP6UtyB/IKj/vKUw=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "c64fa1726fda5190c5f6fe0f1a76262cca1962cd", + "rev": "d9c11ddc1817497981466faba1fc7b8d1ea4f865", "type": "github" }, "original": { @@ -389,11 +389,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1695541019, - "narHash": "sha256-rs++zfk41K9ArWkDAlmBDlGlKO8qeRIRzdjo+9SmNFI=", + "lastModified": 1695887975, + "narHash": "sha256-u3+5FR12dI305jCMb0fJNQx2qwoQ54lv1tPoEWp0hmg=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "61283b30d11f27d5b76439d43f20d0c0c8ff5296", + "rev": "adcfd6aa860d1d129055039696bc457af7d50d0e", "type": "github" }, "original": { @@ -405,11 +405,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1695806987, - "narHash": "sha256-fX5kGs66NZIxCMcpAGIpxuftajHL8Hil1vjHmjjl118=", + "lastModified": 1695837737, + "narHash": "sha256-KcqmJ5hNacLuE7fkz5586kp/vt4NLo6+Prq3DMgrxpQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f3dab3509afca932f3f4fd0908957709bb1c1f57", + "rev": "517501bcf14ae6ec47efd6a17dda0ca8e6d866f9", "type": "github" }, "original": { @@ -421,11 +421,11 @@ }, "nixpkgs-master": { "locked": { - "lastModified": 1695859332, - "narHash": "sha256-w2a7NW3VtI5FgFPUKslYRGAj5Qb7y4i0I2QO0S/lBMQ=", + "lastModified": 1696072632, + "narHash": "sha256-1OptCtmN9TKjORwetaf7q17QSm5Mm3c33GeI3rPmepg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "248a83fffc10b627da67fa6b25d2c13fc7542628", + "rev": "e14dd9c00cfa2690820b86410834130586f8cbf4", "type": "github" }, "original": { @@ -437,11 +437,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1695857902, - "narHash": "sha256-zBTlSQ1TMKdGjZCQk4KrVmDmosq3MQf98ichJ2sXBBE=", + "lastModified": 1696068958, + "narHash": "sha256-KIGoNwQJ9fhRX5//HI0Fzvu7wMyZhliBJH4YOfS2DIo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c9ac6ec01314e8ff2669bd723bfb98bb072723b4", + "rev": "8804d8199e6570113477ec4b624e74d250230c49", "type": "github" }, "original": { @@ -465,11 +465,11 @@ ] }, "locked": { - "lastModified": 1695804493, - "narHash": "sha256-LcHdI5TjeomY7Q244iKwcZUUwT5uZUUFANORNIoslKY=", + "lastModified": 1695992447, + "narHash": "sha256-Vmg5Xvx3RR8zxWiIkJko1K9MT9Z0HSVj7GTZigveFCs=", "owner": "nix-community", "repo": "nixvim", - "rev": "9e448b7ff002505774c53b815726edbb677afea6", + "rev": "3fa81dd06341ad9958b2b51b9e71448f693917f9", "type": "github" }, "original": { @@ -515,11 +515,11 @@ }, "nur": { "locked": { - "lastModified": 1695858410, - "narHash": "sha256-Y/xJxDBhrI8WZGX0L8GDw0vTdFpmh1P10lq9sws6YKo=", + "lastModified": 1696066359, + "narHash": "sha256-yt94loEvHjuzQ+aIVLvN6OzzXtWq7nDgHhxJ11bqZIc=", "owner": "nix-community", "repo": "NUR", - "rev": "b7a926cb0b29662ee27f382bf1c2aa26608f45ec", + "rev": "9948d7c2cf064aa08f6df8f925a811d0f0950e5b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 27b027a..da326a3 100644 --- a/flake.nix +++ b/flake.nix @@ -303,6 +303,9 @@ devShells.default = pkgs.mkShell { inherit (self.checks.${system}.preCommit) shellHook; + # TODO Figure out why direnv overwrites exec-path. Meanwhile leave + # this in devShell. + packages = with pkgs; [nil]; }; formatter = with pkgs; @@ -361,7 +364,6 @@ mpv-autosub = prev.callPackage ./packages/mpv-autosub.nix {}; myip = prev.callPackage ./packages/myip.nix {}; nixfiles = prev.callPackage ./packages/nixfiles.nix {}; - throttled = prev.callPackage ./packages/throttled.nix {}; logcli = prev.grafana-loki.overrideAttrs (_: super: { pname = "logcli"; subPackages = ["cmd/logcli"]; diff --git a/modules/common/common/nix/default.nix b/modules/common/common/nix/default.nix index dc99434..bbb06d0 100644 --- a/modules/common/common/nix/default.nix +++ b/modules/common/common/nix/default.nix @@ -115,8 +115,8 @@ with lib; { patches = final.patches ++ [./patches/alejandra-no-ads.patch]; }); - tdesktop = super.tdesktop.overrideAttrs (_: final: { - patches = final.patches ++ [./patches/tdesktop-no-ads.patch]; + telegram-desktop = super.telegram-desktop.overrideAttrs (_: final: { + patches = final.patches ++ [./patches/telegram-desktop-no-ads.patch]; }); inherit (pkgsPr 245433 "sha256-FF1WW0+/pJ15+mPVjv0bkrh0dpHfQU08HNat2gu1PQk=") openmw; diff --git a/modules/common/common/nix/patches/tdesktop-no-ads.patch b/modules/common/common/nix/patches/tdesktop-no-ads.patch deleted file mode 100644 index d066066..0000000 --- a/modules/common/common/nix/patches/tdesktop-no-ads.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff --git i/Telegram/SourceFiles/data/data_sponsored_messages.cpp w/Telegram/SourceFiles/data/data_sponsored_messages.cpp -index fa21af469..263ea3e61 100644 ---- i/Telegram/SourceFiles/data/data_sponsored_messages.cpp -+++ w/Telegram/SourceFiles/data/data_sponsored_messages.cpp -@@ -179,39 +179,7 @@ bool SponsoredMessages::canHaveFor(not_null history) const { - } - - void SponsoredMessages::request(not_null history, Fn done) { -- if (!canHaveFor(history)) { -- return; -- } -- auto &request = _requests[history]; -- if (request.requestId || TooEarlyForRequest(request.lastReceived)) { -- return; -- } -- { -- const auto it = _data.find(history); -- if (it != end(_data)) { -- auto &list = it->second; -- // Don't rebuild currently displayed messages. -- const auto proj = [](const Entry &e) { -- return e.item != nullptr; -- }; -- if (ranges::any_of(list.entries, proj)) { -- return; -- } -- } -- } -- const auto channel = history->peer->asChannel(); -- Assert(channel != nullptr); -- request.requestId = _session->api().request( -- MTPchannels_GetSponsoredMessages( -- channel->inputChannel) -- ).done([=](const MTPmessages_sponsoredMessages &result) { -- parse(history, result); -- if (done) { -- done(); -- } -- }).fail([=] { -- _requests.remove(history); -- }).send(); -+ return; - } - - void SponsoredMessages::parse( diff --git a/modules/common/common/nix/patches/telegram-desktop-no-ads.patch b/modules/common/common/nix/patches/telegram-desktop-no-ads.patch new file mode 100644 index 0000000..d066066 --- /dev/null +++ b/modules/common/common/nix/patches/telegram-desktop-no-ads.patch @@ -0,0 +1,45 @@ +diff --git i/Telegram/SourceFiles/data/data_sponsored_messages.cpp w/Telegram/SourceFiles/data/data_sponsored_messages.cpp +index fa21af469..263ea3e61 100644 +--- i/Telegram/SourceFiles/data/data_sponsored_messages.cpp ++++ w/Telegram/SourceFiles/data/data_sponsored_messages.cpp +@@ -179,39 +179,7 @@ bool SponsoredMessages::canHaveFor(not_null history) const { + } + + void SponsoredMessages::request(not_null history, Fn done) { +- if (!canHaveFor(history)) { +- return; +- } +- auto &request = _requests[history]; +- if (request.requestId || TooEarlyForRequest(request.lastReceived)) { +- return; +- } +- { +- const auto it = _data.find(history); +- if (it != end(_data)) { +- auto &list = it->second; +- // Don't rebuild currently displayed messages. +- const auto proj = [](const Entry &e) { +- return e.item != nullptr; +- }; +- if (ranges::any_of(list.entries, proj)) { +- return; +- } +- } +- } +- const auto channel = history->peer->asChannel(); +- Assert(channel != nullptr); +- request.requestId = _session->api().request( +- MTPchannels_GetSponsoredMessages( +- channel->inputChannel) +- ).done([=](const MTPmessages_sponsoredMessages &result) { +- parse(history, result); +- if (done) { +- done(); +- } +- }).fail([=] { +- _requests.remove(history); +- }).send(); ++ return; + } + + void SponsoredMessages::parse( diff --git a/modules/common/emacs/default.nix b/modules/common/emacs/default.nix index 1d205b9..a21b5ab 100644 --- a/modules/common/emacs/default.nix +++ b/modules/common/emacs/default.nix @@ -149,7 +149,7 @@ in { (appendq! auth-sources '("${config.secrets.authinfo.path}")) - ;; Font must be set to N+2 because otherwise it looks too small. + ;; The font must be set to n+2, otherwise it looks too small. (setq doom-font (font-spec :family "${config.fontScheme.monospaceFont.family}" :size ${toString (config.fontScheme.monospaceFont.size + 2)}) diff --git a/modules/nixos/emacs.nix b/modules/nixos/emacs.nix index 82c2f6e..5e263c9 100644 --- a/modules/nixos/emacs.nix +++ b/modules/nixos/emacs.nix @@ -12,6 +12,7 @@ in { hm.services.emacs = { enable = true; client.enable = true; + socketActivation.enable = true; }; }; } diff --git a/modules/nixos/profiles/headful.nix b/modules/nixos/profiles/headful.nix index f8df169..6658582 100644 --- a/modules/nixos/profiles/headful.nix +++ b/modules/nixos/profiles/headful.nix @@ -26,7 +26,7 @@ in { element-desktop imv mumble - tdesktop + telegram-desktop tor-browser-bundle-bin ]; diff --git a/modules/nixos/throttled.nix b/modules/nixos/throttled.nix index f182ee1..a84fd27 100644 --- a/modules/nixos/throttled.nix +++ b/modules/nixos/throttled.nix @@ -1,7 +1,6 @@ { config, lib, - pkgs, ... }: with lib; let @@ -10,8 +9,7 @@ in { options.nixfiles.modules.throttled.enable = mkEnableOption "Throttled"; config = mkIf cfg.enable { - # Disable the module we are trying to "override". - services.throttled.enable = mkForce false; + services.throttled.enable = true; environment.etc."throttled.conf".text = '' [GENERAL] @@ -105,15 +103,5 @@ in { # # CPU cache max current (A) # CACHE: ''; - - systemd.services.throttled = { - description = "Stop Intel throttling"; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.throttled}/opt/throttled/throttled.py"; - }; - environment.PYTHONUNBUFFERED = "1"; - wantedBy = ["multi-user.target"]; - }; }; } diff --git a/nixosConfigurations/eonwe/default.nix b/nixosConfigurations/eonwe/default.nix index 852dc07..7a23ef0 100644 --- a/nixosConfigurations/eonwe/default.nix +++ b/nixosConfigurations/eonwe/default.nix @@ -42,6 +42,7 @@ with lib; { obs-studio openmw openttd + qbittorrent qzdl radeontop vcmi diff --git a/nixosConfigurations/melian/default.nix b/nixosConfigurations/melian/default.nix index d38e09b..f4178e2 100644 --- a/nixosConfigurations/melian/default.nix +++ b/nixosConfigurations/melian/default.nix @@ -1,9 +1,4 @@ -{ - lib, - pkgs, - ... -}: -with lib; { +{pkgs, ...}: { nixfiles.modules = { wireguard.client.enable = true; @@ -31,7 +26,7 @@ with lib; { # suspend due to a kernel bug[1] which is still not fixed. # # I guess this can also be fixed differently[2], which does look a lot nicer - # but I just can't bother. + # but I'm just too lazy. # # [1]: https://bbs.archlinux.org/viewtopic.php?id=270964 # [1]: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/522998 diff --git a/packages/bruh.nix b/packages/bruh.nix index 62fe557..2b274f1 100644 --- a/packages/bruh.nix +++ b/packages/bruh.nix @@ -1,18 +1,20 @@ { alsa-utils, fetchFromGitHub, + lib, stdenv, }: -stdenv.mkDerivation rec { +stdenv.mkDerivation (finalAttrs: { pname = "bruh"; version = "2.1"; - src = fetchFromGitHub { - owner = "kejpies"; - repo = pname; - rev = version; - hash = "sha256-Uw6Qes0IZkkfBchFnvnX9l1ZG5T5pyExmV7yUJLPOJ0="; - }; + src = with finalAttrs; + fetchFromGitHub { + owner = "kejpies"; + repo = pname; + rev = version; + hash = "sha256-Uw6Qes0IZkkfBchFnvnX9l1ZG5T5pyExmV7yUJLPOJ0="; + }; postPatch = '' substituteInPlace bruh.c \ @@ -20,4 +22,11 @@ stdenv.mkDerivation rec { ''; makeFlags = ["PREFIX=$(out)"]; -} + + meta = with lib; { + description = "Bruh sound, but as a program"; + inherit (finalAttrs.src.meta) homepage; + license = licenses.gpl3Only; + maintainers = with maintainers; [azahi]; + }; +}) diff --git a/packages/mpv-autosub.nix b/packages/mpv-autosub.nix index 3d8171d..e3fc221 100644 --- a/packages/mpv-autosub.nix +++ b/packages/mpv-autosub.nix @@ -1,15 +1,17 @@ { fetchFromGitHub, + lib, + mpv-unwrapped, python3Packages, stdenvNoCC, }: -stdenvNoCC.mkDerivation rec { +stdenvNoCC.mkDerivation (finalAttrs: { pname = "mpv-autosub"; version = "unstable-2021-06-29"; src = fetchFromGitHub { owner = "davidde"; - repo = pname; + repo = finalAttrs.pname; rev = "35115355bd339681f97d067538356c29e5b14afa"; hash = "sha256-BKT/Tzwl5ZA4fbdc/cxz0+CYc1zyY/KOXc58x5GYow0="; }; @@ -25,8 +27,20 @@ stdenvNoCC.mkDerivation rec { ''; installPhase = '' + runHook preInstall + install -Dm644 autosub.lua $out/share/mpv/scripts/autosub.lua + + runHook postInstall ''; passthru.scriptName = "autosub.lua"; -} + + meta = with lib; { + description = "Automatic downloading of subtitles for MPV"; + inherit (finalAttrs.src.meta) homepage; + license = licenses.mit; + inherit (mpv-unwrapped.meta) platforms; + maintainers = with maintainers; [azahi]; + }; +}) diff --git a/packages/myip.nix b/packages/myip.nix index a830139..67ea1ed 100644 --- a/packages/myip.nix +++ b/packages/myip.nix @@ -1,12 +1,22 @@ { dnsutils, + lib, writeShellApplication, }: writeShellApplication { name = "myip"; + runtimeInputs = [dnsutils]; + text = '' dig -4 +short @resolver1.opendns.com myip.opendns.com A dig -6 +short @resolver1.opendns.com myip.opendns.com AAAA ''; + + meta = with lib; { + description = "A dumb tool to get host's current public IP"; + homepage = "https://git.azahi.cc/nixfiles"; + license = licenses.wtfpl; + maintainers = with maintainers; [azahi]; + }; } diff --git a/packages/nixfiles.nix b/packages/nixfiles.nix index 9b16e84..b534e3c 100644 --- a/packages/nixfiles.nix +++ b/packages/nixfiles.nix @@ -1,8 +1,10 @@ { git, jq, + lib, nix, openssh, + stdenv, symlinkJoin, writeShellApplication, writeTextDir, @@ -11,13 +13,14 @@ bin = writeShellApplication { name = "nixfiles"; - runtimeInputs = [ - git - jq - nix - openssh - xdg-utils - ]; + runtimeInputs = + [ + git + jq + nix + openssh + ] + ++ lib.optional (!stdenv.isDarwin) xdg-utils; # Shamelessly appropriated from https://github.com/ncfavier/config. # Hopefully Naïm will not sue me for copyright infrigment. @@ -26,7 +29,7 @@ cmd=$1 shift case $cmd in - repl|eval|build|rev) + repl|eval|nix-build|rev) args=() flakeArgs=() for arg do case $arg in -w|--wip) @@ -39,10 +42,15 @@ set -- "''${args[@]}" ;;& compare) + if command -v xdg-open >/dev/null; then + open="xdg-open" + else + open="open" + fi input=$1 # shellcheck disable=SC1090 - . <(nix flake metadata --json nixfiles | jq -r --arg input "$input" ' - def browse($url): @sh "xdg-open \($url)"; + . <(nix flake metadata --json nixfiles | jq -r --arg open "$open" --arg input "$input" ' + def browse($url): @sh "$open \($url)"; .locks.nodes[$input] | if .locked.type == "github" then browse("https://github.com/\(.locked.owner)/\(.locked.repo)/compare/\(.locked.rev)...\(.original.ref // "master")") @@ -78,13 +86,14 @@ eval) exec nix eval "''${flakeArgs[@]}" -f ~/.nix-defexpr --json "$@" | jq -r . ;; - build) + nix-build) # https://github.com/NixOS/nix/issues/6661 exec nix-build --log-format bar-with-logs "''${flakeArgs[@]}" ~/.nix-defexpr -A "$@" ;; specialise) name=$1 shift + # Assumes that sudo is already configured. Has setuid baked in if needed and etc. exec sudo /run/current-system/specialisation/"$name"/bin/switch-to-configuration switch ;; revert) @@ -96,6 +105,7 @@ exec nix shell -v ".#$attr" "$@" -c home-manager-generation ;; @*) + # Assumes that hosts are configured in the OpenSSH configuration. host=''${cmd#@} hostname=$(ssh -q "$host" 'echo "$HOSTNAME"') exec nixos-rebuild -v --flake ".#$hostname" --target-host "$host" --use-remote-sudo "$@" @@ -130,13 +140,13 @@ if [[ $cur == @* ]]; then _known_hosts_real -a -- "$cur" else - __compreply -W 'compare update repl eval bld specialise revert home build build-vm test switch boot' + __compreply -W 'compare update repl eval nix-build specialise revert home boot build build-vm build-vm-with-bootloader dry-activate dry-build edit switch test' fi else case ''${words[1]} in compare|update|rev) __complete_nix_cmd "$cword" nix flake lock "$nixfiles" --update-input ;; - repl|eval|bld) + repl|eval|nix-build) compreply -W '-w --wip' ;;& repl) @@ -151,7 +161,7 @@ home) __complete_nix_cmd 2 nix shell "$nixfiles" ;; - build|switch) + switch) __complete_nix_cmd 2 nix build "$nixfiles" ;; esac fi @@ -161,5 +171,13 @@ in symlinkJoin { name = "nixfiles"; + paths = [bin bashCompletion]; + + meta = with lib; { + description = "A helper utility to manage NixOS configurations with Nix flakes"; + homepage = "https://git.azahi.cc/nixfiles"; + license = licenses.wtfpl; + maintainers = with maintainers; [azahi]; + }; } diff --git a/packages/throttled.nix b/packages/throttled.nix deleted file mode 100644 index 1c0f853..0000000 --- a/packages/throttled.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - fetchFromGitHub, - kmod, - python3Packages, - stdenv, -}: -stdenv.mkDerivation rec { - pname = "throttled"; - version = "git"; - - src = fetchFromGitHub { - owner = "erpalma"; - repo = pname; - rev = "1dd726672f0b11b813d4c7b63e0157becde7a013"; - hash = "sha256-0MsPp6y4r/uZB2SplKV+SAiJoxIs2jgOQmQoQQ2ZKwI="; - }; - - nativeBuildInputs = with python3Packages; [wrapPython]; - - pythonPath = - [kmod] - ++ (with python3Packages; [configparser dbus-python pygobject3]); - - installPhase = '' - runHook preInstall - - install -Dm755 -t $out/opt/throttled throttled.py - install -Dm644 -t $out/opt/throttled mmio.py - - runHook postInstall - ''; - - postFixup = '' - wrapPythonProgramsIn $out/opt/throttled "$out $pythonPath" - ''; -} -- cgit v1.2.3