<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
}

// 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
			}
		}

		fetcher := o.FieldNamesFromStruct
		if fetcher == nil {
			fetcher = DefaultFieldNamesFromStruct
		}
		if keys = fetcher(rv); keys == nil {
			// Can't happen, because we check for reflect.Struct,
			// but for completeness
			return nil, errors.New("panic: can only handle structs")
		}
	default:
		return nil, errors.New("cannot get property names from this value")
	}

	return keys, nil
}

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
	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)
			}
		}

		// Otherwise, try the default way
		fetcher := o.FieldNameFromName
		if fetcher == nil {
			fetcher = DefaultFieldNameFromName
		}
		fn := fetcher(rv, pname)
		if fn == "" {
			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)
		if pval == zeroval {
			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 items 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>Set defaults!<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
}

// 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
			}
		}

		fetcher := o.FieldNamesFromStruct
		if fetcher == nil {
			fetcher = DefaultFieldNamesFromStruct
		}
		if keys = fetcher(rv); keys == nil {
			// Can't happen, because we check for reflect.Struct,
			// but for completeness
			return nil, errors.New("panic: can only handle structs")
		}
	default:
		return nil, errors.New("cannot get property names from this value")
	}

	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 {
	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  + "'")
		}

		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)
			}
		}

		// Otherwise, try the default way
		fetcher := o.FieldNameFromName
		if fetcher == nil {
			fetcher = DefaultFieldNameFromName
		}
		fn := fetcher(rv, pname)
		if fn == "" {
			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)
		if pval == zeroval || reflect.Zero(pval.Type()).Interface() == pval.Interface() {
			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 items 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 gitgo

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"fmt"
	"io"
	"strings"
)

type GitObject interface {
	Type() string
}

type gitObject struct {
	Type string

	// Commit fields
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   string
	Size      string

	// Tree
	Blobs []objectMeta
	Trees []objectMeta

	// Blob
	Contents string
}

type Blob struct {
	_type    string
	size     string
	Contents string
}

func (b Blob) Type() string {
	return b._type

}

type Commit struct {
	_type     string
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   string
	size      string
}

func (c Commit) Type() string {
	return c._type
}

type Tree struct {
	_type string
	Blobs []objectMeta
	Trees []objectMeta
	size  string
}

func (t Tree) Type() string {
	return t._type
}

// objectMeta contains the metadata
// (hash, permissions, and filename)
// corresponding either to a blob (leaf) or another tree
type objectMeta struct {
	Hash     SHA
	Perms    string
	filename string
}

func NewObject(input SHA) (obj GitObject, err error) {
	str, err := CatFile(input)
	if err != nil {
		return
	}
	return parseObj(str)
}

func normalizePerms(perms string) string {
	// TODO don't store permissions as a string
	for len(perms) < 6 {
		perms = "0" + perms
	}
	return perms
}

func parseObj(obj string) (result GitObject, err error) {

	parts := strings.Split(obj, "\x00")
	parts = strings.Fields(parts[0])
	resultType := parts[0]
	resultSize := parts[1]
	nullIndex := strings.Index(obj, "\x00")

	lines := strings.Split(obj[nullIndex+1:], "\n")

	switch resultType {
	case "commit":
		var commit = Commit{_type: resultType, size: resultSize}
		for i, line := range lines {
			// The next line is the commit message
			if len(strings.Fields(line)) == 0 {
				commit.Message = strings.Join(lines[i+1:], "\n")
				break
			}
			parts := strings.Fields(line)
			key := parts[0]
			switch KeyType(key) {
			case TreeKey:
				commit.Tree = parts[1]
			case ParentKey:
				commit.Parents = append(commit.Parents, parts[1])
			case AuthorKey:
				commit.Author = strings.Join(parts[1:], " ")
			case CommitterKey:
				commit.Committer = strings.Join(parts[1:], " ")
			default:
				err = fmt.Errorf("Encounterd unknown field in commit: %s", key)
				return
			}
		}
		result = commit
	case "tree":
		var tree = Tree{_type: resultType, size: resultSize}

		scanner := bufio.NewScanner(bytes.NewBuffer([]byte(obj)))
		scanner.Split(ScanNullLines)

		var tmp objectMeta

		var resultObjs []objectMeta

		for count := 0; ; count++ {
			done := !scanner.Scan()
			if done {
				break
			}

			txt := scanner.Text()

			if count == 0 {
				// the first time through, scanner.Text() will be
				// "tree <size>"
				continue
			}
			if count == 1 {
				// the second time through, scanner.Text() will be
				// <perms> <filename>
				// separated by a space
				fields := strings.Fields(txt)
				tmp.Perms = normalizePerms(fields[0])
				tmp.filename = fields[1]
				continue
			}

			// after the second time through, scanner.Text() will be
			// <sha><perms2> <file2>
			// where perms2 and file2 refer to the permissions and filename (respectively)
			// of the NEXT object, and <sha> is the first 20 bytes exactly.
			// If there is no next object (this is the last object)
			// then scanner.Text() will yield exactly 20 bytes.

			// decode the next 20 bytes to get the SHA
			tmp.Hash = SHA(hex.EncodeToString([]byte(txt[:20])))
			resultObjs = append(resultObjs, tmp)
			if len(txt) <= 20 {
				// We've read the last line
				break
			}

			// Now, tmp points to the next object in the tree listing
			tmp = objectMeta{}
			remainder := txt[20:]
			fields := strings.Fields(remainder)
			tmp.Perms = normalizePerms(fields[0])
			tmp.filename = fields[1]
		}

		if err := scanner.Err(); err != nil && err != io.EOF {
			return tree, err
		}

		for _, part := range resultObjs {
			obj, err := NewObject(part.Hash)
			if err != nil {
				return tree, err
			}
			switch obj.Type() {
			case "tree":
				tree.Trees = append(tree.Trees, part)
			case "blob":
				tree.Blobs = append(tree.Blobs, part)
			default:
				return tree, fmt.Errorf("Unknown type found: %s", obj.Type())
			}
		}
		result = tree
	case "blob":
		var blob = Blob{_type: resultType, size: resultSize}
		blob.Contents = obj[nullIndex+1:]
		result = blob
	default:
		err = fmt.Errorf("Received unknown object type %s", resultType)
	}

	return
}

// ScanNullLines is like bufio.ScanLines, except it uses the null character as the delimiter
// instead of a newline
func ScanNullLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\x00'); i >= 0 {
		// We have a full null-terminated line.
		return i + 1, data[0:i], nil
	}
	// If we're at EOF, we have a final, non-terminated "line". Return it.
	if atEOF {
		return len(data), data, nil
	}
	// Request more data.
	return 0, nil, nil
}
<commit_msg>Fix typo<commit_after>package gitgo

import (
	"bufio"
	"bytes"
	"encoding/hex"
	"fmt"
	"io"
	"strings"
)

type GitObject interface {
	Type() string
}

type gitObject struct {
	Type string

	// Commit fields
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   string
	Size      string

	// Tree
	Blobs []objectMeta
	Trees []objectMeta

	// Blob
	Contents string
}

type Blob struct {
	_type    string
	size     string
	Contents string
}

func (b Blob) Type() string {
	return b._type

}

type Commit struct {
	_type     string
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   string
	size      string
}

func (c Commit) Type() string {
	return c._type
}

type Tree struct {
	_type string
	Blobs []objectMeta
	Trees []objectMeta
	size  string
}

func (t Tree) Type() string {
	return t._type
}

// objectMeta contains the metadata
// (hash, permissions, and filename)
// corresponding either to a blob (leaf) or another tree
type objectMeta struct {
	Hash     SHA
	Perms    string
	filename string
}

func NewObject(input SHA) (obj GitObject, err error) {
	str, err := CatFile(input)
	if err != nil {
		return
	}
	return parseObj(str)
}

func normalizePerms(perms string) string {
	// TODO don't store permissions as a string
	for len(perms) < 6 {
		perms = "0" + perms
	}
	return perms
}

