diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+
+Version 0.1
+-----
+
+* Initial version.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2016 David Sorokin <david.sorokin@gmail.com>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Simulation/Aivika/RealTime.hs b/Simulation/Aivika/RealTime.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime.hs
@@ -0,0 +1,18 @@
+
+-- |
+-- Module     : Simulation.Aivika.RealTime
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- This module re-exports the library functionality.
+--
+module Simulation.Aivika.RealTime
+       (-- * Modules
+        module Simulation.Aivika.RealTime.RT,
+        module Simulation.Aivika.RealTime.Event) where
+
+import Simulation.Aivika.RealTime.RT
+import Simulation.Aivika.RealTime.Event
diff --git a/Simulation/Aivika/RealTime/Event.hs b/Simulation/Aivika/RealTime/Event.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime/Event.hs
@@ -0,0 +1,18 @@
+
+{-# LANGUAGE TypeFamilies #-}
+
+-- |
+-- Module     : Simulation.Aivika.RealTime.Event
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- The module defines an event queue, where 'RT' can be an instance of 'EventQueueing'.
+--
+module Simulation.Aivika.RealTime.Event () where
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.RealTime.Internal.Event
+import Simulation.Aivika.RealTime.Internal.RT
diff --git a/Simulation/Aivika/RealTime/Internal/Channel.hs b/Simulation/Aivika/RealTime/Internal/Channel.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime/Internal/Channel.hs
@@ -0,0 +1,76 @@
+
+-- |
+-- Module     : Simulation.Aivika.RealTime.Internal.Channel
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- This module defines a channel with fast checking procedure whether the channel is empty.
+--
+module Simulation.Aivika.RealTime.Internal.Channel
+       (Channel,
+        newChannel,
+        channelEmpty,
+        readChannel,
+        writeChannel,
+        awaitChannel) where
+
+import Data.List
+import Data.IORef
+
+import Control.Concurrent.STM
+import Control.Monad
+
+-- | A channel.
+data Channel a =
+  Channel { channelList :: TVar [a],
+            channelListEmpty :: TVar Bool,
+            channelListEmptyIO :: IORef Bool
+          }
+
+-- | Create a new channel.
+newChannel :: IO (Channel a)
+newChannel =
+  do list <- newTVarIO []
+     listEmpty <- newTVarIO True
+     listEmptyIO <- newIORef True
+     return Channel { channelList = list,
+                      channelListEmpty = listEmpty,
+                      channelListEmptyIO = listEmptyIO }
+
+-- | Test quickly whether the channel is empty.
+channelEmpty :: Channel a -> IO Bool
+channelEmpty ch =
+  readIORef (channelListEmptyIO ch)
+
+-- | Read all data from the channel. 
+readChannel :: Channel a -> IO [a]
+readChannel ch =
+  do empty <- readIORef (channelListEmptyIO ch)
+     if empty
+       then return []
+       else do writeIORef (channelListEmptyIO ch) True
+               xs <- atomically $
+                     do xs <- readTVar (channelList ch)
+                        writeTVar (channelList ch) []
+                        writeTVar (channelListEmpty ch) True
+                        return xs
+               return (reverse xs)
+
+-- | Write the value in the channel.
+writeChannel :: Channel a -> a -> IO ()
+writeChannel ch a =
+  do atomically $
+       do xs <- readTVar (channelList ch)
+          writeTVar (channelList ch) (a : xs)
+          writeTVar (channelListEmpty ch) False
+     writeIORef (channelListEmptyIO ch) False
+
+-- | Wait for data in the channel.
+awaitChannel :: Channel a -> IO ()
+awaitChannel ch =
+  atomically $
+  do empty <- readTVar (channelListEmpty ch)
+     when empty retry
diff --git a/Simulation/Aivika/RealTime/Internal/Event.hs b/Simulation/Aivika/RealTime/Internal/Event.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime/Internal/Event.hs
@@ -0,0 +1,224 @@
+
+{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
+
+-- |
+-- Module     : Simulation.Aivika.RealTime.Internal.Event
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- The module defines an event queue.
+--
+module Simulation.Aivika.RealTime.Internal.Event () where
+
+import Data.Maybe
+import Data.IORef
+import Data.Time.Clock
+
+import System.Timeout
+
+import Control.Monad
+import Control.Monad.Trans
+import Control.Exception
+
+import qualified Simulation.Aivika.PriorityQueue as PQ
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.Trans.Internal.Types
+
+import Simulation.Aivika.RealTime.Internal.Channel
+import Simulation.Aivika.RealTime.Internal.RT
+
+-- | An implementation of the 'EventQueueing' type class.
+instance MonadIO m => EventQueueing (RT m) where
+
+  {-# SPECIALIZE instance EventQueueing (RT IO) #-}
+
+  -- | The event queue type.
+  data EventQueue (RT m) =
+    EventQueueRT { queuePQ :: PQ.PriorityQueue (Point (RT m) -> RT m ()),
+                   -- ^ the underlying priority queue
+                   queueBusy :: IORef Bool,
+                   -- ^ whether the queue is currently processing events
+                   queueTime :: IORef Double,
+                   -- ^ the actual time of the event queue
+                   queueStartUTCTime :: UTCTime
+                   -- ^ the system time of starting the simulation
+                 }
+
+  newEventQueue specs =
+    do t0 <- liftIO getCurrentTime
+       t  <- liftIO $ newIORef $ spcStartTime specs
+       f  <- liftIO $ newIORef False
+       pq <- liftIO PQ.newQueue
+       return EventQueueRT { queuePQ   = pq,
+                             queueBusy = f,
+                             queueTime = t,
+                             queueStartUTCTime = t0 }
+
+  enqueueEvent t (Event m) =
+    Event $ \p ->
+    let pq = queuePQ $ runEventQueue $ pointRun p
+    in liftIO $ PQ.enqueue pq t m
+
+  runEventWith processing (Event e) =
+    Dynamics $ \p ->
+    do invokeDynamics p $ processEvents processing
+       e p
+
+  eventQueueCount =
+    Event $ \p ->
+    let pq = queuePQ $ runEventQueue $ pointRun p
+    in liftIO $ PQ.queueCount pq
+
+-- | Return the current event point.
+currentEventPoint :: MonadIO m => Event (RT m) (Point (RT m))
+{-# INLINE currentEventPoint #-}
+currentEventPoint =
+  Event $ \p ->
+  do let q = runEventQueue $ pointRun p
+     t' <- liftIO $ readIORef (queueTime q)
+     if t' == pointTime p
+       then return p
+       else let sc = pointSpecs p
+                t0 = spcStartTime sc
+                dt = spcDT sc
+                n' = fromIntegral $ floor ((t' - t0) / dt)
+            in return p { pointTime = t',
+                          pointIteration = n',
+                          pointPhase = -1 }
+
+-- | Process the pending events.
+processPendingEventsCore :: MonadIO m => Bool -> Dynamics (RT m) ()
+{-# INLINE processPendingEventsCore #-}
+processPendingEventsCore includingCurrentEvents = Dynamics r where
+  r p =
+    do let q = runEventQueue $ pointRun p
+           f = queueBusy q
+       f' <- liftIO $ readIORef f
+       if f'
+         then error $
+              "Detected an event loop, which may indicate to " ++
+              "a logical error in the model: processPendingEventsCore"
+         else do liftIO $ writeIORef f True
+                 call q p p
+                 liftIO $ writeIORef f False
+  call q p p0 =
+    do let pq = queuePQ q
+           r  = pointRun p
+       -- process external actions
+       p1 <- invokeEvent p0 currentEventPoint
+       invokeEvent p1 processChannelActions
+       -- proceed with processing the events
+       f <- liftIO $ PQ.queueNull pq
+       unless f $
+         do (t2, c2) <- liftIO $ PQ.queueFront pq
+            let t = queueTime q
+            t' <- liftIO $ readIORef t
+            when (t2 < t') $ 
+              -- error "The time value is too small: processPendingEventsCore"
+              error $
+              "The time value is too small (" ++ show t2 ++
+              " < " ++ show t' ++ "): processPendingEventsCore"
+            when ((t2 < pointTime p) ||
+                  (includingCurrentEvents && (t2 == pointTime p))) $
+              do emulated <- invokeEvent p1 $ emulateRealTimeDelay t2
+                 if emulated
+                   then do let sc = pointSpecs p
+                               t0 = spcStartTime sc
+                               dt = spcDT sc
+                               n2 = fromIntegral $ floor ((t2 - t0) / dt)
+                               p2 = p { pointTime = t2,
+                                        pointIteration = n2,
+                                        pointPhase = -1 }
+                           liftIO $ writeIORef t t2
+                           liftIO $ PQ.dequeue pq
+                           c2 p2
+                           call q p p2
+                   else call q p p1
+
+-- | Process the pending events synchronously, i.e. without past.
+processPendingEvents :: MonadIO m => Bool -> Dynamics (RT m) ()
+{-# INLINE processPendingEvents #-}
+processPendingEvents includingCurrentEvents = Dynamics r where
+  r p =
+    do let q = runEventQueue $ pointRun p
+           t = queueTime q
+       t' <- liftIO $ readIORef t
+       if pointTime p < t'
+         then error $
+              "The current time is less than " ++
+              "the time in the queue: processPendingEvents"
+         else invokeDynamics p m
+  m = processPendingEventsCore includingCurrentEvents
+
+-- | A memoized value.
+processEventsIncludingCurrent :: MonadIO m => Dynamics (RT m) ()
+{-# INLINE processEventsIncludingCurrent #-}
+processEventsIncludingCurrent = processPendingEvents True
+
+-- | A memoized value.
+processEventsIncludingEarlier :: MonadIO m => Dynamics (RT m) ()
+{-# INLINE processEventsIncludingEarlier #-}
+processEventsIncludingEarlier = processPendingEvents False
+
+-- | A memoized value.
+processEventsIncludingCurrentCore :: MonadIO m => Dynamics (RT m) ()
+{-# INLINE processEventsIncludingCurrentCore #-}
+processEventsIncludingCurrentCore = processPendingEventsCore True
+
+-- | A memoized value.
+processEventsIncludingEarlierCore :: MonadIO m => Dynamics (RT m) ()
+{-# INLINE processEventsIncludingEarlierCore #-}
+processEventsIncludingEarlierCore = processPendingEventsCore True
+
+-- | Process the events.
+processEvents :: MonadIO m => EventProcessing -> Dynamics (RT m) ()
+{-# INLINABLE processEvents #-}
+processEvents CurrentEvents = processEventsIncludingCurrent
+processEvents EarlierEvents = processEventsIncludingEarlier
+processEvents CurrentEventsOrFromPast = processEventsIncludingCurrentCore
+processEvents EarlierEventsOrFromPast = processEventsIncludingEarlierCore
+
+-- | Process the channel actions.
+processChannelActions :: MonadIO m => Event (RT m) ()
+{-# INLINABLE processChannelActions #-}
+processChannelActions =
+  Event $ \p ->
+  do ch <- rtChannel
+     f  <- liftIO $ channelEmpty ch
+     unless f $
+       do xs <- liftIO $ readChannel ch
+          forM_ xs $ invokeEvent p
+
+-- | Try to emulate the real time delay till the specified
+-- modeling time without interruption.
+emulateRealTimeDelay :: MonadIO m => Double -> Event (RT m) Bool
+{-# INLINABLE emulateRealTimeDelay #-}
+emulateRealTimeDelay t2 =
+  Event $ \p ->
+  do ps  <- rtParams
+     utc <- liftIO getCurrentTime
+     let scaling = rtScaling ps
+         delta   = rtIntervalDelta ps
+         sc = pointSpecs p
+         t0 = spcStartTime sc
+         t  = pointTime p
+         dt = rtScale scaling t0 t2
+         q  = runEventQueue (pointRun p)
+         utc0 = queueStartUTCTime q
+         utc' = addUTCTime (fromRational $ toRational dt) utc0
+         rdt  = fromRational $ toRational (diffUTCTime utc' utc)
+     if rdt < delta
+       then return True
+       else do ch <- rtChannel
+               let dt = secondsToMicroseconds rdt
+               interrupted <- liftIO $
+                              timeout dt $ awaitChannel ch
+               return $ isNothing interrupted
+
+-- | Convert seconds to microseconds.
+secondsToMicroseconds :: Double -> Int
+secondsToMicroseconds x = fromInteger $ toInteger $ round (1000000 * x) 
diff --git a/Simulation/Aivika/RealTime/Internal/RT.hs b/Simulation/Aivika/RealTime/Internal/RT.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime/Internal/RT.hs
@@ -0,0 +1,157 @@
+
+-- |
+-- Module     : Simulation.Aivika.RealTime.Internal.RT
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- This module defines a soft real-time computation based on 'IO'.
+--
+module Simulation.Aivika.RealTime.Internal.RT
+       (RT(..),
+        RTParams(..),
+        RTContext(..),
+        RTScaling(..),
+        invokeRT,
+        runRT,
+        defaultRTParams,
+        newRTContext,
+        rtParams,
+        rtChannel,
+        rtScale) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans
+
+import Simulation.Aivika.Trans.Exception
+import Simulation.Aivika.Trans.Internal.Types
+
+import Simulation.Aivika.RealTime.Internal.Channel
+
+-- | How the modeling time is scaled to a real time.
+data RTScaling = RTLinearScaling Double
+                 -- ^ one unit of modeling time interval matches
+                 -- the specified amount of real seconds
+               | RTLogScaling Double
+                 -- ^ the logarithm of one unit of modeling time
+                 -- interval matches the specified amount of
+                 -- real seconds
+               | RTScalingFunction (Double -> Double -> Double)
+                 -- ^ we explicitly define how many real seconds
+                 -- will we receive for the interval specified by
+                 -- the provided start time and current modeling time
+
+-- | Scale the modeling time to a real time.
+rtScale :: RTScaling
+           -- ^ the scaling method
+           -> Double
+           -- ^ the start modeling time
+           -> Double
+           -- ^ the current modeling time
+           -> Double
+           -- ^ the real time interval
+rtScale (RTLinearScaling k) t0 t = k * (t - t0)
+rtScale (RTLogScaling k) t0 t = k * log (t - t0)
+rtScale (RTScalingFunction f) t0 t = f t0 t
+
+-- | The parameters for the 'RT' computation.
+data RTParams =
+  RTParams { rtScaling :: RTScaling,
+             -- ^ The scaling of the modeling time to a real time.
+             rtIntervalDelta :: Double
+             -- ^ The real time interval accuracy in seconds.
+           }
+
+-- | The soft real-time computation based on 'IO'-derived computation @m@.
+newtype RT m a = RT { unRT :: RTContext m -> m a
+                      -- ^ Unwrap the computation.
+                    }
+
+-- | The context of the 'RT' computation.
+data RTContext m =
+  RTContext { rtChannel0 :: Channel (Event (RT m) ()),
+              -- ^ The channel of pending actions.
+              rtParams0 :: RTParams
+              -- ^ The parameters of the computation.
+            }
+
+instance Monad m => Monad (RT m) where
+
+  {-# INLINE return #-}
+  return = RT . const . return
+
+  {-# INLINE (>>=) #-}
+  (RT m) >>= k = RT $ \ctx ->
+    m ctx >>= \a ->
+    let m' = unRT (k a) in m' ctx
+
+instance Applicative m => Applicative (RT m) where
+
+  {-# INLINE pure #-}
+  pure = RT . const . pure
+
+  {-# INLINE (<*>) #-}
+  (RT f) <*> (RT m) = RT $ \ctx -> f ctx <*> m ctx  
+
+instance Functor m => Functor (RT m) where
+
+  {-# INLINE fmap #-}
+  fmap f (RT m) = RT $ fmap f . m 
+
+instance MonadIO m => MonadIO (RT m) where
+
+  {-# INLINE liftIO #-}
+  liftIO = RT . const . liftIO
+  
+instance MonadException m => MonadException (RT m) where
+
+  {-# INLINE catchComp #-}
+  catchComp (RT m) h = RT $ \ctx ->
+    catchComp (m ctx) (\e -> unRT (h e) ctx)
+
+  {-# INLINE finallyComp #-}
+  finallyComp (RT m1) (RT m2) = RT $ \ctx ->
+    finallyComp (m1 ctx) (m2 ctx)
+
+  {-# INLINE throwComp #-}
+  throwComp e = RT $ \ctx ->
+    throwComp e
+
+-- | Invoke the 'RT' computation.
+invokeRT :: RTContext m -> RT m a -> m a
+{-# INLINE invokeRT #-}
+invokeRT ctx (RT m) = m ctx
+
+-- | The default parameters for the 'RT' computation,
+-- where one unit of modeling time matches one real second
+-- and the real time interval is specified with precision of
+-- one millisecond.
+defaultRTParams :: RTParams
+defaultRTParams =
+  RTParams { rtScaling = RTLinearScaling 1,
+             rtIntervalDelta = 0.001
+           }
+
+-- | Return the parameters of the current computation.
+rtParams :: Monad m => RT m RTParams
+{-# INLINE rtParams #-}
+rtParams = RT $ return . rtParams0
+
+-- | Return the chanel of pending actions.
+rtChannel :: Monad m => RT m (Channel (Event (RT m) ()))
+{-# INLINE rtChannel #-}
+rtChannel = RT $ return . rtChannel0
+
+-- | Run the computation using the specified context.
+runRT :: RT m a -> RTContext m -> m a
+runRT = unRT
+
+-- | Create a new real-time computation context.
+newRTContext :: RTParams -> IO (RTContext m)
+newRTContext ps =
+  do channel <- newChannel
+     return RTContext { rtChannel0 = channel,
+                        rtParams0 = ps }
diff --git a/Simulation/Aivika/RealTime/RT.hs b/Simulation/Aivika/RealTime/RT.hs
new file mode 100644
--- /dev/null
+++ b/Simulation/Aivika/RealTime/RT.hs
@@ -0,0 +1,127 @@
+
+-- |
+-- Module     : Simulation.Aivika.RealTime.RT
+-- Copyright  : Copyright (c) 2016, David Sorokin <david.sorokin@gmail.com>
+-- License    : BSD3
+-- Maintainer : David Sorokin <david.sorokin@gmail.com>
+-- Stability  : experimental
+-- Tested with: GHC 8.0.1
+--
+-- This module defines a soft real-time computation based on 'IO'.
+--
+module Simulation.Aivika.RealTime.RT
+       (-- * Soft real-time computation
+        RT,
+        RTParams(..),
+        RTContext,
+        RTScaling(..),
+        runRT,
+        defaultRTParams,
+        newRTContext,
+        rtParams,
+        rtScale,
+        -- * Invoking actions within the simulation
+        applyEventRT,
+        applyEventRT_,
+        enqueueEventRT,
+        enqueueEventRT_) where
+
+import Control.Monad
+import Control.Monad.Trans
+
+import Control.Concurrent.STM
+import Control.Concurrent.Async
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.IO.Comp
+import Simulation.Aivika.IO.Ref.Base
+import Simulation.Aivika.IO.QueueStrategy
+import Simulation.Aivika.IO.Exception
+
+import Simulation.Aivika.RealTime.Internal.RT
+import Simulation.Aivika.RealTime.Internal.Channel
+import Simulation.Aivika.RealTime.Event
+
+-- | An implementation of the 'MonadTemplate' type class.
+instance (Monad m, MonadIO m, MonadException m) => MonadTemplate (RT m)
+
+-- | An implementation of the 'MonadDES' type class.
+instance (Monad m, MonadIO m, MonadException m) => MonadDES (RT m) where
+
+  {-# SPECIALIZE instance MonadDES (RT IO) #-}
+
+-- | An implementation of the 'EventIOQueueing' type class.
+instance (Monad m, MonadIO m, MonadException m) => EventIOQueueing (RT m) where
+
+  {-# SPECIALIZE instance EventIOQueueing (RT IO) #-}
+
+  enqueueEventIO = enqueueEvent
+
+-- | Invoke the action within the soft real-time simulation.
+invokeEventRT_ :: MonadIO m
+                  => RTContext m
+                  -- ^ the computation context
+                  -> (Event (RT m) () -> Event (RT m) ())
+                  -- ^ the computation transform
+                  -> Event (RT m) ()
+                  -- ^ the computation to invoke
+                  -> m ()
+                  -- ^ the action of invoking the computation
+{-# INLINABLE invokeEventRT_ #-}
+invokeEventRT_ ctx f m =
+  let ch = rtChannel0 ctx
+  in liftIO $ writeChannel ch $ f m
+
+-- | Invoke the action within the soft real-time simulation.
+invokeEventRT :: MonadIO m
+                 => RTContext m
+                 -- ^ the computation context
+                 -> (Event (RT m) () -> Event (RT m) ())
+                 -- ^ the computation transform
+                 -> Event (RT m) a
+                 -- ^ the computation to invoke
+                 -> m (Async a)
+                 -- ^ the result of computation
+{-# INLINABLE invokeEventRT #-}
+invokeEventRT ctx f m =
+  do let ch = rtChannel0 ctx
+     v <- liftIO $ newTVarIO Nothing
+     liftIO $
+       writeChannel ch $
+       f $
+       do a <- m
+          liftIO $
+            atomically $
+            writeTVar v (Just a)
+     liftIO $
+       async $
+       atomically $
+       do b <- readTVar v
+          case b of
+            Just a -> return a
+            Nothing -> retry
+
+-- | Apply the 'Event' computation within the soft real-time simulation
+-- with the specified context and return the result.
+applyEventRT :: MonadIO m => RTContext m -> Event (RT m) a -> m (Async a)
+{-# INLINABLE applyEventRT #-}
+applyEventRT ctx m = invokeEventRT ctx id m
+
+-- | Apply the 'Event' computation within the soft real-time simulation
+-- with the specified context.
+applyEventRT_ :: MonadIO m => RTContext m -> Event (RT m) () -> m ()
+{-# INLINABLE applyEventRT_ #-}
+applyEventRT_ ctx m = invokeEventRT_ ctx id m
+
+-- | Enqueue the 'Event' computation within the soft real-time simulation
+-- with the specified context at the modeling time provided and
+-- then return the result.
+enqueueEventRT :: MonadIO m => RTContext m -> Double -> Event (RT m) a -> m (Async a)
+{-# INLINABLE enqueueEventRT #-}
+enqueueEventRT ctx t m = invokeEventRT ctx (enqueueEvent t) m
+
+-- | Enqueue the 'Event' computation within the soft real-time simulation
+-- with the specified context at the modeling time provided.
+enqueueEventRT_ :: MonadIO m => RTContext m -> Double -> Event (RT m) () -> m ()
+{-# INLINABLE enqueueEventRT_ #-}
+enqueueEventRT_ ctx t m = invokeEventRT_ ctx (enqueueEvent t) m
diff --git a/aivika-realtime.cabal b/aivika-realtime.cabal
new file mode 100644
--- /dev/null
+++ b/aivika-realtime.cabal
@@ -0,0 +1,53 @@
+name:            aivika-realtime
+version:         0.1
+synopsis:        Soft real-time simulation module for the Aivika library
+description:
+    This package allows running soft real-time simulations based on the aivika-transformers [1] library.
+    .
+    \[1] <http://hackage.haskell.org/package/aivika-transformers>
+    .
+category:        Simulation
+license:         BSD3
+license-file:    LICENSE
+copyright:       (c) 2016. David Sorokin <david.sorokin@gmail.com>
+author:          David Sorokin
+maintainer:      David Sorokin <david.sorokin@gmail.com>
+homepage:        http://www.aivikasoft.com/en/products/aivika.html
+cabal-version:   >= 1.6
+build-type:      Simple
+tested-with:     GHC == 7.10.3
+
+extra-source-files:  CHANGELOG.md
+                     tests/MachRep1.hs
+                     tests/MachRep1Ver2.hs
+                     tests/MachRep1Ver3.hs
+
+library
+
+    exposed-modules: Simulation.Aivika.RealTime
+                     Simulation.Aivika.RealTime.Event
+                     Simulation.Aivika.RealTime.RT
+
+    other-modules:   Simulation.Aivika.RealTime.Internal.Channel
+                     Simulation.Aivika.RealTime.Internal.Event
+                     Simulation.Aivika.RealTime.Internal.RT
+
+    build-depends:   base >= 3 && < 6,
+                     mtl >= 2.1.1,
+                     stm >= 2.4.2,
+                     containers >= 0.4.0.0,
+                     async >= 2.0,
+                     time >= 1.5.0.1,
+                     aivika >= 4.5,
+                     aivika-transformers >= 4.5.1
+
+    extensions:      TypeFamilies,
+                     MultiParamTypeClasses,
+                     FlexibleInstances
+
+    ghc-options:     -O2
+
+source-repository head
+
+    type:     git
+    location: https://github.com/dsorokin/aivika-lattice
diff --git a/tests/MachRep1.hs b/tests/MachRep1.hs
new file mode 100644
--- /dev/null
+++ b/tests/MachRep1.hs
@@ -0,0 +1,80 @@
+
+-- It corresponds to model MachRep1 described in document 
+-- Introduction to Discrete-Event Simulation and the SimPy Language
+-- [http://heather.cs.ucdavis.edu/~matloff/156/PLN/DESimIntro.pdf]. 
+-- SimPy is available on [http://simpy.sourceforge.net/].
+--   
+-- The model description is as follows.
+--
+-- Two machines, which sometimes break down.
+-- Up time is exponentially distributed with mean 1.0, and repair time is
+-- exponentially distributed with mean 0.5. There are two repairpersons,
+-- so the two machines can be repaired simultaneously if they are down
+-- at the same time.
+--
+-- Output is long-run proportion of up time. Should get value of about
+-- 0.66.
+
+import Control.Monad.Trans
+
+import Data.Time.Clock
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.RealTime
+
+type DES = RT IO
+
+meanUpTime = 1.0
+meanRepairTime = 0.5
+
+specs = Specs { spcStartTime = 0.0,
+                -- spcStopTime = 1000.0,
+                spcStopTime = 30.0,
+                spcDT = 1.0,
+                spcMethod = RungeKutta4,
+                spcGeneratorType = SimpleGenerator }
+        
+model :: Simulation DES (Results DES)
+model =
+  do totalUpTime <- newRef 0.0
+     
+     let machine =
+           do upTime <-
+                liftParameter $
+                randomExponential meanUpTime
+              holdProcess upTime
+              liftEvent $ 
+                modifyRef totalUpTime (+ upTime)
+              repairTime <-
+                liftParameter $
+                randomExponential meanRepairTime
+              holdProcess repairTime
+              machine
+
+     runEventInStartTime $
+       enqueueEventWithIntegTimes $
+       do utc <- liftIO getCurrentTime
+          traceEvent ("current time: " ++ show utc) $
+            return ()
+
+     runProcessInStartTime machine
+     runProcessInStartTime machine
+
+     let upTimeProp =
+           do x <- readRef totalUpTime
+              y <- liftDynamics time
+              return $ x / (2 * y)
+
+     return $
+       results
+       [resultSource
+        "upTimeProp"
+        "The long-run proportion of up time (~ 0.66)"
+        upTimeProp]
+  
+main =
+  do let rt = printSimulationResultsInStopTime
+              printResultSourceInEnglish
+              model specs
+     ctx <- newRTContext $ defaultRTParams { rtScaling = RTLinearScaling 1 }
+     runRT rt ctx
diff --git a/tests/MachRep1Ver2.hs b/tests/MachRep1Ver2.hs
new file mode 100644
--- /dev/null
+++ b/tests/MachRep1Ver2.hs
@@ -0,0 +1,87 @@
+
+-- It corresponds to model MachRep1 described in document 
+-- Introduction to Discrete-Event Simulation and the SimPy Language
+-- [http://heather.cs.ucdavis.edu/~matloff/156/PLN/DESimIntro.pdf]. 
+-- SimPy is available on [http://simpy.sourceforge.net/].
+--   
+-- The model description is as follows.
+--
+-- Two machines, which sometimes break down.
+-- Up time is exponentially distributed with mean 1.0, and repair time is
+-- exponentially distributed with mean 0.5. There are two repairpersons,
+-- so the two machines can be repaired simultaneously if they are down
+-- at the same time.
+--
+-- Output is long-run proportion of up time. Should get value of about
+-- 0.66.
+
+import Control.Monad.Trans
+import Control.Concurrent
+
+import Data.Time.Clock
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.RealTime
+
+type DES = RT IO
+
+meanUpTime = 1.0
+meanRepairTime = 0.5
+
+specs = Specs { spcStartTime = 0.0,
+                -- spcStopTime = 1000.0,
+                spcStopTime = 30.0,
+                spcDT = 1.0,
+                spcMethod = RungeKutta4,
+                spcGeneratorType = SimpleGenerator }
+        
+model :: Simulation DES (Results DES)
+model =
+  do totalUpTime <- newRef 0.0
+     
+     let machine =
+           do upTime <-
+                liftParameter $
+                randomExponential meanUpTime
+              holdProcess upTime
+              liftEvent $ 
+                modifyRef totalUpTime (+ upTime)
+              repairTime <-
+                liftParameter $
+                randomExponential meanRepairTime
+              holdProcess repairTime
+              machine
+
+     runEventInStartTime $
+       enqueueEventWithIntegTimes $
+       do utc <- liftIO getCurrentTime
+          traceEvent ("current time: " ++ show utc) $
+            return ()
+
+     runProcessInStartTime machine
+     runProcessInStartTime machine
+
+     let upTimeProp =
+           do x <- readRef totalUpTime
+              y <- liftDynamics time
+              return $ x / (2 * y)
+
+     return $
+       results
+       [resultSource
+        "upTimeProp"
+        "The long-run proportion of up time (~ 0.66)"
+        upTimeProp]
+  
+main =
+  do let rt = printSimulationResultsInStopTime
+              printResultSourceInEnglish
+              model specs
+     ctx <- newRTContext $ defaultRTParams { rtScaling = RTLinearScaling 1 }
+     forkIO $
+       do threadDelay (round $ 15.5 * 1000000)
+          putStrLn "Invoking the action (after 15.5 sec.)"
+          applyEventRT_ ctx $
+            traceEvent "The action was invoked" $
+            return ()
+     runRT rt ctx
diff --git a/tests/MachRep1Ver3.hs b/tests/MachRep1Ver3.hs
new file mode 100644
--- /dev/null
+++ b/tests/MachRep1Ver3.hs
@@ -0,0 +1,91 @@
+
+-- It corresponds to model MachRep1 described in document 
+-- Introduction to Discrete-Event Simulation and the SimPy Language
+-- [http://heather.cs.ucdavis.edu/~matloff/156/PLN/DESimIntro.pdf]. 
+-- SimPy is available on [http://simpy.sourceforge.net/].
+--   
+-- The model description is as follows.
+--
+-- Two machines, which sometimes break down.
+-- Up time is exponentially distributed with mean 1.0, and repair time is
+-- exponentially distributed with mean 0.5. There are two repairpersons,
+-- so the two machines can be repaired simultaneously if they are down
+-- at the same time.
+--
+-- Output is long-run proportion of up time. Should get value of about
+-- 0.66.
+
+import Control.Monad.Trans
+import Control.Concurrent
+import Control.Concurrent.Async
+
+import Data.Time.Clock
+
+import Simulation.Aivika.Trans
+import Simulation.Aivika.RealTime
+
+type DES = RT IO
+
+meanUpTime = 1.0
+meanRepairTime = 0.5
+
+specs = Specs { spcStartTime = 0.0,
+                -- spcStopTime = 1000.0,
+                spcStopTime = 30.0,
+                spcDT = 1.0,
+                spcMethod = RungeKutta4,
+                spcGeneratorType = SimpleGenerator }
+        
+model :: Simulation DES (Results DES)
+model =
+  do totalUpTime <- newRef 0.0
+     
+     let machine =
+           do upTime <-
+                liftParameter $
+                randomExponential meanUpTime
+              holdProcess upTime
+              liftEvent $ 
+                modifyRef totalUpTime (+ upTime)
+              repairTime <-
+                liftParameter $
+                randomExponential meanRepairTime
+              holdProcess repairTime
+              machine
+
+     runEventInStartTime $
+       enqueueEventWithIntegTimes $
+       do utc <- liftIO getCurrentTime
+          traceEvent ("current time: " ++ show utc) $
+            return ()
+
+     runProcessInStartTime machine
+     runProcessInStartTime machine
+
+     let upTimeProp =
+           do x <- readRef totalUpTime
+              y <- liftDynamics time
+              return $ x / (2 * y)
+
+     return $
+       results
+       [resultSource
+        "upTimeProp"
+        "The long-run proportion of up time (~ 0.66)"
+        upTimeProp]
+  
+main =
+  do let rt = printSimulationResultsInStopTime
+              printResultSourceInEnglish
+              model specs
+     ctx <- newRTContext $ defaultRTParams { rtScaling = RTLinearScaling 1 }
+     forkIO $
+       do threadDelay (round $ 15.5 * 1000000)
+          putStrLn "Invoking the action (after 15.5 sec.)"
+          future <-
+            applyEventRT ctx $
+            traceEvent "The action was invoked" $
+            liftDynamics time
+          t <- wait future
+          putStrLn $ "The time of invocation t = " ++ show t
+     runRT rt ctx
