<commit_before>package megos

// State represents the JSON from the state.json of a mesos node
type State struct {
	ActivatedSlaves        float64     `json:"activated_slaves"`
	BuildDate              string      `json:"build_date"`
	BuildTime              float64     `json:"build_time"`
	BuildUser              string      `json:"build_user"`
	Cluster                string      `json:"cluster"`
	CompletedFrameworks    []Framework `json:"completed_frameworks"`
	DeactivatedSlaves      float64     `json:"deactivated_slaves"`
	ElectedTime            float64     `json:"elected_time"`
	Flags                  Flags       `json:"flags"`
	Frameworks             []Framework `json:"frameworks"`
	GitSHA                 string      `json:"git_sha"`
	GitBranch              string      `json:"git_branch"`
	GitTag                 string      `json:"git_tag"`
	Hostname               string      `json:"hostname"`
	ID                     string      `json:"id"`
	Leader                 string      `json:"leader"`
	LogDir                 string      `json:"log_dir"`
	ExternalLogFile        string      `json:"external_log_file"`
	OrphanTasks            []Task      `json:"orphan_tasks"`
	PID                    string      `json:"pid"`
	Slaves                 []Slave     `json:"slaves"`
	StartTime              float64     `json:"start_time"`
	UnregisteredFrameworks []string    `json:"unregistered_frameworks"`
	Version                string      `json:"version"`
}

// Flags represents the flags of a mesos state
type Flags struct {
	AllocationInterval          string `json:"allocation_interval"`
	Allocator                   string `json:"allocator"`
	Authenticate                string `json:"authenticate"`
	Authenticatee               string `json:"authenticatee"`
	AuthenticateSlaves          string `json:"authenticate_slaves"`
	Authenticators              string `json:"authenticators"`
	Authorizers                 string `json:"authorizers"`
	CgroupsEnableCfs            string `json:"cgroups_enable_cfs"`
	CgroupsHierarchy            string `json:"cgroups_hierarchy"`
	CgroupsLimitSwap            string `json:"cgroups_limit_swap"`
	CgroupsRoot                 string `json:"cgroups_root"`
	Cluster                     string `json:"cluster"`
	ContainerDiskWatchInterval  string `json:"container_disk_watch_interval"`
	Containerizers              string `json:"containerizers"`
	DefaultRole                 string `json:"default_role"`
	DiskWatchInterval           string `json:"disk_watch_interval"`
	Docker                      string `json:"docker"`
	DockerRemoveDelay           string `json:"docker_remove_delay"`
	DockerSandboxDirectory      string `json:"docker_sandbox_directory"`
	DockerStopTimeout           string `json:"docker_stop_timeout"`
	EnforceContainerDiskQuota   string `json:"enforce_container_disk_quota"`
	ExecutorRegistrationTimeout string `json:"executor_registration_timeout"`
	ExecutorShutdownGracePeriod string `json:"executor_shutdown_grace_period"`
	FrameworksHome              string `json:"frameworks_home"`
	FrameworkSorter             string `json:"framework_sorter"`
	GCDelay                     string `json:"gc_delay"`
	GCDiskHeadroom              string `json:"gc_disk_headroom"`
	HadoopHome                  string `json:"hadoop_home"`
	Help                        string `json:"help"`
	Hostname                    string `json:"hostname"`
	InitializeDriverLogging     string `json:"initialize_driver_logging"`
	IP                          string `json:"ip"`
	Isolation                   string `json:"isolation"`
	LauncherDir                 string `json:"launcher_dir"`
	LogAutoInitialize           string `json:"log_auto_initialize"`
	LogDir                      string `json:"log_dir"`
	Logbufsecs                  string `json:"logbufsecs"`
	LoggingLevel                string `json:"logging_level"`
	MaxSlavePingTimeouts        string `json:"max_slave_ping_timeouts"`
	Master                      string `json:"master"`
	PerfDuration                string `json:"perf_duration"`
	PerfInterval                string `json:"perf_interval"`
	Port                        string `json:"port"`
	Quiet                       string `json:"quiet"`
	Quorum                      string `json:"quorum"`
	Recover                     string `json:"recover"`
	RecoverySlaveRemovalLimit   string `json:"recovery_slave_removal_limit"`
	RecoveryTimeout             string `json:"recovery_timeout"`
	RegistrationBackoffFactor   string `json:"registration_backoff_factor"`
	Registry                    string `json:"registry"`
	RegistryFetchTimeout        string `json:"registry_fetch_timeout"`
	RegistryStoreTimeout        string `json:"registry_store_timeout"`
	RegistryStrict              string `json:"registry_strict"`
	ResourceMonitoringInterval  string `json:"resource_monitoring_interval"`
	RootSubmissions             string `json:"root_submissions"`
	SlavePingTimeout            string `json:"slave_ping_timeout"`
	SlaveReregisterTimeout      string `json:"slave_reregister_timeout"`
	Strict                      string `json:"strict"`
	SwitchUser                  string `json:"switch_user"`
	UserSorter                  string `json:"user_sorter"`
	Version                     string `json:"version"`
	WebuiDir                    string `json:"webui_dir"`
	WorkDir                     string `json:"work_dir"`
	ZK                          string `json:"zk"`
	ZKSessionTimeout            string `json:"zk_session_timeout"`
}

// Framework represent a single framework of a mesos node
type Framework struct {
	Active           bool       `json:"active"`
	Checkpoint       bool       `json:"checkpoint"`
	CompletedTasks   []Task     `json:"completed_tasks"`
	Executors        []Executor `json:"executors"`
	FailoverTimeout  float64    `json:"failover_timeout"`
	Hostname         string     `json:"hostname"`
	ID               string     `json:"id"`
	Name             string     `json:"name"`
	OfferedResources Resources  `json:"offered_resources"`
	Offers           []Offer    `json:"offers"`
	RegisteredTime   float64    `json:"registered_time"`
	ReregisteredTime float64    `json:"reregistered_time"`
	Resources        Resources  `json:"resources"`
	Role             string     `json:"role"`
	Tasks            []Task     `json:"tasks"`
	UnregisteredTime float64    `json:"unregistered_time"`
	UsedResources    Resources  `json:"used_resources"`
	User             string     `json:"user"`
	WebuiURL         string     `json:"webui_url"`
	Labels           []Label    `json:"label"`
}

// Offer represents a single offer from a Mesos Slave to a Mesos master
type Offer struct {
	ID          string            `json:"id"`
	FrameworkID string            `json:"framework_id"`
	SlaveID     string            `json:"slave_id"`
	Hostname    string            `json:"hostname"`
	URL         URL               `json:"url"`
	Resources   Resources         `json:"resources"`
	Attributes  map[string]string `json:"attributes"`
}

// URL represents a single URL
type URL struct {
	Scheme     string      `json:"scheme"`
	Address    Address     `json:"address"`
	Path       string      `json:"path"`
	Parameters []Parameter `json:"parameters"`
}

// Address represents a single address.
// e.g. from a Slave or from a Master
type Address struct {
	Hostname string `json:"hostname"`
	IP       string `json:"ip"`
	Port     int    `json:"port"`
}

// Parameter represents a single key / value pair for parameters
type Parameter struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Label represents a single key / value pair for labeling
type Label struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Task represent a single Mesos task
type Task struct {
	// Missing fields
	// TODO: "labels": [],
	ExecutorID  string       `json:"executor_id"`
	FrameworkID string       `json:"framework_id"`
	ID          string       `json:"id"`
	Name        string       `json:"name"`
	Resources   Resources    `json:"resources"`
	SlaveID     string       `json:"slave_id"`
	State       string       `json:"state"`
	Statuses    []TaskStatus `json:"statuses"`
}

// Resources represents a resource type for a task
type Resources struct {
	CPUs  float64 `json:"cpus"`
	Disk  float64 `json:"disk"`
	Mem   float64 `json:"mem"`
	Ports string  `json:"ports"`
}

// TaskStatus represents the status of a single task
type TaskStatus struct {
	State     string  `json:"state"`
	Timestamp float64 `json:"timestamp"`
}

// Slave represents a single mesos slave node
type Slave struct {
	Active         bool              `json:"active"`
	Hostname       string            `json:"hostname"`
	ID             string            `json:"id"`
	PID            string            `json:"pid"`
	RegisteredTime float64           `json:"registered_time"`
	Resources      Resources         `json:"resources"`
	Attributes     map[string]string `json:"attributes"`
}

// Executor represents a single executor of a framework
type Executor struct {
	// Missing fields
	// TODO "queued_tasks": [],
	// TODO "tasks": []
	CompletedTasks []Task    `json:"completed_tasks"`
	Container      string    `json:"container"`
	Directory      string    `json:"directory"`
	ID             string    `json:"id"`
	Name           string    `json:"name"`
	Resources      Resources `json:"resources"`
	Source         string    `json:"source"`
}
<commit_msg>Added missing structs for leader state<commit_after>package megos

// State represents the JSON from the state.json of a mesos node
type State struct {
	ActivatedSlaves        float64     `json:"activated_slaves"`
	BuildDate              string      `json:"build_date"`
	BuildTime              float64     `json:"build_time"`
	BuildUser              string      `json:"build_user"`
	Cluster                string      `json:"cluster"`
	CompletedFrameworks    []Framework `json:"completed_frameworks"`
	DeactivatedSlaves      float64     `json:"deactivated_slaves"`
	ElectedTime            float64     `json:"elected_time"`
	Flags                  Flags       `json:"flags"`
	Frameworks             []Framework `json:"frameworks"`
	GitSHA                 string      `json:"git_sha"`
	GitBranch              string      `json:"git_branch"`
	GitTag                 string      `json:"git_tag"`
	Hostname               string      `json:"hostname"`
	ID                     string      `json:"id"`
	Leader                 string      `json:"leader"`
	LogDir                 string      `json:"log_dir"`
	ExternalLogFile        string      `json:"external_log_file"`
	OrphanTasks            []Task      `json:"orphan_tasks"`
	PID                    string      `json:"pid"`
	Slaves                 []Slave     `json:"slaves"`
	StartTime              float64     `json:"start_time"`
	UnregisteredFrameworks []string    `json:"unregistered_frameworks"`
	Version                string      `json:"version"`
}

