diff --git a/.travis.yml b/.travis.yml
index 54b4ee0..c0ff17a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,7 @@ ghc:
   - 8.4
   - 8.6
   - 8.8
+  - 8.10
 
 before_install:
   - sudo apt-get -qq update
@@ -27,5 +28,5 @@ install:
   - wget https://raw.github.com/ndmitchell/hlint/master/misc/travis.sh
 
 script:
-#  - sh ./travis.sh src
+  - sh ./travis.sh src
   - cabal configure --enable-tests -fall_extensions && cabal build && cabal test
diff --git a/bench/main.hs b/bench/main.hs
new file mode 100644
index 0000000..b6f4c1a
--- /dev/null
+++ b/bench/main.hs
@@ -0,0 +1,32 @@
+{-#LANGUAGE RecordWildCards#-}
+
+import Gauge
+import Xmobar
+import Xmobar.Plugins.Monitors.Common.Types
+import Xmobar.Plugins.Monitors.Common.Run
+import Xmobar.Plugins.Monitors.Cpu
+import Control.Monad.Reader
+import Data.IORef (newIORef)
+
+main :: IO ()
+main = do
+  cpuParams <- mkCpuArgs
+  defaultMain $ normalBench cpuParams
+    where
+      normalBench args = [ bgroup "Cpu Benchmarks" $ normalCpuBench args]
+
+runMonitor :: MConfig -> Monitor a -> IO a
+runMonitor config r = runReaderT r config
+
+mkCpuArgs :: IO CpuArguments
+mkCpuArgs = getArguments ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>%"]
+  
+-- | The action which will be benchmarked
+cpuAction :: CpuArguments -> IO String
+cpuAction = runCpu
+
+cpuBenchmark :: CpuArguments -> Benchmarkable
+cpuBenchmark cpuParams = nfIO $ cpuAction cpuParams
+
+normalCpuBench :: CpuArguments -> [Benchmark]
+normalCpuBench args = [bench "CPU normal args" (cpuBenchmark args)]
diff --git a/changelog.md b/changelog.md
index a88e1ba..eb3f399 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,30 @@
+## Version 0.35.1 (June, 2020)
+
+- Dropped support for GHC < 8.4 (see issue #461)
+
+## Version 0.35 (June, 2020)
+
+_New features_
+
+  - `MultiCoreTemp` now works with Ryzen processors.  New option
+    `--hwmonitor-path` for better performance.
+  - CPU Monitor optimizations.
+  - Version bumps for some dependencies, including timezone-olson.
+
+## Version 0.34 (June, 2020)
+
+_New features_
+
+  - New plugin `HandleReader` for reading data from a Haskell `Handle`. This is
+    useful if you are running xmobar from within a Haskell program.
+  - Build with ghc 8.10 allowed.
+  - Optimize date plugin by avoiding calling getTimeZone for each of
+    the time the date has to be updated. Instead, it's computed once
+    at the start and re-used for each invocation.
+  - Optimize Weather and UVMeter plugin by using global Manager
+    instead of creating for each http request when useManager is
+    explicitly configured as False.
+
 ## Version 0.33 (February, 2020)
 
 _New features_
diff --git a/debian/changelog b/debian/changelog
index 38df16e..6d9f18a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+xmobar (0.35.1-1) UNRELEASED; urgency=medium
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 02 Jul 2020 03:24:00 +0000
+
 xmobar (0.33-1) unstable; urgency=medium
 
   * New upstream version
diff --git a/debian/patches/0001-Fix-typo-in-src-Parsers.hs-fix-lintian-warning.patch b/debian/patches/0001-Fix-typo-in-src-Parsers.hs-fix-lintian-warning.patch
index 8712ce3..5bc9b4b 100644
--- a/debian/patches/0001-Fix-typo-in-src-Parsers.hs-fix-lintian-warning.patch
+++ b/debian/patches/0001-Fix-typo-in-src-Parsers.hs-fix-lintian-warning.patch
@@ -6,9 +6,11 @@ Subject: Fix typo in src/Parsers.hs (fix lintian warning)
  src/Parsers.hs |    2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
---- a/src/Xmobar/Config/Parse.hs
-+++ b/src/Xmobar/Config/Parse.hs
-@@ -167,7 +167,7 @@
+Index: xmobar/src/Xmobar/Config/Parse.hs
+===================================================================
+--- xmobar.orig/src/Xmobar/Config/Parse.hs
++++ xmobar/src/Xmobar/Config/Parse.hs
+@@ -167,7 +167,7 @@ parseConfig defaultConfig =
  commandsErr :: String
  commandsErr = "commands: this usually means that a command could not" ++
                "\nbe parsed." ++
diff --git a/readme.md b/readme.md
index 7afac44..a08268d 100644
--- a/readme.md
+++ b/readme.md
@@ -798,11 +798,14 @@ specification, such as `("clear", "<icon=weather-clear.xbm/>")`.
 - Args: default monitor arguments, plus:
   - `--rx-icon-pattern`: dynamic string for reception rate in `rxipat`.
   - `--tx-icon-pattern`: dynamic string for transmission rate in `txipat`.
+  - `--up`: string used for the `up` variable value when the
+    interface is up.
 - Variables that can be used with the `-t`/`--template` argument:
   `dev`, `rx`, `tx`, `rxbar`, `rxvbar`, `rxipat`, `txbar`, `txvbar`,
-  `txipat`. Reception and transmission rates (`rx` and `tx`) are displayed
-  by default as Kb/s, without any suffixes, but you can set the `-S` to
-  "True" to make them displayed with adaptive units (Kb/s, Mb/s, etc.).
+  `txipat`, `up`. Reception and transmission rates (`rx` and `tx`) are
+  displayed by default as Kb/s, without any suffixes, but you can set
+  the `-S` to "True" to make them displayed with adaptive units (Kb/s,
+  Mb/s, etc.).
 - Default template: `<dev>: <rx>KB|<tx>KB`
 
 ### `DynNetwork Args RefreshRate`
@@ -1132,6 +1135,15 @@ more than one battery.
     limit for percentage calculation.
   - `--maxtemp`: temperature in degree Celsius, that sets the upper
     limit for percentage calculation.
+  - `--hwmonitor-path`: this monitor tries to find coretemp devices by
+    looking for them in directories following the pattern
+    `/sys/bus/platform/devices/coretemp.*/hwmon/hwmon*`, but some
+    processors (notably Ryzen) might expose those files in a different
+    tree (e.g., Ryzen) puts them somewhere in
+    "/sys/class/hwmon/hwmon*", and the lookup is most costly.  With
+    this option, it is possible to explicitly specify the full path to
+    the directory where the `tempN_label` and `tempN_input` files are
+    located.
 - Thresholds refer to temperature in degree Celsius
 - Variables that can be used with the `-t`/`--template` argument:
             `max`, `maxpc`, `maxbar`, `maxvbar`, `maxipat`,
@@ -1147,7 +1159,7 @@ more than one battery.
 
          Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%",
                             "-L", "60", "-H", "80",
-                            "-l", "green", "-n", "yellow", "-h", "red"
+                            "-l", "green", "-n", "yellow", "-h", "red",
                             "--", "--mintemp", "20", "--maxtemp", "100"] 50
 
 ### `Volume Mixer Element Args RefreshRate`
@@ -1610,6 +1622,23 @@ will display "N/A" if for some reason the `date` invocation fails.
           logHook = dynamicLogString myPP >>= xmonadPropLog
         }
 
+### `HandleReader Handle Alias`
+
+- Display data from a Haskell `Handle`
+- This plugin is only useful if you are running xmobar from another Haskell
+  program like XMonad.
+- You can use `System.Process.createPipe` to create a pair of `read` & `write`
+  Handles. Pass the `read` Handle to HandleReader and write your output to the
+  `write` Handle:
+
+        (readHandle, writeHandle) <- createPipe
+        xmobarProcess <- forkProcess $ xmobar myConfig
+                { commands =
+                    Run (HandleReader readHandle "handle") : commands myConfig
+                }
+        hPutStr writeHandle "Hello World"
+
+
 # Plugins
 
 ## Writing a Plugin
@@ -1697,14 +1726,14 @@ Jochen Keil, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry
 Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber, Dmitry
 Malikov, David McLean, Marcin Mikołajczyk, Dino Morelli, Tony Morris,
 Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner,
