<commit_before>package venom

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/spf13/pflag"
)

const (
	SquashFlagsTag = "++"
)

//
// Structures implementing this interface won't be introspected and this function will be called
// instead.
//
type HasFlags interface {
	Flags() *pflag.FlagSet
}

//
// Define new flags based on the provided defaults.
//
// It panics if something goes wrong.
//
func MustDefineFlags(defaults interface{}) *pflag.FlagSet {
	flags, err := DefineFlags(defaults)
	if err != nil {
		panic(err)
	}
	return flags
}

//
// Define new flags based on the provided defaults.
//
func DefineFlags(defaults interface{}) (*pflag.FlagSet, error) {
	a := flagsFactory{
		tags: []string{"flag", "pflag"},
	}
	return a.createFlags(defaults)
}

//
// Parse name for mapstructure tags i.e. fetch banana from:
//
// type Foo struct {
//     foo int `mapstructure:"banana"`
// }
//
func parseMapstructureTag(tag string) (string, bool) {
	parts := strings.SplitN(tag, ",", 2)
	if len(parts) == 0 {
		return "", false
	}
	return parts[0], true
}

type flagInfo struct {
	name      string
	shorthand string
	usage     string
}

//
// Parse flag tag so it later could be used to create cli flag:
//
// type Foo struct {
//     foo int `flag:"foo,f,Do some fooness"`
// }
//
func parseTag(tag string) flagInfo {
	parts := strings.SplitN(tag, ",", 3)

	// flag: bar, b, Some barness -> flag: bar,b,Some barness
	for i, p := range parts {
		parts[i] = strings.TrimSpace(p)
	}

	var f flagInfo
	switch len(parts) {
	case 1:
		// flag: b
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = ""
			return f
		}
		// flag: bar
		f.name = parts[0]
		f.shorthand = ""
		f.usage = ""
		return f
	case 2:
		// flag: b,Some barness
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = parts[1]
			return f
		}
		// flag: bar,b
		if len(parts[1]) == 1 {
			f.name = parts[0]
			f.shorthand = parts[1]
			f.usage = ""
			return f
		}
		// flag: bar,Some barness
		f.name = parts[0]
		f.shorthand = ""
		f.usage = parts[1]
		return f
	case 3:
		// flag: bar,b,Some barness
		f.name = parts[0]
		f.shorthand = parts[1]
		f.usage = parts[2]
		return f
	default:
		return f
	}
}

type flagsFactory struct {
	tags []string
}

func (a flagsFactory) lookupTag(tag reflect.StructTag) (string, bool) {
	for _, name := range a.tags {
		v, ok := tag.Lookup(name)
		if ok {
			return v, true
		}
	}
	return "", false
}

func (a flagsFactory) createFlags(defaults interface{}) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	//
	// Remove one level of indirection.
	//
	v := reflect.ValueOf(defaults)
	if v.Kind() == reflect.Ptr {
		v = reflect.Indirect(v)
	}

	//
	// Make sure we end up with a struct.
	//
	if v.Kind() != reflect.Struct {
		return nil, errors.New("Struct or pointer to struct expected")
	}

	//
	// For every tagged struct field create a flag.
	//
	for i := 0; i < v.Type().NumField(); i++ {
		structField := v.Type().Field(i)
		fieldType := structField.Type
		fieldValue := v.Field(i)

		tag, ok := a.lookupTag(structField.Tag)
		if !ok {
			continue
		}

		//
		// This means we want to squash all flags from the inner structure so they appear as is they are defined
		// in the outer structure.
		//
		if tag == SquashFlagsTag {
			if fieldType.Kind() != reflect.Struct {
				return nil, fmt.Errorf(`flag:"%s" is supported only for inner structs but is set on: %s`, SquashFlagsTag, fieldType)
			}

			// Check if the struct implements HasFlags right away
			if hasFlags, ok := fieldValue.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// Check if struct-ptr implements HasFlags
			if fieldValue.CanAddr() {
				fieldValueAddr := fieldValue.Addr()

				if hasFlags, ok := fieldValueAddr.Interface().(HasFlags); ok {
					innerFlags := hasFlags.Flags()
					flags.AddFlagSet(innerFlags)
					continue
				}
			}

			// Check if inner struct implements HasFlags.
			//
			// I can't manage to get a pointer to inner struct here, it is not addressable and etc. Just as a workaround
			// we make a temporary copy and get a pointer to it instead. Suboptimal but meh, config struct are supposed
			// to be cheap to copy. Note that fieldValueCopy is a pointer.
			//
			fieldValueCopy := reflect.New(fieldType)
			fieldValueCopy.Elem().Set(fieldValue)

			if hasFlags, ok := fieldValueCopy.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// No overrides are provided, continue with recursive introspection
			innerFlags, err := a.createFlags(fieldValue.Interface())
			if err != nil {
				return nil, err
			}
			flags.AddFlagSet(innerFlags)
			continue
		}

		//
		// In case we have mapstructure defined it must have exactly the same name as flag has.
		//
		mapTag, ok := structField.Tag.Lookup("mapstructure")
		if ok {
			mapName, ok := parseMapstructureTag(mapTag)
			if ok && !(tag == mapName || strings.HasPrefix(tag, mapName+",")) {
				return nil, fmt.Errorf(`Both "mapstructure" and "flag" tags must have equal names but are different for field: %s`, structField.Name)
				continue
			}
		}

		fi := parseTag(tag)
		fs, err := a.createFlag(fi, fieldValue, fieldType)
		if err != nil {
			return nil, err
		}
		flags.AddFlagSet(fs)
	}

	return &flags, nil
}

func cloneSlice(slice interface{}) interface{} {
	t, v := reflect.TypeOf(slice), reflect.ValueOf(slice)

	v2 := reflect.MakeSlice(t, v.Len(), v.Len())
	n := reflect.Copy(v2, v)
	if n != v.Len() {
		panic(fmt.Sprintf("Failed to clone slice: %d != %d", n, v.Len()))
	}

	return v2.Interface()
}

//
// Note that we pass both field value and field type as it is defined in the struct. I'm not 100% sure about this and
// just playing safe here:
//
// Probably it is possible to get the value's type i.e. fieldValue.Type() and will be not equal to the fieldType as
// defined in the struct. I think it is possible in case these types are convertible i.e. fieldValue.Type() is
// convertible to fieldType.
//
func (a flagsFactory) createFlag(fi flagInfo, fieldValue reflect.Value, fieldType reflect.Type) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	name := fi.name
	shorthand := fi.shorthand
	usage := fi.usage

	//
	// Note that switch on type must be *before* the next one that is on kind. This is to prevent kind capturing
	// types that are simply aliases for native types e.g. time.Duration.
	//
	switch fieldType {
	case reflect.TypeOf(time.Time{}):
		val := fieldValue.Interface().(time.Time)
		p := &time.Time{}

		value := newTimeValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	case reflect.TypeOf(time.Duration(0)):
		val := fieldValue.Interface().(time.Duration)

		d := time.Duration(0)
		p := &d

		value := newDurationValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	}

	switch fieldType.Kind() {
	case reflect.Bool:
		value := bool(fieldValue.Bool())
		flags.BoolP(name, shorthand, value, usage)
	case reflect.Int:
		value := int(fieldValue.Int())
		flags.IntP(name, shorthand, value, usage)
	case reflect.Int8:
		value := int8(fieldValue.Int())
		flags.Int8P(name, shorthand, value, usage)
	case reflect.Int16:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage) // Not a typo, pflags doesn't have Int16
	case reflect.Int32:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage)
	case reflect.Int64:
		value := int64(fieldValue.Int())
		flags.Int64P(name, shorthand, value, usage)
	case reflect.Uint:
		value := uint(fieldValue.Uint())
		flags.UintP(name, shorthand, value, usage)
	case reflect.Uint8:
		value := uint8(fieldValue.Uint())
		flags.Uint8P(name, shorthand, value, usage)
	case reflect.Uint16:
		value := uint16(fieldValue.Uint())
		flags.Uint16P(name, shorthand, value, usage)
	case reflect.Uint32:
		value := uint32(fieldValue.Uint())
		flags.Uint32P(name, shorthand, value, usage)
	case reflect.Uint64:
		value := uint64(fieldValue.Uint())
		flags.Uint64P(name, shorthand, value, usage)
	case reflect.Float32:
		value := float32(fieldValue.Float())
		flags.Float32P(name, shorthand, value, usage)
	case reflect.Float64:
		value := float64(fieldValue.Float())
		flags.Float64P(name, shorthand, value, usage)
	case reflect.String:
		value := string(fieldValue.String())
		flags.StringP(name, shorthand, value, usage)
	case reflect.Slice:
		switch fieldType.Elem().Kind() {
		case reflect.Bool:
			value := cloneSlice(fieldValue.Interface()).([]bool)
			flags.BoolSliceP(name, shorthand, value, usage)
		case reflect.Int:
			value := cloneSlice(fieldValue.Interface()).([]int)
			flags.IntSliceP(name, shorthand, value, usage)
		case reflect.Uint:
			value := cloneSlice(fieldValue.Interface()).([]uint)
			flags.UintSliceP(name, shorthand, value, usage)
		case reflect.String:
			value := cloneSlice(fieldValue.Interface()).([]string)
			flags.StringSliceP(name, shorthand, value, usage)
		default:
			return nil, fmt.Errorf("Unsupported slice type for field with flag tag %q: %s", name, fieldType)
		}
	default:
		return nil, fmt.Errorf("Unsupported type for field with flag tag %q: %s", name, fieldType)
	}
	return &flags, nil
}
<commit_msg>Catch parsing errors in parseTag<commit_after>package venom

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/spf13/pflag"
)

const (
	SquashFlagsTag = "++"
)

//
// Structures implementing this interface won't be introspected and this function will be called
// instead.
//
type HasFlags interface {
	Flags() *pflag.FlagSet
}

//
// Define new flags based on the provided defaults.
//
// It panics if something goes wrong.
//
func MustDefineFlags(defaults interface{}) *pflag.FlagSet {
	flags, err := DefineFlags(defaults)
	if err != nil {
		panic(err)
	}
	return flags
}