// Flags represents the flags of a mesos state
type Flags struct {
	AllocationInterval            string `json:"allocation_interval"`
	Allocator                     string `json:"allocator"`
	Authenticate                  string `json:"authenticate"`
	AuthenticateHTTP              string `json:"authenticate_http"`
	Authenticatee                 string `json:"authenticatee"`
	AuthenticateSlaves            string `json:"authenticate_slaves"`
	Authenticators                string `json:"authenticators"`
	Authorizers                   string `json:"authorizers"`
	CgroupsEnableCfs              string `json:"cgroups_enable_cfs"`
	CgroupsHierarchy              string `json:"cgroups_hierarchy"`
	CgroupsLimitSwap              string `json:"cgroups_limit_swap"`
	CgroupsRoot                   string `json:"cgroups_root"`
	Cluster                       string `json:"cluster"`
	ContainerDiskWatchInterval    string `json:"container_disk_watch_interval"`
	Containerizers                string `json:"containerizers"`
	DefaultRole                   string `json:"default_role"`
	DiskWatchInterval             string `json:"disk_watch_interval"`
	Docker                        string `json:"docker"`
	DockerRemoveDelay             string `json:"docker_remove_delay"`
	DockerSandboxDirectory        string `json:"docker_sandbox_directory"`
	DockerStopTimeout             string `json:"docker_stop_timeout"`
	EnforceContainerDiskQuota     string `json:"enforce_container_disk_quota"`
	ExecutorRegistrationTimeout   string `json:"executor_registration_timeout"`
	ExecutorShutdownGracePeriod   string `json:"executor_shutdown_grace_period"`
	FrameworksHome                string `json:"frameworks_home"`
	FrameworkSorter               string `json:"framework_sorter"`
	GCDelay                       string `json:"gc_delay"`
	GCDiskHeadroom                string `json:"gc_disk_headroom"`
	HadoopHome                    string `json:"hadoop_home"`
	Help                          string `json:"help"`
	Hostname                      string `json:"hostname"`
	HostnameLookup                string `json:"hostname_lookup"`
	HTTPAuthenticators            string `json:"http_authenticators"`
	InitializeDriverLogging       string `json:"initialize_driver_logging"`
	IP                            string `json:"ip"`
	Isolation                     string `json:"isolation"`
	LauncherDir                   string `json:"launcher_dir"`
	LogAutoInitialize             string `json:"log_auto_initialize"`
	LogDir                        string `json:"log_dir"`
	Logbufsecs                    string `json:"logbufsecs"`
	LoggingLevel                  string `json:"logging_level"`
	MaxCompletedFrameworks        string `json:"max_completed_frameworks"`
	MaxCompletedTasksPerFramework string `json:"max_completed_tasks_per_framework"`
	MaxSlavePingTimeouts          string `json:"max_slave_ping_timeouts"`
	Master                        string `json:"master"`
	PerfDuration                  string `json:"perf_duration"`
	PerfInterval                  string `json:"perf_interval"`
	Port                          string `json:"port"`
	Quiet                         string `json:"quiet"`
	Quorum                        string `json:"quorum"`
	Recover                       string `json:"recover"`
	RecoverySlaveRemovalLimit     string `json:"recovery_slave_removal_limit"`
	RecoveryTimeout               string `json:"recovery_timeout"`
	RegistrationBackoffFactor     string `json:"registration_backoff_factor"`
	Registry                      string `json:"registry"`
	RegistryFetchTimeout          string `json:"registry_fetch_timeout"`
	RegistryStoreTimeout          string `json:"registry_store_timeout"`
	RegistryStrict                string `json:"registry_strict"`
	ResourceMonitoringInterval    string `json:"resource_monitoring_interval"`
	RootSubmissions               string `json:"root_submissions"`
	SlavePingTimeout              string `json:"slave_ping_timeout"`
	SlaveReregisterTimeout        string `json:"slave_reregister_timeout"`
	Strict                        string `json:"strict"`
	SwitchUser                    string `json:"switch_user"`
	UserSorter                    string `json:"user_sorter"`
	Version                       string `json:"version"`
	WebuiDir                      string `json:"webui_dir"`
	WorkDir                       string `json:"work_dir"`
	ZK                            string `json:"zk"`
	ZKSessionTimeout              string `json:"zk_session_timeout"`
}

// Framework represent a single framework of a mesos node
type Framework struct {
	Active           bool       `json:"active"`
	Checkpoint       bool       `json:"checkpoint"`
	CompletedTasks   []Task     `json:"completed_tasks"`
	Executors        []Executor `json:"executors"`
	FailoverTimeout  float64    `json:"failover_timeout"`
	Hostname         string     `json:"hostname"`
	ID               string     `json:"id"`
	Name             string     `json:"name"`
	PID              string     `json:"pid"`
	OfferedResources Resources  `json:"offered_resources"`
	Offers           []Offer    `json:"offers"`
	RegisteredTime   float64    `json:"registered_time"`
	ReregisteredTime float64    `json:"reregistered_time"`
	Resources        Resources  `json:"resources"`
	Role             string     `json:"role"`
	Tasks            []Task     `json:"tasks"`
	UnregisteredTime float64    `json:"unregistered_time"`
	UsedResources    Resources  `json:"used_resources"`
	User             string     `json:"user"`
	WebuiURL         string     `json:"webui_url"`
	Labels           []Label    `json:"label"`
	// Missing fields
	// TODO: "capabilities": [],
}

// Offer represents a single offer from a Mesos Slave to a Mesos master
type Offer struct {
	ID          string            `json:"id"`
	FrameworkID string            `json:"framework_id"`
	SlaveID     string            `json:"slave_id"`
	Hostname    string            `json:"hostname"`
	URL         URL               `json:"url"`
	Resources   Resources         `json:"resources"`
	Attributes  map[string]string `json:"attributes"`
}

// URL represents a single URL
type URL struct {
	Scheme     string      `json:"scheme"`
	Address    Address     `json:"address"`
	Path       string      `json:"path"`
	Parameters []Parameter `json:"parameters"`
}

// Address represents a single address.
// e.g. from a Slave or from a Master
type Address struct {
	Hostname string `json:"hostname"`
	IP       string `json:"ip"`
	Port     int    `json:"port"`
}

// Parameter represents a single key / value pair for parameters
type Parameter struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Label represents a single key / value pair for labeling
type Label struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Task represent a single Mesos task
type Task struct {
	// Missing fields
	// TODO: "labels": [],
	ExecutorID  string        `json:"executor_id"`
	FrameworkID string        `json:"framework_id"`
	ID          string        `json:"id"`
	Name        string        `json:"name"`
	Resources   Resources     `json:"resources"`
	SlaveID     string        `json:"slave_id"`
	State       string        `json:"state"`
	Statuses    []TaskStatus  `json:"statuses"`
	Discovery   TaskDiscovery `json:"discovery"`
}

// TaskDiscovery represents the dicovery information of a task
type TaskDiscovery struct {
	Visibility string `json:"visibility"`
	Name       string `json:"name"`
	Ports      Ports  `json:"ports"`
}

// Ports represents a number of PortDetails
type Ports struct {
	Ports []PortDetails `json:"ports"`
}

// PortDetails represents details about a single port
type PortDetails struct {
	Number   int    `json:"number"`
	Protocol string `json:"protocol"`
}

// Resources represents a resource type for a task
type Resources struct {
	CPUs  float64 `json:"cpus"`
	Disk  float64 `json:"disk"`
	Mem   float64 `json:"mem"`
	Ports string  `json:"ports"`
}

// TaskStatus represents the status of a single task
type TaskStatus struct {
	State           string          `json:"state"`
	Timestamp       float64         `json:"timestamp"`
	ContainerStatus ContainerStatus `json:"container_status"`
}

// ContainerStatus represents the status of a single container inside a task
type ContainerStatus struct {
	NetworkInfos []NetworkInfo `json:"network_infos"`
}

// NetworkInfo represents information about the network of a container
type NetworkInfo struct {
	IpAddress   string      `json:"ip_address"`
	IpAddresses []IpAddress `json:"ip_addresses"`
}

// IpAddress represents a single IpAddress
type IpAddress struct {
	IpAddress string `json:"ip_address"`
}

// Slave represents a single mesos slave node
type Slave struct {
	Active              bool              `json:"active"`
	Hostname            string            `json:"hostname"`
	ID                  string            `json:"id"`
	PID                 string            `json:"pid"`
	RegisteredTime      float64           `json:"registered_time"`
	Resources           Resources         `json:"resources"`
	UsedResources       Resources         `json:"used_resources"`
	OfferedResources    Resources         `json:"offered_resources"`
	ReservedResources   Resources         `json:"reserved_resources"`
	UnreservedResources Resources         `json:"unreserved_resources"`
	Attributes          map[string]string `json:"attributes"`
	Version             string            `json:"version"`
}

// Executor represents a single executor of a framework
type Executor struct {
	// Missing fields
	// TODO "queued_tasks": [],
	// TODO "tasks": []
	CompletedTasks []Task    `json:"completed_tasks"`
	Container      string    `json:"container"`
	Directory      string    `json:"directory"`
	ID             string    `json:"id"`
	Name           string    `json:"name"`
	Resources      Resources `json:"resources"`
	Source         string    `json:"source"`
}
<|endoftext|>


<commit_before>package vitotrol

import (
	"errors"
	"fmt"
	"strconv"
)

// Singletons matching Vitodata™ types.
var (
	TypeDouble    = (*VitodataDouble)(nil)
	TypeDate      = (*VitodataDate)(nil)
	TypeString    = (*VitodataString)(nil)
	TypeOnOffEnum = NewEnum([]string{ // 0 -> 1
		"off",
		"on",
	})
	TypeEnabledEnum = NewEnum([]string{ // 0 -> 1
		"disabled",
		"enabled",
	})
)

// ErrEnumInvalidValue is returned when trying to convert to an enum a
// value that cannot match any value of this enum.
var ErrEnumInvalidValue = errors.New("Invalid Enum value")

// VitodataType is the interface implemented by each Vitodata™ type.
type VitodataType interface {
	Type() string
	Human2VitodataValue(string) (string, error)
	Vitodata2HumanValue(string) (string, error)
	Vitodata2NativeValue(string) (interface{}, error)
}

// A VitodataDouble represent the Vitodata™ Double type.
type VitodataDouble struct{}

// Type returns the "human" name of the type.
func (v *VitodataDouble) Type() string {
	return "Double"
}

// Human2VitodataValue checks that the value is a float number and
// returns it after reformatting.
func (v *VitodataDouble) Human2VitodataValue(value string) (string, error) {
	num, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return "", err
	}
	return strconv.FormatFloat(num, 'f', -1, 64), nil
}

// Vitodata2HumanValue checks that the value is a float number and
// returns it after reformatting.
func (v *VitodataDouble) Vitodata2HumanValue(value string) (string, error) {
	return v.Human2VitodataValue(value)
}

// Vitodata2NativeValue extract the number from the passed string and
// returns it as a float64.
func (v *VitodataDouble) Vitodata2NativeValue(value string) (interface{}, error) {
	num, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return nil, err
	}
	return num, nil
}

// A VitodataDate represent the Vitodata™ Date type.
type VitodataDate struct{}

// Type returns the "human" name of the type.
func (v *VitodataDate) Type() string {
	return "Date"
}

// Human2VitodataValue checks that the value is Vitodata™ formatted date and
// returns it after reformatting.
func (v *VitodataDate) Human2VitodataValue(value string) (string, error) {
	tm, err := ParseVitotrolTime(value)
	if err != nil {
		return "", err
	}
	return tm.String(), nil
}

// Vitodata2HumanValue checks that the value is Vitodata™ formatted date and
// returns it after reformatting.
func (v *VitodataDate) Vitodata2HumanValue(value string) (string, error) {
	return v.Human2VitodataValue(value)
}

// Vitodata2NativeValue extract the Vitodata™ date from
// the passed string and returns it as a vitotrol.Time.
func (v *VitodataDate) Vitodata2NativeValue(value string) (interface{}, error) {
	tm, err := ParseVitotrolTime(value)
	if err != nil {
		return nil, err
	}
	return tm, nil
}

// A VitodataString represent the Vitodata™ String type.
type VitodataString struct{}

// Type returns the "human" name of the type.
func (v *VitodataString) Type() string {
	return "String"
}

// Human2VitodataValue is a no-op here, returning its argument.
func (v *VitodataString) Human2VitodataValue(value string) (string, error) {
	return value, nil
}

// Vitodata2HumanValue is a no-op here, returning its argument.
func (v *VitodataString) Vitodata2HumanValue(value string) (string, error) {
	return value, nil
}

// Vitodata2NativeValue is a no-op here, returning its argument.
func (v *VitodataString) Vitodata2NativeValue(value string) (interface{}, error) {
	return value, nil
}

// A vitodataString represent any Vitodata™ Enum type. It must be composed.
type VitodataEnum struct {
	values    map[string]uint16
	revValues []string
}

// NewEnum specializes an enum to a set of values and returns it.
func NewEnum(values []string) *VitodataEnum {
	pEnum := &VitodataEnum{
		values:    make(map[string]uint16, len(values)),
		revValues: make([]string, len(values)),
	}

	for idx, value := range values {
		pEnum.values[value] = uint16(idx)
		pEnum.revValues[idx] = value
	}

	return pEnum
}

