{-# LANGUAGE Safe #-}
module Data.Progress.Tracker (
newProgress, newProgress',
addCallback, addParent,
incrP, incrP', setP, setP', incrTotal,
setTotal, finishP,
getSpeed,
withStatus,
getETR,
getETA,
ProgressStatus(..),
Progress, ProgressTimeSource,
ProgressCallback,
ProgressStatuses,
defaultTimeSource
)
where
import Control.Concurrent.MVar
import System.Time
import System.Time.Utils
import Data.Ratio
type ProgressTimeSource = IO Integer
type ProgressCallback = ProgressStatus -> ProgressStatus -> IO ()
data ProgressStatus =
ProgressStatus {ProgressStatus -> Integer
completedUnits :: Integer,
ProgressStatus -> Integer
totalUnits :: Integer,
ProgressStatus -> Integer
startTime :: Integer,
ProgressStatus -> String
trackerName :: String,
ProgressStatus -> ProgressTimeSource
timeSource :: ProgressTimeSource
}
data ProgressRecord =
ProgressRecord {ProgressRecord -> [Progress]
parents :: [Progress],
ProgressRecord -> [ProgressCallback]
callbacks :: [ProgressCallback],
ProgressRecord -> ProgressStatus
status :: ProgressStatus}
newtype Progress = Progress (MVar ProgressRecord)
class ProgressStatuses a b where
withStatus :: a -> (ProgressStatus -> b) -> b
class ProgressRecords a b where
withRecord :: a -> (ProgressRecord -> b) -> b
instance ProgressStatuses Progress (IO b) where
withStatus :: Progress -> (ProgressStatus -> IO b) -> IO b
withStatus (Progress x :: MVar ProgressRecord
x) func :: ProgressStatus -> IO b
func = MVar ProgressRecord -> (ProgressRecord -> IO b) -> IO b
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ProgressRecord
x (\y :: ProgressRecord
y -> ProgressStatus -> IO b
func (ProgressRecord -> ProgressStatus
status ProgressRecord
y))
instance ProgressRecords Progress (IO b) where
withRecord :: Progress -> (ProgressRecord -> IO b) -> IO b
withRecord (Progress x :: MVar ProgressRecord
x) func :: ProgressRecord -> IO b
func = MVar ProgressRecord -> (ProgressRecord -> IO b) -> IO b
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ProgressRecord
x ProgressRecord -> IO b
func
instance ProgressStatuses ProgressStatus b where
withStatus :: ProgressStatus -> (ProgressStatus -> b) -> b
withStatus x :: ProgressStatus
x func :: ProgressStatus -> b
func = ProgressStatus -> b
func ProgressStatus
x
newProgress :: String
-> Integer
-> IO Progress
newProgress :: String -> Integer -> IO Progress
newProgress name :: String
name total :: Integer
total =
do Integer
t <- ProgressTimeSource
defaultTimeSource
ProgressStatus -> [ProgressCallback] -> IO Progress
newProgress' (ProgressStatus :: Integer
-> Integer
-> Integer
-> String
-> ProgressTimeSource
-> ProgressStatus
ProgressStatus {completedUnits :: Integer
completedUnits = 0, totalUnits :: Integer
totalUnits = Integer
total,
startTime :: Integer
startTime = Integer
t, trackerName :: String
trackerName = String
name,
timeSource :: ProgressTimeSource
timeSource = ProgressTimeSource
defaultTimeSource})
[]
newProgress' :: ProgressStatus
-> [ProgressCallback] -> IO Progress
newProgress' :: ProgressStatus -> [ProgressCallback] -> IO Progress
newProgress' news :: ProgressStatus
news newcb :: [ProgressCallback]
newcb =
do MVar ProgressRecord
r <- ProgressRecord -> IO (MVar ProgressRecord)
forall a. a -> IO (MVar a)
newMVar (ProgressRecord -> IO (MVar ProgressRecord))
-> ProgressRecord -> IO (MVar ProgressRecord)
forall a b. (a -> b) -> a -> b
$ ProgressRecord :: [Progress]
-> [ProgressCallback] -> ProgressStatus -> ProgressRecord
ProgressRecord {parents :: [Progress]
parents = [],
callbacks :: [ProgressCallback]
callbacks = [ProgressCallback]
newcb, status :: ProgressStatus
status = ProgressStatus
news}
Progress -> IO Progress
forall (m :: * -> *) a. Monad m => a -> m a
return (MVar ProgressRecord -> Progress
Progress MVar ProgressRecord
r)
addCallback :: Progress -> ProgressCallback -> IO ()
addCallback :: Progress -> ProgressCallback -> IO ()
addCallback (Progress mpo :: MVar ProgressRecord
mpo) cb :: ProgressCallback
cb = MVar ProgressRecord
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar ProgressRecord
mpo ((ProgressRecord -> IO ProgressRecord) -> IO ())
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a b. (a -> b) -> a -> b
$ \po :: ProgressRecord
po ->
ProgressRecord -> IO ProgressRecord
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressRecord -> IO ProgressRecord)
-> ProgressRecord -> IO ProgressRecord
forall a b. (a -> b) -> a -> b
$ ProgressRecord
po {callbacks :: [ProgressCallback]
callbacks = ProgressCallback
cb ProgressCallback -> [ProgressCallback] -> [ProgressCallback]
forall a. a -> [a] -> [a]
: ProgressRecord -> [ProgressCallback]
callbacks ProgressRecord
po}
addParent :: Progress
-> Progress
-> IO ()
addParent :: Progress -> Progress -> IO ()
addParent (Progress mcpo :: MVar ProgressRecord
mcpo) ppo :: Progress
ppo = MVar ProgressRecord
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar ProgressRecord
mcpo ((ProgressRecord -> IO ProgressRecord) -> IO ())
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a b. (a -> b) -> a -> b
$ \cpo :: ProgressRecord
cpo ->
do Progress -> Integer -> IO ()
incrP' Progress
ppo (ProgressStatus -> Integer
completedUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
cpo)
Progress -> Integer -> IO ()
incrTotal Progress
ppo (ProgressStatus -> Integer
totalUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
cpo)
ProgressRecord -> IO ProgressRecord
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressRecord -> IO ProgressRecord)
-> ProgressRecord -> IO ProgressRecord
forall a b. (a -> b) -> a -> b
$ ProgressRecord
cpo {parents :: [Progress]
parents = Progress
ppo Progress -> [Progress] -> [Progress]
forall a. a -> [a] -> [a]
: ProgressRecord -> [Progress]
parents ProgressRecord
cpo}
finishP :: Progress -> IO ()
finishP :: Progress -> IO ()
finishP (Progress mp :: MVar ProgressRecord
mp) =
MVar ProgressRecord
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar ProgressRecord
mp ProgressRecord -> IO ProgressRecord
modfunc
where modfunc :: ProgressRecord -> IO ProgressRecord
modfunc :: ProgressRecord -> IO ProgressRecord
modfunc oldpr :: ProgressRecord
oldpr =
do let adjustment :: Integer
adjustment = (ProgressStatus -> Integer
completedUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr)
Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- (ProgressStatus -> Integer
totalUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr)
ProgressRecord -> (Progress -> IO ()) -> IO ()
callParents ProgressRecord
oldpr (\x :: Progress
x -> Progress -> Integer -> IO ()
incrTotal Progress
x Integer
adjustment)
ProgressRecord -> IO ProgressRecord
forall (m :: * -> *) a. Monad m => a -> m a
return (ProgressRecord -> IO ProgressRecord)
-> ProgressRecord -> IO ProgressRecord
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr {status :: ProgressStatus
status = (ProgressRecord -> ProgressStatus
status ProgressRecord
oldpr)
{totalUnits :: Integer
totalUnits = ProgressStatus -> Integer
completedUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr}}
incrP :: Progress -> Integer -> IO ()
incrP :: Progress -> Integer -> IO ()
incrP po :: Progress
po count :: Integer
count = Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po ProgressStatus -> ProgressStatus
statusfunc
where statusfunc :: ProgressStatus -> ProgressStatus
statusfunc s :: ProgressStatus
s =
ProgressStatus
s {completedUnits :: Integer
completedUnits = ProgressStatus -> Integer
newcu ProgressStatus
s,
totalUnits :: Integer
totalUnits = if ProgressStatus -> Integer
newcu ProgressStatus
s Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> ProgressStatus -> Integer
totalUnits ProgressStatus
s
then ProgressStatus -> Integer
newcu ProgressStatus
s
else ProgressStatus -> Integer
totalUnits ProgressStatus
s}
newcu :: ProgressStatus -> Integer
newcu s :: ProgressStatus
s = ProgressStatus -> Integer
completedUnits ProgressStatus
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
count
incrP' :: Progress -> Integer -> IO ()
incrP' :: Progress -> Integer -> IO ()
incrP' po :: Progress
po count :: Integer
count =
Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po (\s :: ProgressStatus
s -> ProgressStatus
s {completedUnits :: Integer
completedUnits = ProgressStatus -> Integer
completedUnits ProgressStatus
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
count})
setP :: Progress -> Integer -> IO ()
setP :: Progress -> Integer -> IO ()
setP po :: Progress
po count :: Integer
count = Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po ProgressStatus -> ProgressStatus
statusfunc
where statusfunc :: ProgressStatus -> ProgressStatus
statusfunc s :: ProgressStatus
s =
ProgressStatus
s {completedUnits :: Integer
completedUnits = Integer
count,
totalUnits :: Integer
totalUnits = if Integer
count Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> ProgressStatus -> Integer
totalUnits ProgressStatus
s
then Integer
count
else ProgressStatus -> Integer
totalUnits ProgressStatus
s}
setP' :: Progress -> Integer -> IO ()
setP' :: Progress -> Integer -> IO ()
setP' po :: Progress
po count :: Integer
count = Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po (\s :: ProgressStatus
s -> ProgressStatus
s {completedUnits :: Integer
completedUnits = Integer
count})
incrTotal :: Progress -> Integer -> IO ()
incrTotal :: Progress -> Integer -> IO ()
incrTotal po :: Progress
po count :: Integer
count =
Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po (\s :: ProgressStatus
s -> ProgressStatus
s {totalUnits :: Integer
totalUnits = ProgressStatus -> Integer
totalUnits ProgressStatus
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
count})
setTotal :: Progress -> Integer -> IO ()
setTotal :: Progress -> Integer -> IO ()
setTotal po :: Progress
po count :: Integer
count =
Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus Progress
po (\s :: ProgressStatus
s -> ProgressStatus
s {totalUnits :: Integer
totalUnits = Integer
count})
getSpeed :: (ProgressStatuses a (IO b), Fractional b) => a -> IO b
getSpeed :: a -> IO b
getSpeed po :: a
po = a -> (ProgressStatus -> IO b) -> IO b
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
po ((ProgressStatus -> IO b) -> IO b)
-> (ProgressStatus -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \status :: ProgressStatus
status ->
do Integer
t <- ProgressStatus -> ProgressTimeSource
timeSource ProgressStatus
status
let elapsed :: Integer
elapsed = Integer
t Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- (ProgressStatus -> Integer
startTime ProgressStatus
status)
b -> IO b
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> IO b) -> b -> IO b
forall a b. (a -> b) -> a -> b
$ if Integer
elapsed Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then Rational -> b
forall a. Fractional a => Rational -> a
fromRational 0
else Rational -> b
forall a. Fractional a => Rational -> a
fromRational ((ProgressStatus -> Integer
completedUnits ProgressStatus
status) Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% Integer
elapsed)
getETR :: (ProgressStatuses a (IO Integer),
ProgressStatuses a (IO Rational)) => a -> IO Integer
getETR :: a -> ProgressTimeSource
getETR po :: a
po =
do Rational
speed <- ((a -> IO Rational
forall a b. (ProgressStatuses a (IO b), Fractional b) => a -> IO b
getSpeed a
po)::IO Rational)
if Rational
speed Rational -> Rational -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then Integer -> ProgressTimeSource
forall (m :: * -> *) a. Monad m => a -> m a
return 0
else
a -> (ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
po ((ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource)
-> (ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource
forall a b. (a -> b) -> a -> b
$ \status :: ProgressStatus
status ->
do let remaining :: Integer
remaining = ProgressStatus -> Integer
totalUnits ProgressStatus
status Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- ProgressStatus -> Integer
completedUnits ProgressStatus
status
Integer -> ProgressTimeSource
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> ProgressTimeSource) -> Integer -> ProgressTimeSource
forall a b. (a -> b) -> a -> b
$ Rational -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (Rational -> Integer) -> Rational -> Integer
forall a b. (a -> b) -> a -> b
$ (Integer -> Rational
forall a. Real a => a -> Rational
toRational Integer
remaining) Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
speed
getETA :: (ProgressStatuses a (IO Integer),
ProgressStatuses a (IO Rational)) => a -> IO Integer
getETA :: a -> ProgressTimeSource
getETA po :: a
po =
do Integer
etr <- a -> ProgressTimeSource
forall a.
(ProgressStatuses a ProgressTimeSource,
ProgressStatuses a (IO Rational)) =>
a -> ProgressTimeSource
getETR a
po
a -> (ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource
forall a b. ProgressStatuses a b => a -> (ProgressStatus -> b) -> b
withStatus a
po ((ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource)
-> (ProgressStatus -> ProgressTimeSource) -> ProgressTimeSource
forall a b. (a -> b) -> a -> b
$ \status :: ProgressStatus
status ->
do Integer
timenow <- ProgressStatus -> ProgressTimeSource
timeSource ProgressStatus
status
Integer -> ProgressTimeSource
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> ProgressTimeSource) -> Integer -> ProgressTimeSource
forall a b. (a -> b) -> a -> b
$ Integer
timenow Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
etr
defaultTimeSource :: ProgressTimeSource
defaultTimeSource :: ProgressTimeSource
defaultTimeSource = IO ClockTime
getClockTime IO ClockTime
-> (ClockTime -> ProgressTimeSource) -> ProgressTimeSource
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Integer -> ProgressTimeSource
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> ProgressTimeSource)
-> (ClockTime -> Integer) -> ClockTime -> ProgressTimeSource
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClockTime -> Integer
forall a. Num a => ClockTime -> a
clockTimeToEpoch)
now :: ProgressRecords a ProgressTimeSource => a -> ProgressTimeSource
now :: a -> ProgressTimeSource
now x :: a
x = a -> (ProgressRecord -> ProgressTimeSource) -> ProgressTimeSource
forall a b. ProgressRecords a b => a -> (ProgressRecord -> b) -> b
withRecord a
x (ProgressStatus -> ProgressTimeSource
timeSource (ProgressStatus -> ProgressTimeSource)
-> (ProgressRecord -> ProgressStatus)
-> ProgressRecord
-> ProgressTimeSource
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status)
modStatus :: Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus :: Progress -> (ProgressStatus -> ProgressStatus) -> IO ()
modStatus (Progress mp :: MVar ProgressRecord
mp) func :: ProgressStatus -> ProgressStatus
func =
MVar ProgressRecord
-> (ProgressRecord -> IO ProgressRecord) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar ProgressRecord
mp ProgressRecord -> IO ProgressRecord
modfunc
where modfunc :: ProgressRecord -> IO ProgressRecord
modfunc :: ProgressRecord -> IO ProgressRecord
modfunc oldpr :: ProgressRecord
oldpr =
do let newpr :: ProgressRecord
newpr = ProgressRecord
oldpr {status :: ProgressStatus
status = ProgressStatus -> ProgressStatus
func (ProgressRecord -> ProgressStatus
status ProgressRecord
oldpr)}
(ProgressCallback -> IO ()) -> [ProgressCallback] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\x :: ProgressCallback
x -> ProgressCallback
x (ProgressRecord -> ProgressStatus
status ProgressRecord
oldpr) (ProgressRecord -> ProgressStatus
status ProgressRecord
newpr))
(ProgressRecord -> [ProgressCallback]
callbacks ProgressRecord
oldpr)
case (ProgressStatus -> Integer
completedUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
newpr) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
-
(ProgressStatus -> Integer
completedUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr) of
0 -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
x :: Integer
x -> ProgressRecord -> (Progress -> IO ()) -> IO ()
callParents ProgressRecord
newpr (\y :: Progress
y -> Progress -> Integer -> IO ()
incrP' Progress
y Integer
x)
case (ProgressStatus -> Integer
totalUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
newpr) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
-
(ProgressStatus -> Integer
totalUnits (ProgressStatus -> Integer)
-> (ProgressRecord -> ProgressStatus) -> ProgressRecord -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgressRecord -> ProgressStatus
status (ProgressRecord -> Integer) -> ProgressRecord -> Integer
forall a b. (a -> b) -> a -> b
$ ProgressRecord
oldpr) of
0 -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
x :: Integer
x -> ProgressRecord -> (Progress -> IO ()) -> IO ()
callParents ProgressRecord
newpr (\y :: Progress
y -> Progress -> Integer -> IO ()
incrTotal Progress
y Integer
x)
ProgressRecord -> IO ProgressRecord
forall (m :: * -> *) a. Monad m => a -> m a
return ProgressRecord
newpr
callParents :: ProgressRecord -> (Progress -> IO ()) -> IO ()
callParents :: ProgressRecord -> (Progress -> IO ()) -> IO ()
callParents pr :: ProgressRecord
pr func :: Progress -> IO ()
func = (Progress -> IO ()) -> [Progress] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Progress -> IO ()
func (ProgressRecord -> [Progress]
parents ProgressRecord
pr)