<commit_before>package jsval

import (
	"errors"
	"reflect"
	"regexp"

	"github.com/lestrrat/go-pdebug"
)

type getPropValuer interface {
	// Given a JSON property name, return the actual field value
	GetPropValue(string) (interface{}, error)
}

type getPropNameser interface {
	// Given a lst of JSON property names
	GetPropNames() ([]string, error)
}

// Object creates a new ObjectConstraint
func Object() *ObjectConstraint {
	return &ObjectConstraint{
		additionalProperties: nil,
		minProperties:        -1,
		maxProperties:        -1,
		patternProperties:    make(map[*regexp.Regexp]Constraint),
		properties:           make(map[string]Constraint),
		propdeps:             make(map[string][]string),
		required:             make(map[string]struct{}),
		schemadeps:           make(map[string]Constraint),
	}
}

// Required specifies required property names
func (o *ObjectConstraint) Required(l ...string) *ObjectConstraint {
	o.reqlock.Lock()
	defer o.reqlock.Unlock()

	for _, pname := range l {
		o.required[pname] = struct{}{}
	}
	return o
}

// IsPropRequired returns true if the given name is listed under
// the required properties
func (o *ObjectConstraint) IsPropRequired(s string) bool {
	o.reqlock.Lock()
	defer o.reqlock.Unlock()

	_, ok := o.required[s]
	return ok
}

// MinProperties specifies the minimum number of properties this
// constraint can allow. If unspecified, it is not checked.
func (o *ObjectConstraint) MinProperties(n int) *ObjectConstraint {
	o.minProperties = n
	return o
}

// MaxProperties specifies the maximum number of properties this
// constraint can allow. If unspecified, it is not checked.
func (o *ObjectConstraint) MaxProperties(n int) *ObjectConstraint {
	o.maxProperties = n
	return o
}

// AdditionalProperties specifies the constraint that additional
// properties should be validated against.
func (o *ObjectConstraint) AdditionalProperties(c Constraint) *ObjectConstraint {
	o.additionalProperties = c
	return o
}

// AddProp adds constraints for a named property.
func (o *ObjectConstraint) AddProp(name string, c Constraint) *ObjectConstraint {
	o.proplock.Lock()
	defer o.proplock.Unlock()

	o.properties[name] = c
	return o
}

// PatternProperties specifies constraints that properties matching
// this pattern must be validated against. Note that properties listed
// using `AddProp` takes precedence.
func (o *ObjectConstraint) PatternProperties(key *regexp.Regexp, c Constraint) *ObjectConstraint {
	o.proplock.Lock()
	defer o.proplock.Unlock()

	o.patternProperties[key] = c
	return o
}

// PatternPropertiesString is the same as PatternProperties, but takes
// a string representing a regular expression. If the regular expression
// cannot be compiled, a panic occurs.
func (o *ObjectConstraint) PatternPropertiesString(key string, c Constraint) *ObjectConstraint {
	rx := regexp.MustCompile(key)
	return o.PatternProperties(rx, c)
}

// PropDependency specifies properties that must be present when
// `from` is present.
func (o *ObjectConstraint) PropDependency(from string, to ...string) *ObjectConstraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	l := o.propdeps[from]
	l = append(l, to...)
	o.propdeps[from] = l
	return o
}

// SchemaDependency specifies a schema that the value being validated
// must also satisfy. Note that the "object" is the target that needs to
// be additionally validated, not the value of the `from` property
func (o *ObjectConstraint) SchemaDependency(from string, c Constraint) *ObjectConstraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	o.schemadeps[from] = c
	return o
}

// GetPropDependencies returns the list of property names that must
// be present for given property name `from`
func (o *ObjectConstraint) GetPropDependencies(from string) []string {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	l, ok := o.propdeps[from]
	if !ok {
		return nil
	}

	return l
}

// GetSchemaDependency returns the Constraint that must be used when
// the property `from` is present.
func (o *ObjectConstraint) GetSchemaDependency(from string) Constraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	c, ok := o.schemadeps[from]
	if !ok {
		return nil
	}

	return c
}

var structInfoRegistry = StructInfoRegistry{
	registry: make(map[reflect.Type]StructInfo),
}

// getProps return all of the property names for this object.
// XXX Map keys can be something other than strings, but
// we can't really allow it?
func (o *ObjectConstraint) getPropNames(rv reflect.Value) ([]string, error) {
	var keys []string
	switch rv.Kind() {
	case reflect.Map:
		vk := rv.MapKeys()
		keys = make([]string, len(vk))
		for i, v := range vk {
			if v.Kind() != reflect.String {
				return nil, errors.New("panic: can only handle maps with string keys")
			}
			keys[i] = v.String()
		}
	case reflect.Struct:
		if gpv, ok := rv.Interface().(getPropNameser); ok {
			pv, err := gpv.GetPropNames()
			if err == nil {
				return pv, nil
			}
		}

		si, ok := structInfoRegistry.Lookup(rv.Type())
		if !ok {
			si = structInfoRegistry.Register(rv.Type())
		}

		return si.PropNames(rv), nil
	default:
		return nil, errors.New("cannot get property names from this value (Kind: " + rv.Kind().String() + ")")
	}

	return keys, nil
}

type setPropValuer interface {
	SetPropValue(string, interface{}) error
}

var spvType = reflect.TypeOf((*setPropValuer)(nil)).Elem()

func (o *ObjectConstraint) setProp(rv reflect.Value, pname string, val interface{}) error {
	pdebug.Printf("setProp %s", pname)
	switch rv.Kind() {
	case reflect.Map:
		rv.SetMapIndex(reflect.ValueOf(pname), reflect.ValueOf(val))
		return nil
	case reflect.Struct:
		spvm := rv.MethodByName("SetPropValue")
		if spvm != zeroval {
			out := spvm.Call([]reflect.Value{reflect.ValueOf(pname), reflect.ValueOf(val)})
			if !out[0].IsNil() {
				return out[0].Interface().(error)
			}
			return nil
		}

		f := o.getProp(rv, pname)
		if f == zeroval {
			return errors.New("setProp: could not find field '" + pname + "'")
		}

		// Is this a Maybe value? If so, we should use its Set() method
		switch {
		case f.Type().Implements(maybeif):
			mv := f.MethodByName("Set")
			mv.Call([]reflect.Value{reflect.ValueOf(val)})
			return nil
		case f.CanAddr() && f.Addr().Type().Implements(maybeif):
			mv := f.Addr().MethodByName("Set")
			mv.Call([]reflect.Value{reflect.ValueOf(val)})
			return nil
		}

		f.Set(reflect.ValueOf(val))
		return nil
	default:
		return errors.New("setProp: don't know what to do with '" + rv.Kind().String() + "'")
	}
}

func (o *ObjectConstraint) getProp(rv reflect.Value, pname string) reflect.Value {
	switch rv.Kind() {
	case reflect.Map:
		pv := reflect.ValueOf(pname)
		return rv.MapIndex(pv)
	case reflect.Struct:
		// This guy knows how to grab the value, given a name. Use that
		if gpv, ok := rv.Interface().(getPropValuer); ok {
			pv, err := gpv.GetPropValue(pname)
			if err == nil {
				return reflect.ValueOf(pv)
			}
		}

		si, ok := structInfoRegistry.Lookup(rv.Type())
		if !ok {
			si = structInfoRegistry.Register(rv.Type())
		}

		fn, ok := si.FieldName(pname)
		if !ok {
			if pdebug.Enabled {
				pdebug.Printf("Could not resolve name '%s'", pname)
			}
			return zeroval
		}
		return rv.FieldByName(fn)
	default:
		return zeroval
	}
}

// Validate validates the given value against this ObjectConstraint
func (o *ObjectConstraint) Validate(v interface{}) (err error) {
	if pdebug.Enabled {
		g := pdebug.IPrintf("START ObjectConstraint.Validate")
		defer func() {
			if err == nil {
				g.IRelease("END ObjectConstraint.Validate (PASS)")
			} else {
				g.IRelease("END ObjectConstraint.Validate (FAIL): %s", err)
			}
		}()
	}

	rv := reflect.ValueOf(v)
	switch rv.Kind() {
	case reflect.Ptr, reflect.Interface:
		rv = rv.Elem()
	}

	fields, err := o.getPropNames(rv)
	if err != nil {
		return err
	}

	lf := len(fields)
	if o.minProperties > -1 && lf < o.minProperties {
		return errors.New("fewer properties than minProperties")
	}
	if o.maxProperties > -1 && lf > o.maxProperties {
		return errors.New("more properties than maxProperties")
	}

	// Find the list of field names that were passed to us
	// "premain" shows extra props, if any.
	// "pseen" shows props that we have already seen
	premain := map[string]struct{}{}
	pseen := map[string]struct{}{}
	for _, k := range fields {
		premain[k] = struct{}{}
	}

	// Now, for all known constraints, validate the prop
	// create a copy of properties so that we don't have to keep the lock
	propdefs := make(map[string]Constraint)
	o.proplock.Lock()
	for pname, c := range o.properties {
		propdefs[pname] = c
	}
	o.proplock.Unlock()

	for pname, c := range propdefs {
		if pdebug.Enabled {
			pdebug.Printf("Validating property '%s'", pname)
		}

		pval := o.getProp(rv, pname)
		propExists := false

		switch {
		case pval == zeroval:
			// If we got a zeroval, we're done for.
		case pval.Type().Implements(maybeif) || reflect.PtrTo(pval.Type()).Implements(maybeif):
			// If we have a Maybe value, we check the Valid() flag
			mv := pval.MethodByName("Valid")
			out := mv.Call(nil)
			if out[0].Bool() {
				propExists = true
				// Swap out pval to be the value pointed to by the Maybe value
				mv = pval.MethodByName("Value")
				out = mv.Call(nil)
				pval = out[0]
			}
		default:
			// Everything else, we have *something*
			propExists = true
		}

		if !propExists {
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' does not exist", pname)
			}

			if o.IsPropRequired(pname) { // required, and not present.
				return errors.New("object property '" + pname + "' is required")
			}

			// At this point we know that the property was not present
			// and that this field was indeed not required.
			if c.HasDefault() {
				if pdebug.Enabled {
					pdebug.Printf("object property '" + pname + "' has default")
				}
				// We have default
				dv := c.DefaultValue()
				if err := o.setProp(rv, pname, dv); err != nil {
					return errors.New("failed to set default value for property '" + pname + "': " + err.Error())
				}
				pval = reflect.ValueOf(dv)
			}

			continue
		}

		// delete from remaining props
		delete(premain, pname)
		// ...and add to props that we have seen
		pseen[pname] = struct{}{}

		if err := c.Validate(pval.Interface()); err != nil {
			return errors.New("object property '" + pname + "' validation failed: " + err.Error())
		}
	}

	for pat, c := range o.patternProperties {
		if pdebug.Enabled {
			pdebug.Printf("Checking patternProperty '%s'", pat.String())
		}
		for pname := range premain {
			if !pat.MatchString(pname) {
				if pdebug.Enabled {
					pdebug.Printf("Property '%s' does not match pattern...", pname)
				}
				continue
			}
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' matches!", pname)
			}
			// No need to check if this pname exists, as we're taking
			// this from "premain"
			pval := o.getProp(rv, pname)

			delete(premain, pname)
			pseen[pname] = struct{}{}
			if err := c.Validate(pval.Interface()); err != nil {
				return errors.New("object property '" + pname + "' validation failed: " + err.Error())
			}
		}
	}

	if len(premain) > 0 {
		c := o.additionalProperties
		if c == nil {
			return errors.New("additional properties are not allowed")
		}

		for pname := range premain {
			pval := o.getProp(rv, pname)
			if err := c.Validate(pval.Interface()); err != nil {
				return errors.New("object property for '" + pname + "' validation failed: " + err.Error())
			}
		}
	}

	for pname := range pseen {
		if deps := o.GetPropDependencies(pname); len(deps) > 0 {
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' has dependencies", pname)
			}
			for _, dep := range deps {
				if _, ok := pseen[dep]; !ok {
					return errors.New("required dependency '" + dep + "' is mising")
				}
			}

			// can't, and shouldn't do object validation after checking prop deps
			continue
		}

		if depc := o.GetSchemaDependency(pname); depc != nil {
			if err := depc.Validate(v); err != nil {
				return err
			}
		}
	}

	return nil
}
<commit_msg>coerce values into receiver's type, if possible<commit_after>package jsval