// Type returns the "human" name of the type.
func (v *VitodataEnum) Type() string {
	return fmt.Sprintf("Enum%d", len(v.revValues))
}

// Human2VitodataValue checks that the value is a Vitodata™ enum value
// and returns its numeric counterpart.
func (v *VitodataEnum) Human2VitodataValue(value string) (string, error) {
	// String version ?
	if num, ok := v.values[value]; ok {
		return strconv.FormatUint(uint64(num), 10), nil
	}

	// Numeric one ?
	num, err := v.Vitodata2NativeValue(value)
	if err != nil {
		return "", err
	}

	return strconv.FormatUint(num.(uint64), 10), nil
}

// Vitodata2HumanValue check that the (numeric) value is a Vitodata™
// enum value and returns its string counterpart.
func (v *VitodataEnum) Vitodata2HumanValue(value string) (string, error) {
	num, err := v.Vitodata2NativeValue(value)
	if err != nil {
		return "", err
	}
	return v.revValues[num.(uint64)], nil
}

// Vitodata2NativeValue extract the numeric Vitodata™ enum value from
// the passed string and returns it as a uint64.
func (v *VitodataEnum) Vitodata2NativeValue(value string) (interface{}, error) {
	num, err := strconv.ParseUint(value, 10, 64)
	if err != nil || num >= uint64(len(v.revValues)) {
		return nil, ErrEnumInvalidValue
	}
	return num, nil
}
<commit_msg>Correct doc<commit_after>package vitotrol

import (
	"errors"
	"fmt"
	"strconv"
)

// Singletons matching Vitodata™ types.
var (
	TypeDouble    = (*VitodataDouble)(nil)
	TypeDate      = (*VitodataDate)(nil)
	TypeString    = (*VitodataString)(nil)
	TypeOnOffEnum = NewEnum([]string{ // 0 -> 1
		"off",
		"on",
	})
	TypeEnabledEnum = NewEnum([]string{ // 0 -> 1
		"disabled",
		"enabled",
	})
)

// ErrEnumInvalidValue is returned when trying to convert to an enum a
// value that cannot match any value of this enum.
var ErrEnumInvalidValue = errors.New("Invalid Enum value")

// VitodataType is the interface implemented by each Vitodata™ type.
type VitodataType interface {
	Type() string
	Human2VitodataValue(string) (string, error)
	Vitodata2HumanValue(string) (string, error)
	Vitodata2NativeValue(string) (interface{}, error)
}

// A VitodataDouble represent the Vitodata™ Double type.
type VitodataDouble struct{}

// Type returns the "human" name of the type.
func (v *VitodataDouble) Type() string {
	return "Double"
}

// Human2VitodataValue checks that the value is a float number and
// returns it after reformatting.
func (v *VitodataDouble) Human2VitodataValue(value string) (string, error) {
	num, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return "", err
	}
	return strconv.FormatFloat(num, 'f', -1, 64), nil
}

// Vitodata2HumanValue checks that the value is a float number and
// returns it after reformatting.
func (v *VitodataDouble) Vitodata2HumanValue(value string) (string, error) {
	return v.Human2VitodataValue(value)
}

// Vitodata2NativeValue extract the number from the passed string and
// returns it as a float64.
func (v *VitodataDouble) Vitodata2NativeValue(value string) (interface{}, error) {
	num, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return nil, err
	}
	return num, nil
}

// A VitodataDate represent the Vitodata™ Date type.
type VitodataDate struct{}

// Type returns the "human" name of the type.
func (v *VitodataDate) Type() string {
	return "Date"
}

// Human2VitodataValue checks that the value is Vitodata™ formatted date and
// returns it after reformatting.
func (v *VitodataDate) Human2VitodataValue(value string) (string, error) {
	tm, err := ParseVitotrolTime(value)
	if err != nil {
		return "", err
	}
	return tm.String(), nil
}

// Vitodata2HumanValue checks that the value is Vitodata™ formatted date and
// returns it after reformatting.
func (v *VitodataDate) Vitodata2HumanValue(value string) (string, error) {
	return v.Human2VitodataValue(value)
}

// Vitodata2NativeValue extract the Vitodata™ date from
// the passed string and returns it as a vitotrol.Time.
func (v *VitodataDate) Vitodata2NativeValue(value string) (interface{}, error) {
	tm, err := ParseVitotrolTime(value)
	if err != nil {
		return nil, err
	}
	return tm, nil
}

// A VitodataString represent the Vitodata™ String type.
type VitodataString struct{}

// Type returns the "human" name of the type.
func (v *VitodataString) Type() string {
	return "String"
}

// Human2VitodataValue is a no-op here, returning its argument.
func (v *VitodataString) Human2VitodataValue(value string) (string, error) {
	return value, nil
}

// Vitodata2HumanValue is a no-op here, returning its argument.
func (v *VitodataString) Vitodata2HumanValue(value string) (string, error) {
	return value, nil
}

// Vitodata2NativeValue is a no-op here, returning its argument.
func (v *VitodataString) Vitodata2NativeValue(value string) (interface{}, error) {
	return value, nil
}

// VitodataEnum represents any Vitodata™ Enum type. See NewEnum to
// specialize it.
type VitodataEnum struct {
	values    map[string]uint16
	revValues []string
}

// NewEnum specializes an enum to a set of values and returns it.
func NewEnum(values []string) *VitodataEnum {
	pEnum := &VitodataEnum{
		values:    make(map[string]uint16, len(values)),
		revValues: make([]string, len(values)),
	}

	for idx, value := range values {
		pEnum.values[value] = uint16(idx)
		pEnum.revValues[idx] = value
	}

	return pEnum
}

// Type returns the "human" name of the type.
func (v *VitodataEnum) Type() string {
	return fmt.Sprintf("Enum%d", len(v.revValues))
}

// Human2VitodataValue checks that the value is a Vitodata™ enum value
// and returns its numeric counterpart.
func (v *VitodataEnum) Human2VitodataValue(value string) (string, error) {
	// String version ?
	if num, ok := v.values[value]; ok {
		return strconv.FormatUint(uint64(num), 10), nil
	}

	// Numeric one ?
	num, err := v.Vitodata2NativeValue(value)
	if err != nil {
		return "", err
	}

	return strconv.FormatUint(num.(uint64), 10), nil
}

// Vitodata2HumanValue check that the (numeric) value is a Vitodata™
// enum value and returns its string counterpart.
func (v *VitodataEnum) Vitodata2HumanValue(value string) (string, error) {
	num, err := v.Vitodata2NativeValue(value)
	if err != nil {
		return "", err
	}
	return v.revValues[num.(uint64)], nil
}

// Vitodata2NativeValue extract the numeric Vitodata™ enum value from
// the passed string and returns it as a uint64.
func (v *VitodataEnum) Vitodata2NativeValue(value string) (interface{}, error) {
	num, err := strconv.ParseUint(value, 10, 64)
	if err != nil || num >= uint64(len(v.revValues)) {
		return nil, ErrEnumInvalidValue
	}
	return num, nil
}
<|endoftext|>


<commit_before>package tgbotapi

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

// APIResponse is a response from the Telegram API with the result
// stored raw.
type APIResponse struct {
	Ok          bool            `json:"ok"`
	Result      json.RawMessage `json:"result"`
	ErrorCode   int             `json:"error_code"`
	Description string          `json:"description"`
}

// Update is an update response, from GetUpdates.
type Update struct {
	UpdateID           int                `json:"update_id"`
	Message            Message            `json:"message"`
	InlineQuery        InlineQuery        `json:"inline_query"`
	ChosenInlineResult ChosenInlineResult `json:"chosen_inline_result"`
}

// User is a user on Telegram.
type User struct {
	ID        int    `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"` // optional
	UserName  string `json:"username"`  // optional
}

// String displays a simple text version of a user.
//
// It is normally a user's username, but falls back to a first/last
// name as available.
func (u *User) String() string {
	if u.UserName != "" {
		return u.UserName
	}

	name := u.FirstName
	if u.LastName != "" {
		name += " " + u.LastName
	}

	return name
}

// GroupChat is a group chat.
type GroupChat struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
}

// Chat contains information about the place a message was sent.
type Chat struct {
	ID        int64  `json:"id"`
	Type      string `json:"type"`
	Title     string `json:"title"`      // optional
	UserName  string `json:"username"`   // optional
	FirstName string `json:"first_name"` // optional
	LastName  string `json:"last_name"`  // optional
}

// IsPrivate returns if the Chat is a private conversation.
func (c *Chat) IsPrivate() bool {
	return c.Type == "private"
}

// IsGroup returns if the Chat is a group.
func (c *Chat) IsGroup() bool {
	return c.Type == "group"
}

// IsSuperGroup returns if the Chat is a supergroup.
func (c *Chat) IsSuperGroup() bool {
	return c.Type == "supergroup"
}

// IsChannel returns if the Chat is a channel.
func (c *Chat) IsChannel() bool {
	return c.Type == "channel"
}

// Message is returned by almost every request, and contains data about
// almost anything.
type Message struct {
	MessageID             int         `json:"message_id"`
	From                  User        `json:"from"` // optional
	Date                  int         `json:"date"`
	Chat                  Chat        `json:"chat"`
	ForwardFrom           User        `json:"forward_from"`            // optional
	ForwardDate           int         `json:"forward_date"`            // optional
	ReplyToMessage        *Message    `json:"reply_to_message"`        // optional
	Text                  string      `json:"text"`                    // optional
	Audio                 Audio       `json:"audio"`                   // optional
	Document              Document    `json:"document"`                // optional
	Photo                 []PhotoSize `json:"photo"`                   // optional
	Sticker               Sticker     `json:"sticker"`                 // optional
	Video                 Video       `json:"video"`                   // optional
	Voice                 Voice       `json:"voice"`                   // optional
	Caption               string      `json:"caption"`                 // optional
	Contact               Contact     `json:"contact"`                 // optional
	Location              Location    `json:"location"`                // optional
	NewChatParticipant    User        `json:"new_chat_participant"`    // optional
	LeftChatParticipant   User        `json:"left_chat_participant"`   // optional
	NewChatTitle          string      `json:"new_chat_title"`          // optional
	NewChatPhoto          []PhotoSize `json:"new_chat_photo"`          // optional
	DeleteChatPhoto       bool        `json:"delete_chat_photo"`       // optional
	GroupChatCreated      bool        `json:"group_chat_created"`      // optional
	SuperGroupChatCreated bool        `json:"supergroup_chat_created"` // optional
	ChannelChatCreated    bool        `json:"channel_chat_created"`    // optional
	MigrateToChatID       int64       `json:"migrate_to_chat_id"`      // optional
	MigrateFromChatID     int64       `json:"migrate_from_chat_id"`    // optional
}

// Time converts the message timestamp into a Time.
func (m *Message) Time() time.Time {
	return time.Unix(int64(m.Date), 0)
}

// IsCommand returns true if message starts with '/'.
func (m *Message) IsCommand() bool {
	return m.Text != "" && m.Text[0] == '/'
}

// Command checks if the message was a command and if it was, returns the
// command. If the Message was not a command, it returns an empty string.
//
// If the command contains the at bot syntax, it removes the bot name.
func (m *Message) Command() string {
	if !m.IsCommand() {
		return ""
	}

	command := strings.SplitN(m.Text, " ", 2)[0][1:]

	if i := strings.Index(command, "@"); i != -1 {
		command = command[:i]
	}

	return command
}

// CommandArguments checks if the message was a command and if it was,
// returns all text after the command name. If the Message was not a
// command, it returns an empty string.
func (m *Message) CommandArguments() string {
	if !m.IsCommand() {
		return ""
	}

	split := strings.SplitN(m.Text, " ", 2)
	if len(split) != 2 {
		return ""
	}

	return strings.SplitN(m.Text, " ", 2)[1]
}

