{-# LANGUAGE Safe #-}
module Data.Progress.Meter (
ProgressMeter,
simpleNewMeter,
newMeter,
setComponents,
addComponent,
removeComponent,
setWidth,
renderMeter,
displayMeter,
clearMeter,
writeMeterString,
autoDisplayMeter,
killAutoDisplayMeter
) where
import safe Data.Progress.Tracker
( ProgressStatuses(..),
Progress,
ProgressStatus(totalUnits, completedUnits, trackerName),
getSpeed,
getETR )
import safe Control.Concurrent
( modifyMVar_,
withMVar,
newMVar,
MVar,
threadDelay,
forkIO,
myThreadId,
yield,
ThreadId )
import Control.Monad (when)
import Data.String.Utils (join)
import System.Time.Utils (renderSecs)
import Data.Quantity (renderNums, binaryOpts)
import safe System.IO ( Handle, hFlush, hPutStr )
import Control.Monad (filterM)
data ProgressMeterR =
ProgressMeterR {ProgressMeterR -> Progress
masterP :: Progress,
ProgressMeterR -> [Progress]
components :: [Progress],
ProgressMeterR -> Int
width :: Int,
ProgressMeterR -> [Char]
unit :: String,
ProgressMeterR -> [Integer] -> [[Char]]
renderer :: [Integer] -> [String],
ProgressMeterR -> [ThreadId]
autoDisplayers :: [ThreadId]
}
type ProgressMeter = MVar ProgressMeterR
simpleNewMeter :: Progress -> IO ProgressMeter
simpleNewMeter :: Progress -> IO ProgressMeter
simpleNewMeter Progress
pt = Progress
-> [Char] -> Int -> ([Integer] -> [[Char]]) -> IO ProgressMeter
newMeter Progress
pt [Char]
"B" Int
80 (SizeOpts -> Int -> [Integer] -> [[Char]]
forall a. (Ord a, Real a) => SizeOpts -> Int -> [a] -> [[Char]]
renderNums SizeOpts
binaryOpts Int
1)
newMeter :: Progress
-> String
-> Int
-> ([Integer] -> [String])
-> IO ProgressMeter
newMeter :: Progress
-> [Char] -> Int -> ([Integer] -> [[Char]]) -> IO ProgressMeter
newMeter Progress
tracker [Char]
u Int
w [Integer] -> [[Char]]
rfunc =
ProgressMeterR -> IO ProgressMeter
forall a. a -> IO (MVar a)
newMVar (ProgressMeterR -> IO ProgressMeter)
-> ProgressMeterR -> IO ProgressMeter
forall a b. (a -> b) -> a -> b
$ ProgressMeterR :: Progress
-> [Progress]
-> Int
-> [Char]
-> ([Integer] -> [[Char]])
-> [ThreadId]
-> ProgressMeterR
ProgressMeterR {masterP :: Progress
masterP = Progress
tracker, components :: [Progress]
components = [],
width :: Int
width = Int
w, renderer :: [Integer] -> [[Char]]
renderer = [Integer] -> [[Char]]
rfunc, autoDisplayers :: [ThreadId]
autoDisplayers = [],
unit :: [Char]
unit = [Char]
u}
setComponents :: ProgressMeter -> [Progress] -> IO ()
setComponents :: ProgressMeter -> [Progress] -> IO ()
setComponents ProgressMeter
meter [Progress]
componentlist = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = [Progress]
componentlist})
addComponent :: ProgressMeter -> Progress -> IO ()
addComponent :: ProgressMeter -> Progress -> IO ()
addComponent ProgressMeter
meter Progress
component =
ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = Progress
component Progress -> [Progress] -> [Progress]
forall a. a -> [a] -> [a]
: ProgressMeterR -> [Progress]
components ProgressMeterR
m})
removeComponent :: ProgressMeter -> String -> IO ()
removeComponent :: ProgressMeter -> [Char] -> IO ()
removeComponent ProgressMeter
meter [Char]
componentname = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter ((ProgressMeterR -> IO ProgressMeterR) -> IO ())
-> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
m ->
do [Progress]
newc <- (Progress -> IO Bool) -> [Progress] -> IO [Progress]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (\Progress
x -> Progress -> (ProgressStatus -> IO Bool) -> IO Bool
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus Progress
x (\ProgressStatus
y -> Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ ProgressStatus -> [Char]
trackerName ProgressStatus
y [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char]
componentname))
(ProgressMeterR -> [Progress]
components ProgressMeterR
m)
ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {components :: [Progress]
components = [Progress]
newc}
setWidth :: ProgressMeter -> Int -> IO ()
setWidth :: ProgressMeter -> Int -> IO ()
setWidth ProgressMeter
meter Int
w = ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
meter (\ProgressMeterR
m -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
m {width :: Int
width = Int
w})
displayMeter :: Handle -> ProgressMeter -> IO ()
displayMeter :: Handle -> ProgressMeter -> IO ()
displayMeter Handle
h ProgressMeter
r = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
r ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
meter ->
do [Char]
s <- ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter
Handle -> [Char] -> IO ()
hPutStr Handle
h ([Char]
"\r" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
s)
Handle -> IO ()
hFlush Handle
h
clearMeter :: Handle -> ProgressMeter -> IO ()
clearMeter :: Handle -> ProgressMeter -> IO ()
clearMeter Handle
h ProgressMeter
pm = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
m ->
do Handle -> [Char] -> IO ()
hPutStr Handle
h (ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
m)
Handle -> IO ()
hFlush Handle
h
writeMeterString :: Handle -> ProgressMeter -> String -> IO ()
writeMeterString :: Handle -> ProgressMeter -> [Char] -> IO ()
writeMeterString Handle
h ProgressMeter
pm [Char]
msg = ProgressMeter -> (ProgressMeterR -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO ()) -> IO ())
-> (ProgressMeterR -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
meter ->
do [Char]
s <- ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter
Handle -> [Char] -> IO ()
hPutStr Handle
h (ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
meter)
Handle -> [Char] -> IO ()
hPutStr Handle
h [Char]
msg
Handle -> [Char] -> IO ()
hPutStr Handle
h [Char]
s
Handle -> IO ()
hFlush Handle
h
clearmeterstr :: ProgressMeterR -> String
clearmeterstr :: ProgressMeterR -> [Char]
clearmeterstr ProgressMeterR
m = [Char]
"\r" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate (ProgressMeterR -> Int
width ProgressMeterR
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Char
' ' [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\r"
autoDisplayMeter :: ProgressMeter
-> Int
-> (ProgressMeter -> IO ())
-> IO ThreadId
autoDisplayMeter :: ProgressMeter -> Int -> (ProgressMeter -> IO ()) -> IO ThreadId
autoDisplayMeter ProgressMeter
pm Int
delay ProgressMeter -> IO ()
displayfunc =
do ThreadId
thread <- IO () -> IO ThreadId
forkIO IO ()
workerthread
ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
pm (\ProgressMeterR
p -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
p {autoDisplayers :: [ThreadId]
autoDisplayers = ThreadId
thread ThreadId -> [ThreadId] -> [ThreadId]
forall a. a -> [a] -> [a]
: ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p})
ThreadId -> IO ThreadId
forall (m :: * -> *) a. Monad m => a -> m a
return ThreadId
thread
where workerthread :: IO ()
workerthread = do ThreadId
tid <- IO ThreadId
myThreadId
IO ()
yield
ThreadId -> IO ()
loop ThreadId
tid
loop :: ThreadId -> IO ()
loop ThreadId
tid = do ProgressMeter -> IO ()
displayfunc ProgressMeter
pm
Int -> IO ()
threadDelay (Int
delay Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000)
Bool
c <- ThreadId -> IO Bool
doIContinue ThreadId
tid
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
c (ThreadId -> IO ()
loop ThreadId
tid)
doIContinue :: ThreadId -> IO Bool
doIContinue ThreadId
tid = ProgressMeter -> (ProgressMeterR -> IO Bool) -> IO Bool
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
pm ((ProgressMeterR -> IO Bool) -> IO Bool)
-> (ProgressMeterR -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \ProgressMeterR
p ->
if ThreadId
tid ThreadId -> [ThreadId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p
then Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
else Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
killAutoDisplayMeter :: ProgressMeter -> ThreadId -> IO ()
killAutoDisplayMeter :: ProgressMeter -> ThreadId -> IO ()
killAutoDisplayMeter ProgressMeter
pm ThreadId
t =
ProgressMeter -> (ProgressMeterR -> IO ProgressMeterR) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ ProgressMeter
pm (\ProgressMeterR
p -> ProgressMeterR -> IO ProgressMeterR
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressMeterR -> IO ProgressMeterR)
-> ProgressMeterR -> IO ProgressMeterR
forall a b. (a -> b) -> a -> b
$ ProgressMeterR
p {autoDisplayers :: [ThreadId]
autoDisplayers = (ThreadId -> Bool) -> [ThreadId] -> [ThreadId]
forall a. (a -> Bool) -> [a] -> [a]
filter (ThreadId -> ThreadId -> Bool
forall a. Eq a => a -> a -> Bool
/= ThreadId
t) (ProgressMeterR -> [ThreadId]
autoDisplayers ProgressMeterR
p)})
renderMeter :: ProgressMeter -> IO String
renderMeter :: ProgressMeter -> IO [Char]
renderMeter ProgressMeter
r = ProgressMeter -> (ProgressMeterR -> IO [Char]) -> IO [Char]
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar ProgressMeter
r ((ProgressMeterR -> IO [Char]) -> IO [Char])
-> (ProgressMeterR -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> IO [Char]
renderMeterR
renderMeterR :: ProgressMeterR -> IO String
renderMeterR :: ProgressMeterR -> IO [Char]
renderMeterR ProgressMeterR
meter =
do [Char]
overallpct <- Progress -> IO [Char]
forall {a} {m :: * -> *}.
(ProgressStatuses a (m [Char]), Monad m) =>
a -> m [Char]
renderpct (Progress -> IO [Char]) -> Progress -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> Progress
masterP ProgressMeterR
meter
[[Char]]
compnnts <- (Progress -> IO [Char]) -> [Progress] -> IO [[Char]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (([Integer] -> [[Char]]) -> Progress -> IO [Char]
rendercomponent (([Integer] -> [[Char]]) -> Progress -> IO [Char])
-> ([Integer] -> [[Char]]) -> Progress -> IO [Char]
forall a b. (a -> b) -> a -> b
$ ProgressMeterR -> [Integer] -> [[Char]]
renderer ProgressMeterR
meter)
(ProgressMeterR -> [Progress]
components ProgressMeterR
meter)
let componentstr :: [Char]
componentstr = case [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
join [Char]
" " [[Char]]
compnnts of
[] -> [Char]
""
[Char]
x -> [Char]
x [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" "
[Char]
rightpart <- ([Integer] -> [[Char]]) -> Progress -> IO [Char]
forall a.
ProgressStatuses a (IO [Char]) =>
([Integer] -> [[Char]]) -> a -> IO [Char]
renderoverall (ProgressMeterR -> [Integer] -> [[Char]]
renderer ProgressMeterR
meter) (ProgressMeterR -> Progress
masterP ProgressMeterR
meter)
let leftpart :: [Char]
leftpart = [Char]
overallpct [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
componentstr
let padwidth :: Int
padwidth = (ProgressMeterR -> Int
width ProgressMeterR
meter) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ([Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
leftpart) Int -> Int -> Int
forall a. Num a => a -> a -> a
- ([Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Char]
rightpart)
if Int
padwidth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1
then [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
take (ProgressMeterR -> Int
width ProgressMeterR
meter Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
leftpart [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
rightpart
else [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
leftpart [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> Char -> [Char]
forall a. Int -> a -> [a]
replicate Int
padwidth Char
' ' [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
rightpart
where
u :: [Char]
u = ProgressMeterR -> [Char]
unit ProgressMeterR
meter
renderpct :: a -> m [Char]
renderpct a
pt =
a -> (ProgressStatus -> m [Char]) -> m [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
pt ProgressStatus -> m [Char]
forall {m :: * -> *}. Monad m => ProgressStatus -> m [Char]
renderpctpts
renderpctpts :: ProgressStatus -> m [Char]
renderpctpts ProgressStatus
pts =
if (ProgressStatus -> Integer
totalUnits ProgressStatus
pts Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0)
then [Char] -> m [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"0%"
else [Char] -> m [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ Integer -> [Char]
forall a. Show a => a -> [Char]
show (((ProgressStatus -> Integer
completedUnits ProgressStatus
pts) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
100) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` (ProgressStatus -> Integer
totalUnits ProgressStatus
pts)) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"%"
rendercomponent :: ([Integer] -> [String]) -> Progress -> IO String
rendercomponent :: ([Integer] -> [[Char]]) -> Progress -> IO [Char]
rendercomponent [Integer] -> [[Char]]
rfunc Progress
pt = Progress -> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus Progress
pt ((ProgressStatus -> IO [Char]) -> IO [Char])
-> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ \ProgressStatus
pts ->
do [Char]
pct <- ProgressStatus -> IO [Char]
forall {m :: * -> *}. Monad m => ProgressStatus -> m [Char]
renderpctpts ProgressStatus
pts
let renders :: [[Char]]
renders = [Integer] -> [[Char]]
rfunc [ProgressStatus -> Integer
totalUnits ProgressStatus
pts, ProgressStatus -> Integer
completedUnits ProgressStatus
pts]
[Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
"[" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ProgressStatus -> [Char]
trackerName ProgressStatus
pts [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
([[Char]]
renders [[Char]] -> Int -> [Char]
forall a. [a] -> Int -> a
!! Int
1) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"/" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
[[Char]] -> [Char]
forall a. [a] -> a
head [[Char]]
renders [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
pct [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"]"
renderoverall :: (ProgressStatuses a (IO [Char])) => ([Integer] -> [[Char]]) -> a -> IO [Char]
renderoverall :: forall a.
ProgressStatuses a (IO [Char]) =>
([Integer] -> [[Char]]) -> a -> IO [Char]
renderoverall [Integer] -> [[Char]]
rfunc a
pt = a -> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
pt ((ProgressStatus -> IO [Char]) -> IO [Char])
-> (ProgressStatus -> IO [Char]) -> IO [Char]
forall a b. (a -> b) -> a -> b
$ \ProgressStatus
pts ->
do Integer
etr <- ProgressStatus -> IO Integer
forall a.
(ProgressStatuses a (IO Integer),
ProgressStatuses a (IO Rational)) =>
a -> IO Integer
getETR ProgressStatus
pts
Double
speed <- ProgressStatus -> IO Double
forall a b. (ProgressStatuses a (IO b), Fractional b) => a -> IO b
getSpeed ProgressStatus
pts
[Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
forall a. [a] -> a
head ([Integer] -> [[Char]]
rfunc [Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double
speed :: Double)]) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
u [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
[Char]
"/s " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Integer -> [Char]
renderSecs Integer
etr