//
// Define new flags based on the provided defaults.
//
func DefineFlags(defaults interface{}) (*pflag.FlagSet, error) {
	a := flagsFactory{
		tags: []string{"flag", "pflag"},
	}
	return a.createFlags(defaults)
}

//
// Parse name for mapstructure tags i.e. fetch banana from:
//
// type Foo struct {
//     foo int `mapstructure:"banana"`
// }
//
func parseMapstructureTag(tag string) (string, bool) {
	parts := strings.SplitN(tag, ",", 2)
	if len(parts) == 0 {
		return "", false
	}
	return parts[0], true
}

type flagInfo struct {
	name      string
	shorthand string
	usage     string
}

//
// Parse flag tag so it later could be used to create cli flag:
//
// type Foo struct {
//     foo int `flag:"foo,f,Do some fooness"`
// }
//
func parseTag(tag string) (flagInfo, error) {
	parts := strings.SplitN(tag, ",", 3)

	// flag: bar, b, Some barness -> flag: bar,b,Some barness
	for i, p := range parts {
		parts[i] = strings.TrimSpace(p)
	}

	var f flagInfo
	switch len(parts) {
	case 1:
		// flag: b
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = ""
			return f, nil
		}
		// flag: bar
		f.name = parts[0]
		f.shorthand = ""
		f.usage = ""
		return f, nil
	case 2:
		// flag: b,Some barness
		if len(parts[0]) == 1 {
			f.name = ""
			f.shorthand = parts[0]
			f.usage = parts[1]
			return f, nil
		}
		// flag: bar,b
		if len(parts[1]) == 1 {
			f.name = parts[0]
			f.shorthand = parts[1]
			f.usage = ""
			return f, nil
		}
		// flag: bar,Some barness
		f.name = parts[0]
		f.shorthand = ""
		f.usage = parts[1]
		return f, nil
	case 3:
		// flag: bar,b,Some barness
		f.name = parts[0]
		f.shorthand = parts[1]
		f.usage = parts[2]
		return f, nil
	default:
		return f, fmt.Errorf("Failed to parse flag tag: %s", tag)
	}
}

type flagsFactory struct {
	tags []string
}

func (a flagsFactory) lookupTag(tag reflect.StructTag) (string, bool) {
	for _, name := range a.tags {
		v, ok := tag.Lookup(name)
		if ok {
			return v, true
		}
	}
	return "", false
}

func (a flagsFactory) createFlags(defaults interface{}) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	//
	// Remove one level of indirection.
	//
	v := reflect.ValueOf(defaults)
	if v.Kind() == reflect.Ptr {
		v = reflect.Indirect(v)
	}

	//
	// Make sure we end up with a struct.
	//
	if v.Kind() != reflect.Struct {
		return nil, errors.New("Struct or pointer to struct expected")
	}

	//
	// For every tagged struct field create a flag.
	//
	for i := 0; i < v.Type().NumField(); i++ {
		structField := v.Type().Field(i)
		fieldType := structField.Type
		fieldValue := v.Field(i)

		tag, ok := a.lookupTag(structField.Tag)
		if !ok {
			continue
		}

		//
		// This means we want to squash all flags from the inner structure so they appear as is they are defined
		// in the outer structure.
		//
		if tag == SquashFlagsTag {
			if fieldType.Kind() != reflect.Struct {
				return nil, fmt.Errorf(`flag:"%s" is supported only for inner structs but is set on: %s`, SquashFlagsTag, fieldType)
			}

			// Check if the struct implements HasFlags right away
			if hasFlags, ok := fieldValue.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// Check if struct-ptr implements HasFlags
			if fieldValue.CanAddr() {
				fieldValueAddr := fieldValue.Addr()

				if hasFlags, ok := fieldValueAddr.Interface().(HasFlags); ok {
					innerFlags := hasFlags.Flags()
					flags.AddFlagSet(innerFlags)
					continue
				}
			}

			// Check if inner struct implements HasFlags.
			//
			// I can't manage to get a pointer to inner struct here, it is not addressable and etc. Just as a workaround
			// we make a temporary copy and get a pointer to it instead. Suboptimal but meh, config struct are supposed
			// to be cheap to copy. Note that fieldValueCopy is a pointer.
			//
			fieldValueCopy := reflect.New(fieldType)
			fieldValueCopy.Elem().Set(fieldValue)

			if hasFlags, ok := fieldValueCopy.Interface().(HasFlags); ok {
				innerFlags := hasFlags.Flags()
				flags.AddFlagSet(innerFlags)
				continue
			}

			// No overrides are provided, continue with recursive introspection
			innerFlags, err := a.createFlags(fieldValue.Interface())
			if err != nil {
				return nil, err
			}
			flags.AddFlagSet(innerFlags)
			continue
		}

		//
		// In case we have mapstructure defined it must have exactly the same name as flag has.
		//
		mapTag, ok := structField.Tag.Lookup("mapstructure")
		if ok {
			mapName, ok := parseMapstructureTag(mapTag)
			if ok && !(tag == mapName || strings.HasPrefix(tag, mapName+",")) {
				return nil, fmt.Errorf(`Both "mapstructure" and "flag" tags must have equal names but are different for field: %s`, structField.Name)
				continue
			}
		}

		fi, err := parseTag(tag)
		if err != nil {
			return nil, err
		}
		fs, err := a.createFlag(fi, fieldValue, fieldType)
		if err != nil {
			return nil, err
		}
		flags.AddFlagSet(fs)
	}

	return &flags, nil
}

func cloneSlice(slice interface{}) interface{} {
	t, v := reflect.TypeOf(slice), reflect.ValueOf(slice)

	v2 := reflect.MakeSlice(t, v.Len(), v.Len())
	n := reflect.Copy(v2, v)
	if n != v.Len() {
		panic(fmt.Sprintf("Failed to clone slice: %d != %d", n, v.Len()))
	}

	return v2.Interface()
}

//
// Note that we pass both field value and field type as it is defined in the struct. I'm not 100% sure about this and
// just playing safe here:
//
// Probably it is possible to get the value's type i.e. fieldValue.Type() and will be not equal to the fieldType as
// defined in the struct. I think it is possible in case these types are convertible i.e. fieldValue.Type() is
// convertible to fieldType.
//
func (a flagsFactory) createFlag(fi flagInfo, fieldValue reflect.Value, fieldType reflect.Type) (*pflag.FlagSet, error) {
	var flags pflag.FlagSet

	name := fi.name
	shorthand := fi.shorthand
	usage := fi.usage

	//
	// Note that switch on type must be *before* the next one that is on kind. This is to prevent kind capturing
	// types that are simply aliases for native types e.g. time.Duration.
	//
	switch fieldType {
	case reflect.TypeOf(time.Time{}):
		val := fieldValue.Interface().(time.Time)
		p := &time.Time{}

		value := newTimeValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	case reflect.TypeOf(time.Duration(0)):
		val := fieldValue.Interface().(time.Duration)

		d := time.Duration(0)
		p := &d

		value := newDurationValue(val, p)
		flags.VarP(value, name, shorthand, usage)
		return &flags, nil
	}

	switch fieldType.Kind() {
	case reflect.Bool:
		value := bool(fieldValue.Bool())
		flags.BoolP(name, shorthand, value, usage)
	case reflect.Int:
		value := int(fieldValue.Int())
		flags.IntP(name, shorthand, value, usage)
	case reflect.Int8:
		value := int8(fieldValue.Int())
		flags.Int8P(name, shorthand, value, usage)
	case reflect.Int16:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage) // Not a typo, pflags doesn't have Int16
	case reflect.Int32:
		value := int32(fieldValue.Int())
		flags.Int32P(name, shorthand, value, usage)
	case reflect.Int64:
		value := int64(fieldValue.Int())
		flags.Int64P(name, shorthand, value, usage)
	case reflect.Uint:
		value := uint(fieldValue.Uint())
		flags.UintP(name, shorthand, value, usage)
	case reflect.Uint8:
		value := uint8(fieldValue.Uint())
		flags.Uint8P(name, shorthand, value, usage)
	case reflect.Uint16:
		value := uint16(fieldValue.Uint())
		flags.Uint16P(name, shorthand, value, usage)
	case reflect.Uint32:
		value := uint32(fieldValue.Uint())
		flags.Uint32P(name, shorthand, value, usage)
	case reflect.Uint64:
		value := uint64(fieldValue.Uint())
		flags.Uint64P(name, shorthand, value, usage)
	case reflect.Float32:
		value := float32(fieldValue.Float())
		flags.Float32P(name, shorthand, value, usage)
	case reflect.Float64:
		value := float64(fieldValue.Float())
		flags.Float64P(name, shorthand, value, usage)
	case reflect.String:
		value := string(fieldValue.String())
		flags.StringP(name, shorthand, value, usage)
	case reflect.Slice:
		switch fieldType.Elem().Kind() {
		case reflect.Bool:
			value := cloneSlice(fieldValue.Interface()).([]bool)
			flags.BoolSliceP(name, shorthand, value, usage)
		case reflect.Int:
			value := cloneSlice(fieldValue.Interface()).([]int)
			flags.IntSliceP(name, shorthand, value, usage)
		case reflect.Uint:
			value := cloneSlice(fieldValue.Interface()).([]uint)
			flags.UintSliceP(name, shorthand, value, usage)
		case reflect.String:
			value := cloneSlice(fieldValue.Interface()).([]string)
			flags.StringSliceP(name, shorthand, value, usage)
		default:
			return nil, fmt.Errorf("Unsupported slice type for field with flag tag %q: %s", name, fieldType)
		}
	default:
		return nil, fmt.Errorf("Unsupported type for field with flag tag %q: %s", name, fieldType)
	}
	return &flags, nil
}
<|endoftext|>


<commit_before>package api

import (
	"time"
)

// MemoryStats holds memory usage related stats
type MemoryStats struct {
	RSS            uint64
	Cache          uint64
	Swap           uint64
	MaxUsage       uint64
	KernelUsage    uint64
	KernelMaxUsage uint64
	Measured       []string
}

// CpuStats holds cpu usage related stats
type CpuStats struct {
	SystemMode       float64
	UserMode         float64
	TotalTicks       float64
	ThrottledPeriods uint64
	ThrottledTime    uint64
	Percent          float64
	Measured         []string
}

