<commit_before>package remoteenvironment

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"

	"github.com/golang/glog"
	"github.com/kyma-project/kyma/components/remote-environment-broker/pkg/apis/applicationconnector/v1alpha1"
	remoteenvironmentv1alpha1 "github.com/kyma-project/kyma/components/remote-environment-broker/pkg/client/clientset/versioned/typed/applicationconnector/v1alpha1"
	reMappinglister "github.com/kyma-project/kyma/components/remote-environment-broker/pkg/client/listers/applicationconnector/v1alpha1"
	"github.com/kyma-project/kyma/components/ui-api-layer/internal/pager"
	"github.com/kyma-project/kyma/components/ui-api-layer/pkg/iosafety"
	"github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/tools/cache"
)

const (
	remoteMappingNameIndex = "mapping-name"
	// This regex comes from the k8s resource name validation and has been checked against traversal attack
	// https://github.com/kubernetes/kubernetes/blob/v1.10.1/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L126
	reNameRegex = `^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`
)

// remoteEnvironmentService provides listing environments along with remote environments.
// It provides also remote environment enabling/disabling in given namespace.
type remoteEnvironmentService struct {
	client          remoteenvironmentv1alpha1.ApplicationconnectorV1alpha1Interface
	mappingLister   reMappinglister.EnvironmentMappingLister
	mappingInformer cache.SharedIndexInformer
	reInformer      cache.SharedIndexInformer
	connectorSvcURL string
	httpClient      *http.Client
	reNameRegex     *regexp.Regexp
}

func newRemoteEnvironmentService(client remoteenvironmentv1alpha1.ApplicationconnectorV1alpha1Interface, cfg Config, mappingInformer cache.SharedIndexInformer, mappingLister reMappinglister.EnvironmentMappingLister, reInformer cache.SharedIndexInformer) (*remoteEnvironmentService, error) {
	mappingInformer.AddIndexers(cache.Indexers{
		remoteMappingNameIndex: func(obj interface{}) ([]string, error) {
			mapping, ok := obj.(*v1alpha1.EnvironmentMapping)
			if !ok {
				return nil, errors.New("cannot convert item")
			}

			return []string{mapping.Name}, nil
		},
	})

	regex, err := regexp.Compile(reNameRegex)
	if err != nil {
		return nil, errors.Wrapf(err, "while compiling %s regex", reNameRegex)
	}
	return &remoteEnvironmentService{
		mappingLister:   mappingLister,
		mappingInformer: mappingInformer,
		reInformer:      reInformer,
		client:          client,
		connectorSvcURL: cfg.Connector.URL,
		httpClient: &http.Client{
			Timeout: cfg.Connector.HTTPCallTimeout,
		},
		reNameRegex: regex,
	}, nil
}

func (svc *remoteEnvironmentService) ListNamespacesFor(reName string) ([]string, error) {
	mappingObjs, err := svc.mappingInformer.GetIndexer().ByIndex(remoteMappingNameIndex, reName)
	if err != nil {
		return nil, errors.Wrapf(err, "while listing environment mappings by index %q with key %q", remoteMappingNameIndex, reName)
	}

	nsList := make([]string, 0, len(mappingObjs))
	for _, item := range mappingObjs {
		reMapping, ok := item.(*v1alpha1.EnvironmentMapping)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'EnvironmentMapping' in version 'v1alpha1'", item)
		}
		nsList = append(nsList, reMapping.Namespace)
	}

	return nsList, nil
}

func (svc *remoteEnvironmentService) Find(name string) (*v1alpha1.RemoteEnvironment, error) {
	remoteEnvironment, exists, err := svc.reInformer.GetStore().GetByKey(name)

	if err != nil || !exists {
		return nil, err
	}

	re, ok := remoteEnvironment.(*v1alpha1.RemoteEnvironment)
	if !ok {

		return nil, fmt.Errorf("Cannot process RemoteEnvironment")
	}

	return re, nil
}

func (svc *remoteEnvironmentService) List(params pager.PagingParams) ([]*v1alpha1.RemoteEnvironment, error) {
	reObjs, err := pager.From(svc.reInformer.GetStore()).Limit(params)
	if err != nil {
		return nil, errors.Wrapf(err, "while listing remote environments with paging params [first: %v] [offset: %v]", params.First, params.Offset)
	}

	res := make([]*v1alpha1.RemoteEnvironment, 0, len(reObjs))
	for _, item := range reObjs {
		re, ok := item.(*v1alpha1.RemoteEnvironment)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'RemoteEnvironment' in version 'v1alpha1'", item)
		}

		res = append(res, re)
	}

	return res, nil
}

func (svc *remoteEnvironmentService) ListInEnvironment(environment string) ([]*v1alpha1.RemoteEnvironment, error) {
	mappings, err := svc.mappingLister.EnvironmentMappings(environment).List(labels.Everything())
	if err != nil {
		return nil, errors.Wrap(err, "while listing environment mappings")
	}

	res := make([]*v1alpha1.RemoteEnvironment, 0)
	for _, mapping := range mappings {
		// Remote Environment CR is cluster wide so the key is only the name
		reObj, exists, err := svc.reInformer.GetIndexer().GetByKey(mapping.Name)
		if err != nil {
			return nil, errors.Wrapf(err, "while getting remote environment with key %s", mapping.Name)
		}

		if !exists {
			glog.Warningf("Found environment mapping %q in namespaces %q but remote environment with name %q does not exists", mapping.Name, mapping.Namespace, mapping.Name)
			continue
		}

		reCR, ok := reObj.(*v1alpha1.RemoteEnvironment)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'RemoteEnvironment' in version 'v1alpha1'", reObj)
		}

		//TODO: Write test to make sure that this is a real deep copy
		deepCopy := reCR.DeepCopy()
		res = append(res, deepCopy)
	}
	return res, nil
}

// Enable enables remote environment in given namespace by creating EnvironmentMappinggo
func (svc *remoteEnvironmentService) Enable(namespace, name string) (*v1alpha1.EnvironmentMapping, error) {
	em, err := svc.client.EnvironmentMappings(namespace).Create(&v1alpha1.EnvironmentMapping{
		TypeMeta: metav1.TypeMeta{
			Kind:       "EnvironmentMapping",
			APIVersion: "remoteenvironment.kyma.cx/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
	})
	return em, err
}

// Disable disables remote environment in given namespace by removing EnvironmentMapping
func (svc *remoteEnvironmentService) Disable(namespace, name string) error {
	return svc.client.EnvironmentMappings(namespace).Delete(name, &metav1.DeleteOptions{})
}

func (svc *remoteEnvironmentService) GetConnectionURL(remoteEnvironment string) (string, error) {
	if ok := svc.reNameRegex.MatchString(remoteEnvironment); !ok {
		return "", fmt.Errorf("Remote evironment name %q does not match regex: %s", remoteEnvironment, reNameRegex)
	}
	reqURL := fmt.Sprintf("%s/v1/remoteenvironments/%s/tokens", svc.connectorSvcURL, remoteEnvironment)

	req, err := http.NewRequest(http.MethodPost, reqURL, nil)
	if err != nil {
		return "", errors.Wrap(err, "while creating HTTP request")
	}

	resp, err := svc.httpClient.Do(req)
	if err != nil {
		return "", errors.Wrap(err, "while making HTTP call")
	}
	defer svc.drainAndCloseBody(resp.Body)

	if resp.StatusCode != http.StatusCreated {
		cause := svc.extractErrorCause(resp.Body)
		return "", errors.Wrapf(cause, "while requesting connection URL obtained unexpected status code %d", resp.StatusCode)
	}

	connectorURL, err := svc.extractConnectionURL(resp.Body)
	if err != nil {
		return "", errors.Wrap(err, "while extracting connection URL from body")
	}

	return connectorURL, nil
}

func (svc *remoteEnvironmentService) extractConnectionURL(body io.ReadCloser) (string, error) {
	var dto struct {
		URL string `json:"url"`
	}
	if err := json.NewDecoder(body).Decode(&dto); err != nil {
		return "", errors.Wrap(err, "while decoding json")
	}

	return dto.URL, nil
}

func (svc *remoteEnvironmentService) extractErrorCause(body io.ReadCloser) error {
	var dto struct {
		Error string `json:"error"`
	}
	if err := json.NewDecoder(body).Decode(&dto); err != nil {
		return errors.Wrap(err, "while decoding json to get error msg from body")
	}

	return errors.New(dto.Error)
}

func (svc *remoteEnvironmentService) drainAndCloseBody(body io.ReadCloser) {
	_ = iosafety.DrainReader(body)
	body.Close()
}
<commit_msg>Fix query about enabling RemoteEnvironment in given namespace (#868)<commit_after>package remoteenvironment

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"

	"github.com/golang/glog"
	"github.com/kyma-project/kyma/components/remote-environment-broker/pkg/apis/applicationconnector/v1alpha1"
	remoteenvironmentv1alpha1 "github.com/kyma-project/kyma/components/remote-environment-broker/pkg/client/clientset/versioned/typed/applicationconnector/v1alpha1"
	reMappinglister "github.com/kyma-project/kyma/components/remote-environment-broker/pkg/client/listers/applicationconnector/v1alpha1"
	"github.com/kyma-project/kyma/components/ui-api-layer/internal/pager"
	"github.com/kyma-project/kyma/components/ui-api-layer/pkg/iosafety"
	"github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/client-go/tools/cache"
)

const (
	remoteMappingNameIndex = "mapping-name"
	// This regex comes from the k8s resource name validation and has been checked against traversal attack
	// https://github.com/kubernetes/kubernetes/blob/v1.10.1/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L126
	reNameRegex = `^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`
)

// remoteEnvironmentService provides listing environments along with remote environments.
// It provides also remote environment enabling/disabling in given namespace.
type remoteEnvironmentService struct {
	client          remoteenvironmentv1alpha1.ApplicationconnectorV1alpha1Interface
	mappingLister   reMappinglister.EnvironmentMappingLister
	mappingInformer cache.SharedIndexInformer
	reInformer      cache.SharedIndexInformer
	connectorSvcURL string
	httpClient      *http.Client
	reNameRegex     *regexp.Regexp
}

func newRemoteEnvironmentService(client remoteenvironmentv1alpha1.ApplicationconnectorV1alpha1Interface, cfg Config, mappingInformer cache.SharedIndexInformer, mappingLister reMappinglister.EnvironmentMappingLister, reInformer cache.SharedIndexInformer) (*remoteEnvironmentService, error) {
	mappingInformer.AddIndexers(cache.Indexers{
		remoteMappingNameIndex: func(obj interface{}) ([]string, error) {
			mapping, ok := obj.(*v1alpha1.EnvironmentMapping)
			if !ok {
				return nil, errors.New("cannot convert item")
			}

			return []string{mapping.Name}, nil
		},
	})

	regex, err := regexp.Compile(reNameRegex)
	if err != nil {
		return nil, errors.Wrapf(err, "while compiling %s regex", reNameRegex)
	}
	return &remoteEnvironmentService{
		mappingLister:   mappingLister,
		mappingInformer: mappingInformer,
		reInformer:      reInformer,
		client:          client,
		connectorSvcURL: cfg.Connector.URL,
		httpClient: &http.Client{
			Timeout: cfg.Connector.HTTPCallTimeout,
		},
		reNameRegex: regex,
	}, nil
}

func (svc *remoteEnvironmentService) ListNamespacesFor(reName string) ([]string, error) {
	mappingObjs, err := svc.mappingInformer.GetIndexer().ByIndex(remoteMappingNameIndex, reName)
	if err != nil {
		return nil, errors.Wrapf(err, "while listing environment mappings by index %q with key %q", remoteMappingNameIndex, reName)
	}

	nsList := make([]string, 0, len(mappingObjs))
	for _, item := range mappingObjs {
		reMapping, ok := item.(*v1alpha1.EnvironmentMapping)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'EnvironmentMapping' in version 'v1alpha1'", item)
		}
		nsList = append(nsList, reMapping.Namespace)
	}

	return nsList, nil
}

func (svc *remoteEnvironmentService) Find(name string) (*v1alpha1.RemoteEnvironment, error) {
	remoteEnvironment, exists, err := svc.reInformer.GetStore().GetByKey(name)

	if err != nil || !exists {
		return nil, err
	}

	re, ok := remoteEnvironment.(*v1alpha1.RemoteEnvironment)
	if !ok {

		return nil, fmt.Errorf("Cannot process RemoteEnvironment")
	}

	return re, nil
}

func (svc *remoteEnvironmentService) List(params pager.PagingParams) ([]*v1alpha1.RemoteEnvironment, error) {
	reObjs, err := pager.From(svc.reInformer.GetStore()).Limit(params)
	if err != nil {
		return nil, errors.Wrapf(err, "while listing remote environments with paging params [first: %v] [offset: %v]", params.First, params.Offset)
	}

	res := make([]*v1alpha1.RemoteEnvironment, 0, len(reObjs))
	for _, item := range reObjs {
		re, ok := item.(*v1alpha1.RemoteEnvironment)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'RemoteEnvironment' in version 'v1alpha1'", item)
		}

		res = append(res, re)
	}

	return res, nil
}