-Jens Petersen, Alexander Polakov, Pavan Rikhi, Petr Rockai, Andrew
-Emmanuel Rosa, Sackville-West, Markus Scherer, Daniel Schüssler,
-Olivier Schneider, Alexander Shabalin, Valentin Shirokov, Peter
-Simons, Alexander Solovyov, Will Song, John Soros, Felix Springer,
-Travis Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar,
-Sergei Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton
-Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Edward Z. Yang
-and Norbert Zeh.
+Jens Petersen, Alexander Polakov, Sibi Prabakaran, Pavan Rikhi, Petr
+Rockai, Andrew Emmanuel Rosa, Sackville-West, Markus Scherer, Daniel
+Schüssler, Olivier Schneider, Alexander Shabalin, Valentin Shirokov,
+Peter Simons, Alexander Solovyov, Will Song, John Soros, Felix
+Springer, Travis Staton, Artem Tarasov, Samuli Thomasson, Edward
+Tjörnhammar, Sergei Trofimovich, Thomas Tuegel, John Tyree, Jan
+Vornberger, Anton Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun
+Hu, Edward Z. Yang and Norbert Zeh.
 
 [jao]: http://jao.io
 [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors
@@ -1741,7 +1770,7 @@ giving me the chance to contribute.
 This software is released under a BSD-style license. See [LICENSE] for
 more details.
 
-Copyright &copy; 2010-2019 Jose Antonio Ortega Ruiz
+Copyright &copy; 2010-2020 Jose Antonio Ortega Ruiz
 
 Copyright &copy; 2007-2010 Andrea Rossato
 
diff --git a/src/Xmobar.hs b/src/Xmobar.hs
index 491aa8d..d2e4126 100644
--- a/src/Xmobar.hs
+++ b/src/Xmobar.hs
@@ -32,6 +32,7 @@ module Xmobar (xmobar
               , module Xmobar.Plugins.DateZone
 #endif
               , module Xmobar.Plugins.EWMH
+              , module Xmobar.Plugins.HandleReader
               , module Xmobar.Plugins.Kbd
               , module Xmobar.Plugins.Locks
 #ifdef INOTIFY
@@ -57,6 +58,7 @@ import Xmobar.Plugins.Date
 import Xmobar.Plugins.DateZone
 #endif
 import Xmobar.Plugins.EWMH
+import Xmobar.Plugins.HandleReader
 import Xmobar.Plugins.Kbd
 import Xmobar.Plugins.Locks
 #ifdef INOTIFY
diff --git a/src/Xmobar/App/EventLoop.hs b/src/Xmobar/App/EventLoop.hs
index f6ab932..cad95a5 100644
--- a/src/Xmobar/App/EventLoop.hs
+++ b/src/Xmobar/App/EventLoop.hs
@@ -40,6 +40,7 @@ import Control.Exception (bracket_, handle, SomeException(..))
 import Data.Bits
 import Data.Map hiding (foldr, map, filter)
 import Data.Maybe (fromJust, isJust)
+import qualified Data.List.NonEmpty as NE
 
 import Xmobar.System.Signal
 import Xmobar.Config.Types
@@ -52,6 +53,7 @@ import Xmobar.X11.Text
 import Xmobar.X11.Draw
 import Xmobar.X11.Bitmap as Bitmap
 import Xmobar.X11.Types
+import Xmobar.System.Utils (safeIndex)
 
 #ifndef THREADED_RUNTIME
 import Xmobar.X11.Events(nextEvent')
@@ -208,7 +210,7 @@ eventLoop tv xc@(XConf d r w fs vos is cfg) as signal = do
             eventLoop tv xc as signal
 
         reposWindow rcfg = do
-          r' <- repositionWin d w (head fs) rcfg
+          r' <- repositionWin d w (NE.head fs) rcfg
           eventLoop tv (XConf d r' w fs vos is rcfg) as signal
 
         updateConfigPosition ocfg =
@@ -262,7 +264,7 @@ updateActions conf (Rectangle _ _ wid _) ~[left,center,right] = do
       strLn :: [(Widget, String, Int, Maybe [Action])] -> IO [(Maybe [Action], Position, Position)]
       strLn  = liftIO . mapM getCoords
       iconW i = maybe 0 Bitmap.width (lookup i $ iconS conf)
-      getCoords (Text s,_,i,a) = textWidth d (fs!!i) s >>= \tw -> return (a, 0, fi tw)
+      getCoords (Text s,_,i,a) = textWidth d (safeIndex fs i) s >>= \tw -> return (a, 0, fi tw)
       getCoords (Icon s,_,_,a) = return (a, 0, fi $ iconW s)
       partCoord off xs = map (\(a, x, x') -> (fromJust a, x, x')) $
                          filter (\(a, _,_) -> isJust a) $
diff --git a/src/Xmobar/App/Main.hs b/src/Xmobar/App/Main.hs
index e0b0329..f173e12 100644
--- a/src/Xmobar/App/Main.hs
+++ b/src/Xmobar/App/Main.hs
@@ -29,6 +29,7 @@ import System.Environment (getArgs)
 import System.FilePath
 import System.FilePath.Posix (takeBaseName, takeDirectory)
 import Text.Parsec.Error (ParseError)
+import Data.List.NonEmpty (NonEmpty(..))
 
 import Graphics.X11.Xlib
 
@@ -63,7 +64,7 @@ xmobar conf = withDeferSignals $ do
       let ic = Map.empty
           to = textOffset conf
           ts = textOffsets conf ++ replicate (length fl) (-1)
-      startLoop (XConf d r w (fs:fl) (to:ts) ic conf) sig refLock vars
+      startLoop (XConf d r w (fs :| fl) (to:ts) ic conf) sig refLock vars
 
 configFromArgs :: Config -> IO Config
 configFromArgs cfg = getArgs >>= getOpts >>= doOpts cfg . fst
diff --git a/src/Xmobar/App/Opts.hs b/src/Xmobar/App/Opts.hs
index dfb2f23..5015546 100644
--- a/src/Xmobar/App/Opts.hs
+++ b/src/Xmobar/App/Opts.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.App.Opts
--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -104,9 +104,9 @@ usage = usageInfo header options ++ footer
 
 info :: String
 info = "xmobar " ++ showVersion version
-        ++ "\n (C) 2007 - 2010 Andrea Rossato "
-        ++ "\n (C) 2010 - 2019 Jose A Ortega Ruiz\n "
-        ++ mail ++ "\n" ++ license
+        ++ "\n (C) 2010 - 2020 Jose A Ortega Ruiz"
+        ++ "\n (C) 2007 - 2010 Andrea Rossato\n "
+        ++ mail ++ "\n" ++ license ++ "\n"
 
 mail :: String
 mail = "<mail@jao.io>"
diff --git a/src/Xmobar/Plugins/BufferedPipeReader.hs b/src/Xmobar/Plugins/BufferedPipeReader.hs
index f98d0d4..cf5a071 100644
--- a/src/Xmobar/Plugins/BufferedPipeReader.hs
+++ b/src/Xmobar/Plugins/BufferedPipeReader.hs
@@ -23,7 +23,6 @@ import System.IO.Unsafe(unsafePerformIO)
 import Xmobar.Run.Exec
 import Xmobar.System.Signal
 import Xmobar.System.Environment
-import Xmobar.System.Utils(hGetLineSafe)
 
 data BufferedPipeReader = BufferedPipeReader String [(Int, Bool, String)]
     deriving (Read, Show)
@@ -55,7 +54,7 @@ instance Exec BufferedPipeReader where
         reader :: (Int, Bool, FilePath) -> TChan (Int, Bool, String) -> IO ()
         reader p@(to, tg, fp) tc = do
             fp' <- expandEnv fp
-            openFile fp' ReadWriteMode >>= hGetLineSafe >>= \dt ->
+            openFile fp' ReadWriteMode >>= hGetLine >>= \dt ->
                 atomically $ writeTChan tc (to, tg, dt)
             reader p tc
 
diff --git a/src/Xmobar/Plugins/CommandReader.hs b/src/Xmobar/Plugins/CommandReader.hs
index 9cf6d0e..a54377a 100644
--- a/src/Xmobar/Plugins/CommandReader.hs
+++ b/src/Xmobar/Plugins/CommandReader.hs
@@ -17,7 +17,6 @@ module Xmobar.Plugins.CommandReader(CommandReader(..)) where
 
 import System.IO
 import Xmobar.Run.Exec
-import Xmobar.System.Utils (hGetLineSafe)
 import System.Process(runInteractiveCommand, getProcessExitCode)
 
 data CommandReader = CommandReader String String
@@ -31,7 +30,7 @@ instance Exec CommandReader where
         hClose hstderr
         hSetBinaryMode hstdout False
         hSetBuffering hstdout LineBuffering
-        forever ph (hGetLineSafe hstdout >>= cb)
+        forever ph (hGetLine hstdout >>= cb)
         where forever ph a =
                   do a
                      ec <- getProcessExitCode ph
diff --git a/src/Xmobar/Plugins/Date.hs b/src/Xmobar/Plugins/Date.hs
index 1cb0596..83ca1c9 100644
--- a/src/Xmobar/Plugins/Date.hs
+++ b/src/Xmobar/Plugins/Date.hs
@@ -31,8 +31,16 @@ data Date = Date String String Int
 
 instance Exec Date where
     alias (Date _ a _) = a
-    run   (Date f _ _) = date f
     rate  (Date _ _ r) = r
+    start (Date f _ r) cb = do
+      t <- getCurrentTime
+      zone <- getTimeZone t
+      go zone
+     where
+      go zone = doEveryTenthSeconds r $ date zone f >>= cb
 
-date :: String -> IO String
-date format = fmap (formatTime defaultTimeLocale format) getZonedTime
+date :: TimeZone -> String -> IO String
+date timezone format = do
+  time <- getCurrentTime
+  let zonedTime = utcToZonedTime timezone time
+  pure $ formatTime defaultTimeLocale format zonedTime
diff --git a/src/Xmobar/Plugins/HandleReader.hs b/src/Xmobar/Plugins/HandleReader.hs
new file mode 100644
index 0000000..4e5c30e
--- /dev/null
+++ b/src/Xmobar/Plugins/HandleReader.hs
@@ -0,0 +1,70 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.HandleReader
+-- Copyright   :  (c) Pavan Rikhi
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Pavan Rikhi <pavan.rikhi@gmail.com>
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- A plugin for reading from 'Handle's
+--
+-----------------------------------------------------------------------------
+
+module Xmobar.Plugins.HandleReader
+    ( HandleReader(..)
+    )
+where
+
+import           System.IO                      ( Handle
+                                                , hIsEOF
+                                                , hGetLine
+                                                )
+
+import           Xmobar.Run.Exec                ( Exec(..) )
+
+
+-- | A HandleReader displays any text received from a Handle.
+--
+-- This is only useful if you are running @xmobar@ from other Haskell code.
+-- You can create a pair of @(read, write)@ 'Handle's using
+-- 'System.Process.createPipe'. Pass the @read@ 'Handle' to HandleReader
+-- and write your desired output to the @write@ 'Handle'.
+--
+-- @
+--  (readHandle, writeHandle) <- 'System.Process.createPipe'
+--  xmobarProcess <- 'System.Posix.Process.forkProcess' $ 'Xmobar.xmobar' myConfig
+--          { commands =
+--              'Xmobar.Run' ('HandleReader' readHandle "handle") : 'Xmobar.commands' myConfig
+--          }
+--  'System.IO.hPutStr' writeHandle "Hello World"
+-- @
+data HandleReader
+    = HandleReader
+        Handle
+        -- ^ The Handle to read from.
+        String
+        -- ^ Alias for the HandleReader
+    deriving (Show)
+
+-- | WARNING: This Read instance will throw an exception if used! It is
+-- only implemented because it is required to use HandleReader with
+-- 'Xmobar.Run' in 'Xmobar.commands'.
+instance Read HandleReader where
+    -- | Throws an 'error'!
+    readsPrec = error "HandleReader: Read instance is stub"
+
+-- | Asynchronously read from the 'Handle'.
+instance Exec HandleReader where
+    -- | Read from the 'Handle' until it is closed.
+    start (HandleReader handle _) cb =
+        untilM (hIsEOF handle) $ hGetLine handle >>= cb
+    -- | Use the 2nd argument to HandleReader as its alias.
+    alias (HandleReader _ a) = a
+
+-- Loop the action until predicateM returns True.
+untilM :: Monad m => m Bool -> m () -> m ()
+untilM predicateM action = do
+    predicate <- predicateM
+    if predicate then return () else action >> untilM predicateM action
diff --git a/src/Xmobar/Plugins/MarqueePipeReader.hs b/src/Xmobar/Plugins/MarqueePipeReader.hs
index 084331b..f1fdee0 100644
--- a/src/Xmobar/Plugins/MarqueePipeReader.hs
+++ b/src/Xmobar/Plugins/MarqueePipeReader.hs
@@ -14,10 +14,9 @@
 
 module Xmobar.Plugins.MarqueePipeReader(MarqueePipeReader(..)) where
 
-import System.IO (openFile, IOMode(ReadWriteMode), Handle)
+import System.IO (openFile, IOMode(ReadWriteMode), Handle, hGetLine)
 import Xmobar.System.Environment
 import Xmobar.Run.Exec(Exec(alias, start), tenthSeconds)
-import Xmobar.System.Utils(hGetLineSafe)
 import System.Posix.Files (getFileStatus, isNamedPipe)
 import Control.Concurrent(forkIO, threadDelay)
 import Control.Concurrent.STM (TChan, atomically, writeTChan, tryReadTChan, newTChan)
@@ -39,7 +38,7 @@ instance Exec MarqueePipeReader where
         unless (null def) (cb def)
         checkPipe pipe
         h <- openFile pipe ReadWriteMode
-        line <- hGetLineSafe h
+        line <- hGetLine h
         chan <- atomically newTChan
         forkIO $ writer (toInfTxt line sep) sep len rate chan cb
         forever $ pipeToChan h chan
@@ -50,7 +49,7 @@ instance Exec MarqueePipeReader where
 
 pipeToChan :: Handle -> TChan String -> IO ()
 pipeToChan h chan = do
-    line <- hGetLineSafe h
+    line <- hGetLine h
     atomically $ writeTChan chan line
 
 writer :: String -> Separator -> Length -> Rate -> TChan String -> (String -> IO ()) -> IO ()
diff --git a/src/Xmobar/Plugins/Monitors/Common/Output.hs b/src/Xmobar/Plugins/Monitors/Common/Output.hs
index 7a14a74..c41ef19 100644
--- a/src/Xmobar/Plugins/Monitors/Common/Output.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Output.hs
@@ -1,3 +1,5 @@
+{-#LANGUAGE RecordWildCards#-}
+
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Plugins.Monitors.Strings
@@ -37,6 +39,11 @@ module Xmobar.Plugins.Monitors.Common.Output ( IconPattern
                                              , parseFloat
                                              , parseInt
                                              , stringParser
+                                             , pShowPercentsWithColors
+                                             , pShowPercentBar
+                                             , pShowVerticalBar
+                                             , pShowIconPattern
+                                             , pShowPercentWithColors
                                              ) where
 
 import Data.Char
@@ -44,11 +51,64 @@ import Data.List (intercalate, sort)
 import qualified Data.ByteString.Lazy.Char8 as B
 import Numeric
 import Control.Monad (zipWithM)
-
+import Control.Monad.IO.Class (MonadIO(..))
 import Xmobar.Plugins.Monitors.Common.Types
 
 type IconPattern = Int -> String
 
+pShowVerticalBar :: (MonadIO m) => MonitorConfig -> Float -> Float -> m String
+pShowVerticalBar p v x = pColorizeString p v [convert $ 100 * x]
+  where convert :: Float -> Char
+        convert val
+          | t <= 9600 = ' '
+          | t > 9608 = chr 9608
+          | otherwise = chr t
+          where t = 9600 + (round val `div` 12)
+
+pShowPercentsWithColors :: (MonadIO m) => MonitorConfig -> [Float] -> m [String]
+pShowPercentsWithColors p fs =
+  do let fstrs = map (pFloatToPercent p) fs
+         temp = map (*100) fs
+     zipWithM (pShowWithColors p . const) fstrs temp
+
+pShowPercentWithColors :: (MonadIO m) => MonitorConfig -> Float -> m String
+pShowPercentWithColors p f = fmap head $ pShowPercentsWithColors p [f]
+
+pShowPercentBar :: (MonadIO m) => MonitorConfig -> Float -> Float -> m String
+pShowPercentBar p@MonitorConfig{..} v x = do
+  let len = min pBarWidth $ round (fromIntegral pBarWidth * x)
+  s <- pColorizeString p v (take len $ cycle pBarFore)
+  return $ s ++ take (pBarWidth - len) (cycle pBarBack)
+
+pShowWithColors :: (Num a, Ord a, MonadIO m) => MonitorConfig -> (a -> String) -> a -> m String
+pShowWithColors p f x = do
+  let str = pShowWithPadding p (f x)
+  pColorizeString p x str
+
+pColorizeString :: (Num a, Ord a, MonadIO m) => MonitorConfig -> a -> String -> m String
+pColorizeString p x s = do
+    let col = pSetColor p s
+        [ll,hh] = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low
+    pure $ head $ [col pHighColor   | x > hh ] ++
+                  [col pNormalColor | x > ll ] ++
+                  [col pLowColor    | True]
+
+pSetColor :: MonitorConfig -> String -> PSelector (Maybe String) -> String
+pSetColor config str s =
+    do let a = getPConfigValue config s
+       case a of
+            Nothing -> str
+            Just c -> "<fc=" ++ c ++ ">" ++ str ++ "</fc>"
+
+pShowWithPadding :: MonitorConfig -> String -> String
+pShowWithPadding MonitorConfig {..} =
+  padString pMinWidth pMaxWidth pPadChars pPadRight pMaxWidthEllipsis
+
+pFloatToPercent :: MonitorConfig -> Float -> String
+pFloatToPercent MonitorConfig{..} n = let p = showDigits 0 (n * 100)
+                                          ps = if pUseSuffix then "%" else ""
+                                      in padString pPpad pPpad pPadChars pPadRight "" p ++ ps
+
 parseIconPattern :: String -> IconPattern
 parseIconPattern path =
     let spl = splitOnPercent path
@@ -174,6 +234,15 @@ showIconPattern (Just str) x = return $ str $ convert $ 100 * x
           | otherwise = t
           where t = round val `div` 12
 
+pShowIconPattern :: Maybe IconPattern -> Float -> IO String
+pShowIconPattern Nothing _ = return ""
+pShowIconPattern (Just str) x = return $ str $ convert $ 100 * x
+  where convert val
+          | t <= 0 = 0
+          | t > 8 = 8
+          | otherwise = t
+          where t = round val `div` 12
+
 showVerticalBar :: Float -> Float -> Monitor String
 showVerticalBar v x = colorizeString v [convert $ 100 * x]
   where convert :: Float -> Char
diff --git a/src/Xmobar/Plugins/Monitors/Common/Parsers.hs b/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
index 7a813e5..db2a652 100644
--- a/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
@@ -1,3 +1,6 @@
+{-#LANGUAGE RecordWildCards#-}
+{-#LANGUAGE ScopedTypeVariables#-}
+
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Plugins.Monitors.Parsers
@@ -25,6 +28,10 @@ module Xmobar.Plugins.Monitors.Common.Parsers ( runP
                                               , parseTemplate
                                               , parseTemplate'
                                               , parseOptsWith
+                                              , templateParser
+                                              , runExportParser
+                                              , runTemplateParser
+                                              , pureParseTemplate
                                               ) where
 
 import Xmobar.Plugins.Monitors.Common.Types
@@ -34,6 +41,35 @@ import qualified Data.Map as Map
 import System.Console.GetOpt (ArgOrder(Permute), OptDescr, getOpt)
 import Text.ParserCombinators.Parsec
 
+runTemplateParser :: MonitorConfig -> IO [(String, String, String)]
+runTemplateParser MonitorConfig{..} = runP templateParser pTemplate
+
+runExportParser :: [String] -> IO [(String, [(String, String,String)])]
+runExportParser [] = pure []
+runExportParser (x:xs) = do
+  s <- runP templateParser x
+  rest <- runExportParser xs
+  pure $ (x,s):rest
+
+pureParseTemplate :: MonitorConfig -> TemplateInput -> IO String
+pureParseTemplate MonitorConfig{..} TemplateInput{..} =
+    do let m = let expSnds :: [([(String, String, String)], String)]  = zip (map snd temAllTemplate) temMonitorValues
+               in Map.fromList $ zip (map fst temAllTemplate) expSnds
+       s <- minCombine m temInputTemplate
+       let (n, s') = if pMaxTotalWidth > 0 && length s > pMaxTotalWidth
+                     then trimTo (pMaxTotalWidth - length pMaxTotalWidthEllipsis) "" s
+                     else (1, s)
+       return $ if n > 0 then s' else s' ++ pMaxTotalWidthEllipsis
+
+minCombine :: Map.Map String ([(String, String, String)], String) -> [(String, String, String)] -> IO String
+minCombine _ [] = return []
+minCombine m ((s,ts,ss):xs) =
+    do next <- minCombine m xs
+       str <- case Map.lookup ts m of
+         Nothing -> return $ "<" ++ ts ++ ">"
+         Just (s',r) -> let f "" = r; f n = n; in f <$> minCombine m s'
+       pure $ s ++ str ++ ss ++ next
+
 runP :: Parser [a] -> String -> IO [a]
 runP p i =
     case parse p "" i of
diff --git a/src/Xmobar/Plugins/Monitors/Common/Run.hs b/src/Xmobar/Plugins/Monitors/Common/Run.hs
index 3baa7aa..188b02a 100644
--- a/src/Xmobar/Plugins/Monitors/Common/Run.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Run.hs
@@ -22,6 +22,9 @@ module Xmobar.Plugins.Monitors.Common.Run ( runM
                                           , runML
                                           , runMLD
                                           , getArgvs
+                                          , doArgs
+                                          , computeMonitorConfig
+                                          , pluginOptions
                                           ) where
 
 import Control.Exception (SomeException,handle)
@@ -32,11 +35,11 @@ import System.Console.GetOpt
 import Xmobar.Plugins.Monitors.Common.Types
 import Xmobar.Run.Exec (doEveryTenthSeconds)
 
-options :: [OptDescr Opts]
-options =
+pluginOptions :: [OptDescr Opts]
+pluginOptions =
     [
-      Option "H" ["High"] (ReqArg High "number") "The high threshold"
-    , Option "L" ["Low"] (ReqArg Low "number") "The low threshold"
+      Option ['H'] ["High"] (ReqArg High "number") "The high threshold"
+    , Option ['L'] ["Low"] (ReqArg Low "number") "The low threshold"
     , Option "h" ["high"] (ReqArg HighColor "color number") "Color for the high threshold: ex \"#FF0000\""
     , Option "n" ["normal"] (ReqArg NormalColor "color number") "Color for the normal threshold: ex \"#00FF00\""
     , Option "l" ["low"] (ReqArg LowColor "color number") "Color for the low threshold: ex \"#0000FF\""
@@ -61,16 +64,18 @@ options =
 -- | Get all argument values out of a list of arguments.
 getArgvs :: [String] -> [String]
 getArgvs args =
-    case getOpt Permute options args of
+    case getOpt Permute pluginOptions args of
         (_, n, []  ) -> n
         (_, _, errs) -> errs
 
+
+
 doArgs :: [String]
        -> ([String] -> Monitor String)
        -> ([String] -> Monitor Bool)
        -> Monitor String
 doArgs args action detect =
-    case getOpt Permute options args of
+    case getOpt Permute pluginOptions args of
       (o, n, [])   -> do doConfigOptions o
                          ready <- detect n
                          if ready
@@ -139,3 +144,18 @@ runMLD args conf action looper detect cb = handle (cb . showException) loop
 
 showException :: SomeException -> String
 showException = ("error: "++) . show . flip asTypeOf undefined
+
+computeMonitorConfig :: [String] -> IO MConfig -> IO MonitorConfig
+computeMonitorConfig args mconfig = do
+  newConfig <- getMConfig args mconfig
+  getMonitorConfig newConfig
+
+getMConfig :: [String] -> IO MConfig -> IO MConfig
+getMConfig args mconfig = do
+  config <- mconfig
+  runReaderT (updateOptions args >> ask) config
+
+updateOptions :: [String] -> Monitor ()
+updateOptions args= case getOpt Permute pluginOptions args of
+                      (o, _, []) -> doConfigOptions o
+                      _ -> return ()
diff --git a/src/Xmobar/Plugins/Monitors/Common/Types.hs b/src/Xmobar/Plugins/Monitors/Common/Types.hs
index fc71da3..d09da8e 100644
--- a/src/Xmobar/Plugins/Monitors/Common/Types.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Types.hs
@@ -1,3 +1,5 @@
+{-#LANGUAGE RecordWildCards#-}
+
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Plugins.Monitors.Types
@@ -20,9 +22,14 @@ module Xmobar.Plugins.Monitors.Common.Types ( Monitor
                                             , Opts (..)
                                             , Selector
                                             , setConfigValue
-                                            , getConfigValue
                                             , mkMConfig
                                             , io
+                                            , MonitorConfig (..)
+                                            , getPConfigValue
+                                            , getConfigValue
+                                            , getMonitorConfig
+                                            , PSelector
+                                            , TemplateInput(..)
                                             ) where
 
 import Control.Monad.Reader (ReaderT, ask, liftIO)
@@ -34,6 +41,12 @@ type Monitor a = ReaderT MConfig IO a
 io :: IO a -> Monitor a
 io = liftIO
 
+data TemplateInput = TemplateInput {
+      temMonitorValues :: [String],
+      temInputTemplate :: [(String, String, String)],
+      temAllTemplate :: [(String, [(String, String, String)])]
+    }
+
 data MConfig =
     MC { normalColor :: IORef (Maybe String)
        , low :: IORef Int
@@ -58,8 +71,63 @@ data MConfig =
        , maxTotalWidthEllipsis :: IORef String
        }
 
+data MonitorConfig =
+  MonitorConfig
+    { pNormalColor :: Maybe String
+    , pLow :: Int
+    , pLowColor :: Maybe String
+    , pHigh :: Int
+    , pHighColor :: Maybe String
+    , pTemplate :: String
+    , pExport :: [String]
+    , pPpad :: Int
+    , pDecDigits :: Int
+    , pMinWidth :: Int
+    , pMaxWidth :: Int
+    , pMaxWidthEllipsis :: String
+    , pPadChars :: String
+    , pPadRight :: Bool
+    , pBarBack :: String
+    , pBarFore :: String
+    , pBarWidth :: Int
+    , pUseSuffix :: Bool
+    , pNaString :: String
+    , pMaxTotalWidth :: Int
+    , pMaxTotalWidthEllipsis :: String
+    }
+  deriving (Eq, Ord)
+
+getMonitorConfig :: MConfig -> IO MonitorConfig
+getMonitorConfig MC{..} = do
+  pNormalColor <- readIORef normalColor
+  pLow <- readIORef low
+  pLowColor <- readIORef lowColor
+  pHigh <- readIORef high
+  pHighColor <- readIORef highColor
+  pTemplate <- readIORef template
+  pExport <- readIORef export
+  pPpad <- readIORef ppad
+  pDecDigits <- readIORef decDigits
+  pMinWidth <- readIORef minWidth
+  pMaxWidth <- readIORef maxWidth
+  pMaxWidthEllipsis <- readIORef maxWidthEllipsis
+  pPadChars <- readIORef padChars
+  pPadRight <- readIORef padRight
+  pBarBack <- readIORef barBack
+  pBarFore <- readIORef barFore
+  pBarWidth <- readIORef barWidth
+  pUseSuffix <- readIORef useSuffix 
+  pNaString <- readIORef naString
+  pMaxTotalWidth <- readIORef maxTotalWidth
+  pMaxTotalWidthEllipsis <- readIORef maxTotalWidthEllipsis
+  pure $ MonitorConfig {..}
+
 -- | from 'http:\/\/www.haskell.org\/hawiki\/MonadState'
 type Selector a = MConfig -> IORef a
+type PSelector a = MonitorConfig -> a
+
+psel :: MonitorConfig -> PSelector a -> a
+psel value accessor = accessor value
 
 sel :: Selector a -> Monitor a
 sel s =
@@ -78,6 +146,9 @@ setConfigValue v s =
 getConfigValue :: Selector a -> Monitor a
 getConfigValue = sel
 
+getPConfigValue :: MonitorConfig -> PSelector a -> a
+getPConfigValue = psel
+
 mkMConfig :: String
           -> [String]
           -> IO MConfig
diff --git a/src/Xmobar/Plugins/Monitors/Cpu.hs b/src/Xmobar/Plugins/Monitors/Cpu.hs
index 157631d..895eeb3 100644
--- a/src/Xmobar/Plugins/Monitors/Cpu.hs
+++ b/src/Xmobar/Plugins/Monitors/Cpu.hs
@@ -1,3 +1,5 @@
+{-#LANGUAGE RecordWildCards#-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Cpu
@@ -13,12 +15,23 @@
 --
 -----------------------------------------------------------------------------
 
-module Xmobar.Plugins.Monitors.Cpu (startCpu) where
+module Xmobar.Plugins.Monitors.Cpu
+  ( startCpu
+  , runCpu
+  , cpuConfig
+  , CpuDataRef
+  , CpuOpts
+  , CpuArguments
+  , parseCpu
+  , getArguments
+  ) where
 
 import Xmobar.Plugins.Monitors.Common
 import qualified Data.ByteString.Lazy.Char8 as B
 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
 import System.Console.GetOpt
+import Xmobar.App.Timer (doEveryTenthSeconds)
+import Control.Monad (void)
 
 newtype CpuOpts = CpuOpts
   { loadIconPattern :: Maybe IconPattern
@@ -35,48 +48,206 @@ options =
      o { loadIconPattern = Just $ parseIconPattern x }) "") ""
   ]
 
+barField :: String
+barField = "bar"
+
+vbarField :: String
+vbarField = "vbar"
+
+ipatField :: String
+ipatField = "ipat"
+
+totalField :: String
+totalField = "total"
+
+userField :: String
+userField = "user"
+
+niceField :: String
+niceField = "nice"
+
+systemField :: String
+systemField = "system"
+
+idleField :: String
+idleField = "idle"
+
+iowaitField :: String
+iowaitField = "iowait"
+
 cpuConfig :: IO MConfig
-cpuConfig = mkMConfig
-       "Cpu: <total>%"
-       ["bar","vbar","ipat","total","user","nice","system","idle","iowait"]
+cpuConfig =
+  mkMConfig
+    "Cpu: <total>%"
+    [ barField
+    , vbarField
+    , ipatField
+    , totalField
+    , userField
+    , niceField
+    , systemField
+    , idleField
+    , iowaitField
+    ]
 
 type CpuDataRef = IORef [Int]
 
+-- Details about the fields here: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
 cpuData :: IO [Int]
-cpuData = cpuParser `fmap` B.readFile "/proc/stat"
+cpuData = cpuParser <$> B.readFile "/proc/stat"
+
+readInt :: B.ByteString -> Int
+readInt bs = case B.readInt bs of
+               Nothing -> 0
+               Just (i, _) -> i
 
 cpuParser :: B.ByteString -> [Int]
-cpuParser = map (read . B.unpack) . tail . B.words . head . B.lines
+cpuParser = map readInt . tail . B.words . head . B.lines
+
+data CpuData = CpuData {
+      cpuUser :: !Float,
+      cpuNice :: !Float,
+      cpuSystem :: !Float,
+      cpuIdle :: !Float,
+      cpuIowait :: !Float,
+      cpuTotal :: !Float
+    }
+
+convertToCpuData :: [Float] -> CpuData
+convertToCpuData (u:n:s:ie:iw:_) =
+  CpuData
+    { cpuUser = u
+    , cpuNice = n
+    , cpuSystem = s
+    , cpuIdle = ie
+    , cpuIowait = iw
+    , cpuTotal = sum [u, n, s]
+    }
+convertToCpuData args = error $ "convertToCpuData: Unexpected list" <> show args
 
-parseCpu :: CpuDataRef -> IO [Float]
+parseCpu :: CpuDataRef -> IO CpuData
 parseCpu cref =
     do a <- readIORef cref
        b <- cpuData
        writeIORef cref b
        let dif = zipWith (-) b a
            tot = fromIntegral $ sum dif
-           percent = map ((/ tot) . fromIntegral) dif
-       return percent
-
-formatCpu :: CpuOpts -> [Float] -> Monitor [String]
-formatCpu _ [] = return $ replicate 8 ""
-formatCpu opts xs = do
-  let t = sum $ take 3 xs
-  b <- showPercentBar (100 * t) t
-  v <- showVerticalBar (100 * t) t
-  d <- showIconPattern (loadIconPattern opts) t
-  ps <- showPercentsWithColors (t:xs)
-  return (b:v:d:ps)
-
-runCpu :: CpuDataRef -> [String] -> Monitor String
-runCpu cref argv =
-    do c <- io (parseCpu cref)
-       opts <- io $ parseOptsWith options defaultOpts argv
-       l <- formatCpu opts c
-       parseTemplate l
+           safeDiv n = case tot of
+                         0 -> 0
+                         v -> fromIntegral n / v
+           percent = map safeDiv dif
+       return $ convertToCpuData percent
+
+data Field = Field {
+      fieldName :: !String,
+      fieldCompute :: !ShouldCompute
+    } deriving (Eq, Ord, Show)
+
+data ShouldCompute = Compute | Skip deriving (Eq, Ord, Show)
+
+formatField :: MonitorConfig -> CpuOpts -> CpuData -> Field -> IO String
+formatField cpuParams cpuOpts cpuInfo@CpuData {..} Field {..}
+  | fieldName == barField =
+    if fieldCompute == Compute
+      then pShowPercentBar cpuParams (100 * cpuTotal) cpuTotal
+      else pure []
+  | fieldName == vbarField =
+    if fieldCompute == Compute
+      then pShowVerticalBar cpuParams (100 * cpuTotal) cpuTotal
+      else pure []
+  | fieldName == ipatField =
+    if fieldCompute == Compute
+      then pShowIconPattern (loadIconPattern cpuOpts) cpuTotal
+      else pure []
+  | otherwise =
+    if fieldCompute == Compute
+      then pShowPercentWithColors cpuParams (getFieldValue fieldName cpuInfo)
+      else pure []
+
+getFieldValue :: String -> CpuData -> Float
+getFieldValue field CpuData{..}
+    | field == barField = cpuTotal
+    | field == vbarField = cpuTotal
+    | field == ipatField = cpuTotal
+    | field == totalField = cpuTotal
+    | field == userField = cpuUser
+    | field == niceField = cpuNice
+    | field == systemField = cpuSystem
+    | field == idleField = cpuIdle
+    | otherwise = cpuIowait
+
+computeFields :: [String] -> [String] -> [Field]
+computeFields [] _ = []
+computeFields (x:xs) inputFields =
+  if x `elem` inputFields
+    then (Field {fieldName = x, fieldCompute = Compute}) :
+         computeFields xs inputFields
+    else (Field {fieldName = x, fieldCompute = Skip}) :
+         computeFields xs inputFields
+
+formatCpu :: CpuArguments -> CpuData -> IO [String]
+formatCpu CpuArguments{..} cpuInfo = do
+  strs <- mapM (formatField cpuParams cpuOpts cpuInfo) cpuFields
+  pure $ filter (not . null) strs
+
+getInputFields :: CpuArguments -> [String]
+getInputFields CpuArguments{..} = map (\(_,f,_) -> f) cpuInputTemplate
+
+optimizeAllTemplate :: CpuArguments -> CpuArguments
+optimizeAllTemplate args@CpuArguments {..} =
+  let inputFields = getInputFields args
+      allTemplates =
+        filter (\(field, _) -> field `elem` inputFields) cpuAllTemplate
+   in args {cpuAllTemplate = allTemplates}
+
+data CpuArguments =
+  CpuArguments
+    { cpuDataRef :: !CpuDataRef
+    , cpuParams :: !MonitorConfig
+    , cpuArgs :: ![String]
+    , cpuOpts :: !CpuOpts
+    , cpuInputTemplate :: ![(String, String, String)] -- [("Cpu: ","total","% "),("","user","%")]
+    , cpuAllTemplate :: ![(String, [(String, String, String)])] -- [("bar",[]),("vbar",[]),("ipat",[]),("total",[]),...]
+    , cpuFields :: ![Field]
+    }
+
+
+getArguments :: [String] -> IO CpuArguments
+getArguments cpuArgs = do
+  initCpuData <- cpuData
+  cpuDataRef <- newIORef initCpuData
+  void $ parseCpu cpuDataRef
+  cpuParams <- computeMonitorConfig cpuArgs cpuConfig
+  cpuInputTemplate <- runTemplateParser cpuParams
+  cpuAllTemplate <- runExportParser (pExport cpuParams)
+  nonOptions <-
+    case getOpt Permute pluginOptions cpuArgs of
+      (_, n, []) -> pure n
+      (_, _, errs) -> error $ "getArguments: " <> show errs
+  cpuOpts <-
+    case getOpt Permute options nonOptions of
+      (o, _, []) -> pure $ foldr id defaultOpts o
+      (_, _, errs) -> error $ "getArguments options: " <> show errs
+  let cpuFields =
+        computeFields
+          (map fst cpuAllTemplate)
+          (map (\(_, f, _) -> f) cpuInputTemplate)
+  pure $ optimizeAllTemplate CpuArguments {..}
+
+
+runCpu :: CpuArguments -> IO String
+runCpu args@CpuArguments {..} = do
+  cpuValue <- parseCpu cpuDataRef
+  temMonitorValues <- formatCpu args cpuValue
+  let templateInput =
+        TemplateInput
+          { temInputTemplate = cpuInputTemplate
+          , temAllTemplate = cpuAllTemplate
+          , ..
+          }
+  pureParseTemplate cpuParams templateInput
 
 startCpu :: [String] -> Int -> (String -> IO ()) -> IO ()
-startCpu a r cb = do
-  cref <- newIORef []
-  _ <- parseCpu cref
-  runM a cpuConfig (runCpu cref) r cb
+startCpu args refreshRate cb = do
+  cpuArgs <- getArguments args
+  doEveryTenthSeconds refreshRate (runCpu cpuArgs >>= cb)
diff --git a/src/Xmobar/Plugins/Monitors/MPD.hs b/src/Xmobar/Plugins/Monitors/MPD.hs
index 3274c42..c8c2dc9 100644
--- a/src/Xmobar/Plugins/Monitors/MPD.hs
+++ b/src/Xmobar/Plugins/Monitors/MPD.hs
@@ -20,14 +20,17 @@ import Xmobar.Plugins.Monitors.Common
 import System.Console.GetOpt
 import qualified Network.MPD as M
 import Control.Concurrent (threadDelay)
+import Control.Monad.Except (catchError)
+
+templateVars :: [String]
+templateVars = [ "bar", "vbar", "ipat", "state", "statei", "volume", "length"
+               , "lapsed", "remaining", "plength", "ppos", "flags", "file"
+               , "name", "artist", "composer", "performer"
+               , "album", "title", "track", "genre", "date"
+               ]
 
 mpdConfig :: IO MConfig
-mpdConfig = mkMConfig "MPD: <state>"
-              [ "bar", "vbar", "ipat", "state", "statei", "volume", "length"
-              , "lapsed", "remaining", "plength", "ppos", "flags", "file"
-              , "name", "artist", "composer", "performer"
-              , "album", "title", "track", "genre", "date"
-              ]
+mpdConfig = mkMConfig "MPD: <state>" templateVars
 
 data MOpts = MOpts
   { mPlaying :: String
@@ -60,7 +63,8 @@ options =
   ]
 
 withMPD :: MOpts -> M.MPD a -> IO (M.Response a)
-withMPD opts = M.withMPD_ (mHost opts) (mPort opts)
+withMPD opts a =
+  M.withMPD_ (mHost opts) (mPort opts) a `catchError` (\_ -> return (Left M.NoMPD))
 
 runMPD :: [String] -> Monitor String
 runMPD args = do
@@ -74,7 +78,7 @@ mpdWait :: IO ()
 mpdWait = do
   status <- M.withMPD $ M.idle [M.PlayerS, M.MixerS, M.OptionsS]
   case status of
-    Left _ -> threadDelay 10000000
+    Left _ -> threadDelay 5000
     _ -> return ()
 
 mpdReady :: [String] -> Monitor Bool
@@ -91,19 +95,21 @@ mpdReady args = do
 
 parseMPD :: M.Response M.Status -> M.Response (Maybe M.Song) -> MOpts
             -> Monitor [String]
-parseMPD (Left e) _ _ = return $ show e:replicate 19 ""
+parseMPD (Left _) _ _ = return $ "N/A": repeat ""
 parseMPD (Right st) song opts = do
   songData <- parseSong song
   bar <- showPercentBar (100 * b) b
   vbar <- showVerticalBar (100 * b) b
   ipat <- showIconPattern (mLapsedIconPattern opts) b
-  return $ [bar, vbar, ipat, ss, si, vol, len, lap, remain, plen, ppos, flags] ++ songData
+  return $ [bar, vbar, ipat, ss, si, vol, len, lap, remain, plen, ppos, flags]
+           ++ songData
   where s = M.stState st
         ss = show s
         si = stateGlyph s opts
         vol = int2str $ fromMaybe 0 (M.stVolume st)
         (p, t) = fromMaybe (0, 0) (M.stTime st)
-        [lap, len, remain] = map showTime [floor p, floor t, max 0 (floor t - floor p)]
+        [lap, len, remain] = map showTime
+                                 [floor p, floor t, max 0 (floor t - floor p)]
         b = if t > 0 then realToFrac $ p / t else 0
         plen = int2str $ M.stPlaylistLength st
         ppos = maybe "" (int2str . (+1)) $ M.stSongPos st
diff --git a/src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs b/src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs
index d8b7a3e..8c1d1ad 100644
--- a/src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs
+++ b/src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.MultiCoreTemp
--- Copyright   :  (c) 2019 Felix Springer
+-- Copyright   :  (c) 2019, 2020 Felix Springer
 -- License     :  BSD-style (see LICENSE)
 --
 -- Maintainer  :  Felix Springer <felixspringer149@gmail.com>
@@ -26,6 +26,7 @@ data CTOpts = CTOpts { maxIconPattern :: Maybe IconPattern
                      , avgIconPattern :: Maybe IconPattern
                      , mintemp :: Float
                      , maxtemp :: Float
+                     , hwMonitorPath :: Maybe String
                      }
 
 -- | Set default Options.
@@ -34,6 +35,7 @@ defaultOpts = CTOpts { maxIconPattern = Nothing
                      , avgIconPattern = Nothing
                      , mintemp = 0
                      , maxtemp = 100
+                     , hwMonitorPath = Nothing
                      }
 
 -- | Apply configured Options.
@@ -58,6 +60,11 @@ options = [ Option [] ["max-icon-pattern"]
                 (\ arg opts -> opts { maxtemp = read arg })
                 "")
               ""
+          , Option [] ["hwmon-path"]
+              (ReqArg
+                (\ arg opts -> opts { hwMonitorPath = Just arg })
+                "")
+              ""
           ]
 
 -- | Generate Config with a default template and options.
@@ -68,41 +75,50 @@ cTConfig = mkMConfig cTTemplate cTOptions
                     , "avg" , "avgpc" , "avgbar" , "avgvbar" , "avgipat"
                     ] ++ map (("core" ++) . show) [0 :: Int ..]
 
+
 -- | Returns the first coretemp.N path found.
-coretempPath :: IO String
+coretempPath :: IO (Maybe String)
 coretempPath = do xs <- filterM doesDirectoryExist ps
-                  let x = head xs
-                  return x
-  where ps = [ "/sys/bus/platform/devices/coretemp." ++ show (x :: Int) ++ "/" | x <- [0..9] ]
-
--- | Returns the first hwmonN path found.
-hwmonPath :: IO String
-hwmonPath = do p <- coretempPath
-               xs <- filterM doesDirectoryExist [ p ++ "hwmon/hwmon" ++ show (x :: Int) ++ "/" | x <- [0..9] ]
-               let x = head xs
-               return x
+                  return (if null xs then Nothing else Just $ head xs)
+  where ps = [ "/sys/bus/platform/devices/coretemp." ++ show (x :: Int) ++ "/"
+             | x <- [0..9] ]
+
+-- | Returns the first hwmonN in coretemp path found or the ones in sys/class.
+hwmonPaths :: IO [String]
+hwmonPaths = do p <- coretempPath
+                let (sc, path) = case p of
+                                   Just s -> (False, s)
+                                   Nothing -> (True, "/sys/class/")
+                let cps  = [ path ++ "hwmon/hwmon" ++ show (x :: Int) ++ "/"
+                           | x <- [0..9] ]
+                ecps <- filterM doesDirectoryExist cps
+                return $ if sc || null ecps then ecps else [head ecps]
 
 -- | Checks Labels, if they refer to a core and returns Strings of core-
 -- temperatures.
-corePaths :: IO [String]
-corePaths = do p <- hwmonPath
-               ls <- filterM doesFileExist [ p ++ "temp" ++ show (x :: Int) ++ "_label" | x <- [0..9] ]
-               cls <- filterM isLabelFromCore ls
-               return $ map labelToCore cls
+corePaths :: Maybe String -> IO [String]
+corePaths s = do ps <- case s of
+                        Just pth -> return [pth]
+                        _ -> hwmonPaths
+                 let cps = [p ++ "temp" ++ show (x :: Int) ++ "_label"
+                           | x <- [0..9], p <- ps ]
+                 ls <- filterM doesFileExist cps
+                 cls <- filterM isLabelFromCore ls
+                 return $ map labelToCore cls
 
 -- | Checks if Label refers to a core.
 isLabelFromCore :: FilePath -> IO Bool
 isLabelFromCore p = do a <- readFile p
-                       return $ take 4 a == "Core"
+                       return $ take 4 a `elem` ["Core", "Tdie", "Tctl"]
 
 -- | Transform a path to Label to a path to core-temperature.
 labelToCore :: FilePath -> FilePath
 labelToCore = (++ "input") . reverse . drop 5 . reverse
 
 -- | Reads core-temperatures as data from the system.
-cTData :: IO [Float]
-cTData = do fps <- corePaths
-            traverse readSingleFile fps
+cTData :: Maybe String -> IO [Float]
+cTData p = do fps <- corePaths p
+              traverse readSingleFile fps
   where readSingleFile :: FilePath -> IO Float
         readSingleFile s = do a <- readFile s
                               return $ parseContent a
@@ -110,10 +126,10 @@ cTData = do fps <- corePaths
                 parseContent = read . head . lines
 
 -- | Transforms data of temperatures into temperatures of degree Celsius.
-parseCT :: IO [Float]
-parseCT = do rawCTs <- cTData
-             let normalizedCTs = map (/ 1000) rawCTs :: [Float]
-             return normalizedCTs
+parseCT :: CTOpts -> IO [Float]
+parseCT opts = do rawCTs <- cTData (hwMonitorPath opts)
+                  let normalizedCTs = map (/ 1000) rawCTs :: [Float]
+                  return normalizedCTs
 
 -- | Performs calculation for maximum and average.
 -- Sets up Bars and Values to be printed.
@@ -150,8 +166,8 @@ formatCT opts cTs = do let CTOpts { mintemp = minT
 
 
 runCT :: [String] -> Monitor String
-runCT argv = do cTs <- io parseCT
-                opts <- io $ parseOptsWith options defaultOpts argv
+runCT argv = do opts <- io $ parseOptsWith options defaultOpts argv
+                cTs <- io $ parseCT opts
                 l <- formatCT opts cTs
                 parseTemplate l
 
diff --git a/src/Xmobar/Plugins/Monitors/Net.hs b/src/Xmobar/Plugins/Monitors/Net.hs
index db11724..97deacd 100644
--- a/src/Xmobar/Plugins/Monitors/Net.hs
+++ b/src/Xmobar/Plugins/Monitors/Net.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Net
--- Copyright   :  (c) 2011, 2012, 2013, 2014, 2017 Jose Antonio Ortega Ruiz
+-- Copyright   :  (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz
 --                (c) 2007-2010 Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
 --
@@ -49,6 +49,7 @@ data NetOpts = NetOpts
   { rxIconPattern :: Maybe IconPattern
   , txIconPattern :: Maybe IconPattern
   , onlyDevList :: Maybe DevList
+  , upIndicator :: String
   }
 
 defaultOpts :: NetOpts
@@ -56,6 +57,7 @@ defaultOpts = NetOpts
   { rxIconPattern = Nothing
   , txIconPattern = Nothing
   , onlyDevList = Nothing
+  , upIndicator = "+"
   }
 
 options :: [OptDescr (NetOpts -> NetOpts)]
@@ -64,6 +66,7 @@ options =
      o { rxIconPattern = Just $ parseIconPattern x }) "") ""
   , Option "" ["tx-icon-pattern"] (ReqArg (\x o ->
      o { txIconPattern = Just $ parseIconPattern x }) "") ""
+  , Option "" ["up"] (ReqArg (\x o -> o { upIndicator = x }) "") ""
   , Option "" ["devices"] (ReqArg (\x o ->
      o { onlyDevList = Just $ parseDevList x }) "") ""
   ]
@@ -103,7 +106,7 @@ instance Ord num => Ord (NetDevInfo num) where
 netConfig :: IO MConfig
 netConfig = mkMConfig
     "<dev>: <rx>KB|<tx>KB"      -- template
-    ["dev", "rx", "tx", "rxbar", "rxvbar", "rxipat", "txbar", "txvbar", "txipat"]     -- available replacements
+    ["dev", "rx", "tx", "rxbar", "rxvbar", "rxipat", "txbar", "txvbar", "txipat", "up"]     -- available replacements
 
 operstateDir :: String -> FilePath
 operstateDir d = "/sys/class/net" </> d </> "operstate"
@@ -160,7 +163,7 @@ printNet opts nd =
     N d (ND r t) -> do
         (rx, rb, rvb, ripat) <- formatNet (rxIconPattern opts) r
         (tx, tb, tvb, tipat) <- formatNet (txIconPattern opts) t
-        parseTemplate [d,rx,tx,rb,rvb,ripat,tb,tvb,tipat]
+        parseTemplate [d,rx,tx,rb,rvb,ripat,tb,tvb,tipat, upIndicator opts]
     N _ NI -> return ""
     NA -> getConfigValue naString
 
diff --git a/src/Xmobar/Plugins/Monitors/UVMeter.hs b/src/Xmobar/Plugins/Monitors/UVMeter.hs
index e184cb1..95abd66 100644
--- a/src/Xmobar/Plugins/Monitors/UVMeter.hs
+++ b/src/Xmobar/Plugins/Monitors/UVMeter.hs
@@ -21,14 +21,11 @@ import qualified Control.Exception as CE
 import Network.HTTP.Conduit
     ( Manager
     , httpLbs
-    , managerConnCount
-    , newManager
     , parseRequest
     , responseBody
-    , tlsManagerSettings
     )
+import Network.HTTP.Client.TLS (getGlobalManager)
 import Data.ByteString.Lazy.Char8 as B
-import Data.Maybe (fromMaybe)
 import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(Option))
 import Text.Read (readMaybe)
 import Text.Parsec
@@ -66,12 +63,9 @@ uvURL :: String
 uvURL = "https://uvdata.arpansa.gov.au/xml/uvvalues.xml"
 
 -- | Get the UV data from the given url.
-getData :: Maybe Manager -> IO String
-getData uvMan = CE.catch
-    (do man <- flip fromMaybe uvMan <$> mkManager
-        -- Create a new manager if none was present or the user does not want to
-        -- use one, otherwise use the provided manager.
-        request <- parseRequest uvURL
+getData ::Manager -> IO String
+getData man = CE.catch
+    (do request <- parseRequest uvURL
         res <- httpLbs request man
         return $ B.unpack $ responseBody res)
     errHandler
@@ -105,15 +99,13 @@ startUVMeter
     -> Int       -- ^ Update rate
     -> (String -> IO ())
     -> IO ()
-startUVMeter station args rate cb = do
-    opts  <- parseOptsWith options defaultOpts (getArgvs args)
-    uvMan <- tryMakeManager opts
-    runM (station : args) uvConfig (runUVMeter uvMan) rate cb
-
-runUVMeter :: Maybe Manager -> [String] -> Monitor String
-runUVMeter _ [] = return "N.A."
-runUVMeter uvMan (s:_) = do
-    resp <- io $ getData uvMan
+startUVMeter station args = runM (station : args) uvConfig runUVMeter
+
+runUVMeter :: [String] -> Monitor String
+runUVMeter [] = return "N.A."
+runUVMeter (s:_) = do
+    man <- io getGlobalManager
+    resp <- io $ getData man
     case textToXMLDocument resp of
         Right doc -> formatUVRating (getUVRating s doc)
         Left _ -> getConfigValue naString
@@ -195,15 +187,3 @@ attribute = do
     char '"'
     spaces
     return (Attribute (name, value))
-
--- | Possibly create a new 'Manager', based upon the users preference.  If one
--- is created, this 'Manager' will be used throughout the monitor.
-tryMakeManager :: UVMeterOpts -> IO (Maybe Manager)
-tryMakeManager opts =
-    if useManager opts
-        then Just <$> mkManager
-        else pure Nothing
-
--- | Create a new 'Manager' for managing network connections.
-mkManager :: IO Manager
-mkManager = newManager $ tlsManagerSettings {managerConnCount = 1}
diff --git a/src/Xmobar/Plugins/Monitors/Volume.hs b/src/Xmobar/Plugins/Monitors/Volume.hs
index a52261f..8840472 100644
--- a/src/Xmobar/Plugins/Monitors/Volume.hs
+++ b/src/Xmobar/Plugins/Monitors/Volume.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Volume
--- Copyright   :  (c) 2011, 2013, 2015, 2018 Thomas Tuegel
+-- Copyright   :  (c) 2011, 2013, 2015, 2018, 2020 Thomas Tuegel
 -- License     :  BSD-style (see LICENSE)
 --
 -- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>
@@ -23,7 +23,6 @@ module Xmobar.Plugins.Monitors.Volume
 
 import Control.Applicative ( (<$>), liftA3 )
 import Control.Monad ( liftM2, liftM3, mplus )
-import Data.Maybe (fromMaybe)
 import Data.Traversable (sequenceA)
 import Xmobar.Plugins.Monitors.Common
 import Sound.ALSA.Mixer
@@ -257,6 +256,5 @@ runVolumeWith opts mixerName controlName = do
 
     -- | Determine whether the volume is off based on the value of 'sw' from
     -- 'runVolumeWith'.
-    isVolOff = not . fromMaybe False
-
+    isVolOff = (Just True /=)
     unavailable = getConfigValue naString
diff --git a/src/Xmobar/Plugins/Monitors/Weather.hs b/src/Xmobar/Plugins/Monitors/Weather.hs
index f9c9f39..e71de10 100644
--- a/src/Xmobar/Plugins/Monitors/Weather.hs
+++ b/src/Xmobar/Plugins/Monitors/Weather.hs
@@ -21,33 +21,30 @@ import qualified Control.Exception as CE
 
 import qualified Data.ByteString.Lazy.Char8 as B
 import Data.Char (toLower)
-import Data.Maybe (fromMaybe)
 import Network.HTTP.Conduit
 import Network.HTTP.Types.Status
 import Network.HTTP.Types.Method
+import Network.HTTP.Client.TLS (getGlobalManager)
 
 import Text.ParserCombinators.Parsec
 import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(Option))
 
 
 -- | Options the user may specify.
-data WeatherOpts = WeatherOpts
+newtype WeatherOpts = WeatherOpts
   { weatherString :: String
-  , useManager    :: Bool
   }
 
 -- | Default values for options.
 defaultOpts :: WeatherOpts
 defaultOpts = WeatherOpts
   { weatherString = ""
-  , useManager    = True
   }
 
 -- | Apply options.
 options :: [OptDescr (WeatherOpts -> WeatherOpts)]
 options =
   [ Option "w" ["weathers"  ] (ReqArg (\s o -> o { weatherString = s   }) "") ""
-  , Option "m" ["useManager"] (ReqArg (\b o -> o { useManager = read b }) "") ""
   ]
 
 weatherConfig :: IO MConfig
@@ -213,12 +210,10 @@ stationUrl :: String -> String
 stationUrl station = defUrl ++ station ++ ".TXT"
 
 -- | Get the decoded weather data from the given station.
-getData :: Maybe Manager -> String -> IO String
-getData weMan station = CE.catch
-    (do man <- flip fromMaybe weMan <$> mkManager
-        -- Create a new manager if none was present or the user does not want to
-        -- use one.
-        request <- parseUrlThrow $ stationUrl station
+getData :: String -> IO String
+getData station = CE.catch
+    (do request <- parseUrlThrow $ stationUrl station
+        man <- getGlobalManager
         res <- httpLbs request man
         return $ B.unpack $ responseBody res)
     errHandler
@@ -261,11 +256,10 @@ startWeather'
     -> IO ()
 startWeather' sks station args rate cb = do
     opts  <- parseOptsWith options defaultOpts (getArgvs args)
-    weRef <- tryMakeManager opts
     runMD
         (station : args)
         weatherConfig
-        (runWeather sks weRef opts)
+        (runWeather sks opts)
         rate
         weatherReady
         cb
@@ -278,12 +272,11 @@ startWeather = startWeather' []
 -- | Run a weather monitor.
 runWeather
     :: [(String, String)]  -- ^ 'SkyConditionS' replacement strings
-    -> Maybe Manager       -- ^ Whether to use a 'Manager'
     -> WeatherOpts         -- ^ Weather specific options
     -> [String]            -- ^ User supplied arguments
     -> Monitor String
-runWeather sks weMan opts args = do
-    d <- io $ getData weMan (head args)
+runWeather sks opts args = do
+    d <- io $ getData (head args)
     i <- io $ runP parseData d
     formatWeather opts sks i
 
@@ -293,7 +286,7 @@ weatherReady str = io $ do
     let request = initRequest { method = methodHead }
 
     CE.catch
-        (do man <- mkManager
+        (do man <- getGlobalManager
             res  <- httpLbs request man
             return $ checkResult $ responseStatus res)
         errHandler
@@ -308,15 +301,3 @@ weatherReady str = io $ do
         | statusIsServerError status = False
         | statusIsClientError status = False
         | otherwise = True
-
--- | Possibly create a new 'Manager', based upon the users preference.  If one
--- is created, this 'Manager' will be used throughout the monitor.
-tryMakeManager :: WeatherOpts -> IO (Maybe Manager)
-tryMakeManager opts =
-    if useManager opts
-        then Just <$> mkManager
-        else pure Nothing
-
--- | Create a new 'Manager' for managing network connections.
-mkManager :: IO Manager
-mkManager = newManager $ tlsManagerSettings { managerConnCount = 1 }
diff --git a/src/Xmobar/Plugins/Monitors/Wireless.hs b/src/Xmobar/Plugins/Monitors/Wireless.hs
index 1237aa9..bd6d52e 100644
--- a/src/Xmobar/Plugins/Monitors/Wireless.hs
+++ b/src/Xmobar/Plugins/Monitors/Wireless.hs
@@ -1,4 +1,7 @@
-{-# LANGUAGE TypeApplications, CPP #-}
+{-# LANGUAGE CPP #-}
+#ifdef USE_NL80211
+{-# LANGUAGE TypeApplications #-}
+#endif
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Wireless
@@ -16,7 +19,6 @@
 module Xmobar.Plugins.Monitors.Wireless (wirelessConfig, runWireless)  where
 
 import System.Console.GetOpt
-import Data.Maybe (fromMaybe)
 
 import Xmobar.Plugins.Monitors.Common
 
@@ -26,7 +28,7 @@ import Network.IWlib
 import Control.Exception (bracket)
 import qualified Data.Map as M
 import GHC.Int (Int8)
-import Data.Maybe (listToMaybe)
+import Data.Maybe (listToMaybe, fromMaybe)
 import Control.Monad.IO.Class (liftIO)
 import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
 import Data.ByteString.Char8 (unpack)
@@ -42,12 +44,12 @@ import System.Posix.IO (closeFd)
 data IwData = IwData { wiEssid :: String, wiSignal :: Maybe Int, wiQuality :: Int }
 
 getWirelessInfo :: String -> IO IwData
-getWirelessInfo ifname = do
+getWirelessInfo ifname =
   bracket makeNL80211Socket (closeFd . getFd) (\s -> do
   iflist <- getInterfaceList s
   iwdata <- runMaybeT $ do
     ifidx <- MaybeT . return $ foldr (\(n, i) z ->
-                                       if (ifname == "" || ifname == n) then Just i else z)
+                                       if ifname == "" || ifname == n then Just i else z)
                                      Nothing
                                      iflist
     scanp <- liftIO (getConnectedWifi s ifidx) >>=
@@ -63,13 +65,16 @@ getWirelessInfo ifname = do
                                 return . unpack
         signal = staInfoFromPacket stap >>= staSignalMBM >>=
                  return . fromIntegral @Int8 . fromIntegral
-        qlty   = fromMaybe (-1) (round @Float . (/ 0.7) . (+ 110) .
-                                                clamp (-110) (-40) . fromIntegral <$> signal)
+        qlty   = maybe (-1) (round @Float . (/ 0.7) . (+ 110) .
+                                            clamp (-110) (-40) . fromIntegral) signal
     MaybeT . return $ Just $ IwData ssid signal qlty
   return $ fromMaybe (IwData "" Nothing (-1)) iwdata)
   where
     rightToMaybe = either (const Nothing) Just
-    clamp lb up v = if v < lb then lb else if v > up then up else v
+    clamp lb up v
+      | v < lb = lb
+      | v > up = up
+      | otherwise = v
 #endif
 
 newtype WirelessOpts = WirelessOpts
diff --git a/src/Xmobar/Plugins/PipeReader.hs b/src/Xmobar/Plugins/PipeReader.hs
index 9c6e628..1a10abf 100644
--- a/src/Xmobar/Plugins/PipeReader.hs
+++ b/src/Xmobar/Plugins/PipeReader.hs
@@ -16,7 +16,6 @@ module Xmobar.Plugins.PipeReader(PipeReader(..)) where
 
 import System.IO
 import Xmobar.Run.Exec(Exec(..))
-import Xmobar.System.Utils(hGetLineSafe)
 import Xmobar.System.Environment(expandEnv)
 import System.Posix.Files
 import Control.Concurrent(threadDelay)
@@ -34,7 +33,7 @@ instance Exec PipeReader where
         unless (null def) (cb def)
         checkPipe pipe
         h <- openFile pipe ReadWriteMode
-        forever (hGetLineSafe h >>= cb)
+        forever (hGetLine h >>= cb)
       where
         split c xs | c `elem` xs = let (pre, post) = span (c /=) xs
                                    in (pre, dropWhile (c ==) post)
diff --git a/src/Xmobar/Plugins/StdinReader.hs b/src/Xmobar/Plugins/StdinReader.hs
index 4b80044..a29c1ad 100644
--- a/src/Xmobar/Plugins/StdinReader.hs
+++ b/src/Xmobar/Plugins/StdinReader.hs
@@ -22,23 +22,30 @@ import Prelude
 import System.Posix.Process
 import System.Exit
 import System.IO
-import Control.Exception (SomeException(..), handle)
 import Xmobar.Run.Exec
 import Xmobar.X11.Actions (stripActions)
-import Xmobar.System.Utils (hGetLineSafe)
+import Xmobar.System.Utils (onSomeException)
+import Control.Monad (when)
 
 data StdinReader = StdinReader | UnsafeStdinReader
   deriving (Read, Show)
 
 instance Exec StdinReader where
   start stdinReader cb = do
-    s <- handle (\(SomeException e) -> do hPrint stderr e; return "")
-                (hGetLineSafe stdin)
-    cb $ escape stdinReader s
+    -- The EOF check is necessary for certain systems
+    -- More details here https://github.com/jaor/xmobar/issues/442
     eof <- isEOF
-    if eof
-      then exitImmediately ExitSuccess
-      else start stdinReader cb
+    when eof $
+      do hPrint stderr "xmobar: eof at an early stage"
+         exitImmediately ExitSuccess
+    s <-
+      getLine `onSomeException`
+      (\e -> do
+         let errorMessage = "xmobar: Received exception " <> show e
+         hPrint stderr errorMessage
+         cb errorMessage)
+    cb $ escape stdinReader s
+    start stdinReader cb
 
 escape :: StdinReader -> String -> String
 escape StdinReader = stripActions
diff --git a/src/Xmobar/Run/Command.hs b/src/Xmobar/Run/Command.hs
index e6153c1..430d142 100644
--- a/src/Xmobar/Run/Command.hs
+++ b/src/Xmobar/Run/Command.hs
@@ -20,8 +20,7 @@ module Xmobar.Run.Command where
 import Control.Exception (handle, SomeException(..))
 import System.Process
 import System.Exit
-import System.IO (hClose)
-import Xmobar.System.Utils (hGetLineSafe)
+import System.IO (hClose, hGetLine)
 
 import Xmobar.Run.Exec
 
@@ -47,7 +46,7 @@ instance Exec Command where
                 exit <- waitForProcess p
                 let closeHandles = hClose o >> hClose i >> hClose e
                     getL = handle (\(SomeException _) -> return "")
-                                  (hGetLineSafe o)
+                                  (hGetLine o)
                 case exit of
                   ExitSuccess -> do str <- getL
                                     closeHandles
diff --git a/src/Xmobar/Run/Exec.hs b/src/Xmobar/Run/Exec.hs
index d8cf81a..e1b6709 100644
--- a/src/Xmobar/Run/Exec.hs
+++ b/src/Xmobar/Run/Exec.hs
@@ -10,7 +10,7 @@
 --
 -- The 'Exec' class and the 'Command' data type.
 --
--- The 'Exec' class rappresents the executable types, whose constructors may
+-- The 'Exec' class represents the executable types, whose constructors may
 -- appear in the 'Config.commands' field of the 'Config.Config' data type.
 --
 -- The 'Command' data type is for OS commands to be run by xmobar
diff --git a/src/Xmobar/System/Utils.hs b/src/Xmobar/System/Utils.hs
index d4bdd78..53052ea 100644
--- a/src/Xmobar/System/Utils.hs
+++ b/src/Xmobar/System/Utils.hs
@@ -3,7 +3,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Utils
--- Copyright: (c) 2010, 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2010, 2018, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: Jose A Ortega Ruiz <jao@gnu.org>
@@ -17,27 +17,21 @@
 ------------------------------------------------------------------------------
 
 
-module Xmobar.System.Utils (expandHome, changeLoop, hGetLineSafe)
-where
+module Xmobar.System.Utils
+  ( expandHome
+  , changeLoop
+  , onSomeException
+  , safeIndex
+  ) where
 
 import Control.Monad
 import Control.Concurrent.STM
+import qualified Data.List.NonEmpty as NE
+import Data.Maybe (fromMaybe)
 
 import System.Environment
 import System.FilePath
-import System.IO
-
-#if defined XFT || defined UTF8
-import qualified System.IO as S (hGetLine)
-#endif
-
-hGetLineSafe :: Handle -> IO String
-#if defined XFT || defined UTF8
-hGetLineSafe = S.hGetLine
-#else
-hGetLineSafe = hGetLine
-#endif
-
+import Control.Exception
 
 expandHome :: FilePath -> IO FilePath
 expandHome ('~':'/':path) = fmap (</> path) (getEnv "HOME")
@@ -52,3 +46,26 @@ changeLoop s f = atomically s >>= go
             new <- s
             guard (new /= old)
             return new)
+
+-- | Like 'finally', but only performs the final action if there was an
+-- exception raised by the computation.
+--
+-- Note that this implementation is a slight modification of
+-- onException function.
+onSomeException :: IO a -> (SomeException -> IO b) -> IO a
+onSomeException io what = io `catch` \e -> do _ <- what e
+                                              throwIO (e :: SomeException)
+
+(!!?) :: [a] -> Int -> Maybe a
+(!!?) xs i
+    | i < 0     = Nothing
+    | otherwise = go i xs
+  where
+    go :: Int -> [a] -> Maybe a
+    go 0 (x:_)  = Just x
+    go j (_:ys) = go (j - 1) ys
+    go _ []     = Nothing
+{-# INLINE (!!?) #-}
+
+safeIndex :: NE.NonEmpty a -> Int -> a
+safeIndex xs index = fromMaybe (NE.head xs) (NE.toList xs !!? index)
diff --git a/src/Xmobar/X11/Draw.hs b/src/Xmobar/X11/Draw.hs
index 23003b3..b7f58ca 100644
--- a/src/Xmobar/X11/Draw.hs
+++ b/src/Xmobar/X11/Draw.hs
@@ -25,6 +25,7 @@ import Control.Monad.Reader
 import Control.Monad (when)
 import Control.Arrow ((&&&))
 import Data.Map hiding (foldr, map, filter)
+import qualified Data.List.NonEmpty as NE
 
 import Graphics.X11.Xlib hiding (textExtents, textWidth)
 import Graphics.X11.Xlib.Extras
@@ -37,6 +38,7 @@ import Xmobar.X11.Text
 import Xmobar.X11.ColorCache
 import Xmobar.X11.Window (drawBorder)
 import Xmobar.X11.Parsers (Widget(..))
+import Xmobar.System.Utils (safeIndex)
 
 #ifdef XFT
 import Xmobar.X11.MinXft
@@ -55,7 +57,7 @@ drawInWin wr@(Rectangle _ _ wid ht) ~[left,center,right] = do
       strLn = liftIO . mapM getWidth
       iconW i = maybe 0 B.width (lookup i $ iconS r)
       getWidth (Text s,cl,i,_) =
-        textWidth d (fs!!i) s >>= \tw -> return (Text s,cl,i,fi tw)
+        textWidth d (safeIndex fs i) s >>= \tw -> return (Text s,cl,i,fi tw)
       getWidth (Icon s,cl,i,_) = return (Icon s,cl,i,fi $ iconW s)
 
   p <- liftIO $ createPixmap d w wid ht
@@ -126,7 +128,7 @@ printString dpy drw fs@(Xft fonts) _ fc bc x y s al =
 #endif
 
 -- | An easy way to print the stuff we need to print
-printStrings :: Drawable -> GC -> [XFont] -> [Int] -> Position
+printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> [Int] -> Position
              -> Align -> [(Widget, String, Int, Position)] -> X ()
 printStrings _ _ _ _ _ _ [] = return ()
 printStrings dr gc fontlist voffs offs a sl@((s,c,i,l):xs) = do
@@ -136,7 +138,7 @@ printStrings dr gc fontlist voffs offs a sl@((s,c,i,l):xs) = do
       Rectangle _ _ wid ht = rect r
       totSLen = foldr (\(_,_,_,len) -> (+) len) 0 sl
       remWidth = fi wid - fi totSLen
-      fontst = fontlist !! i
+      fontst = safeIndex fontlist i
       offset = case a of
                  C -> (remWidth + offs) `div` 2
                  R -> remWidth
@@ -144,7 +146,7 @@ printStrings dr gc fontlist voffs offs a sl@((s,c,i,l):xs) = do
       (fc,bc) = case break (==',') c of
                  (f,',':b) -> (f, b           )
                  (f,    _) -> (f, bgColor conf)
-  valign <- verticalOffset ht s (head fontlist) (voffs !! i) conf
+  valign <- verticalOffset ht s (NE.head fontlist) (voffs !! i) conf
   case s of
     (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign t alph
     (Icon p) -> liftIO $ maybe (return ())
diff --git a/src/Xmobar/X11/Parsers.hs b/src/Xmobar/X11/Parsers.hs
index 7fa42d7..1d486d9 100644
--- a/src/Xmobar/X11/Parsers.hs
+++ b/src/Xmobar/X11/Parsers.hs
@@ -20,7 +20,9 @@ import Xmobar.Config.Types
 import Xmobar.X11.Actions
 
 import Control.Monad (guard, mzero)
+import Data.Maybe (fromMaybe)
 import Text.ParserCombinators.Parsec
+import Text.Read (readMaybe)
 import Graphics.X11.Types (Button)
 
 data Widget = Icon String | Text String
@@ -138,7 +140,7 @@ fontParser :: ColorString -> Maybe [Action]
               -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
 fontParser c a = do
   f <- between (string "<fn=") (string ">") colors
-  s <- manyTill (allParsers c (read f) a) (try $ string "</fn>")
+  s <- manyTill (allParsers c (fromMaybe 0 $ readMaybe f) a) (try $ string "</fn>")
   return (concat s)
 
 -- | Parses a color specification (hex or named)
diff --git a/src/Xmobar/X11/Types.hs b/src/Xmobar/X11/Types.hs
index 333dc96..b22f807 100644
--- a/src/Xmobar/X11/Types.hs
+++ b/src/Xmobar/X11/Types.hs
@@ -20,6 +20,7 @@ module Xmobar.X11.Types (X, XConf (..)) where
 import Graphics.X11.Xlib
 import Control.Monad.Reader
 import Data.Map
+import qualified Data.List.NonEmpty as NE
 
 import Xmobar.X11.Bitmap
 import Xmobar.X11.Text
@@ -33,7 +34,7 @@ data XConf =
     XConf { display   :: Display
           , rect      :: Rectangle
           , window    :: Window
-          , fontListS :: [XFont]
+          , fontListS :: NE.NonEmpty XFont
           , verticalOffsets :: [Int]
           , iconS     :: Map FilePath Bitmap
           , config    :: Config
diff --git a/test/Xmobar/Plugins/Monitors/AlsaSpec.hs b/test/Xmobar/Plugins/Monitors/AlsaSpec.hs
index 14810dd..70beda1 100644
--- a/test/Xmobar/Plugins/Monitors/AlsaSpec.hs
+++ b/test/Xmobar/Plugins/Monitors/AlsaSpec.hs
@@ -1,9 +1,12 @@
 {-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE CPP #-}
+
 module Xmobar.Plugins.Monitors.AlsaSpec
   ( main
   , spec
   ) where
 
+#ifdef ALSA
 import Control.Concurrent
 import Control.Concurrent.Async
 import Control.Monad
@@ -158,3 +161,11 @@ withFifoWriteHandle fifoPath body = do
       $ \(Just h) _ _ _ -> do
         hSetBuffering h LineBuffering
         body h
+#else
+-- These No-Op values are required for HSpec's test discovery.
+main :: IO ()
+main = return ()
+
+spec :: Monad m => m ()
+spec = return ()
+#endif
diff --git a/test/Xmobar/Plugins/Monitors/CpuSpec.hs b/test/Xmobar/Plugins/Monitors/CpuSpec.hs
new file mode 100644
index 0000000..449acd5
--- /dev/null
+++ b/test/Xmobar/Plugins/Monitors/CpuSpec.hs
@@ -0,0 +1,41 @@
+module Xmobar.Plugins.Monitors.CpuSpec
+  ( 
+   spec, main
+  ) where
+
+import Test.Hspec
+import Xmobar.Plugins.Monitors.Common
+import Xmobar.Plugins.Monitors.Cpu
+import Data.List
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec =
+  describe "CPU Spec" $ do
+    it "works with total template" $
+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>%"]
+         cpuArgs <- getArguments args
+         cpuValue <- runCpu cpuArgs
+         cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` item)
+    it "works with bar template" $
+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>"]
+         cpuArgs <- getArguments args
+         cpuValue <- runCpu cpuArgs
+         cpuValue `shouldSatisfy` (\item -> "::" `isSuffixOf` item)
+    it "works with no icon pattern template" $
+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>", "--", "--load-icon-pattern", "<icon=bright_%%.xpm/>"]
+         cpuArgs <- getArguments args
+         cpuValue <- runCpu cpuArgs
+         cpuValue `shouldSatisfy` (\item -> not $ "<icon=bright_" `isInfixOf` cpuValue)
+    it "works with icon pattern template" $
+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar> <ipat>", "--", "--load-icon-pattern", "<icon=bright_%%.xpm/>"]
+         cpuArgs <- getArguments args
+         cpuValue <- runCpu cpuArgs
+         cpuValue `shouldSatisfy` (\item -> "<icon=bright_" `isInfixOf` cpuValue)
+    it "works with other parameters in template" $
+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <user> <nice> <iowait>"]
+         cpuArgs <- getArguments args
+         cpuValue <- runCpu cpuArgs
+         cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` cpuValue)
diff --git a/xmobar.cabal b/xmobar.cabal
index c2089f4..4fee00e 100644
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,5 +1,5 @@
 name:               xmobar
-version:            0.33
+version:            0.35.1
 homepage:           http://xmobar.org
 synopsis:           A Minimalistic Text Based Status Bar
 description: 	    Xmobar is a minimalistic text based status bar.
@@ -13,7 +13,7 @@ license-file:       license
 author:             Andrea Rossato and Jose A. Ortega Ruiz
 maintainer:         Jose A. Ortega Ruiz <jao@gnu.org>
 bug-reports:        https://github.com/jaor/xmobar/issues
-cabal-version:      >= 1.8
+cabal-version:      >= 1.10
 build-type:         Simple
 
 extra-source-files: readme.md, changelog.md,
@@ -92,9 +92,13 @@ flag with_weather
   default: True
 
 library
+    default-language: Haskell2010
     hs-source-dirs:  src
 
-    exposed-modules: Xmobar
+    exposed-modules: Xmobar,
+                     Xmobar.Plugins.Monitors.Common.Types,
+                     Xmobar.Plugins.Monitors.Common.Run,
+                     Xmobar.Plugins.Monitors.Cpu
 
     other-modules: Paths_xmobar,
                    Xmobar.Config.Types,
@@ -129,6 +133,7 @@ library
                    Xmobar.Plugins.CommandReader,
                    Xmobar.Plugins.Date,
                    Xmobar.Plugins.EWMH,
+                   Xmobar.Plugins.HandleReader,
                    Xmobar.Plugins.PipeReader,
                    Xmobar.Plugins.MarqueePipeReader,
                    Xmobar.Plugins.StdinReader,
@@ -138,14 +143,11 @@ library
                    Xmobar.Plugins.Monitors,
                    Xmobar.Plugins.Monitors.Batt,
                    Xmobar.Plugins.Monitors.Common,
-                   Xmobar.Plugins.Monitors.Common.Types,
-                   Xmobar.Plugins.Monitors.Common.Run,
                    Xmobar.Plugins.Monitors.Common.Output,
                    Xmobar.Plugins.Monitors.Common.Parsers,
                    Xmobar.Plugins.Monitors.Common.Files,
                    Xmobar.Plugins.Monitors.CoreTemp,
                    Xmobar.Plugins.Monitors.CpuFreq,
-                   Xmobar.Plugins.Monitors.Cpu,
                    Xmobar.Plugins.Monitors.Disk,
                    Xmobar.Plugins.Monitors.Mem,
                    Xmobar.Plugins.Monitors.MultiCoreTemp,
@@ -164,12 +166,12 @@ library
     ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
 
     build-depends:
-      base >= 4.9.1.0 && < 4.14,
+      base >= 4.11.0 && < 4.15,
       containers,
       regex-compat,
       process,
       old-locale,
-      bytestring,
+      bytestring >= 0.10.8.2,
       directory,
       unix,
       time,
@@ -210,11 +212,11 @@ library
 
     if flag(with_inotify) || flag(all_extensions)
        build-depends: hinotify >= 0.3 && < 0.5
-       exposed-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox
+       other-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox
        cpp-options: -DINOTIFY
 
     if flag(with_iwlib) || flag(with_nl80211) || flag(all_extensions)
-       exposed-modules: Xmobar.Plugins.Monitors.Wireless
+       other-modules: Xmobar.Plugins.Monitors.Wireless
 
     if flag(with_iwlib)
        extra-libraries: iw
@@ -228,25 +230,25 @@ library
 
     if flag(with_mpd) || flag(all_extensions)
        build-depends: libmpd >= 0.9.0.10
-       exposed-modules: Xmobar.Plugins.Monitors.MPD
+       other-modules: Xmobar.Plugins.Monitors.MPD
        cpp-options: -DLIBMPD
 
     if flag(with_alsa) || flag(all_extensions)
        build-depends: alsa-mixer >= 0.3 && < 0.4
        build-depends: alsa-core == 0.5.*,
                       process >= 1.4.3.0
-       exposed-modules: Xmobar.Plugins.Monitors.Volume
+       other-modules: Xmobar.Plugins.Monitors.Volume
                         Xmobar.Plugins.Monitors.Alsa
        cpp-options: -DALSA
 
     if flag(with_datezone) || flag(all_extensions)
-       build-depends: timezone-olson == 0.1.*, timezone-series == 0.1.*
-       exposed-modules: Xmobar.Plugins.DateZone
+       build-depends: timezone-olson >= 0.1 && < 0.3, timezone-series == 0.1.*
+       other-modules: Xmobar.Plugins.DateZone
        cpp-options: -DDATEZONE
 
     if flag(with_mpris) || flag(all_extensions)
        build-depends: dbus >= 1
-       exposed-modules: Xmobar.Plugins.Monitors.Mpris
+       other-modules: Xmobar.Plugins.Monitors.Mpris
        cpp-options: -DMPRIS
 
     if flag(with_dbus) || flag(all_extensions)
@@ -260,12 +262,12 @@ library
        cpp-options: -DXPM
 
     if flag(with_weather) || flag(all_extensions)
-       exposed-modules: Xmobar.Plugins.Monitors.Weather
+       other-modules: Xmobar.Plugins.Monitors.Weather
        cpp-options: -DWEATHER
-       build-depends: http-conduit, http-types
+       build-depends: http-conduit, http-types, http-client-tls
 
     if flag(with_uvmeter)
-       exposed-modules: Xmobar.Plugins.Monitors.UVMeter
+       other-modules: Xmobar.Plugins.Monitors.UVMeter
        build-depends: http-conduit, http-types
        cpp-options: -DUVMETER
 
@@ -275,6 +277,7 @@ library
        cpp-options: -DFREEBSD
 
 executable xmobar
+    default-language:   Haskell2010
     hs-source-dirs:     app
     main-is:            Main.hs
     build-depends:      base,
@@ -300,6 +303,7 @@ executable xmobar
        cpp-options: -DTHREADED_RUNTIME
 
 test-suite XmobarTest
+  default-language:   Haskell2010
   type:           exitcode-stdio-1.0
   hs-source-dirs: src, test
   main-is:        Spec.hs
@@ -327,10 +331,11 @@ test-suite XmobarTest
   other-modules: Xmobar.Plugins.Monitors.CommonSpec
                  Xmobar.Plugins.Monitors.Common
                  Xmobar.Plugins.Monitors.Common.Parsers
-                 Xmobar.Plugins.Monitors.Common.Run
                  Xmobar.Plugins.Monitors.Common.Types
                  Xmobar.Plugins.Monitors.Common.Output
                  Xmobar.Plugins.Monitors.Common.Files
+                 Xmobar.Plugins.Monitors.Cpu
+                 Xmobar.Plugins.Monitors.Common.Run
                  Xmobar.Run.Exec
                  Xmobar.App.Timer
                  Xmobar.System.Signal
@@ -342,5 +347,15 @@ test-suite XmobarTest
       other-modules: Xmobar.Plugins.Monitors.Volume
                      Xmobar.Plugins.Monitors.Alsa
                      Xmobar.Plugins.Monitors.AlsaSpec
+                     Xmobar.Plugins.Monitors.CpuSpec
 
       cpp-options: -DALSA
+
+benchmark xmobarbench
+  type: exitcode-stdio-1.0
+  main-is: main.hs
+  hs-source-dirs:
+      bench
+  ghc-options: -O2
+  build-depends: base, gauge, xmobar, mtl
+  default-language: Haskell2010