diff --git a/news.md b/news.md
--- a/news.md
+++ b/news.md
@@ -1,5 +1,26 @@
 % xmobar - Release notes
 
+## Version 0.21 (Jul 1, 2014)
+
+_New features_
+
+  - Vertical bar indicators using unicode available for most monitors,
+    by Eric Mrak.
+  - `CoreTemp`: support for linux 3.15, by Tomáš Janoušek.
+  - New `CatInt` monitor, displaying integer values read from a file,
+    by Nathaniel Wesley Filardo.
+  - New `<raw>` tag for safer input parsing, also by Nathaniel.
+  - New `UnsafeXMonadLog` monitor (by Eric Mrak) and their xproperty
+    counterparts, `UnsafeXPropertyLog` and `UnsafeNamedXPropertyLog`.
+
+_Bug fixes_
+
+  - `Network` now reports status for ppp connections (see
+    [issue #89]).
+  - Fix for very long running `Cpu` monitors, by Robert J Macomber.
+
+[issue #89]: https://github.com/jaor/xmobar/issues/89
+
 ## Version 0.20.1 (March 13, 2014)
 
 _New features_
@@ -8,7 +29,7 @@
     configuration option, `pickBroadest`, for choosing the broadest
     (see [issue #158]).
 
-[issue #158]: https://github.com/jaor/xmobar/issues/76
+[issue #158]: https://github.com/jaor/xmobar/issues/158
 
 ## Version 0.20 (March 10, 2014)
 
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -202,6 +202,22 @@
   (left mouse button). Using old syntax (without backticks surrounding `command`)
   will result in `button` attribute being ignored.
 
+- `<raw=len:str/>` allows the encapsulation of arbitrary text `str` (which
+  must be `len` `Char`s long, where `len` is encoded as a decimal sequence).
+  Careful use of this and `UnsafeStdinReader`, for example, permits window
+  managers to feed xmobar strings with `<action>` tags mixed with un-trusted
+  content (e.g. window titles).  For example, if xmobar is invoked as
+
+    ```xmobar -c "[Run UnsafeStdinReader]" -t "%UnsafeStdinReader%"```
+
+  and receives on standard input the line
+
+    ```<action=`echo test` button=1><raw=41:<action=`echo mooo`
+button=1>foo</action>/></action>```
+
+  then it will display the text ```<action=`echo mooo` button=1>foo</action>```,
+  which, when clicked, will cause `test` to be echoed.
+
 Other configuration options:
 
 `font`
@@ -672,9 +688,9 @@
   `%eth0%`
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
-  `dev`, `rx`, `tx`, `rxbar`, `txbar`. Reception and transmission
-  rates (`rx` and `tx`) are displayed in Kbytes per second, and you
-  can set the `-S` to "True" to make them displayed with units (the
+  `dev`, `rx`, `tx`, `rxbar`, `rxvbar`, `txbar`, `txvbar`. Reception and
+  transmission rates (`rx` and `tx`) are displayed in Kbytes per second,
+  and you can set the `-S` to "True" to make them displayed with units (the
   string "Kb/s").
 - Default template: `<dev>: <rx>KB|<tx>KB`
 
@@ -684,9 +700,9 @@
 - Aliases to "dynnetwork"
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
-  `dev`, `rx`, `tx`, `rxbar`, `txbar`. Reception and transmission
-  rates (`rx` and `tx`) are displayed in Kbytes per second, and you
-  can set the `-S` to "True" to make them displayed with units (the
+  `dev`, `rx`, `tx`, `rxbar`, `rxvbar`, `txbar`, `txvbar`. Reception and
+  transmission rates (`rx` and `tx`) are displayed in Kbytes per second,
+  and you can set the `-S` to "True" to make them displayed with units (the
   string "Kb/s").
 - Default template: `<dev>: <rx>KB|<tx>KB`
 
@@ -696,7 +712,7 @@
   "wlan0" []` can be used as `%wlan0wi%`
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
-            `essid`, `quality`, `qualitybar`
+            `essid`, `quality`, `qualitybar`, `qualityvbar`
 - Default template: `<essid> <quality>`
 - Requires the C library [iwlib] (part of the wireless tools suite)
   installed in your system. In addition, to activate this plugin you
@@ -708,7 +724,7 @@
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
              `total`, `free`, `buffer`, `cache`, `rest`, `used`,
-             `usedratio`, `usedbar`, `freeratio`, `freebar`
+             `usedratio`, `usedbar`, `usedvbar`, `freeratio`, `freebar`, `freevbar`
 - Default template: `Mem: <usedratio>% (<cache>M)`
 
 ### `Swap Args RefreshRate`
@@ -724,7 +740,7 @@
 - Aliases to `cpu`
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
-	    `total`, `bar`, `user`, `nice`, `system`, `idle`, `iowait`
+	    `total`, `bar`, `vbar`, `user`, `nice`, `system`, `idle`, `iowait`
 - Default template: `Cpu: <total>%`
 
 ### `MultiCpu Args RefreshRate`
@@ -732,9 +748,9 @@
 - Aliases to `multicpu`
 - Args: default monitor arguments
 - Variables that can be used with the `-t`/`--template` argument:
-	    `autototal`, `autobar`, `autouser`, `autonice`,
-	    `autosystem`, `autoidle`, `total`, `bar`, `user`, `nice`,
-	    `system`, `idle`, `total0`, `bar0`, `user0`, `nice0`,
+	    `autototal`, `autobar`, `autovbar`, `autouser`, `autonice`,
+	    `autosystem`, `autoidle`, `total`, `bar`, `vbar`, `user`, `nice`,
+	    `system`, `idle`, `total0`, `bar0`, `vbar0`, `user0`, `nice0`,
 	    `system0`, `idle0`, ...
   The auto* variables automatically detect the number of CPUs on the system
   and display one entry for each.
@@ -767,7 +783,7 @@
     "AC/online")
 
 - Variables that can be used with the `-t`/`--template` argument:
-	    `left`, `leftbar`, `timeleft`, `watts`, `acstatus`
+	    `left`, `leftbar`, `leftvbar`, `timeleft`, `watts`, `acstatus`
 - Default template: `Batt: <watts>, <left>% / <timeleft>`
 - Example (note that you need "--" to separate regular monitor options from
   Battery's specific ones):
@@ -840,14 +856,15 @@
 - Aliases to `disku`
 - Disks: list of pairs of the form (device or mount point, template),
   where the template can contain `<size>`, `<free>`, `<used>`, `<freep>` or
-  `<usedp>`, `<freebar>` or `<usedbar>` for total, free, used, free
-  percentage and used percentage of the given file system capacity.
+  `<usedp>`, `<freebar>`, `<freevbar>`, `<usedbar>` or `<usedvbar>` for total,
+  free, used, free percentage and used percentage of the given file system
+  capacity.
 - Args: default monitor arguments. `-t`/`--template` is ignored.
 - Default template: none (you must specify a template for each file system).
 - Example:
 
          DiskU [("/", "<used>/<size>"), ("sdb1", "<usedbar>")]
-               ["-L", "20", "-H", "50", "-m", "1", "-p", "3",]
+               ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]
                20
 
 ### `DiskIO Disks Args RefreshRate`
@@ -855,7 +872,9 @@
 - Aliases to `diskio`
 - Disks: list of pairs of the form (device or mount point, template),
   where the template can contain `<total>`, `<read>`, `<write>` for total,
-  read and write speed, respectively.
+  read and write speed, respectively. There are also bar versions of each:
+  `<totalbar>`, `<totalvbar>`, `<readbar>`, `<readvbar>`, `<writebar>`, and
+  `<writevbar>`.
 - Args: default monitor arguments. `-t`/`--template` is ignored.
 - Default template: none (you must specify a template for each file system).
 - Example:
@@ -945,7 +964,7 @@
     - `--highd` _number_ High threshold for dB. Defaults to -5.0.
     - `--lowd` _number_ Low threshold for dB. Defaults to -30.0.
 - Variables that can be used with the `-t`/`--template` argument:
-            `volume`, `volumebar`, `dB`, `status`
+            `volume`, `volumebar`, `volumevbar`, `dB`, `status`
 - Note that `dB` might only return 0 on your system. This is known
   to happen on systems with a pulseaudio backend.
 - Default template: `Vol: <volume>% <status>`
@@ -964,7 +983,7 @@
   The environment variables `MPD_HOST` and `MPD_PORT` are used to configure the
   mpd server to communicate with.
 - Variables that can be used with the `-t`/`--template` argument:
-             `bar`, `state`, `statei`, `volume`, `length`,
+             `bar`, `vbar`, `state`, `statei`, `volume`, `length`,
              `lapsed`, `remaining`,
              `plength` (playlist length), `ppos` (playlist position),
              `name`, `artist`, `composer`, `performer`,
@@ -993,7 +1012,7 @@
 
 ### `Mpris2 PlayerName Args RefreshRate`
 
-- Aliases to `mpris1`
+- Aliases to `mpris2`
 - Requires [dbus] and [text] packages.
   To activate, pass `--flags="with_mpris"` during compilation.
 - PlayerName: player supporting MPRIS v2 protocol, in lowercase.
@@ -1004,7 +1023,7 @@
 - Default template: `<artist> - <title>`
 - Example:
 
-         Run Mpris2 "clementine" ["-t", "<artist> - [<composer>] <title>"] 10
+         Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10
 
 ### `Mail Args Alias`
 
@@ -1056,10 +1075,24 @@
 
 [samples/xmonadpropwrite.hs script]: https://github.com/jaor/xmobar/raw/master/samples/xmonadpropwrite.hs
 
+### `UnsafeXPropertyLog PropName`
+
+- Aliases to `PropName`
+- Same as `XPropertyLog`, but the input is not filtered to avoid
+  injection of actions (cf. `UnsafeXMonadLog`).  The program writing
+  the value of the read property is responsible of performing any
+  needed cleanups.
+
 ### `NamedXPropertyLog PropName Alias`
 
-- Same as XPropertyLog, but a custom alias can be specified.
+- Aliases to `Alias`
+- Same as `XPropertyLog`, but a custom alias can be specified.
 
+### `NamedXPropertyLog PropName Alias`
+
+- Aliases to `Alias`
+- Same as `UnsafeXPropertyLog`, but a custom alias can be specified.
+
 ### `Brightness Args RefreshRate`
 
 - Aliases to `bright`
@@ -1071,7 +1104,7 @@
     - `-M`: file with the maximum brightness (default:
        max_brightness)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `hbar`, `percent`, `bar`
+	    `vbar`, `percent`, `bar`
 - Default template: `<percent>`
 - Example:
 
@@ -1097,6 +1130,16 @@
 
 	Run Locks
 
+### `CatInt n fn`
+
+- Reads and displays an integer from the file whose path is `fn`
+  (especially useful with files in `/sys`).
+- Aliases as `catn` (e.g. `Cat 0` as `cat0`, etc.) so you can
+  have several.
+- Example:
+
+    Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50
+
 ## Executing External Commands
 
 In order to execute an external command you can either write the
@@ -1228,6 +1271,19 @@
 
 [here]: http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html
 
+<font size="+1">**`UnsafeXMonadLog`**</font>
+
+- Aliases to UnsafeXMonadLog
+- Similar to StdinReader versus UnsafeStdinReader, this does not strip `<action
+  ...>` tags from XMonad's `_XMONAD_LOG`.
+- It is advised that you still use `xmobarStrip` for the ppTitle in your
+  logHook:
+
+        myPP = defaultPP { ppTitle = xmobarStrip }
+        main = xmonad $ defaultConfig {
+          logHook = dynamicLogString myPP >>= xmonadPropLog
+        }
+
 Plugins
 =======
 
@@ -1353,14 +1409,15 @@
 with the help of the greater xmobar and Haskell communities.
 
 In particular, xmobar [incorporates patches] by Ben Boeckel, Roman
-Cheplyaka, Patrick Chilton, John Goerzen, Reto Hablützel, Juraj
-Hercek, Tomas Janousek, Spencer Janssen, Jochen Keil, Lennart
-Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter,
-Dmitry Malikov, David McLean, Marcin Mikołajczyk, Thiago Negri, Edward
-O'Callaghan, Svein Ove, Martin Perner, Jens Petersen, Alexander
-Polakov, Petr Rockai, Peter Simons, Andrew Sackville-West, Alexander
-Solovyov, John Soros, Artem Tarasov, Sergei Trofimovich, Thomas
-Tuegel, Jan Vornberger, Daniel Wagner and Norbert Zeh.
+Cheplyaka, Patrick Chilton, Nathaniel Wesley Filardo, John Goerzen,
+Reto Hablützel, Juraj Hercek, Tomas Janousek, Spencer Janssen, Jochen
+Keil, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin,
+Todd Lunter, Robert J. Macomber, Dmitry Malikov, David McLean, Marcin
+Mikołajczyk, Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove,
+Martin Perner, Jens Petersen, Alexander Polakov, Petr Rockai, Peter
+Simons, Andrew Sackville-West, Alexander Solovyov, John Soros, Artem
+Tarasov, Sergei Trofimovich, Thomas Tuegel, Jan Vornberger, Daniel
+Wagner and Norbert Zeh.
 
 [jao]: http://jao.io
 [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors
diff --git a/src/Actions.hs b/src/Actions.hs
--- a/src/Actions.hs
+++ b/src/Actions.hs
@@ -12,7 +12,7 @@
 
 module Actions (Action(..), runAction, stripActions) where
 
-import System.Process (system)
+import System.Process (runCommand)
 import Control.Monad (void)
 import Text.Regex (Regex, subRegex, mkRegex, matchRegex)
 import Graphics.X11.Types (Button)
@@ -21,7 +21,7 @@
                 deriving (Eq)
 
 runAction :: Action -> IO ()
-runAction (Spawn _ s) = void $ system (s ++ "&")
+runAction (Spawn _ s) = void $ runCommand s
 
 stripActions :: String -> String
 stripActions s = case matchRegex actionRegex s of
diff --git a/src/Parsers.hs b/src/Parsers.hs
--- a/src/Parsers.hs
+++ b/src/Parsers.hs
@@ -25,6 +25,7 @@
 import Commands
 import Actions
 
+import Control.Monad (guard, mzero)
 import qualified Data.Map as Map
 import Text.ParserCombinators.Parsec
 import Text.ParserCombinators.Parsec.Perm
@@ -43,11 +44,20 @@
                           , Nothing)]
       Right x -> return (concat x)
 
+allParsers :: ColorString
+           -> Maybe [Action]
+           -> Parser [(Widget, ColorString, Maybe [Action])]
+allParsers c a =
+        textParser c a
+  <|> try (iconParser c a)
+  <|> try (rawParser c a)
+  <|> try (actionParser c a)
+  <|> colorParser a
+
 -- | Gets the string and combines the needed parsers
 stringParser :: String -> Maybe [Action]
                 -> Parser [[(Widget, ColorString, Maybe [Action])]]
-stringParser c a = manyTill (textParser c a <|> try (iconParser c a) <|>
-                             try (actionParser c a) <|> colorParser a) eof
+stringParser c a = manyTill (allParsers c a) eof
 
 -- | Parses a maximal string without color markup.
 textParser :: String -> Maybe [Action]
@@ -59,9 +69,30 @@
                                    try (string "action=") <|>
                                    try (string "/action>") <|>
                                    try (string "icon=") <|>
+                                   try (string "raw=") <|>
                                    string "/fc>"))
                     return [(Text s, c, a)]
 
+-- | Parse a "raw" tag, which we use to prevent other tags from creeping in.
+-- The format here is net-string-esque: a literal "<raw=" followed by a
+-- string of digits (base 10) denoting the length of the raw string,
+-- a literal ":" as digit-string-terminator, the raw string itself, and
+-- then a literal "/>".
+rawParser :: ColorString
+          -> Maybe [Action]
+          -> Parser [(Widget, ColorString, Maybe [Action])]
+rawParser c a = do
+  string "<raw="
+  lenstr <- many1 digit
+  char ':'
+  case reads lenstr of
+    [(len,[])] -> do
+      guard ((len :: Integer) <= (fromIntegral (maxBound :: Int)))
+      s <- count (fromIntegral len) anyChar
+      string "/>"
+      return [(Text s, c, a)]
+    _ -> mzero
+
 -- | Wrapper for notFollowedBy that returns the result of the first parser.
 --   Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy
 --   accepts only parsers with return type Char.
@@ -88,9 +119,7 @@
       a' = case act of
         Nothing -> Just [a]
         Just act' -> Just $ a : act'
-  s <- manyTill (try (textParser c a') <|> try (iconParser c a') <|>
-                 try (colorParser a') <|> actionParser c a')
-                (try $ string "</action>")
+  s <- manyTill (allParsers c a') (try $ string "</action>")
   return (concat s)
 
 toButtons :: String -> [Button]
@@ -100,8 +129,7 @@
 colorParser :: Maybe [Action] -> Parser [(Widget, ColorString, Maybe [Action])]
 colorParser a = do
   c <- between (string "<fc=") (string ">") colors
-  s <- manyTill (try (textParser c a) <|> try (iconParser c a) <|>
-                 try (colorParser a) <|> actionParser c a) (try $ string "</fc>")
+  s <- manyTill (allParsers c a) (try $ string "</fc>")
   return (concat s)
 
 -- | Parses a color specification (hex or named)
diff --git a/src/Plugins/Mail.hs b/src/Plugins/Mail.hs
--- a/src/Plugins/Mail.hs
+++ b/src/Plugins/Mail.hs
@@ -62,9 +62,9 @@
             atomically $ modifyTVar v (S.union s)
 
         changeLoop (mapM (fmap S.size . readTVar) vs) $ \ns ->
-            cb . unwords $ [m ++ ":" ++  show n
-                                    | (m, n) <- zip ts ns
-                                    , n /= 0 ]
+            cb . unwords $ [m ++ show n
+                            | (m, n) <- zip ts ns
+                            , n /= 0 ]
 
 handle :: TVar (Set String) -> Event -> IO ()
 handle v e = atomically $ modifyTVar v $ case e of
diff --git a/src/Plugins/Monitors.hs b/src/Plugins/Monitors.hs
--- a/src/Plugins/Monitors.hs
+++ b/src/Plugins/Monitors.hs
@@ -35,6 +35,7 @@
 import Plugins.Monitors.Disk
 import Plugins.Monitors.Top
 import Plugins.Monitors.Uptime
+import Plugins.Monitors.CatInt
 #ifdef IWLIB
 import Plugins.Monitors.Wireless
 #endif
@@ -69,6 +70,7 @@
               | TopProc      Args        Rate
               | TopMem       Args        Rate
               | Uptime       Args        Rate
+              | CatInt       Int FilePath Args Rate
 #ifdef IWLIB
               | Wireless Interface  Args Rate
 #endif
@@ -116,6 +118,7 @@
     alias (DiskU _ _ _) = "disku"
     alias (DiskIO _ _ _) = "diskio"
     alias (Uptime _ _) = "uptime"
+    alias (CatInt n _ _ _) = "cat" ++ (show n)
 #ifdef IWLIB
     alias (Wireless i _ _) = i ++ "wi"
 #endif
@@ -151,6 +154,7 @@
     start (DiskU s a r) = runM a diskUConfig (runDiskU s) r
     start (DiskIO s a r) = startDiskIO s a r
     start (Uptime a r) = runM a uptimeConfig runUptime r
+    start (CatInt _ s a r) = runM a catIntConfig (runCatInt s) r
 #ifdef IWLIB
     start (Wireless i a r) = runM (a ++ [i]) wirelessConfig runWireless r
 #endif
diff --git a/src/Plugins/Monitors/Batt.hs b/src/Plugins/Monitors/Batt.hs
--- a/src/Plugins/Monitors/Batt.hs
+++ b/src/Plugins/Monitors/Batt.hs
@@ -80,7 +80,7 @@
 battConfig :: IO MConfig
 battConfig = mkMConfig
        "Batt: <watts>, <left>% / <timeleft>" -- template
-       ["leftbar", "left", "acstatus", "timeleft", "watts"] -- replacements
+       ["leftbar", "leftvbar", "left", "acstatus", "timeleft", "watts"] -- replacements
 
 data Files = Files
   { fFull :: String
@@ -174,7 +174,8 @@
           let x' = minimum [1, x]
           p <- showPercentWithColors x'
           b <- showPercentBar (100 * x') x'
-          return [b, p]
+          vb <- showVerticalBar (100 * x') x'
+          return [b, vb, p]
         fmtWatts x o s d = do
           ws <- showWithPadding $ showDigits d x ++ (if s then "W" else "")
           return $ color x o ws
diff --git a/src/Plugins/Monitors/Bright.hs b/src/Plugins/Monitors/Bright.hs
--- a/src/Plugins/Monitors/Bright.hs
+++ b/src/Plugins/Monitors/Bright.hs
@@ -16,7 +16,6 @@
 
 import Control.Exception (SomeException, handle)
 import qualified Data.ByteString.Lazy.Char8 as B
-import Data.Char
 import System.FilePath ((</>))
 import System.Posix.Files (fileExist)
 import System.Console.GetOpt
@@ -52,7 +51,7 @@
 
 brightConfig :: IO MConfig
 brightConfig = mkMConfig "<percent>" -- template
-                         ["hbar", "percent", "bar"] -- replacements
+                         ["vbar", "percent", "bar"] -- replacements
 
 data Files = Files { fCurr :: String
                    , fMax :: String
@@ -78,7 +77,7 @@
     NoFiles -> return "hurz"
     _ -> fmtPercent c >>= parseTemplate
   where fmtPercent :: Float -> Monitor [String]
-        fmtPercent c = do r <- showHorizontalBar (100 * c)
+        fmtPercent c = do r <- showVerticalBar (100 * c) c
                           s <- showPercentWithColors c
                           t <- showPercentBar (100 * c) c
                           return [r,s,t]
@@ -92,14 +91,3 @@
   where grab f = handle handler (fmap (read . B.unpack) $ B.readFile f)
         handler = const (return 0) :: SomeException -> IO Float
 
-showHorizontalBar :: Float -> Monitor String
-showHorizontalBar x = do
-  return $ [convert x]
-  where convert :: Float -> Char
-        convert val
-          | t <= 9600 = ' '
-          | t > 9608 = chr 9608
-          | otherwise = chr t
-          where
-            -- we scale from 0 to 100, we have 8 slots (9 elements), 100/8 = 12
-            t = 9600 + ((round val) `div` 12)
diff --git a/src/Plugins/Monitors/CatInt.hs b/src/Plugins/Monitors/CatInt.hs
new file mode 100644
--- /dev/null
+++ b/src/Plugins/Monitors/CatInt.hs
@@ -0,0 +1,25 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.CatInt
+-- Copyright   :  (c) Nathaniel Wesley Filardo
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Nathaniel Wesley Filardo
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Monitors.CatInt where
+
+import Plugins.Monitors.Common
+import Plugins.Monitors.CoreCommon
+
+catIntConfig :: IO MConfig
+catIntConfig = mkMConfig "<v>" ["v"]
+
+runCatInt :: FilePath -> [String] -> Monitor String
+runCatInt p _ =
+  let failureMessage = "Cannot read: " ++ (show p)
+      fmt x = show (truncate x :: Int)
+  in  checkedDataRetrieval failureMessage [[p]] Nothing id fmt
diff --git a/src/Plugins/Monitors/Common.hs b/src/Plugins/Monitors/Common.hs
--- a/src/Plugins/Monitors/Common.hs
+++ b/src/Plugins/Monitors/Common.hs
@@ -47,7 +47,9 @@
                        , showPercentWithColors
                        , showPercentsWithColors
                        , showPercentBar
+                       , showVerticalBar
                        , showLogBar
+                       , showLogVBar
                        , showWithUnits
                        , takeDigits
                        , showDigits
@@ -63,6 +65,7 @@
 import Data.IORef
 import qualified Data.Map as Map
 import Data.List
+import Data.Char
 import Numeric
 import Text.ParserCombinators.Parsec
 import System.Console.GetOpt
@@ -449,6 +452,15 @@
   s <- colorizeString v (take len $ cycle bf)
   return $ s ++ take (bw - len) (cycle bb)
 
+showVerticalBar :: Float -> Float -> Monitor String
+showVerticalBar v x = colorizeString 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)
+
 showLogBar :: Float -> Float -> Monitor String
 showLogBar f v = do
   h <- fromIntegral `fmap` getConfigValue high
@@ -459,3 +471,14 @@
                | x <= ll = 1 / bw
                | otherwise = f + logBase 2 (x / hh) / bw
   showPercentBar v $ choose v
+
+showLogVBar :: Float -> Float -> Monitor String
+showLogVBar f v = do
+  h <- fromIntegral `fmap` getConfigValue high
+  l <- fromIntegral `fmap` getConfigValue low
+  bw <- fromIntegral `fmap` getConfigValue barWidth
+  let [ll, hh] = sort [l, h]
+      choose x | x == 0.0 = 0
+               | x <= ll = 1 / bw
+               | otherwise = f + logBase 2 (x / hh) / bw
+  showVerticalBar v $ choose v
diff --git a/src/Plugins/Monitors/CoreCommon.hs b/src/Plugins/Monitors/CoreCommon.hs
--- a/src/Plugins/Monitors/CoreCommon.hs
+++ b/src/Plugins/Monitors/CoreCommon.hs
@@ -26,10 +26,11 @@
 import System.Directory
 
 checkedDataRetrieval :: (Ord a, Num a)
-                     => String -> [String] -> Maybe (String, String -> Int)
+                     => String -> [[String]] -> Maybe (String, String -> Int)
                      -> (Double -> a) -> (a -> String) -> Monitor String
-checkedDataRetrieval msg path lbl trans fmt = liftM (fromMaybe msg) $
-                                              retrieveData path lbl trans fmt
+checkedDataRetrieval msg paths lbl trans fmt =
+  liftM (fromMaybe msg . listToMaybe . catMaybes) $
+    mapM (\p -> retrieveData p lbl trans fmt) paths
 
 retrieveData :: (Ord a, Num a)
              => [String] -> Maybe (String, String -> Int)
diff --git a/src/Plugins/Monitors/CoreTemp.hs b/src/Plugins/Monitors/CoreTemp.hs
--- a/src/Plugins/Monitors/CoreTemp.hs
+++ b/src/Plugins/Monitors/CoreTemp.hs
@@ -38,7 +38,8 @@
    dn <- getConfigValue decDigits
    failureMessage <- getConfigValue naString
    let path = ["/sys/bus/platform/devices/coretemp.", "/temp", "_input"]
+       path' = ["/sys/bus/platform/devices/coretemp.", "/hwmon/hwmon", "/temp", "_input"]
        lbl  = Just ("_label", read . (dropWhile (not . isDigit)))
        divisor = 1e3 :: Double
        show' = showDigits (max 0 dn)
-   checkedDataRetrieval failureMessage path lbl (/divisor) show'
+   checkedDataRetrieval failureMessage [path, path'] lbl (/divisor) show'
diff --git a/src/Plugins/Monitors/Cpu.hs b/src/Plugins/Monitors/Cpu.hs
--- a/src/Plugins/Monitors/Cpu.hs
+++ b/src/Plugins/Monitors/Cpu.hs
@@ -22,14 +22,14 @@
 cpuConfig :: IO MConfig
 cpuConfig = mkMConfig
        "Cpu: <total>%"
-       ["bar","total","user","nice","system","idle","iowait"]
+       ["bar","vbar","total","user","nice","system","idle","iowait"]
 
-type CpuDataRef = IORef [Float]
+type CpuDataRef = IORef [Int]
 
-cpuData :: IO [Float]
+cpuData :: IO [Int]
 cpuData = cpuParser `fmap` B.readFile "/proc/stat"
 
-cpuParser :: B.ByteString -> [Float]
+cpuParser :: B.ByteString -> [Int]
 cpuParser = map (read . B.unpack) . tail . B.words . head . B.lines
 
 parseCpu :: CpuDataRef -> IO [Float]
@@ -38,17 +38,18 @@
        b <- cpuData
        writeIORef cref b
        let dif = zipWith (-) b a
-           tot = foldr (+) 0 dif
-           percent = map (/ tot) dif
+           tot = fromIntegral $ foldr (+) 0 dif
+           percent = map (/ tot) (map fromIntegral dif)
        return percent
 
 formatCpu :: [Float] -> Monitor [String]
-formatCpu [] = return $ replicate 6 ""
+formatCpu [] = return $ replicate 8 ""
 formatCpu xs = do
   let t = sum $ take 3 xs
   b <- showPercentBar (100 * t) t
+  v <- showVerticalBar (100 * t) t
   ps <- showPercentsWithColors (t:xs)
-  return (b:ps)
+  return (b:v:ps)
 
 runCpu :: CpuDataRef -> [String] -> Monitor String
 runCpu cref _ =
diff --git a/src/Plugins/Monitors/CpuFreq.hs b/src/Plugins/Monitors/CpuFreq.hs
--- a/src/Plugins/Monitors/CpuFreq.hs
+++ b/src/Plugins/Monitors/CpuFreq.hs
@@ -36,4 +36,4 @@
       fmt x | x < 1 = (show (round (x * 1000) :: Integer)) ++ "MHz"
             | otherwise = (show x) ++ "GHz"
   failureMessage <- getConfigValue naString
-  checkedDataRetrieval failureMessage path Nothing (/divisor) fmt
+  checkedDataRetrieval failureMessage [path] Nothing (/divisor) fmt
diff --git a/src/Plugins/Monitors/Disk.hs b/src/Plugins/Monitors/Disk.hs
--- a/src/Plugins/Monitors/Disk.hs
+++ b/src/Plugins/Monitors/Disk.hs
@@ -27,12 +27,14 @@
 import System.Directory (canonicalizePath, doesFileExist)
 
 diskIOConfig :: IO MConfig
-diskIOConfig = mkMConfig "" ["total", "read", "write",
-                             "totalbar", "readbar", "writebar"]
+diskIOConfig = mkMConfig "" ["total", "read", "write"
+                            ,"totalbar", "readbar", "writebar"
+                            ,"totalvbar", "readvbar", "writevbar"
+                            ]
 
 diskUConfig :: IO MConfig
 diskUConfig = mkMConfig ""
-              ["size", "free", "used", "freep", "usedp", "freebar", "usedbar"]
+              ["size", "free", "used", "freep", "usedp", "freebar", "freevbar", "usedbar", "usedvbar"]
 
 type DevName = String
 type Path = String
@@ -129,8 +131,9 @@
 runDiskIO' (tmp, xs) = do
   s <- mapM (showWithColors speedToStr) xs
   b <- mapM (showLogBar 0.8) xs
+  vb <- mapM (showLogVBar 0.8) xs
   setConfigValue tmp template
-  parseTemplate $ s ++ b
+  parseTemplate $ s ++ b ++ vb
 
 runDiskIO :: DevDataRef -> [(String, String)] -> [String] -> Monitor String
 runDiskIO dref disks _ = do
@@ -167,8 +170,10 @@
   s <- zipWithM showWithColors' strs [100, freep, 100 - freep]
   sp <- showPercentsWithColors [fr, 1 - fr]
   fb <- showPercentBar (fromIntegral freep) fr
+  fvb <- showVerticalBar (fromIntegral freep) fr
   ub <- showPercentBar (fromIntegral $ 100 - freep) (1 - fr)
-  parseTemplate $ s ++ sp ++ [fb, ub]
+  uvb <- showVerticalBar (fromIntegral $ 100 - freep) (1 - fr)
+  parseTemplate $ s ++ sp ++ [fb,fvb,ub,uvb]
   where ign = const (return [0, 0, 0]) :: SomeException -> IO [Integer]
 
 
diff --git a/src/Plugins/Monitors/MPD.hs b/src/Plugins/Monitors/MPD.hs
--- a/src/Plugins/Monitors/MPD.hs
+++ b/src/Plugins/Monitors/MPD.hs
@@ -22,7 +22,7 @@
 
 mpdConfig :: IO MConfig
 mpdConfig = mkMConfig "MPD: <state>"
-              [ "bar", "state", "statei", "volume", "length"
+              [ "bar", "vbar", "state", "statei", "volume", "length"
               , "lapsed", "remaining", "plength", "ppos", "file"
               , "name", "artist", "composer", "performer"
               , "album", "title", "track", "genre"
@@ -82,11 +82,12 @@
 
 parseMPD :: M.Response M.Status -> M.Response (Maybe M.Song) -> MOpts
             -> Monitor [String]
-parseMPD (Left e) _ _ = return $ show e:replicate 18 ""
+parseMPD (Left e) _ _ = return $ show e:replicate 19 ""
 parseMPD (Right st) song opts = do
   songData <- parseSong song
   bar <- showPercentBar (100 * b) b
-  return $ [bar, ss, si, vol, len, lap, remain, plen, ppos] ++ songData
+  vbar <- showVerticalBar (100 * b) b
+  return $ [bar, vbar, ss, si, vol, len, lap, remain, plen, ppos] ++ songData
   where s = M.stState st
         ss = show s
         si = stateGlyph s opts
diff --git a/src/Plugins/Monitors/Mem.hs b/src/Plugins/Monitors/Mem.hs
--- a/src/Plugins/Monitors/Mem.hs
+++ b/src/Plugins/Monitors/Mem.hs
@@ -20,7 +20,7 @@
 memConfig :: IO MConfig
 memConfig = mkMConfig
        "Mem: <usedratio>% (<cache>M)" -- template
-       ["usedbar", "freebar", "usedratio", "freeratio", "total",
+       ["usedbar", "usedvbar", "freebar", "freevbar", "usedratio", "freeratio", "total",
         "free", "buffer", "cache", "rest", "used"] -- available replacements
 
 fileMEM :: IO String
@@ -49,11 +49,13 @@
     do let f = showDigits 0
            rr = 100 * r
        ub <- showPercentBar rr r
+       uvb <- showVerticalBar rr r
        fb <- showPercentBar (100 - rr) (1 - r)
+       fvb <- showVerticalBar (100 - rr) ( 1 - r)
        rs <- showPercentWithColors r
        fs <- showPercentWithColors fr
        s <- mapM (showWithColors f) xs
-       return (ub:fb:rs:fs:s)
+       return (ub:uvb:fb:fvb:rs:fs:s)
 formatMem _ = replicate 10 `fmap` getConfigValue naString
 
 runMem :: [String] -> Monitor String
diff --git a/src/Plugins/Monitors/MultiCpu.hs b/src/Plugins/Monitors/MultiCpu.hs
--- a/src/Plugins/Monitors/MultiCpu.hs
+++ b/src/Plugins/Monitors/MultiCpu.hs
@@ -19,13 +19,17 @@
 import Data.List (isPrefixOf, transpose, unfoldr)
 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
 
+variables :: [String]
+variables = ["bar", "vbar","total","user","nice","system","idle"]
+vNum :: Int
+vNum = length variables
+
 multiCpuConfig :: IO MConfig
 multiCpuConfig =
   mkMConfig "Cpu: <total>%" $
-            ["auto" ++ k | k <- monitors] ++
+            ["auto" ++ k | k <- variables] ++
             [ k ++ n     | n <- "" : map show [0 :: Int ..]
-                         , k <- monitors]
-    where monitors = ["bar","total","user","nice","system","idle"]
+                         , k <- variables]
 
 type CpuDataRef = IORef [[Float]]
 
@@ -56,20 +60,21 @@
 
 formatCpu :: [Float] -> Monitor [String]
 formatCpu xs
-  | length xs < 4 = showPercentsWithColors $ replicate 6 0.0
+  | length xs < 4 = showPercentsWithColors $ replicate vNum 0.0
   | otherwise = let t = foldr (+) 0 $ take 3 xs
                 in do b <- showPercentBar (100 * t) t
+                      h <- showVerticalBar (100 * t) t
                       ps <- showPercentsWithColors (t:xs)
-                      return (b:ps)
+                      return (b:h:ps)
 
 splitEvery :: (Eq a) => Int -> [a] -> [[a]]
 splitEvery n = unfoldr (\x -> if null x then Nothing else Just $ splitAt n x)
 
 groupData :: [String] -> [[String]]
-groupData = transpose . tail . splitEvery 6
+groupData = transpose . tail . splitEvery vNum
 
 formatAutoCpus :: [String] -> Monitor [String]
-formatAutoCpus [] = return $ replicate 6 ""
+formatAutoCpus [] = return $ replicate vNum ""
 formatAutoCpus xs = return $ map unwords (groupData xs)
 
 runMultiCpu :: CpuDataRef -> [String] -> Monitor String
diff --git a/src/Plugins/Monitors/Net.hs b/src/Plugins/Monitors/Net.hs
--- a/src/Plugins/Monitors/Net.hs
+++ b/src/Plugins/Monitors/Net.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.Net
--- Copyright   :  (c) 2011, 2012, 2013 Jose Antonio Ortega Ruiz
+-- Copyright   :  (c) 2011, 2012, 2013, 2014 Jose Antonio Ortega Ruiz
 --                (c) 2007-2010 Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
 --
@@ -53,7 +53,7 @@
 netConfig :: IO MConfig
 netConfig = mkMConfig
     "<dev>: <rx>KB|<tx>KB"      -- template
-    ["dev", "rx", "tx", "rxbar", "txbar"]     -- available replacements
+    ["dev", "rx", "tx", "rxbar", "rxvbar", "txbar", "txvbar"]     -- available replacements
 
 operstateDir :: String -> FilePath
 operstateDir d = "/sys/class/net" </> d </> "operstate"
@@ -67,7 +67,7 @@
 isUp :: String -> IO Bool
 isUp d = do
   operstate <- B.readFile (operstateDir d)
-  return $ "up" == (B.unpack . head . B.lines) operstate
+  return $ (B.unpack . head . B.lines) operstate `elem`  ["up", "unknown"]
 
 readNetDev :: [String] -> IO NetDev
 readNetDev (d:x:y:_) = do
@@ -97,22 +97,23 @@
         isDev (NI d) = d == dev
         isDev NA = False
 
-formatNet :: Float -> Monitor (String, String)
+formatNet :: Float -> Monitor (String, String, String)
 formatNet d = do
     s <- getConfigValue useSuffix
     dd <- getConfigValue decDigits
     let str = if s then (++"Kb/s") . showDigits dd else showDigits dd
     b <- showLogBar 0.9 d
+    vb <- showLogVBar 0.9 d
     x <- showWithColors str d
-    return (x, b)
+    return (x, b, vb)
 
 printNet :: NetDev -> Monitor String
 printNet nd =
   case nd of
     ND d r t -> do
-        (rx, rb) <- formatNet r
-        (tx, tb) <- formatNet t
-        parseTemplate [d,rx,tx,rb,tb]
+        (rx, rb, rvb) <- formatNet r
+        (tx, tb, tvb) <- formatNet t
+        parseTemplate [d,rx,tx,rb,rvb,tb,tvb]
     NI _ -> return ""
     NA -> getConfigValue naString
 
diff --git a/src/Plugins/Monitors/Volume.hs b/src/Plugins/Monitors/Volume.hs
--- a/src/Plugins/Monitors/Volume.hs
+++ b/src/Plugins/Monitors/Volume.hs
@@ -24,7 +24,7 @@
 
 volumeConfig :: IO MConfig
 volumeConfig = mkMConfig "Vol: <volume>% <status>"
-                         ["volume", "volumebar", "dB","status"]
+                         ["volume", "volumebar", "volumevbar", "dB","status"]
 
 
 data VolumeOpts = VolumeOpts
@@ -76,6 +76,10 @@
 formatVolBar lo hi v =
     showPercentBar (100 * x) x where x = percent v lo hi
 
+formatVolVBar :: Integer -> Integer -> Integer -> Monitor String
+formatVolVBar lo hi v =
+    showVerticalBar (100 * x) x where x = percent v lo hi
+
 switchHelper :: VolumeOpts
              -> (VolumeOpts -> Maybe String)
              -> (VolumeOpts -> String)
@@ -119,9 +123,10 @@
         return (lo, hi, val, db, sw)
     p <- liftMonitor $ liftM3 formatVol lo hi val
     b <- liftMonitor $ liftM3 formatVolBar lo hi val
+    v <- liftMonitor $ liftM3 formatVolVBar lo hi val
     d <- getFormatDB opts db
     s <- getFormatSwitch opts sw
-    parseTemplate [p, b, d, s]
+    parseTemplate [p, b, v, d, s]
 
   where
 
diff --git a/src/Plugins/Monitors/Weather.hs b/src/Plugins/Monitors/Weather.hs
--- a/src/Plugins/Monitors/Weather.hs
+++ b/src/Plugins/Monitors/Weather.hs
@@ -16,7 +16,8 @@
 
 import Plugins.Monitors.Common
 
-import Control.Exception (catch, IOException)
+import qualified Control.Exception as CE
+
 import Network.HTTP
 
 import Text.ParserCombinators.Parsec
@@ -133,8 +134,8 @@
 getData :: String -> IO String
 getData station = do
     let request = getRequest (stationUrl station)
-    catch (simpleHTTP request >>= getResponseBody) errHandler
-    where errHandler :: IOException -> IO String
+    CE.catch (simpleHTTP request >>= getResponseBody) errHandler
+    where errHandler :: CE.IOException -> IO String
           errHandler _ = return "<Could not retrieve data>"
 
 formatWeather :: [WeatherInfo] -> Monitor String
@@ -154,8 +155,8 @@
 weatherReady str = do
     let station = head str
         request = headRequest (stationUrl station)
-    io $ catch (simpleHTTP request >>= checkResult) errHandler
-    where errHandler :: IOException -> IO Bool
+    io $ CE.catch (simpleHTTP request >>= checkResult) errHandler
+    where errHandler :: CE.IOException -> IO Bool
           errHandler _ = return False
           checkResult result = do
             case result of
diff --git a/src/Plugins/Monitors/Wireless.hs b/src/Plugins/Monitors/Wireless.hs
--- a/src/Plugins/Monitors/Wireless.hs
+++ b/src/Plugins/Monitors/Wireless.hs
@@ -19,7 +19,7 @@
 
 wirelessConfig :: IO MConfig
 wirelessConfig =
-  mkMConfig "<essid> <quality>" ["essid", "quality", "qualitybar"]
+  mkMConfig "<essid> <quality>" ["essid", "quality", "qualitybar", "qualityvbar"]
 
 runWireless :: [String] -> Monitor String
 runWireless (iface:_) = do
@@ -33,5 +33,6 @@
        then showPercentWithColors (qlty / 100)
        else showWithPadding ""
   qb <- showPercentBar qlty (qlty / 100)
-  parseTemplate [ep, q, qb]
+  qvb <- showVerticalBar qlty (qlty / 100)
+  parseTemplate [ep, q, qb, qvb]
 runWireless _ = getConfigValue naString
diff --git a/src/Plugins/XMonadLog.hs b/src/Plugins/XMonadLog.hs
--- a/src/Plugins/XMonadLog.hs
+++ b/src/Plugins/XMonadLog.hs
@@ -31,20 +31,35 @@
 import Actions (stripActions)
 
 data XMonadLog = XMonadLog
+               | UnsafeXMonadLog
                | XPropertyLog String
+               | UnsafeXPropertyLog String
                | NamedXPropertyLog String String
+               | UnsafeNamedXPropertyLog String String
     deriving (Read, Show)
 
 instance Exec XMonadLog where
     alias XMonadLog = "XMonadLog"
+    alias UnsafeXMonadLog = "UnsafeXMonadLog"
     alias (XPropertyLog atom) = atom
     alias (NamedXPropertyLog _ name) = name
+    alias (UnsafeXPropertyLog atom) = atom
+    alias (UnsafeNamedXPropertyLog _ name) = name
 
     start x cb = do
         let atom = case x of
-                XMonadLog             -> "_XMONAD_LOG"
-                XPropertyLog      a   -> a
+                XMonadLog -> "_XMONAD_LOG"
+                UnsafeXMonadLog -> "_XMONAD_LOG"
+                XPropertyLog a -> a
+                UnsafeXPropertyLog a -> a
                 NamedXPropertyLog a _ -> a
+                UnsafeNamedXPropertyLog a _ -> a
+            sanitize = case x of
+                UnsafeXMonadLog -> id
+                UnsafeXPropertyLog _ -> id
+                UnsafeNamedXPropertyLog _ _ -> id
+                _ -> stripActions
+
         d <- openDisplay ""
         xlog <- internAtom d atom False
 
@@ -53,7 +68,7 @@
 
         let update = do
                         mwp <- getWindowProperty8 d xlog root
-                        maybe (return ()) (cb . stripActions. decodeCChar) mwp
+                        maybe (return ()) (cb . sanitize . decodeCChar) mwp
 
         update
 
diff --git a/src/StatFS.hsc b/src/StatFS.hsc
--- a/src/StatFS.hsc
+++ b/src/StatFS.hsc
@@ -54,7 +54,7 @@
 #ifdef IS_BSD_SYSTEM
 foreign import ccall unsafe "sys/mount.h statfs"
 #else
-foreign import ccall unsafe "sys/statvfs.h statvfs"
+foreign import ccall unsafe "sys/vfs.h statvfs"
 #endif
   c_statfs :: CString -> Ptr CStatfs -> IO CInt
 
diff --git a/xmobar.cabal b/xmobar.cabal
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,7 +1,6 @@
 name:               xmobar
-version:            0.20.1
-homepage:           http://projects.haskell.org/xmobar/
-bug-reports:        http://code.google.com/p/xmobar/issues
+version:            0.21
+homepage:           http://xmobar.org
 synopsis:           A Minimalistic Text Based Status Bar
 description: 	    Xmobar is a minimalistic text based status bar.
 		    .
@@ -11,8 +10,9 @@
 category:           System
 license:            BSD3
 license-file:       license
-author:             Andrea Rossato, Jose A. Ortega Ruiz
+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.6
 build-type:         Simple
 
@@ -88,7 +88,7 @@
       Plugins.Monitors.Swap, Plugins.Monitors.Thermal,
       Plugins.Monitors.ThermalZone, Plugins.Monitors.Top,
       Plugins.Monitors.Uptime, Plugins.Monitors.Weather,
-      Plugins.Monitors.Bright
+      Plugins.Monitors.Bright, Plugins.Monitors.CatInt
 
     ghc-prof-options:   -prof -auto-all
     ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
@@ -106,7 +106,7 @@
       time,
       filepath,
       X11 >= 1.6.1,
-      mtl >= 2.0 && < 2.2,
+      mtl >= 2.0 && < 2.3,
       parsec == 3.1.*,
       HTTP >= 4000,
       stm >= 2.3 && < 2.5