// ResourceUsage holds information related to cpu and memory stats
type ResourceUsage struct {
	MemoryStats *MemoryStats
	CpuStats    *CpuStats
}

// TaskResourceUsage holds aggregated resource usage of all processes in a Task
// and the resource usage of the individual pids
type TaskResourceUsage struct {
	ResourceUsage *ResourceUsage
	Timestamp     int64
	Pids          map[string]*ResourceUsage
}

// AllocResourceUsage holds the aggregated task resource usage of the
// allocation.
type AllocResourceUsage struct {
	ResourceUsage *ResourceUsage
	Tasks         map[string]*TaskResourceUsage
	Timestamp     int64
}

// RestartPolicy defines how the Nomad client restarts
// tasks in a taskgroup when they fail
type RestartPolicy struct {
	Interval time.Duration
	Attempts int
	Delay    time.Duration
	Mode     string
}

// The ServiceCheck data model represents the consul health check that
// Nomad registers for a Task
type ServiceCheck struct {
	Id        string
	Name      string
	Type      string
	Command   string
	Args      []string
	Path      string
	Protocol  string `mapstructure:"port"`
	PortLabel string `mapstructure:"port"`
	Interval  time.Duration
	Timeout   time.Duration
}

// The Service model represents a Consul service definition
type Service struct {
	Id        string
	Name      string
	Tags      []string
	PortLabel string `mapstructure:"port"`
	Checks    []ServiceCheck
}

// TaskGroup is the unit of scheduling.
type TaskGroup struct {
	Name          string
	Count         int
	Constraints   []*Constraint
	Tasks         []*Task
	RestartPolicy *RestartPolicy
	Meta          map[string]string
}

// NewTaskGroup creates a new TaskGroup.
func NewTaskGroup(name string, count int) *TaskGroup {
	return &TaskGroup{
		Name:  name,
		Count: count,
	}
}

// Constrain is used to add a constraint to a task group.
func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
	g.Constraints = append(g.Constraints, c)
	return g
}

// AddMeta is used to add a meta k/v pair to a task group
func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
	if g.Meta == nil {
		g.Meta = make(map[string]string)
	}
	g.Meta[key] = val
	return g
}

// AddTask is used to add a new task to a task group.
func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
	g.Tasks = append(g.Tasks, t)
	return g
}

// LogConfig provides configuration for log rotation
type LogConfig struct {
	MaxFiles      int
	MaxFileSizeMB int
}

// Task is a single process in a task group.
type Task struct {
	Name        string
	Driver      string
	User        string
	Config      map[string]interface{}
	Constraints []*Constraint
	Env         map[string]string
	Services    []Service
	Resources   *Resources
	Meta        map[string]string
	KillTimeout time.Duration
	LogConfig   *LogConfig
	Artifacts   []*TaskArtifact
	Vault       *Vault
}

// TaskArtifact is used to download artifacts before running a task.
type TaskArtifact struct {
	GetterSource  string
	GetterOptions map[string]string
	RelativeDest  string
}

type Vault struct {
	Policies []string
}

// NewTask creates and initializes a new Task.
func NewTask(name, driver string) *Task {
	return &Task{
		Name:   name,
		Driver: driver,
	}
}

// Configure is used to configure a single k/v pair on
// the task.
func (t *Task) SetConfig(key string, val interface{}) *Task {
	if t.Config == nil {
		t.Config = make(map[string]interface{})
	}
	t.Config[key] = val
	return t
}

// SetMeta is used to add metadata k/v pairs to the task.
func (t *Task) SetMeta(key, val string) *Task {
	if t.Meta == nil {
		t.Meta = make(map[string]string)
	}
	t.Meta[key] = val
	return t
}

// Require is used to add resource requirements to a task.
func (t *Task) Require(r *Resources) *Task {
	t.Resources = r
	return t
}

// Constraint adds a new constraints to a single task.
func (t *Task) Constrain(c *Constraint) *Task {
	t.Constraints = append(t.Constraints, c)
	return t
}

// SetLogConfig sets a log config to a task
func (t *Task) SetLogConfig(l *LogConfig) *Task {
	t.LogConfig = l
	return t
}

// TaskState tracks the current state of a task and events that caused state
// transitions.
type TaskState struct {
	State  string
	Events []*TaskEvent
}

const (
	TaskDriverFailure          = "Driver Failure"
	TaskReceived               = "Received"
	TaskFailedValidation       = "Failed Validation"
	TaskStarted                = "Started"
	TaskTerminated             = "Terminated"
	TaskKilling                = "Killing"
	TaskKilled                 = "Killed"
	TaskRestarting             = "Restarting"
	TaskNotRestarting          = "Not Restarting"
	TaskDownloadingArtifacts   = "Downloading Artifacts"
	TaskArtifactDownloadFailed = "Failed Artifact Download"
	TaskDiskExceeded           = "Disk Exceeded"
)

// TaskEvent is an event that effects the state of a task and contains meta-data
// appropriate to the events type.
type TaskEvent struct {
	Type            string
	Time            int64
	RestartReason   string
	DriverError     string
	ExitCode        int
	Signal          int
	Message         string
	KillTimeout     time.Duration
	KillError       string
	StartDelay      int64
	DownloadError   string
	ValidationError string
}
<commit_msg>api/tasks.go: add check initial_status<commit_after>package api

import (
	"time"
)

// MemoryStats holds memory usage related stats
type MemoryStats struct {
	RSS            uint64
	Cache          uint64
	Swap           uint64
	MaxUsage       uint64
	KernelUsage    uint64
	KernelMaxUsage uint64
	Measured       []string
}

// CpuStats holds cpu usage related stats
type CpuStats struct {
	SystemMode       float64
	UserMode         float64
	TotalTicks       float64
	ThrottledPeriods uint64
	ThrottledTime    uint64
	Percent          float64
	Measured         []string
}

// ResourceUsage holds information related to cpu and memory stats
type ResourceUsage struct {
	MemoryStats *MemoryStats
	CpuStats    *CpuStats
}

// TaskResourceUsage holds aggregated resource usage of all processes in a Task
// and the resource usage of the individual pids
type TaskResourceUsage struct {
	ResourceUsage *ResourceUsage
	Timestamp     int64
	Pids          map[string]*ResourceUsage
}

// AllocResourceUsage holds the aggregated task resource usage of the
// allocation.
type AllocResourceUsage struct {
	ResourceUsage *ResourceUsage
	Tasks         map[string]*TaskResourceUsage
	Timestamp     int64
}

// RestartPolicy defines how the Nomad client restarts
// tasks in a taskgroup when they fail
type RestartPolicy struct {
	Interval time.Duration
	Attempts int
	Delay    time.Duration
	Mode     string
}

// The ServiceCheck data model represents the consul health check that
// Nomad registers for a Task
type ServiceCheck struct {
	Id            string
	Name          string
	Type          string
	Command       string
	Args          []string
	Path          string
	Protocol      string `mapstructure:"port"`
	PortLabel     string `mapstructure:"port"`
	Interval      time.Duration
	Timeout       time.Duration
	InitialStatus string `mapstructure:"initial_status"`
}

// The Service model represents a Consul service definition
type Service struct {
	Id        string
	Name      string
	Tags      []string
	PortLabel string `mapstructure:"port"`
	Checks    []ServiceCheck
}

// TaskGroup is the unit of scheduling.
type TaskGroup struct {
	Name          string
	Count         int
	Constraints   []*Constraint
	Tasks         []*Task
	RestartPolicy *RestartPolicy
	Meta          map[string]string
}

// NewTaskGroup creates a new TaskGroup.
func NewTaskGroup(name string, count int) *TaskGroup {
	return &TaskGroup{
		Name:  name,
		Count: count,
	}
}

// Constrain is used to add a constraint to a task group.
func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
	g.Constraints = append(g.Constraints, c)
	return g
}

// AddMeta is used to add a meta k/v pair to a task group
func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
	if g.Meta == nil {
		g.Meta = make(map[string]string)
	}
	g.Meta[key] = val
	return g
}

// AddTask is used to add a new task to a task group.
func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
	g.Tasks = append(g.Tasks, t)
	return g
}

// LogConfig provides configuration for log rotation
type LogConfig struct {
	MaxFiles      int
	MaxFileSizeMB int
}

// Task is a single process in a task group.
type Task struct {
	Name        string
	Driver      string
	User        string
	Config      map[string]interface{}
	Constraints []*Constraint
	Env         map[string]string
	Services    []Service
	Resources   *Resources
	Meta        map[string]string
	KillTimeout time.Duration
	LogConfig   *LogConfig
	Artifacts   []*TaskArtifact
	Vault       *Vault
}

// TaskArtifact is used to download artifacts before running a task.
type TaskArtifact struct {
	GetterSource  string
	GetterOptions map[string]string
	RelativeDest  string
}

type Vault struct {
	Policies []string
}

// NewTask creates and initializes a new Task.
func NewTask(name, driver string) *Task {
	return &Task{
		Name:   name,
		Driver: driver,
	}
}

// Configure is used to configure a single k/v pair on
// the task.
func (t *Task) SetConfig(key string, val interface{}) *Task {
	if t.Config == nil {
		t.Config = make(map[string]interface{})
	}
	t.Config[key] = val
	return t
}

// SetMeta is used to add metadata k/v pairs to the task.
func (t *Task) SetMeta(key, val string) *Task {
	if t.Meta == nil {
		t.Meta = make(map[string]string)
	}
	t.Meta[key] = val
	return t
}

// Require is used to add resource requirements to a task.
func (t *Task) Require(r *Resources) *Task {
	t.Resources = r
	return t
}

// Constraint adds a new constraints to a single task.
func (t *Task) Constrain(c *Constraint) *Task {
	t.Constraints = append(t.Constraints, c)
	return t
}

// SetLogConfig sets a log config to a task
func (t *Task) SetLogConfig(l *LogConfig) *Task {
	t.LogConfig = l
	return t
}

// TaskState tracks the current state of a task and events that caused state
// transitions.
type TaskState struct {
	State  string
	Events []*TaskEvent
}

