func (factory *AppExaminerCommandFactory) appStatus(context *cli.Context) {

	summaryFlag := context.Bool("summary")
	rateFlag := context.Duration("rate")

	if len(context.Args()) < 1 {
		factory.ui.SayIncorrectUsage("App Name required")
		factory.exitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	appName := context.Args()[0]

	appInfo, err := factory.appExaminer.AppStatus(appName)
	if err != nil {
		factory.ui.SayLine(err.Error())
		factory.exitHandler.Exit(exit_codes.CommandFailed)
		return
	}

	factory.printAppInfo(appInfo)

	if summaryFlag || rateFlag != 0 {
		factory.printInstanceSummary(appInfo.ActualInstances)
	} else {
		factory.printInstanceInfo(appInfo.ActualInstances)
	}

	if rateFlag == 0 {
		return
	}

	linesWritten := appStatusLinesWritten(appInfo)
	closeChan := make(chan struct{})
	defer factory.ui.Say(cursor.Show())
	factory.ui.Say(cursor.Hide())

	factory.exitHandler.OnExit(func() {
		closeChan <- struct{}{}
		factory.ui.Say(cursor.Show())
	})

	for {
		select {
		case <-closeChan:
			return
		case <-factory.clock.NewTimer(rateFlag).C():
			appInfo, err = factory.appExaminer.AppStatus(appName)
			if err != nil {
				factory.ui.SayLine("Error getting status: " + err.Error())
				return
			}
			factory.ui.Say(cursor.Up(linesWritten))
			factory.printAppInfo(appInfo)
			factory.printInstanceSummary(appInfo.ActualInstances)
			linesWritten = appStatusLinesWritten(appInfo)
		}
	}
}
func (factory *AppExaminerCommandFactory) visualizeCells(context *cli.Context) {
	rate := context.Duration("rate")
	graphicalFlag := context.Bool("graphical")

	if graphicalFlag {
		err := factory.graphicalVisualizer.PrintDistributionChart(rate)
		if err != nil {
			factory.ui.SayLine("Error Visualization: " + err.Error())
			factory.exitHandler.Exit(exit_codes.CommandFailed)
		}
		return
	}

	factory.ui.SayLine(colors.Bold("Distribution"))
	linesWritten := factory.printDistribution()

	if rate == 0 {
		return
	}

	closeChan := make(chan struct{})
	factory.ui.Say(cursor.Hide())

	factory.exitHandler.OnExit(func() {
		closeChan <- struct{}{}
		factory.ui.Say(cursor.Show())

	})

	for {
		select {
		case <-closeChan:
			return
		case <-factory.clock.NewTimer(rate).C():
			factory.ui.Say(cursor.Up(linesWritten))
			linesWritten = factory.printDistribution()
		}
	}
}
				closeChan = test_helpers.AsyncExecuteCommandWithArgs(visualizeCommand, []string{"--rate", "2s"})

				Eventually(outputBuffer).Should(test_helpers.SayLine("cell-0: " + colors.Red("empty") + cursor.ClearToEndOfLine()))
				Eventually(outputBuffer).Should(test_helpers.SayLine("cell-1" + colors.Red("[MISSING]") + ": " + cursor.ClearToEndOfLine()))

				setNumberOfRunningInstances(2)

				fakeClock.IncrementBySeconds(1)

				Consistently(outputBuffer).ShouldNot(test_helpers.Say("cell: \n")) // TODO: how would this happen

				fakeClock.IncrementBySeconds(1)

				Eventually(outputBuffer).Should(test_helpers.Say(cursor.Hide()))
				Eventually(outputBuffer).Should(test_helpers.Say(cursor.Up(2)))
				Eventually(outputBuffer).Should(test_helpers.SayLine("cell-0: " + colors.Green("••") + cursor.ClearToEndOfLine()))
				Eventually(outputBuffer).Should(test_helpers.SayLine("cell-1" + colors.Red("[MISSING]") + ": " + colors.Green("••") + cursor.ClearToEndOfLine()))
				Eventually(outputBuffer).Should(test_helpers.Say(cursor.ClearToEndOfDisplay()))

				Consistently(closeChan).ShouldNot(BeClosed())
			})

			It("dynamically displays any errors", func() {
				fakeAppExaminer.ListCellsReturns(nil, errors.New("Spilled the Paint"))

				closeChan = test_helpers.AsyncExecuteCommandWithArgs(visualizeCommand, []string{"--rate", "1s"})

				Eventually(outputBuffer).Should(test_helpers.SayLine("Error visualizing: Spilled the Paint" + cursor.ClearToEndOfLine()))

				fakeClock.IncrementBySeconds(1)
func (factory *AppExaminerCommandFactory) appStatus(context *cli.Context) {
	detailedFlag := context.Bool("detailed")
	rateFlag := context.Duration("rate")

	if len(context.Args()) < 1 {
		factory.ui.SayIncorrectUsage("App Name required")
		factory.exitHandler.Exit(exit_codes.InvalidSyntax)
		return
	}

	appName := context.Args()[0]

	writer := new(bytes.Buffer)

	appInfo, err := factory.appExaminer.AppStatus(appName)
	if err != nil {
		factory.ui.SayLine(err.Error())
		factory.exitHandler.Exit(exit_codes.CommandFailed)
		return
	}

	factory.printAppInfo(writer, appInfo)

	if rateFlag != 0 {
		if detailedFlag {
			factory.ui.SayLine("WARNING: flags '--detailed' and '--rate' are incompatible.")
		}
		factory.printInstanceSummary(writer, appInfo.ActualInstances)
	} else if detailedFlag {
		factory.printInstanceInfo(writer, appInfo.ActualInstances)
	} else {
		factory.printInstanceSummary(writer, appInfo.ActualInstances)
	}

	factory.ui.Write(writer.Bytes())

	if rateFlag == 0 {
		return
	}

	linesWritten := factory.lineCount(writer.Bytes())

	closeChan := make(chan struct{})
	defer factory.ui.Say(cursor.Show())
	factory.ui.Say(cursor.Hide())

	factory.exitHandler.OnExit(func() {
		closeChan <- struct{}{}
		factory.ui.Say(cursor.Show())
	})

	for {
		select {
		case <-closeChan:
			return
		case <-factory.clock.NewTimer(rateFlag).C():
			appInfo, err = factory.appExaminer.AppStatus(appName)
			if err != nil {
				factory.ui.SayLine("Error getting status: " + err.Error())
				return
			}
			factory.ui.Say(cursor.Up(linesWritten))
			writer = new(bytes.Buffer)
			factory.printAppInfo(writer, appInfo)
			factory.printInstanceSummary(writer, appInfo.ActualInstances)
			factory.ui.Write(writer.Bytes())
			linesWritten = factory.lineCount(writer.Bytes())
		}
	}
}