func parseObj(obj string) (result GitObject, err error) {

	parts := strings.Split(obj, "\x00")
	parts = strings.Fields(parts[0])
	resultType := parts[0]
	resultSize := parts[1]
	nullIndex := strings.Index(obj, "\x00")

	lines := strings.Split(obj[nullIndex+1:], "\n")

	switch resultType {
	case "commit":
		var commit = Commit{_type: resultType, size: resultSize}
		for i, line := range lines {
			// The next line is the commit message
			if len(strings.Fields(line)) == 0 {
				commit.Message = strings.Join(lines[i+1:], "\n")
				break
			}
			parts := strings.Fields(line)
			key := parts[0]
			switch KeyType(key) {
			case TreeKey:
				commit.Tree = parts[1]
			case ParentKey:
				commit.Parents = append(commit.Parents, parts[1])
			case AuthorKey:
				commit.Author = strings.Join(parts[1:], " ")
			case CommitterKey:
				commit.Committer = strings.Join(parts[1:], " ")
			default:
				err = fmt.Errorf("Encountered unknown field in commit: %s", key)
				return
			}
		}
		result = commit
	case "tree":
		var tree = Tree{_type: resultType, size: resultSize}

		scanner := bufio.NewScanner(bytes.NewBuffer([]byte(obj)))
		scanner.Split(ScanNullLines)

		var tmp objectMeta

		var resultObjs []objectMeta

		for count := 0; ; count++ {
			done := !scanner.Scan()
			if done {
				break
			}

			txt := scanner.Text()

			if count == 0 {
				// the first time through, scanner.Text() will be
				// "tree <size>"
				continue
			}
			if count == 1 {
				// the second time through, scanner.Text() will be
				// <perms> <filename>
				// separated by a space
				fields := strings.Fields(txt)
				tmp.Perms = normalizePerms(fields[0])
				tmp.filename = fields[1]
				continue
			}

			// after the second time through, scanner.Text() will be
			// <sha><perms2> <file2>
			// where perms2 and file2 refer to the permissions and filename (respectively)
			// of the NEXT object, and <sha> is the first 20 bytes exactly.
			// If there is no next object (this is the last object)
			// then scanner.Text() will yield exactly 20 bytes.

			// decode the next 20 bytes to get the SHA
			tmp.Hash = SHA(hex.EncodeToString([]byte(txt[:20])))
			resultObjs = append(resultObjs, tmp)
			if len(txt) <= 20 {
				// We've read the last line
				break
			}

			// Now, tmp points to the next object in the tree listing
			tmp = objectMeta{}
			remainder := txt[20:]
			fields := strings.Fields(remainder)
			tmp.Perms = normalizePerms(fields[0])
			tmp.filename = fields[1]
		}

		if err := scanner.Err(); err != nil && err != io.EOF {
			return tree, err
		}

		for _, part := range resultObjs {
			obj, err := NewObject(part.Hash)
			if err != nil {
				return tree, err
			}
			switch obj.Type() {
			case "tree":
				tree.Trees = append(tree.Trees, part)
			case "blob":
				tree.Blobs = append(tree.Blobs, part)
			default:
				return tree, fmt.Errorf("Unknown type found: %s", obj.Type())
			}
		}
		result = tree
	case "blob":
		var blob = Blob{_type: resultType, size: resultSize}
		blob.Contents = obj[nullIndex+1:]
		result = blob
	default:
		err = fmt.Errorf("Received unknown object type %s", resultType)
	}

	return
}

// ScanNullLines is like bufio.ScanLines, except it uses the null character as the delimiter
// instead of a newline
func ScanNullLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\x00'); i >= 0 {
		// We have a full null-terminated line.
		return i + 1, data[0:i], nil
	}
	// If we're at EOF, we have a final, non-terminated "line". Return it.
	if atEOF {
		return len(data), data, nil
	}
	// Request more data.
	return 0, nil, nil
}
<|endoftext|>


<commit_before>package cwl

import (
	"crypto/sha1"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/otiai10/jsonindent"
)

// Output represents and conbines "CommandOutputParameter" and "WorkflowOutputParameter"
// @see
// - http://www.commonwl.org/v1.0/CommandLineTool.html#CommandOutputParameter
// - http://www.commonwl.org/v1.0/Workflow.html#WorkflowOutputParameter
type Output struct {
	ID             string   `json:"id"`
	Label          string   `json:"label"`
	Doc            []string `json:"doc"`
	Format         string   `json:"format"`
	Binding        *Binding `json:"outputBinding"`
	Source         []string `json:"outputSource"`
	Types          []Type   `json:"type"`
	SecondaryFiles []SecondaryFile

	// Loaded Contents if Binding.LoadContents == true
	Contents interface{} `json:"contents"`
}

// New constructs "Output" struct from interface.
func (o Output) New(i interface{}) Output {
	dest := Output{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "outputBinding":
				dest.Binding = Binding{}.New(v)
			case "outputSource":
				dest.Source = StringArrayable(v)
			case "doc":
				dest.Doc = StringArrayable(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
	case string:
		dest.Types = Type{}.NewList(x)
	}
	return dest
}

// Outputs represents "outputs" field in "CWL".
type Outputs []Output

// New constructs "Outputs" struct.
func (outs Outputs) New(i interface{}) Outputs {
	dest := Outputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Output{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			output := Output{}.New(v)
			output.ID = key
			dest = append(dest, output)
		}
	}
	return dest
}

// Len for sorting
func (outs Outputs) Len() int {
	return len(outs)
}