const (
	TaskDriverFailure          = "Driver Failure"
	TaskReceived               = "Received"
	TaskFailedValidation       = "Failed Validation"
	TaskStarted                = "Started"
	TaskTerminated             = "Terminated"
	TaskKilling                = "Killing"
	TaskKilled                 = "Killed"
	TaskRestarting             = "Restarting"
	TaskNotRestarting          = "Not Restarting"
	TaskDownloadingArtifacts   = "Downloading Artifacts"
	TaskArtifactDownloadFailed = "Failed Artifact Download"
	TaskDiskExceeded           = "Disk Exceeded"
)

// TaskEvent is an event that effects the state of a task and contains meta-data
// appropriate to the events type.
type TaskEvent struct {
	Type            string
	Time            int64
	RestartReason   string
	DriverError     string
	ExitCode        int
	Signal          int
	Message         string
	KillTimeout     time.Duration
	KillError       string
	StartDelay      int64
	DownloadError   string
	ValidationError string
}
<|endoftext|>


<commit_before>package cloudflare

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/pkg/errors"
)

// APIToken is the full API token.
type APIToken struct {
	ID         string             `json:"id,omitempty"`
	Name       string             `json:"name"`
	Status     string             `json:"status,omitempty"`
	IssuedOn   *time.Time         `json:"issued_on,omitempty"`
	ModifiedOn *time.Time         `json:"modified_on,omitempty"`
	NotBefore  *time.Time         `json:"not_before,omitempty"`
	ExpiresOn  *time.Time         `json:"expires_on,omitempty"`
	Policies   []APITokenPolicies `json:"policies"`
	Condition  *APITokenCondition `json:"condition,omitempty"`
	Value      string             `json:"value,omitempty"`
}

// APITokenPermissionGroups is the permission groups associated with API tokens.
type APITokenPermissionGroups struct {
	ID     string   `json:"id"`
	Name   string   `json:"name,omitempty"`
	Scopes []string `json:"scopes,omitempty"`
}

// APITokenPolicies are policies attached to an API token.
type APITokenPolicies struct {
	ID               string                     `json:"id,omitempty"`
	Effect           string                     `json:"effect"`
	Resources        map[string]interface{}     `json:"resources"`
	PermissionGroups []APITokenPermissionGroups `json:"permission_groups"`
}

// APITokenRequestIPCondition is the struct for adding an IP restriction to an
// API token.
type APITokenRequestIPCondition struct {
	In    []string `json:"in,omitempty"`
	NotIn []string `json:"not_in,omitempty"`
}

// APITokenCondition is the outer structure for request conditions (currently
// only IPs).
type APITokenCondition struct {
	RequestIP *APITokenRequestIPCondition `json:"request.ip,omitempty"`
}

// APITokenResponse is the API response for a single API token.
type APITokenResponse struct {
	Response
	Result APIToken `json:"result"`
}

// APITokenListResponse is the API response for multiple API tokens.
type APITokenListResponse struct {
	Response
	Result []APIToken `json:"result"`
}

// APITokenRollResponse is the API response when rolling the token.
type APITokenRollResponse struct {
	Response
	Result string `json:"result"`
}

// APITokenVerifyResponse is the API response for verifying a token.
type APITokenVerifyResponse struct {
	Response
	Result APITokenVerifyBody `json:"result"`
}

// APITokenPermissionGroupsResponse is the API response for the available
// permission groups.
type APITokenPermissionGroupsResponse struct {
	Response
	Result []APITokenPermissionGroups `json:"result"`
}

// APITokenVerifyBody is the API body for verifying a token.
type APITokenVerifyBody struct {
	ID        string    `json:"id"`
	Status    string    `json:"status"`
	NotBefore time.Time `json:"not_before"`
	ExpiresOn time.Time `json:"expires_on"`
}