// PhotoSize contains information about photos.
type PhotoSize struct {
	FileID   string `json:"file_id"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	FileSize int    `json:"file_size"` // optional
}

// Audio contains information about audio.
type Audio struct {
	FileID    string `json:"file_id"`
	Duration  int    `json:"duration"`
	Performer string `json:"performer"` // optional
	Title     string `json:"title"`     // optional
	MimeType  string `json:"mime_type"` // optional
	FileSize  int    `json:"file_size"` // optional
}

// Document contains information about a document.
type Document struct {
	FileID    string    `json:"file_id"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	FileName  string    `json:"file_name"` // optional
	MimeType  string    `json:"mime_type"` // optional
	FileSize  int       `json:"file_size"` // optional
}

// Sticker contains information about a sticker.
type Sticker struct {
	FileID    string    `json:"file_id"`
	Width     int       `json:"width"`
	Height    int       `json:"height"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	FileSize  int       `json:"file_size"` // optional
}

// Video contains information about a video.
type Video struct {
	FileID    string    `json:"file_id"`
	Width     int       `json:"width"`
	Height    int       `json:"height"`
	Duration  int       `json:"duration"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	MimeType  string    `json:"mime_type"` // optional
	FileSize  int       `json:"file_size"` // optional
}

// Voice contains information about a voice.
type Voice struct {
	FileID   string `json:"file_id"`
	Duration int    `json:"duration"`
	MimeType string `json:"mime_type"` // optional
	FileSize int    `json:"file_size"` // optional
}

// Contact contains information about a contact.
//
// Note that LastName and UserID may be empty.
type Contact struct {
	PhoneNumber string `json:"phone_number"`
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"` // optional
	UserID      int    `json:"user_id"`   // optional
}

// Location contains information about a place.
type Location struct {
	Longitude float32 `json:"longitude"`
	Latitude  float32 `json:"latitude"`
}

// UserProfilePhotos contains a set of user profile photos.
type UserProfilePhotos struct {
	TotalCount int         `json:"total_count"`
	Photos     []PhotoSize `json:"photos"`
}

// File contains information about a file to download from Telegram.
type File struct {
	FileID   string `json:"file_id"`
	FileSize int    `json:"file_size"` // optional
	FilePath string `json:"file_path"` // optional
}

// Link returns a full path to the download URL for a File.
//
// It requires the Bot Token to create the link.
func (f *File) Link(token string) string {
	return fmt.Sprintf(FileEndpoint, token, f.FilePath)
}

// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
type ReplyKeyboardMarkup struct {
	Keyboard        [][]string `json:"keyboard"`
	ResizeKeyboard  bool       `json:"resize_keyboard"`   // optional
	OneTimeKeyboard bool       `json:"one_time_keyboard"` // optional
	Selective       bool       `json:"selective"`         // optional
}

// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
type ReplyKeyboardHide struct {
	HideKeyboard bool `json:"hide_keyboard"`
	Selective    bool `json:"selective"` // optional
}

// ForceReply allows the Bot to have users directly reply to it without
// additional interaction.
type ForceReply struct {
	ForceReply bool `json:"force_reply"`
	Selective  bool `json:"selective"` // optional
}

// InlineQuery is a Query from Telegram for an inline request.
type InlineQuery struct {
	ID     string `json:"id"`
	From   User   `json:"from"`
	Query  string `json:"query"`
	Offset string `json:"offset"`
}

// InlineQueryResultArticle is an inline query response article.
type InlineQueryResultArticle struct {
	Type                  string `json:"type"`         // required
	ID                    string `json:"id"`           // required
	Title                 string `json:"title"`        // required
	MessageText           string `json:"message_text"` // required
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
	URL                   string `json:"url"`
	HideURL               bool   `json:"hide_url"`
	Description           string `json:"description"`
	ThumbURL              string `json:"thumb_url"`
	ThumbWidth            int    `json:"thumb_width"`
	ThumbHeight           int    `json:"thumb_height"`
}