// Less for sorting
func (outs Outputs) Less(i, j int) bool {
	prev, next := outs[i].Binding, outs[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return false
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting
func (outs Outputs) Swap(i, j int) {
	outs[i], outs[j] = outs[j], outs[i]
}

// Dump ...
func (outs Outputs) Dump(dir string, stdout, stderr string, w io.Writer) error {

	dest := map[string]map[string]interface{}{}
	for _, o := range outs {
		if err := o.DumpFileMeta(dest, dir, stdout, stderr, w); err != nil {
			return err
		}
	}
	return nil
}

// DumpFileMeta ...
func (o Output) DumpFileMeta(dest map[string]map[string]interface{}, dir string, stdout, stderr string, w io.Writer) error {

	// This output should not be dumped
	if o.Binding != nil && o.Binding.LoadContents {
		return nil
	}

	switch o.Types[0].Type {
	case "File":
		for _, glob := range o.Binding.Glob {
			metadata, err := getFileMetaData(filepath.Join(dir, glob))
			if err != nil {
				return err
			}
			dest[o.ID] = metadata
		}
	case "stdout":
		name := o.ID
		if stdout != "" && name != stdout {
			name = stdout
		}
		metadata, err := getFileMetaData(filepath.Join(dir, name))
		if err != nil {
			return err
		}
		dest[o.ID] = metadata
	case "stderr":
		name := o.ID
		if stderr != "" && name != stderr {
			name = stderr
		}
		metadata, err := getFileMetaData(filepath.Join(dir, name))
		if err != nil {
			return err
		}
		dest[o.ID] = metadata
	default:
		return nil // do nothing
	}

	return jsonindent.NewEncoder(w).Encode(dest)
}

// getFileMetaData
func getFileMetaData(targetfilepath string) (map[string]interface{}, error) {
	targetfile, err := os.Open(targetfilepath)
	if err != nil {
		return nil, err
	}
	defer targetfile.Close()
	info, err := os.Stat(targetfilepath)
	if err != nil {
		return nil, err
	}
	h := sha1.New()
	if _, err := io.Copy(h, targetfile); err != nil {
		return nil, err
	}
	return map[string]interface{}{
		"checksum": fmt.Sprintf("sha1$%x", string(h.Sum(nil))),
		"basename": filepath.Base(targetfilepath),
		"location": fmt.Sprintf("file://%s", targetfilepath),
		"path":     targetfilepath,
		"class":    "File",
		"size":     info.Size(),
	}, nil
}
<commit_msg>Nonsense refactor: Pass otto VM<commit_after>package cwl

import (
	"crypto/sha1"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/robertkrimen/otto"

	"github.com/otiai10/jsonindent"
)

// Output represents and conbines "CommandOutputParameter" and "WorkflowOutputParameter"
// @see
// - http://www.commonwl.org/v1.0/CommandLineTool.html#CommandOutputParameter
// - http://www.commonwl.org/v1.0/Workflow.html#WorkflowOutputParameter
type Output struct {
	ID             string   `json:"id"`
	Label          string   `json:"label"`
	Doc            []string `json:"doc"`
	Format         string   `json:"format"`
	Binding        *Binding `json:"outputBinding"`
	Source         []string `json:"outputSource"`
	Types          []Type   `json:"type"`
	SecondaryFiles []SecondaryFile

	// Loaded Contents if Binding.LoadContents == true
	Contents interface{} `json:"contents"`
}

// New constructs "Output" struct from interface.
func (o Output) New(i interface{}) Output {
	dest := Output{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "outputBinding":
				dest.Binding = Binding{}.New(v)
			case "outputSource":
				dest.Source = StringArrayable(v)
			case "doc":
				dest.Doc = StringArrayable(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
	case string:
		dest.Types = Type{}.NewList(x)
	}
	return dest
}

// Outputs represents "outputs" field in "CWL".
type Outputs []Output

// New constructs "Outputs" struct.
func (outs Outputs) New(i interface{}) Outputs {
	dest := Outputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Output{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			output := Output{}.New(v)
			output.ID = key
			dest = append(dest, output)
		}
	}
	return dest
}

// Len for sorting
func (outs Outputs) Len() int {
	return len(outs)
}

// Less for sorting
func (outs Outputs) Less(i, j int) bool {
	prev, next := outs[i].Binding, outs[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return false
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting
func (outs Outputs) Swap(i, j int) {
	outs[i], outs[j] = outs[j], outs[i]
}

// LoadContents ...
func (outs Outputs) LoadContents() (*otto.Otto, error) {
	return nil, nil
}

// Dump ...
func (outs Outputs) Dump(vm *otto.Otto, dir string, stdout, stderr string, w io.Writer) error {

	dest := map[string]map[string]interface{}{}
	for _, o := range outs {
		if err := o.DumpFileMeta(dest, dir, stdout, stderr, w); err != nil {
			return err
		}
	}
	return nil
}

// DumpFileMeta ...
func (o Output) DumpFileMeta(dest map[string]map[string]interface{}, dir string, stdout, stderr string, w io.Writer) error {

	// This output should not be dumped
	if o.Binding != nil && o.Binding.LoadContents {
		return nil
	}

	switch o.Types[0].Type {
	case "File":
		for _, glob := range o.Binding.Glob {
			metadata, err := getFileMetaData(filepath.Join(dir, glob))
			if err != nil {
				return err
			}
			dest[o.ID] = metadata
		}
	case "stdout":
		name := o.ID
		if stdout != "" && name != stdout {
			name = stdout
		}
		metadata, err := getFileMetaData(filepath.Join(dir, name))
		if err != nil {
			return err
		}
		dest[o.ID] = metadata
	case "stderr":
		name := o.ID
		if stderr != "" && name != stderr {
			name = stderr
		}
		metadata, err := getFileMetaData(filepath.Join(dir, name))
		if err != nil {
			return err
		}
		dest[o.ID] = metadata
	default:
		return nil // do nothing
	}

	return jsonindent.NewEncoder(w).Encode(dest)
}

// getFileMetaData
func getFileMetaData(targetfilepath string) (map[string]interface{}, error) {
	targetfile, err := os.Open(targetfilepath)
	if err != nil {
		return nil, err
	}
	defer targetfile.Close()
	info, err := os.Stat(targetfilepath)
	if err != nil {
		return nil, err
	}
	h := sha1.New()
	if _, err := io.Copy(h, targetfile); err != nil {
		return nil, err
	}
	return map[string]interface{}{
		"checksum": fmt.Sprintf("sha1$%x", string(h.Sum(nil))),
		"basename": filepath.Base(targetfilepath),
		"location": fmt.Sprintf("file://%s", targetfilepath),
		"path":     targetfilepath,
		"class":    "File",
		"size":     info.Size(),
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	X, Y int
}

type sprite struct {
	Name   string
	Offset image.Point
	Size   Size
	img    image.Image
	area   int
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

type Node struct {
	child [2]*Node
	rect  image.Rectangle
	img   *sprite
}

func (n *Node) size() Size {
	return Size{n.rect.Dx(), n.rect.Dy()}
}

func (n *Node) print() {
	fmt.Println(n)
	if n.child[0] != nil {
		n.child[0].print()
	}
	if n.child[1] != nil {
		n.child[1].print()
	}
}

func (n *Node) isLeaf() bool {
	return n.child[0] == nil || n.child[1] == nil
}

func (n *Node) insert(img *sprite) *Node {
	if !n.isLeaf() {
		node := n.child[0].insert(img)

		if node != nil {
			return node
		} else {
			return n.child[1].insert(img)
		}
	}

	// there is already an image in this node
	if n.img != nil {
		return nil
	}

	// space too small
	if n.rect.Dx() < img.Size.X || n.rect.Dy() < img.Size.Y {
		return nil
	}

	// just right
	if n.rect.Dx() == img.Size.X && n.rect.Dy() == img.Size.Y {
		img.Offset = n.rect.Min
		n.img = img
		return n
	}

	// the space that is left will be large enough to split
	n.split(img)

	return n.child[0].insert(img)
}

func (n *Node) split(img *sprite) {
	dx := n.rect.Dx() - img.Size.X
	dy := n.rect.Dy() - img.Size.Y

	if dx > dy {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Min.X+img.Size.X,
			n.rect.Max.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X+img.Size.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	} else {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Min.Y+img.Size.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y+img.Size.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	}

}

func main() {
	var space int
	var dim string

	flag.IntVar(&space, "space", 1, "space added between images")
	flag.StringVar(&dim, "dimensions", "1024x1024", "atlas size")

	flag.Parse()

	args := flag.Args()

	inputDir := args[0]
	outputName := args[1]

	dimX, dimY, err := parseDimensions(dim)
	if err != nil {
		log.Fatal(err)
	}

	files, err := ioutil.ReadDir(inputDir)
	if err != nil {
		log.Fatal(err)
	}

	sprites := make([]sprite, len(files))

	totalArea := 0

	for i := range sprites {
		s, err := readSprite(inputDir, files[i].Name(), space)
		if err != nil {
			log.Fatal(err)
		}
		totalArea += s.area
		sprites[i] = s
	}

	if totalArea > dimX*dimY {
		log.Fatalf("%s atlas to small", dim)
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	img := image.NewRGBA(image.Rect(0, 0, dimX, dimY))

	n := Node{rect: image.Rect(0, 0, dimX, dimY)}

	var data []byte

	for i := range sprites {
		s := &sprites[i]
		node := n.insert(s)

		j, err := json.Marshal(s)
		if err != nil {
			log.Fatal(err)
		}
		data = append(data, j...)

		if node != nil {
			draw.Draw(img, node.rect, s.img, image.ZP, draw.Src)
		} else {
			log.Fatalf("could not place %s\n", s.Name)
		}

	}

	err = writeAtlas(outputName, img, data)
	if err != nil {
		log.Fatal(err)
	}
}

func parseDimensions(dim string) (dimX, dimY int, err error) {
	dims := strings.Split(dim, "x")
	if len(dims) != 2 {
		err = fmt.Errorf("couldn't parse dimension %s\n", dims)
		return
	}

	dimX, err = strconv.Atoi(dims[0])
	if err != nil {
		return
	}

	dimY, err = strconv.Atoi(dims[1])
	if err != nil {
		return
	}

	return
}

func readSprite(dir, name string, space int) (s sprite, err error) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err := image.Decode(reader)
	if err != nil {
		return
	}

	s.Name = strings.TrimSuffix(name, filepath.Ext(name))
	s.img = img
	rect := img.Bounds()
	s.Size = Size{rect.Dx() + space, rect.Dy() + space}
	s.area = s.Size.X * s.Size.Y
	return
}

func writeAtlas(name string, img *image.RGBA, data []byte) (err error) {
	imageName := name + ".png"
	dataName := name + ".json"

	imageWriter, err := os.Create(imageName)
	if err != nil {
		return
	}
	defer imageWriter.Close()

	dataWriter, err := os.Create(dataName)
	if err != nil {
		return
	}
	defer dataWriter.Close()

	_, err = dataWriter.Write(data)
	if err != nil {
		return
	}

	err = png.Encode(imageWriter, img)
	if err != nil {
		return
	}

	return
}
<commit_msg>More informative error on json write failure<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"

	"image"
	"image/draw"
	"image/png"
)

type Size struct {
	X, Y int
}

type sprite struct {
	Name   string
	Offset image.Point
	Size   Size
	img    image.Image
	area   int
}

type ByArea []sprite

func (a ByArea) Len() int           { return len(a) }
func (a ByArea) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByArea) Less(i, j int) bool { return a[i].area < a[j].area }

type Node struct {
	child [2]*Node
	rect  image.Rectangle
	img   *sprite
}

func (n *Node) size() Size {
	return Size{n.rect.Dx(), n.rect.Dy()}
}

func (n *Node) print() {
	fmt.Println(n)
	if n.child[0] != nil {
		n.child[0].print()
	}
	if n.child[1] != nil {
		n.child[1].print()
	}
}

func (n *Node) isLeaf() bool {
	return n.child[0] == nil || n.child[1] == nil
}

func (n *Node) insert(img *sprite) *Node {
	if !n.isLeaf() {
		node := n.child[0].insert(img)

		if node != nil {
			return node
		} else {
			return n.child[1].insert(img)
		}
	}

	// there is already an image in this node
	if n.img != nil {
		return nil
	}

	// space too small
	if n.rect.Dx() < img.Size.X || n.rect.Dy() < img.Size.Y {
		return nil
	}

	// just right
	if n.rect.Dx() == img.Size.X && n.rect.Dy() == img.Size.Y {
		img.Offset = n.rect.Min
		n.img = img
		return n
	}

	// the space that is left will be large enough to split
	n.split(img)

	return n.child[0].insert(img)
}

func (n *Node) split(img *sprite) {
	dx := n.rect.Dx() - img.Size.X
	dy := n.rect.Dy() - img.Size.Y

	if dx > dy {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Min.X+img.Size.X,
			n.rect.Max.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X+img.Size.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	} else {
		n.child[0] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y,
			n.rect.Max.X,
			n.rect.Min.Y+img.Size.Y)}
		n.child[1] = &Node{rect: image.Rect(
			n.rect.Min.X,
			n.rect.Min.Y+img.Size.Y,
			n.rect.Max.X,
			n.rect.Max.Y)}
	}

}

func main() {
	var space int
	var dim string

	flag.IntVar(&space, "space", 1, "space added between images")
	flag.StringVar(&dim, "dimensions", "1024x1024", "atlas size")

	flag.Parse()

	args := flag.Args()

	inputDir := args[0]
	outputName := args[1]

	dimX, dimY, err := parseDimensions(dim)
	if err != nil {
		log.Fatal(err)
	}

	files, err := ioutil.ReadDir(inputDir)
	if err != nil {
		log.Fatal(err)
	}

	sprites := make([]sprite, len(files))

	totalArea := 0

	for i := range sprites {
		s, err := readSprite(inputDir, files[i].Name(), space)
		if err != nil {
			log.Fatal(err)
		}
		totalArea += s.area
		sprites[i] = s
	}

	if totalArea > dimX*dimY {
		log.Fatalf("%s atlas to small", dim)
	}

	// we want to place the largest sprite first
	sort.Sort(sort.Reverse(ByArea(sprites)))

	// the final image
	img := image.NewRGBA(image.Rect(0, 0, dimX, dimY))

	n := Node{rect: image.Rect(0, 0, dimX, dimY)}

	var data []byte

	for i := range sprites {
		s := &sprites[i]
		node := n.insert(s)

		j, err := json.Marshal(s)
		if err != nil {
			log.Fatal(err)
		}
		data = append(data, j...)

		if node != nil {
			draw.Draw(img, node.rect, s.img, image.ZP, draw.Src)
		} else {
			log.Fatalf("could not place %s\n", s.Name)
		}

	}

	err = writeAtlas(outputName, img, data)
	if err != nil {
		log.Fatal(err)
	}
}

func parseDimensions(dim string) (dimX, dimY int, err error) {
	dims := strings.Split(dim, "x")
	if len(dims) != 2 {
		err = fmt.Errorf("couldn't parse dimension %s\n", dims)
		return
	}

	dimX, err = strconv.Atoi(dims[0])
	if err != nil {
		return
	}

	dimY, err = strconv.Atoi(dims[1])
	if err != nil {
		return
	}

	return
}

func readSprite(dir, name string, space int) (s sprite, err error) {
	path := path.Join(dir, name)
	reader, err := os.Open(path)
	if err != nil {
		return
	}
	defer reader.Close()

	img, _, err := image.Decode(reader)
	if err != nil {
		return
	}

	s.Name = strings.TrimSuffix(name, filepath.Ext(name))
	s.img = img
	rect := img.Bounds()
	s.Size = Size{rect.Dx() + space, rect.Dy() + space}
	s.area = s.Size.X * s.Size.Y
	return
}

func writeAtlas(name string, img *image.RGBA, data []byte) error {
	imageName := name + ".png"
	dataName := name + ".json"

	imageWriter, err := os.Create(imageName)
	if err != nil {
		return err
	}
	defer imageWriter.Close()

	dataWriter, err := os.Create(dataName)
	if err != nil {
		return err
	}
	defer dataWriter.Close()

	n, err := dataWriter.Write(data)
	if err != nil {
		return fmt.Errorf("position: %d error: %s", n, err)
	}

	err = png.Encode(imageWriter, img)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Markus Dittrich. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// pagoda is a go library for command line parsing
package pagoda

import (
  "encoding/json"
  "os"
  "fmt"
  "strconv"
  "unicode/utf8"
)

// parse_spec describes all options and usage actually present on the
// command line and also keeps track of any remaining command line entries
type parsedSpec struct {
  templateSpec
  cmdlOptions []*jsonOption
  remainder []string      // unparsed remainder of command line
}

// target_spec describes all possible options and usage per json spec file
type templateSpec struct {
  Usage_info string
  Options []jsonOption    // options according to the spec
}

// json_option describes a single option specification as parsed from the
// JSON description
type jsonOption struct {
  Short_option string
  Long_option string
  Description string
  Type string
  Default *string      // use a pointer to be able to distinguish the empty
                       // string from non-present option
  value interface{}    // option value of type Type
}

// Value returns the value known for the given option. Either the
// long or short option can be provided.
// NOTE: The look up could be made more efficient via a map
func (p *parsedSpec) Value(key string) (interface{}, error) {

  for _, opt := range p.cmdlOptions {
    if key == opt.Short_option || key == opt.Long_option {
      return opt.value, nil
    }
  }

  return nil, fmt.Errorf("command line option %s not found", key)
}

// Remainder returns a slice with all command line options that
// were not parsed into options
func (p *parsedSpec) Remainder() []string {
  return p.remainder
}

// Init parses the specification of option in JSON format
func Init(content []byte) (*parsedSpec, error) {

  var parse_info templateSpec
  err := json.Unmarshal(content, &parse_info)
  if err != nil {
    return nil, err
  }

  err = validate_specs(&parse_info)
  if err != nil {
    return nil, err
  }

  err = extract_defaults(&parse_info)
  if err != nil {
    return nil, err
  }

  inject_default_help_option(&parse_info)

  matched_info, err := match_spec_to_args(&parse_info, os.Args)
  if err != nil {
    return nil, err
  }

  // check if help was requested. In that case show Usage() and then exit
  if _, err := matched_info.Value("h"); err == nil {
    matched_info.Usage()
    os.Exit(0)
  }

  return matched_info, nil
}

// Usage prints the usage information for the package
func (p *parsedSpec) Usage() {
  fmt.Printf("Usage: %s %s\n", os.Args[0], p.Usage_info)
  fmt.Println()
  for _, opt := range p.Options {

    if opt.Long_option == "" {
      fmt.Printf("\t-%s             %s", opt.Short_option, opt.Description)
    } else if opt.Short_option == "" {
      fmt.Printf("\t    --%-10s  %s", opt.Long_option, opt.Description)
    } else {
      fmt.Printf("\t-%s  --%-10s  %s", opt.Short_option, opt.Long_option,
        opt.Description)
    }

    if opt.Default != nil && opt.Type != "bool" {
      fmt.Printf("  [default: %s]", *opt.Default)
    }
    fmt.Printf("\n")
  }
}

// validate_defaults checks that a usage string was given and
// that each spec has at least a short or a long option
func validate_specs(parse_info *templateSpec) error {
  if parse_info.Usage_info == "" {
    return fmt.Errorf("Usage string missing")
  }

  for _, opt := range parse_info.Options {
    if opt.Short_option == "" && opt.Long_option == "" {
      return fmt.Errorf("Need at least a short or long description.")
    }

    if opt.Type == "" {
      return fmt.Errorf("Need a type descriptor for option %s.",
        opt.Short_option)
    }
  }

  return nil
}

// extract_defaults extracts the default field in the proper type
func extract_defaults(parse_info *templateSpec) error {

  opts := parse_info.Options
  for i := 0; i < len(opts); i++ {
    if opts[i].Default != nil {
      val, err := string_to_type(*opts[i].Default, opts[i].Type)
      if err != nil {
        return err
      }

      opts[i].value = val
    }
  }

  return nil
}

// string_to_type converts value to the requested type and strows
// an error if that fails
func string_to_type(value string, theType string) (interface{}, error) {

  switch theType {
  case "bool":
    if value == "true" {
      return true, nil
    } else if value == "false" {
      return false, nil
    } else {
      return nil, fmt.Errorf("cannot convert %s to requested type %s",
        value, theType)
    }

  case "int":
    if i, err := strconv.Atoi(value); err == nil {
      return i, nil
    } else {
      return nil, fmt.Errorf("cannot convert %s to requested type %s",
        value, theType)
    }

  case "float":
    if v, err := strconv.ParseFloat(value, 64); err == nil {
      return v, nil
    } else {
      return nil, fmt.Errorf("cannot convert %s to requested type %s",
        value, theType)
    }

  case "string":
    return value, nil

  default:
    return nil, fmt.Errorf("unknow type %s", theType)
  }
}

// inject_default_help_option adds a default help option to the list of
// command line switches
func inject_default_help_option(spec *templateSpec) {

  helpDefault := "true"
  spec.Options = append(spec.Options,
    jsonOption{"h", "help", "print this help text and exit", "bool",
      &helpDefault, nil})
}

// test_for_option determines if a string is an option (i.e. starts
// either with a dash ('-') or a double dash ('--')). In that
// case it returns the name of the option and the value if the
// option was given via --opt=val.
func decode_option(item string) (string, string, bool) {

  // check for dash
  c, s := utf8.DecodeRuneInString(item)
  if s == 0 || string(c) != "-" {
    return "", "", false
  }
  i := s

  // skip next dash if present
  c, s = utf8.DecodeRuneInString(item[i:])
  if s != 0 && string(c) == "-" {
    i += s;
  }

  // scan until end of string or until we hit a "="
  opt := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    } else if string(c) == "=" {
      break
    }

    opt += string(c)
  }

  // scan for optional value specified via opt=val
  val := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    }

    val += string(c)
  }

  return opt, val, true
}

