anchor.diff:    | Todo of id:Guid
     | Pass of id:Guid
     | Fail of id:Guid * ex:Exception
  -  | RunOver of minutes:int * seconds:int
  +  | RunOver of minutes:int * seconds:int * AsyncReplyChannel<int>
   
   let colorWriteReset color message =
     Console.ForegroundColor <- color
  
positive.code:           printMessages id
            colorWriteReset color.Yellow "Todo"
            return! loop passed failed skipped (todo + 1)
          | Reporter.RunOver (minutes, seconds) ->
              printfn ""
              printfn "%i minutes %i seconds to execute" minutes seconds
              colorWriteReset color.Green (sprintf "%i passed" passed)
              colorWriteReset color.Yellow (sprintf "%i skipped" skipped)
              colorWriteReset color.Yellow (sprintf "%i todo" todo)
              colorWriteReset color.Red (sprintf "%i failed" failed)
              return ()
        }
      loop 0 0 0 0)
  
negative.code: let newManager maxDOP : actor<Manager> =
    let sw = System.Diagnostics.Stopwatch.StartNew()
    actor.Start(fun self ->
      let rec loop workers maxWorkers doneWorkers replyChannel =
        async {
          let! msg = self.Receive ()
          match msg with
          | Manager.Initialize (suites) ->
            //build a worker per suite/test combo and give them their work
            let workers = suites |> List.map (fun suite -> suite.Tests |> List.map (fun test -> newWorker self test)) |> List.concat |> List.rev
            return! loop workers workers.Length 0 replyChannel
          | Manager.Start(replyChannel) ->
            //kick off the initial X workers
            self.Post(Manager.Run maxDOP)
            return! loop workers maxWorkers doneWorkers (Some replyChannel)
          | Manager.Run(count) ->
            if count = 0 then
              return! loop workers maxWorkers doneWorkers replyChannel
            else
              match workers with
              | [] -> return! loop [] maxWorkers doneWorkers replyChannel
              | head :: tail ->
                head.Post(Worker.Run)
                self.Post(Manager.Run(count - 1))
                return! loop tail maxWorkers doneWorkers replyChannel
          | Manager.WorkerDone ->
            self.Post(Manager.Run(1))
            let doneWorkers = doneWorkers + 1
            if doneWorkers = maxWorkers then
              let failed = reporter.PostAndReply(fun replyChannel -> Reporter.RunOver(int sw.Elapsed.TotalMinutes, int sw.Elapsed.TotalSeconds, replyChannel))
              replyChannel.Value.Reply failed
              return ()
            else
              return! loop workers maxWorkers doneWorkers replyChannel
        }
      loop [] 0 0 None)
  
  let run maxDOP =
    // suites list is in reverse order and have to be reversed before running the tests
    suites <- List.rev suites
    let manager = newManager maxDOP
    manager.Post(Manager.Initialize(suites))
    manager.PostAndReply(fun replyChannel -> Manager.Start replyChannel)
  
  //demo
  context "Test Context"
  