func (svc *remoteEnvironmentService) ListInEnvironment(environment string) ([]*v1alpha1.RemoteEnvironment, error) {
	mappings, err := svc.mappingLister.EnvironmentMappings(environment).List(labels.Everything())
	if err != nil {
		return nil, errors.Wrap(err, "while listing environment mappings")
	}

	res := make([]*v1alpha1.RemoteEnvironment, 0)
	for _, mapping := range mappings {
		// Remote Environment CR is cluster wide so the key is only the name
		reObj, exists, err := svc.reInformer.GetIndexer().GetByKey(mapping.Name)
		if err != nil {
			return nil, errors.Wrapf(err, "while getting remote environment with key %s", mapping.Name)
		}

		if !exists {
			glog.Warningf("Found environment mapping %q in namespaces %q but remote environment with name %q does not exists", mapping.Name, mapping.Namespace, mapping.Name)
			continue
		}

		reCR, ok := reObj.(*v1alpha1.RemoteEnvironment)
		if !ok {
			return nil, fmt.Errorf("incorrect item type: %T, should be: 'RemoteEnvironment' in version 'v1alpha1'", reObj)
		}

		//TODO: Write test to make sure that this is a real deep copy
		deepCopy := reCR.DeepCopy()
		res = append(res, deepCopy)
	}
	return res, nil
}

