<commit_before>package openapi3filter

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"sync"

	"github.com/getkin/kin-openapi/openapi3"
)

// ErrInvalidRequired is an error that happens when a required value of a parameter or request's body is not defined.
var ErrInvalidRequired = fmt.Errorf("must have a value")

func ValidateRequest(c context.Context, input *RequestValidationInput) error {
	options := input.Options
	if options == nil {
		options = DefaultOptions
	}
	route := input.Route
	if route == nil {
		return errors.New("invalid route")
	}
	operation := route.Operation
	if operation == nil {
		return errRouteMissingOperation
	}
	operationParameters := operation.Parameters
	pathItemParameters := route.PathItem.Parameters

	// For each parameter of the PathItem
	for _, parameterRef := range pathItemParameters {
		parameter := parameterRef.Value
		if operationParameters != nil {
			if override := operationParameters.GetByInAndName(parameter.In, parameter.Name); override != nil {
				continue
			}
			if err := ValidateParameter(c, input, parameter); err != nil {
				return err
			}
		}
	}

	// For each parameter of the Operation
	for _, parameter := range operationParameters {
		if err := ValidateParameter(c, input, parameter.Value); err != nil {
			return err
		}
	}

	// RequestBody
	requestBody := operation.RequestBody
	if requestBody != nil && !options.ExcludeRequestBody {
		if err := ValidateRequestBody(c, input, requestBody.Value); err != nil {
			return err
		}
	}

	// Security
	security := operation.Security
	// If there aren't any security requirements for the operation
	if security == nil {
		if route.Swagger == nil {
			return errRouteMissingSwagger
		} else {
			// Use the global security requirements.
			security = &route.Swagger.Security
		}
	}
	if security != nil {
		if err := ValidateSecurityRequirements(c, input, *security); err != nil {
			return err
		}
	}
	return nil
}

// ValidateParameter validates a parameter's value by JSON schema.
// The function returns RequestError with a ParseError cause when unable to parse a value.
// The function returns RequestError with ErrInvalidRequired cause when a value of a required parameter is not defined.
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
func ValidateParameter(c context.Context, input *RequestValidationInput, parameter *openapi3.Parameter) error {
	if parameter.Schema == nil && parameter.Content == nil {
		// We have no schema for the parameter. Assume that everything passes
		// a schema-less check, but this could also be an error. The Swagger
		// validation allows this to happen.
		return nil
	}

	var value interface{}
	var err error
	var schema *openapi3.Schema

	// Validation will ensure that we either have content or schema.
	if parameter.Content != nil {
		value, schema, err = decodeContentParameter(parameter, input)
		if err != nil {
			return &RequestError{Input: input, Parameter: parameter, Err: err}
		}
	} else {
		value, err = decodeStyledParameter(parameter, input)
		if err != nil {
			return &RequestError{Input: input, Parameter: parameter, Err: err}
		}
		schema = parameter.Schema.Value
	}
	// Validate a parameter's value.
	if value == nil {
		if parameter.Required {
			return &RequestError{Input: input, Parameter: parameter, Reason: "must have a value", Err: ErrInvalidRequired}
		}
		return nil
	}
	if schema == nil {
		// A parameter's schema is not defined so skip validation of a parameter's value.
		return nil
	}
	if err = schema.VisitJSON(value); err != nil {
		return &RequestError{Input: input, Parameter: parameter, Err: err}
	}
	return nil
}

// ValidateRequestBody validates data of a request's body.
//
// The function returns RequestError with ErrInvalidRequired cause when a value is required but not defined.
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
func ValidateRequestBody(c context.Context, input *RequestValidationInput, requestBody *openapi3.RequestBody) error {
	var (
		req  = input.Request
		data []byte
	)

	if req.Body != http.NoBody {
		defer req.Body.Close()
		var err error
		if data, err = ioutil.ReadAll(req.Body); err != nil {
			return &RequestError{
				Input:       input,
				RequestBody: requestBody,
				Reason:      "reading failed",
				Err:         err,
			}
		}
		// Put the data back into the input
		req.Body = ioutil.NopCloser(bytes.NewReader(data))
	}

	if len(data) == 0 {
		if requestBody.Required {
			return &RequestError{Input: input, RequestBody: requestBody, Err: ErrInvalidRequired}
		}
		return nil
	}

	content := requestBody.Content
	if len(content) == 0 {
		// A request's body does not have declared content, so skip validation.
		return nil
	}

	inputMIME := req.Header.Get("Content-Type")
	contentType := requestBody.Content.Get(inputMIME)
	if contentType == nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      fmt.Sprintf("header 'Content-Type' has unexpected value: %q", inputMIME),
		}
	}

	if contentType.Schema == nil {
		// A JSON schema that describes the received data is not declared, so skip validation.
		return nil
	}

	encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
	value, err := decodeBody(bytes.NewReader(data), req.Header, contentType.Schema, encFn)
	if err != nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      "failed to decode request body",
			Err:         err,
		}
	}

	// Validate JSON with the schema
	if err := contentType.Schema.Value.VisitJSON(value); err != nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      "doesn't match the schema",
			Err:         err,
		}
	}
	return nil
}

// ValidateSecurityRequirements validates a multiple OpenAPI 3 security requirements.
// Returns nil if one of them inputed.
// Otherwise returns an error describing the security failures.
func ValidateSecurityRequirements(c context.Context, input *RequestValidationInput, srs openapi3.SecurityRequirements) error {
	// Alternative requirements
	if len(srs) == 0 {
		return nil
	}

	var wg sync.WaitGroup
	errs := make([]error, len(srs))

	// For each alternative security requirement
	for i, securityRequirement := range srs {
		// Capture index from iteration variable
		currentIndex := i
		currentSecurityRequirement := securityRequirement

		// Add a work item
		wg.Add(1)

		go func() {
			defer func() {
				v := recover()
				if v != nil {
					if err, ok := v.(error); ok {
						errs[currentIndex] = err
					} else {
						errs[currentIndex] = errors.New("Panicked")
					}
				}

				// Remove a work item
				wg.Done()
			}()

			if err := validateSecurityRequirement(c, input, currentSecurityRequirement); err != nil {
				errs[currentIndex] = err
			}
		}()
	}

	// Wait for all
	wg.Wait()

	// If any security requirement was met
	for _, err := range errs {
		if err == nil {
			// Return no error
			return nil
		}
	}
	return &SecurityRequirementsError{
		SecurityRequirements: srs,
		Errors:               errs,
	}
}

// validateSecurityRequirement validates a single OpenAPI 3 security requirement
func validateSecurityRequirement(c context.Context, input *RequestValidationInput, securityRequirement openapi3.SecurityRequirement) error {
	swagger := input.Route.Swagger
	if swagger == nil {
		return errRouteMissingSwagger
	}
	securitySchemes := swagger.Components.SecuritySchemes

	// Ensure deterministic order
	names := make([]string, 0, len(securityRequirement))
	for name := range securityRequirement {
		names = append(names, name)
	}
	sort.Strings(names)

	// Get authentication function
	options := input.Options
	if options == nil {
		options = DefaultOptions
	}
	f := options.AuthenticationFunc
	if f == nil {
		return ErrAuthenticationServiceMissing
	}

	// For each scheme for the requirement
	for _, name := range names {
		var securityScheme *openapi3.SecurityScheme
		if securitySchemes != nil {
			if ref := securitySchemes[name]; ref != nil {
				securityScheme = ref.Value
			}
		}
		if securityScheme == nil {
			return &RequestError{
				Input: input,
				Err:   fmt.Errorf("Security scheme '%s' is not declared", name),
			}
		}
		scopes := securityRequirement[name]
		if err := f(c, &AuthenticationInput{
			RequestValidationInput: input,
			SecuritySchemeName:     name,
			SecurityScheme:         securityScheme,
			Scopes:                 scopes,
		}); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>add nil check in request body validation (#108)<commit_after>package openapi3filter

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"sync"

	"github.com/getkin/kin-openapi/openapi3"
)

// ErrInvalidRequired is an error that happens when a required value of a parameter or request's body is not defined.
var ErrInvalidRequired = fmt.Errorf("must have a value")

func ValidateRequest(c context.Context, input *RequestValidationInput) error {
	options := input.Options
	if options == nil {
		options = DefaultOptions
	}
	route := input.Route
	if route == nil {
		return errors.New("invalid route")
	}
	operation := route.Operation
	if operation == nil {
		return errRouteMissingOperation
	}
	operationParameters := operation.Parameters
	pathItemParameters := route.PathItem.Parameters

	// For each parameter of the PathItem
	for _, parameterRef := range pathItemParameters {
		parameter := parameterRef.Value
		if operationParameters != nil {
			if override := operationParameters.GetByInAndName(parameter.In, parameter.Name); override != nil {
				continue
			}
			if err := ValidateParameter(c, input, parameter); err != nil {
				return err
			}
		}
	}

	// For each parameter of the Operation
	for _, parameter := range operationParameters {
		if err := ValidateParameter(c, input, parameter.Value); err != nil {
			return err
		}
	}

	// RequestBody
	requestBody := operation.RequestBody
	if requestBody != nil && !options.ExcludeRequestBody {
		if err := ValidateRequestBody(c, input, requestBody.Value); err != nil {
			return err
		}
	}

	// Security
	security := operation.Security
	// If there aren't any security requirements for the operation
	if security == nil {
		if route.Swagger == nil {
			return errRouteMissingSwagger
		} else {
			// Use the global security requirements.
			security = &route.Swagger.Security
		}
	}
	if security != nil {
		if err := ValidateSecurityRequirements(c, input, *security); err != nil {
			return err
		}
	}
	return nil
}

// ValidateParameter validates a parameter's value by JSON schema.
// The function returns RequestError with a ParseError cause when unable to parse a value.
// The function returns RequestError with ErrInvalidRequired cause when a value of a required parameter is not defined.
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
func ValidateParameter(c context.Context, input *RequestValidationInput, parameter *openapi3.Parameter) error {
	if parameter.Schema == nil && parameter.Content == nil {
		// We have no schema for the parameter. Assume that everything passes
		// a schema-less check, but this could also be an error. The Swagger
		// validation allows this to happen.
		return nil
	}

	var value interface{}
	var err error
	var schema *openapi3.Schema

	// Validation will ensure that we either have content or schema.
	if parameter.Content != nil {
		value, schema, err = decodeContentParameter(parameter, input)
		if err != nil {
			return &RequestError{Input: input, Parameter: parameter, Err: err}
		}
	} else {
		value, err = decodeStyledParameter(parameter, input)
		if err != nil {
			return &RequestError{Input: input, Parameter: parameter, Err: err}
		}
		schema = parameter.Schema.Value
	}
	// Validate a parameter's value.
	if value == nil {
		if parameter.Required {
			return &RequestError{Input: input, Parameter: parameter, Reason: "must have a value", Err: ErrInvalidRequired}
		}
		return nil
	}
	if schema == nil {
		// A parameter's schema is not defined so skip validation of a parameter's value.
		return nil
	}
	if err = schema.VisitJSON(value); err != nil {
		return &RequestError{Input: input, Parameter: parameter, Err: err}
	}
	return nil
}

// ValidateRequestBody validates data of a request's body.
//
// The function returns RequestError with ErrInvalidRequired cause when a value is required but not defined.
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
func ValidateRequestBody(c context.Context, input *RequestValidationInput, requestBody *openapi3.RequestBody) error {
	var (
		req  = input.Request
		data []byte
	)

	if req.Body != http.NoBody && req.Body != nil {
		defer req.Body.Close()
		var err error
		if data, err = ioutil.ReadAll(req.Body); err != nil {
			return &RequestError{
				Input:       input,
				RequestBody: requestBody,
				Reason:      "reading failed",
				Err:         err,
			}
		}
		// Put the data back into the input
		req.Body = ioutil.NopCloser(bytes.NewReader(data))
	}

	if len(data) == 0 {
		if requestBody.Required {
			return &RequestError{Input: input, RequestBody: requestBody, Err: ErrInvalidRequired}
		}
		return nil
	}

	content := requestBody.Content
	if len(content) == 0 {
		// A request's body does not have declared content, so skip validation.
		return nil
	}

	inputMIME := req.Header.Get("Content-Type")
	contentType := requestBody.Content.Get(inputMIME)
	if contentType == nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      fmt.Sprintf("header 'Content-Type' has unexpected value: %q", inputMIME),
		}
	}

	if contentType.Schema == nil {
		// A JSON schema that describes the received data is not declared, so skip validation.
		return nil
	}

	encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
	value, err := decodeBody(bytes.NewReader(data), req.Header, contentType.Schema, encFn)
	if err != nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      "failed to decode request body",
			Err:         err,
		}
	}

	// Validate JSON with the schema
	if err := contentType.Schema.Value.VisitJSON(value); err != nil {
		return &RequestError{
			Input:       input,
			RequestBody: requestBody,
			Reason:      "doesn't match the schema",
			Err:         err,
		}
	}
	return nil
}

