diff --git a/Monky.hs b/Monky.hs
--- a/Monky.hs
+++ b/Monky.hs
@@ -33,51 +33,90 @@
 other functions later on.
 -}
 module Monky
-  ( startLoop
-  )
+    ( startLoop
+    , startLoopT
+    )
 where
 
-
-import Control.Concurrent (threadDelay)
+import System.Timeout
+import Data.Time.Clock.POSIX
+import Control.Concurrent.MVar
 import Data.IORef (IORef, readIORef, writeIORef, newIORef, atomicWriteIORef)
 import Monky.Modules
-import Control.Monad (when)
+import Control.Monad (when, void)
 import Control.Concurrent (forkIO)
 
 
 data ModuleWrapper = MWrapper Modules (IORef [MonkyOut])
 
 -- |Packs a module into a wrapper with an IORef for cached output
-packMod :: Modules -> IO ModuleWrapper
-packMod x@(Poll (NMW m _)) = do
-  sref <- newIORef []
-  initialize m
-  return (MWrapper x sref)
-packMod x@(Evt (DW m)) = do
-  sref <- newIORef []
-  _ <- forkIO (startEvtLoop m (atomicWriteIORef sref))
-  return $ MWrapper x sref
+packMod :: MVar Bool -> Modules -> IO ModuleWrapper
+packMod _ x@(Poll (NMW m _)) = do
+    sref <- newIORef []
+    initialize m
+    return (MWrapper x sref)
+packMod mvar x@(Evt (DW m)) = do
+    sref <- newIORef []
+    _ <- forkIO . startEvtLoop m $ \val -> do
+        atomicWriteIORef sref val
+        void $ tryPutMVar mvar True
+    return $ MWrapper x sref
 
 getWrapperText :: Int -> ModuleWrapper -> IO [MonkyOut]
 getWrapperText tick (MWrapper (Poll (NMW m i)) r) = do
-  when (tick `mod` i == 0) (writeIORef r =<< getOutput m)
-  readIORef r
+    when (tick `mod` i == 0) (writeIORef r =<< getOutput m)
+    readIORef r
 getWrapperText _ (MWrapper (Evt _) r) = readIORef r
 
 doMonkyLine :: MonkyOutput o => Int -> o -> [ModuleWrapper] -> IO ()
 doMonkyLine t o xs =
-  doLine o =<< mapM (getWrapperText t) xs
+    doLine o =<< mapM (getWrapperText t) xs
 
-mainLoop :: MonkyOutput o => Int -> o -> [ModuleWrapper] -> IO ()
-mainLoop t o xs = do
-  doMonkyLine t o xs
-  threadDelay 1000000
-  mainLoop (t+1) o xs
+doCachedLine :: MonkyOutput o => o -> [ModuleWrapper] -> IO ()
+doCachedLine out xs =
+    doLine out =<< mapM (\(MWrapper _ r) -> readIORef r) xs
 
--- |Start the mainLoop of monky. This should be the return type of your main
+waitTick :: MonkyOutput o => Int -> MVar Bool -> o -> [ModuleWrapper] -> IO ()
+waitTick limit mvar out xs = do
+    pre <- getPOSIXTime
+    ret <- timeout limit $ takeMVar mvar
+    case ret of
+        Nothing -> return ()
+        Just _ -> do
+            doCachedLine out xs
+            post <- getPOSIXTime
+            let passed = round . (* 1000000) $ post - pre
+            if passed > limit
+                then return ()
+                else waitTick (limit - passed) mvar out xs
+
+mainLoop :: MonkyOutput o => Int -> MVar Bool -> Int -> o -> [ModuleWrapper] -> IO ()
+mainLoop l r t o xs = do
+    doMonkyLine t o xs
+    waitTick l r o xs
+    mainLoop l r (t+1) o xs
+
+{- | Start the mainLoop of monky. With custom tick timer (in μs)
+
+For 1s tick-timer pass @1000000@ to this.
+This does not scale the timers for collection modules passed into it.
+So if @500000@ is passed here, and a collector should update every second
+it needs to update every 2nd tick, so it has to be scaled.
+
+@
+    startLoop getAsciiOut [ pollPack 1 $ getRawCPU ]
+
+    startLoopT 500000 getAsciiOut [ pollPack 2 $ getRawCPU ]
+@
+-}
+startLoopT :: MonkyOutput o => Int -> IO o -> [IO Modules] -> IO ()
+startLoopT t out mods = do
+    mvar <- newEmptyMVar
+    m <- sequence mods
+    l <- mapM (packMod mvar) m
+    o <- out
+    mainLoop t mvar 0 o l
+
+-- | Start the mainLoop of monky. This should be the return type of your main
 startLoop :: MonkyOutput o => IO o -> [IO Modules] -> IO ()