// InlineQueryResultPhoto is an inline query response photo.
type InlineQueryResultPhoto struct {
	Type                  string `json:"type"`      // required
	ID                    string `json:"id"`        // required
	URL                   string `json:"photo_url"` // required
	MimeType              string `json:"mime_type"`
	Width                 int    `json:"photo_width"`
	Height                int    `json:"photo_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Description           string `json:"description"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultGIF is an inline query response GIF.
type InlineQueryResultGIF struct {
	Type                  string `json:"type"`    // required
	ID                    string `json:"id"`      // required
	URL                   string `json:"gif_url"` // required
	Width                 int    `json:"gif_width"`
	Height                int    `json:"gif_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
type InlineQueryResultMPEG4GIF struct {
	Type                  string `json:"type"`      // required
	ID                    string `json:"id"`        // required
	URL                   string `json:"mpeg4_url"` // required
	Width                 int    `json:"mpeg4_width"`
	Height                int    `json:"mpeg4_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultVideo is an inline query response video.
type InlineQueryResultVideo struct {
	Type                  string `json:"type"`         // required
	ID                    string `json:"id"`           // required
	URL                   string `json:"video_url"`    // required
	MimeType              string `json:"mime_type"`    // required
	MessageText           string `json:"message_text"` // required
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
	Width                 int    `json:"video_width"`
	Height                int    `json:"video_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Description           string `json:"description"`
}

// ChosenInlineResult is an inline query result chosen by a User
type ChosenInlineResult struct {
	ResultID string `json:"result_id"`
	From     User   `json:"from"`
	Query    string `json:"query"`
}
<commit_msg>Fix UserProfilePhotos type<commit_after>package tgbotapi

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

// APIResponse is a response from the Telegram API with the result
// stored raw.
type APIResponse struct {
	Ok          bool            `json:"ok"`
	Result      json.RawMessage `json:"result"`
	ErrorCode   int             `json:"error_code"`
	Description string          `json:"description"`
}

// Update is an update response, from GetUpdates.
type Update struct {
	UpdateID           int                `json:"update_id"`
	Message            Message            `json:"message"`
	InlineQuery        InlineQuery        `json:"inline_query"`
	ChosenInlineResult ChosenInlineResult `json:"chosen_inline_result"`
}

// User is a user on Telegram.
type User struct {
	ID        int    `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"` // optional
	UserName  string `json:"username"`  // optional
}

// String displays a simple text version of a user.
//
// It is normally a user's username, but falls back to a first/last
// name as available.
func (u *User) String() string {
	if u.UserName != "" {
		return u.UserName
	}

	name := u.FirstName
	if u.LastName != "" {
		name += " " + u.LastName
	}

	return name
}

// GroupChat is a group chat.
type GroupChat struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
}

// Chat contains information about the place a message was sent.
type Chat struct {
	ID        int64  `json:"id"`
	Type      string `json:"type"`
	Title     string `json:"title"`      // optional
	UserName  string `json:"username"`   // optional
	FirstName string `json:"first_name"` // optional
	LastName  string `json:"last_name"`  // optional
}

// IsPrivate returns if the Chat is a private conversation.
func (c *Chat) IsPrivate() bool {
	return c.Type == "private"
}

// IsGroup returns if the Chat is a group.
func (c *Chat) IsGroup() bool {
	return c.Type == "group"
}

// IsSuperGroup returns if the Chat is a supergroup.
func (c *Chat) IsSuperGroup() bool {
	return c.Type == "supergroup"
}

// IsChannel returns if the Chat is a channel.
func (c *Chat) IsChannel() bool {
	return c.Type == "channel"
}

// Message is returned by almost every request, and contains data about
// almost anything.
type Message struct {
	MessageID             int         `json:"message_id"`
	From                  User        `json:"from"` // optional
	Date                  int         `json:"date"`
	Chat                  Chat        `json:"chat"`
	ForwardFrom           User        `json:"forward_from"`            // optional
	ForwardDate           int         `json:"forward_date"`            // optional
	ReplyToMessage        *Message    `json:"reply_to_message"`        // optional
	Text                  string      `json:"text"`                    // optional
	Audio                 Audio       `json:"audio"`                   // optional
	Document              Document    `json:"document"`                // optional
	Photo                 []PhotoSize `json:"photo"`                   // optional
	Sticker               Sticker     `json:"sticker"`                 // optional
	Video                 Video       `json:"video"`                   // optional
	Voice                 Voice       `json:"voice"`                   // optional
	Caption               string      `json:"caption"`                 // optional
	Contact               Contact     `json:"contact"`                 // optional
	Location              Location    `json:"location"`                // optional
	NewChatParticipant    User        `json:"new_chat_participant"`    // optional
	LeftChatParticipant   User        `json:"left_chat_participant"`   // optional
	NewChatTitle          string      `json:"new_chat_title"`          // optional
	NewChatPhoto          []PhotoSize `json:"new_chat_photo"`          // optional
	DeleteChatPhoto       bool        `json:"delete_chat_photo"`       // optional
	GroupChatCreated      bool        `json:"group_chat_created"`      // optional
	SuperGroupChatCreated bool        `json:"supergroup_chat_created"` // optional
	ChannelChatCreated    bool        `json:"channel_chat_created"`    // optional
	MigrateToChatID       int64       `json:"migrate_to_chat_id"`      // optional
	MigrateFromChatID     int64       `json:"migrate_from_chat_id"`    // optional
}

// Time converts the message timestamp into a Time.
func (m *Message) Time() time.Time {
	return time.Unix(int64(m.Date), 0)
}

// IsCommand returns true if message starts with '/'.
func (m *Message) IsCommand() bool {
	return m.Text != "" && m.Text[0] == '/'
}

// Command checks if the message was a command and if it was, returns the
// command. If the Message was not a command, it returns an empty string.
//
// If the command contains the at bot syntax, it removes the bot name.
func (m *Message) Command() string {
	if !m.IsCommand() {
		return ""
	}

	command := strings.SplitN(m.Text, " ", 2)[0][1:]

	if i := strings.Index(command, "@"); i != -1 {
		command = command[:i]
	}

	return command
}

// CommandArguments checks if the message was a command and if it was,
// returns all text after the command name. If the Message was not a
// command, it returns an empty string.
func (m *Message) CommandArguments() string {
	if !m.IsCommand() {
		return ""
	}

	split := strings.SplitN(m.Text, " ", 2)
	if len(split) != 2 {
		return ""
	}

	return strings.SplitN(m.Text, " ", 2)[1]
}

// PhotoSize contains information about photos.
type PhotoSize struct {
	FileID   string `json:"file_id"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	FileSize int    `json:"file_size"` // optional
}

// Audio contains information about audio.
type Audio struct {
	FileID    string `json:"file_id"`
	Duration  int    `json:"duration"`
	Performer string `json:"performer"` // optional
	Title     string `json:"title"`     // optional
	MimeType  string `json:"mime_type"` // optional
	FileSize  int    `json:"file_size"` // optional
}

// Document contains information about a document.
type Document struct {
	FileID    string    `json:"file_id"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	FileName  string    `json:"file_name"` // optional
	MimeType  string    `json:"mime_type"` // optional
	FileSize  int       `json:"file_size"` // optional
}

// Sticker contains information about a sticker.
type Sticker struct {
	FileID    string    `json:"file_id"`
	Width     int       `json:"width"`
	Height    int       `json:"height"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	FileSize  int       `json:"file_size"` // optional
}

// Video contains information about a video.
type Video struct {
	FileID    string    `json:"file_id"`
	Width     int       `json:"width"`
	Height    int       `json:"height"`
	Duration  int       `json:"duration"`
	Thumbnail PhotoSize `json:"thumb"`     // optional
	MimeType  string    `json:"mime_type"` // optional
	FileSize  int       `json:"file_size"` // optional
}

// Voice contains information about a voice.
type Voice struct {
	FileID   string `json:"file_id"`
	Duration int    `json:"duration"`
	MimeType string `json:"mime_type"` // optional
	FileSize int    `json:"file_size"` // optional
}

// Contact contains information about a contact.
//
// Note that LastName and UserID may be empty.
type Contact struct {
	PhoneNumber string `json:"phone_number"`
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"` // optional
	UserID      int    `json:"user_id"`   // optional
}

// Location contains information about a place.
type Location struct {
	Longitude float32 `json:"longitude"`
	Latitude  float32 `json:"latitude"`
}

// UserProfilePhotos contains a set of user profile photos.
type UserProfilePhotos struct {
	TotalCount int           `json:"total_count"`
	Photos     [][]PhotoSize `json:"photos"`
}

// File contains information about a file to download from Telegram.
type File struct {
	FileID   string `json:"file_id"`
	FileSize int    `json:"file_size"` // optional
	FilePath string `json:"file_path"` // optional
}

// Link returns a full path to the download URL for a File.
//
// It requires the Bot Token to create the link.
func (f *File) Link(token string) string {
	return fmt.Sprintf(FileEndpoint, token, f.FilePath)
}

// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
type ReplyKeyboardMarkup struct {
	Keyboard        [][]string `json:"keyboard"`
	ResizeKeyboard  bool       `json:"resize_keyboard"`   // optional
	OneTimeKeyboard bool       `json:"one_time_keyboard"` // optional
	Selective       bool       `json:"selective"`         // optional
}

// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
type ReplyKeyboardHide struct {
	HideKeyboard bool `json:"hide_keyboard"`
	Selective    bool `json:"selective"` // optional
}

// ForceReply allows the Bot to have users directly reply to it without
// additional interaction.
type ForceReply struct {
	ForceReply bool `json:"force_reply"`
	Selective  bool `json:"selective"` // optional
}

// InlineQuery is a Query from Telegram for an inline request.
type InlineQuery struct {
	ID     string `json:"id"`
	From   User   `json:"from"`
	Query  string `json:"query"`
	Offset string `json:"offset"`
}

// InlineQueryResultArticle is an inline query response article.
type InlineQueryResultArticle struct {
	Type                  string `json:"type"`         // required
	ID                    string `json:"id"`           // required
	Title                 string `json:"title"`        // required
	MessageText           string `json:"message_text"` // required
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
	URL                   string `json:"url"`
	HideURL               bool   `json:"hide_url"`
	Description           string `json:"description"`
	ThumbURL              string `json:"thumb_url"`
	ThumbWidth            int    `json:"thumb_width"`
	ThumbHeight           int    `json:"thumb_height"`
}

// InlineQueryResultPhoto is an inline query response photo.
type InlineQueryResultPhoto struct {
	Type                  string `json:"type"`      // required
	ID                    string `json:"id"`        // required
	URL                   string `json:"photo_url"` // required
	MimeType              string `json:"mime_type"`
	Width                 int    `json:"photo_width"`
	Height                int    `json:"photo_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Description           string `json:"description"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultGIF is an inline query response GIF.
type InlineQueryResultGIF struct {
	Type                  string `json:"type"`    // required
	ID                    string `json:"id"`      // required
	URL                   string `json:"gif_url"` // required
	Width                 int    `json:"gif_width"`
	Height                int    `json:"gif_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
type InlineQueryResultMPEG4GIF struct {
	Type                  string `json:"type"`      // required
	ID                    string `json:"id"`        // required
	URL                   string `json:"mpeg4_url"` // required
	Width                 int    `json:"mpeg4_width"`
	Height                int    `json:"mpeg4_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Caption               string `json:"caption"`
	MessageText           string `json:"message_text"`
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
}

// InlineQueryResultVideo is an inline query response video.
type InlineQueryResultVideo struct {
	Type                  string `json:"type"`         // required
	ID                    string `json:"id"`           // required
	URL                   string `json:"video_url"`    // required
	MimeType              string `json:"mime_type"`    // required
	MessageText           string `json:"message_text"` // required
	ParseMode             string `json:"parse_mode"`
	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
	Width                 int    `json:"video_width"`
	Height                int    `json:"video_height"`
	ThumbURL              string `json:"thumb_url"`
	Title                 string `json:"title"`
	Description           string `json:"description"`
}

// ChosenInlineResult is an inline query result chosen by a User
type ChosenInlineResult struct {
	ResultID string `json:"result_id"`
	From     User   `json:"from"`
	Query    string `json:"query"`
}
<|endoftext|>


<commit_before>package guber

// Common
//==============================================================================
type ResourceDefinition struct {
	Kind       string `json:"kind"`
	ApiVersion string `json:"apiVersion"`
}

type Metadata struct {
	Name              string            `json:"name"`
	Namespace         string            `json:"namespace"`
	Labels            map[string]string `json:"labels,omitempty"`
	CreationTimestamp string            `json:"creationTimestamp,omitempty"`
}

// Namespace
//==============================================================================
type Namespace struct {
	collection *Namespaces
	*ResourceDefinition

	Metadata *Metadata `json:"metadata"`
}

type NamespaceList struct {
	Items []*Namespace `json:"items"`
}

// Node
//==============================================================================
type NodeSpec struct {
	ExternalID string `json:"externalID"`
}

type NodeStatusCapacity struct {
	CPU    string `json:"cpu"`
	Memory string `json:"memory"`
}

type NodeStatusCondition struct {
	Type   string `json:"type"`
	Status string `json:"status"`
}

type NodeStatus struct {
	Capacity   *NodeStatusCapacity    `json:"capacity"`
	Conditions []*NodeStatusCondition `json:"conditions"`
}

type Node struct {
	collection *Nodes
	*ResourceDefinition

	Metadata *Metadata   `json:"metadata"`
	Spec     *NodeSpec   `json:"spec"`
	Status   *NodeStatus `json:"status"`
}

type NodeList struct {
	Items []*Node `json:"items"`
}

// ReplicationController
//==============================================================================
type PodTemplate struct {
	Metadata *Metadata `json:"metadata"`
	Spec     *PodSpec  `json:"spec"`
}

type ReplicationControllerSpec struct {
	Selector map[string]string `json:"selector"`
	Replicas int               `json:"replicas"`
	Template *PodTemplate      `json:"template"`
}

type ReplicationControllerStatus struct {
	Replicas int `json:"replicas"`
}

type ReplicationController struct {
	collection *ReplicationControllers
	*ResourceDefinition

	Metadata *Metadata                    `json:"metadata"`
	Spec     *ReplicationControllerSpec   `json:"spec"`
	Status   *ReplicationControllerStatus `json:"status,omitempty"`
}

type ReplicationControllerList struct {
	Items []*ReplicationController `json:"items"`
}

// Pod
//==============================================================================
type AwsElasticBlockStore struct {
	VolumeID string `json:"volumeID"`
	FSType   string `json:"fsType"`
}

type Volume struct {
	Name                 string                `json:"name"`
	AwsElasticBlockStore *AwsElasticBlockStore `json:"awsElasticBlockStore"`
}

type VolumeMount struct {
	Name      string `json:"name"`
	MountPath string `json:"mountPath"`
}

type ResourceValues struct {
	Memory string `json:"memory,omitempty"`
	CPU    string `json:"cpu,omitempty"`
}

type Resources struct {
	Limits   *ResourceValues `json:"limits"`
	Requests *ResourceValues `json:"requests"`
}

type ContainerPort struct {
	Name          string `json:"name,omitempty"`
	ContainerPort int    `json:"containerPort"`
	Protocol      string `json:"protocol,omitempty"`
}

type EnvVar struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type SecurityContext struct {
	Privileged bool `json:"privileged"`
}

type Container struct {
	Name            string           `json:"name"`
	Image           string           `json:"image"`
	Command         []string         `json:"command"`
	Resources       *Resources       `json:"resources"`
	Ports           []*ContainerPort `json:"ports"`
	VolumeMounts    []*VolumeMount   `json:"volumeMounts"`
	Env             []*EnvVar        `json:"env"`
	SecurityContext *SecurityContext `json:"securityContext"`
	ImagePullPolicy string           `json:"imagePullPolicy"`
}

type ImagePullSecret struct {
	Name string `json:"name"`
}

type PodSpec struct {
	Volumes                       []*Volume          `json:"volumes"`
	Containers                    []*Container       `json:"containers"`
	ImagePullSecrets              []*ImagePullSecret `json:"imagePullSecrets"`
	TerminationGracePeriodSeconds int                `json:"terminationGracePeriodSeconds"`
	RestartPolicy                 string             `json:"restartPolicy"`
}

// type ContainerStatus struct {
// 	Name string `json:"name"`
// 	...
// }

type PodStatusCondition struct {
	Type   string `json:"type"`
	Status string `json:"status"`
}

type PodStatus struct {
	Phase             string                `json:"phase"`
	Conditions        []*PodStatusCondition `json:"conditions"`
	ContainerStatuses []interface{}         `json:"containerStatuses"`
}

type Pod struct {
	collection *Pods
	*ResourceDefinition

	Metadata *Metadata  `json:"metadata"`
	Spec     *PodSpec   `json:"spec"`
	Status   *PodStatus `json:"status"`
}

type PodList struct {
	Items []*Pod `json:"items"`
}

// Service
//==============================================================================
type ServicePort struct {
	Name       string `json:"name"`
	Port       int    `json:"port"`
	Protocol   string `json:"protocol,omitempty"`
	NodePort   int    `json:"nodePort,omitempty"`
	TargetPort int    `json:"targetPort,omitempty"`
}

type ServiceSpec struct {
	Type     string            `json:"type,omitempty"`
	Selector map[string]string `json:"selector"`
	Ports    []*ServicePort    `json:"ports"`

	ClusterIP string `json:"clusterIP,omitempty"`
}

type Service struct {
	collection *Services
	*ResourceDefinition

	Metadata *Metadata    `json:"metadata"`
	Spec     *ServiceSpec `json:"spec"`
	// Status   *ServiceStatus `json:"status"`
}

type ServiceList struct {
	Items []*Service `json:"items"`
}

// Secret
//==============================================================================
type Secret struct {
	collection *Secrets
	*ResourceDefinition

	Metadata *Metadata         `json:"metadata"`
	Type     string            `json:"type"`
	Data     map[string]string `json:"data"`
}

type SecretList struct {
	Items []*Secret `json:"items"`
}

// Event
//==============================================================================
type Source struct {
	Host string `json:"host"`
}

type Event struct {
	collection *Events
	*ResourceDefinition

	Metadata *Metadata `json:"metadata"`
	Message  string    `json:"message"`
	Count    int       `json:"count"`
	Source   *Source   `json:"source"`
}

type EventList struct {
	Items []*Event `json:"items"`
}

// TODO not sure if this should be in the types file.. related to queries, but is a Kube-specific thing
type QueryParams struct {
	LabelSelector string
	FieldSelector string
}
<commit_msg>add ContainerStatus and ContainerState to Pod<commit_after>package guber

// Common
//==============================================================================
type ResourceDefinition struct {
	Kind       string `json:"kind"`
	ApiVersion string `json:"apiVersion"`
}

type Metadata struct {
	Name              string            `json:"name"`
	Namespace         string            `json:"namespace"`
	Labels            map[string]string `json:"labels,omitempty"`
	CreationTimestamp string            `json:"creationTimestamp,omitempty"`
}

// Namespace
//==============================================================================
type Namespace struct {
	collection *Namespaces
	*ResourceDefinition

	Metadata *Metadata `json:"metadata"`
}

type NamespaceList struct {
	Items []*Namespace `json:"items"`
}

// Node
//==============================================================================
type NodeSpec struct {
	ExternalID string `json:"externalID"`
}

type NodeStatusCapacity struct {
	CPU    string `json:"cpu"`
	Memory string `json:"memory"`
}

type NodeStatusCondition struct {
	Type   string `json:"type"`
	Status string `json:"status"`
}

type NodeStatus struct {
	Capacity   *NodeStatusCapacity    `json:"capacity"`
	Conditions []*NodeStatusCondition `json:"conditions"`
}

type Node struct {
	collection *Nodes
	*ResourceDefinition

	Metadata *Metadata   `json:"metadata"`
	Spec     *NodeSpec   `json:"spec"`
	Status   *NodeStatus `json:"status"`
}

type NodeList struct {
	Items []*Node `json:"items"`
}

// ReplicationController
//==============================================================================
type PodTemplate struct {
	Metadata *Metadata `json:"metadata"`
	Spec     *PodSpec  `json:"spec"`
}

type ReplicationControllerSpec struct {
	Selector map[string]string `json:"selector"`
	Replicas int               `json:"replicas"`
	Template *PodTemplate      `json:"template"`
}

type ReplicationControllerStatus struct {
	Replicas int `json:"replicas"`
}

type ReplicationController struct {
	collection *ReplicationControllers
	*ResourceDefinition

	Metadata *Metadata                    `json:"metadata"`
	Spec     *ReplicationControllerSpec   `json:"spec"`
	Status   *ReplicationControllerStatus `json:"status,omitempty"`
}

type ReplicationControllerList struct {
	Items []*ReplicationController `json:"items"`
}

// Pod
//==============================================================================
type AwsElasticBlockStore struct {
	VolumeID string `json:"volumeID"`
	FSType   string `json:"fsType"`
}

type Volume struct {
	Name                 string                `json:"name"`
	AwsElasticBlockStore *AwsElasticBlockStore `json:"awsElasticBlockStore"`
}

type VolumeMount struct {
	Name      string `json:"name"`
	MountPath string `json:"mountPath"`
}

type ResourceValues struct {
	Memory string `json:"memory,omitempty"`
	CPU    string `json:"cpu,omitempty"`
}

type Resources struct {
	Limits   *ResourceValues `json:"limits"`
	Requests *ResourceValues `json:"requests"`
}

type ContainerPort struct {
	Name          string `json:"name,omitempty"`
	ContainerPort int    `json:"containerPort"`
	Protocol      string `json:"protocol,omitempty"`
}

type EnvVar struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type SecurityContext struct {
	Privileged bool `json:"privileged"`
}

type Container struct {
	Name            string           `json:"name"`
	Image           string           `json:"image"`
	Command         []string         `json:"command"`
	Resources       *Resources       `json:"resources"`
	Ports           []*ContainerPort `json:"ports"`
	VolumeMounts    []*VolumeMount   `json:"volumeMounts"`
	Env             []*EnvVar        `json:"env"`
	SecurityContext *SecurityContext `json:"securityContext"`
	ImagePullPolicy string           `json:"imagePullPolicy"`
}

type ImagePullSecret struct {
	Name string `json:"name"`
}

type PodSpec struct {
	Volumes                       []*Volume          `json:"volumes"`
	Containers                    []*Container       `json:"containers"`
	ImagePullSecrets              []*ImagePullSecret `json:"imagePullSecrets"`
	TerminationGracePeriodSeconds int                `json:"terminationGracePeriodSeconds"`
	RestartPolicy                 string             `json:"restartPolicy"`
}

type ContainerStateRunning struct {
	StartedAt string `json:"startedAt"` // TODO should be time type
}

type ContainerStateTerminated struct {
	ExitCode   int    `json:"exitcode"`
	StartedAt  string `json:"startedAt"`  // TODO should be time type
	FinishedAt string `json:"finishedAt"` // TODO should be time type
	Reason     string `json:"reason"`
}

type ContainerState struct {
	Running    *ContainerStateRunning    `json:"running"`
	Terminated *ContainerStateTerminated `json:"terminated"`
}

type ContainerStatus struct {
	ContainerID  string          `json:"containerID"`
	Image        string          `json:"image"`
	ImageID      string          `json:"imageID"`
	Name         string          `json:"name"`
	Ready        bool            `json:"ready"`
	RestartCount int             `json:"restartCount"`
	State        *ContainerState `json:"state"`
	LastState    *ContainerState `json:"state"`
}

type PodStatusCondition struct {
	Type   string `json:"type"`
	Status string `json:"status"`
}

type PodStatus struct {
	Phase             string                `json:"phase"`
	Conditions        []*PodStatusCondition `json:"conditions"`
	ContainerStatuses []*ContainerStatus    `json:"containerStatuses"`
}

type Pod struct {
	collection *Pods
	*ResourceDefinition

	Metadata *Metadata  `json:"metadata"`
	Spec     *PodSpec   `json:"spec"`
	Status   *PodStatus `json:"status"`
}

type PodList struct {
	Items []*Pod `json:"items"`
}

// Service
//==============================================================================
type ServicePort struct {
	Name       string `json:"name"`
	Port       int    `json:"port"`
	Protocol   string `json:"protocol,omitempty"`
	NodePort   int    `json:"nodePort,omitempty"`
	TargetPort int    `json:"targetPort,omitempty"`
}

type ServiceSpec struct {
	Type     string            `json:"type,omitempty"`
	Selector map[string]string `json:"selector"`
	Ports    []*ServicePort    `json:"ports"`

	ClusterIP string `json:"clusterIP,omitempty"`
}

type Service struct {
	collection *Services
	*ResourceDefinition

	Metadata *Metadata    `json:"metadata"`
	Spec     *ServiceSpec `json:"spec"`
	// Status   *ServiceStatus `json:"status"`
}

type ServiceList struct {
	Items []*Service `json:"items"`
}

// Secret
//==============================================================================
type Secret struct {
	collection *Secrets
	*ResourceDefinition

	Metadata *Metadata         `json:"metadata"`
	Type     string            `json:"type"`
	Data     map[string]string `json:"data"`
}

type SecretList struct {
	Items []*Secret `json:"items"`
}

// Event
//==============================================================================
type Source struct {
	Host string `json:"host"`
}

type Event struct {
	collection *Events
	*ResourceDefinition

	Metadata *Metadata `json:"metadata"`
	Message  string    `json:"message"`
	Count    int       `json:"count"`
	Source   *Source   `json:"source"`
}

type EventList struct {
	Items []*Event `json:"items"`
}

// TODO not sure if this should be in the types file.. related to queries, but is a Kube-specific thing
type QueryParams struct {
	LabelSelector string
	FieldSelector string
}
<|endoftext|>


<commit_before>package gobus

import "sync"

type (
    // Map that holds all listener references, indexed through input argument name.

    // Uses an IListenerSet interface as return type, for optimization purposes.

    // Example of subscriptions map:
    //     map
    //     |--> string (built-in)
    //     |    |--> printString1(str string), printString2(str string)
    //     |
    //     |--> Struct1 (user-defined)
    //          |--> printStruct1(s1 Struct1), doSomethingStruct1(s1 Struct1)
    //
    Subscription map[string]IListenerSet

    // EventBus, of course
    EventBus struct {
        dispatcher   chan interface{}
        subscription Subscription
        waitGroup    sync.WaitGroup
    }

    // ListenerSet is a struct that uses an interface{} slice
    // to implement a listeners set (IListenerSet interface).
    ListenerSet struct {
        listeners []interface{}
    }

    // Interface for listener set.
    IListenerSet interface {
        Add(listener interface{})    IListenerSet
        Remove(listener interface{}) IListenerSet
        Values() []interface{}
        Empty()  bool
    }
)
<commit_msg>Finish documenting<commit_after>package gobus

import "sync"

type (
    // Map that holds all listener references, indexed through input argument name.
    // Uses an IListenerSet interface as return type, for optimization purposes.
    // Example of subscriptions map:
    //     map
    //     |--> string (built-in)
    //     |    |--> printString1(str string), printString2(str string)
    //     |
    //     |--> Struct1 (user-defined)
    //          |--> printStruct1(s1 Struct1), doSomethingStruct1(s1 Struct1)
    //
    Subscription map[string]IListenerSet

    // EventBus, of course
    EventBus struct {
        dispatcher   chan interface{}
        subscription Subscription
        waitGroup    sync.WaitGroup
    }

    // ListenerSet is a struct that uses an interface{} slice
    // to implement a listeners set (IListenerSet interface).
    ListenerSet struct {
        listeners []interface{}
    }

    // Interface for listener set.
    IListenerSet interface {
        Add(listener interface{})    IListenerSet
        Remove(listener interface{}) IListenerSet
        Values() []interface{}
        Empty()  bool
    }
)
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/csv"
	"fmt"
	"log"
	"os"

	// Register hdb driver.
	_ "github.com/SAP/go-hdb/driver"
	// ini config
	"github.com/go-ini/ini"
	// internal
	"github.com/morxs/go-hana/utils"
	// cli
	"github.com/urfave/cli"
)

func main() {
	const (
		t024SQL = `select
MANDT
, EKGRP
, EKNAM
, EKTEL
, LDEST
, TELFX
, TEL_NUMBER
, TEL_EXTENS
, SMTP_ADDR
from z_wilmar1.t024
where mandt = '777'`
		cFile = "t024.csv"
	)

	var sCfg string
	var bLog bool

	app := cli.NewApp()
	app.Name = "T024"
	app.Usage = "Get table T024"
	app.Version = "0.1.1"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "config, c",
			Value:       "config.ini",
			Usage:       "Custom config file",
			Destination: &sCfg,
		},
		cli.BoolFlag{
			Name:        "log, l",
			Hidden:      true,
			Usage:       "Enable logging. Log filename will be <query_filename>+.log",
			Destination: &bLog,
		},
	}

	app.Action = func(c *cli.Context) error {
		// read config file
		utils.WriteMsg("READ CONFIG")
		iniCfg, err := ini.Load(sCfg)
		if err != nil {
			utils.WriteMsg("CONFIG")
			log.Fatal(err)
		}
		iniSection := iniCfg.Section("server")
		iniKeyUsername := iniSection.Key("uid").String()
		iniKeyPassword := iniSection.Key("pwd").String()
		iniKeyHost := iniSection.Key("host").String()
		iniKeyPort := iniSection.Key("port").String()
		hdbDsn := "hdb://" + iniKeyUsername + ":" + iniKeyPassword + "@" + iniKeyHost + ":" + iniKeyPort

		utils.WriteMsg("OPEN HDB")
		db, err := sql.Open(utils.DriverName, hdbDsn)
		if err != nil {
			log.Fatal(err)
		}
		defer db.Close()

		if err := db.Ping(); err != nil {
			log.Fatal(err)
		}

		// create file
		utils.WriteMsg("CREATE FILE: " + cFile)
		file, err := os.Create(cFile)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()

		// try to query
		utils.WriteMsg("QUERY")
		rows, err := db.Query(t024SQL)
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()

		// prepare file
		utils.WriteMsg("WRITE CSV")
		w := csv.NewWriter(file)
		w.Comma = ';'

		fmt.Println(rows.Columns())

		// add header to file
		rs, _ := rows.Columns()
		var rec []string
		for i := 0; i < len(rs); i++ {
			rec = append(rec, rs[i])
		}
		w.Write(rec)

		for rows.Next() {
			var mandt, ekgrp, eknam, ektel, ldest string
			var telfx, tel_number, tel_extens, smtp_addr string

			if err := rows.Scan(&mandt, &ekgrp, &eknam, &ektel, &ldest, &telfx, &tel_number, &tel_extens, &smtp_addr); err != nil {
				utils.WriteMsg("SCAN")
				log.Fatal(err)
			}

			/*
				var bi big.Int
				var z float64
				var neg bool
				var i int
			*/

			var record []string

			record = append(record, mandt)
			record = append(record, ekgrp)
			record = append(record, eknam)
			record = append(record, ektel)
			record = append(record, ldest)
			record = append(record, telfx)
			record = append(record, tel_number)
			record = append(record, tel_extens)
			record = append(record, smtp_addr)
			w.Write(record)
			//fmt.Println(record)
		}
		w.Flush()

		if err := rows.Err(); err != nil {
			utils.WriteMsg("ROWS")
			log.Fatal(err)
		}
		return nil
	}

	// init the program
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>- all const must go local! - refactor cFile to become --output/-o flag - refactor read ini config become DSN builder from util packge<commit_after>package main