// Enable enables remote environment in given namespace by creating EnvironmentMappinggo
func (svc *remoteEnvironmentService) Enable(namespace, name string) (*v1alpha1.EnvironmentMapping, error) {
	em, err := svc.client.EnvironmentMappings(namespace).Create(&v1alpha1.EnvironmentMapping{
		TypeMeta: metav1.TypeMeta{
			Kind:       "EnvironmentMapping",
			APIVersion: "applicationconnector.kyma-project.io/v1alpha1",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
	})
	return em, err
}

// Disable disables remote environment in given namespace by removing EnvironmentMapping
func (svc *remoteEnvironmentService) Disable(namespace, name string) error {
	return svc.client.EnvironmentMappings(namespace).Delete(name, &metav1.DeleteOptions{})
}

func (svc *remoteEnvironmentService) GetConnectionURL(remoteEnvironment string) (string, error) {
	if ok := svc.reNameRegex.MatchString(remoteEnvironment); !ok {
		return "", fmt.Errorf("Remote evironment name %q does not match regex: %s", remoteEnvironment, reNameRegex)
	}
	reqURL := fmt.Sprintf("%s/v1/remoteenvironments/%s/tokens", svc.connectorSvcURL, remoteEnvironment)

	req, err := http.NewRequest(http.MethodPost, reqURL, nil)
	if err != nil {
		return "", errors.Wrap(err, "while creating HTTP request")
	}

	resp, err := svc.httpClient.Do(req)
	if err != nil {
		return "", errors.Wrap(err, "while making HTTP call")
	}
	defer svc.drainAndCloseBody(resp.Body)

	if resp.StatusCode != http.StatusCreated {
		cause := svc.extractErrorCause(resp.Body)
		return "", errors.Wrapf(cause, "while requesting connection URL obtained unexpected status code %d", resp.StatusCode)
	}

	connectorURL, err := svc.extractConnectionURL(resp.Body)
	if err != nil {
		return "", errors.Wrap(err, "while extracting connection URL from body")
	}

	return connectorURL, nil
}

func (svc *remoteEnvironmentService) extractConnectionURL(body io.ReadCloser) (string, error) {
	var dto struct {
		URL string `json:"url"`
	}
	if err := json.NewDecoder(body).Decode(&dto); err != nil {
		return "", errors.Wrap(err, "while decoding json")
	}

	return dto.URL, nil
}

func (svc *remoteEnvironmentService) extractErrorCause(body io.ReadCloser) error {
	var dto struct {
		Error string `json:"error"`
	}
	if err := json.NewDecoder(body).Decode(&dto); err != nil {
		return errors.Wrap(err, "while decoding json to get error msg from body")
	}

	return errors.New(dto.Error)
}

func (svc *remoteEnvironmentService) drainAndCloseBody(body io.ReadCloser) {
	_ = iosafety.DrainReader(body)
	body.Close()
}
<|endoftext|>


<commit_before>package act

import (
	"fmt"
	"log"
)

//
// GenServerImpl is the default implementation of GenServer interface
//
type GenServerImpl struct {
	GenServer
	self   *Pid // Pid of process
	prefix string
	name   interface{} // Registered name of process
}

//
// Init initializes process state using arbitrary arguments
//
func (gs *GenServerImpl) Init(args ...interface{}) Term {

	log.Printf("GenServerImpl:Init : pid: #%d, reg name: %s/%s, args: %#v",
		gs.Self().Id(), gs.Prefix(), gs.NameStr(), args)

	return GsInitOk
}

//
// HandleCast handles incoming messages from `pid.Cast(data)`
//
func (gs *GenServerImpl) HandleCast(req Term) Term {

	log.Printf("GenServerImpl:HandleCast : %#v", req)

	return GsCastNoReply
}

//
// HandleCall handles incoming messages from `pid.Call(data)`
//
func (gs *GenServerImpl) HandleCall(req Term, from From) Term {

	log.Printf("GenServerImpl:HandleCall : %#v, From: %#v", req, from)

	return GsCallReplyOk
}

//
// Terminate called when process died
//
func (gs *GenServerImpl) Terminate(reason string) {
	log.Printf("GenServerImpl:Terminate : %#v", reason)
}

func (gs *GenServerImpl) setPid(pid *Pid) {
	gs.self = pid
}

func (gs *GenServerImpl) setPrefix(prefix string) {
	gs.prefix = prefix
}

func (gs *GenServerImpl) setName(name interface{}) {
	gs.name = name
}

//
// Self returns pid of the process
//
func (gs *GenServerImpl) Self() *Pid {
	return gs.self
}

//
// Prefix returns prefix of the process
//
func (gs *GenServerImpl) Prefix() string {
	return gs.prefix
}

//
// Name returns name of the process
//
func (gs *GenServerImpl) Name() interface{} {
	return gs.name
}

//
// NameStr return name of the process as a string
//
func (gs *GenServerImpl) NameStr() string {
	switch name := gs.name.(type) {
	case string:
		return name
	default:
		if name == nil {
			return ""
		}
		return fmt.Sprintf("%v", name)
	}
}
<commit_msg>remove log<commit_after>package act

import (
	"fmt"
)

//
// GenServerImpl is the default implementation of GenServer interface
//
type GenServerImpl struct {
	GenServer
	self   *Pid // Pid of process
	prefix string
	name   interface{} // Registered name of process
}

//
// Init initializes process state using arbitrary arguments
//
func (gs *GenServerImpl) Init(args ...interface{}) Term {

	return GsInitOk
}

//
// HandleCast handles incoming messages from `pid.Cast(data)`
//
func (gs *GenServerImpl) HandleCast(req Term) Term {

	return GsCastNoReply
}

//
// HandleCall handles incoming messages from `pid.Call(data)`
//
func (gs *GenServerImpl) HandleCall(req Term, from From) Term {

	return GsCallReplyOk
}

//
// Terminate called when process died
//
func (gs *GenServerImpl) Terminate(reason string) {
}

func (gs *GenServerImpl) setPid(pid *Pid) {
	gs.self = pid
}

func (gs *GenServerImpl) setPrefix(prefix string) {
	gs.prefix = prefix
}

func (gs *GenServerImpl) setName(name interface{}) {
	gs.name = name
}

//
// Self returns pid of the process
//
func (gs *GenServerImpl) Self() *Pid {
	return gs.self
}

//
// Id returns id of the process
//
func (gs *GenServerImpl) Id() uint64 {
	return gs.self.Id()
}

//
// Prefix returns prefix of the process
//
func (gs *GenServerImpl) Prefix() string {
	return gs.prefix
}

//
// Name returns name of the process
//
func (gs *GenServerImpl) Name() interface{} {
	return gs.name
}

//
// NameStr return name of the process as a string
//
func (gs *GenServerImpl) NameStr() string {
	switch name := gs.name.(type) {
	case string:
		return name
	default:
		if name == nil {
			return ""
		}
		return fmt.Sprintf("%v", name)
	}
}
<|endoftext|>


<commit_before>package repo

import (
	"encoding/json"
	"io"
	"regexp"
)

type Revision string
type RevisionContents struct {
	Revision Revision
	Paths    []string
}

type RevisionMetadata struct {
	Revision    Revision
	Timestamp   int64
	Subject     string
	AuthorName  string
	AuthorEmail string
}

type Alias struct {
	Branch   string
	Revision Revision
}

type Line struct {
	Revision   Revision
	FileName   string
	LineNumber int
	Contents   string
}

// Key that uniquely identifies a TODO.
type TodoId struct {
	Revision   Revision
	FileName   string
	LineNumber int
}

type TodoDetails struct {
	Id               TodoId
	RevisionMetadata RevisionMetadata
	Context          string
}

type Repository interface {
	ListBranches() []Alias
	ReadRevisionContents(revision Revision) *RevisionContents
	ReadRevisionMetadata(revision Revision) RevisionMetadata
	ReadFileAtRevision(revision Revision, path string) []Line
}

func WriteJson(w io.Writer, repository Repository) error {
	bytes, err := json.Marshal(repository.ListBranches())
	if err != nil {
		return err
	}
	w.Write(bytes)
	return nil
}

const (
	// TODO: Make this configurable.
	TodoRegex = "[^[:alpha:]](t|T)(o|O)(d|D)(o|O)[^[:alpha:]]"
)

// TODO: Return a slice of TodoId instead of Line.
func LoadTodos(repository Repository, revision Revision) []Line {
	todos := make([]Line, 0)
	for _, path := range repository.ReadRevisionContents(revision).Paths {
		for _, line := range repository.ReadFileAtRevision(revision, path) {
			matched, err := regexp.MatchString(TodoRegex, line.Contents)
			if err == nil && matched {
				todos = append(todos, line)
			}
		}
	}
	return todos
}

func WriteTodosJson(w io.Writer, repository Repository, revision Revision) error {
	bytes, err := json.Marshal(LoadTodos(repository, revision))
	if err != nil {
		return err
	}
	w.Write(bytes)
	return nil
}

// TODO: Add a method for getting a JSON blob of the TodoDetails given a TodoId.
<commit_msg>Added a method to read the details for a TODO<commit_after>package repo

import (
	"encoding/json"
	"io"
	"regexp"
)

type Revision string
type RevisionContents struct {
	Revision Revision
	Paths    []string
}

type RevisionMetadata struct {
	Revision    Revision
	Timestamp   int64
	Subject     string
	AuthorName  string
	AuthorEmail string
}

type Alias struct {
	Branch   string
	Revision Revision
}

type Line struct {
	Revision   Revision
	FileName   string
	LineNumber int
	Contents   string
}

// Key that uniquely identifies a TODO.
type TodoId struct {
	Revision   Revision
	FileName   string
	LineNumber int
}

type TodoDetails struct {
	Id               TodoId
	RevisionMetadata RevisionMetadata
	Context          string
}

type Repository interface {
	ListBranches() []Alias
	ReadRevisionContents(revision Revision) *RevisionContents
	ReadRevisionMetadata(revision Revision) RevisionMetadata
	ReadFileAtRevision(revision Revision, path string) []Line
}

func WriteJson(w io.Writer, repository Repository) error {
	bytes, err := json.Marshal(repository.ListBranches())
	if err != nil {
		return err
	}
	w.Write(bytes)
	return nil
}

const (
	// TODO: Make this configurable.
	TodoRegex = "[^[:alpha:]](t|T)(o|O)(d|D)(o|O)[^[:alpha:]]"
)

func LoadTodos(repository Repository, revision Revision) []Line {
	todos := make([]Line, 0)
	for _, path := range repository.ReadRevisionContents(revision).Paths {
		for _, line := range repository.ReadFileAtRevision(revision, path) {
			matched, err := regexp.MatchString(TodoRegex, line.Contents)
			if err == nil && matched {
				todos = append(todos, line)
			}
		}
	}
	return todos
}

func LoadTodoDetails(repository Repository, todoId TodoId, linesBefore int, linesAfter int) *TodoDetails {
	lines := repository.ReadFileAtRevision(todoId.Revision, todoId.FileName)
	startLine := todoId.LineNumber - linesBefore
	endLine := todoId.LineNumber + linesAfter + 1
	if startLine < 0 {
		startLine = 0
	}
	if endLine > len(lines) {
		endLine = len(lines)
	}
	context := ""
	for _, line := range lines[startLine:endLine] {
		context += line.Contents + "\n"
	}
	return &TodoDetails{
		Id:               todoId,
		RevisionMetadata: repository.ReadRevisionMetadata(todoId.Revision),
		Context:          context,
	}
}

func WriteTodosJson(w io.Writer, repository Repository, revision Revision) error {
	bytes, err := json.Marshal(LoadTodos(repository, revision))
	if err != nil {
		return err
	}
	w.Write(bytes)
	return nil
}

func WriteTodoDetailsJson(w io.Writer, repository Repository, todoId TodoId) error {
	// TODO: Make the lines before and after a parameter.
	bytes, err := json.Marshal(LoadTodoDetails(repository, todoId, 5, 5))
	if err != nil {
		return err
	}
	w.Write(bytes)
	return nil
}
<|endoftext|>


<commit_before>package cache

import (
	"log"
	"os"
	"testing"

	"github.com/syou6162/go-active-learning/lib/example"
)

func TestMain(m *testing.M) {
	err := Init()
	if err != nil {
		log.Fatal(err.Error())
	}
	defer Close()

	ret := m.Run()
	os.Exit(ret)
}

func TestPing(t *testing.T) {
	if err := Ping(); err != nil {
		t.Errorf(err.Error())
	}
}

func TestAttachMetaData(t *testing.T) {
	e1 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 := example.NewExample("https://github.com", example.UNLABELED)
	examples := example.Examples{e1, e2, e3}
	for _, e := range examples {
		key := "url:" + e.Url
		client.Del(key)
	}

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}
	AttachMetadata(examples, false, false)

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "" {
		t.Errorf("OgType must be empty for %s", examples[1].Url)
	}

	AttachMetadata(examples, true, false)
	if examples[0].Title == "" {
		t.Errorf("Title must not be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) == 0 {
		t.Errorf("Feature vector must not be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}

	e4 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e5 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e6 := example.NewExample("https://github.com", example.UNLABELED)
	examples = example.Examples{e4, e5, e6}
	AttachMetadata(examples, false, false)

	if examples[0].Title == "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) == 0 {
		t.Errorf("Feature vector must not be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}
}

func TestAttachLightMetaData(t *testing.T) {
	e1 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 := example.NewExample("https://github.com", example.UNLABELED)
	examples := example.Examples{e1, e2, e3}
	for _, e := range examples {
		key := "url:" + e.Url
		client.Del(key)
	}

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}
	AttachMetadata(examples, false, false)

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "" {
		t.Errorf("OgType must be empty for %s", examples[1].Url)
	}

	AttachMetadata(examples, true, true)

	e1 = example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 = example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 = example.NewExample("https://github.com", example.UNLABELED)
	examples = example.Examples{e1, e2, e3}

	AttachMetadata(examples, false, true)

	if examples[0].Title == "" {
		t.Errorf("Title must not be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}
}
<commit_msg>リストの出し入れをテスト<commit_after>package cache

import (
	"log"
	"os"
	"testing"

	"github.com/syou6162/go-active-learning/lib/example"
)

func TestMain(m *testing.M) {
	err := Init()
	if err != nil {
		log.Fatal(err.Error())
	}
	defer Close()

	ret := m.Run()
	os.Exit(ret)
}

func TestPing(t *testing.T) {
	if err := Ping(); err != nil {
		t.Errorf(err.Error())
	}
}

func TestAttachMetaData(t *testing.T) {
	e1 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 := example.NewExample("https://github.com", example.UNLABELED)
	examples := example.Examples{e1, e2, e3}
	for _, e := range examples {
		key := "url:" + e.Url
		client.Del(key)
	}

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}
	AttachMetadata(examples, false, false)

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "" {
		t.Errorf("OgType must be empty for %s", examples[1].Url)
	}

	AttachMetadata(examples, true, false)
	if examples[0].Title == "" {
		t.Errorf("Title must not be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) == 0 {
		t.Errorf("Feature vector must not be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}

	e4 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e5 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e6 := example.NewExample("https://github.com", example.UNLABELED)
	examples = example.Examples{e4, e5, e6}
	AttachMetadata(examples, false, false)

	if examples[0].Title == "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) == 0 {
		t.Errorf("Feature vector must not be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}
}

func TestAttachLightMetaData(t *testing.T) {
	e1 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 := example.NewExample("https://github.com", example.UNLABELED)
	examples := example.Examples{e1, e2, e3}
	for _, e := range examples {
		key := "url:" + e.Url
		client.Del(key)
	}

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}
	AttachMetadata(examples, false, false)

	if examples[0].Title != "" {
		t.Errorf("Title must be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "" {
		t.Errorf("OgType must be empty for %s", examples[1].Url)
	}

	AttachMetadata(examples, true, true)

	e1 = example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 = example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 = example.NewExample("https://github.com", example.UNLABELED)
	examples = example.Examples{e1, e2, e3}

	AttachMetadata(examples, false, true)

	if examples[0].Title == "" {
		t.Errorf("Title must not be empty for %s", examples[0].Url)
	}
	if len(examples[0].Fv) != 0 {
		t.Errorf("Feature vector must be empty for %s", examples[0].Url)
	}

	if examples[1].OgType != "blog" {
		t.Errorf("OgType must be blog for %s", examples[1].Url)
	}
}

func TestAddExamplesToListAndGetUrlsFromList(t *testing.T) {
	listName := "general"
	client.Del("list:" + listName)
	err := AddExamplesToList(listName, example.Examples{})
	if err == nil {
		t.Error("Error should occur when adding empty list")
	}

	e1 := example.NewExample("http://b.hatena.ne.jp", example.POSITIVE)
	e2 := example.NewExample("http://www.yasuhisay.info", example.NEGATIVE)
	e3 := example.NewExample("https://github.com", example.UNLABELED)
	examples := example.Examples{e1, e2, e3}
	for _, e := range examples {
		key := "url:" + e.Url
		client.Del(key)
	}
	AttachMetadata(examples, true, false)

	err = AddExamplesToList(listName, examples)
	if err != nil {
		t.Error(err.Error())
	}

	list, err := GetUrlsFromList(listName, 0, 100)
	if err != nil {
		t.Error(err.Error())
	}
	if len(list) != 3 {
		t.Errorf("len(list) == %d, want 3", len(list))
	}
}
<|endoftext|>


<commit_before>package central

import (
	"nli-go/lib/common"
	"nli-go/lib/mentalese"
)

// The answerer takes a relation set in domain format
// and returns a relation set in domain format
// It uses Solution structures to determine how to act
type Answerer struct {
	solutions []mentalese.Solution
	matcher   *mentalese.RelationMatcher
	solver    *ProblemSolver
	builder   *RelationSetBuilder
	log       *common.SystemLog
}

func NewAnswerer(matcher *mentalese.RelationMatcher, solver *ProblemSolver, log *common.SystemLog) *Answerer {

	builder := NewRelationSetBuilder()
	builder.addGenerator(NewSystemGenerator())

	return &Answerer{
		solutions: []mentalese.Solution{},
		matcher:   matcher,
		solver:    solver,
		builder:   builder,
		log:       log,
	}
}

func (answerer *Answerer) AddSolutions(solutions []mentalese.Solution) {
	answerer.solutions = append(answerer.solutions, solutions...)
}

// goal e.g. [ question(Q) child(S, O) EntityId(S, 'Janice', fullName) number_of(O, N) focus(Q, N) ]
// return e.g. [ child(S, O) gender(S, female) number_of(O, N) ]
func (answerer Answerer) Answer(goal mentalese.RelationSet, keyCabinet *mentalese.KeyCabinet) mentalese.RelationSet {

	answerer.log.StartDebug("Answer")

	answer := mentalese.RelationSet{}
	transformer := mentalese.NewRelationTransformer(answerer.matcher, answerer.log)

	//// scope here, just before finding the solution
	//quantifierScoper := mentalese.NewQuantifierScoper(answerer.log)
	//scopedGoal := quantifierScoper.Scope(goal)
	scopedGoal := goal

//	answerer.log.AddProduction("Scoped", scopedGoal.String())

	// apply sequences
//	sequenceApplier := mentalese.NewSequenceApplier(answerer.log)
//	sequencedGoal := sequenceApplier.ApplySequences(scopedGoal)

//	answerer.log.AddProduction("With Sequences", sequencedGoal.String())
	sequencedGoal := scopedGoal

	// conditionBindings: map condition variables to goal variables
	allSolutions := answerer.findSolutions(sequencedGoal)

	if len(allSolutions) == 0 {

		answerer.log.AddError("Answerer could not find a solution.")

	} else {

		for i, solution := range allSolutions {

			// apply transformation, if available
			transformedGoal := transformer.Replace(solution.Transformations, sequencedGoal)

			// resultBindings: map goal variables to answers
			resultBindings := answerer.solver.SolveRelationSet(transformedGoal, keyCabinet, mentalese.Bindings{{}})

			// choose a handler based on whether there were results
			resultHandler := solution.NoResults
			if len(resultBindings) > 0 {
				resultHandler = solution.SomeResults
			} else {
				// no results? try the next solution (if there is one)
				if i < len(allSolutions) - 1 {
					continue
				}
			}

			// solutionBindings: map condition variables to results
			var solutionBindings = resultBindings

			// extend solution bindings by executing the preparation
			if !resultHandler.Preparation.IsEmpty() {
				solutionBindings = answerer.solver.SolveRelationSet(resultHandler.Preparation, keyCabinet, resultBindings)
			}

			// create answer relation sets by binding 'answer' to solutionBindings
			answer = answerer.builder.Build(resultHandler.Answer, solutionBindings)

			// stop after the first solution
			break
		}
	}

	answerer.log.EndDebug("Answer", answer)
	return answer
}

// Returns the solutions whose condition matches the goal, and a set of bindings per solution
func (answerer Answerer) findSolutions(goal mentalese.RelationSet) []mentalese.Solution {

	answerer.log.StartDebug("findSolutions", goal)

	var solutions []mentalese.Solution

	for _, aSolution := range answerer.solutions {

		unScopedGoal := goal.UnScope()

		bindings, found := answerer.matcher.MatchSequenceToSet(aSolution.Condition, unScopedGoal, mentalese.Binding{})
		if found {

			for _, binding := range bindings {
				boundSolution := aSolution.BindSingle(binding)
				solutions = append(solutions, boundSolution)
			}
		}
	}

	answerer.log.EndDebug("findSolutions", solutions)

	return solutions
}
<commit_msg>clean up answerer<commit_after>package central

import (
	"nli-go/lib/common"
	"nli-go/lib/mentalese"
)

// The answerer takes a relation set in domain format
// and returns a relation set in domain format
// It uses Solution structures to determine how to act
type Answerer struct {
	solutions []mentalese.Solution
	matcher   *mentalese.RelationMatcher
	solver    *ProblemSolver
	builder   *RelationSetBuilder
	log       *common.SystemLog
}

func NewAnswerer(matcher *mentalese.RelationMatcher, solver *ProblemSolver, log *common.SystemLog) *Answerer {

	builder := NewRelationSetBuilder()
	builder.addGenerator(NewSystemGenerator())

	return &Answerer{
		solutions: []mentalese.Solution{},
		matcher:   matcher,
		solver:    solver,
		builder:   builder,
		log:       log,
	}
}

func (answerer *Answerer) AddSolutions(solutions []mentalese.Solution) {
	answerer.solutions = append(answerer.solutions, solutions...)
}

// goal e.g. [ question(Q) child(S, O) EntityId(S, 'Janice', fullName) number_of(O, N) focus(Q, N) ]
// return e.g. [ child(S, O) gender(S, female) number_of(O, N) ]
func (answerer Answerer) Answer(goal mentalese.RelationSet, keyCabinet *mentalese.KeyCabinet) mentalese.RelationSet {

	answerer.log.StartDebug("Answer")

	answer := mentalese.RelationSet{}
	transformer := mentalese.NewRelationTransformer(answerer.matcher, answerer.log)

	// conditionBindings: map condition variables to goal variables
	allSolutions := answerer.findSolutions(goal)

	if len(allSolutions) == 0 {

		answerer.log.AddError("Answerer could not find a solution.")

	} else {

		for i, solution := range allSolutions {

			// apply transformation, if available
			transformedGoal := transformer.Replace(solution.Transformations, goal)

			// resultBindings: map goal variables to answers
			resultBindings := answerer.solver.SolveRelationSet(transformedGoal, keyCabinet, mentalese.Bindings{{}})

			// choose a handler based on whether there were results
			resultHandler := solution.NoResults
			if len(resultBindings) > 0 {
				resultHandler = solution.SomeResults
			} else {
				// no results? try the next solution (if there is one)
				if i < len(allSolutions) - 1 {
					continue
				}
			}

			// solutionBindings: map condition variables to results
			var solutionBindings = resultBindings

			// extend solution bindings by executing the preparation
			if !resultHandler.Preparation.IsEmpty() {
				solutionBindings = answerer.solver.SolveRelationSet(resultHandler.Preparation, keyCabinet, resultBindings)
			}

			// create answer relation sets by binding 'answer' to solutionBindings
			answer = answerer.builder.Build(resultHandler.Answer, solutionBindings)

			// stop after the first solution
			break
		}
	}

	answerer.log.EndDebug("Answer", answer)
	return answer
}

// Returns the solutions whose condition matches the goal, and a set of bindings per solution
func (answerer Answerer) findSolutions(goal mentalese.RelationSet) []mentalese.Solution {

	answerer.log.StartDebug("findSolutions", goal)

	var solutions []mentalese.Solution

	for _, aSolution := range answerer.solutions {

		unScopedGoal := goal.UnScope()

		bindings, found := answerer.matcher.MatchSequenceToSet(aSolution.Condition, unScopedGoal, mentalese.Binding{})
		if found {

			for _, binding := range bindings {
				boundSolution := aSolution.BindSingle(binding)
				solutions = append(solutions, boundSolution)
			}
		}
	}

	answerer.log.EndDebug("findSolutions", solutions)

	return solutions
}
<|endoftext|>


<commit_before>package stm

import (
	"sync"
	"testing"
	"time"
)

func TestDecrement(t *testing.T) {
	x := NewVar(1000)
	for i := 0; i < 500; i++ {
		go Atomically(func(tx *Tx) {
			cur := tx.Get(x).(int)
			tx.Set(x, cur-1)
		})
	}
	done := make(chan struct{})
	go func() {
		for {
			if AtomicGet(x).(int) == 500 {
				break
			}
		}
		done <- struct{}{}
	}()
	select {
	case <-done:
	case <-time.After(time.Second):
		t.Fatal("decrement did not complete in time")
	}
}

// read-only transaction aren't exempt from calling tx.verify
func TestReadVerify(t *testing.T) {
	read := make(chan struct{})
	x, y := NewVar(1), NewVar(2)

	// spawn a transaction that writes to x
	go func() {
		<-read
		AtomicSet(x, 3)
		read <- struct{}{}
		// other tx should retry, so we need to read/send again
		read <- <-read
	}()

	// spawn a transaction that reads x, then y. The other tx will modify x in
	// between the reads, causing this tx to retry.
	var x2, y2 int
	Atomically(func(tx *Tx) {
		x2 = tx.Get(x).(int)
		read <- struct{}{}
		<-read // wait for other tx to complete
		y2 = tx.Get(y).(int)
	})
	if x2 == 1 && y2 == 2 {
		t.Fatal("read was not verified")
	}
}

func TestRetry(t *testing.T) {
	x := NewVar(10)
	// spawn 10 transactions, one every 10 milliseconds. This will decrement x
	// to 0 over the course of 100 milliseconds.
	go func() {
		for i := 0; i < 10; i++ {
			time.Sleep(10 * time.Millisecond)
			Atomically(func(tx *Tx) {
				cur := tx.Get(x).(int)
				tx.Set(x, cur-1)
			})
		}
	}()
	// Each time we read x before the above loop has finished, we need to
	// retry. This should result in no more than 1 retry per transaction.
	retry := 0
	Atomically(func(tx *Tx) {
		cur := tx.Get(x).(int)
		if cur != 0 {
			retry++
			tx.Retry()
		}
	})
	if retry > 10 {
		t.Fatal("should have retried at most 10 times, got", retry)
	}
}

func TestVerify(t *testing.T) {
	// tx.verify should check more than pointer equality
	type foo struct {
		i int
	}
	x := NewVar(&foo{3})
	read := make(chan struct{})

	// spawn a transaction that modifies x
	go func() {
		Atomically(func(tx *Tx) {
			<-read
			rx := tx.Get(x).(*foo)
			rx.i = 7
			tx.Set(x, rx)
		})
		read <- struct{}{}
		// other tx should retry, so we need to read/send again
		read <- <-read
	}()

	// spawn a transaction that reads x, then y. The other tx will modify x in
	// between the reads, causing this tx to retry.
	var i int
	Atomically(func(tx *Tx) {
		f := tx.Get(x).(*foo)
		i = f.i
		read <- struct{}{}
		<-read // wait for other tx to complete
	})
	if i == 3 {
		t.Fatal("verify did not retry despite modified Var", i)
	}
}

func TestSelect(t *testing.T) {
	// empty Select should block forever
	c := make(chan struct{})
	go func() {
		Atomically(Select())
		c <- struct{}{}
	}()
	select {
	case <-c:
		t.Fatal("empty Select did not block forever")
	case <-time.After(10*time.Millisecond):
	}

	// with one arg, Select adds no effect
	x := NewVar(2)
	Atomically(Select(func(tx *Tx) {
		tx.Assert(tx.Get(x).(int) == 2)
	}))

	var picked int
	Atomically(Select(
		// always blocks; should never be selected
		func(tx *Tx) {
			tx.Retry()
			picked = 1
		},
		// always succeeds; should always be selected
		func(tx *Tx) {
			picked = 2
		},
		// always succeeds; should never be selected
		func(tx *Tx) {
			picked = 3
		},
	))
	if picked != 2 {
		t.Fatal("Select selected wrong transaction:", picked)
	}
}

func TestCompose(t *testing.T) {
	nums := make([]int, 100)
	fns := make([]func(*Tx), 100)
	for i := range fns {
		fns[i] = func(x int) func(*Tx) {
			return func(*Tx) { nums[x] = x }
		}(i) // capture loop var
	}
	Atomically(Compose(fns...))
	for i := range nums {
		if nums[i] != i {
			t.Error("Compose failed:", nums[i], i)
		}
	}
}

func TestPanic(t *testing.T) {
	defer func() {
		if recover() == nil {
			t.Fatal("expected panic, got nil")
		}
	}()
	// normal panics should escape Atomically
	Atomically(func(*Tx) {
		panic("foo")
	})
}

func TestReadWritten(t *testing.T) {
	// reading a variable written in the same transaction should return the
	// previously written value
	x := NewVar(3)
	Atomically(func(tx *Tx) {
		tx.Set(x, 5)
		tx.Assert(tx.Get(x).(int) == 5)
	})
}

func BenchmarkAtomicGet(b *testing.B) {
	x := NewVar(0)
	for i := 0; i < b.N; i++ {
		AtomicGet(x)
	}
}

func BenchmarkAtomicSet(b *testing.B) {
	x := NewVar(0)
	for i := 0; i < b.N; i++ {
		AtomicSet(x, 0)
	}
}

func BenchmarkIncrementSTM(b *testing.B) {
	for i := 0; i < b.N; i++ {
		// spawn 1000 goroutines that each increment x by 1
		x := NewVar(0)
		for i := 0; i < 1000; i++ {
			go Atomically(func(tx *Tx) {
				cur := tx.Get(x).(int)
				tx.Set(x, cur+1)
			})
		}
		// wait for x to reach 1000
		Atomically(func(tx *Tx) {
			tx.Assert(tx.Get(x).(int) == 1000)
		})
	}
}

func BenchmarkIncrementMutex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var mu sync.Mutex
		x := 0
		for i := 0; i < 1000; i++ {
			go func() {
				mu.Lock()
				x++
				mu.Unlock()
			}()
		}
		for {
			mu.Lock()
			read := x
			mu.Unlock()
			if read == 1000 {
				break
			}
		}
	}
}

func BenchmarkIncrementChannel(b *testing.B) {
	for i := 0; i < b.N; i++ {
		c := make(chan int, 1)
		c <- 0
		for i := 0; i < 1000; i++ {
			go func() {
				c <- 1 + <-c
			}()
		}
		for {
			read := <-c
			if read == 1000 {
				break
			}
			c <- read
		}
	}
}

func BenchmarkReadVarSTM(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var wg sync.WaitGroup
		wg.Add(1000)
		x := NewVar(0)
		for i := 0; i < 1000; i++ {
			go func() {
				AtomicGet(x)
				wg.Done()
			}()
		}
		wg.Wait()
	}
}

func BenchmarkReadVarMutex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var mu sync.Mutex
		var wg sync.WaitGroup
		wg.Add(1000)
		x := 0
		for i := 0; i < 1000; i++ {
			go func() {
				mu.Lock()
				_ = x
				mu.Unlock()
				wg.Done()
			}()
		}
		wg.Wait()
	}
}

func BenchmarkReadVarChannel(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var wg sync.WaitGroup
		wg.Add(1000)
		c := make(chan int)
		close(c)
		for i := 0; i < 1000; i++ {
			go func() {
				<-c
				wg.Done()
			}()
		}
		wg.Wait()
	}
}
<commit_msg>go fmt<commit_after>package stm

import (
	"sync"
	"testing"
	"time"
)

func TestDecrement(t *testing.T) {
	x := NewVar(1000)
	for i := 0; i < 500; i++ {
		go Atomically(func(tx *Tx) {
			cur := tx.Get(x).(int)
			tx.Set(x, cur-1)
		})
	}
	done := make(chan struct{})
	go func() {
		for {
			if AtomicGet(x).(int) == 500 {
				break
			}
		}
		done <- struct{}{}
	}()
	select {
	case <-done:
	case <-time.After(time.Second):
		t.Fatal("decrement did not complete in time")
	}
}

// read-only transaction aren't exempt from calling tx.verify
func TestReadVerify(t *testing.T) {
	read := make(chan struct{})
	x, y := NewVar(1), NewVar(2)

	// spawn a transaction that writes to x
	go func() {
		<-read
		AtomicSet(x, 3)
		read <- struct{}{}
		// other tx should retry, so we need to read/send again
		read <- <-read
	}()

	// spawn a transaction that reads x, then y. The other tx will modify x in
	// between the reads, causing this tx to retry.
	var x2, y2 int
	Atomically(func(tx *Tx) {
		x2 = tx.Get(x).(int)
		read <- struct{}{}
		<-read // wait for other tx to complete
		y2 = tx.Get(y).(int)
	})
	if x2 == 1 && y2 == 2 {
		t.Fatal("read was not verified")
	}
}

func TestRetry(t *testing.T) {
	x := NewVar(10)
	// spawn 10 transactions, one every 10 milliseconds. This will decrement x
	// to 0 over the course of 100 milliseconds.
	go func() {
		for i := 0; i < 10; i++ {
			time.Sleep(10 * time.Millisecond)
			Atomically(func(tx *Tx) {
				cur := tx.Get(x).(int)
				tx.Set(x, cur-1)
			})
		}
	}()
	// Each time we read x before the above loop has finished, we need to
	// retry. This should result in no more than 1 retry per transaction.
	retry := 0
	Atomically(func(tx *Tx) {
		cur := tx.Get(x).(int)
		if cur != 0 {
			retry++
			tx.Retry()
		}
	})
	if retry > 10 {
		t.Fatal("should have retried at most 10 times, got", retry)
	}
}

func TestVerify(t *testing.T) {
	// tx.verify should check more than pointer equality
	type foo struct {
		i int
	}
	x := NewVar(&foo{3})
	read := make(chan struct{})

	// spawn a transaction that modifies x
	go func() {
		Atomically(func(tx *Tx) {
			<-read
			rx := tx.Get(x).(*foo)
			rx.i = 7
			tx.Set(x, rx)
		})
		read <- struct{}{}
		// other tx should retry, so we need to read/send again
		read <- <-read
	}()

	// spawn a transaction that reads x, then y. The other tx will modify x in
	// between the reads, causing this tx to retry.
	var i int
	Atomically(func(tx *Tx) {
		f := tx.Get(x).(*foo)
		i = f.i
		read <- struct{}{}
		<-read // wait for other tx to complete
	})
	if i == 3 {
		t.Fatal("verify did not retry despite modified Var", i)
	}
}

func TestSelect(t *testing.T) {
	// empty Select should block forever
	c := make(chan struct{})
	go func() {
		Atomically(Select())
		c <- struct{}{}
	}()
	select {
	case <-c:
		t.Fatal("empty Select did not block forever")
	case <-time.After(10 * time.Millisecond):
	}

	// with one arg, Select adds no effect
	x := NewVar(2)
	Atomically(Select(func(tx *Tx) {
		tx.Assert(tx.Get(x).(int) == 2)
	}))

	var picked int
	Atomically(Select(
		// always blocks; should never be selected
		func(tx *Tx) {
			tx.Retry()
			picked = 1
		},
		// always succeeds; should always be selected
		func(tx *Tx) {
			picked = 2
		},
		// always succeeds; should never be selected
		func(tx *Tx) {
			picked = 3
		},
	))
	if picked != 2 {
		t.Fatal("Select selected wrong transaction:", picked)
	}
}

func TestCompose(t *testing.T) {
	nums := make([]int, 100)
	fns := make([]func(*Tx), 100)
	for i := range fns {
		fns[i] = func(x int) func(*Tx) {
			return func(*Tx) { nums[x] = x }
		}(i) // capture loop var
	}
	Atomically(Compose(fns...))
	for i := range nums {
		if nums[i] != i {
			t.Error("Compose failed:", nums[i], i)
		}
	}
}

func TestPanic(t *testing.T) {
	defer func() {
		if recover() == nil {
			t.Fatal("expected panic, got nil")
		}
	}()
	// normal panics should escape Atomically
	Atomically(func(*Tx) {
		panic("foo")
	})
}

func TestReadWritten(t *testing.T) {
	// reading a variable written in the same transaction should return the
	// previously written value
	x := NewVar(3)
	Atomically(func(tx *Tx) {
		tx.Set(x, 5)
		tx.Assert(tx.Get(x).(int) == 5)
	})
}

func BenchmarkAtomicGet(b *testing.B) {
	x := NewVar(0)
	for i := 0; i < b.N; i++ {
		AtomicGet(x)
	}
}

func BenchmarkAtomicSet(b *testing.B) {
	x := NewVar(0)
	for i := 0; i < b.N; i++ {
		AtomicSet(x, 0)
	}
}

func BenchmarkIncrementSTM(b *testing.B) {
	for i := 0; i < b.N; i++ {
		// spawn 1000 goroutines that each increment x by 1
		x := NewVar(0)
		for i := 0; i < 1000; i++ {
			go Atomically(func(tx *Tx) {
				cur := tx.Get(x).(int)
				tx.Set(x, cur+1)
			})
		}
		// wait for x to reach 1000
		Atomically(func(tx *Tx) {
			tx.Assert(tx.Get(x).(int) == 1000)
		})
	}
}

func BenchmarkIncrementMutex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var mu sync.Mutex
		x := 0
		for i := 0; i < 1000; i++ {
			go func() {
				mu.Lock()
				x++
				mu.Unlock()
			}()
		}
		for {
			mu.Lock()
			read := x
			mu.Unlock()
			if read == 1000 {
				break
			}
		}
	}
}