// find_option retrieves the parse_spec option entry corresponding
// to the given name f present. Otherwise returns false.
func find_parse_spec(spec *templateSpec, name string) (*jsonOption, bool) {

  opts := spec.Options
  for i := 0; i < len(opts); i++ {
    if opts[i].Short_option == name || opts[i].Long_option == name {
      return &opts[i], true
    }
  }

  return &jsonOption{}, false
}

// match_spec_to_args matches a parse_info spec to the provided command
// line options. Entries in parse_info which are lacking are ignored.
// If the command line contains entries which are not in the spec the
// function throws an error.
// NOTE: We catch the option -h as the help option
func match_spec_to_args(template *templateSpec, args []string) (*parsedSpec,
  error) {

  // initialize final parsed specs
  parsed := parsedSpec{}
  parsed.Options = template.Options
  parsed.cmdlOptions = make([]*jsonOption, 0)
  parsed.Usage_info = template.Usage_info

  var opt_name, opt_val string
  var ok bool
  for i := 1; i < len(args); i++ {
    opt_name, opt_val, ok = decode_option(args[i])
    if !ok {
      parsed.remainder = args[i:]
      break
    }

    opt_spec, ok := find_parse_spec(template, opt_name)
    if !ok {
      return nil, fmt.Errorf("Unknown command line option %s", args[i])
    }

    // if the option is not of type bool and we don't have
    // a value yet we peak at the next arg if present
    if opt_val == "" && opt_spec.Type != "bool" {
      if i+1 < len(args) {
        if _, _, ok := decode_option(args[i+1]); !ok {
          i++
          opt_val = args[i]
        }
      }
    }

    // check that we got a value if the option doesn't have default
    if opt_spec.Default == nil && opt_val == "" {
      return nil, fmt.Errorf("Missing value for option %s",
        opt_spec.Short_option)
    }

    // check that the provided option has the correct type
    if opt_val != "" {
      val, err := string_to_type(opt_val, opt_spec.Type)
      if err != nil {
        return nil, err
      }
      opt_spec.value = val
    }

    parsed.cmdlOptions = append(parsed.cmdlOptions, opt_spec)
  }
  return &parsed, nil
}
<commit_msg>Improved error messages.<commit_after>// Copyright 2014 Markus Dittrich. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// pagoda is a go library for command line parsing
package pagoda