// ValidateSecurityRequirements validates a multiple OpenAPI 3 security requirements.
// Returns nil if one of them inputed.
// Otherwise returns an error describing the security failures.
func ValidateSecurityRequirements(c context.Context, input *RequestValidationInput, srs openapi3.SecurityRequirements) error {
	// Alternative requirements
	if len(srs) == 0 {
		return nil
	}

	var wg sync.WaitGroup
	errs := make([]error, len(srs))

	// For each alternative security requirement
	for i, securityRequirement := range srs {
		// Capture index from iteration variable
		currentIndex := i
		currentSecurityRequirement := securityRequirement

		// Add a work item
		wg.Add(1)

		go func() {
			defer func() {
				v := recover()
				if v != nil {
					if err, ok := v.(error); ok {
						errs[currentIndex] = err
					} else {
						errs[currentIndex] = errors.New("Panicked")
					}
				}

				// Remove a work item
				wg.Done()
			}()

			if err := validateSecurityRequirement(c, input, currentSecurityRequirement); err != nil {
				errs[currentIndex] = err
			}
		}()
	}

	// Wait for all
	wg.Wait()

	// If any security requirement was met
	for _, err := range errs {
		if err == nil {
			// Return no error
			return nil
		}
	}
	return &SecurityRequirementsError{
		SecurityRequirements: srs,
		Errors:               errs,
	}
}

// validateSecurityRequirement validates a single OpenAPI 3 security requirement
func validateSecurityRequirement(c context.Context, input *RequestValidationInput, securityRequirement openapi3.SecurityRequirement) error {
	swagger := input.Route.Swagger
	if swagger == nil {
		return errRouteMissingSwagger
	}
	securitySchemes := swagger.Components.SecuritySchemes

	// Ensure deterministic order
	names := make([]string, 0, len(securityRequirement))
	for name := range securityRequirement {
		names = append(names, name)
	}
	sort.Strings(names)

	// Get authentication function
	options := input.Options
	if options == nil {
		options = DefaultOptions
	}
	f := options.AuthenticationFunc
	if f == nil {
		return ErrAuthenticationServiceMissing
	}

	// For each scheme for the requirement
	for _, name := range names {
		var securityScheme *openapi3.SecurityScheme
		if securitySchemes != nil {
			if ref := securitySchemes[name]; ref != nil {
				securityScheme = ref.Value
			}
		}
		if securityScheme == nil {
			return &RequestError{
				Input: input,
				Err:   fmt.Errorf("Security scheme '%s' is not declared", name),
			}
		}
		scopes := securityRequirement[name]
		if err := f(c, &AuthenticationInput{
			RequestValidationInput: input,
			SecuritySchemeName:     name,
			SecurityScheme:         securityScheme,
			Scopes:                 scopes,
		}); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package user

import (
	"net/http"
	"strings"
	"xorkevin.dev/governor"
	"xorkevin.dev/governor/util/rank"
)

func (s *service) UpdateUser(userid string, ruser reqUserPut) error {
	m, err := s.users.GetByID(userid)
	if err != nil {
		if governor.ErrorStatus(err) == http.StatusNotFound {
			return governor.NewErrorUser("", 0, err)
		}
		return err
	}
	m.Username = ruser.Username
	m.FirstName = ruser.FirstName
	m.LastName = ruser.LastName
	if err = s.users.Update(m); err != nil {
		return err
	}
	return nil
}

func (s *service) UpdateRank(userid string, updaterid string, editAddRank rank.Rank, editRemoveRank rank.Rank) error {
	updaterRank, err := s.roles.IntersectRoles(updaterid, combineModRoles(editAddRank, editRemoveRank))
	if err != nil {
		return err
	}

	if err := canUpdateRank(editAddRank, updaterRank, userid, updaterid, true); err != nil {
		return err
	}
	if err := canUpdateRank(editRemoveRank, updaterRank, userid, updaterid, false); err != nil {
		return err
	}

	m, err := s.users.GetByID(userid)
	if err != nil {
		if governor.ErrorStatus(err) == http.StatusNotFound {
			return governor.NewErrorUser("", 0, err)
		}
		return err
	}

	editAddRank.Remove(editRemoveRank)

	if editAddRank.Has("admin") {
		s.logger.Info("add admin status", map[string]string{
			"userid":   userid,
			"username": m.Username,
		})
	}
	if editRemoveRank.Has("admin") {
		s.logger.Info("remove admin status", map[string]string{
			"userid":   userid,
			"username": m.Username,
		})
	}

	if err := s.roles.InsertRoles(m.Userid, editAddRank); err != nil {
		return err
	}
	if err := s.roles.DeleteRoles(m.Userid, editRemoveRank); err != nil {
		return err
	}

	return nil
}

func combineModRoles(r1, r2 rank.Rank) rank.Rank {
	roles := rank.Rank{
		rank.TagAdmin: struct{}{},
	}
	for key := range r1 {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			continue
		}
		roles[rank.TagModPrefix+"_"+k[1]] = struct{}{}
	}
	for key := range r2 {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			continue
		}
		roles[rank.TagModPrefix+"_"+k[1]] = struct{}{}
	}
	return roles
}

func canUpdateRank(edit, updater rank.Rank, editid, updaterid string, add bool) error {
	updaterIsAdmin := updater.Has(rank.TagAdmin)
	for key := range edit {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			switch k[0] {
			case rank.TagAdmin:
				// updater cannot change one's own admin status nor change another's admin status if he is not admin
				if editid == updaterid {
					return governor.NewErrorUser("Cannot modify own admin status", http.StatusForbidden, nil)
				}
				if !updaterIsAdmin {
					return governor.NewErrorUser("Must be admin to modify admin status", http.StatusForbidden, nil)
				}
			case rank.TagSystem:
				// no one can change the system status
				return governor.NewErrorUser("Forbidden rank edit", http.StatusForbidden, nil)
			case rank.TagUser:
				// only admins can change the user status
				if !updaterIsAdmin {
					return governor.NewErrorUser("Must be admin to modify user status", http.StatusForbidden, nil)
				}
			default:
				// other tags cannot be edited
				return governor.NewErrorUser("Invalid tag name", http.StatusForbidden, nil)
			}
		} else {
			switch k[0] {
			case rank.TagModPrefix:
				// cannot edit mod group rank if not an admin and not a moderator of that group
				if !updaterIsAdmin && !updater.HasMod(k[1]) {
					return governor.NewErrorUser("Must be moderator of the group to modify mod status", http.StatusForbidden, nil)
				}
			case rank.TagBanPrefix:
				// cannot edit ban group rank if not an admin and not a moderator of that group
				if !updaterIsAdmin && !updater.HasMod(k[1]) {
					return governor.NewErrorUser("Must be moderator of the group to modify ban status", http.StatusForbidden, nil)
				}
			case rank.TagUserPrefix:
				if add {
					// cannot add user if not admin and not a moderator of that group
					if !updaterIsAdmin && !updater.HasMod(k[1]) {
						return governor.NewErrorUser("Must be a moderator of the group to add user status", http.StatusForbidden, nil)
					}
				} else {
					// cannot remove user if not admin and not a moderator of that group and not self
					if !updaterIsAdmin && !updater.HasMod(k[1]) && editid != updaterid {
						return governor.NewErrorUser("Cannot update other user status", http.StatusForbidden, nil)
					}
				}
			default:
				// other tags cannot be edited
				return governor.NewErrorUser("Invalid tag name", http.StatusBadRequest, nil)
			}
		}
	}
	return nil
}
<commit_msg>Clean up rank add mod<commit_after>package user

import (
	"net/http"
	"strings"
	"xorkevin.dev/governor"
	"xorkevin.dev/governor/util/rank"
)

func (s *service) UpdateUser(userid string, ruser reqUserPut) error {
	m, err := s.users.GetByID(userid)
	if err != nil {
		if governor.ErrorStatus(err) == http.StatusNotFound {
			return governor.NewErrorUser("", 0, err)
		}
		return err
	}
	m.Username = ruser.Username
	m.FirstName = ruser.FirstName
	m.LastName = ruser.LastName
	if err = s.users.Update(m); err != nil {
		return err
	}
	return nil
}

func (s *service) UpdateRank(userid string, updaterid string, editAddRank rank.Rank, editRemoveRank rank.Rank) error {
	updaterRank, err := s.roles.IntersectRoles(updaterid, combineModRoles(editAddRank, editRemoveRank))
	if err != nil {
		return err
	}

	if err := canUpdateRank(editAddRank, updaterRank, userid, updaterid, true); err != nil {
		return err
	}
	if err := canUpdateRank(editRemoveRank, updaterRank, userid, updaterid, false); err != nil {
		return err
	}

	m, err := s.users.GetByID(userid)
	if err != nil {
		if governor.ErrorStatus(err) == http.StatusNotFound {
			return governor.NewErrorUser("", 0, err)
		}
		return err
	}

	editAddRank.Remove(editRemoveRank)

	if editAddRank.Has("admin") {
		s.logger.Info("add admin status", map[string]string{
			"userid":   userid,
			"username": m.Username,
		})
	}
	if editRemoveRank.Has("admin") {
		s.logger.Info("remove admin status", map[string]string{
			"userid":   userid,
			"username": m.Username,
		})
	}

	if err := s.roles.InsertRoles(m.Userid, editAddRank); err != nil {
		return err
	}
	if err := s.roles.DeleteRoles(m.Userid, editRemoveRank); err != nil {
		return err
	}

	return nil
}

func combineModRoles(r1, r2 rank.Rank) rank.Rank {
	roles := rank.Rank{
		rank.TagAdmin: struct{}{},
	}
	for key := range r1 {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			continue
		}
		roles.AddMod(k[1])
	}
	for key := range r2 {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			continue
		}
		roles.AddMod(k[1])
	}
	return roles
}