func BenchmarkIncrementChannel(b *testing.B) {
	for i := 0; i < b.N; i++ {
		c := make(chan int, 1)
		c <- 0
		for i := 0; i < 1000; i++ {
			go func() {
				c <- 1 + <-c
			}()
		}
		for {
			read := <-c
			if read == 1000 {
				break
			}
			c <- read
		}
	}
}

func BenchmarkReadVarSTM(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var wg sync.WaitGroup
		wg.Add(1000)
		x := NewVar(0)
		for i := 0; i < 1000; i++ {
			go func() {
				AtomicGet(x)
				wg.Done()
			}()
		}
		wg.Wait()
	}
}

func BenchmarkReadVarMutex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var mu sync.Mutex
		var wg sync.WaitGroup
		wg.Add(1000)
		x := 0
		for i := 0; i < 1000; i++ {
			go func() {
				mu.Lock()
				_ = x
				mu.Unlock()
				wg.Done()
			}()
		}
		wg.Wait()
	}
}

func BenchmarkReadVarChannel(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var wg sync.WaitGroup
		wg.Add(1000)
		c := make(chan int)
		close(c)
		for i := 0; i < 1000; i++ {
			go func() {
				<-c
				wg.Done()
			}()
		}
		wg.Wait()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/jackpal/bencode-go"
	"net"
	"os"
	"strings"
)