// GetAPIToken returns a single API token based on the ID.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-token-details
func (api *API) GetAPIToken(ctx context.Context, tokenID string) (APIToken, error) {
	uri := fmt.Sprintf("/user/tokens/%s", tokenID)

	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
	if err != nil {
		return APIToken{}, err
	}

	var apiTokenResponse APITokenResponse
	err = json.Unmarshal(res, &apiTokenResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenResponse.Result, nil
}

// APITokens returns all available API tokens.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-list-tokens
func (api *API) APITokens(ctx context.Context) ([]APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens", nil)
	if err != nil {
		return []APIToken{}, err
	}

	var apiTokenListResponse APITokenListResponse
	err = json.Unmarshal(res, &apiTokenListResponse)
	if err != nil {
		return []APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenListResponse.Result, nil
}

// CreateAPIToken creates a new token. Returns the API token that has been
// generated.
//
// The token value itself is only shown once (post create) and will present as
// `Value` from this method. If you fail to capture it at this point, you will
// need to roll the token in order to get a new value.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-create-token
func (api *API) CreateAPIToken(ctx context.Context, token APIToken) (APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodPost, "/user/tokens", token)
	if err != nil {
		return APIToken{}, err
	}

	var createTokenAPIResponse APITokenResponse
	err = json.Unmarshal(res, &createTokenAPIResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return createTokenAPIResponse.Result, nil
}

// UpdateAPIToken updates an existing API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-update-token
func (api *API) UpdateAPIToken(ctx context.Context, tokenID string, token APIToken) (APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodPut, "/user/tokens/"+tokenID, token)
	if err != nil {
		return APIToken{}, err
	}

	var updatedTokenResponse APITokenResponse
	err = json.Unmarshal(res, &updatedTokenResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return updatedTokenResponse.Result, nil
}

// RollAPIToken rolls the credential associated with the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-roll-token
func (api *API) RollAPIToken(ctx context.Context, tokenID string) (string, error) {
	uri := fmt.Sprintf("/user/tokens/%s/value", tokenID)

	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, nil)
	if err != nil {
		return "", err
	}

	var apiTokenRollResponse APITokenRollResponse
	err = json.Unmarshal(res, &apiTokenRollResponse)
	if err != nil {
		return "", errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenRollResponse.Result, nil
}

// VerifyAPIToken tests the validity of the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-verify-token
func (api *API) VerifyAPIToken(ctx context.Context) (APITokenVerifyBody, error) {
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/verify", nil)
	if err != nil {
		return APITokenVerifyBody{}, err
	}

	var apiTokenVerifyResponse APITokenVerifyResponse
	err = json.Unmarshal(res, &apiTokenVerifyResponse)
	if err != nil {
		return APITokenVerifyBody{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenVerifyResponse.Result, nil
}

// DeleteAPIToken deletes a single API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-delete-token
func (api *API) DeleteAPIToken(ctx context.Context, tokenID string) error {
	_, err := api.makeRequestContext(ctx, http.MethodDelete, "/user/tokens/"+tokenID, nil)
	if err != nil {
		return err
	}

	return nil
}

// ListAPITokensPermissionGroups returns all available API token permission groups.
//
// API reference: https://api.cloudflare.com/#permission-groups-list-permission-groups
func (api *API) ListAPITokensPermissionGroups(ctx context.Context) ([]APITokenPermissionGroups, error) {
	var r APITokenPermissionGroupsResponse
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/permission_groups", nil)
	if err != nil {
		return []APITokenPermissionGroups{}, err
	}

	err = json.Unmarshal(res, &r)
	if err != nil {
		return []APITokenPermissionGroups{}, errors.Wrap(err, errUnmarshalError)
	}

	return r.Result, nil
}
<commit_msg>add 'omitempty' to APIToken 'name' and 'policies' fields<commit_after>package cloudflare

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/pkg/errors"
)

// APIToken is the full API token.
type APIToken struct {
	ID         string             `json:"id,omitempty"`
	Name       string             `json:"name,omitempty"`
	Status     string             `json:"status,omitempty"`
	IssuedOn   *time.Time         `json:"issued_on,omitempty"`
	ModifiedOn *time.Time         `json:"modified_on,omitempty"`
	NotBefore  *time.Time         `json:"not_before,omitempty"`
	ExpiresOn  *time.Time         `json:"expires_on,omitempty"`
	Policies   []APITokenPolicies `json:"policies,omitempty"`
	Condition  *APITokenCondition `json:"condition,omitempty"`
	Value      string             `json:"value,omitempty"`
}

// APITokenPermissionGroups is the permission groups associated with API tokens.
type APITokenPermissionGroups struct {
	ID     string   `json:"id"`
	Name   string   `json:"name,omitempty"`
	Scopes []string `json:"scopes,omitempty"`
}

// APITokenPolicies are policies attached to an API token.
type APITokenPolicies struct {
	ID               string                     `json:"id,omitempty"`
	Effect           string                     `json:"effect"`
	Resources        map[string]interface{}     `json:"resources"`
	PermissionGroups []APITokenPermissionGroups `json:"permission_groups"`
}

// APITokenRequestIPCondition is the struct for adding an IP restriction to an
// API token.
type APITokenRequestIPCondition struct {
	In    []string `json:"in,omitempty"`
	NotIn []string `json:"not_in,omitempty"`
}

// APITokenCondition is the outer structure for request conditions (currently
// only IPs).
type APITokenCondition struct {
	RequestIP *APITokenRequestIPCondition `json:"request.ip,omitempty"`
}

// APITokenResponse is the API response for a single API token.
type APITokenResponse struct {
	Response
	Result APIToken `json:"result"`
}

// APITokenListResponse is the API response for multiple API tokens.
type APITokenListResponse struct {
	Response
	Result []APIToken `json:"result"`
}

// APITokenRollResponse is the API response when rolling the token.
type APITokenRollResponse struct {
	Response
	Result string `json:"result"`
}

// APITokenVerifyResponse is the API response for verifying a token.
type APITokenVerifyResponse struct {
	Response
	Result APITokenVerifyBody `json:"result"`
}

// APITokenPermissionGroupsResponse is the API response for the available
// permission groups.
type APITokenPermissionGroupsResponse struct {
	Response
	Result []APITokenPermissionGroups `json:"result"`
}

// APITokenVerifyBody is the API body for verifying a token.
type APITokenVerifyBody struct {
	ID        string    `json:"id"`
	Status    string    `json:"status"`
	NotBefore time.Time `json:"not_before"`
	ExpiresOn time.Time `json:"expires_on"`
}

// GetAPIToken returns a single API token based on the ID.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-token-details
func (api *API) GetAPIToken(ctx context.Context, tokenID string) (APIToken, error) {
	uri := fmt.Sprintf("/user/tokens/%s", tokenID)

	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
	if err != nil {
		return APIToken{}, err
	}

	var apiTokenResponse APITokenResponse
	err = json.Unmarshal(res, &apiTokenResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenResponse.Result, nil
}

// APITokens returns all available API tokens.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-list-tokens
func (api *API) APITokens(ctx context.Context) ([]APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens", nil)
	if err != nil {
		return []APIToken{}, err
	}

	var apiTokenListResponse APITokenListResponse
	err = json.Unmarshal(res, &apiTokenListResponse)
	if err != nil {
		return []APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenListResponse.Result, nil
}

// CreateAPIToken creates a new token. Returns the API token that has been
// generated.
//
// The token value itself is only shown once (post create) and will present as
// `Value` from this method. If you fail to capture it at this point, you will
// need to roll the token in order to get a new value.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-create-token
func (api *API) CreateAPIToken(ctx context.Context, token APIToken) (APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodPost, "/user/tokens", token)
	if err != nil {
		return APIToken{}, err
	}

	var createTokenAPIResponse APITokenResponse
	err = json.Unmarshal(res, &createTokenAPIResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return createTokenAPIResponse.Result, nil
}

// UpdateAPIToken updates an existing API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-update-token
func (api *API) UpdateAPIToken(ctx context.Context, tokenID string, token APIToken) (APIToken, error) {
	res, err := api.makeRequestContext(ctx, http.MethodPut, "/user/tokens/"+tokenID, token)
	if err != nil {
		return APIToken{}, err
	}

	var updatedTokenResponse APITokenResponse
	err = json.Unmarshal(res, &updatedTokenResponse)
	if err != nil {
		return APIToken{}, errors.Wrap(err, errUnmarshalError)
	}

	return updatedTokenResponse.Result, nil
}

// RollAPIToken rolls the credential associated with the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-roll-token
func (api *API) RollAPIToken(ctx context.Context, tokenID string) (string, error) {
	uri := fmt.Sprintf("/user/tokens/%s/value", tokenID)

	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, nil)
	if err != nil {
		return "", err
	}

	var apiTokenRollResponse APITokenRollResponse
	err = json.Unmarshal(res, &apiTokenRollResponse)
	if err != nil {
		return "", errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenRollResponse.Result, nil
}

// VerifyAPIToken tests the validity of the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-verify-token
func (api *API) VerifyAPIToken(ctx context.Context) (APITokenVerifyBody, error) {
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/verify", nil)
	if err != nil {
		return APITokenVerifyBody{}, err
	}

	var apiTokenVerifyResponse APITokenVerifyResponse
	err = json.Unmarshal(res, &apiTokenVerifyResponse)
	if err != nil {
		return APITokenVerifyBody{}, errors.Wrap(err, errUnmarshalError)
	}

	return apiTokenVerifyResponse.Result, nil
}

// DeleteAPIToken deletes a single API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-delete-token
func (api *API) DeleteAPIToken(ctx context.Context, tokenID string) error {
	_, err := api.makeRequestContext(ctx, http.MethodDelete, "/user/tokens/"+tokenID, nil)
	if err != nil {
		return err
	}

	return nil
}

// ListAPITokensPermissionGroups returns all available API token permission groups.
//
// API reference: https://api.cloudflare.com/#permission-groups-list-permission-groups
func (api *API) ListAPITokensPermissionGroups(ctx context.Context) ([]APITokenPermissionGroups, error) {
	var r APITokenPermissionGroupsResponse
	res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/permission_groups", nil)
	if err != nil {
		return []APITokenPermissionGroups{}, err
	}

	err = json.Unmarshal(res, &r)
	if err != nil {
		return []APITokenPermissionGroups{}, errors.Wrap(err, errUnmarshalError)
	}

	return r.Result, nil
}
<|endoftext|>


<commit_before>// Test APP
package main

import (
	"log"
	"net/http"
)

func adminList(w http.ResponseWriter, r *http.Request, s []string) {
	p := Page{
		Config:   conf,
		Title:    "Admin interface",
		Articles: data.Articles,
	}
	err := tmpl.ExecuteTemplate(w, "admin.tmpl", p)
	if err != nil {
		log.Fatal(err)
	}
}

func adminSlug(w http.ResponseWriter, r *http.Request, s []string) {
	var p Page

	a, err := data.Articles.Find(s[0])
	if err != nil {
		p = Page{
			Config: conf,
			Error:  err,
		}
	} else {
		p = Page{
			Config:  conf,
			Title:   a.Title,
			Article: a,
		}
	}

	err = tmpl.ExecuteTemplate(w, "admin.tmpl", p)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>cleanup<commit_after>package main

import (
	"log"
	"net/http"
)

func adminList(w http.ResponseWriter, r *http.Request, s []string) {
	p := Page{
		Config:   conf,
		Title:    "Admin interface",
		Articles: data.Articles,
	}
	err := tmpl.ExecuteTemplate(w, "admin.tmpl", p)
	if err != nil {
		log.Fatal(err)
	}
}

func adminSlug(w http.ResponseWriter, r *http.Request, s []string) {
	var p Page

	a, err := data.Articles.Find(s[0])
	if err != nil {
		p = Page{
			Config: conf,
			Error:  err,
		}
	} else {
		p = Page{
			Config:  conf,
			Title:   a.Title,
			Article: a,
		}
	}

	err = tmpl.ExecuteTemplate(w, "admin.tmpl", p)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Package jest provides a minimal wrapper to net/http for building JSON in/out
// API's. Jest assumes all routes require authorization unless stated otherwise
// and conveniences such as secure response headers and `OPTIONS` responses.
// Jest also respects routes declared on net/http directly.
//
//  package main
//
//  import (
//    "encoding/json"
//    "github.com/daneharrigan/jest"
//    "net/http"
//  )
//
//  func main() {
//    jest.Auth(handleAuth)
//    jest.Get("/", serveIndex)
//    http.ListenAndServe(":5000", jest.Handler())
//  }
//
//  func handleAuth(w http.ResponseWriter, r *http.Request) *jest.Status {
//    if loggedIn() {
//      return jest.OK
//    }
//
//    return jest.Forbidden
//  }
//
//  func serveIndex(w http.ResponseWriter, r *http.Request) *jest.Status {
//    json.NewEncoder(w).Encode(getItems())
//    return jest.OK
//  }
package jest

import (
	"encoding/json"
	"github.com/kr/secureheader"
	"net/http"
	"os"
	"regexp"
	"strings"
)

var (
	config      *secureheader.Config
	routes      []route
	authorize   func(http.ResponseWriter, *http.Request) *Status
	contentType string
)

func init() {
	contentType = "application/json"
	config = secureheader.DefaultConfig
	http.HandleFunc("/", serveResponses)
}

/* public */

// Handler returns an http handler for http.ListenAndServe. The handler is
// provided by github.com/kr/secureheader and decorates HTTP response with
// a series of secure header information.
func Handler() *secureheader.Config {
	config.HTTPSRedirect = os.Getenv("JEST_HTTPS") != "false"
	return config
}

// Auth accepts a method for granting/denying access to protected routes.
// Returning a jest.Status struct is used to determine whether authorization
// should be allowed or denied.
func Auth(fn func(http.ResponseWriter, *http.Request) *Status) {
	authorize = fn
}

func Get(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("GET", uri, f)
}

func Post(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("POST", uri, f)
}

func Put(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PUT", uri, f)
}

func Patch(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PATCH", uri, f)
}

func Delete(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("DELETE", uri, f)
}

/* private */

func request(m, u string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	rs := &response{fn: fn}
	for _, r := range routes {
		if r.URI == u {
			r.Responses[m] = rs
			return rs
		}
	}

	v := "([a-zA-Z0-9_-]+)"
	rx := regexp.MustCompile(":" + v)
	r := route{
		URI:       u,
		Responses: make(map[string]*response),
	}

	mr := regexp.MustCompile("^" + rx.ReplaceAllString(u, v) + "$")
	pr := regexp.MustCompile("^" + rx.ReplaceAllString(u, ":"+v) + "$")

	r.Responses[m] = rs
	r.URIMatcher = mr
	r.ParamMatcher = pr

	routes = append(routes, r)
	return rs
}

func serveResponses(ow http.ResponseWriter, r *http.Request) {
	w := &responseWriter{rw: ow}
	w.Header().Set("Content-Type", contentType)
	defer r.Body.Close()

	header := r.Header.Get("Content-Type")
	if header != "" && header != contentType {
		write(w, BadRequest)
		return
	}

	for _, route := range routes {
		if !route.URIMatcher.MatchString(r.URL.Path) {
			continue
		}

		m, mOK := route.Responses[r.Method]
		switch {
		default:
			write(w, MethodNotAllowed)
			return
		case r.Method == "OPTIONS":
			var methods []string
			for m, _ := range route.Responses {
				methods = append(methods, m)
			}

			methods = append(methods, "OPTIONS")

			w.Header().Set("Content-Length", "0")
			w.Header().Set("Allow", strings.Join(methods, ", "))
			return
		case mOK:
			if !m.public {
				if authorize == nil {
					write(w, Forbidden)
					return
				}

				s := authorize(w, r)
				if s != nil && (s.Code < 200 || s.Code > 299) {
					write(w, s)
					return
				}
			}

			write(w, m.fn(w, r))
			return
		}
	}

	write(w, NotFound)
}

func write(w *responseWriter, s *Status) {
	if s == nil {
		s = OK
	}

	if !w.written {
		if !w.writtenHeader {
			w.WriteHeader(s.Code)
		}

		if s != NoContent {
			json.NewEncoder(w).Encode(s)
		}
	}
}
<commit_msg>read HTTP and JEST_HTTPS<commit_after>// Package jest provides a minimal wrapper to net/http for building JSON in/out
// API's. Jest assumes all routes require authorization unless stated otherwise
// and conveniences such as secure response headers and `OPTIONS` responses.
// Jest also respects routes declared on net/http directly.
//
//  package main
//
//  import (
//    "encoding/json"
//    "github.com/daneharrigan/jest"
//    "net/http"
//  )
//
//  func main() {
//    jest.Auth(handleAuth)
//    jest.Get("/", serveIndex)
//    http.ListenAndServe(":5000", jest.Handler())
//  }
//
//  func handleAuth(w http.ResponseWriter, r *http.Request) *jest.Status {
//    if loggedIn() {
//      return jest.OK
//    }
//
//    return jest.Forbidden
//  }
//
//  func serveIndex(w http.ResponseWriter, r *http.Request) *jest.Status {
//    json.NewEncoder(w).Encode(getItems())
//    return jest.OK
//  }
package jest

import (
	"encoding/json"
	"github.com/kr/secureheader"
	"net/http"
	"os"
	"regexp"
	"strings"
)

var (
	config      *secureheader.Config
	routes      []route
	authorize   func(http.ResponseWriter, *http.Request) *Status
	contentType string
)

func init() {
	contentType = "application/json"
	config = secureheader.DefaultConfig
	http.HandleFunc("/", serveResponses)
}

/* public */

// Handler returns an http handler for http.ListenAndServe. The handler is
// provided by github.com/kr/secureheader and decorates HTTP response with
// a series of secure header information.
func Handler() *secureheader.Config {
	https := os.Getenv("HTTPS")
	if https == "" {
		https = os.Getenv("JEST_HTTPS")
	}

	config.HTTPSRedirect = https != "false"
	return config
}

// Auth accepts a method for granting/denying access to protected routes.
// Returning a jest.Status struct is used to determine whether authorization
// should be allowed or denied.
func Auth(fn func(http.ResponseWriter, *http.Request) *Status) {
	authorize = fn
}

func Get(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("GET", uri, f)
}

func Post(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("POST", uri, f)
}

func Put(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PUT", uri, f)
}

func Patch(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("PATCH", uri, f)
}

func Delete(uri string, f func(http.ResponseWriter, *http.Request) *Status) *response {
	return request("DELETE", uri, f)
}

/* private */

func request(m, u string, fn func(http.ResponseWriter, *http.Request) *Status) *response {
	rs := &response{fn: fn}
	for _, r := range routes {
		if r.URI == u {
			r.Responses[m] = rs
			return rs
		}
	}

	v := "([a-zA-Z0-9_-]+)"
	rx := regexp.MustCompile(":" + v)
	r := route{
		URI:       u,
		Responses: make(map[string]*response),
	}

	mr := regexp.MustCompile("^" + rx.ReplaceAllString(u, v) + "$")
	pr := regexp.MustCompile("^" + rx.ReplaceAllString(u, ":"+v) + "$")

	r.Responses[m] = rs
	r.URIMatcher = mr
	r.ParamMatcher = pr

	routes = append(routes, r)
	return rs
}

func serveResponses(ow http.ResponseWriter, r *http.Request) {
	w := &responseWriter{rw: ow}
	w.Header().Set("Content-Type", contentType)
	defer r.Body.Close()

	header := r.Header.Get("Content-Type")
	if header != "" && header != contentType {
		write(w, BadRequest)
		return
	}

	for _, route := range routes {
		if !route.URIMatcher.MatchString(r.URL.Path) {
			continue
		}

		m, mOK := route.Responses[r.Method]
		switch {
		default:
			write(w, MethodNotAllowed)
			return
		case r.Method == "OPTIONS":
			var methods []string
			for m, _ := range route.Responses {
				methods = append(methods, m)
			}

			methods = append(methods, "OPTIONS")

			w.Header().Set("Content-Length", "0")
			w.Header().Set("Allow", strings.Join(methods, ", "))
			return
		case mOK:
			if !m.public {
				if authorize == nil {
					write(w, Forbidden)
					return
				}

				s := authorize(w, r)
				if s != nil && (s.Code < 200 || s.Code > 299) {
					write(w, s)
					return
				}
			}

			write(w, m.fn(w, r))
			return
		}
	}

	write(w, NotFound)
}

func write(w *responseWriter, s *Status) {
	if s == nil {
		s = OK
	}

	if !w.written {
		if !w.writtenHeader {
			w.WriteHeader(s.Code)
		}

		if s != NoContent {
			json.NewEncoder(w).Encode(s)
		}
	}
}
<|endoftext|>


<commit_before>//
// Copyright 2017, Arkbriar
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package gitlab

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"time"
)

// JobsService handles communication with the ci builds related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
type JobsService struct {
	client *Client
}

// Job represents a ci build.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
type Job struct {
	Commit        *Commit    `json:"commit"`
	CreatedAt     *time.Time `json:"created_at"`
	Coverage      float64    `json:"coverage"`
	ArtifactsFile struct {
		Filename string `json:"filename"`
		Size     int    `json:"size"`
	} `json:"artifacts_file"`
	FinishedAt *time.Time `json:"finished_at"`
	ID         int        `json:"id"`
	Name       string     `json:"name"`
	Ref        string     `json:"ref"`
	Runner     struct {
		ID          int    `json:"id"`
		Description string `json:"description"`
		Active      bool   `json:"active"`
		IsShared    bool   `json:"is_shared"`
		Name        string `json:"name"`
	} `json:"runner"`
	Stage     string     `json:"stage"`
	StartedAt *time.Time `json:"started_at"`
	Status    string     `json:"status"`
	Tag       bool       `json:"tag"`
	User      *User      `json:"user"`
	WebURL    string     `json:"web_url"`
}

// ListJobsOptions are options for two list apis
type ListJobsOptions struct {
	ListOptions
	Scope []BuildStateValue `url:"scope,omitempty" json:"scope,omitempty"`
}

// ListProjectJobs gets a list of jobs in a project.
//
// The scope of jobs to show, one or array of: created, pending, running,
// failed, success, canceled, skipped; showing all jobs if none provided
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs
func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	var jobs []Job
	resp, err := s.client.Do(req, &jobs)
	if err != nil {
		return nil, resp, err
	}

	return jobs, resp, err
}

// ListPipelineJobs gets a list of jobs for specific pipeline in a
// project. If the pipeline ID is not found, it will respond with 404.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs
func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", url.QueryEscape(project), pipelineID)

	req, err := s.client.NewRequest("GET", u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	var jobs []*Job
	resp, err := s.client.Do(req, &jobs)
	if err != nil {
		return nil, resp, err
	}

	return jobs, resp, err
}

// GetJob gets a single job of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job
func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// GetJobArtifacts get jobs artifacts of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts
func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactsBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactsBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactsBuf, resp, err
}

// DownloadArtifactsFile download the artifacts file from the given
// reference name and job provided the job finished successfully.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job string, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download?job=%s", url.QueryEscape(project), refName, job)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactsBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactsBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactsBuf, resp, err
}

// DownloadSingleArtifactsFile download a file from the artifacts from the
// given reference name and job provided the job finished successfully.
// Only a single file is going to be extracted from the archive and streamed
// to a client.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file
func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf(
		"projects/%s/jobs/%d/artifacts/%s",
		url.QueryEscape(project),
		jobID,
		artifactPath,
	)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactBuf, resp, err
}

// GetTraceFile gets a trace of a specific job of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file
func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/trace", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	traceBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, traceBuf)
	if err != nil {
		return nil, resp, err
	}

	return traceBuf, resp, err
}

// CancelJob cancels a single job of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job
func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/cancel", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// RetryJob retries a single job of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job
func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/retry", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// EraseJob erases a single job of a project, removes a job
// artifacts and a job trace.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job
func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/erase", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// KeepArtifacts prevents artifacts from being deleted when
// expiration is set.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts
func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// PlayJob triggers a manual action to start a job.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#play-a-job
func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/play", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}
<commit_msg>(jobs) support `pipeline` in jobs response<commit_after>//
// Copyright 2017, Arkbriar
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package gitlab

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"time"
)