import (
	"database/sql"
	"encoding/csv"
	"fmt"
	"log"
	"os"

	// Register hdb driver.
	_ "github.com/SAP/go-hdb/driver"

	// internal
	"github.com/morxs/go-hana/utils"
	// cli
	"github.com/urfave/cli"
)

func main() {
	const (
		t024SQL = `select
MANDT
, EKGRP
, EKNAM
, EKTEL
, LDEST
, TELFX
, TEL_NUMBER
, TEL_EXTENS
, SMTP_ADDR
from z_wilmar1.t024
where mandt = '777'`
	)

	var sCfg, sOutputFile string
	var bLog bool

	app := cli.NewApp()
	app.Name = "T024"
	app.Usage = "Get table T024"
	app.Version = "0.1.1"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "config, c",
			Value:       "config.ini",
			Usage:       "Custom config file",
			Destination: &sCfg,
		},
		cli.StringFlag{
			Name:        "output, o",
			Usage:       "Output file",
			Value:       "t024.csv",
			Destination: &sOutputFile,
		},
		cli.BoolFlag{
			Name:        "log, l",
			Hidden:      true,
			Usage:       "Enable logging. Log filename will be <query_filename>+.log",
			Destination: &bLog,
		},
	}

	app.Action = func(c *cli.Context) error {
		// read config file
		utils.WriteMsg("READ CONFIG")
		hdbDsn, err := utils.ReadConfig(sCfg)
		if err != nil {
			log.Fatal(err)
		}

		utils.WriteMsg("OPEN HDB")
		db, err := sql.Open(utils.DriverName, hdbDsn)
		if err != nil {
			log.Fatal(err)
		}
		defer db.Close()

		if err := db.Ping(); err != nil {
			log.Fatal(err)
		}

		// create file
		utils.WriteMsg("CREATE FILE: " + sOutputFile)
		file, err := os.Create(sOutputFile)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()

		// try to query
		utils.WriteMsg("QUERY")
		rows, err := db.Query(t024SQL)
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()

		// prepare file
		utils.WriteMsg("WRITE CSV")
		w := csv.NewWriter(file)
		w.Comma = ';'

		fmt.Println(rows.Columns())

		// add header to file
		rs, _ := rows.Columns()
		var rec []string
		for i := 0; i < len(rs); i++ {
			rec = append(rec, rs[i])
		}
		w.Write(rec)

		for rows.Next() {
			var mandt, ekgrp, eknam, ektel, ldest string
			var telfx, tel_number, tel_extens, smtp_addr string

			if err := rows.Scan(&mandt, &ekgrp, &eknam, &ektel, &ldest, &telfx, &tel_number, &tel_extens, &smtp_addr); err != nil {
				utils.WriteMsg("SCAN")
				log.Fatal(err)
			}

			/*
				var bi big.Int
				var z float64
				var neg bool
				var i int
			*/

			var record []string

			record = append(record, mandt)
			record = append(record, ekgrp)
			record = append(record, eknam)
			record = append(record, ektel)
			record = append(record, ldest)
			record = append(record, telfx)
			record = append(record, tel_number)
			record = append(record, tel_extens)
			record = append(record, smtp_addr)
			w.Write(record)
			//fmt.Println(record)
		}
		w.Flush()

		if err := rows.Err(); err != nil {
			utils.WriteMsg("ROWS")
			log.Fatal(err)
		}
		return nil
	}

	// init the program
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.