import (
	"errors"
	"reflect"
	"regexp"

	"github.com/lestrrat/go-pdebug"
)

type getPropValuer interface {
	// Given a JSON property name, return the actual field value
	GetPropValue(string) (interface{}, error)
}

type getPropNameser interface {
	// Given a lst of JSON property names
	GetPropNames() ([]string, error)
}

// Object creates a new ObjectConstraint
func Object() *ObjectConstraint {
	return &ObjectConstraint{
		additionalProperties: nil,
		minProperties:        -1,
		maxProperties:        -1,
		patternProperties:    make(map[*regexp.Regexp]Constraint),
		properties:           make(map[string]Constraint),
		propdeps:             make(map[string][]string),
		required:             make(map[string]struct{}),
		schemadeps:           make(map[string]Constraint),
	}
}

// Required specifies required property names
func (o *ObjectConstraint) Required(l ...string) *ObjectConstraint {
	o.reqlock.Lock()
	defer o.reqlock.Unlock()

	for _, pname := range l {
		o.required[pname] = struct{}{}
	}
	return o
}

// IsPropRequired returns true if the given name is listed under
// the required properties
func (o *ObjectConstraint) IsPropRequired(s string) bool {
	o.reqlock.Lock()
	defer o.reqlock.Unlock()

	_, ok := o.required[s]
	return ok
}

// MinProperties specifies the minimum number of properties this
// constraint can allow. If unspecified, it is not checked.
func (o *ObjectConstraint) MinProperties(n int) *ObjectConstraint {
	o.minProperties = n
	return o
}

// MaxProperties specifies the maximum number of properties this
// constraint can allow. If unspecified, it is not checked.
func (o *ObjectConstraint) MaxProperties(n int) *ObjectConstraint {
	o.maxProperties = n
	return o
}

// AdditionalProperties specifies the constraint that additional
// properties should be validated against.
func (o *ObjectConstraint) AdditionalProperties(c Constraint) *ObjectConstraint {
	o.additionalProperties = c
	return o
}

// AddProp adds constraints for a named property.
func (o *ObjectConstraint) AddProp(name string, c Constraint) *ObjectConstraint {
	o.proplock.Lock()
	defer o.proplock.Unlock()

	o.properties[name] = c
	return o
}

// PatternProperties specifies constraints that properties matching
// this pattern must be validated against. Note that properties listed
// using `AddProp` takes precedence.
func (o *ObjectConstraint) PatternProperties(key *regexp.Regexp, c Constraint) *ObjectConstraint {
	o.proplock.Lock()
	defer o.proplock.Unlock()

	o.patternProperties[key] = c
	return o
}

// PatternPropertiesString is the same as PatternProperties, but takes
// a string representing a regular expression. If the regular expression
// cannot be compiled, a panic occurs.
func (o *ObjectConstraint) PatternPropertiesString(key string, c Constraint) *ObjectConstraint {
	rx := regexp.MustCompile(key)
	return o.PatternProperties(rx, c)
}

// PropDependency specifies properties that must be present when
// `from` is present.
func (o *ObjectConstraint) PropDependency(from string, to ...string) *ObjectConstraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	l := o.propdeps[from]
	l = append(l, to...)
	o.propdeps[from] = l
	return o
}

// SchemaDependency specifies a schema that the value being validated
// must also satisfy. Note that the "object" is the target that needs to
// be additionally validated, not the value of the `from` property
func (o *ObjectConstraint) SchemaDependency(from string, c Constraint) *ObjectConstraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	o.schemadeps[from] = c
	return o
}

// GetPropDependencies returns the list of property names that must
// be present for given property name `from`
func (o *ObjectConstraint) GetPropDependencies(from string) []string {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	l, ok := o.propdeps[from]
	if !ok {
		return nil
	}

	return l
}

// GetSchemaDependency returns the Constraint that must be used when
// the property `from` is present.
func (o *ObjectConstraint) GetSchemaDependency(from string) Constraint {
	o.deplock.Lock()
	defer o.deplock.Unlock()

	c, ok := o.schemadeps[from]
	if !ok {
		return nil
	}

	return c
}

var structInfoRegistry = StructInfoRegistry{
	registry: make(map[reflect.Type]StructInfo),
}

// getProps return all of the property names for this object.
// XXX Map keys can be something other than strings, but
// we can't really allow it?
func (o *ObjectConstraint) getPropNames(rv reflect.Value) ([]string, error) {
	var keys []string
	switch rv.Kind() {
	case reflect.Map:
		vk := rv.MapKeys()
		keys = make([]string, len(vk))
		for i, v := range vk {
			if v.Kind() != reflect.String {
				return nil, errors.New("panic: can only handle maps with string keys")
			}
			keys[i] = v.String()
		}
	case reflect.Struct:
		if gpv, ok := rv.Interface().(getPropNameser); ok {
			pv, err := gpv.GetPropNames()
			if err == nil {
				return pv, nil
			}
		}

		si, ok := structInfoRegistry.Lookup(rv.Type())
		if !ok {
			si = structInfoRegistry.Register(rv.Type())
		}

		return si.PropNames(rv), nil
	default:
		return nil, errors.New("cannot get property names from this value (Kind: " + rv.Kind().String() + ")")
	}

	return keys, nil
}

var (
	maybefloatT = reflect.TypeOf(MaybeFloat{})
	maybeintT = reflect.TypeOf(MaybeInt{})
	intT = reflect.TypeOf(int64(0))
	floatT = reflect.TypeOf(float64(0))
)

func coerceValue(v interface{}, t reflect.Type) reflect.Value {
	vv := reflect.ValueOf(v)
	switch vv.Kind() {
	case reflect.Interface:
		vv = vv.Elem()
	}

	// For known Maybe types, we should do our best, too
	switch {
	case t == maybefloatT:
		t = floatT
	case t == maybeintT:
		t = intT
	}

	if vv.Type().ConvertibleTo(t) {
		return vv.Convert(t)
	}
	return vv
}

type setPropValuer interface {
	SetPropValue(string, interface{}) error
}

var spvType = reflect.TypeOf((*setPropValuer)(nil)).Elem()

func (o *ObjectConstraint) setProp(rv reflect.Value, pname string, val interface{}) error {
	switch rv.Kind() {
	case reflect.Map:
		rv.SetMapIndex(reflect.ValueOf(pname), reflect.ValueOf(val))
		return nil
	case reflect.Struct:
		spvm := rv.MethodByName("SetPropValue")
		if spvm != zeroval {
			out := spvm.Call([]reflect.Value{reflect.ValueOf(pname), reflect.ValueOf(val)})
			if !out[0].IsNil() {
				return out[0].Interface().(error)
			}
			return nil
		}

		f := o.getProp(rv, pname)
		if f == zeroval {
			return errors.New("setProp: could not find field '" + pname + "'")
		}

		// Usability: If you specify `Default(10)` on an int64 value,
		// it doesn't work. But these values are compatible. We should
		// do our best to align them
		dv := coerceValue(val, f.Type())

		// Is this a Maybe value? If so, we should use its Set() method
		var mv reflect.Value
		switch {
		case f.Type().Implements(maybeif):
			mv = f.MethodByName("Set")
		case f.CanAddr() && f.Addr().Type().Implements(maybeif):
			mv = f.Addr().MethodByName("Set")
		}

		if mv != zeroval {
			out := mv.Call([]reflect.Value{dv})
			if !out[0].IsNil() {
				return out[0].Interface().(error)
			}
			return nil
		}
		f.Set(dv)
		return nil
	default:
		return errors.New("setProp: don't know what to do with '" + rv.Kind().String() + "'")
	}
}

func (o *ObjectConstraint) getProp(rv reflect.Value, pname string) reflect.Value {
	switch rv.Kind() {
	case reflect.Map:
		pv := reflect.ValueOf(pname)
		return rv.MapIndex(pv)
	case reflect.Struct:
		// This guy knows how to grab the value, given a name. Use that
		if gpv, ok := rv.Interface().(getPropValuer); ok {
			pv, err := gpv.GetPropValue(pname)
			if err == nil {
				return reflect.ValueOf(pv)
			}
		}

		si, ok := structInfoRegistry.Lookup(rv.Type())
		if !ok {
			si = structInfoRegistry.Register(rv.Type())
		}

		fn, ok := si.FieldName(pname)
		if !ok {
			if pdebug.Enabled {
				pdebug.Printf("Could not resolve name '%s'", pname)
			}
			return zeroval
		}
		return rv.FieldByName(fn)
	default:
		return zeroval
	}
}