// JobsService handles communication with the ci builds related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
type JobsService struct {
	client *Client
}

// Job represents a ci build.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
type Job struct {
	Commit        *Commit    `json:"commit"`
	CreatedAt     *time.Time `json:"created_at"`
	Coverage      float64    `json:"coverage"`
	ArtifactsFile struct {
		Filename string `json:"filename"`
		Size     int    `json:"size"`
	} `json:"artifacts_file"`
	FinishedAt *time.Time `json:"finished_at"`
	ID         int        `json:"id"`
	Name       string     `json:"name"`
	Pipeline   struct {
		ID     int    `json:"id"`
		Ref    string `json:"ref"`
		Sha    string `json:"sha"`
		Status string `json:"status"`
	} `json:"pipeline"`
	Ref    string `json:"ref"`
	Runner struct {
		ID          int    `json:"id"`
		Description string `json:"description"`
		Active      bool   `json:"active"`
		IsShared    bool   `json:"is_shared"`
		Name        string `json:"name"`
	} `json:"runner"`
	Stage     string     `json:"stage"`
	StartedAt *time.Time `json:"started_at"`
	Status    string     `json:"status"`
	Tag       bool       `json:"tag"`
	User      *User      `json:"user"`
	WebURL    string     `json:"web_url"`
}

// ListJobsOptions are options for two list apis
type ListJobsOptions struct {
	ListOptions
	Scope []BuildStateValue `url:"scope,omitempty" json:"scope,omitempty"`
}

// ListProjectJobs gets a list of jobs in a project.
//
// The scope of jobs to show, one or array of: created, pending, running,
// failed, success, canceled, skipped; showing all jobs if none provided
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs
func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	var jobs []Job
	resp, err := s.client.Do(req, &jobs)
	if err != nil {
		return nil, resp, err
	}

	return jobs, resp, err
}

// ListPipelineJobs gets a list of jobs for specific pipeline in a
// project. If the pipeline ID is not found, it will respond with 404.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs
func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", url.QueryEscape(project), pipelineID)

	req, err := s.client.NewRequest("GET", u, opts, options)
	if err != nil {
		return nil, nil, err
	}

	var jobs []*Job
	resp, err := s.client.Do(req, &jobs)
	if err != nil {
		return nil, resp, err
	}

	return jobs, resp, err
}

// GetJob gets a single job of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job
func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// GetJobArtifacts get jobs artifacts of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts
func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactsBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactsBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactsBuf, resp, err
}

// DownloadArtifactsFile download the artifacts file from the given
// reference name and job provided the job finished successfully.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job string, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download?job=%s", url.QueryEscape(project), refName, job)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactsBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactsBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactsBuf, resp, err
}