type Request struct {
	Op   string "op"
	Code string "code"
}

type Response struct {
	Session string   "session"
	Out     string   "out"
	Status  []string "status"
	Ex      string   "ex"
	RootEx  string   "root-ex"
}

func message(args []string) (string, error) {
	conn, err := net.Dial("tcp", "0.0.0.0:53788")
	if err != nil {
		return "", err
	}
	var tasks string
	if len(args) > 0 {
		tasks = strings.Join(args, " ")
	} else {
		tasks = "help"
	}
  fmt.Print(tasks)
	if err := bencode.Marshal(conn, Request{"eval", "(boot " + tasks + ") nil"}); err != nil {
		return "", err
	}
	var res Response
	if err := bencode.Unmarshal(conn, &res); err != nil {
		return "", err
	}
	if res.Ex != "" {
		return "", errors.New(res.Ex)
	}
	return res.Out, nil
}

func main() {
	out, err := message(os.Args[1:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	} else {
		fmt.Fprint(os.Stdout, out)
		os.Exit(0)
	}
}
<commit_msg>improvements to boot client.<commit_after>package main

import (
	"fmt"
	"github.com/jackpal/bencode-go"
	"net"
	"os"
	"strconv"
)

type Request struct {
	Op   string "op"
	Code string "code"
}

type Response struct {
	Session string   "session"
	Out     string   "out"
	Status  []string "status"
	Ex      string   "ex"
	RootEx  string   "root-ex"
}

func (req Request) send(conn net.Conn) (*Response, error) {
  if err := bencode.Marshal(conn, req); err != nil {
		return nil, err
	}
  res := &Response{}
	if err := bencode.Unmarshal(conn, res); err != nil {
		return nil, err
	}
	return res, nil
}

func NewRequest(taskargs []string) *Request {
	code := "(boot"
	for _, taskarg := range taskargs {
		code += " " + strconv.Quote(taskarg)
	}
	code += ")"
	return &Request{"eval", code}
}

func main() {
	conn, err := net.Dial("tcp", "0.0.0.0:50243")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error connecting to boot build server: %v\n", err)
		os.Exit(1)
	}
	req := NewRequest(os.Args[1:])
	res, err := req.send(conn)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error encoding or decoding tasks: %v\n", err)
		os.Exit(1)
	} else if res.Ex != "" {
		fmt.Fprintf(os.Stderr, "Error from boot build server: %v\n", res.Ex)
		os.Exit(1)
	}
	fmt.Print(res.Out)
}
<|endoftext|>


<commit_before>package vitali

import (
    "os"
    "io"
    "log"
    "fmt"
    "net/http"
    "time"
    "regexp"
    "strings"
    "reflect"
)

const (
    PUBLIC = iota
    AUTHENTICATED
)

type RouteRule struct {
    Pattern string
    Resource interface{}
}

type PatternMapping struct {
    Re *regexp.Regexp
    Names []string
}

type UserProvider interface {
    AuthHeader(*http.Request) string
    User(*http.Request) string
}

type webApp struct {
    RouteRules []RouteRule
    PatternMappings []PatternMapping
    UserProvider UserProvider
    Settings map[string]string
}

func checkPermission(perm Perm, method string, user string) bool {
    required, exist := perm[method]
    if !exist {
        required = perm["*"]
    }
    return !(required==AUTHENTICATED && user == "")
}

func matchRules(c webApp, w *wrappedWriter, r *http.Request) {
    for i, routeRule := range c.RouteRules {
        params := c.PatternMappings[i].Re.FindStringSubmatch(r.URL.Path)
        if params != nil {
            pathParams := make(map[string]string)
            if len(params) > 1 {
                for j, param := range params[1:] {
                    pathParams[c.PatternMappings[i].Names[j]] = param
                }
            }

            ctx := Ctx {
                pathParams: pathParams,
                Username: c.UserProvider.User(r),
                Request: r,
                ResponseWriter: w,
            }

            vResource := reflect.ValueOf(routeRule.Resource)
            vNewResource := reflect.New(reflect.TypeOf(routeRule.Resource)).Elem()
            for i := 0; i < vResource.NumField(); i++ {
                srcField := vResource.Field(i)
                newField := vNewResource.Field(i)

                switch reflect.TypeOf(srcField.Interface()).Name() {
                case "Ctx":
                    newField.Set(reflect.ValueOf(ctx))
                case "Perm":
                    if !checkPermission(srcField.Interface().(Perm), r.Method, ctx.Username) {
                        if c.Settings["401_PAGE"] != "" {
                            w.Header().Set("Content-Type", "text/html")
                            w.Header()["WWW-Authenticate"] = []string{c.UserProvider.AuthHeader(r)}
                            w.WriteHeader(http.StatusUnauthorized)
                            f, err := os.Open(c.Settings["401_PAGE"])
                            if err != nil {
                                panic(err)
                            }
                            io.Copy(w, f)
                        } else {
                            http.Error(w, "unauthorized", http.StatusUnauthorized)
                        }
                        return
                    }
                default:
                    newField.Set(srcField)
                }
            }
            resource := vNewResource.Interface()

            result := getResult(r.Method, resource)
            writeResponse(w, r, result)
            return
        }
    }
    http.NotFound(w, r)
}

func getAllowed(resource interface{}) (allowed []string) {
    _, ok := resource.(Getter)
    if ok {
        allowed = append(allowed, "GET", "HEAD")
    }
    _, ok = resource.(Poster)
    if ok {
        allowed = append(allowed, "POST")
    }
    _, ok = resource.(Putter)
    if ok {
        allowed = append(allowed, "PUT")
    }
    _, ok = resource.(Deleter)
    if ok {
        allowed = append(allowed, "DELETE")
    }
    return
}

func getResult(method string, resource interface{}) (result interface{}) {
    defer func() {
        if r := recover(); r != nil {
            rstr := fmt.Sprintf("%s", r)
            result = internalError {
                where: lineInfo(3),
                why: rstr + fullTrace(5, "\n\t"),
                code: errorCode(rstr),
            }
        }
    }()

    switch method {
    case "HEAD", "GET":
        h, ok := resource.(Getter)
        if ok {
            result = h.Get()
        }
    case "POST":
        h, ok := resource.(Poster)
        if ok {
            result = h.Post()
        }
    case "PUT":
        h, ok := resource.(Putter)
        if ok {
            result = h.Put()
        }
    case "DELETE":
        h, ok := resource.(Deleter)
        if ok {
            result = h.Delete()
        }
    default:
        return notImplemented{}
    }

    return methodNotAllowed{getAllowed(resource)}
}

func (c webApp) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    ww := &wrappedWriter{
        status: 0,
        writer: w,
        inTime: time.Now(),
    }

    matchRules(c, ww, r)

    elapsedMs := float64(time.Now().UnixNano() - ww.inTime.UnixNano()) / 1000000
    if ww.status == 0 {
        log.Printf("%s %s %s Client Disconnected (%.2f ms)", r.RemoteAddr, r.Method,
            r.URL.Path, elapsedMs)
    } else {
        errMsg := ""
        if ww.err.why != "" {
            errMsg = fmt.Sprintf("%s #%d %s ", ww.err.where, ww.err.code, ww.err.why)
        }
        log.Printf("%s %s %s %s %s(%.2f ms, %d bytes)", r.RemoteAddr, r.Method, r.URL.Path,
            http.StatusText(ww.status), errMsg, elapsedMs, ww.written)
    }
}

type EmptyUserProvider struct {
}

func (c EmptyUserProvider) AuthHeader(r *http.Request) string {
    return ""
}

func (c EmptyUserProvider) User(r *http.Request) string {
    return ""
}

func CreateWebApp(rules []RouteRule) webApp {
    patternMappings := make([]PatternMapping, len(rules))
    for i, v := range rules {
        re := regexp.MustCompile("{[^}]*}")
        params := re.FindAllString(v.Pattern, -1)
        names := make([]string, len(params))

        transformedPattern := v.Pattern
        for j, param := range params {
            names[j] = param[1:len(param)-1]
            transformedPattern = strings.Replace(transformedPattern, param, "([^/]+)", -1)
        }
        patternMappings[i] = PatternMapping{regexp.MustCompile("^"+transformedPattern+"$"), names}
    }

    return webApp{
        RouteRules: rules,
        PatternMappings: patternMappings,
        UserProvider: EmptyUserProvider{},
        Settings: make(map[string]string),
    }
}

type Perm map[string]int
<commit_msg>getResult does not return success result, fix it<commit_after>package vitali

import (
    "os"
    "io"
    "log"
    "fmt"
    "net/http"
    "time"
    "regexp"
    "strings"
    "reflect"
)

const (
    PUBLIC = iota
    AUTHENTICATED
)

type RouteRule struct {
    Pattern string
    Resource interface{}
}

type PatternMapping struct {
    Re *regexp.Regexp
    Names []string
}

type UserProvider interface {
    AuthHeader(*http.Request) string
    User(*http.Request) string
}

type webApp struct {
    RouteRules []RouteRule
    PatternMappings []PatternMapping
    UserProvider UserProvider
    Settings map[string]string
}

func checkPermission(perm Perm, method string, user string) bool {
    required, exist := perm[method]
    if !exist {
        required = perm["*"]
    }
    return !(required==AUTHENTICATED && user == "")
}