func canUpdateRank(edit, updater rank.Rank, editid, updaterid string, add bool) error {
	updaterIsAdmin := updater.Has(rank.TagAdmin)
	for key := range edit {
		k := strings.SplitN(key, "_", 2)
		if len(k) == 1 {
			switch k[0] {
			case rank.TagAdmin:
				// updater cannot change one's own admin status nor change another's admin status if he is not admin
				if editid == updaterid {
					return governor.NewErrorUser("Cannot modify own admin status", http.StatusForbidden, nil)
				}
				if !updaterIsAdmin {
					return governor.NewErrorUser("Must be admin to modify admin status", http.StatusForbidden, nil)
				}
			case rank.TagSystem:
				// no one can change the system status
				return governor.NewErrorUser("Forbidden rank edit", http.StatusForbidden, nil)
			case rank.TagUser:
				// only admins can change the user status
				if !updaterIsAdmin {
					return governor.NewErrorUser("Must be admin to modify user status", http.StatusForbidden, nil)
				}
			default:
				// other tags cannot be edited
				return governor.NewErrorUser("Invalid tag name", http.StatusForbidden, nil)
			}
		} else {
			switch k[0] {
			case rank.TagModPrefix:
				// cannot edit mod group rank if not an admin and not a moderator of that group
				if !updaterIsAdmin && !updater.HasMod(k[1]) {
					return governor.NewErrorUser("Must be moderator of the group to modify mod status", http.StatusForbidden, nil)
				}
			case rank.TagBanPrefix:
				// cannot edit ban group rank if not an admin and not a moderator of that group
				if !updaterIsAdmin && !updater.HasMod(k[1]) {
					return governor.NewErrorUser("Must be moderator of the group to modify ban status", http.StatusForbidden, nil)
				}
			case rank.TagUserPrefix:
				if add {
					// cannot add user if not admin and not a moderator of that group
					if !updaterIsAdmin && !updater.HasMod(k[1]) {
						return governor.NewErrorUser("Must be a moderator of the group to add user status", http.StatusForbidden, nil)
					}
				} else {
					// cannot remove user if not admin and not a moderator of that group and not self
					if !updaterIsAdmin && !updater.HasMod(k[1]) && editid != updaterid {
						return governor.NewErrorUser("Cannot update other user status", http.StatusForbidden, nil)
					}
				}
			default:
				// other tags cannot be edited
				return governor.NewErrorUser("Invalid tag name", http.StatusBadRequest, nil)
			}
		}
	}
	return nil
}
<|endoftext|>


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

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 4
	// Patch is the curernt patched version of the master branch.
	Patch = 1
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "stable"
)
<commit_msg>Bumping dev release.<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 4
	// Patch is the curernt patched version of the master branch.
	Patch = 2
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "dev"
)
<|endoftext|>


<commit_before>package logs

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/alauda/aster/utils"
	rotatelogs "github.com/lestrrat/go-file-rotatelogs"
	"io"
	"os"
)

type LogConfig struct {
	Stdout    bool
	LogDir    string
	AppName   string
	Level     logrus.Level
	Formatter logrus.Formatter
}

func DefaultTextFormatter() logrus.Formatter {
	customFormatter := new(logrus.TextFormatter)
	customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
	customFormatter.FullTimestamp = true
	return customFormatter
}

func InitStdoutLogger(conf LogConfig) *logrus.Logger {
	logger := logrus.New()
	logger.Out = os.Stdout
	logger.Level = conf.Level
	logger.Formatter = conf.Formatter
	return logger
}

func SetupLogger(conf LogConfig) (*logrus.Logger, error) {

	if conf.Stdout {
		return InitStdoutLogger(conf), nil
	}

	var err error
	path := fmt.Sprintf("%s/%s.log.%s", conf.LogDir, conf.AppName, "%Y%m%d")
	if err = utils.EnsureDir(path); err != nil {
		return nil, err
	}

	rl, err := rotatelogs.New(path)
	if err != nil {
		return nil, err
	}
	rotatelogs.WithLinkName(fmt.Sprintf("%s/%s", conf.LogDir, conf.AppName)).Configure(rl)

	out := io.MultiWriter(os.Stdout, rl)
	logger := logrus.Logger{
		//Formatter: &logrus.JSONFormatter{},
		Formatter: conf.Formatter,
		Level:     conf.Level,
		Out:       out,
	}
	logger.Info("Setup log finished.")

	return &logger, nil
}
<commit_msg>add log file's extension<commit_after>package logs

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/alauda/aster/utils"
	rotatelogs "github.com/lestrrat/go-file-rotatelogs"
	"io"
	"os"
)

type LogConfig struct {
	Stdout    bool
	LogDir    string
	AppName   string
	Level     logrus.Level
	Formatter logrus.Formatter
}

func DefaultTextFormatter() logrus.Formatter {
	customFormatter := new(logrus.TextFormatter)
	customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
	customFormatter.FullTimestamp = true
	return customFormatter
}

func InitStdoutLogger(conf LogConfig) *logrus.Logger {
	logger := logrus.New()
	logger.Out = os.Stdout
	logger.Level = conf.Level
	logger.Formatter = conf.Formatter
	return logger
}

func SetupLogger(conf LogConfig) (*logrus.Logger, error) {

	if conf.Stdout {
		return InitStdoutLogger(conf), nil
	}

	var err error
	path := fmt.Sprintf("%s/%s.log.%s", conf.LogDir, conf.AppName, "%Y%m%d")
	if err = utils.EnsureDir(path); err != nil {
		return nil, err
	}

	rl, err := rotatelogs.New(path)
	if err != nil {
		return nil, err
	}
	rotatelogs.WithLinkName(fmt.Sprintf("%s/%s.log", conf.LogDir, conf.AppName)).Configure(rl)

	out := io.MultiWriter(os.Stdout, rl)
	logger := logrus.Logger{
		//Formatter: &logrus.JSONFormatter{},
		Formatter: conf.Formatter,
		Level:     conf.Level,
		Out:       out,
	}
	logger.Info("Setup log finished.")

	return &logger, nil
}
<|endoftext|>


<commit_before>package ltcp_test

import (
	"net"
	"testing"

	"github.com/fourcube/ltcp"
)

func TestListen(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	close(done)
}

func TestAddressAlreadyInUse(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	err = ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err == nil {
		t.Errorf("Expected listen to fail when address is in use, got no error")
	}

	close(done)
}

func TestListenAny(t *testing.T) {
	done := make(chan struct{})

	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	if addr == nil {
		t.Errorf("Expected server to listen on some address, got nil")
	}

	close(done)
}