// DownloadSingleArtifactsFile download a file from the artifacts from the
// given reference name and job provided the job finished successfully.
// Only a single file is going to be extracted from the archive and streamed
// to a client.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file
func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf(
		"projects/%s/jobs/%d/artifacts/%s",
		url.QueryEscape(project),
		jobID,
		artifactPath,
	)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	artifactBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, artifactBuf)
	if err != nil {
		return nil, resp, err
	}

	return artifactBuf, resp, err
}

// GetTraceFile gets a trace of a specific job of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file
func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/trace", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	traceBuf := new(bytes.Buffer)
	resp, err := s.client.Do(req, traceBuf)
	if err != nil {
		return nil, resp, err
	}

	return traceBuf, resp, err
}

// CancelJob cancels a single job of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job
func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/cancel", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// RetryJob retries a single job of a project
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job
func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/retry", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// EraseJob erases a single job of a project, removes a job
// artifacts and a job trace.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job
func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/erase", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// KeepArtifacts prevents artifacts from being deleted when
// expiration is set.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts
func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}

// PlayJob triggers a manual action to start a job.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/jobs.html#play-a-job
func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/jobs/%d/play", url.QueryEscape(project), jobID)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	job := new(Job)
	resp, err := s.client.Do(req, job)
	if err != nil {
		return nil, resp, err
	}

	return job, resp, err
}
<|endoftext|>


<commit_before>package linear

import (
	"bytes"
	"fmt"
	"math"
	"strconv"

	"github.com/a-h/linear/tolerance"
)

// Line consists of a normal vector which specifies the direction, and a constant term.
// The basepoint is calculated by the NewLine function.
type Line struct {
	Basepoint    Vector
	NormalVector Vector
	ConstantTerm float64
}

// NewLine creates a new Line based on the variable terms, e.g.:
// Ax + By = C
// For example, for a 2D vector (2, 3) and constant 5 would result in 2x + 3y = 5
// The slope intercept (y = mx + b) form of that would be:
//  2x + 3y = 5
//       3y = 5 - 2x
//        y = 1/3(5-2x)
// To get back to standard form:
// To find the y intercept (a point on the line), set x to zero.
//  2x + 3y = 5
//       3y = 5 - 0
//        y = 5/3
//  y intercept = (0, 5/3)
// To find the x intercept, set y to zero.
//  2x + 3y = 5
//  2x - 0 = 5
//  2x = 5
//  x = 5/2
//   x intercept = (5/2, 0)
func NewLine(normalVector Vector, constantTerm float64) Line {
	basepointVector := make([]float64, len(normalVector))
	nonZeroIndex := firstNonZeroElement(normalVector)
	basepointVector[nonZeroIndex] = constantTerm / normalVector[nonZeroIndex]

	return Line{
		ConstantTerm: constantTerm,
		Basepoint:    basepointVector,
		NormalVector: normalVector,
	}
}

func firstNonZeroElement(v Vector) (index int) {
	for i := 0; i < len(v); i++ {
		if !tolerance.IsWithin(v[i], 0, DefaultTolerance) {
			return i
		}
	}

	return 0
}

func (l1 Line) String() string {
	buf := bytes.Buffer{}
	for i, p := range l1.NormalVector {
		if i == 0 {
			// The first element should have an integrated +/- sign.
			if !tolerance.IsWithin(p, 0.0, DefaultTolerance) {
				// If the value is not zero, write it out.
				buf.WriteString(fmt.Sprintf("%v", p))
			}
			// Write out the x_1 specifier.
			buf.WriteString(fmt.Sprintf("x%s", getSubscript(i+1)))
			continue
		}

		// For anything after index zero, the sign becomes the operator.
		buf.WriteString(operator(p))

		// Write out the absolute value if it's non-zero.
		if !tolerance.IsWithin(p, 0.0, DefaultTolerance) {
			buf.WriteString(fmt.Sprintf("%v", math.Abs(p)))
		}
		// Write out the x_1 specifier.
		buf.WriteString(fmt.Sprintf("x%s", getSubscript(i+1)))
	}
	// Write out the constant term.
	buf.WriteString(fmt.Sprintf(" = %v", l1.ConstantTerm))
	return buf.String()
}

func operator(v float64) string {
	if v < 0 {
		return " - "
	}
	return " + "
}

func getSubscript(i int) string {
	buf := bytes.Buffer{}
	str := strconv.Itoa(i)
	for _, v := range str {
		switch v {
		case '0':
			buf.WriteRune('₀')
		case '1':
			buf.WriteRune('₁')
		case '2':
			buf.WriteRune('₂')
		case '3':
			buf.WriteRune('₃')
		case '4':
			buf.WriteRune('₄')
		case '5':
			buf.WriteRune('₅')
		case '6':
			buf.WriteRune('₆')
		case '7':
			buf.WriteRune('₇')
		case '8':
			buf.WriteRune('₈')
		case '9':
			buf.WriteRune('₉')
		}
	}

	return buf.String()
}

// IsParallelTo determines whether two lines are parallel to each other.
func (l1 Line) IsParallelTo(l2 Line) (bool, error) {
	return l1.NormalVector.IsParallelTo(l2.NormalVector)
}

// Eq determines if two lines are equal.
func (l1 Line) Eq(l2 Line) (bool, error) {
	if l1.NormalVector.IsZeroVector() {
		if !l2.NormalVector.IsZeroVector() {
			return false, nil
		}
		// Check the constant terms are the same if both are zero vectors.
		return tolerance.IsWithin(l1.ConstantTerm, l2.ConstantTerm, DefaultTolerance), nil
	}

	// If they're not parallel, there's no way they're going to be equal.
	isParallel, err := l1.IsParallelTo(l2)
	if !isParallel || err != nil {
		return false, err
	}

	// Subtract a point on l2 from l1, which creates a vector between the two points.
	// The vector that joins the lines should be orthogonal to the normal vector, or it's not equal.
	// No need to capture the error here, because the error would be because the number of terms in the vector
	// is different, which is already captured by the parallel check.
	basepointDifference, _ := l1.Basepoint.Sub(l2.Basepoint)

	// No need to check orthogonality of both vectors, because they're parallel to each other.
	return basepointDifference.IsOrthogonalTo(l1.NormalVector)
}

// Y gets the Y value for a given X.
func (l1 Line) Y(x float64) float64 {
	// ax + by = c
	// by = c - ax
	// y = (c - ax) / b
	return (l1.ConstantTerm - (l1.NormalVector[0] * x)) / l1.NormalVector[1]
}

// X gets the X value for a given Y value.
func (l1 Line) X(y float64) float64 {
	// ax + by = c
	// ax = c - by
	// x = (c - by) / a
	return (l1.ConstantTerm - (l1.NormalVector[1] * y)) / l1.NormalVector[0]
}

// IntersectionWith calculates the intersection with another line.
// intersects is set to true if the lines intersect.
// equal is set to true if the lines are equal and therefore intersect infinitely many times.
func (l1 Line) IntersectionWith(l2 Line) (intersection Vector, intersects bool, equal bool, err error) {
	// Handle zero vector edge case.
	if l1.NormalVector.IsZeroVector() || l2.NormalVector.IsZeroVector() {
		return Vector{}, false, false, nil
	}

	// If the lines are equal, there are infinitely many intersections.
	eq, err := l1.Eq(l2)
	if err != nil {
		return Vector{}, false, false, err
	}
	if eq {
		return l1.Basepoint, true, true, nil
	}

	// If the lines are parallel but not equal, there will never be an intersection unless the lines are equal.
	// No need to catch the error, the Eq test above has already done the same.
	isParallel, _ := l1.IsParallelTo(l2)
	if isParallel {
		return Vector{}, false, false, nil
	}

	// Explanation at http://math.stackexchange.com/questions/48395/how-to-find-the-point-of-intersection-of-two-lines
	// And https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_the_equations_of_the_lines
	// At the point where the two lines intersect (if they do), both y coordinates will be the same, hence the following equality:
	// y=ax+c and y=bx+d
	// i.e. ax+c=bx+d

	a, b, c := l1.NormalVector[0], l1.NormalVector[1], l1.ConstantTerm
	d, e, f := l2.NormalVector[0], l2.NormalVector[1], l2.ConstantTerm

	// Given that x and y have the same value in each equation.
	// ax + by = c
	// dx + ey = f
	// Find the definition of y
	// by = c - ax
	// y = (c - ax)/b
	// Insert the reworked equation in to replace y in the 2nd equation and get the value of x
	// dx + ey = f
	// dx + e((c - ax)/b) = f
	// dx + ec/b - eax/b = f
	// dx - eax/b = f - ec/b
	// bdx - eax = bf - ec
	// x(bd - ea) = bf - ec
	// x = bf - ec / bd - ea
	x := ((b * f) - (e * c)) / ((b * d) - (e * a))
	y := (c - (a * x)) / b
	return NewVector(x, y), true, false, nil

	// Adapted from Udacity code. Passes the tests, but I haven't worked it out from first principles yet...
	/*
		a, b := l1.NormalVector[0], l1.NormalVector[1]
		c, d := l2.NormalVector[0], l2.NormalVector[1]
		f := l1.ConstantTerm
		g := l2.ConstantTerm

		xnum := d*f - b*g
		ynum := -c*f + a*g

		oneOver := float64(1.0) / (a*d - b*c)
		return NewVector(xnum, ynum).Scale(oneOver), true, false, nil
	*/
}
<commit_msg>Added more comments.<commit_after>package linear

import (
	"bytes"
	"fmt"
	"math"
	"strconv"

	"github.com/a-h/linear/tolerance"
)

// Line consists of a normal vector which specifies the direction, and a constant term.
// The basepoint is calculated by the NewLine function.
type Line struct {
	Basepoint    Vector
	NormalVector Vector
	ConstantTerm float64
}