import (
  "encoding/json"
  "os"
  "fmt"
  "strconv"
  "unicode/utf8"
)

// parse_spec describes all options and usage actually present on the
// command line and also keeps track of any remaining command line entries
type parsedSpec struct {
  templateSpec
  cmdlOptions []*jsonOption
  remainder []string      // unparsed remainder of command line
}

// target_spec describes all possible options and usage per json spec file
type templateSpec struct {
  Usage_info string
  Options []jsonOption    // options according to the spec
}

// json_option describes a single option specification as parsed from the
// JSON description
type jsonOption struct {
  Short_option string
  Long_option string
  Description string
  Type string
  Default *string      // use a pointer to be able to distinguish the empty
                       // string from non-present option
  value interface{}    // option value of type Type
}

// Value returns the value known for the given option. Either the
// long or short option can be provided.
// NOTE: The look up could be made more efficient via a map
func (p *parsedSpec) Value(key string) (interface{}, error) {

  for _, opt := range p.cmdlOptions {
    if key == opt.Short_option || key == opt.Long_option {
      return opt.value, nil
    }
  }

  return nil, fmt.Errorf("Pagoda: command line option %s not found", key)
}

// Remainder returns a slice with all command line options that
// were not parsed into options
func (p *parsedSpec) Remainder() []string {
  return p.remainder
}

// Init parses the specification of option in JSON format
func Init(content []byte) (*parsedSpec, error) {

  var parse_info templateSpec
  err := json.Unmarshal(content, &parse_info)
  if err != nil {
    return nil, err
  }

  err = validate_specs(&parse_info)
  if err != nil {
    return nil, err
  }

  err = extract_defaults(&parse_info)
  if err != nil {
    return nil, err
  }

  inject_default_help_option(&parse_info)

  matched_info, err := match_spec_to_args(&parse_info, os.Args)
  if err != nil {
    return nil, err
  }

  // check if help was requested. In that case show Usage() and then exit
  if _, err := matched_info.Value("h"); err == nil {
    matched_info.Usage()
    os.Exit(0)
  }

  return matched_info, nil
}

// Usage prints the usage information for the package
func (p *parsedSpec) Usage() {
  fmt.Printf("Usage: %s %s\n", os.Args[0], p.Usage_info)
  fmt.Println()
  for _, opt := range p.Options {

    if opt.Long_option == "" {
      fmt.Printf("\t-%-15s  %s", opt.Short_option, opt.Description)
    } else if opt.Short_option == "" {
      fmt.Printf("\t    --%-10s  %s", opt.Long_option, opt.Description)
    } else {
      fmt.Printf("\t-%s  --%-10s  %s", opt.Short_option, opt.Long_option,
        opt.Description)
    }

    if opt.Default != nil && opt.Type != "bool" {
      fmt.Printf("  [default: %s]", *opt.Default)
    }
    fmt.Printf("\n")
  }
}

// validate_defaults checks that a usage string was given and
// that each spec has at least a short or a long option
func validate_specs(parse_info *templateSpec) error {
  if parse_info.Usage_info == "" {
    return fmt.Errorf("Pagoda: Usage string missing")
  }

  for _, opt := range parse_info.Options {
    if opt.Short_option == "" && opt.Long_option == "" {
      return fmt.Errorf("Pagoda: Need at least a short or long description.")
    }

    if opt.Type == "" {
      return fmt.Errorf("Pagoda: Need a type descriptor for option %s.",
        opt.Short_option)
    }
  }

  return nil
}

// extract_defaults extracts the default field in the proper type
func extract_defaults(parse_info *templateSpec) error {

  opts := parse_info.Options
  for i := 0; i < len(opts); i++ {
    if opts[i].Default != nil {
      val, err := string_to_type(*opts[i].Default, opts[i].Type)
      if err != nil {
        return err
      }

      opts[i].value = val
    }
  }

  return nil
}

// string_to_type converts value to the requested type and strows
// an error if that fails
func string_to_type(value string, theType string) (interface{}, error) {

  switch theType {
  case "bool":
    if value == "true" {
      return true, nil
    } else if value == "false" {
      return false, nil
    } else {
      return nil, fmt.Errorf("cannot convert %s to requested type %s",
        value, theType)
    }

  case "int":
    if i, err := strconv.Atoi(value); err == nil {
      return i, nil
    } else {
      return nil, fmt.Errorf("Pagoda: cannot convert %s to requested type %s",
        value, theType)
    }

  case "float":
    if v, err := strconv.ParseFloat(value, 64); err == nil {
      return v, nil
    } else {
      return nil, fmt.Errorf("Pagoda: cannot convert %s to requested type %s",
        value, theType)
    }

  case "string":
    return value, nil

  default:
    return nil, fmt.Errorf("Pagoda: unknow type %s", theType)
  }
}

// inject_default_help_option adds a default help option to the list of
// command line switches
func inject_default_help_option(spec *templateSpec) {

  helpDefault := "true"
  spec.Options = append(spec.Options,
    jsonOption{"h", "help", "print this help text and exit", "bool",
      &helpDefault, nil})
}

// test_for_option determines if a string is an option (i.e. starts
// either with a dash ('-') or a double dash ('--')). In that
// case it returns the name of the option and the value if the
// option was given via --opt=val.
func decode_option(item string) (string, string, bool) {

  // check for dash
  c, s := utf8.DecodeRuneInString(item)
  if s == 0 || string(c) != "-" {
    return "", "", false
  }
  i := s

  // skip next dash if present
  c, s = utf8.DecodeRuneInString(item[i:])
  if s != 0 && string(c) == "-" {
    i += s;
  }

  // scan until end of string or until we hit a "="
  opt := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    } else if string(c) == "=" {
      break
    }

    opt += string(c)
  }

  // scan for optional value specified via opt=val
  val := ""
  for i < len(item) {
    c, s = utf8.DecodeRuneInString(item[i:])
    i += s

    if s == 0 {
      return "", "", false
    }

    val += string(c)
  }

  return opt, val, true
}

// find_option retrieves the parse_spec option entry corresponding
// to the given name f present. Otherwise returns false.
func find_parse_spec(spec *templateSpec, name string) (*jsonOption, bool) {

  opts := spec.Options
  for i := 0; i < len(opts); i++ {
    if opts[i].Short_option == name || opts[i].Long_option == name {
      return &opts[i], true
    }
  }

  return &jsonOption{}, false
}

// match_spec_to_args matches a parse_info spec to the provided command
// line options. Entries in parse_info which are lacking are ignored.
// If the command line contains entries which are not in the spec the
// function throws an error.
// NOTE: We catch the option -h as the help option
func match_spec_to_args(template *templateSpec, args []string) (*parsedSpec,
  error) {

  // initialize final parsed specs
  parsed := parsedSpec{}
  parsed.Options = template.Options
  parsed.cmdlOptions = make([]*jsonOption, 0)
  parsed.Usage_info = template.Usage_info

  var opt_name, opt_val string
  var ok bool
  for i := 1; i < len(args); i++ {
    opt_name, opt_val, ok = decode_option(args[i])
    if !ok {
      parsed.remainder = args[i:]
      break
    }

    opt_spec, ok := find_parse_spec(template, opt_name)
    if !ok {
      return nil, fmt.Errorf("Pagoda: Unknown command line option %s", args[i])
    }

    // if the option is not of type bool and we don't have
    // a value yet we peak at the next arg if present
    if opt_val == "" && opt_spec.Type != "bool" {
      if i+1 < len(args) {
        if _, _, ok := decode_option(args[i+1]); !ok {
          i++
          opt_val = args[i]
        }
      }
    }

    // check that we got a value if the option doesn't have default
    if opt_spec.Default == nil && opt_val == "" {
      return nil, fmt.Errorf("Pagoda: Missing value for option %s",
        opt_spec.Short_option)
    }

    // check that the provided option has the correct type
    if opt_val != "" {
      val, err := string_to_type(opt_val, opt_spec.Type)
      if err != nil {
        return nil, err
      }
      opt_spec.value = val
    }

    parsed.cmdlOptions = append(parsed.cmdlOptions, opt_spec)
  }
  return &parsed, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"io"
	"regexp"
	"strconv"
)

