func (r *marathonClient) ApplicationOK(name string) (bool, error) {
	application, err := r.Application(name)
	if err != nil {
		return false, err
	}
	if !application.AllTaskRunning() {
		return false, nil
	}
	if application.HealthChecks == nil || len(*application.HealthChecks) == 0 {
		return true, nil
	}
	for _, task := range application.Tasks {
		if task.HealthCheckResults == nil {
			return false, nil
		}
		for _, check := range task.HealthCheckResults {
			if check == nil || !check.Alive {
				return false, nil
			}
		}
	}
	return true, nil
}
ApplicationOK validates that the application, or more appropriately it's tasks have passed all the health checks.
If no health checks exist, we simply return true
name: 		the id used to identify the application
package marathon
import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"time"
)
var (
	ErrNoApplicationContainer = errors.New("you have not specified a docker container yet")
)
type Applications struct {
	Apps []Application `json:"apps"`
}
type IPAddressPerTask struct {
	Groups      *[]string          `json:"groups,omitempty"`
	Labels      *map[string]string `json:"labels,omitempty"`
	Discovery   *Discovery         `json:"discovery,omitempty"`
	NetworkName string             `json:"networkName,omitempty"`
}
type Discovery struct {
	Ports *[]Port `json:"ports,omitempty"`
}
type Port struct {
	Number   int    `json:"number,omitempty"`
	Name     string `json:"name,omitempty"`
	Protocol string `json:"protocol,omitempty"`
}
type Application struct {
	ID                         string              `json:"id,omitempty"`
	Cmd                        *string             `json:"cmd,omitempty"`
	Args                       *[]string           `json:"args,omitempty"`
	Constraints                *[][]string         `json:"constraints,omitempty"`
	Container                  *Container          `json:"container,omitempty"`
	CPUs                       float64             `json:"cpus,omitempty"`
	GPUs                       *float64            `json:"gpus,omitempty"`
	Disk                       *float64            `json:"disk,omitempty"`
	Env                        *map[string]string  `json:"env,omitempty"`
	Executor                   *string             `json:"executor,omitempty"`
	HealthChecks               *[]HealthCheck      `json:"healthChecks,omitempty"`
	ReadinessChecks            *[]ReadinessCheck   `json:"readinessChecks,omitempty"`
	Instances                  *int                `json:"instances,omitempty"`
	Mem                        *float64            `json:"mem,omitempty"`
	Tasks                      []*Task             `json:"tasks,omitempty"`
	Ports                      []int               `json:"ports"`
	PortDefinitions            *[]PortDefinition   `json:"portDefinitions,omitempty"`
	RequirePorts               *bool               `json:"requirePorts,omitempty"`
	BackoffSeconds             *float64            `json:"backoffSeconds,omitempty"`
	BackoffFactor              *float64            `json:"backoffFactor,omitempty"`
	MaxLaunchDelaySeconds      *float64            `json:"maxLaunchDelaySeconds,omitempty"`
	TaskKillGracePeriodSeconds *float64            `json:"taskKillGracePeriodSeconds,omitempty"`
	Deployments                []map[string]string `json:"deployments,omitempty"`
	ReadinessCheckResults *[]ReadinessCheckResult `json:"readinessCheckResults,omitempty"`
	Dependencies          []string                `json:"dependencies"`
	TasksRunning          int                     `json:"tasksRunning,omitempty"`
	TasksStaged           int                     `json:"tasksStaged,omitempty"`
	TasksHealthy          int                     `json:"tasksHealthy,omitempty"`
	TasksUnhealthy        int                     `json:"tasksUnhealthy,omitempty"`
	TaskStats             map[string]TaskStats    `json:"taskStats,omitempty"`
	User                  string                  `json:"user,omitempty"`
	UpgradeStrategy       *UpgradeStrategy        `json:"upgradeStrategy,omitempty"`
	UnreachableStrategy   *UnreachableStrategy    `json:"unreachableStrategy,omitempty"`
	KillSelection         string                  `json:"killSelection,omitempty"`
	Uris                  *[]string               `json:"uris,omitempty"`
	Version               string                  `json:"version,omitempty"`
	VersionInfo           *VersionInfo            `json:"versionInfo,omitempty"`
	Labels                *map[string]string      `json:"labels,omitempty"`
	AcceptedResourceRoles []string                `json:"acceptedResourceRoles,omitempty"`
	LastTaskFailure       *LastTaskFailure        `json:"lastTaskFailure,omitempty"`
	Fetch                 *[]Fetch                `json:"fetch,omitempty"`
	IPAddressPerTask      *IPAddressPerTask       `json:"ipAddress,omitempty"`
}
type ApplicationVersions struct {
	Versions []string `json:"versions"`
}
type ApplicationVersion struct {
	Version string `json:"version"`
}
type VersionInfo struct {
	LastScalingAt      string `json:"lastScalingAt,omitempty"`
	LastConfigChangeAt string `json:"lastConfigChangeAt,omitempty"`
}
type Fetch struct {
	URI        string `json:"uri"`
	Executable bool   `json:"executable"`
	Extract    bool   `json:"extract"`
	Cache      bool   `json:"cache"`
}
type GetAppOpts struct {
	Embed []string `url:"embed,omitempty"`
}
type DeleteAppOpts struct {
	Force bool `url:"force,omitempty"`
}
type TaskStats struct {
	Stats Stats `json:"stats"`
}
type Stats struct {
	Counts   map[string]int     `json:"counts"`
	LifeTime map[string]float64 `json:"lifeTime"`
}
func (r *Application) SetIPAddressPerTask(ipAddressPerTask IPAddressPerTask) *Application {
	r.Ports = make([]int, 0)
	r.EmptyPortDefinitions()
	r.IPAddressPerTask = &ipAddressPerTask
	return r
}
func NewDockerApplication() *Application {
	application := new(Application)
	application.Container = NewDockerContainer()
	return application
}
func (r *Application) Name(id string) *Application {
	r.ID = validateID(id)
	return r
}
func (r *Application) Command(cmd string) *Application {
	r.Cmd = &cmd
	return r
}
func (r *Application) CPU(cpu float64) *Application {
	r.CPUs = cpu
	return r
}
func (r *Application) SetGPUs(gpu float64) *Application {
	r.GPUs = &gpu
	return r
}
func (r *Application) EmptyGPUs() *Application {
	g := 0.0
	r.GPUs = &g
	return r
}
func (r *Application) Storage(disk float64) *Application {
	r.Disk = &disk
	return r
}
func (r *Application) AllTaskRunning() bool {
	if r.Instances == nil || *r.Instances == 0 {
		return true
	}
	if r.Tasks == nil {
		return false
	}
	if r.TasksRunning == *r.Instances {
		return true
	}
	return false
}
func (r *Application) DependsOn(names ...string) *Application {
	if r.Dependencies == nil {
		r.Dependencies = make([]string, 0)
	}
	r.Dependencies = append(r.Dependencies, names...)
	return r
}
func (r *Application) Memory(memory float64) *Application {
	r.Mem = &memory
	return r
}
func (r *Application) AddPortDefinition(portDefinition PortDefinition) *Application {
	if r.PortDefinitions == nil {
		r.EmptyPortDefinitions()
	}
	portDefinitions := *r.PortDefinitions
	portDefinitions = append(portDefinitions, portDefinition)
	r.PortDefinitions = &portDefinitions
	return r
}
func (r *Application) EmptyPortDefinitions() *Application {
	r.PortDefinitions = &[]PortDefinition{}
	return r
}
func (r *Application) Count(count int) *Application {
	r.Instances = &count
	return r
}
func (r *Application) SetTaskKillGracePeriod(seconds float64) *Application {
	r.TaskKillGracePeriodSeconds = &seconds
	return r
}
func (r *Application) AddArgs(arguments ...string) *Application {
	if r.Args == nil {
		r.EmptyArgs()
	}
	args := *r.Args
	args = append(args, arguments...)
	r.Args = &args
	return r
}
func (r *Application) EmptyArgs() *Application {
	r.Args = &[]string{}
	return r
}
func (r *Application) AddConstraint(constraints ...string) *Application {
	if r.Constraints == nil {
		r.EmptyConstraints()
	}
	c := *r.Constraints
	c = append(c, constraints)
	r.Constraints = &c
	return r
}
func (r *Application) EmptyConstraints() *Application {
	r.Constraints = &[][]string{}
	return r
}
func (r *Application) AddLabel(name, value string) *Application {
	if r.Labels == nil {
		r.EmptyLabels()
	}
	(*r.Labels)[name] = value
	return r
}
func (r *Application) EmptyLabels() *Application {
	r.Labels = &map[string]string{}
	return r
}
func (r *Application) AddEnv(name, value string) *Application {
	if r.Env == nil {
		r.EmptyEnvs()
	}
	(*r.Env)[name] = value
	return r
}
func (r *Application) EmptyEnvs() *Application {
	r.Env = &map[string]string{}
	return r
}
func (r *Application) SetExecutor(executor string) *Application {
	r.Executor = &executor
	return r
}
func (r *Application) AddHealthCheck(healthCheck HealthCheck) *Application {
	if r.HealthChecks == nil {
		r.EmptyHealthChecks()
	}
	healthChecks := *r.HealthChecks
	healthChecks = append(healthChecks, healthCheck)
	r.HealthChecks = &healthChecks
	return r
}
func (r *Application) EmptyHealthChecks() *Application {
	r.HealthChecks = &[]HealthCheck{}
	return r
}
func (r *Application) HasHealthChecks() bool {
	return r.HealthChecks != nil && len(*r.HealthChecks) > 0
}
func (r *Application) AddReadinessCheck(readinessCheck ReadinessCheck) *Application {
	if r.ReadinessChecks == nil {
		r.EmptyReadinessChecks()
	}
	readinessChecks := *r.ReadinessChecks
	readinessChecks = append(readinessChecks, readinessCheck)
	r.ReadinessChecks = &readinessChecks
	return r
}
func (r *Application) EmptyReadinessChecks() *Application {
	r.ReadinessChecks = &[]ReadinessCheck{}
	return r
}
func (r *Application) DeploymentIDs() []*DeploymentID {
	var deployments []*DeploymentID
	if r.Deployments == nil {
		return deployments
	}
	for _, deploy := range r.Deployments {
		if id, found := deploy["id"]; found {
			deployment := &DeploymentID{
				Version:      r.Version,
				DeploymentID: id,
			}
			deployments = append(deployments, deployment)
		}
	}
	return deployments
}
func (r *Application) CheckHTTP(uri string, port, interval int) (*Application, error) {
	if r.Container == nil || r.Container.Docker == nil {
		return nil, ErrNoApplicationContainer
	}
	portIndex, err := r.Container.Docker.ServicePortIndex(port)
	if err != nil {
		return nil, err
	}
	health := NewDefaultHealthCheck()
	health.IntervalSeconds = interval
	*health.Path = uri
	*health.PortIndex = portIndex
	r.AddHealthCheck(*health)
	return r, nil
}
func (r *Application) CheckTCP(port, interval int) (*Application, error) {
	if r.Container == nil || r.Container.Docker == nil {
		return nil, ErrNoApplicationContainer
	}
	portIndex, err := r.Container.Docker.ServicePortIndex(port)
	if err != nil {
		return nil, err
	}
	health := NewDefaultHealthCheck()
	health.Protocol = "TCP"
	health.IntervalSeconds = interval
	*health.PortIndex = portIndex
	r.AddHealthCheck(*health)
	return r, nil
}
func (r *Application) AddUris(newUris ...string) *Application {
	if r.Uris == nil {
		r.EmptyUris()
	}
	uris := *r.Uris
	uris = append(uris, newUris...)
	r.Uris = &uris
	return r
}
func (r *Application) EmptyUris() *Application {
	r.Uris = &[]string{}
	return r
}
func (r *Application) AddFetchURIs(fetchURIs ...Fetch) *Application {
	if r.Fetch == nil {
		r.EmptyFetchURIs()
	}
	fetch := *r.Fetch
	fetch = append(fetch, fetchURIs...)
	r.Fetch = &fetch
	return r
}
func (r *Application) EmptyFetchURIs() *Application {
	r.Fetch = &[]Fetch{}
	return r
}
func (r *Application) SetUpgradeStrategy(us UpgradeStrategy) *Application {
	r.UpgradeStrategy = &us
	return r
}
func (r *Application) EmptyUpgradeStrategy() *Application {
	r.UpgradeStrategy = &UpgradeStrategy{}
	return r
}
func (r *Application) SetUnreachableStrategy(us UnreachableStrategy) *Application {
	r.UnreachableStrategy = &us
	return r
}
func (r *Application) EmptyUnreachableStrategy() *Application {
	r.UnreachableStrategy = &UnreachableStrategy{}
	return r
}
func (r *Application) String() string {
	s, err := json.MarshalIndent(r, "", "  ")
	if err != nil {
		return fmt.Sprintf(`{"error": "error decoding type into json: %s"}`, err)
	}
	return string(s)
}
func (r *marathonClient) Applications(v url.Values) (*Applications, error) {
	query := v.Encode()
	if query != "" {
		query = "?" + query
	}
	applications := new(Applications)
	err := r.apiGet(marathonAPIApps+query, nil, applications)
	if err != nil {
		return nil, err
	}
	return applications, nil
}
func (r *marathonClient) ListApplications(v url.Values) ([]string, error) {
	applications, err := r.Applications(v)
	if err != nil {
		return nil, err
	}
	var list []string
	for _, application := range applications.Apps {
		list = append(list, application.ID)
	}
	return list, nil
}
func (r *marathonClient) HasApplicationVersion(name, version string) (bool, error) {
	id := trimRootPath(name)
	versions, err := r.ApplicationVersions(id)
	if err != nil {
		return false, err
	}
	return contains(versions.Versions, version), nil
}
func (r *marathonClient) ApplicationVersions(name string) (*ApplicationVersions, error) {
	uri := fmt.Sprintf("%s/versions", buildURI(name))
	versions := new(ApplicationVersions)
	if err := r.apiGet(uri, nil, versions); err != nil {
		return nil, err
	}
	return versions, nil
}
func (r *marathonClient) SetApplicationVersion(name string, version *ApplicationVersion) (*DeploymentID, error) {
	uri := fmt.Sprintf(buildURI(name))
	deploymentID := new(DeploymentID)
	if err := r.apiPut(uri, version, deploymentID); err != nil {
		return nil, err
	}
	return deploymentID, nil
}
func (r *marathonClient) Application(name string) (*Application, error) {
	var wrapper struct {
		Application *Application `json:"app"`
	}
	if err := r.apiGet(buildURI(name), nil, &wrapper); err != nil {
		return nil, err
	}
	return wrapper.Application, nil
}
func (r *marathonClient) ApplicationBy(name string, opts *GetAppOpts) (*Application, error) {
	u, err := addOptions(buildURI(name), opts)
	if err != nil {
		return nil, err
	}
	var wrapper struct {
		Application *Application `json:"app"`
	}
	if err := r.apiGet(u, nil, &wrapper); err != nil {
		return nil, err
	}
	return wrapper.Application, nil
}
func (r *marathonClient) ApplicationByVersion(name, version string) (*Application, error) {
	app := new(Application)
	uri := fmt.Sprintf("%s/versions/%s", buildURI(name), version)
	if err := r.apiGet(uri, nil, app); err != nil {
		return nil, err
	}
	return app, nil
}