func TestServerActuallyResponds(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", listenAddress)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}
<commit_msg>Add test for handling connection with ListenAny<commit_after>package ltcp_test

import (
	"net"
	"testing"

	"github.com/fourcube/ltcp"
)

func TestListen(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	close(done)
}

func TestAddressAlreadyInUse(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	err = ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err == nil {
		t.Errorf("Expected listen to fail when address is in use, got no error")
	}

	close(done)
}

func TestListenAny(t *testing.T) {
	done := make(chan struct{})

	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	if addr == nil {
		t.Errorf("Expected server to listen on some address, got nil")
	}

	close(done)
}

func TestServerActuallyResponds(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", listenAddress)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}

func TestServerActuallyRespondsDuringListenAny(t *testing.T) {
	done := make(chan struct{})
	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}
<|endoftext|>


<commit_before>package gocube

// xMoveTranslation maps moves from the Y axis phase-1 cube to moves on the X
// axis cube. The mapping is: F->F, B->B, U->R, D->L, L->U, R->D.
// For example, doing U on a Y-axis cube is like doing R on the X-axis version
// of that cube.
// This mapping is kind of like doing a "z" rotation before the move.
var xMoveTranslation []Move = []Move{4, 5, 2, 3, 1, 0, 10, 11, 8, 9, 7, 6, 16,
	17, 14, 15, 13, 12}

// zMoveTranslation is like xMoveTranslation, but it's for doing an "x" rotation
// before applying a move. The mapping is: R->R, L->L, F->U, B->D, U->B, D->F.
var zMoveTranslation []Move = []Move{3, 2, 0, 1, 4, 5, 9, 8, 6, 7, 10, 11, 15,
	14, 12, 13, 16, 17}

// A Phase1Axis represents the y-axis corner orientations, ZZ edge orientations,
// and the permutation of the E slice.
type Phase1Axis struct {
	CornerOrientations int
	EdgeOrientations   int
	SlicePerm          int
}

// A Phase1Cube is an efficient way to represent the parts of a cube which
// matter for the first phase of Kociemba's algorithm.
// The FB edge orientation can be used for both Y and X phase-1 goals, and the
// UD edge orientation can be used for the Z phase-1 goal. Thus, no RL edge
// orientations are needed.
type Phase1Cube struct {
	XCornerOrientation int
	YCornerOrientation int
	ZCornerOrientation int

	FBEdgeOrientation int
	UDEdgeOrientation int

	MSlicePermutation int
	ESlicePermutation int
	SSlicePermutation int
}

// SolvedPhase1Cube returns a solved phase1 cube.
func SolvedPhase1Cube() Phase1Cube {
	return Phase1Cube{
		1093, 1093, 1093,
		0, 0,
		220, 220, 220,
	}
}

// Move applies a move to a Phase1Cube.
func (p *Phase1Cube) Move(m Move, moves *Phase1Moves) {
	// Apply the move to the y-axis cube.
	p.YCornerOrientation = moves.COMoves[p.YCornerOrientation][m]
	p.FBEdgeOrientation = moves.EOMoves[p.FBEdgeOrientation][m]
	p.ESlicePermutation = moves.ESliceMoves[p.ESlicePermutation][m]

	// Apply the move to the z-axis cube.
	zMove := zMoveTranslation[m]
	p.ZCornerOrientation = moves.COMoves[p.ZCornerOrientation][zMove]
	p.UDEdgeOrientation = moves.EOMoves[p.UDEdgeOrientation][zMove]
	p.SSlicePermutation = moves.ESliceMoves[p.SSlicePermutation][zMove]

	// Apply the move to the x-axis cube.
	xMove := xMoveTranslation[m]
	p.XCornerOrientation = moves.COMoves[p.XCornerOrientation][xMove]
	p.MSlicePermutation = moves.ESliceMoves[p.MSlicePermutation][xMove]
}

// Solved returns whether the phase-1 cube is solved in all three axes.
func (p *Phase1Cube) Solved() (x bool, y bool, z bool) {
	x = true
	y = true
	z = true
	if p.XCornerOrientation != 1093 {
		x = false
	} else if p.MSlicePermutation != 220 {
		x = false
	} else if p.FBEdgeOrientation != 0 {
		x = false
	}
	if p.YCornerOrientation != 1093 {
		y = false
	} else if p.ESlicePermutation != 220 {
		y = false
	} else if p.FBEdgeOrientation != 0 {
		y = false
	}
	if p.ZCornerOrientation != 1093 {
		z = false
	} else if p.SSlicePermutation != 220 {
		z = false
	} else if p.UDEdgeOrientation != 0 {
		z = false
	}
	return
}

// Phase1Moves is a table containing the necessary data to efficiently perform
// moves on a Phase1Cube.
// Note that only one move table is needed for all 3 axes (i.e. all three
// phase-1 goals). Thus, the move tables apply directly to the Y-oriented
// phase-1 goal. Moves much be translated for the X-oriented and Z-oriented
// goals.
type Phase1Moves struct {
	ESliceMoves [495][18]int
	EOMoves     [2048][18]int
	COMoves     [2187][18]int
}

// NewPhase1Moves generates tables for applying phase-1 moves.
func NewPhase1Moves() *Phase1Moves {
	res := &Phase1Moves{}

	// Generate the CO cases and do moves on them.
	for i := 0; i < 2187; i++ {
		corners := decodeCO(i)
		for m := 0; m < 18; m++ {
			aCase := corners
			aCase.Move(Move(m))
			res.COMoves[i][m] = encodeCO(&aCase)
		}
	}

	// Generate the EO cases and do moves on them.
	for i := 0; i < 2048; i++ {
		edges := decodeEO(i)
		for m := 0; m < 18; m++ {
			aCase := edges
			aCase.Move(Move(m))
			res.EOMoves[i][m] = encodeEO(&aCase)
		}
	}

	// Generate the E-slice cases and do moves on them.
	eSliceCase := 0
	for w := 0; w < 12; w++ {
		for x := w + 1; x < 12; x++ {
			for y := x + 1; y < 12; y++ {
				for z := y + 1; z < 12; z++ {
					// The state is bogus, but moves work on it.
					var edges CubieEdges
					edges[w].Piece = 1
					edges[x].Piece = 1
					edges[y].Piece = 1
					edges[z].Piece = 1
					for m := 0; m < 18; m++ {
						aCase := edges
						aCase.Move(Move(m))
						encoded := encodeBogusESlice(&aCase)
						res.ESliceMoves[eSliceCase][m] = encoded
					}
					eSliceCase++
				}
			}
		}
	}

	return res
}

func decodeCO(co int) CubieCorners {
	corners := SolvedCubieCorners()

	// Compute the orientations of the first 7 corners.
	scaler := 1
	for x := 0; x < 7; x++ {
		corners[x].Orientation = (co / scaler) % 3
		scaler *= 3
	}

	// Apply sune combos to orient all the corners except the last one.
	ordering := []int{0, 1, 5, 4, 6, 2, 3, 7}
	orientations := make([]int, 8)
	for i := 0; i < 8; i++ {
		orientations[i] = corners[ordering[i]].Orientation
	}
	for i := 0; i < 7; i++ {
		thisOrientation := orientations[i]
		nextOrientation := orientations[i+1]
		// Twist thisOrientation to be solved, affecting the next corner in the
		// sequence.
		if thisOrientation == 2 {
			// y -> x, x -> z, z -> y
			orientations[i+1] = (nextOrientation + 2) % 3
		} else if thisOrientation == 0 {
			// z -> x, x -> y, y -> z
			orientations[i+1] = (nextOrientation + 1) % 3
		}
	}

	// The twist of the last corner is the inverse of what it should be in the
	// scramble.
	if orientations[7] == 0 {
		corners[7].Orientation = 2
	} else if orientations[7] == 2 {
		corners[7].Orientation = 0
	}

	return corners
}

func decodeEO(eo int) CubieEdges {
	edges := SolvedCubieEdges()
	parity := false
	for x := uint(0); x < 11; x++ {
		if (eo & (1 << x)) != 0 {
			parity = !parity
			edges[x].Flip = true
		}
	}
	edges[11].Flip = parity
	return edges
}

func encodeBogusESlice(c *CubieEdges) int {
	list := make([]bool, 12)
	for i := 0; i < 12; i++ {
		list[i] = (*c)[i].Piece == 1
	}
	return encodeChoice(list)
}

func encodeCO(c *CubieCorners) int {
	res := 0
	scaler := 1
	for i := uint(0); i < 7; i++ {
		res += scaler * (*c)[i].Orientation
		scaler *= 3
	}
	return res
}

func encodeEO(c *CubieEdges) int {
	res := 0
	for i := uint(0); i < 11; i++ {
		if (*c)[i].Flip {
			res |= (1 << i)
		}
	}
	return res
}
<commit_msg>encode the easy parts of the cube<commit_after>package gocube

// xMoveTranslation maps moves from the Y axis phase-1 cube to moves on the X
// axis cube. The mapping is: F->F, B->B, U->R, D->L, L->U, R->D.
// For example, doing U on a Y-axis cube is like doing R on the X-axis version
// of that cube.
// This mapping is kind of like doing a "z" rotation before the move.
var xMoveTranslation []Move = []Move{4, 5, 2, 3, 1, 0, 10, 11, 8, 9, 7, 6, 16,
	17, 14, 15, 13, 12}

// zMoveTranslation is like xMoveTranslation, but it's for doing an "x" rotation
// before applying a move. The mapping is: R->R, L->L, F->U, B->D, U->B, D->F.
var zMoveTranslation []Move = []Move{3, 2, 0, 1, 4, 5, 9, 8, 6, 7, 10, 11, 15,
	14, 12, 13, 16, 17}

// A Phase1Cube is an efficient way to represent the parts of a cube which
// matter for the first phase of Kociemba's algorithm.
// The FB edge orientation can be used for both Y and X phase-1 goals, and the
// UD edge orientation can be used for the Z phase-1 goal. Thus, no RL edge
// orientations are needed.
type Phase1Cube struct {
	XCornerOrientation int
	YCornerOrientation int
	ZCornerOrientation int

	FBEdgeOrientation int
	UDEdgeOrientation int

	MSlicePermutation int
	ESlicePermutation int
	SSlicePermutation int
}

// SolvedPhase1Cube returns a solved phase1 cube.
func SolvedPhase1Cube() Phase1Cube {
	return Phase1Cube{
		1093, 1093, 1093,
		0, 0,
		220, 220, 220,
	}
}

// Move applies a move to a Phase1Cube.
func (p *Phase1Cube) Move(m Move, moves *Phase1Moves) {
	// Apply the move to the y-axis cube.
	p.YCornerOrientation = moves.COMoves[p.YCornerOrientation][m]
	p.FBEdgeOrientation = moves.EOMoves[p.FBEdgeOrientation][m]
	p.ESlicePermutation = moves.ESliceMoves[p.ESlicePermutation][m]

	// Apply the move to the z-axis cube.
	zMove := zMoveTranslation[m]
	p.ZCornerOrientation = moves.COMoves[p.ZCornerOrientation][zMove]
	p.UDEdgeOrientation = moves.EOMoves[p.UDEdgeOrientation][zMove]
	p.SSlicePermutation = moves.ESliceMoves[p.SSlicePermutation][zMove]

	// Apply the move to the x-axis cube.
	xMove := xMoveTranslation[m]
	p.XCornerOrientation = moves.COMoves[p.XCornerOrientation][xMove]
	p.MSlicePermutation = moves.ESliceMoves[p.MSlicePermutation][xMove]
}

// Solved returns whether the phase-1 cube is solved in all three axes.
func (p *Phase1Cube) Solved() (x bool, y bool, z bool) {
	x = true
	y = true
	z = true
	if p.XCornerOrientation != 1093 {
		x = false
	} else if p.MSlicePermutation != 220 {
		x = false
	} else if p.FBEdgeOrientation != 0 {
		x = false
	}
	if p.YCornerOrientation != 1093 {
		y = false
	} else if p.ESlicePermutation != 220 {
		y = false
	} else if p.FBEdgeOrientation != 0 {
		y = false
	}
	if p.ZCornerOrientation != 1093 {
		z = false
	} else if p.SSlicePermutation != 220 {
		z = false
	} else if p.UDEdgeOrientation != 0 {
		z = false
	}
	return
}

// Phase1Moves is a table containing the necessary data to efficiently perform
// moves on a Phase1Cube.
// Note that only one move table is needed for all 3 axes (i.e. all three
// phase-1 goals). Thus, the move tables apply directly to the Y-oriented
// phase-1 goal. Moves much be translated for the X-oriented and Z-oriented
// goals.
type Phase1Moves struct {
	ESliceMoves [495][18]int
	EOMoves     [2048][18]int
	COMoves     [2187][18]int
}

// NewPhase1Moves generates tables for applying phase-1 moves.
func NewPhase1Moves() *Phase1Moves {
	res := &Phase1Moves{}

	// Generate the CO cases and do moves on them.
	for i := 0; i < 2187; i++ {
		corners := decodeCO(i)
		for m := 0; m < 18; m++ {
			aCase := corners
			aCase.Move(Move(m))
			res.COMoves[i][m] = encodeCO(&aCase)
		}
	}

	// Generate the EO cases and do moves on them.
	for i := 0; i < 2048; i++ {
		edges := decodeEO(i)
		for m := 0; m < 18; m++ {
			aCase := edges
			aCase.Move(Move(m))
			res.EOMoves[i][m] = encodeEO(&aCase)
		}
	}

	// Generate the E-slice cases and do moves on them.
	eSliceCase := 0
	for w := 0; w < 12; w++ {
		for x := w + 1; x < 12; x++ {
			for y := x + 1; y < 12; y++ {
				for z := y + 1; z < 12; z++ {
					// The state is bogus, but moves work on it.
					var edges CubieEdges
					edges[w].Piece = 1
					edges[x].Piece = 1
					edges[y].Piece = 1
					edges[z].Piece = 1
					for m := 0; m < 18; m++ {
						aCase := edges
						aCase.Move(Move(m))
						encoded := encodeBogusESlice(&aCase)
						res.ESliceMoves[eSliceCase][m] = encoded
					}
					eSliceCase++
				}
			}
		}
	}

	return res
}

func (c *CubieCube) Phase1Cube() Phase1Cube {
	var res Phase1Cube

	// Encode FB edge orientations
	for i := uint(0); i < 11; i++ {
		if c.Edges[i].Flip {
			res.FBEdgeOrientation |= (1 << i)
		}
	}

	// Encode the UD corner orientations
	scaler := 1
	for i := 0; i < 7; i++ {
		res.YCornerOrientation += scaler * c.Corners[i].Orientation
		scaler *= 3
	}

	// Encode the E slice permutation
	var eChoice [12]bool
	for i := 0; i < 12; i++ {
		piece := c.Edges[i].Piece
		if piece == 1 || piece == 3 || piece == 7 || piece == 9 {
			eChoice[i] = true
		}
	}
	res.ESlicePermutation = encodeChoice(eChoice[:])

	return res
}

func decodeCO(co int) CubieCorners {
	corners := SolvedCubieCorners()

	// Compute the orientations of the first 7 corners.
	scaler := 1
	for x := 0; x < 7; x++ {
		corners[x].Orientation = (co / scaler) % 3
		scaler *= 3
	}

	// Apply sune combos to orient all the corners except the last one.
	ordering := []int{0, 1, 5, 4, 6, 2, 3, 7}
	orientations := make([]int, 8)
	for i := 0; i < 8; i++ {
		orientations[i] = corners[ordering[i]].Orientation
	}
	for i := 0; i < 7; i++ {
		thisOrientation := orientations[i]
		nextOrientation := orientations[i+1]
		// Twist thisOrientation to be solved, affecting the next corner in the
		// sequence.
		if thisOrientation == 2 {
			// y -> x, x -> z, z -> y
			orientations[i+1] = (nextOrientation + 2) % 3
		} else if thisOrientation == 0 {
			// z -> x, x -> y, y -> z
			orientations[i+1] = (nextOrientation + 1) % 3
		}
	}

	// The twist of the last corner is the inverse of what it should be in the
	// scramble.
	if orientations[7] == 0 {
		corners[7].Orientation = 2
	} else if orientations[7] == 2 {
		corners[7].Orientation = 0
	}

	return corners
}

func decodeEO(eo int) CubieEdges {
	edges := SolvedCubieEdges()
	parity := false
	for x := uint(0); x < 11; x++ {
		if (eo & (1 << x)) != 0 {
			parity = !parity
			edges[x].Flip = true
		}
	}
	edges[11].Flip = parity
	return edges
}

func encodeBogusESlice(c *CubieEdges) int {
	list := make([]bool, 12)
	for i := 0; i < 12; i++ {
		list[i] = (*c)[i].Piece == 1
	}
	return encodeChoice(list)
}

func encodeCO(c *CubieCorners) int {
	res := 0
	scaler := 1
	for i := uint(0); i < 7; i++ {
		res += scaler * (*c)[i].Orientation
		scaler *= 3
	}
	return res
}

func encodeEO(c *CubieEdges) int {
	res := 0
	for i := uint(0); i < 11; i++ {
		if (*c)[i].Flip {
			res |= (1 << i)
		}
	}
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"os/user"
	"path"
	"strconv"
	"strings"
)

/*
 * We'll flesh this out to be lists of ranges
 * We will want a list of available ranges (all ranges
 * which lxd may use) and taken range (parts of the
 * available ranges which are already in use by containers)
 *
 * We also may want some way of deciding which containers may
 * or perhaps must not share ranges
 *
 * For now, we simply have a single range, shared by all
 * containers
 */
type Idmap struct {
	Uidmin, Uidrange uint
	Gidmin, Gidrange uint
}

func checkmap(fname string, username string) (uint, uint, error) {
	f, err := os.Open(fname)
	var min uint
	var idrange uint
	if err != nil {
		return 0, 0, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	min = 0
	idrange = 0
	for scanner.Scan() {
		s := strings.Split(scanner.Text(), ":")
		fmt.Println(s)
		if len(s) < 3 {
			return 0, 0, fmt.Errorf("unexpected values in %q: %q", fname, s)
		}
		if strings.EqualFold(s[0], username) {
			bigmin, err := strconv.ParseUint(s[1], 10, 32)
			if err != nil {
				continue
			}
			biGidrange, err := strconv.ParseUint(s[2], 10, 32)
			if err != nil {
				continue
			}
			min = uint(bigmin)
			idrange = uint(biGidrange)
			return min, idrange, nil
		}
	}

	return 0, 0, fmt.Errorf("User %q has no %ss.", username, path.Base(fname))
}

func NewIdmap() (*Idmap, error) {
	me, err := user.Current()
	if err != nil {
		return nil, err
	}

	m := new(Idmap)
	umin, urange, err := checkmap("/etc/subuid", me.Username)
	if err != nil {
		return nil, err
	}
	gmin, grange, err := checkmap("/etc/subgid", me.Username)
	if err != nil {
		return nil, err
	}
	m.Uidmin = umin
	m.Uidrange = urange
	m.Gidmin = gmin
	m.Gidrange = grange
	return m, nil
}
<commit_msg>remove spurious debug statement<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"os/user"
	"path"
	"strconv"
	"strings"
)

/*
 * We'll flesh this out to be lists of ranges
 * We will want a list of available ranges (all ranges
 * which lxd may use) and taken range (parts of the
 * available ranges which are already in use by containers)
 *
 * We also may want some way of deciding which containers may
 * or perhaps must not share ranges
 *
 * For now, we simply have a single range, shared by all
 * containers
 */
type Idmap struct {
	Uidmin, Uidrange uint
	Gidmin, Gidrange uint
}

func checkmap(fname string, username string) (uint, uint, error) {
	f, err := os.Open(fname)
	var min uint
	var idrange uint
	if err != nil {
		return 0, 0, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	min = 0
	idrange = 0
	for scanner.Scan() {
		s := strings.Split(scanner.Text(), ":")
		if len(s) < 3 {
			return 0, 0, fmt.Errorf("unexpected values in %q: %q", fname, s)
		}
		if strings.EqualFold(s[0], username) {
			bigmin, err := strconv.ParseUint(s[1], 10, 32)
			if err != nil {
				continue
			}
			biGidrange, err := strconv.ParseUint(s[2], 10, 32)
			if err != nil {
				continue
			}
			min = uint(bigmin)
			idrange = uint(biGidrange)
			return min, idrange, nil
		}
	}

	return 0, 0, fmt.Errorf("User %q has no %ss.", username, path.Base(fname))
}

func NewIdmap() (*Idmap, error) {
	me, err := user.Current()
	if err != nil {
		return nil, err
	}

	m := new(Idmap)
	umin, urange, err := checkmap("/etc/subuid", me.Username)
	if err != nil {
		return nil, err
	}
	gmin, grange, err := checkmap("/etc/subgid", me.Username)
	if err != nil {
		return nil, err
	}
	m.Uidmin = umin
	m.Uidrange = urange
	m.Gidmin = gmin
	m.Gidrange = grange
	return m, nil
}
<|endoftext|>


<commit_before>package bnblog

import (
	"fmt"
	"github.com/codegangsta/martini"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/appengine"
	"google.golang.org/appengine/file"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
	"google.golang.org/appengine/user"
	"google.golang.org/cloud"
	"google.golang.org/cloud/storage"
	"io/ioutil"
	"net/http"
)

func UploadFile(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if fmt.Sprintf("%s", u) != "ben@benjojo.co.uk" && fmt.Sprintf("%s", u) != "ben@benjojo.com" {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	hc := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(c, storage.ScopeFullControl),
			Base:   &urlfetch.Transport{Context: c},
		},
	}

	file_from_client, headers, err := req.FormFile("fileToUpload")

	if err != nil {
		http.Error(rw, "Was that even a file?!", http.StatusBadRequest)
		return
	}

	defer file_from_client.Close()

	bucket := ""
	if bucket == "" {
		var err error
		if bucket, err = file.DefaultBucketName(c); err != nil {
			// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
			return
		}
	}
	ctx := cloud.NewContext(appengine.AppID(c), hc)

	fn := RandString(10)

	bin, _ := ioutil.ReadAll(file_from_client)

	wc1 := storage.NewWriter(ctx, bucket, fn)
	wc1.ContentType = headers.Header.Get("Content-Type")
	wc1.ACL = []storage.ACLRule{{storage.AllUsers, storage.RoleReader}}
	if _, err := wc1.Write(bin); err != nil {
		log.Warningf(c, "ouch! %s", err)
	}
	if err := wc1.Close(); err != nil {
		log.Warningf(c, "ouch! %s", err)
	}
	log.Infof(c, "updated object:", wc1.Object())

	rw.Write([]byte(fn))
	log.Warningf(c, "fin.")

}

func ReadFile(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	var c context.Context
	var ctx context.Context
	c = appengine.NewContext(req)

	var err error
	var bucket string
	if bucket, err = file.DefaultBucketName(c); err != nil {
		// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
		return
	}

	hc := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(c, storage.ScopeFullControl),
			Base:   &urlfetch.Transport{Context: c},
		},
	}

	ctx = cloud.NewContext(appengine.AppID(c), hc)

	rc, err := storage.NewReader(ctx, bucket, params["tag"])
	if err != nil {
		log.Warningf(c, "readFile: unable to open file from bucket %q, file %q: %v", bucket, params["tag"], err)
		return
	}
	defer rc.Close()
	slurp, err := ioutil.ReadAll(rc)
	if err != nil {
		log.Warningf(c, "readFile: unable to read data from bucket %q, file %q: %v", bucket, params["tag"], err)
		return
	}
	o, err := storage.StatObject(ctx, bucket, params["tag"])
	if err != nil {
		rw.Header().Add("Content-Type", "image/png")
	} else {
		rw.Header().Add("Content-Type", o.ContentType)
	}

	rw.Write([]byte(slurp))
}