const (
	GCRegexpGo14 = `gc\d+\(\d+\): ([\d.]+\+?)+ us, \d+ -> (?P<Heap1>\d+) MB, \d+ \(\d+-\d+\) objects,( \d+ goroutines,)? \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`
	GCRegexpGo15 = `^gc (#)\d+ @[\d.]+s \d+%: [\d.+/]+ ms clock, [\d.+/]+ ms cpu, \d+->\d+->\d+ MB, (?P<Heap1>\d+) MB goal, \d+ P`
	SCVGRegexp   = `scvg\d+: inuse: (?P<inuse>\d+), idle: (?P<idle>\d+), sys: (?P<sys>\d+), released: (?P<released>\d+), consumed: (?P<consumed>\d+) \(MB\)`
)

var (
	gcrego14 = regexp.MustCompile(GCRegexpGo14)
	gcrego15 = regexp.MustCompile(GCRegexpGo15)
	scvgre   = regexp.MustCompile(SCVGRegexp)
)

type Parser struct {
	reader      io.Reader
	GcChan      chan *gctrace
	ScvgChan    chan *scvgtrace
	NoMatchChan chan string
	done        chan bool

	Err error

	scvgRegexp *regexp.Regexp
}

func NewParser(r io.Reader) *Parser {
	return &Parser{
		reader:      r,
		GcChan:      make(chan *gctrace, 1),
		ScvgChan:    make(chan *scvgtrace, 1),
		NoMatchChan: make(chan string, 1),
		done:        make(chan bool),
	}
}

func (p *Parser) Run() {
	sc := bufio.NewScanner(p.reader)

	for sc.Scan() {
		line := sc.Text()

		if result := gcrego15.FindStringSubmatch(line); result != nil {
			p.GcChan <- parseGCTrace(gcrego15, result)
			continue
		}

		if result := gcrego14.FindStringSubmatch(line); result != nil {
			p.GcChan <- parseGCTrace(gcrego14, result)
			continue
		}

		if result := scvgre.FindStringSubmatch(line); result != nil {
			p.ScvgChan <- parseSCVGTrace(result)
			continue
		}

		p.NoMatchChan <- line
	}

	p.Err = sc.Err()

	close(p.done)
}

func parseGCTrace(gcre *regexp.Regexp, matches []string) *gctrace {
	matchMap := getMatchMap(gcre, matches)

	return &gctrace{
		Heap1: matchMap["Heap1"],
	}
}

func parseSCVGTrace(matches []string) *scvgtrace {
	matchMap := getMatchMap(scvgre, matches)

	return &scvgtrace{
		inuse:    matchMap["inuse"],
		idle:     matchMap["idle"],
		sys:      matchMap["sys"],
		released: matchMap["released"],
		consumed: matchMap["consumed"],
	}
}

// Transform our matches in a readable hash map.
//
// The resulting hash map will be something like { "Heap1": 123 }
func getMatchMap(re *regexp.Regexp, matches []string) map[string]int64 {
	matchingNames := re.SubexpNames()
	matchMap := map[string]int64{}
	for i, value := range matches {
		intVal, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			// Happens on first element of range and any matching parenthesis
			// that includes non-parseable string
			//
			// For example a matching array would contain:
			// [ "scvg1: inuse:3 ..." "3" ]
			continue
		}
		matchMap[matchingNames[i]] = intVal
	}
	return matchMap
}
<commit_msg>fix  parsing for go1.5 and tip<commit_after>package main

import (
	"bufio"
	"io"
	"regexp"
	"strconv"
)

const (
	GCRegexpGo14 = `gc\d+\(\d+\): ([\d.]+\+?)+ us, \d+ -> (?P<Heap1>\d+) MB, \d+ \(\d+-\d+\) objects,( \d+ goroutines,)? \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`
	GCRegexpGo15 = `^gc #?\d+ @[\d.]+s \d+%: [\d.+/]+ ms clock, [\d.+/]+ ms cpu, \d+->\d+->\d+ MB, (?P<Heap1>\d+) MB goal, \d+ P`
	SCVGRegexp   = `scvg\d+: inuse: (?P<inuse>\d+), idle: (?P<idle>\d+), sys: (?P<sys>\d+), released: (?P<released>\d+), consumed: (?P<consumed>\d+) \(MB\)`
)

var (
	gcrego14 = regexp.MustCompile(GCRegexpGo14)
	gcrego15 = regexp.MustCompile(GCRegexpGo15)
	scvgre   = regexp.MustCompile(SCVGRegexp)
)

type Parser struct {
	reader      io.Reader
	GcChan      chan *gctrace
	ScvgChan    chan *scvgtrace
	NoMatchChan chan string
	done        chan bool

	Err error

	scvgRegexp *regexp.Regexp
}

func NewParser(r io.Reader) *Parser {
	return &Parser{
		reader:      r,
		GcChan:      make(chan *gctrace, 1),
		ScvgChan:    make(chan *scvgtrace, 1),
		NoMatchChan: make(chan string, 1),
		done:        make(chan bool),
	}
}

func (p *Parser) Run() {
	sc := bufio.NewScanner(p.reader)

	for sc.Scan() {
		line := sc.Text()

		if result := gcrego15.FindStringSubmatch(line); result != nil {
			p.GcChan <- parseGCTrace(gcrego15, result)
			continue
		}

		if result := gcrego14.FindStringSubmatch(line); result != nil {
			p.GcChan <- parseGCTrace(gcrego14, result)
			continue
		}

		if result := scvgre.FindStringSubmatch(line); result != nil {
			p.ScvgChan <- parseSCVGTrace(result)
			continue
		}

		p.NoMatchChan <- line
	}

	p.Err = sc.Err()

	close(p.done)
}

func parseGCTrace(gcre *regexp.Regexp, matches []string) *gctrace {
	matchMap := getMatchMap(gcre, matches)

	return &gctrace{
		Heap1: matchMap["Heap1"],
	}
}

func parseSCVGTrace(matches []string) *scvgtrace {
	matchMap := getMatchMap(scvgre, matches)

	return &scvgtrace{
		inuse:    matchMap["inuse"],
		idle:     matchMap["idle"],
		sys:      matchMap["sys"],
		released: matchMap["released"],
		consumed: matchMap["consumed"],
	}
}

// Transform our matches in a readable hash map.
//
// The resulting hash map will be something like { "Heap1": 123 }
func getMatchMap(re *regexp.Regexp, matches []string) map[string]int64 {
	matchingNames := re.SubexpNames()
	matchMap := map[string]int64{}
	for i, value := range matches {
		intVal, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			// Happens on first element of range and any matching parenthesis
			// that includes non-parseable string
			//
			// For example a matching array would contain:
			// [ "scvg1: inuse:3 ..." "3" ]
			continue
		}
		matchMap[matchingNames[i]] = intVal
	}
	return matchMap
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 Apcera Inc. All rights reserved.

package nats

import (
	"fmt"
)

type msgArg struct {
	subject []byte
	reply   []byte
	sid     int64
	size    int
}

const MAX_CONTROL_LINE_SIZE = 1024

type parseState struct {
	state   int
	as      int
	drop    int
	ma      msgArg
	argBuf  []byte
	msgBuf  []byte
	scratch [MAX_CONTROL_LINE_SIZE]byte
}

const (
	OP_START = iota
	OP_PLUS
	OP_PLUS_O
	OP_PLUS_OK
	OP_MINUS
	OP_MINUS_E
	OP_MINUS_ER
	OP_MINUS_ERR
	OP_MINUS_ERR_SPC
	MINUS_ERR_ARG
	OP_M
	OP_MS
	OP_MSG
	OP_MSG_SPC
	MSG_ARG
	MSG_PAYLOAD
	MSG_END
	OP_P
	OP_PI
	OP_PIN
	OP_PING
	OP_PO
	OP_PON
	OP_PONG
)

