about summary refs log tree commit diff
path: root/pkgs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/applications/audio/openmpt123/default.nix4
-rw-r--r--pkgs/applications/editors/android-studio/common.nix2
-rw-r--r--pkgs/applications/editors/apostrophe/default.nix6
-rw-r--r--pkgs/applications/graphics/xournalpp/default.nix4
-rw-r--r--pkgs/applications/misc/kanboard/default.nix4
-rw-r--r--pkgs/applications/misc/pwsafe/default.nix8
-rw-r--r--pkgs/applications/misc/sidequest/default.nix4
-rw-r--r--pkgs/applications/networking/browsers/chromium/upstream-info.nix6
-rw-r--r--pkgs/applications/networking/instant-messengers/psi-plus/default.nix17
-rw-r--r--pkgs/applications/networking/mailreaders/mblaze/default.nix8
-rw-r--r--pkgs/applications/networking/mumble/default.nix3
-rw-r--r--pkgs/applications/networking/newsreaders/quiterss/default.nix9
-rw-r--r--pkgs/applications/networking/remote/citrix-workspace/default.nix15
-rw-r--r--pkgs/applications/networking/syncthing/default.nix7
-rw-r--r--pkgs/applications/office/trilium/default.nix6
-rw-r--r--pkgs/applications/science/astronomy/stellarium/default.nix4
-rw-r--r--pkgs/applications/science/biology/mosdepth/default.nix8
-rw-r--r--pkgs/applications/science/chemistry/octopus/default.nix2
-rw-r--r--pkgs/applications/science/machine-learning/shogun/default.nix2
-rw-r--r--pkgs/applications/science/math/R/default.nix2
-rw-r--r--pkgs/applications/science/math/giac/default.nix2
-rw-r--r--pkgs/applications/science/math/gmsh/default.nix2
-rw-r--r--pkgs/applications/science/math/sage/sage-env.nix2
-rw-r--r--pkgs/applications/science/math/sage/sage-with-env.nix2
-rw-r--r--pkgs/applications/science/math/sage/sagelib.nix2
-rw-r--r--pkgs/applications/version-management/git-and-tools/thicket/default.nix14
-rw-r--r--pkgs/applications/video/kodi/default.nix4
-rw-r--r--pkgs/applications/window-managers/dwm/dwm-status.nix6
-rw-r--r--pkgs/applications/window-managers/i3/default.nix4
-rw-r--r--pkgs/build-support/alternatives/blas/default.nix16
-rw-r--r--pkgs/build-support/alternatives/lapack/default.nix14
-rw-r--r--pkgs/build-support/src-only/default.nix2
-rw-r--r--pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch4726
-rw-r--r--pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/default.nix11
-rw-r--r--pkgs/development/compilers/crystal/build-package.nix124
-rw-r--r--pkgs/development/compilers/crystal/crystal2nix.nix8
-rw-r--r--pkgs/development/compilers/julia/1.3.nix4
-rw-r--r--pkgs/development/compilers/julia/shared.nix4
-rw-r--r--pkgs/development/compilers/ldc/binary.nix41
-rw-r--r--pkgs/development/compilers/ldc/bootstrap.nix10
-rw-r--r--pkgs/development/compilers/ldc/default.nix174
-rw-r--r--pkgs/development/compilers/ldc/generic.nix143
-rw-r--r--pkgs/development/compilers/mint/default.nix27
-rw-r--r--pkgs/development/compilers/mint/shards.nix26
-rw-r--r--pkgs/development/interpreters/octave/default.nix6
-rw-r--r--pkgs/development/libraries/appstream-glib/default.nix4
-rw-r--r--pkgs/development/libraries/fflas-ffpack/default.nix2
-rw-r--r--pkgs/development/libraries/icu/65.nix4
-rw-r--r--pkgs/development/libraries/icu/66.nix4
-rw-r--r--pkgs/development/libraries/icu/base.nix3
-rw-r--r--pkgs/development/libraries/linbox/default.nix2
-rw-r--r--pkgs/development/libraries/qrupdate/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/arpack/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/ipopt/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/magma/default.nix11
-rw-r--r--pkgs/development/libraries/science/math/scalapack/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/scs/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/suitesparse/4.2.nix2
-rw-r--r--pkgs/development/libraries/science/math/suitesparse/4.4.nix2
-rw-r--r--pkgs/development/libraries/science/math/suitesparse/default.nix2
-rw-r--r--pkgs/development/libraries/science/math/superlu/default.nix2
-rw-r--r--pkgs/development/libraries/sundials/2.x.nix2
-rw-r--r--pkgs/development/libraries/sundials/default.nix2
-rw-r--r--pkgs/development/libraries/waylandpp/default.nix16
-rw-r--r--pkgs/development/ocaml-modules/lacaml/default.nix2
-rw-r--r--pkgs/development/ocaml-modules/owl/default.nix2
-rw-r--r--pkgs/development/python-modules/cvxopt/default.nix2
-rw-r--r--pkgs/development/python-modules/dotnetcore2/default.nix14
-rw-r--r--pkgs/development/python-modules/goobook/default.nix3
-rw-r--r--pkgs/development/python-modules/goobook/fix-build.patch32
-rw-r--r--pkgs/development/python-modules/google-api-python-client/default.nix4
-rw-r--r--pkgs/development/python-modules/matrix-nio/default.nix6
-rw-r--r--pkgs/development/python-modules/numpy/default.nix8
-rw-r--r--pkgs/development/python-modules/pulsectl/default.nix31
-rw-r--r--pkgs/development/python-modules/pulsectl/library-paths.patch22
-rw-r--r--pkgs/development/python-modules/pylatexenc/default.nix16
-rw-r--r--pkgs/development/python-modules/pyroma/default.nix21
-rw-r--r--pkgs/development/python-modules/pytest/4.nix14
-rw-r--r--pkgs/development/python-modules/simpleaudio/default.nix24
-rw-r--r--pkgs/development/tools/ameba/default.nix36
-rw-r--r--pkgs/development/tools/build-managers/shards/default.nix17
-rw-r--r--pkgs/development/tools/clj-kondo/default.nix4
-rw-r--r--pkgs/development/tools/continuous-integration/gitlab-runner/default.nix8
-rw-r--r--pkgs/development/tools/database/ephemeralpg/default.nix4
-rw-r--r--pkgs/development/tools/icr/default.nix34
-rw-r--r--pkgs/development/tools/icr/shards.nix8
-rw-r--r--pkgs/development/tools/metals/default.nix4
-rw-r--r--pkgs/development/tools/ocaml/merlin/default.nix4
-rw-r--r--pkgs/development/tools/scry/default.nix24
-rw-r--r--pkgs/development/web/lucky-cli/default.nix42
-rw-r--r--pkgs/development/web/lucky-cli/shard.lock5
-rw-r--r--pkgs/development/web/lucky-cli/shards.nix8
-rw-r--r--pkgs/development/web/shopify-themekit/default.nix25
-rw-r--r--pkgs/development/web/shopify-themekit/shopify-themekit_deps.nix300
-rw-r--r--pkgs/games/openrct2/default.nix15
-rw-r--r--pkgs/misc/cbeams/default.nix21
-rw-r--r--pkgs/misc/emulators/pcsx2/default.nix6
-rw-r--r--pkgs/misc/uboot/default.nix22
-rw-r--r--pkgs/os-specific/linux/kernel/hardened-patches.json24
-rw-r--r--pkgs/os-specific/linux/kernel/linux-4.19.nix4
-rw-r--r--pkgs/os-specific/linux/kernel/linux-5.4.nix4
-rw-r--r--pkgs/os-specific/linux/kernel/linux-5.5.nix4
-rw-r--r--pkgs/os-specific/linux/kernel/linux-5.6.nix4
-rw-r--r--pkgs/servers/mautrix-whatsapp/default.nix8
-rw-r--r--pkgs/servers/mpd/default.nix3
-rw-r--r--pkgs/servers/nosql/mongodb/mongodb.nix6
-rw-r--r--pkgs/servers/nosql/mongodb/v3_4.nix1
-rw-r--r--pkgs/servers/oauth2_proxy/default.nix15
-rw-r--r--pkgs/servers/oauth2_proxy/deps.nix550
-rw-r--r--pkgs/servers/tailscale/default.nix10
-rw-r--r--pkgs/shells/fish/default.nix3
-rw-r--r--pkgs/shells/oil/default.nix6
-rw-r--r--pkgs/tools/archivers/p7zip/default.nix11
-rw-r--r--pkgs/tools/graphics/spirv-cross/default.nix23
-rw-r--r--pkgs/tools/misc/hpl/default.nix2
-rw-r--r--pkgs/tools/misc/ili2c/default.nix4
-rw-r--r--pkgs/tools/networking/babeld/default.nix4
-rw-r--r--pkgs/tools/networking/cjdns/default.nix4
-rw-r--r--pkgs/tools/networking/ferm/default.nix20
-rw-r--r--pkgs/tools/networking/mu/default.nix4
-rw-r--r--pkgs/tools/networking/yggdrasil/default.nix4
-rw-r--r--pkgs/tools/package-management/nixpkgs-review/default.nix4
-rw-r--r--pkgs/tools/system/tre-command/default.nix4
-rw-r--r--pkgs/tools/text/transifex-client/default.nix6
-rw-r--r--pkgs/tools/typesetting/sile/default.nix4
-rw-r--r--pkgs/tools/virtualization/cri-tools/default.nix4
-rw-r--r--pkgs/top-level/aliases.nix1
-rw-r--r--pkgs/top-level/all-packages.nix21
-rw-r--r--pkgs/top-level/python-packages.nix8
-rw-r--r--pkgs/top-level/release-alternatives.nix6
130 files changed, 6499 insertions, 628 deletions
diff --git a/pkgs/applications/audio/openmpt123/default.nix b/pkgs/applications/audio/openmpt123/default.nix
index aebc7dc7baa7..de903bf32768 100644
--- a/pkgs/applications/audio/openmpt123/default.nix
+++ b/pkgs/applications/audio/openmpt123/default.nix
@@ -2,14 +2,14 @@
 , usePulseAudio ? config.pulseaudio or false, libpulseaudio }:
 
 let
-  version = "0.4.11";
+  version = "0.4.12";
 in stdenv.mkDerivation {
   pname = "openmpt123";
   inherit version;
 
   src = fetchurl {
     url = "https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-${version}+release.autotools.tar.gz";
-    sha256 = "1g96bpwh419s429wb387lkmhjsn3ldsjrzrb8h9p3wva5z6943i6";
+    sha256 = "0q2yf9g6hcwvr2nk3zggkscyf0np6i03q2g7fx10i2kcdr3n9k8c";
   };
 
   enableParallelBuilding = true;
diff --git a/pkgs/applications/editors/android-studio/common.nix b/pkgs/applications/editors/android-studio/common.nix
index 0625431462cb..1a6904b21768 100644
--- a/pkgs/applications/editors/android-studio/common.nix
+++ b/pkgs/applications/editors/android-studio/common.nix
@@ -39,6 +39,7 @@
 , nss
 , pciutils
 , pkgsi686Linux
+, ps
 , setxkbmap
 , stdenv
 , systemd
@@ -89,6 +90,7 @@ let
 
           # Runtime stuff
           git
+          ps
         ]}" \
         --prefix LD_LIBRARY_PATH : "${stdenv.lib.makeLibraryPath [
 
diff --git a/pkgs/applications/editors/apostrophe/default.nix b/pkgs/applications/editors/apostrophe/default.nix
index 623f86a61c2c..391a87345632 100644
--- a/pkgs/applications/editors/apostrophe/default.nix
+++ b/pkgs/applications/editors/apostrophe/default.nix
@@ -11,14 +11,14 @@ let
 
 in stdenv.mkDerivation rec {
   pname = "apostrophe";
-  version = "unstable-2020-03-29";
+  version = "2.2.0.2";
 
   src = fetchFromGitLab {
     owner  = "somas";
     repo   = pname;
     domain = "gitlab.gnome.org";
-    rev    = "219fa8976e3b8a6f0cea15cfefe4e336423f2bdb";
-    sha256 = "192n5qs3x6rx62mqxd6wajwm453pns8kjyz5v3xc891an6bm1kqx";
+    rev    = "v${version}";
+    sha256 = "13wvfkg0jw9mayd9ifzkqnhf8fmfjgr1lsj4niqbyrw130y9r9f6";
   };
 
   nativeBuildInputs = [ meson ninja cmake pkgconfig desktop-file-utils
diff --git a/pkgs/applications/graphics/xournalpp/default.nix b/pkgs/applications/graphics/xournalpp/default.nix
index 65aa17e3b4ee..ba396bfd92c5 100644
--- a/pkgs/applications/graphics/xournalpp/default.nix
+++ b/pkgs/applications/graphics/xournalpp/default.nix
@@ -22,13 +22,13 @@
 
 stdenv.mkDerivation rec {
   pname = "xournalpp";
-  version = "1.0.17";
+  version = "1.0.18";
 
   src = fetchFromGitHub {
     owner = "xournalpp";
     repo = pname;
     rev = version;
-    sha256 = "0xw2mcgnm4sa9hrhfgp669lfypw97drxjmz5w8i5whaprpvmkxzw";
+    sha256 = "0a9ygbmd4dwgck3k8wsrm2grynqa0adb12wwspzmzvpisbadffjy";
   };
 
   nativeBuildInputs = [ cmake gettext pkgconfig wrapGAppsHook ];
diff --git a/pkgs/applications/misc/kanboard/default.nix b/pkgs/applications/misc/kanboard/default.nix
index 9e2857c960fc..e6193d435639 100644
--- a/pkgs/applications/misc/kanboard/default.nix
+++ b/pkgs/applications/misc/kanboard/default.nix
@@ -2,13 +2,13 @@
 
 stdenv.mkDerivation rec {
   pname = "kanboard";
-  version = "1.2.13";
+  version = "1.2.14";
 
   src = fetchFromGitHub {
     owner = "kanboard";
     repo = "kanboard";
     rev = "v${version}";
-    sha256 = "0mm5sx323v1rwykd1dhvk4d3ipgvgvi3wvhrlavbja3lgay3mdwk";
+    sha256 = "11bwajzidnyagdyip7i8rwni1f66acv0k4lybdm0mc4195anivjh";
   };
 
   dontBuild = true;
diff --git a/pkgs/applications/misc/pwsafe/default.nix b/pkgs/applications/misc/pwsafe/default.nix
index 91845abc8b21..43197c6bf276 100644
--- a/pkgs/applications/misc/pwsafe/default.nix
+++ b/pkgs/applications/misc/pwsafe/default.nix
@@ -1,25 +1,25 @@
 { stdenv, fetchFromGitHub, cmake, pkgconfig, zip, gettext, perl
-, wxGTK30, libXext, libXi, libXt, libXtst, xercesc
+, wxGTK31, libXext, libXi, libXt, libXtst, xercesc
 , qrencode, libuuid, libyubikey, yubikey-personalization
 , curl, openssl, file
 }:
 
 stdenv.mkDerivation rec {
   pname = "pwsafe";
-  version = "1.09.0";
+  version = "3.52.0";
 
   src = fetchFromGitHub {
     owner = pname;
     repo = pname;
     rev = "${version}";
-    sha256 = "0dmazm95d53wq74qvsjvhl7r6fr4dv11nzf8sgdy47nyxv06xs1b";
+    sha256 = "1ka7xsl63v0559fzf3pwc1iqr37gwr4vq5iaxa2hzar2g28hsxvh";
   };
 
   nativeBuildInputs = [ 
     cmake gettext perl pkgconfig zip
   ];
   buildInputs = [
-    libXext libXi libXt libXtst wxGTK30
+    libXext libXi libXt libXtst wxGTK31
     curl qrencode libuuid openssl xercesc
     libyubikey yubikey-personalization
     file
diff --git a/pkgs/applications/misc/sidequest/default.nix b/pkgs/applications/misc/sidequest/default.nix
index 3638a1d18809..6c55c3157f5c 100644
--- a/pkgs/applications/misc/sidequest/default.nix
+++ b/pkgs/applications/misc/sidequest/default.nix
@@ -1,7 +1,7 @@
 { stdenv, lib, fetchurl, buildFHSUserEnv, makeDesktopItem, makeWrapper, atomEnv, libuuid, at-spi2-atk, icu, openssl, zlib }:
 	let
 		pname = "sidequest";
-		version = "0.8.7";
+		version = "0.10.2";
 
 		desktopItem = makeDesktopItem rec {
 			name = "SideQuest";
@@ -16,7 +16,7 @@
 
 			src = fetchurl {
 				url = "https://github.com/the-expanse/SideQuest/releases/download/v${version}/SideQuest-${version}.tar.xz";
-				sha256 = "1hbr6ml689zq4k3mzmn2xcn4r4dy717rgq3lgm32pzwgy5w92i2j";
+				sha256 = "1vfxn4gx5b138gj6nk4w3jlp2l56cqpb8hq2kn5mrf4dhjii8n88";
 			};
 
 			buildInputs = [ makeWrapper ];
diff --git a/pkgs/applications/networking/browsers/chromium/upstream-info.nix b/pkgs/applications/networking/browsers/chromium/upstream-info.nix
index cf542faa8a1e..77505b47d857 100644
--- a/pkgs/applications/networking/browsers/chromium/upstream-info.nix
+++ b/pkgs/applications/networking/browsers/chromium/upstream-info.nix
@@ -11,8 +11,8 @@
     version = "84.0.4115.5";
   };
   stable = {
-    sha256 = "0hsxxw7fm1p8g53msqb644v8vr4cpvjmpln444c2268rm43yik17";
-    sha256bin64 = "0ap7flrw3h885454fa2r7psa4sh8567ql7v7x96q11gh9gjrdvp3";
-    version = "81.0.4044.113";
+    sha256 = "0ahqh3vmzbpai4xwn7qybgw9phc8ssjdvfc7384mxqk9swqgv7qg";
+    sha256bin64 = "0gpgim244594m35qwf625blwdqgjbp4qr846wq75a9a9zqwqs05w";
+    version = "81.0.4044.122";
   };
 }
diff --git a/pkgs/applications/networking/instant-messengers/psi-plus/default.nix b/pkgs/applications/networking/instant-messengers/psi-plus/default.nix
index 010c06e0c2ac..bd9d706d4e30 100644
--- a/pkgs/applications/networking/instant-messengers/psi-plus/default.nix
+++ b/pkgs/applications/networking/instant-messengers/psi-plus/default.nix
@@ -6,26 +6,15 @@
 
 stdenv.mkDerivation rec {
   pname = "psi-plus";
-  version = "1.4.984";
+  version = "1.4.1086";
 
   src = fetchFromGitHub {
     owner = "psi-plus";
     repo = "psi-plus-snapshots";
     rev = version;
-    sha256 = "1nii2nfi37i6mn79xmygscmm8ax75ky244wxkzlga0ya8i8wfjh7";
+    sha256 = "0war4hbjs1m7ll6rvpl3lj44lb0p5fi0g2siinnxpjffz2ydi97p";
   };
 
-  resources = fetchFromGitHub {
-    owner = "psi-plus";
-    repo = "resources";
-    rev = "2f1c12564f7506bf902a26040fdb47ead4df6b73";
-    sha256 = "1dgm9k052fq7f2bpx13kchg7sxb227dkn115lyspzvhnhprnypz2";
-  };
-
-  postUnpack = ''
-    cp -a "${resources}/iconsets" "$sourceRoot"
-  '';
-
   cmakeFlags = [
     "-DENABLE_PLUGINS=ON"
   ];
@@ -38,8 +27,6 @@ stdenv.mkDerivation rec {
     libgcrypt libotr html-tidy libgpgerror libsignal-protocol-c
   ];
 
-  enableParallelBuilding = true;
-
   meta = with stdenv.lib; {
     description = "XMPP (Jabber) client";
     maintainers = with maintainers; [ orivej misuzu ];
diff --git a/pkgs/applications/networking/mailreaders/mblaze/default.nix b/pkgs/applications/networking/mailreaders/mblaze/default.nix
index 82550cf43ccf..fc9001e59e32 100644
--- a/pkgs/applications/networking/mailreaders/mblaze/default.nix
+++ b/pkgs/applications/networking/mailreaders/mblaze/default.nix
@@ -1,10 +1,10 @@
-{ stdenv, fetchFromGitHub, fetchpatch, libiconv }:
+{ stdenv, lib, fetchFromGitHub, fetchpatch, libiconv, ruby ? null }:
 
 stdenv.mkDerivation rec {
   pname = "mblaze";
   version = "0.5.1";
 
-  buildInputs = stdenv.lib.optionals stdenv.isDarwin [ libiconv ];
+  buildInputs = [ ruby ] ++ lib.optionals stdenv.isDarwin [ libiconv ];
 
   src = fetchFromGitHub {
     owner = "chneukirchen";
@@ -24,9 +24,11 @@ stdenv.mkDerivation rec {
 
   postInstall = ''
     install -Dm644 -t $out/share/zsh/site-functions contrib/_mblaze
+  '' + lib.optionalString (ruby != null) ''
+    install -Dt $out/bin contrib/msuck contrib/mblow
   '';
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     homepage = "https://github.com/chneukirchen/mblaze";
     description = "Unix utilities to deal with Maildir";
     license = licenses.cc0;
diff --git a/pkgs/applications/networking/mumble/default.nix b/pkgs/applications/networking/mumble/default.nix
index 4408994ba8f0..633d6e63dce9 100644
--- a/pkgs/applications/networking/mumble/default.nix
+++ b/pkgs/applications/networking/mumble/default.nix
@@ -6,6 +6,7 @@
 , speechdSupport ? false, speechd ? null
 , pulseSupport ? false, libpulseaudio ? null
 , iceSupport ? false, zeroc-ice ? null
+, nixosTests
 }:
 
 assert jackSupport -> libjack2 != null;
@@ -63,6 +64,8 @@ let
 
     enableParallelBuilding = true;
 
+    passthru.tests.connectivity = nixosTests.mumble;
+
     meta = {
       description = "Low-latency, high quality voice chat software";
       homepage = "https://mumble.info";
diff --git a/pkgs/applications/networking/newsreaders/quiterss/default.nix b/pkgs/applications/networking/newsreaders/quiterss/default.nix
index 6fa4dc19799c..1cc4be8cb27a 100644
--- a/pkgs/applications/networking/newsreaders/quiterss/default.nix
+++ b/pkgs/applications/networking/newsreaders/quiterss/default.nix
@@ -1,19 +1,19 @@
-{ stdenv, fetchFromGitHub, qmake, pkgconfig, wrapQtAppsHook
+{ stdenv, fetchFromGitHub, qmake, pkg-config, wrapQtAppsHook
 , qtbase, qttools, qtwebkit, sqlite
 }:
 
 stdenv.mkDerivation rec {
   pname = "quiterss";
-  version = "0.19.3";
+  version = "0.19.4";
 
   src = fetchFromGitHub {
     owner = "QuiteRSS";
     repo = "quiterss";
     rev = version;
-    sha256 = "06m5mhzxvv8q2adaqcrar3sx2c1hc89h2i0qfjxmirfc5z67hdw2";
+    sha256 = "1cgvl67vhn5y7bj5gbjbgk26bhb0196bgrgsp3r5fmrislarj8s6";
   };
 
-  nativeBuildInputs = [ qmake pkgconfig wrapQtAppsHook ];
+  nativeBuildInputs = [ qmake pkg-config wrapQtAppsHook ];
   buildInputs = [ qtbase qttools qtwebkit sqlite.dev ];
 
   meta = with stdenv.lib; {
@@ -23,6 +23,7 @@ stdenv.mkDerivation rec {
       written on Qt/C++
     '';
     homepage = "https://quiterss.org";
+    changelog = "https://github.com/QuiteRSS/quiterss/blob/${version}/CHANGELOG";
     license = licenses.gpl3;
     platforms = platforms.linux;
     maintainers = with maintainers; [ primeos ];
diff --git a/pkgs/applications/networking/remote/citrix-workspace/default.nix b/pkgs/applications/networking/remote/citrix-workspace/default.nix
index 0936f4e75521..a62b1bf5ee15 100644
--- a/pkgs/applications/networking/remote/citrix-workspace/default.nix
+++ b/pkgs/applications/networking/remote/citrix-workspace/default.nix
@@ -24,7 +24,7 @@
 , gtk_engines
 , alsaLib
 , zlib
-, version ? "19.12.0"
+, version ? "20.04.0"
 }:
 
 let
@@ -71,7 +71,18 @@ let
         x86hash   = "07rfp90ksnvr8zv7ix7f0z6a59n48s7bd4kqbzilfwxgs4ddqmcy";
         x64suffix = "19";
         x86suffix = "19";
-        homepage  = "https://www.citrix.com/de-de/downloads/workspace-app/linux/workspace-app-for-linux-latest.html";
+        homepage  = "https://www.citrix.com/downloads/workspace-app/legacy-workspace-app-for-linux/workspace-app-for-linux-1912.html";
+      };
+
+      "20.04.0" = {
+        major     = "20";
+        minor     = "04";
+        patch     = "0";
+        x64hash   = "E923592216F9541173846F932784E6C062CB09C9E8858219C7489607BF82A0FB";
+        x86hash   = "A2E2E1882723DA6796E68916B3BB2B44DD575A83DEB03CA90A262F6C81B1A53F";
+        x64suffix = "21";
+        x86suffix = "21";
+        homepage  = "https://www.citrix.com/downloads/workspace-app/linux/workspace-app-for-linux-latest.html";
       };
     };
 
diff --git a/pkgs/applications/networking/syncthing/default.nix b/pkgs/applications/networking/syncthing/default.nix
index 31cf76be5efc..94fec82fdf72 100644
--- a/pkgs/applications/networking/syncthing/default.nix
+++ b/pkgs/applications/networking/syncthing/default.nix
@@ -1,4 +1,4 @@
-{ buildGoModule, stdenv, lib, procps, fetchFromGitHub }:
+{ buildGoModule, stdenv, lib, procps, fetchFromGitHub, nixosTests }:
 
 let
   common = { stname, target, postInstall ? "" }:
@@ -35,6 +35,11 @@ let
 
       inherit postInstall;
 
+      passthru.tests = with nixosTests; {
+        init = syncthing-init;
+        relay = syncthing-relay;
+      };
+
       meta = with lib; {
         homepage = "https://www.syncthing.net/";
         description = "Open Source Continuous File Synchronization";
diff --git a/pkgs/applications/office/trilium/default.nix b/pkgs/applications/office/trilium/default.nix
index 18c512874db4..967f91d962e1 100644
--- a/pkgs/applications/office/trilium/default.nix
+++ b/pkgs/applications/office/trilium/default.nix
@@ -19,7 +19,7 @@ let
     maintainers = with maintainers; [ emmanuelrosa dtzWill kampka ];
   };
 
-  version = "0.40.5";
+  version = "0.40.7";
 
 in {
   
@@ -30,7 +30,7 @@ in {
 
     src = fetchurl {
       url = "https://github.com/zadam/trilium/releases/download/v${version}/trilium-linux-x64-${version}.tar.xz";
-      sha256 = "02hmfgv8viy1hn2ix4b0gdzbcj7piddsmjdnb0b5hpwahqrikiyi";
+      sha256 = "0xi3bb0kbphbgpk2wlsad509g0hwwb259q2vkv0kgyr4i4wcyc1f";
     };
   
     # Fetch from source repo, no longer included in release.
@@ -78,7 +78,7 @@ in {
 
     src = fetchurl {
       url = "https://github.com/zadam/trilium/releases/download/v${version}/trilium-linux-x64-server-${version}.tar.xz";
-      sha256 = "00b7qx2h26qrdhw2a7y0irhbr442yynnzpm1pz55hi33zpckbrc7";
+      sha256 = "15bspngnnbq6mhp1f82j9hccg0ymhm6i4rddpgz3n7dw5wxdj0sm";
     };
 
     nativeBuildInputs = [
diff --git a/pkgs/applications/science/astronomy/stellarium/default.nix b/pkgs/applications/science/astronomy/stellarium/default.nix
index a0cd535f362c..7ef7776c0fe8 100644
--- a/pkgs/applications/science/astronomy/stellarium/default.nix
+++ b/pkgs/applications/science/astronomy/stellarium/default.nix
@@ -6,13 +6,13 @@
 
 mkDerivation rec {
   pname = "stellarium";
-  version = "0.20.0";
+  version = "0.20.1";
 
   src = fetchFromGitHub {
     owner = "Stellarium";
     repo = "stellarium";
     rev = "v${version}";
-    sha256 = "1732dxkgyqd4xf0ry7v930vcbv60l8iry596869z1d47j2piibs4";
+    sha256 = "1x8svan03k1x9jwqflimbpj7jpg6mjrbz26bg1sbhsqdlc8rbhky";
   };
 
   nativeBuildInputs = [ cmake perl wrapQtAppsHook ];
diff --git a/pkgs/applications/science/biology/mosdepth/default.nix b/pkgs/applications/science/biology/mosdepth/default.nix
index 569c63afa7a1..21af5b82207b 100644
--- a/pkgs/applications/science/biology/mosdepth/default.nix
+++ b/pkgs/applications/science/biology/mosdepth/default.nix
@@ -4,8 +4,8 @@ let
   hts-nim = fetchFromGitHub {
     owner = "brentp";
     repo = "hts-nim";
-    rev = "v0.2.14";
-    sha256 = "0d1z4b6mrppmz3hgkxd4wcy79w68icvhi7q7n3m2k17n8f3xbdx3";
+    rev = "v0.3.4";
+    sha256 = "0670phk1bq3l9j2zaa8i5wcpc5dyfrc0l2a6c21g0l2mmdczffa7";
   };
 
   docopt = fetchFromGitHub {
@@ -17,13 +17,13 @@ let
 
 in stdenv.mkDerivation rec {
   pname = "mosdepth";
-  version = "0.2.6";
+  version = "0.2.9";
 
   src = fetchFromGitHub {
     owner = "brentp";
     repo = "mosdepth";
     rev = "v${version}";
-    sha256 = "0i9pl9lsli3y84ygxanrr525gfg8fs9h481944cbzsmqmbldwvgk";
+    sha256 = "01gm9gj2x2zs4yx6wk761fi1papi7qr3gp4ln1kkn8n2f9y9h849";
   };
 
   buildInputs = [ nim ];
diff --git a/pkgs/applications/science/chemistry/octopus/default.nix b/pkgs/applications/science/chemistry/octopus/default.nix
index f30954367cf7..adb31d326509 100644
--- a/pkgs/applications/science/chemistry/octopus/default.nix
+++ b/pkgs/applications/science/chemistry/octopus/default.nix
@@ -2,7 +2,7 @@
 , libyaml, libxc, fftw, blas, lapack, gsl, netcdf, arpack, autoreconfHook
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "octopus";
diff --git a/pkgs/applications/science/machine-learning/shogun/default.nix b/pkgs/applications/science/machine-learning/shogun/default.nix
index 33871df87f33..031ca55a0480 100644
--- a/pkgs/applications/science/machine-learning/shogun/default.nix
+++ b/pkgs/applications/science/machine-learning/shogun/default.nix
@@ -13,7 +13,7 @@
 assert pythonSupport -> pythonPackages != null;
 assert opencvSupport -> opencv != null;
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 let
   pname = "shogun";
diff --git a/pkgs/applications/science/math/R/default.nix b/pkgs/applications/science/math/R/default.nix
index 836ce004fff2..617a18265371 100644
--- a/pkgs/applications/science/math/R/default.nix
+++ b/pkgs/applications/science/math/R/default.nix
@@ -9,7 +9,7 @@
 , static ? false
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   name = "R-3.6.3";
diff --git a/pkgs/applications/science/math/giac/default.nix b/pkgs/applications/science/math/giac/default.nix
index be3c1e6dcc88..ea9c921f19e1 100644
--- a/pkgs/applications/science/math/giac/default.nix
+++ b/pkgs/applications/science/math/giac/default.nix
@@ -5,7 +5,7 @@
 }:
 
 assert enableGUI -> libGLU != null && libGL != null && xorg != null && fltk != null;
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "giac${lib.optionalString enableGUI "-with-xcas"}";
diff --git a/pkgs/applications/science/math/gmsh/default.nix b/pkgs/applications/science/math/gmsh/default.nix
index 8ece2e7819cf..946beff8003f 100644
--- a/pkgs/applications/science/math/gmsh/default.nix
+++ b/pkgs/applications/science/math/gmsh/default.nix
@@ -1,7 +1,7 @@
 { stdenv, fetchurl, cmake, blas, lapack, gfortran, gmm, fltk, libjpeg
 , zlib, libGL, libGLU, xorg, opencascade-occt }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "gmsh";
diff --git a/pkgs/applications/science/math/sage/sage-env.nix b/pkgs/applications/science/math/sage/sage-env.nix
index c0dfeef1119b..626e1bf1ea92 100644
--- a/pkgs/applications/science/math/sage/sage-env.nix
+++ b/pkgs/applications/science/math/sage/sage-env.nix
@@ -54,7 +54,7 @@
 , less
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 # This generates a `sage-env` shell file that will be sourced by sage on startup.
 # It sets up various environment variables, telling sage where to find its
diff --git a/pkgs/applications/science/math/sage/sage-with-env.nix b/pkgs/applications/science/math/sage/sage-with-env.nix
index 77bc65c2be12..87c1e07f5307 100644
--- a/pkgs/applications/science/math/sage/sage-with-env.nix
+++ b/pkgs/applications/science/math/sage/sage-with-env.nix
@@ -23,7 +23,7 @@
 }:
 
 # lots of segfaults with (64 bit) blas
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 # Wrapper that combined `sagelib` with `sage-env` to produce an actually
 # executable sage. No tests are run yet and no documentation is built.
diff --git a/pkgs/applications/science/math/sage/sagelib.nix b/pkgs/applications/science/math/sage/sagelib.nix
index 92b4e8efa2ec..830d806a8bcd 100644
--- a/pkgs/applications/science/math/sage/sagelib.nix
+++ b/pkgs/applications/science/math/sage/sagelib.nix
@@ -53,7 +53,7 @@
 , pplpy
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 # This is the core sage python package. Everything else is just wrappers gluing
 # stuff together. It is not very useful on its own though, since it will not
diff --git a/pkgs/applications/version-management/git-and-tools/thicket/default.nix b/pkgs/applications/version-management/git-and-tools/thicket/default.nix
index 42819043d58b..4a02baa465c6 100644
--- a/pkgs/applications/version-management/git-and-tools/thicket/default.nix
+++ b/pkgs/applications/version-management/git-and-tools/thicket/default.nix
@@ -1,9 +1,12 @@
 { lib
 , fetchFromGitHub
-, crystal
+, crystal_0_33
 }:
 
-crystal.buildCrystalPackage rec {
+let
+  crystal = crystal_0_33;
+
+in crystal.buildCrystalPackage rec {
   pname = "thicket";
   version = "0.1.3";
 
@@ -14,13 +17,18 @@ crystal.buildCrystalPackage rec {
     sha256 = "0hkmmssiwipx373d0zw9a2yn72gqzqzcvwkqbs522m5adz6qmkzw";
   };
 
+  format = "shards";
+
   shardsFile = ./shards.nix;
   crystalBinaries.thicket.src = "src/thicket.cr";
 
+  # there is one test that tries to clone a repo
+  doCheck = false;
+
   meta = with lib; {
     description = "A better one-line git log";
     homepage = "https://github.com/taylorthurlow/thicket";
     license = licenses.mit;
     maintainers = with maintainers; [ filalex77 ];
   };
-}
\ No newline at end of file
+}
diff --git a/pkgs/applications/video/kodi/default.nix b/pkgs/applications/video/kodi/default.nix
index d13dd3201a32..2354ba0f4090 100644
--- a/pkgs/applications/video/kodi/default.nix
+++ b/pkgs/applications/video/kodi/default.nix
@@ -183,7 +183,7 @@ in stdenv.mkDerivation {
     ++ lib.optional  usbSupport      libusb
     ++ lib.optional  vdpauSupport    libvdpau
     ++ lib.optionals useWayland [
-      wayland waylandpp
+      wayland waylandpp.dev
       # Not sure why ".dev" is needed here, but CMake doesn't find libxkbcommon otherwise
       libxkbcommon.dev
     ]
@@ -200,7 +200,7 @@ in stdenv.mkDerivation {
       which
       pkgconfig gnumake
       autoconf automake libtool # still needed for some components. Check if that is the case with 19.0
-    ] ++ lib.optionals useWayland [ wayland-protocols ];
+    ] ++ lib.optionals useWayland [ wayland-protocols waylandpp.bin ];
 
     cmakeFlags = [
       "-Dlibdvdcss_URL=${libdvdcss.src}"
diff --git a/pkgs/applications/window-managers/dwm/dwm-status.nix b/pkgs/applications/window-managers/dwm/dwm-status.nix
index 01887b3bcf16..568258ee2c40 100644
--- a/pkgs/applications/window-managers/dwm/dwm-status.nix
+++ b/pkgs/applications/window-managers/dwm/dwm-status.nix
@@ -9,19 +9,19 @@ in
 
 rustPlatform.buildRustPackage rec {
   pname = "dwm-status";
-  version = "1.6.3";
+  version = "1.6.4";
 
   src = fetchFromGitHub {
     owner = "Gerschtli";
     repo = "dwm-status";
     rev = version;
-    sha256 = "02sprsr7822ynkwpf3xdgmkdrgkw3vgijhlh65bayiv3b5lwb54n";
+    sha256 = "05dhd2gy7ysrnchdimrdd7jvzs1db9fyrk4ci7850jhrgavfd7c4";
   };
 
   nativeBuildInputs = [ makeWrapper pkgconfig ];
   buildInputs = [ dbus gdk-pixbuf libnotify xorg.libX11 ];
 
-  cargoSha256 = "0xybd6110b29ghl66kxfs64704qlhnn9jb5vl7lfk9sv62cs564i";
+  cargoSha256 = "0zkbps8vsjcvy7x0sgb07kacszi57dlyq8j6ia6yy0jyqnvlaqa7";
 
   postInstall = lib.optionalString (bins != [])  ''
     wrapProgram $out/bin/dwm-status --prefix "PATH" : "${stdenv.lib.makeBinPath bins}"
diff --git a/pkgs/applications/window-managers/i3/default.nix b/pkgs/applications/window-managers/i3/default.nix
index fd964215d455..eec7d88dbc72 100644
--- a/pkgs/applications/window-managers/i3/default.nix
+++ b/pkgs/applications/window-managers/i3/default.nix
@@ -5,11 +5,11 @@
 
 stdenv.mkDerivation rec {
   pname = "i3";
-  version = "4.18";
+  version = "4.18.1";
 
   src = fetchurl {
     url = "https://i3wm.org/downloads/${pname}-${version}.tar.bz2";
-    sha256 = "0dv5g8ycfmijxfjyw8hzsxaf80v09lb73zh7x2vszy78h3amifqz";
+    sha256 = "0z709cianlzw0x0qwq4361347354xd9ckj1v7vjvhb1zh3x91gws";
   };
 
   nativeBuildInputs = [ which pkgconfig makeWrapper ];
diff --git a/pkgs/build-support/alternatives/blas/default.nix b/pkgs/build-support/alternatives/blas/default.nix
index 36708ce8841a..8bba49b45504 100644
--- a/pkgs/build-support/alternatives/blas/default.nix
+++ b/pkgs/build-support/alternatives/blas/default.nix
@@ -1,7 +1,7 @@
 { lib, stdenv
 , lapack-reference, openblasCompat, openblas
-, is64bit ? false
-, blasProvider ? if is64bit then openblas else openblasCompat }:
+, isILP64 ? false
+, blasProvider ? if isILP64 then openblas else openblasCompat }:
 
 let
   blasFortranSymbols = [
@@ -31,12 +31,12 @@ let
                        else stdenv.hostPlatform.extensions.sharedLibrary;
 
 
-  is64bit = blasProvider.blas64 or false;
+  isILP64 = blasProvider.blas64 or false;
   blasImplementation = lib.getName blasProvider;
 
 in
 
-assert is64bit -> (blasImplementation == "openblas" && blasProvider.blas64) || blasImplementation == "mkl";
+assert isILP64 -> (blasImplementation == "openblas" && blasProvider.blas64) || blasImplementation == "mkl";
 
 stdenv.mkDerivation {
   pname = "blas";
@@ -49,7 +49,7 @@ stdenv.mkDerivation {
   };
 
   passthru = {
-    inherit is64bit;
+    inherit isILP64;
     provider = blasProvider;
     implementation = blasImplementation;
   };
@@ -58,6 +58,8 @@ stdenv.mkDerivation {
   dontConfigure = true;
   unpackPhase = "src=$PWD";
 
+  dontPatchELF = true;
+
   installPhase = (''
   mkdir -p $out/lib $dev/include $dev/lib/pkgconfig
 
@@ -132,6 +134,8 @@ Libs: -L$out/lib -lcblas
 EOF
 '' + stdenv.lib.optionalString (blasImplementation == "mkl") ''
   mkdir -p $out/nix-support
-  echo 'export MKL_INTERFACE_LAYER=${lib.optionalString is64bit "I"}LP64,GNU' > $out/nix-support/setup-hook
+  echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
+  ln -s $out/lib/libblas${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
+  ln -sf ${blasProvider}/include/* $dev/include
 '');
 }
diff --git a/pkgs/build-support/alternatives/lapack/default.nix b/pkgs/build-support/alternatives/lapack/default.nix
index 24c339042a2f..e260ad1bd931 100644
--- a/pkgs/build-support/alternatives/lapack/default.nix
+++ b/pkgs/build-support/alternatives/lapack/default.nix
@@ -1,7 +1,7 @@
 { lib, stdenv
 , lapack-reference, openblasCompat, openblas
-, is64bit ? false
-, lapackProvider ? if is64bit then openblas else openblasCompat }:
+, isILP64 ? false
+, lapackProvider ? if isILP64 then openblas else openblasCompat }:
 
 let
 
@@ -14,7 +14,7 @@ let
 
 in
 
-assert is64bit -> (lapackImplementation == "openblas" && lapackProvider.blas64) || lapackImplementation == "mkl";
+assert isILP64 -> (lapackImplementation == "openblas" && lapackProvider.blas64) || lapackImplementation == "mkl";
 
 stdenv.mkDerivation {
   pname = "lapack";
@@ -27,7 +27,7 @@ stdenv.mkDerivation {
   };
 
   passthru = {
-    inherit is64bit;
+    inherit isILP64;
     provider = lapackProvider;
     implementation = lapackImplementation;
   };
@@ -36,6 +36,8 @@ stdenv.mkDerivation {
   dontConfigure = true;
   unpackPhase = "src=$PWD";
 
+  dontPatchELF = true;
+
   installPhase = (''
   mkdir -p $out/lib $dev/include $dev/lib/pkgconfig
 
@@ -106,6 +108,8 @@ Libs: -L$out/lib -llapacke
 EOF
 '' + stdenv.lib.optionalString (lapackImplementation == "mkl") ''
   mkdir -p $out/nix-support
-  echo 'export MKL_INTERFACE_LAYER=${lib.optionalString is64bit "I"}LP64,GNU' > $out/nix-support/setup-hook
+  echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
+  ln -s $out/lib/liblapack${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
+  ln -sf ${lapackProvider}/include/* $dev/include
 '');
 }
diff --git a/pkgs/build-support/src-only/default.nix b/pkgs/build-support/src-only/default.nix
index c2f7cfb93998..a93b36480908 100644
--- a/pkgs/build-support/src-only/default.nix
+++ b/pkgs/build-support/src-only/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, name, src, patches ? [], buildInputs ? [] }:
+{stdenv, name, src, patches ? [], buildInputs ? [], ...}: 
 stdenv.mkDerivation {
   inherit src buildInputs patches name;
   installPhase = "cp -r . $out";
diff --git a/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch b/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch
new file mode 100644
index 000000000000..c4d6d8574a53
--- /dev/null
+++ b/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/207.patch
@@ -0,0 +1,4726 @@
+From 20228e34bf97f67b1dd542a22e92cd90f0db5c72 Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Thu, 9 Apr 2020 16:30:16 +0300
+Subject: [PATCH 1/8] added a single namespace
+
+---
+ meson.build                                   |  14 +-
+ src/DateIterator.vala                         |  82 -----
+ src/DateRange.vala                            |  66 ----
+ src/Indicator.vala                            | 341 +++++++++---------
+ .../calendar => Models}/CalendarModel.vala    |   4 +-
+ src/Services/TimeManager.vala                 | 230 ++++++------
+ src/Util/DateIterator.vala                    |  84 +++++
+ src/Util/DateRange.vala                       |  68 ++++
+ src/{Widgets/calendar => Util}/Util.vala      |   8 +-
+ src/Widgets/CalendarView.vala                 | 185 ++++++++++
+ src/Widgets/EventRow.vala                     | 184 +++++-----
+ src/Widgets/{calendar => }/Grid.vala          |  12 +-
+ src/Widgets/GridDay.vala                      | 180 +++++++++
+ src/Widgets/PanelLabel.vala                   |  80 ++--
+ src/Widgets/calendar/CalendarView.vala        | 183 ----------
+ src/Widgets/calendar/GridDay.vala             | 178 ---------
+ 16 files changed, 957 insertions(+), 942 deletions(-)
+ delete mode 100644 src/DateIterator.vala
+ delete mode 100644 src/DateRange.vala
+ rename src/{Widgets/calendar => Models}/CalendarModel.vala (99%)
+ create mode 100644 src/Util/DateIterator.vala
+ create mode 100644 src/Util/DateRange.vala
+ rename src/{Widgets/calendar => Util}/Util.vala (96%)
+ create mode 100644 src/Widgets/CalendarView.vala
+ rename src/Widgets/{calendar => }/Grid.vala (95%)
+ create mode 100644 src/Widgets/GridDay.vala
+ delete mode 100644 src/Widgets/calendar/CalendarView.vala
+ delete mode 100644 src/Widgets/calendar/GridDay.vala
+
+diff --git a/meson.build b/meson.build
+index 2555723..b44c5bd 100644
+--- a/meson.build
++++ b/meson.build
+@@ -39,16 +39,16 @@ endif
+ shared_module(
+     meson.project_name(),
+     gresource,
+-    'src/DateIterator.vala',
+-    'src/DateRange.vala',
+     'src/Indicator.vala',
++    'src/Util/DateIterator.vala',
++    'src/Util/DateRange.vala',
++    'src/Util/Util.vala',
++    'src/Models/CalendarModel.vala',
++    'src/Widgets/CalendarView.vala',
+     'src/Widgets/EventRow.vala',
++    'src/Widgets/Grid.vala',
++    'src/Widgets/GridDay.vala',
+     'src/Widgets/PanelLabel.vala',
+-    'src/Widgets/calendar/CalendarModel.vala',
+-    'src/Widgets/calendar/CalendarView.vala',
+-    'src/Widgets/calendar/Grid.vala',
+-    'src/Widgets/calendar/GridDay.vala',
+-    'src/Widgets/calendar/Util.vala',
+     'src/Services/TimeManager.vala',
+     dependencies: [
+         dependency('glib-2.0'),
+diff --git a/src/DateIterator.vala b/src/DateIterator.vala
+deleted file mode 100644
+index 961895b..0000000
+--- a/src/DateIterator.vala
++++ /dev/null
+@@ -1,82 +0,0 @@
+-/*
+- * Copyright 2011-2018 elementary, Inc. (https://elementary.io)
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public
+- * License as published by the Free Software Foundation; either
+- * version 2 of the License, or (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+- * General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public
+- * License along with this program; if not, write to the
+- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+- * Boston, MA 02110-1301 USA.
+- *
+- * Authored by: Corentin Noël <corentin@elementaryos.org>
+- */
+-
+-public class Util.DateIterator : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterator<GLib.DateTime> {
+-    public GLib.DateTime current { get; construct set; }
+-    public Util.DateRange range { get; construct; }
+-
+-    // Required by Gee.Iterator
+-    public bool valid {
+-        get {
+-            return true;
+-        }
+-    }
+-
+-    // Required by Gee.Iterator
+-    public bool read_only {
+-        get {
+-            return false;
+-        }
+-    }
+-
+-    public DateIterator (Util.DateRange range) {
+-        Object (
+-            range: range,
+-            current: range.first_dt.add_days (-1)
+-        );
+-    }
+-
+-    public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
+-        var element = range.first_dt;
+-
+-        while (element.compare (range.last_dt) < 0) {
+-            if (f (element) == false) {
+-                return false;
+-            }
+-
+-            element = element.add_days (1);
+-        }
+-
+-        return true;
+-    }
+-
+-    public bool next () {
+-        if (!has_next ()) {
+-            return false;
+-        }
+-
+-        current = this.current.add_days (1);
+-
+-        return true;
+-    }
+-
+-    public bool has_next () {
+-        return current.compare (range.last_dt) < 0;
+-    }
+-
+-    public new GLib.DateTime get () {
+-        return current;
+-    }
+-
+-    public void remove () {
+-        assert_not_reached ();
+-    }
+-}
+diff --git a/src/DateRange.vala b/src/DateRange.vala
+deleted file mode 100644
+index 08e4c00..0000000
+--- a/src/DateRange.vala
++++ /dev/null
+@@ -1,66 +0,0 @@
+-/*
+- * Copyright 2011-2019 elementary, Inc. (https://elementary.io)
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public
+- * License as published by the Free Software Foundation; either
+- * version 2 of the License, or (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+- * General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public
+- * License along with this program; if not, write to the
+- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+- * Boston, MA 02110-1301 USA.
+- *
+- * Authored by: Corentin Noël <corentin@elementaryos.org>
+- */
+-
+-/* Represents date range from 'first' to 'last' inclusive */
+-public class Util.DateRange : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterable<GLib.DateTime> {
+-    public GLib.DateTime first_dt { get; construct; }
+-    public GLib.DateTime last_dt { get; construct; }
+-
+-    public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
+-        foreach (var date in this) {
+-            if (f (date) == false) {
+-                return false;
+-            }
+-        }
+-
+-        return true;
+-    }
+-
+-    public DateRange (GLib.DateTime first, GLib.DateTime last) {
+-        Object (
+-            first_dt: first,
+-            last_dt: last
+-        );
+-    }
+-
+-    public bool equals (DateRange other) {
+-        return (first_dt == other.first_dt && last_dt == other.last_dt);
+-    }
+-
+-    public Gee.Iterator<GLib.DateTime> iterator () {
+-        return new DateIterator (this);
+-    }
+-
+-    public Gee.List<GLib.DateTime> to_list () {
+-        var list = new Gee.ArrayList<GLib.DateTime> ((Gee.EqualDataFunc<GLib.DateTime>? )datetime_equal_func);
+-
+-        foreach (var date in this) {
+-            list.add (date);
+-        }
+-
+-        return list;
+-    }
+-
+-    /* Returns true if 'a' and 'b' are the same GLib.DateTime */
+-    private bool datetime_equal_func (GLib.DateTime a, GLib.DateTime b) {
+-        return a.equal (b);
+-    }
+-}
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index 77aa35c..b712c12 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -17,218 +17,219 @@
+  * Boston, MA 02110-1301 USA.
+  */
+ 
+-public class DateTime.Indicator : Wingpanel.Indicator {
+-    public static GLib.Settings settings;
+-
+-    private Widgets.PanelLabel panel_label;
+-    private Gtk.Grid main_grid;
+-    private Widgets.CalendarView calendar;
+-    private Gtk.ListBox event_listbox;
+-    private uint update_events_idle_source = 0;
+-
+-    public Indicator () {
+-        Object (
+-            code_name: Wingpanel.Indicator.DATETIME,
+-            display_name: _("Date & Time"),
+-            description: _("The date and time indicator")
+-        );
+-    }
+-
+-    static construct {
+-        settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
+-    }
++namespace DateTimeIndicator {
++    public class Indicator : Wingpanel.Indicator {
++        public static GLib.Settings settings;
++
++        private Widgets.PanelLabel panel_label;
++        private Gtk.Grid main_grid;
++        private Widgets.CalendarView calendar;
++        private Gtk.ListBox event_listbox;
++        private uint update_events_idle_source = 0;
++
++        public Indicator () {
++            Object (
++                code_name: Wingpanel.Indicator.DATETIME,
++                display_name: _("Date & Time"),
++                description: _("The date and time indicator")
++            );
++        }
+ 
+-    construct {
+-        visible = true;
+-    }
++        static construct {
++            settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
++        }
+ 
+-    public override Gtk.Widget get_display_widget () {
+-        if (panel_label == null) {
+-            panel_label = new Widgets.PanelLabel ();
++        construct {
++            visible = true;
+         }
+ 
+-        return panel_label;
+-    }
++        public override Gtk.Widget get_display_widget () {
++            if (panel_label == null) {
++                panel_label = new Widgets.PanelLabel ();
++            }
+ 
+-    public override Gtk.Widget? get_widget () {
+-        if (main_grid == null) {
+-            calendar = new Widgets.CalendarView ();
+-            calendar.margin_bottom = 6;
+-
+-            var placeholder_label = new Gtk.Label (_("No Events on This Day"));
+-            placeholder_label.wrap = true;
+-            placeholder_label.wrap_mode = Pango.WrapMode.WORD;
+-            placeholder_label.margin_start = 12;
+-            placeholder_label.margin_end = 12;
+-            placeholder_label.max_width_chars = 20;
+-            placeholder_label.justify = Gtk.Justification.CENTER;
+-            placeholder_label.show_all ();
+-
+-            var placeholder_style_context = placeholder_label.get_style_context ();
+-            placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
+-            placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
+-
+-            event_listbox = new Gtk.ListBox ();
+-            event_listbox.selection_mode = Gtk.SelectionMode.NONE;
+-            event_listbox.set_header_func (header_update_func);
+-            event_listbox.set_placeholder (placeholder_label);
+-            event_listbox.set_sort_func (sort_function);
+-
+-            var scrolled_window = new Gtk.ScrolledWindow (null, null);
+-            scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
+-            scrolled_window.add (event_listbox);
+-
+-            var settings_button = new Gtk.ModelButton ();
+-            settings_button.text = _("Date & Time Settings…");
+-
+-            main_grid = new Gtk.Grid ();
+-            main_grid.margin_top = 12;
+-            main_grid.attach (calendar, 0, 0);
+-            main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
+-            main_grid.attach (scrolled_window, 2, 0);
+-            main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
+-            main_grid.attach (settings_button, 0, 3, 3);
+-
+-            var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
+-            size_group.add_widget (calendar);
+-            size_group.add_widget (event_listbox);
+-
+-            calendar.day_double_click.connect (() => {
+-                close ();
+-            });
++            return panel_label;
++        }
+ 
+-            calendar.selection_changed.connect ((date) => {
+-                idle_update_events ();
+-            });
++        public override Gtk.Widget? get_widget () {
++            if (main_grid == null) {
++                calendar = new Widgets.CalendarView ();
++                calendar.margin_bottom = 6;
++
++                var placeholder_label = new Gtk.Label (_("No Events on This Day"));
++                placeholder_label.wrap = true;
++                placeholder_label.wrap_mode = Pango.WrapMode.WORD;
++                placeholder_label.margin_start = 12;
++                placeholder_label.margin_end = 12;
++                placeholder_label.max_width_chars = 20;
++                placeholder_label.justify = Gtk.Justification.CENTER;
++                placeholder_label.show_all ();
++
++                var placeholder_style_context = placeholder_label.get_style_context ();
++                placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
++                placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
++
++                event_listbox = new Gtk.ListBox ();
++                event_listbox.selection_mode = Gtk.SelectionMode.NONE;
++                event_listbox.set_header_func (header_update_func);
++                event_listbox.set_placeholder (placeholder_label);
++                event_listbox.set_sort_func (sort_function);
++
++                var scrolled_window = new Gtk.ScrolledWindow (null, null);
++                scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
++                scrolled_window.add (event_listbox);
++
++                var settings_button = new Gtk.ModelButton ();
++                settings_button.text = _("Date & Time Settings…");
++
++                main_grid = new Gtk.Grid ();
++                main_grid.margin_top = 12;
++                main_grid.attach (calendar, 0, 0);
++                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
++                main_grid.attach (scrolled_window, 2, 0);
++                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
++                main_grid.attach (settings_button, 0, 3, 3);
++
++                var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
++                size_group.add_widget (calendar);
++                size_group.add_widget (event_listbox);
++
++                calendar.day_double_click.connect (() => {
++                    close ();
++                });
++
++                calendar.selection_changed.connect ((date) => {
++                    idle_update_events ();
++                });
++
++                event_listbox.row_activated.connect ((row) => {
++                    calendar.show_date_in_maya (((EventRow) row).date);
++                    close ();
++                });
++
++                settings_button.clicked.connect (() => {
++                    try {
++                        AppInfo.launch_default_for_uri ("settings://time", null);
++                    } catch (Error e) {
++                        warning ("Failed to open time and date settings: %s", e.message);
++                    }
++                });
++            }
+ 
+-            event_listbox.row_activated.connect ((row) => {
+-                calendar.show_date_in_maya (((DateTime.EventRow) row).date);
+-                close ();
+-            });
++            return main_grid;
++        }
+ 
+-            settings_button.clicked.connect (() => {
+-                try {
+-                    AppInfo.launch_default_for_uri ("settings://time", null);
+-                } catch (Error e) {
+-                    warning ("Failed to open time and date settings: %s", e.message);
++        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
++            var row = (EventRow) lbrow;
++            if (lbbefore != null) {
++                var before = (EventRow) lbbefore;
++                if (row.is_allday == before.is_allday) {
++                    row.set_header (null);
++                    return;
+                 }
+-            });
+-        }
+ 
+-        return main_grid;
+-    }
++                if (row.is_allday != before.is_allday) {
++                    var header_label = new Granite.HeaderLabel (_("During the Day"));
++                    header_label.margin_start = header_label.margin_end = 6;
+ 
+-    private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
+-        var row = (DateTime.EventRow) lbrow;
+-        if (lbbefore != null) {
+-            var before = (DateTime.EventRow) lbbefore;
+-            if (row.is_allday == before.is_allday) {
+-                row.set_header (null);
++                    row.set_header (header_label);
++                    return;
++                }
++            } else {
++                if (row.is_allday) {
++                    var allday_header = new Granite.HeaderLabel (_("All Day"));
++                    allday_header.margin_start = allday_header.margin_end = 6;
++
++                    row.set_header (allday_header);
++                }
+                 return;
+             }
++        }
+ 
+-            if (row.is_allday != before.is_allday) {
+-                var header_label = new Granite.HeaderLabel (_("During the Day"));
+-                header_label.margin_start = header_label.margin_end = 6;
++        [CCode (instance_pos = -1)]
++        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
++            var e1 = (EventRow) child1;
++            var e2 = (EventRow) child2;
+ 
+-                row.set_header (header_label);
+-                return;
++            if (e1.start_time.compare (e2.start_time) != 0) {
++                return e1.start_time.compare (e2.start_time);
+             }
+-        } else {
+-            if (row.is_allday) {
+-                var allday_header = new Granite.HeaderLabel (_("All Day"));
+-                allday_header.margin_start = allday_header.margin_end = 6;
+ 
+-                row.set_header (allday_header);
++            // If they have the same date, sort them wholeday first
++            if (e1.is_allday) {
++                return -1;
++            } else if (e2.is_allday) {
++                return 1;
+             }
+-            return;
+-        }
+-    }
+-
+-    [CCode (instance_pos = -1)]
+-    private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
+-        var e1 = (EventRow) child1;
+-        var e2 = (EventRow) child2;
+ 
+-        if (e1.start_time.compare (e2.start_time) != 0) {
+-            return e1.start_time.compare (e2.start_time);
++            return 0;
+         }
+ 
+-        // If they have the same date, sort them wholeday first
+-        if (e1.is_allday) {
+-            return -1;
+-        } else if (e2.is_allday) {
+-            return 1;
++        private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
++            idle_update_events ();
+         }
+ 
+-        return 0;
+-    }
+-
+-    private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
+-        idle_update_events ();
+-    }
++        private void idle_update_events () {
++            if (update_events_idle_source > 0) {
++                GLib.Source.remove (update_events_idle_source);
++            }
+ 
+-    private void idle_update_events () {
+-        if (update_events_idle_source > 0) {
+-            GLib.Source.remove (update_events_idle_source);
++            update_events_idle_source = GLib.Idle.add (update_events);
+         }
+ 
+-        update_events_idle_source = GLib.Idle.add (update_events);
+-    }
+-
+-    private bool update_events () {
+-        foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
+-            widget.destroy ();
+-        }
++        private bool update_events () {
++            foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
++                widget.destroy ();
++            }
+ 
+-        if (calendar.selected_date == null) {
+-            update_events_idle_source = 0;
+-            return GLib.Source.REMOVE;
+-        }
++            if (calendar.selected_date == null) {
++                update_events_idle_source = 0;
++                return GLib.Source.REMOVE;
++            }
+ 
+-        var date = calendar.selected_date;
++            var date = calendar.selected_date;
+ 
+-        var model = Widgets.CalendarModel.get_default ();
++            var model = Models.CalendarModel.get_default ();
+ 
+-        var events_on_day = new Gee.TreeMap<string, DateTime.EventRow> ();
++            var events_on_day = new Gee.TreeMap<string, EventRow> ();
+ 
+-        model.source_events.@foreach ((source, component_map) => {
+-            foreach (var comp in component_map.get_values ()) {
+-                if (Util.calcomp_is_on_day (comp, date)) {
+-                    unowned ICal.Component ical = comp.get_icalcomponent ();
+-                    var event_uid = ical.get_uid ();
+-                    if (!events_on_day.has_key (event_uid)) {
+-                        events_on_day[event_uid] = new DateTime.EventRow (date, ical, source);
++            model.source_events.@foreach ((source, component_map) => {
++                foreach (var comp in component_map.get_values ()) {
++                    if (Util.calcomp_is_on_day (comp, date)) {
++                        unowned ICal.Component ical = comp.get_icalcomponent ();
++                        var event_uid = ical.get_uid ();
++                        if (!events_on_day.has_key (event_uid)) {
++                            events_on_day[event_uid] = new EventRow (date, ical, source);
+ 
+-                        event_listbox.add (events_on_day[event_uid]);
++                            event_listbox.add (events_on_day[event_uid]);
++                        }
+                     }
+                 }
+-            }
+-        });
++            });
+ 
+-        event_listbox.show_all ();
+-        update_events_idle_source = 0;
+-        return GLib.Source.REMOVE;
+-    }
++            event_listbox.show_all ();
++            update_events_idle_source = 0;
++            return GLib.Source.REMOVE;
++        }
+ 
+-    public override void opened () {
+-        calendar.show_today ();
++        public override void opened () {
++            calendar.show_today ();
+ 
+-        Widgets.CalendarModel.get_default ().events_added.connect (update_events_model);
+-        Widgets.CalendarModel.get_default ().events_updated.connect (update_events_model);
+-        Widgets.CalendarModel.get_default ().events_removed.connect (update_events_model);
+-    }
++            Models.CalendarModel.get_default ().events_added.connect (update_events_model);
++            Models.CalendarModel.get_default ().events_updated.connect (update_events_model);
++            Models.CalendarModel.get_default ().events_removed.connect (update_events_model);
++        }
+ 
+-    public override void closed () {
+-        Widgets.CalendarModel.get_default ().events_added.disconnect (update_events_model);
+-        Widgets.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
+-        Widgets.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
++        public override void closed () {
++            Models.CalendarModel.get_default ().events_added.disconnect (update_events_model);
++            Models.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
++            Models.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
++        }
+     }
+ }
+-
+ public Wingpanel.Indicator get_indicator (Module module) {
+     debug ("Activating DateTime Indicator");
+-    var indicator = new DateTime.Indicator ();
++    var indicator = new DateTimeIndicator.Indicator ();
+ 
+     return indicator;
+ }
+diff --git a/src/Widgets/calendar/CalendarModel.vala b/src/Models/CalendarModel.vala
+similarity index 99%
+rename from src/Widgets/calendar/CalendarModel.vala
+rename to src/Models/CalendarModel.vala
+index 7602303..965b93e 100644
+--- a/src/Widgets/calendar/CalendarModel.vala
++++ b/src/Models/CalendarModel.vala
+@@ -15,8 +15,8 @@
+  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-namespace DateTime.Widgets {
+-    public class CalendarModel : Object {
++namespace DateTimeIndicator {
++    public class Models.CalendarModel : Object {
+         /* The data_range is the range of dates for which this model is storing
+          * data.
+          *
+diff --git a/src/Services/TimeManager.vala b/src/Services/TimeManager.vala
+index b68f158..5baa136 100644
+--- a/src/Services/TimeManager.vala
++++ b/src/Services/TimeManager.vala
+@@ -32,153 +32,155 @@ interface FDO.Accounts : Object {
+     public abstract string find_user_by_name (string username) throws GLib.Error;
+ }
+ 
+-public class DateTime.Services.TimeManager : Gtk.Calendar {
+-    private static TimeManager? instance = null;
++namespace DateTimeIndicator {
++    public class Services.TimeManager : Gtk.Calendar {
++        private static TimeManager? instance = null;
+ 
+-    public signal void minute_changed ();
++        public signal void minute_changed ();
+ 
+-    private GLib.DateTime? current_time = null;
+-    private uint timeout_id = 0;
+-    private Manager? manager = null;
++        private GLib.DateTime? current_time = null;
++        private uint timeout_id = 0;
++        private Manager? manager = null;
+ 
+-    public bool clock_show_seconds { get; set; }
+-    public bool is_12h { get; set; }
++        public bool clock_show_seconds { get; set; }
++        public bool is_12h { get; set; }
+ 
+-    public TimeManager () {
+-        update_current_time ();
+-
+-        if (current_time == null) {
+-            return;
+-        }
++        public TimeManager () {
++            update_current_time ();
+ 
+-        add_timeout ();
+-        try {
+-            var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
+-            clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
++            if (current_time == null) {
++                return;
++            }
+ 
+-            notify["clock-show-seconds"].connect (() => {
+-                add_timeout ();
+-            });
++            add_timeout ();
++            try {
++                var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
++                clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
+ 
+-            // Listen for the D-BUS server that controls time settings
+-            Bus.watch_name (BusType.SYSTEM, "org.freedesktop.timedate1", BusNameWatcherFlags.NONE, on_watch, on_unwatch);
+-            // Listen for the signal that is fired when waking up from sleep, then update time
+-            manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.login1", "/org/freedesktop/login1");
+-            manager.prepare_for_sleep.connect ((sleeping) => {
+-                if (!sleeping) {
+-                    update_current_time ();
+-                    minute_changed ();
++                notify["clock-show-seconds"].connect (() => {
+                     add_timeout ();
+-                }
+-            });
+-        } catch (Error e) {
+-            warning (e.message);
++                });
++
++                // Listen for the D-BUS server that controls time settings
++                Bus.watch_name (BusType.SYSTEM, "org.freedesktop.timedate1", BusNameWatcherFlags.NONE, on_watch, on_unwatch);
++                // Listen for the signal that is fired when waking up from sleep, then update time
++                manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.login1", "/org/freedesktop/login1");
++                manager.prepare_for_sleep.connect ((sleeping) => {
++                    if (!sleeping) {
++                        update_current_time ();
++                        minute_changed ();
++                        add_timeout ();
++                    }
++                });
++            } catch (Error e) {
++                warning (e.message);
++            }
+         }
+-    }
+-
+-    construct {
+-        setup_time_format.begin ();
+-    }
+ 
+-    private async void setup_time_format () {
+-        try {
+-            var accounts_service = yield GLib.Bus.get_proxy<FDO.Accounts> (GLib.BusType.SYSTEM,
+-                                                                           "org.freedesktop.Accounts",
+-                                                                           "/org/freedesktop/Accounts");
+-            var user_path = accounts_service.find_user_by_name (GLib.Environment.get_user_name ());
+-
+-            var greeter_act = yield GLib.Bus.get_proxy<Pantheon.AccountsService> (GLib.BusType.SYSTEM,
+-                                                    "org.freedesktop.Accounts",
+-                                                    user_path,
+-                                                    GLib.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
+-            is_12h = ("12h" in greeter_act.time_format);
+-            ((GLib.DBusProxy) greeter_act).g_properties_changed.connect ((changed_properties, invalidated_properties) => {
+-                if (changed_properties.lookup_value ("TimeFormat", GLib.VariantType.STRING) != null) {
+-                    is_12h = ("12h" in greeter_act.time_format);
+-                }
+-            });
+-        } catch (Error e) {
+-            critical (e.message);
+-            // Connect to the GSettings instead
+-            var clock_settings = new GLib.Settings ("org.gnome.desktop.interface");
+-            clock_settings.changed["clock-format"].connect (() => {
+-                is_12h = ("12h" in clock_settings.get_string ("clock-format"));
+-            });
+-
+-            is_12h = ("12h" in clock_settings.get_string ("clock-format"));
++        construct {
++            setup_time_format.begin ();
+         }
+-    }
+ 
+-    private void on_watch (DBusConnection conn) {
+-        // Start updating the time display quicker because someone is changing settings
+-        add_timeout (true);
+-    }
++        private async void setup_time_format () {
++            try {
++                var accounts_service = yield GLib.Bus.get_proxy<FDO.Accounts> (GLib.BusType.SYSTEM,
++                                                                               "org.freedesktop.Accounts",
++                                                                               "/org/freedesktop/Accounts");
++                var user_path = accounts_service.find_user_by_name (GLib.Environment.get_user_name ());
++
++                var greeter_act = yield GLib.Bus.get_proxy<Pantheon.AccountsService> (GLib.BusType.SYSTEM,
++                                                        "org.freedesktop.Accounts",
++                                                        user_path,
++                                                        GLib.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
++                is_12h = ("12h" in greeter_act.time_format);
++                ((GLib.DBusProxy) greeter_act).g_properties_changed.connect ((changed_properties, invalidated_properties) => {
++                    if (changed_properties.lookup_value ("TimeFormat", GLib.VariantType.STRING) != null) {
++                        is_12h = ("12h" in greeter_act.time_format);
++                    }
++                });
++            } catch (Error e) {
++                critical (e.message);
++                // Connect to the GSettings instead
++                var clock_settings = new GLib.Settings ("org.gnome.desktop.interface");
++                clock_settings.changed["clock-format"].connect (() => {
++                    is_12h = ("12h" in clock_settings.get_string ("clock-format"));
++                });
+ 
+-    private void on_unwatch (DBusConnection conn) {
+-        // Stop updating the time display quicker
+-        add_timeout (false);
+-    }
++                is_12h = ("12h" in clock_settings.get_string ("clock-format"));
++            }
++        }
+ 
+-    private void add_timeout (bool update_fast = false) {
+-        uint interval;
+-        if (update_fast || clock_show_seconds) {
+-            interval = 500;
+-        } else {
+-            interval = calculate_time_until_next_minute ();
++        private void on_watch (DBusConnection conn) {
++            // Start updating the time display quicker because someone is changing settings
++            add_timeout (true);
+         }
+ 
+-        if (timeout_id > 0) {
+-            Source.remove (timeout_id);
++        private void on_unwatch (DBusConnection conn) {
++            // Stop updating the time display quicker
++            add_timeout (false);
+         }
+ 
+-        timeout_id = Timeout.add (interval, () => {
+-            update_current_time ();
+-            minute_changed ();
+-            add_timeout (update_fast);
++        private void add_timeout (bool update_fast = false) {
++            uint interval;
++            if (update_fast || clock_show_seconds) {
++                interval = 500;
++            } else {
++                interval = calculate_time_until_next_minute ();
++            }
+ 
+-            return false;
+-        });
+-    }
++            if (timeout_id > 0) {
++                Source.remove (timeout_id);
++            }
+ 
+-    public string format (string format) {
+-        if (current_time == null) {
+-            return "undef";
++            timeout_id = Timeout.add (interval, () => {
++                update_current_time ();
++                minute_changed ();
++                add_timeout (update_fast);
++
++                return false;
++            });
+         }
+ 
+-        return current_time.format (format);
+-    }
++        public string format (string format) {
++            if (current_time == null) {
++                return "undef";
++            }
+ 
+-    public GLib.DateTime get_current_time () {
+-        return current_time;
+-    }
++            return current_time.format (format);
++        }
+ 
+-    private void update_current_time () {
+-        var local_time = new GLib.DateTime.now_local ();
++        public GLib.DateTime get_current_time () {
++            return current_time;
++        }
+ 
+-        if (local_time == null) {
+-            critical ("Can't get the local time.");
++        private void update_current_time () {
++            var local_time = new GLib.DateTime.now_local ();
+ 
+-            return;
+-        }
++            if (local_time == null) {
++                critical ("Can't get the local time.");
+ 
+-        current_time = local_time;
+-    }
++                return;
++            }
+ 
+-    private uint calculate_time_until_next_minute () {
+-        if (current_time == null) {
+-            return 60 * 1000;
++            current_time = local_time;
+         }
+ 
+-        var seconds_until_next_minute = 60 - (current_time.to_unix () % 60);
++        private uint calculate_time_until_next_minute () {
++            if (current_time == null) {
++                return 60 * 1000;
++            }
+ 
+-        return (uint)seconds_until_next_minute * 1000;
+-    }
++            var seconds_until_next_minute = 60 - (current_time.to_unix () % 60);
+ 
+-    public static TimeManager get_default () {
+-        if (instance == null) {
+-            instance = new TimeManager ();
++            return (uint)seconds_until_next_minute * 1000;
+         }
+ 
+-        return instance;
++        public static TimeManager get_default () {
++            if (instance == null) {
++                instance = new TimeManager ();
++            }
++
++            return instance;
++        }
+     }
+ }
+diff --git a/src/Util/DateIterator.vala b/src/Util/DateIterator.vala
+new file mode 100644
+index 0000000..c2c771e
+--- /dev/null
++++ b/src/Util/DateIterator.vala
+@@ -0,0 +1,84 @@
++/*
++ * Copyright 2011-2018 elementary, Inc. (https://elementary.io)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301 USA.
++ *
++ * Authored by: Corentin Noël <corentin@elementaryos.org>
++ */
++
++namespace DateTimeIndicator {
++    public class Util.DateIterator : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterator<GLib.DateTime> {
++        public GLib.DateTime current { get; construct set; }
++        public Util.DateRange range { get; construct; }
++
++        // Required by Gee.Iterator
++        public bool valid {
++            get {
++                return true;
++            }
++        }
++
++        // Required by Gee.Iterator
++        public bool read_only {
++            get {
++                return false;
++            }
++        }
++
++        public DateIterator (Util.DateRange range) {
++            Object (
++                range: range,
++                current: range.first_dt.add_days (-1)
++            );
++        }
++
++        public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
++            var element = range.first_dt;
++
++            while (element.compare (range.last_dt) < 0) {
++                if (f (element) == false) {
++                    return false;
++                }
++
++                element = element.add_days (1);
++            }
++
++            return true;
++        }
++
++        public bool next () {
++            if (!has_next ()) {
++                return false;
++            }
++
++            current = this.current.add_days (1);
++
++            return true;
++        }
++
++        public bool has_next () {
++            return current.compare (range.last_dt) < 0;
++        }
++
++        public new GLib.DateTime get () {
++            return current;
++        }
++
++        public void remove () {
++            assert_not_reached ();
++        }
++    }
++}
+diff --git a/src/Util/DateRange.vala b/src/Util/DateRange.vala
+new file mode 100644
+index 0000000..82da7c8
+--- /dev/null
++++ b/src/Util/DateRange.vala
+@@ -0,0 +1,68 @@
++/*
++ * Copyright 2011-2019 elementary, Inc. (https://elementary.io)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
++ * Boston, MA 02110-1301 USA.
++ *
++ * Authored by: Corentin Noël <corentin@elementaryos.org>
++ */
++
++namespace DateTimeIndicator {
++/* Represents date range from 'first' to 'last' inclusive */
++    public class Util.DateRange : Object, Gee.Traversable<GLib.DateTime>, Gee.Iterable<GLib.DateTime> {
++        public GLib.DateTime first_dt { get; construct; }
++        public GLib.DateTime last_dt { get; construct; }
++
++        public bool @foreach (Gee.ForallFunc<GLib.DateTime> f) {
++            foreach (var date in this) {
++                if (f (date) == false) {
++                    return false;
++                }
++            }
++
++            return true;
++        }
++
++        public DateRange (GLib.DateTime first, GLib.DateTime last) {
++            Object (
++                first_dt: first,
++                last_dt: last
++            );
++        }
++
++        public bool equals (DateRange other) {
++            return (first_dt == other.first_dt && last_dt == other.last_dt);
++        }
++
++        public Gee.Iterator<GLib.DateTime> iterator () {
++            return new DateIterator (this);
++        }
++
++        public Gee.List<GLib.DateTime> to_list () {
++            var list = new Gee.ArrayList<GLib.DateTime> ((Gee.EqualDataFunc<GLib.DateTime>? )datetime_equal_func);
++
++            foreach (var date in this) {
++                list.add (date);
++            }
++
++            return list;
++        }
++
++        /* Returns true if 'a' and 'b' are the same GLib.DateTime */
++        private bool datetime_equal_func (GLib.DateTime a, GLib.DateTime b) {
++            return a.equal (b);
++        }
++    }
++}
+diff --git a/src/Widgets/calendar/Util.vala b/src/Util/Util.vala
+similarity index 96%
+rename from src/Widgets/calendar/Util.vala
+rename to src/Util/Util.vala
+index e51f784..c261f4b 100644
+--- a/src/Widgets/calendar/Util.vala
++++ b/src/Util/Util.vala
+@@ -19,7 +19,7 @@
+  * Authored by: Corentin Noël <corentin@elementaryos.org>
+  */
+ 
+-namespace Util {
++namespace DateTimeIndicator.Util {
+     static bool has_scrolled = false;
+ 
+     public bool on_scroll_event (Gdk.EventScroll event) {
+@@ -35,7 +35,7 @@ namespace Util {
+ 
+         /* It's mouse scroll ! */
+         if (choice == 1 || choice == -1) {
+-            DateTime.Widgets.CalendarModel.get_default ().change_month ((int)choice);
++            Models.CalendarModel.get_default ().change_month ((int)choice);
+ 
+             return true;
+         }
+@@ -46,14 +46,14 @@ namespace Util {
+ 
+         if (choice > 0.3) {
+             reset_timer.begin ();
+-            DateTime.Widgets.CalendarModel.get_default ().change_month (1);
++            Models.CalendarModel.get_default ().change_month (1);
+ 
+             return true;
+         }
+ 
+         if (choice < -0.3) {
+             reset_timer.begin ();
+-            DateTime.Widgets.CalendarModel.get_default ().change_month (-1);
++            Models.CalendarModel.get_default ().change_month (-1);
+ 
+             return true;
+         }
+diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
+new file mode 100644
+index 0000000..65cee28
+--- /dev/null
++++ b/src/Widgets/CalendarView.vala
+@@ -0,0 +1,185 @@
++/*-
++ * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Authored by: Maxwell Barvian
++ *              Corentin Noël <corentin@elementaryos.org>
++ */
++
++namespace DateTimeIndicator {
++    public class Widgets.CalendarView : Gtk.Grid {
++        public signal void day_double_click ();
++        public signal void event_updates ();
++        public signal void selection_changed (GLib.DateTime? new_date);
++
++        public GLib.DateTime? selected_date { get; private set; }
++
++        private Widgets.Grid grid;
++        private Gtk.Stack stack;
++        private Gtk.Grid big_grid;
++
++        construct {
++            var label = new Gtk.Label (new GLib.DateTime.now_local ().format (_("%OB, %Y")));
++            label.hexpand = true;
++            label.margin_start = 6;
++            label.xalign = 0;
++            label.width_chars = 13;
++
++            var provider = new Gtk.CssProvider ();
++            provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/ControlHeader.css");
++
++            var label_style_context = label.get_style_context ();
++            label_style_context.add_class ("header-label");
++            label_style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++            var left_button = new Gtk.Button.from_icon_name ("pan-start-symbolic");
++            var center_button = new Gtk.Button.from_icon_name ("office-calendar-symbolic");
++            center_button.tooltip_text = _("Go to today's date");
++            var right_button = new Gtk.Button.from_icon_name ("pan-end-symbolic");
++
++            var box_buttons = new Gtk.Grid ();
++            box_buttons.margin_end = 6;
++            box_buttons.valign = Gtk.Align.CENTER;
++            box_buttons.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
++            box_buttons.add (left_button);
++            box_buttons.add (center_button);
++            box_buttons.add (right_button);
++
++            big_grid = create_big_grid ();
++
++            stack = new Gtk.Stack ();
++            stack.add (big_grid);
++            stack.show_all ();
++            stack.expand = true;
++
++            stack.notify["transition-running"].connect (() => {
++                if (stack.transition_running == false) {
++                    stack.get_children ().foreach ((child) => {
++                        if (child != stack.visible_child) {
++                            child.destroy ();
++                        }
++                    });
++                }
++            });
++
++            column_spacing = 6;
++            row_spacing = 6;
++            margin_start = margin_end = 10;
++            attach (label, 0, 0);
++            attach (box_buttons, 1, 0);
++            attach (stack, 0, 1, 2);
++
++            var model = Models.CalendarModel.get_default ();
++            model.notify["data-range"].connect (() => {
++                label.label = model.month_start.format (_("%OB, %Y"));
++
++                sync_with_model ();
++
++                selected_date = null;
++                selection_changed (selected_date);
++            });
++
++            left_button.clicked.connect (() => {
++                model.change_month (-1);
++            });
++
++            right_button.clicked.connect (() => {
++                model.change_month (1);
++            });
++
++            center_button.clicked.connect (() => {
++                show_today ();
++            });
++        }
++
++        private Gtk.Grid create_big_grid () {
++            grid = new Widgets.Grid ();
++            grid.show_all ();
++
++            grid.on_event_add.connect ((date) => {
++                show_date_in_maya (date);
++                day_double_click ();
++            });
++
++            grid.selection_changed.connect ((date) => {
++                selected_date = date;
++                selection_changed (date);
++            });
++
++            return grid;
++        }
++
++        public void show_today () {
++            var calmodel = Models.CalendarModel.get_default ();
++            var today = Util.strip_time (new GLib.DateTime.now_local ());
++            var start = Util.get_start_of_month (today);
++            selected_date = today;
++            if (!start.equal (calmodel.month_start)) {
++                calmodel.month_start = start;
++            }
++            sync_with_model ();
++
++            grid.set_focus_to_today ();
++        }
++
++        // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
++        public void show_date_in_maya (GLib.DateTime date) {
++            var command = "io.elementary.calendar --show-day %s".printf (date.format ("%F"));
++
++            try {
++                var appinfo = AppInfo.create_from_commandline (command, null, AppInfoCreateFlags.NONE);
++                appinfo.launch_uris (null, null);
++            } catch (GLib.Error e) {
++                var dialog = new Granite.MessageDialog.with_image_from_icon_name (
++                    _("Unable To Launch Calendar"),
++                    _("The program \"io.elementary.calendar\" may not be installed"),
++                    "dialog-error"
++                );
++                dialog.show_error_details (e.message);
++                dialog.run ();
++                dialog.destroy ();
++            }
++        }
++
++        /* Sets the calendar widgets to the date range of the model */
++        private void sync_with_model () {
++            var model = Models.CalendarModel.get_default ();
++            if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
++                grid.update_today ();
++                return; // nothing else to do
++            }
++
++            GLib.DateTime previous_first = null;
++            if (grid.grid_range != null)
++                previous_first = grid.grid_range.first_dt;
++
++            big_grid = create_big_grid ();
++            stack.add (big_grid);
++
++            grid.set_range (model.data_range, model.month_start);
++            grid.update_weeks (model.data_range.first_dt, model.num_weeks);
++
++            if (previous_first != null) {
++                if (previous_first.compare (grid.grid_range.first_dt) == -1) {
++                    stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
++                } else {
++                    stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
++                }
++            }
++
++            stack.set_visible_child (big_grid);
++        }
++    }
++}
+diff --git a/src/Widgets/EventRow.vala b/src/Widgets/EventRow.vala
+index 8e0513e..1268311 100644
+--- a/src/Widgets/EventRow.vala
++++ b/src/Widgets/EventRow.vala
+@@ -17,104 +17,106 @@
+  * Boston, MA 02110-1301 USA.
+  */
+ 
+-public class DateTime.EventRow : Gtk.ListBoxRow {
+-    public GLib.DateTime date { get; construct; }
+-    public unowned ICal.Component component { get; construct; }
+-    public unowned E.SourceCalendar cal { get; construct; }
+-
+-    public GLib.DateTime start_time { get; private set; }
+-    public GLib.DateTime? end_time { get; private set; }
+-    public bool is_allday { get; private set; default = false; }
+-
+-    private static Services.TimeManager time_manager;
+-    private static Gtk.CssProvider css_provider;
+-
+-    private Gtk.Grid grid;
+-    private Gtk.Image event_image;
+-    private Gtk.Label time_label;
+-
+-    public EventRow (GLib.DateTime date, ICal.Component component, E.Source source) {
+-        Object (
+-            component: component,
+-            date: date,
+-            cal: (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR)
+-        );
+-    }
+-
+-    static construct {
+-        css_provider = new Gtk.CssProvider ();
+-        css_provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/EventRow.css");
+-
+-        time_manager = Services.TimeManager.get_default ();
+-    }
++namespace DateTimeIndicator {
++    public class EventRow : Gtk.ListBoxRow {
++        public GLib.DateTime date { get; construct; }
++        public unowned ICal.Component component { get; construct; }
++        public unowned E.SourceCalendar cal { get; construct; }
++
++        public GLib.DateTime start_time { get; private set; }
++        public GLib.DateTime? end_time { get; private set; }
++        public bool is_allday { get; private set; default = false; }
++
++        private static Services.TimeManager time_manager;
++        private static Gtk.CssProvider css_provider;
++
++        private Gtk.Grid grid;
++        private Gtk.Image event_image;
++        private Gtk.Label time_label;
++
++        public EventRow (GLib.DateTime date, ICal.Component component, E.Source source) {
++            Object (
++                component: component,
++                date: date,
++                cal: (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR)
++            );
++        }
+ 
+-    construct {
+-        start_time = Util.ical_to_date_time (component.get_dtstart ());
+-        end_time = Util.ical_to_date_time (component.get_dtend ());
++        static construct {
++            css_provider = new Gtk.CssProvider ();
++            css_provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/EventRow.css");
+ 
+-        if (end_time != null && Util.is_the_all_day (start_time, end_time)) {
+-            is_allday = true;
++            time_manager = Services.TimeManager.get_default ();
+         }
+ 
+-        unowned string icon_name = "office-calendar-symbolic";
+-        if (end_time == null) {
+-            icon_name = "alarm-symbolic";
++        construct {
++            start_time = Util.ical_to_date_time (component.get_dtstart ());
++            end_time = Util.ical_to_date_time (component.get_dtend ());
++
++            if (end_time != null && Util.is_the_all_day (start_time, end_time)) {
++                is_allday = true;
++            }
++
++            unowned string icon_name = "office-calendar-symbolic";
++            if (end_time == null) {
++                icon_name = "alarm-symbolic";
++            }
++
++            event_image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.MENU);
++            event_image.valign = Gtk.Align.START;
++
++            unowned Gtk.StyleContext event_image_context = event_image.get_style_context ();
++            event_image_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++            var name_label = new Gtk.Label (component.get_summary ());
++            name_label.hexpand = true;
++            name_label.ellipsize = Pango.EllipsizeMode.END;
++            name_label.lines = 3;
++            name_label.max_width_chars = 30;
++            name_label.wrap = true;
++            name_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
++            name_label.xalign = 0;
++
++            unowned Gtk.StyleContext name_label_context = name_label.get_style_context ();
++            name_label_context.add_class ("title");
++            name_label_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++            time_label = new Gtk.Label (null);
++            time_label.use_markup = true;
++            time_label.xalign = 0;
++            time_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
++
++            grid = new Gtk.Grid ();
++            grid.column_spacing = 6;
++            grid.margin = 3;
++            grid.margin_start = grid.margin_end = 6;
++            grid.attach (event_image, 0, 0);
++            grid.attach (name_label, 1, 0);
++            if (!is_allday) {
++                grid.attach (time_label, 1, 1);
++            }
++
++            unowned Gtk.StyleContext grid_context = grid.get_style_context ();
++            grid_context.add_class ("event");
++            grid_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++            add (grid);
++
++            set_color ();
++            cal.notify["color"].connect (set_color);
++
++            update_timelabel ();
++            time_manager.notify["is-12h"].connect (update_timelabel);
+         }
+ 
+-        event_image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.MENU);
+-        event_image.valign = Gtk.Align.START;
+-
+-        unowned Gtk.StyleContext event_image_context = event_image.get_style_context ();
+-        event_image_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-
+-        var name_label = new Gtk.Label (component.get_summary ());
+-        name_label.hexpand = true;
+-        name_label.ellipsize = Pango.EllipsizeMode.END;
+-        name_label.lines = 3;
+-        name_label.max_width_chars = 30;
+-        name_label.wrap = true;
+-        name_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
+-        name_label.xalign = 0;
+-
+-        unowned Gtk.StyleContext name_label_context = name_label.get_style_context ();
+-        name_label_context.add_class ("title");
+-        name_label_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-
+-        time_label = new Gtk.Label (null);
+-        time_label.use_markup = true;
+-        time_label.xalign = 0;
+-        time_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
+-
+-        grid = new Gtk.Grid ();
+-        grid.column_spacing = 6;
+-        grid.margin = 3;
+-        grid.margin_start = grid.margin_end = 6;
+-        grid.attach (event_image, 0, 0);
+-        grid.attach (name_label, 1, 0);
+-        if (!is_allday) {
+-            grid.attach (time_label, 1, 1);
++        private void update_timelabel () {
++            var time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h);
++            time_label.label = "<small>%s – %s</small>".printf (start_time.format (time_format), end_time.format (time_format));
+         }
+ 
+-        unowned Gtk.StyleContext grid_context = grid.get_style_context ();
+-        grid_context.add_class ("event");
+-        grid_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-
+-        add (grid);
+-
+-        set_color ();
+-        cal.notify["color"].connect (set_color);
+-
+-        update_timelabel ();
+-        time_manager.notify["is-12h"].connect (update_timelabel);
+-    }
+-
+-    private void update_timelabel () {
+-        var time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h);
+-        time_label.label = "<small>%s – %s</small>".printf (start_time.format (time_format), end_time.format (time_format));
+-    }
+-
+-    private void set_color () {
+-        Util.set_event_calendar_color (cal, grid);
+-        Util.set_event_calendar_color (cal, event_image);
++        private void set_color () {
++            Util.set_event_calendar_color (cal, grid);
++            Util.set_event_calendar_color (cal, event_image);
++        }
+     }
+ }
+diff --git a/src/Widgets/calendar/Grid.vala b/src/Widgets/Grid.vala
+similarity index 95%
+rename from src/Widgets/calendar/Grid.vala
+rename to src/Widgets/Grid.vala
+index 2b48636..165d11d 100644
+--- a/src/Widgets/calendar/Grid.vala
++++ b/src/Widgets/Grid.vala
+@@ -20,11 +20,11 @@
+  *              Corentin Noël <corentin@elementaryos.org>
+  */
+ 
+-namespace DateTime.Widgets {
++namespace DateTimeIndicator {
+ /**
+  * Represents the entire date grid as a table.
+  */
+-    public class Grid : Gtk.Grid {
++    public class Widgets.Grid : Gtk.Grid {
+         public Util.DateRange grid_range { get; private set; }
+ 
+         /*
+@@ -59,7 +59,7 @@ namespace DateTime.Widgets {
+             hexpand = true;
+             attach (week_sep_revealer, 1, 1, 1, 6);
+ 
+-            DateTime.Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
++            Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
+ 
+             data = new Gee.HashMap<uint, GridDay> ();
+             events |= Gdk.EventMask.SCROLL_MASK;
+@@ -77,7 +77,7 @@ namespace DateTime.Widgets {
+             day.set_selected (true);
+             day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
+             selection_changed (selected_date);
+-            var calmodel = CalendarModel.get_default ();
++            var calmodel = Models.CalendarModel.get_default ();
+             var date_month = selected_date.get_month () - calmodel.month_start.get_month ();
+             var date_year = selected_date.get_year () - calmodel.month_start.get_year ();
+ 
+@@ -127,7 +127,7 @@ namespace DateTime.Widgets {
+             /* Create new widgets for the new range */
+ 
+             var date = Util.strip_time (today);
+-            date = date.add_days (CalendarModel.get_default ().week_starts_on - date.get_day_of_week ());
++            date = date.add_days (Models.CalendarModel.get_default ().week_starts_on - date.get_day_of_week ());
+             foreach (var label in header_labels) {
+                 label.label = date.format ("%a");
+                 date = date.add_days (1);
+@@ -221,7 +221,7 @@ namespace DateTime.Widgets {
+                 week_labels[c].add (week_label);
+                 week_labels[c].show_all ();
+ 
+-                DateTime.Indicator.settings.bind ("show-weeks", week_labels[c], "reveal-child", GLib.SettingsBindFlags.DEFAULT);
++                Indicator.settings.bind ("show-weeks", week_labels[c], "reveal-child", GLib.SettingsBindFlags.DEFAULT);
+ 
+                 attach (week_labels[c], 0, c + 1);
+ 
+diff --git a/src/Widgets/GridDay.vala b/src/Widgets/GridDay.vala
+new file mode 100644
+index 0000000..8c44443
+--- /dev/null
++++ b/src/Widgets/GridDay.vala
+@@ -0,0 +1,180 @@
++// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
++/*-
++ * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ *
++ * Authored by: Maxwell Barvian
++ *              Corentin Noël <corentin@elementaryos.org>
++ */
++
++namespace DateTimeIndicator {
++/**
++ * Represents a single day on the grid.
++ */
++    public class Widgets.GridDay : Gtk.EventBox {
++        /*
++         * Event emitted when the day is double clicked or the ENTER key is pressed.
++         */
++        public signal void on_event_add (GLib.DateTime date);
++
++        public GLib.DateTime date { get; construct set; }
++
++        private static Gtk.CssProvider provider;
++        private static Models.CalendarModel model;
++
++        private Gee.HashMap<string, Gtk.Widget> event_dots;
++        private Gtk.Grid event_grid;
++        private Gtk.Label label;
++        private bool valid_grab = false;
++
++        public GridDay (GLib.DateTime date) {
++            Object (date: date);
++        }
++
++        static construct {
++            model = Models.CalendarModel.get_default ();
++
++            provider = new Gtk.CssProvider ();
++            provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/GridDay.css");
++        }
++
++        construct {
++            unowned Gtk.StyleContext style_context = get_style_context ();
++            style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++            style_context.add_class ("circular");
++
++            label = new Gtk.Label (null);
++
++            event_grid = new Gtk.Grid ();
++            event_grid.halign = Gtk.Align.CENTER;
++            event_grid.height_request = 6;
++
++            var grid = new Gtk.Grid ();
++            grid.halign = grid.valign = Gtk.Align.CENTER;
++            grid.attach (label, 0, 0);
++            grid.attach (event_grid, 0, 1);
++
++            can_focus = true;
++            events |= Gdk.EventMask.BUTTON_PRESS_MASK;
++            events |= Gdk.EventMask.KEY_PRESS_MASK;
++            events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
++            set_size_request (35, 35);
++            halign = Gtk.Align.CENTER;
++            hexpand = true;
++            add (grid);
++            show_all ();
++
++            // Signals and handlers
++            button_press_event.connect (on_button_press);
++            key_press_event.connect (on_key_press);
++            scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
++
++            notify["date"].connect (() => {
++                label.label = date.get_day_of_month ().to_string ();
++            });
++
++            event_dots = new Gee.HashMap<string, Gtk.Widget> ();
++
++            model.events_added.connect (add_event_dots);
++            model.events_removed.connect (remove_event_dots);
++        }
++
++        private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            foreach (var component in events) {
++                if (event_dots.size >= 3) {
++                    return;
++                }
++
++                if (Util.calcomp_is_on_day (component, date)) {
++                    unowned ICal.Component ical = component.get_icalcomponent ();
++
++                    var event_uid = ical.get_uid ();
++                    if (!event_dots.has_key (event_uid)) {
++                        var event_dot = new Gtk.Image ();
++                        event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
++                        event_dot.pixel_size = 6;
++
++                        unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
++                        style_context.add_class (Granite.STYLE_CLASS_ACCENT);
++                        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++                        var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++                        Util.set_event_calendar_color (source_calendar, event_dot);
++
++                        event_dots[event_uid] = event_dot;
++
++                        event_grid.add (event_dot);
++                    }
++                }
++            }
++
++            event_grid.show_all ();
++        }
++
++        private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            foreach (var component in events) {
++                unowned ICal.Component ical = component.get_icalcomponent ();
++                var event_uid = ical.get_uid ();
++                var dot = event_dots[event_uid];
++                if (dot != null) {
++                    dot.destroy ();
++                    event_dots.remove (event_uid);
++                }
++            }
++        }
++
++        public void set_selected (bool selected) {
++            if (selected) {
++                set_state_flags (Gtk.StateFlags.SELECTED, true);
++            } else {
++                set_state_flags (Gtk.StateFlags.NORMAL, true);
++            }
++        }
++
++        public void grab_focus_force () {
++            valid_grab = true;
++            grab_focus ();
++        }
++
++        public override void grab_focus () {
++            if (valid_grab) {
++                base.grab_focus ();
++                valid_grab = false;
++            }
++        }
++
++        public void sensitive_container (bool sens) {
++            label.sensitive = sens;
++            event_grid.sensitive = sens;
++        }
++
++        private bool on_button_press (Gdk.EventButton event) {
++            if (event.type == Gdk.EventType.2BUTTON_PRESS && event.button == Gdk.BUTTON_PRIMARY)
++                on_event_add (date);
++            valid_grab = true;
++            grab_focus ();
++            return false;
++        }
++
++        private bool on_key_press (Gdk.EventKey event) {
++            if (event.keyval == Gdk.keyval_from_name ("Return") ) {
++                on_event_add (date);
++                return true;
++            }
++
++            return false;
++        }
++    }
++}
+diff --git a/src/Widgets/PanelLabel.vala b/src/Widgets/PanelLabel.vala
+index f253f9b..dff9a21 100644
+--- a/src/Widgets/PanelLabel.vala
++++ b/src/Widgets/PanelLabel.vala
+@@ -17,55 +17,57 @@
+  * Boston, MA 02110-1301 USA.
+  */
+ 
+-public class DateTime.Widgets.PanelLabel : Gtk.Grid {
+-    private Gtk.Label date_label;
+-    private Gtk.Label time_label;
+-    private Services.TimeManager time_manager;
++namespace DateTimeIndicator {
++    public class Widgets.PanelLabel : Gtk.Grid {
++        private Gtk.Label date_label;
++        private Gtk.Label time_label;
++        private Services.TimeManager time_manager;
+ 
+-    public string clock_format { get; set; }
+-    public bool clock_show_seconds { get; set; }
+-    public bool clock_show_weekday { get; set; }
++        public string clock_format { get; set; }
++        public bool clock_show_seconds { get; set; }
++        public bool clock_show_weekday { get; set; }
+ 
+-    construct {
+-        date_label = new Gtk.Label (null);
+-        date_label.margin_end = 12;
++        construct {
++            date_label = new Gtk.Label (null);
++            date_label.margin_end = 12;
+ 
+-        var date_revealer = new Gtk.Revealer ();
+-        date_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT;
+-        date_revealer.add (date_label);
++            var date_revealer = new Gtk.Revealer ();
++            date_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT;
++            date_revealer.add (date_label);
+ 
+-        time_label = new Gtk.Label (null);
++            time_label = new Gtk.Label (null);
+ 
+-        valign = Gtk.Align.CENTER;
+-        add (date_revealer);
+-        add (time_label);
++            valign = Gtk.Align.CENTER;
++            add (date_revealer);
++            add (time_label);
+ 
+-        var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
+-        clock_settings.bind ("clock-format", this, "clock-format", SettingsBindFlags.DEFAULT);
+-        clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
+-        clock_settings.bind ("clock-show-date", date_revealer, "reveal_child", SettingsBindFlags.DEFAULT);
+-        clock_settings.bind ("clock-show-weekday", this, "clock-show-weekday", SettingsBindFlags.DEFAULT);
++            var clock_settings = new GLib.Settings ("io.elementary.desktop.wingpanel.datetime");
++            clock_settings.bind ("clock-format", this, "clock-format", SettingsBindFlags.DEFAULT);
++            clock_settings.bind ("clock-show-seconds", this, "clock-show-seconds", SettingsBindFlags.DEFAULT);
++            clock_settings.bind ("clock-show-date", date_revealer, "reveal_child", SettingsBindFlags.DEFAULT);
++            clock_settings.bind ("clock-show-weekday", this, "clock-show-weekday", SettingsBindFlags.DEFAULT);
+ 
+-        notify.connect (() => {
+-            update_labels ();
+-        });
++            notify.connect (() => {
++                update_labels ();
++            });
+ 
+-        time_manager = Services.TimeManager.get_default ();
+-        time_manager.minute_changed.connect (update_labels);
+-        time_manager.notify["is-12h"].connect (update_labels);
+-    }
+-
+-    private void update_labels () {
+-        string date_format;
+-        if (clock_format == "ISO8601") {
+-            date_format = "%F";
+-        } else {
+-            date_format = Granite.DateTime.get_default_date_format (clock_show_weekday, true, false);
++            time_manager = Services.TimeManager.get_default ();
++            time_manager.minute_changed.connect (update_labels);
++            time_manager.notify["is-12h"].connect (update_labels);
+         }
+ 
+-        date_label.label = time_manager.format (date_format);
++        private void update_labels () {
++            string date_format;
++            if (clock_format == "ISO8601") {
++                date_format = "%F";
++            } else {
++                date_format = Granite.DateTime.get_default_date_format (clock_show_weekday, true, false);
++            }
+ 
+-        string time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h, clock_show_seconds);
+-        time_label.label = time_manager.format (time_format);
++            date_label.label = time_manager.format (date_format);
++
++            string time_format = Granite.DateTime.get_default_time_format (time_manager.is_12h, clock_show_seconds);
++            time_label.label = time_manager.format (time_format);
++        }
+     }
+ }
+diff --git a/src/Widgets/calendar/CalendarView.vala b/src/Widgets/calendar/CalendarView.vala
+deleted file mode 100644
+index ef3f8f9..0000000
+--- a/src/Widgets/calendar/CalendarView.vala
++++ /dev/null
+@@ -1,183 +0,0 @@
+-/*-
+- * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
+- *
+- * This program is free software: you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation, either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+- *
+- * Authored by: Maxwell Barvian
+- *              Corentin Noël <corentin@elementaryos.org>
+- */
+-
+-public class DateTime.Widgets.CalendarView : Gtk.Grid {
+-    public signal void day_double_click ();
+-    public signal void event_updates ();
+-    public signal void selection_changed (GLib.DateTime? new_date);
+-
+-    public GLib.DateTime? selected_date { get; private set; }
+-
+-    private Grid grid;
+-    private Gtk.Stack stack;
+-    private Gtk.Grid big_grid;
+-
+-    construct {
+-        var label = new Gtk.Label (new GLib.DateTime.now_local ().format (_("%OB, %Y")));
+-        label.hexpand = true;
+-        label.margin_start = 6;
+-        label.xalign = 0;
+-        label.width_chars = 13;
+-
+-        var provider = new Gtk.CssProvider ();
+-        provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/ControlHeader.css");
+-
+-        var label_style_context = label.get_style_context ();
+-        label_style_context.add_class ("header-label");
+-        label_style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-
+-        var left_button = new Gtk.Button.from_icon_name ("pan-start-symbolic");
+-        var center_button = new Gtk.Button.from_icon_name ("office-calendar-symbolic");
+-        center_button.tooltip_text = _("Go to today's date");
+-        var right_button = new Gtk.Button.from_icon_name ("pan-end-symbolic");
+-
+-        var box_buttons = new Gtk.Grid ();
+-        box_buttons.margin_end = 6;
+-        box_buttons.valign = Gtk.Align.CENTER;
+-        box_buttons.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
+-        box_buttons.add (left_button);
+-        box_buttons.add (center_button);
+-        box_buttons.add (right_button);
+-
+-        big_grid = create_big_grid ();
+-
+-        stack = new Gtk.Stack ();
+-        stack.add (big_grid);
+-        stack.show_all ();
+-        stack.expand = true;
+-
+-        stack.notify["transition-running"].connect (() => {
+-            if (stack.transition_running == false) {
+-                stack.get_children ().foreach ((child) => {
+-                    if (child != stack.visible_child) {
+-                        child.destroy ();
+-                    }
+-                });
+-            }
+-        });
+-
+-        column_spacing = 6;
+-        row_spacing = 6;
+-        margin_start = margin_end = 10;
+-        attach (label, 0, 0);
+-        attach (box_buttons, 1, 0);
+-        attach (stack, 0, 1, 2);
+-
+-        var model = CalendarModel.get_default ();
+-        model.notify["data-range"].connect (() => {
+-            label.label = model.month_start.format (_("%OB, %Y"));
+-
+-            sync_with_model ();
+-
+-            selected_date = null;
+-            selection_changed (selected_date);
+-        });
+-
+-        left_button.clicked.connect (() => {
+-            model.change_month (-1);
+-        });
+-
+-        right_button.clicked.connect (() => {
+-            model.change_month (1);
+-        });
+-
+-        center_button.clicked.connect (() => {
+-            show_today ();
+-        });
+-    }
+-
+-    private Gtk.Grid create_big_grid () {
+-        grid = new DateTime.Widgets.Grid ();
+-        grid.show_all ();
+-
+-        grid.on_event_add.connect ((date) => {
+-            show_date_in_maya (date);
+-            day_double_click ();
+-        });
+-
+-        grid.selection_changed.connect ((date) => {
+-            selected_date = date;
+-            selection_changed (date);
+-        });
+-
+-        return grid;
+-    }
+-
+-    public void show_today () {
+-        var calmodel = CalendarModel.get_default ();
+-        var today = Util.strip_time (new GLib.DateTime.now_local ());
+-        var start = Util.get_start_of_month (today);
+-        selected_date = today;
+-        if (!start.equal (calmodel.month_start)) {
+-            calmodel.month_start = start;
+-        }
+-        sync_with_model ();
+-
+-        grid.set_focus_to_today ();
+-    }
+-
+-    // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
+-    public void show_date_in_maya (GLib.DateTime date) {
+-        var command = "io.elementary.calendar --show-day %s".printf (date.format ("%F"));
+-
+-        try {
+-            var appinfo = AppInfo.create_from_commandline (command, null, AppInfoCreateFlags.NONE);
+-            appinfo.launch_uris (null, null);
+-        } catch (GLib.Error e) {
+-            var dialog = new Granite.MessageDialog.with_image_from_icon_name (
+-                _("Unable To Launch Calendar"),
+-                _("The program \"io.elementary.calendar\" may not be installed"),
+-                "dialog-error"
+-            );
+-            dialog.show_error_details (e.message);
+-            dialog.run ();
+-            dialog.destroy ();
+-        }
+-    }
+-
+-    /* Sets the calendar widgets to the date range of the model */
+-    private void sync_with_model () {
+-        var model = CalendarModel.get_default ();
+-        if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
+-            grid.update_today ();
+-            return; // nothing else to do
+-        }
+-
+-        GLib.DateTime previous_first = null;
+-        if (grid.grid_range != null)
+-            previous_first = grid.grid_range.first_dt;
+-
+-        big_grid = create_big_grid ();
+-        stack.add (big_grid);
+-
+-        grid.set_range (model.data_range, model.month_start);
+-        grid.update_weeks (model.data_range.first_dt, model.num_weeks);
+-
+-        if (previous_first != null) {
+-            if (previous_first.compare (grid.grid_range.first_dt) == -1) {
+-                stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
+-            } else {
+-                stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
+-            }
+-        }
+-
+-        stack.set_visible_child (big_grid);
+-    }
+-}
+diff --git a/src/Widgets/calendar/GridDay.vala b/src/Widgets/calendar/GridDay.vala
+deleted file mode 100644
+index a9b5a28..0000000
+--- a/src/Widgets/calendar/GridDay.vala
++++ /dev/null
+@@ -1,178 +0,0 @@
+-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
+-/*-
+- * Copyright (c) 2011–2018 elementary, Inc. (https://elementary.io)
+- *
+- * This program is free software: you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation, either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+- *
+- * Authored by: Maxwell Barvian
+- *              Corentin Noël <corentin@elementaryos.org>
+- */
+-
+-/**
+- * Represents a single day on the grid.
+- */
+-public class DateTime.Widgets.GridDay : Gtk.EventBox {
+-    /*
+-     * Event emitted when the day is double clicked or the ENTER key is pressed.
+-     */
+-    public signal void on_event_add (GLib.DateTime date);
+-
+-    public GLib.DateTime date { get; construct set; }
+-
+-    private static Gtk.CssProvider provider;
+-    private static Widgets.CalendarModel model;
+-
+-    private Gee.HashMap<string, Gtk.Widget> event_dots;
+-    private Gtk.Grid event_grid;
+-    private Gtk.Label label;
+-    private bool valid_grab = false;
+-
+-    public GridDay (GLib.DateTime date) {
+-        Object (date: date);
+-    }
+-
+-    static construct {
+-        model = Widgets.CalendarModel.get_default ();
+-
+-        provider = new Gtk.CssProvider ();
+-        provider.load_from_resource ("/io/elementary/desktop/wingpanel/datetime/GridDay.css");
+-    }
+-
+-    construct {
+-        unowned Gtk.StyleContext style_context = get_style_context ();
+-        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-        style_context.add_class ("circular");
+-
+-        label = new Gtk.Label (null);
+-
+-        event_grid = new Gtk.Grid ();
+-        event_grid.halign = Gtk.Align.CENTER;
+-        event_grid.height_request = 6;
+-
+-        var grid = new Gtk.Grid ();
+-        grid.halign = grid.valign = Gtk.Align.CENTER;
+-        grid.attach (label, 0, 0);
+-        grid.attach (event_grid, 0, 1);
+-
+-        can_focus = true;
+-        events |= Gdk.EventMask.BUTTON_PRESS_MASK;
+-        events |= Gdk.EventMask.KEY_PRESS_MASK;
+-        events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
+-        set_size_request (35, 35);
+-        halign = Gtk.Align.CENTER;
+-        hexpand = true;
+-        add (grid);
+-        show_all ();
+-
+-        // Signals and handlers
+-        button_press_event.connect (on_button_press);
+-        key_press_event.connect (on_key_press);
+-        scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
+-
+-        notify["date"].connect (() => {
+-            label.label = date.get_day_of_month ().to_string ();
+-        });
+-
+-        event_dots = new Gee.HashMap<string, Gtk.Widget> ();
+-
+-        model.events_added.connect (add_event_dots);
+-        model.events_removed.connect (remove_event_dots);
+-    }
+-
+-    private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-        foreach (var component in events) {
+-            if (event_dots.size >= 3) {
+-                return;
+-            }
+-
+-            if (Util.calcomp_is_on_day (component, date)) {
+-                unowned ICal.Component ical = component.get_icalcomponent ();
+-
+-                var event_uid = ical.get_uid ();
+-                if (!event_dots.has_key (event_uid)) {
+-                    var event_dot = new Gtk.Image ();
+-                    event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
+-                    event_dot.pixel_size = 6;
+-
+-                    unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
+-                    style_context.add_class (Granite.STYLE_CLASS_ACCENT);
+-                    style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+-
+-                    var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+-                    Util.set_event_calendar_color (source_calendar, event_dot);
+-
+-                    event_dots[event_uid] = event_dot;
+-
+-                    event_grid.add (event_dot);
+-                }
+-            }
+-        }
+-
+-        event_grid.show_all ();
+-    }
+-
+-    private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-        foreach (var component in events) {
+-            unowned ICal.Component ical = component.get_icalcomponent ();
+-            var event_uid = ical.get_uid ();
+-            var dot = event_dots[event_uid];
+-            if (dot != null) {
+-                dot.destroy ();
+-                event_dots.remove (event_uid);
+-            }
+-        }
+-    }
+-
+-    public void set_selected (bool selected) {
+-        if (selected) {
+-            set_state_flags (Gtk.StateFlags.SELECTED, true);
+-        } else {
+-            set_state_flags (Gtk.StateFlags.NORMAL, true);
+-        }
+-    }
+-
+-    public void grab_focus_force () {
+-        valid_grab = true;
+-        grab_focus ();
+-    }
+-
+-    public override void grab_focus () {
+-        if (valid_grab) {
+-            base.grab_focus ();
+-            valid_grab = false;
+-        }
+-    }
+-
+-    public void sensitive_container (bool sens) {
+-        label.sensitive = sens;
+-        event_grid.sensitive = sens;
+-    }
+-
+-    private bool on_button_press (Gdk.EventButton event) {
+-        if (event.type == Gdk.EventType.2BUTTON_PRESS && event.button == Gdk.BUTTON_PRIMARY)
+-            on_event_add (date);
+-        valid_grab = true;
+-        grab_focus ();
+-        return false;
+-    }
+-
+-    private bool on_key_press (Gdk.EventKey event) {
+-        if (event.keyval == Gdk.keyval_from_name ("Return") ) {
+-            on_event_add (date);
+-            return true;
+-        }
+-
+-        return false;
+-    }
+-}
+
+From 11f11073d74dac1d831560c3a92687531aaf846e Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Thu, 9 Apr 2020 20:46:31 +0300
+Subject: [PATCH 2/8] Events list moved to a separate file
+
+---
+ meson.build                    |   1 +
+ src/Indicator.vala             | 113 +++------------------------------
+ src/Widgets/EventsListBox.vala | 102 +++++++++++++++++++++++++++++
+ 3 files changed, 113 insertions(+), 103 deletions(-)
+ create mode 100644 src/Widgets/EventsListBox.vala
+
+diff --git a/meson.build b/meson.build
+index b44c5bd..1b52276 100644
+--- a/meson.build
++++ b/meson.build
+@@ -46,6 +46,7 @@ shared_module(
+     'src/Models/CalendarModel.vala',
+     'src/Widgets/CalendarView.vala',
+     'src/Widgets/EventRow.vala',
++    'src/Widgets/EventsListBox.vala',
+     'src/Widgets/Grid.vala',
+     'src/Widgets/GridDay.vala',
+     'src/Widgets/PanelLabel.vala',
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index b712c12..6a8d001 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -22,9 +22,9 @@ namespace DateTimeIndicator {
+         public static GLib.Settings settings;
+ 
+         private Widgets.PanelLabel panel_label;
+-        private Gtk.Grid main_grid;
+         private Widgets.CalendarView calendar;
+-        private Gtk.ListBox event_listbox;
++        private Widgets.EventsListBox event_listbox;
++        private Gtk.Grid main_grid;
+         private uint update_events_idle_source = 0;
+ 
+         public Indicator () {
+@@ -56,24 +56,7 @@ namespace DateTimeIndicator {
+                 calendar = new Widgets.CalendarView ();
+                 calendar.margin_bottom = 6;
+ 
+-                var placeholder_label = new Gtk.Label (_("No Events on This Day"));
+-                placeholder_label.wrap = true;
+-                placeholder_label.wrap_mode = Pango.WrapMode.WORD;
+-                placeholder_label.margin_start = 12;
+-                placeholder_label.margin_end = 12;
+-                placeholder_label.max_width_chars = 20;
+-                placeholder_label.justify = Gtk.Justification.CENTER;
+-                placeholder_label.show_all ();
+-
+-                var placeholder_style_context = placeholder_label.get_style_context ();
+-                placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
+-                placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
+-
+-                event_listbox = new Gtk.ListBox ();
+-                event_listbox.selection_mode = Gtk.SelectionMode.NONE;
+-                event_listbox.set_header_func (header_update_func);
+-                event_listbox.set_placeholder (placeholder_label);
+-                event_listbox.set_sort_func (sort_function);
++                event_listbox = new Widgets.EventsListBox ();
+ 
+                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
+                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
+@@ -84,11 +67,11 @@ namespace DateTimeIndicator {
+ 
+                 main_grid = new Gtk.Grid ();
+                 main_grid.margin_top = 12;
+-                main_grid.attach (calendar, 0, 0);
+-                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0);
+-                main_grid.attach (scrolled_window, 2, 0);
+-                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 2, 3);
+-                main_grid.attach (settings_button, 0, 3, 3);
++                main_grid.attach (calendar,                                     0, 0);
++                main_grid.attach (new Wingpanel.Widgets.Separator (),           0, 1);
++                main_grid.attach (settings_button,                              0, 2);
++                main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 3);
++                main_grid.attach (scrolled_window,                              2, 0, 1, 3);
+ 
+                 var size_group = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL);
+                 size_group.add_widget (calendar);
+@@ -119,52 +102,6 @@ namespace DateTimeIndicator {
+             return main_grid;
+         }
+ 
+-        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
+-            var row = (EventRow) lbrow;
+-            if (lbbefore != null) {
+-                var before = (EventRow) lbbefore;
+-                if (row.is_allday == before.is_allday) {
+-                    row.set_header (null);
+-                    return;
+-                }
+-
+-                if (row.is_allday != before.is_allday) {
+-                    var header_label = new Granite.HeaderLabel (_("During the Day"));
+-                    header_label.margin_start = header_label.margin_end = 6;
+-
+-                    row.set_header (header_label);
+-                    return;
+-                }
+-            } else {
+-                if (row.is_allday) {
+-                    var allday_header = new Granite.HeaderLabel (_("All Day"));
+-                    allday_header.margin_start = allday_header.margin_end = 6;
+-
+-                    row.set_header (allday_header);
+-                }
+-                return;
+-            }
+-        }
+-
+-        [CCode (instance_pos = -1)]
+-        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
+-            var e1 = (EventRow) child1;
+-            var e2 = (EventRow) child2;
+-
+-            if (e1.start_time.compare (e2.start_time) != 0) {
+-                return e1.start_time.compare (e2.start_time);
+-            }
+-
+-            // If they have the same date, sort them wholeday first
+-            if (e1.is_allday) {
+-                return -1;
+-            } else if (e2.is_allday) {
+-                return 1;
+-            }
+-
+-            return 0;
+-        }
+-
+         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
+             idle_update_events ();
+         }
+@@ -174,42 +111,12 @@ namespace DateTimeIndicator {
+                 GLib.Source.remove (update_events_idle_source);
+             }
+ 
+-            update_events_idle_source = GLib.Idle.add (update_events);
+-        }
+-
+-        private bool update_events () {
+-            foreach (unowned Gtk.Widget widget in event_listbox.get_children ()) {
+-                widget.destroy ();
+-            }
++            update_events_idle_source = GLib.Idle.add (() => {
++                event_listbox.update_events (calendar.selected_date);
+ 
+-            if (calendar.selected_date == null) {
+                 update_events_idle_source = 0;
+                 return GLib.Source.REMOVE;
+-            }
+-
+-            var date = calendar.selected_date;
+-
+-            var model = Models.CalendarModel.get_default ();
+-
+-            var events_on_day = new Gee.TreeMap<string, EventRow> ();
+-
+-            model.source_events.@foreach ((source, component_map) => {
+-                foreach (var comp in component_map.get_values ()) {
+-                    if (Util.calcomp_is_on_day (comp, date)) {
+-                        unowned ICal.Component ical = comp.get_icalcomponent ();
+-                        var event_uid = ical.get_uid ();
+-                        if (!events_on_day.has_key (event_uid)) {
+-                            events_on_day[event_uid] = new EventRow (date, ical, source);
+-
+-                            event_listbox.add (events_on_day[event_uid]);
+-                        }
+-                    }
+-                }
+             });
+-
+-            event_listbox.show_all ();
+-            update_events_idle_source = 0;
+-            return GLib.Source.REMOVE;
+         }
+ 
+         public override void opened () {
+diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
+new file mode 100644
+index 0000000..547e4c5
+--- /dev/null
++++ b/src/Widgets/EventsListBox.vala
+@@ -0,0 +1,102 @@
++namespace DateTimeIndicator {
++    public class Widgets.EventsListBox : Gtk.ListBox {
++
++        public EventsListBox () {
++            selection_mode = Gtk.SelectionMode.NONE;
++
++            var placeholder_label = new Gtk.Label (_("No Events on This Day"));
++            placeholder_label.wrap = true;
++            placeholder_label.wrap_mode = Pango.WrapMode.WORD;
++            placeholder_label.margin_start = 12;
++            placeholder_label.margin_end = 12;
++            placeholder_label.max_width_chars = 20;
++            placeholder_label.justify = Gtk.Justification.CENTER;
++            placeholder_label.show_all ();
++
++            var placeholder_style_context = placeholder_label.get_style_context ();
++            placeholder_style_context.add_class (Gtk.STYLE_CLASS_DIM_LABEL);
++            placeholder_style_context.add_class (Granite.STYLE_CLASS_H3_LABEL);
++
++            set_header_func (header_update_func);
++            set_placeholder (placeholder_label);
++            set_sort_func (sort_function);
++        }
++
++        public void update_events (GLib.DateTime? selected_date) {
++            foreach (unowned Gtk.Widget widget in get_children ()) {
++                widget.destroy ();
++            }
++
++            if (selected_date == null) {
++                return;
++            }
++
++            var model = Models.CalendarModel.get_default ();
++
++            var events_on_day = new Gee.TreeMap<string, EventRow> ();
++
++            model.source_events.@foreach ((source, component_map) => {
++                foreach (var comp in component_map.get_values ()) {
++                    if (Util.calcomp_is_on_day (comp, selected_date)) {
++                        unowned ICal.Component ical = comp.get_icalcomponent ();
++                        var event_uid = ical.get_uid ();
++                        if (!events_on_day.has_key (event_uid)) {
++                            events_on_day[event_uid] = new EventRow (selected_date, ical, source);
++
++                            add (events_on_day[event_uid]);
++                        }
++                    }
++                }
++            });
++
++            show_all ();
++            return;
++        }
++
++        private void header_update_func (Gtk.ListBoxRow lbrow, Gtk.ListBoxRow? lbbefore) {
++            var row = (EventRow) lbrow;
++            if (lbbefore != null) {
++                var before = (EventRow) lbbefore;
++                if (row.is_allday == before.is_allday) {
++                    row.set_header (null);
++                    return;
++                }
++
++                if (row.is_allday != before.is_allday) {
++                    var header_label = new Granite.HeaderLabel (_("During the Day"));
++                    header_label.margin_start = header_label.margin_end = 6;
++
++                    row.set_header (header_label);
++                    return;
++                }
++            } else {
++                if (row.is_allday) {
++                    var allday_header = new Granite.HeaderLabel (_("All Day"));
++                    allday_header.margin_start = allday_header.margin_end = 6;
++
++                    row.set_header (allday_header);
++                }
++                return;
++            }
++        }
++
++        [CCode (instance_pos = -1)]
++        private int sort_function (Gtk.ListBoxRow child1, Gtk.ListBoxRow child2) {
++            var e1 = (EventRow) child1;
++            var e2 = (EventRow) child2;
++
++            if (e1.start_time.compare (e2.start_time) != 0) {
++                return e1.start_time.compare (e2.start_time);
++            }
++
++            // If they have the same date, sort them wholeday first
++            if (e1.is_allday) {
++                return -1;
++            } else if (e2.is_allday) {
++                return 1;
++            }
++
++            return 0;
++        }
++    }
++}
+
+From 262d91676f78f031bcfbff637344e52c63ab89bd Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Sat, 11 Apr 2020 21:56:33 +0300
+Subject: [PATCH 3/8] added event manager
+
+---
+ meson.build                     |   1 +
+ src/Indicator.vala              |  38 ++++--
+ src/Models/CalendarModel.vala   | 224 +------------------------------
+ src/Services/EventsManager.vala | 226 ++++++++++++++++++++++++++++++++
+ src/Util/Util.vala              |  57 ++------
+ src/Widgets/CalendarView.vala   |   9 ++
+ src/Widgets/EventsListBox.vala  |   7 +-
+ src/Widgets/Grid.vala           |  31 +++++
+ src/Widgets/GridDay.vala        | 111 +++++++++++-----
+ 9 files changed, 385 insertions(+), 319 deletions(-)
+ create mode 100644 src/Services/EventsManager.vala
+
+diff --git a/meson.build b/meson.build
+index 1b52276..e348e3d 100644
+--- a/meson.build
++++ b/meson.build
+@@ -50,6 +50,7 @@ shared_module(
+     'src/Widgets/Grid.vala',
+     'src/Widgets/GridDay.vala',
+     'src/Widgets/PanelLabel.vala',
++    'src/Services/EventsManager.vala',
+     'src/Services/TimeManager.vala',
+     dependencies: [
+         dependency('glib-2.0'),
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index 6a8d001..bf4358f 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -24,9 +24,14 @@ namespace DateTimeIndicator {
+         private Widgets.PanelLabel panel_label;
+         private Widgets.CalendarView calendar;
+         private Widgets.EventsListBox event_listbox;
++
++        private Services.EventsManager event_manager;
++
+         private Gtk.Grid main_grid;
+         private uint update_events_idle_source = 0;
+ 
++        private bool opened_widget = false;
++
+         public Indicator () {
+             Object (
+                 code_name: Wingpanel.Indicator.DATETIME,
+@@ -56,10 +61,22 @@ namespace DateTimeIndicator {
+                 calendar = new Widgets.CalendarView ();
+                 calendar.margin_bottom = 6;
+ 
++                event_manager = new Services.EventsManager ();
++                event_manager.events_updated.connect (update_events_model);
++                event_manager.events_added.connect ((source, events) => {
++                    calendar.add_event_dots (source, events);
++                    update_events_model (source, events);
++                });
++                event_manager.events_removed.connect ((source, events) => {
++                    calendar.remove_event_dots (source, events);
++                    update_events_model (source, events);
++                });
++
+                 event_listbox = new Widgets.EventsListBox ();
+ 
+                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
+                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
++                scrolled_window.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
+                 scrolled_window.add (event_listbox);
+ 
+                 var settings_button = new Gtk.ModelButton ();
+@@ -90,6 +107,12 @@ namespace DateTimeIndicator {
+                     close ();
+                 });
+ 
++                var model = Models.CalendarModel.get_default ();
++                model.notify["month-start"].connect (() => {
++                    model.compute_ranges ();
++                    event_manager.load_all_sources ();
++                });
++
+                 settings_button.clicked.connect (() => {
+                     try {
+                         AppInfo.launch_default_for_uri ("settings://time", null);
+@@ -103,7 +126,9 @@ namespace DateTimeIndicator {
+         }
+ 
+         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
+-            idle_update_events ();
++            if (opened_widget) {
++                idle_update_events ();
++            }
+         }
+ 
+         private void idle_update_events () {
+@@ -112,7 +137,7 @@ namespace DateTimeIndicator {
+             }
+ 
+             update_events_idle_source = GLib.Idle.add (() => {
+-                event_listbox.update_events (calendar.selected_date);
++                event_listbox.update_events (calendar.selected_date, event_manager.source_events);
+ 
+                 update_events_idle_source = 0;
+                 return GLib.Source.REMOVE;
+@@ -122,18 +147,15 @@ namespace DateTimeIndicator {
+         public override void opened () {
+             calendar.show_today ();
+ 
+-            Models.CalendarModel.get_default ().events_added.connect (update_events_model);
+-            Models.CalendarModel.get_default ().events_updated.connect (update_events_model);
+-            Models.CalendarModel.get_default ().events_removed.connect (update_events_model);
++            opened_widget = true;
+         }
+ 
+         public override void closed () {
+-            Models.CalendarModel.get_default ().events_added.disconnect (update_events_model);
+-            Models.CalendarModel.get_default ().events_updated.disconnect (update_events_model);
+-            Models.CalendarModel.get_default ().events_removed.disconnect (update_events_model);
++            opened_widget = false;
+         }
+     }
+ }
++
+ public Wingpanel.Indicator get_indicator (Module module) {
+     debug ("Activating DateTime Indicator");
+     var indicator = new DateTimeIndicator.Indicator ();
+diff --git a/src/Models/CalendarModel.vala b/src/Models/CalendarModel.vala
+index 965b93e..d60a9ac 100644
+--- a/src/Models/CalendarModel.vala
++++ b/src/Models/CalendarModel.vala
+@@ -35,17 +35,6 @@ namespace DateTimeIndicator {
+         /* The start of week, ie. Monday=1 or Sunday=7 */
+         public GLib.DateWeekday week_starts_on { get; set; }
+ 
+-        public HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events { get; private set; }
+-
+-        /* Notifies when events are added, updated, or removed */
+-        public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
+-        public signal void events_updated (E.Source source, Gee.Collection<ECal.Component> events);
+-        public signal void events_removed (E.Source source, Gee.Collection<ECal.Component> events);
+-
+-        private E.SourceRegistry registry { get; private set; }
+-        private HashTable<string, ECal.Client> source_client;
+-        private HashTable<string, ECal.ClientView> source_view;
+-
+         private static CalendarModel? calendar_model = null;
+ 
+         public static CalendarModel get_default () {
+@@ -59,12 +48,6 @@ namespace DateTimeIndicator {
+         }
+ 
+         construct {
+-            open.begin ();
+-
+-            source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
+-            source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
+-            source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
+-
+             int week_start = Posix.NLTime.FIRST_WEEKDAY.to_string ().data[0];
+             if (week_start >= 1 && week_start <= 7) {
+                 week_starts_on = (GLib.DateWeekday) (week_start - 1);
+@@ -72,66 +55,6 @@ namespace DateTimeIndicator {
+ 
+             month_start = Util.get_start_of_month ();
+             compute_ranges ();
+-            notify["month-start"].connect (on_parameter_changed);
+-        }
+-
+-        private async void open () {
+-            try {
+-                registry = yield new E.SourceRegistry (null);
+-                registry.source_removed.connect (remove_source);
+-                registry.source_added.connect ((source) => add_source_async.begin (source));
+-
+-                // Add sources
+-                registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
+-                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+-                    if (cal.selected == true && source.enabled == true) {
+-                        add_source_async.begin (source);
+-                    }
+-                });
+-
+-                load_all_sources ();
+-            } catch (GLib.Error error) {
+-                critical (error.message);
+-            }
+-        }
+-
+-        private void load_all_sources () {
+-            lock (source_client) {
+-                foreach (var id in source_client.get_keys ()) {
+-                    var source = registry.ref_source (id);
+-                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+-
+-                    if (cal.selected == true && source.enabled == true) {
+-                        load_source (source);
+-                    }
+-                }
+-            }
+-        }
+-
+-        private void remove_source (E.Source source) {
+-            debug ("Removing source '%s'", source.dup_display_name ());
+-            /* Already out of the model, so do nothing */
+-            unowned string uid = source.get_uid ();
+-
+-            if (!source_view.contains (uid)) {
+-                return;
+-            }
+-
+-            var current_view = source_view.get (uid);
+-            try {
+-                current_view.stop ();
+-            } catch (Error e) {
+-                warning (e.message);
+-            }
+-
+-            source_view.remove (uid);
+-            lock (source_client) {
+-                source_client.remove (uid);
+-            }
+-
+-            var events = source_events.get (source).get_values ().read_only_view;
+-            events_removed (source, events);
+-            source_events.remove (source);
+         }
+ 
+         public void change_month (int relative) {
+@@ -144,7 +67,7 @@ namespace DateTimeIndicator {
+ 
+         /* --- Helper Methods ---// */
+ 
+-        private void compute_ranges () {
++        public void compute_ranges () {
+             var month_end = month_start.add_full (0, 1, -1);
+ 
+             int dow = month_start.get_day_of_week ();
+@@ -182,150 +105,5 @@ namespace DateTimeIndicator {
+ 
+             debug (@"Date ranges: ($data_range_first <= $month_start < $month_end <= $data_range_last)");
+         }
+-
+-        private void load_source (E.Source source) {
+-            /* create empty source-event map */
+-            var events = new Gee.TreeMultiMap<string, ECal.Component> (
+-                (GLib.CompareDataFunc<ECal.Component>?) GLib.strcmp,
+-                (GLib.CompareDataFunc<ECal.Component>?) Util.calcomponent_compare_func
+-            );
+-            source_events.set (source, events);
+-            /* query client view */
+-            var iso_first = ECal.isodate_from_time_t ((time_t)data_range.first_dt.to_unix ());
+-            var iso_last = ECal.isodate_from_time_t ((time_t)data_range.last_dt.add_days (1).to_unix ());
+-            var query = @"(occur-in-time-range? (make-time \"$iso_first\") (make-time \"$iso_last\"))";
+-
+-            ECal.Client client;
+-            lock (source_client) {
+-                client = source_client.get (source.dup_uid ());
+-            }
+-
+-            if (client == null) {
+-                return;
+-            }
+-
+-            debug ("Getting client-view for source '%s'", source.dup_display_name ());
+-            client.get_view.begin (query, null, (obj, results) => {
+-                var view = on_client_view_received (results, source, client);
+-                view.objects_added.connect ((objects) => on_objects_added (source, client, objects));
+-                view.objects_removed.connect ((objects) => on_objects_removed (source, client, objects));
+-                view.objects_modified.connect ((objects) => on_objects_modified (source, client, objects));
+-                try {
+-                    view.start ();
+-                } catch (Error e) {
+-                    critical (e.message);
+-                }
+-
+-                source_view.set (source.dup_uid (), view);
+-            });
+-        }
+-
+-        private async void add_source_async (E.Source source) {
+-            debug ("Adding source '%s'", source.dup_display_name ());
+-            try {
+-                var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
+-                source_client.insert (source.dup_uid (), client);
+-            } catch (Error e) {
+-                critical (e.message);
+-            }
+-
+-            Idle.add (() => {
+-                load_source (source);
+-
+-                return false;
+-            });
+-        }
+-
+-        private void debug_event (E.Source source, ECal.Component event) {
+-            unowned ICal.Component comp = event.get_icalcomponent ();
+-            debug (@"Event ['$(comp.get_summary())', $(source.dup_display_name()), $(comp.get_uid()))]");
+-        }
+-
+-        /* --- Signal Handlers ---// */
+-        private void on_parameter_changed () {
+-            compute_ranges ();
+-            load_all_sources ();
+-        }
+-
+-        private ECal.ClientView on_client_view_received (AsyncResult results, E.Source source, ECal.Client client) {
+-            ECal.ClientView view;
+-            try {
+-                debug ("Received client-view for source '%s'", source.dup_display_name ());
+-                bool status = client.get_view.end (results, out view);
+-                assert (status == true);
+-            } catch (Error e) {
+-                critical ("Error loading client-view from source '%s': %s", source.dup_display_name (), e.message);
+-            }
+-
+-            return view;
+-        }
+-
+-#if E_CAL_2_0
+-        private void on_objects_added (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
+-#else
+-        private void on_objects_added (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
+-#endif
+-            debug (@"Received $(objects.length()) added event(s) for source '%s'", source.dup_display_name ());
+-            var events = source_events.get (source);
+-            var added_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
+-            objects.foreach ((comp) => {
+-                unowned string uid = comp.get_uid ();
+-#if E_CAL_2_0
+-                client.generate_instances_for_object_sync (comp, (time_t) data_range.first_dt.to_unix (), (time_t) data_range.last_dt.to_unix (), null, (comp, start, end) => {
+-                    var event = new ECal.Component.from_icalcomponent (comp);
+-#else
+-                client.generate_instances_for_object_sync (comp, (time_t) data_range.first_dt.to_unix (), (time_t) data_range.last_dt.to_unix (), (event, start, end) => {
+-#endif
+-                    debug_event (source, event);
+-                    events.set (uid, event);
+-                    added_events.add (event);
+-                    return true;
+-                });
+-            });
+-        }
+-
+-#if E_CAL_2_0
+-        private void on_objects_modified (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
+-#else
+-        private void on_objects_modified (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
+-#endif
+-            debug (@"Received $(objects.length()) modified event(s) for source '%s'", source.dup_display_name ());
+-            var updated_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
+-
+-            objects.foreach ((comp) => {
+-                unowned string uid = comp.get_uid ();
+-                var events = source_events.get (source).get (uid);
+-                updated_events.add_all (events);
+-                foreach (var event in events) {
+-                    debug_event (source, event);
+-                }
+-            });
+-
+-            events_updated (source, updated_events.read_only_view);
+-        }
+-
+-#if E_CAL_2_0
+-        private void on_objects_removed (E.Source source, ECal.Client client, SList<ECal.ComponentId?> cids) {
+-#else
+-        private void on_objects_removed (E.Source source, ECal.Client client, SList<weak ECal.ComponentId?> cids) {
+-#endif
+-            debug (@"Received $(cids.length()) removed event(s) for source '%s'", source.dup_display_name ());
+-            var events = source_events.get (source);
+-            var removed_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
+-
+-            cids.foreach ((cid) => {
+-                if (cid == null) {
+-                    return;
+-                }
+-
+-                var comps = events.get (cid.get_uid ());
+-                foreach (ECal.Component event in comps) {
+-                    removed_events.add (event);
+-                    debug_event (source, event);
+-                }
+-            });
+-
+-            events_removed (source, removed_events.read_only_view);
+-        }
+     }
+ }
+diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
+new file mode 100644
+index 0000000..d939777
+--- /dev/null
++++ b/src/Services/EventsManager.vala
+@@ -0,0 +1,226 @@
++namespace DateTimeIndicator {
++    public class Services.EventsManager : GLib.Object {
++        public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
++        public signal void events_updated (E.Source source, Gee.Collection<ECal.Component> events);
++        public signal void events_removed (E.Source source, Gee.Collection<ECal.Component> events);
++
++        public HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events { get; private set; }
++
++        private E.SourceRegistry registry { get; private set; }
++        private HashTable<string, ECal.Client> source_client;
++        private HashTable<string, ECal.ClientView> source_view;
++
++        public EventsManager () {
++
++        }
++
++        construct {
++            source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
++            source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
++            source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
++
++            open.begin ();
++        }
++
++        private async void open () {
++            try {
++                registry = yield new E.SourceRegistry (null);
++                registry.source_removed.connect (remove_source);
++                registry.source_added.connect ((source) => add_source_async.begin (source));
++
++                // Add sources
++                registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
++                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++                    if (cal.selected == true && source.enabled == true) {
++                        add_source_async.begin (source);
++                    }
++                });
++
++                load_all_sources ();
++            } catch (GLib.Error error) {
++                critical (error.message);
++            }
++        }
++
++        public void load_all_sources () {
++            lock (source_client) {
++                foreach (var id in source_client.get_keys ()) {
++                    var source = registry.ref_source (id);
++                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++
++                    if (cal.selected == true && source.enabled == true) {
++                        load_source (source);
++                    }
++                }
++            }
++        }
++
++        private void remove_source (E.Source source) {
++            debug ("Removing source '%s'", source.dup_display_name ());
++            /* Already out of the model, so do nothing */
++            unowned string uid = source.get_uid ();
++
++            if (!source_view.contains (uid)) {
++                return;
++            }
++
++            var current_view = source_view.get (uid);
++            try {
++                current_view.stop ();
++            } catch (Error e) {
++                warning (e.message);
++            }
++
++            source_view.remove (uid);
++            lock (source_client) {
++                source_client.remove (uid);
++            }
++
++            var events = source_events.get (source).get_values ().read_only_view;
++            events_removed (source, events);
++            source_events.remove (source);
++        }
++
++        private void load_source (E.Source source) {
++            var model = Models.CalendarModel.get_default ();
++
++            /* create empty source-event map */
++            var events = new Gee.TreeMultiMap<string, ECal.Component> (
++                (GLib.CompareDataFunc<ECal.Component>?) GLib.strcmp,
++                (GLib.CompareDataFunc<ECal.Component>?) Util.calcomponent_compare_func
++            );
++            source_events.set (source, events);
++            /* query client view */
++            var iso_first = ECal.isodate_from_time_t ((time_t) model.data_range.first_dt.to_unix ());
++            var iso_last = ECal.isodate_from_time_t ((time_t) model.data_range.last_dt.add_days (1).to_unix ());
++            var query = @"(occur-in-time-range? (make-time \"$iso_first\") (make-time \"$iso_last\"))";
++
++            ECal.Client client;
++            lock (source_client) {
++                client = source_client.get (source.dup_uid ());
++            }
++
++            if (client == null) {
++                return;
++            }
++
++            debug ("Getting client-view for source '%s'", source.dup_display_name ());
++            client.get_view.begin (query, null, (obj, results) => {
++                var view = on_client_view_received (results, source, client);
++                view.objects_added.connect ((objects) => on_objects_added (source, client, objects));
++                view.objects_removed.connect ((objects) => on_objects_removed (source, client, objects));
++                view.objects_modified.connect ((objects) => on_objects_modified (source, client, objects));
++                try {
++                    view.start ();
++                } catch (Error e) {
++                    critical (e.message);
++                }
++
++                source_view.set (source.dup_uid (), view);
++            });
++        }
++
++        private async void add_source_async (E.Source source) {
++            debug ("Adding source '%s'", source.dup_display_name ());
++            try {
++                var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
++                source_client.insert (source.dup_uid (), client);
++            } catch (Error e) {
++                critical (e.message);
++            }
++
++            Idle.add (() => {
++                load_source (source);
++
++                return false;
++            });
++        }
++
++        private void debug_event (E.Source source, ECal.Component event) {
++            unowned ICal.Component comp = event.get_icalcomponent ();
++            debug (@"Event ['$(comp.get_summary())', $(source.dup_display_name()), $(comp.get_uid()))]");
++        }
++
++        private ECal.ClientView on_client_view_received (AsyncResult results, E.Source source, ECal.Client client) {
++            ECal.ClientView view;
++            try {
++                debug ("Received client-view for source '%s'", source.dup_display_name ());
++                bool status = client.get_view.end (results, out view);
++                assert (status == true);
++            } catch (Error e) {
++                critical ("Error loading client-view from source '%s': %s", source.dup_display_name (), e.message);
++            }
++
++            return view;
++        }
++
++#if E_CAL_2_0
++        private void on_objects_added (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
++#else
++        private void on_objects_added (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
++#endif
++            debug (@"Received $(objects.length()) added event(s) for source '%s'", source.dup_display_name ());
++            var events = source_events.get (source);
++            var added_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
++            var model = Models.CalendarModel.get_default ();
++            objects.foreach ((comp) => {
++                unowned string uid = comp.get_uid ();
++#if E_CAL_2_0
++                client.generate_instances_for_object_sync (comp, (time_t) model.data_range.first_dt.to_unix (), (time_t) model.data_range.last_dt.to_unix (), null, (comp, start, end) => {
++                    var event = new ECal.Component.from_icalcomponent (comp);
++#else
++                client.generate_instances_for_object_sync (comp, (time_t) model.data_range.first_dt.to_unix (), (time_t) model.data_range.last_dt.to_unix (), (event, start, end) => {
++#endif
++                    debug_event (source, event);
++                    events.set (uid, event);
++                    added_events.add (event);
++                    return true;
++                });
++            });
++        }
++
++#if E_CAL_2_0
++        private void on_objects_modified (E.Source source, ECal.Client client, SList<ICal.Component> objects) {
++#else
++        private void on_objects_modified (E.Source source, ECal.Client client, SList<weak ICal.Component> objects) {
++#endif
++            debug (@"Received $(objects.length()) modified event(s) for source '%s'", source.dup_display_name ());
++            var updated_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
++
++            objects.foreach ((comp) => {
++                unowned string uid = comp.get_uid ();
++                var events = source_events.get (source).get (uid);
++                updated_events.add_all (events);
++                foreach (var event in events) {
++                    debug_event (source, event);
++                }
++            });
++
++            events_updated (source, updated_events.read_only_view);
++        }
++
++#if E_CAL_2_0
++        private void on_objects_removed (E.Source source, ECal.Client client, SList<ECal.ComponentId?> cids) {
++#else
++        private void on_objects_removed (E.Source source, ECal.Client client, SList<weak ECal.ComponentId?> cids) {
++#endif
++            debug (@"Received $(cids.length()) removed event(s) for source '%s'", source.dup_display_name ());
++            var events = source_events.get (source);
++            var removed_events = new Gee.ArrayList<ECal.Component> ((Gee.EqualDataFunc<ECal.Component>?) Util.calcomponent_equal_func);
++
++            cids.foreach ((cid) => {
++                if (cid == null) {
++                    return;
++                }
++
++                var comps = events.get (cid.get_uid ());
++                foreach (ECal.Component event in comps) {
++                    removed_events.add (event);
++                    debug_event (source, event);
++                }
++            });
++
++            events_removed (source, removed_events.read_only_view);
++        }
++    }
++}
+diff --git a/src/Util/Util.vala b/src/Util/Util.vala
+index c261f4b..b0bdf98 100644
+--- a/src/Util/Util.vala
++++ b/src/Util/Util.vala
+@@ -20,47 +20,6 @@
+  */
+ 
+ namespace DateTimeIndicator.Util {
+-    static bool has_scrolled = false;
+-
+-    public bool on_scroll_event (Gdk.EventScroll event) {
+-        double delta_x;
+-        double delta_y;
+-        event.get_scroll_deltas (out delta_x, out delta_y);
+-
+-        double choice = delta_x;
+-
+-        if (((int)delta_x).abs () < ((int)delta_y).abs ()) {
+-            choice = delta_y;
+-        }
+-
+-        /* It's mouse scroll ! */
+-        if (choice == 1 || choice == -1) {
+-            Models.CalendarModel.get_default ().change_month ((int)choice);
+-
+-            return true;
+-        }
+-
+-        if (has_scrolled == true) {
+-            return true;
+-        }
+-
+-        if (choice > 0.3) {
+-            reset_timer.begin ();
+-            Models.CalendarModel.get_default ().change_month (1);
+-
+-            return true;
+-        }
+-
+-        if (choice < -0.3) {
+-            reset_timer.begin ();
+-            Models.CalendarModel.get_default ().change_month (-1);
+-
+-            return true;
+-        }
+-
+-        return false;
+-    }
+-
+     public GLib.DateTime get_start_of_month (owned GLib.DateTime? date = null) {
+         if (date == null) {
+             date = new GLib.DateTime.now_local ();
+@@ -225,12 +184,12 @@ namespace DateTimeIndicator.Util {
+         return a.dup_uid () == b.dup_uid ();
+     }
+ 
+-    public async void reset_timer () {
+-        has_scrolled = true;
+-        Timeout.add (500, () => {
+-            has_scrolled = false;
+-
+-            return false;
+-        });
+-    }
++    // public async void reset_timer () {
++    //     has_scrolled = true;
++    //     Timeout.add (500, () => {
++    //         has_scrolled = false;
++    //
++    //         return false;
++    //     });
++    // }
+ }
+diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
+index 65cee28..070580f 100644
+--- a/src/Widgets/CalendarView.vala
++++ b/src/Widgets/CalendarView.vala
+@@ -181,5 +181,14 @@ namespace DateTimeIndicator {
+ 
+             stack.set_visible_child (big_grid);
+         }
++
++        public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            grid.add_event_dots (source, events);
++        }
++
++
++        public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            grid.remove_event_dots (source, events);
++        }
+     }
+ }
+diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
+index 547e4c5..c25af2e 100644
+--- a/src/Widgets/EventsListBox.vala
++++ b/src/Widgets/EventsListBox.vala
+@@ -1,6 +1,5 @@
+ namespace DateTimeIndicator {
+     public class Widgets.EventsListBox : Gtk.ListBox {
+-
+         public EventsListBox () {
+             selection_mode = Gtk.SelectionMode.NONE;
+ 
+@@ -22,7 +21,7 @@ namespace DateTimeIndicator {
+             set_sort_func (sort_function);
+         }
+ 
+-        public void update_events (GLib.DateTime? selected_date) {
++        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
+             foreach (unowned Gtk.Widget widget in get_children ()) {
+                 widget.destroy ();
+             }
+@@ -31,11 +30,9 @@ namespace DateTimeIndicator {
+                 return;
+             }
+ 
+-            var model = Models.CalendarModel.get_default ();
+-
+             var events_on_day = new Gee.TreeMap<string, EventRow> ();
+ 
+-            model.source_events.@foreach ((source, component_map) => {
++            source_events.@foreach ((source, component_map) => {
+                 foreach (var comp in component_map.get_values ()) {
+                     if (Util.calcomp_is_on_day (comp, selected_date)) {
+                         unowned ICal.Component ical = comp.get_icalcomponent ();
+diff --git a/src/Widgets/Grid.vala b/src/Widgets/Grid.vala
+index 165d11d..660f212 100644
+--- a/src/Widgets/Grid.vala
++++ b/src/Widgets/Grid.vala
+@@ -261,5 +261,36 @@ namespace DateTimeIndicator {
+             return date.get_year () * 10000 + date.get_month () * 100 + date.get_day_of_month ();
+         }
+ 
++        public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            data.foreach ((entry) => {
++
++                foreach (var component in events) {
++                    if (entry.value.skip_day ()) {
++                        return true;
++                    }
++
++                    if (Util.calcomp_is_on_day (component, entry.value.date)) {
++                        entry.value.add_dots (source, component.get_icalcomponent ());
++                    }
++                }
++
++                entry.value.show_event_grid ();
++
++                return true;
++            });
++        }
++
++        public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
++            foreach (var component in events) {
++                unowned ICal.Component ical = component.get_icalcomponent ();
++                var event_uid = ical.get_uid ();
++                data.foreach ((entry) => {
++                    if (entry.value.exist_event (event_uid)) {
++                        entry.value.remove_dots (event_uid);
++                    }
++                    return true;
++                });
++            }
++        }
+     }
+ }
+diff --git a/src/Widgets/GridDay.vala b/src/Widgets/GridDay.vala
+index 8c44443..00f82ea 100644
+--- a/src/Widgets/GridDay.vala
++++ b/src/Widgets/GridDay.vala
+@@ -31,6 +31,8 @@ namespace DateTimeIndicator {
+ 
+         public GLib.DateTime date { get; construct set; }
+ 
++        private bool has_scrolled = false;
++
+         private static Gtk.CssProvider provider;
+         private static Models.CalendarModel model;
+ 
+@@ -79,59 +81,100 @@ namespace DateTimeIndicator {
+             // Signals and handlers
+             button_press_event.connect (on_button_press);
+             key_press_event.connect (on_key_press);
+-            scroll_event.connect ((event) => {return Util.on_scroll_event (event);});
++            scroll_event.connect (on_scroll_event);
+ 
+             notify["date"].connect (() => {
+                 label.label = date.get_day_of_month ().to_string ();
+             });
+ 
+             event_dots = new Gee.HashMap<string, Gtk.Widget> ();
+-
+-            model.events_added.connect (add_event_dots);
+-            model.events_removed.connect (remove_event_dots);
+         }
+ 
+-        private void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-            foreach (var component in events) {
+-                if (event_dots.size >= 3) {
+-                    return;
+-                }
++        public bool on_scroll_event (Gdk.EventScroll event) {
++            double delta_x;
++            double delta_y;
++            event.get_scroll_deltas (out delta_x, out delta_y);
++
++            double choice = delta_x;
++
++            if (((int)delta_x).abs () < ((int)delta_y).abs ()) {
++                choice = delta_y;
++            }
++
++            /* It's mouse scroll ! */
++            if (choice == 1 || choice == -1) {
++                Models.CalendarModel.get_default ().change_month ((int)choice);
+ 
+-                if (Util.calcomp_is_on_day (component, date)) {
+-                    unowned ICal.Component ical = component.get_icalcomponent ();
++                return true;
++            }
+ 
+-                    var event_uid = ical.get_uid ();
+-                    if (!event_dots.has_key (event_uid)) {
+-                        var event_dot = new Gtk.Image ();
+-                        event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
+-                        event_dot.pixel_size = 6;
++            if (has_scrolled == true) {
++                return true;
++            }
+ 
+-                        unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
+-                        style_context.add_class (Granite.STYLE_CLASS_ACCENT);
+-                        style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++            if (choice > 0.3) {
++                reset_timer.begin ();
++                Models.CalendarModel.get_default ().change_month (1);
+ 
+-                        var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+-                        Util.set_event_calendar_color (source_calendar, event_dot);
++                return true;
++            }
+ 
+-                        event_dots[event_uid] = event_dot;
++            if (choice < -0.3) {
++                reset_timer.begin ();
++                Models.CalendarModel.get_default ().change_month (-1);
+ 
+-                        event_grid.add (event_dot);
+-                    }
+-                }
++                return true;
+             }
+ 
++            return false;
++        }
++
++        public async void reset_timer () {
++            has_scrolled = true;
++            Timeout.add (500, () => {
++                has_scrolled = false;
++
++                return false;
++            });
++        }
++
++        public bool skip_day () {
++            return event_dots.size >= 3 ? true : false;
++        }
++
++        public void show_event_grid () {
+             event_grid.show_all ();
+         }
+ 
+-        private void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-            foreach (var component in events) {
+-                unowned ICal.Component ical = component.get_icalcomponent ();
+-                var event_uid = ical.get_uid ();
+-                var dot = event_dots[event_uid];
+-                if (dot != null) {
+-                    dot.destroy ();
+-                    event_dots.remove (event_uid);
+-                }
++        public void add_dots (E.Source source, ICal.Component ical) {
++            var event_uid = ical.get_uid ();
++            if (!event_dots.has_key (event_uid)) {
++                var event_dot = new Gtk. Image ();
++                event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
++                event_dot.pixel_size = 6;
++
++                unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
++                style_context.add_class (Granite.STYLE_CLASS_ACCENT);
++                style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++
++                var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++                Util.set_event_calendar_color (source_calendar, event_dot);
++
++                event_dots[event_uid] = event_dot;
++
++                event_grid.add (event_dot);
++            }
++        }
++
++        public bool exist_event (string ical_uid) {
++            return event_dots.has_key (ical_uid);
++        }
++
++        public void remove_dots (string event_uid) {
++            var dot = event_dots[event_uid];
++            if (dot != null) {
++                dot.destroy ();
++                event_dots.unset (event_uid);
+             }
+         }
+ 
+
+From c99db5e63b9c48aa1d069b97b98b0c07481de27d Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Sat, 11 Apr 2020 23:44:14 +0300
+Subject: [PATCH 4/8] rename calendar elements
+
+---
+ meson.build                                   |  4 +--
+ .../{GridDay.vala => CalendarDay.vala}        |  4 +--
+ src/Widgets/{Grid.vala => CalendarGrid.vala}  | 26 +++++++--------
+ src/Widgets/CalendarView.vala                 | 33 +++++++++----------
+ 4 files changed, 33 insertions(+), 34 deletions(-)
+ rename src/Widgets/{GridDay.vala => CalendarDay.vala} (98%)
+ rename src/Widgets/{Grid.vala => CalendarGrid.vala} (91%)
+
+diff --git a/meson.build b/meson.build
+index e348e3d..dcdd9b2 100644
+--- a/meson.build
++++ b/meson.build
+@@ -44,11 +44,11 @@ shared_module(
+     'src/Util/DateRange.vala',
+     'src/Util/Util.vala',
+     'src/Models/CalendarModel.vala',
++    'src/Widgets/CalendarDay.vala',
++    'src/Widgets/CalendarGrid.vala',
+     'src/Widgets/CalendarView.vala',
+     'src/Widgets/EventRow.vala',
+     'src/Widgets/EventsListBox.vala',
+-    'src/Widgets/Grid.vala',
+-    'src/Widgets/GridDay.vala',
+     'src/Widgets/PanelLabel.vala',
+     'src/Services/EventsManager.vala',
+     'src/Services/TimeManager.vala',
+diff --git a/src/Widgets/GridDay.vala b/src/Widgets/CalendarDay.vala
+similarity index 98%
+rename from src/Widgets/GridDay.vala
+rename to src/Widgets/CalendarDay.vala
+index 00f82ea..a5ca920 100644
+--- a/src/Widgets/GridDay.vala
++++ b/src/Widgets/CalendarDay.vala
+@@ -23,7 +23,7 @@ namespace DateTimeIndicator {
+ /**
+  * Represents a single day on the grid.
+  */
+-    public class Widgets.GridDay : Gtk.EventBox {
++    public class Widgets.CalendarDay : Gtk.EventBox {
+         /*
+          * Event emitted when the day is double clicked or the ENTER key is pressed.
+          */
+@@ -41,7 +41,7 @@ namespace DateTimeIndicator {
+         private Gtk.Label label;
+         private bool valid_grab = false;
+ 
+-        public GridDay (GLib.DateTime date) {
++        public CalendarDay (GLib.DateTime date) {
+             Object (date: date);
+         }
+ 
+diff --git a/src/Widgets/Grid.vala b/src/Widgets/CalendarGrid.vala
+similarity index 91%
+rename from src/Widgets/Grid.vala
+rename to src/Widgets/CalendarGrid.vala
+index 660f212..66e2757 100644
+--- a/src/Widgets/Grid.vala
++++ b/src/Widgets/CalendarGrid.vala
+@@ -24,7 +24,7 @@ namespace DateTimeIndicator {
+ /**
+  * Represents the entire date grid as a table.
+  */
+-    public class Widgets.Grid : Gtk.Grid {
++    public class Widgets.CalendarGrid : Gtk.Grid {
+         public Util.DateRange grid_range { get; private set; }
+ 
+         /*
+@@ -34,8 +34,8 @@ namespace DateTimeIndicator {
+ 
+         public signal void selection_changed (GLib.DateTime new_date);
+ 
+-        private Gee.HashMap<uint, GridDay> data;
+-        private GridDay selected_gridday;
++        private Gee.HashMap<uint, Widgets.CalendarDay> data;
++        private Widgets.CalendarDay selected_gridday;
+         private Gtk.Label[] header_labels;
+         private Gtk.Revealer[] week_labels;
+ 
+@@ -61,12 +61,12 @@ namespace DateTimeIndicator {
+ 
+             Indicator.settings.bind ("show-weeks", week_sep_revealer, "reveal-child", GLib.SettingsBindFlags.DEFAULT);
+ 
+-            data = new Gee.HashMap<uint, GridDay> ();
++            data = new Gee.HashMap<uint, Widgets.CalendarDay> ();
+             events |= Gdk.EventMask.SCROLL_MASK;
+             events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
+         }
+ 
+-        private void on_day_focus_in (GridDay day) {
++        private void on_day_focus_in (Widgets.CalendarDay day) {
+             debug ("on_day_focus_in %s", day.date.to_string ());
+             if (selected_gridday != null) {
+                 selected_gridday.set_selected (false);
+@@ -94,7 +94,7 @@ namespace DateTimeIndicator {
+             Gee.List<GLib.DateTime> dates = grid_range.to_list ();
+             for (int i = 0; i < dates.size; i++) {
+                 var date = dates[i];
+-                GridDay? day = data[day_hash (date)];
++                Widgets.CalendarDay? day = data[day_hash (date)];
+                 if (day != null && day.name == "today") {
+                     day.grab_focus_force ();
+                     return;
+@@ -119,7 +119,7 @@ namespace DateTimeIndicator {
+ 
+             var new_dates = new_range.to_list ();
+ 
+-            var data_new = new Gee.HashMap<uint, GridDay> ();
++            var data_new = new Gee.HashMap<uint, Widgets.CalendarDay> ();
+ 
+             /* Assert that a valid number of weeks should be displayed */
+             assert (new_dates.size % 7 == 0);
+@@ -138,7 +138,7 @@ namespace DateTimeIndicator {
+ 
+             for (i = 0; i < new_dates.size; i++) {
+                 var new_date = new_dates[i];
+-                GridDay day;
++                Widgets.CalendarDay day;
+ 
+                 if (i < old_dates.size) {
+                     /* A widget already exists for this date, just change it */
+@@ -147,7 +147,7 @@ namespace DateTimeIndicator {
+                     day = update_day (data[day_hash (old_date)], new_date, today, month_start);
+                 } else {
+                     /* Still update_day to get the color of etc. right */
+-                    day = update_day (new GridDay (new_date), new_date, today, month_start);
++                    day = update_day (new Widgets.CalendarDay (new_date), new_date, today, month_start);
+                     day.on_event_add.connect ((date) => on_event_add (date));
+                     day.scroll_event.connect ((event) => { scroll_event (event); return false; });
+                     day.focus_in_event.connect ((event) => {
+@@ -182,9 +182,9 @@ namespace DateTimeIndicator {
+         }
+ 
+         /**
+-         * Updates the given GridDay so that it shows the given date. Changes to its style etc.
++         * Updates the given CalendarDay so that it shows the given date. Changes to its style etc.
+          */
+-        private GridDay update_day (GridDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
++        private Widgets.CalendarDay update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
+             update_today_style (day, new_date, today);
+             if (new_date.get_month () == month_start.get_month ()) {
+                 day.sensitive_container (true);
+@@ -237,13 +237,13 @@ namespace DateTimeIndicator {
+             int i = 0;
+             for (i = 0; i < dates.size; i++) {
+                 var date = dates[i];
+-                GridDay? day = data[day_hash (date)];
++                Widgets.CalendarDay? day = data[day_hash (date)];
+                 if (day == null) return;
+                 update_today_style (day, date, today);
+             }
+         }
+ 
+-        private void update_today_style (GridDay day, GLib.DateTime date, GLib.DateTime today) {
++        private void update_today_style (Widgets.CalendarDay day, GLib.DateTime date, GLib.DateTime today) {
+             if (date.get_day_of_year () == today.get_day_of_year () && date.get_year () == today.get_year ()) {
+                 day.name = "today";
+                 day.get_style_context ().add_class (Granite.STYLE_CLASS_ACCENT);
+diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
+index 070580f..db2139c 100644
+--- a/src/Widgets/CalendarView.vala
++++ b/src/Widgets/CalendarView.vala
+@@ -26,7 +26,7 @@ namespace DateTimeIndicator {
+ 
+         public GLib.DateTime? selected_date { get; private set; }
+ 
+-        private Widgets.Grid grid;
++        private Widgets.CalendarGrid calendar_grid;
+         private Gtk.Stack stack;
+         private Gtk.Grid big_grid;
+ 
+@@ -105,20 +105,20 @@ namespace DateTimeIndicator {
+         }
+ 
+         private Gtk.Grid create_big_grid () {
+-            grid = new Widgets.Grid ();
+-            grid.show_all ();
++            calendar_grid = new Widgets.CalendarGrid ();
++            calendar_grid.show_all ();
+ 
+-            grid.on_event_add.connect ((date) => {
++            calendar_grid.on_event_add.connect ((date) => {
+                 show_date_in_maya (date);
+                 day_double_click ();
+             });
+ 
+-            grid.selection_changed.connect ((date) => {
++            calendar_grid.selection_changed.connect ((date) => {
+                 selected_date = date;
+                 selection_changed (date);
+             });
+ 
+-            return grid;
++            return calendar_grid;
+         }
+ 
+         public void show_today () {
+@@ -131,7 +131,7 @@ namespace DateTimeIndicator {
+             }
+             sync_with_model ();
+ 
+-            grid.set_focus_to_today ();
++            calendar_grid.set_focus_to_today ();
+         }
+ 
+         // TODO: As far as maya supports it use the Dbus Activation feature to run the calendar-app.
+@@ -156,23 +156,23 @@ namespace DateTimeIndicator {
+         /* Sets the calendar widgets to the date range of the model */
+         private void sync_with_model () {
+             var model = Models.CalendarModel.get_default ();
+-            if (grid.grid_range != null && (model.data_range.equals (grid.grid_range) || grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
+-                grid.update_today ();
++            if (calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
++                calendar_grid.update_today ();
+                 return; // nothing else to do
+             }
+ 
+             GLib.DateTime previous_first = null;
+-            if (grid.grid_range != null)
+-                previous_first = grid.grid_range.first_dt;
++            if (calendar_grid.grid_range != null)
++                previous_first = calendar_grid.grid_range.first_dt;
+ 
+             big_grid = create_big_grid ();
+             stack.add (big_grid);
+ 
+-            grid.set_range (model.data_range, model.month_start);
+-            grid.update_weeks (model.data_range.first_dt, model.num_weeks);
++            calendar_grid.set_range (model.data_range, model.month_start);
++            calendar_grid.update_weeks (model.data_range.first_dt, model.num_weeks);
+ 
+             if (previous_first != null) {
+-                if (previous_first.compare (grid.grid_range.first_dt) == -1) {
++                if (previous_first.compare (calendar_grid.grid_range.first_dt) == -1) {
+                     stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT;
+                 } else {
+                     stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
+@@ -183,12 +183,11 @@ namespace DateTimeIndicator {
+         }
+ 
+         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-            grid.add_event_dots (source, events);
++            calendar_grid.add_event_dots (source, events);
+         }
+ 
+-
+         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-            grid.remove_event_dots (source, events);
++            calendar_grid.remove_event_dots (source, events);
+         }
+     }
+ }
+
+From 6b1b15305a9c90ff8b7e7244727a225984d34a14 Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Sun, 12 Apr 2020 03:10:24 +0300
+Subject: [PATCH 5/8] evolution data server now optional
+
+---
+ meson.build                   | 55 ++++++++++++++---------
+ meson_options.txt             |  1 +
+ src/Indicator.vala            | 43 ++++++++++--------
+ src/Util/Util.vala            | 85 ++++++++++++++++-------------------
+ src/Widgets/CalendarDay.vala  |  2 +
+ src/Widgets/CalendarGrid.vala |  2 +
+ src/Widgets/CalendarView.vala |  2 +
+ 7 files changed, 104 insertions(+), 86 deletions(-)
+ create mode 100644 meson_options.txt
+
+diff --git a/meson.build b/meson.build
+index dcdd9b2..5fee9ab 100644
+--- a/meson.build
++++ b/meson.build
+@@ -24,18 +24,40 @@ gresource = gnome.compile_resources(
+ wingpanel_dep = dependency('wingpanel-2.0')
+ wingpanel_indicatorsdir = wingpanel_dep.get_pkgconfig_variable('indicatorsdir', define_variable: ['libdir', libdir])
+ 
++deps = [
++    dependency('glib-2.0'),
++    dependency('gobject-2.0'),
++    dependency('granite'),
++    dependency('gtk+-3.0'),
++    wingpanel_dep,
++    meson.get_compiler('vala').find_library('posix')
++]
+ 
+-libecal_dep = dependency('libecal-2.0', required: false)
+-if libecal_dep.found()
+-    libical_dep = dependency('libical-glib')
+-    add_project_arguments('--define=E_CAL_2_0', language: 'vala')
+-    add_project_arguments('-DLIBICAL_GLIB_UNSTABLE_API=1', language: 'c')
+-else
+-    libecal_dep = dependency('libecal-1.2', version: '>=3.8.0')
+-    libical_dep = dependency('libical')
+-    add_project_arguments('--vapidir', join_paths(meson.current_source_dir(), 'vapi'), language: 'vala')
++opt_files = []
++
++if get_option('evo')
++    libecal_dep = dependency ('libecal-2.0', required: false)
++    if libecal_dep.found()
++        deps += dependency('libical-glib')
++        deps += libecal_dep
++        add_project_arguments('--define=E_CAL_2_0', language: 'vala')
++        add_project_arguments('-DLIBICAL_GLIB_UNSTABLE_API=1', language: 'c')
++    else
++        deps += dependency('libecal-1.2', version: '>=3.8.0')
++        deps += dependency('libical')
++        add_project_arguments('--vapidir', join_paths(meson.current_source_dir(), 'vapi'), language: 'vala')
++    endif
++
++    deps += dependency ('libedataserver-1.2')
++    opt_files += files (
++        'src/Widgets/EventRow.vala',
++        'src/Widgets/EventsListBox.vala',
++        'src/Services/EventsManager.vala',
++    )
++    add_project_arguments('--define=USE_EVO', language: 'vala')
+ endif
+ 
++
+ shared_module(
+     meson.project_name(),
+     gresource,
+@@ -47,21 +69,10 @@ shared_module(
+     'src/Widgets/CalendarDay.vala',
+     'src/Widgets/CalendarGrid.vala',
+     'src/Widgets/CalendarView.vala',
+-    'src/Widgets/EventRow.vala',
+-    'src/Widgets/EventsListBox.vala',
+     'src/Widgets/PanelLabel.vala',
+-    'src/Services/EventsManager.vala',
+     'src/Services/TimeManager.vala',
+-    dependencies: [
+-        dependency('glib-2.0'),
+-        dependency('gobject-2.0'),
+-        dependency('granite'),
+-        dependency('gtk+-3.0'),
+-        libecal_dep,
+-        dependency('libedataserver-1.2'),
+-        libical_dep,
+-        wingpanel_dep,
+-    ],
++    opt_files,
++    dependencies: deps,
+     install: true,
+     install_dir : wingpanel_indicatorsdir,
+ )
+diff --git a/meson_options.txt b/meson_options.txt
+new file mode 100644
+index 0000000..a1c9f0e
+--- /dev/null
++++ b/meson_options.txt
+@@ -0,0 +1 @@
++option ('evo', type : 'boolean', value : true)
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index bf4358f..31c7af5 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -23,9 +23,11 @@ namespace DateTimeIndicator {
+ 
+         private Widgets.PanelLabel panel_label;
+         private Widgets.CalendarView calendar;
+-        private Widgets.EventsListBox event_listbox;
+ 
++#if USE_EVO
++        private Widgets.EventsListBox event_listbox;
+         private Services.EventsManager event_manager;
++#endif
+ 
+         private Gtk.Grid main_grid;
+         private uint update_events_idle_source = 0;
+@@ -60,7 +62,20 @@ namespace DateTimeIndicator {
+             if (main_grid == null) {
+                 calendar = new Widgets.CalendarView ();
+                 calendar.margin_bottom = 6;
++                calendar.day_double_click.connect (() => {
++                    close ();
++                });
++
++                var settings_button = new Gtk.ModelButton ();
++                settings_button.text = _("Date & Time Settings…");
+ 
++                main_grid = new Gtk.Grid ();
++                main_grid.margin_top = 12;
++                main_grid.attach (calendar,                           0, 0);
++                main_grid.attach (new Wingpanel.Widgets.Separator (), 0, 1);
++                main_grid.attach (settings_button,                    0, 2);
++
++#if USE_EVO
+                 event_manager = new Services.EventsManager ();
+                 event_manager.events_updated.connect (update_events_model);
+                 event_manager.events_added.connect ((source, events) => {
+@@ -73,20 +88,16 @@ namespace DateTimeIndicator {
+                 });
+ 
+                 event_listbox = new Widgets.EventsListBox ();
++                event_listbox.row_activated.connect ((row) => {
++                    calendar.show_date_in_maya (((EventRow) row).date);
++                    close ();
++                });
+ 
+                 var scrolled_window = new Gtk.ScrolledWindow (null, null);
+                 scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
+                 scrolled_window.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
+                 scrolled_window.add (event_listbox);
+ 
+-                var settings_button = new Gtk.ModelButton ();
+-                settings_button.text = _("Date & Time Settings…");
+-
+-                main_grid = new Gtk.Grid ();
+-                main_grid.margin_top = 12;
+-                main_grid.attach (calendar,                                     0, 0);
+-                main_grid.attach (new Wingpanel.Widgets.Separator (),           0, 1);
+-                main_grid.attach (settings_button,                              0, 2);
+                 main_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 3);
+                 main_grid.attach (scrolled_window,                              2, 0, 1, 3);
+ 
+@@ -94,23 +105,17 @@ namespace DateTimeIndicator {
+                 size_group.add_widget (calendar);
+                 size_group.add_widget (event_listbox);
+ 
+-                calendar.day_double_click.connect (() => {
+-                    close ();
+-                });
+-
+                 calendar.selection_changed.connect ((date) => {
+                     idle_update_events ();
+                 });
+-
+-                event_listbox.row_activated.connect ((row) => {
+-                    calendar.show_date_in_maya (((EventRow) row).date);
+-                    close ();
+-                });
++#endif
+ 
+                 var model = Models.CalendarModel.get_default ();
+                 model.notify["month-start"].connect (() => {
+                     model.compute_ranges ();
++#if USE_EVO
+                     event_manager.load_all_sources ();
++#endif
+                 });
+ 
+                 settings_button.clicked.connect (() => {
+@@ -125,6 +130,7 @@ namespace DateTimeIndicator {
+             return main_grid;
+         }
+ 
++#if USE_EVO
+         private void update_events_model (E.Source source, Gee.Collection<ECal.Component> events) {
+             if (opened_widget) {
+                 idle_update_events ();
+@@ -143,6 +149,7 @@ namespace DateTimeIndicator {
+                 return GLib.Source.REMOVE;
+             });
+         }
++#endif
+ 
+         public override void opened () {
+             calendar.show_today ();
+diff --git a/src/Util/Util.vala b/src/Util/Util.vala
+index b0bdf98..26b343a 100644
+--- a/src/Util/Util.vala
++++ b/src/Util/Util.vala
+@@ -32,38 +32,6 @@ namespace DateTimeIndicator.Util {
+         return datetime.add_full (0, 0, 0, -datetime.get_hour (), -datetime.get_minute (), -datetime.get_second ());
+     }
+ 
+-    /**
+-     * Converts the given ICal.Time to a DateTime.
+-     */
+-    public TimeZone timezone_from_ical (ICal.Time date) {
+-        int is_daylight;
+-        var interval = date.get_timezone ().get_utc_offset (null, out is_daylight);
+-        bool is_positive = interval >= 0;
+-        interval = interval.abs ();
+-        var hours = (interval / 3600);
+-        var minutes = (interval % 3600) / 60;
+-        var hour_string = "%s%02d:%02d".printf (is_positive ? "+" : "-", hours, minutes);
+-
+-        return new TimeZone (hour_string);
+-    }
+-
+-    /**
+-     * Converts the given ICal.Time to a DateTime.
+-     * XXX : Track next versions of evolution in order to convert ICal.Timezone to GLib.TimeZone with a dedicated function…
+-     */
+-    public GLib.DateTime ical_to_date_time (ICal.Time date) {
+-#if E_CAL_2_0
+-        int year, month, day, hour, minute, second;
+-        date.get_date (out year, out month, out day);
+-        date.get_time (out hour, out minute, out second);
+-        return new GLib.DateTime (timezone_from_ical (date), year, month,
+-            day, hour, minute, second);
+-#else
+-        return new GLib.DateTime (timezone_from_ical (date), date.year, date.month,
+-            date.day, date.hour, date.minute, date.second);
+-#endif
+-    }
+-
+     /**
+      * Say if an event lasts all day.
+      */
+@@ -78,6 +46,7 @@ namespace DateTimeIndicator.Util {
+         }
+     }
+ 
++#if USE_EVO
+     private Gee.HashMap<string, Gtk.CssProvider>? providers;
+     public void set_event_calendar_color (E.SourceCalendar cal, Gtk.Widget widget) {
+         if (providers == null) {
+@@ -104,6 +73,38 @@ namespace DateTimeIndicator.Util {
+         style_context.add_provider (providers[color], Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+     }
+ 
++    /**
++     * Converts the given ICal.Time to a DateTime.
++     */
++    public TimeZone timezone_from_ical (ICal.Time date) {
++        int is_daylight;
++        var interval = date.get_timezone ().get_utc_offset (null, out is_daylight);
++        bool is_positive = interval >= 0;
++        interval = interval.abs ();
++        var hours = (interval / 3600);
++        var minutes = (interval % 3600) / 60;
++        var hour_string = "%s%02d:%02d".printf (is_positive ? "+" : "-", hours, minutes);
++
++        return new TimeZone (hour_string);
++    }
++
++    /**
++     * Converts the given ICal.Time to a DateTime.
++     * XXX : Track next versions of evolution in order to convert ICal.Timezone to GLib.TimeZone with a dedicated function…
++     */
++    public GLib.DateTime ical_to_date_time (ICal.Time date) {
++#if E_CAL_2_0
++        int year, month, day, hour, minute, second;
++        date.get_date (out year, out month, out day);
++        date.get_time (out hour, out minute, out second);
++        return new GLib.DateTime (timezone_from_ical (date), year, month,
++            day, hour, minute, second);
++#else
++        return new GLib.DateTime (timezone_from_ical (date), date.year, date.month,
++            date.day, date.hour, date.minute, date.second);
++#endif
++    }
++
+     /*
+      * Gee Utility Functions
+      */
+@@ -113,6 +114,11 @@ namespace DateTimeIndicator.Util {
+         return key.dup_uid (). hash ();
+     }
+ 
++    /* Returns true if 'a' and 'b' are the same E.Source */
++    public bool source_equal_func (E.Source a, E.Source b) {
++        return a.dup_uid () == b.dup_uid ();
++    }
++
+     /* Returns true if 'a' and 'b' are the same ECal.Component */
+     public bool calcomponent_equal_func (ECal.Component a, ECal.Component b) {
+         return a.get_id ().equal (b.get_id ());
+@@ -178,18 +184,5 @@ namespace DateTimeIndicator.Util {
+ 
+         return false;
+     }
+-
+-    /* Returns true if 'a' and 'b' are the same E.Source */
+-    public bool source_equal_func (E.Source a, E.Source b) {
+-        return a.dup_uid () == b.dup_uid ();
+-    }
+-
+-    // public async void reset_timer () {
+-    //     has_scrolled = true;
+-    //     Timeout.add (500, () => {
+-    //         has_scrolled = false;
+-    //
+-    //         return false;
+-    //     });
+-    // }
++#endif
+ }
+diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
+index a5ca920..f9c742a 100644
+--- a/src/Widgets/CalendarDay.vala
++++ b/src/Widgets/CalendarDay.vala
+@@ -146,6 +146,7 @@ namespace DateTimeIndicator {
+             event_grid.show_all ();
+         }
+ 
++#if USE_EVO
+         public void add_dots (E.Source source, ICal.Component ical) {
+             var event_uid = ical.get_uid ();
+             if (!event_dots.has_key (event_uid)) {
+@@ -177,6 +178,7 @@ namespace DateTimeIndicator {
+                 event_dots.unset (event_uid);
+             }
+         }
++#endif
+ 
+         public void set_selected (bool selected) {
+             if (selected) {
+diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
+index 66e2757..1d1e06c 100644
+--- a/src/Widgets/CalendarGrid.vala
++++ b/src/Widgets/CalendarGrid.vala
+@@ -261,6 +261,7 @@ namespace DateTimeIndicator {
+             return date.get_year () * 10000 + date.get_month () * 100 + date.get_day_of_month ();
+         }
+ 
++#if USE_EVO
+         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+             data.foreach ((entry) => {
+ 
+@@ -292,5 +293,6 @@ namespace DateTimeIndicator {
+                 });
+             }
+         }
++#endif
+     }
+ }
+diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
+index db2139c..77c233c 100644
+--- a/src/Widgets/CalendarView.vala
++++ b/src/Widgets/CalendarView.vala
+@@ -182,6 +182,7 @@ namespace DateTimeIndicator {
+             stack.set_visible_child (big_grid);
+         }
+ 
++#if USE_EVO
+         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+             calendar_grid.add_event_dots (source, events);
+         }
+@@ -189,5 +190,6 @@ namespace DateTimeIndicator {
+         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+             calendar_grid.remove_event_dots (source, events);
+         }
++#endif
+     }
+ }
+
+From 16715f5114c0597d6961880bf877f04414400334 Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Mon, 13 Apr 2020 22:21:07 +0300
+Subject: [PATCH 6/8] returned dots in the calendar
+
+---
+ src/Indicator.vala              |  6 ++--
+ src/Services/EventsManager.vala | 28 +++++----------
+ src/Widgets/CalendarDay.vala    | 62 ++++++++++++++++++---------------
+ src/Widgets/CalendarGrid.vala   | 29 ++++++---------
+ 4 files changed, 57 insertions(+), 68 deletions(-)
+
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index 31c7af5..c7550aa 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -105,8 +105,10 @@ namespace DateTimeIndicator {
+                 size_group.add_widget (calendar);
+                 size_group.add_widget (event_listbox);
+ 
+-                calendar.selection_changed.connect ((date) => {
+-                    idle_update_events ();
++                event_manager.open.begin ((obj, res) => {
++                    calendar.selection_changed.connect ((date) => {
++                        idle_update_events ();
++                    });
+                 });
+ #endif
+ 
+diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
+index d939777..ad0397d 100644
+--- a/src/Services/EventsManager.vala
++++ b/src/Services/EventsManager.vala
+@@ -10,33 +10,25 @@ namespace DateTimeIndicator {
+         private HashTable<string, ECal.Client> source_client;
+         private HashTable<string, ECal.ClientView> source_view;
+ 
+-        public EventsManager () {
+-
+-        }
+-
+         construct {
+             source_client = new HashTable<string, ECal.Client> (str_hash, str_equal);
+             source_events = new HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component> > (Util.source_hash_func, Util.source_equal_func);
+             source_view = new HashTable<string, ECal.ClientView> (str_hash, str_equal);
+-
+-            open.begin ();
+         }
+ 
+-        private async void open () {
++        public async void open () {
+             try {
+                 registry = yield new E.SourceRegistry (null);
+                 registry.source_removed.connect (remove_source);
+-                registry.source_added.connect ((source) => add_source_async.begin (source));
++                registry.source_added.connect (add_source);
+ 
+                 // Add sources
+                 registry.list_sources (E.SOURCE_EXTENSION_CALENDAR).foreach ((source) => {
+-                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++                    E.SourceCalendar cal = (E.SourceCalendar) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+                     if (cal.selected == true && source.enabled == true) {
+-                        add_source_async.begin (source);
++                        add_source (source);
+                     }
+                 });
+-
+-                load_all_sources ();
+             } catch (GLib.Error error) {
+                 critical (error.message);
+             }
+@@ -46,7 +38,7 @@ namespace DateTimeIndicator {
+             lock (source_client) {
+                 foreach (var id in source_client.get_keys ()) {
+                     var source = registry.ref_source (id);
+-                    E.SourceCalendar cal = (E.SourceCalendar)source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++                    E.SourceCalendar cal = (E.SourceCalendar) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+ 
+                     if (cal.selected == true && source.enabled == true) {
+                         load_source (source);
+@@ -120,7 +112,7 @@ namespace DateTimeIndicator {
+             });
+         }
+ 
+-        private async void add_source_async (E.Source source) {
++        private void add_source (E.Source source) {
+             debug ("Adding source '%s'", source.dup_display_name ());
+             try {
+                 var client = (ECal.Client) ECal.Client.connect_sync (source, ECal.ClientSourceType.EVENTS, -1, null);
+@@ -129,11 +121,7 @@ namespace DateTimeIndicator {
+                 critical (e.message);
+             }
+ 
+-            Idle.add (() => {
+-                load_source (source);
+-
+-                return false;
+-            });
++            load_source (source);
+         }
+ 
+         private void debug_event (E.Source source, ECal.Component event) {
+@@ -177,6 +165,8 @@ namespace DateTimeIndicator {
+                     return true;
+                 });
+             });
++
++            events_added (source, added_events.read_only_view);
+         }
+ 
+ #if E_CAL_2_0
+diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
+index f9c742a..a2c4922 100644
+--- a/src/Widgets/CalendarDay.vala
++++ b/src/Widgets/CalendarDay.vala
+@@ -36,7 +36,8 @@ namespace DateTimeIndicator {
+         private static Gtk.CssProvider provider;
+         private static Models.CalendarModel model;
+ 
+-        private Gee.HashMap<string, Gtk.Widget> event_dots;
++        // private Gee.HashMap<string, Gtk.Widget> event_dots;
++        private Gee.ArrayList<string> event_dots;
+         private Gtk.Grid event_grid;
+         private Gtk.Label label;
+         private bool valid_grab = false;
+@@ -87,7 +88,8 @@ namespace DateTimeIndicator {
+                 label.label = date.get_day_of_month ().to_string ();
+             });
+ 
+-            event_dots = new Gee.HashMap<string, Gtk.Widget> ();
++            // event_dots = new Gee.HashMap<string, Gtk.Widget> ();
++            event_dots = new Gee.ArrayList<string> ();
+         }
+ 
+         public bool on_scroll_event (Gdk.EventScroll event) {
+@@ -138,44 +140,46 @@ namespace DateTimeIndicator {
+             });
+         }
+ 
+-        public bool skip_day () {
+-            return event_dots.size >= 3 ? true : false;
+-        }
+-
+-        public void show_event_grid () {
+-            event_grid.show_all ();
+-        }
+-
+ #if USE_EVO
+         public void add_dots (E.Source source, ICal.Component ical) {
+             var event_uid = ical.get_uid ();
+-            if (!event_dots.has_key (event_uid)) {
+-                var event_dot = new Gtk. Image ();
+-                event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
+-                event_dot.pixel_size = 6;
++            if (event_dots.contains (event_uid)) {
++                return;
++            }
+ 
+-                unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
+-                style_context.add_class (Granite.STYLE_CLASS_ACCENT);
+-                style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
++            event_dots.add (event_uid);
++            if (event_dots.size > 3) {
++                return;
++            }
+ 
+-                var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
+-                Util.set_event_calendar_color (source_calendar, event_dot);
++            var event_dot = new Gtk.Image ();
++            event_dot.gicon = new ThemedIcon ("pager-checked-symbolic");
++            event_dot.pixel_size = 6;
+ 
+-                event_dots[event_uid] = event_dot;
++            unowned Gtk.StyleContext style_context = event_dot.get_style_context ();
++            style_context.add_class (Granite.STYLE_CLASS_ACCENT);
++            style_context.add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+ 
+-                event_grid.add (event_dot);
+-            }
+-        }
++            var source_calendar = (E.SourceCalendar?) source.get_extension (E.SOURCE_EXTENSION_CALENDAR);
++            Util.set_event_calendar_color (source_calendar, event_dot);
+ 
+-        public bool exist_event (string ical_uid) {
+-            return event_dots.has_key (ical_uid);
++            event_grid.add (event_dot);
++            event_dot.show ();
+         }
+ 
+         public void remove_dots (string event_uid) {
+-            var dot = event_dots[event_uid];
+-            if (dot != null) {
+-                dot.destroy ();
+-                event_dots.unset (event_uid);
++            if (event_dots.contains (event_uid)) {
++                return;
++            }
++
++            event_dots.remove (event_uid);
++            if (event_dots.size >= 3) {
++                return;
++            }
++
++            var w = event_grid.get_children ();
++            if (w.length () > 0) {
++                w.nth_data (0).destroy ();
+             }
+         }
+ #endif
+diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
+index 1d1e06c..c544404 100644
+--- a/src/Widgets/CalendarGrid.vala
++++ b/src/Widgets/CalendarGrid.vala
+@@ -263,22 +263,16 @@ namespace DateTimeIndicator {
+ 
+ #if USE_EVO
+         public void add_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+-            data.foreach ((entry) => {
+-
+-                foreach (var component in events) {
+-                    if (entry.value.skip_day ()) {
+-                        return true;
+-                    }
+-
+-                    if (Util.calcomp_is_on_day (component, entry.value.date)) {
+-                        entry.value.add_dots (source, component.get_icalcomponent ());
+-                    }
++            foreach (var component in events) {
++                unowned ICal.Component? icomp = component.get_icalcomponent ();
++                ICal.Time? start_time = icomp.get_dtstart ();
++                time_t start_unix = start_time.as_timet ();
++                var t = new DateTime.from_unix_utc (start_unix);
++                var d_hash = day_hash (t);
++                if (data.has_key (d_hash)) {
++                    data[d_hash].add_dots (source, component.get_icalcomponent ());
+                 }
+-
+-                entry.value.show_event_grid ();
+-
+-                return true;
+-            });
++            }
+         }
+ 
+         public void remove_event_dots (E.Source source, Gee.Collection<ECal.Component> events) {
+@@ -286,9 +280,8 @@ namespace DateTimeIndicator {
+                 unowned ICal.Component ical = component.get_icalcomponent ();
+                 var event_uid = ical.get_uid ();
+                 data.foreach ((entry) => {
+-                    if (entry.value.exist_event (event_uid)) {
+-                        entry.value.remove_dots (event_uid);
+-                    }
++                    entry.value.remove_dots (event_uid);
++
+                     return true;
+                 });
+             }
+
+From 149da28659883b01ceb0773b35c018d31aa1d912 Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Tue, 14 Apr 2020 00:16:01 +0300
+Subject: [PATCH 7/8] issue #55
+
+---
+ src/Services/EventsManager.vala |  2 ++
+ src/Widgets/CalendarDay.vala    |  2 +-
+ src/Widgets/CalendarGrid.vala   | 11 +++++++----
+ 3 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
+index ad0397d..959762f 100644
+--- a/src/Services/EventsManager.vala
++++ b/src/Services/EventsManager.vala
+@@ -208,6 +208,8 @@ namespace DateTimeIndicator {
+                     removed_events.add (event);
+                     debug_event (source, event);
+                 }
++
++                events.remove_all (cid.get_uid ());
+             });
+ 
+             events_removed (source, removed_events.read_only_view);
+diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
+index a2c4922..10d088c 100644
+--- a/src/Widgets/CalendarDay.vala
++++ b/src/Widgets/CalendarDay.vala
+@@ -168,7 +168,7 @@ namespace DateTimeIndicator {
+         }
+ 
+         public void remove_dots (string event_uid) {
+-            if (event_dots.contains (event_uid)) {
++            if (!event_dots.contains (event_uid)) {
+                 return;
+             }
+ 
+diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
+index c544404..6e6cbdb 100644
+--- a/src/Widgets/CalendarGrid.vala
++++ b/src/Widgets/CalendarGrid.vala
+@@ -279,11 +279,14 @@ namespace DateTimeIndicator {
+             foreach (var component in events) {
+                 unowned ICal.Component ical = component.get_icalcomponent ();
+                 var event_uid = ical.get_uid ();
+-                data.foreach ((entry) => {
+-                    entry.value.remove_dots (event_uid);
+ 
+-                    return true;
+-                });
++                ICal.Time? start_time = ical.get_dtstart ();
++                time_t start_unix = start_time.as_timet ();
++                var t = new DateTime.from_unix_utc (start_unix);
++                var d_hash = day_hash (t);
++                if (data.has_key (d_hash)) {
++                    data[d_hash].remove_dots (event_uid);
++                }
+             }
+         }
+ #endif
+
+From a3910e2b8242b8c4837cc764da7f268a02d05d6e Mon Sep 17 00:00:00 2001
+From: Dirli <litandrej85@gmail.com>
+Date: Fri, 17 Apr 2020 00:52:53 +0300
+Subject: [PATCH 8/8] issue #127
+
+---
+ src/Indicator.vala              |  1 +
+ src/Models/CalendarModel.vala   | 17 ++++++---
+ src/Services/EventsManager.vala | 17 +++++++++
+ src/Widgets/CalendarDay.vala    |  3 +-
+ src/Widgets/CalendarGrid.vala   | 66 ++++++++++++++++++++++-----------
+ src/Widgets/CalendarView.vala   | 17 ++++-----
+ src/Widgets/EventsListBox.vala  |  6 ++-
+ 7 files changed, 87 insertions(+), 40 deletions(-)
+
+diff --git a/src/Indicator.vala b/src/Indicator.vala
+index c7550aa..63614e0 100644
+--- a/src/Indicator.vala
++++ b/src/Indicator.vala
+@@ -116,6 +116,7 @@ namespace DateTimeIndicator {
+                 model.notify["month-start"].connect (() => {
+                     model.compute_ranges ();
+ #if USE_EVO
++                    event_listbox.clear_list ();
+                     event_manager.load_all_sources ();
+ #endif
+                 });
+diff --git a/src/Models/CalendarModel.vala b/src/Models/CalendarModel.vala
+index d60a9ac..48b6e78 100644
+--- a/src/Models/CalendarModel.vala
++++ b/src/Models/CalendarModel.vala
+@@ -57,12 +57,17 @@ namespace DateTimeIndicator {
+             compute_ranges ();
+         }
+ 
+-        public void change_month (int relative) {
+-            month_start = month_start.add_months (relative);
+-        }
+-
+-        public void change_year (int relative) {
+-            month_start = month_start.add_years (relative);
++        public void change_month (int m_relative, int y_relative = 0) {
++            if (y_relative == 0) {
++                month_start = month_start.add_months (m_relative);
++            } else {
++                if (m_relative == 0) {
++                    month_start = month_start.add_years (y_relative);
++                } else {
++                    GLib.DateTime tmp_date = month_start.add_months (m_relative);
++                    month_start = tmp_date.add_years (y_relative);
++                }
++            }
+         }
+ 
+         /* --- Helper Methods ---// */
+diff --git a/src/Services/EventsManager.vala b/src/Services/EventsManager.vala
+index 959762f..6ece557 100644
+--- a/src/Services/EventsManager.vala
++++ b/src/Services/EventsManager.vala
+@@ -1,3 +1,20 @@
++/*
++ * Copyright (c) 2011-2020 elementary, Inc. (https://elementary.io)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License as published by the Free Software Foundation; either
++ * version 3 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
+ namespace DateTimeIndicator {
+     public class Services.EventsManager : GLib.Object {
+         public signal void events_added (E.Source source, Gee.Collection<ECal.Component> events);
+diff --git a/src/Widgets/CalendarDay.vala b/src/Widgets/CalendarDay.vala
+index 10d088c..735fdc1 100644
+--- a/src/Widgets/CalendarDay.vala
++++ b/src/Widgets/CalendarDay.vala
+@@ -36,7 +36,6 @@ namespace DateTimeIndicator {
+         private static Gtk.CssProvider provider;
+         private static Models.CalendarModel model;
+ 
+-        // private Gee.HashMap<string, Gtk.Widget> event_dots;
+         private Gee.ArrayList<string> event_dots;
+         private Gtk.Grid event_grid;
+         private Gtk.Label label;
+@@ -105,7 +104,7 @@ namespace DateTimeIndicator {
+ 
+             /* It's mouse scroll ! */
+             if (choice == 1 || choice == -1) {
+-                Models.CalendarModel.get_default ().change_month ((int)choice);
++                Models.CalendarModel.get_default ().change_month ((int) choice);
+ 
+                 return true;
+             }
+diff --git a/src/Widgets/CalendarGrid.vala b/src/Widgets/CalendarGrid.vala
+index 6e6cbdb..ef8edb6 100644
+--- a/src/Widgets/CalendarGrid.vala
++++ b/src/Widgets/CalendarGrid.vala
+@@ -32,7 +32,7 @@ namespace DateTimeIndicator {
+          */
+         public signal void on_event_add (GLib.DateTime date);
+ 
+-        public signal void selection_changed (GLib.DateTime new_date);
++        public signal void selection_changed (GLib.DateTime new_date, bool up);
+ 
+         private Gee.HashMap<uint, Widgets.CalendarDay> data;
+         private Widgets.CalendarDay selected_gridday;
+@@ -66,25 +66,32 @@ namespace DateTimeIndicator {
+             events |= Gdk.EventMask.SMOOTH_SCROLL_MASK;
+         }
+ 
+-        private void on_day_focus_in (Widgets.CalendarDay day) {
+-            debug ("on_day_focus_in %s", day.date.to_string ());
++        private bool on_day_focus_in (Gdk.EventFocus event) {
++            var day = get_focus_child ();
++            if (day == null) {
++                return false;
++            }
++
+             if (selected_gridday != null) {
+                 selected_gridday.set_selected (false);
+             }
+ 
+-            var selected_date = day.date;
+-            selected_gridday = day;
+-            day.set_selected (true);
++            var selected_date = (day as Widgets.CalendarDay).date;
++            selected_gridday = day as Widgets.CalendarDay;
++            (day as Widgets.CalendarDay).set_selected (true);
+             day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
+-            selection_changed (selected_date);
+             var calmodel = Models.CalendarModel.get_default ();
+             var date_month = selected_date.get_month () - calmodel.month_start.get_month ();
+             var date_year = selected_date.get_year () - calmodel.month_start.get_year ();
+ 
+             if (date_month != 0 || date_year != 0) {
+-                calmodel.change_month (date_month);
+-                calmodel.change_year (date_year);
++                selection_changed (selected_date, false);
++                calmodel.change_month (date_month, date_year);
++            } else {
++                selection_changed (selected_date, true);
+             }
++
++            return false;
+         }
+ 
+         public void set_focus_to_today () {
+@@ -106,7 +113,7 @@ namespace DateTimeIndicator {
+          * Sets the given range to be displayed in the grid. Note that the number of days
+          * must remain the same.
+          */
+-        public void set_range (Util.DateRange new_range, GLib.DateTime month_start) {
++        public void set_range (Util.DateRange new_range, GLib.DateTime month_start, GLib.DateTime? selected_date) {
+             var today = new GLib.DateTime.now_local ();
+ 
+             Gee.List<GLib.DateTime> old_dates;
+@@ -138,28 +145,46 @@ namespace DateTimeIndicator {
+ 
+             for (i = 0; i < new_dates.size; i++) {
+                 var new_date = new_dates[i];
+-                Widgets.CalendarDay day;
++                Widgets.CalendarDay? day = null;
+ 
+                 if (i < old_dates.size) {
+                     /* A widget already exists for this date, just change it */
+ 
+                     var old_date = old_dates[i];
+-                    day = update_day (data[day_hash (old_date)], new_date, today, month_start);
+-                } else {
++                    var d_hash = day_hash (old_date);
++                    if (data.has_key (d_hash)) {
++                        day = data[d_hash];
++                    }
++                }
++
++                if (day == null) {
+                     /* Still update_day to get the color of etc. right */
+-                    day = update_day (new Widgets.CalendarDay (new_date), new_date, today, month_start);
++                    day = new Widgets.CalendarDay (new_date);
+                     day.on_event_add.connect ((date) => on_event_add (date));
+-                    day.scroll_event.connect ((event) => { scroll_event (event); return false; });
+-                    day.focus_in_event.connect ((event) => {
+-                        on_day_focus_in (day);
+-
++                    day.scroll_event.connect ((event) => {
++                        scroll_event (event);
+                         return false;
+                     });
++                    day.focus_in_event.connect (on_day_focus_in);
+ 
+                     attach (day, col + 2, row);
+                     day.show_all ();
+                 }
+ 
++                update_day (day, new_date, month_start);
++                update_today_style (day, new_date, today);
++                if (selected_date != null && day.date.equal (selected_date)) {
++                    /* disabled the signal to avoid unnecessary signals and selected
++                    * the specified day from the new period */
++                    debug (@"focus selected day $selected_date");
++                    day.focus_in_event.disconnect (on_day_focus_in);
++                    day.grab_focus_force ();
++                    day.set_selected (true);
++                    day.set_state_flags (Gtk.StateFlags.FOCUSED, false);
++                    selected_gridday = day;
++                    day.focus_in_event.connect (on_day_focus_in);
++                }
++
+                 col = (col + 1) % 7;
+                 row = (col == 0) ? row + 1 : row;
+                 data_new.set (day_hash (new_date), day);
+@@ -184,8 +209,7 @@ namespace DateTimeIndicator {
+         /**
+          * Updates the given CalendarDay so that it shows the given date. Changes to its style etc.
+          */
+-        private Widgets.CalendarDay update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime today, GLib.DateTime month_start) {
+-            update_today_style (day, new_date, today);
++        private void update_day (Widgets.CalendarDay day, GLib.DateTime new_date, GLib.DateTime month_start) {
+             if (new_date.get_month () == month_start.get_month ()) {
+                 day.sensitive_container (true);
+             } else {
+@@ -193,8 +217,6 @@ namespace DateTimeIndicator {
+             }
+ 
+             day.date = new_date;
+-
+-            return day;
+         }
+ 
+         public void update_weeks (GLib.DateTime date, int nr_of_weeks) {
+diff --git a/src/Widgets/CalendarView.vala b/src/Widgets/CalendarView.vala
+index 77c233c..fe957ab 100644
+--- a/src/Widgets/CalendarView.vala
++++ b/src/Widgets/CalendarView.vala
+@@ -85,10 +85,7 @@ namespace DateTimeIndicator {
+             model.notify["data-range"].connect (() => {
+                 label.label = model.month_start.format (_("%OB, %Y"));
+ 
+-                sync_with_model ();
+-
+-                selected_date = null;
+-                selection_changed (selected_date);
++                sync_with_model (selected_date != null);
+             });
+ 
+             left_button.clicked.connect (() => {
+@@ -113,9 +110,11 @@ namespace DateTimeIndicator {
+                 day_double_click ();
+             });
+ 
+-            calendar_grid.selection_changed.connect ((date) => {
++            calendar_grid.selection_changed.connect ((date, up) => {
+                 selected_date = date;
+-                selection_changed (date);
++                if (up) {
++                    selection_changed (date);
++                }
+             });
+ 
+             return calendar_grid;
+@@ -154,9 +153,9 @@ namespace DateTimeIndicator {
+         }
+ 
+         /* Sets the calendar widgets to the date range of the model */
+-        private void sync_with_model () {
++        private void sync_with_model (bool show_selected = false) {
+             var model = Models.CalendarModel.get_default ();
+-            if (calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
++            if (!show_selected && calendar_grid.grid_range != null && (model.data_range.equals (calendar_grid.grid_range) || calendar_grid.grid_range.first_dt.compare (model.data_range.first_dt) == 0)) {
+                 calendar_grid.update_today ();
+                 return; // nothing else to do
+             }
+@@ -168,7 +167,7 @@ namespace DateTimeIndicator {
+             big_grid = create_big_grid ();
+             stack.add (big_grid);
+ 
+-            calendar_grid.set_range (model.data_range, model.month_start);
++            calendar_grid.set_range (model.data_range, model.month_start, show_selected ? selected_date : null);
+             calendar_grid.update_weeks (model.data_range.first_dt, model.num_weeks);
+ 
+             if (previous_first != null) {
+diff --git a/src/Widgets/EventsListBox.vala b/src/Widgets/EventsListBox.vala
+index c25af2e..9022072 100644
+--- a/src/Widgets/EventsListBox.vala
++++ b/src/Widgets/EventsListBox.vala
+@@ -21,10 +21,14 @@ namespace DateTimeIndicator {
+             set_sort_func (sort_function);
+         }
+ 
+-        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
++        public void clear_list () {
+             foreach (unowned Gtk.Widget widget in get_children ()) {
+                 widget.destroy ();
+             }
++        }
++
++        public void update_events (GLib.DateTime? selected_date, HashTable<E.Source, Gee.TreeMultiMap<string, ECal.Component>> source_events) {
++            clear_list ();
+ 
+             if (selected_date == null) {
+                 return;
diff --git a/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/default.nix b/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/default.nix
index ed70687e0502..c6a0e2f7779f 100644
--- a/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/default.nix
+++ b/pkgs/desktops/pantheon/desktop/wingpanel-indicators/datetime/default.nix
@@ -1,5 +1,5 @@
 { stdenv
-, fetchFromGitHub 
+, fetchFromGitHub
 , pantheon
 , pkgconfig
 , meson
@@ -28,6 +28,15 @@ stdenv.mkDerivation rec {
     sha256 = "0a0pqrpmrdd5pch30lizr9righlc7165z7krmnaxrzd0fvfkbr2h";
   };
 
+  patches = [
+    # https://github.com/elementary/wingpanel-indicator-datetime/pull/207
+    # Fixes lots of issues despite being rejected upstream
+    # https://github.com/elementary/wingpanel-indicator-datetime/issues/206
+    # https://github.com/elementary/wingpanel-indicator-datetime/issues/55
+    # https://github.com/elementary/wingpanel-indicator-datetime/issues/127
+    ./207.patch
+  ];
+
   passthru = {
     updateScript = pantheon.updateScript {
       attrPath = "pantheon.${pname}";
diff --git a/pkgs/development/compilers/crystal/build-package.nix b/pkgs/development/compilers/crystal/build-package.nix
index 8ffa89a11b4a..856c6e58bc18 100644
--- a/pkgs/development/compilers/crystal/build-package.nix
+++ b/pkgs/development/compilers/crystal/build-package.nix
@@ -1,53 +1,109 @@
-{ stdenv, lib, crystal, linkFarm, fetchFromGitHub }:
-{ # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root
-  shardsFile ? null
+{ stdenv, lib, crystal, shards, git, pkgconfig, which, linkFarm, fetchFromGitHub, installShellFiles }:
+
+{ # Some projects do not include a lock file, so you can pass one
+  lockFile ? null
+  # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root
+, shardsFile ? null
+  # We support different builders. To make things more straight forward, make it
+  # user selectable instead of trying to autodetect
+, format ? "make"
+, installManPages ? true
   # Specify binaries to build in the form { foo.src = "src/foo.cr"; }
   # The default `crystal build` options can be overridden with { foo.options = [ "--no-debug" ]; }
-, crystalBinaries ? {}
-, ...
-}@args:
+, crystalBinaries ? { }, ... }@args:
+
+assert (builtins.elem format [ "make" "crystal" "shards" ]);
+
 let
-  mkDerivationArgs = builtins.removeAttrs args [ "shardsFile" "crystalBinaries" ];
+  mkDerivationArgs = builtins.removeAttrs args [
+    "format"
+    "installManPages"
+    "lockFile"
+    "shardsFile"
+    "crystalBinaries"
+  ];
 
   crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList (name: value: {
     inherit name;
     path = fetchFromGitHub value;
   }) (import shardsFile));
 
-  defaultOptions = [ "--release" "--progress" "--no-debug" "--verbose" ];
+  # we previously had --no-debug here but that is not recommended by upstream
+  defaultOptions = [ "--release" "--progress" "--verbose" ];
 
+  buildDirectly = shardsFile == null || crystalBinaries != { };
 in stdenv.mkDerivation (mkDerivationArgs // {
 
-  configurePhase = args.configurePhase or ''
-    runHook preConfigure
-    ${lib.optionalString (shardsFile != null) "ln -s ${crystalLib} lib"}
-    runHook postConfigure
-  '';
+  configurePhase = args.configurePhase or lib.concatStringsSep "\n" ([
+    "runHook preConfigure"
+  ] ++ lib.optional (lockFile != null)   "ln -s ${lockFile} ./shard.lock"
+    ++ lib.optional (shardsFile != null) "ln -s ${crystalLib} lib"
+    ++ [ "runHook postConfigure "]);
 
-  buildInputs = args.buildInputs or [] ++ [ crystal ];
-
-  buildPhase = args.buildPhase or ''
-    runHook preBuild
-    ${lib.concatStringsSep "\n" (lib.mapAttrsToList (bin: attrs: ''
-      crystal ${lib.escapeShellArgs ([
-        "build"
-        "-o" bin
-        (attrs.src or (throw "No source file for crystal binary ${bin} provided"))
-      ] ++ attrs.options or defaultOptions)}
-    '') crystalBinaries)}
-    runHook postBuild
-  '';
+  CRFLAGS = lib.concatStringsSep " " defaultOptions;
+
+  PREFIX = placeholder "out";
+
+  buildInputs = args.buildInputs or [ ] ++ [ crystal ]
+    ++ lib.optional (format != "crystal") shards;
+
+  nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [ git installShellFiles pkgconfig which ];
+
+  buildPhase = args.buildPhase or (lib.concatStringsSep "\n" ([
+    "runHook preBuild"
+  ] ++ lib.optional (format == "make")
+    ''make ''${buildTargets:-build} $makeFlags''
+  ++ lib.optionals (format == "crystal") (lib.mapAttrsToList (bin: attrs: ''
+        crystal ${lib.escapeShellArgs (["build" "-o" bin
+            (attrs.src or (throw "No source file for crystal binary ${bin} provided"))
+        ] ++ (attrs.options or defaultOptions))}
+      '') crystalBinaries)
+  ++ lib.optional (format == "shards")
+      "shards build --local --production ${lib.concatStringsSep " " defaultOptions}"
+  ++ [ "runHook postBuild" ]));
+
+  installPhase = args.installPhase or (lib.concatStringsSep "\n" ([
+    "runHook preInstall"
+  ] ++ lib.optional (format == "make")
+    ''make ''${installTargets:-install} $installFlags''
+  ++ lib.optionals (format == "crystal") (map (bin: ''
+      install -Dm555 ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]}
+    '') (lib.attrNames crystalBinaries))
+  ++ lib.optional (format == "shards")
+      ''install -Dm555 bin/* -t $out/bin''
+  ++ [
+    ''
+      for f in README* *.md LICENSE; do
+        test -f $f && install -Dm444 $f -t $out/share/doc/${args.pname}
+      done
+    ''
+  ] ++ (lib.optional installManPages ''
+      if [ -d man ]; then
+        installManPage man/*.?
+      fi
+  '') ++ [
+    "runHook postInstall"
+  ]));
+
+  doCheck = args.doCheck or true;
+
+  checkPhase = args.checkPhase or (lib.concatStringsSep "\n" ([
+    "runHook preCheck"
+  ] ++ lib.optional (format == "make")
+    ''make ''${checkTarget:-test} $checkFlags''
+  ++ lib.optional (format != "make")
+    ''crystal ''${checkTarget:-spec} $checkFlags''
+  ++ [ "runHook postCheck" ]));
+
+  doInstallCheck = args.doInstallCheck or true;
 
-  installPhase = args.installPhase or ''
-    runHook preInstall
-    mkdir -p "$out/bin"
-    ${lib.concatMapStringsSep "\n" (bin: ''
-      mv ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]}
-    '') (lib.attrNames crystalBinaries)}
-    runHook postInstall
+  installCheckPhase = args.installCheckPhase or ''
+    for f in $out/bin/*; do
+      $f --help
+    done
   '';
 
-  meta = args.meta or {} // {
+  meta = args.meta or { } // {
     platforms = args.meta.platforms or crystal.meta.platforms;
   };
 })
diff --git a/pkgs/development/compilers/crystal/crystal2nix.nix b/pkgs/development/compilers/crystal/crystal2nix.nix
index ac69b9b3d965..5fc40cd23741 100644
--- a/pkgs/development/compilers/crystal/crystal2nix.nix
+++ b/pkgs/development/compilers/crystal/crystal2nix.nix
@@ -1,4 +1,5 @@
 { lib, crystal, nix-prefetch-git }:
+
 crystal.buildCrystalPackage {
   pname = "crystal2nix";
   version = "unstable-2018-07-31";
@@ -6,11 +7,16 @@ crystal.buildCrystalPackage {
   nixPrefetchGit = "${lib.getBin nix-prefetch-git}/bin/nix-prefetch-git";
   unpackPhase = "substituteAll ${./crystal2nix.cr} crystal2nix.cr";
 
+  format = "crystal";
+
   crystalBinaries.crystal2nix.src = "crystal2nix.cr";
 
+  # it will blow up without a shard.yml file
+  doInstallCheck = false;
+
   meta = with lib; {
     description = "Utility to convert Crystal's shard.lock files to a Nix file";
     license = licenses.mit;
-    maintainers = [ maintainers.manveru ];
+    maintainers = with maintainers; [ manveru ];
   };
 }
diff --git a/pkgs/development/compilers/julia/1.3.nix b/pkgs/development/compilers/julia/1.3.nix
index 49dc17a27f45..b67a78b4a5ab 100644
--- a/pkgs/development/compilers/julia/1.3.nix
+++ b/pkgs/development/compilers/julia/1.3.nix
@@ -12,7 +12,7 @@
 , CoreServices, ApplicationServices
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 with stdenv.lib;
 
@@ -88,7 +88,7 @@ stdenv.mkDerivation rec {
       "SHELL=${stdenv.shell}"
 
       "USE_SYSTEM_BLAS=1"
-      "USE_BLAS64=${if blas.is64bit then "1" else "0"}"
+      "USE_BLAS64=${if blas.isILP64 then "1" else "0"}"
 
       "USE_SYSTEM_LAPACK=1"
 
diff --git a/pkgs/development/compilers/julia/shared.nix b/pkgs/development/compilers/julia/shared.nix
index 92e3d4a5c14b..29ac41150506 100644
--- a/pkgs/development/compilers/julia/shared.nix
+++ b/pkgs/development/compilers/julia/shared.nix
@@ -22,7 +22,7 @@
 
 with stdenv.lib;
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 let
   dsfmtVersion = "2.2.3";
@@ -137,7 +137,7 @@ stdenv.mkDerivation rec {
       "SHELL=${stdenv.shell}"
 
       "USE_SYSTEM_BLAS=1"
-      "USE_BLAS64=${if blas.is64bit then "1" else "0"}"
+      "USE_BLAS64=${if blas.isILP64 then "1" else "0"}"
 
       "USE_SYSTEM_LAPACK=1"
 
diff --git a/pkgs/development/compilers/ldc/binary.nix b/pkgs/development/compilers/ldc/binary.nix
deleted file mode 100644
index 56d40be86194..000000000000
--- a/pkgs/development/compilers/ldc/binary.nix
+++ /dev/null
@@ -1,41 +0,0 @@
-{ stdenv, fetchurl, curl, tzdata, autoPatchelfHook, fixDarwinDylibNames, libxml2
-, version, hashes }:
-with stdenv;
-let
-  OS = if hostPlatform.isDarwin then "osx" else hostPlatform.parsed.kernel.name;
-  ARCH = toString hostPlatform.parsed.cpu.name;
-in mkDerivation {
-  pname = "ldc-bootstrap";
-  inherit version;
-
-  src = fetchurl rec {
-    name = "ldc2-${version}-${OS}-${ARCH}.tar.xz";
-    url = "https://github.com/ldc-developers/ldc/releases/download/v${version}/${name}";
-    sha256 = hashes."${OS}-${ARCH}" or (throw "missing bootstrap sha256 for ${OS}-${ARCH}");
-  };
-
-  dontConfigure = true;
-  dontBuild = true;
-
-  nativeBuildInputs = [ fixDarwinDylibNames autoPatchelfHook ];
-
-  buildInputs = lib.optionals stdenv.hostPlatform.isLinux [ libxml2 stdenv.cc.cc ];
-
-  propagatedBuildInputs = [ curl tzdata ];
-
-  installPhase = ''
-    mkdir -p $out
-
-    mv bin etc import lib LICENSE README $out/
-  '';
-
-  meta = with lib; {
-    inherit version;
-    description = "The LLVM-based D Compiler";
-    homepage = "https://github.com/ldc-developers/ldc";
-    # from https://github.com/ldc-developers/ldc/blob/master/LICENSE
-    license = with licenses; [ bsd3 boost mit ncsa gpl2Plus ];
-    maintainers = with maintainers; [ ThomasMader lionello ];
-    platforms = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
-  };
-}
diff --git a/pkgs/development/compilers/ldc/bootstrap.nix b/pkgs/development/compilers/ldc/bootstrap.nix
deleted file mode 100644
index fde4c8426848..000000000000
--- a/pkgs/development/compilers/ldc/bootstrap.nix
+++ /dev/null
@@ -1,10 +0,0 @@
-{ callPackage }:
-callPackage ./binary.nix {
-  version = "1.19.0";
-  hashes = {
-    # Get these from `nix-prefetch-url https://github.com/ldc-developers/ldc/releases/download/v1.19.0/ldc2-1.19.0-osx-x86_64.tar.xz` etc..
-    osx-x86_64 = "1bp3xkh9zp64dzq8isanib1gacb3nfbl70qv15qygwk1zan6zgy7";
-    linux-x86_64 = "146grr2lwarfk13wgkpyb77xb6b3as1is2rf4s2hipqjmc8biy1h";
-    linux-aarch64  = "1fv6jshfvi15m7masgxq1hgp216qjd5amizrqdf26vhrq3a08li3";
-  };
-}
diff --git a/pkgs/development/compilers/ldc/default.nix b/pkgs/development/compilers/ldc/default.nix
index 5a4baabcf8d8..19fe2981c833 100644
--- a/pkgs/development/compilers/ldc/default.nix
+++ b/pkgs/development/compilers/ldc/default.nix
@@ -1,5 +1,173 @@
-import ./generic.nix {
-  version = "1.20.1";
-  ldcSha256 = "1bqsgab22v02pc3c9gcyf15y7aimadv24d68icaw5lpgnvzxy89b";
+{ stdenv, fetchurl, cmake, ninja, llvm_5, llvm_8, curl, tzdata
+, libconfig, lit, gdb, unzip, darwin, bash
+, callPackage, makeWrapper, runCommand, targetPackages
+, bootstrapVersion ? false
+, version ? "1.17.0"
+, ldcSha256 ? "1aag5jfrng6p4ms0fs90hjbv9bcj3hj8h52r68c3cm6racdajbva"
+}:
+
+let
+  bootstrapLdc = if !bootstrapVersion then
+    # LDC 0.17.x is the last version which doesn't need a working D compiler to
+    # build so we use that version to bootstrap the actual build.
+    callPackage ./default.nix {
+      bootstrapVersion = true;
+      version = "0.17.6";
+      ldcSha256 = "0qf5kbxddgmg3kqzi0kf4bgv8vdrnv16y07hcpm0cwv9mc3qr2w6";
+    }
+  else
+    "";
+
+  pathConfig = runCommand "ldc-lib-paths" {} ''
+    mkdir $out
+    echo ${tzdata}/share/zoneinfo/ > $out/TZDatabaseDirFile
+    echo ${curl.out}/lib/libcurl${stdenv.hostPlatform.extensions.sharedLibrary} > $out/LibcurlPathFile
+  '';
+in
+
+stdenv.mkDerivation rec {
+  pname = "ldc";
+  inherit version;
+
+  enableParallelBuilding = true;
+
+  src = fetchurl {
+    url = "https://github.com/ldc-developers/ldc/releases/download/v${version}/ldc-${version}-src.tar.gz";
+    sha256 = ldcSha256;
+  };
+
+  # https://issues.dlang.org/show_bug.cgi?id=19553
+  hardeningDisable = [ "fortify" ];
+
+  postUnpack = ''
+    patchShebangs .
+  ''
+
+  + stdenv.lib.optionalString (!bootstrapVersion) ''
+      rm ldc-${version}-src/tests/d2/dmd-testsuite/fail_compilation/mixin_gc.d
+      rm ldc-${version}-src/tests/d2/dmd-testsuite/runnable/xtest46_gc.d
+      rm ldc-${version}-src/tests/d2/dmd-testsuite/runnable/testptrref_gc.d
+
+      # test depends on current year
+      rm ldc-${version}-src/tests/d2/dmd-testsuite/compilable/ddocYear.d
+  ''
+
+  + stdenv.lib.optionalString (!bootstrapVersion && stdenv.hostPlatform.isDarwin) ''
+      # https://github.com/NixOS/nixpkgs/issues/34817
+      rm -r ldc-${version}-src/tests/plugins/addFuncEntryCall
+  '';
+
+  postPatch = ''
+      # Setting SHELL=$SHELL when dmd testsuite is run doesn't work on Linux somehow
+      substituteInPlace tests/d2/dmd-testsuite/Makefile --replace "SHELL=/bin/bash" "SHELL=${bash}/bin/bash"
+    ''
+
+  + stdenv.lib.optionalString (!bootstrapVersion && stdenv.hostPlatform.isLinux) ''
+      substituteInPlace runtime/phobos/std/socket.d --replace "assert(ih.addrList[0] == 0x7F_00_00_01);" ""
+  ''
+
+  + stdenv.lib.optionalString (!bootstrapVersion && stdenv.hostPlatform.isDarwin) ''
+      substituteInPlace runtime/phobos/std/socket.d --replace "foreach (name; names)" "names = []; foreach (name; names)"
+  ''
+
+  + stdenv.lib.optionalString (bootstrapVersion && stdenv.hostPlatform.isDarwin) ''
+      # Was not able to compile on darwin due to "__inline_isnanl"
+      # being undefined.
+      # TODO Remove with version > 0.17.6
+      substituteInPlace dmd2/root/port.c --replace __inline_isnanl __inline_isnan
+  '';
+
+  nativeBuildInputs = [ cmake ninja makeWrapper unzip ]
+    ++ stdenv.lib.optionals (!bootstrapVersion) [
+      bootstrapLdc lit lit.python
+    ]
+    ++ stdenv.lib.optional (!bootstrapVersion && stdenv.hostPlatform.isDarwin)
+      # https://github.com/NixOS/nixpkgs/issues/57120
+      # https://github.com/NixOS/nixpkgs/pull/59197#issuecomment-481972515
+      llvm_5
+    ++ stdenv.lib.optional (!bootstrapVersion && !stdenv.hostPlatform.isDarwin)
+      llvm_8
+    ++ stdenv.lib.optional (!bootstrapVersion && !stdenv.hostPlatform.isDarwin)
+      # https://github.com/NixOS/nixpkgs/pull/36378#issuecomment-385034818
+      gdb
+    ++ stdenv.lib.optionals (bootstrapVersion) [
+      libconfig llvm_5
+    ]
+    ++ stdenv.lib.optional stdenv.hostPlatform.isDarwin
+      darwin.apple_sdk.frameworks.Foundation;
+
+
+  buildInputs = [ curl tzdata ];
+
+  cmakeFlags = stdenv.lib.optionals (!bootstrapVersion) [
+    "-DD_FLAGS=-d-version=TZDatabaseDir;-d-version=LibcurlPath;-J${pathConfig}"
+    "-DCMAKE_BUILD_TYPE=Release"
+  ];
+
+  postConfigure = ''
+    export DMD=$PWD/bin/ldmd2
+  '';
+
+  makeFlags = [ "DMD=$DMD" ];
+
+  fixNames = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin  ''
+    fixDarwinDylibNames() {
+      local flags=()
+
+      for fn in "$@"; do
+        flags+=(-change "$(basename "$fn")" "$fn")
+      done
+
+      for fn in "$@"; do
+        if [ -L "$fn" ]; then continue; fi
+        echo "$fn: fixing dylib"
+        install_name_tool -id "$fn" "''${flags[@]}" "$fn"
+      done
+    }
+
+    fixDarwinDylibNames $(find "$(pwd)/lib" -name "*.dylib")
+    export DYLD_LIBRARY_PATH=$(pwd)/lib
+  '';
+
+  # https://github.com/ldc-developers/ldc/issues/2497#issuecomment-459633746
+  additionalExceptions = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin
+    "|druntime-test-shared";
+
+  doCheck = !bootstrapVersion;
+
+  checkPhase = stdenv.lib.optionalString doCheck ''
+    # Build default lib test runners
+    ninja -j$NIX_BUILD_CORES all-test-runners
+
+    ${fixNames}
+
+    # Run dmd testsuite
+    export DMD_TESTSUITE_MAKE_ARGS="-j$NIX_BUILD_CORES DMD=$DMD CC=$CXX"
+    ctest -V -R "dmd-testsuite"
+
+    # Build and run LDC D unittests.
+    ctest --output-on-failure -R "ldc2-unittest"
+
+    # Run LIT testsuite.
+    ctest -V -R "lit-tests"
+
+    # Run default lib unittests
+    ctest -j$NIX_BUILD_CORES --output-on-failure -E "ldc2-unittest|lit-tests|dmd-testsuite${additionalExceptions}"
+  '';
+
+  postInstall = ''
+    wrapProgram $out/bin/ldc2 \
+        --prefix PATH ":" "${targetPackages.stdenv.cc}/bin" \
+        --set-default CC "${targetPackages.stdenv.cc}/bin/cc"
+   '';
+
+  meta = with stdenv.lib; {
+    description = "The LLVM-based D compiler";
+    homepage = "https://github.com/ldc-developers/ldc";
+    # from https://github.com/ldc-developers/ldc/blob/master/LICENSE
+    license = with licenses; [ bsd3 boost mit ncsa gpl2Plus ];
+    maintainers = with maintainers; [ ThomasMader ];
+    platforms = [ "x86_64-linux" "i686-linux" "x86_64-darwin" ];
+  };
 }
 
diff --git a/pkgs/development/compilers/ldc/generic.nix b/pkgs/development/compilers/ldc/generic.nix
deleted file mode 100644
index c93d423945cb..000000000000
--- a/pkgs/development/compilers/ldc/generic.nix
+++ /dev/null
@@ -1,143 +0,0 @@
-{ version, ldcSha256 }:
-{ stdenv, fetchurl, cmake, ninja, llvm_5, llvm_8, curl, tzdata
-, libconfig, lit, gdb, unzip, darwin, bash
-, callPackage, makeWrapper, runCommand, targetPackages
-, ldcBootstrap ? callPackage ./bootstrap.nix { }
-}:
-
-let
-  pathConfig = runCommand "ldc-lib-paths" {} ''
-    mkdir $out
-    echo ${tzdata}/share/zoneinfo/ > $out/TZDatabaseDirFile
-    echo ${curl.out}/lib/libcurl${stdenv.hostPlatform.extensions.sharedLibrary} > $out/LibcurlPathFile
-  '';
-
-in
-
-stdenv.mkDerivation rec {
-  pname = "ldc";
-  inherit version;
-
-  enableParallelBuilding = true;
-
-  src = fetchurl {
-    url = "https://github.com/ldc-developers/ldc/releases/download/v${version}/ldc-${version}-src.tar.gz";
-    sha256 = ldcSha256;
-  };
-
-  # https://issues.dlang.org/show_bug.cgi?id=19553
-  hardeningDisable = [ "fortify" ];
-
-  postUnpack = ''
-    patchShebangs .
-  ''
-  + ''
-      rm ldc-${version}-src/tests/d2/dmd-testsuite/fail_compilation/mixin_gc.d
-      rm ldc-${version}-src/tests/d2/dmd-testsuite/runnable/xtest46_gc.d
-      rm ldc-${version}-src/tests/d2/dmd-testsuite/runnable/testptrref_gc.d
-
-      # test depends on current year
-      rm ldc-${version}-src/tests/d2/dmd-testsuite/compilable/ddocYear.d
-  ''
-  + stdenv.lib.optionalString stdenv.hostPlatform.isDarwin ''
-      # https://github.com/NixOS/nixpkgs/issues/34817
-      rm -r ldc-${version}-src/tests/plugins/addFuncEntryCall
-  '';
-
-  postPatch = ''
-    # Setting SHELL=$SHELL when dmd testsuite is run doesn't work on Linux somehow
-    substituteInPlace tests/d2/dmd-testsuite/Makefile --replace "SHELL=/bin/bash" "SHELL=${bash}/bin/bash"
-  ''
-  + stdenv.lib.optionalString stdenv.hostPlatform.isLinux ''
-      substituteInPlace runtime/phobos/std/socket.d --replace "assert(ih.addrList[0] == 0x7F_00_00_01);" ""
-  ''
-  + stdenv.lib.optionalString stdenv.hostPlatform.isDarwin ''
-      substituteInPlace runtime/phobos/std/socket.d --replace "foreach (name; names)" "names = []; foreach (name; names)"
-  '';
-
-  nativeBuildInputs = [
-    cmake ninja makeWrapper unzip ldcBootstrap lit lit.python
-  ]
-  ++ stdenv.lib.optionals stdenv.hostPlatform.isDarwin [
-    darwin.apple_sdk.frameworks.Foundation
-    # https://github.com/NixOS/nixpkgs/issues/57120
-    # https://github.com/NixOS/nixpkgs/pull/59197#issuecomment-481972515
-    llvm_5
-  ]
-  ++ stdenv.lib.optionals (!stdenv.hostPlatform.isDarwin) [
-    llvm_8
-    # https://github.com/NixOS/nixpkgs/pull/36378#issuecomment-385034818
-    gdb
-  ];
-
-  buildInputs = [ curl tzdata ];
-
-  cmakeFlags = [
-    "-DD_FLAGS=-d-version=TZDatabaseDir;-d-version=LibcurlPath;-J${pathConfig}"
-    "-DCMAKE_BUILD_TYPE=Release"
-  ];
-
-  postConfigure = ''
-    export DMD=$PWD/bin/ldmd2
-  '';
-
-  makeFlags = [ "DMD=$DMD" ];
-
-  fixNames = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin  ''
-    fixDarwinDylibNames() {
-      local flags=()
-
-      for fn in "$@"; do
-        flags+=(-change "$(basename "$fn")" "$fn")
-      done
-
-      for fn in "$@"; do
-        if [ -L "$fn" ]; then continue; fi
-        echo "$fn: fixing dylib"
-        install_name_tool -id "$fn" "''${flags[@]}" "$fn"
-      done
-    }
-
-    fixDarwinDylibNames $(find "$(pwd)/lib" -name "*.dylib")
-    export DYLD_LIBRARY_PATH=$(pwd)/lib
-  '';
-
-  # https://github.com/ldc-developers/ldc/issues/2497#issuecomment-459633746
-  additionalExceptions = stdenv.lib.optionalString stdenv.hostPlatform.isDarwin
-    "|druntime-test-shared";
-
-  checkPhase = ''
-    # Build default lib test runners
-    ninja -j$NIX_BUILD_CORES all-test-runners
-
-    ${fixNames}
-
-    # Run dmd testsuite
-    export DMD_TESTSUITE_MAKE_ARGS="-j$NIX_BUILD_CORES DMD=$DMD"
-    ctest -V -R "dmd-testsuite"
-
-    # Build and run LDC D unittests.
-    ctest --output-on-failure -R "ldc2-unittest"
-
-    # Run LIT testsuite.
-    ctest -V -R "lit-tests"
-
-    # Run default lib unittests
-    ctest -j$NIX_BUILD_CORES --output-on-failure -E "ldc2-unittest|lit-tests|dmd-testsuite${additionalExceptions}"
-  '';
-
-  postInstall = ''
-    wrapProgram $out/bin/ldc2 \
-        --prefix PATH ":" "${targetPackages.stdenv.cc}/bin" \
-        --set-default CC "${targetPackages.stdenv.cc}/bin/cc"
-   '';
-
-  meta = with stdenv.lib; {
-    description = "The LLVM-based D compiler";
-    homepage = "https://github.com/ldc-developers/ldc";
-    # from https://github.com/ldc-developers/ldc/blob/master/LICENSE
-    license = with licenses; [ bsd3 boost mit ncsa gpl2Plus ];
-    maintainers = with maintainers; [ ThomasMader lionello ];
-    platforms = [ "x86_64-linux" "i686-linux" "x86_64-darwin" ];
-  };
-}
diff --git a/pkgs/development/compilers/mint/default.nix b/pkgs/development/compilers/mint/default.nix
index 7f5af5e834b0..d1d103c047fb 100644
--- a/pkgs/development/compilers/mint/default.nix
+++ b/pkgs/development/compilers/mint/default.nix
@@ -1,27 +1,36 @@
-{ lib, fetchFromGitHub, crystal, zlib, openssl, duktape, which, libyaml }:
-crystal.buildCrystalPackage rec {
-  version = "0.7.1";
+{ lib, fetchFromGitHub, crystal_0_33, openssl }:
+
+let crystal = crystal_0_33;
+in crystal.buildCrystalPackage rec {
+  version = "0.9.0";
   pname = "mint";
+
   src = fetchFromGitHub {
     owner = "mint-lang";
     repo = "mint";
     rev = version;
-    sha256 = "18cg96kl4dn89bj6fm3080zzyd1r7rsfi17agdjjayd2v9fgs95l";
+    sha256 = "0y1qr616x7s0pjgih6s1n4wiwb8kn8l1knnzmib6j4jmqax0jhz0";
   };
 
-  buildInputs = [ openssl ];
+  postPatch = ''
+    export HOME=$TMP
+  '';
+
+  format = "shards";
 
   # Update with
   #   nix-shell -p crystal2nix --run crystal2nix
   # with mint's shard.lock file in the current directory
   shardsFile = ./shards.nix;
-  crystalBinaries.mint.src = "src/mint.cr";
 
-  meta = {
+  buildInputs = [ openssl ];
+
+  meta = with lib; {
     description = "A refreshing language for the front-end web";
     homepage = "https://mint-lang.com/";
-    license = lib.licenses.bsd3;
-    maintainers = with lib.maintainers; [ manveru ];
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ manveru ];
     platforms = [ "x86_64-linux" "i686-linux" "x86_64-darwin" ];
+    broken = lib.versionOlder crystal.version "0.33";
   };
 }
diff --git a/pkgs/development/compilers/mint/shards.nix b/pkgs/development/compilers/mint/shards.nix
index b3583ac2cbaa..8e2b6b6ad4df 100644
--- a/pkgs/development/compilers/mint/shards.nix
+++ b/pkgs/development/compilers/mint/shards.nix
@@ -2,26 +2,26 @@
   admiral = {
     owner = "jwaldrip";
     repo = "admiral.cr";
-    rev = "v1.7.3";
-    sha256 = "0b98qjy43wsrc08am7lkhcdsxc7gplf9hcmbvd4p3dw4g107rk91";
+    rev = "v1.9.0";
+    sha256 = "0y8gsh1qz42bc9jawcrn0i49mzzfvf8znmivd8lybapf0f53fblz";
   };
   ameba = {
-    owner = "veelenga";
+    owner = "crystal-ameba";
     repo = "ameba";
-    rev = "v0.10.1";
-    sha256 = "0dcw7px7g0c5pxpdlirhirqzhcc7gdwdfiwb9kgm4x1k74ghjgxq";
+    rev = "v0.12.0";
+    sha256 = "0g68yijbm2j4ig536fwq49d1z7x2iv9kp4g3gjklf5zn1sbqhm12";
   };
   baked_file_system = {
     owner = "schovi";
     repo = "baked_file_system";
-    rev = "v0.9.7";
-    sha256 = "1fi6zag1a6h4xwrfizy01dls3hhraqw0cmpwj7rjv1qcddjgig5z";
+    rev = "v0.9.8";
+    sha256 = "12l375jllg1lxvfh610dz0a39p803xw6q9fxlmnc6hy55i0gm0y3";
   };
   diff = {
     owner = "MakeNowJust";
     repo = "crystal-diff";
-    rev = "51962dc36f9bbb1b926d557f7cb8993a6c73cc63";
-    sha256 = "1nwnsxm8srfw8jg0yfi2v19x6j3dadx62hq0xpxra40qcqz9dbnp";
+    rev = "v1.1.0";
+    sha256 = "1q5q2d5mp1r8c6k5v4755sb3b6awiz85d1j280djzhbd0pggk3z7";
   };
   dotenv = {
     owner = "gdotdesign";
@@ -32,14 +32,14 @@
   exception_page = {
     owner = "crystal-loot";
     repo = "exception_page";
-    rev = "v0.1.2";
-    sha256 = "0j5ishhyriq9p339yaawrmawl9wgmp1paniq30a8d6a0568h3avq";
+    rev = "v0.1.4";
+    sha256 = "0bsp2m89sl0bg9d5szbs1nxyk7yk58rkk24aibr39hhb5zi70pqi";
   };
   kemal = {
     owner = "kemalcr";
     repo = "kemal";
-    rev = "v0.25.1";
-    sha256 = "1334i905xj6vlmp8acyybwwlaxsgmf90b59da7brzpnf28wci782";
+    rev = "v0.26.1";
+    sha256 = "169pwkjmk7x6j8i0rf5rpyk1y0hl7jaf9h6yrq4ha2ag9yq9i8fr";
   };
   kilt = {
     owner = "jeromegn";
diff --git a/pkgs/development/interpreters/octave/default.nix b/pkgs/development/interpreters/octave/default.nix
index 4d2bf40b3292..06d69ed8117f 100644
--- a/pkgs/development/interpreters/octave/default.nix
+++ b/pkgs/development/interpreters/octave/default.nix
@@ -53,7 +53,7 @@
 , darwin
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   version = "5.2.0";
@@ -125,12 +125,12 @@ stdenv.mkDerivation rec {
   enableParallelBuilding = true;
 
   # See https://savannah.gnu.org/bugs/?50339
-  F77_INTEGER_8_FLAG = if blas.is64bit then "-fdefault-integer-8" else "";
+  F77_INTEGER_8_FLAG = if blas.isILP64 then "-fdefault-integer-8" else "";
 
   configureFlags = [
     "--with-blas=blas"
     "--with-lapack=lapack"
-    (if blas.is64bit then "--enable-64" else "--disable-64")
+    (if blas.isILP64 then "--enable-64" else "--disable-64")
   ]
     ++ (if stdenv.isDarwin then [ "--enable-link-all-dependencies" ] else [ ])
     ++ stdenv.lib.optionals enableReadline [ "--enable-readline" ]
diff --git a/pkgs/development/libraries/appstream-glib/default.nix b/pkgs/development/libraries/appstream-glib/default.nix
index ceb4c238a7b0..5b777dff3ea2 100644
--- a/pkgs/development/libraries/appstream-glib/default.nix
+++ b/pkgs/development/libraries/appstream-glib/default.nix
@@ -23,7 +23,7 @@
 , pngquant
 }:
 stdenv.mkDerivation rec {
-  name = "appstream-glib-0.7.16";
+  name = "appstream-glib-0.7.17";
 
   outputs = [ "out" "dev" "man" "installedTests" ];
   outputBin = "dev";
@@ -32,7 +32,7 @@ stdenv.mkDerivation rec {
     owner = "hughsie";
     repo = "appstream-glib";
     rev = stdenv.lib.replaceStrings [ "." "-" ] [ "_" "_" ] name;
-    sha256 = "05x2pmsq18fcpgfvx0y54qdlryy5c9k3sxk6kgank8frkzhgnm9r";
+    sha256 = "06pm8l58y0ladimyckbvlslr5bjj9rwb70rgjmn09l41pdpipy2i";
   };
 
   nativeBuildInputs = [
diff --git a/pkgs/development/libraries/fflas-ffpack/default.nix b/pkgs/development/libraries/fflas-ffpack/default.nix
index 16a9e3e79d45..bc84039a9aa2 100644
--- a/pkgs/development/libraries/fflas-ffpack/default.nix
+++ b/pkgs/development/libraries/fflas-ffpack/default.nix
@@ -2,7 +2,7 @@
 , gmpxx
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "fflas-ffpack";
diff --git a/pkgs/development/libraries/icu/65.nix b/pkgs/development/libraries/icu/65.nix
new file mode 100644
index 000000000000..c5074eea114d
--- /dev/null
+++ b/pkgs/development/libraries/icu/65.nix
@@ -0,0 +1,4 @@
+import ./base.nix {
+  version = "65.1";
+  sha256 = "0j6r6qqnhfr5iqkx53k63ifkm93kv1kkb7h2mlgd1mnnndk79qsk";
+}
diff --git a/pkgs/development/libraries/icu/66.nix b/pkgs/development/libraries/icu/66.nix
new file mode 100644
index 000000000000..5dfad945d291
--- /dev/null
+++ b/pkgs/development/libraries/icu/66.nix
@@ -0,0 +1,4 @@
+import ./base.nix {
+  version = "66.1";
+  sha256 = "0bharwzc9nzkbrcf405z2nb3h7q0711z450arz0mjmdrk8hg58sj";
+}
diff --git a/pkgs/development/libraries/icu/base.nix b/pkgs/development/libraries/icu/base.nix
index 96b00027e207..81f75ad526a7 100644
--- a/pkgs/development/libraries/icu/base.nix
+++ b/pkgs/development/libraries/icu/base.nix
@@ -9,8 +9,7 @@ let
 
   baseAttrs = {
     src = fetchurl {
-      url = "http://download.icu-project.org/files/${pname}/${version}/${pname}-"
-        + (stdenv.lib.replaceChars ["."] ["_"] version) + "-src.tgz";
+      url = "https://github.com/unicode-org/icu/releases/download/release-${lib.replaceChars [ "." ] [ "-" ] version}/icu4c-${lib.replaceChars [ "." ] [ "_" ] version}-src.tgz";
       inherit sha256;
     };
 
diff --git a/pkgs/development/libraries/linbox/default.nix b/pkgs/development/libraries/linbox/default.nix
index 6d25cb459870..2217996acdbc 100644
--- a/pkgs/development/libraries/linbox/default.nix
+++ b/pkgs/development/libraries/linbox/default.nix
@@ -10,7 +10,7 @@
 , withSage ? false # sage support
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "linbox";
diff --git a/pkgs/development/libraries/qrupdate/default.nix b/pkgs/development/libraries/qrupdate/default.nix
index f6c16583ad75..424502dce0d4 100644
--- a/pkgs/development/libraries/qrupdate/default.nix
+++ b/pkgs/development/libraries/qrupdate/default.nix
@@ -18,7 +18,7 @@ stdenv.mkDerivation {
           -e 's,^LAPACK=.*,LAPACK=-L${lapack}/lib -llapack,' \
           Makeconf
     ''
-    + stdenv.lib.optionalString blas.is64bit
+    + stdenv.lib.optionalString blas.isILP64
     ''
       sed -i Makeconf -e '/^FFLAGS=.*/ s/$/-fdefault-integer-8/'
     '';
diff --git a/pkgs/development/libraries/science/math/arpack/default.nix b/pkgs/development/libraries/science/math/arpack/default.nix
index a5fbb679df5b..0829557d0f3d 100644
--- a/pkgs/development/libraries/science/math/arpack/default.nix
+++ b/pkgs/development/libraries/science/math/arpack/default.nix
@@ -27,7 +27,7 @@ stdenv.mkDerivation {
 
   cmakeFlags = [
     "-DBUILD_SHARED_LIBS=ON"
-    "-DINTERFACE64=${optionalString blas.is64bit "1"}"
+    "-DINTERFACE64=${optionalString blas.isILP64 "1"}"
   ];
 
   preCheck = if stdenv.isDarwin then ''
diff --git a/pkgs/development/libraries/science/math/ipopt/default.nix b/pkgs/development/libraries/science/math/ipopt/default.nix
index 647fd82ec0e9..97374fb0d477 100644
--- a/pkgs/development/libraries/science/math/ipopt/default.nix
+++ b/pkgs/development/libraries/science/math/ipopt/default.nix
@@ -1,6 +1,6 @@
 { stdenv, fetchurl, unzip, blas, lapack, gfortran }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "ipopt";
diff --git a/pkgs/development/libraries/science/math/magma/default.nix b/pkgs/development/libraries/science/math/magma/default.nix
index b34139e7f484..dbe162c60b34 100644
--- a/pkgs/development/libraries/science/math/magma/default.nix
+++ b/pkgs/development/libraries/science/math/magma/default.nix
@@ -1,8 +1,4 @@
-{ stdenv, fetchurl, cmake, gfortran, cudatoolkit, libpthreadstubs, lapack, blas
-, mklSupport ? false, mkl ? null
-}:
-
-assert !mklSupport || mkl != null;
+{ stdenv, fetchurl, cmake, gfortran, cudatoolkit, libpthreadstubs, lapack, blas }:
 
 with stdenv.lib;
 
@@ -17,13 +13,10 @@ in stdenv.mkDerivation {
     name = "magma-${version}.tar.gz";
   };
 
-  buildInputs = [ gfortran cudatoolkit libpthreadstubs cmake ]
-    ++ (if mklSupport then [ mkl ] else [ lapack blas ]);
+  buildInputs = [ gfortran cudatoolkit libpthreadstubs cmake lapack blas ];
 
   doCheck = false;
 
-  MKLROOT = optionalString mklSupport mkl;
-
   preConfigure = ''
     export CC=${cudatoolkit.cc}/bin/gcc CXX=${cudatoolkit.cc}/bin/g++
   '';
diff --git a/pkgs/development/libraries/science/math/scalapack/default.nix b/pkgs/development/libraries/science/math/scalapack/default.nix
index d20219860296..1cf9c2ed8d53 100644
--- a/pkgs/development/libraries/science/math/scalapack/default.nix
+++ b/pkgs/development/libraries/science/math/scalapack/default.nix
@@ -2,7 +2,7 @@
 , gfortran, mpi, blas, lapack
 } :
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "scalapack";
diff --git a/pkgs/development/libraries/science/math/scs/default.nix b/pkgs/development/libraries/science/math/scs/default.nix
index 2dcb47f11baa..3820f2b95275 100644
--- a/pkgs/development/libraries/science/math/scs/default.nix
+++ b/pkgs/development/libraries/science/math/scs/default.nix
@@ -1,6 +1,6 @@
 { stdenv, fetchFromGitHub, blas, lapack, gfortran, fixDarwinDylibNames }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "scs";
diff --git a/pkgs/development/libraries/science/math/suitesparse/4.2.nix b/pkgs/development/libraries/science/math/suitesparse/4.2.nix
index 34a1fb7ad9e6..b1c1202c5780 100644
--- a/pkgs/development/libraries/science/math/suitesparse/4.2.nix
+++ b/pkgs/development/libraries/science/math/suitesparse/4.2.nix
@@ -1,7 +1,7 @@
 { stdenv, fetchurl, gfortran, blas, lapack }:
 
 let
-  int_t = if blas.is64bit then "int64_t" else "int32_t";
+  int_t = if blas.isILP64 then "int64_t" else "int32_t";
 in
 stdenv.mkDerivation rec {
   version = "4.2.1";
diff --git a/pkgs/development/libraries/science/math/suitesparse/4.4.nix b/pkgs/development/libraries/science/math/suitesparse/4.4.nix
index b2b7e666b7ef..81a80c920b53 100644
--- a/pkgs/development/libraries/science/math/suitesparse/4.4.nix
+++ b/pkgs/development/libraries/science/math/suitesparse/4.4.nix
@@ -6,7 +6,7 @@ let
   version = "4.4.4";
   name = "suitesparse-${version}";
 
-  int_t = if blas.is64bit then "int64_t" else "int32_t";
+  int_t = if blas.isILP64 then "int64_t" else "int32_t";
   SHLIB_EXT = stdenv.hostPlatform.extensions.sharedLibrary;
 in
 stdenv.mkDerivation {
diff --git a/pkgs/development/libraries/science/math/suitesparse/default.nix b/pkgs/development/libraries/science/math/suitesparse/default.nix
index 48177987a7a2..f0480e1e2381 100644
--- a/pkgs/development/libraries/science/math/suitesparse/default.nix
+++ b/pkgs/development/libraries/science/math/suitesparse/default.nix
@@ -44,7 +44,7 @@ stdenv.mkDerivation rec {
     "BLAS=-lblas"
     "LAPACK=-llapack"
     "MY_METIS_LIB=-lmetis"
-  ] ++ stdenv.lib.optionals blas.is64bit [
+  ] ++ stdenv.lib.optionals blas.isILP64 [
     "CFLAGS=-DBLAS64"
   ] ++ stdenv.lib.optionals enableCuda [
     "CUDA_PATH=${cudatoolkit}"
diff --git a/pkgs/development/libraries/science/math/superlu/default.nix b/pkgs/development/libraries/science/math/superlu/default.nix
index 05ceb21387d3..ff59297bd839 100644
--- a/pkgs/development/libraries/science/math/superlu/default.nix
+++ b/pkgs/development/libraries/science/math/superlu/default.nix
@@ -1,7 +1,7 @@
 { stdenv, fetchurl, cmake,
   gfortran, blas, lapack}:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   version = "5.2.1";
diff --git a/pkgs/development/libraries/sundials/2.x.nix b/pkgs/development/libraries/sundials/2.x.nix
index 08cbd52ba394..b54e537fb823 100644
--- a/pkgs/development/libraries/sundials/2.x.nix
+++ b/pkgs/development/libraries/sundials/2.x.nix
@@ -8,7 +8,7 @@
 , gfortran
 , lapackSupport ? true }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "sundials";
diff --git a/pkgs/development/libraries/sundials/default.nix b/pkgs/development/libraries/sundials/default.nix
index 8ed8d6cfcb55..46cf437d72ca 100644
--- a/pkgs/development/libraries/sundials/default.nix
+++ b/pkgs/development/libraries/sundials/default.nix
@@ -7,7 +7,7 @@
 , gfortran
 , lapackSupport ? true }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "sundials";
diff --git a/pkgs/development/libraries/waylandpp/default.nix b/pkgs/development/libraries/waylandpp/default.nix
index 06faec558c01..824df552a1ac 100644
--- a/pkgs/development/libraries/waylandpp/default.nix
+++ b/pkgs/development/libraries/waylandpp/default.nix
@@ -1,19 +1,27 @@
-{ stdenv, fetchFromGitHub, cmake, pkgconfig, pugixml, wayland, libGL }:
+{ stdenv, fetchFromGitHub, cmake, pkgconfig, pugixml, wayland, libGL
+, docSupport ? true, doxygen ? null }:
 
+assert docSupport -> doxygen != null;
+
+with stdenv.lib;
 stdenv.mkDerivation rec {
   pname = "waylandpp";
-  version = "0.2.5";
+  version = "0.2.7";
 
   src = fetchFromGitHub {
     owner = "NilsBrause";
     repo = pname;
     rev = version;
-    sha256 = "16h57hzd688664qcyznzhjp3hxipdkzgv46x82yhkww24av8b55n";
+    sha256 = "1r4m0xhvwpcqxrqvp3hz1bzlkxqj2jiymd5r6hj8xjzz536hyprz";
   };
 
-  nativeBuildInputs = [ cmake pkgconfig ];
+  nativeBuildInputs = [ cmake pkgconfig ] ++ optional docSupport doxygen;
   buildInputs = [ pugixml wayland libGL ];
 
+  outputs = [ "bin" "dev" "lib" "out" ] ++ optionals docSupport [ "doc" "devman" ];
+
+  cmakeFlags = [ "-DCMAKE_INSTALL_DATADIR=${placeholder "dev"}" ];
+
   meta = with stdenv.lib; {
     description = "Wayland C++ binding";
     homepage = "https://github.com/NilsBrause/waylandpp/";
diff --git a/pkgs/development/ocaml-modules/lacaml/default.nix b/pkgs/development/ocaml-modules/lacaml/default.nix
index e4da2216a83d..23b38e469b4b 100644
--- a/pkgs/development/ocaml-modules/lacaml/default.nix
+++ b/pkgs/development/ocaml-modules/lacaml/default.nix
@@ -1,7 +1,7 @@
 { stdenv, fetchFromGitHub, darwin, ocaml, findlib, dune, base, stdio, lapack, blas }:
 
 assert stdenv.lib.versionAtLeast (stdenv.lib.getVersion ocaml) "4.05.0";
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "ocaml${ocaml.version}-lacaml";
diff --git a/pkgs/development/ocaml-modules/owl/default.nix b/pkgs/development/ocaml-modules/owl/default.nix
index c84743a8da52..b306ee9ce6d2 100644
--- a/pkgs/development/ocaml-modules/owl/default.nix
+++ b/pkgs/development/ocaml-modules/owl/default.nix
@@ -11,7 +11,7 @@
 , npy
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 assert blas.implementation == "openblas" && lapack.implementation == "openblas";
 
 buildDunePackage rec {
diff --git a/pkgs/development/python-modules/cvxopt/default.nix b/pkgs/development/python-modules/cvxopt/default.nix
index 9266f406b151..2b6d1b4d2484 100644
--- a/pkgs/development/python-modules/cvxopt/default.nix
+++ b/pkgs/development/python-modules/cvxopt/default.nix
@@ -14,7 +14,7 @@
 , withFftw ? true
 }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 buildPythonPackage rec {
   pname = "cvxopt";
diff --git a/pkgs/development/python-modules/dotnetcore2/default.nix b/pkgs/development/python-modules/dotnetcore2/default.nix
index 4d3edf0906a0..eeb962a845fd 100644
--- a/pkgs/development/python-modules/dotnetcore2/default.nix
+++ b/pkgs/development/python-modules/dotnetcore2/default.nix
@@ -7,7 +7,7 @@
 
 buildPythonPackage rec {
   pname = "dotnetcore2";
-  version = "2.1.11";
+  version = "2.1.13";
   format = "wheel";
   disabled = isPy27;
 
@@ -15,7 +15,7 @@ buildPythonPackage rec {
     inherit pname version format;
     python = "py3";
     platform = "manylinux1_x86_64";
-    sha256 = "0qhp94bjz4icz2f0fnhgck875chiqzy4lvsp6lwhj5jd0zsv2bb3";
+    sha256 = "1fbg3pn7g0a6pg0gb5vaapcc3cdp6wfnliim57fn3cnzmx5d8p6i";
   };
 
   nativeBuildInputs = [ unzip ];
@@ -35,13 +35,9 @@ buildPythonPackage rec {
     )
   ];
 
-  # unfortunately the noraml pip install fails because the manylinux1 format check fails with NixOS
-  installPhase = ''
-    mkdir -p $out/${python.sitePackages}/${pname}
-    # copy metadata
-    cp -r dotnetcore2-2* $out/${python.sitePackages}
-    # copy non-dotnetcore related files
-    cp -r dotnetcore2/{__init__.py,runtime.py} $out/${python.sitePackages}/${pname}
+  # prevent exposing a broken dotnet executable
+  postInstall = ''
+    rm -r $out/${python.sitePackages}/${pname}/bin
   '';
 
   # no tests, ensure it's one useful function works
diff --git a/pkgs/development/python-modules/goobook/default.nix b/pkgs/development/python-modules/goobook/default.nix
index f8daf66c1564..ac658b1940f4 100644
--- a/pkgs/development/python-modules/goobook/default.nix
+++ b/pkgs/development/python-modules/goobook/default.nix
@@ -12,6 +12,9 @@ buildPythonPackage rec {
     sha256 = "089a95s6g9izsy1fzpz48p6pz0wpngcbbrvsillm1n53492gfhjg";
   };
 
+  # Required for a breaking change in google-api-python-client 1.8.1:
+  patches = [ ./fix-build.patch ];
+
   propagatedBuildInputs = [
     google_api_python_client simplejson oauth2client setuptools
   ];
diff --git a/pkgs/development/python-modules/goobook/fix-build.patch b/pkgs/development/python-modules/goobook/fix-build.patch
new file mode 100644
index 000000000000..1121dbfdcb32
--- /dev/null
+++ b/pkgs/development/python-modules/goobook/fix-build.patch
@@ -0,0 +1,32 @@
+From 8de09b82c5ac900317043e1c1025f431516b6788 Mon Sep 17 00:00:00 2001
+From: Michael Weiss <dev.primeos@gmail.com>
+Date: Tue, 21 Apr 2020 21:41:04 +0200
+Subject: [PATCH] Switch from the alias apiclient to googleapiclient
+
+This fixes the package after a breaking change / bug in
+google-api-python-client 1.8.1 (see [0] and a lot of duplicate issues).
+
+The module apiclient is just an alias for googleapiclient [1].
+
+[0]: https://github.com/googleapis/google-api-python-client/issues/870
+[1]: https://github.com/googleapis/google-api-python-client/blob/v1.8.1/apiclient/__init__.py
+---
+ goobook/goobook.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/goobook/goobook.py b/goobook/goobook.py
+index 5bcb0b3..a2e25e9 100755
+--- a/goobook/goobook.py
++++ b/goobook/goobook.py
+@@ -31,7 +31,7 @@ import sys
+ import time
+ 
+ import httplib2
+-from apiclient.discovery import build
++from googleapiclient.discovery import build
+ 
+ from goobook.storage import Storage, storageify, unstorageify
+ 
+-- 
+2.26.1
+
diff --git a/pkgs/development/python-modules/google-api-python-client/default.nix b/pkgs/development/python-modules/google-api-python-client/default.nix
index 2d7ae43f7f1e..ac7bcb5cd524 100644
--- a/pkgs/development/python-modules/google-api-python-client/default.nix
+++ b/pkgs/development/python-modules/google-api-python-client/default.nix
@@ -4,11 +4,11 @@
 
 buildPythonPackage rec {
   pname = "google-api-python-client";
-  version = "1.8.0";
+  version = "1.8.2";
 
   src = fetchPypi {
     inherit pname version;
-    sha256 = "003rgr15r9j080f3n5y2x6ymxsfv652m3r7j83p7sbrd9shl4nqg";
+    sha256 = "09g7v6yrf8p0kgmjnzy9d0fx9p1zngk2pmprf0bx19j1zc9jqj5z";
   };
 
   # No tests included in archive
diff --git a/pkgs/development/python-modules/matrix-nio/default.nix b/pkgs/development/python-modules/matrix-nio/default.nix
index 9320efc91a23..ff4f6198aa5e 100644
--- a/pkgs/development/python-modules/matrix-nio/default.nix
+++ b/pkgs/development/python-modules/matrix-nio/default.nix
@@ -20,13 +20,13 @@
 
 buildPythonPackage rec {
   pname = "nio";
-  version = "0.9.0";
+  version = "0.10.0";
 
   src = fetchFromGitHub {
     owner = "poljar";
     repo = "matrix-nio";
     rev = version;
-    sha256 = "0gqhk9d06w1in6dj7aqy45skzyg8018nmclqd5r0m5nnw8yns6gz";
+    sha256 = "04ryf9lrm0820hqij46hav6mgplabnyl9dfj46iwvxasn06fh2j8";
   };
 
   nativeBuildInputs = [
@@ -56,6 +56,6 @@ buildPythonPackage rec {
     description = "A Python Matrix client library, designed according to sans I/O principles";
     homepage = "https://github.com/poljar/matrix-nio";
     license = licenses.isc;
-    maintainers = with maintainers; [ tilpner emily ];
+    maintainers = with maintainers; [ tilpner emily symphorien ];
   };
 }
diff --git a/pkgs/development/python-modules/numpy/default.nix b/pkgs/development/python-modules/numpy/default.nix
index 949d5e5898b3..4a062ca7b97d 100644
--- a/pkgs/development/python-modules/numpy/default.nix
+++ b/pkgs/development/python-modules/numpy/default.nix
@@ -12,18 +12,16 @@
 , setuptoolsBuildHook
  }:
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 let
   cfg = writeTextFile {
     name = "site.cfg";
     text = (lib.generators.toINI {} {
       ${blas.implementation} = {
-        include_dirs = "${blas}/include:${lapack}/include";
+        include_dirs = "${lib.getDev blas}/include:${lib.getDev lapack}/include";
         library_dirs = "${blas}/lib:${lapack}/lib";
-      } // lib.optionalAttrs (blas.implementation == "mkl") {
-        mkl_libs = "mkl_rt";
-        lapack_libs = "";
+        libraries = "lapack,lapacke,blas,cblas";
       };
     });
   };
diff --git a/pkgs/development/python-modules/pulsectl/default.nix b/pkgs/development/python-modules/pulsectl/default.nix
new file mode 100644
index 000000000000..dec80abda151
--- /dev/null
+++ b/pkgs/development/python-modules/pulsectl/default.nix
@@ -0,0 +1,31 @@
+{ lib, buildPythonPackage, fetchPypi, libpulseaudio, glibc, substituteAll, stdenv, pulseaudio, python }:
+
+buildPythonPackage rec {
+  pname = "pulsectl";
+  version = "20.4.3";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "1m5fz740r4rk2i8qsnblsn16hai7givqxbx21swhpflan1yzvzzm";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./library-paths.patch;
+      libpulse = "${libpulseaudio.out}/lib/libpulse${stdenv.hostPlatform.extensions.sharedLibrary}";
+      librt = "${glibc.out}/lib/librt${stdenv.hostPlatform.extensions.sharedLibrary}";
+    })
+  ];
+
+  checkInputs = [ pulseaudio ];
+  checkPhase = ''
+    ${python.interpreter} -m unittest pulsectl.tests.all
+  '';
+
+  meta = with lib; {
+    description = "Python high-level interface and ctypes-based bindings for PulseAudio (libpulse)";
+    homepage = "https://pypi.python.org/pypi/pulsectl/";
+    license = licenses.mit;
+    maintainers = with maintainers; [ hexa ];
+  };
+}
diff --git a/pkgs/development/python-modules/pulsectl/library-paths.patch b/pkgs/development/python-modules/pulsectl/library-paths.patch
new file mode 100644
index 000000000000..5840e515258d
--- /dev/null
+++ b/pkgs/development/python-modules/pulsectl/library-paths.patch
@@ -0,0 +1,22 @@
+diff --git a/pulsectl/_pulsectl.py b/pulsectl/_pulsectl.py
+index 4422ddf..3fb2f39 100644
+--- a/pulsectl/_pulsectl.py
++++ b/pulsectl/_pulsectl.py
+@@ -31,7 +31,7 @@ else:
+ 		if not hasattr(mono_time, 'ts'):
+ 			class timespec(Structure):
+ 				_fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]
+-			librt = CDLL('librt.so.1', use_errno=True)
++			librt = CDLL('@librt@', use_errno=True)
+ 			mono_time.get = librt.clock_gettime
+ 			mono_time.get.argtypes = [c_int, POINTER(timespec)]
+ 			mono_time.ts = timespec
+@@ -625,7 +625,7 @@ class LibPulse(object):
+ 
+ 
+ 	def __init__(self):
+-		p = CDLL(ctypes.util.find_library('libpulse') or 'libpulse.so.0')
++		p = CDLL('@libpulse@')
+ 
+ 		self.funcs = dict()
+ 		for k, spec in self.func_defs.items():
diff --git a/pkgs/development/python-modules/pylatexenc/default.nix b/pkgs/development/python-modules/pylatexenc/default.nix
index 146aed9a3ecf..d4f14f3be014 100644
--- a/pkgs/development/python-modules/pylatexenc/default.nix
+++ b/pkgs/development/python-modules/pylatexenc/default.nix
@@ -1,30 +1,28 @@
 { lib
 , buildPythonPackage
 , fetchFromGitHub
-, pytest
+, pytestCheckHook
 }:
 
 buildPythonPackage rec {
   pname = "pylatexenc";
-  version = "2.1";
+  version = "2.2";
 
   src = fetchFromGitHub {
     owner = "phfaist";
-    repo = pname;
+    repo = "pylatexenc";
     rev = "v${version}";
-    sha256 = "0wnl00y5dl56aw9j4y21kqapraaravbycwfxdmjsbgl11nk4llx9";
+    sha256 = "0icwd7iipz3sv4jdh9iam7h4xslvdqg16rwsmczrna3mmjbwccdk";
   };
 
   pythonImportsCheck = [ "pylatexenc" ];
-  checkInputs = [ pytest ];
-  checkPhase = ''
-    pytest
-  '';
+  dontUseSetuptoolsCheck = true;
+  checkInputs = [ pytestCheckHook ];
 
   meta = with lib; {
     description = "Simple LaTeX parser providing latex-to-unicode and unicode-to-latex conversion";
     homepage = "https://pylatexenc.readthedocs.io";
-    downloadPage = "https;//www.github.com/phfaist/pylatexenc";
+    downloadPage = "https://www.github.com/phfaist/pylatexenc/releases";
     license = licenses.mit;
     maintainers = with maintainers; [ drewrisinger ];
   };
diff --git a/pkgs/development/python-modules/pyroma/default.nix b/pkgs/development/python-modules/pyroma/default.nix
new file mode 100644
index 000000000000..4ec06506b38b
--- /dev/null
+++ b/pkgs/development/python-modules/pyroma/default.nix
@@ -0,0 +1,21 @@
+{ stdenv, buildPythonPackage, fetchPypi
+, docutils, pygments, setuptools
+}:
+
+buildPythonPackage rec {
+  pname = "pyroma";
+  version = "2.6";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "00j1j81kiipi5yppmk385cbfccf2ih0xyapl7pw6nqhrf8vh1764";
+  };
+
+  propagatedBuildInputs = [ docutils pygments setuptools ];
+
+  meta = with stdenv.lib; {
+    description = "Test your project's packaging friendliness";
+    homepage = "https://github.com/regebro/pyroma";
+    license = licenses.mit;
+  };
+}
diff --git a/pkgs/development/python-modules/pytest/4.nix b/pkgs/development/python-modules/pytest/4.nix
index be2ef93e6ee5..d77e52ab7f6d 100644
--- a/pkgs/development/python-modules/pytest/4.nix
+++ b/pkgs/development/python-modules/pytest/4.nix
@@ -6,11 +6,6 @@ buildPythonPackage rec {
   version = "4.6.8";
   pname = "pytest";
 
-  preCheck = ''
-    # don't test bash builtins
-    rm testing/test_argcomplete.py
-  '';
-
   src = fetchPypi {
     inherit pname version;
     sha256 = "6192875be8af57b694b7c4904e909680102befcb99e610ef3d9f786952f795aa";
@@ -25,7 +20,14 @@ buildPythonPackage rec {
   doCheck = !isPyPy; # https://github.com/pytest-dev/pytest/issues/3460
   checkPhase = ''
     runHook preCheck
-    $out/bin/py.test -x testing/ -k "not test_collect_pyargs_with_testpaths"
+
+    # don't test bash builtins
+    rm testing/test_argcomplete.py
+
+    # determinism - this test writes non deterministic bytecode
+    rm -rf testing/test_assertrewrite.py
+
+    PYTHONDONTWRITEBYTECODE=1 $out/bin/py.test -x testing/ -k "not test_collect_pyargs_with_testpaths"
     runHook postCheck
   '';
 
diff --git a/pkgs/development/python-modules/simpleaudio/default.nix b/pkgs/development/python-modules/simpleaudio/default.nix
new file mode 100644
index 000000000000..948716a9b7cb
--- /dev/null
+++ b/pkgs/development/python-modules/simpleaudio/default.nix
@@ -0,0 +1,24 @@
+{ alsaLib, buildPythonPackage, fetchFromGitHub, isPy27, lib }:
+
+buildPythonPackage rec {
+  pname = "simpleaudio";
+  version = "1.0.4";
+  disabled = isPy27;
+
+  src = fetchFromGitHub {
+    owner = "hamiltron";
+    repo = "py-simple-audio";
+    rev = version;
+    sha256 = "12nypzb1m14yip4zrbzin5jc5awyp1d5md5y40g5anj4phb4hx1i";
+  };
+
+  buildInputs = [ alsaLib ];
+
+  meta = with lib; {
+    homepage = "https://github.com/hamiltron/py-simple-audio";
+    description =
+      "A simple audio playback Python extension - cross-platform, asynchronous, dependency-free";
+    license = licenses.mit;
+    maintainers = with maintainers; [ lucus16 ];
+  };
+}
diff --git a/pkgs/development/tools/ameba/default.nix b/pkgs/development/tools/ameba/default.nix
index 2f3ebcbed0a6..a2d829f85c28 100644
--- a/pkgs/development/tools/ameba/default.nix
+++ b/pkgs/development/tools/ameba/default.nix
@@ -1,38 +1,16 @@
-{ stdenv, lib, fetchFromGitHub, crystal, shards }:
+{ stdenv, lib, fetchFromGitHub, crystal }:
 
-stdenv.mkDerivation rec {
+crystal.buildCrystalPackage rec {
   pname = "ameba";
-  version = "0.12.0";
+  version = "0.12.1";
 
   src = fetchFromGitHub {
-    owner  = "crystal-ameba";
-    repo   = "ameba";
-    rev    = "v${version}";
-    sha256 = "0g68yijbm2j4ig536fwq49d1z7x2iv9kp4g3gjklf5zn1sbqhm12";
+    owner = "crystal-ameba";
+    repo = "ameba";
+    rev = "v${version}";
+    sha256 = "0c2j2qki0czkpsqxv75qg95pk9f0w4rqa5ln07rs4bj9dk2lrr3l";
   };
 
-  nativeBuildInputs = [ crystal shards ];
-
-  buildPhase = ''
-    runHook preBuild
-    shards build --release
-    runHook postBuild
-  '';
-
-  installPhase = ''
-    runHook preInstall
-    install -Dm755 -t $out/bin bin/ameba
-    runHook postInstall
-  '';
-
-  doCheck = true;
-
-  checkPhase = ''
-    runHook preCheck
-    crystal spec
-    runHook postCheck
-  '';
-
   meta = with stdenv.lib; {
     description = "A static code analysis tool for Crystal";
     homepage = "https://crystal-ameba.github.io";
diff --git a/pkgs/development/tools/build-managers/shards/default.nix b/pkgs/development/tools/build-managers/shards/default.nix
index 4ad78778a916..53bc057fc131 100644
--- a/pkgs/development/tools/build-managers/shards/default.nix
+++ b/pkgs/development/tools/build-managers/shards/default.nix
@@ -1,22 +1,29 @@
-{ stdenv, fetchFromGitHub, crystal, pcre, libyaml, which }:
+{ stdenv, fetchFromGitHub, crystal }:
 
 crystal.buildCrystalPackage rec {
   pname = "shards";
   version = "0.10.0";
 
   src = fetchFromGitHub {
-    owner  = "crystal-lang";
-    repo   = "shards";
-    rev    = "v${version}";
+    owner = "crystal-lang";
+    repo = "shards";
+    rev = "v${version}";
     sha256 = "1bjy3hcdqq8769bx73f3pwn26rnkj23dngyfbw4iv32bw23x1d49";
   };
 
+  # we cannot use `make` here as it would introduce a dependency on itself
+  format = "crystal";
+
   shardsFile = ./shards.nix;
+
   crystalBinaries.shards.src = "./src/shards.cr";
 
+  # tries to execute git which fails spectacularly
+  doCheck = false;
+
   meta = with stdenv.lib; {
     description = "Dependency manager for the Crystal language";
-    license     = licenses.asl20;
+    license = licenses.asl20;
     maintainers = with maintainers; [ peterhoeg ];
     inherit (crystal.meta) homepage platforms;
   };
diff --git a/pkgs/development/tools/clj-kondo/default.nix b/pkgs/development/tools/clj-kondo/default.nix
index 769c30578c97..b809d550097e 100644
--- a/pkgs/development/tools/clj-kondo/default.nix
+++ b/pkgs/development/tools/clj-kondo/default.nix
@@ -2,7 +2,7 @@
 
 stdenv.mkDerivation rec{
   pname = "clj-kondo";
-  version = "2020.03.20";
+  version = "2020.04.05";
 
   reflectionJson = fetchurl {
     name = "reflection.json";
@@ -12,7 +12,7 @@ stdenv.mkDerivation rec{
 
   src = fetchurl {
     url = "https://github.com/borkdude/${pname}/releases/download/v${version}/${pname}-${version}-standalone.jar";
-    sha256 = "05z80cdzk8aw3j0nxfynzwpb9hhpbl54bbrv18dpqj5dj893mbgm";
+    sha256 = "0k9samcqkpkdgzbzr2bpixf75987lsabh97101v1fg12qvjhf187";
   };
 
   dontUnpack = true;
diff --git a/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix b/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
index 1d94408bd21b..b18bea0c907f 100644
--- a/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
+++ b/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
@@ -1,16 +1,16 @@
 { lib, buildGoPackage, fetchFromGitLab, fetchurl }:
 
 let
-  version = "12.9.0";
+  version = "12.10.0";
   # Gitlab runner embeds some docker images these are prebuilt for arm and x86_64
   docker_x86_64 = fetchurl {
     url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/helper-images/prebuilt-x86_64.tar.xz";
-    sha256 = "0kd4zc9rgzsl6imk9vi2yqpaxrgy8ywcz2vvpsfzrhhmm2yx3qh0";
+    sha256 = "1a2cfr72b15h3ymxf69a0inb4amfxivdhfaj711wgyvcf5ymnbsv";
   };
 
   docker_arm = fetchurl {
     url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/helper-images/prebuilt-arm.tar.xz";
-    sha256 = "13xwcvw6m3p5ffas5mr55jkqks9s3f7qg1b928vcxkx57j06kb22";
+    sha256 = "18if2xbkldpn0bwfyk6bgbdl9rdg4rjxc0im6lclwcgpbmslwx5r";
   };
 in
 buildGoPackage rec {
@@ -29,7 +29,7 @@ buildGoPackage rec {
     owner = "gitlab-org";
     repo = "gitlab-runner";
     rev = "v${version}";
-    sha256 = "0p9i4z0xsq5rl6gkqjpwpz6hb57vi6wl969gncrsfskjjc1kcifq";
+    sha256 = "0bsd3dk2fi21klqwzw8c181gv61qxbd32lj6mhkj9liz4flarhmv";
   };
 
   patches = [ ./fix-shell-path.patch ];
diff --git a/pkgs/development/tools/database/ephemeralpg/default.nix b/pkgs/development/tools/database/ephemeralpg/default.nix
index 87b23d10f496..53f3c1df628d 100644
--- a/pkgs/development/tools/database/ephemeralpg/default.nix
+++ b/pkgs/development/tools/database/ephemeralpg/default.nix
@@ -1,10 +1,10 @@
 { stdenv, fetchurl, postgresql, getopt, makeWrapper }:
 stdenv.mkDerivation rec {
   pname = "ephemeralpg";
-  version = "2.9";
+  version = "3.0";
   src = fetchurl {
     url = "http://ephemeralpg.org/code/${pname}-${version}.tar.gz";
-    sha256 = "1ghp3kya4lxvfwz3c022cx9vqf55jbf9sjw60bxjcb5sszklyc89";
+    sha256 = "1j0g7g114ma7y7sadbng5p1ss1zsm9zpicm77qspym6565733vvh";
   };
   buildInputs = [ makeWrapper ];
   installPhase = ''
diff --git a/pkgs/development/tools/icr/default.nix b/pkgs/development/tools/icr/default.nix
index 3a39d0ddf6bd..50a349d8ff71 100644
--- a/pkgs/development/tools/icr/default.nix
+++ b/pkgs/development/tools/icr/default.nix
@@ -1,28 +1,30 @@
-{ stdenv, fetchFromGitHub, crystal, shards, which
-, openssl, readline, libyaml }:
+{ stdenv, lib, fetchFromGitHub, crystal, shards, makeWrapper, pkgconfig, which
+, openssl, readline, libyaml, zlib }:
 
-stdenv.mkDerivation rec {
+crystal.buildCrystalPackage rec {
   pname = "icr";
-  version = "0.6.0";
+  version = "0.8.0";
 
   src = fetchFromGitHub {
-    owner  = "crystal-community";
-    repo   = pname;
-    rev    = "v${version}";
-    sha256 = "0kkdqrxk4f4bqbb84mgjrk9r0fz1hsz95apvjsc49gav4c8xx3mb";
+    owner = "crystal-community";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "1bz2bhs6csyg2rhrlknlvaiilq3vq8plxjh1hdxmbrfi3n6c7k5a";
   };
 
-  postPatch = ''
-    substituteInPlace Makefile \
-      --replace /usr/local $out
-  '';
+  shardsFile = ./shards.nix;
+
+  buildInputs = [ libyaml openssl readline zlib ];
 
-  buildInputs = [ crystal libyaml openssl readline ];
+  nativeBuildInputs = [ makeWrapper pkgconfig which ];
 
-  nativeBuildInputs = [ shards which ];
+  # tests are failing due to our sandbox
+  doCheck = false;
 
-  doCheck = true;
-  checkTarget = "test";
+  postFixup = ''
+    wrapProgram $out/bin/icr \
+      --prefix PATH : ${lib.makeBinPath [ crystal shards makeWrapper which ]}
+  '';
 
   meta = with stdenv.lib; {
     description = "Interactive console for the Crystal programming language";
diff --git a/pkgs/development/tools/icr/shards.nix b/pkgs/development/tools/icr/shards.nix
new file mode 100644
index 000000000000..1dddd5a42c39
--- /dev/null
+++ b/pkgs/development/tools/icr/shards.nix
@@ -0,0 +1,8 @@
+{
+  readline = {
+    owner = "crystal-lang";
+    repo = "crystal-readline";
+    rev = "0fb7d186da8e1b157998d98d1c96e99699b791eb";
+    sha256 = "1rk27vw3ssldgnfgprwvz2gag02v4g6d6yg56b3sk9w3fn8jyyi8";
+  };
+}
diff --git a/pkgs/development/tools/metals/default.nix b/pkgs/development/tools/metals/default.nix
index 638fae592a54..4cd87480070a 100644
--- a/pkgs/development/tools/metals/default.nix
+++ b/pkgs/development/tools/metals/default.nix
@@ -2,7 +2,7 @@
 
 let
   baseName = "metals";
-  version = "0.8.3";
+  version = "0.8.4";
   deps = stdenv.mkDerivation {
     name = "${baseName}-deps-${version}";
     buildCommand = ''
@@ -15,7 +15,7 @@ let
     '';
     outputHashMode = "recursive";
     outputHashAlgo = "sha256";
-    outputHash     = "1l196glr7rbsvrqmq6i7iw532jkz8d1w5m9nh0kh5z12visc7bkk";
+    outputHash     = "1r8aff082m3kh6wy5diyvq8bzg5x4dp1da9sfz223ii0kc1yp6w5";
   };
 in
 stdenv.mkDerivation rec {
diff --git a/pkgs/development/tools/ocaml/merlin/default.nix b/pkgs/development/tools/ocaml/merlin/default.nix
index ed3d5efc789d..fa78e47951f3 100644
--- a/pkgs/development/tools/ocaml/merlin/default.nix
+++ b/pkgs/development/tools/ocaml/merlin/default.nix
@@ -2,13 +2,13 @@
 
 buildDunePackage rec {
   pname = "merlin";
-  version = "3.3.3";
+  version = "3.3.4";
 
   minimumOCamlVersion = "4.02.1";
 
   src = fetchurl {
     url = "https://github.com/ocaml/merlin/releases/download/v${version}/merlin-v${version}.tbz";
-    sha256 = "05dfkbpbb7nvs4g6y0iw7a9f73ygvhs9l45l2g56y7zagvs9x43j";
+    sha256 = "12wxric6n3rmsn0w16xm8vjd8p5aw24cj76zw2x87qfwwgmy1kdd";
   };
 
   buildInputs = [ yojson ];
diff --git a/pkgs/development/tools/scry/default.nix b/pkgs/development/tools/scry/default.nix
index 7bd3fa38332d..ed823896ad0f 100644
--- a/pkgs/development/tools/scry/default.nix
+++ b/pkgs/development/tools/scry/default.nix
@@ -1,6 +1,8 @@
-{ lib, fetchFromGitHub, crystal }:
+{ lib, fetchFromGitHub, crystal_0_31, coreutils, shards, makeWrapper, which }:
 
-crystal.buildCrystalPackage rec {
+let crystal = crystal_0_31;
+
+in crystal.buildCrystalPackage rec {
   pname = "scry";
   version = "0.8.1";
 
@@ -11,9 +13,27 @@ crystal.buildCrystalPackage rec {
     sha256 = "0ii4k9l3dgm1c9lllc8ni9dar59lrxik0v9iz7gk3d6v62wwnq79";
   };
 
+  # we are already testing for this, so we can ignore the failures
+  postPatch = ''
+    rm spec/scry/executable_spec.cr
+  '';
+
+  format = "crystal";
+
+  nativeBuildInputs = [ makeWrapper ];
+
   shardsFile = ./shards.nix;
+
   crystalBinaries.scry.src = "src/scry.cr";
 
+  postFixup = ''
+    wrapProgram $out/bin/scry \
+      --prefix PATH : ${lib.makeBinPath [ crystal coreutils ]}
+  '';
+
+  # the binary doesn't take any arguments, so this will hang
+  doInstallCheck = false;
+
   meta = with lib; {
     description = "Code analysis server for the Crystal programming language";
     homepage = "https://github.com/crystal-lang-tools/scry";
diff --git a/pkgs/development/web/lucky-cli/default.nix b/pkgs/development/web/lucky-cli/default.nix
new file mode 100644
index 000000000000..76f40de4ed13
--- /dev/null
+++ b/pkgs/development/web/lucky-cli/default.nix
@@ -0,0 +1,42 @@
+{ lib, fetchFromGitHub, crystal, makeWrapper, openssl }:
+
+crystal.buildCrystalPackage rec {
+  pname = "lucky-cli";
+  version = "0.20.0";
+
+  src = fetchFromGitHub {
+    owner = "luckyframework";
+    repo = "lucky_cli";
+    rev = "v${version}";
+    sha256 = "0n7fgnsivf39bkxpf7xgg9dqkam08axdn1j45wl1n0r4qmfkjs94";
+  };
+
+  # the integration tests will try to clone a remote repos
+  postPatch = ''
+    rm -rf spec/integration
+  '';
+
+  format = "crystal";
+
+  lockFile = ./shard.lock;
+  shardsFile = ./shards.nix;
+
+  crystalBinaries.lucky.src = "src/lucky.cr";
+
+  buildInputs = [ openssl ];
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  postInstall = ''
+    wrapProgram $out/bin/lucky \
+      --prefix PATH : ${lib.makeBinPath [ crystal ]}
+  '';
+
+  meta = with lib; {
+    description =
+      "A Crystal library for creating and running tasks. Also generates Lucky projects";
+    license = licenses.mit;
+    maintainers = with maintainers; [ peterhoeg ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/development/web/lucky-cli/shard.lock b/pkgs/development/web/lucky-cli/shard.lock
new file mode 100644
index 000000000000..6564e86624f7
--- /dev/null
+++ b/pkgs/development/web/lucky-cli/shard.lock
@@ -0,0 +1,5 @@
+version: 1.0
+shards:
+  teeplate:
+    github: luckyframework/teeplate
+    version: 0.8.1
diff --git a/pkgs/development/web/lucky-cli/shards.nix b/pkgs/development/web/lucky-cli/shards.nix
new file mode 100644
index 000000000000..0fa5aec9e06d
--- /dev/null
+++ b/pkgs/development/web/lucky-cli/shards.nix
@@ -0,0 +1,8 @@
+{
+  teeplate = {
+    owner = "luckyframework";
+    repo = "teeplate";
+    rev = "v0.8.1";
+    sha256 = "022jmmg3d2wq2xnhc63afldm9vrcr8xqn43s9i39d7qflrzrfc7v";
+  };
+}
diff --git a/pkgs/development/web/shopify-themekit/default.nix b/pkgs/development/web/shopify-themekit/default.nix
new file mode 100644
index 000000000000..b8bc3deaca18
--- /dev/null
+++ b/pkgs/development/web/shopify-themekit/default.nix
@@ -0,0 +1,25 @@
+{ stdenv, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  pname = "shopify-themekit";
+  version = "1.0.3";
+
+  goPackagePath = "github.com/Shopify/themekit/";
+
+  goDeps = ./shopify-themekit_deps.nix;
+
+  src = fetchFromGitHub {
+    owner = "Shopify";
+    repo = "themekit";
+    rev = "v${version}";
+    sha256 = "1780h33mf2h2lv6mr4xx3shfvsabr7w138yb59vvdgvjng9wjkg0";
+  };
+
+  meta = with stdenv.lib; {
+    description = "A command line tool for shopify themes";
+    homepage = "https://shopify.github.io/themekit/";
+    license = licenses.mit;
+    maintainers = with maintainers; [ maintainers."1000101" ];
+    platforms = platforms.all;
+  };
+}
\ No newline at end of file
diff --git a/pkgs/development/web/shopify-themekit/shopify-themekit_deps.nix b/pkgs/development/web/shopify-themekit/shopify-themekit_deps.nix
new file mode 100644
index 000000000000..8a70c7cecd92
--- /dev/null
+++ b/pkgs/development/web/shopify-themekit/shopify-themekit_deps.nix
@@ -0,0 +1,300 @@
+# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
+[
+  {
+    goPackagePath = "github.com/VividCortex/ewma";
+    fetch = {
+      type = "git";
+      url = "https://github.com/VividCortex/ewma";
+      rev = "v1.1.1";
+      sha256 = "14v2dy5gqchjn7k0sd6cx59ms42v681r6xz7cb1kspp4b28a74rw";
+    };
+  }
+  {
+    goPackagePath = "github.com/aws/aws-sdk-go";
+    fetch = {
+      type = "git";
+      url = "https://github.com/aws/aws-sdk-go";
+      rev = "1c16cd01d785";
+      sha256 = "129iizv2rny2frg36057hayynpsdav53nhj41dia3mi2r6zyalny";
+    };
+  }
+  {
+    goPackagePath = "github.com/caarlos0/env";
+    fetch = {
+      type = "git";
+      url = "https://github.com/caarlos0/env";
+      rev = "d0de832ed2fb";
+      sha256 = "013shh38rs2jv4a2hsbix0hlanjr2a539akmkqkwwg0il9h3qmq2";
+    };
+  }
+  {
+    goPackagePath = "github.com/davecgh/go-spew";
+    fetch = {
+      type = "git";
+      url = "https://github.com/davecgh/go-spew";
+      rev = "v1.1.1";
+      sha256 = "0hka6hmyvp701adzag2g26cxdj47g21x6jz4sc6jjz1mn59d474y";
+    };
+  }
+  {
+    goPackagePath = "github.com/fatih/color";
+    fetch = {
+      type = "git";
+      url = "https://github.com/fatih/color";
+      rev = "v1.7.0";
+      sha256 = "0v8msvg38r8d1iiq2i5r4xyfx0invhc941kjrsg5gzwvagv55inv";
+    };
+  }
+  {
+    goPackagePath = "github.com/fsnotify/fsnotify";
+    fetch = {
+      type = "git";
+      url = "https://github.com/fsnotify/fsnotify";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "github.com/go-ini/ini";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go-ini/ini";
+      rev = "v1.25.4";
+      sha256 = "0b6cql5ripbiyrm18d6bfd1rfjnwcbskppw3d0vb80l0wy72d0c6";
+    };
+  }
+  {
+    goPackagePath = "github.com/hashicorp/go-version";
+    fetch = {
+      type = "git";
+      url = "https://github.com/hashicorp/go-version";
+      rev = "270f2f71b1ee";
+      sha256 = "1d43wlp932nqbwkca4bhw8l4x6cg25jyh8l1s3814vddscfpfz2v";
+    };
+  }
+  {
+    goPackagePath = "github.com/imdario/mergo";
+    fetch = {
+      type = "git";
+      url = "https://github.com/imdario/mergo";
+      rev = "v0.3.6";
+      sha256 = "1lbzy8p8wv439sqgf0n21q52flf2wbamp6qa1jkyv6an0nc952q7";
+    };
+  }
+  {
+    goPackagePath = "github.com/inconshreveable/go-update";
+    fetch = {
+      type = "git";
+      url = "https://github.com/inconshreveable/go-update";
+      rev = "8152e7eb6ccf";
+      sha256 = "07czhspakpi7al004rm669cmf4h5l0vnygsm11280nkfn2zxqdi3";
+    };
+  }
+  {
+    goPackagePath = "github.com/inconshreveable/mousetrap";
+    fetch = {
+      type = "git";
+      url = "https://github.com/inconshreveable/mousetrap";
+      rev = "v1.0.0";
+      sha256 = "1mn0kg48xkd74brf48qf5hzp0bc6g8cf5a77w895rl3qnlpfw152";
+    };
+  }
+  {
+    goPackagePath = "github.com/jmespath/go-jmespath";
+    fetch = {
+      type = "git";
+      url = "https://github.com/jmespath/go-jmespath";
+      rev = "0b12d6b521d8";
+      sha256 = "1vv6hph8j6xgv7gwl9vvhlsaaqsm22sxxqmgmldi4v11783pc1ld";
+    };
+  }
+  {
+    goPackagePath = "github.com/joho/godotenv";
+    fetch = {
+      type = "git";
+      url = "https://github.com/joho/godotenv";
+      rev = "v1.3.0";
+      sha256 = "0ri8if0pc3x6jg4c3i8wr58xyfpxkwmcjk3rp8gb398a1aa3gpjm";
+    };
+  }
+  {
+    goPackagePath = "github.com/mattn/go-colorable";
+    fetch = {
+      type = "git";
+      url = "https://github.com/mattn/go-colorable";
+      rev = "efa589957cd0";
+      sha256 = "0kshi4hvm0ayrsxqxy0599iv81kryhd2fn9lwjyczpj593cq069r";
+    };
+  }
+  {
+    goPackagePath = "github.com/mattn/go-isatty";
+    fetch = {
+      type = "git";
+      url = "https://github.com/mattn/go-isatty";
+      rev = "v0.0.4";
+      sha256 = "0zs92j2cqaw9j8qx1sdxpv3ap0rgbs0vrvi72m40mg8aa36gd39w";
+    };
+  }
+  {
+    goPackagePath = "github.com/pmezard/go-difflib";
+    fetch = {
+      type = "git";
+      url = "https://github.com/pmezard/go-difflib";
+      rev = "v1.0.0";
+      sha256 = "0c1cn55m4rypmscgf0rrb88pn58j3ysvc2d0432dp3c6fqg6cnzw";
+    };
+  }
+  {
+    goPackagePath = "github.com/radovskyb/watcher";
+    fetch = {
+      type = "git";
+      url = "https://github.com/radovskyb/watcher";
+      rev = "v1.0.6";
+      sha256 = "1xlbrfgm6ha161szdjq2rab53plkdhmh5h86lpbk5g7fmq881945";
+    };
+  }
+  {
+    goPackagePath = "github.com/ryanuber/go-glob";
+    fetch = {
+      type = "git";
+      url = "https://github.com/ryanuber/go-glob";
+      rev = "572520ed46db";
+      sha256 = "0dzbpqp1h7gjmlm4irnh6lpbfz5zjc721jidibyvmxj7xcx3wp5d";
+    };
+  }
+  {
+    goPackagePath = "github.com/shibukawa/configdir";
+    fetch = {
+      type = "git";
+      url = "https://github.com/shibukawa/configdir";
+      rev = "e180dbdc8da0";
+      sha256 = "0vbma9jkwh0ifz8dk2ssgmy7aiaify63lpa0lah7i4dkkxr94c9z";
+    };
+  }
+  {
+    goPackagePath = "github.com/skratchdot/open-golang";
+    fetch = {
+      type = "git";
+      url = "https://github.com/skratchdot/open-golang";
+      rev = "75fb7ed4208c";
+      sha256 = "1b67imqbsdvg19vif1q1dfmapxy3v2anagacbql95fwnnw0v8jga";
+    };
+  }
+  {
+    goPackagePath = "github.com/spf13/cobra";
+    fetch = {
+      type = "git";
+      url = "https://github.com/spf13/cobra";
+      rev = "7c4570c3ebeb";
+      sha256 = "16amh0prlzqrrbg5j629sg0f688nfzfgn9sair8jyybqampr3wc7";
+    };
+  }
+  {
+    goPackagePath = "github.com/spf13/pflag";
+    fetch = {
+      type = "git";
+      url = "https://github.com/spf13/pflag";
+      rev = "v1.0.2";
+      sha256 = "005598piihl3l83a71ahj10cpq9pbhjck4xishx1b4dzc02r9xr2";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/objx";
+    fetch = {
+      type = "git";
+      url = "https://github.com/stretchr/objx";
+      rev = "v0.1.1";
+      sha256 = "0iph0qmpyqg4kwv8jsx6a56a7hhqq8swrazv40ycxk9rzr0s8yls";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/testify";
+    fetch = {
+      type = "git";
+      url = "https://github.com/stretchr/testify";
+      rev = "v1.2.2";
+      sha256 = "0dlszlshlxbmmfxj5hlwgv3r22x0y1af45gn1vd198nvvs3pnvfs";
+    };
+  }
+  {
+    goPackagePath = "github.com/vbauerster/mpb";
+    fetch = {
+      type = "git";
+      url = "https://github.com/vbauerster/mpb";
+      rev = "v3.3.2";
+      sha256 = "18m66b80iv9z768c15dqsx5mnjq6iaa6b5lckpdqnynqzkkvw8kk";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/crypto";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/crypto";
+      rev = "a1f597ede03a";
+      sha256 = "0yiczljll72ip2vkxgd6052rhpaba37a68vf6si3v8s8s3g870lc";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/lint";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/lint";
+      rev = "d0100b6bd8b3";
+      sha256 = "0b0amr9x4ji66iv9ayfx7zrfx52k1m5g66qfcxkgj80qrb1y2yn7";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/net";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/net";
+      rev = "1272bf9dcd53";
+      sha256 = "1500gryd7jli7yjn4c927ppyllry8lxcmnsmpn7zxfd1k14q7nyv";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/sync";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sync";
+      rev = "1d60e4601c6f";
+      sha256 = "046jlanz2lkxq1r57x9bl6s4cvfqaic6p2xybsj8mq1120jv4rs6";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/sys";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sys";
+      rev = "6c81ef8f67ca";
+      sha256 = "1iqrral339vxb635ip5jjzn84aa86kb629kbp1w29qwyfzbs0yqi";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/text";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/text";
+      rev = "v0.3.0";
+      sha256 = "0r6x6zjzhr8ksqlpiwm5gdd7s209kwk5p4lw54xjvz10cs3qlq19";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/tools";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/tools";
+      rev = "3f1ed9edd1b4";
+      sha256 = "00d2h0df03gv57valad4wr3g2rc8dcn8w3ci783x9wzzc86y4giw";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/yaml.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/yaml.v1";
+      rev = "9f9df34309c0";
+      sha256 = "1r8d346szqa9x8q03wiycik5qy3d6w8qq4hs99z1p64q5lm0g7gm";
+    };
+  }
+]
diff --git a/pkgs/games/openrct2/default.nix b/pkgs/games/openrct2/default.nix
index 48114cb766c4..b519e0c7e925 100644
--- a/pkgs/games/openrct2/default.nix
+++ b/pkgs/games/openrct2/default.nix
@@ -4,21 +4,20 @@
 }:
 
 let
-  name = "openrct2-${version}";
-  version = "0.2.4";
+  version = "0.2.6";
 
   openrct2-src = fetchFromGitHub {
     owner = "OpenRCT2";
     repo = "OpenRCT2";
     rev = "v${version}";
-    sha256 = "1rlw3w20llg36sj3bk50g661qw766ng8ma3p42sdkj8br9dw800h";
+    sha256 = "1vikbkg3wh5ngzdfilb6irbh6nqinf138qpdz8wz9izlvl8s36k4";
   };
 
   objects-src = fetchFromGitHub {
     owner = "OpenRCT2";
     repo = "objects";
-    rev = "v1.0.12";
-    sha256 = "0vfhyldc8nfvkg4d9kry669haxz2165walbxzgza7pqpnd7aqgrf";
+    rev = "v1.0.14";
+    sha256 = "1bqbia5y73v4r0sv5cvi5729jh2ns7cxn557blh715yxswk91590";
   };
 
   title-sequences-src = fetchFromGitHub {
@@ -29,7 +28,8 @@ let
   };
 in
 stdenv.mkDerivation {
-  inherit name;
+  inherit version;
+  pname = "openrct2";
 
   src = openrct2-src;
 
@@ -61,12 +61,11 @@ stdenv.mkDerivation {
   '';
 
   cmakeFlags = [
-    "-DCMAKE_BUILD_TYPE=RELWITHDEBINFO"
     "-DDOWNLOAD_OBJECTS=OFF"
     "-DDOWNLOAD_TITLE_SEQUENCES=OFF"
   ];
 
-  makeFlags = ["all" "g2"];
+  enableParallelBuilding = true;
 
   preFixup = "ln -s $out/share/openrct2 $out/bin/data";
 
diff --git a/pkgs/misc/cbeams/default.nix b/pkgs/misc/cbeams/default.nix
new file mode 100644
index 000000000000..ec045ebf3efd
--- /dev/null
+++ b/pkgs/misc/cbeams/default.nix
@@ -0,0 +1,21 @@
+{ lib, buildPythonApplication, fetchPypi, isPy3k, blessings, docopt }:
+
+buildPythonApplication rec {
+  pname = "cbeams";
+  version = "1.0.3";
+  disabled = !isPy3k;
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "1agcjg6kmcyvk834xd2j60mi349qi9iw3dc2vwpd7pqwq1daq3gi";
+  };
+
+  propagatedBuildInputs = [ blessings docopt ];
+
+  meta = with lib; {
+    homepage = "https://github.com/tartley/cbeams";
+    description = "Command-line program to draw animated colored circles in the terminal";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ geistesk ];
+  };
+}
diff --git a/pkgs/misc/emulators/pcsx2/default.nix b/pkgs/misc/emulators/pcsx2/default.nix
index 6f28c5777ca1..3faba2ee467c 100644
--- a/pkgs/misc/emulators/pcsx2/default.nix
+++ b/pkgs/misc/emulators/pcsx2/default.nix
@@ -5,13 +5,13 @@
 
 stdenv.mkDerivation rec {
   pname = "pcsx2";
-  version = "unstable-2020-01-05";
+  version = "1.6.0-rc";
 
   src = fetchFromGitHub {
     owner = "PCSX2";
     repo = "pcsx2";
-    rev = "9c12937351c51b921e1f28d44b019bc52e747c51";
-    sha256 = "0y1f5v99a6njmf6hyvl4z5xnrm7351rkyw2fn4f09hqn92r7zmi5";
+    rev = "v${version}";
+    sha256 = "1mdv1dgwawb4k6bs1jh6j2jaaxg168fbssm1lwnlk5di0gz31h23";
   };
 
   postPatch = "sed '1i#include \"x86intrin.h\"' -i common/src/x86emitter/cpudetect.cpp";
diff --git a/pkgs/misc/uboot/default.nix b/pkgs/misc/uboot/default.nix
index 06da268ff533..321891892b7b 100644
--- a/pkgs/misc/uboot/default.nix
+++ b/pkgs/misc/uboot/default.nix
@@ -1,15 +1,27 @@
-{ stdenv, lib, fetchurl, fetchpatch, fetchFromGitHub, bc, bison, dtc, flex
-, openssl, swig, meson-tools, armTrustedFirmwareAllwinner
-, armTrustedFirmwareRK3328, armTrustedFirmwareRK3399
+{ stdenv
+, lib
+, fetchurl
+, fetchpatch
+, fetchFromGitHub
+, bc
+, bison
+, dtc
+, flex
+, openssl
+, swig
+, meson-tools
+, armTrustedFirmwareAllwinner
+, armTrustedFirmwareRK3328
+, armTrustedFirmwareRK3399
 , armTrustedFirmwareS905
 , buildPackages
 }:
 
 let
-  defaultVersion = "2020.01";
+  defaultVersion = "2020.04";
   defaultSrc = fetchurl {
     url = "ftp://ftp.denx.de/pub/u-boot/u-boot-${defaultVersion}.tar.bz2";
-    sha256 = "1w9ml4jl15q6ixpdqzspxjnl7d3rgxd7f99ms1xv5c8869h3qida";
+    sha256 = "0wjkasnz87q86hx93inspdjfjsinmxi87bcvj30c773x0fpjlwzy";
   };
   buildUBoot = {
     version ? null
diff --git a/pkgs/os-specific/linux/kernel/hardened-patches.json b/pkgs/os-specific/linux/kernel/hardened-patches.json
index 97fbbb405e3e..6eb83ee8bb1e 100644
--- a/pkgs/os-specific/linux/kernel/hardened-patches.json
+++ b/pkgs/os-specific/linux/kernel/hardened-patches.json
@@ -4,24 +4,24 @@
         "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.14.176.a/linux-hardened-4.14.176.a.patch",
         "version_suffix": "a"
     },
-    "4.19.116": {
-        "sha256": "00y4i905gzs9w9kckrn1frh2vw32fsndz03g2psl1gk17snc3q7c",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.116.a/linux-hardened-4.19.116.a.patch",
+    "4.19.117": {
+        "sha256": "0c8dvh49nzypxwvsls10i896smvpdrk40x8ybljb3qk3r8j7niaw",
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/4.19.117.a/linux-hardened-4.19.117.a.patch",
         "version_suffix": "a"
     },
-    "5.4.33": {
-        "sha256": "1hjfvhyvz5kyvx25809brhsvfv9mjv9q1mw6ydb71gfwhw6q8d8b",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.33.a/linux-hardened-5.4.33.a.patch",
+    "5.4.34": {
+        "sha256": "1xwpqr9nzpjg837b3wnzb8fmrl2g9rz8gz5yb55vnnllbzbz36v6",
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.4.34.a/linux-hardened-5.4.34.a.patch",
         "version_suffix": "a"
     },
-    "5.5.18": {
-        "sha256": "0v7vla784sf1fk6d8qa5x8hkyhjb1jkw4lxxcgvvlqbmxl8md8ld",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.18.a/linux-hardened-5.5.18.a.patch",
+    "5.5.19": {
+        "sha256": "1ya5nsfhr3nwz6qiz4pdhvm6k9mx1kr0prhdvhx3p40f1vk281sc",
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.5.19.a/linux-hardened-5.5.19.a.patch",
         "version_suffix": "a"
     },
-    "5.6.5": {
-        "sha256": "19cdpygm5zx3szxl456lfjg5sffqcmn18470wv7prm8rf6liqdj3",
-        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.5.a/linux-hardened-5.6.5.a.patch",
+    "5.6.6": {
+        "sha256": "0jiqh0frxirjbccgfdk007fca6r6n36n0pkqq4jszkckn59ayl7r",
+        "url": "https://github.com/anthraxx/linux-hardened/releases/download/5.6.6.a/linux-hardened-5.6.6.a.patch",
         "version_suffix": "a"
     }
 }
diff --git a/pkgs/os-specific/linux/kernel/linux-4.19.nix b/pkgs/os-specific/linux/kernel/linux-4.19.nix
index cdb19fd54ab7..6ff9919e1926 100644
--- a/pkgs/os-specific/linux/kernel/linux-4.19.nix
+++ b/pkgs/os-specific/linux/kernel/linux-4.19.nix
@@ -3,7 +3,7 @@
 with stdenv.lib;
 
 buildLinux (args // rec {
-  version = "4.19.116";
+  version = "4.19.117";
 
   # modDirVersion needs to be x.y.z, will automatically add .0 if needed
   modDirVersion = if (modDirVersionArg == null) then concatStringsSep "." (take 3 (splitVersion "${version}.0")) else modDirVersionArg;
@@ -13,6 +13,6 @@ buildLinux (args // rec {
 
   src = fetchurl {
     url = "mirror://kernel/linux/kernel/v4.x/linux-${version}.tar.xz";
-    sha256 = "0r3vdc3npl1bn06w9v6wsq7d5mm7bnhm9wsz36pb9ar3xhimvrlf";
+    sha256 = "12xc1pwhwq4vp67hmn7hdynl4ik76cni79356hpzf1lbiqlrya6n";
   };
 } // (args.argsOverride or {}))
diff --git a/pkgs/os-specific/linux/kernel/linux-5.4.nix b/pkgs/os-specific/linux/kernel/linux-5.4.nix
index b2de6ea86899..69519a156fe3 100644
--- a/pkgs/os-specific/linux/kernel/linux-5.4.nix
+++ b/pkgs/os-specific/linux/kernel/linux-5.4.nix
@@ -3,7 +3,7 @@
 with stdenv.lib;
 
 buildLinux (args // rec {
-  version = "5.4.33";
+  version = "5.4.34";
 
   # modDirVersion needs to be x.y.z, will automatically add .0 if needed
   modDirVersion = if (modDirVersionArg == null) then concatStringsSep "." (take 3 (splitVersion "${version}.0")) else modDirVersionArg;
@@ -13,6 +13,6 @@ buildLinux (args // rec {
 
   src = fetchurl {
     url = "mirror://kernel/linux/kernel/v5.x/linux-${version}.tar.xz";
-    sha256 = "0q9q48ij6vppfcrdf7fr24pvpwsd13pxjkdni6rnjq9a60hrcmxm";
+    sha256 = "1ljcsrw9jknw2d9hb0yfr1pwy85l8z4rqycgd0kad9mb9lrw2glh";
   };
 } // (args.argsOverride or {}))
diff --git a/pkgs/os-specific/linux/kernel/linux-5.5.nix b/pkgs/os-specific/linux/kernel/linux-5.5.nix
index ecb92b5bfe7d..96a349d985c9 100644
--- a/pkgs/os-specific/linux/kernel/linux-5.5.nix
+++ b/pkgs/os-specific/linux/kernel/linux-5.5.nix
@@ -3,7 +3,7 @@
 with stdenv.lib;
 
 buildLinux (args // rec {
-  version = "5.5.18";
+  version = "5.5.19";
 
   # modDirVersion needs to be x.y.z, will automatically add .0 if needed
   modDirVersion = if (modDirVersionArg == null) then concatStringsSep "." (take 3 (splitVersion "${version}.0")) else modDirVersionArg;
@@ -13,6 +13,6 @@ buildLinux (args // rec {
 
   src = fetchurl {
     url = "mirror://kernel/linux/kernel/v5.x/linux-${version}.tar.xz";
-    sha256 = "01iiiq4dsyyc5y6b52wax9as6dzhdi172vd1423sc1yp4rrk8178";
+    sha256 = "1sqiw9d25sqqzdh04dd722i7ff6kchj869jp4l8zalpvf51k6j0l";
   };
 } // (args.argsOverride or {}))
diff --git a/pkgs/os-specific/linux/kernel/linux-5.6.nix b/pkgs/os-specific/linux/kernel/linux-5.6.nix
index d3334293dc19..4ed77c983011 100644
--- a/pkgs/os-specific/linux/kernel/linux-5.6.nix
+++ b/pkgs/os-specific/linux/kernel/linux-5.6.nix
@@ -3,7 +3,7 @@
 with stdenv.lib;
 
 buildLinux (args // rec {
-  version = "5.6.5";
+  version = "5.6.6";
 
   # modDirVersion needs to be x.y.z, will automatically add .0 if needed
   modDirVersion = if (modDirVersionArg == null) then concatStringsSep "." (take 3 (splitVersion "${version}.0")) else modDirVersionArg;
@@ -13,6 +13,6 @@ buildLinux (args // rec {
 
   src = fetchurl {
     url = "mirror://kernel/linux/kernel/v5.x/linux-${version}.tar.xz";
-    sha256 = "1rjjkcmzsj9azggh960qnk2x44ns475b8nbd4nxazrz1rgdx76zp";
+    sha256 = "1m3blvkma08v5y11jh0vhf4sr7jbcylkh15bssb5dgp40p8cx134";
   };
 } // (args.argsOverride or {}))
diff --git a/pkgs/servers/mautrix-whatsapp/default.nix b/pkgs/servers/mautrix-whatsapp/default.nix
index 924209174e7d..5e011f17b70f 100644
--- a/pkgs/servers/mautrix-whatsapp/default.nix
+++ b/pkgs/servers/mautrix-whatsapp/default.nix
@@ -2,16 +2,16 @@
 
 buildGoModule {
   pname = "mautrix-whatsapp-unstable";
-  version = "2020-04-12";
+  version = "2020-04-21";
 
   src = fetchFromGitHub {
     owner = "tulir";
     repo = "mautrix-whatsapp";
-    rev = "44bb623e7a7486a0cdd13fd67b2aaca2ddba20ce";
-    sha256 = "1fwxn6511pq9fdc8d2jp4vgkm1zag55pig75qdxfn63hl3i2607k";
+    rev = "53fe1b18184fc0967658805abc8560641f8d2cb0";
+    sha256 = "0rahj9v7cgvk4w3m41jbs8vnya37dhq5wxyhyg74kwrv8a2nqxra";
   };
 
-  modSha256 = "04pdap1q7zsa1wv2h0j9104fawn95g37yqslmp2mq7722hiqhp9x";
+  modSha256 = "0jn88a4hagwfkw9bv8cg12ywsg35znmfkmhi1v7k2qpj5qzi81w6";
 
   meta = with stdenv.lib; {
     homepage = "https://github.com/tulir/mautrix-whatsapp";
diff --git a/pkgs/servers/mpd/default.nix b/pkgs/servers/mpd/default.nix
index 4f97e3fc7838..d5a3b9de3c0a 100644
--- a/pkgs/servers/mpd/default.nix
+++ b/pkgs/servers/mpd/default.nix
@@ -18,6 +18,7 @@
 , mpd_clientlib
 # Tag support
 , libid3tag
+, nixosTests
 }:
 
 let
@@ -128,6 +129,8 @@ let
         ++ lib.optional (builtins.elem "systemd" features_)
           "-Dsystemd_system_unit_dir=etc/systemd/system";
 
+      passthru.tests.nixos = nixosTests.mpd;
+
       meta = with stdenv.lib; {
         description = "A flexible, powerful daemon for playing music";
         homepage    = "https://www.musicpd.org/";
diff --git a/pkgs/servers/nosql/mongodb/mongodb.nix b/pkgs/servers/nosql/mongodb/mongodb.nix
index e3d277ba5afb..8ffdbcd63c4c 100644
--- a/pkgs/servers/nosql/mongodb/mongodb.nix
+++ b/pkgs/servers/nosql/mongodb/mongodb.nix
@@ -6,7 +6,9 @@
 
 with stdenv.lib;
 
-{ version, sha256, patches ? [] }@args:
+{ version, sha256, patches ? []
+, license ? stdenv.lib.licenses.sspl
+}@args:
 
 let
   python = python27.withPackages (ps: with ps; [ pyyaml typing cheetah ]);
@@ -109,7 +111,7 @@ in stdenv.mkDerivation rec {
   meta = {
     description = "A scalable, high-performance, open source NoSQL database";
     homepage = "http://www.mongodb.org";
-    license = licenses.sspl;
+    inherit license;
 
     maintainers = with maintainers; [ bluescreen303 offline cstrahan ];
     platforms = subtractLists systems.doubles.i686 systems.doubles.unix;
diff --git a/pkgs/servers/nosql/mongodb/v3_4.nix b/pkgs/servers/nosql/mongodb/v3_4.nix
index 2f02ae7f72ad..e1c71bc13f7a 100644
--- a/pkgs/servers/nosql/mongodb/v3_4.nix
+++ b/pkgs/servers/nosql/mongodb/v3_4.nix
@@ -12,4 +12,5 @@ in buildMongoDB {
   version = "3.4.24";
   sha256 = "0j6mvgv0jnsnvgkl8505bl88kbxkba66qijlpi1la0dd5pd1imfr";
   patches = [ ./forget-build-dependencies-3-4.patch ];
+  license = stdenv.lib.licenses.agpl3;
 }
diff --git a/pkgs/servers/oauth2_proxy/default.nix b/pkgs/servers/oauth2_proxy/default.nix
index d0a571988202..225c221b319e 100644
--- a/pkgs/servers/oauth2_proxy/default.nix
+++ b/pkgs/servers/oauth2_proxy/default.nix
@@ -2,23 +2,28 @@
 
 buildGoPackage rec {
   pname = "oauth2_proxy";
-  version = "3.2.0";
-  
+  version = "5.1.0";
+
   goPackagePath = "github.com/pusher/${pname}";
 
   src = fetchFromGitHub {
     repo = pname;
     owner = "pusher";
-    sha256 = "0k73ggyh12g2vzjq91i9d3bxbqfvh5k6njzza1lvkzasgp07wisg";
+    sha256 = "190k1v2c1f6vp9waqs01rlzm0jc3vrmsq1w1n0c2q2nfqx76y2wz";
     rev = "v${version}";
   };
 
   goDeps = ./deps.nix;
 
+  doCheck = true;
+
+  # Taken from https://github.com/oauth2-proxy/oauth2-proxy/blob/master/Makefile
+  buildFlagsArray = ("-ldflags=-X main.VERSION=${version}");
+
   meta = with lib; {
-    description = "A reverse proxy that provides authentication with Google, Github or other provider";
+    description = "A reverse proxy that provides authentication with Google, Github, or other providers";
     homepage = "https://github.com/pusher/oauth2_proxy/";
     license = licenses.mit;
-    maintainers = [ maintainers.yorickvp ];
+    maintainers = with maintainers; [ yorickvp knl ];
   };
 }
diff --git a/pkgs/servers/oauth2_proxy/deps.nix b/pkgs/servers/oauth2_proxy/deps.nix
index dd10ab286689..611a07c2fda0 100644
--- a/pkgs/servers/oauth2_proxy/deps.nix
+++ b/pkgs/servers/oauth2_proxy/deps.nix
@@ -1,183 +1,615 @@
-# file generated from Gopkg.lock using dep2nix (https://github.com/nixcloud/dep2nix)
+# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
 [
   {
-    goPackagePath  = "cloud.google.com/go";
+    goPackagePath = "cloud.google.com/go";
     fetch = {
       type = "git";
       url = "https://code.googlesource.com/gocloud";
-      rev =  "2d3a6656c17a60b0815b7e06ab0be04eacb6e613";
-      sha256 = "0fi3qj9fvc4bxbrwa1m5sxsb8yhvawiwigaddvmmizjykxbq5csq";
+      rev = "v0.38.0";
+      sha256 = "0n6n13b7lri2fmc4bn4ifszyawj31dpbzvyv0xafsf81440z8cyh";
     };
   }
   {
-    goPackagePath  = "github.com/BurntSushi/toml";
+    goPackagePath = "github.com/BurntSushi/toml";
     fetch = {
       type = "git";
       url = "https://github.com/BurntSushi/toml";
-      rev =  "b26d9c308763d68093482582cea63d69be07a0f0";
-      sha256 = "0k7v2i1d2d6si8gswn83qb84czhhia53v2wdy33yz9ppdidxk0ry";
+      rev = "v0.3.1";
+      sha256 = "1fjdwwfzyzllgiwydknf1pwjvy49qxfsczqx5gz3y0izs7as99j6";
     };
   }
   {
-    goPackagePath  = "github.com/bitly/go-simplejson";
+    goPackagePath = "github.com/alicebob/gopher-json";
+    fetch = {
+      type = "git";
+      url = "https://github.com/alicebob/gopher-json";
+      rev = "5a6b3ba71ee6";
+      sha256 = "0hx6n722zq51p852lv56k39yjy09lw6mnr2c3x0p23rfyyrakj2p";
+    };
+  }
+  {
+    goPackagePath = "github.com/alicebob/miniredis";
+    fetch = {
+      type = "git";
+      url = "https://github.com/alicebob/miniredis";
+      rev = "v2.11.2";
+      sha256 = "1fc6w9n1jznwj8ks2svxmjrv87pk3spjf5z3kcxpgpynp13pd55n";
+    };
+  }
+  {
+    goPackagePath = "github.com/bitly/go-simplejson";
     fetch = {
       type = "git";
       url = "https://github.com/bitly/go-simplejson";
-      rev =  "aabad6e819789e569bd6aabf444c935aa9ba1e44";
+      rev = "v0.5.0";
       sha256 = "0n9f9dz1jn1jx86d48569nznpjn9fmq3knn7r65xpy7jhih284jj";
     };
   }
   {
-    goPackagePath  = "github.com/coreos/go-oidc";
+    goPackagePath = "github.com/bmizerany/assert";
+    fetch = {
+      type = "git";
+      url = "https://github.com/bmizerany/assert";
+      rev = "b7ed37b82869";
+      sha256 = "18hy1wyl9zdi7sgxafrn3m7fadh6in0rhhb8l0cvkxqzdl0jcw2s";
+    };
+  }
+  {
+    goPackagePath = "github.com/census-instrumentation/opencensus-proto";
+    fetch = {
+      type = "git";
+      url = "https://github.com/census-instrumentation/opencensus-proto";
+      rev = "v0.2.1";
+      sha256 = "19fcx3sc99i5dsklny6r073z5j20vlwn2xqm6di1q3b1xwchzqfj";
+    };
+  }
+  {
+    goPackagePath = "github.com/chzyer/logex";
+    fetch = {
+      type = "git";
+      url = "https://github.com/chzyer/logex";
+      rev = "v1.1.10";
+      sha256 = "08pbjj3wx9acavlwyr055isa8a5hnmllgdv5k6ra60l5y1brmlq4";
+    };
+  }
+  {
+    goPackagePath = "github.com/chzyer/readline";
+    fetch = {
+      type = "git";
+      url = "https://github.com/chzyer/readline";
+      rev = "2972be24d48e";
+      sha256 = "104q8dazj8yf6b089jjr82fy9h1g80zyyzvp3g8b44a7d8ngjj6r";
+    };
+  }
+  {
+    goPackagePath = "github.com/chzyer/test";
+    fetch = {
+      type = "git";
+      url = "https://github.com/chzyer/test";
+      rev = "a1ea475d72b1";
+      sha256 = "0rns2aqk22i9xsgyap0pq8wi4cfaxsri4d9q6xxhhyma8jjsnj2k";
+    };
+  }
+  {
+    goPackagePath = "github.com/client9/misspell";
+    fetch = {
+      type = "git";
+      url = "https://github.com/client9/misspell";
+      rev = "v0.3.4";
+      sha256 = "1vwf33wsc4la25zk9nylpbp9px3svlmldkm0bha4hp56jws4q9cs";
+    };
+  }
+  {
+    goPackagePath = "github.com/coreos/go-oidc";
     fetch = {
       type = "git";
       url = "https://github.com/coreos/go-oidc";
-      rev =  "77e7f2010a464ade7338597afe650dfcffbe2ca8";
-      sha256 = "0mh8fa7al9gfzx4k7rd623bpy14s06s96iz6lbf6psi5q2bnbs2r";
+      rev = "v2.2.1";
+      sha256 = "11m6slbpi33ynffml7812piq4anhjlf1qszjlsf26f5y7x3qh8n5";
     };
   }
   {
-    goPackagePath  = "github.com/davecgh/go-spew";
+    goPackagePath = "github.com/davecgh/go-spew";
     fetch = {
       type = "git";
       url = "https://github.com/davecgh/go-spew";
-      rev =  "346938d642f2ec3594ed81d874461961cd0faa76";
+      rev = "v1.1.0";
       sha256 = "0d4jfmak5p6lb7n2r6yvf5p1zcw0l8j74kn55ghvr7zr7b7axm6c";
     };
   }
   {
-    goPackagePath  = "github.com/dgrijalva/jwt-go";
+    goPackagePath = "github.com/dgrijalva/jwt-go";
     fetch = {
       type = "git";
       url = "https://github.com/dgrijalva/jwt-go";
-      rev =  "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e";
+      rev = "v3.2.0";
       sha256 = "08m27vlms74pfy5z79w67f9lk9zkx6a9jd68k3c4msxy75ry36mp";
     };
   }
   {
-    goPackagePath  = "github.com/golang/protobuf";
+    goPackagePath = "github.com/envoyproxy/go-control-plane";
+    fetch = {
+      type = "git";
+      url = "https://github.com/envoyproxy/go-control-plane";
+      rev = "5f8ba28d4473";
+      sha256 = "1f1s764rd41vd9vgk3r14h1m6fz6pdvxj6fd83q58gxifbc4q5w4";
+    };
+  }
+  {
+    goPackagePath = "github.com/envoyproxy/protoc-gen-validate";
+    fetch = {
+      type = "git";
+      url = "https://github.com/envoyproxy/protoc-gen-validate";
+      rev = "v0.1.0";
+      sha256 = "0kxd3wwh3xwqk0r684hsy281xq4y71cd11d4q2hspcjbnlbwh7cy";
+    };
+  }
+  {
+    goPackagePath = "github.com/fsnotify/fsnotify";
+    fetch = {
+      type = "git";
+      url = "https://github.com/fsnotify/fsnotify";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "github.com/go-redis/redis";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go-redis/redis";
+      rev = "v6.15.7";
+      sha256 = "0fc0sfispyzn652ny05wn6bz18a60n6ryk23ki8j97xx3l24nq2g";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/glog";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/glog";
+      rev = "23def4e6c14b";
+      sha256 = "0jb2834rw5sykfr937fxi8hxi2zy80sj2bdn9b3jb4b26ksqng30";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/mock";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/mock";
+      rev = "v1.2.0";
+      sha256 = "12ddj2g8ab87id6n2n67vnbhq6p8dvgsq1pzpqfriym4dk8w54fg";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/protobuf";
     fetch = {
       type = "git";
       url = "https://github.com/golang/protobuf";
-      rev =  "1e59b77b52bf8e4b449a57e6f79f21226d571845";
-      sha256 = "19bkh81wnp6njg3931wky6hsnnl2d1ig20vfjxpv450sd3k6yys8";
+      rev = "v1.3.2";
+      sha256 = "1k1wb4zr0qbwgpvz9q5ws9zhlal8hq7dmq62pwxxriksayl6hzym";
+    };
+  }
+  {
+    goPackagePath = "github.com/gomodule/redigo";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gomodule/redigo";
+      rev = "v2.0.0";
+      sha256 = "1kg7s8027b4g1sfw0v3nh30c15j407kv684s53gg281r807dnfpk";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/btree";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/btree";
+      rev = "4030bb1f1f0c";
+      sha256 = "0ba430m9fbnagacp57krgidsyrgp3ycw5r7dj71brgp5r52g82p6";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/go-cmp";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/go-cmp";
+      rev = "v0.3.0";
+      sha256 = "1hyxx3434zshl2m9ja78gwlkg1rx9yl6diqa7dnjb31xz5x4gbjj";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/martian";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/martian";
+      rev = "v2.1.0";
+      sha256 = "197hil6vrjk50b9wvwyzf61csid83whsjj6ik8mc9r2lryxlyyrp";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/pprof";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/pprof";
+      rev = "3ea8567a2e57";
+      sha256 = "09rhjn3ms0a72dw0yzbp237p7yhqma772zspddn6mgkh3gi3kn4c";
+    };
+  }
+  {
+    goPackagePath = "github.com/googleapis/gax-go";
+    fetch = {
+      type = "git";
+      url = "https://github.com/googleapis/gax-go";
+      rev = "v2.0.5";
+      sha256 = "1lxawwngv6miaqd25s3ba0didfzylbwisd2nz7r4gmbmin6jsjrx";
+    };
+  }
+  {
+    goPackagePath = "github.com/hashicorp/golang-lru";
+    fetch = {
+      type = "git";
+      url = "https://github.com/hashicorp/golang-lru";
+      rev = "v0.5.1";
+      sha256 = "13f870cvk161bzjj6x41l45r5x9i1z9r2ymwmvm7768kg08zznpy";
+    };
+  }
+  {
+    goPackagePath = "github.com/hpcloud/tail";
+    fetch = {
+      type = "git";
+      url = "https://github.com/hpcloud/tail";
+      rev = "v1.0.0";
+      sha256 = "1njpzc0pi1acg5zx9y6vj9xi6ksbsc5d387rd6904hy6rh2m6kn0";
+    };
+  }
+  {
+    goPackagePath = "github.com/jstemmer/go-junit-report";
+    fetch = {
+      type = "git";
+      url = "https://github.com/jstemmer/go-junit-report";
+      rev = "af01ea7f8024";
+      sha256 = "1lp3n94ris12hac02wi31f3whs88lcrzwgdg43a5j6cafg9p1d0s";
+    };
+  }
+  {
+    goPackagePath = "github.com/kr/pretty";
+    fetch = {
+      type = "git";
+      url = "https://github.com/kr/pretty";
+      rev = "v0.2.0";
+      sha256 = "1ywbfzz1h3a3qd8rpkiqwi1dm4w8ls9ijb4x1b7567grns9f0vnp";
     };
   }
   {
-    goPackagePath  = "github.com/mbland/hmacauth";
+    goPackagePath = "github.com/kr/pty";
+    fetch = {
+      type = "git";
+      url = "https://github.com/kr/pty";
+      rev = "v1.1.1";
+      sha256 = "0383f0mb9kqjvncqrfpidsf8y6ns5zlrc91c6a74xpyxjwvzl2y6";
+    };
+  }
+  {
+    goPackagePath = "github.com/kr/text";
+    fetch = {
+      type = "git";
+      url = "https://github.com/kr/text";
+      rev = "v0.1.0";
+      sha256 = "1gm5bsl01apvc84bw06hasawyqm4q84vx1pm32wr9jnd7a8vjgj1";
+    };
+  }
+  {
+    goPackagePath = "github.com/mbland/hmacauth";
     fetch = {
       type = "git";
       url = "https://github.com/mbland/hmacauth";
-      rev =  "107c17adcc5eccc9935cd67d9bc2feaf5255d2cb";
-      sha256 = "1zd9r8znhkxyl997lhjk8nrlxlfv5s1hn7ql87wrcyvlsszx3mzh";
+      rev = "44256dfd4bfa";
+      sha256 = "1d5pbjgc5j8pi3frsjp5gqg7j12bxdbl55nhy01cv4c96hay2ij1";
     };
   }
   {
-    goPackagePath  = "github.com/mreiferson/go-options";
+    goPackagePath = "github.com/mreiferson/go-options";
     fetch = {
       type = "git";
       url = "https://github.com/mreiferson/go-options";
-      rev =  "20ba7d382d05facb01e02eb777af0c5f229c5c95";
-      sha256 = "1vdz3wqkj885a0jkggaygl4k6k8b94fpspywr26snm4xnb8vgxsf";
+      rev = "v1.0.0";
+      sha256 = "1pxs9ybrh196qy14ijn4zn51h2z28lj31y6vxrz2xxhgvpmfmxyl";
+    };
+  }
+  {
+    goPackagePath = "github.com/onsi/ginkgo";
+    fetch = {
+      type = "git";
+      url = "https://github.com/onsi/ginkgo";
+      rev = "v1.12.0";
+      sha256 = "0ly246i0ax53l6dn9f1zlhkd9gs03hvbk7aazxay2dd5fxzh9n65";
     };
   }
   {
-    goPackagePath  = "github.com/pmezard/go-difflib";
+    goPackagePath = "github.com/onsi/gomega";
+    fetch = {
+      type = "git";
+      url = "https://github.com/onsi/gomega";
+      rev = "v1.9.0";
+      sha256 = "0l69r6nbnz6b3j9zrqn8aql88jjv1pqykzkvqdbhfprss9b2dy46";
+    };
+  }
+  {
+    goPackagePath = "github.com/pmezard/go-difflib";
     fetch = {
       type = "git";
       url = "https://github.com/pmezard/go-difflib";
-      rev =  "792786c7400a136282c1664665ae0a8db921c6c2";
+      rev = "v1.0.0";
       sha256 = "0c1cn55m4rypmscgf0rrb88pn58j3ysvc2d0432dp3c6fqg6cnzw";
     };
   }
   {
-    goPackagePath  = "github.com/pquerna/cachecontrol";
+    goPackagePath = "github.com/pquerna/cachecontrol";
     fetch = {
       type = "git";
       url = "https://github.com/pquerna/cachecontrol";
-      rev =  "0dec1b30a0215bb68605dfc568e8855066c9202d";
-      sha256 = "14yyfhrv60rvb983rqm7s916nwvn9kcmbvnrcna2md0s3mkzs3yh";
+      rev = "1555304b9b35";
+      sha256 = "0nr3p9pms6jmr2s44vy2s22q1d3v6xns2kzsvkq2gg1rkx6c1hc9";
     };
   }
   {
-    goPackagePath  = "github.com/stretchr/testify";
+    goPackagePath = "github.com/prometheus/client_model";
+    fetch = {
+      type = "git";
+      url = "https://github.com/prometheus/client_model";
+      rev = "14fe0d1b01d4";
+      sha256 = "0zdmk6rbbx39cvfz0r59v2jg5sg9yd02b4pds5n5llgvivi99550";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/objx";
+    fetch = {
+      type = "git";
+      url = "https://github.com/stretchr/objx";
+      rev = "v0.1.0";
+      sha256 = "19ynspzjdynbi85xw06mh8ad5j0qa1vryvxjgvbnyrr8rbm4vd8w";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/testify";
     fetch = {
       type = "git";
       url = "https://github.com/stretchr/testify";
-      rev =  "69483b4bd14f5845b5a1e55bca19e954e827f1d0";
-      sha256 = "11lzrwkdzdd8yyag92akncc008h2f9d1bpc489mxiwp0jrmz4ivb";
+      rev = "v1.5.1";
+      sha256 = "09r89m1wy4cjv2nps1ykp00qjpi0531r07q3s34hr7m6njk4srkl";
     };
   }
   {
-    goPackagePath  = "github.com/yhat/wsutil";
+    goPackagePath = "github.com/yhat/wsutil";
     fetch = {
       type = "git";
       url = "https://github.com/yhat/wsutil";
-      rev =  "1d66fa95c997864ba4d8479f56609620fe542928";
+      rev = "1d66fa95c997";
       sha256 = "1agh4ss6y1laps8pg4mdl844ivmw2wrb7rnpfyag4gai4693i7bv";
     };
   }
   {
-    goPackagePath  = "golang.org/x/crypto";
+    goPackagePath = "github.com/yuin/gopher-lua";
+    fetch = {
+      type = "git";
+      url = "https://github.com/yuin/gopher-lua";
+      rev = "ab39c6098bdb";
+      sha256 = "13b0rrpv3988qw8rq6z7npajn1my059ybhafi5mxff9jw09k9sja";
+    };
+  }
+  {
+    goPackagePath = "go.opencensus.io";
+    fetch = {
+      type = "git";
+      url = "https://github.com/census-instrumentation/opencensus-go";
+      rev = "v0.21.0";
+      sha256 = "14s0a12xdzjvad0dgksgv8m3hh7nc585abvjkvyk6r67a29lxj6x";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/crypto";
     fetch = {
       type = "git";
       url = "https://go.googlesource.com/crypto";
-      rev =  "9f005a07e0d31d45e6656d241bb5c0f2efd4bc94";
-      sha256 = "1mhmr6ljzl3iafsz4qy8vval7rmr828wh59dlqqqjqx6sqmcs1dv";
+      rev = "2aa609cf4a9d";
+      sha256 = "1yvis6fqbsd7f356aqyi18f76vnwj3bry6mxqnkvshq4cwrf92il";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/exp";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/exp";
+      rev = "509febef88a4";
+      sha256 = "02isrh39z8znrp5znplzy0dip2gnrl3jm1355raliyvhnhg04j6q";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/lint";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/lint";
+      rev = "959b441ac422";
+      sha256 = "1mgcv5f00pkzsbwnq2y7vqvd1b4lr5a3s47cphh2qv4indfk7pck";
     };
   }
   {
-    goPackagePath  = "golang.org/x/net";
+    goPackagePath = "golang.org/x/net";
     fetch = {
       type = "git";
       url = "https://go.googlesource.com/net";
-      rev =  "9dfe39835686865bff950a07b394c12a98ddc811";
-      sha256 = "0z8mnl4mi88syafrgqys2ak2gg3yrbna25hpz88y3anl8x4jhg1a";
+      rev = "0de0cce0169b";
+      sha256 = "1db7s5kbzyh2zd5lpv05n7hp8wbwdvgk0wpiwrlnig94mkr0y5aq";
     };
   }
   {
-    goPackagePath  = "golang.org/x/oauth2";
+    goPackagePath = "golang.org/x/oauth2";
     fetch = {
       type = "git";
       url = "https://go.googlesource.com/oauth2";
-      rev =  "9ff8ebcc8e241d46f52ecc5bff0e5a2f2dbef402";
-      sha256 = "035v5w1nad6r1l22cj6f73zzr6qi4jgq71yjywf2c6rvsa5147r2";
+      rev = "bf48bf16ab8d";
+      sha256 = "1sirdib60zwmh93kf9qrx51r8544k1p9rs5mk0797wibz3m4mrdg";
     };
   }
   {
-    goPackagePath  = "google.golang.org/api";
+    goPackagePath = "golang.org/x/sync";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sync";
+      rev = "112230192c58";
+      sha256 = "05i2k43j2d0llq768hg5pf3hb2yhfzp9la1w5wp0rsnnzblr0lfn";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/sys";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sys";
+      rev = "bd437916bb0e";
+      sha256 = "1i8x26frmlin55k69k936zd1rp5sqnq14y5ms4rkxbfzhasdm2rx";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/text";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/text";
+      rev = "v0.3.2";
+      sha256 = "0flv9idw0jm5nm8lx25xqanbkqgfiym6619w575p7nrdh0riqwqh";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/time";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/time";
+      rev = "85acf8d2951c";
+      sha256 = "0yqnxsrarjk4qkda8kcxzmk7y90kkkxzx9iwryzrk7bzs87ky3xc";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/tools";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/tools";
+      rev = "2c0ae7006135";
+      sha256 = "1lsi2ssxajclj3bciz2a41v1vjv768ja3v6wnbyhxy8xphwkp4fk";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/xerrors";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/xerrors";
+      rev = "a985d3407aa7";
+      sha256 = "00wzr5w8aadipgc3rkk8f11i41znskfj9ix5nhhaxyg7isrslgcj";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/api";
     fetch = {
       type = "git";
       url = "https://code.googlesource.com/google-api-go-client";
-      rev =  "8791354e7ab150705ede13637a18c1fcc16b62e8";
-      sha256 = "0ps7y4m9787wvkqwrwqyb4nmmibhrihmg7xqh7sba2cyj397wngm";
+      rev = "v0.19.0";
+      sha256 = "0rbwijzl91xmbr9kqhiwx4fydm7r6ci6rxsi9jsy8zap9zy120f6";
     };
   }
   {
-    goPackagePath  = "google.golang.org/appengine";
+    goPackagePath = "google.golang.org/appengine";
     fetch = {
       type = "git";
       url = "https://github.com/golang/appengine";
-      rev =  "150dc57a1b433e64154302bdc40b6bb8aefa313a";
-      sha256 = "0w3knznv39k8bm85ri62f83czcrxknql7dv6p9hk1a5jx3xljgxq";
+      rev = "v1.5.0";
+      sha256 = "0l7mkdnwhidv8m686x432vmx8z5nqcrr9f46ddgvrxbh4wvyfcll";
     };
   }
   {
-    goPackagePath  = "gopkg.in/fsnotify/fsnotify.v1";
+    goPackagePath = "google.golang.org/genproto";
     fetch = {
       type = "git";
-      url = "https://github.com/fsnotify/fsnotify";
-      rev =  "836bfd95fecc0f1511dd66bdbf2b5b61ab8b00b6";
-      sha256 = "0470dznkcbabncskgr8hfilpj5w24ygg455pyggbfbssmfv1m9gg";
+      url = "https://github.com/google/go-genproto";
+      rev = "24fa4b261c55";
+      sha256 = "109zhaqlfd8zkbr1hk6zqbs6vcxfrk64scjwh2nswph05gr0m84d";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/grpc";
+    fetch = {
+      type = "git";
+      url = "https://github.com/grpc/grpc-go";
+      rev = "v1.27.0";
+      sha256 = "1ijrmgrxyabfn51nm3p9l81iaasq5fg237wnr6mdc4dzsfcg8kd7";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/check.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/check.v1";
+      rev = "20d25e280405";
+      sha256 = "0k1m83ji9l1a7ng8a7v40psbymxasmssbrrhpdv2wl4rhs0nc3np";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/fsnotify.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/fsnotify.v1";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/fsnotify/fsnotify.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/fsnotify/fsnotify.v1";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/natefinch/lumberjack.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/natefinch/lumberjack.v2";
+      rev = "v2.0.0";
+      sha256 = "1m2sxypk7p805jvc68padvylyx5v7cwkh5klnnxxr0340kgspf08";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/square/go-jose.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/square/go-jose.v2";
+      rev = "v2.4.1";
+      sha256 = "1y0angxwryishwd1z0q7fp2xwjjhpw70kqh4ml4ly40akfhf1f5a";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/tomb.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/tomb.v1";
+      rev = "dd632973f1e7";
+      sha256 = "1lqmq1ag7s4b3gc3ddvr792c5xb5k6sfn0cchr3i2s7f1c231zjv";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/yaml.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/yaml.v2";
+      rev = "v2.2.4";
+      sha256 = "11bwj757wi8kdrcnlgfqb8vv2d2xdhlghmyagd19i62khrkchsg2";
     };
   }
   {
-    goPackagePath  = "gopkg.in/square/go-jose.v2";
+    goPackagePath = "honnef.co/go/tools";
     fetch = {
       type = "git";
-      url = "https://github.com/square/go-jose";
-      rev =  "f8f38de21b4dcd69d0413faf231983f5fd6634b1";
-      sha256 = "1bjrs3xq3m2ckfds0l4wqf81311ymm9agipmkllbvkadac156dsa";
+      url = "https://github.com/dominikh/go-tools";
+      rev = "ea95bdfd59fc";
+      sha256 = "1763nw7pwpzkvzfnm63dgzcgbq9hwmq5l1nffchnhh77vgkaq4ic";
     };
   }
-]
\ No newline at end of file
+]
diff --git a/pkgs/servers/tailscale/default.nix b/pkgs/servers/tailscale/default.nix
index e4cc0889c31f..24a8aa66151a 100644
--- a/pkgs/servers/tailscale/default.nix
+++ b/pkgs/servers/tailscale/default.nix
@@ -2,13 +2,15 @@
 
 buildGoModule rec {
   pname = "tailscale";
-  version = "0.97";
+  version = "0.97-219";
 
   src = fetchFromGitHub {
     owner = "tailscale";
     repo = "tailscale";
-    rev = "v${version}";
-    sha256 = "0ckjqhj99c25h8xgyfkrd19nw5w4a7972nvba9r5faw5micjs02n";
+    # Tailscale uses "git describe" as version numbers. v0.97-219
+    # means "tag v0.97 plus 219 commits", which is what this rev is.
+    rev = "afbfe4f217a2a202f0eefe943c7c1ef648311339";
+    sha256 = "1an897ys3gycdmclqd0yqs9f7q88zxqxyc6r0gcgs4678svxhb68";
   };
 
   nativeBuildInputs = [ makeWrapper ];
@@ -16,7 +18,7 @@ buildGoModule rec {
   CGO_ENABLED = 0;
 
   goPackagePath = "tailscale.com";
-  modSha256 = "0anpakcqz4irwxnm0iwm7wqzh84kv3yxxdvyr38154pbd0ys5pa2";
+  modSha256 = "1xgdhbck3pkix10lfshzdszrv6d3p0hbx8jdjvswz7jjd0vzm4x1";
   subPackages = [ "cmd/tailscale" "cmd/tailscaled" ];
 
   postInstall = ''
diff --git a/pkgs/shells/fish/default.nix b/pkgs/shells/fish/default.nix
index 0ea8dce44059..bea56bd8c5a5 100644
--- a/pkgs/shells/fish/default.nix
+++ b/pkgs/shells/fish/default.nix
@@ -6,7 +6,7 @@
   , fetchpatch
 
   , writeText
-
+  , nixosTests
   , useOperatingSystemEtc ? true
 
 }:
@@ -179,6 +179,7 @@ let
 
     passthru = {
       shellPath = "/bin/fish";
+      tests.nixos = nixosTests.fish;
     };
   };
 
diff --git a/pkgs/shells/oil/default.nix b/pkgs/shells/oil/default.nix
index 9e2aa3454d2c..019a66c77eb7 100644
--- a/pkgs/shells/oil/default.nix
+++ b/pkgs/shells/oil/default.nix
@@ -1,12 +1,12 @@
-{ stdenv, lib, fetchurl, fetchpatch, readline }:
+{ stdenv, lib, fetchurl, readline }:
 
 stdenv.mkDerivation rec {
   pname = "oil";
-  version = "0.7.0";
+  version = "0.8.pre4";
 
   src = fetchurl {
     url = "https://www.oilshell.org/download/oil-${version}.tar.xz";
-    sha256 = "12c9s462879adb6mwd3fqafk0dnqsm16s18rhym6cmzfzy8v8zm3";
+    sha256 = "07kj86hrvlz9f1gh3qv4hdaz3qnb4a2qf0dnxhd2r0qilrkjanxh";
   };
 
   postPatch = ''
diff --git a/pkgs/tools/archivers/p7zip/default.nix b/pkgs/tools/archivers/p7zip/default.nix
index f44791ce021b..3f0c2487c91b 100644
--- a/pkgs/tools/archivers/p7zip/default.nix
+++ b/pkgs/tools/archivers/p7zip/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl }:
+{ stdenv, fetchurl, lib, enableUnfree ? false }:
 
 stdenv.mkDerivation rec {
   pname = "p7zip";
@@ -24,6 +24,11 @@ stdenv.mkDerivation rec {
     substituteInPlace makefile.machine \
       --replace 'CC=gcc'  'CC=${stdenv.cc.targetPrefix}gcc' \
       --replace 'CXX=g++' 'CXX=${stdenv.cc.targetPrefix}g++'
+  '' + lib.optionalString (!enableUnfree) ''
+    # Remove non-free RAR source code
+    # (see DOC/License.txt, https://fedoraproject.org/wiki/Licensing:Unrar)
+    rm -r CPP/7zip/Compress/Rar*
+    find . -name makefile'*' -exec sed -i '/Rar/d' {} +
   '';
 
   preConfigure = ''
@@ -42,9 +47,9 @@ stdenv.mkDerivation rec {
   meta = {
     homepage = "http://p7zip.sourceforge.net/";
     description = "A port of the 7-zip archiver";
-    # license = stdenv.lib.licenses.lgpl21Plus; + "unRAR restriction"
     platforms = stdenv.lib.platforms.unix;
     maintainers = [ stdenv.lib.maintainers.raskin ];
-    license = stdenv.lib.licenses.lgpl2Plus;
+    # RAR code is under non-free UnRAR license, but we remove it
+    license = if enableUnfree then lib.licenses.unfree else lib.licenses.lgpl2Plus;
   };
 }
diff --git a/pkgs/tools/graphics/spirv-cross/default.nix b/pkgs/tools/graphics/spirv-cross/default.nix
new file mode 100644
index 000000000000..57b447b1ad79
--- /dev/null
+++ b/pkgs/tools/graphics/spirv-cross/default.nix
@@ -0,0 +1,23 @@
+{ stdenv, fetchFromGitHub, cmake, python3 }:
+
+stdenv.mkDerivation rec {
+  pname = "spirv-cross";
+  version = "2020-04-03";
+
+  src = fetchFromGitHub {
+    owner = "KhronosGroup";
+    repo = "SPIRV-Cross";
+    rev = version;
+    sha256 = "0489s29kqgq20clxqg22y299yxz23p0yjh87yhka705hm9skx4sa";
+  };
+
+  nativeBuildInputs = [ cmake python3 ];
+
+  meta = with stdenv.lib; {
+    description = "A tool designed for parsing and converting SPIR-V to other shader languages";
+    homepage = "https://github.com/KhronosGroup/SPIRV-Cross";
+    platforms = platforms.linux;
+    license = licenses.asl20;
+    maintainers = with maintainers; [ Flakebi ];
+  };
+}
diff --git a/pkgs/tools/misc/hpl/default.nix b/pkgs/tools/misc/hpl/default.nix
index c131de021806..d688f3adf30e 100644
--- a/pkgs/tools/misc/hpl/default.nix
+++ b/pkgs/tools/misc/hpl/default.nix
@@ -1,6 +1,6 @@
 { stdenv, fetchurl, blas, lapack, mpi } :
 
-assert (!blas.is64bit) && (!lapack.is64bit);
+assert (!blas.isILP64) && (!lapack.isILP64);
 
 stdenv.mkDerivation rec {
   pname = "hpl";
diff --git a/pkgs/tools/misc/ili2c/default.nix b/pkgs/tools/misc/ili2c/default.nix
index 4d78f797f109..43eed8367c47 100644
--- a/pkgs/tools/misc/ili2c/default.nix
+++ b/pkgs/tools/misc/ili2c/default.nix
@@ -2,7 +2,7 @@
 
 stdenv.mkDerivation rec {
   pname = "ili2c";
-  version = "5.0.0";
+  version = "5.0.8";
 
   nativeBuildInputs = [ ant jdk makeWrapper ];
 
@@ -10,7 +10,7 @@ stdenv.mkDerivation rec {
     owner = "claeis";
     repo = pname;
     rev = "${pname}-${version}";
-    sha256 = "0xps2343d5gdr2aj8j3l4cjq4k9zbxxlhnp8sjlhxh1wdczxlwx6";
+    sha256 = "1yhsyh940kb33y2n6xl7zhf0f6q0nrxbyg6c4g5n2imllpn54sgi";
   };
 
   buildPhase = "ant jar";
diff --git a/pkgs/tools/networking/babeld/default.nix b/pkgs/tools/networking/babeld/default.nix
index a2f486717da7..debd918eb39d 100644
--- a/pkgs/tools/networking/babeld/default.nix
+++ b/pkgs/tools/networking/babeld/default.nix
@@ -2,11 +2,11 @@
 
 stdenv.mkDerivation rec {
   pname = "babeld";
-  version = "1.9.1";
+  version = "1.9.2";
 
   src = fetchurl {
     url = "http://www.pps.univ-paris-diderot.fr/~jch/software/files/${pname}-${version}.tar.gz";
-    sha256 = "1d503igqv9s5pgrhvxp1czjy2xfsjhagyyh2iny7g4cjvl0kq6qy";
+    sha256 = "01vzhrspnm4sy9ggaz9n3bfl5hy3qlynr218j3mdcddzm3h00kqm";
   };
 
   preBuild = ''
diff --git a/pkgs/tools/networking/cjdns/default.nix b/pkgs/tools/networking/cjdns/default.nix
index 452181754b17..9a74344d2936 100644
--- a/pkgs/tools/networking/cjdns/default.nix
+++ b/pkgs/tools/networking/cjdns/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchFromGitHub, nodejs, which, python27, utillinux }:
+{ stdenv, fetchFromGitHub, nodejs, which, python27, utillinux, nixosTests }:
 
 let version = "20.6"; in
 stdenv.mkDerivation {
@@ -29,6 +29,8 @@ stdenv.mkDerivation {
     cp -R contrib tools node_build node_modules $out/share/cjdns/
   '';
 
+  passthru.tests.basic = nixosTests.cjdns;
+
   meta = with stdenv.lib; {
     homepage = "https://github.com/cjdelisle/cjdns";
     description = "Encrypted networking for regular people";
diff --git a/pkgs/tools/networking/ferm/default.nix b/pkgs/tools/networking/ferm/default.nix
index 8fcdeb234ec3..855a57b7720f 100644
--- a/pkgs/tools/networking/ferm/default.nix
+++ b/pkgs/tools/networking/ferm/default.nix
@@ -3,23 +3,27 @@
 let
   inherit (stdenv.lib.versions) majorMinor;
 in stdenv.mkDerivation rec {
-  version = "2.5";
+  version = "2.5.1";
   pname = "ferm";
 
   src = fetchurl {
     url = "http://ferm.foo-projects.org/download/${majorMinor version}/ferm-${version}.tar.xz";
-    sha256 = "0lxqcpirphihpvdqrh5kq0621aqq0h2vdy9q2v85gqdhd52js20p";
+    sha256 = "0awl9s243sxgayr2fcmfks8xydhrmb9gy8bd9sfq738dgq7vybjb";
   };
 
-  buildInputs = [ perl ipset ebtables iptables makeWrapper ];
-  preConfigure = ''
-    substituteInPlace config.mk --replace "PERL = /usr/bin/perl" "PERL = ${perl}/bin/perl"
-    substituteInPlace config.mk --replace "PREFIX = /usr" "PREFIX = $out"
-  '';
+  # perl is used at build time to gather the ferm version.
+  nativeBuildInputs = [ makeWrapper perl ];
+  buildInputs = [ perl ];
+
+  makeFlags = [
+    "PERL=perl"
+    "PREFIX=${placeholder "out"}"
+  ];
+
   postInstall = ''
     rm -r $out/lib/systemd
     for i in "$out/sbin/"*; do
-      wrapProgram "$i" --prefix PATH : "${iptables}/bin:${ipset}/bin:${ebtables}/bin"
+      wrapProgram "$i" --prefix PATH : "${stdenv.lib.makeBinPath [ iptables ipset ebtables ]}"
     done
   '';
 
diff --git a/pkgs/tools/networking/mu/default.nix b/pkgs/tools/networking/mu/default.nix
index ae1ca3f77611..aa1e004d1afc 100644
--- a/pkgs/tools/networking/mu/default.nix
+++ b/pkgs/tools/networking/mu/default.nix
@@ -22,8 +22,6 @@ stdenv.mkDerivation rec {
 
   enableParallelBuilding = true;
 
-  preConfigure = "./autogen.sh";
-
   preBuild = ''
     # Fix mu4e-builddir (set it to $out)
     substituteInPlace mu4e/mu4e-meta.el.in \
@@ -43,7 +41,7 @@ stdenv.mkDerivation rec {
     description = "A collection of utilties for indexing and searching Maildirs";
     license = licenses.gpl3Plus;
     homepage = "https://www.djcbsoftware.nl/code/mu/";
-    platforms = platforms.mesaPlatforms;
     maintainers = with maintainers; [ antono the-kenny peterhoeg ];
+    platforms = platforms.mesaPlatforms;
   };
 }
diff --git a/pkgs/tools/networking/yggdrasil/default.nix b/pkgs/tools/networking/yggdrasil/default.nix
index 91b080153279..d8c8c429ef98 100644
--- a/pkgs/tools/networking/yggdrasil/default.nix
+++ b/pkgs/tools/networking/yggdrasil/default.nix
@@ -1,4 +1,4 @@
-{ lib, buildGoModule, fetchFromGitHub }:
+{ lib, buildGoModule, fetchFromGitHub, nixosTests }:
 
 buildGoModule rec {
   pname = "yggdrasil";
@@ -27,6 +27,8 @@ buildGoModule rec {
       -s -w
   '';
 
+  passthru.tests.basic = nixosTests.yggdrasil;
+
   meta = with lib; {
     description =
       "An experiment in scalable routing as an encrypted IPv6 overlay network";
diff --git a/pkgs/tools/package-management/nixpkgs-review/default.nix b/pkgs/tools/package-management/nixpkgs-review/default.nix
index d8811b2a7e2f..b6455cc1705b 100644
--- a/pkgs/tools/package-management/nixpkgs-review/default.nix
+++ b/pkgs/tools/package-management/nixpkgs-review/default.nix
@@ -8,13 +8,13 @@
 
 python3.pkgs.buildPythonApplication rec {
   pname = "nixpkgs-review";
-  version = "2.2.0";
+  version = "2.3.0";
 
   src = fetchFromGitHub {
     owner = "Mic92";
     repo = "nixpkgs-review";
     rev = version;
-    sha256 = "0qsvrcxl97nih1yprydzlqc6n1ppg726664d6harx5kjzp5776mr";
+    sha256 = "0qkvjl4f8a1905yj3ml32rfdr5q76igz21gn3dcya0pfqhrnb28i";
   };
 
   makeWrapperArgs = [
diff --git a/pkgs/tools/system/tre-command/default.nix b/pkgs/tools/system/tre-command/default.nix
index 0cbe87ccd377..bc0fa7ea988d 100644
--- a/pkgs/tools/system/tre-command/default.nix
+++ b/pkgs/tools/system/tre-command/default.nix
@@ -2,7 +2,7 @@
 
 rustPlatform.buildRustPackage rec {
   pname = "tre";
-  version = "0.2.2";
+  version = "0.2.3";
 
   src = fetchFromGitHub {
     owner = "dduan";
@@ -11,7 +11,7 @@ rustPlatform.buildRustPackage rec {
     sha256 = "1fazw2wn738iknbv54gv7qll7d4q2gy9bq1s3f3cv21cdv6bqral";
   };
 
-  cargoSha256 = "1m3ccp5ncafkifg8sxyxczsg3ja1gvq8wmgni68bgzm2lwxh2qgw";
+  cargoSha256 = "16bvnwgjf3kj99d77j1pkldbasxfwy55sj9sv9vf2z6llfmzfabd";
 
   meta = with stdenv.lib; {
     description = "Tree command, improved";
diff --git a/pkgs/tools/text/transifex-client/default.nix b/pkgs/tools/text/transifex-client/default.nix
index 403adaf71b6f..ac10564c9f76 100644
--- a/pkgs/tools/text/transifex-client/default.nix
+++ b/pkgs/tools/text/transifex-client/default.nix
@@ -3,7 +3,7 @@
 
 buildPythonApplication rec {
   pname = "transifex-client";
-  version = "0.13.6";
+  version = "0.13.9";
 
   propagatedBuildInputs = [
     urllib3 requests python-slugify six setuptools
@@ -11,13 +11,13 @@ buildPythonApplication rec {
 
   src = fetchPypi {
     inherit pname version;
-    sha256 = "0y6pprlmkmi7wfqr3k70sb913qa70p3i90q5mravrai7cr32y1w8";
+    sha256 = "0lgd77vrddvyn8afkxr7a7hblmp4k5sr0i9i1032xdih2bipdd9f";
   };
 
   prePatch = ''
     substituteInPlace requirements.txt --replace "urllib3<1.24" "urllib3>=1.24" \
       --replace "six==1.11.0" "six>=1.11.0" \
-      --replace "python-slugify==1.2.6" "python-slugify>=1.2.6"
+      --replace "python-slugify<2.0.0" "python-slugify>2.0.0"
   '';
 
   # Requires external resources
diff --git a/pkgs/tools/typesetting/sile/default.nix b/pkgs/tools/typesetting/sile/default.nix
index 5bb4c5b7fb2f..a8969fd45985 100644
--- a/pkgs/tools/typesetting/sile/default.nix
+++ b/pkgs/tools/typesetting/sile/default.nix
@@ -13,11 +13,11 @@ in
 
 stdenv.mkDerivation rec {
   pname = "sile";
-  version = "0.10.3";
+  version = "0.10.4";
 
   src = fetchurl {
     url = "https://github.com/sile-typesetter/sile/releases/download/v${version}/${pname}-${version}.tar.bz2";
-    sha256 = "d89d5ce7d2bf46fb062e5299ffd8b5d821dc3cb3462a0e7c1109edeee111d856";
+    sha256 = "08j2vv6spnzz8bsh62wbdv1pjiziiba71cadscsy5hw6pklzndni";
   };
 
   configureFlags = [ "--with-system-luarocks" ];
diff --git a/pkgs/tools/virtualization/cri-tools/default.nix b/pkgs/tools/virtualization/cri-tools/default.nix
index 2aa23f04fe48..8c57fdeed005 100644
--- a/pkgs/tools/virtualization/cri-tools/default.nix
+++ b/pkgs/tools/virtualization/cri-tools/default.nix
@@ -2,12 +2,12 @@
 
 buildGoPackage rec {
   pname = "cri-tools";
-  version = "1.17.0";
+  version = "1.18.0";
   src = fetchFromGitHub {
     owner = "kubernetes-sigs";
     repo = pname;
     rev = "v${version}";
-    sha256 = "0h9gry56graif761lmcy91q9fzwvmwb15wcx8245927yfg5j0zgh";
+    sha256 = "06sxjhjpd893fn945c1s4adri2bf7s50ddvcw5pnwb6qndzfljw6";
   };
 
   goPackagePath = "github.com/kubernetes-sigs/cri-tools";
diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix
index 4b2b36eb352c..9ad282149aa6 100644
--- a/pkgs/top-level/aliases.nix
+++ b/pkgs/top-level/aliases.nix
@@ -216,7 +216,6 @@ mapAliases ({
   keymon = throw "keymon has been removed from nixpkgs, as it's abandoned and archived."; # 2019-12-10
   kvm = qemu_kvm; # added 2018-04-25
   latinmodern-math = lmmath;
-  ldc2 = ldc; # added 2020-04-18
   letsencrypt = certbot; # added 2016-05-16
   libaudit = audit; # added 2018-04-25
   libcanberra_gtk2 = libcanberra-gtk2; # added 2018-02-25
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 434b6906ca5d..f45b6df2970b 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -2472,6 +2472,7 @@ in
   circus = callPackage ../tools/networking/circus { };
 
   citrix_workspace_unwrapped = callPackage ../applications/networking/remote/citrix-workspace { };
+  citrix_workspace_unwrapped_20_04_0 = citrix_workspace_unwrapped.override { version = "20.04.0"; };
   citrix_workspace_unwrapped_19_12_0 = citrix_workspace_unwrapped.override { version = "19.12.0"; };
   citrix_workspace_unwrapped_19_10_0 = citrix_workspace_unwrapped.override { version = "19.10.0"; };
   citrix_workspace_unwrapped_19_8_0 = citrix_workspace_unwrapped.override { version = "19.8.0"; };
@@ -3990,6 +3991,8 @@ in
 
   httplab = callPackage ../tools/networking/httplab { };
 
+  lucky-cli = callPackage ../development/web/lucky-cli { };
+
   partclone = callPackage ../tools/backup/partclone { };
 
   partimage = callPackage ../tools/backup/partimage { };
@@ -6531,6 +6534,8 @@ in
 
   shocco = callPackage ../tools/text/shocco { };
 
+  shopify-themekit = callPackage ../development/web/shopify-themekit { };
+
   shorewall = callPackage ../tools/networking/shorewall { };
 
   shotwell = callPackage ../applications/graphics/shotwell { };
@@ -8113,9 +8118,7 @@ in
     crystal
     crystal2nix;
 
-  icr = callPackage ../development/tools/icr {
-    openssl = openssl_1_0_2;
-  };
+  icr = callPackage ../development/tools/icr { };
 
   scry = callPackage ../development/tools/scry {};
 
@@ -12189,6 +12192,16 @@ in
   } // (stdenv.lib.optionalAttrs (stdenv.hostPlatform.isi686 && stdenv.cc.isGNU) {
       stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4'
     }));
+  icu65 = callPackage ../development/libraries/icu/65.nix ({
+    nativeBuildRoot = buildPackages.icu65.override { buildRootOnly = true; };
+  } // (stdenv.lib.optionalAttrs (stdenv.hostPlatform.isi686 && stdenv.cc.isGNU) {
+      stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4'
+    }));
+  icu66 = callPackage ../development/libraries/icu/66.nix ({
+    nativeBuildRoot = buildPackages.icu66.override { buildRootOnly = true; };
+  } // (stdenv.lib.optionalAttrs (stdenv.hostPlatform.isi686 && stdenv.cc.isGNU) {
+      stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4'
+    }));
 
   icu = icu64;
 
@@ -14515,6 +14528,8 @@ in
 
   spice-up = callPackage ../applications/office/spice-up { };
 
+  spirv-cross = callPackage ../tools/graphics/spirv-cross { };
+
   sratom = callPackage ../development/libraries/audio/sratom { };
 
   srm = callPackage ../tools/security/srm { };
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index cb5cbb5375a7..ea246c3f86a5 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -560,6 +560,8 @@ in {
 
   catalogue = callPackage ../development/python-modules/catalogue { };
 
+  cbeams = callPackage ../misc/cbeams { };
+
   cdecimal = callPackage ../development/python-modules/cdecimal { };
 
   cfn-flip = callPackage ../development/python-modules/cfn-flip { };
@@ -1063,6 +1065,8 @@ in {
 
   proglog = callPackage ../development/python-modules/proglog { };
 
+  pulsectl = callPackage ../development/python-modules/pulsectl { };
+
   pure-python-adb-homeassistant = callPackage ../development/python-modules/pure-python-adb-homeassistant { };
 
   purl = callPackage ../development/python-modules/purl { };
@@ -1463,6 +1467,8 @@ in {
 
   shellingham = callPackage ../development/python-modules/shellingham {};
 
+  simpleaudio = callPackage ../development/python-modules/simpleaudio { };
+
   simpleeval = callPackage ../development/python-modules/simpleeval { };
 
   simple-salesforce = callPackage ../development/python-modules/simple-salesforce { };
@@ -3266,6 +3272,8 @@ in {
 
   peewee =  callPackage ../development/python-modules/peewee { };
 
+  pyroma = callPackage ../development/python-modules/pyroma { };
+
   pyroute2 = callPackage ../development/python-modules/pyroute2 { };
 
   pyspf = callPackage ../development/python-modules/pyspf { };
diff --git a/pkgs/top-level/release-alternatives.nix b/pkgs/top-level/release-alternatives.nix
index eef239d4e0a8..7479377bd302 100644
--- a/pkgs/top-level/release-alternatives.nix
+++ b/pkgs/top-level/release-alternatives.nix
@@ -59,7 +59,7 @@ in
 {
   blas = mapListToAttrs supportedSystems (system': let system = lib.systems.elaborate { system = system'; };
     in mapListToAttrs (blasProviders system) (provider: let
-      is64bit = builtins.elem provider (["mkl64"] ++ lib.optional system.is64bit "openblas");
+      isILP64 = builtins.elem provider (["mkl64"] ++ lib.optional system.is64bit "openblas");
       pkgs = pkgsFun {
         config = { inherit allowUnfree; };
         system = system';
@@ -68,13 +68,13 @@ in
             lapackProvider = if provider == "mkl64"
                              then super.mkl
                              else builtins.getAttr provider super;
-            inherit is64bit;
+            inherit isILP64;
           };
           blas = super.blas.override {
             blasProvider = if provider == "mkl64"
                            then super.mkl
                            else builtins.getAttr provider super;
-            inherit is64bit;
+            inherit isILP64;
           };
         })];
       };