package tail

import (
	"bufio"
	"fmt"
	"github.com/ActiveState/tail/util"
	"github.com/ActiveState/tail/watch"
	"io"
	"launchpad.net/tomb"
	"log"
	"os"
	"time"
)

var (
	ErrStop = fmt.Errorf("tail should now stop")
)

type Line struct {
	Text string
	Time time.Time
	Err  error // Error from tail
}

// NewLine returns a Line with present time.
func NewLine(text string) *Line {
	return &Line{text, time.Now(), nil}
}

// SeekInfo represents arguments to `os.Seek`
type SeekInfo struct {
	Offset int64
	Whence int // os.SEEK_*
}

// Config is used to specify how a file must be tailed.
type Config struct {
	// File-specifc
	Location  *SeekInfo // Seek to this location before tailing
	ReOpen    bool      // Reopen recreated files (tail -F)
	MustExist bool      // Fail early if the file does not exist
	Poll      bool      // Poll for file changes instead of using inotify
	LimitRate int64     // Maximum read rate (lines per second)

	// Generic IO
	Follow      bool // Continue looking for new lines (tail -f)
	MaxLineSize int  // If non-zero, split longer lines into multiple lines
}

type Tail struct {
	Filename string
	Lines    chan *Line
	Config

	file    *os.File
	reader  *bufio.Reader
	watcher watch.FileWatcher
	changes *watch.FileChanges
	rateMon *RateMonitor

	tomb.Tomb // provides: Done, Kill, Dying
}

// TailFile begins tailing the file. Output stream is made available
// via the `Tail.Lines` channel. To handle errors during tailing,
// invoke the `Wait` or `Err` method after finishing reading from the
// `Lines` channel.
func TailFile(filename string, config Config) (*Tail, error) {
	if config.ReOpen && !config.Follow {
		util.Fatal("cannot set ReOpen without Follow.")
	}

	t := &Tail{
		Filename: filename,
		Lines:    make(chan *Line),
		Config:   config}

	t.rateMon = new(RateMonitor)

	if t.Poll {
		t.watcher = watch.NewPollingFileWatcher(filename)
	} else {
		t.watcher = watch.NewInotifyFileWatcher(filename)
	}

	if t.MustExist {
		var err error
		t.file, err = os.Open(t.Filename)
		if err != nil {
			return nil, err
		}
	}

	go t.tailFileSync()

	return t, nil
}

// Return the file's current position, like stdio's ftell().
// But this value is not very accurate.
// it may readed one line in the chan(tail.Lines),
// so it may lost one line.
func (tail *Tail) Tell() (offset int64, err error) {
	if tail.file == nil {
		return
	}
	offset, err = tail.file.Seek(0, os.SEEK_CUR)
	if err == nil {
		offset -= int64(tail.reader.Buffered())
	}
	return
}

// Stop stops the tailing activity.
func (tail *Tail) Stop() error {
	tail.Kill(nil)
	return tail.Wait()
}

func (tail *Tail) close() {
	close(tail.Lines)
	if tail.file != nil {
		tail.file.Close()
	}
}

func (tail *Tail) reopen() error {
	if tail.file != nil {
		tail.file.Close()
	}
	for {
		var err error
		tail.file, err = os.Open(tail.Filename)
		if err != nil {
			if os.IsNotExist(err) {
				log.Printf("Waiting for %s to appear...", tail.Filename)
				if err := tail.watcher.BlockUntilExists(&tail.Tomb); err != nil {
					if err == tomb.ErrDying {
						return err
					}
					return fmt.Errorf("Failed to detect creation of %s: %s", tail.Filename, err)
				}
				continue
			}
			return fmt.Errorf("Unable to open file %s: %s", tail.Filename, err)
		}
		break
	}
	return nil
}

func (tail *Tail) readLine() ([]byte, error) {
	line, _, err := tail.reader.ReadLine()
	return line, err
}

func (tail *Tail) tailFileSync() {
	defer tail.Done()
	defer tail.close()

	if !tail.MustExist {
		// deferred first open.
		err := tail.reopen()
		if err != nil {
			if err != tomb.ErrDying {
				tail.Kill(err)
			}
			return
		}
	}

	// Seek to requested location on first open of the file.
	if tail.Location != nil {
		_, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence)
		// log.Printf("Seeked %s - %+v\n", tail.Filename, tail.Location)
		if err != nil {
			tail.Killf("Seek error on %s: %s", tail.Filename, err)
			return
		}
	}

	tail.reader = bufio.NewReader(tail.file)

	// Read line by line.
	for {
		line, err := tail.readLine()

		switch err {
		case nil:
			if line != nil {
				cooloff := !tail.sendLine(line)
				if cooloff {
					msg := "Too much activity; entering a cool-off period"
					tail.Lines <- &Line{
						msg,
						time.Now(),
						fmt.Errorf(msg)}
					// Wait a second before seeking till the end of
					// file when rate limit is reached.
					select {
					case <-time.After(time.Second):
					case <-tail.Dying():
						return
					}
					_, err := tail.file.Seek(0, 2) // Seek to fine end
					if err != nil {
						tail.Killf("Seek error on %s: %s", tail.Filename, err)
						return
					}
				}
			}
		case io.EOF:
			if !tail.Follow {
				return
			}
			// When EOF is reached, wait for more data to become
			// available. Wait strategy is based on the `tail.watcher`
			// implementation (inotify or polling).
			err := tail.waitForChanges()
			if err != nil {
				if err != ErrStop {
					tail.Kill(err)
				}
				return
			}
		default: // non-EOF error
			tail.Killf("Error reading %s: %s", tail.Filename, err)
			return
		}

		select {
		case <-tail.Dying():
			return
		default:
		}
	}
}

// waitForChanges waits until the file has been appended, deleted,
// moved or truncated. When moved or deleted - the file will be
// reopened if ReOpen is true. Truncated files are always reopened.
func (tail *Tail) waitForChanges() error {
	if tail.changes == nil {
		st, err := tail.file.Stat()
		if err != nil {
			return err
		}
		tail.changes = tail.watcher.ChangeEvents(&tail.Tomb, st)
	}

	select {
	case <-tail.changes.Modified:
		return nil
	case <-tail.changes.Deleted:
		tail.changes = nil
		if tail.ReOpen {
			// XXX: we must not log from a library.
			log.Printf("Re-opening moved/deleted file %s ...", tail.Filename)
			if err := tail.reopen(); err != nil {
				return err
			}
			log.Printf("Successfully reopened %s", tail.Filename)
			tail.reader = bufio.NewReader(tail.file)
			return nil
		} else {
			log.Printf("Stopping tail as file no longer exists: %s", tail.Filename)
			return ErrStop
		}
	case <-tail.changes.Truncated:
		// Always reopen truncated files (Follow is true)
		log.Printf("Re-opening truncated file %s ...", tail.Filename)
		if err := tail.reopen(); err != nil {
			return err
		}
		log.Printf("Successfully reopened truncated %s", tail.Filename)
		tail.reader = bufio.NewReader(tail.file)
		return nil
	case <-tail.Dying():
		return ErrStop
	}
	panic("unreachable")
}

// sendLine sends the line(s) to Lines channel, splitting longer lines
// if necessary. Return false if rate limit is reached.
func (tail *Tail) sendLine(line []byte) bool {
	now := time.Now()
	nowUnix := now.Unix()
	lines := []string{string(line)}

	// Split longer lines
	if tail.MaxLineSize > 0 && len(line) > tail.MaxLineSize {
		lines = util.PartitionString(
			string(line), tail.MaxLineSize)
	}

	for _, line := range lines {
		tail.Lines <- &Line{line, now, nil}
		rate := tail.rateMon.Tick(nowUnix)
		if tail.LimitRate > 0 && rate > tail.LimitRate {
			log.Printf("Rate limit (%v < %v) reached on file (%v); entering 1s cooloff period.\n",
				tail.LimitRate,
				rate,
				tail.Filename)
			return false
		}
	}

	return true
}

// Cleanup removes inotify watches added by the tail package. This function is
// meant to be invoked from a process's exit handler. Linux kernel may not
// automatically remove inotify watches after the process exits.
func Cleanup() {
	watch.Cleanup()
}
<commit_msg>Add logging options to config<commit_after>// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.