// Validate validates the given value against this ObjectConstraint
func (o *ObjectConstraint) Validate(v interface{}) (err error) {
	if pdebug.Enabled {
		g := pdebug.IPrintf("START ObjectConstraint.Validate")
		defer func() {
			if err == nil {
				g.IRelease("END ObjectConstraint.Validate (PASS)")
			} else {
				g.IRelease("END ObjectConstraint.Validate (FAIL): %s", err)
			}
		}()
	}

	rv := reflect.ValueOf(v)
	switch rv.Kind() {
	case reflect.Ptr, reflect.Interface:
		rv = rv.Elem()
	}

	fields, err := o.getPropNames(rv)
	if err != nil {
		return err
	}

	lf := len(fields)
	if o.minProperties > -1 && lf < o.minProperties {
		return errors.New("fewer properties than minProperties")
	}
	if o.maxProperties > -1 && lf > o.maxProperties {
		return errors.New("more properties than maxProperties")
	}

	// Find the list of field names that were passed to us
	// "premain" shows extra props, if any.
	// "pseen" shows props that we have already seen
	premain := map[string]struct{}{}
	pseen := map[string]struct{}{}
	for _, k := range fields {
		premain[k] = struct{}{}
	}

	// Now, for all known constraints, validate the prop
	// create a copy of properties so that we don't have to keep the lock
	propdefs := make(map[string]Constraint)
	o.proplock.Lock()
	for pname, c := range o.properties {
		propdefs[pname] = c
	}
	o.proplock.Unlock()

	for pname, c := range propdefs {
		if pdebug.Enabled {
			pdebug.Printf("Validating property '%s'", pname)
		}

		pval := o.getProp(rv, pname)
		propExists := false

		switch {
		case pval == zeroval:
			// If we got a zeroval, we're done for.
		case pval.Type().Implements(maybeif) || reflect.PtrTo(pval.Type()).Implements(maybeif):
			// If we have a Maybe value, we check the Valid() flag
			mv := pval.MethodByName("Valid")
			out := mv.Call(nil)
			if out[0].Bool() {
				propExists = true
				// Swap out pval to be the value pointed to by the Maybe value
				mv = pval.MethodByName("Value")
				out = mv.Call(nil)
				pval = out[0]
			}
		default:
			// Everything else, we have *something*
			propExists = true
		}

		if !propExists {
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' does not exist", pname)
			}

			if o.IsPropRequired(pname) { // required, and not present.
				return errors.New("object property '" + pname + "' is required")
			}

			// At this point we know that the property was not present
			// and that this field was indeed not required.
			if c.HasDefault() {
				if pdebug.Enabled {
					pdebug.Printf("object property '" + pname + "' has default")
				}
				// We have default
				dv := c.DefaultValue()

				if err := o.setProp(rv, pname, dv); err != nil {
					return errors.New("failed to set default value for property '" + pname + "': " + err.Error())
				}
				pval = reflect.ValueOf(dv)
			}

			continue
		}

		// delete from remaining props
		delete(premain, pname)
		// ...and add to props that we have seen
		pseen[pname] = struct{}{}

		if err := c.Validate(pval.Interface()); err != nil {
			return errors.New("object property '" + pname + "' validation failed: " + err.Error())
		}
	}

	for pat, c := range o.patternProperties {
		if pdebug.Enabled {
			pdebug.Printf("Checking patternProperty '%s'", pat.String())
		}
		for pname := range premain {
			if !pat.MatchString(pname) {
				if pdebug.Enabled {
					pdebug.Printf("Property '%s' does not match pattern...", pname)
				}
				continue
			}
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' matches!", pname)
			}
			// No need to check if this pname exists, as we're taking
			// this from "premain"
			pval := o.getProp(rv, pname)

			delete(premain, pname)
			pseen[pname] = struct{}{}
			if err := c.Validate(pval.Interface()); err != nil {
				return errors.New("object property '" + pname + "' validation failed: " + err.Error())
			}
		}
	}

	if len(premain) > 0 {
		c := o.additionalProperties
		if c == nil {
			return errors.New("additional properties are not allowed")
		}

		for pname := range premain {
			pval := o.getProp(rv, pname)
			if err := c.Validate(pval.Interface()); err != nil {
				return errors.New("object property for '" + pname + "' validation failed: " + err.Error())
			}
		}
	}

	for pname := range pseen {
		if deps := o.GetPropDependencies(pname); len(deps) > 0 {
			if pdebug.Enabled {
				pdebug.Printf("Property '%s' has dependencies", pname)
			}
			for _, dep := range deps {
				if _, ok := pseen[dep]; !ok {
					return errors.New("required dependency '" + dep + "' is mising")
				}
			}

			// can't, and shouldn't do object validation after checking prop deps
			continue
		}

		if depc := o.GetSchemaDependency(pname); depc != nil {
			if err := depc.Validate(v); err != nil {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Package colonycore define the struct that needed by other package in colony
package colonycore

import (
	/*"github.com/eaciit/errorlib"
		// "github.com/eaciit/orm/v1"
		// "log"
		"mime/multipart"
		"strconv"
		"strings"
	    "github.com/eaciit/toolkit"
	*/
	"time"

	"github.com/eaciit/orm/v1"
	tk "github.com/eaciit/toolkit"
)

const (
/*ACTION_TYPE_HIVE     = "HIVE"
ACTION_TYPE_HDFS     = "HDFS"
ACTION_TYPE_SPARK    = "SPARK"
ACTION_TYPE_DECISION = "DECISION"
ACTION_TYPE_SSH      = "SSH"
ACTION_TYPE_KAFKA    = "KAFKA"

FORK_TYPE_ALL       = "ALL"
FORK_TYPE_ONE       = "ONE"
FORK_TYPE_MANDATORY = "MANDATORY"

SSH_OPERATION_MKDIR = "MKDIR"*/
// SSH_OPERATION_* please define
)

// DataFlow to define the flow name and description
// and also have the list of the actions inside the flow
// Actions list of action, the content of the action can be FlowAction or "list of FlowAction" -> for fork action
type DataFlow struct {
	orm.ModelBase
	ID           string       `json:"_id",bson:"_id"`
	Name         string       `json:"name"`
	Description  string       `json:"description"`
	CreatedDate  time.Time    `json:"createddate"`
	LastModified time.Time    `json:"lastmodified"`
	CreatedBy    string       `json:"createdby"`
	Actions      []FlowAction `json:"actions"`
	DataShapes   tk.M         `json:"datashapes"`
	GlobalParam  tk.M         `json:"globalparam"`
	Percentage   int          `json:"pct"`
}

func (c *DataFlow) TableName() string {
	return "dataflow"
}

func (c *DataFlow) RecordID() interface{} {
	return c.ID
}

/*// ActionBridge, to define the input and output of the previous action and next action
// PrevAction, ID of the previouse action
// NextAction, ID of the next action
// MappingParam, define the output and input paremeter name of the previous and next action
//      e.g.:
//              OUTPUT                INPUT
//              "id"                : "id"
//              "name"              : "name"
//              "address"           : "note"
//              "tag"               : "global.tag"
//              "global.address"    : "address"
type Bridge struct {
	Id           string
	Type         string
	PrevAction   string
	NextAction   string
	MappingParam tk.M
}*/

// FlowAction define the action that exist
// Type refer to cons ACTION_TYPE_*
// Action define the type of action e.g. Spark, HDFS, etc
// Server define which server for the action
// OK next step to go if the result is OK
// KO next step to go if the result is KO or NOT OK or ERROR
// Retry how many time the system will do the process if ERROR happen and then go to KO condition, default will be 3
// Wait interval in minute, default will be 1
// InputParam, will be the list of input that needed by the action
// OutputParam, will be the list of output from the action
// OutputType, will be the type of the output (text, json, *sv, xml)
// OutputPath, path of the output in the hdfs if empty then consider as stdout
type FlowAction struct {
	Id          string      `json:"_id"`
	Name        string      `json:"name"`
	Description string      `json:"description"`
	Type        string      `json:"type"`
	Server      Server      `json:"server"`
	Action      interface{} `json:"action"`
	OK          []string    `json:"ok"`
	KO          []string    `json:"ko"`
	Retry       int         `json:"retry"`
	Interval    int         `json:"interval"`
	FirstAction bool        `json:"firstaction"`
	InputParam  tk.M        `json:"inputparam"`
	OutputParam tk.M        `json:"outputparam"`
	OutputType  string      `json:"outputtype"`
	OutputPath  string      `json:"outputtype"`
}

// ActionHive action for HIVE
// ScriptPath path of the hive script to run
type ActionHive struct {
	ScriptPath string   `json:"scrippath"`
	Params     []string `json:"params"`
}

// ActionHDFS action for HDFS type for server
// Operation type operation
// The HDFS connection will be provided by the server from FlowAction
// Path can be used for the current path, or old path, also can included the filename
// NewPath can be used for move, copy, etc
// Permission e.g. rwx-r--r-
type ActionHDFS struct {
	/*Operation  string `json:"operation"`
	Path       string `json:"path"`
	NewPath    string `json:"newpath"`
	Permission string
	User       string
	Group      string*/
	Command string `json:"command"`
}

// ActionSSH action for SSH type of server
// Operation type operation
// The ssh connection will be provided by the server from FlowAction
// Path can be used for the current path, or old path, also can included the filename
// NewPath can be used for move, copy, etc
// Permission e.g. rwx-r--r-
type ActionSSH struct {
	Command string `json:"command"`
}

// ActionSpark action for SPARK
// Type of the code upload e.g. Java, Scala
// Mode e.g. client, cluster
// Args for other arguments, e.g. --executor-memory 2G
// Application the spark code will be mantain as application
type ActionSpark struct {
	Type      string `json:"type"`
	Master    string `json:"master"`
	Mode      string `json:"node"`
	File      string `json:"file"`
	MainClass string `json:"mainclass"`
	Args      string `json:"args"`
	// AppName   string
	// Args      []string
}

// ActionSpark action for Application
// Type e.g. Java, Scala, GO
// Application refer to application page
// when creating the action with type = application then should follow the application screen standard
type ActionApplication struct {
	Type        string      `json: "type"`
	Application Application `json:"application"`
}

// ActionHadoopStreaming for hadoop streaming
// Mapper name
// Reducer name
// Input can be folder or file
// Output folder
// Files list of file inside the hdfs
// the server type should be hdfs
type ActionHadoopStreaming struct {
	Jar     string   `json:"jar"`
	Mapper  string   `json:"mapper"`
	Reducer string   `json:"reducer"`
	Input   string   `json:"input"`
	Output  string   `json:"output"`
	Files   []string `json:"files"`
	// Params  []string
	Params string `json:"params"`
}

// ActionKafka action for KAFKA
type ActionKafka struct {
	// other field will be different for each action type
}

/*
Doesn't need the Queestion, can be achived by using OK and KO or using decision
type ActionQuestion struct {
	Question string `json:"question"`
	Yes      string `json:"yes"`
	No       string `json:"no"`
	// other field will be different for each action type
}*/

// ActionDecision action to define the list of decision that action have
type ActionDecision struct {
	Conditions []Condition `json:"conditions"`
	IsFork     bool        `json:"isfork"`
	// other field will be different for each action type
}

// Condition condition for the action decision
type Condition struct {
	Stat       string `json:"stat"`
	FlowAction string `json:"flowaction"`
}

type ActionStop struct {
	Message string `json:"message"`
}

type ActionShellScript struct {
	Script string `json:"script"`
}

type ActionJavaApp struct {
	Jar string `json:"jar"`
}

type ActionEmail struct {
	To      string `json:"to"`
	Cc      string `json:"cc"`
	Subject string `json:"subject"`
	Body    string `json:"body"`
}

// ActionFork to define the forking condition
// Type refer to cons FORK_TYPE_*
type ActionFork struct {
	Actions []FlowAction `json:"actions"`
	Type    string       `json: "type"`
}

// status, running - success - error
// steps should be the list of the action(FlowAction) that have been run
type DataFlowProcess struct {
	orm.ModelBase
	Id          string        `json:"_id"`
	Flow        DataFlow      `json:"flow"`
	Steps       []interface{} `json:"steps"`
	StartDate   time.Time     `json:"startdate"`
	EndDate     time.Time     `json:"enddate"`
	StartedBy   string        `json:"startedby"`
	GlobalParam tk.M          `json:"globalparam"`
	Status      string        `json:"status"`
	Percentage  int           `json:"pct"`
}

func (c *DataFlowProcess) TableName() string {
	return "dataflowprocess"
}

func (c *DataFlowProcess) RecordID() interface{} {
	return c.Id
}
<commit_msg>finds function<commit_after>// Package colonycore define the struct that needed by other package in colony
package colonycore

import (
	/*"github.com/eaciit/errorlib"
		// "github.com/eaciit/orm/v1"
		// "log"
		"mime/multipart"
		"strconv"
		"strings"
	    "github.com/eaciit/toolkit"
	*/
	"time"

	"github.com/eaciit/orm/v1"
	tk "github.com/eaciit/toolkit"
)

const (
/*ACTION_TYPE_HIVE     = "HIVE"
ACTION_TYPE_HDFS     = "HDFS"
ACTION_TYPE_SPARK    = "SPARK"
ACTION_TYPE_DECISION = "DECISION"
ACTION_TYPE_SSH      = "SSH"
ACTION_TYPE_KAFKA    = "KAFKA"

FORK_TYPE_ALL       = "ALL"
FORK_TYPE_ONE       = "ONE"
FORK_TYPE_MANDATORY = "MANDATORY"

SSH_OPERATION_MKDIR = "MKDIR"*/
// SSH_OPERATION_* please define
)

// DataFlow to define the flow name and description
// and also have the list of the actions inside the flow
// Actions list of action, the content of the action can be FlowAction or "list of FlowAction" -> for fork action
type DataFlow struct {
	orm.ModelBase
	ID           string       `json:"_id",bson:"_id"`
	Name         string       `json:"name"`
	Description  string       `json:"description"`
	CreatedDate  time.Time    `json:"createddate"`
	LastModified time.Time    `json:"lastmodified"`
	CreatedBy    string       `json:"createdby"`
	Actions      []FlowAction `json:"actions"`
	DataShapes   tk.M         `json:"datashapes"`
	GlobalParam  tk.M         `json:"globalparam"`
}

func (c *DataFlow) TableName() string {
	return "dataflow"
}

func (c *DataFlow) RecordID() interface{} {
	return c.ID
}

/*// ActionBridge, to define the input and output of the previous action and next action
// PrevAction, ID of the previouse action
// NextAction, ID of the next action
// MappingParam, define the output and input paremeter name of the previous and next action
//      e.g.:
//              OUTPUT                INPUT
//              "id"                : "id"
//              "name"              : "name"
//              "address"           : "note"
//              "tag"               : "global.tag"
//              "global.address"    : "address"
type Bridge struct {
	Id           string
	Type         string
	PrevAction   string
	NextAction   string
	MappingParam tk.M
}*/

// FlowAction define the action that exist
// Type refer to cons ACTION_TYPE_*
// Action define the type of action e.g. Spark, HDFS, etc
// Server define which server for the action
// OK next step to go if the result is OK
// KO next step to go if the result is KO or NOT OK or ERROR
// Retry how many time the system will do the process if ERROR happen and then go to KO condition, default will be 3
// Wait interval in minute, default will be 1
// InputParam, will be the list of input that needed by the action
// OutputParam, will be the list of output from the action
// OutputType, will be the type of the output (text, json, *sv, xml)
// OutputPath, path of the output in the hdfs if empty then consider as stdout
type FlowAction struct {
	Id          string      `json:"_id"`
	Name        string      `json:"name"`
	Description string      `json:"description"`
	Type        string      `json:"type"`
	Server      Server      `json:"server"`
	Action      interface{} `json:"action"`
	OK          []string    `json:"ok"`
	KO          []string    `json:"ko"`
	Retry       int         `json:"retry"`
	Interval    int         `json:"interval"`
	FirstAction bool        `json:"firstaction"`
	InputParam  tk.M        `json:"inputparam"`
	OutputParam tk.M        `json:"outputparam"`
	OutputType  string      `json:"outputtype"`
	OutputPath  string      `json:"outputtype"`
}

// ActionHive action for HIVE
// ScriptPath path of the hive script to run
type ActionHive struct {
	ScriptPath string   `json:"scrippath"`
	Params     []string `json:"params"`
}

// ActionHDFS action for HDFS type for server
// Operation type operation
// The HDFS connection will be provided by the server from FlowAction
// Path can be used for the current path, or old path, also can included the filename
// NewPath can be used for move, copy, etc
// Permission e.g. rwx-r--r-
type ActionHDFS struct {
	/*Operation  string `json:"operation"`
	Path       string `json:"path"`
	NewPath    string `json:"newpath"`
	Permission string
	User       string
	Group      string*/
	Command string `json:"command"`
}

// ActionSSH action for SSH type of server
// Operation type operation
// The ssh connection will be provided by the server from FlowAction
// Path can be used for the current path, or old path, also can included the filename
// NewPath can be used for move, copy, etc
// Permission e.g. rwx-r--r-
type ActionSSH struct {
	Command string `json:"command"`
}

// ActionSpark action for SPARK
// Type of the code upload e.g. Java, Scala
// Mode e.g. client, cluster
// Args for other arguments, e.g. --executor-memory 2G
// Application the spark code will be mantain as application
type ActionSpark struct {
	Type      string `json:"type"`
	Master    string `json:"master"`
	Mode      string `json:"node"`
	File      string `json:"file"`
	MainClass string `json:"mainclass"`
	Args      string `json:"args"`
	// AppName   string
	// Args      []string
}

// ActionSpark action for Application
// Type e.g. Java, Scala, GO
// Application refer to application page
// when creating the action with type = application then should follow the application screen standard
type ActionApplication struct {
	Type        string      `json: "type"`
	Application Application `json:"application"`
}

// ActionHadoopStreaming for hadoop streaming
// Mapper name
// Reducer name
// Input can be folder or file
// Output folder
// Files list of file inside the hdfs
// the server type should be hdfs
type ActionHadoopStreaming struct {
	Jar     string   `json:"jar"`
	Mapper  string   `json:"mapper"`
	Reducer string   `json:"reducer"`
	Input   string   `json:"input"`
	Output  string   `json:"output"`
	Files   []string `json:"files"`
	// Params  []string
	Params string `json:"params"`
}

// ActionKafka action for KAFKA
type ActionKafka struct {
	// other field will be different for each action type
}

/*
Doesn't need the Queestion, can be achived by using OK and KO or using decision
type ActionQuestion struct {
	Question string `json:"question"`
	Yes      string `json:"yes"`
	No       string `json:"no"`
	// other field will be different for each action type
}*/

// ActionDecision action to define the list of decision that action have
type ActionDecision struct {
	Conditions []Condition `json:"conditions"`
	IsFork     bool        `json:"isfork"`
	// other field will be different for each action type
}

// Condition condition for the action decision
type Condition struct {
	Stat       string `json:"stat"`
	FlowAction string `json:"flowaction"`
}

type ActionStop struct {
	Message string `json:"message"`
}

type ActionShellScript struct {
	Script string `json:"script"`
}

type ActionJavaApp struct {
	Jar string `json:"jar"`
}

type ActionEmail struct {
	To      string `json:"to"`
	Cc      string `json:"cc"`
	Subject string `json:"subject"`
	Body    string `json:"body"`
}

// ActionFork to define the forking condition
// Type refer to cons FORK_TYPE_*
type ActionFork struct {
	Actions []FlowAction `json:"actions"`
	Type    string       `json: "type"`
}

// status, running - success - error
// steps should be the list of the action(FlowAction) that have been run
type DataFlowProcess struct {
	orm.ModelBase
	Id          string        `json:"_id"`
	Flow        DataFlow      `json:"flow"`
	Steps       []interface{} `json:"steps"`
	StartDate   time.Time     `json:"startdate"`
	EndDate     time.Time     `json:"enddate"`
	StartedBy   string        `json:"startedby"`
	GlobalParam tk.M          `json:"globalparam"`
	Status      string        `json:"status"`
	Percentage  int           `json:"pct"`
}

func (c *DataFlowProcess) TableName() string {
	return "dataflowprocess"
}

func (c *DataFlowProcess) RecordID() interface{} {
	return c.Id
}
<|endoftext|>


<commit_before>package forecast

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"
)

// URL example:  "https://api.darksky.net/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.darksky.net/forecast"
)

type Flags struct {
	DarkSkyUnavailable string   `json:"darksky-unavailable"`
	DarkSkyStations    []string `json:"darksky-stations"`
	DataPointStations  []string `json:"datapoint-stations"`
	ISDStations        []string `json:"isds-stations"`
	LAMPStations       []string `json:"lamp-stations"`
	METARStations      []string `json:"metars-stations"`
	METNOLicense       string   `json:"metnol-license"`
	Sources            []string `json:"sources"`
	Units              string   `json:"units"`
}

type DataPoint struct {
	Time                   float64 `json:"time"`
	Summary                string  `json:"summary"`
	Icon                   string  `json:"icon"`
	SunriseTime            float64 `json:"sunriseTime"`
	SunsetTime             float64 `json:"sunsetTime"`
	PrecipIntensity        float64 `json:"precipIntensity"`
	PrecipIntensityMax     float64 `json:"precipIntensityMax"`
	PrecipIntensityMaxTime float64 `json:"precipIntensityMaxTime"`
	PrecipProbability      float64 `json:"precipProbability"`
	PrecipType             string  `json:"precipType"`
	PrecipAccumulation     float64 `json:"precipAccumulation"`
	Temperature            float64 `json:"temperature"`
	TemperatureMin         float64 `json:"temperatureMin"`
	TemperatureMinTime     float64 `json:"temperatureMinTime"`
	TemperatureMax         float64 `json:"temperatureMax"`
	TemperatureMaxTime     float64 `json:"temperatureMaxTime"`
	ApparentTemperature    float64 `json:"apparentTemperature"`
	DewPoint               float64 `json:"dewPoint"`
	WindSpeed              float64 `json:"windSpeed"`
	WindBearing            float64 `json:"windBearing"`
	CloudCover             float64 `json:"cloudCover"`
	Humidity               float64 `json:"humidity"`
	Pressure               float64 `json:"pressure"`
	Visibility             float64 `json:"visibility"`
	Ozone                  float64 `json:"ozone"`
	MoonPhase              float64 `json:"moonPhase"`
}

type DataBlock struct {
	Summary string      `json:"summary"`
	Icon    string      `json:"icon"`
	Data    []DataPoint `json:"data"`
}

type alert struct {
	Title       string  `json:"title"`
	Description string  `json:"description"`
	Time        float64 `json:"time"`
	Expires     float64 `json:"expires"`
	URI         string  `json:"uri"`
}

type Forecast struct {
	Latitude  float64   `json:"latitude"`
	Longitude float64   `json:"longitude"`
	Timezone  string    `json:"timezone"`
	Offset    float64   `json:"offset"`
	Currently DataPoint `json:"currently"`
	Minutely  DataBlock `json:"minutely"`
	Hourly    DataBlock `json:"hourly"`
	Daily     DataBlock `json:"daily"`
	Alerts    []alert   `json:"alerts"`
	Flags     Flags     `json:"flags"`
	APICalls  int       `json:"apicalls"`
	Code      int       `json:"code"`
}

type Units string

const (
	CA   Units = "ca"
	SI   Units = "si"
	US   Units = "us"
	UK   Units = "uk"
	AUTO Units = "auto"
)

func Get(key string, lat string, long string, time string, units Units) (*Forecast, error) {
	res, err := GetResponse(key, lat, long, time, units)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	f, err := FromJSON(body)
	if err != nil {
		return nil, err
	}

	calls, _ := strconv.Atoi(res.Header.Get("X-Forecast-API-Calls"))
	f.APICalls = calls

	return f, nil
}

func FromJSON(json_blob []byte) (*Forecast, error) {
	var f Forecast
	err := json.Unmarshal(json_blob, &f)
	if err != nil {
		return nil, err
	}

	return &f, nil
}

func GetResponse(key string, lat string, long string, time string, units Units) (*http.Response, error) {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=" + string(units)
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=" + string(units)
	}

	res, err := http.Get(url)
	if err != nil {
		return res, err
	}

	return res, nil
}
<commit_msg>Use json.Decorder rather than json.Unmarshal.<commit_after>package forecast