func matchRules(c webApp, w *wrappedWriter, r *http.Request) {
    for i, routeRule := range c.RouteRules {
        params := c.PatternMappings[i].Re.FindStringSubmatch(r.URL.Path)
        if params != nil {
            pathParams := make(map[string]string)
            if len(params) > 1 {
                for j, param := range params[1:] {
                    pathParams[c.PatternMappings[i].Names[j]] = param
                }
            }

            ctx := Ctx {
                pathParams: pathParams,
                Username: c.UserProvider.User(r),
                Request: r,
                ResponseWriter: w,
            }

            vResource := reflect.ValueOf(routeRule.Resource)
            vNewResource := reflect.New(reflect.TypeOf(routeRule.Resource)).Elem()
            for i := 0; i < vResource.NumField(); i++ {
                srcField := vResource.Field(i)
                newField := vNewResource.Field(i)

                switch reflect.TypeOf(srcField.Interface()).Name() {
                case "Ctx":
                    newField.Set(reflect.ValueOf(ctx))
                case "Perm":
                    if !checkPermission(srcField.Interface().(Perm), r.Method, ctx.Username) {
                        if c.Settings["401_PAGE"] != "" {
                            w.Header().Set("Content-Type", "text/html")
                            w.Header()["WWW-Authenticate"] = []string{c.UserProvider.AuthHeader(r)}
                            w.WriteHeader(http.StatusUnauthorized)
                            f, err := os.Open(c.Settings["401_PAGE"])
                            if err != nil {
                                panic(err)
                            }
                            io.Copy(w, f)
                        } else {
                            http.Error(w, "unauthorized", http.StatusUnauthorized)
                        }
                        return
                    }
                default:
                    newField.Set(srcField)
                }
            }
            resource := vNewResource.Interface()

            result := getResult(r.Method, resource)
            writeResponse(w, r, result)
            return
        }
    }
    http.NotFound(w, r)
}

func getAllowed(resource interface{}) (allowed []string) {
    _, ok := resource.(Getter)
    if ok {
        allowed = append(allowed, "GET", "HEAD")
    }
    _, ok = resource.(Poster)
    if ok {
        allowed = append(allowed, "POST")
    }
    _, ok = resource.(Putter)
    if ok {
        allowed = append(allowed, "PUT")
    }
    _, ok = resource.(Deleter)
    if ok {
        allowed = append(allowed, "DELETE")
    }
    return
}

func getResult(method string, resource interface{}) (result interface{}) {
    defer func() {
        if r := recover(); r != nil {
            rstr := fmt.Sprintf("%s", r)
            result = internalError {
                where: lineInfo(3),
                why: rstr + fullTrace(5, "\n\t"),
                code: errorCode(rstr),
            }
        }
    }()

    switch method {
    case "HEAD", "GET":
        h, ok := resource.(Getter)
        if ok {
            result = h.Get()
        }
    case "POST":
        h, ok := resource.(Poster)
        if ok {
            result = h.Post()
        }
    case "PUT":
        h, ok := resource.(Putter)
        if ok {
            result = h.Put()
        }
    case "DELETE":
        h, ok := resource.(Deleter)
        if ok {
            result = h.Delete()
        }
    default:
        return notImplemented{}
    }

    if result == nil {
        return methodNotAllowed{getAllowed(resource)}
    }
    return
}

func (c webApp) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    ww := &wrappedWriter{
        status: 0,
        writer: w,
        inTime: time.Now(),
    }

    matchRules(c, ww, r)

    elapsedMs := float64(time.Now().UnixNano() - ww.inTime.UnixNano()) / 1000000
    if ww.status == 0 {
        log.Printf("%s %s %s Client Disconnected (%.2f ms)", r.RemoteAddr, r.Method,
            r.URL.Path, elapsedMs)
    } else {
        errMsg := ""
        if ww.err.why != "" {
            errMsg = fmt.Sprintf("%s #%d %s ", ww.err.where, ww.err.code, ww.err.why)
        }
        log.Printf("%s %s %s %s %s(%.2f ms, %d bytes)", r.RemoteAddr, r.Method, r.URL.Path,
            http.StatusText(ww.status), errMsg, elapsedMs, ww.written)
    }
}

type EmptyUserProvider struct {
}

func (c EmptyUserProvider) AuthHeader(r *http.Request) string {
    return ""
}

func (c EmptyUserProvider) User(r *http.Request) string {
    return ""
}

func CreateWebApp(rules []RouteRule) webApp {
    patternMappings := make([]PatternMapping, len(rules))
    for i, v := range rules {
        re := regexp.MustCompile("{[^}]*}")
        params := re.FindAllString(v.Pattern, -1)
        names := make([]string, len(params))

        transformedPattern := v.Pattern
        for j, param := range params {
            names[j] = param[1:len(param)-1]
            transformedPattern = strings.Replace(transformedPattern, param, "([^/]+)", -1)
        }
        patternMappings[i] = PatternMapping{regexp.MustCompile("^"+transformedPattern+"$"), names}
    }

    return webApp{
        RouteRules: rules,
        PatternMappings: patternMappings,
        UserProvider: EmptyUserProvider{},
        Settings: make(map[string]string),
    }
}

type Perm map[string]int
<|endoftext|>


<commit_before>package template

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/fortytw2/clarent/util"
)

func Clarent(args []string) error {
	app := cli.NewApp()
	cli.AppHelpTemplate = util.AppletHelpTemplate
	app.Name = "template"
	app.Usage = "what is a template?"
	app.Action = cli.ShowAppHelp

	app.Commands = []cli.Command{
		{
			Name:      "example",
			ShortName: "e",
			Usage:     "print some example text, then exit",
			Action:    example,
		},
	}

	app.Run(args)

	return nil
}

func example() {
	fmt.Println("I did things")
}
<commit_msg>fix template/travis build<commit_after>package template

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/fortytw2/clarent/util"
)

func Clarent(args []string) error {
	app := cli.NewApp()
	cli.AppHelpTemplate = util.AppletHelpTemplate
	app.Name = "template"
	app.Usage = "what is a template?"
	app.Action = cli.ShowAppHelp

	app.Commands = []cli.Command{
		{
			Name:      "example",
			ShortName: "e",
			Usage:     "print some example text, then exit",
			Action:    example,
		},
	}

	app.Run(args)

	return nil
}

func example(c *cli.Context) {
	fmt.Println("I did things")
}
<|endoftext|>


<commit_before>package application

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

func TestRegistration(t *testing.T) {
	server := httptest.NewServer(GetRouter(true))
	defer server.Close()

	file, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	db, err := gorm.Open("sqlite3", file.Name())
	db.AutoMigrate(&User{})
	Gorm = db

	data := []byte("_123_")
	authKey := fmt.Sprintf("%x", md5.Sum(data))
	jsonBytes, _ := json.Marshal(AuthRequestPart{
		AuthKey: authKey,
		ExtID:   "123",
		SysID:   "VK",
	})
	reader := bytes.NewReader(jsonBytes)

	resp, err := http.Post(fmt.Sprint(server.URL, "/ReqEnter"), "application/json", reader)
	if err != nil {
		t.Fatal(err)
	}
	t.Fatal(string(resp))
}
<commit_msg>debug<commit_after>package application

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

func TestRegistration(t *testing.T) {
	server := httptest.NewServer(GetRouter(true))
	defer server.Close()

	file, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	db, err := gorm.Open("sqlite3", file.Name())
	db.AutoMigrate(&User{})
	Gorm = db

	data := []byte("_123_")
	authKey := fmt.Sprintf("%x", md5.Sum(data))
	jsonBytes, _ := json.Marshal(AuthRequestPart{
		AuthKey: authKey,
		ExtID:   123,
		SysID:   "VK",
	})
	reader := bytes.NewReader(jsonBytes)

	resp, err := http.Post(fmt.Sprint(server.URL, "/ReqEnter"), "application/json", reader)
	if err != nil {
		t.Fatal(err)
	}
	decoder := json.NewDecoder(resp.Body)
	var response enterResponse
	err = decoder.Decode(response)
	if err != nil {
		t.Fatal(err)
	}
	t.Fatal(response)
}
<|endoftext|>


<commit_before>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>
#include <stdint.h>

extern void IndexQueryCallback(void *, void *);
extern void goIndexSendQueryResult(size_t, void *);
extern uint32_t *IndexQuery(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, uint32_t *);
extern void IndexAdd(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, size_t);

*/
import "C"
import (
	"sync"
	"unsafe"
)

// IndexGeom is a struct for indexed geometries used by Index
// and returned by IndexQuery.
type IndexGeom struct {
	Geom *Geom
}
type Index struct {
	v     *C.GEOSSTRtree
	mu    *sync.Mutex
	geoms []IndexGeom
}

func (this *Geos) CreateIndex() *Index {
	tree := C.GEOSSTRtree_create_r(this.v, 10)
	if tree == nil {
		panic("unable to create tree")
	}
	return &Index{tree, &sync.Mutex{}, []IndexGeom{}}
}

// IndexQuery adds a geom to the index with the id.
func (this *Geos) IndexAdd(index *Index, geom *Geom) {
	index.mu.Lock()
	defer index.mu.Unlock()
	id := len(index.geoms)
	C.IndexAdd(this.v, index.v, geom.v, C.size_t(id))
	index.geoms = append(index.geoms, IndexGeom{geom})
}

// IndexQueryGeoms queries the index for intersections with geom.
func (this *Geos) IndexQueryGeoms(index *Index, geom *Geom) []IndexGeom {
	hits := this.IndexQuery(index, geom)

	var geoms []IndexGeom
	for _, idx := range hits {
		geoms = append(geoms, index.geoms[idx])
	}
	return geoms
}

