anchor.diff:  type IActivity =
       inherit ISchedulable
   
  -    abstract member TaskList    : TaskList    
  +    abstract member TaskList                    : TaskList    
       abstract member TaskHeartbeatTimeout        : Seconds
       abstract member TaskScheduleToStartTimeout  : Seconds
       abstract member TaskStartToCloseTimeout     : Seconds
  
positive.code:         // on the appropriate next course of action
          | ActivityTaskFailed(scheduledEvtId, _, details, reason) ->
              let (ActivityTaskScheduled(activityId, _, _, _, control, input, _, _, _, _)) = findEventTypeById scheduledEvtId events
              failedStage control activityId input details reason
  
          | ActivityTaskTimedOut(scheduledEvtId, _, timeoutType, details) ->
              let (ActivityTaskScheduled(activityId, _, _, _, control, input, _, _, _, _)) = findEventTypeById scheduledEvtId events            
              failedStage control activityId input details (Some(sprintf "Timeout : %s" <| str timeoutType))
  
          | ActivityTaskCompleted(scheduledEvtId, _, result) ->
              let (ActivityTaskScheduled(_, _, _, _, control, _, _, _, _, _)) = findEventTypeById scheduledEvtId events
  
negative.code:     
      /// Processes a string input and returns the result
      abstract member Process     : string -> string
  
  // Represents a workflow
  type IWorkflow = 
      inherit ISchedulable
  
      abstract member TaskList                     : TaskList
      abstract member Version                      : string
      abstract member TaskStartToCloseTimeout      : Seconds option
      abstract member ExecutionStartToCloseTimeout : Seconds option
      abstract member ChildPolicy                  : ChildPolicy option
  
      abstract member Start       : Amazon.SimpleWorkflow.AmazonSimpleWorkflowClient -> unit
  
  // #endregion
  
  type SchedulableState =
      {
          mutable StageNumber   : int
          mutable AttemptNumber : int
          mutable MaxAttempts   : int
          mutable ActionNumber  : int     // zero-based index of the action
          mutable TotalActions  : int     // total number of actions scheduled together
      }
  
  type Reducer = string[] -> string
  
  /// The different actions that can be taken as a stage in the workflow
  type StageAction = 
      | ScheduleActivity      of IActivity
      | StartChildWorkflow    of IWorkflow
      // ParallelActions args :
      //      the list of ISchedulable actions to schedule
      //      reducer to aggregate results from all the scheduled actions into a single result
      | ParallelActions       of ISchedulable[] * Reducer
  
  /// Represents a stage in the workflow
  type Stage =
      {
          StageNumber : int           // zero-based index, e.g. 5 = 6th stage
          Action      : StageAction   // what action to perform at this stage in the workflow?
      }
  
  type WorkflowState =
      {
          CurrentStageNumber  : int   // zero-based index of the currently executing stage
          TotalActions        : int   // total number of actions scheduled at this stage
          CompletedActions    : int   // the number of completed 
      }
  
  [<AutoOpen>]
  module WorkflowUtils =
      let private schedulableStateSerializer = JsonSerializer<SchedulableState>()
      let private workflowSerializer         = JsonSerializer<WorkflowState>()
  
      /// Serialize/Deserialize a SchedulableState to and from string
      let serializeSchedulableState   = schedulableStateSerializer.SerializeToString
      let deserializeSchedulableState = schedulableStateSerializer.DeserializeFromString
  
      /// Serialize/Deserialize a WorkflowState to and from string
      let serializeWorkflowState      = workflowSerializer.SerializeToString
      let deserializeWorkflowState    = workflowSerializer.DeserializeFromString
  
      /// Returns the scheduled action given the action's current state and the stage of workflow it's at
      let getScheduled state = function
          | { Action = ScheduleActivity(activity) }       -> activity :> ISchedulable
          | { Action = StartChildWorkflow(workflow) }     -> workflow :> ISchedulable
          | { Action = ParallelActions(schedulables, _) } -> schedulables.[state.ActionNumber]
  
      /// Identifies the key events which we need to respond to
      let (|KeyEvent|_|) historyEvt = 
          match historyEvt with
          | { EventType = ActivityTaskFailed _ } 
          | { EventType = ActivityTaskTimedOut _ } 
          | { EventType = ActivityTaskCompleted _ }
          | { EventType = ChildWorkflowExecutionFailed _ } 
          | { EventType = ChildWorkflowExecutionCompleted _ } 
          | { EventType = ChildWorkflowExecutionCompleted _ }
          | { EventType = StartChildWorkflowExecutionInitiated _ }
          | { EventType = WorkflowExecutionStarted _ }
              -> Some historyEvt.EventType
          | _ -> None
  
      /// Given an array of ISchedulable, returns the activities
      let getActivities (arr : ISchedulable[]) = arr |> Array.choose (function | :? IActivity as activity -> Some activity | _ -> None)
  
      /// Given an array of ISchedulable, returns the workflows
      let getWorkflows (arr : ISchedulable[])  = arr |> Array.choose (function | :? IWorkflow as workflow -> Some workflow | _ -> None)
  
      /// Formats the activity ID for an activity given its current state
      let getActionId actionName { StageNumber = stageNum; AttemptNumber = attempts; ActionNumber = actionNum } = 
          sprintf "%d.stag_%s.act_%d.attempt_%d" stageNum actionName actionNum attempts
  
      /// Formats the activity version for an activity at a particular stage of a workflow
      let getActivityVersion workflowName stageNum = sprintf "%s.%d" workflowName stageNum
      
      /// Returns the event type associated with the specified event ID
      let findEventTypeById eventId (evts : HistoryEvent seq) =
          evts |> Seq.pick (function 
              | { EventId = eventId'; EventType = eventType } when eventId = eventId' 
                  -> Some eventType 
              | _ -> None)
  
      /// Returns the decision to schedule an activity
      let scheduleActivity actionNum totalActions workflowName stageNum (activity : IActivity) input attempts = 
          let activityType = ActivityType(Name = activity.Name, Version = getActivityVersion workflowName stageNum)
          let state        = { 
                                  StageNumber   = stageNum
                                  AttemptNumber = attempts + 1
                                  MaxAttempts   = activity.MaxAttempts
                                  ActionNumber  = actionNum
                                  TotalActions  = totalActions
                              }
          let control      = serializeSchedulableState state
          let decision     = ScheduleActivityTask(getActionId activity.Name state, 
                                                  activityType,
                                                  Some activity.TaskList, 
                                                  input,
                                                  Some activity.TaskHeartbeatTimeout, 
                                                  Some activity.TaskScheduleToStartTimeout, 
                                                  Some activity.TaskStartToCloseTimeout, 
                                                  Some activity.TaskScheduleToCloseTimeout,
                                                  Some control)
          decision
  
      /// Returns the decision to schedule a stage with a single activity
      let scheduleActivityStage = scheduleActivity 0 1
  
      /// Returns the decision to schedule a child workflow
      let scheduleChildWorkflow actionNum totalActions stageNum (workflow : IWorkflow) input attempts =
              let schedulable  = workflow :> ISchedulable
              let workflowType = WorkflowType(Name = schedulable.Name, Version = workflow.Version)
              let state        = { 
                                      StageNumber   = stageNum
                                      AttemptNumber = attempts + 1
                                      MaxAttempts   = schedulable.MaxAttempts
                                      ActionNumber  = actionNum
                                      TotalActions  = totalActions
                                 }
              let control      = serializeSchedulableState state
              let decision     = StartChildWorkflowExecution(getActionId schedulable.Name state, 
                                                             workflowType,
                                                             workflow.ChildPolicy,
                                                             Some workflow.TaskList, 
                                                             input,
                                                             None,
                                                             workflow.ExecutionStartToCloseTimeout,
                                                             workflow.TaskStartToCloseTimeout,                                                             
                                                             Some control)
              decision
  
      /// Returns the decision to schedule a stage with a single child workflow
      let scheduleChildWorkflowStage = scheduleChildWorkflow 0 1
  
  // #region Activity Definition
  
  /// Represents an activity, which in essence, is a function that takes some input and 
  /// returns some output
  