type File struct {
	Name    string
	Content []byte
	Type    string
}

func ExportAllFiles(rw http.ResponseWriter, req *http.Request) (export []File) {
	c := appengine.NewContext(req)

	export = make([]File, 0)

	bucket := ""
	if bucket == "" {
		var err error
		if bucket, err = file.DefaultBucketName(c); err != nil {
			// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
			return
		}
	}

	hc := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(c, storage.ScopeFullControl),
			Base:   &urlfetch.Transport{Context: c},
		},
	}

	ctx := cloud.NewContext(appengine.AppID(c), hc)

	query := &storage.Query{Prefix: ""}
	for query != nil {
		objs, err := storage.ListObjects(ctx, bucket, query)
		if err != nil {
			//d.errorf("listBucket: unable to list bucket %q: %v", bucket, err)
			return
		}
		query = objs.Next

		for _, obj := range objs.Results {
			//d.dumpStats(obj)
			newfile := File{}
			newfile.Name = obj.Name
			newfile.Type = obj.ContentType

			rc, err := storage.NewReader(ctx, bucket, obj.Name)
			if err != nil {
				log.Warningf(c, "readFile: unable to open file from bucket %q, file %q: %v", bucket, obj.Name, err)
				return
			}
			defer rc.Close()
			slurp, err := ioutil.ReadAll(rc)

			newfile.Content = slurp
			export = append(export, newfile)
		}
	}

	return export
}

func GimmeDC(rw http.ResponseWriter, req *http.Request) string {
	c := appengine.NewContext(req)
	return appengine.Datacenter(c)
}
<commit_msg>Fix google API breaking changes<commit_after>package bnblog

import (
	"fmt"

	"github.com/codegangsta/martini"

	"io/ioutil"
	"net/http"

	"golang.org/x/net/context"
	"google.golang.org/api/iterator"
	"google.golang.org/appengine"
	"google.golang.org/appengine/file"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
	"google.golang.org/cloud/storage"
)

func UploadFile(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	u := user.Current(c)
	if u == nil {
		http.Error(rw, fmt.Sprintf("wat %s", u), http.StatusForbidden)
		return
	}

	if fmt.Sprintf("%s", u) != "ben@benjojo.co.uk" && fmt.Sprintf("%s", u) != "ben@benjojo.com" {
		http.Error(rw, fmt.Sprintf("wat? %s", u), http.StatusForbidden)
		return
	}

	file_from_client, headers, err := req.FormFile("fileToUpload")

	if err != nil {
		http.Error(rw, "Was that even a file?!", http.StatusBadRequest)
		return
	}

	defer file_from_client.Close()

	bucket := ""
	if bucket == "" {
		var err error
		if bucket, err = file.DefaultBucketName(c); err != nil {
			// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
			return
		}
	}
	storageclient, err := storage.NewClient(c)
	defer storageclient.Close()
	actualbucket := storageclient.Bucket(bucket)

	fn := RandString(10)

	bin, _ := ioutil.ReadAll(file_from_client)

	wc1 := actualbucket.Object(fn).NewWriter(c)
	wc1.ContentType = headers.Header.Get("Content-Type")

	wc1.ACL = []storage.ACLRule{{storage.AllUsers, storage.RoleReader}}
	if _, err := wc1.Write(bin); err != nil {
		log.Warningf(c, "ouch! %s", err)
	}
	if err := wc1.Close(); err != nil {
		log.Warningf(c, "ouch! %s", err)
	}
	// log.Infof(c, "updated object:", wc1.Object())

	rw.Write([]byte(fn))
	log.Warningf(c, "fin.")

}

func ReadFile(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	var c context.Context
	c = appengine.NewContext(req)

	var err error
	var bucket string
	if bucket, err = file.DefaultBucketName(c); err != nil {
		// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
		return
	}

	storageclient, err := storage.NewClient(c)
	defer storageclient.Close()
	actualbucket := storageclient.Bucket(bucket)

	rc, err := actualbucket.Object(params["tag"]).NewReader(c)
	if err != nil {
		log.Warningf(c, "readFile: unable to open file from bucket %q, file %q: %v", bucket, params["tag"], err)
		return
	}
	defer rc.Close()
	slurp, err := ioutil.ReadAll(rc)
	if err != nil {
		log.Warningf(c, "readFile: unable to read data from bucket %q, file %q: %v", bucket, params["tag"], err)
		return
	}
	o, err := actualbucket.Object(params["tag"]).Attrs(c)
	if err != nil {
		rw.Header().Add("Content-Type", "image/png")
	} else {
		rw.Header().Add("Content-Type", o.ContentType)
	}

	rw.Write([]byte(slurp))
}

type File struct {
	Name    string
	Content []byte
	Type    string
}

