func (factory *AppExaminerCommandFactory) printAppRoutes(w io.Writer, appInfo app_examiner.AppInfo) {
	formatRoute := func(hostname string, port uint16) string {
		return colors.Cyan(fmt.Sprintf("%s => %d", hostname, port))
	}

	portSet := factory.getAppPortSet(appInfo)
	ports := make(UInt16Slice, 0)
	for port, _ := range portSet {
		ports = append(ports, port)
	}

	routeStringsByPort := appInfo.Routes.AppRoutes.HostnamesByPort()
	externalPortsByContainerPort := make(map[uint16][]uint16)
	for _, tcpRoute := range appInfo.Routes.TcpRoutes {
		if _, ok := portSet[tcpRoute.Port]; ok {
			if externalPorts, ok := externalPortsByContainerPort[tcpRoute.Port]; ok {
				externalPortsByContainerPort[tcpRoute.Port] = append(externalPorts, tcpRoute.ExternalPort)
			} else {
				externalPortsByContainerPort[tcpRoute.Port] = []uint16{tcpRoute.ExternalPort}
			}
		}
	}
	sort.Sort(ports)

	routeIndex := 0
	for portIndex, port := range ports {
		routeStrs, _ := routeStringsByPort[uint16(port)]
		for _, routeStr := range routeStrs {
			if routeIndex == 0 && portIndex == 0 {
				fmt.Fprintf(w, "%s\t%s\n", "Routes", formatRoute(routeStrs[0], port))
			} else {
				fmt.Fprintf(w, "\t%s\n", formatRoute(routeStr, port))
			}
			routeIndex++
		}

		externalPorts, _ := externalPortsByContainerPort[uint16(port)]
		for _, externalPort := range externalPorts {
			route := fmt.Sprintf("%s:%d", factory.systemDomain, externalPort)
			if routeIndex == 0 && portIndex == 0 {
				fmt.Fprintf(w, "%s\t%s\n", "Routes", formatRoute(route, port))
			} else {
				fmt.Fprintf(w, "\t%s\n", formatRoute(route, port))
			}
			routeIndex++
		}
	}
}
func printAppRoutes(w io.Writer, appInfo app_examiner.AppInfo) {
	formatRoute := func(hostname string, port uint16) string {
		return colors.Cyan(fmt.Sprintf("%s => %d", hostname, port))
	}

	routeStringsByPort := appInfo.Routes.HostnamesByPort()
	ports := make(UInt16Slice, 0, len(routeStringsByPort))
	for port, _ := range routeStringsByPort {
		ports = append(ports, port)
	}
	sort.Sort(ports)

	for portIndex, port := range ports {
		routeStrs, _ := routeStringsByPort[uint16(port)]
		for routeIndex, routeStr := range routeStrs {
			if routeIndex == 0 && portIndex == 0 {
				fmt.Fprintf(w, "%s\t%s\n", "Routes", formatRoute(routeStrs[0], port))
			} else {
				fmt.Fprintf(w, "\t%s\n", formatRoute(routeStr, port))
			}
		}
	}
}
func (factory *AppExaminerCommandFactory) listApps(context *cli.Context) {
	appList, err := factory.appExaminer.ListApps()
	if err == nil {
		w := &tabwriter.Writer{}
		w.Init(factory.ui, 10+colors.ColorCodeLength, 8, 1, '\t', 0)
		appTableHeader := strings.Repeat("-", 30) + "= Apps =" + strings.Repeat("-", 31)
		fmt.Fprintln(w, appTableHeader)
		if len(appList) != 0 {
			header := fmt.Sprintf("%s\t%s\t%s\t%s\t%s", colors.Bold("App Name"), colors.Bold("Instances"), colors.Bold("DiskMB"), colors.Bold("MemoryMB"), colors.Bold("Route"))
			fmt.Fprintln(w, header)

			for _, appInfo := range appList {
				displayedRoutes := factory.getRoutes(appInfo)
				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", colors.Bold(appInfo.ProcessGuid), colorInstances(appInfo), colors.NoColor(strconv.Itoa(appInfo.DiskMB)), colors.NoColor(strconv.Itoa(appInfo.MemoryMB)), colors.Cyan(displayedRoutes))
			}

		} else {
			fmt.Fprintf(w, "No apps to display."+"\n")
		}
		w.Flush()
	} else {
		factory.ui.SayLine("Error listing apps: " + err.Error())
		factory.exitHandler.Exit(exit_codes.CommandFailed)
	}
	taskList, err := factory.taskExaminer.ListTasks()
	if err == nil {
		wTask := &tabwriter.Writer{}
		wTask.Init(factory.ui, 10+colors.ColorCodeLength, 8, 1, '\t', 0)
		factory.ui.SayNewLine()
		taskTableHeader := strings.Repeat("-", 30) + "= Tasks =" + strings.Repeat("-", 30)
		fmt.Fprintln(wTask, taskTableHeader)
		if len(taskList) != 0 {
			taskHeader := fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t", colors.Bold("Task Name"), colors.Bold("Cell ID"), colors.Bold("Status"), colors.Bold("Result"), colors.Bold("Failure Reason"))
			fmt.Fprintln(wTask, taskHeader)

			for _, taskInfo := range taskList {
				if taskInfo.CellID == "" {
					taskInfo.CellID = "N/A"
				}
				if taskInfo.Result == "" {
					taskInfo.Result = "N/A"
				}
				if taskInfo.FailureReason == "" {
					taskInfo.FailureReason = "N/A"
				}
				coloumnInfo := fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t", colors.Bold(taskInfo.TaskGuid), colors.NoColor(taskInfo.CellID), colors.NoColor(taskInfo.State), colors.NoColor(taskInfo.Result), colors.NoColor(taskInfo.FailureReason))
				fmt.Fprintln(wTask, coloumnInfo)
			}

		} else {
			fmt.Fprintf(wTask, "No tasks to display.\n")
		}
		wTask.Flush()
	} else {
		factory.ui.SayLine("Error listing tasks: " + err.Error())
		factory.exitHandler.Exit(exit_codes.CommandFailed)
	}
}
		})

		itShouldNotColorizeWhitespace(colors.Red)
	})

	Describe("Green", func() {
		It("adds the green color code", func() {
			Expect(colors.Green("TOO GOOD")).To(Equal("\x1b[32mTOO GOOD\x1b[0m"))
		})

		itShouldNotColorizeWhitespace(colors.Green)
	})

	Describe("Cyan", func() {
		It("adds the cyan color code", func() {
			Expect(colors.Cyan("INFO")).To(Equal("\x1b[36mINFO\x1b[0m"))
		})

		itShouldNotColorizeWhitespace(colors.Cyan)
	})

	Describe("Yellow", func() {
		It("adds the yellow color code", func() {
			Expect(colors.Yellow("INFO")).To(Equal("\x1b[33mINFO\x1b[0m"))
		})

		itShouldNotColorizeWhitespace(colors.Yellow)
	})

	Describe("Gray", func() {
		It("adds the gray color code", func() {
		terminalUI = terminal.NewUI(nil, outputBuffer, nil)
		logReader = fake_log_reader.NewFakeLogReader()
		consoleTailedLogsOutputter = console_tailed_logs_outputter.NewConsoleTailedLogsOutputter(terminalUI, logReader)
	})

	Describe("OutputTailedLogs", func() {
		It("Tails logs", func() {
			now := time.Now()
			logReader.AddLog(buildLogMessage("RTR", "1", now, []byte("First log")))
			logReader.AddError(errors.New("First Error"))

			go consoleTailedLogsOutputter.OutputTailedLogs("my-app-guid")

			Eventually(logReader.GetAppGuid).Should(Equal("my-app-guid"))

			logOutputBufferString := fmt.Sprintf("%s [%s|%s] First log\n", colors.Cyan(now.Format("01/02 15:04:05.00")), colors.Yellow("RTR"), colors.Yellow("1"))
			Eventually(outputBuffer).Should(test_helpers.Say(logOutputBufferString))
			Eventually(outputBuffer).Should(test_helpers.Say("First Error\n"))
		})
	})

	Describe("OutputDebugLogs", func() {
		It("tails logs with pretty formatting", func() {
			now := time.Now()
			logReader.AddLog(buildLogMessage("rep", "cell-1", now, []byte("First log")))
			logReader.AddError(errors.New("First Error"))

			go consoleTailedLogsOutputter.OutputDebugLogs(true)

			Eventually(logReader.GetAppGuid).Should(Equal(reserved_app_ids.LatticeDebugLogStreamAppId))
		Context("when there is a placement error", func() {
			It("colors UNCLAIMED red", func() {
				instanceInfo := app_examiner.InstanceInfo{
					State:          string(receptor.ActualLRPStateUnclaimed),
					PlacementError: "I misplaced my cells. Uh oh.",
				}

				Expect(presentation.ColorInstanceState(instanceInfo)).To(Equal(colors.Red(string(receptor.ActualLRPStateUnclaimed))))
			})
		})

		Context("when there is not a placement error", func() {
			It("colors UNCLAIMED cyan", func() {
				instanceInfo := app_examiner.InstanceInfo{State: string(receptor.ActualLRPStateUnclaimed)}
				Expect(presentation.ColorInstanceState(instanceInfo)).To(Equal(colors.Cyan(string(receptor.ActualLRPStateUnclaimed))))
			})
		})

		It("colors INVALID red", func() {
			instanceInfo := app_examiner.InstanceInfo{State: string(receptor.ActualLRPStateInvalid)}
			Expect(presentation.ColorInstanceState(instanceInfo)).To(Equal(colors.Red(string(receptor.ActualLRPStateInvalid))))
		})

		It("colors CRASHED red", func() {
			instanceInfo := app_examiner.InstanceInfo{State: string(receptor.ActualLRPStateCrashed)}
			Expect(presentation.ColorInstanceState(instanceInfo)).To(Equal(colors.Red(string(receptor.ActualLRPStateCrashed))))
		})
	})

	Describe("PadAndColorInstanceState", func() {
func (ctlo *ConsoleTailedLogsOutputter) logCallback(log *events.LogMessage) {
	timeString := time.Unix(0, log.GetTimestamp()).Format("01/02 15:04:05.00")
	logOutput := fmt.Sprintf("%s [%s|%s] %s", colors.Cyan(timeString), colors.Yellow(log.GetSourceType()), colors.Yellow(log.GetSourceInstance()), log.GetMessage())
	ctlo.outputChan <- logOutput
}