import (
	"encoding/json"
	"io"
	"net/http"
	"strconv"
)

// URL example:  "https://api.darksky.net/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.darksky.net/forecast"
)

type Flags struct {
	DarkSkyUnavailable string   `json:"darksky-unavailable"`
	DarkSkyStations    []string `json:"darksky-stations"`
	DataPointStations  []string `json:"datapoint-stations"`
	ISDStations        []string `json:"isds-stations"`
	LAMPStations       []string `json:"lamp-stations"`
	METARStations      []string `json:"metars-stations"`
	METNOLicense       string   `json:"metnol-license"`
	Sources            []string `json:"sources"`
	Units              string   `json:"units"`
}

type DataPoint struct {
	Time                   float64 `json:"time"`
	Summary                string  `json:"summary"`
	Icon                   string  `json:"icon"`
	SunriseTime            float64 `json:"sunriseTime"`
	SunsetTime             float64 `json:"sunsetTime"`
	PrecipIntensity        float64 `json:"precipIntensity"`
	PrecipIntensityMax     float64 `json:"precipIntensityMax"`
	PrecipIntensityMaxTime float64 `json:"precipIntensityMaxTime"`
	PrecipProbability      float64 `json:"precipProbability"`
	PrecipType             string  `json:"precipType"`
	PrecipAccumulation     float64 `json:"precipAccumulation"`
	Temperature            float64 `json:"temperature"`
	TemperatureMin         float64 `json:"temperatureMin"`
	TemperatureMinTime     float64 `json:"temperatureMinTime"`
	TemperatureMax         float64 `json:"temperatureMax"`
	TemperatureMaxTime     float64 `json:"temperatureMaxTime"`
	ApparentTemperature    float64 `json:"apparentTemperature"`
	DewPoint               float64 `json:"dewPoint"`
	WindSpeed              float64 `json:"windSpeed"`
	WindBearing            float64 `json:"windBearing"`
	CloudCover             float64 `json:"cloudCover"`
	Humidity               float64 `json:"humidity"`
	Pressure               float64 `json:"pressure"`
	Visibility             float64 `json:"visibility"`
	Ozone                  float64 `json:"ozone"`
	MoonPhase              float64 `json:"moonPhase"`
}