package tail

import (
	"bufio"
	"fmt"
	"github.com/ActiveState/tail/util"
	"github.com/ActiveState/tail/watch"
	"io"
	"launchpad.net/tomb"
	"log"
	"os"
	"time"
)

var (
	ErrStop = fmt.Errorf("tail should now stop")
)

type Line struct {
	Text string
	Time time.Time
	Err  error // Error from tail
}

// NewLine returns a Line with present time.
func NewLine(text string) *Line {
	return &Line{text, time.Now(), nil}
}

// SeekInfo represents arguments to `os.Seek`
type SeekInfo struct {
	Offset int64
	Whence int // os.SEEK_*
}

// Config is used to specify how a file must be tailed.
type Config struct {
	// File-specifc
	Location  *SeekInfo // Seek to this location before tailing
	ReOpen    bool      // Reopen recreated files (tail -F)
	MustExist bool      // Fail early if the file does not exist
	Poll      bool      // Poll for file changes instead of using inotify
	LimitRate int64     // Maximum read rate (lines per second)

	// Generic IO
	Follow      bool // Continue looking for new lines (tail -f)
	MaxLineSize int  // If non-zero, split longer lines into multiple lines

	// Logging
	DisableLogging bool        // when true, disables all logging (i.e. Config.Logger isn't used)
	Logger         *log.Logger // when not specified (nil), this will be set to `log.New(os.Stderr, "", log.LstdFlags)`
}

type Tail struct {
	Filename string
	Lines    chan *Line
	Config

	file    *os.File
	reader  *bufio.Reader
	watcher watch.FileWatcher
	changes *watch.FileChanges
	rateMon *RateMonitor

	tomb.Tomb // provides: Done, Kill, Dying
}

// TailFile begins tailing the file. Output stream is made available
// via the `Tail.Lines` channel. To handle errors during tailing,
// invoke the `Wait` or `Err` method after finishing reading from the
// `Lines` channel.
func TailFile(filename string, config Config) (*Tail, error) {
	if config.ReOpen && !config.Follow {
		util.Fatal("cannot set ReOpen without Follow.")
	}

	t := &Tail{
		Filename: filename,
		Lines:    make(chan *Line),
		Config:   config,
	}

	// when Logger was not specified in config, use default logger
	if t.Logger == nil {
		t.Logger = log.New(os.Stderr, "", log.LstdFlags)
	}

	t.rateMon = new(RateMonitor)

	if t.Poll {
		t.watcher = watch.NewPollingFileWatcher(filename)
	} else {
		t.watcher = watch.NewInotifyFileWatcher(filename)
	}

	if t.MustExist {
		var err error
		t.file, err = os.Open(t.Filename)
		if err != nil {
			return nil, err
		}
	}

	go t.tailFileSync()

	return t, nil
}

// Return the file's current position, like stdio's ftell().
// But this value is not very accurate.
// it may readed one line in the chan(tail.Lines),
// so it may lost one line.
func (tail *Tail) Tell() (offset int64, err error) {
	if tail.file == nil {
		return
	}
	offset, err = tail.file.Seek(0, os.SEEK_CUR)
	if err == nil {
		offset -= int64(tail.reader.Buffered())
	}
	return
}

// Stop stops the tailing activity.
func (tail *Tail) Stop() error {
	tail.Kill(nil)
	return tail.Wait()
}

func (tail *Tail) close() {
	close(tail.Lines)
	if tail.file != nil {
		tail.file.Close()
	}
}

func (tail *Tail) reopen() error {
	if tail.file != nil {
		tail.file.Close()
	}
	for {
		var err error
		tail.file, err = os.Open(tail.Filename)
		if err != nil {
			if os.IsNotExist(err) {
				if !tail.DisableLogging {
					tail.Logger.Printf("Waiting for %s to appear...", tail.Filename)
				}
				if err := tail.watcher.BlockUntilExists(&tail.Tomb); err != nil {
					if err == tomb.ErrDying {
						return err
					}
					return fmt.Errorf("Failed to detect creation of %s: %s", tail.Filename, err)
				}
				continue
			}
			return fmt.Errorf("Unable to open file %s: %s", tail.Filename, err)
		}
		break
	}
	return nil
}

func (tail *Tail) readLine() ([]byte, error) {
	line, _, err := tail.reader.ReadLine()
	return line, err
}

func (tail *Tail) tailFileSync() {
	defer tail.Done()
	defer tail.close()

	if !tail.MustExist {
		// deferred first open.
		err := tail.reopen()
		if err != nil {
			if err != tomb.ErrDying {
				tail.Kill(err)
			}
			return
		}
	}

	// Seek to requested location on first open of the file.
	if tail.Location != nil {
		_, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence)
		if !tail.DisableLogging { //
			tail.Logger.Printf("Seeked %s - %+v\n", tail.Filename, tail.Location)
		}
		if err != nil {
			tail.Killf("Seek error on %s: %s", tail.Filename, err)
			return
		}
	}

	tail.reader = bufio.NewReader(tail.file)

	// Read line by line.
	for {
		line, err := tail.readLine()

		switch err {
		case nil:
			if line != nil {
				cooloff := !tail.sendLine(line)
				if cooloff {
					msg := "Too much activity; entering a cool-off period"
					tail.Lines <- &Line{
						msg,
						time.Now(),
						fmt.Errorf(msg)}
					// Wait a second before seeking till the end of
					// file when rate limit is reached.
					select {
					case <-time.After(time.Second):
					case <-tail.Dying():
						return
					}
					_, err := tail.file.Seek(0, 2) // Seek to fine end
					if err != nil {
						tail.Killf("Seek error on %s: %s", tail.Filename, err)
						return
					}
				}
			}
		case io.EOF:
			if !tail.Follow {
				return
			}
			// When EOF is reached, wait for more data to become
			// available. Wait strategy is based on the `tail.watcher`
			// implementation (inotify or polling).
			err := tail.waitForChanges()
			if err != nil {
				if err != ErrStop {
					tail.Kill(err)
				}
				return
			}
		default: // non-EOF error
			tail.Killf("Error reading %s: %s", tail.Filename, err)
			return
		}

		select {
		case <-tail.Dying():
			return
		default:
		}
	}
}

// waitForChanges waits until the file has been appended, deleted,
// moved or truncated. When moved or deleted - the file will be
// reopened if ReOpen is true. Truncated files are always reopened.
func (tail *Tail) waitForChanges() error {
	if tail.changes == nil {
		st, err := tail.file.Stat()
		if err != nil {
			return err
		}
		tail.changes = tail.watcher.ChangeEvents(&tail.Tomb, st)
	}

	select {
	case <-tail.changes.Modified:
		return nil
	case <-tail.changes.Deleted:
		tail.changes = nil
		if tail.ReOpen {
			// XXX: we must not log from a library.
			if !tail.DisableLogging {
				tail.Logger.Printf("Re-opening moved/deleted file %s ...", tail.Filename)
			}
			if err := tail.reopen(); err != nil {
				return err
			}
			if !tail.DisableLogging {
				tail.Logger.Printf("Successfully reopened %s", tail.Filename)
			}
			tail.reader = bufio.NewReader(tail.file)
			return nil
		} else {
			if !tail.DisableLogging {
				tail.Logger.Printf("Stopping tail as file no longer exists: %s", tail.Filename)
			}
			return ErrStop
		}
	case <-tail.changes.Truncated:
		// Always reopen truncated files (Follow is true)
		if !tail.DisableLogging {
			tail.Logger.Printf("Re-opening truncated file %s ...", tail.Filename)
		}
		if err := tail.reopen(); err != nil {
			return err
		}
		if !tail.DisableLogging {
			tail.Logger.Printf("Successfully reopened truncated %s", tail.Filename)
		}
		tail.reader = bufio.NewReader(tail.file)
		return nil
	case <-tail.Dying():
		return ErrStop
	}
	panic("unreachable")
}

// sendLine sends the line(s) to Lines channel, splitting longer lines
// if necessary. Return false if rate limit is reached.
func (tail *Tail) sendLine(line []byte) bool {
	now := time.Now()
	nowUnix := now.Unix()
	lines := []string{string(line)}

	// Split longer lines
	if tail.MaxLineSize > 0 && len(line) > tail.MaxLineSize {
		lines = util.PartitionString(
			string(line), tail.MaxLineSize)
	}

	for _, line := range lines {
		tail.Lines <- &Line{line, now, nil}
		rate := tail.rateMon.Tick(nowUnix)
		if tail.LimitRate > 0 && rate > tail.LimitRate {
			if !tail.DisableLogging {
				tail.Logger.Printf("Rate limit (%v < %v) reached on file (%v); entering 1s cooloff period.\n",
					tail.LimitRate,
					rate,
					tail.Filename)
			}
			return false
		}
	}

	return true
}

// Cleanup removes inotify watches added by the tail package. This function is
// meant to be invoked from a process's exit handler. Linux kernel may not
// automatically remove inotify watches after the process exits.
func Cleanup() {
	watch.Cleanup()
}
<|endoftext|>


<commit_before>package contractor

import (
	"errors"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// TestIntegrationReplaceOffline tests that when a host goes offline, its
// contract is eventually replaced.
func TestIntegrationReplaceOffline(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	h, c, m, err := newTestingTrio(t.Name())
	if err != nil {
		t.Fatal(err)
	}

	// form a contract with h
	c.SetAllowance(modules.Allowance{
		Funds:       types.SiacoinPrecision.Mul64(250),
		Hosts:       1,
		Period:      50,
		RenewWindow: 20,
	})
	// Block until the contract is registered.
	err = build.Retry(50, 100*time.Millisecond, func() error {
		c.mu.Lock()
		lenC := c.staticContracts.Len()
		c.mu.Unlock()
		if lenC < 1 {
			return errors.New("allowance forming seems to have failed")
		}
		return nil
	})
	if err != nil {
		t.Log(len(c.Contracts()))
		t.Error(err)
	}

	// Take the first host offline.
	err = h.Close()
	if err != nil {
		t.Error(err)
	}
	// Block until the host is seen as offline.
	hosts := c.hdb.AllHosts()
	err = build.Retry(250, 250*time.Millisecond, func() error {
		hosts = c.hdb.AllHosts()
		if len(hosts) != 1 {
			return errors.New("only expecting one host")
		}
		sh := hosts[0].ScanHistory
		if sh[len(sh)-1].Success {
			return errors.New("host is reporting as online")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// create another host
	dir := build.TempDir("contractor", t.Name(), "Host2")
	h2, err := newTestingHost(dir, c.cs.(modules.ConsensusSet), c.tpool.(modules.TransactionPool))
	if err != nil {
		t.Fatal(err)
	}
	// Announce the second host.
	err = h2.Announce()
	if err != nil {
		t.Fatal(err)
	}
	// Mine a block to get the announcement on-chain.
	_, err = m.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Wait for a scan of the host to complete.
	err = build.Retry(250, 250*time.Millisecond, func() error {
		hosts = c.hdb.AllHosts()
		if len(hosts) < 2 {
			return errors.New("waiting for at least two hosts to show up")
		}
		for _, host := range hosts {
			if len(host.ScanHistory) < 3 {
				return errors.New("waiting for the hosts to have been scanned")
			}
		}
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// Mine 3 blocks to trigger an allowance refresh, which should cause the
	// second, online host to be picked up. Three are mined because mining just
	// one was causing NDFs.
	_, err = m.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	var numContracts int
	err = build.Retry(250, 250*time.Millisecond, func() error {
		numContracts = len(c.Contracts())
		if numContracts < 2 {
			return errors.New("still waiting to form the second contract")
		}
		return nil
	})
	if err != nil {
		t.Fatal(err, numContracts)
	}
}
<commit_msg>remove redundant uptime_test.go<commit_after><|endoftext|>