   constructor: ->
     @oldSize = null
     @uploadWorker = null
+    @busy = false
     @reset()
 
   assertNotBusy: ->
-    if @uploadWorker isnt null
+    if @busy
       throw new Error "Animator is busy"
       
   reset: ->
-    if @uploadWorker isnt null
-      @cancelWork()
+    @cancelWork() if @busy
     @startChain = null
     @startOffset = null
     @endChain = null

    framesBeforeGeneration = stepsPerGen

    imageNameTemplate = E('upload-name').value
    @beginWork()
    @uploadWorker = setInterval (=>
      observer.navigateTo @startChain, @startOffset
      p = index / totalSteps
      observer.modifyView M.hyperbolicInv Tinterp(p)
      drawEverything()
      imageName = formatString imageNameTemplate, [pad(index,4)]
      uploadToServer imageName, (ajax)->
        if ajax.readyState is XMLHttpRequest.DONE and ajax.status is 200
          console.log "Upload success"
        else
          console.log "Upload failure"
          console.log ajax.responseText
      index +=1
      framesBeforeGeneration -= 1
      if framesBeforeGeneration is 0
        doStep()
        framesBeforeGeneration = stepsPerGen

      if index > totalSteps
        clearInterval @uploadWorker
        @uploadWorker = null
        @endWork()
      ), 100

serverSupportsUpload = -> ((""+window.location).match /:8000\//) and true
# ============================================  app code ===============

    [canvas.width, canvas.height] = @oldSize
    @oldSize = null
    canvasSizeUpdateBlocked = false
    redraw()

  _beginWork: ->
    @busy = true
    @_setCanvasSize()
    console.log "Started animation"
    
  _endWork: ->
    @_restoreCanvasSize()
    console.log "End animation"
    @busy = false
        
  cancelWork: ->
    return unless @busy
    clearTimeout @uploadWorker is @uploadWorker
    @uploadWorker = null
    @_endWork()
    
  animate: (observer, stepsPerGen, generations, callback)->
    return unless @startChain? and @endChain?