type DataBlock struct {
	Summary string      `json:"summary"`
	Icon    string      `json:"icon"`
	Data    []DataPoint `json:"data"`
}

type alert struct {
	Title       string  `json:"title"`
	Description string  `json:"description"`
	Time        float64 `json:"time"`
	Expires     float64 `json:"expires"`
	URI         string  `json:"uri"`
}

type Forecast struct {
	Latitude  float64   `json:"latitude"`
	Longitude float64   `json:"longitude"`
	Timezone  string    `json:"timezone"`
	Offset    float64   `json:"offset"`
	Currently DataPoint `json:"currently"`
	Minutely  DataBlock `json:"minutely"`
	Hourly    DataBlock `json:"hourly"`
	Daily     DataBlock `json:"daily"`
	Alerts    []alert   `json:"alerts"`
	Flags     Flags     `json:"flags"`
	APICalls  int       `json:"apicalls"`
	Code      int       `json:"code"`
}

type Units string

const (
	CA   Units = "ca"
	SI   Units = "si"
	US   Units = "us"
	UK   Units = "uk"
	AUTO Units = "auto"
)

func Get(key string, lat string, long string, time string, units Units) (*Forecast, error) {
	res, err := GetResponse(key, lat, long, time, units)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	f, err := FromJSON(res.Body)
	if err != nil {
		return nil, err
	}

	calls, _ := strconv.Atoi(res.Header.Get("X-Forecast-API-Calls"))
	f.APICalls = calls

	return f, nil
}

func FromJSON(reader io.Reader) (*Forecast, error) {
	var f Forecast
	if err := json.NewDecoder(reader).Decode(&f); err != nil {
		return nil, err
	}

	return &f, nil
}

func GetResponse(key string, lat string, long string, time string, units Units) (*http.Response, error) {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=" + string(units)
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=" + string(units)
	}

	res, err := http.Get(url)
	if err != nil {
		return res, err
	}

	return res, nil
}
<|endoftext|>


<commit_before>package repo

// GetStorageBlocks returns the list of storage blocks used by the specified object ID.
func (r *ObjectManager) GetStorageBlocks(oid ObjectID) ([]string, error) {
	result := map[string]bool{}
	if err := r.addStorageBlocks(result, oid); err != nil {
		return nil, err
	}

	var b []string
	for k := range result {
		b = append(b, k)
	}
	return b, nil
}

func (r *ObjectManager) addStorageBlocks(result map[string]bool, oid ObjectID) error {
	if oid.Section != nil {
		return r.addStorageBlocks(result, oid.Section.Base)
	}

	if oid.StorageBlock != "" {
		result[oid.StorageBlock] = true
	}

	if oid.Indirect == nil {
		return nil
	}

	or, err := r.Open(*oid.Indirect)
	if err != nil {
		return err
	}
	defer or.Close()

	chunks, err := r.flattenListChunk(or)
	if err != nil {
		return err
	}
	for _, st := range chunks {
		if st.Object != nil {
			if err := r.addStorageBlocks(result, *st.Object); err != nil {
				return err
			}
		}
	}

	return r.addStorageBlocks(result, *oid.Indirect)
}
<commit_msg>added pack support to GetStorageBlocks()<commit_after>package repo

// GetStorageBlocks returns the list of storage blocks used by the specified object ID.
func (r *ObjectManager) GetStorageBlocks(oid ObjectID) ([]string, error) {
	result := map[string]bool{}
	if err := r.addStorageBlocks(result, oid); err != nil {
		return nil, err
	}

	var b []string
	for k := range result {
		b = append(b, k)
	}
	return b, nil
}

func (r *ObjectManager) addStorageBlocks(result map[string]bool, oid ObjectID) error {
	if oid.Section != nil {
		return r.addStorageBlocks(result, oid.Section.Base)
	}

	if oid.StorageBlock != "" {
		result[oid.StorageBlock] = true
	}

	if oid.PackID != "" {
		s, err := r.packIDToSection(oid)
		if err != nil {
			return err
		}

		r.addStorageBlocks(result, s.Base)
	}

	if oid.Indirect == nil {
		return nil
	}

	or, err := r.Open(*oid.Indirect)
	if err != nil {
		return err
	}
	defer or.Close()

	chunks, err := r.flattenListChunk(or)
	if err != nil {
		return err
	}
	for _, st := range chunks {
		if st.Object != nil {
			if err := r.addStorageBlocks(result, *st.Object); err != nil {
				return err
			}
		}
	}

	return r.addStorageBlocks(result, *oid.Indirect)
}
<|endoftext|>


<commit_before>package repo

import (
	"fmt"
	"os/exec"
)

const defaultCommitMessage = "[skip ci] Commit dirty state"

// ForceAdd forces the addition of all dirty files.
func ForceAdd() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"add",
		"--all",
		"--force")

	return cmd
}

// Add updates the index to match the working tree.
func Add() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"add",
		"--all")

	return cmd
}

// TestCleanTree returns non-zero if diff between index and local repository
func TestCleanTree() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"diff-index",
		"--quiet",
		"HEAD",
		"--ignore-submodules")

	return cmd
}

// EmptyCommit simply create an empty commit
func EmptyCommit(msg string) *exec.Cmd {
	if msg == "" {
		msg = defaultCommitMessage
	}

	cmd := exec.Command(
		"git",
		"commit",
		"--allow-empty",
		fmt.Sprintf("-m \"%s\"", msg))

	return cmd
}

// ForceCommit commits every change while skipping CI.
func ForceCommit(msg string) *exec.Cmd {
	if msg == "" {
		msg = defaultCommitMessage
	}

	cmd := exec.Command(
		"git",
		"commit",
		fmt.Sprintf("-m \"%s\"", msg))

	return cmd
}
<commit_msg>remove double quote<commit_after>package repo

import (
	"fmt"
	"os/exec"
)

const defaultCommitMessage = "[skip ci] Commit dirty state"

// ForceAdd forces the addition of all dirty files.
func ForceAdd() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"add",
		"--all",
		"--force")

	return cmd
}

// Add updates the index to match the working tree.
func Add() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"add",
		"--all")

	return cmd
}

// TestCleanTree returns non-zero if diff between index and local repository
func TestCleanTree() *exec.Cmd {
	cmd := exec.Command(
		"git",
		"diff-index",
		"--quiet",
		"HEAD",
		"--ignore-submodules")

	return cmd
}

// EmptyCommit simply create an empty commit
func EmptyCommit(msg string) *exec.Cmd {
	if msg == "" {
		msg = defaultCommitMessage
	}

	cmd := exec.Command(
		"git",
		"commit",
		"--allow-empty",
		"-m",
		msg,
	)

	return cmd
}

// ForceCommit commits every change while skipping CI.
func ForceCommit(msg string) *exec.Cmd {
	if msg == "" {
		msg = defaultCommitMessage
	}

	cmd := exec.Command(
		"git",
		"commit",
		"-m",
		msg,
	)

	return cmd
}
<|endoftext|>


<commit_before>package main

import "fmt"

type RestAPI struct {
	Name string
	Endpoints
}

type RestAPIGreediMonki RestAPI

type Endpoints map[string]Endpoint

type Endpoint struct {
	id          string
	url         string
	description string
}

type HelloWorldEndpoint struct {
	ep Endpoint
}

type GitEndpoint struct {
	Endpoint
}

type LoginEndpoint struct{}

type RestAPIInit interface {
	init(string) RestAPI
}

func (api *RestAPI) init(name string) {
	api.Name = name
	eps := make(Endpoints)

	ephw := HelloWorldEndpoint{}
	ephw.ep.id = "hw"
	ephw.ep.url = "/hw"
	ephw.ep.description = "hello world! endpoint"

	epgit := GitEndpoint{
		Endpoint{
			id:          "git",
			url:         "/github.com/user",
			description: "github user endpoint",
		},
	}

	eps[ephw.ep.id] = ephw.ep
	eps[epgit.id] = epgit.Endpoint

	api.Endpoints = eps

}

func (api *RestAPIGreediMonki) init(name string) {
	api.Name = name
	eps := make(Endpoints)

	eps["login"] = Endpoint{
		id:          "login",
		url:         "/login",
		description: "user login",
	}

	api.Endpoints = eps

}

func main() {

	api := &RestAPI{}
	api.init("GoCloud")

	fmt.Println("RestAPI:", api.Name)
	for _, ep := range api.Endpoints {
		fmt.Println("\tEndpoint:", ep)
	}

	apigm := &RestAPIGreediMonki{}
	apigm.init("GreediMonki")

	fmt.Println("RestAPI:", apigm.Name)
	for _, ep := range apigm.Endpoints {
		fmt.Println("\tEndpoint:", ep)
	}

}
<commit_msg>add second restapi<commit_after>package main

import "fmt"

type RestAPI struct {
	Name string
	Endpoints
	RestAPIIniter
}

type RestAPIMPC RestAPI
type RestAPIGreediMonki RestAPI

type Endpoints map[string]Endpoint

type Endpoint struct {
	id          string
	url         string
	description string
}

type HelloWorldEndpoint struct {
	ep Endpoint
}

type GitEndpoint struct {
	Endpoint
}

type LoginEndpoint struct{}

type RestAPIIniter interface {
	Init(string) error
}

func InitAPI(init RestAPIIniter) error {
	return init.Init(string)
}

func (api *RestAPI) Init() error {
	api.Name = name
	eps := make(Endpoints)

	ephw := HelloWorldEndpoint{}
	ephw.ep.id = "hw"
	ephw.ep.url = "/hw"
	ephw.ep.description = "hello world! endpoint"

	epgit := GitEndpoint{
		Endpoint{
			id:          "git",
			url:         "/github.com/user",
			description: "github user endpoint",
		},
	}

	eps[ephw.ep.id] = ephw.ep
	eps[epgit.id] = epgit.Endpoint

	api.Endpoints = eps
	return nil
}

func (api *RestAPIGreediMonki) Init() error {
	api.Name = name
	eps := make(Endpoints)

	eps["login"] = Endpoint{
		id:          "login",
		url:         "/login",
		description: "user login",
	}

	api.Endpoints = eps
	return nil
}

func main() {

	api := &RestAPI{Name: "GoCloud"}
	InitAPI(api)

	fmt.Println("RestAPI:", api.Name)
	for _, ep := range api.Endpoints {
		fmt.Println("\tEndpoint:", ep)
	}

	apigm := &RestAPIGreediMonki{Name: "GreediMonki"}
	Init(apigm)

	fmt.Println("RestAPI:", apigm.Name)
	for _, ep := range apigm.Endpoints {
		fmt.Println("\tEndpoint:", ep)
	}

}
<|endoftext|>


<commit_before>package packer

import (
	"fmt"
	"sort"
)