// NewLine creates a new Line based on the variable terms, e.g.:
// Ax + By = C
// For example, for a 2D vector (2, 3) and constant 5 would result in 2x + 3y = 5
// The slope intercept (y = mx + b) form of that would be:
//  2x + 3y = 5
//       3y = 5 - 2x
//        y = 1/3(5-2x)
// To get back to standard form:
// To find the y intercept (a point on the line), set x to zero.
//  2x + 3y = 5
//       3y = 5 - 0
//        y = 5/3
//  y intercept = (0, 5/3)
// To find the x intercept, set y to zero.
//  2x + 3y = 5
//  2x - 0 = 5
//  2x = 5
//  x = 5/2
//   x intercept = (5/2, 0)
func NewLine(normalVector Vector, constantTerm float64) Line {
	basepointVector := make([]float64, len(normalVector))
	nonZeroIndex := firstNonZeroElement(normalVector)
	basepointVector[nonZeroIndex] = constantTerm / normalVector[nonZeroIndex]

	return Line{
		ConstantTerm: constantTerm,
		Basepoint:    basepointVector,
		NormalVector: normalVector,
	}
}

func firstNonZeroElement(v Vector) (index int) {
	for i := 0; i < len(v); i++ {
		if !tolerance.IsWithin(v[i], 0, DefaultTolerance) {
			return i
		}
	}

	return 0
}

func (l1 Line) String() string {
	buf := bytes.Buffer{}
	for i, p := range l1.NormalVector {
		if i == 0 {
			// The first element should have an integrated +/- sign.
			if !tolerance.IsWithin(p, 0.0, DefaultTolerance) {
				// If the value is not zero, write it out.
				buf.WriteString(fmt.Sprintf("%v", p))
			}
			// Write out the x_1 specifier.
			buf.WriteString(fmt.Sprintf("x%s", getSubscript(i+1)))
			continue
		}

		// For anything after index zero, the sign becomes the operator.
		buf.WriteString(operator(p))

		// Write out the absolute value if it's non-zero.
		if !tolerance.IsWithin(p, 0.0, DefaultTolerance) {
			buf.WriteString(fmt.Sprintf("%v", math.Abs(p)))
		}
		// Write out the x_1 specifier.
		buf.WriteString(fmt.Sprintf("x%s", getSubscript(i+1)))
	}
	// Write out the constant term.
	buf.WriteString(fmt.Sprintf(" = %v", l1.ConstantTerm))
	return buf.String()
}

func operator(v float64) string {
	if v < 0 {
		return " - "
	}
	return " + "
}

func getSubscript(i int) string {
	buf := bytes.Buffer{}
	str := strconv.Itoa(i)
	for _, v := range str {
		switch v {
		case '0':
			buf.WriteRune('₀')
		case '1':
			buf.WriteRune('₁')
		case '2':
			buf.WriteRune('₂')
		case '3':
			buf.WriteRune('₃')
		case '4':
			buf.WriteRune('₄')
		case '5':
			buf.WriteRune('₅')
		case '6':
			buf.WriteRune('₆')
		case '7':
			buf.WriteRune('₇')
		case '8':
			buf.WriteRune('₈')
		case '9':
			buf.WriteRune('₉')
		}
	}

	return buf.String()
}

// IsParallelTo determines whether two lines are parallel to each other.
func (l1 Line) IsParallelTo(l2 Line) (bool, error) {
	return l1.NormalVector.IsParallelTo(l2.NormalVector)
}

// Eq determines if two lines are equal.
func (l1 Line) Eq(l2 Line) (bool, error) {
	if l1.NormalVector.IsZeroVector() {
		if !l2.NormalVector.IsZeroVector() {
			return false, nil
		}
		// Check the constant terms are the same if both are zero vectors.
		return tolerance.IsWithin(l1.ConstantTerm, l2.ConstantTerm, DefaultTolerance), nil
	}

	// If they're not parallel, there's no way they're going to be equal.
	isParallel, err := l1.IsParallelTo(l2)
	if !isParallel || err != nil {
		return false, err
	}

	// Subtract a point on l2 from l1, which creates a vector between the two points.
	// The vector that joins the lines should be orthogonal to the normal vector, or it's not equal.
	// No need to capture the error here, because the error would be because the number of terms in the vector
	// is different, which is already captured by the parallel check.
	basepointDifference, _ := l1.Basepoint.Sub(l2.Basepoint)

	// No need to check orthogonality of both vectors, because they're parallel to each other.
	return basepointDifference.IsOrthogonalTo(l1.NormalVector)
}

// Y gets the Y value for a given X.
func (l1 Line) Y(x float64) float64 {
	// ax + by = c
	// by = c - ax
	// y = (c - ax) / b
	return (l1.ConstantTerm - (l1.NormalVector[0] * x)) / l1.NormalVector[1]
}

// X gets the X value for a given Y value.
func (l1 Line) X(y float64) float64 {
	// ax + by = c
	// ax = c - by
	// x = (c - by) / a
	return (l1.ConstantTerm - (l1.NormalVector[1] * y)) / l1.NormalVector[0]
}

// IntersectionWith calculates the intersection with another line.
// intersects is set to true if the lines intersect.
// equal is set to true if the lines are equal and therefore intersect infinitely many times.
func (l1 Line) IntersectionWith(l2 Line) (intersection Vector, intersects bool, equal bool, err error) {
	// Handle zero vector edge case.
	if l1.NormalVector.IsZeroVector() || l2.NormalVector.IsZeroVector() {
		return Vector{}, false, false, nil
	}

	// If the lines are equal, there are infinitely many intersections.
	eq, err := l1.Eq(l2)
	if err != nil {
		return Vector{}, false, false, err
	}
	if eq {
		return l1.Basepoint, true, true, nil
	}

	// If the lines are parallel but not equal, there will never be an intersection unless the lines are equal.
	// No need to catch the error, the Eq test above has already done the same.
	isParallel, _ := l1.IsParallelTo(l2)
	if isParallel {
		return Vector{}, false, false, nil
	}

	// Explanation at http://math.stackexchange.com/questions/48395/how-to-find-the-point-of-intersection-of-two-lines
	// And https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_the_equations_of_the_lines
	// At the point where the two lines intersect (if they do), both y coordinates will be the same, hence the following equality:
	// y=ax+c and y=bx+d
	// i.e. ax+c=bx+d

	a, b, c := l1.NormalVector[0], l1.NormalVector[1], l1.ConstantTerm
	d, e, f := l2.NormalVector[0], l2.NormalVector[1], l2.ConstantTerm

	// Given that x and y have the same value in each equation.
	// ax + by = c
	// dx + ey = f
	// Find the definition of y
	// by = c - ax
	// y = (c - ax)/b (use later to calculate the y value once we have the value of x)
	// Insert the reworked equation in to replace y in the 2nd equation and get the value of x
	// dx + ey = f
	// dx + e((c - ax)/b) = f
	// dx + ec/b - eax/b = f
	// dx - eax/b = f - ec/b
	// bdx - eax = bf - ec
	// x(bd - ea) = bf - ec
	// x = bf - ec / bd - ea
	x := ((b * f) - (e * c)) / ((b * d) - (e * a))
	y := (c - (a * x)) / b
	return NewVector(x, y), true, false, nil

	// Adapted from Udacity code. Passes the tests, but I haven't worked it out from first principles yet...
	/*
		a, b := l1.NormalVector[0], l1.NormalVector[1]
		c, d := l2.NormalVector[0], l2.NormalVector[1]
		f := l1.ConstantTerm
		g := l2.ConstantTerm

		xnum := d*f - b*g
		ynum := -c*f + a*g

		oneOver := float64(1.0) / (a*d - b*c)
		return NewVector(xnum, ynum).Scale(oneOver), true, false, nil
	*/
}
<|endoftext|>


<commit_before>package crazyradio

import (
	"fmt"

	"github.com/kylelemons/gousb/usb"
)

const (
	Vendor  = 0x1915
	Product = 0x7777
)

type DeviceInfo interface {
	Bus() int
	Address() int
	MajorVer() int
	MinorVer() int
	String() string
}

// ListDevices returns the list of attached CrazyRadio devices.
func ListDevices() ([]DeviceInfo, error) {
	ctx := usb.NewContext()
	defer ctx.Close()

	var d []DeviceInfo
	_, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
		if desc.Vendor == Vendor && desc.Product == Product {
			d = append(d, deviceInfo{*desc})
		}
		return false
	})
	if err != nil {
		return nil, err
	}
	return d, nil
}

type deviceInfo struct {
	desc usb.Descriptor
}

func (d deviceInfo) Bus() int      { return int(d.desc.Bus) }
func (d deviceInfo) Address() int  { return int(d.desc.Address) }
func (d deviceInfo) MajorVer() int { return int((d.desc.Device >> 8) & 0xFF) }
func (d deviceInfo) MinorVer() int { return int(d.desc.Device & 0xFF) }
func (d deviceInfo) String() string {
	return fmt.Sprintf("CrazyRadio-Bus:%d-Address:%d-v%02x.%02x",
		d.Bus(), d.Address(), d.MajorVer, d.MinorVer)
}
<commit_msg>Fix deviceInfo.String: major and minor versions are functions and must be called<commit_after>package crazyradio

import (
	"fmt"

	"github.com/kylelemons/gousb/usb"
)

const (
	Vendor  = 0x1915
	Product = 0x7777
)

type DeviceInfo interface {
	Bus() int
	Address() int
	MajorVer() int
	MinorVer() int
	String() string
}

// ListDevices returns the list of attached CrazyRadio devices.
func ListDevices() ([]DeviceInfo, error) {
	ctx := usb.NewContext()
	defer ctx.Close()

	var d []DeviceInfo
	_, err := ctx.ListDevices(func(desc *usb.Descriptor) bool {
		if desc.Vendor == Vendor && desc.Product == Product {
			d = append(d, deviceInfo{*desc})
		}
		return false
	})
	if err != nil {
		return nil, err
	}
	return d, nil
}

type deviceInfo struct {
	desc usb.Descriptor
}

func (d deviceInfo) Bus() int      { return int(d.desc.Bus) }
func (d deviceInfo) Address() int  { return int(d.desc.Address) }
func (d deviceInfo) MajorVer() int { return int((d.desc.Device >> 8) & 0xFF) }
func (d deviceInfo) MinorVer() int { return int(d.desc.Device & 0xFF) }
func (d deviceInfo) String() string {
	return fmt.Sprintf("CrazyRadio-Bus:%d-Address:%d-v%02x.%02x",
		d.Bus(), d.Address(), d.MajorVer(), d.MinorVer())
}
<|endoftext|>