packages feed

arbtt 0.4 → 0.4.1

raw patch · 11 files changed

+213/−229 lines, 11 filesdep −setlocaledep −tabular

Dependencies removed: setlocale, tabular

Files

README view
@@ -28,112 +28,15 @@ If you want to record samples at a different rate than one per minute, you will have to pass the "--sample-rate" parameter to arbtt-capture.  -Configuration-=============--Once arbtt-capture is running, it will start recording, without further-configuration. The configuration is only needed to do an analysis of the-recorded data. Thus, if you improve your categorization later, it will-apply even to previous data samples!--The configuration file needs to be placed in ~/.arbtt/categorize.cfg. An-example file is included, which should be more enlighting than this rather-formal description.--Whitespace is non-significant and Haskell-style comments are allowed.--Here is grammar of the file:--Rules := [ "aliases" AliasSpec ] Rule ( ("," Rule)* | (";" Rule)* )--Rule := "{" Rules "}" | Cond "==>" Rule | "if" Cond "then" Rule "else" Rule-      | "tag" Tag--Cond := "(" Cond ")" | "!" Cond | Cond "&&" Cond | Cond "||" Cond -      | "$" SVar "==" String | "$" SVar "/=" String-      | "$" SVar "=~" "/" Regex "/" |-      | "$" NVar NOp Number-      | "$" TVar NOp TSpec-      | "$" BVar-      | "current window" Cond-      | "any window" Cond--NOp := "<=" | "<" | "==" | ">" | ">="--SVar := "title" | "program"-NVar := "idle"-BVar := "active"-TVar := "time" | "sampleage"--The variables $title, $program, $active refer to the "window in scope". At-first, no window is in scope. Only when evaluating the condition passed to-"current window" or "any window", this changes.--For "current window", the currently active window is in scopre. If there is-no such window, the condition is false.--For "any window", the condition is applied to each window, and if any-window matches the condition, the result is true. If it matches more than-one window, of which match the variables $1,.. (see below) will be taken.--Tags are not enclosed in quotation marks, and contain only letters, dashes-or underscores (e.g. work).--They may be prepended with a category,-separated by a colon (e.g. Project:arbtt). This category can later be used-for pie chart like statistics. For each category, no more than one tags can-be matched per sample. If multiple tags with the same category are-generated by the rules, only the first one will be taken.--A tag can also interpolate variables, including in the category part.-Available variables are:- $1, $2,..  Matches from the last successfully applied regular expression-            in the enclosing condition- $current.title- $current.program-	    The title or the name of the currently active program. If no-	    program happens to be active, this tag will be ignored.--The variable $time refers to the time-of-day of the sample (i.e. the time-since 0:00 that day), while $sampleage refers to the timespan from when the-sample was created until now, the time of evaluating the statistics. They-can be compared with expressions of the type "hh:mm", for example:- $time >=  8:00 && $time < 12:00 ==> tag time-of-day:morning,--Statistics-==========--Run the statistics program arbtt-stats with the parameter --help to get an-overview of the options.--By default, any sample with the tag "inactive" are excluded from the-statistics, and tags with a percentage lower than one will not be shown.--The tags that affect the selection (-x, -o, --also-inactive) of samples can-be mixed with the report options (-m) and the reports (-i, -t, -c), but-will apply to all reports.--The flag --filter (-f) allows you to sepecify an arbitrary complex-condition using the same syntax for conditions that you can use in the-categorize.cfg file.--Some useful examples:--  # Only consider the time when I was programming in Haskell -  arbtt-stats -o Editing-Haskell--  # Tell me what evolution folders I spend my time in when I actually do-  # work with e-Mail-  arbtt-stats -o Program:evolution -c Evo-Folder--  # Generate statistics about the last hour-  arbtt-stats -f '$sampleage < 1:00'--Data Dump-=========+Documentation+============ -If you need to inspect the recorded sample, for example to think about-interesting things to match, use arbtt-dump.+Full documentation is now provided in the user manual in the doc/+directory. If you have the docbook xsl toolchain installed, you can+generate the HTML documentation by entering "make" in that directory.+Otherwise, you can use the online version at+http://darcs.nomeata.de/arbtt/doc/users_guide/+Beware that this will also reflect the latest version.  Development ===========@@ -146,15 +49,13 @@   * A graphical viewer that allows you to expore the tags in an appealing,    interactive way. Possibly based on the Charts haskell library.- * A better representation of the data in the log, to keep the size and -   parsing speed down.   * Looking forward and backwards in time when writing rules. (Information    is already passed to the categorizing function, but not exposed to the    syntax).  * $total_idle time, which is the maximum idle time until it is reset. This    would allow the user to catch the idle times more exactly.  * Rules based on day of time, to create tags for worktime, weekend, late-   at night.+   at night. (Partially done)  * Statistics based on time, to visualize trends.  * Possibly more data sources? 
arbtt.cabal view
@@ -1,5 +1,5 @@ name:               arbtt-version:            0.4+version:            0.4.1 license:            GPL license-file:       LICENSE category:           Desktop@@ -37,26 +37,29 @@         TimeLog         UpgradeLog1         Graphics.X11.XScreenSaver+        System.Locale.SetLocale  executable arbtt-stats     main-is:            stats-main.hs     hs-source-dirs:     src     build-depends:-        base == 4.*, parsec == 2.*, containers, pcre-light, tabular, setlocale+        base == 4.*, parsec == 2.*, containers, pcre-light     other-modules:         Data         Categorize         TimeLog         Stats+        System.Locale.SetLocale  executable arbtt-dump     main-is:            dump-main.hs     hs-source-dirs:     src     build-depends:-        base == 4.*, parsec == 2.*, containers, setlocale+        base == 4.*, parsec == 2.*, containers     other-modules:         Data         TimeLog+        System.Locale.SetLocale  source-repository head     type:     darcs
src/Capture.hs view
@@ -8,21 +8,26 @@ import Data.Maybe import Control.Applicative import Data.Time.Clock+import System.IO  captureData :: IO CaptureData captureData = do-	dpy <- openDisplay ":0"+	dpy <- openDisplay ""         xSetErrorHandler 	let rwin = defaultRootWindow dpy  	a <- internAtom dpy "_NET_CLIENT_LIST" False 	p <- getWindowProperty32 dpy a rwin-	let cwins = maybe [] (map fromIntegral) p +	wins <- case p of+		Just wins -> return (map fromIntegral wins)+		Nothing -> do hPutStrLn stderr "arbtt: ERROR: No _NET_CLIENT_LIST set for the root window"+		              return []+ 	(fsubwin,_) <- getInputFocus dpy-	fwin <- followTreeUntil dpy (`elem` cwins) fsubwin+	fwin <- followTreeUntil dpy (`elem` wins) fsubwin -	winData <- mapM (\w -> (,,) (w == fwin) <$> getWindowTitle dpy w <*> getProgramName dpy w) cwins+	winData <- mapM (\w -> (,,) (w == fwin) <$> getWindowTitle dpy w <*> getProgramName dpy w) wins  	it <- fromIntegral `fmap` getXIdleTime dpy @@ -30,10 +35,10 @@ 	return $ CaptureData winData it  getWindowTitle :: Display -> Window -> IO String-getWindowTitle dpy w = fmap (fromMaybe "") $ fetchName dpy w+getWindowTitle dpy = fmap (fromMaybe "") . fetchName dpy  getProgramName :: Display -> Window -> IO String-getProgramName dpy w = fmap resName $ getClassHint dpy w+getProgramName dpy = fmap resName . getClassHint dpy  -- | Follows the tree of windows up until the condition is met or the root -- window is reached.@@ -43,4 +48,3 @@              | otherwise = do (r,p,_) <- queryTree dpy w 	                      if p == 0 then return w 			                else go p -
src/Categorize.hs view
@@ -2,7 +2,6 @@  import Data -import Data.Maybe import qualified Text.Regex.PCRE.Light.Char8 as RE import qualified Data.Map as M import Control.Monad@@ -45,16 +44,15 @@ 	case parse (do {r <- parseRules; eof ; return r}) filename content of 	  Left err -> do 	  	putStrLn "Parser error:"-		putStrLn (show err)+		print err 		exitFailure 	  Right cat -> return ((fmap . fmap) (mkSecond (postpare . cat)) . prepare time)  applyCond :: String -> TimeLog (Ctx, ActivityData) -> TimeLog (Ctx, ActivityData) applyCond s =  	case parse (do {c <- parseCond; eof ; return c}) "commad line parameter" s of-	  Left err -> do-		error (show err)-	  Right c -> filter (isJust . c . fst . tlData)+	  Left err -> error (show err)+	  Right c  -> filter (isJust . c . fst . tlData)  prepare :: UTCTime -> TimeLog CaptureData -> TimeLog Ctx prepare time tl = go' [] tl tl@@ -67,7 +65,7 @@ -- | Here, we filter out tags appearing twice, and make sure that only one of --   each category survives postpare :: ActivityData -> ActivityData-postpare = nubBy $ go+postpare = nubBy go   where go (Activity (Just c1) _) (Activity (Just c2) _) = c1 == c2         go a1                     a2                     = a1 == a2 @@ -184,7 +182,7 @@ 		     time <- parseTime 		     return $ checkTimeCmp op varname time 		, do guard $ varname == "active"-		     return $ checkActive+		     return checkActive 		] 	, do reserved lang "current window" 	     cond <- parseCond@@ -208,7 +206,7 @@ parseTime :: Parser NominalDiffTime parseTime = fmap fromIntegral $ lexeme lang $ do                h <- digitToInt <$> digit-	       mh <- optionMaybe (do{ digitToInt <$> digit })+	       mh <- optionMaybe (digitToInt <$> digit) 	       char ':'                m1 <- digitToInt <$> digit                m2 <- digitToInt <$> digit
src/Stats.hs view
@@ -5,8 +5,6 @@ import Data.Maybe import Data.List import Data.Ord-import Text.Tabular-import qualified Text.Tabular.AsciiArt as TA import Text.Printf import qualified Data.Map as M import qualified Data.Set as S@@ -24,6 +22,14 @@ data ReportOption = MinPercentage Double         deriving Eq +-- Data format semantically representing the result of a report, including the+-- title+data ReportResults =+	ListOfFields String [(String, String)]+	| ListOfTimePercValues String [(String, String, Double)]+	| PieChartOfTimePercValues  String [(String, String, Double)]++ applyFilters :: [Filter] -> TimeLog (Ctx, ActivityData) -> TimeLog (Ctx, ActivityData) applyFilters filters tle =          foldr (\flag -> case flag of @@ -44,12 +50,12 @@ 	{ firstDate :: UTCTime 	, lastDate  :: UTCTime 	, timeDiff :: NominalDiffTime-	, totalTimeRec :: Integer-	, totalTimeSel :: Integer+	, totalTimeRec :: NominalDiffTime+	, totalTimeSel :: NominalDiffTime 	, fractionRec :: Double 	, fractionSel :: Double 	, fractionSelRec :: Double-	, sums :: M.Map Activity Integer+	, sums :: M.Map Activity NominalDiffTime 	, allTags :: TimeLog (Ctx, ActivityData) 	, tags :: TimeLog (Ctx, ActivityData) 	}@@ -60,25 +66,25 @@ 	  { firstDate = tlTime (head allTags) 	  , lastDate = tlTime (last allTags) 	  , timeDiff = diffUTCTime (lastDate c) (firstDate c)-	  , totalTimeRec = sum (map tlRate allTags)-	  , totalTimeSel = sum (map tlRate tags)-	  , fractionRec = fromIntegral (totalTimeRec c) / (realToFrac (timeDiff c) * 1000)-	  , fractionSel = fromIntegral (totalTimeSel c) / (realToFrac (timeDiff c) * 1000)-	  , fractionSelRec = fromIntegral (totalTimeSel c) / fromIntegral (totalTimeRec c)+	  , totalTimeRec = fromInteger (sum (map tlRate allTags))/1000+	  , totalTimeSel = fromInteger (sum (map tlRate tags))/1000+	  , fractionRec = realToFrac (totalTimeRec c) / (realToFrac (timeDiff c))+	  , fractionSel = realToFrac (totalTimeSel c) / (realToFrac (timeDiff c))+	  , fractionSelRec = realToFrac (totalTimeSel c) / realToFrac (totalTimeRec c) 	  , sums = sumUp tags 	  , allTags 	  , tags 	  } in c  -- | Sums up each occurence of an 'Activity', weighted by the sampling rate-sumUp :: TimeLog (Ctx, ActivityData) -> M.Map Activity Integer-sumUp = foldr go (M.empty) +sumUp :: TimeLog (Ctx, ActivityData) -> M.Map Activity NominalDiffTime+sumUp = foldr go M.empty   where go tl m = foldr go' m (snd (tlData tl))-          where go' act = M.insertWith (+) act (tlRate tl)+          where go' act = M.insertWith (+) act (fromInteger (tlRate tl)/1000)   listCategories :: TimeLog (Ctx, ActivityData) -> [Category]-listCategories = S.toList . foldr go (S.empty) +listCategories = S.toList . foldr go S.empty   where go tl m = foldr go' m (snd (tlData tl))           where go' (Activity (Just cat) _) = S.insert cat 	        go' _                       = id@@ -88,95 +94,106 @@  putReport :: [ReportOption] -> Calculations -> Report -> IO () putReport opts c EachCategory = putReports opts c (map Category (listCategories (tags c)))-putReport opts c r = let (h,t) = reportToTable opts c r-  			in putStrLnUnderlined h >> putStr (TA.render id id id t)+putReport opts c r = renderReport $ reportToTable opts c r -reportToTable :: [ReportOption] -> Calculations -> Report -> (String, Table String String String)+reportToTable :: [ReportOption] -> Calculations -> Report -> ReportResults reportToTable opts (Calculations {..}) r = case r of- 	GeneralInfos -> ("General Information",-		empty ^..^ colH "Value"-		+.+ row "FirstRecord"-		        [show firstDate]-		+.+ row "LastRecord"-		        [show lastDate]-		+.+ row "Number of records"-		        [show (length allTags)]-		+.+ row "Total time recorded"-		        [formatSeconds (fromIntegral totalTimeRec / 1000)]-		+.+ row "Total time selected"-		        [formatSeconds (fromIntegral totalTimeSel / 1000)]-		+.+ row "Fraction of total time recorded"-		        [printf "%3.0f%%" (fractionRec * 100) ]-		+.+ row "Fraction of total time selected"-		        [printf "%3.0f%%" (fractionSel * 100) ]-		+.+ row "Fraction of recorded time selected"-		        [printf "%3.0f%%" (fractionSelRec * 100) ]-		)+ 	GeneralInfos -> ListOfFields "General Information" $+		[ ("FirstRecord", show firstDate)+		, ("LastRecord",  show lastDate)+		, ("Number of records", show (length allTags))+		, ("Total time recorded",  showTimeDiff totalTimeRec)+		, ("Total time selected",  showTimeDiff totalTimeSel)+		, ("Fraction of total time recorded", printf "%3.0f%%" (fractionRec * 100))+		, ("Fraction of total time selected", printf "%3.0f%%" (fractionSel * 100))+		, ("Fraction of recorded time selected", printf "%3.0f%%" (fractionSelRec * 100))+		] - 	TotalTime -> ("Total time per tag",-		foldr (\(tag,time) ->-		      let perc = fromIntegral time/fromIntegral totalTimeSel*100 in-		      if perc >= minPercentage-	 	      then (+.+ row (show tag) [-		      		formatSeconds (fromIntegral time/1000),-				printf "%.1f%%" perc])-		      else id-		      )-		(empty ^..^ colH "Time" ^..^ colH "Percentage")-		(sortBy (comparing snd) $ M.toList sums)-		)+ 	TotalTime -> ListOfTimePercValues "Total time per tag" $+		mapMaybe (\(tag,time) ->+		      let perc = realToFrac time/realToFrac totalTimeSel in+		      if perc*100 >= minPercentage+	 	      then Just $ ( show tag+		                  , showTimeDiff time+				  , perc)+		      else Nothing+		      ) $+		reverse $+		sortBy (comparing snd) $+		M.toList sums 	-	Category cat -> ("Statistics for category " ++ cat,+	Category cat -> PieChartOfTimePercValues ("Statistics for category " ++ cat) $          	let filteredSums = M.filterWithKey (\a _ -> isCategory cat a) sums 	            uncategorizedTime = totalTimeSel - M.fold (+) 0 filteredSums-          	    tooSmallSums = M.filter (\t -> fromIntegral t / fromIntegral totalTimeSel * 100 < minPercentage) filteredSums+          	    tooSmallSums = M.filter (\t -> realToFrac t / realToFrac totalTimeSel * 100 < minPercentage) filteredSums 	  	    tooSmallTimes = M.fold (+) 0 tooSmallSums 		in -		(if uncategorizedTime > 0-		then (+.+ row "(unmatched time)" [-                        formatSeconds (fromIntegral uncategorizedTime/1000),-                        printf "%.1f%%" (fromIntegral uncategorizedTime/fromIntegral totalTimeSel*100::Double)])-		else id-		)-		.	+		mapMaybe (\(tag,time) ->+		      let perc = realToFrac time/realToFrac totalTimeSel in+		      if perc*100 >= minPercentage+	 	      then Just ( show tag+		      		, showTimeDiff time+				, perc)+		      else Nothing+		      )+          	      (reverse $ sortBy (comparing snd) $ M.toList filteredSums)+		++ 		( 		if tooSmallTimes > 0-		then (+.+ row (printf "(%d entries omitted)" (M.size tooSmallSums)) [-                        formatSeconds (fromIntegral tooSmallTimes/1000),-                        printf "%.1f%%" (fromIntegral tooSmallTimes/fromIntegral totalTimeSel*100::Double) ])-		else id+		then [( printf "(%d entries omitted)" (M.size tooSmallSums)+		      , showTimeDiff tooSmallTimes+		      , realToFrac tooSmallTimes/realToFrac totalTimeSel+		      )]+		else [] 		)-		$	-		foldr (\(tag,time) ->-		      let perc = fromIntegral time/fromIntegral totalTimeSel*100 in-		      if perc >= minPercentage-	 	      then (+.+ row (show tag) [-		      		formatSeconds (fromIntegral time/1000),-				printf "%.1f%%" perc])-		      else id-		      )--		(empty ^..^ colH "Time" ^..^ colH "Percentage")--          	(sortBy (comparing snd) $ M.toList filteredSums)+		++	+		(if uncategorizedTime > 0+		then [( "(unmatched time)"+                      , showTimeDiff uncategorizedTime+                      , realToFrac uncategorizedTime/realToFrac totalTimeSel+		      )]+		else [] 		)    where minPercentage = last $ mapMaybe (\f -> case f of {MinPercentage m -> Just m {- ; _ -> Nothing -} }) opts  -formatSeconds :: Double -> String-formatSeconds s' = go $ zip [days,hours,mins,secs] ["d","h","m","s"]-  where s = round s' :: Integer+renderReport (ListOfFields title dats) = do+	putStrLnUnderlined title+	putStr $ tabulate False $ map (\(f,v) -> [f,v]) dats++renderReport (ListOfTimePercValues title dats) = do+	putStrLnUnderlined title+	putStr $ tabulate True $ ["Tag","Time","Percentage"] : map (\(f,t,p) -> [f,t,printf "%.2f" (p*100)]) dats++renderReport (PieChartOfTimePercValues title dats) = do+	putStrLnUnderlined title+	putStr $ tabulate True $ ["Tag","Time","Percentage"] : map (\(f,t,p) -> [f,t,printf "%.2f" (p*100)]) dats+++tabulate :: Bool -> [[String]] -> String+tabulate titlerow rows = unlines $ addTitleRow $ map (intercalate " | " . zipWith (\l s -> take (l - length s) (repeat ' ') ++ s) colwidths) rows+  where cols = transpose rows+        colwidths = map (maximum . map length) cols+	addTitleRow | titlerow  = \(l:ls) -> (map (\c -> if c == ' ' then '_' else c) l ++ "_")+	                                     : ls+	         -- | titlerow  = \(l:ls) -> l : (take (length l) (repeat '-')) : ls+	            | otherwise = id++showTimeDiff :: NominalDiffTime -> String+showTimeDiff t = go False $ zip [days,hours,mins,secs] ["d","h","m","s"]+  where s = round t :: Integer         days  =  s `div` (24*60*60)         hours = (s `div` (60*60)) `mod` 24-        mins  = (s `div` (60)) `mod` 60-	secs  = (s `mod` (60))-	go | s == 0    = const "0s"-	   | otherwise = concat . snd . mapAccumL go' False -	go' True  (a,u)             = (True, printf "%02d%s" a u)-	go' False (a,u) | a > 0     = (True, printf "%2d%s" a u)-	                | otherwise = (False, "")+        mins  = (s `div` 60) `mod` 60+	secs  =  s `mod` 60 +	go False []         = "0s"+	go True  []         = ""+--	go True  vs         | all (==0) (map fst vs) = concat (replicate (length vs) "   ")+	go True  ((a,u):vs)             = printf "%02d%s" a u ++ go True vs+	go False ((a,u):vs) | a > 0     = printf "%2d%s" a u ++ go True vs+	                    | otherwise =                       go False vs  putStrLnUnderlined str = do         putStrLn str
+ src/System/Locale/SetLocale.hsc view
@@ -0,0 +1,61 @@+{-# LANGUAGE ForeignFunctionInterface #-}++{-+This file is copied from the setlocale-0.0.3 package. Its author is Lukas Mai+and it is placed in the Public Domain.+-}++module System.Locale.SetLocale (+    Category(..),+    categoryToCInt,+    setLocale+) where++import Foreign.Ptr+import Foreign.C.Types+import Foreign.C.String++import Data.Typeable++-- | A type representing the various locale categories. See @man 7 locale@.+data Category+    = LC_ALL+    | LC_COLLATE+    | LC_CTYPE+    | LC_MESSAGES+    | LC_MONETARY+    | LC_NUMERIC+    | LC_TIME+    deriving (Eq, Ord, Read, Show, Enum, Bounded)++instance Typeable Category where+    typeOf _ = mkTyConApp (mkTyCon "System.Locale.SetLocale.Category") []++#include <locale.h>++-- | Convert a 'Category' to the corresponding system-specific @LC_*@ code.+-- You probably don't need this function.+categoryToCInt :: Category -> CInt+categoryToCInt LC_ALL = #const LC_ALL+categoryToCInt LC_COLLATE = #const LC_COLLATE+categoryToCInt LC_CTYPE = #const LC_CTYPE+categoryToCInt LC_MESSAGES = #const LC_MESSAGES+categoryToCInt LC_MONETARY = #const LC_MONETARY+categoryToCInt LC_NUMERIC = #const LC_NUMERIC+categoryToCInt LC_TIME = #const LC_TIME++ptr2str :: Ptr CChar -> IO (Maybe String)+ptr2str p+    | p == nullPtr = return Nothing+    | otherwise = fmap Just $ peekCString p++str2ptr :: Maybe String -> (Ptr CChar -> IO a) -> IO a+str2ptr Nothing  f = f nullPtr+str2ptr (Just s) f = withCString s f++foreign import ccall unsafe "locale.h setlocale" c_setlocale :: CInt -> Ptr CChar -> IO (Ptr CChar)++-- | A Haskell version of @setlocale()@. See @man 3 setlocale@.+setLocale :: Category -> Maybe String -> IO (Maybe String)+setLocale cat str =+    str2ptr str $ \p -> c_setlocale (categoryToCInt cat) p >>= ptr2str
src/TimeLog.hs view
@@ -15,7 +15,7 @@  import qualified Data.ByteString.Lazy as BS -magic = BS.pack $ map (fromIntegral.ord) $ "arbtt-timelog-v1\n"+magic = BS.pack $ map (fromIntegral.ord) "arbtt-timelog-v1\n"  -- | Runs the given action each delay milliseconds and appends the TimeLog to the -- given file.@@ -33,7 +33,7 @@ 	when (not ex || force) $ BS.writeFile filename magic  appendTimeLog :: Binary a => FilePath -> TimeLogEntry a -> IO ()-appendTimeLog filename tle = BS.appendFile filename $ encode $ tle+appendTimeLog filename = BS.appendFile filename . encode  writeTimeLog :: Binary a => FilePath -> TimeLog a -> IO () writeTimeLog filename tl = do createTimeLog True filename
src/UpgradeLog1.hs view
@@ -48,7 +48,7 @@                         renameFile captureFile oldFile                         captures <- readTimeLog oldFile                         writeTimeLog captureFile (upgrade captures)-                        putStrLn $ "done."+                        putStrLn   "done."   where oldFile = captureFile ++ ".old" 
src/capture-main.hs view
@@ -38,10 +38,10 @@      [ Option "h?"     ["help"]               (NoArg Help) 	      "show this help"-     , Option ['V']    ["version"]+     , Option "V"      ["version"]               (NoArg Version) 	      "show the version number"-     , Option ['r']    ["sample-rate"]+     , Option "r"      ["sample-rate"]      	      (ReqArg (SetRate . read) "RATE") 	      "set the sample rate in seconds (default: 60)"      ]	     
src/dump-main.hs view
@@ -24,7 +24,7 @@      [ Option "h?"     ["help"]               (NoArg Help) 	      "show this help"-     , Option ['V']     ["version"]+     , Option "V"      ["version"]               (NoArg Version) 	      "show the version number"      ]
src/stats-main.hs view
@@ -36,38 +36,38 @@  options :: [OptDescr Flag] options =-     [ Option "h?"     ["help"]+     [ Option "h?"      ["help"]               (NoArg Help) 	      "show this help"-     , Option ['V']     ["version"]+     , Option "V"       ["version"]               (NoArg Version) 	      "show the version number" --     , Option ['g']     ["graphical"] (NoArg Graphical)    "render the reports as graphical charts"-     , Option ['x']     ["exclude"]+     , Option "x"       ["exclude"]               (ReqArg (Filter . Exclude . Activity Nothing) "TAG") 	      "ignore samples containing this tag"-     , Option ['o']     ["only"]+     , Option "o"       ["only"]               (ReqArg (Filter . Only . read) "TAG") 	      "only consider samples containing this tag"-     , Option []        ["also-inactive"]+     , Option ""        ["also-inactive"]               (NoArg (Filter AlsoInactive)) 	      "include samples with the tag \"inactive\""-     , Option ['f']     ["filter"]+     , Option "f"       ["filter"]               (ReqArg (Filter . GeneralCond) "COND") 	      "only consider samples matching the condition"-     , Option ['m']     ["min-percentage"]+     , Option "m"       ["min-percentage"]               (ReqArg (ReportOption . MinPercentage . read) "PERC") 	      "do not show tags with a percentage lower than PERC% (default: 1)"-     , Option ['i']     ["information"]+     , Option "i"       ["information"]               (NoArg (Report GeneralInfos)) 	      "show general statistics about the data"-     , Option ['t']     ["total-time"]+     , Option "t"       ["total-time"]               (NoArg (Report TotalTime)) 	      "show total time for each tag"-     , Option ['c']     ["category"]+     , Option "c"       ["category"]               (ReqArg (Report . Category) "CATEGORY") 	      "show statistics about category CATEGORY"-     , Option []       ["each-category"]+     , Option ""        ["each-category"]               (NoArg (Report EachCategory)) 	      "show statistics about each category found"      ]@@ -91,9 +91,9 @@    let categorizeFilename = dir </> "categorize.cfg"   fileEx <- doesFileExist categorizeFilename-  unless (fileEx) $ do+  unless fileEx $ do      putStrLn $ printf "Configuration file %s does not exist." categorizeFilename-     putStrLn $ "Please see the example file and the README for more details"+     putStrLn "Please see the example file and the README for more details"      exitFailure   categorizer <- readCategorizer categorizeFilename