// IndexQuery queries the index for intersections with geom.
func (this *Geos) IndexQuery(index *Index, geom *Geom) []int {
	index.mu.Lock()
	defer index.mu.Unlock()
	var num C.uint32_t
	r := C.IndexQuery(this.v, index.v, geom.v, &num)
	if r == nil {
		return nil
	}
	hits := (*[2 << 16]C.uint32_t)(unsafe.Pointer(r))[:num]
	defer C.free(unsafe.Pointer(r))

	indices := make([]int, len(hits))
	for i := range hits {
		indices[i] = int(hits[i])
	}
	return indices
}
<commit_msg>Fix typo (#191)<commit_after>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>
#include <stdint.h>

extern void IndexQueryCallback(void *, void *);
extern void goIndexSendQueryResult(size_t, void *);
extern uint32_t *IndexQuery(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, uint32_t *);
extern void IndexAdd(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, size_t);

*/
import "C"
import (
	"sync"
	"unsafe"
)

// IndexGeom is a struct for indexed geometries used by Index
// and returned by IndexQuery.
type IndexGeom struct {
	Geom *Geom
}
type Index struct {
	v     *C.GEOSSTRtree
	mu    *sync.Mutex
	geoms []IndexGeom
}

func (this *Geos) CreateIndex() *Index {
	tree := C.GEOSSTRtree_create_r(this.v, 10)
	if tree == nil {
		panic("unable to create tree")
	}
	return &Index{tree, &sync.Mutex{}, []IndexGeom{}}
}

// IndexAdd adds a geom to the index with the id.
func (this *Geos) IndexAdd(index *Index, geom *Geom) {
	index.mu.Lock()
	defer index.mu.Unlock()
	id := len(index.geoms)
	C.IndexAdd(this.v, index.v, geom.v, C.size_t(id))
	index.geoms = append(index.geoms, IndexGeom{geom})
}

// IndexQueryGeoms queries the index for intersections with geom.
func (this *Geos) IndexQueryGeoms(index *Index, geom *Geom) []IndexGeom {
	hits := this.IndexQuery(index, geom)

	var geoms []IndexGeom
	for _, idx := range hits {
		geoms = append(geoms, index.geoms[idx])
	}
	return geoms
}

// IndexQuery queries the index for intersections with geom.
func (this *Geos) IndexQuery(index *Index, geom *Geom) []int {
	index.mu.Lock()
	defer index.mu.Unlock()
	var num C.uint32_t
	r := C.IndexQuery(this.v, index.v, geom.v, &num)
	if r == nil {
		return nil
	}
	hits := (*[2 << 16]C.uint32_t)(unsafe.Pointer(r))[:num]
	defer C.free(unsafe.Pointer(r))

	indices := make([]int, len(hits))
	for i := range hits {
		indices[i] = int(hits[i])
	}
	return indices
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"fmt"
	"math/rand"
	"runtime"
)

const NumProcesses = 3
const NumMessages = 100

type Message struct {
	Message string
	From int
	To int
	ProcessEpoch int
	Frequency int
	FrequencyEpoch int
}

type Force struct {
}

type Process struct {
	Id int
	CurrentEpoch int
	Frequency int
	FrequencyEpoch int
	LastVoteEpoch int
	NextElection time.Time
	Election *Election
	Inbox chan *Message
	Outbox chan *Message
	God chan *Force
	Ticker *time.Ticker
}

type Election struct {
	NewFrequency int
	FrequencyEpoch int
	NumVotes int
	NumProcesses int
}

func NewProcess(id int, mailbox chan *Message) *Process {
	return &Process{
		Id: id,
		CurrentEpoch: 0,
		FrequencyEpoch: 0,
		Frequency: -1,
		LastVoteEpoch: 0,
		Inbox: make(chan *Message, 10),
		Outbox: mailbox,
		Ticker: time.NewTicker(5 * time.Second),
	}
}

func (process *Process) Spawn() {
	go process.Run()
}

func (process *Process) Run() {
	for {
		if process.Frequency == -1 &&
			time.Now().After(process.NextElection) {
			secondsToWait := time.Duration(30 + rand.Int31n(30)) * time.Second
			process.NextElection = time.Now().Add(secondsToWait)
			process.ElectMe()
		}

		process.Iterate()
	}
}

func (process *Process) Iterate() {
	select {
	case message := <-process.Inbox:
		process.HandleMessage(message)
	case _ = <-process.Ticker.C:
		// Send an update to a random neighbor
		process.SendUpdate(int(rand.Int31n(NumProcesses)))
	case force := <-process.God:
		fmt.Printf("Process #%d Force: %d\n", process.Id, force)
	}
}

func (process *Process) HandleMessage(message *Message) {
	if process.CurrentEpoch < message.ProcessEpoch {
		// Always update the current epoch
		process.CurrentEpoch = message.ProcessEpoch
	}

	switch message.Message {
	case "heartbeat":
		fmt.Printf("Received heartbeat. Process: %v Frequency: %v Epoch: %v\n",
			process.Id, process.Frequency, process.FrequencyEpoch)
		if process.FrequencyEpoch >= message.FrequencyEpoch {
			return
		}

		process.Frequency = message.Frequency
		process.FrequencyEpoch = message.FrequencyEpoch
		fmt.Printf("Updating from heartbeat. Process: %v New Frequency: %v New Epoch: %v\n",
			process.Id, process.Frequency, process.FrequencyEpoch)
	case "elect_me":
		if process.CurrentEpoch > message.ProcessEpoch ||
			process.LastVoteEpoch >= process.CurrentEpoch ||
			process.FrequencyEpoch > message.FrequencyEpoch {
			// Do not vote if: I have a more recent view of time than
			// the message, or I already voted for this epoch, or my
			// last observed frequency change is more recent than the
			// requesting machine.
			fmt.Printf("Not voting. Process: %v Epoch: %v LastVoteEpoch: %v FrequencyEpoch: %v Message: %#v\n",
				process.Id, process.CurrentEpoch, process.LastVoteEpoch, process.FrequencyEpoch, message)
			return
		}

		fmt.Printf("You have my vote. Process %v Frequency: %v Epoch: %v\n",
			process.Id, message.Frequency, message.ProcessEpoch)
		process.LastVoteEpoch = process.CurrentEpoch
		message := &Message{
			Message: "you_have_my_vote",
			ProcessEpoch: process.CurrentEpoch,
			From: process.Id,
			To: message.From,
		}
		process.Outbox <- message
	case "you_have_my_vote":
		if message.ProcessEpoch < process.CurrentEpoch {
			return
		}

		fmt.Printf("Received vote. Process: %v Frequency: %v Epoch: %v\n",
			process.Id, process.Election.NewFrequency, process.Election.FrequencyEpoch)
		process.Election.NumVotes++
		if process.Election.NumVotes * 2 > process.Election.NumProcesses {
			fmt.Println("New frequency elected.")
			process.Frequency = process.Election.NewFrequency
			process.FrequencyEpoch = process.Election.FrequencyEpoch
			process.PropagateFrequency()
		}
	default:
		fmt.Printf("Process #%d Message received: %v\n", process.Id, message)
	}
}

func (process *Process) SendUpdate(toProcessId int) {
	message := &Message{
		From: process.Id,
		To: toProcessId,
		ProcessEpoch: process.CurrentEpoch,
		Frequency: process.Frequency,
		FrequencyEpoch: process.FrequencyEpoch,
		Message: "heartbeat",
	}

	process.Outbox <- message
}

func (process *Process) PropagateFrequency() {
	for peerId := 0; peerId < NumProcesses; peerId++ {
		if process.Id == peerId {
			continue
		}

		process.SendUpdate(peerId)
	}
}

func (process *Process) ElectMe() {
	process.CurrentEpoch++
	process.LastVoteEpoch = process.CurrentEpoch
	process.Election = &Election{
		NewFrequency: int(rand.Int31n(100)),
		FrequencyEpoch: process.CurrentEpoch,
		NumVotes: 1,
		NumProcesses: NumProcesses,
	}

	fmt.Printf("Sending elect_me. Process: %v Election: %#v\n",
		process.Id, process.Election)

	for peerId := 0; peerId < NumProcesses; peerId++ {
		if process.Id == peerId {
			continue
		}

		message := &Message{
			Message: "elect_me",
			ProcessEpoch: process.CurrentEpoch,
			Frequency: process.Election.NewFrequency,
			FrequencyEpoch: process.FrequencyEpoch,
			From: process.Id,
			To: peerId,
		}

		process.Outbox <- message
	}
}

func Mailbox(processes []*Process, mailbox chan *Message) {
	for messageNum := 0; messageNum < NumMessages; messageNum++ {
		message := <-mailbox
		fmt.Printf("Mailbox: %v\n", message)
		processes[message.To].Inbox <- message
	}
}

func main() {
	runtime.GOMAXPROCS(4)
	rand.Seed(time.Now().Unix())
	mailbox := make(chan *Message, 10)
	processes := make([]*Process, 0, NumProcesses)
	for processNum := 0; processNum < NumProcesses; processNum++ {
		processes = append(processes, NewProcess(processNum, mailbox))
	}

	for _, process := range processes {
		process.Spawn()
	}

	Mailbox(processes, mailbox)
}
<commit_msg>Remove race when starting the program that causes the first winning election to take unnecessarily long. Add ability for a single process to force a new election<commit_after>package main

import (
	"fmt"
	"math/rand"
	"runtime"
	"time"
)

const NumProcesses = 3
const NumMessages = 100

type Message struct {
	Message        string
	From           int
	To             int
	ProcessEpoch   int
	Frequency      int
	FrequencyEpoch int
}

type Force struct {
	Election bool
}

type Process struct {
	Id             int
	CurrentEpoch   int
	Frequency      int
	FrequencyEpoch int
	LastVoteEpoch  int
	NextElection   time.Time
	Election       *Election
	Inbox          chan *Message
	Outbox         chan *Message
	God            chan *Force
	Ticker         *time.Ticker
	ElectionForced bool
}

type Election struct {
	NewFrequency   int
	FrequencyEpoch int
	NumVotes       int
	NumProcesses   int
}

func NewProcess(id int, mailbox chan *Message) *Process {
	var nextElectionSeed time.Duration
	if id > 0 {
		nextElectionSeed = time.Minute
	}

	return &Process{
		Id:             id,
		CurrentEpoch:   0,
		FrequencyEpoch: 0,
		Frequency:      -1,
		LastVoteEpoch:  0,
		NextElection:   time.Now().Add(nextElectionSeed),
		Inbox:          make(chan *Message, 10),
		Outbox:         mailbox,
		God:            make(chan *Force, 1),
		Ticker:         time.NewTicker(5 * time.Second),
	}
}

func (process *Process) Spawn() {
	go process.Run()
}

func (process *Process) Run() {
	for {
		wantsNewElection := process.Frequency == -1 ||
			process.ElectionForced == true

		if wantsNewElection &&
			time.Now().After(process.NextElection) {

			process.ElectionForced = false
			// Random wait between attempts for an election.
			secondsToWait := time.Duration(10+rand.Int31n(10)) * time.Second
			process.NextElection = time.Now().Add(secondsToWait)
			process.ElectMe()
		}

		process.Iterate()
	}
}

func (process *Process) Iterate() {
	select {
	case message := <-process.Inbox:
		process.HandleMessage(message)
	case _ = <-process.Ticker.C:
		// Send an update to a random neighbor
		process.SendUpdate(int(rand.Int31n(NumProcesses)))
	case force := <-process.God:
		fmt.Printf("Process #%d Force: %#v\n", process.Id, force)
		process.ElectionForced = force.Election
	}
}

func (process *Process) HandleMessage(message *Message) {
	if process.CurrentEpoch < message.ProcessEpoch {
		// Always update the current epoch
		process.CurrentEpoch = message.ProcessEpoch
	}

	switch message.Message {
	case "heartbeat":
		//fmt.Printf("Received heartbeat. Process: %v Frequency: %v Epoch: %v\n",
		//process.Id, process.Frequency, process.FrequencyEpoch)
		if process.FrequencyEpoch >= message.FrequencyEpoch {
			return
		}

		process.Frequency = message.Frequency
		process.FrequencyEpoch = message.FrequencyEpoch
		fmt.Printf("Updating from heartbeat. Process: %v New Frequency: %v New Epoch: %v\n",
			process.Id, process.Frequency, process.FrequencyEpoch)
	case "elect_me":
		if process.CurrentEpoch > message.ProcessEpoch ||
			process.LastVoteEpoch >= process.CurrentEpoch ||
			process.FrequencyEpoch > message.FrequencyEpoch {
			// Do not vote if: I have a more recent view of time than
			// the message, or I already voted for this epoch, or my
			// last observed frequency change is more recent than the
			// requesting machine.
			fmt.Printf("Not voting. Process: %v Epoch: %v LastVoteEpoch: %v FrequencyEpoch: %v Message: %#v\n",
				process.Id, process.CurrentEpoch, process.LastVoteEpoch, process.FrequencyEpoch, message)
			return
		}

		fmt.Printf("You have my vote. Process %v Frequency: %v Epoch: %v\n",
			process.Id, message.Frequency, message.ProcessEpoch)
		process.LastVoteEpoch = process.CurrentEpoch
		message := &Message{
			Message:      "you_have_my_vote",
			ProcessEpoch: process.CurrentEpoch,
			From:         process.Id,
			To:           message.From,
		}
		process.Outbox <- message
	case "you_have_my_vote":
		if message.ProcessEpoch < process.CurrentEpoch {
			return
		}

		fmt.Printf("Received vote. Process: %v Frequency: %v Epoch: %v\n",
			process.Id, process.Election.NewFrequency, process.Election.FrequencyEpoch)
		process.Election.NumVotes++
		if process.Election.NumVotes*2 > process.Election.NumProcesses {
			fmt.Println("New frequency elected.")
			process.Frequency = process.Election.NewFrequency
			process.FrequencyEpoch = process.Election.FrequencyEpoch
			process.PropagateFrequency()
		}
	default:
		fmt.Printf("Process #%d Message received: %v\n", process.Id, message)
	}
}

func (process *Process) SendUpdate(toProcessId int) {
	message := &Message{
		From:           process.Id,
		To:             toProcessId,
		ProcessEpoch:   process.CurrentEpoch,
		Frequency:      process.Frequency,
		FrequencyEpoch: process.FrequencyEpoch,
		Message:        "heartbeat",
	}

	process.Outbox <- message
}

func (process *Process) PropagateFrequency() {
	for peerId := 0; peerId < NumProcesses; peerId++ {
		if process.Id == peerId {
			continue
		}

		process.SendUpdate(peerId)
	}
}

func (process *Process) ElectMe() {
	process.CurrentEpoch++
	process.LastVoteEpoch = process.CurrentEpoch
	process.Election = &Election{
		NewFrequency:   int(rand.Int31n(100)),
		FrequencyEpoch: process.CurrentEpoch,
		NumVotes:       1,
		NumProcesses:   NumProcesses,
	}

	fmt.Printf("Sending elect_me. Process: %v Election: %#v\n",
		process.Id, process.Election)

	for peerId := 0; peerId < NumProcesses; peerId++ {
		if process.Id == peerId {
			continue
		}

		message := &Message{
			Message:        "elect_me",
			ProcessEpoch:   process.CurrentEpoch,
			Frequency:      process.Election.NewFrequency,
			FrequencyEpoch: process.FrequencyEpoch,
			From:           process.Id,
			To:             peerId,
		}

		process.Outbox <- message
	}
}

func Mailbox(processes []*Process, mailbox chan *Message) {
	for messageNum := 0; messageNum < NumMessages; messageNum++ {
		message := <-mailbox
		fmt.Printf("Mailbox: %#v\n", message)
		processes[message.To].Inbox <- message
	}
}

func main() {
	runtime.GOMAXPROCS(4)
	rand.Seed(time.Now().Unix())
	mailbox := make(chan *Message, 10)
	processes := make([]*Process, 0, NumProcesses)
	for processNum := 0; processNum < NumProcesses; processNum++ {
		processes = append(processes, NewProcess(processNum, mailbox))
	}

	for _, process := range processes {
		process.Spawn()
	}

	go func() {
		time.Sleep(5 * time.Second)
		fmt.Println("Forcing an election")
		processes[1].God <- &Force{Election: true}
	}()

	Mailbox(processes, mailbox)
}
<|endoftext|>


<commit_before>package geomop

// Simplify performs Ramer-Douglas-Peucker simplification.

import (
	"github.com/foobaz/geom"
	"math"
)

type algorithm int

const (
	TypeRDP algorithm = iota
	TypeGrid
)

// there are two components that might be extremely slow
// the ring simplification algorithm searches for the
// maximally separated nodes, which is O(n^2), and the
// RDP simplification itself is typically O(n log n) but
// is O(n^2) in its worst case.
//
// If a poly with more than maxNodesToSimplify is used
// as input to the simplifier it will return the original.
const maxNodesToSimplify = 10000

func Simplify(g geom.T, eps float64, alg algorithm) {
	switch (g).(type) {
	case geom.Polygon:
		p := g.(geom.Polygon)
		for n, r := range p {
			// note if the first and last points are the same
			inputDupe := d(r[0], r[len(r)-1]) < tolerance
			newRing := simplifyRing(r, eps, alg)
			// if our first and last were the same before, make it so now
			if inputDupe {
				outputDupe := d(newRing[0], newRing[len(newRing)-1]) < tolerance
				if !outputDupe {
					newRing = append(newRing, newRing[0])
				}
			}
			p[n] = newRing

		}
	case geom.MultiPolygon:
		for _, p := range g.(geom.MultiPolygon) {
			Simplify(p, eps, alg)
		}
	case geom.GeometryCollection:
		for _, g := range g.(geom.GeometryCollection) {
			Simplify(g, eps, alg)
		}
	}
}

// Simplify a single ring; return the new ring.
func simplifyRing(r geom.Ring, eps float64, alg algorithm) geom.Ring {
	// rule out degenerate case
	if len(r) < 4 {
		return r
	}
	// which type of simplification?
	switch alg {
	case TypeRDP:
		return simplifyRingRDP(r, eps)
	case TypeGrid:
		return simplifyRingGrid(r, eps)
	default:
		panic("unknown poly simplification method invoked")
	}
}
func simplifyRingRDP(r geom.Ring, eps float64) geom.Ring {
	// to prevent this from bogging down on a ridiculous
	// input
	numPoints := len(r)
	if numPoints > maxNodesToSimplify {
		return r
	}
	// find the two points with maximal separation,
	// and use those two points to create the polylines
	// which will be simplified
	//
	// this should result in stable simplification,
	// meaning that the resulting simplified polygon
	// will be the same when processed with a
	// different starting point.
	maxDistance := 0.0
	startIndex := 0
	endIndex := 0
	for i := 0; i < (numPoints - 1); i++ {
		for j := i + 1; j < numPoints; j++ {
			dist := d(r[i], r[j])
			if dist > maxDistance {
				maxDistance = dist
				startIndex = i
				endIndex = j
			}
		}
	}
	var s1, s2 []geom.Point
	// note: the nodes at startIndex and endIndex must be in both polylines
	s1 = append(s1, r[startIndex:endIndex+1]...)
	s2 = append(s2, r[endIndex:]...)
	s2 = append(s2, r[:startIndex+1]...)

	news1 := rdpSimplify(s1, eps)
	news2 := rdpSimplify(s2, eps)

	// seam these back together
	var newRing geom.Ring
	newRing = append(newRing, news1...)
	newRing = append(newRing, news2[1:len(news2)-1]...)

	return newRing
}

func simplifyRingGrid(r geom.Ring, eps float64) geom.Ring {
	var newCoords []geom.Point
	for i := 0; i < len(r); i++ {
		newPoint := roundedPoint(r[i], eps)
		count := len(newCoords)
		// add if it's the first point or different from the most recent point
		if count == 0 || d(newPoint, newCoords[count-1]) > tolerance {
			newCoords = append(newCoords, newPoint)
		}
	}

	// check for collinearity
	// this check is a little more robust due to the removal of repeated points above
	cursor := 0
	polySize := len(newCoords)
	for cursor < polySize {
		// get indices for point before and after
		before := (cursor + polySize - 1) % polySize
		after := (cursor + 1) % polySize
		if distPointToSegment(newCoords[cursor], newCoords[before], newCoords[after]) < tolerance {
			// remove the point, reduce the size, leave the cursor alone
			newCoords = append(newCoords[:cursor], newCoords[cursor+1:]...)
			polySize--
		} else {
			// keep this point, bump the cursor
			cursor++
		}
	}
	return geom.Ring(newCoords)
}

func rdpSimplify(points []geom.Point, epsilon float64) []geom.Point {
	return points[:rdpCompress(points, epsilon)]
}

func rdpCompress(points []geom.Point, epsilon float64) int {
	end := len(points)

	if end < 3 {
		// return points
		return end
	}

	// Find the point with the maximum distance
	var (
		first = points[0]
		last  = points[end-1]

		dmax  float64
		index int
	)

	for i := 1; i < end-1; i++ {
		d := distPointToSegment(points[i], first, last)
		if d > dmax {
			dmax, index = d, i
		}
	}

	// If max distance is lte to epsilon, return segment containing
	// the first and last points.
	if dmax <= epsilon {
		// return []point{first, last}
		points[1] = last
		return 2
	}

	// Recursive call
	r1 := rdpCompress(points[:index+1], epsilon)
	r2 := rdpCompress(points[index:], epsilon)

	// Build the result list
	// return append(r1[:len(r1)-1], r2...)
	x := r1 - 1
	n := copy(points[x:], points[index:index+r2])

	return x + n
}

func roundedPoint(p geom.Point, eps float64) geom.Point {
	// protect against stupidity
	if eps == 0.0 {
		return p
	}
	var newPoint geom.Point
	for i := 0; i < len(p); i++ {
		coord := math.Floor(p[i]/eps+0.5) * eps
		newPoint = append(newPoint, coord)
	}
	return newPoint
}
<commit_msg>gridded simplifier changes: better collinearity test, ear removal<commit_after>package geomop

// Simplify performs Ramer-Douglas-Peucker simplification.

import (
	"github.com/foobaz/geom"
	"math"
)

type algorithm int

const (
	TypeRDP algorithm = iota
	TypeGrid
)

// there are two components that might be extremely slow
// the ring simplification algorithm searches for the
// maximally separated nodes, which is O(n^2), and the
// RDP simplification itself is typically O(n log n) but
// is O(n^2) in its worst case.
//
// If a poly with more than maxNodesToSimplify is used
// as input to the simplifier it will return the original.
const maxNodesToSimplify = 10000

// gridded simplification is followed by an attempt to clip off
// degenerate structures such as ears or zero-width peninsulas
// this is the number of nodes that will be searched ahead
// when looking for these degenerate structures
//
// TODO: get rid of this magic number.
// search through the whole poly for ears and in each case
// keep the side with the greater area.
const earSearchNodes = 9

func Simplify(g geom.T, eps float64, alg algorithm) {
	switch (g).(type) {
	case geom.Polygon:
		p := g.(geom.Polygon)
		for n, r := range p {
			// note if the first and last points are the same
			inputDupe := d(r[0], r[len(r)-1]) < tolerance
			newRing := simplifyRing(r, eps, alg)
			// if our first and last were the same before, make it so now
			if inputDupe {
				outputDupe := d(newRing[0], newRing[len(newRing)-1]) < tolerance
				if !outputDupe {
					newRing = append(newRing, newRing[0])
				}
			}
			p[n] = newRing

		}
	case geom.MultiPolygon:
		for _, p := range g.(geom.MultiPolygon) {
			Simplify(p, eps, alg)
		}
	case geom.GeometryCollection:
		for _, g := range g.(geom.GeometryCollection) {
			Simplify(g, eps, alg)
		}
	}
}

// Simplify a single ring; return the new ring.
func simplifyRing(r geom.Ring, eps float64, alg algorithm) geom.Ring {
	// rule out degenerate case
	if len(r) < 4 {
		return r
	}
	// which type of simplification?
	switch alg {
	case TypeRDP:
		return simplifyRingRDP(r, eps)
	case TypeGrid:
		return simplifyRingGrid(r, eps)
	default:
		panic("unknown poly simplification method invoked")
	}
}
func simplifyRingRDP(r geom.Ring, eps float64) geom.Ring {
	// to prevent this from bogging down on a ridiculous
	// input
	numPoints := len(r)
	if numPoints > maxNodesToSimplify {
		return r
	}
	// find the two points with maximal separation,
	// and use those two points to create the polylines
	// which will be simplified
	//
	// this should result in stable simplification,
	// meaning that the resulting simplified polygon
	// will be the same when processed with a
	// different starting point.
	maxDistance := 0.0
	startIndex := 0
	endIndex := 0
	for i := 0; i < (numPoints - 1); i++ {
		for j := i + 1; j < numPoints; j++ {
			dist := d(r[i], r[j])
			if dist > maxDistance {
				maxDistance = dist
				startIndex = i
				endIndex = j
			}
		}
	}
	var s1, s2 []geom.Point
	// note: the nodes at startIndex and endIndex must be in both polylines
	s1 = append(s1, r[startIndex:endIndex+1]...)
	s2 = append(s2, r[endIndex:]...)
	s2 = append(s2, r[:startIndex+1]...)

	news1 := rdpSimplify(s1, eps)
	news2 := rdpSimplify(s2, eps)

	// seam these back together
	var newRing geom.Ring
	newRing = append(newRing, news1...)
	newRing = append(newRing, news2[1:len(news2)-1]...)

	return newRing
}

func simplifyRingGrid(r geom.Ring, eps float64) geom.Ring {
	var newCoords []geom.Point
	for i := 0; i < len(r); i++ {
		newPoint := roundedPoint(r[i], eps)
		count := len(newCoords)
		// add if it's the first point or different from the most recent point
		if count == 0 || d(newPoint, newCoords[count-1]) > tolerance {
			newCoords = append(newCoords, newPoint)
		}
	}

	// check for collinearity
	// this check is a little more robust due to the removal of repeated points above
	cursor := 0
	polySize := len(newCoords)
	for cursor < polySize {
		// get indices for point before and after
		before := (cursor + polySize - 1) % polySize
		after := (cursor + 1) % polySize
		// maybe optimize this sometime
		triangle := []geom.Point{newCoords[before], newCoords[cursor], newCoords[after]}
		if math.Abs(area(triangle)) < tolerance {
			//if distPointToSegment(newCoords[cursor], newCoords[before], newCoords[after]) < tolerance {
			// remove the point, reduce the size, leave the cursor alone
			newCoords = append(newCoords[:cursor], newCoords[cursor+1:]...)
			polySize--
		} else {
			// keep this point, bump the cursor
			cursor++
		}
	}

	// check for ears/degenerate structures
	cursor = 0
	polySize = len(newCoords)
	for cursor < polySize {
		clipped := false
		for i := 2; !clipped && i < earSearchNodes; i++ {
			after := (cursor + i) % polySize
			if d(newCoords[cursor], newCoords[after]) < tolerance {
				// make sure this won't result in a degenerate poly
				// if we remove it...
				if (polySize - i) > 3 {
					// safe to remove
					clipped = true
					polySize -= i
					// removing from the middle?
					if after > cursor {
						newCoords = append(newCoords[:cursor], newCoords[cursor+i:]...)
					} else {
						// potentially removing from both ends
						newCoords = newCoords[after:cursor]
					}
				}
			}
		}
		// if we didn't clip, the cursor needs to be advanced.
		if !clipped {
			cursor++
		}
	}

	return geom.Ring(newCoords)
}

func rdpSimplify(points []geom.Point, epsilon float64) []geom.Point {
	return points[:rdpCompress(points, epsilon)]
}

func rdpCompress(points []geom.Point, epsilon float64) int {
	end := len(points)

	if end < 3 {
		// return points
		return end
	}

	// Find the point with the maximum distance
	var (
		first = points[0]
		last  = points[end-1]

		dmax  float64
		index int
	)

	for i := 1; i < end-1; i++ {
		d := distPointToSegment(points[i], first, last)
		if d > dmax {
			dmax, index = d, i
		}
	}

	// If max distance is lte to epsilon, return segment containing
	// the first and last points.
	if dmax <= epsilon {
		// return []point{first, last}
		points[1] = last
		return 2
	}

	// Recursive call
	r1 := rdpCompress(points[:index+1], epsilon)
	r2 := rdpCompress(points[index:], epsilon)

	// Build the result list
	// return append(r1[:len(r1)-1], r2...)
	x := r1 - 1
	n := copy(points[x:], points[index:index+r2])

	return x + n
}

func roundedPoint(p geom.Point, eps float64) geom.Point {
	// protect against stupidity
	if eps == 0.0 {
		return p
	}
	var newPoint geom.Point
	for i := 0; i < len(p); i++ {
		coord := math.Floor(p[i]/eps+0.5) * eps
		newPoint = append(newPoint, coord)
	}
	return newPoint
}
<|endoftext|>