// parse is the fast protocol parser engine.
func (nc *Conn) parse(buf []byte) error {
	var i int
	var b byte

	for i, b = range buf {
		switch nc.ps.state {
		case OP_START:
			switch b {
			case 'M', 'm':
				nc.ps.state = OP_M
			case 'P', 'p':
				nc.ps.state = OP_P
			case '+':
				nc.ps.state = OP_PLUS
			case '-':
				nc.ps.state = OP_MINUS
			default:
				goto parseErr
			}
		case OP_M:
			switch b {
			case 'S', 's':
				nc.ps.state = OP_MS
			default:
				goto parseErr
			}
		case OP_MS:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_MSG
			default:
				goto parseErr
			}
		case OP_MSG:
			switch b {
			case ' ', '\t':
				nc.ps.state = OP_MSG_SPC
			default:
				goto parseErr
			}
		case OP_MSG_SPC:
			switch b {
			case ' ', '\t':
				continue
			default:
				nc.ps.state = MSG_ARG
				nc.ps.as = i
			}
		case MSG_ARG:
			switch b {
			case '\r':
				nc.ps.drop = 1
			case '\n':
				var arg []byte
				if nc.ps.argBuf != nil {
					arg = nc.ps.argBuf
				} else {
					arg = buf[nc.ps.as : i-nc.ps.drop]
				}
				if err := nc.processMsgArgs(arg); err != nil {
					return err
				}
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, MSG_PAYLOAD
			default:
				if nc.ps.argBuf != nil {
					nc.ps.argBuf = append(nc.ps.argBuf, b)
				}
			}
		case MSG_PAYLOAD:
			if nc.ps.msgBuf != nil {
				if len(nc.ps.msgBuf) >= nc.ps.ma.size {
					nc.processMsg(nc.ps.msgBuf)
					nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
				} else {
					nc.ps.msgBuf = append(nc.ps.msgBuf, b)
				}
			} else if i-nc.ps.as >= nc.ps.ma.size {
				nc.processMsg(buf[nc.ps.as:i])
				nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
			}
		case MSG_END:
			switch b {
			case '\n':
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
			default:
				continue
			}
		case OP_PLUS:
			switch b {
			case 'O', 'o':
				nc.ps.state = OP_PLUS_O
			default:
				goto parseErr
			}
		case OP_PLUS_O:
			switch b {
			case 'K', 'k':
				nc.ps.state = OP_PLUS_OK
			default:
				goto parseErr
			}
		case OP_PLUS_OK:
			switch b {
			case '\n':
				nc.processOK()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		case OP_MINUS:
			switch b {
			case 'E', 'e':
				nc.ps.state = OP_MINUS_E
			default:
				goto parseErr
			}
		case OP_MINUS_E:
			switch b {
			case 'R', 'r':
				nc.ps.state = OP_MINUS_ER
			default:
				goto parseErr
			}
		case OP_MINUS_ER:
			switch b {
			case 'R', 'r':
				nc.ps.state = OP_MINUS_ERR
			default:
				goto parseErr
			}
		case OP_MINUS_ERR:
			switch b {
			case ' ', '\t':
				nc.ps.state = OP_MINUS_ERR_SPC
			default:
				goto parseErr
			}
		case OP_MINUS_ERR_SPC:
			switch b {
			case ' ', '\t':
				continue
			default:
				nc.ps.state = MINUS_ERR_ARG
				nc.ps.as = i
			}
		case MINUS_ERR_ARG:
			switch b {
			case '\r':
				nc.ps.drop = 1
			case '\n':
				var arg []byte
				if nc.ps.argBuf != nil {
					arg = nc.ps.argBuf
					nc.ps.argBuf = nil
				} else {
					arg = buf[nc.ps.as : i-nc.ps.drop]
				}
				nc.processErr(string(arg))
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
			default:
				if nc.ps.argBuf != nil {
					nc.ps.argBuf = append(nc.ps.argBuf, b)
				}
			}
		case OP_P:
			switch b {
			case 'I', 'i':
				nc.ps.state = OP_PI
			case 'O', 'o':
				nc.ps.state = OP_PO
			default:
				goto parseErr
			}
		case OP_PO:
			switch b {
			case 'N', 'n':
				nc.ps.state = OP_PON
			default:
				goto parseErr
			}
		case OP_PON:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_PONG
			default:
				goto parseErr
			}
		case OP_PONG:
			switch b {
			case '\n':
				nc.processPong()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		case OP_PI:
			switch b {
			case 'N', 'n':
				nc.ps.state = OP_PIN
			default:
				goto parseErr
			}
		case OP_PIN:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_PING
			default:
				goto parseErr
			}
		case OP_PING:
			switch b {
			case '\n':
				nc.processPing()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		default:
			goto parseErr
		}
	}
	// Check for split buffer scenarios
	if (nc.ps.state == MSG_ARG || nc.ps.state == MINUS_ERR_ARG) && nc.ps.argBuf == nil {
		nc.ps.argBuf = nc.ps.scratch[:0]
		nc.ps.argBuf = append(nc.ps.argBuf, buf[nc.ps.as:(i+1)-nc.ps.drop]...)
		// FIXME, check max len
	}
	// Check for split msg
	if nc.ps.state == MSG_PAYLOAD && nc.ps.msgBuf == nil {
		// We need to clone the msgArg if it is still referencing the
		// read buffer and we are not able to process the msg.
		if nc.ps.argBuf == nil {
			nc.cloneMsgArg()
		}
		// FIXME: copy better here? Make whole buf if large?
		nc.ps.msgBuf = nc.ps.scratch[len(nc.ps.argBuf):len(nc.ps.argBuf)]
		nc.ps.msgBuf = append(nc.ps.msgBuf, (buf[nc.ps.as:])...)
	}

	return nil

parseErr:
	return fmt.Errorf("nats: Parse Error [%d]: '%s'", nc.ps.state, buf[i:])
}

// cloneMsgArg is used when the split buffer scenario has the pubArg in the existing read buffer, but
// we need to hold onto it into the next read.
func (nc *Conn) cloneMsgArg() {
	nc.ps.argBuf = nc.ps.scratch[:0]
	nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.subject...)
	nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.reply...)
	nc.ps.ma.subject = nc.ps.argBuf[:len(nc.ps.ma.subject)]
	if nc.ps.ma.reply != nil {
		nc.ps.ma.reply = nc.ps.argBuf[len(nc.ps.ma.subject):]
	}
}

const argsLenMax = 4

func (nc *Conn) processMsgArgs(arg []byte) error {
	// Unroll splitArgs to avoid runtime/heap issues
	a := [argsLenMax][]byte{}
	args := a[:0]
	start := -1
	for i, b := range arg {
		switch b {
		case ' ', '\t', '\r', '\n':
			if start >= 0 {
				args = append(args, arg[start:i])
				start = -1
			}
		default:
			if start < 0 {
				start = i
			}
		}
	}
	if start >= 0 {
		args = append(args, arg[start:])
	}

	switch len(args) {
	case 3:
		nc.ps.ma.subject = args[0]
		nc.ps.ma.sid = parseInt64(args[1])
		nc.ps.ma.reply = nil
		nc.ps.ma.size = int(parseInt64(args[2]))
	case 4:
		nc.ps.ma.subject = args[0]
		nc.ps.ma.sid = parseInt64(args[1])
		nc.ps.ma.reply = args[2]
		nc.ps.ma.size = int(parseInt64(args[3]))
	default:
		return fmt.Errorf("nats: processMsgArgs Parse Error: '%s'", arg)
	}
	if nc.ps.ma.sid < 0 {
		return fmt.Errorf("nats: processMsgArgs Bad or Missing Sid: '%s'", arg)
	}
	if nc.ps.ma.size < 0 {
		return fmt.Errorf("nats: processMsgArgs Bad or Missing Size: '%s'", arg)
	}
	return nil
}

// Ascii numbers 0-9
const (
	ascii_0 = 48
	ascii_9 = 57
)

// parseInt64 expects decimal positive numbers. We
// return -1 to signal error
func parseInt64(d []byte) (n int64) {
	if len(d) == 0 {
		return -1
	}
	for _, dec := range d {
		if dec < ascii_0 || dec > ascii_9 {
			return -1
		}
		n = n*10 + (int64(dec) - ascii_0)
	}
	return n
}
<commit_msg>Optimize for lager messages.<commit_after>// Copyright 2012-2014 Apcera Inc. All rights reserved.

package nats

import (
	"fmt"
)

type msgArg struct {
	subject []byte
	reply   []byte
	sid     int64
	size    int
}

const MAX_CONTROL_LINE_SIZE = 1024

type parseState struct {
	state   int
	as      int
	drop    int
	ma      msgArg
	argBuf  []byte
	msgBuf  []byte
	scratch [MAX_CONTROL_LINE_SIZE]byte
}

const (
	OP_START = iota
	OP_PLUS
	OP_PLUS_O
	OP_PLUS_OK
	OP_MINUS
	OP_MINUS_E
	OP_MINUS_ER
	OP_MINUS_ERR
	OP_MINUS_ERR_SPC
	MINUS_ERR_ARG
	OP_M
	OP_MS
	OP_MSG
	OP_MSG_SPC
	MSG_ARG
	MSG_PAYLOAD
	MSG_END
	OP_P
	OP_PI
	OP_PIN
	OP_PING
	OP_PO
	OP_PON
	OP_PONG
)