// BestFit packs sprites into a rectangle using 4 different sorting algorithms,
// modifying the x/y of the sprite to give the tighest pack in a rectangle.
func BestFit(sprites Sprites) *Canvas {

	// compute area of the shapes to determine best layout below
	spriteArea := 0

	// Copy each list of sprites so they can be packed most efficiently.
	// Since we're dealing with a slice of pointers, seems like we have
	// to copy each struct.  Is there a better way??
	byWidth := make(Sprites, len(sprites))
	byHeight := make(Sprites, len(sprites))
	byArea := make(Sprites, len(sprites))
	byMax := make(Sprites, len(sprites))

	for i, s := range sprites {
		byWidth[i] = NewSprite(s.Name, s.Width, s.Height)
		byHeight[i] = NewSprite(s.Name, s.Width, s.Height)
		byArea[i] = NewSprite(s.Name, s.Width, s.Height)
		byMax[i] = NewSprite(s.Name, s.Width, s.Height)

		spriteArea += s.Width * s.Height
	}

	// Try to layout Sprites 4 different ways.  What we have here
	// is an "embarrassingly parallel" problem, the easiest kind
	// to perform concurrently
	ch := make(chan *Canvas)

	go doit(ch, byWidth, LayoutByWidth)
	go doit(ch, byHeight, LayoutByHeight)
	go doit(ch, byArea, LayoutByArea)
	go doit(ch, byMax, LayoutByMax)

	// Canvi ... canvases
	numCanvi := 4

	// TODO DANGER what if we're laying huge, int64 range area here
	// Should we just use int64 everywhere instead of int ??
	minWaste := 1<<31 - 1

	var bestCanvas *Canvas

	for i := 0; i < numCanvi; i++ {
		c := <-ch
		waste := (c.Root.Width * c.Root.Height) - spriteArea
		fmt.Printf("%s <%dx%d> has wasted %d pixels\n", c.layout, c.Root.Width, c.Root.Height, waste)
		if waste < minWaste {
			minWaste = waste
			bestCanvas = c
		}
	}
	fmt.Println(">>>> RETURNING ", bestCanvas.layout)

	return bestCanvas
}

func doit(ch chan<- *Canvas, sprites Sprites, layout Layout) {
	switch layout {
	case LayoutByWidth:
		sort.Sort(SpritesByWidth(sprites))
	case LayoutByHeight:
		sort.Sort(SpritesByHeight(sprites))
	case LayoutByArea:
		sort.Sort(SpritesByArea(sprites))
	default:
		sort.Sort(SpritesByMax(sprites))
	}

	canvas := Fit(sprites)
	canvas.layout = layout
	ch <- canvas
}

// Fit sprites
func Fit(sprites Sprites) *Canvas {

	root := newPosSprite("", 0, 0, sprites[0].Width, sprites[0].Height)
	canvas := &Canvas{Root: root}

	for _, sprite := range sprites {
		w := sprite.Width
		h := sprite.Height
		if node := canvas.findNode(canvas.Root, w, h); node != nil {
			sprite.fit = canvas.splitNode(node, w, h)
		} else {
			sprite.fit = canvas.growNode(w, h)
		}
		sprite.fit.Name = sprite.Name
	}

	return canvas.dup(sprites)
}

func (c *Canvas) dup(nodes Sprites) *Canvas {
	r := c.Root
	root := newPosSprite("#root#", r.X, r.Y, r.Width, r.Height)
	sprites := make(Sprites, len(nodes))
	for i, s := range nodes {
		sprites[i] = s.fit
	}

	return &Canvas{Root: root, Sprites: sprites}
}

func (c *Canvas) findNode(node *Sprite, w, h int) *Sprite {
	if node.used {
		if r := c.findNode(node.right, w, h); r != nil {
			return r
		}
		return c.findNode(node.down, w, h)
	} else if w <= node.Width && h <= node.Height {
		return node
	}

	return nil
}

func (c *Canvas) splitNode(node *Sprite, w, h int) *Sprite {
	node.used = true
	node.down = newPosSprite("", node.X, node.Y+h, node.Width, node.Height-h)
	node.right = newPosSprite("", node.X+w, node.Y, node.Width-w, h)
	node.Width = w
	node.Height = h

	return node
}

func (c *Canvas) growNode(w, h int) *Sprite {

	rw := c.Root.Width
	rh := c.Root.Height

	canGrowDown := (w <= rw)
	canGrowRight := (h <= rh)

	// attempt to keep square-ish by growing right when height is much greater than width
	shouldGrowRight := canGrowRight && (rh >= (rw + w))

	// attempt to keep square-ish by growing down  when width  is much greater than height
	shouldGrowDown := canGrowDown && (rw >= (rh + h))

	if shouldGrowRight {
		return c.growRight(w, h)
	} else if shouldGrowDown {
		return c.growDown(w, h)
	} else if canGrowRight {
		return c.growRight(w, h)
	} else if canGrowDown {
		return c.growDown(w, h)
	}

	// need to ensure sensible root starting size to avoid this happening
	return nil
}

// duplicate sprite ... is a deep copy needed here????
func dup(s *Sprite) *Sprite {
	newSprite := *s
	return &newSprite
}

func (c *Canvas) growRight(w, h int) *Sprite {
	newRoot := newPosSprite("", 0, 0, c.Root.Width+w, c.Root.Height)
	newRoot.used = true
	newRoot.down = dup(c.Root)
	newRoot.right = newPosSprite("", c.Root.Width, 0, w, c.Root.Height)

	c.Root = newRoot

	if node := c.findNode(c.Root, w, h); node != nil {
		return c.splitNode(node, w, h)
	}

	return nil
}

func (c *Canvas) growDown(w, h int) *Sprite {
	newRoot := newPosSprite("", 0, 0, c.Root.Width, c.Root.Height+h)
	newRoot.used = true
	newRoot.down = newPosSprite("", 0, c.Root.Height, c.Root.Width, h)
	newRoot.right = dup(c.Root)

	c.Root = newRoot

	if node := c.findNode(c.Root, w, h); node != nil {
		return c.splitNode(node, w, h)
	}

	return nil
}
<commit_msg>add comment to Fit<commit_after>package packer

import (
	"fmt"
	"sort"
)

// BestFit packs sprites into a rectangle using 4 different sorting algorithms,
// modifying the x/y of the sprite to give the tighest pack in a rectangle.
func BestFit(sprites Sprites) *Canvas {

	// compute area of the shapes to determine best layout below
	spriteArea := 0

	// Copy each list of sprites so they can be packed most efficiently.
	// Since we're dealing with a slice of pointers, seems like we have
	// to copy each struct.  Is there a better way??
	byWidth := make(Sprites, len(sprites))
	byHeight := make(Sprites, len(sprites))
	byArea := make(Sprites, len(sprites))
	byMax := make(Sprites, len(sprites))

	for i, s := range sprites {
		byWidth[i] = NewSprite(s.Name, s.Width, s.Height)
		byHeight[i] = NewSprite(s.Name, s.Width, s.Height)
		byArea[i] = NewSprite(s.Name, s.Width, s.Height)
		byMax[i] = NewSprite(s.Name, s.Width, s.Height)

		spriteArea += s.Width * s.Height
	}

	// Try to layout Sprites 4 different ways.  What we have here
	// is an "embarrassingly parallel" problem, the easiest kind
	// to perform concurrently
	ch := make(chan *Canvas)

	go doit(ch, byWidth, LayoutByWidth)
	go doit(ch, byHeight, LayoutByHeight)
	go doit(ch, byArea, LayoutByArea)
	go doit(ch, byMax, LayoutByMax)

	// Canvi ... canvases
	numCanvi := 4

	// TODO DANGER what if we're laying huge, int64 range area here
	// Should we just use int64 everywhere instead of int ??
	minWaste := 1<<31 - 1

	var bestCanvas *Canvas

	for i := 0; i < numCanvi; i++ {
		c := <-ch
		waste := (c.Root.Width * c.Root.Height) - spriteArea
		fmt.Printf("%s <%dx%d> has wasted %d pixels\n", c.layout, c.Root.Width, c.Root.Height, waste)
		if waste < minWaste {
			minWaste = waste
			bestCanvas = c
		}
	}
	fmt.Println(">>>> RETURNING ", bestCanvas.layout)

	return bestCanvas
}

func doit(ch chan<- *Canvas, sprites Sprites, layout Layout) {
	switch layout {
	case LayoutByWidth:
		sort.Sort(SpritesByWidth(sprites))
	case LayoutByHeight:
		sort.Sort(SpritesByHeight(sprites))
	case LayoutByArea:
		sort.Sort(SpritesByArea(sprites))
	default:
		sort.Sort(SpritesByMax(sprites))
	}

	canvas := Fit(sprites)
	canvas.layout = layout
	ch <- canvas
}

// Fit sprites in a rectangle.  Sprites must be sorted before calling Fit.  It's
// easiest to call BestFit which calls this method with 4 different sorts to
// determine the tightest packing.
func Fit(sprites Sprites) *Canvas {

	root := newPosSprite("", 0, 0, sprites[0].Width, sprites[0].Height)
	canvas := &Canvas{Root: root}

	for _, sprite := range sprites {
		w := sprite.Width
		h := sprite.Height
		if node := canvas.findNode(canvas.Root, w, h); node != nil {
			sprite.fit = canvas.splitNode(node, w, h)
		} else {
			sprite.fit = canvas.growNode(w, h)
		}
		sprite.fit.Name = sprite.Name
	}

	return canvas.dup(sprites)
}

func (c *Canvas) dup(nodes Sprites) *Canvas {
	r := c.Root
	root := newPosSprite("#root#", r.X, r.Y, r.Width, r.Height)
	sprites := make(Sprites, len(nodes))
	for i, s := range nodes {
		sprites[i] = s.fit
	}

	return &Canvas{Root: root, Sprites: sprites}
}

func (c *Canvas) findNode(node *Sprite, w, h int) *Sprite {
	if node.used {
		if r := c.findNode(node.right, w, h); r != nil {
			return r
		}
		return c.findNode(node.down, w, h)
	} else if w <= node.Width && h <= node.Height {
		return node
	}

	return nil
}

func (c *Canvas) splitNode(node *Sprite, w, h int) *Sprite {
	node.used = true
	node.down = newPosSprite("", node.X, node.Y+h, node.Width, node.Height-h)
	node.right = newPosSprite("", node.X+w, node.Y, node.Width-w, h)
	node.Width = w
	node.Height = h

	return node
}

func (c *Canvas) growNode(w, h int) *Sprite {

	rw := c.Root.Width
	rh := c.Root.Height

	canGrowDown := (w <= rw)
	canGrowRight := (h <= rh)

	// attempt to keep square-ish by growing right when height is much greater than width
	shouldGrowRight := canGrowRight && (rh >= (rw + w))

	// attempt to keep square-ish by growing down  when width  is much greater than height
	shouldGrowDown := canGrowDown && (rw >= (rh + h))

	if shouldGrowRight {
		return c.growRight(w, h)
	} else if shouldGrowDown {
		return c.growDown(w, h)
	} else if canGrowRight {
		return c.growRight(w, h)
	} else if canGrowDown {
		return c.growDown(w, h)
	}

	// need to ensure sensible root starting size to avoid this happening
	return nil
}

// duplicate sprite ... is a deep copy needed here????
func dup(s *Sprite) *Sprite {
	newSprite := *s
	return &newSprite
}

func (c *Canvas) growRight(w, h int) *Sprite {
	newRoot := newPosSprite("", 0, 0, c.Root.Width+w, c.Root.Height)
	newRoot.used = true
	newRoot.down = dup(c.Root)
	newRoot.right = newPosSprite("", c.Root.Width, 0, w, c.Root.Height)

	c.Root = newRoot

	if node := c.findNode(c.Root, w, h); node != nil {
		return c.splitNode(node, w, h)
	}

	return nil
}

func (c *Canvas) growDown(w, h int) *Sprite {
	newRoot := newPosSprite("", 0, 0, c.Root.Width, c.Root.Height+h)
	newRoot.used = true
	newRoot.down = newPosSprite("", 0, c.Root.Height, c.Root.Width, h)
	newRoot.right = dup(c.Root)

	c.Root = newRoot

	if node := c.findNode(c.Root, w, h); node != nil {
		return c.splitNode(node, w, h)
	}

	return nil
}
<|endoftext|>


<commit_before>package route

//import "gopkg.in/webnice/debug.v1"
//import "gopkg.in/webnice/log.v2"
import "gopkg.in/webnice/web.v1/context"
import "gopkg.in/webnice/web.v1/context/handlers"
import "gopkg.in/webnice/web.v1/context/errors"
import "gopkg.in/webnice/web.v1/method"
import (
	"fmt"
	"net/http"
	"runtime"
)