func ExportAllFiles(rw http.ResponseWriter, req *http.Request) (export []File) {
	c := appengine.NewContext(req)

	export = make([]File, 0)

	bucket := ""
	if bucket == "" {
		var err error
		if bucket, err = file.DefaultBucketName(c); err != nil {
			// log.Errorf(c, "failed to get default GCS bucket name: %v", err)
			return
		}
	}

	storageclient, _ := storage.NewClient(c)
	defer storageclient.Close()
	actualbucket := storageclient.Bucket(bucket)

	query := &storage.Query{Prefix: ""}
	for query != nil {

		objs := actualbucket.Objects(c, query)

		for {
			obj, err := objs.Next()
			if err == iterator.Done {
				break
			}
			if err != nil {
				return
			}

			newfile := File{}
			newfile.Name = obj.Name
			newfile.Type = obj.ContentType

			rc, err := actualbucket.Object(obj.Name).NewReader(c)
			if err != nil {
				log.Warningf(c, "readFile: unable to open file from bucket %q, file %q: %v", bucket, obj.Name, err)
				return
			}
			defer rc.Close()
			slurp, err := ioutil.ReadAll(rc)
			if err != nil {
				log.Warningf(c, "readFile: unable to read data from bucket %q, file %q: %v", bucket, obj.Name, err)
				return
			}
			newfile.Content = slurp
			export = append(export, newfile)
		}
	}

	return export
}

func GimmeDC(rw http.ResponseWriter, req *http.Request) string {
	c := appengine.NewContext(req)
	return appengine.Datacenter(c)
}
<|endoftext|>


<commit_before>package shortening // import "vallon.me/shortening"

import (
	"errors"
	"math"
)

var (
	// charSet - 64 ascii byte values (0-127)
	charSet     = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`)
	pow64       = powerArray(64)
	lookupTable = makeTable(charSet)
)

// Encode turns an uint64 into a slice of characters from 'charSet'
func Encode(n uint64) []byte {
	if n == math.MaxUint64 {
		return []byte("_---------O")
	}

	b := make([]byte, 0, 11) // preallocate to avoid growslice

	n++
	for 0 != n {
		n--
		b = append(b, charSet[n%64])
		n /= 64
	}

	return b
}

// Decode turns a slice of characters back into the original unit64.
//
// Errors are returned for invalid characters or input that would
// cause an overflow.
func Decode(b []byte) (n uint64, err error) {
	if 11 < len(b) || len(b) == 0 {
		return 0, errors.New("shortening: invalid decode length")
	}

	for i, c := range b {
		ind := lookupTable[c]
		if ind == -1 {
			return 0, errors.New("shortening: invalid decode character")
		}

		nn := n + uint64(ind+1)*pow64[i]
		if nn-1 < n {
			return 0, errors.New("shortening: int64 overflow")
		}

		n = nn
	}

	return n - 1, nil
}

func makeTable(cs []byte) []int8 {
	t := make([]int8, 256)

	// fill table with error values
	for i := range t {
		t[i] = -1
	}

	for i, c := range cs {
		t[c] = int8(i)
	}

	return t
}

func powerArray(base uint64) []uint64 {
	parr := make([]uint64, 1, 11)
	parr[0] = 1

	for i := 1; ; i++ {
		n := base * parr[i-1]

		if n < parr[i-1] {
			break // overflow
		}

		parr = append(parr, n)
	}

	return parr
}
<commit_msg>replace power array with a bit shift<commit_after>package shortening // import "vallon.me/shortening"

import (
	"errors"
	"math"
)

var (
	// charSet - 64 ascii byte values (0-127)
	charSet     = []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`)
	lookupTable = makeTable(charSet)
)

// Encode turns an uint64 into a slice of characters from 'charSet'
func Encode(n uint64) []byte {
	if n == math.MaxUint64 {
		return []byte("_---------O")
	}

	b := make([]byte, 0, 11) // preallocate to avoid growslice

	n++
	for 0 != n {
		n--
		b = append(b, charSet[n%64])
		n /= 64
	}

	return b
}

// Decode turns a slice of characters back into the original unit64.
//
// Errors are returned for invalid characters or input that would
// cause an overflow.
func Decode(b []byte) (n uint64, err error) {
	if 11 < len(b) || len(b) == 0 {
		return 0, errors.New("shortening: invalid decode length")
	}

	for i, c := range b {
		ind := lookupTable[c]
		if ind == -1 {
			return 0, errors.New("shortening: invalid decode character")
		}

		nn := n + uint64(ind+1)<<uint(6*i)
		if nn-1 < n {
			return 0, errors.New("shortening: int64 overflow")
		}

		n = nn
	}

	return n - 1, nil
}

func makeTable(cs []byte) []int8 {
	t := make([]int8, 256)

	// fill table with error values
	for i := range t {
		t[i] = -1
	}

	for i, c := range cs {
		t[c] = int8(i)
	}

	return t
}
<|endoftext|>


<commit_before>//  The MIT License (MIT) - http://opensource.org/licenses/MIT
//
//  Copyright (c) 2014 slowfei
//
//  Create on 2014-11-05
//  Update on 2014-12-09
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//	golang implement parser
package golang

import (
	"github.com/slowfei/gosfcore/utils/filemanager"
	"github.com/slowfei/gosfcore/utils/sub"
	"github.com/slowfei/gosfdoc"
	"github.com/slowfei/gosfdoc/index"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"
)

const (
	GO_NAME        = "go"
	GO_SUFFIX      = ".go"
	GO_TEST_SUFFIX = "_test.go"
)

var (
	//	\/\*\*[\s]*\n(\s|.)*?\*/\nfunc\s[a-zA-z_].*\(.*\)\s*\{\s*\n(?:\{\s*|.*\}|\s|.)*?\}
	//	type ([A-Z]\w*) \w+(\s?\{(\s*|.*)*?\})*
	REXType    = regexp.MustCompile("type ([A-Z]\\w*) \\w+[ ]*(\\{)?")
	SNBraces   = SFSubUtil.NewSubNest([]byte("{"), []byte("}"))
	SNBetweens = []*SFSubUtil.SubNest{
		SNBraces,
		SFSubUtil.NewSubNest([]byte("`"), []byte("`")),
		SFSubUtil.NewSubNest([]byte(`"`), []byte(`"`)),
		SFSubUtil.NewSubNest([]byte(`'`), []byte(`'`)),
	}
)

func init() {
	gosfdoc.AddParser(NewParser())
}

/**
 *	golang parser
 */
type GolangParser struct {
	config  gosfdoc.MainConfig
	indexDB index.IndexDB
}

/**
 *	new golang parser
 */
func NewParser() *GolangParser {
	gp := new(GolangParser)
	gp.indexDB = index.CreateIndexDB(GO_NAME, index.DBTypeFile)
	return gp
}

//#pragma mark github.com/slowfei/gosfdoc.DocParser interface ---------------------------------------------------------------------

