<commit_before>package open_falcon

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestConvertToTransferData(t *testing.T) {
	sender := TransferSender{}
	var timeStamp int64 = 1000000
	data, ok := sender.converToTransferData("key1", "test", timeStamp)
	assert.Equal(t, false, ok)
	data, ok = sender.converToTransferData("key2", "0.02", timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, 0.02, data.Value)
	data, ok = sender.converToTransferData("key3", 10, timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(10), data.Value)
	data, ok = sender.converToTransferData("key3", int32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key2", json.Number("0.02"), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, 0.02, data.Value)
}

func TestSetTags(t *testing.T) {
	tags := setTags("", nil, "vccenter", "10.10.1.1")
	assert.EqualValues(t, "vccenter=10.10.1.1", tags)

	tags = setTags(tags, nil, "dcname", "cluster1")
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1", tags)

	tags = setTags(tags, nil, "esxhostname", 1.2)
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1,esxhostname=1.2", tags)

	tags = setTags(tags, nil, "clustername", struct {
		Name string
	}{"name"})
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1,esxhostname=1.2,clustername={name}", tags)

	tags = setTags("", map[string]bool{"a": true}, "vccenter", "10.10.1.1")
	assert.EqualValues(t, "", tags)

	tags = setTags(tags, map[string]bool{"a": true}, "a", "10.10.1.1")
	assert.EqualValues(t, "a=10.10.1.1", tags)

	tags = setTags(tags, map[string]bool{"b": true}, "b", "cluster1")
	assert.EqualValues(t, "a=10.10.1.1,b=cluster1", tags)
}
<commit_msg>add test<commit_after>package open_falcon

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestConvertToTransferData(t *testing.T) {
	sender := TransferSender{}
	var timeStamp int64 = 1000000
	data, ok := sender.converToTransferData("key1", "test", timeStamp)
	assert.Equal(t, false, ok)
	data, ok = sender.converToTransferData("key2", "0.02", timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, 0.02, data.Value)
	data, ok = sender.converToTransferData("key3", 10, timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(10), data.Value)
	data, ok = sender.converToTransferData("key3", int32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint32(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key3", uint(0), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, float64(0), data.Value)
	data, ok = sender.converToTransferData("key2", json.Number("0.02"), timeStamp)
	assert.Equal(t, true, ok)
	assert.Equal(t, 0.02, data.Value)
}

func TestGetEndpoint(t *testing.T) {
	separator := "."
	tagsEndpoint := map[string]string{"vmname": "vm", "endpoint": "endpoint", "esxhostname": "host", "dsname": "ds"}

	v := getEndpoint("vsphere.vm.", "", tagsEndpoint)
	assert.Equal(t, v, "endpoint")
	delete(tagsEndpoint, "endpoint")
	v = getEndpoint("vsphere.vm.", "", tagsEndpoint)
	assert.Equal(t, v, "vm")
}

func TestSetTags(t *testing.T) {
	tags := setTags("", nil, "vccenter", "10.10.1.1")
	assert.EqualValues(t, "vccenter=10.10.1.1", tags)

	tags = setTags(tags, nil, "dcname", "cluster1")
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1", tags)

	tags = setTags(tags, nil, "esxhostname", 1.2)
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1,esxhostname=1.2", tags)

	tags = setTags(tags, nil, "clustername", struct {
		Name string
	}{"name"})
	assert.EqualValues(t, "vccenter=10.10.1.1,dcname=cluster1,esxhostname=1.2,clustername={name}", tags)

	tags = setTags("", map[string]bool{"a": true}, "vccenter", "10.10.1.1")
	assert.EqualValues(t, "", tags)

	tags = setTags(tags, map[string]bool{"a": true}, "a", "10.10.1.1")
	assert.EqualValues(t, "a=10.10.1.1", tags)

	tags = setTags(tags, map[string]bool{"b": true}, "b", "cluster1")
	assert.EqualValues(t, "a=10.10.1.1,b=cluster1", tags)
}
<|endoftext|>


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

package scorecard

import (
	"context"
	"crypto/md5"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/forseti-security/config-validator/pkg/api/validator"
	"github.com/forseti-security/config-validator/pkg/gcv"
	_struct "github.com/golang/protobuf/ptypes/struct"
	"github.com/pkg/errors"
)

// ScoringConfig holds settings for generating a score
type ScoringConfig struct {
	categories  map[string]*constraintCategory   // available constraint categories
	constraints map[string]*constraintViolations // a map of constraints violated and their violations
	validator   *gcv.Validator                   // the validator instance used for scoring
}

// NewScoringConfigFromValidator creates a scoring engine with a given validator.
func NewScoringConfigFromValidator(v *gcv.Validator) *ScoringConfig {
	config := &ScoringConfig{}
	config.validator = v
	return config
}

// NewScoringConfig creates a scoring engine for the given policy library
func NewScoringConfig(ctx context.Context, policyPath string) (*ScoringConfig, error) {
	flag.Parse()
	v, err := gcv.NewValidator(
		[]string{filepath.Join(policyPath, "policies")},
		filepath.Join(policyPath, "lib"),
	)
	if err != nil {
		return nil, errors.Wrap(err, "initializing gcv validator")
	}
	config := NewScoringConfigFromValidator(v)
	return config, nil
}

const otherCategoryKey = "other"

// constraintCategory holds constraints by category
type constraintCategory struct {
	Name        string
	constraints []*constraintViolations
}

func (c constraintCategory) Count() int {
	sum := 0
	for _, cv := range c.constraints {
		sum += cv.Count()
	}
	return sum
}

// constraintViolations holds violations for a particular constraint
type constraintViolations struct {
	constraint string
	Violations []*validator.Violation `protobuf:"bytes,1,rep,name=violations,proto3" json:"violations,omitempty"`
}

func (cv constraintViolations) Count() int {
	return len(cv.Violations)
}

func getConstraintShortName(constraintName string) string {
	return strings.Split(constraintName, ".")[1]
}

// RichViolation holds a violation with its category
type RichViolation struct {
	Category string // category of violation
	Resource string
	Message  string
	Metadata *_struct.Value `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
}

// NewRichViolation creates a new RichViolation
func NewRichViolation(categoryName string, violation *validator.Violation) (*RichViolation, error) {
	richViolation := &RichViolation{}
	richViolation.Category = categoryName
	richViolation.Resource = violation.Resource
	richViolation.Message = violation.Message
	richViolation.Metadata = violation.Metadata
	return richViolation, nil
}

var availableCategories = map[string]string{
	"operational-efficiency": "Operational Efficiency",
	"security":               "Security",
	"reliability":            "Reliability",
	otherCategoryKey:         "Other",
}

func (config *ScoringConfig) getConstraintForViolation(violation *validator.Violation) (*constraintViolations, error) {
	key := violation.GetConstraint()
	cv, found := config.constraints[key]
	if !found {
		constraint := key
		cv = &constraintViolations{
			constraint: constraint,
		}
		config.constraints[key] = cv

		metadata := violation.GetMetadata().GetStructValue().GetFields()["constraint"]
		annotations := metadata.GetStructValue().GetFields()["annotations"].GetStructValue().GetFields()
		categoryKey := otherCategoryKey
		categoryValue, found := annotations["bundles.validator.forsetisecurity.org/scorecard-v1"]
		if found {
			categoryKey = categoryValue.GetStringValue()
		}

		category, found := config.categories[categoryKey]
		if !found {
			return nil, fmt.Errorf("Unknown constraint category %v for constraint %v", categoryKey, key)
		}
		category.constraints = append(category.constraints, cv)
	}
	return cv, nil
}

// attachViolations puts violations into their appropriate categories
func (config *ScoringConfig) attachViolations(audit *validator.AuditResponse) error {
	// Build map of categories
	config.categories = make(map[string]*constraintCategory)
	for k, name := range availableCategories {
		config.categories[k] = &constraintCategory{
			Name: name,
		}
	}

	// Categorize violations
	config.constraints = make(map[string]*constraintViolations)
	for _, v := range audit.Violations {
		cv, err := config.getConstraintForViolation(v)
		if err != nil {
			return errors.Wrap(err, "Categorizing violation")
		}

		cv.Violations = append(cv.Violations, v)
	}

	return nil
}

// Score creates a Scorecard for an inventory
func (inventory *InventoryConfig) Score(config *ScoringConfig, outputPath string, outputFormat string, outputMetadataFields []string) error {
	auditResult, err := getViolations(inventory, config)
	if err != nil {
		return err
	}
	Log.Debug("AuditResult from Config Validator", "# of Violations", len(auditResult.Violations))
	auditResult.Violations = uniqueViolations(auditResult.Violations)
	Log.Debug("AuditResult from Config Validator", "# of Unique Violations", len(auditResult.Violations))

	err = config.attachViolations(auditResult)
	if err != nil {
		return err
	}
	var dest io.Writer
	if len(auditResult.Violations) > 0 {
		if outputPath == "" {
			dest = os.Stdout
		} else {
			outputFile := "scorecard." + outputFormat
			dest, err = os.Create(filepath.Join(outputPath, outputFile))
			if err != nil {
				return err
			}
		}
		switch outputFormat {
		case "json":
			for _, category := range config.categories {
				for _, cv := range category.constraints {
					for _, v := range cv.Violations {
						richViolation, err := NewRichViolation(category.Name, v)
						if err != nil {
							return err
						}
						if len(outputMetadataFields) > 0 {
							newMetadata := make(map[string]interface{})
							oldMetadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue()
							for _, field := range outputMetadataFields {
								newMetadata[field], _ = interfaceViaJSON(oldMetadata.Fields[field])
							}
							err := protoViaJSON(newMetadata, richViolation.Metadata)
							if err != nil {
								return err
							}
						}
						byteContent, err := json.MarshalIndent(richViolation, "", "  ")
						if err != nil {
							return err
						}
						io.WriteString(dest, string(byteContent)+"\n")
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
		case "csv":
			w := csv.NewWriter(dest)
			header := []string{"Category", "Constraint", "Resource", "Message"}
			for _, field := range outputMetadataFields {
				header = append(header, field)
			}
			w.Write(header)
			w.Flush()
			for _, category := range config.categories {
				for _, cv := range category.constraints {
					for _, v := range cv.Violations {
						record := []string{category.Name, getConstraintShortName(v.Constraint), v.Resource, v.Message}
						for _, field := range outputMetadataFields {
							metadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue().Fields[field]
							value, _ := stringViaJSON(metadata)
							record = append(record, value)
						}
						w.Write(record)
						w.Flush()
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
		case "txt":
			io.WriteString(dest, fmt.Sprintf("\n\n%v total issues found\n", len(auditResult.Violations)))
			for _, category := range config.categories {
				io.WriteString(dest, fmt.Sprintf("\n\n%v: %v issues found\n", category.Name, category.Count()))
				io.WriteString(dest, fmt.Sprintf("----------\n"))
				for _, cv := range category.constraints {
					io.WriteString(dest, fmt.Sprintf("%v: %v issues\n", getConstraintShortName(cv.constraint), cv.Count()))
					for _, v := range cv.Violations {
						io.WriteString(dest, fmt.Sprintf("- %v\n", v.Message))
						for _, field := range outputMetadataFields {
							metadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue().Fields[field]
							value, _ := stringViaJSON(metadata)
							if value != "" {
								io.WriteString(dest, fmt.Sprintf("  %v: %v\n", field, value))
							}
						}
						io.WriteString(dest, "\n")
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
		default:
			return fmt.Errorf("Unsupported output format %v", outputFormat)
		}
	} else {
		fmt.Println("No issues found found! You have a perfect score.")
	}

	return nil
}

func uniqueViolations(violations []*validator.Violation) []*validator.Violation {
	uniqueViolationMap := make(map[string]*validator.Violation)
	for _, v := range violations {
		b, _ := json.Marshal(v)
		hash := md5.Sum(b)
		uniqueViolationMap[string(hash[:])] = v
	}
	uniqueViolations := make([]*validator.Violation, 0, len(uniqueViolationMap))
	for _, v := range uniqueViolationMap {
		uniqueViolations = append(uniqueViolations, v)
	}
	return uniqueViolations
}
<commit_msg>fix(scorecard): Fix JSON output for multiple violations (#857)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package scorecard

import (
	"context"
	"crypto/md5"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/forseti-security/config-validator/pkg/api/validator"
	"github.com/forseti-security/config-validator/pkg/gcv"
	_struct "github.com/golang/protobuf/ptypes/struct"
	"github.com/pkg/errors"
)

// ScoringConfig holds settings for generating a score
type ScoringConfig struct {
	categories  map[string]*constraintCategory   // available constraint categories
	constraints map[string]*constraintViolations // a map of constraints violated and their violations
	validator   *gcv.Validator                   // the validator instance used for scoring
}

// NewScoringConfigFromValidator creates a scoring engine with a given validator.
func NewScoringConfigFromValidator(v *gcv.Validator) *ScoringConfig {
	config := &ScoringConfig{}
	config.validator = v
	return config
}

// NewScoringConfig creates a scoring engine for the given policy library
func NewScoringConfig(ctx context.Context, policyPath string) (*ScoringConfig, error) {
	flag.Parse()
	v, err := gcv.NewValidator(
		[]string{filepath.Join(policyPath, "policies")},
		filepath.Join(policyPath, "lib"),
	)
	if err != nil {
		return nil, errors.Wrap(err, "initializing gcv validator")
	}
	config := NewScoringConfigFromValidator(v)
	return config, nil
}

const otherCategoryKey = "other"

// constraintCategory holds constraints by category
type constraintCategory struct {
	Name        string
	constraints []*constraintViolations
}

func (c constraintCategory) Count() int {
	sum := 0
	for _, cv := range c.constraints {
		sum += cv.Count()
	}
	return sum
}

// constraintViolations holds violations for a particular constraint
type constraintViolations struct {
	constraint string
	Violations []*validator.Violation `protobuf:"bytes,1,rep,name=violations,proto3" json:"violations,omitempty"`
}

func (cv constraintViolations) Count() int {
	return len(cv.Violations)
}

func getConstraintShortName(constraintName string) string {
	return strings.Split(constraintName, ".")[1]
}

// RichViolation holds a violation with its category
type RichViolation struct {
	Category string // category of violation
	Resource string
	Message  string
	Metadata *_struct.Value `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
}

// NewRichViolation creates a new RichViolation
func NewRichViolation(categoryName string, violation *validator.Violation) (*RichViolation, error) {
	richViolation := &RichViolation{}
	richViolation.Category = categoryName
	richViolation.Resource = violation.Resource
	richViolation.Message = violation.Message
	richViolation.Metadata = violation.Metadata
	return richViolation, nil
}

var availableCategories = map[string]string{
	"operational-efficiency": "Operational Efficiency",
	"security":               "Security",
	"reliability":            "Reliability",
	otherCategoryKey:         "Other",
}

func (config *ScoringConfig) getConstraintForViolation(violation *validator.Violation) (*constraintViolations, error) {
	key := violation.GetConstraint()
	cv, found := config.constraints[key]
	if !found {
		constraint := key
		cv = &constraintViolations{
			constraint: constraint,
		}
		config.constraints[key] = cv

		metadata := violation.GetMetadata().GetStructValue().GetFields()["constraint"]
		annotations := metadata.GetStructValue().GetFields()["annotations"].GetStructValue().GetFields()
		categoryKey := otherCategoryKey
		categoryValue, found := annotations["bundles.validator.forsetisecurity.org/scorecard-v1"]
		if found {
			categoryKey = categoryValue.GetStringValue()
		}

		category, found := config.categories[categoryKey]
		if !found {
			return nil, fmt.Errorf("Unknown constraint category %v for constraint %v", categoryKey, key)
		}
		category.constraints = append(category.constraints, cv)
	}
	return cv, nil
}

// attachViolations puts violations into their appropriate categories
func (config *ScoringConfig) attachViolations(audit *validator.AuditResponse) error {
	// Build map of categories
	config.categories = make(map[string]*constraintCategory)
	for k, name := range availableCategories {
		config.categories[k] = &constraintCategory{
			Name: name,
		}
	}

	// Categorize violations
	config.constraints = make(map[string]*constraintViolations)
	for _, v := range audit.Violations {
		cv, err := config.getConstraintForViolation(v)
		if err != nil {
			return errors.Wrap(err, "Categorizing violation")
		}

		cv.Violations = append(cv.Violations, v)
	}

	return nil
}

// Score creates a Scorecard for an inventory
func (inventory *InventoryConfig) Score(config *ScoringConfig, outputPath string, outputFormat string, outputMetadataFields []string) error {
	auditResult, err := getViolations(inventory, config)
	if err != nil {
		return err
	}
	Log.Debug("AuditResult from Config Validator", "# of Violations", len(auditResult.Violations))
	auditResult.Violations = uniqueViolations(auditResult.Violations)
	Log.Debug("AuditResult from Config Validator", "# of Unique Violations", len(auditResult.Violations))

	err = config.attachViolations(auditResult)
	if err != nil {
		return err
	}
	var dest io.Writer
	if len(auditResult.Violations) > 0 {
		if outputPath == "" {
			dest = os.Stdout
		} else {
			outputFile := "scorecard." + outputFormat
			dest, err = os.Create(filepath.Join(outputPath, outputFile))
			if err != nil {
				return err
			}
		}
		switch outputFormat {
		case "json":
			var richViolations []*RichViolation
			for _, category := range config.categories {
				for _, cv := range category.constraints {
					for _, v := range cv.Violations {
						richViolation, err := NewRichViolation(category.Name, v)
						if err != nil {
							return err
						}
						if len(outputMetadataFields) > 0 {
							newMetadata := make(map[string]interface{})
							oldMetadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue()
							for _, field := range outputMetadataFields {
								newMetadata[field], _ = interfaceViaJSON(oldMetadata.Fields[field])
							}
							err := protoViaJSON(newMetadata, richViolation.Metadata)
							if err != nil {
								return err
							}
						}
						richViolations = append(richViolations, richViolation)
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
			byteContent, err := json.MarshalIndent(richViolations, "", "  ")
			if err != nil {
				return err
			}
			io.WriteString(dest, string(byteContent)+"\n")
		case "csv":
			w := csv.NewWriter(dest)
			header := []string{"Category", "Constraint", "Resource", "Message"}
			for _, field := range outputMetadataFields {
				header = append(header, field)
			}
			w.Write(header)
			w.Flush()
			for _, category := range config.categories {
				for _, cv := range category.constraints {
					for _, v := range cv.Violations {
						record := []string{category.Name, getConstraintShortName(v.Constraint), v.Resource, v.Message}
						for _, field := range outputMetadataFields {
							metadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue().Fields[field]
							value, _ := stringViaJSON(metadata)
							record = append(record, value)
						}
						w.Write(record)
						w.Flush()
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
		case "txt":
			io.WriteString(dest, fmt.Sprintf("\n\n%v total issues found\n", len(auditResult.Violations)))
			for _, category := range config.categories {
				io.WriteString(dest, fmt.Sprintf("\n\n%v: %v issues found\n", category.Name, category.Count()))
				io.WriteString(dest, fmt.Sprintf("----------\n"))
				for _, cv := range category.constraints {
					io.WriteString(dest, fmt.Sprintf("%v: %v issues\n", getConstraintShortName(cv.constraint), cv.Count()))
					for _, v := range cv.Violations {
						io.WriteString(dest, fmt.Sprintf("- %v\n", v.Message))
						for _, field := range outputMetadataFields {
							metadata := v.Metadata.GetStructValue().Fields["details"].GetStructValue().Fields[field]
							value, _ := stringViaJSON(metadata)
							if value != "" {
								io.WriteString(dest, fmt.Sprintf("  %v: %v\n", field, value))
							}
						}
						io.WriteString(dest, "\n")
						Log.Debug("Violation metadata", "metadata", v.GetMetadata())
					}
				}
			}
		default:
			return fmt.Errorf("Unsupported output format %v", outputFormat)
		}
	} else {
		fmt.Println("No issues found found! You have a perfect score.")
	}

	return nil
}

func uniqueViolations(violations []*validator.Violation) []*validator.Violation {
	uniqueViolationMap := make(map[string]*validator.Violation)
	for _, v := range violations {
		b, _ := json.Marshal(v)
		hash := md5.Sum(b)
		uniqueViolationMap[string(hash[:])] = v
	}
	uniqueViolations := make([]*validator.Violation, 0, len(uniqueViolationMap))
	for _, v := range uniqueViolationMap {
		uniqueViolations = append(uniqueViolations, v)
	}
	return uniqueViolations
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/deis/deis/client-go/controller/client"
	"github.com/deis/deis/client-go/controller/models/perms"
	"github.com/deis/deis/client-go/pkg/git"
)

// PermsList prints which users have permissions.
func PermsList(appID string, admin bool, results int) error {
	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	var users []string
	var count int

	if admin {
		if results == defaultLimit {
			results = c.ResponseLimit
		}
		users, count, err = perms.ListAdmins(c, results)
	} else {
		users, err = perms.List(c, appID)
	}

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("=== Administrators%s", limitCount(len(users), count))
	} else {
		fmt.Printf("=== %s's Users\n", appID)
	}

	for _, user := range users {
		fmt.Println(user)
	}

	return nil
}

// PermCreate adds a user to an app or makes them an administrator.
func PermCreate(appID string, username string, admin bool) error {

	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("Adding %s to system administrators... ", username)
		perms.NewAdmin(c, username)
	} else {
		fmt.Printf("Adding %s to %s collaborators... ", username, appID)
		perms.New(c, appID, username)
	}

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}

// PermDelete removes a user from an app or revokes admin privilages.
func PermDelete(appID string, username string, admin bool) error {

	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("Removing %s from system administrators... ", username)
		perms.DeleteAdmin(c, username)
	} else {
		fmt.Printf("Removing %s from %s collaborators... ", username, appID)
		perms.Delete(c, appID, username)
	}

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}

func permsLoad(appID string, admin bool) (*client.Client, string, error) {
	c, err := client.New()

	if err != nil {
		return nil, "", err
	}

	if !admin && appID == "" {
		appID, err = git.DetectAppName(c.ControllerURL.Host)

		if err != nil {
			return nil, "", err
		}
	}

	return c, appID, err
}
<commit_msg>fix(client-go): return perms command errors<commit_after>package cmd

import (
	"fmt"

	"github.com/deis/deis/client-go/controller/client"
	"github.com/deis/deis/client-go/controller/models/perms"
	"github.com/deis/deis/client-go/pkg/git"
)

// PermsList prints which users have permissions.
func PermsList(appID string, admin bool, results int) error {
	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	var users []string
	var count int

	if admin {
		if results == defaultLimit {
			results = c.ResponseLimit
		}
		users, count, err = perms.ListAdmins(c, results)
	} else {
		users, err = perms.List(c, appID)
	}

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("=== Administrators%s", limitCount(len(users), count))
	} else {
		fmt.Printf("=== %s's Users\n", appID)
	}

	for _, user := range users {
		fmt.Println(user)
	}

	return nil
}

// PermCreate adds a user to an app or makes them an administrator.
func PermCreate(appID string, username string, admin bool) error {

	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("Adding %s to system administrators... ", username)
		err = perms.NewAdmin(c, username)
	} else {
		fmt.Printf("Adding %s to %s collaborators... ", username, appID)
		err = perms.New(c, appID, username)
	}

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}

// PermDelete removes a user from an app or revokes admin privilages.
func PermDelete(appID string, username string, admin bool) error {

	c, appID, err := permsLoad(appID, admin)

	if err != nil {
		return err
	}

	if admin {
		fmt.Printf("Removing %s from system administrators... ", username)
		err = perms.DeleteAdmin(c, username)
	} else {
		fmt.Printf("Removing %s from %s collaborators... ", username, appID)
		err = perms.Delete(c, appID, username)
	}

	if err != nil {
		return err
	}

	fmt.Println("done")

	return nil
}

func permsLoad(appID string, admin bool) (*client.Client, string, error) {
	c, err := client.New()

	if err != nil {
		return nil, "", err
	}

	if !admin && appID == "" {
		appID, err = git.DetectAppName(c.ControllerURL.Host)

		if err != nil {
			return nil, "", err
		}
	}

	return c, appID, err
}
<|endoftext|>


<commit_before>package cms

//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

// SiteMonitor is a nested struct in cms response
type SiteMonitor struct {
	TaskId      string `json:"TaskId" xml:"TaskId"`
	TaskType    string `json:"TaskType" xml:"TaskType"`
	Address     string `json:"Address" xml:"Address"`
	TaskState   string `json:"TaskState" xml:"TaskState"`
	CreateTime  string `json:"CreateTime" xml:"CreateTime"`
	TaskName    string `json:"TaskName" xml:"TaskName"`
	Interval    string `json:"Interval" xml:"Interval"`
	UpdateTime  string `json:"UpdateTime" xml:"UpdateTime"`
	OptionsJson string `json:"OptionsJson" xml:"OptionsJson"`
}
<commit_msg>fix:cms unmarshal<commit_after>package cms

//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//
// Code generated by Alibaba Cloud SDK Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

// SiteMonitor is a nested struct in cms response
type SiteMonitor struct {
	TaskId      string                 `json:"TaskId" xml:"TaskId"`
	TaskType    string                 `json:"TaskType" xml:"TaskType"`
	Address     string                 `json:"Address" xml:"Address"`
	TaskState   string                 `json:"TaskState" xml:"TaskState"`
	CreateTime  string                 `json:"CreateTime" xml:"CreateTime"`
	TaskName    string                 `json:"TaskName" xml:"TaskName"`
	Interval    string                 `json:"Interval" xml:"Interval"`
	UpdateTime  string                 `json:"UpdateTime" xml:"UpdateTime"`
	OptionsJson map[string]interface{} `json:"OptionsJson" xml:"OptionsJson"`
}
<|endoftext|>


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

package driver

import (
	"context"
)

// Cluster provides access to cluster wide specific operations.
// To use this interface, an ArangoDB cluster is required.
// If this method is a called without a cluster, a PreconditionFailed error is returned.
func (c *client) Cluster(ctx context.Context) (Cluster, error) {
	role, err := c.ServerRole(ctx)
	if err != nil {
		return nil, WithStack(err)
	}
	if role == ServerRoleSingle {
		// Standalone server, this is wrong
		return nil, WithStack(newArangoError(412, 0, "Cluster expected, found SINGLE server"))
	}
	cl, err := newCluster(c.conn)
	if err != nil {
		return nil, WithStack(err)
	}
	return cl, nil
}
<commit_msg>Role fix<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package driver

import (
	"context"
)

// Cluster provides access to cluster wide specific operations.
// To use this interface, an ArangoDB cluster is required.
// If this method is a called without a cluster, a PreconditionFailed error is returned.
func (c *client) Cluster(ctx context.Context) (Cluster, error) {
	role, err := c.ServerRole(ctx)
	if err != nil {
		return nil, WithStack(err)
	}
	if role == ServerRoleSingle || role == ServerRoleSingleResilient {
		// Standalone server, this is wrong
		return nil, WithStack(newArangoError(412, 0, "Cluster expected, found SINGLE server"))
	}
	cl, err := newCluster(c.conn)
	if err != nil {
		return nil, WithStack(err)
	}
	return cl, nil
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"reflect"
	"strings"
)

type ServiceConfig map[string]interface{}

func (sc ServiceConfig) Assign(to interface{}) error {
	t := reflect.TypeOf(to)
	v := reflect.ValueOf(to)
	fc := t.NumField()
	for i := 0; i < fc; i++ {
		tf := t.Field(i)
		if tf.Anonymous {
			continue
		}

		if !v.CanSet() {
			continue
		}
		tag, ok := tf.Tag.Lookup("servconf")
		if !ok {
			continue
		}
		vf := v.Field(i)
		sc.handleField(tag, &vf)

	}

	return nil
}

func (sc ServiceConfig) handleField(tag string, vf *reflect.Value) error {
	tagVals := strings.Split(tag, ",")
	tvc := len(tagVals)
	if tvc < 1 {
		return fmt.Errorf("TODO implement error type for invalid struct fields")
	}

	fName := strings.TrimSpace(tagVals[0])
	if fName == "" {
		return fmt.Errorf("TODO implement error type for empty name field")
	}

	value, ok := sc[fName]

	required := false

	if tvc >= 2 {
		required = tagVals[1] == "required"
	}

	if !ok {
		if required {
			return fmt.Errorf("TODO implement error type for missing required field")
		}
	} else {
		if err := assignValueToField(value, vf, required); err != nil {
			return err
		}

	}

	return nil
}

func assignValueToField(value interface{}, vf *reflect.Value, required bool) error {
	vsc, ok := value.(ServiceConfig)
	if ok {
		//TODO figure out if this mess works
		iface := vf.Interface()
		err := vsc.Assign(&iface)
		if err != nil {
			return err
		}
		value = iface
	}

	valType := reflect.TypeOf(value)
	valVal := reflect.ValueOf(value)
	t := vf.Type()

	if valType.AssignableTo(t) {
		vf.Set(valVal)
	} else if valType.ConvertibleTo(t) {
		converted := valVal.Convert(t)
		vf.Set(converted)
	}
	return nil
}
<commit_msg>service/service_config: Make sure we get a struct<commit_after>package config

import (
	"fmt"
	"reflect"
	"strings"
)

type ServiceConfig map[string]interface{}

func (sc ServiceConfig) Assign(to interface{}) error {
	t := reflect.TypeOf(to)
	v := reflect.ValueOf(to)
	if v.Kind() != reflect.Struct {
		return fmt.Errorf("TODO implement error type for when interface is not a struct")
	}
	fc := t.NumField()
	for i := 0; i < fc; i++ {
		tf := t.Field(i)
		if tf.Anonymous {
			continue
		}

		if !v.CanSet() {
			continue
		}
		tag, ok := tf.Tag.Lookup("servconf")
		if !ok {
			continue
		}
		vf := v.Field(i)
		sc.handleField(tag, &vf)

	}

	return nil
}

func (sc ServiceConfig) handleField(tag string, vf *reflect.Value) error {
	tagVals := strings.Split(tag, ",")
	tvc := len(tagVals)
	if tvc < 1 {
		return fmt.Errorf("TODO implement error type for invalid struct fields")
	}

	fName := strings.TrimSpace(tagVals[0])
	if fName == "" {
		return fmt.Errorf("TODO implement error type for empty name field")
	}

	value, ok := sc[fName]

	required := false

	if tvc >= 2 {
		required = tagVals[1] == "required"
	}

	if !ok {
		if required {
			return fmt.Errorf("TODO implement error type for missing required field")
		}
	} else {
		if err := assignValueToField(value, vf, required); err != nil {
			return err
		}

	}

	return nil
}

func assignValueToField(value interface{}, vf *reflect.Value, required bool) error {
	vsc, ok := value.(ServiceConfig)
	if ok {
		//TODO figure out if this mess works
		iface := vf.Interface()
		err := vsc.Assign(&iface)
		if err != nil {
			return err
		}
		value = iface
	}

	valType := reflect.TypeOf(value)
	valVal := reflect.ValueOf(value)
	t := vf.Type()

	if valType.AssignableTo(t) {
		vf.Set(valVal)
	} else if valType.ConvertibleTo(t) {
		converted := valVal.Convert(t)
		vf.Set(converted)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2017 Artem Sidorenko <artem@posteo.de>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package github

import (
	"context"

	"fmt"

	"github.com/google/go-github/github"
)

// API builds a wrapper around GitHub API from
// github.com/google/go-github/github
// We need this in order to allow unit testing without to fire
// requests to GitHub during the tests
type API interface {
	ListTags(string, string) ([]*github.RepositoryTag, error)
	GetCommit(string, string, string) (*github.RepositoryCommit, error)
	ListIssues(string, string) ([]*github.Issue, error)
	ListPRs(string, string) ([]*github.PullRequest, error)
}

// APIClient implements the API interface
// and connects the needed functions to the github API library
type APIClient struct {
	context context.Context
	client  *github.Client
}

// ListTags implements the github.Client.Repositories.ListTags()
func (a *APIClient) ListTags(owner, repo string) (tags []*github.RepositoryTag, err error) {
	tags, _, err = a.client.Repositories.ListTags(a.context, owner, repo, nil)
	if err != nil {
		return nil, a.formatErrorCode("ListTags", err)
	}

	return
}

// GetCommit implements the github.Client.Repositories.GetCommit()
func (a *APIClient) GetCommit(owner, repo, sha string) (
	commit *github.RepositoryCommit, err error) {

	commit, _, err = a.client.Repositories.GetCommit(a.context, owner, repo, sha)
	if err != nil {
		return nil, a.formatErrorCode("GetCommit", err)
	}

	return
}

// ListIssues implements the github.Client.Issues.ListByRepo()
// and returns all closed issues and PRs
func (a *APIClient) ListIssues(owner, repo string) ([]*github.Issue, error) {
	opt := &github.IssueListByRepoOptions{
		State: "closed",
	}

	var ret []*github.Issue
	for {
		issues, resp, err := a.client.Issues.ListByRepo(a.context, owner, repo, opt)
		if err != nil {
			return nil, a.formatErrorCode("ListIssues", err)
		}

		ret = append(ret, issues...)

		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	return ret, nil
}

// ListPRs implements the github.Client.PullRequests.List()
// and returns all closed PRs
func (a *APIClient) ListPRs(owner, repo string) ([]*github.PullRequest, error) {
	opt := &github.PullRequestListOptions{
		State: "closed",
	}

	var ret []*github.PullRequest
	for {
		prs, resp, err := a.client.PullRequests.List(a.context, owner, repo, opt)
		if err != nil {
			return nil, a.formatErrorCode("ListPRs", err)
		}

		ret = append(ret, prs...)

		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	return ret, nil
}

// formatErrorCode formats the error message for this connector
func (a *APIClient) formatErrorCode(query string, err error) error {
	return fmt.Errorf("GitHub query '%s' failed: %s", query, err)
}

// NewAPIClient returns the initialized and ready to use APIClient
func NewAPIClient() *APIClient {
	return &APIClient{
		context: context.Background(),
		client:  github.NewClient(nil),
	}
}
<commit_msg>Pagination for ListTags() API<commit_after>/*
   Copyright 2017 Artem Sidorenko <artem@posteo.de>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package github

import (
	"context"

	"fmt"

	"github.com/google/go-github/github"
)

// API builds a wrapper around GitHub API from
// github.com/google/go-github/github
// We need this in order to allow unit testing without to fire
// requests to GitHub during the tests
type API interface {
	ListTags(string, string) ([]*github.RepositoryTag, error)
	GetCommit(string, string, string) (*github.RepositoryCommit, error)
	ListIssues(string, string) ([]*github.Issue, error)
	ListPRs(string, string) ([]*github.PullRequest, error)
}

// APIClient implements the API interface
// and connects the needed functions to the github API library
type APIClient struct {
	context context.Context
	client  *github.Client
}

// ListTags implements the github.Client.Repositories.ListTags()
func (a *APIClient) ListTags(owner, repo string) ([]*github.RepositoryTag, error) {
	opt := &github.ListOptions{}

	var ret []*github.RepositoryTag
	for {
		tags, resp, err := a.client.Repositories.ListTags(a.context, owner, repo, nil)
		if err != nil {
			return nil, a.formatErrorCode("ListTags", err)
		}

		ret = append(ret, tags...)

		if resp.NextPage == 0 {
			break
		}

		opt.Page = resp.NextPage
	}

	return ret, nil
}

// GetCommit implements the github.Client.Repositories.GetCommit()
func (a *APIClient) GetCommit(owner, repo, sha string) (
	commit *github.RepositoryCommit, err error) {

	commit, _, err = a.client.Repositories.GetCommit(a.context, owner, repo, sha)
	if err != nil {
		return nil, a.formatErrorCode("GetCommit", err)
	}

	return
}

// ListIssues implements the github.Client.Issues.ListByRepo()
// and returns all closed issues and PRs
func (a *APIClient) ListIssues(owner, repo string) ([]*github.Issue, error) {
	opt := &github.IssueListByRepoOptions{
		State: "closed",
	}

	var ret []*github.Issue
	for {
		issues, resp, err := a.client.Issues.ListByRepo(a.context, owner, repo, opt)
		if err != nil {
			return nil, a.formatErrorCode("ListIssues", err)
		}

		ret = append(ret, issues...)

		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	return ret, nil
}

// ListPRs implements the github.Client.PullRequests.List()
// and returns all closed PRs
func (a *APIClient) ListPRs(owner, repo string) ([]*github.PullRequest, error) {
	opt := &github.PullRequestListOptions{
		State: "closed",
	}

	var ret []*github.PullRequest
	for {
		prs, resp, err := a.client.PullRequests.List(a.context, owner, repo, opt)
		if err != nil {
			return nil, a.formatErrorCode("ListPRs", err)
		}

		ret = append(ret, prs...)

		if resp.NextPage == 0 {
			break
		}
		opt.Page = resp.NextPage
	}

	return ret, nil
}

// formatErrorCode formats the error message for this connector
func (a *APIClient) formatErrorCode(query string, err error) error {
	return fmt.Errorf("GitHub query '%s' failed: %s", query, err)
}

// NewAPIClient returns the initialized and ready to use APIClient
func NewAPIClient() *APIClient {
	return &APIClient{
		context: context.Background(),
		client:  github.NewClient(nil),
	}
}
<|endoftext|>


<commit_before>package controller

import "net/http"
import "github.com/ishiikurisu/moneyweb/model"
import "github.com/ishiikurisu/moneyweb/view"

/*********************
 * SERVER DEFINITION *
 *********************/

// The definitions of a server.
type Server struct {
    // This storage is responsible for dealing with Cookies.
    Storage *model.LocalStorage

    // This is the port this webserver will serve upon.
    Port string
}

// Create a webserver for this app.
func CreateServer() Server {
    // Create server structure
    storage, oops := model.NewLocalStorage()
    if oops != nil {
        panic(oops)
    }

    server := Server{
        Storage: storage,
        Port: model.GetPort(),
    }

    // Route stuff
    http.HandleFunc("/", server.SayHello)
    http.HandleFunc("/add", server.AddEntry)
    http.HandleFunc("/register", server.Register)
    http.HandleFunc("/raw", server.DownloadLog)
    http.HandleFunc("/upload", server.UploadLog)
    http.HandleFunc("/uploading", server.UploadingLog)

    return server
}

// Puts the webserver to, well, serve.
func (server *Server) Serve() {
    http.ListenAndServe(server.Port, nil)
}

/***************************
 * SERVER ROUTED FUNCTIONS *
 ***************************/

// Function for index function
func (server *Server) SayHello(w http.ResponseWriter, r *http.Request) {
    log := server.Storage.GetLog(w, r)
    if len(log) > 0 {
        view.BeUseful(w, model.LogToMap(log))
    } else {
        view.SayHello(w)
    }
}

// Function for adding a entry
func (server *Server) AddEntry(w http.ResponseWriter, r *http.Request) {
    rawLog := server.Storage.GetLog(w, r)
    msg := model.GetRandomMessage()

    if len(rawLog) == 0 {
        msg = "First log!"
    }

    data := make(map[string]string)
    data["Message"] = msg
    view.AddEntry(w, data)
}

// Saves entry to cookies and to model format
func (server *Server) Register(w http.ResponseWriter, r *http.Request) {
    // Extract data from request
    description := r.FormValue("description")
    value := r.FormValue("value")

    // Save entry to current log
    server.Storage.AddEntryFromRaw(description, value)
    w, r = server.Storage.SaveLog(w, r)
    server.Storage.StoreLog(w, r)

    // Redirecting to correct page
    http.Redirect(w, r, "/", http.StatusFound)
}

// Displays raw log on browser
func (server *Server) DownloadLog(w http.ResponseWriter, r *http.Request) {
    view.EnableData(w, server.Storage.GetLog(w, r))
}

// Displays the page to download log
func (server *Server) UploadLog(w http.ResponseWriter, r *http.Request) {
    view.UploadLog(w)
}

// Loads file from user's computer to use on logging
func (server *Server) UploadingLog(w http.ResponseWriter, r *http.Request) {
    // Extract data from request
    rawLog, _, err := r.FormFile("file")
    if err != nil {
        panic(err)
    }

    // Save entry to current log
    server.Storage.AddLogFromFile(rawLog)
    w, r = server.Storage.SaveLog(w, r)
    server.Storage.StoreLog(w, r)

    // Redirecting to correct page
    http.Redirect(w, r, "/", http.StatusFound)
}
<commit_msg>Maybe I shouldn't be saving this file<commit_after>package controller

import "net/http"
import "github.com/ishiikurisu/moneyweb/model"
import "github.com/ishiikurisu/moneyweb/view"

/*********************
 * SERVER DEFINITION *
 *********************/

// The definitions of a server.
type Server struct {
    // This storage is responsible for dealing with Cookies.
    Storage *model.LocalStorage

    // This is the port this webserver will serve upon.
    Port string
}

// Create a webserver for this app.
func CreateServer() Server {
    // Create server structure
    storage, oops := model.NewLocalStorage()
    if oops != nil {
        panic(oops)
    }

    server := Server{
        Storage: storage,
        Port: model.GetPort(),
    }

    // Route stuff
    http.HandleFunc("/", server.SayHello)
    http.HandleFunc("/add", server.AddEntry)
    http.HandleFunc("/register", server.Register)
    http.HandleFunc("/raw", server.DownloadLog)
    http.HandleFunc("/upload", server.UploadLog)
    http.HandleFunc("/uploading", server.UploadingLog)

    return server
}

// Puts the webserver to, well, serve.
func (server *Server) Serve() {
    http.ListenAndServe(server.Port, nil)
}

/***************************
 * SERVER ROUTED FUNCTIONS *
 ***************************/

// Function for index function
func (server *Server) SayHello(w http.ResponseWriter, r *http.Request) {
    log := server.Storage.GetLog(w, r)
    if len(log) > 0 {
        view.BeUseful(w, model.LogToMap(log))
    } else {
        view.SayHello(w)
    }
}

// Function for adding a entry
func (server *Server) AddEntry(w http.ResponseWriter, r *http.Request) {
    rawLog := server.Storage.GetLog(w, r)
    msg := model.GetRandomMessage()

    if len(rawLog) == 0 {
        msg = "First log!"
    }

    data := make(map[string]string)
    data["Message"] = msg
    view.AddEntry(w, data)
}

// Saves entry to cookies and to model format
func (server *Server) Register(w http.ResponseWriter, r *http.Request) {
    // Extract data from request
    description := r.FormValue("description")
    value := r.FormValue("value")

    // Save entry to current log
    server.Storage.AddEntryFromRaw(description, value)
    w, r = server.Storage.SaveLog(w, r)

    // Redirecting to correct page
    http.Redirect(w, r, "/", http.StatusFound)
}

// Displays raw log on browser
func (server *Server) DownloadLog(w http.ResponseWriter, r *http.Request) {
    view.EnableData(w, server.Storage.GetLog(w, r))
}

// Displays the page to download log
func (server *Server) UploadLog(w http.ResponseWriter, r *http.Request) {
    view.UploadLog(w)
}

// Loads file from user's computer to use on logging
func (server *Server) UploadingLog(w http.ResponseWriter, r *http.Request) {
    // Extract data from request
    rawLog, _, err := r.FormFile("file")
    if err != nil {
        panic(err)
    }

    // Save entry to current log
    server.Storage.AddLogFromFile(rawLog)
    w, r = server.Storage.SaveLog(w, r)

    // Redirecting to correct page
    http.Redirect(w, r, "/", http.StatusFound)
}
<|endoftext|>


<commit_before>package core

import (
	"strconv"
	"time"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type PartnersGuardian struct {
	model.ClockConsumer

	stop        chan struct{}
	referential *Referential
}

func NewPartnersGuardian(referential *Referential) *PartnersGuardian {
	return &PartnersGuardian{referential: referential}
}

func (guardian *PartnersGuardian) Start() {
	logger.Log.Debugf("Start partners guardian")

	guardian.stop = make(chan struct{})
	go guardian.Run()
}

func (guardian *PartnersGuardian) Stop() {
	if guardian.stop != nil {
		close(guardian.stop)
	}
}

func (guardian *PartnersGuardian) Run() {
	for {
		select {
		case <-guardian.stop:
			logger.Log.Debugf("Stop Partners Guardian")
			return
		case <-guardian.Clock().After(30 * time.Second):
			logger.Log.Debugf("Check partners status")
			for _, partner := range guardian.referential.Partners().FindAll() {
				go guardian.routineWork(partner)
			}
		}
	}
}

func (guardian *PartnersGuardian) routineWork(partner *Partner) {
	s := guardian.checkPartnerStatus(partner)
	if !s {
		return
	}

	guardian.checkSubscriptionsTerminatedTime(partner)
}

func (guardian *PartnersGuardian) checkPartnerStatus(partner *Partner) bool {
	defer func() {
		if r := recover(); r != nil {
			logger.Log.Printf("Recovered error %v in checkPartnerStatus for partner %#v", r, partner)
		}
	}()

	partnerStatus, _ := partner.CheckStatus()

	if partnerStatus.OperationnalStatus != partner.PartnerStatus.OperationnalStatus {
		logger.Log.Debugf("Partner %v status changed after a CheckStatus: was %v, now is %v", partner.Slug(), partner.PartnerStatus.OperationnalStatus, partnerStatus.OperationnalStatus)
		guardian.referential.CollectManager().HandlePartnerStatusChange(string(partner.Slug()), guardian.partnerStatus == OPERATIONNAL_STATUS_UP)
	}

	if partnerStatus.OperationnalStatus == OPERATIONNAL_STATUS_UNKNOWN || partnerStatus.OperationnalStatus == OPERATIONNAL_STATUS_DOWN || partnerStatus.ServiceStartedAt != partner.PartnerStatus.ServiceStartedAt {
		partner.PartnerStatus = partnerStatus

		if b, _ := strconv.ParseBool(partner.Setting("subscriptions.persistent")); b {
			partner.Subscriptions().CancelCollectSubscriptions()
			return false
		}

		partner.CancelSubscriptions()

		return false
	}

	partner.PartnerStatus = partnerStatus
	return true
}

func (guardian *PartnersGuardian) checkSubscriptionsTerminatedTime(partner *Partner) {
	if partner.Subscriptions() == nil {
		return
	}

	for _, sub := range partner.Subscriptions().FindAll() {
		for key, value := range sub.ResourcesByObjectIDCopy() {
			if !value.SubscribedUntil.Before(guardian.Clock().Now()) || value.SubscribedAt.IsZero() {
				continue
			}
			sub.DeleteResource(key)
			logger.Log.Printf("Deleting ressource %v from subscription with id %v", key, sub.Id())
		}
		if sub.ResourcesLen() == 0 {
			sub.Delete()
		}
	}
}
<commit_msg>Fix type<commit_after>package core

import (
	"strconv"
	"time"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type PartnersGuardian struct {
	model.ClockConsumer

	stop        chan struct{}
	referential *Referential
}

func NewPartnersGuardian(referential *Referential) *PartnersGuardian {
	return &PartnersGuardian{referential: referential}
}

func (guardian *PartnersGuardian) Start() {
	logger.Log.Debugf("Start partners guardian")

	guardian.stop = make(chan struct{})
	go guardian.Run()
}

func (guardian *PartnersGuardian) Stop() {
	if guardian.stop != nil {
		close(guardian.stop)
	}
}

func (guardian *PartnersGuardian) Run() {
	for {
		select {
		case <-guardian.stop:
			logger.Log.Debugf("Stop Partners Guardian")
			return
		case <-guardian.Clock().After(30 * time.Second):
			logger.Log.Debugf("Check partners status")
			for _, partner := range guardian.referential.Partners().FindAll() {
				go guardian.routineWork(partner)
			}
		}
	}
}

func (guardian *PartnersGuardian) routineWork(partner *Partner) {
	s := guardian.checkPartnerStatus(partner)
	if !s {
		return
	}

	guardian.checkSubscriptionsTerminatedTime(partner)
}

func (guardian *PartnersGuardian) checkPartnerStatus(partner *Partner) bool {
	defer func() {
		if r := recover(); r != nil {
			logger.Log.Printf("Recovered error %v in checkPartnerStatus for partner %#v", r, partner)
		}
	}()

	partnerStatus, _ := partner.CheckStatus()

	if partnerStatus.OperationnalStatus != partner.PartnerStatus.OperationnalStatus {
		logger.Log.Debugf("Partner %v status changed after a CheckStatus: was %v, now is %v", partner.Slug(), partner.PartnerStatus.OperationnalStatus, partnerStatus.OperationnalStatus)
		guardian.referential.CollectManager().HandlePartnerStatusChange(string(partner.Slug()), partnerStatus.OperationnalStatus == OPERATIONNAL_STATUS_UP)
	}

	if partnerStatus.OperationnalStatus == OPERATIONNAL_STATUS_UNKNOWN || partnerStatus.OperationnalStatus == OPERATIONNAL_STATUS_DOWN || partnerStatus.ServiceStartedAt != partner.PartnerStatus.ServiceStartedAt {
		partner.PartnerStatus = partnerStatus

		if b, _ := strconv.ParseBool(partner.Setting("subscriptions.persistent")); b {
			partner.Subscriptions().CancelCollectSubscriptions()
			return false
		}

		partner.CancelSubscriptions()

		return false
	}

	partner.PartnerStatus = partnerStatus
	return true
}

func (guardian *PartnersGuardian) checkSubscriptionsTerminatedTime(partner *Partner) {
	if partner.Subscriptions() == nil {
		return
	}

	for _, sub := range partner.Subscriptions().FindAll() {
		for key, value := range sub.ResourcesByObjectIDCopy() {
			if !value.SubscribedUntil.Before(guardian.Clock().Now()) || value.SubscribedAt.IsZero() {
				continue
			}
			sub.DeleteResource(key)
			logger.Log.Printf("Deleting ressource %v from subscription with id %v", key, sub.Id())
		}
		if sub.ResourcesLen() == 0 {
			sub.Delete()
		}
	}
}
<|endoftext|>


<commit_before>package fst

import (
	"fmt"
	"github.com/balzaczyy/golucene/core/util"
)

/* Expert: invoked by Builder whenever a suffix is serialized. */
type FreezeTail func([]*UnCompiledNode, int, *util.IntsRef) error

/*
Builds a minimal FST (maps an []int term to an arbitrary output) from
pre-sorted terms with outputs. The FST becomes an FSA if you use
NoOutputs. The FST is written on-the-fly into a compact serialized
format byte array, which can be saved to / loaded from a Directory or
used directly for traversal. The FST is always finite (no cycles).

NOTE: the algorithm is described at
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.3698

FSTs larger than 2.1GB are now possible (as of Lucene 4.2). FSTs
containing more than 2.1B nodes are also now possible, however they
cannot be packed.
*/
type Builder struct {
	dedupHash *NodeHash
	fst       *FST
	NO_OUTPUT interface{}

	// simplistic pruning: we prune node (and all following nodes) if
	// less than this number of terms go through it:
	minSuffixCount1 int

	// better pruning: we prune node (and all following nodes) if the
	// prior node has less than this number of terms go through it:
	minSuffixCount2 int

	doShareNonSingletonNodes bool
	shareMaxTailLength       int

	lastInput *util.IntsRef

	// for packing
	doPackFST               bool
	acceptableOverheadRatio float32

	// current frontier
	frontier []*UnCompiledNode

	_freezeTail FreezeTail
}

/* Expert: holds a pending (seen but not yet serialized) arc */
type builderArc struct {
	label  int // really an "unsigned" byte
	Target Node
}

/*
NOTE: not many instances of Node or CompiledNode are in memory while
the FST is being built; it's only the current "frontier":
*/
type Node interface {
	isCompiled() bool
}

/* Expert: holds a pending (seen but not yet serialized) Node. */
type UnCompiledNode struct {
	owner      *Builder
	NumArcs    int
	Arcs       []*builderArc
	output     interface{}
	IsFinal    bool
	InputCount int64

	// This node's depth, starting from the automaton root.
	depth int
}

func NewUnCompiledNode(owner *Builder, depth int) *UnCompiledNode {
	return &UnCompiledNode{
		owner:  owner,
		Arcs:   []*builderArc{new(builderArc)},
		output: owner.NO_OUTPUT,
		depth:  depth,
	}
}

func (n *UnCompiledNode) isCompiled() bool { return false }

func (n *UnCompiledNode) Clear() {
	n.NumArcs = 0
	n.IsFinal = false
	n.output = n.owner.NO_OUTPUT
	n.InputCount = 0

	// we don't clear the depth here becaues it never changes
	// for nodes on the frontier (even when reused).
}

func (n *UnCompiledNode) lastOutput(labelToMatch int) interface{} {
	panic("not implementd yet")
}

func (n *UnCompiledNode) addArc(label int, target Node) {
	panic("not implemented yet")
}

/*
Instantiates an FST/FSA builder with all the possible tuning and
construction tweaks. Read parameter documentation carefully.

...
*/
func NewBuilder(inputType InputType, minSuffixCount1, minSuffixCount2 int,
	doShareSuffix, doShareNonSingletonNodes bool, shareMaxTailLength int,
	outputs Outputs, freezeTail FreezeTail, doPackFST bool,
	acceptableOverheadRatio float32, allowArrayArcs bool, bytesPageBits int) *Builder {

	fst := newFST(inputType, outputs, doPackFST, acceptableOverheadRatio, allowArrayArcs, bytesPageBits)
	f := make([]*UnCompiledNode, 10)
	ans := &Builder{
		minSuffixCount1:          minSuffixCount1,
		minSuffixCount2:          minSuffixCount2,
		_freezeTail:              freezeTail,
		doShareNonSingletonNodes: doShareNonSingletonNodes,
		shareMaxTailLength:       shareMaxTailLength,
		doPackFST:                doPackFST,
		acceptableOverheadRatio:  acceptableOverheadRatio,
		fst:       fst,
		NO_OUTPUT: outputs.NoOutput(),
		frontier:  f,
		lastInput: util.NewEmptyIntsRef(),
	}
	if doShareSuffix {
		ans.dedupHash = newNodeHash(fst, fst.bytes.reverseReaderAllowSingle(false))
	}
	for i, _ := range f {
		f[i] = NewUnCompiledNode(ans, i)
	}
	return ans
}

func (b *Builder) freezeTail(prefixLenPlus1 int) error {
	if b._freezeTail != nil {
		// Custom plugin:
		return b._freezeTail(b.frontier, prefixLenPlus1, b.lastInput)
	}
	panic("not implemented yet")
}

/*
It's OK to add the same input twice in a row with different outputs,
as long as outputs impls the merge method. Note that input is fully
consumed after this method is returned (so caller is free to reuse),
but output is not. So if your outputs are changeable (eg
ByteSequenceOutputs or IntSequenceOutputs) then you cannot reuse
across calls.
*/
func (b *Builder) Add(input *util.IntsRef, output interface{}) error {
	assert2(b.lastInput.Length == 0 || !input.CompareTo(b.lastInput),
		"inputs are added out of order, lastInput=%v vs input=%v",
		b.lastInput, input)

	if input.Length == 0 {
		// empty input: only allowed as first input. We have to special
		// case this becaues the packed FST format cannot represent the
		// empty input since 'finalness' is stored on the incoming arc,
		// not on the node
		b.frontier[0].InputCount++
		b.frontier[0].IsFinal = true
		b.fst.setEmptyOutput(output)
		return nil
	}

	// compare shared prefix length
	pos1 := 0
	pos2 := input.Offset
	pos1Stop := b.lastInput.Length
	if input.Length < pos1Stop {
		pos1Stop = input.Length
	}
	for {
		b.frontier[pos1].InputCount++
		if pos1 >= pos1Stop || b.lastInput.Ints[pos1] != input.Ints[pos2] {
			break
		}
		pos1++
		pos2++
	}
	prefixLenPlus1 := pos1 + 1

	if len(b.frontier) < input.Length+1 {
		next := make([]*UnCompiledNode, util.Oversize(input.Length+1, util.NUM_BYTES_OBJECT_REF))
		copy(next, b.frontier)
		for idx := len(b.frontier); idx < len(next); idx++ {
			next[idx] = NewUnCompiledNode(b, idx)
		}
		b.frontier = next
	}

	// minimize/compile states from previous input's orphan'd suffix
	err := b.freezeTail(prefixLenPlus1)
	if err != nil {
		return err
	}

	// init tail states for current input
	for idx := prefixLenPlus1; idx <= input.Length; idx++ {
		b.frontier[idx-1].addArc(input.Ints[input.Offset+idx-1], b.frontier[idx])
		b.frontier[idx].InputCount++
	}

	lastNode := b.frontier[input.Length]
	if b.lastInput.Length != input.Length || prefixLenPlus1 != input.Length+1 {
		lastNode.IsFinal = true
		lastNode.output = b.NO_OUTPUT
	}

	// push conflicting outputs forward, only as far as needed
	for idx := 1; idx < prefixLenPlus1; idx++ {
		// node := b.frontier[idx]
		parentNode := b.frontier[idx-1]

		lastOutput := parentNode.lastOutput(input.Ints[input.Offset+idx-1])

		var commonOutputPrefix interface{}
		// var wordSuffix interface{}

		if lastOutput != b.NO_OUTPUT {
			panic("not implemented yet")
		} else {
			panic("not implemented yet")
		}

		output = b.fst.outputs.Subtract(output, commonOutputPrefix)
	}

	if b.lastInput.Length == input.Length && prefixLenPlus1 == 1+input.Length {
		// same input more than 1 time in a row, mapping to multiple outputs
		panic("not implemented yet")
	} else {
		panic("not implemented yet")
	}

	// save last input
	b.lastInput.CopyInts(input)
	return nil
}

func assert(ok bool) {
	assert2(ok, "assert fail")
}

func assert2(ok bool, msg string, args ...interface{}) {
	if !ok {
		panic(fmt.Sprintf(msg, args...))
	}
}
<commit_msg>implement UnCompiledNode.addArc()<commit_after>package fst

import (
	"fmt"
	"github.com/balzaczyy/golucene/core/util"
)

/* Expert: invoked by Builder whenever a suffix is serialized. */
type FreezeTail func([]*UnCompiledNode, int, *util.IntsRef) error

/*
Builds a minimal FST (maps an []int term to an arbitrary output) from
pre-sorted terms with outputs. The FST becomes an FSA if you use
NoOutputs. The FST is written on-the-fly into a compact serialized
format byte array, which can be saved to / loaded from a Directory or
used directly for traversal. The FST is always finite (no cycles).

NOTE: the algorithm is described at
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.3698

FSTs larger than 2.1GB are now possible (as of Lucene 4.2). FSTs
containing more than 2.1B nodes are also now possible, however they
cannot be packed.
*/
type Builder struct {
	dedupHash *NodeHash
	fst       *FST
	NO_OUTPUT interface{}

	// simplistic pruning: we prune node (and all following nodes) if
	// less than this number of terms go through it:
	minSuffixCount1 int

	// better pruning: we prune node (and all following nodes) if the
	// prior node has less than this number of terms go through it:
	minSuffixCount2 int

	doShareNonSingletonNodes bool
	shareMaxTailLength       int

	lastInput *util.IntsRef

	// for packing
	doPackFST               bool
	acceptableOverheadRatio float32

	// current frontier
	frontier []*UnCompiledNode

	_freezeTail FreezeTail
}

/* Expert: holds a pending (seen but not yet serialized) arc */
type builderArc struct {
	label           int // really an "unsigned" byte
	Target          Node
	isFinal         bool
	output          interface{}
	nextFinalOutput interface{}
}

/*
NOTE: not many instances of Node or CompiledNode are in memory while
the FST is being built; it's only the current "frontier":
*/
type Node interface {
	isCompiled() bool
}

/* Expert: holds a pending (seen but not yet serialized) Node. */
type UnCompiledNode struct {
	owner      *Builder
	NumArcs    int
	Arcs       []*builderArc
	output     interface{}
	IsFinal    bool
	InputCount int64

	// This node's depth, starting from the automaton root.
	depth int
}

func NewUnCompiledNode(owner *Builder, depth int) *UnCompiledNode {
	return &UnCompiledNode{
		owner:  owner,
		Arcs:   []*builderArc{new(builderArc)},
		output: owner.NO_OUTPUT,
		depth:  depth,
	}
}

func (n *UnCompiledNode) isCompiled() bool { return false }

func (n *UnCompiledNode) Clear() {
	n.NumArcs = 0
	n.IsFinal = false
	n.output = n.owner.NO_OUTPUT
	n.InputCount = 0

	// we don't clear the depth here becaues it never changes
	// for nodes on the frontier (even when reused).
}

func (n *UnCompiledNode) lastOutput(labelToMatch int) interface{} {
	panic("not implementd yet")
}

func (n *UnCompiledNode) addArc(label int, target Node) {
	assert(label >= 0)
	if n.NumArcs != 0 {
		assert2(label > n.Arcs[n.NumArcs-1].label,
			"arc[-1].label=%v new label=%v numArcs=%v",
			n.Arcs[n.NumArcs-1].label, label, n.NumArcs)
	}
	if n.NumArcs == len(n.Arcs) {
		newArcs := make([]*builderArc, util.Oversize(n.NumArcs+1, util.NUM_BYTES_OBJECT_REF))
		copy(newArcs, n.Arcs)
		n.Arcs = newArcs
	}
	arc := n.Arcs[n.NumArcs]
	n.NumArcs++
	arc.label = label
	arc.Target = target
	arc.output = n.owner.NO_OUTPUT
	arc.nextFinalOutput = n.owner.NO_OUTPUT
	arc.isFinal = false
}

/*
Instantiates an FST/FSA builder with all the possible tuning and
construction tweaks. Read parameter documentation carefully.

...
*/
func NewBuilder(inputType InputType, minSuffixCount1, minSuffixCount2 int,
	doShareSuffix, doShareNonSingletonNodes bool, shareMaxTailLength int,
	outputs Outputs, freezeTail FreezeTail, doPackFST bool,
	acceptableOverheadRatio float32, allowArrayArcs bool, bytesPageBits int) *Builder {

	fst := newFST(inputType, outputs, doPackFST, acceptableOverheadRatio, allowArrayArcs, bytesPageBits)
	f := make([]*UnCompiledNode, 10)
	ans := &Builder{
		minSuffixCount1:          minSuffixCount1,
		minSuffixCount2:          minSuffixCount2,
		_freezeTail:              freezeTail,
		doShareNonSingletonNodes: doShareNonSingletonNodes,
		shareMaxTailLength:       shareMaxTailLength,
		doPackFST:                doPackFST,
		acceptableOverheadRatio:  acceptableOverheadRatio,
		fst:       fst,
		NO_OUTPUT: outputs.NoOutput(),
		frontier:  f,
		lastInput: util.NewEmptyIntsRef(),
	}
	if doShareSuffix {
		ans.dedupHash = newNodeHash(fst, fst.bytes.reverseReaderAllowSingle(false))
	}
	for i, _ := range f {
		f[i] = NewUnCompiledNode(ans, i)
	}
	return ans
}

func (b *Builder) freezeTail(prefixLenPlus1 int) error {
	if b._freezeTail != nil {
		// Custom plugin:
		return b._freezeTail(b.frontier, prefixLenPlus1, b.lastInput)
	}
	panic("not implemented yet")
}

/*
It's OK to add the same input twice in a row with different outputs,
as long as outputs impls the merge method. Note that input is fully
consumed after this method is returned (so caller is free to reuse),
but output is not. So if your outputs are changeable (eg
ByteSequenceOutputs or IntSequenceOutputs) then you cannot reuse
across calls.
*/
func (b *Builder) Add(input *util.IntsRef, output interface{}) error {
	assert2(b.lastInput.Length == 0 || !input.CompareTo(b.lastInput),
		"inputs are added out of order, lastInput=%v vs input=%v",
		b.lastInput, input)

	if input.Length == 0 {
		// empty input: only allowed as first input. We have to special
		// case this becaues the packed FST format cannot represent the
		// empty input since 'finalness' is stored on the incoming arc,
		// not on the node
		b.frontier[0].InputCount++
		b.frontier[0].IsFinal = true
		b.fst.setEmptyOutput(output)
		return nil
	}

	// compare shared prefix length
	pos1 := 0
	pos2 := input.Offset
	pos1Stop := b.lastInput.Length
	if input.Length < pos1Stop {
		pos1Stop = input.Length
	}
	for {
		b.frontier[pos1].InputCount++
		if pos1 >= pos1Stop || b.lastInput.Ints[pos1] != input.Ints[pos2] {
			break
		}
		pos1++
		pos2++
	}
	prefixLenPlus1 := pos1 + 1

	if len(b.frontier) < input.Length+1 {
		next := make([]*UnCompiledNode, util.Oversize(input.Length+1, util.NUM_BYTES_OBJECT_REF))
		copy(next, b.frontier)
		for idx := len(b.frontier); idx < len(next); idx++ {
			next[idx] = NewUnCompiledNode(b, idx)
		}
		b.frontier = next
	}

	// minimize/compile states from previous input's orphan'd suffix
	err := b.freezeTail(prefixLenPlus1)
	if err != nil {
		return err
	}

	// init tail states for current input
	for idx := prefixLenPlus1; idx <= input.Length; idx++ {
		b.frontier[idx-1].addArc(input.Ints[input.Offset+idx-1], b.frontier[idx])
		b.frontier[idx].InputCount++
	}

	lastNode := b.frontier[input.Length]
	if b.lastInput.Length != input.Length || prefixLenPlus1 != input.Length+1 {
		lastNode.IsFinal = true
		lastNode.output = b.NO_OUTPUT
	}

	// push conflicting outputs forward, only as far as needed
	for idx := 1; idx < prefixLenPlus1; idx++ {
		// node := b.frontier[idx]
		parentNode := b.frontier[idx-1]

		lastOutput := parentNode.lastOutput(input.Ints[input.Offset+idx-1])

		var commonOutputPrefix interface{}
		// var wordSuffix interface{}

		if lastOutput != b.NO_OUTPUT {
			panic("not implemented yet")
		} else {
			panic("not implemented yet")
		}

		output = b.fst.outputs.Subtract(output, commonOutputPrefix)
	}

	if b.lastInput.Length == input.Length && prefixLenPlus1 == 1+input.Length {
		// same input more than 1 time in a row, mapping to multiple outputs
		panic("not implemented yet")
	} else {
		panic("not implemented yet")
	}

	// save last input
	b.lastInput.CopyInts(input)
	return nil
}

func assert(ok bool) {
	assert2(ok, "assert fail")
}

func assert2(ok bool, msg string, args ...interface{}) {
	if !ok {
		panic(fmt.Sprintf(msg, args...))
	}
}
<|endoftext|>


<commit_before>package stat

import (
	"github.com/satyrius/gonx"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestConstructor(t *testing.T) {
	stat := NewStat("request", "")
	assert.Equal(t, stat.EntriesParsed, 0)
	assert.Equal(t, stat.GroupBy, "request")
}

func TestTiming(t *testing.T) {
	start := time.Now()
	stat := NewStat("request", "")
	assert.WithinDuration(t, start, stat.StartedAt, time.Duration(time.Millisecond),
		"Constructor should setup StartedAt")
	assert.Equal(t, stat.ElapsedTime, 0)
	elapsed := stat.Stop()
	assert.NotEqual(t, stat.ElapsedTime, 0)
	assert.NotEqual(t, stat.ElapsedTime, elapsed)
}

func TestEmptyRegexp(t *testing.T) {
	stat := NewStat("request", "")
	assert.Nil(t, stat.GroupByRegexp)
}

func TestRegexp(t *testing.T) {
	exp := `^\w+\s+(\S+)(?:\?|$)`
	stat := NewStat("request", exp)
	assert.Equal(t, stat.GroupByRegexp.String(), exp)
}

func TestAdd(t *testing.T) {
	stat := NewStat("request", "")
	request := "GET /foo/bar"
	entry := &gonx.Entry{"request": request}

	assert.NoError(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 1)
	counter, ok := stat.Data[request]
	assert.True(t, ok)
	assert.Equal(t, counter, 1)

	assert.NoError(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 2)
	counter, ok = stat.Data[request]
	assert.True(t, ok)
	assert.Equal(t, counter, 2)
}

func TestAddInvalid(t *testing.T) {
	stat := NewStat("request", "")
	entry := &gonx.Entry{"foo": "bar"}
	assert.Error(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 0)
	assert.Equal(t, len(stat.Data), 0)
}

func TestAddLog(t *testing.T) {
	stat := NewStat("request", "")
	assert.Empty(t, stat.Logs)
	file := "/var/log/nginx/access.log"
	stat.AddLog(file)
	assert.Equal(t, stat.Logs, []string{file})
}
<commit_msg>fix timing test<commit_after>package stat

import (
	"github.com/satyrius/gonx"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

func TestConstructor(t *testing.T) {
	stat := NewStat("request", "")
	assert.Equal(t, stat.EntriesParsed, 0)
	assert.Equal(t, stat.GroupBy, "request")
}

func TestTiming(t *testing.T) {
	start := time.Now()
	stat := NewStat("request", "")
	assert.WithinDuration(t, start, stat.StartedAt, time.Duration(time.Millisecond),
		"Constructor should setup StartedAt")
	assert.Equal(t, stat.ElapsedTime, 0)
	elapsed := stat.Stop()
	assert.NotEqual(t, stat.ElapsedTime, 0)
	assert.Equal(t, stat.ElapsedTime, elapsed)
}

func TestEmptyRegexp(t *testing.T) {
	stat := NewStat("request", "")
	assert.Nil(t, stat.GroupByRegexp)
}

func TestRegexp(t *testing.T) {
	exp := `^\w+\s+(\S+)(?:\?|$)`
	stat := NewStat("request", exp)
	assert.Equal(t, stat.GroupByRegexp.String(), exp)
}

func TestAdd(t *testing.T) {
	stat := NewStat("request", "")
	request := "GET /foo/bar"
	entry := &gonx.Entry{"request": request}

	assert.NoError(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 1)
	counter, ok := stat.Data[request]
	assert.True(t, ok)
	assert.Equal(t, counter, 1)

	assert.NoError(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 2)
	counter, ok = stat.Data[request]
	assert.True(t, ok)
	assert.Equal(t, counter, 2)
}

func TestAddInvalid(t *testing.T) {
	stat := NewStat("request", "")
	entry := &gonx.Entry{"foo": "bar"}
	assert.Error(t, stat.Add(entry))
	assert.Equal(t, stat.EntriesParsed, 0)
	assert.Equal(t, len(stat.Data), 0)
}

func TestAddLog(t *testing.T) {
	stat := NewStat("request", "")
	assert.Empty(t, stat.Logs)
	file := "/var/log/nginx/access.log"
	stat.AddLog(file)
	assert.Equal(t, stat.Logs, []string{file})
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Christian Pointner <equinox@spreadspace.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of whawty.groups nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

package store

import (
	"fmt"
	"os"
	"path/filepath"
)

// fileExists returns whether the given file or directory exists or not
// this is from: stackoverflow.com/questions/10510691
func fileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

// UserFile is the representation of a single user file inside the store.
// Use NewUserFile to create it.
type UserFile struct {
	store *Dir
	user  string
}

// NewUserFile creates a new whawty.groups UserFile for user inside basedir.
func NewUserFile(store *Dir, user string) (u *UserFile) {
	u = &UserFile{}
	u.store = store
	u.user = user
	return
}

func (u *UserFile) getFilename() string {
	return filepath.Join(u.store.basedir, u.user)
}

// Add creates the user file. It is an error if the user already exists.
func (u *UserFile) Add() (err error) {
	var exists bool
	if exists, err = u.Exists(); err != nil {
		return
	} else if exists {
		return fmt.Errorf("whawty.groups.store: user '%s' already exists", u.user)
	}
	var file *os.File
	file, err = os.Create(u.getFilename())
	defer file.Close()
	// TODO: write inital data to file ?!?
	return nil
}

// Remove deletes file file.
func (u *UserFile) Remove() {
	os.Remove(u.getFilename())
	return
}

// Exists checks if user exists.
func (u *UserFile) Exists() (exists bool, err error) {
	return fileExists(u.getFilename())
}
<commit_msg>added changed date/time to user file<commit_after>//
// Copyright (c) 2016 Christian Pointner <equinox@spreadspace.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of whawty.groups nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

package store

import (
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/pelletier/go-toml"
)

// fileExists returns whether the given file or directory exists or not
// this is from: stackoverflow.com/questions/10510691
func fileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

// UserFile is the representation of a single user file inside the store.
// Use NewUserFile to create it.
type UserFile struct {
	store *Dir
	user  string
}

// NewUserFile creates a new whawty.groups UserFile for user inside basedir.
func NewUserFile(store *Dir, user string) (u *UserFile) {
	u = &UserFile{}
	u.store = store
	u.user = user
	return
}

func (u *UserFile) getFilename() string {
	return filepath.Join(u.store.basedir, u.user)
}

// Add creates the user file. It is an error if the user already exists.
func (u *UserFile) Add() (err error) {
	var exists bool
	if exists, err = u.Exists(); err != nil {
		return
	} else if exists {
		return fmt.Errorf("whawty.groups.store: user '%s' already exists", u.user)
	}
	var file *os.File
	file, err = os.Create(u.getFilename())
	defer file.Close()

	m := make(map[string]interface{})
	m["changed"] = time.Now()
	t := toml.TreeFromMap(m)
	file.WriteString(t.ToString())
	return nil
}

// Remove deletes file file.
func (u *UserFile) Remove() {
	os.Remove(u.getFilename())
	return
}

// Exists checks if user exists.
func (u *UserFile) Exists() (exists bool, err error) {
	return fileExists(u.getFilename())
}
<|endoftext|>