// New returns a newly initialized router object that implements the Router interface
func New() Interface {
	var rou = &impl{tree: &node{}}
	rou.context = context.New()
	rou.pool.New = func() interface{} {
		return context.New(rou.context)
	}
	return rou
}

// Errors interface
func (rou *impl) Errors() errors.Interface { rou.setErrors(); return rou.context.Errors() }

// Handlers interface
func (rou *impl) Handlers() handlers.Interface { return rou.context.Handlers() }

// Copy all errors to errors named object
func (rou *impl) setErrors() {
	var err = "Errors:\n"
	if len(rou.errors) == 0 {
		return
	}
	for _, e := range rou.errors {
		err += " - " + e.Error() + "\n"
	}
	_ = rou.context.Errors().RouteConfigurationError(fmt.Errorf(err))
}

// ServeHTTP is the single method of the http.Handler interface that makes
// route interoperable with the standard library.
// It uses a sync.Pool to get and reuse routing contexts for each request
func (rou *impl) ServeHTTP(wr http.ResponseWriter, rq *http.Request) {
	var ctx context.Interface

	// Fetch a RouteContext object from the sync pool, and call the computed
	// handler that is comprised of middlewares + routeHTTP
	// Once the request is finished, reset the routing context and put it back
	// into the pool for reuse from another request
	if !context.IsContext(rq) {
		ctx = rou.pool.Get().(context.Interface)
		ctx.Route().Reset()
		ctx.Errors().Reset()
		ctx.Handlers().InternalServerError(rou.context.Handlers().InternalServerError(nil))
		rq = ctx.NewRequest(rq)
		defer rou.pool.Put(ctx)
	}

	// Ensure the route has some routes defined on the route
	if rou.handler == nil {
		ctx = context.New(rq)
		_ = ctx.Errors().InternalServerError(fmt.Errorf("Attempting to route with no handlers"))
		ctx.Handlers().InternalServerError(nil)(wr, rq)
		rou.pool.Put(ctx)
		return
	}

	if len(rou.errors) > 0 {
		rou.setErrors()
		ctx = context.New(rq)
		_ = ctx.Errors().InternalServerError(rou.context.Errors().RouteConfigurationError(nil))
		ctx.Handlers().InternalServerError(nil)(wr, rq)
		rou.pool.Put(ctx)
		return
	}

	rou.handler.ServeHTTP(wr, rq)
}

// Use appends a middleware handler to the middleware stack
//
// The middleware stack for any route will execute before searching for a matching
// route to a specific handler, which provides opportunity to respond early,
// change the course of the request execution, or set request-scoped values for
// the next http.Handler
func (rou *impl) Use(middlewares ...func(http.Handler) http.Handler) {
	const errorMiddlewares = "All middlewares must be defined before use"
	if rou.handler != nil {
		rou.errors = append(rou.errors, rou.context.Errors().InternalServerError(fmt.Errorf(errorMiddlewares)))
		return
	}
	rou.middlewares = append(rou.middlewares, middlewares...)
}

// Handle adds the route `pattern` that matches any http method to execute the `handler` http.Handler
func (rou *impl) Handle(pattern string, handler http.Handler) {
	rou.handle(method.Any, pattern, handler)
}

// HandleFunc adds the route `pattern` that matches any http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Any, pattern, handlerFn)
}

// Connect adds the route `pattern` that matches a CONNECT http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Connect(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Connect, pattern, handlerFn)
}

// Delete adds the route `pattern` that matches a DELETE http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Delete(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Delete, pattern, handlerFn)
}

// Get adds the route `pattern` that matches a GET http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Get(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Get, pattern, handlerFn)
}

// Head adds the route `pattern` that matches a HEAD http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Head(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Head, pattern, handlerFn)
}

// Options adds the route `pattern` that matches a OPTIONS http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Options(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Options, pattern, handlerFn)
}

// Patch adds the route `pattern` that matches a PATCH http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Patch(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Patch, pattern, handlerFn)
}

// Post adds the route `pattern` that matches a POST http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Post(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Post, pattern, handlerFn)
}

// Put adds the route `pattern` that matches a PUT http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Put(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Put, pattern, handlerFn)
}

// Trace adds the route `pattern` that matches a TRACE http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Trace(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Trace, pattern, handlerFn)
}

// Chain returns a Middlewares type from a slice of middleware handlers
func (rou *impl) Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
	return Middlewares(middlewares)
}

// With adds inline middlewares for an endpoint handler
func (rou *impl) With(middlewares ...func(http.Handler) http.Handler) Interface {
	var mws Middlewares
	var im *impl

	// Similarly as in handle(), we must build the route handler once further
	// middleware registration isn't allowed for this stack, like now
	if !rou.inline && rou.handler == nil {
		rou.buildRouteHandler()
	}

	// Copy middlewares from parent inline route
	if rou.inline {
		mws = make(Middlewares, len(rou.middlewares))
		copy(mws, rou.middlewares)
	}
	mws = append(mws, middlewares...)

	im = &impl{inline: true, parent: rou, tree: rou.tree, middlewares: mws}
	return im
}

// Group creates a new inline-route with a fresh middleware stack. It's useful
// for a group of handlers along the same routing path that use an additional set of middlewares
func (rou *impl) Group(fn func(r Interface)) Interface {
	var im = rou.With().(*impl)
	if fn != nil {
		fn(im)
	}
	return im
}

// Subroute creates a new route with a fresh middleware stack and mounts it
// along the `pattern` as a subrouter. Effectively, this is a short-hand call to Mount
func (rou *impl) Subroute(pattern string, fn func(r Interface)) Interface {
	var subRouter = New()
	if fn != nil {
		fn(subRouter)
	}
	rou.Mount(pattern, subRouter)
	if len(subRouter.(*impl).errors) > 0 {
		rou.errors = append(rou.errors, subRouter.(*impl).errors...)
	}
	return subRouter
}

// Mount attaches another http.Handler or Router as a subrouter along a routing
// path. It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount.
//
// Note that Mount() simply sets a wildcard along the `pattern` that will continue
// routing at the `handler`, which in most cases is another router.
// As a result, if you define two Mount() routes on the exact same pattern the mount will panic
func (rou *impl) Mount(pattern string, handler http.Handler) {
	const existingPath = `Attempting to Mount() a handler on an existing path %q`
	var subr *impl
	var ok bool
	var mtd method.Method
	var n *node
	var subHandler http.HandlerFunc
	var subroutes Routes

	// Provide runtime safety for ensuring a pattern isn't mounted on an existing routing pattern
	if rou.tree.findPattern(pattern+"*") != nil || rou.tree.findPattern(pattern+"/*") != nil {
		rou.errors = append(rou.errors, fmt.Errorf(existingPath, pattern))
		return
	}

	// Assign sub-Router's with the parent not found & method not allowed handler if not specified
	if subr, ok = handler.(*impl); ok && subr.Handlers() != rou.Handlers() {
		subr.Handlers().NotFound(rou.Handlers().NotFound(nil))
		subr.Handlers().MethodNotAllowed(rou.Handlers().MethodNotAllowed(nil))
	}

	// Wrap the sub-router in a handlerFunc to scope the request path for routing.
	subHandler = http.HandlerFunc(func(wr http.ResponseWriter, rq *http.Request) {
		var ctx = context.New(rq)
		ctx.Route().Path("/" + ctx.Route().Params().Del("*"))
		handler.ServeHTTP(wr, rq)
	})

	if pattern == "" || pattern[len(pattern)-1] != '/' {
		rou.handle(method.Any|method.Stub, pattern, subHandler)
		rou.handle(method.Any|method.Stub, pattern+"/", rou.Handlers().NotFound(nil))
		pattern += "/"
	}

	mtd = method.Any
	subroutes, _ = handler.(Routes)
	if subroutes != nil {
		mtd |= method.Stub
	}
	if n = rou.handle(mtd, pattern+"*", subHandler); n == nil {
		return
	}
	if subroutes != nil {
		n.subroutes = subroutes
	}
}

// Middlewares return all middlewares
func (rou *impl) Middlewares() Middlewares { return rou.middlewares }

// Routes Return all routes
func (rou *impl) Routes() []Route { return rou.tree.routes() }

// builds the single handler that is a chain of the middleware stack, as defined by
// calls to Use(), and the tree router itself. After this point, no other middlewares
// can be registered on stack. But you can still compose additional middlewares via
// Group()'s or using a chained middleware handler
func (rou *impl) buildRouteHandler() {
	rou.handler = chain(rou.middlewares, http.HandlerFunc(rou.routeHTTP))
}

// registers a http.Handler in the routing tree for a particular http method and routing pattern
func (rou *impl) handle(mtd method.Method, pattern string, handler http.Handler) (nde *node) {
	const (
		mustBeginWith    = `Routing pattern must begin with '/' in %q`
		insertRouteError = `Insert route error: %s`
	)
	var err error
	var her http.Handler

	if len(pattern) == 0 || pattern[0] != '/' {
		if _, file, line, ok := runtime.Caller(2); ok {
			rou.errors = append(rou.errors, fmt.Errorf(mustBeginWith+" (%s:%d)", pattern, file, line))
		} else {
			rou.errors = append(rou.errors, fmt.Errorf(mustBeginWith, pattern))
		}

		return nil
	}

	// Build the final routing handler for this route
	if !rou.inline && rou.handler == nil {
		rou.buildRouteHandler()
	}

	// Build endpoint handler with inline middlewares for the route

	if rou.inline {
		rou.handler = http.HandlerFunc(rou.routeHTTP)
		her = rou.Chain(rou.middlewares...).Handler(handler)
	} else {
		her = handler
	}

	// Add the endpoint to the tree and return the node
	nde, err = rou.tree.InsertRoute(mtd, pattern, her)
	if err != nil {
		if _, file, line, ok := runtime.Caller(2); ok {
			rou.errors = append(rou.errors, fmt.Errorf(insertRouteError+" (%s:%d)", err, file, line))
		} else {
			rou.errors = append(rou.errors, fmt.Errorf(insertRouteError, err))
		}
		return
	}

	return
}

// routes a http.Request through the routing tree to serve the matching handler for a particular http method
func (rou *impl) routeHTTP(wr http.ResponseWriter, rq *http.Request) {
	var err error
	var ctx context.Interface
	var routePath string
	var mtd method.Method
	var hs methodHandlers
	var h http.Handler
	var ok bool

	// Grab the route context object
	if context.IsContext(rq) {
		ctx = context.New(rq)
	} else {
		ctx = context.New()
		rq = ctx.NewRequest(rq)
	}
	// The request routing path
	routePath = ctx.Route().Path()
	if routePath == "" {
		if rq.URL.RawPath != "" {
			routePath = rq.URL.RawPath
		} else {
			routePath = rq.URL.Path
		}
	}
	// Check if method is supported
	if mtd, err = method.Parse(rq.Method); err != nil {
		rou.Handlers().MethodNotAllowed(nil).ServeHTTP(wr, rq)
		return
	}
	// Find the route
	hs = rou.tree.FindRoute(ctx, routePath)
	if hs == nil {
		rou.Handlers().NotFound(nil).ServeHTTP(wr, rq)
		return
	}
	if h, ok = hs[mtd]; !ok {
		rou.Handlers().MethodNotAllowed(nil).ServeHTTP(wr, rq)
		return
	}
	// Serve it up
	h.ServeHTTP(wr, rq)
}

// Recursively update data on child routers
//func (rou *impl) updateSubRoutes(fn func(subMux *impl)) {
//	var r Route
//	var ok bool
//	var subMux *impl
//	for _, r = range rou.tree.routes() {
//		subMux, ok = r.SubRoutes.(*impl)
//		if !ok {
//			continue
//		}
//		fn(subMux)
//	}
//}
<commit_msg>Update<commit_after>package route