func (g *GolangParser) Name() string {
	return GO_NAME
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseStart(config gosfdoc.MainConfig) {
	g.config = config
	g.indexDB.Open()
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseEnd() {
	g.indexDB.Close()
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) CheckFile(filePath string, info os.FileInfo) bool {
	result := false

	if 0 != len(filePath) && nil != info && !info.IsDir() {
		result = strings.HasSuffix(filePath, GO_SUFFIX)

		if result {
			result = !strings.HasSuffix(filePath, GO_TEST_SUFFIX)
		}
	}
	return result
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) EachIndexFile(filebuf *gosfdoc.FileBuf) {
	// find type (XXXX)
	var outBetweens [][]int
	for i := 0; i < len(SNBetweens); i++ {
		tempIndexs := filebuf.SubNestAllIndex(SNBetweens[i], nil)
		if 0 != len(tempIndexs) {
			outBetweens = append(outBetweens, tempIndexs...)
		}
	}
	var typeInfos []index.TypeInfo
	tempPackage := ""

	//	包查询 TODO， 解决如何查询包
	gopaths := SFFileManager.GetGOPATHDirs()
	for i := 0; i < len(gopaths); i++ {
		gopath := path.Join(gopaths[i], "src")
		filebufPath := path.Dir(filebuf.Path())
		if strings.HasPrefix(filebufPath, gopath) {
			tempPackage = filebufPath[len(gopath)+1 : len(filebufPath)]
			//	TODO 需要考虑查询的情况，直接使用这样的包名是否可以查找。
		}
	}

	//	类型查询
	typeIndexs := filebuf.FindAllSubmatchIndex(REXType)
	for i := 0; i < len(typeIndexs); i++ {
		indexs := typeIndexs[i]
		startIndex := indexs[0]
		endIndex := indexs[1]
		tempType := index.TypeInfo{}

		// type GolangParser struct { [1 27 6 18 26 27]
		// type OperateResult int [88 110 93 106 -1 -1]
		if 6 == len(indexs) && !isRuleOutIndex(startIndex, outBetweens) {

			leftBraces := indexs[4]
			rightBraces := indexs[5]
			if -1 != leftBraces && -1 != rightBraces {
				bracesIndexs := filebuf.SubNestIndex(leftBraces, SNBraces, outBetweens)
				if 2 == len(bracesIndexs) && -1 != bracesIndexs[0] && -1 != bracesIndexs[1] {
					endIndex = bracesIndexs[1]
				}
			}

			lines := filebuf.LineNumberByIndex(startIndex, endIndex)
			if -1 != lines[0] && -1 != lines[1] {
				tempType.LineStart = lines[0]
				tempType.LineEnd = lines[1]
			}

			startName := indexs[2]
			endName := indexs[3]
			if -1 != startName && -1 != endName {
				tempType.Name = string(filebuf.SubBytes(startName, endName))
			} else {
				tempType.Name = ""
			}
		}
	}

}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParsePreview(filebuf *gosfdoc.FileBuf) []gosfdoc.Preview {
	return nil
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseCodeblock(filebuf *gosfdoc.FileBuf) []gosfdoc.CodeBlock {
	return nil
}

/**
 *	see DocParser interface
 */
func (n *GolangParser) ParsePackageInfo(filebuf *gosfdoc.FileBuf) string {
	return ""
}

/**
 *	判断是否是排除坐标
 *
 *	@return 在坐标范围内返回 true
 */
func isRuleOutIndex(index int, outBetweens [][]int) bool {
	result := false

	for i := 0; i < len(outBetweens); i++ {
		indexs := outBetweens[i]
		if 2 == len(indexs) {
			s := indexs[0]
			e := indexs[1]
			if index > s && index < e {
				result = true
				break
			}
		}
	}
	return result
}
<commit_msg>功能：已经编写完索引的操作<commit_after>//  The MIT License (MIT) - http://opensource.org/licenses/MIT
//
//  Copyright (c) 2014 slowfei
//
//  Create on 2014-11-05
//  Update on 2014-12-09
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//	golang implement parser
package golang

import (
	"bytes"
	"fmt"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"github.com/slowfei/gosfcore/utils/sub"
	"github.com/slowfei/gosfdoc"
	"github.com/slowfei/gosfdoc/index"
	"os"
	"path"
	"regexp"
	"strings"
)

const (
	GO_NAME        = "go"
	GO_SUFFIX      = ".go"
	GO_TEST_SUFFIX = "_test.go"
)

var (
	// e.g.: type Temp struct {
	REGType = regexp.MustCompile("type ([A-Z]\\w*) \\w+[ ]*(\\{)?")
	// e.g.: package main
	REGPackage = regexp.MustCompile("package (\\w+)\\s*")
	// e.g.: /** ... */[\n]package main; //...[\n]package main
	REGPackageInfo = regexp.MustCompile("(/\\*\\*[\\S\\s]+?\\*/\n|(?:(?:[ ]*//.*?\n)+))[ ]*package \\w+")
	// e.g.: /** ... */[\n]const TConst = 1; //...[\n]const (
	REGConst = regexp.MustCompile("(/\\*\\*[\\S\\s]+?\\*/\n|(?:(?:[ ]*//.*?\n)+))?[ ]*(const[\\s]+(?:[A-Z].*|\\()+?)")

	SNBraces   = SFSubUtil.NewSubNest([]byte("{"), []byte("}"))
	SNBetweens = []*SFSubUtil.SubNest{
		SNBraces,
		SFSubUtil.NewSubNest([]byte("`"), []byte("`")),
		SFSubUtil.NewSubNest([]byte(`"`), []byte(`"`)),
		SFSubUtil.NewSubNest([]byte(`'`), []byte(`'`)),
	}
)

func init() {
	gosfdoc.AddParser(NewParser())
}

type goConst struct {
}

type goVar struct {
}

type goFunc struct {
}

type goType struct {
	funcs []goTypeFunc
}

type goTypeFunc struct {
}

/**
 *	golang parser
 */
type GolangParser struct {
	config  gosfdoc.MainConfig
	indexDB index.IndexDB
}

/**
 *	new golang parser
 */
func NewParser() *GolangParser {
	gp := new(GolangParser)
	gp.indexDB = index.CreateIndexDB(GO_NAME, index.DBTypeFile)
	return gp
}

//#pragma mark github.com/slowfei/gosfdoc.DocParser interface ---------------------------------------------------------------------

func (g *GolangParser) Name() string {
	return GO_NAME
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseStart(config gosfdoc.MainConfig) {
	g.config = config
	g.indexDB.Open()
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseEnd() {
	g.indexDB.Close()
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) CheckFile(filePath string, info os.FileInfo) bool {
	result := false

	if 0 != len(filePath) && nil != info && !info.IsDir() {
		result = strings.HasSuffix(filePath, GO_SUFFIX)

		if result {
			result = !strings.HasSuffix(filePath, GO_TEST_SUFFIX)
		}
	}
	return result
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) EachIndexFile(filebuf *gosfdoc.FileBuf) {
	// find type (XXXX)
	var outBetweens [][]int
	if nil == filebuf.UserData {
		outBetweens = getOutBetweens(filebuf)
		filebuf.UserData = outBetweens
	}

	tempPackagePath := ""
	tempPackageName := ""

	// find package name
	packageIndexs := filebuf.FindAllSubmatchIndex(REGPackage)
	for i := 0; i < len(packageIndexs); i++ {
		indexs := packageIndexs[i]
		if 4 == len(indexs) && !isRuleOutIndex(indexs[0], outBetweens) {
			tempPackageName = string(filebuf.SubBytes(indexs[2], indexs[3]))
			break
		}
	}

	//	查询不到package 证明是无效的文件
	if 0 == len(tempPackageName) {
		fmt.Println("InvalidFile: find less than the package name. file path:", filebuf.Path())
		return
	}

	// find package path
	gopaths := SFFileManager.GetGOPATHDirs()
	for i := 0; i < len(gopaths); i++ {
		gopath := path.Join(gopaths[i], "src")
		filebufPath := path.Dir(filebuf.Path())
		if strings.HasPrefix(filebufPath, gopath) {
			tempPackagePath = filebufPath[len(gopath)+1 : len(filebufPath)]
		}
	}

	//	无效文件提示
	if 0 == len(tempPackagePath) {
		fmt.Println("InvalidFile: is not a valid golang working environment file. file path:", filebuf.Path())
		return
	}

	//	类型查询
	typeIndexs := filebuf.FindAllSubmatchIndex(REGType)
	for i := 0; i < len(typeIndexs); i++ {
		indexs := typeIndexs[i]
		startIndex := indexs[0]
		endIndex := indexs[1]
		tempType := index.TypeInfo{}
		tempType.PackageName = tempPackageName
		tempType.PackagePath = tempPackagePath

		// type GolangParser struct { [1 27 6 18 26 27]
		// type OperateResult int [88 110 93 106 -1 -1]
		if 6 == len(indexs) && !isRuleOutIndex(startIndex, outBetweens) {

			leftBraces := indexs[4]
			rightBraces := indexs[5]
			if -1 != leftBraces && -1 != rightBraces {
				bracesIndexs := filebuf.SubNestIndex(leftBraces, SNBraces, outBetweens)
				if 2 == len(bracesIndexs) && -1 != bracesIndexs[0] && -1 != bracesIndexs[1] {
					endIndex = bracesIndexs[1]
				}
			}

			lines := filebuf.LineNumberByIndex(startIndex, endIndex)
			if -1 != lines[0] && -1 != lines[1] {
				tempType.LineStart = lines[0]
				tempType.LineEnd = lines[1]
			}

			tempType.TypeName = string(filebuf.SubBytes(indexs[2], indexs[3]))
			if 0 != len(tempType.TypeName) {
				err := g.indexDB.SetType(tempType)
				if nil != err {
					fmt.Println("IndexError:", err.Error())
				}
			}

		}
	} // End for i := 0; i < len(typeIndexs); i++ {

}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParsePreview(filebuf *gosfdoc.FileBuf) []gosfdoc.Preview {
	//	TODO
	// 1. const const{ }
	// 2. var var { }
	// 3. func
	// 4. type
	// 5. 	return func type
	// 6. 	type func

	return nil
}

/**
 *	see DocParser interface
 */
func (g *GolangParser) ParseCodeblock(filebuf *gosfdoc.FileBuf) []gosfdoc.CodeBlock {
	return nil
}

/**
 *	see DocParser interface
 */
func (n *GolangParser) ParsePackageInfo(filebuf *gosfdoc.FileBuf) string {
	result := bytes.NewBuffer(nil)

	subBytes := filebuf.FindSubmatch(REGPackageInfo)
	if 2 != len(subBytes) {
		return ""
	}

	infoLines := bytes.Split(subBytes[1], []byte("\n"))
	reCount := 0
	var prefixTag []byte = nil
	prefixLen := 0

	//	判断是否存在 /* */ 如果存在则去除首行和尾行的扫描
	if 0 != len(infoLines) &&
		0 <= bytes.Index(infoLines[0], []byte("/*")) {
		reCount = 1
	}

	//	 len(infoLines)-reCount (-1) 由于正则截取的规则中会包含一个\n符号，所以需要去除
	for i := reCount; i < len(infoLines)-reCount-1; i++ {
		infoBytes := infoLines[i]

		if i == reCount {
			prefixTag = gosfdoc.FindPrefixFilterTag(infoBytes)
			prefixLen = len(prefixTag)
		}

		if nil != prefixTag {

			if 0 == bytes.Index(infoBytes, prefixTag) {
				result.Write(infoBytes[prefixLen:])
			} else {
				trimed := bytes.TrimSpace(infoBytes)
				// 有可能是空行，所需需要判断这行是否只有（ "*" || "//" ），如果不是则添加追加这一行内容
				if !bytes.Equal(trimed, []byte("*")) && !bytes.Equal(trimed, []byte("//")) {
					result.Write(infoBytes)
				} else {
					result.WriteByte('\n')
				}
			}

		} else {
			result.Write(infoBytes)
		}

		result.WriteByte('\n')
	}

	return result.String()
}

/**
 *	find constant
 *
 *	e.g:
 *	const xxx
 *	const ( ... )
 */
func findConst(filebuf *gosfdoc.FileBuf) {

}

/**
 *	find variable
 *
 *	e.g:
 *	var xxx
 *	var ( ... )
 */
func findVar() {

}

/**
 *	find function
 *
 *	e.g:
 *	func funcName()
 */
func findFunc() {

}

/**
 *	find type and function
 *
 *	e.g:
 *	type xxx
 *		func NewType() xxx
 *		func (type) funcName() xxx
 */
func findTypeAndFunc() {

}

/**
 *	获取文件排除范围的坐标范围
 *
 *	@param `filebuf`
 *	@return
 */
func getOutBetweens(filebuf *gosfdoc.FileBuf) [][]int {

	outBetweens := make([][]int, 0, 0)

	for i := 0; i < len(SNBetweens); i++ {
		tempIndexs := filebuf.SubNestAllIndex(SNBetweens[i], nil)
		if 0 != len(tempIndexs) {
			outBetweens = append(outBetweens, tempIndexs...)
		}
	}

	return outBetweens
}

/**
 *	判断是否是排除坐标
 *
 *	@return 在坐标范围内返回 true
 */
func isRuleOutIndex(index int, outBetweens [][]int) bool {
	result := false

	for i := 0; i < len(outBetweens); i++ {
		indexs := outBetweens[i]
		if 2 == len(indexs) {
			s := indexs[0]
			e := indexs[1]
			if index > s && index < e {
				result = true
				break
			}
		}
	}
	return result
}
<|endoftext|>


<commit_before>package fakeyagnats

import (
	"sync"

	"github.com/cloudfoundry/yagnats"
)

type FakeYagnats struct {
	subscriptions        map[string][]yagnats.Subscription
	publishedMessages    map[string][]yagnats.Message
	unsubscriptions      []int64
	unsubscribedSubjects []string

	connectedConnectionProvider yagnats.ConnectionProvider

	connectError     error
	unsubscribeError error

	whenSubscribing map[string]func() error
	whenPublishing  map[string]func() error

	onPing       func() bool
	pingResponse bool

	nextSubscriptionID int64

	sync.RWMutex
}

func New() *FakeYagnats {
	fake := &FakeYagnats{}
	fake.Reset()
	return fake
}

func (f *FakeYagnats) Reset() {
	f.Lock()
	defer f.Unlock()

	f.publishedMessages = map[string][]yagnats.Message{}
	f.subscriptions = map[string][]yagnats.Subscription{}
	f.unsubscriptions = []int64{}
	f.unsubscribedSubjects = []string{}

	f.connectedConnectionProvider = nil

	f.connectError = nil
	f.unsubscribeError = nil

	f.whenSubscribing = map[string]func() error{}
	f.whenPublishing = map[string]func() error{}

	f.pingResponse = true

	f.nextSubscriptionID = 0
}

func (f *FakeYagnats) OnPing(onPingCallback func() bool) {
	f.Lock()
	f.onPing = onPingCallback
	f.Unlock()
}

func (f *FakeYagnats) Ping() bool {
	f.RLock()
	onPing := f.onPing
	response := f.pingResponse
	f.RUnlock()

	if onPing != nil {
		return onPing()
	}

	return response
}

func (f *FakeYagnats) Connect(connectionProvider yagnats.ConnectionProvider) error {
	f.Lock()
	defer f.Unlock()

	if f.connectError != nil {
		return f.connectError
	}

	f.connectedConnectionProvider = connectionProvider

	return f.connectError
}

func (f *FakeYagnats) Disconnect() {
	f.Lock()
	defer f.Unlock()

	f.connectedConnectionProvider = nil
	return
}

func (f *FakeYagnats) Publish(subject string, payload []byte) error {
	return f.PublishWithReplyTo(subject, "", payload)
}

func (f *FakeYagnats) PublishWithReplyTo(subject, reply string, payload []byte) error {
	f.RLock()

	injectedCallback, injected := f.whenPublishing[subject]

	message := &yagnats.Message{
		Subject: subject,
		ReplyTo: reply,
		Payload: payload,
	}

	var callback yagnats.Callback

	if len(f.subscriptions[subject]) > 0 {
		callback = f.subscriptions[subject][0].Callback
	}

	f.RUnlock()

	if injected {
		err := injectedCallback()
		if err != nil {
			return err
		}
	}

	f.Lock()
	f.publishedMessages[subject] = append(f.publishedMessages[subject], *message)
	f.Unlock()

	if callback != nil {
		callback(message)
	}

	return nil
}

func (f *FakeYagnats) Subscribe(subject string, callback yagnats.Callback) (int64, error) {
	return f.SubscribeWithQueue(subject, "", callback)
}

func (f *FakeYagnats) SubscribeWithQueue(subject, queue string, callback yagnats.Callback) (int64, error) {
	f.RLock()

	injectedCallback, injected := f.whenSubscribing[subject]

	f.RUnlock()

	if injected {
		err := injectedCallback()
		if err != nil {
			return 0, err
		}
	}

	f.Lock()
	defer f.Unlock()

	f.nextSubscriptionID++

	subscription := yagnats.Subscription{
		Subject:  subject,
		Queue:    queue,
		ID:       f.nextSubscriptionID,
		Callback: callback,
	}

	f.subscriptions[subject] = append(f.subscriptions[subject], subscription)

	return subscription.ID, nil
}

func (f *FakeYagnats) Unsubscribe(subscription int64) error {
	f.Lock()
	defer f.Unlock()

	if f.unsubscribeError != nil {
		return f.unsubscribeError
	}

	f.unsubscriptions = append(f.unsubscriptions, subscription)

	return nil
}

func (f *FakeYagnats) UnsubscribeAll(subject string) {
	f.Lock()
	defer f.Unlock()

	f.unsubscribedSubjects = append(f.unsubscribedSubjects, subject)
}

func (f *FakeYagnats) WhenSubscribing(subject string, callback func() error) {
	f.Lock()
	defer f.Unlock()

	f.whenSubscribing[subject] = callback
}

func (f *FakeYagnats) Subscriptions(subject string) []yagnats.Subscription {
	f.RLock()
	defer f.RUnlock()

	return f.subscriptions[subject]
}

func (f *FakeYagnats) WhenPublishing(subject string, callback func() error) {
	f.Lock()
	defer f.Unlock()

	f.whenPublishing[subject] = callback
}

func (f *FakeYagnats) PublishedMessages(subject string) []yagnats.Message {
	f.RLock()
	defer f.RUnlock()

	return f.publishedMessages[subject]
}
<commit_msg>WhenPublishing/Subscribing take callback/message<commit_after>package fakeyagnats

import (
	"sync"

	"github.com/cloudfoundry/yagnats"
)

type FakeYagnats struct {
	subscriptions        map[string][]yagnats.Subscription
	publishedMessages    map[string][]yagnats.Message
	unsubscriptions      []int64
	unsubscribedSubjects []string

	connectedConnectionProvider yagnats.ConnectionProvider

	connectError     error
	unsubscribeError error

	whenSubscribing map[string]func(yagnats.Callback) error
	whenPublishing  map[string]func(*yagnats.Message) error

	onPing       func() bool
	pingResponse bool

	nextSubscriptionID int64

	sync.RWMutex
}

func New() *FakeYagnats {
	fake := &FakeYagnats{}
	fake.Reset()
	return fake
}

func (f *FakeYagnats) Reset() {
	f.Lock()
	defer f.Unlock()

	f.publishedMessages = map[string][]yagnats.Message{}
	f.subscriptions = map[string][]yagnats.Subscription{}
	f.unsubscriptions = []int64{}
	f.unsubscribedSubjects = []string{}

	f.connectedConnectionProvider = nil

	f.connectError = nil
	f.unsubscribeError = nil

	f.whenSubscribing = map[string]func(yagnats.Callback) error{}
	f.whenPublishing = map[string]func(*yagnats.Message) error{}

	f.pingResponse = true

	f.nextSubscriptionID = 0
}

func (f *FakeYagnats) OnPing(onPingCallback func() bool) {
	f.Lock()
	f.onPing = onPingCallback
	f.Unlock()
}

func (f *FakeYagnats) Ping() bool {
	f.RLock()
	onPing := f.onPing
	response := f.pingResponse
	f.RUnlock()

	if onPing != nil {
		return onPing()
	}

	return response
}

func (f *FakeYagnats) Connect(connectionProvider yagnats.ConnectionProvider) error {
	f.Lock()
	defer f.Unlock()

	if f.connectError != nil {
		return f.connectError
	}

	f.connectedConnectionProvider = connectionProvider

	return f.connectError
}

func (f *FakeYagnats) Disconnect() {
	f.Lock()
	defer f.Unlock()

	f.connectedConnectionProvider = nil
	return
}

func (f *FakeYagnats) Publish(subject string, payload []byte) error {
	return f.PublishWithReplyTo(subject, "", payload)
}

func (f *FakeYagnats) PublishWithReplyTo(subject, reply string, payload []byte) error {
	f.RLock()

	injectedCallback, injected := f.whenPublishing[subject]

	message := &yagnats.Message{
		Subject: subject,
		ReplyTo: reply,
		Payload: payload,
	}

	var callback yagnats.Callback

	if len(f.subscriptions[subject]) > 0 {
		callback = f.subscriptions[subject][0].Callback
	}

	f.RUnlock()

	if injected {
		err := injectedCallback(message)
		if err != nil {
			return err
		}
	}

	f.Lock()
	f.publishedMessages[subject] = append(f.publishedMessages[subject], *message)
	f.Unlock()

	if callback != nil {
		callback(message)
	}

	return nil
}

func (f *FakeYagnats) Subscribe(subject string, callback yagnats.Callback) (int64, error) {
	return f.SubscribeWithQueue(subject, "", callback)
}

func (f *FakeYagnats) SubscribeWithQueue(subject, queue string, callback yagnats.Callback) (int64, error) {
	f.RLock()

	injectedCallback, injected := f.whenSubscribing[subject]

	f.RUnlock()

	if injected {
		err := injectedCallback(callback)
		if err != nil {
			return 0, err
		}
	}

	f.Lock()
	defer f.Unlock()

	f.nextSubscriptionID++

	subscription := yagnats.Subscription{
		Subject:  subject,
		Queue:    queue,
		ID:       f.nextSubscriptionID,
		Callback: callback,
	}

	f.subscriptions[subject] = append(f.subscriptions[subject], subscription)

	return subscription.ID, nil
}

func (f *FakeYagnats) Unsubscribe(subscription int64) error {
	f.Lock()
	defer f.Unlock()

	if f.unsubscribeError != nil {
		return f.unsubscribeError
	}

	f.unsubscriptions = append(f.unsubscriptions, subscription)

	return nil
}

func (f *FakeYagnats) UnsubscribeAll(subject string) {
	f.Lock()
	defer f.Unlock()

	f.unsubscribedSubjects = append(f.unsubscribedSubjects, subject)
}

func (f *FakeYagnats) WhenSubscribing(subject string, callback func(yagnats.Callback) error) {
	f.Lock()
	defer f.Unlock()

	f.whenSubscribing[subject] = callback
}

func (f *FakeYagnats) Subscriptions(subject string) []yagnats.Subscription {
	f.RLock()
	defer f.RUnlock()

	return f.subscriptions[subject]
}

func (f *FakeYagnats) WhenPublishing(subject string, callback func(*yagnats.Message) error) {
	f.Lock()
	defer f.Unlock()

	f.whenPublishing[subject] = callback
}

func (f *FakeYagnats) PublishedMessages(subject string) []yagnats.Message {
	f.RLock()
	defer f.RUnlock()

	return f.publishedMessages[subject]
}
<|endoftext|>


<commit_before>package lazyquicktime

import "testing"
import "fmt"
import "net/url"
//import "io"
import "os"

import "github.com/amarburg/go-lazyfs"

import "image/png"
import "github.com/amarburg/go-lazyfs-testfiles/http_server"

//import "net/url"
//var TestUrlRoot = "https://amarburg.github.io/go-lazyfs-testfiles/"
//var TestUrlRoot = "http://localhost:8080/files/"
//var TestUrl,_ = url.Parse( TestUrlRoot + TestMovPath )
var TestMovPath = "CamHD_Vent_Short.mov"

// For local testing
//var TestMovPath = lazyfs_testfiles.TestMovPath

var SparseHttpStoreRoot = "cache/httpsparse/"

func TestConvert( t *testing.T ) {

  srv := lazyfs_testfiles.HttpServer( 4567 )

  testUrl,err := url.Parse( srv.Url + TestMovPath )

  source,err := lazyfs.OpenHttpSource( *testUrl )
  //fmt.Println(source)
  //source,err := lazyfs.OpenLocalFileSource( "../go-lazyfs-testfiles/", TestMovPath )
  if err != nil {
    panic("Couldn't open HttpFSSource")
  }

  store,err := lazyfs.OpenSparseFileStore( source, SparseHttpStoreRoot )
  if store == nil {
    panic("Couldn't open SparesFileFSStore")
  }

  mov := LoadMovMetadata( store )

  // Try extracting a frame
  frame := 2
  img,_ := mov.ExtractFrame( frame )

  if err != nil { panic(fmt.Sprintf("Error decoding frame: %s", err.Error()))}

  img_filename := fmt.Sprintf("frame%06d.png", frame)
  img_file,err := os.Create(img_filename)
  if err != nil { panic(fmt.Sprintf("Error creating png %s: %s", img_filename, err.Error()))}

  err = png.Encode( img_file, img )
  if err != nil { panic(fmt.Sprintf("Error writing png %s: %s", img_filename, err.Error()))}

  srv.Stop()
}
<commit_msg>Hm, maybe removing URL wasn't a great idea.<commit_after>package lazyquicktime

import "testing"
import "fmt"
import "net/url"
//import "io"
import "os"

import "github.com/amarburg/go-lazyfs"

import "image/png"
import "github.com/amarburg/go-lazyfs-testfiles/http_server"

//import "net/url"
//var TestUrlRoot = "https://amarburg.github.io/go-lazyfs-testfiles/"
//var TestUrlRoot = "http://localhost:8080/files/"
//var TestUrl,_ = url.Parse( TestUrlRoot + TestMovPath )
var TestMovPath = "CamHD_Vent_Short.mov"

// For local testing
//var TestMovPath = lazyfs_testfiles.TestMovPath

var SparseHttpStoreRoot = "cache/httpsparse/"

func TestConvert( t *testing.T ) {

  srv := lazyfs_testfiles.HttpServer( 4567 )

  testUrl,err := url.Parse( "http://localhost:4567/" + TestMovPath )

  source,err := lazyfs.OpenHttpSource( *testUrl )
  //fmt.Println(source)
  //source,err := lazyfs.OpenLocalFileSource( "../go-lazyfs-testfiles/", TestMovPath )
  if err != nil {
    panic("Couldn't open HttpFSSource")
  }

  store,err := lazyfs.OpenSparseFileStore( source, SparseHttpStoreRoot )
  if store == nil {
    panic("Couldn't open SparesFileFSStore")
  }

  mov := LoadMovMetadata( store )

  // Try extracting a frame
  frame := 2
  img,_ := mov.ExtractFrame( frame )

  if err != nil { panic(fmt.Sprintf("Error decoding frame: %s", err.Error()))}

  img_filename := fmt.Sprintf("frame%06d.png", frame)
  img_file,err := os.Create(img_filename)
  if err != nil { panic(fmt.Sprintf("Error creating png %s: %s", img_filename, err.Error()))}

  err = png.Encode( img_file, img )
  if err != nil { panic(fmt.Sprintf("Error writing png %s: %s", img_filename, err.Error()))}

  srv.Stop()
}
<|endoftext|>