// parse is the fast protocol parser engine.
func (nc *Conn) parse(buf []byte) error {
	var i int
	var b byte

	// Move to loop instead of range syntax to allow jumping of i
	for i = 0; i < len(buf); i++ {
		b = buf[i]

		switch nc.ps.state {
		case OP_START:
			switch b {
			case 'M', 'm':
				nc.ps.state = OP_M
			case 'P', 'p':
				nc.ps.state = OP_P
			case '+':
				nc.ps.state = OP_PLUS
			case '-':
				nc.ps.state = OP_MINUS
			default:
				goto parseErr
			}
		case OP_M:
			switch b {
			case 'S', 's':
				nc.ps.state = OP_MS
			default:
				goto parseErr
			}
		case OP_MS:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_MSG
			default:
				goto parseErr
			}
		case OP_MSG:
			switch b {
			case ' ', '\t':
				nc.ps.state = OP_MSG_SPC
			default:
				goto parseErr
			}
		case OP_MSG_SPC:
			switch b {
			case ' ', '\t':
				continue
			default:
				nc.ps.state = MSG_ARG
				nc.ps.as = i
			}
		case MSG_ARG:
			switch b {
			case '\r':
				nc.ps.drop = 1
			case '\n':
				var arg []byte
				if nc.ps.argBuf != nil {
					arg = nc.ps.argBuf
				} else {
					arg = buf[nc.ps.as : i-nc.ps.drop]
				}
				if err := nc.processMsgArgs(arg); err != nil {
					return err
				}
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, MSG_PAYLOAD

				// jump ahead with the index. If this overruns
				// what is left we fall out and process split
				// buffer.
				i = nc.ps.as + nc.ps.ma.size - 1
			default:
				if nc.ps.argBuf != nil {
					nc.ps.argBuf = append(nc.ps.argBuf, b)
				}
			}
		case MSG_PAYLOAD:
			if nc.ps.msgBuf != nil {
				if len(nc.ps.msgBuf) >= nc.ps.ma.size {
					nc.processMsg(nc.ps.msgBuf)
					nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
				} else {
					// copy as much as we can to the buffer and skip ahead.
					toCopy := nc.ps.ma.size - len(nc.ps.msgBuf)
					avail := len(buf) - i

					if avail < toCopy {
						toCopy = avail
					}

					if toCopy > 0 {
						start := len(nc.ps.msgBuf)
						// This is needed for copy to work.
						nc.ps.msgBuf = nc.ps.msgBuf[:start+toCopy]
						copy(nc.ps.msgBuf[start:], buf[i:i+toCopy])
						// Update our index
						i = (i + toCopy) - 1
					} else {
						nc.ps.msgBuf = append(nc.ps.msgBuf, b)
					}
				}
			} else if i-nc.ps.as >= nc.ps.ma.size {
				nc.processMsg(buf[nc.ps.as:i])
				nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
			}
		case MSG_END:
			switch b {
			case '\n':
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
			default:
				continue
			}
		case OP_PLUS:
			switch b {
			case 'O', 'o':
				nc.ps.state = OP_PLUS_O
			default:
				goto parseErr
			}
		case OP_PLUS_O:
			switch b {
			case 'K', 'k':
				nc.ps.state = OP_PLUS_OK
			default:
				goto parseErr
			}
		case OP_PLUS_OK:
			switch b {
			case '\n':
				nc.processOK()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		case OP_MINUS:
			switch b {
			case 'E', 'e':
				nc.ps.state = OP_MINUS_E
			default:
				goto parseErr
			}
		case OP_MINUS_E:
			switch b {
			case 'R', 'r':
				nc.ps.state = OP_MINUS_ER
			default:
				goto parseErr
			}
		case OP_MINUS_ER:
			switch b {
			case 'R', 'r':
				nc.ps.state = OP_MINUS_ERR
			default:
				goto parseErr
			}
		case OP_MINUS_ERR:
			switch b {
			case ' ', '\t':
				nc.ps.state = OP_MINUS_ERR_SPC
			default:
				goto parseErr
			}
		case OP_MINUS_ERR_SPC:
			switch b {
			case ' ', '\t':
				continue
			default:
				nc.ps.state = MINUS_ERR_ARG
				nc.ps.as = i
			}
		case MINUS_ERR_ARG:
			switch b {
			case '\r':
				nc.ps.drop = 1
			case '\n':
				var arg []byte
				if nc.ps.argBuf != nil {
					arg = nc.ps.argBuf
					nc.ps.argBuf = nil
				} else {
					arg = buf[nc.ps.as : i-nc.ps.drop]
				}
				nc.processErr(string(arg))
				nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
			default:
				if nc.ps.argBuf != nil {
					nc.ps.argBuf = append(nc.ps.argBuf, b)
				}
			}
		case OP_P:
			switch b {
			case 'I', 'i':
				nc.ps.state = OP_PI
			case 'O', 'o':
				nc.ps.state = OP_PO
			default:
				goto parseErr
			}
		case OP_PO:
			switch b {
			case 'N', 'n':
				nc.ps.state = OP_PON
			default:
				goto parseErr
			}
		case OP_PON:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_PONG
			default:
				goto parseErr
			}
		case OP_PONG:
			switch b {
			case '\n':
				nc.processPong()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		case OP_PI:
			switch b {
			case 'N', 'n':
				nc.ps.state = OP_PIN
			default:
				goto parseErr
			}
		case OP_PIN:
			switch b {
			case 'G', 'g':
				nc.ps.state = OP_PING
			default:
				goto parseErr
			}
		case OP_PING:
			switch b {
			case '\n':
				nc.processPing()
				nc.ps.drop, nc.ps.state = 0, OP_START
			}
		default:
			goto parseErr
		}
	}
	// Check for split buffer scenarios
	if (nc.ps.state == MSG_ARG || nc.ps.state == MINUS_ERR_ARG) && nc.ps.argBuf == nil {
		nc.ps.argBuf = nc.ps.scratch[:0]
		nc.ps.argBuf = append(nc.ps.argBuf, buf[nc.ps.as:i-nc.ps.drop]...)
		// FIXME, check max len
	}
	// Check for split msg
	if nc.ps.state == MSG_PAYLOAD && nc.ps.msgBuf == nil {
		// We need to clone the msgArg if it is still referencing the
		// read buffer and we are not able to process the msg.
		if nc.ps.argBuf == nil {
			nc.cloneMsgArg()
		}

		// If we will overflow the scratch buffer, just create a
		// new buffer to hold the split message.
		if nc.ps.ma.size > cap(nc.scratch)-len(nc.ps.argBuf) {
			lrem := len(buf[nc.ps.as:])

			nc.ps.msgBuf = make([]byte, lrem, nc.ps.ma.size)
			copy(nc.ps.msgBuf, buf[nc.ps.as:])
		} else {
			nc.ps.msgBuf = nc.ps.scratch[len(nc.ps.argBuf):len(nc.ps.argBuf)]
			nc.ps.msgBuf = append(nc.ps.msgBuf, (buf[nc.ps.as:])...)
		}
	}

	return nil

parseErr:
	return fmt.Errorf("nats: Parse Error [%d]: '%s'", nc.ps.state, buf[i:])
}

// cloneMsgArg is used when the split buffer scenario has the pubArg in the existing read buffer, but
// we need to hold onto it into the next read.
func (nc *Conn) cloneMsgArg() {
	nc.ps.argBuf = nc.ps.scratch[:0]
	nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.subject...)
	nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.reply...)
	nc.ps.ma.subject = nc.ps.argBuf[:len(nc.ps.ma.subject)]
	if nc.ps.ma.reply != nil {
		nc.ps.ma.reply = nc.ps.argBuf[len(nc.ps.ma.subject):]
	}
}

const argsLenMax = 4

func (nc *Conn) processMsgArgs(arg []byte) error {
	// Unroll splitArgs to avoid runtime/heap issues
	a := [argsLenMax][]byte{}
	args := a[:0]
	start := -1
	for i, b := range arg {
		switch b {
		case ' ', '\t', '\r', '\n':
			if start >= 0 {
				args = append(args, arg[start:i])
				start = -1
			}
		default:
			if start < 0 {
				start = i
			}
		}
	}
	if start >= 0 {
		args = append(args, arg[start:])
	}

	switch len(args) {
	case 3:
		nc.ps.ma.subject = args[0]
		nc.ps.ma.sid = parseInt64(args[1])
		nc.ps.ma.reply = nil
		nc.ps.ma.size = int(parseInt64(args[2]))
	case 4:
		nc.ps.ma.subject = args[0]
		nc.ps.ma.sid = parseInt64(args[1])
		nc.ps.ma.reply = args[2]
		nc.ps.ma.size = int(parseInt64(args[3]))
	default:
		return fmt.Errorf("nats: processMsgArgs Parse Error: '%s'", arg)
	}
	if nc.ps.ma.sid < 0 {
		return fmt.Errorf("nats: processMsgArgs Bad or Missing Sid: '%s'", arg)
	}
	if nc.ps.ma.size < 0 {
		return fmt.Errorf("nats: processMsgArgs Bad or Missing Size: '%s'", arg)
	}
	return nil
}

// Ascii numbers 0-9
const (
	ascii_0 = 48
	ascii_9 = 57
)

// parseInt64 expects decimal positive numbers. We
// return -1 to signal error
func parseInt64(d []byte) (n int64) {
	if len(d) == 0 {
		return -1
	}
	for _, dec := range d {
		if dec < ascii_0 || dec > ascii_9 {
			return -1
		}
		n = n*10 + (int64(dec) - ascii_0)
	}
	return n
}
<|endoftext|>