//import "gopkg.in/webnice/debug.v1"
//import "gopkg.in/webnice/log.v2"
import "gopkg.in/webnice/web.v1/context"
import "gopkg.in/webnice/web.v1/context/handlers"
import "gopkg.in/webnice/web.v1/context/errors"
import "gopkg.in/webnice/web.v1/method"
import (
	"fmt"
	"net/http"
	"runtime"
)

// New returns a newly initialized router object that implements the Router interface
func New() Interface {
	var rou = &impl{tree: &node{}}
	rou.context = context.New()
	rou.pool.New = func() interface{} {
		return context.New(rou.context)
	}
	return rou
}

// Errors interface
func (rou *impl) Errors() errors.Interface { rou.setErrors(); return rou.context.Errors() }

// Handlers interface
func (rou *impl) Handlers() handlers.Interface { return rou.context.Handlers() }

// Copy all errors to errors named object
func (rou *impl) setErrors() {
	var err = "Errors:\n"
	if len(rou.errors) == 0 {
		return
	}
	for _, e := range rou.errors {
		err += " - " + e.Error() + "\n"
	}
	_ = rou.context.Errors().RouteConfigurationError(fmt.Errorf(err))
}

// ServeHTTP is the single method of the http.Handler interface that makes
// route interoperable with the standard library.
// It uses a sync.Pool to get and reuse routing contexts for each request
func (rou *impl) ServeHTTP(wr http.ResponseWriter, rq *http.Request) {
	var ctx context.Interface

	// Fetch a RouteContext object from the sync pool, and call the computed
	// handler that is comprised of middlewares + routeHTTP
	// Once the request is finished, reset the routing context and put it back
	// into the pool for reuse from another request
	if !context.IsContext(rq) {
		ctx = context.New(rou.pool.Get().(context.Interface))
		rq = ctx.NewRequest(rq)
		defer rou.pool.Put(ctx)
	}

	// Ensure the route has some routes defined on the route
	if rou.handler == nil {
		ctx = context.New(rq)
		_ = ctx.Errors().InternalServerError(fmt.Errorf("Attempting to route with no handlers"))
		ctx.Handlers().InternalServerError(nil)(wr, rq)
		rou.pool.Put(ctx)
		return
	}

	if len(rou.errors) > 0 {
		rou.setErrors()
		ctx = context.New(rq)
		_ = ctx.Errors().InternalServerError(rou.context.Errors().RouteConfigurationError(nil))
		ctx.Handlers().InternalServerError(nil)(wr, rq)
		rou.pool.Put(ctx)
		return
	}

	rou.handler.ServeHTTP(wr, rq)
}

// Use appends a middleware handler to the middleware stack
//
// The middleware stack for any route will execute before searching for a matching
// route to a specific handler, which provides opportunity to respond early,
// change the course of the request execution, or set request-scoped values for
// the next http.Handler
func (rou *impl) Use(middlewares ...func(http.Handler) http.Handler) {
	const errorMiddlewares = "All middlewares must be defined before use"
	if rou.handler != nil {
		rou.errors = append(rou.errors, rou.context.Errors().InternalServerError(fmt.Errorf(errorMiddlewares)))
		return
	}
	rou.middlewares = append(rou.middlewares, middlewares...)
}

// Handle adds the route `pattern` that matches any http method to execute the `handler` http.Handler
func (rou *impl) Handle(pattern string, handler http.Handler) {
	rou.handle(method.Any, pattern, handler)
}

// HandleFunc adds the route `pattern` that matches any http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Any, pattern, handlerFn)
}

// Connect adds the route `pattern` that matches a CONNECT http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Connect(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Connect, pattern, handlerFn)
}

// Delete adds the route `pattern` that matches a DELETE http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Delete(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Delete, pattern, handlerFn)
}

// Get adds the route `pattern` that matches a GET http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Get(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Get, pattern, handlerFn)
}

// Head adds the route `pattern` that matches a HEAD http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Head(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Head, pattern, handlerFn)
}

// Options adds the route `pattern` that matches a OPTIONS http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Options(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Options, pattern, handlerFn)
}

// Patch adds the route `pattern` that matches a PATCH http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Patch(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Patch, pattern, handlerFn)
}

// Post adds the route `pattern` that matches a POST http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Post(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Post, pattern, handlerFn)
}

// Put adds the route `pattern` that matches a PUT http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Put(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Put, pattern, handlerFn)
}

// Trace adds the route `pattern` that matches a TRACE http method to execute the `handlerFn` http.HandlerFunc
func (rou *impl) Trace(pattern string, handlerFn http.HandlerFunc) {
	rou.handle(method.Trace, pattern, handlerFn)
}

// Chain returns a Middlewares type from a slice of middleware handlers
func (rou *impl) Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
	return Middlewares(middlewares)
}

// With adds inline middlewares for an endpoint handler
func (rou *impl) With(middlewares ...func(http.Handler) http.Handler) Interface {
	var mws Middlewares
	var im *impl

	// Similarly as in handle(), we must build the route handler once further
	// middleware registration isn't allowed for this stack, like now
	if !rou.inline && rou.handler == nil {
		rou.buildRouteHandler()
	}

	// Copy middlewares from parent inline route
	if rou.inline {
		mws = make(Middlewares, len(rou.middlewares))
		copy(mws, rou.middlewares)
	}
	mws = append(mws, middlewares...)

	im = &impl{inline: true, parent: rou, tree: rou.tree, middlewares: mws}
	return im
}

// Group creates a new inline-route with a fresh middleware stack. It's useful
// for a group of handlers along the same routing path that use an additional set of middlewares
func (rou *impl) Group(fn func(r Interface)) Interface {
	var im = rou.With().(*impl)
	if fn != nil {
		fn(im)
	}
	return im
}

// Subroute creates a new route with a fresh middleware stack and mounts it
// along the `pattern` as a subrouter. Effectively, this is a short-hand call to Mount
func (rou *impl) Subroute(pattern string, fn func(r Interface)) Interface {
	var subRouter = New()
	if fn != nil {
		fn(subRouter)
	}
	rou.Mount(pattern, subRouter)
	if len(subRouter.(*impl).errors) > 0 {
		rou.errors = append(rou.errors, subRouter.(*impl).errors...)
	}
	return subRouter
}

// Mount attaches another http.Handler or Router as a subrouter along a routing
// path. It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount.
//
// Note that Mount() simply sets a wildcard along the `pattern` that will continue
// routing at the `handler`, which in most cases is another router.
// As a result, if you define two Mount() routes on the exact same pattern the mount will panic
func (rou *impl) Mount(pattern string, handler http.Handler) {
	const existingPath = `Attempting to Mount() a handler on an existing path %q`
	var subr *impl
	var ok bool
	var mtd method.Method
	var n *node
	var subHandler http.HandlerFunc
	var subroutes Routes

	// Provide runtime safety for ensuring a pattern isn't mounted on an existing routing pattern
	if rou.tree.findPattern(pattern+"*") != nil || rou.tree.findPattern(pattern+"/*") != nil {
		rou.errors = append(rou.errors, fmt.Errorf(existingPath, pattern))
		return
	}

	// Assign sub-Router's with the parent not found & method not allowed handler if not specified
	if subr, ok = handler.(*impl); ok && subr.Handlers() != rou.Handlers() {
		subr.Handlers().NotFound(rou.Handlers().NotFound(nil))
		subr.Handlers().MethodNotAllowed(rou.Handlers().MethodNotAllowed(nil))
	}

	// Wrap the sub-router in a handlerFunc to scope the request path for routing.
	subHandler = http.HandlerFunc(func(wr http.ResponseWriter, rq *http.Request) {
		var ctx = context.New(rq)
		ctx.Route().Path("/" + ctx.Route().Params().Del("*"))
		handler.ServeHTTP(wr, rq)
	})

	if pattern == "" || pattern[len(pattern)-1] != '/' {
		rou.handle(method.Any|method.Stub, pattern, subHandler)
		rou.handle(method.Any|method.Stub, pattern+"/", rou.Handlers().NotFound(nil))
		pattern += "/"
	}

	mtd = method.Any
	subroutes, _ = handler.(Routes)
	if subroutes != nil {
		mtd |= method.Stub
	}
	if n = rou.handle(mtd, pattern+"*", subHandler); n == nil {
		return
	}
	if subroutes != nil {
		n.subroutes = subroutes
	}
}

// Middlewares return all middlewares
func (rou *impl) Middlewares() Middlewares { return rou.middlewares }

// Routes Return all routes
func (rou *impl) Routes() []Route { return rou.tree.routes() }

// builds the single handler that is a chain of the middleware stack, as defined by
// calls to Use(), and the tree router itself. After this point, no other middlewares
// can be registered on stack. But you can still compose additional middlewares via
// Group()'s or using a chained middleware handler
func (rou *impl) buildRouteHandler() {
	rou.handler = chain(rou.middlewares, http.HandlerFunc(rou.routeHTTP))
}

// registers a http.Handler in the routing tree for a particular http method and routing pattern
func (rou *impl) handle(mtd method.Method, pattern string, handler http.Handler) (nde *node) {
	const (
		mustBeginWith    = `Routing pattern must begin with '/' in %q`
		insertRouteError = `Insert route error: %s`
	)
	var err error
	var her http.Handler

	if len(pattern) == 0 || pattern[0] != '/' {
		if _, file, line, ok := runtime.Caller(2); ok {
			rou.errors = append(rou.errors, fmt.Errorf(mustBeginWith+" (%s:%d)", pattern, file, line))
		} else {
			rou.errors = append(rou.errors, fmt.Errorf(mustBeginWith, pattern))
		}

		return nil
	}

	// Build the final routing handler for this route
	if !rou.inline && rou.handler == nil {
		rou.buildRouteHandler()
	}

	// Build endpoint handler with inline middlewares for the route

	if rou.inline {
		rou.handler = http.HandlerFunc(rou.routeHTTP)
		her = rou.Chain(rou.middlewares...).Handler(handler)
	} else {
		her = handler
	}

	// Add the endpoint to the tree and return the node
	nde, err = rou.tree.InsertRoute(mtd, pattern, her)
	if err != nil {
		if _, file, line, ok := runtime.Caller(2); ok {
			rou.errors = append(rou.errors, fmt.Errorf(insertRouteError+" (%s:%d)", err, file, line))
		} else {
			rou.errors = append(rou.errors, fmt.Errorf(insertRouteError, err))
		}
		return
	}

	return
}

// routes a http.Request through the routing tree to serve the matching handler for a particular http method
func (rou *impl) routeHTTP(wr http.ResponseWriter, rq *http.Request) {
	var err error
	var ctx context.Interface
	var routePath string
	var mtd method.Method
	var hs methodHandlers
	var h http.Handler
	var ok bool

	// Grab the route context object
	ctx = context.New(rq)
	// The request routing path
	routePath = ctx.Route().Path()
	if routePath == "" {
		if rq.URL.RawPath != "" {
			routePath = rq.URL.RawPath
		} else {
			routePath = rq.URL.Path
		}
	}
	// Check if method is supported
	if mtd, err = method.Parse(rq.Method); err != nil {
		rou.Handlers().MethodNotAllowed(nil).ServeHTTP(wr, rq)
		return
	}
	// Find the route
	hs = rou.tree.FindRoute(ctx, routePath)
	if hs == nil {
		rou.Handlers().NotFound(nil).ServeHTTP(wr, rq)
		return
	}
	if h, ok = hs[mtd]; !ok {
		rou.Handlers().MethodNotAllowed(nil).ServeHTTP(wr, rq)
		return
	}
	// Serve it up
	h.ServeHTTP(wr, rq)
}

// Recursively update data on child routers
//func (rou *impl) updateSubRoutes(fn func(subMux *impl)) {
//	var r Route
//	var ok bool
//	var subMux *impl
//	for _, r = range rou.tree.routes() {
//		subMux, ok = r.SubRoutes.(*impl)
//		if !ok {
//			continue
//		}
//		fn(subMux)
//	}
//}
<|endoftext|>