-startLoop o mods = do
-  m <- sequence mods
-  l <- mapM packMod m
-  out <- o
-  mainLoop 0 out l
+startLoop out mods = startLoopT 1000000 out mods
diff --git a/Monky/CPU.hs b/Monky/CPU.hs
--- a/Monky/CPU.hs
+++ b/Monky/CPU.hs
@@ -1,5 +1,5 @@
 {-
-    Copyright 2015 Markus Ongyerth, Stephan Guenther
+    Copyright 2015-2017 Markus Ongyerth, Stephan Guenther
 
     This file is part of Monky.
 
@@ -115,16 +115,23 @@
 getCPUFreqsMax = mapM (fopen . pathMaxScaling)
 
 
--- |Check if thermal zone is x86_pkg_temp
-isX86PkgTemp :: String -> Bool
-isX86PkgTemp xs = unsafePerformIO $do
-  str <- readFile (thermalBaseP ++ xs ++ "/type")
-  return (str == "x86_pkg_temp\n")
+-- | Check if thermal zone is x86_pkg_temp
+checkType :: (String -> Bool) ->  String -> Bool
+checkType f xs = unsafePerformIO $ do
+    f <$> readFile (thermalBaseP ++ xs ++ "/type")
 
--- |Try to guess the thermal zones
+-- | Get the filter function for the thermal zone getter
+thermalGuesser :: String -> Bool
+thermalGuesser =
+    let (ma, mi) = getKernelVersion
+     in if ma <= 3 && mi <= 13
+           then checkType ("pkg-temp-" `isPrefixOf`)
+           else checkType (== "x86_pkg_temp\n")
+
+-- | Try to guess the thermal zones
 guessThermalZones :: IO [String]
 guessThermalZones = do
-  filter isX86PkgTemp . filter ("thermal_zone" `isPrefixOf`) <$> tzones
+  filter thermalGuesser . filter ("thermal_zone" `isPrefixOf`) <$> tzones
   where tzones = getDirectoryContents thermalBaseP
 
 -- |Tries to guess the thermal zone based on type
diff --git a/Monky/CUtil.hsc b/Monky/CUtil.hsc
new file mode 100644
--- /dev/null
+++ b/Monky/CUtil.hsc
@@ -0,0 +1,82 @@
+{-
+    Copyright 2017 Markus Ongyerth
+
+    This file is part of Monky.
+
+    Monky is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Monky is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with Monky.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-|
+Module      : Monky.CUtil
+Description : Provides C utility functions
+Maintainer  : ongy
+Stability   : testing
+Portability : Linux
+
+This provides low-level utility wrappers used by Monky.Util
+-}
+module Monky.CUtil
+    ( UName(..)
+    , uname
+    )
+where
+
+import Data.Word (Word)
+import Foreign.Ptr
+import Foreign.C.Types
+
+import Data.Text (Text)
+import qualified Data.Text.Foreign as T
+
+import Foreign.Storable
+import Foreign.Marshal.Alloc
+
+import Control.Applicative ((<$>), (<*>))
+
+#include <sys/utsname.h>
+
+foreign import ccall unsafe "strlen" c_strlen :: Ptr CChar -> IO Word
+foreign import ccall unsafe "uname" c_uname :: Ptr UName -> IO ()
+
+-- | The haskell type for Cs utsname (man uname)
+data UName = UName
+    { _uSysName  :: Text
+    , _uNodeName :: Text
+    , _uRelease  :: Text
+    , _uVersion  :: Text
+    , _uMachine  :: Text
+    } deriving (Eq, Show)
+
+peekCString :: Ptr CChar -> IO Text
+peekCString ptr = do
+    len <- c_strlen ptr
+    T.peekCStringLen (ptr, fromIntegral len)
+
+instance Storable UName where
+    sizeOf _ = #{size struct utsname}
+    alignment _ = alignment (undefined :: CLong)
+    peek p = UName
+        <$> peekCString (#{ptr struct utsname, sysname} p)
+        <*> peekCString (#{ptr struct utsname, nodename} p)
+        <*> peekCString (#{ptr struct utsname, release} p)
+        <*> peekCString (#{ptr struct utsname, version} p)
+        <*> peekCString (#{ptr struct utsname, machine} p)
+    poke _ _ = error "There is no reason we should EVER poke a struct utsname. Please check your code."
+
+-- | Get a UName structure for the current kernel
+uname :: IO UName
+uname = alloca $ \ptr -> do
+    c_uname ptr
+    peek ptr
diff --git a/Monky/Examples/Sound/Pulse.hs b/Monky/Examples/Sound/Pulse.hs
--- a/Monky/Examples/Sound/Pulse.hs
+++ b/Monky/Examples/Sound/Pulse.hs
@@ -38,13 +38,12 @@
 where
 
 import Monky.Modules
-import Data.Maybe (fromMaybe)
 import Control.Monad (void)
-import Control.Concurrent.MVar
-import Control.Concurrent
+import Control.Monad.IO.Class
 
 import System.Environment (getProgName)
 
+import Sound.Pulse
 import Sound.Pulse.Context
 import Sound.Pulse.Mainloop
 import Sound.Pulse.Mainloop.Simple
@@ -83,32 +82,22 @@
         else sformat ((left 3 ' ' %. int) % "%") (round rvol :: Int)
     fun [MonkyPlain str]
 
--- |Start the subscription loop that will give us the updates.
-startLoop :: Context -> ([MonkyOut] -> IO ()) -> Sinkinfo -> IO ()
-startLoop cxt cfun info = do 
-    void $ subscribeEvents cxt [SubscriptionMaskSink] fun
-    printSink cfun info
-    where fun :: ((SubscriptionEventFacility, SubscriptionEventType) -> Word32 -> IO ())
-          fun _ 0 = void $ getContextSinkByIndex cxt (siIndex info) (printSink cfun)
-          fun _ _ = return ()
-
--- |Use the name (string) to find the index, print once and find the main loop
-startWithName :: Context -> String -> ([MonkyOut] -> IO ()) -> IO ()
-startWithName cxt name fun = void $ getContextSinkByName cxt name (startLoop cxt fun)
-
--- |Get the default sink and start the main loop
-getDefaultSink :: Context -> ([MonkyOut] -> IO ()) -> IO ()
-getDefaultSink cxt cfun = void $ getServerInfo cxt fun
-    where fun :: ServerInfo -> IO ()
-          fun serv = let name = defaultSinkName serv
-                     in startWithName cxt name cfun
+-- | Find the index of our sink and register the event handler
+startLoopM :: Maybe String -> ([MonkyOut] -> IO ()) -> Pulse ()
+startLoopM str fun = do
+    name <- maybe (defaultSinkName <$> getServerInfoM) return str
+    sink <- getContextSinkByNameM name
+    void $ subscribeEventsM [SubscriptionMaskSink] (sub $ siIndex sink)
+    liftIO $ printSink fun sink
+    where sub :: Word32 -> Context -> ((SubscriptionEventFacility, SubscriptionEventType) -> Word32 -> IO ())
+          sub i cxt _ 0 = void $ getContextSinkByIndex cxt i (printSink fun)
+          sub _ _   _ _ = return ()
 
--- |Try to start pulse loop. silently fail!
+-- | Try to start pulse loop. silently fail!
 startPulse :: Maybe String -> ([MonkyOut] -> IO ()) -> IO ()
 startPulse = startPulseMaybe (return ())
 
-
--- |Connect to pulse server and try to start the main loop for this module.
+-- | Connect to pulse server and try to start the main loop for this module.
 startPulseMaybe
     :: IO () -- ^The continuation if everything fails
     -> Maybe String -- ^Sink to use (Nothing for default)
@@ -124,9 +113,8 @@
             ContextFailed -> do
                 hPutStrLn stderr "Could not connect to pulse :("
                 quitLoop impl (-1)
-            ContextReady -> fromMaybe
-                (getDefaultSink cxt fun )
-                (startWithName cxt <$> sinkName <*> return fun)
+            ContextReady ->
+                runPulse_ cxt (startLoopM sinkName fun)
             _ -> return ()
     _ <- connectContext cxt Nothing []
     _ <- doLoop impl
diff --git a/Monky/Outputs/Ascii.hs b/Monky/Outputs/Ascii.hs
--- a/Monky/Outputs/Ascii.hs
+++ b/Monky/Outputs/Ascii.hs
@@ -17,7 +17,6 @@
     along with Monky.  If not, see <http://www.gnu.org/licenses/>.
 -}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE EmptyDataDecls #-}
 {-|
 Module      : Monky.Outputs.Ascii
 Description : Output module for Ascii
@@ -30,6 +29,7 @@
 module Monky.Outputs.Ascii
   ( AsciiOutput
   , getAsciiOut
+  , getAsciiOutDiv
   )
 where
 
@@ -39,7 +39,7 @@
 import qualified Data.Text.IO as T
 
 -- |The output handle for a ascii pipe
-data AsciiOutput = AsciiOutput
+data AsciiOutput = AsciiOutput MonkyOut
 
 doOut :: MonkyOut -> IO ()
 doOut (MonkyPlain t)   = T.putStr t
@@ -57,11 +57,17 @@
     doSegment x
     putStr "\n"
     hFlush stdout
-  doLine h (x:xs) = do
+  doLine h@(AsciiOutput d) (x:xs) = do
     doSegment x
-    putStr " | "
+    doOut d
     doLine h xs
 
--- |Get an output handle for ascii formatting
+-- |Get an output handle for ascii formatting. Divider Defaults to @" | "@
 getAsciiOut :: IO AsciiOutput
-getAsciiOut = return AsciiOutput
+getAsciiOut = getAsciiOutDiv $ MonkyPlain " | "
+
+-- |Get an output handle for ascii formatting
+getAsciiOutDiv
+  :: MonkyOut -- ^The Divider
+  -> IO AsciiOutput
+getAsciiOutDiv = return . AsciiOutput
diff --git a/Monky/Outputs/Dzen2.hs b/Monky/Outputs/Dzen2.hs
--- a/Monky/Outputs/Dzen2.hs
+++ b/Monky/Outputs/Dzen2.hs
@@ -30,6 +30,7 @@
   ( DzenOutput
   , getDzenOut
   , getDzenOut'
+  , getDzenOutDiv
   )
 where
 
@@ -42,19 +43,19 @@
 import qualified Data.Text.IO as T
 
 -- |The output handle for dzen2 pipe
-data DzenOutput = DzenOutput Int Text
+data DzenOutput = DzenOutput Int Text MonkyOut
 
 doOut :: DzenOutput -> MonkyOut -> IO ()
 doOut _ (MonkyPlain t) = T.putStr t
-doOut (DzenOutput _ p) (MonkyImage path _) = do
+doOut (DzenOutput _ p _) (MonkyImage path _) = do
   T.putStr ("^i(" `T.append` p)
   T.putStr path
   T.putStr ".xbm) "
-doOut (DzenOutput h _) (MonkyBar p) = do
+doOut (DzenOutput h _ _) (MonkyBar p) = do
   T.putStr "^p(3)^p(_TOP)^r(6x"
   putStr . show $ h - div (h * p) 100
   T.putStr ")^pa()"
-doOut (DzenOutput h _) (MonkyHBar p) = do
+doOut (DzenOutput h _ _) (MonkyHBar p) = do
   T.putStr "^r("
   putStr . show $ p
   T.putStr ("x" `T.append` (T.pack . show $ h `div` 2) `T.append` ")")
@@ -77,24 +78,33 @@
     doSegment h x
     putStr "\n"
     hFlush stdout
-  doLine h (x:xs) = do
+  doLine h@(DzenOutput _ _ d) (x:xs) = do
     doSegment h x
-    putStr " | "
+    doOut h d
     doLine h xs
 
 -- |Get an output handle for dzen2 formatting
+-- Assumes @" | "@ as divider
 getDzenOut
   :: Int -- ^The height of your dzen bar in pixel (required for block-drawing)
   -> Text -- ^Path to the directory cointaining your .xbm files.
   -> IO DzenOutput
-getDzenOut h = return . DzenOutput h . flip T.append "/"
+getDzenOut h p = return $ DzenOutput h (T.append p "/") $ MonkyPlain " | "
 
 
 -- |Get the output handle for dzen2 formatting. Will asume your .xbm files are
--- |in <monkydir>/xbm/
+-- in \<monkydir\>\/xbm\/
 getDzenOut'
     :: Int -- ^The height of your dzen bar in pixel (for block drawing)
     -> IO DzenOutput
 getDzenOut' h = do
     pwd <- getCurrentDirectory
     getDzenOut h (T.pack pwd `T.append` "/xbm/")
+
+-- |Get an output handle for dzen2 formatting
+getDzenOutDiv
+    :: Int -- ^The height of your dzen bar in pixel (required for block-drawing)
+    -> Text -- ^Path to the directory containing your .xbm files.
+    -> MonkyOut -- ^Divider
+    -> IO DzenOutput
+getDzenOutDiv h p d = return $ DzenOutput h (T.append p "/") d
diff --git a/Monky/Outputs/Guess.hs b/Monky/Outputs/Guess.hs
--- a/Monky/Outputs/Guess.hs
+++ b/Monky/Outputs/Guess.hs
@@ -19,6 +19,7 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-|
 Module      : Monky.Outputs.Guess
 Description : Guess the output that should be used based on pipe
@@ -30,6 +31,7 @@
 module Monky.Outputs.Guess
   ( guessOutput
   , GuessOut
+  , guessOutputDiv
   )
 where
 
@@ -46,7 +48,7 @@
 import Monky.Modules
 import Monky.Outputs.Fallback (chooseTerminalOut)
 import Monky.Outputs.Show (getShowOut)
-import Monky.Outputs.Dzen2 (getDzenOut)
+import Monky.Outputs.Dzen2 (getDzenOutDiv)
 import Monky.Outputs.I3 (getI3Output)
 import Monky.Outputs.Serialize (getSerializeOut)
 
@@ -122,10 +124,11 @@
 chooseProcessOut
   :: Int
   -> Text
+  -> MonkyOut
   -> String
   -> IO GuessOut
-chooseProcessOut height path x
-  | x == "dzen2" = GO <$> getDzenOut height path
+chooseProcessOut height path divider x
+  | x == "dzen2" = GO <$> getDzenOutDiv height path divider
   | x == "i3bar" = GO <$> getI3Output
   | x `elem`networkOuts = GO <$> getSerializeOut
   | otherwise = GO <$> getShowOut
@@ -135,9 +138,18 @@
   :: Int -- ^Dzen height
   -> Text -- ^Dzen xbm path
   -> IO GuessOut
-guessOutput height path = do
+guessOutput height path = guessOutputDiv height path $ MonkyPlain " | "
+
+-- | Guess output based on isatty and other side of the stdout fd
+guessOutputDiv
+  :: Int -- ^Dzen height
+  -> Text -- ^Dzen xbm path
+  -> MonkyOut -- ^The Divider to use
+  -> IO GuessOut
+guessOutputDiv height path divider = do
   out <- getOutputType
   case out of
     Terminal -> GO <$> chooseTerminalOut
     Other -> {- for other we just use show -} GO <$> getShowOut
-    (Process x) -> chooseProcessOut height path x
+    (Process x) -> chooseProcessOut height path divider x
+
diff --git a/Monky/Outputs/I3.hs b/Monky/Outputs/I3.hs
--- a/Monky/Outputs/I3.hs
+++ b/Monky/Outputs/I3.hs
@@ -51,6 +51,10 @@
 i3Full :: Text -> Text
 i3Full xs = "\"full_text\": \"" `T.append` xs `T.append` "\""
 
+makeColor :: Text -> Text -> Text
+makeColor "" _ = ""
+makeColor x y = T.concat [ ", \"", y, "\": \"", x, "\"" ]
+
 getOut :: MonkyOut -> Text
 getOut (MonkyPlain t)   = i3Full t
 getOut (MonkyImage _ c)   = i3Full $ T.singleton c -- Images are not supported :(
@@ -58,11 +62,8 @@
 getOut (MonkyHBar p)    = i3Full $ T.pack (replicate (p `div` 10) '█') `T.append` (T.singleton $ hBarChar (p `mod` 10 * 10))
 getOut (MonkyColor (f, b) o) = T.concat
   [ getOut o
-  , ", \"color\": \""
-  , f
-  , "\", \"background\": \""
-  , b
-  , "\""
+  , makeColor f "color"
+  , makeColor b "background"
   ]
 
 doSegment :: [MonkyOut] -> IO ()
diff --git a/Monky/Outputs/Modify.hs b/Monky/Outputs/Modify.hs
new file mode 100644
--- /dev/null
+++ b/Monky/Outputs/Modify.hs
@@ -0,0 +1,49 @@
+{-
+    Copyright 2016 Markus Ongyerth
+
+    This file is part of Monky.
+
+    Monky is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Monky is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with Monky.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{-# LANGUAGE CPP #-}
+{-|
+Module      : Monky.Output.Modify
+Description : Monky module that modifies other outputs behaviour
+Maintainer  : ongy
+Stability   : testing
+Portability : Linux
+
+-}
+module Monky.Outputs.Modify
+  ( ModifyOutput
+  , getModifyOutput
+  )
+where
+
+#if MIN_VERSION_base(4,8,0)
+#else
+import Control.Applicative ((<$>))
+#endif
+
+import Monky.Modules
+
+-- |Handle for modifying a line before it's passed to the output
+data ModifyOutput a = MH ([[MonkyOut]] -> [[MonkyOut]]) a
+
+-- |Get a handle to purely modify a line
+getModifyOutput :: ([[MonkyOut]] -> [[MonkyOut]]) -> IO a -> IO (ModifyOutput a)
+getModifyOutput = fmap . MH
+
+instance MonkyOutput a => MonkyOutput (ModifyOutput a) where
+    doLine (MH f x) line = doLine x $ f line
diff --git a/Monky/Outputs/Utf8.hs b/Monky/Outputs/Utf8.hs
--- a/Monky/Outputs/Utf8.hs
+++ b/Monky/Outputs/Utf8.hs
@@ -17,7 +17,6 @@
     along with Monky.  If not, see <http://www.gnu.org/licenses/>.
 -}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE EmptyDataDecls #-}
 {-|
 Module      : Monky.Outputs.Utf8
 Description : Output module for utf8
@@ -30,6 +29,7 @@
 module Monky.Outputs.Utf8
   ( Utf8Output
   , getUtf8Out
+  , getUtf8OutDiv
   )
 where
 
@@ -40,11 +40,11 @@
 import qualified Data.Text.IO as T
 
 -- |The output handle for a utf8 pipe
-data Utf8Output = Utf8Output
+data Utf8Output = Utf8Output MonkyOut
 
 doOut :: MonkyOut -> IO ()
 doOut (MonkyPlain t)   = T.putStr t
-doOut (MonkyImage _ c)   = putChar c -- Images are not supported :(
+doOut (MonkyImage _ c) = putChar c -- Images are not supported :(
 doOut (MonkyBar p)     = putChar (barChar p)
 doOut (MonkyHBar p)    = do
   putStr $ replicate (p `div` 10) '█'
@@ -60,11 +60,18 @@
     doSegment x
     putStr "\n"
     hFlush stdout
-  doLine h (x:xs) = do
+  doLine h@(Utf8Output d) (x:xs) = do
     doSegment x
-    putStr " | "
+    doOut d
     doLine h xs
 
--- |Get an output handle for utf8 formatting
+-- |Get an output handle for utf8 formatting. Divider defaults to @" | "@
 getUtf8Out :: IO Utf8Output
-getUtf8Out = return Utf8Output
+getUtf8Out = getUtf8OutDiv $ MonkyPlain " | "
+
+
+-- |Get an output handle for utf8 formatting.
+getUtf8OutDiv
+  :: MonkyOut -- ^The divider between segments
+  -> IO Utf8Output
+getUtf8OutDiv = return . Utf8Output
diff --git a/Monky/Utility.hs b/Monky/Utility.hs
--- a/Monky/Utility.hs
+++ b/Monky/Utility.hs
@@ -1,5 +1,5 @@
 {-
-    Copyright 2015,2016 Markus Ongyerth, Stephan Guenther
+    Copyright 2015-2017 Markus Ongyerth, Stephan Guenther
 
     This file is part of Monky.
 
@@ -28,26 +28,34 @@
 This module provides utility functions used in monky modules
 -}
 module Monky.Utility
- ( readValue
- , readValues
- , fopen
- , fclose
- , File
- , readLine
- , readContent
- , findLine
- , splitAtEvery
- , maybeOpenFile
- , sdivBound
- , sdivUBound
- , listDirectory
- )
+    ( readValue
+    , readValues
+    , fopen
+    , fclose
+    , File
+    , readLine
+    , readContent
+    , findLine
+    , splitAtEvery
+    , maybeOpenFile
+    , sdivBound
+    , sdivUBound
+    , listDirectory
+    , C.UName
+    , getUname
+    , getKernelVersion
+    )
 where
 
+import Data.Word (Word)
+import qualified Monky.CUtil as C
 import System.IO
+import System.IO.Unsafe (unsafePerformIO)
 import Data.List (isPrefixOf)
 
 import Data.Maybe (fromMaybe)
+import qualified Data.Text as T
+import qualified Data.Text.Read as T
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as BS
 
@@ -172,3 +180,15 @@
 sdivUBound x y _ = x `div` y
 
 infixl 7 `sdivBound`, `sdivUBound`
+
+-- This should never change while we are on the same kernel
+-- | Get the kernel name/version/release and so forth
+getUname :: C.UName
+getUname = unsafePerformIO C.uname
+
+-- | Get the kernel version as (major, minor)
+getKernelVersion :: (Word, Word)
+getKernelVersion =
+    let txt = T.splitOn (T.pack ".") . C._uRelease $ getUname
+        (Right major: Right minor:_) = fmap T.decimal txt
+     in (fst major, fst minor)
diff --git a/bin/Main.hs b/bin/Main.hs
--- a/bin/Main.hs
+++ b/bin/Main.hs
@@ -43,6 +43,7 @@
   )
 where
 
+import GHC.IO.Handle (hDuplicate)
 import Monky.Version (getVersion)
 import Control.Monad (when, unless)
 import Data.List (isSuffixOf, nub, sort)
@@ -50,7 +51,7 @@
 import System.Exit (ExitCode(..), exitFailure)
 import System.IO (withFile, IOMode(..), hPutStr, hPutStrLn, stderr)
 import System.Posix.Process (executeFile)
-import System.Process (system)
+import System.Process (shell, waitForProcess, CreateProcess(..), createProcess, StdStream(..))
 import Data.Monoid ((<>))
 
 import Options.Applicative
@@ -153,12 +154,20 @@
   files <- getDirectoryContents "."
   return $ "monky.hs" `notElem` files
 
+runGHC :: Config -> IO ExitCode
+runGHC c = do
+    let com = "ghc " ++ compilerFlags ++ " monky.hs -o " ++ exeName c
+    let proc = shell com
+    file <- hDuplicate stderr
+    (_, _, _, h) <- createProcess proc { std_out = UseHandle file }
+    waitForProcess h
 
+
 compile :: Config -> IO ()
 compile c = unless (confNoCompile c) $ do
   exists <- doesFileExist "monky.hs"
   when exists $ do
-    ret <- system ("ghc " ++ compilerFlags ++ " monky.hs -o " ++ exeName c)
+    ret <- runGHC c
     case ret of
       (ExitFailure _) -> do
         hPutStrLn stderr "Compilation failed"
diff --git a/monky.cabal b/monky.cabal
--- a/monky.cabal
+++ b/monky.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             2.1.0.0
+version:             2.1.3.0
 
 -- The ABOVE LINE has to stay AS IS (except for version changes) for the
 -- template to work properly
@@ -145,10 +145,11 @@
 
   exposed-modules: Monky.Outputs.Dzen2 Monky.Outputs.Ascii Monky.Outputs.Utf8 Monky.Outputs.Guess
   exposed-modules: Monky.Outputs.Show  Monky.Outputs.Fallback Monky.Outputs.Serialize Monky.Outputs.I3
+  exposed-modules: Monky.Outputs.Modify
   exposed-modules: Monky.Examples.Modify Monky.IP Monky.IP.Raw
 
   exposed-modules: Monky.Outputs.Unicode Monky.Examples.Images
-  other-modules: Monky.Template Monky.VersionTH
+  other-modules: Monky.Template Monky.VersionTH Monky.CUtil
 
 
   build-depends:       base >=4.6.0.1 && <=5, directory, time
@@ -173,7 +174,7 @@
 
   if impl(ghc >= 7.8)
     if flag(pulse)
-      build-depends: pulseaudio
+      build-depends: pulseaudio >= 0.0.2.0 && < 0.1.0.0
       exposed-modules: Monky.Examples.Sound.Pulse
 
   ghc-options:         -Wall
