content: 
  -- Example: Reneging from a Queue
  --
  -- It is described in [1]. This is section 7.8.
  -- 
  -- This example models customers arriving to a queue and leaving a queue
  -- after a prescribed period of time. The time between arrivals is 
  -- exponentially distributed with a mean of 20 minutes. The service time 
  -- for customers is uniformly distributed between 15 and 25 minutes. 
  -- Customers will only wait for service if the waiting time is less than
  -- a renege time which is lognormally distributed with a mean of 10 minutes
  -- and a standard deviation of 2 minutes. It is desired to estimate the time
  -- in the system for those customers served, the percent of customers that
  -- renege and the length of the waiting time.
  -- 
  -- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.
  
  import Control.Monad
  import Control.Monad.Trans
  
  import Data.Array
  
  import Simulation.Aivika
  import qualified Simulation.Aivika.Queue.Infinite as IQ
  
  -- | The simulation specs.
  specs = Specs { spcStartTime = 0.0,
                  spcStopTime = 10000.0,
                  spcDT = 0.1,
                  spcMethod = RungeKutta4,
                  spcGeneratorType = SimpleGenerator }
  
  mu = 10
  nu = 2
  
  logMu = log mu - logNu * logNu / 2
  logNu = sqrt $ log ((nu * nu) / (mu * mu) + 1) 
  
  model :: Simulation Results
  model = do
    let customers = randomExponentialStream 20
    timeInSystem <- newRef emptySamplingStats
    renegeEvents <- newRef (0 :: Int)
    queue <- runEventInStartTime $ IQ.newFCFSQueue
    let queueProcess =
          do x <- IQ.dequeue queue
             randomUniformProcess_ 15 25
             t <- liftDynamics time
             liftEvent $
               modifyRef timeInSystem $
               addSamplingStats (t - arrivalTime x)
             queueProcess
        renegingProcess x =
          do randomLogNormalProcess_ logMu logNu
             liftEvent $
               do f <- IQ.queueDelete queue x
                  when f $ modifyRef renegeEvents ((+) 1)
    runProcessInStartTime queueProcess
    runProcessInStartTime $
      flip consumeStream customers $ \x ->
      liftEvent $
      do IQ.enqueue queue x
         runProcess $ renegingProcess x
    return $
      results
      [resultSource
       "queue" "the queue"
       queue,
       --
       resultSource
       "timeInSystem" "time in system"
       timeInSystem,
       --
       resultSource
       "renegeEvents" "renege events"
       renegeEvents]
  
  modelSummary :: Simulation Results
  modelSummary =
    fmap resultSummary model
  
  main =
    do printSimulationResultsInStopTime
         printResultSourceInEnglish
         modelSummary specs
  