<commit_before>package gko

import (
	"cloud.google.com/go/bigquery"

	"golang.org/x/net/context"

	"google.golang.org/api/option"
)

var (
	_ BigQueryFactory = (*bigQueryFactoryImpl)(nil)
	_ BigQuery        = (*bigQueryClient)(nil)
)

var bigqueryFactory BigQueryFactory

// GetBigQueryFactory return bigquery factory.
func GetBigQueryFactory() BigQueryFactory {
	if bigqueryFactory == nil {
		bigqueryFactory = &bigQueryFactoryImpl{}
	}
	return bigqueryFactory
}

// BigQueryFactory is bigquery factory interface.
type BigQueryFactory interface {
	New(context.Context) (BigQuery, error)
}

// gaeBigQueryFactoryImpl is implementation of bigquery factory.
type bigQueryFactoryImpl struct{}

// New return bigquery client.
func (b *bigQueryFactoryImpl) New(ctx context.Context) (BigQuery, error) {
	return newBigQueryClient(ctx)
}

// BigQuery is bigquery interface along with reader and writer.
type BigQuery interface {
	BigQueryReader
	BigQueryWriter
}

// BigQueryReader is bigquery reader interface.
type BigQueryReader interface {
	Query(string, bool) (*bigquery.Job, error)
	GetQueryResult(*bigquery.Job) (*bigquery.RowIterator, error)
}

// BigQueryWriter is bigquery writer interface.
type BigQueryWriter interface {
	CreateTable(dataset, table string) error
	DeleteTable(dataset, table string) error
	UploadRow(dataset, table, suffix string, src interface{}) error
}

// bigQueryClient is bigquery client.
type bigQueryClient struct {
	ctx    context.Context
	client *bigquery.Client
}

// newBigQueryClient return new bigquery client.
func newBigQueryClient(ctx context.Context) (*bigQueryClient, error) {
	t, projectID, err := getDefaultTokenSource(ctx, bigquery.Scope)
	if err != nil {
		return nil, err
	}

	client, err := bigquery.NewClient(ctx, projectID, option.WithTokenSource(t))
	if err != nil {
		return nil, err
	}

	return &bigQueryClient{ctx, client}, nil
}

// Query run bigquery query, then return job.
func (b *bigQueryClient) Query(q string, useStdSQL bool) (*bigquery.Job, error) {
	query := b.client.Query(q)
	query.UseStandardSQL = useStdSQL
	return query.Run(b.ctx)
}

func (b *bigQueryClient) GetQueryResult(job *bigquery.Job) (*bigquery.RowIterator, error) {
	stat, err := job.Wait(b.ctx)
	if err != nil {
		return nil, err
	}

	if stat.Err() != nil {
		return nil, stat.Err()
	}

	return job.Read(b.ctx)
}

// CreateTable create table in dataset bigquery client have.
//
// This method always create table with standard sql option.
func (b *bigQueryClient) CreateTable(dataset, table string) error {
	return b.client.Dataset(dataset).Table(table).Create(b.ctx, bigquery.UseStandardSQL())
}

// DeleteTable delete table in dataset bigquery client have.
func (b *bigQueryClient) DeleteTable(dataset, table string) error {
	return b.client.Dataset(dataset).Table(table).Delete(b.ctx)
}

// UploadRow upload one or more row.
func (b *bigQueryClient) UploadRow(dataset, table, suffix string, src interface{}) error {
	t := b.client.Dataset(dataset).Table(table)
	// check src is valid
	if _, err := bigquery.InferSchema(src); err != nil {
		return err
	}

	upl := t.Uploader()
	upl.TableTemplateSuffix = suffix
	return upl.Put(b.ctx, src)
}
<commit_msg>update bigquery client to add some operation<commit_after>package gko

import (
	"errors"

	"cloud.google.com/go/bigquery"

	"golang.org/x/net/context"

	"fmt"

	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
)

var (
	_ BigQueryFactory = (*bigQueryFactoryImpl)(nil)
	_ BigQuery        = (*bigQueryClient)(nil)
)

var (
	errTableAlreadyExist   = errors.New("table is already exist")
	errDatasetAlreadyExist = errors.New("dataset is already exist")
)

var bigqueryFactory BigQueryFactory

// GetBigQueryFactory return bigquery factory.
func GetBigQueryFactory() BigQueryFactory {
	if bigqueryFactory == nil {
		bigqueryFactory = &bigQueryFactoryImpl{}
	}
	return bigqueryFactory
}

// BigQueryFactory is bigquery factory interface.
type BigQueryFactory interface {
	New(context.Context) (BigQuery, error)
}

// gaeBigQueryFactoryImpl is implementation of bigquery factory.
type bigQueryFactoryImpl struct{}

// New return bigquery client.
func (b *bigQueryFactoryImpl) New(ctx context.Context) (BigQuery, error) {
	return newBigQueryClient(ctx)
}

// BigQuery is bigquery interface along with reader and writer.
type BigQuery interface {
	BigQueryReader
	BigQueryWriter
}

// BigQueryReader is bigquery reader interface.
type BigQueryReader interface {
	Query(string, bool) (*bigquery.Job, error)
	GetQueryResult(*bigquery.Job) (*bigquery.RowIterator, error)
}

// BigQueryWriter is bigquery writer interface.
type BigQueryWriter interface {
	CreateTable(dataset, table string, useStdSQL bool) error
	DeleteTable(dataset, table string) error
	UploadRow(dataset, table, suffix string, src interface{}) error
}

// bigQueryClient is bigquery client.
type bigQueryClient struct {
	ctx    context.Context
	client *bigquery.Client
}

// newBigQueryClient return new bigquery client.
func newBigQueryClient(ctx context.Context) (*bigQueryClient, error) {
	t, projectID, err := getDefaultTokenSource(ctx, bigquery.Scope)
	if err != nil {
		return nil, err
	}

	client, err := bigquery.NewClient(ctx, projectID, option.WithTokenSource(t))
	if err != nil {
		return nil, err
	}

	return &bigQueryClient{ctx, client}, nil
}

// Query run bigquery query, then return job.
func (b *bigQueryClient) Query(q string, useStdSQL bool) (*bigquery.Job, error) {
	query := b.client.Query(q)
	query.UseStandardSQL = useStdSQL
	return query.Run(b.ctx)
}

func (b *bigQueryClient) GetQueryResult(job *bigquery.Job) (*bigquery.RowIterator, error) {
	stat, err := job.Wait(b.ctx)
	if err != nil {
		return nil, err
	}

	if stat.Err() != nil {
		return nil, stat.Err()
	}

	return job.Read(b.ctx)
}

// CreateDataset creates new bigquery dataset.
//
// If dataset is already exist, return error.
func (b *bigQueryClient) CreateDataset(dataset string) error {
	if err := b.checkDatasetExist(dataset); err != nil {
		return err
	}
	return b.client.Dataset(dataset).Create(b.ctx)
}

func (b *bigQueryClient) DeleteDataset(dataset string) error {
	if err := b.checkDatasetExist(dataset); err != errDatasetAlreadyExist {
		if err == nil {
			return fmt.Errorf("%s is not already exist", dataset)
		}
		return err
	}
	return b.client.Dataset(dataset).Delete(b.ctx)
}

// CreateTable create table in dataset bigquery client have.
//
// This method always create table with standard sql option.
// If table is already exist in dataset, return error.
func (b *bigQueryClient) CreateTable(dataset, table string, useStdSQL bool) error {
	if err := b.checkTableExist(dataset, table); err != nil {
		return err
	}
	var opts []bigquery.CreateTableOption
	if useStdSQL {
		opts = append(opts, bigquery.UseStandardSQL())
	}
	return b.client.Dataset(dataset).Table(table).Create(b.ctx, opts...)
}

// DeleteTable delete table in dataset bigquery client have.
func (b *bigQueryClient) DeleteTable(dataset, table string) error {
	if err := b.checkTableExist(dataset, table); err != errTableAlreadyExist {
		if err == nil {
			return fmt.Errorf("%s:%s is not already exist", dataset, table)
		}
		return err
	}
	return b.client.Dataset(dataset).Table(table).Delete(b.ctx)
}

// UploadRow upload one or more row.
func (b *bigQueryClient) UploadRow(dataset, table, suffix string, src interface{}) error {
	t := b.client.Dataset(dataset).Table(table)
	upl := t.Uploader()
	upl.TableTemplateSuffix = suffix
	return upl.Put(b.ctx, src)
}

// checkTableExist checks bigquery table is already exist.
//
// If table is already exist, return error.
func (b *bigQueryClient) checkTableExist(dataset, table string) error {
	_, err := b.client.Dataset(dataset).Table(table).Metadata(b.ctx)
	if err != nil {
		// if status code is not 404, return error because of exist
		if gapierr, ok := err.(*googleapi.Error); ok && gapierr.Code == 404 {
			return nil
		}
		return err
	}
	return errTableAlreadyExist
}

// checkDatasetExist checks bigquery dataset is already exist.
//
// If dataset is already exist, return error.
func (b *bigQueryClient) checkDatasetExist(dataset string) error {
	_, err := b.client.Dataset(dataset).Metadata(b.ctx)
	if err != nil {
		// if status code is not 404, return error because of exist
		if gapierr, ok := err.(*googleapi.Error); ok && gapierr.Code == 404 {
			return nil
		}
		return err
	}
	return errDatasetAlreadyExist
}
<|endoftext|>


<commit_before>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	Global Logger
)

func init() {
	// auto load config from default position
	Global = NewDefaultLogger(DEBUG)
	file, _ := exec.LookPath(os.Args[0])
	dir := filepath.Dir(file)
	if _, err := os.Stat("log4go.xml"); !os.IsNotExist(err) {
		Global.LoadConfiguration("log4go.xml")
	} else if _, err := os.Stat(filepath.Join(dir, "/log4go.xml")); !os.IsNotExist(err) {
		Global.LoadConfiguration(filepath.Join(dir, "log4go.xml"))
	} else if _, err := os.Stat(filepath.Join(dir, "/conf/log4go.xml")); !os.IsNotExist(err) {
		Global.LoadConfiguration(filepath.Join(dir, "/conf/log4go.xml"))
	} else {
		fmt.Fprintf(os.Stdout, "log4go config not found, exec dir is: %s, u need to load it by yourself.\n", dir)
	}
}

// Wrapper for (*Logger).LoadConfiguration
func LoadConfiguration(filename string) {
	Global.LoadConfiguration(filename)
}

// Wrapper for (*Logger).AddFilter
func AddFilter(name string, lvl Level, writer LogWriter) {
	Global.AddFilter(name, lvl, writer)
}

// Wrapper for (*Logger).Close (closes and removes all logwriters)
func Close() {
	Global.Close()
}

func Crash(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(CRITICAL, strings.Repeat(" %v", len(args))[1:], args...)
	}
	panic(args)
}

// Logs the given message and crashes the program
func Crashf(format string, args ...interface{}) {
	Global.intLogf(CRITICAL, format, args...)
	Global.Close() // so that hopefully the messages get logged
	panic(fmt.Sprintf(format, args...))
}

// Compatibility with `log`
func Exit(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
	}
	Global.Close() // so that hopefully the messages get logged
	os.Exit(0)
}

// Compatibility with `log`
func Exitf(format string, args ...interface{}) {
	Global.intLogf(ERROR, format, args...)
	Global.Close() // so that hopefully the messages get logged
	os.Exit(0)
}

// Compatibility with `log`
func Stderr(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
	}
}

// Compatibility with `log`
func Stderrf(format string, args ...interface{}) {
	Global.intLogf(ERROR, format, args...)
}

// Compatibility with `log`
func Stdout(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(INFO, strings.Repeat(" %v", len(args))[1:], args...)
	}
}

// Compatibility with `log`
func Stdoutf(format string, args ...interface{}) {
	Global.intLogf(INFO, format, args...)
}

// Send a log message manually
// Wrapper for (*Logger).Log
func Log(lvl Level, source, message string) {
	Global.Log(lvl, source, message)
}

// Send a formatted log message easily
// Wrapper for (*Logger).Logf
func Logf(lvl Level, format string, args ...interface{}) {
	Global.intLogf(lvl, format, args...)
}

// Send a closure log message
// Wrapper for (*Logger).Logc
func Logc(lvl Level, closure func() string) {
	Global.intLogc(lvl, closure)
}

// Utility for finest log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Finest
func Finest(arg0 interface{}, args ...interface{}) {
	const (
		lvl = FINEST
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for fine log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Fine
func Fine(arg0 interface{}, args ...interface{}) {
	const (
		lvl = FINE
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for debug log messages
// When given a string as the first argument, this behaves like Logf but with the DEBUG log level (e.g. the first argument is interpreted as a format for the latter arguments)
// When given a closure of type func()string, this logs the string returned by the closure iff it will be logged.  The closure runs at most one time.
// When given anything else, the log message will be each of the arguments formatted with %v and separated by spaces (ala Sprint).
// Wrapper for (*Logger).Debug
func Debug(arg0 interface{}, args ...interface{}) {
	const (
		lvl = DEBUG
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for trace log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Trace
func Trace(arg0 interface{}, args ...interface{}) {
	const (
		lvl = TRACE
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for info log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Info
func Info(arg0 interface{}, args ...interface{}) {
	const (
		lvl = INFO
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for Access log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Info
func Access(arg0 interface{}, args ...interface{}) {
	const (
		lvl = ACCESS
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for warn log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Warn
func Warn(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = WARNING
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s", str)
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

// Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Error
func Error(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = ERROR
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s", str)
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

// Utility for critical log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Critical. This method will log the call stack
func Critical(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = CRITICAL
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		msg := fmt.Sprintf("%s\n%s", fmt.Sprintf(first, args...), CallStack(3))
		Global.intLogf(lvl, msg)
		//Global.intLogf(lvl, "%s", CallStack(3))
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s\n%s", str, CallStack(3))
		//Global.intLogf(lvl, "%s", CallStack(3))
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		msg := fmt.Sprintf("%s\n%s", fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...), CallStack(3))
		Global.intLogf(lvl, msg)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

func Recover(arg0 interface{}, args ...interface{}) {
	if err := recover(); err != nil {
		Critical(arg0, args...)
	} else {
		Error(arg0, args...)
	}
}<commit_msg>refactor Recover(), now you can pass an func sign as `func(err interface{}) string`. This change makes you can hold the error which recover by log4go.Recover() method<commit_after>// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.

package log4go

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	Global Logger
)

func init() {
	// auto load config from default position
	Global = NewDefaultLogger(DEBUG)
	file, _ := exec.LookPath(os.Args[0])
	dir := filepath.Dir(file)
	if _, err := os.Stat("log4go.xml"); !os.IsNotExist(err) {
		Global.LoadConfiguration("log4go.xml")
	} else if _, err := os.Stat(filepath.Join(dir, "/log4go.xml")); !os.IsNotExist(err) {
		Global.LoadConfiguration(filepath.Join(dir, "log4go.xml"))
	} else if _, err := os.Stat(filepath.Join(dir, "/conf/log4go.xml")); !os.IsNotExist(err) {
		Global.LoadConfiguration(filepath.Join(dir, "/conf/log4go.xml"))
	} else {
		fmt.Fprintf(os.Stdout, "log4go config not found, exec dir is: %s, u need to load it by yourself.\n", dir)
	}
}

// Wrapper for (*Logger).LoadConfiguration
func LoadConfiguration(filename string) {
	Global.LoadConfiguration(filename)
}

// Wrapper for (*Logger).AddFilter
func AddFilter(name string, lvl Level, writer LogWriter) {
	Global.AddFilter(name, lvl, writer)
}

// Wrapper for (*Logger).Close (closes and removes all logwriters)
func Close() {
	Global.Close()
}

func Crash(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(CRITICAL, strings.Repeat(" %v", len(args))[1:], args...)
	}
	panic(args)
}

// Logs the given message and crashes the program
func Crashf(format string, args ...interface{}) {
	Global.intLogf(CRITICAL, format, args...)
	Global.Close() // so that hopefully the messages get logged
	panic(fmt.Sprintf(format, args...))
}

// Compatibility with `log`
func Exit(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
	}
	Global.Close() // so that hopefully the messages get logged
	os.Exit(0)
}

// Compatibility with `log`
func Exitf(format string, args ...interface{}) {
	Global.intLogf(ERROR, format, args...)
	Global.Close() // so that hopefully the messages get logged
	os.Exit(0)
}

// Compatibility with `log`
func Stderr(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
	}
}

// Compatibility with `log`
func Stderrf(format string, args ...interface{}) {
	Global.intLogf(ERROR, format, args...)
}

// Compatibility with `log`
func Stdout(args ...interface{}) {
	if len(args) > 0 {
		Global.intLogf(INFO, strings.Repeat(" %v", len(args))[1:], args...)
	}
}

// Compatibility with `log`
func Stdoutf(format string, args ...interface{}) {
	Global.intLogf(INFO, format, args...)
}

// Send a log message manually
// Wrapper for (*Logger).Log
func Log(lvl Level, source, message string) {
	Global.Log(lvl, source, message)
}

// Send a formatted log message easily
// Wrapper for (*Logger).Logf
func Logf(lvl Level, format string, args ...interface{}) {
	Global.intLogf(lvl, format, args...)
}

// Send a closure log message
// Wrapper for (*Logger).Logc
func Logc(lvl Level, closure func() string) {
	Global.intLogc(lvl, closure)
}

// Utility for finest log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Finest
func Finest(arg0 interface{}, args ...interface{}) {
	const (
		lvl = FINEST
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for fine log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Fine
func Fine(arg0 interface{}, args ...interface{}) {
	const (
		lvl = FINE
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for debug log messages
// When given a string as the first argument, this behaves like Logf but with the DEBUG log level (e.g. the first argument is interpreted as a format for the latter arguments)
// When given a closure of type func()string, this logs the string returned by the closure iff it will be logged.  The closure runs at most one time.
// When given anything else, the log message will be each of the arguments formatted with %v and separated by spaces (ala Sprint).
// Wrapper for (*Logger).Debug
func Debug(arg0 interface{}, args ...interface{}) {
	const (
		lvl = DEBUG
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for trace log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Trace
func Trace(arg0 interface{}, args ...interface{}) {
	const (
		lvl = TRACE
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for info log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Info
func Info(arg0 interface{}, args ...interface{}) {
	const (
		lvl = INFO
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for Access log messages (see Debug() for parameter explanation)
// Wrapper for (*Logger).Info
func Access(arg0 interface{}, args ...interface{}) {
	const (
		lvl = ACCESS
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
	case func() string:
		// Log the closure (no other arguments used)
		Global.intLogc(lvl, first)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
	}
}

// Utility for warn log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Warn
func Warn(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = WARNING
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s", str)
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

// Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Error
func Error(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = ERROR
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		Global.intLogf(lvl, first, args...)
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s", str)
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

// Utility for critical log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
// These functions will execute a closure exactly once, to build the error message for the return
// Wrapper for (*Logger).Critical. This method will log the call stack
func Critical(arg0 interface{}, args ...interface{}) error {
	const (
		lvl = CRITICAL
	)
	switch first := arg0.(type) {
	case string:
		// Use the string as a format string
		msg := fmt.Sprintf("%s\n%s", fmt.Sprintf(first, args...), CallStack(3))
		Global.intLogf(lvl, msg)
		//Global.intLogf(lvl, "%s", CallStack(3))
		return errors.New(fmt.Sprintf(first, args...))
	case func() string:
		// Log the closure (no other arguments used)
		str := first()
		Global.intLogf(lvl, "%s\n%s", str, CallStack(3))
		//Global.intLogf(lvl, "%s", CallStack(3))
		return errors.New(str)
	case func(interface{}) string:
		str := first(args[0])
		Global.intLogf(lvl, "%s\n%s", str, CallStack(3))
		return errors.New(str)
	default:
		// Build a format string so that it will be similar to Sprint
		msg := fmt.Sprintf("%s\n%s", fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...), CallStack(3))
		Global.intLogf(lvl, msg)
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
	}
	return nil
}

// Recover used to log the stack when panic occur.
// usage: defer log4go.Recover("this is a msg: %v", "msg")
// or:
//      defer log4go.Recover(func(err interface{}) string {
//          // ... your code here, return the error message
//          return fmt.Sprintf("recover..v1=%v;v2=%v;err=%v", 1, 2, err)
//      })
func Recover(arg0 interface{}, args ...interface{}) {
	if err := recover(); err != nil {
		switch arg0.(type) {
		case func(interface{}) string:
			// the recovered err will pass to this func
			Critical(arg0, append([]interface{}{err}, args)...)
		default:
			Critical(arg0, args...)
		}
	} else {
		Error(arg0, args...)
	}
}
<|endoftext|>


<commit_before>package sudoku

import (
	"fmt"
	"log"
	"strconv"
)

type forcingChainsTechnique struct {
	*basicSolveTechnique
}

func (self *forcingChainsTechnique) HumanLikelihood() float64 {
	//TODO: figure out what the baseDifficulty should be
	return self.difficultyHelper(200.0)
}

func (self *forcingChainsTechnique) Description(step *SolveStep) string {
	//TODO: implement this
	return "ERROR: NOT IMPLEMENTED"
}

func (self *forcingChainsTechnique) Find(grid *Grid, results chan *SolveStep, done chan bool) {
	//TODO: test that this will find multiple if they exist.
	//TODO: Implement this.

	getter := grid.queue().DefaultGetter()

	_MAX_IMPLICATION_STEPS := 6

	for {

		//Check if it's time to stop.
		select {
		case <-done:
			return
		default:
		}

		candidate := getter.GetSmallerThan(3)

		if candidate == nil {
			break
		}

		candidateCell := candidate.(*Cell)

		if len(candidateCell.Possibilities()) != 2 {
			//We found one with 1 possibility, which isn't interesting for us--nakedSingle should do that one.
			continue
		}

		firstPossibilityNum := candidateCell.Possibilities()[0]
		secondPossibilityNum := candidateCell.Possibilities()[1]

		firstGrid := grid.Copy()
		secondGrid := grid.Copy()

		//Check that the neighbor isn't just already having a single possibility, because then this technique is overkill.

		firstAccumulator := makeChainSeacherAccumulator(_MAX_IMPLICATION_STEPS)
		secondAccumulator := makeChainSeacherAccumulator(_MAX_IMPLICATION_STEPS)

		chainSearcher(_MAX_IMPLICATION_STEPS,
			candidateCell.InGrid(firstGrid),
			firstPossibilityNum,
			firstAccumulator)

		chainSearcher(_MAX_IMPLICATION_STEPS,
			candidateCell.InGrid(secondGrid),
			secondPossibilityNum,
			secondAccumulator)

		//TODO:Check if the sets overlap.

		log.Println(firstAccumulator)
		log.Println(secondAccumulator)

		/*
			//Check pairwise through each of the result sets for each side and see if any overlap in an interestin way

			for i, theSet := range firstAffectedCellSets {
				theCellMapping := firstAffectedCellNums[i]
				for j, theSecondSet := range secondAffectedCellSets {
					theSecondCellMapping := secondAffectedCellNums[j]

					intersection := theSet.intersection(theSecondSet)
					if len(intersection) > 0 {
						//Okay, a cell overlapped... did they both set the same number?
						//TODO: should we look at all items that overlap if it's greater than 1?

						cell := intersection.toSlice()[0]

						if theCellMapping[cell] == theSecondCellMapping[cell] {
							//Booyah, found a step.

							step := &SolveStep{self,
								CellSlice{cell},
								IntSlice{theCellMapping[cell]},
								CellSlice{candidateCell},
								candidateCell.Possibilities(),
							}

							if step.IsUseful(grid) {
								select {
								case results <- step:
								case <-done:
									return
								}
							}
						}
					}

				}
			}
		*/

	}
}

type chainSearcherGenerationDetails struct {
	affectedCells cellSet
	filledNumbers map[*Cell]int
}

func (c chainSearcherGenerationDetails) String() string {
	result := "Begin map\n"
	for cell, num := range c.filledNumbers {
		result += "\t" + cell.String() + " : " + strconv.Itoa(num) + "\n"
	}
	result += "End map\n"
	return result
}

type chainSearcherAccumulator []*chainSearcherGenerationDetails

func (c chainSearcherAccumulator) String() string {
	result := "Accumulator[\n"
	for _, rec := range c {
		result += fmt.Sprintf("%s\n", rec)
	}
	result += "]\n"
	return result
}

func makeChainSeacherAccumulator(size int) chainSearcherAccumulator {
	result := make(chainSearcherAccumulator, size)
	for i := 0; i < size; i++ {
		result[i] = &chainSearcherGenerationDetails{
			affectedCells: make(cellSet),
			filledNumbers: make(map[*Cell]int),
		}
	}
	return result
}

func chainSearcher(i int, cell *Cell, numToApply int, accumulator chainSearcherAccumulator) {
	if i <= 0 || cell == nil {
		//Base case
		return
	}

	if i-1 >= len(accumulator) {
		panic("The accumulator provided was not big enough for the i provided.")
	}

	generationDetails := accumulator[i-1]

	//Find the nextCells that WILL have their numbers forced by the cell we're thinking of fillint.
	cellsToVisit := cell.Neighbors().FilterByPossible(numToApply).FilterByNumPossibilities(2)

	//Now that we know which cells will be affected and what their next number will be,
	//set the number in the given cell and then recurse downward down each branch.
	cell.SetNumber(numToApply)

	generationDetails.affectedCells[cell] = true
	generationDetails.filledNumbers[cell] = numToApply

	for _, cellToVisit := range cellsToVisit {

		possibilities := cellToVisit.Possibilities()

		if len(possibilities) != 1 {
			panic("Expected the cell to have one possibility")
		}

		forcedNum := possibilities[0]

		//Each branch modifies the grid, so create a new copy
		newGrid := cellToVisit.grid.Copy()
		cellToVisit = cellToVisit.InGrid(newGrid)

		//Recurse downward
		chainSearcher(i-1, cellToVisit, forcedNum, accumulator)

	}

}
<commit_msg>TESTS FAIL. Only print out details for the one interesting cell in the test set for debugging purposes.<commit_after>package sudoku

import (
	"fmt"
	"log"
	"strconv"
)

type forcingChainsTechnique struct {
	*basicSolveTechnique
}

func (self *forcingChainsTechnique) HumanLikelihood() float64 {
	//TODO: figure out what the baseDifficulty should be
	return self.difficultyHelper(200.0)
}

func (self *forcingChainsTechnique) Description(step *SolveStep) string {
	//TODO: implement this
	return "ERROR: NOT IMPLEMENTED"
}

func (self *forcingChainsTechnique) Find(grid *Grid, results chan *SolveStep, done chan bool) {
	//TODO: test that this will find multiple if they exist.
	//TODO: Implement this.

	getter := grid.queue().DefaultGetter()

	_MAX_IMPLICATION_STEPS := 6

	for {

		//Check if it's time to stop.
		select {
		case <-done:
			return
		default:
		}

		candidate := getter.GetSmallerThan(3)

		if candidate == nil {
			break
		}

		candidateCell := candidate.(*Cell)

		if len(candidateCell.Possibilities()) != 2 {
			//We found one with 1 possibility, which isn't interesting for us--nakedSingle should do that one.
			continue
		}

		firstPossibilityNum := candidateCell.Possibilities()[0]
		secondPossibilityNum := candidateCell.Possibilities()[1]

		firstGrid := grid.Copy()
		secondGrid := grid.Copy()

		//Check that the neighbor isn't just already having a single possibility, because then this technique is overkill.

		firstAccumulator := makeChainSeacherAccumulator(_MAX_IMPLICATION_STEPS)
		secondAccumulator := makeChainSeacherAccumulator(_MAX_IMPLICATION_STEPS)

		chainSearcher(_MAX_IMPLICATION_STEPS,
			candidateCell.InGrid(firstGrid),
			firstPossibilityNum,
			firstAccumulator)

		chainSearcher(_MAX_IMPLICATION_STEPS,
			candidateCell.InGrid(secondGrid),
			secondPossibilityNum,
			secondAccumulator)

		//TODO:Check if the sets overlap.

		//For these debugging purposes, only print out the candidateCell we know to be interesting in the test case.
		if candidateCell.Row() == 1 && candidateCell.Col() == 0 {
			log.Println(firstAccumulator)
			log.Println(secondAccumulator)
		}

		/*
			//Check pairwise through each of the result sets for each side and see if any overlap in an interestin way

			for i, theSet := range firstAffectedCellSets {
				theCellMapping := firstAffectedCellNums[i]
				for j, theSecondSet := range secondAffectedCellSets {
					theSecondCellMapping := secondAffectedCellNums[j]

					intersection := theSet.intersection(theSecondSet)
					if len(intersection) > 0 {
						//Okay, a cell overlapped... did they both set the same number?
						//TODO: should we look at all items that overlap if it's greater than 1?

						cell := intersection.toSlice()[0]

						if theCellMapping[cell] == theSecondCellMapping[cell] {
							//Booyah, found a step.

							step := &SolveStep{self,
								CellSlice{cell},
								IntSlice{theCellMapping[cell]},
								CellSlice{candidateCell},
								candidateCell.Possibilities(),
							}

							if step.IsUseful(grid) {
								select {
								case results <- step:
								case <-done:
									return
								}
							}
						}
					}

				}
			}
		*/

	}
}

type chainSearcherGenerationDetails struct {
	affectedCells cellSet
	filledNumbers map[*Cell]int
}

func (c chainSearcherGenerationDetails) String() string {
	result := "Begin map\n"
	for cell, num := range c.filledNumbers {
		result += "\t" + cell.String() + " : " + strconv.Itoa(num) + "\n"
	}
	result += "End map\n"
	return result
}

type chainSearcherAccumulator []*chainSearcherGenerationDetails

func (c chainSearcherAccumulator) String() string {
	result := "Accumulator[\n"
	for _, rec := range c {
		result += fmt.Sprintf("%s\n", rec)
	}
	result += "]\n"
	return result
}

func makeChainSeacherAccumulator(size int) chainSearcherAccumulator {
	result := make(chainSearcherAccumulator, size)
	for i := 0; i < size; i++ {
		result[i] = &chainSearcherGenerationDetails{
			affectedCells: make(cellSet),
			filledNumbers: make(map[*Cell]int),
		}
	}
	return result
}

func chainSearcher(i int, cell *Cell, numToApply int, accumulator chainSearcherAccumulator) {
	if i <= 0 || cell == nil {
		//Base case
		return
	}

	if i-1 >= len(accumulator) {
		panic("The accumulator provided was not big enough for the i provided.")
	}

	generationDetails := accumulator[i-1]

	//Find the nextCells that WILL have their numbers forced by the cell we're thinking of fillint.
	cellsToVisit := cell.Neighbors().FilterByPossible(numToApply).FilterByNumPossibilities(2)

	//Now that we know which cells will be affected and what their next number will be,
	//set the number in the given cell and then recurse downward down each branch.
	cell.SetNumber(numToApply)

	generationDetails.affectedCells[cell] = true
	generationDetails.filledNumbers[cell] = numToApply

	for _, cellToVisit := range cellsToVisit {

		possibilities := cellToVisit.Possibilities()

		if len(possibilities) != 1 {
			panic("Expected the cell to have one possibility")
		}

		forcedNum := possibilities[0]

		//Each branch modifies the grid, so create a new copy
		newGrid := cellToVisit.grid.Copy()
		cellToVisit = cellToVisit.InGrid(newGrid)

		//Recurse downward
		chainSearcher(i-1, cellToVisit, forcedNum, accumulator)

	}

}
<|endoftext|>


<commit_before>package relay

import (
	"errors"
	"net/http"
	"sync"

	"github.com/gorilla/websocket"
	"github.com/influx6/flux"
)

// ErrClosed is returned to indicated an already closed struct
var ErrClosed = errors.New("Already Closed")

// ErrInvalidType is returned when the type required is not met
var ErrInvalidType = errors.New("Unsupported Type")

// Websocket provides a cover for websocket connection
type Websocket struct {
	*websocket.Conn
	Req    *http.Request
	Res    http.ResponseWriter
	Params Collector
}

// WebsocketMessage provides small abstraction for processing a message
type WebsocketMessage struct {
	codec   SocketCodec
	payload []byte
	mtype   int
	Socket  *Websocket
	Worker  *SocketWorker
}

// Message returns the data of the socket
func (m *WebsocketMessage) Message() (interface{}, error) {
	return m.codec.Decode(m.mtype, m.payload)
}

// MessageType returns the type of the message
func (m *WebsocketMessage) MessageType() int {
	return m.mtype
}

// Write encodes and writes the given data returns the (int,error) of the total writes while
func (m *WebsocketMessage) Write(bw []byte) (int, error) {
	return m.codec.Encode(m.Socket, m.mtype, bw)
}

// SocketWorker provides a workpool for socket connections
type SocketWorker struct {
	codec   SocketCodec
	data    chan interface{}
	mesgs   chan *WebsocketMessage
	closer  chan bool
	queue   *flux.Queue
	wo      *Websocket
	ro, rd  sync.Mutex
	closed  bool
	writing bool
}

// NewSocketWorker returns a new socketworker instance
func NewSocketWorker(wo *Websocket, codec SocketCodec) *SocketWorker {
	data := make(chan interface{})

	sw := SocketWorker{
		codec:  codec,
		wo:     wo,
		closer: make(chan bool),
		data:   data,
		queue:  flux.NewQueue(data),
	}

	go sw.manage()
	return &sw
}

// Messages returns a receive only channel for socket messages
func (s *SocketWorker) Messages() <-chan *WebsocketMessage {
	if s.writing {
		return s.mesgs
	}

	flux.GoDefer("Socket:Message:Receiver", func() {
		for dag := range s.data {
			if mg, ok := dag.(*WebsocketMessage); ok {
				s.mesgs <- mg
			}
		}
	})

	return s.mesgs
}

// Write returns the internal socket for the worker
func (s *SocketWorker) Write(t int, data []byte) (int, error) {
	return s.codec.Encode(s.wo, t, data)
}

// Socket returns the internal socket for the worker
func (s *SocketWorker) Socket() *Websocket {
	return s.wo
}

// Equals returns true/false if interface matches
func (s *SocketWorker) Equals(b interface{}) bool {
	if sc, ok := b.(*websocket.Conn); ok {
		return s.wo.Conn == sc
	}

	if ws, ok := b.(*Websocket); ok {
		return s.wo == ws
	}

	if sw, ok := b.(*SocketWorker); ok {
		return s == sw
	}

	return false
}

// CloseNotify returns a chan that is used to notify closing of socket
func (s *SocketWorker) CloseNotify() chan bool {
	return s.closer
}

// Close closes the socket read goroutine and notifies a closure using the close channel
func (s *SocketWorker) Close() error {
	if s.closed {
		return ErrClosed
	}
	s.ro.Lock()
	s.closed = true
	close(s.closer)
	s.ro.Unlock()
	return s.wo.Conn.Close()
}

func (s *SocketWorker) manage() {
	defer s.Close()
	for {
		select {
		case <-s.closer:
			return
		default:
			tp, do, err := s.wo.Conn.ReadMessage()

			if err != nil {
				return
			}

			s.queue.Enqueue(&WebsocketMessage{
				codec:   s.codec,
				payload: do,
				mtype:   tp,
				Socket:  s.wo,
			})
		}
	}
}

// SocketStore provides a map store for SocketHub
type SocketStore map[*SocketWorker]bool

// SocketHubHandler provides a function type that encapsulates the socket hub message operations
type SocketHubHandler func(*SocketHub, *WebsocketMessage)

// SocketHub provides a central command for websocket message handling,its the base struct through which different websocket messaging procedures can be implemented on, it provides a go-routine approach,by taking each new websocket connection,stashing it then receiving data from it for processing
type SocketHub struct {
	so      sync.RWMutex
	sockets SocketStore
	handler SocketHubHandler
	closer  chan bool
	closed  bool
}

// NewSocketHub returns a new SocketHub instance,allows the passing of a codec for encoding and decoding data
func NewSocketHub(fx SocketHubHandler) (sh *SocketHub) {
	sh = &SocketHub{
		sockets: make(SocketStore),
		handler: fx,
	}
	return
}

// Close closes the hub
func (s *SocketHub) Close() {
	if s.closed {
		return
	}
	s.closed = true
	close(s.closer)
}

// CloseNotify provides a means of checking the close state of the hub
func (s *SocketHub) CloseNotify() <-chan bool {
	return s.closer
}

// AddConnection adds a new socket connection
func (s *SocketHub) AddConnection(ws *SocketWorker) {
	var ok bool

	s.so.RLock()
	ok = s.sockets[ws]
	s.so.RUnlock()

	if ok {
		return
	}

	s.so.Lock()
	s.sockets[ws] = true
	s.so.Unlock()

	go s.manageSocket(ws)
}

// SocketWorkerHandler provides a function type that encapsulates the socket workers
type SocketWorkerHandler func(*SocketWorker)

// Distribute propagates through the set of defined websocket workers and
//calls a function on it
func (s *SocketHub) Distribute(hsx SocketWorkerHandler, except *SocketWorker) {
	s.so.RLock()
	for wo := range s.sockets {
		if wo != except {
			go hsx(wo)
		}
	}
	s.so.RUnlock()
}

// manageSocket takes a socket and spawns a go-routine to manage the operations of the socket,getting the data and delivery them as WebsocketRequests
func (s *SocketHub) manageSocket(ws *SocketWorker) {
	defer func() {
		s.so.Lock()
		delete(s.sockets, ws)
		s.so.Unlock()
	}()
	for {
		select {
		case <-s.CloseNotify():
			return
		case <-ws.CloseNotify():
			return
		case data, ok := <-ws.Messages():
			if !ok {
				return
			}
			go s.handler(s, data)
		}
	}
}

// WebsocketPort provides a websocket port,handling websocket connection
type WebsocketPort struct {
	FlatChains
	codec   SocketCodec
	upgrade *websocket.Upgrader
	headers http.Header
	handle  SocketHandler
}

// Handle handles the reception of http request and returns a HTTPRequest object
func (ws *WebsocketPort) Handle(res http.ResponseWriter, req *http.Request, params Collector) {
	defer ws.FlatChains.Handle(res, req, params)
	conn, err := ws.upgrade.Upgrade(res, req, ws.headers)

	if err != nil {
		return
	}

	ws.handle(NewSocketWorker(&Websocket{
		Conn:   conn,
		Req:    req,
		Res:    res,
		Params: params,
	}, ws.codec))
}

//SocketHandler provides an handler type without the port option
type SocketHandler func(*SocketWorker)

// NewWebsocketPort returns a new websocket port
func NewWebsocketPort(codec SocketCodec, upgrader *websocket.Upgrader, headers http.Header, hs SocketHandler) (ws *WebsocketPort) {
	ws = &WebsocketPort{
		FlatChains: FlatChainIdentity(),
		codec:      codec,
		headers:    headers,
		upgrade:    upgrader,
		handle:     hs,
	}
	return
}
<commit_msg>go-routine the socket handler code<commit_after>package relay

import (
	"errors"
	"fmt"
	"net/http"
	"sync"

	"github.com/gorilla/websocket"
	"github.com/influx6/flux"
)

// ErrClosed is returned to indicated an already closed struct
var ErrClosed = errors.New("Already Closed")

// ErrInvalidType is returned when the type required is not met
var ErrInvalidType = errors.New("Unsupported Type")

// Websocket provides a cover for websocket connection
type Websocket struct {
	*websocket.Conn
	Req    *http.Request
	Res    http.ResponseWriter
	Params Collector
}

// WebsocketMessage provides small abstraction for processing a message
type WebsocketMessage struct {
	codec   SocketCodec
	payload []byte
	mtype   int
	Socket  *Websocket
	Worker  *SocketWorker
}

// Message returns the data of the socket
func (m *WebsocketMessage) Message() (interface{}, error) {
	return m.codec.Decode(m.mtype, m.payload)
}

// MessageType returns the type of the message
func (m *WebsocketMessage) MessageType() int {
	return m.mtype
}

// Write encodes and writes the given data returns the (int,error) of the total writes while
func (m *WebsocketMessage) Write(bw []byte) (int, error) {
	return m.codec.Encode(m.Socket, m.mtype, bw)
}

// SocketWorker provides a workpool for socket connections
type SocketWorker struct {
	codec   SocketCodec
	data    chan interface{}
	mesgs   chan *WebsocketMessage
	closer  chan bool
	queue   *flux.Queue
	wo      *Websocket
	ro, rd  sync.Mutex
	closed  bool
	writing bool
}

// NewSocketWorker returns a new socketworker instance
func NewSocketWorker(wo *Websocket, codec SocketCodec) *SocketWorker {
	data := make(chan interface{})

	sw := SocketWorker{
		codec:  codec,
		wo:     wo,
		closer: make(chan bool),
		data:   data,
		queue:  flux.NewQueue(data),
	}

	go sw.manage()
	return &sw
}

// Messages returns a receive only channel for socket messages
func (s *SocketWorker) Messages() <-chan *WebsocketMessage {
	if s.writing {
		return s.mesgs
	}

	flux.GoDefer("Socket:Message:Receiver", func() {
		for dag := range s.data {
			if mg, ok := dag.(*WebsocketMessage); ok {
				s.mesgs <- mg
			}
		}
	})

	return s.mesgs
}

// Write returns the internal socket for the worker
func (s *SocketWorker) Write(t int, data []byte) (int, error) {
	return s.codec.Encode(s.wo, t, data)
}

// Socket returns the internal socket for the worker
func (s *SocketWorker) Socket() *Websocket {
	return s.wo
}

// Equals returns true/false if interface matches
func (s *SocketWorker) Equals(b interface{}) bool {
	if sc, ok := b.(*websocket.Conn); ok {
		return s.wo.Conn == sc
	}

	if ws, ok := b.(*Websocket); ok {
		return s.wo == ws
	}

	if sw, ok := b.(*SocketWorker); ok {
		return s == sw
	}

	return false
}

// CloseNotify returns a chan that is used to notify closing of socket
func (s *SocketWorker) CloseNotify() chan bool {
	return s.closer
}

// Close closes the socket read goroutine and notifies a closure using the close channel
func (s *SocketWorker) Close() error {
	if s.closed {
		return ErrClosed
	}
	s.ro.Lock()
	s.closed = true
	close(s.closer)
	s.ro.Unlock()
	return s.wo.Conn.Close()
}

func (s *SocketWorker) manage() {
	defer s.Close()
	for {
		select {
		case <-s.closer:
			return
		default:
			tp, do, err := s.wo.Conn.ReadMessage()

			if err != nil {
				return
			}

			s.queue.Enqueue(&WebsocketMessage{
				codec:   s.codec,
				payload: do,
				mtype:   tp,
				Socket:  s.wo,
			})
		}
	}
}

// SocketStore provides a map store for SocketHub
type SocketStore map[*SocketWorker]bool

// SocketHubHandler provides a function type that encapsulates the socket hub message operations
type SocketHubHandler func(*SocketHub, *WebsocketMessage)

// SocketHub provides a central command for websocket message handling,its the base struct through which different websocket messaging procedures can be implemented on, it provides a go-routine approach,by taking each new websocket connection,stashing it then receiving data from it for processing
type SocketHub struct {
	so      sync.RWMutex
	sockets SocketStore
	handler SocketHubHandler
	closer  chan bool
	closed  bool
}

// NewSocketHub returns a new SocketHub instance,allows the passing of a codec for encoding and decoding data
func NewSocketHub(fx SocketHubHandler) (sh *SocketHub) {
	sh = &SocketHub{
		sockets: make(SocketStore),
		handler: fx,
	}
	return
}

// Close closes the hub
func (s *SocketHub) Close() {
	if s.closed {
		return
	}
	s.closed = true
	close(s.closer)
}

// CloseNotify provides a means of checking the close state of the hub
func (s *SocketHub) CloseNotify() <-chan bool {
	return s.closer
}

// AddConnection adds a new socket connection
func (s *SocketHub) AddConnection(ws *SocketWorker) {
	var ok bool

	s.so.RLock()
	ok = s.sockets[ws]
	s.so.RUnlock()

	if ok {
		return
	}

	s.so.Lock()
	s.sockets[ws] = true
	s.so.Unlock()

	go s.manageSocket(ws)
}

// SocketWorkerHandler provides a function type that encapsulates the socket workers
type SocketWorkerHandler func(*SocketWorker)

// Distribute propagates through the set of defined websocket workers and
//calls a function on it
func (s *SocketHub) Distribute(hsx SocketWorkerHandler, except *SocketWorker) {
	s.so.RLock()
	for wo := range s.sockets {
		if wo != except {
			go hsx(wo)
		}
	}
	s.so.RUnlock()
}

// manageSocket takes a socket and spawns a go-routine to manage the operations of the socket,getting the data and delivery them as WebsocketRequests
func (s *SocketHub) manageSocket(ws *SocketWorker) {
	defer func() {
		s.so.Lock()
		delete(s.sockets, ws)
		s.so.Unlock()
	}()
	for {
		select {
		case <-s.CloseNotify():
			return
		case <-ws.CloseNotify():
			return
		case data, ok := <-ws.Messages():
			if !ok {
				return
			}
			go s.handler(s, data)
		}
	}
}

// WebsocketPort provides a websocket port,handling websocket connection
type WebsocketPort struct {
	FlatChains
	codec   SocketCodec
	upgrade *websocket.Upgrader
	headers http.Header
	handle  SocketHandler
}

// Handle handles the reception of http request and returns a HTTPRequest object
func (ws *WebsocketPort) Handle(res http.ResponseWriter, req *http.Request, params Collector) {
	defer ws.FlatChains.Handle(res, req, params)
	conn, err := ws.upgrade.Upgrade(res, req, ws.headers)

	if err != nil {
		return
	}

	flux.GoDefer(fmt.Sprintf("WebSocketPort.Handler"), func() {
		ws.handle(NewSocketWorker(&Websocket{
			Conn:   conn,
			Req:    req,
			Res:    res,
			Params: params,
		}, ws.codec))
	})
}

//SocketHandler provides an handler type without the port option
type SocketHandler func(*SocketWorker)

// NewWebsocketPort returns a new websocket port
func NewWebsocketPort(codec SocketCodec, upgrader *websocket.Upgrader, headers http.Header, hs SocketHandler) (ws *WebsocketPort) {
	ws = &WebsocketPort{
		FlatChains: FlatChainIdentity(),
		codec:      codec,
		headers:    headers,
		upgrade:    upgrader,
		handle:     hs,
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2020 CUE Authors
//
// 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 cue

import (
	"fmt"
	"strconv"
	"strings"

	"cuelang.org/go/cue/ast"
	"cuelang.org/go/cue/errors"
	"cuelang.org/go/cue/literal"
	"cuelang.org/go/cue/parser"
	"cuelang.org/go/cue/token"
	"cuelang.org/go/internal"
	"cuelang.org/go/internal/core/adt"
	"github.com/cockroachdb/apd/v2"
)

// A Selector is a component of a path.
type Selector struct {
	sel selector
}

// String reports the CUE representation of a selector.
func (sel Selector) String() string {
	return sel.sel.String()
}

type selector interface {
	String() string

	feature(ctx adt.Runtime) adt.Feature
	kind() adt.FeatureType
}

// A Path is series of selectors to query a CUE value.
type Path struct {
	path []Selector
}

// MakePath creates a Path from a sequence of selectors.
func MakePath(selectors ...Selector) Path {
	return Path{path: selectors}
}

// ParsePath parses a CUE expression into a Path. Any error resulting from
// this conversion can be obtained by calling Err on the result.
//
// Unlike with normal CUE expressions, the first element of the path may be
// a string literal.
//
// A path may not contain hidden fields. To create a path with hidden fields,
// use MakePath and Ident.
func ParsePath(s string) Path {
	if s == "" {
		return Path{}
	}
	expr, err := parser.ParseExpr("", s)
	if err != nil {
		return MakePath(Selector{pathError{errors.Promote(err, "invalid path")}})
	}

	p := Path{path: toSelectors(expr)}
	for _, sel := range p.path {
		if sel.sel.kind().IsHidden() {
			return MakePath(Selector{pathError{errors.Newf(token.NoPos,
				"invalid path: hidden fields not allowed in path %s", s)}})
		}
	}
	return p
}

// Selectors reports the individual selectors of a path.
func (p Path) Selectors() []Selector {
	return p.path
}

// String reports the CUE representation of p.
func (p Path) String() string {
	if err := p.Err(); err != nil {
		return "_|_"
	}

	b := &strings.Builder{}
	for i, sel := range p.path {
		x := sel.sel
		// TODO: use '.' in all cases, once supported.
		switch {
		case x.kind() == adt.IntLabel:
			b.WriteByte('[')
			b.WriteString(x.String())
			b.WriteByte(']')
			continue
		case i > 0:
			b.WriteByte('.')
		}

		b.WriteString(x.String())
	}
	return b.String()
}

func toSelectors(expr ast.Expr) []Selector {
	switch x := expr.(type) {
	case *ast.Ident:
		return []Selector{identSelector(x)}

	case *ast.BasicLit:
		return []Selector{basicLitSelector(x)}

	case *ast.IndexExpr:
		a := toSelectors(x.X)
		var sel Selector
		if b, ok := x.Index.(*ast.BasicLit); !ok {
			sel = Selector{pathError{
				errors.Newf(token.NoPos, "non-constant expression %s",
					internal.DebugStr(x.Index))}}
		} else {
			sel = basicLitSelector(b)
		}
		return appendSelector(a, sel)

	case *ast.SelectorExpr:
		a := toSelectors(x.X)
		return appendSelector(a, identSelector(x.Sel))

	default:
		return []Selector{{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}}
	}
}

// appendSelector is like append(a, sel), except that it collects errors
// in a one-element slice.
func appendSelector(a []Selector, sel Selector) []Selector {
	err, isErr := sel.sel.(pathError)
	if len(a) == 1 {
		if p, ok := a[0].sel.(pathError); ok {
			if isErr {
				p.Error = errors.Append(p.Error, err.Error)
			}
			return a
		}
	}
	if isErr {
		return []Selector{sel}
	}
	return append(a, sel)
}

func basicLitSelector(b *ast.BasicLit) Selector {
	switch b.Kind {
	case token.INT:
		var n literal.NumInfo
		if err := literal.ParseNum(b.Value, &n); err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value),
			}}
		}
		var d apd.Decimal
		_ = n.Decimal(&d)
		i, err := d.Int64()
		if err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "integer %s out of range", b.Value),
			}}
		}
		return Index(int(i))

	case token.STRING:
		info, _, _, _ := literal.ParseQuotes(b.Value, b.Value)
		if !info.IsDouble() {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value)}}
		}
		s, _ := literal.Unquote(b.Value)
		return Selector{stringSelector(s)}

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid literal %s", b.Value),
		}}
	}
}

func identSelector(label ast.Label) Selector {
	switch x := label.(type) {
	case *ast.Ident:
		switch s := x.Name; {
		case strings.HasPrefix(s, "_"):
			// TODO: extract package from a bound identifier.
			return Selector{pathError{errors.Newf(token.NoPos,
				"invalid path: hidden label %s not allowed", s),
			}}
		case strings.HasPrefix(s, "#"):
			return Selector{definitionSelector(x.Name)}
		default:
			return Selector{stringSelector(x.Name)}
		}

	case *ast.BasicLit:
		return basicLitSelector(x)

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}
	}
}

// Err reports errors that occurred when generating the path.
func (p Path) Err() error {
	var errs errors.Error
	for _, x := range p.path {
		if err, ok := x.sel.(pathError); ok {
			errs = errors.Append(errs, err.Error)
		}
	}
	return errs
}

func isHiddenOrDefinition(s string) bool {
	return strings.HasPrefix(s, "#") || strings.HasPrefix(s, "_")
}

// Hid returns a selector for a hidden field. It panics is pkg is empty.
// Hidden fields are scoped by package, and pkg indicates for which package
// the hidden field must apply.For anonymous packages, it must be set to "_".
func Hid(name, pkg string) Selector {
	if !ast.IsValidIdent(name) {
		panic(fmt.Sprintf("invalid identifier %s", name))
	}
	if !strings.HasPrefix(name, "_") {
		panic(fmt.Sprintf("%s is not a hidden field identifier", name))
	}
	if pkg == "" {
		panic(fmt.Sprintf("missing package for hidden identifier %s", name))
	}
	return Selector{scopedSelector{name, pkg}}
}

type scopedSelector struct {
	name, pkg string
}

// String returns the CUE representation of the definition.
func (s scopedSelector) String() string {
	return s.name
}

func (s scopedSelector) kind() adt.FeatureType {
	switch {
	case strings.HasPrefix(s.name, "#"):
		return adt.DefinitionLabel
	case strings.HasPrefix(s.name, "_#"):
		return adt.HiddenDefinitionLabel
	case strings.HasPrefix(s.name, "_"):
		return adt.HiddenLabel
	default:
		return adt.StringLabel
	}
}

func (s scopedSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, s.name, s.pkg)
}

// A Def marks a string as a definition label. An # will be added if a string is
// not prefixed with a #. It will panic if s cannot be written as a valid
// identifier.
func Def(s string) Selector {
	if !strings.HasPrefix(s, "#") {
		s = "#" + s
	}
	if !ast.IsValidIdent(s) {
		panic(fmt.Sprintf("invalid definition %s", s))
	}
	return Selector{definitionSelector(s)}
}

type definitionSelector string

// String returns the CUE representation of the definition.
func (d definitionSelector) String() string {
	return string(d)
}

func (d definitionSelector) kind() adt.FeatureType {
	return adt.DefinitionLabel
}

func (d definitionSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, string(d), "")
}

// A Str is a CUE string label. Definition selectors are defined with Def.
func Str(s string) Selector {
	return Selector{stringSelector(s)}
}

type stringSelector string

func (s stringSelector) String() string {
	str := string(s)
	if isHiddenOrDefinition(str) || !ast.IsValidIdent(str) {
		return literal.Label.Quote(str)
	}
	return str
}

func (s stringSelector) kind() adt.FeatureType { return adt.StringLabel }

func (s stringSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeStringLabel(r, string(s))
}

// An Index selects a list element by index.
func Index(x int) Selector {
	f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel)
	if err != nil {
		return Selector{pathError{err}}
	}
	return Selector{indexSelector(f)}
}

type indexSelector adt.Feature

func (s indexSelector) String() string {
	return strconv.Itoa(adt.Feature(s).Index())
}

func (s indexSelector) kind() adt.FeatureType { return adt.IntLabel }

func (s indexSelector) feature(r adt.Runtime) adt.Feature {
	return adt.Feature(s)
}

// TODO: allow import paths to be represented?
//
// // ImportPath defines a lookup at the root of an instance. It must be the first
// // element of a Path.
// func ImportPath(s string) Selector {
// 	return importSelector(s)
// }

// type importSelector string

// func (s importSelector) String() string {
// 	return literal.String.Quote(string(s))
// }

// func (s importSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

// TODO: allow looking up in parent scopes?

// // Parent returns a Selector for looking up in the parent of a current node.
// // Parent selectors may only occur at the start of a Path.
// func Parent() Selector {
// 	return parentSelector{}
// }

// type parentSelector struct{}

// func (p parentSelector) String() string { return "__up" }
// func (p parentSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

type pathError struct {
	errors.Error
}

func (p pathError) String() string        { return p.Error.Error() }
func (p pathError) kind() adt.FeatureType { return 0 }
func (p pathError) feature(r adt.Runtime) adt.Feature {
	return adt.InvalidLabel
}
<commit_msg>cue: expose some path utilities<commit_after>// Copyright 2020 CUE Authors
//
// 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 cue

import (
	"fmt"
	"strconv"
	"strings"

	"cuelang.org/go/cue/ast"
	"cuelang.org/go/cue/errors"
	"cuelang.org/go/cue/literal"
	"cuelang.org/go/cue/parser"
	"cuelang.org/go/cue/token"
	"cuelang.org/go/internal"
	"cuelang.org/go/internal/core/adt"
	"github.com/cockroachdb/apd/v2"
)

// A Selector is a component of a path.
type Selector struct {
	sel selector
}

// String reports the CUE representation of a selector.
func (sel Selector) String() string {
	return sel.sel.String()
}

// IsString reports whether sel is a regular label type.
func (sel Selector) IsString() bool {
	return sel.sel.kind() == adt.StringLabel
}

type selector interface {
	String() string

	feature(ctx adt.Runtime) adt.Feature
	kind() adt.FeatureType
}

// A Path is series of selectors to query a CUE value.
type Path struct {
	path []Selector
}

// MakePath creates a Path from a sequence of selectors.
func MakePath(selectors ...Selector) Path {
	return Path{path: selectors}
}

// ParsePath parses a CUE expression into a Path. Any error resulting from
// this conversion can be obtained by calling Err on the result.
//
// Unlike with normal CUE expressions, the first element of the path may be
// a string literal.
//
// A path may not contain hidden fields. To create a path with hidden fields,
// use MakePath and Ident.
func ParsePath(s string) Path {
	if s == "" {
		return Path{}
	}
	expr, err := parser.ParseExpr("", s)
	if err != nil {
		return MakePath(Selector{pathError{errors.Promote(err, "invalid path")}})
	}

	p := Path{path: toSelectors(expr)}
	for _, sel := range p.path {
		if sel.sel.kind().IsHidden() {
			return MakePath(Selector{pathError{errors.Newf(token.NoPos,
				"invalid path: hidden fields not allowed in path %s", s)}})
		}
	}
	return p
}

// Selectors reports the individual selectors of a path.
func (p Path) Selectors() []Selector {
	return p.path
}

// String reports the CUE representation of p.
func (p Path) String() string {
	if err := p.Err(); err != nil {
		return "_|_"
	}

	b := &strings.Builder{}
	for i, sel := range p.path {
		x := sel.sel
		// TODO: use '.' in all cases, once supported.
		switch {
		case x.kind() == adt.IntLabel:
			b.WriteByte('[')
			b.WriteString(x.String())
			b.WriteByte(']')
			continue
		case i > 0:
			b.WriteByte('.')
		}

		b.WriteString(x.String())
	}
	return b.String()
}

func toSelectors(expr ast.Expr) []Selector {
	switch x := expr.(type) {
	case *ast.Ident:
		return []Selector{Label(x)}

	case *ast.BasicLit:
		return []Selector{basicLitSelector(x)}

	case *ast.IndexExpr:
		a := toSelectors(x.X)
		var sel Selector
		if b, ok := x.Index.(*ast.BasicLit); !ok {
			sel = Selector{pathError{
				errors.Newf(token.NoPos, "non-constant expression %s",
					internal.DebugStr(x.Index))}}
		} else {
			sel = basicLitSelector(b)
		}
		return appendSelector(a, sel)

	case *ast.SelectorExpr:
		a := toSelectors(x.X)
		return appendSelector(a, Label(x.Sel))

	default:
		return []Selector{{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}}
	}
}

// appendSelector is like append(a, sel), except that it collects errors
// in a one-element slice.
func appendSelector(a []Selector, sel Selector) []Selector {
	err, isErr := sel.sel.(pathError)
	if len(a) == 1 {
		if p, ok := a[0].sel.(pathError); ok {
			if isErr {
				p.Error = errors.Append(p.Error, err.Error)
			}
			return a
		}
	}
	if isErr {
		return []Selector{sel}
	}
	return append(a, sel)
}

func basicLitSelector(b *ast.BasicLit) Selector {
	switch b.Kind {
	case token.INT:
		var n literal.NumInfo
		if err := literal.ParseNum(b.Value, &n); err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value),
			}}
		}
		var d apd.Decimal
		_ = n.Decimal(&d)
		i, err := d.Int64()
		if err != nil {
			return Selector{pathError{
				errors.Newf(token.NoPos, "integer %s out of range", b.Value),
			}}
		}
		return Index(int(i))

	case token.STRING:
		info, _, _, _ := literal.ParseQuotes(b.Value, b.Value)
		if !info.IsDouble() {
			return Selector{pathError{
				errors.Newf(token.NoPos, "invalid string index %s", b.Value)}}
		}
		s, _ := literal.Unquote(b.Value)
		return Selector{stringSelector(s)}

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid literal %s", b.Value),
		}}
	}
}

// Label converts an AST label to a Selector.
func Label(label ast.Label) Selector {
	switch x := label.(type) {
	case *ast.Ident:
		switch s := x.Name; {
		case strings.HasPrefix(s, "_"):
			// TODO: extract package from a bound identifier.
			return Selector{pathError{errors.Newf(token.NoPos,
				"invalid path: hidden label %s not allowed", s),
			}}
		case strings.HasPrefix(s, "#"):
			return Selector{definitionSelector(x.Name)}
		default:
			return Selector{stringSelector(x.Name)}
		}

	case *ast.BasicLit:
		return basicLitSelector(x)

	default:
		return Selector{pathError{
			errors.Newf(token.NoPos, "invalid label %s ", internal.DebugStr(x)),
		}}
	}
}

// Err reports errors that occurred when generating the path.
func (p Path) Err() error {
	var errs errors.Error
	for _, x := range p.path {
		if err, ok := x.sel.(pathError); ok {
			errs = errors.Append(errs, err.Error)
		}
	}
	return errs
}

func isHiddenOrDefinition(s string) bool {
	return strings.HasPrefix(s, "#") || strings.HasPrefix(s, "_")
}

// Hid returns a selector for a hidden field. It panics is pkg is empty.
// Hidden fields are scoped by package, and pkg indicates for which package
// the hidden field must apply.For anonymous packages, it must be set to "_".
func Hid(name, pkg string) Selector {
	if !ast.IsValidIdent(name) {
		panic(fmt.Sprintf("invalid identifier %s", name))
	}
	if !strings.HasPrefix(name, "_") {
		panic(fmt.Sprintf("%s is not a hidden field identifier", name))
	}
	if pkg == "" {
		panic(fmt.Sprintf("missing package for hidden identifier %s", name))
	}
	return Selector{scopedSelector{name, pkg}}
}

type scopedSelector struct {
	name, pkg string
}

// String returns the CUE representation of the definition.
func (s scopedSelector) String() string {
	return s.name
}

func (s scopedSelector) kind() adt.FeatureType {
	switch {
	case strings.HasPrefix(s.name, "#"):
		return adt.DefinitionLabel
	case strings.HasPrefix(s.name, "_#"):
		return adt.HiddenDefinitionLabel
	case strings.HasPrefix(s.name, "_"):
		return adt.HiddenLabel
	default:
		return adt.StringLabel
	}
}

func (s scopedSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, s.name, s.pkg)
}

// A Def marks a string as a definition label. An # will be added if a string is
// not prefixed with a #. It will panic if s cannot be written as a valid
// identifier.
func Def(s string) Selector {
	if !strings.HasPrefix(s, "#") {
		s = "#" + s
	}
	if !ast.IsValidIdent(s) {
		panic(fmt.Sprintf("invalid definition %s", s))
	}
	return Selector{definitionSelector(s)}
}

type definitionSelector string

// String returns the CUE representation of the definition.
func (d definitionSelector) String() string {
	return string(d)
}

func (d definitionSelector) kind() adt.FeatureType {
	return adt.DefinitionLabel
}

func (d definitionSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeIdentLabel(r, string(d), "")
}

// A Str is a CUE string label. Definition selectors are defined with Def.
func Str(s string) Selector {
	return Selector{stringSelector(s)}
}

type stringSelector string

func (s stringSelector) String() string {
	str := string(s)
	if isHiddenOrDefinition(str) || !ast.IsValidIdent(str) {
		return literal.Label.Quote(str)
	}
	return str
}

func (s stringSelector) kind() adt.FeatureType { return adt.StringLabel }

func (s stringSelector) feature(r adt.Runtime) adt.Feature {
	return adt.MakeStringLabel(r, string(s))
}

// An Index selects a list element by index.
func Index(x int) Selector {
	f, err := adt.MakeLabel(nil, int64(x), adt.IntLabel)
	if err != nil {
		return Selector{pathError{err}}
	}
	return Selector{indexSelector(f)}
}

type indexSelector adt.Feature

func (s indexSelector) String() string {
	return strconv.Itoa(adt.Feature(s).Index())
}

func (s indexSelector) kind() adt.FeatureType { return adt.IntLabel }

func (s indexSelector) feature(r adt.Runtime) adt.Feature {
	return adt.Feature(s)
}

// TODO: allow import paths to be represented?
//
// // ImportPath defines a lookup at the root of an instance. It must be the first
// // element of a Path.
// func ImportPath(s string) Selector {
// 	return importSelector(s)
// }

// type importSelector string

// func (s importSelector) String() string {
// 	return literal.String.Quote(string(s))
// }

// func (s importSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

// TODO: allow looking up in parent scopes?

// // Parent returns a Selector for looking up in the parent of a current node.
// // Parent selectors may only occur at the start of a Path.
// func Parent() Selector {
// 	return parentSelector{}
// }

// type parentSelector struct{}

// func (p parentSelector) String() string { return "__up" }
// func (p parentSelector) feature(r adt.Runtime) adt.Feature {
// 	return adt.InvalidLabel
// }

type pathError struct {
	errors.Error
}

func (p pathError) String() string        { return p.Error.Error() }
func (p pathError) kind() adt.FeatureType { return 0 }
func (p pathError) feature(r adt.Runtime) adt.Feature {
	return adt.InvalidLabel
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"strings"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

var (
	identityDataHelper = "/usr/bin/mender-device-identity"
)

type IdentityDataGetter interface {
	// obtain identity data as a string or return an error
	Get() (string, error)
}

type IdentityDataRunner struct {
	Helper string
	cmdr   Commander
}

func NewIdentityDataGetter() IdentityDataGetter {
	return &IdentityDataRunner{
		identityDataHelper,
		&osCalls{},
	}
}

// Obtain identity data by calling a suitable helper tool
func (id IdentityDataRunner) Get() (string, error) {
	helper := identityDataHelper

	if id.Helper != "" {
		helper = id.Helper
	}

	cmd := id.cmdr.Command(helper)
	data, err := cmd.Output()

	if err != nil {
		return "", errors.Wrapf(err, "failed to call %s", helper)
	}

	idata, err := parseIdentityData(data)
	if err != nil {
		return "", errors.Wrapf(err, "failed to parse identity data")
	}

	encdata, err := json.Marshal(idata)
	if err != nil {
		return "", errors.Wrapf(err, "failed to encode identity data")
	}

	return string(encdata), nil
}

// device identity data content
type IdentityData map[string]string

func parseIdentityData(data []byte) (interface{}, error) {
	idata := make(IdentityData)

	in := bufio.NewScanner(bytes.NewBuffer(data))
	for in.Scan() {
		line := in.Text()

		if len(line) == 0 {
			continue
		}

		val := strings.SplitN(line, "=", 2)

		if len(val) < 2 {
			return nil, errors.Errorf("incorrect line '%s'", line)
		}

		if _, ok := idata[val[0]]; ok {
			log.Warningf("attribute %v already present in identity data", val[0])
		}
		idata[val[0]] = val[1]
	}

	if len(idata) == 0 {
		return nil, errors.Errorf("no data found")
	}

	return &idata, nil
}
<commit_msg>identity_data: use system path helpers<commit_after>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"path"
	"strings"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

var (
	identityDataHelper = path.Join(getBinDirPath(), "mender-device-identity")
)

type IdentityDataGetter interface {
	// obtain identity data as a string or return an error
	Get() (string, error)
}

type IdentityDataRunner struct {
	Helper string
	cmdr   Commander
}

func NewIdentityDataGetter() IdentityDataGetter {
	return &IdentityDataRunner{
		identityDataHelper,
		&osCalls{},
	}
}

// Obtain identity data by calling a suitable helper tool
func (id IdentityDataRunner) Get() (string, error) {
	helper := identityDataHelper

	if id.Helper != "" {
		helper = id.Helper
	}

	cmd := id.cmdr.Command(helper)
	data, err := cmd.Output()

	if err != nil {
		return "", errors.Wrapf(err, "failed to call %s", helper)
	}

	idata, err := parseIdentityData(data)
	if err != nil {
		return "", errors.Wrapf(err, "failed to parse identity data")
	}

	encdata, err := json.Marshal(idata)
	if err != nil {
		return "", errors.Wrapf(err, "failed to encode identity data")
	}

	return string(encdata), nil
}

// device identity data content
type IdentityData map[string]string

func parseIdentityData(data []byte) (interface{}, error) {
	idata := make(IdentityData)

	in := bufio.NewScanner(bytes.NewBuffer(data))
	for in.Scan() {
		line := in.Text()

		if len(line) == 0 {
			continue
		}

		val := strings.SplitN(line, "=", 2)

		if len(val) < 2 {
			return nil, errors.Errorf("incorrect line '%s'", line)
		}

		if _, ok := idata[val[0]]; ok {
			log.Warningf("attribute %v already present in identity data", val[0])
		}
		idata[val[0]] = val[1]
	}

	if len(idata) == 0 {
		return nil, errors.Errorf("no data found")
	}

	return &idata, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/die-net/fotomat/imager"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
)

var maxBufferDimension = flag.Uint("max_buffer_dimension", 2048, "Maximum width or height of an image buffer to allocate.")

func init() {
	http.HandleFunc("/albums/crop", imageCropHandler)
}

/*
        Supported geometries:
	WxH#        - scale down so the shorter edge fits within this bounding box, crop to new aspect ratio
	WxH or WxH> - scale down so the longer edge fits within this bounding box, no crop
*/
var (
	matchGeometry = regexp.MustCompile(`^(\d{1,5})x(\d{1,5})([>#])?$`)
)

const maxDimension = 2048

func imageCropHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" && r.Method != "HEAD" {
		sendError(w, nil, http.StatusMethodNotAllowed)
	}

	if err := r.ParseForm(); err != nil {
		sendError(w, err, 0)
	}

	orig, err, status := fetchUrl(r.FormValue("image_url"))
	if err != nil {
		sendError(w, err, status)
		return
	}

	width, height, crop, ok := parseGeometry(r.FormValue("geometry"))
	if !ok {
		sendError(w, nil, 400)
		return
	}

	img, err := imager.New(orig, *maxBufferDimension)
	if err != nil {
		sendError(w, err, 0)
		return
	}

	defer img.Close()

	var thumb []byte
	if crop {
		thumb, err = img.Crop(width, height)
	} else {
		thumb, err = img.Thumbnail(width, height, true)
	}
	if err != nil {
		sendError(w, err, 0)
		return
	}

	w.Write(thumb)
}

func fetchUrl(url string) ([]byte, error, int) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err, 0
	}

	defer resp.Body.Close()

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

	switch resp.StatusCode {
	case http.StatusOK, http.StatusNoContent, http.StatusNotFound:
		return body, nil, resp.StatusCode
	default:
		err := fmt.Errorf("Proxy received %d %s", resp.StatusCode, http.StatusText(resp.StatusCode))
		return nil, err, http.StatusBadGateway
	}
}

func parseGeometry(geometry string) (uint, uint, bool, bool) {
	g := matchGeometry.FindStringSubmatch(geometry)
	if len(g) != 4 {
		return 0, 0, false, false
	}
	width, err := strconv.Atoi(g[1])
	if err != nil || width <= 0 || width >= maxDimension {
		return 0, 0, false, false
	}
	height, err := strconv.Atoi(g[2])
	if err != nil || height <= 0 || height >= maxDimension {
		return 0, 0, false, false
	}
	crop := (g[3] == "#")
	return uint(width), uint(height), crop, true
}

func sendError(w http.ResponseWriter, err error, status int) {
	if status == 0 {
		switch err {
		case imager.UnknownFormat:
			status = http.StatusNotFound
		case imager.TooBig:
			status = http.StatusForbidden
		default:
			status = http.StatusInternalServerError
		}
	}
	if err == nil {
		err = fmt.Errorf(http.StatusText(status))
	}
	http.Error(w, err.Error(), status)
}
<commit_msg>Pass through 403 errors.<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/die-net/fotomat/imager"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
)

var maxBufferDimension = flag.Uint("max_buffer_dimension", 2048, "Maximum width or height of an image buffer to allocate.")

func init() {
	http.HandleFunc("/albums/crop", imageCropHandler)
}

/*
        Supported geometries:
	WxH#        - scale down so the shorter edge fits within this bounding box, crop to new aspect ratio
	WxH or WxH> - scale down so the longer edge fits within this bounding box, no crop
*/
var (
	matchGeometry = regexp.MustCompile(`^(\d{1,5})x(\d{1,5})([>#])?$`)
)

const maxDimension = 2048

func imageCropHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" && r.Method != "HEAD" {
		sendError(w, nil, http.StatusMethodNotAllowed)
	}

	if err := r.ParseForm(); err != nil {
		sendError(w, err, 0)
	}

	orig, err, status := fetchUrl(r.FormValue("image_url"))
	if err != nil {
		sendError(w, err, status)
		return
	}

	width, height, crop, ok := parseGeometry(r.FormValue("geometry"))
	if !ok {
		sendError(w, nil, 400)
		return
	}

	img, err := imager.New(orig, *maxBufferDimension)
	if err != nil {
		sendError(w, err, 0)
		return
	}

	defer img.Close()

	var thumb []byte
	if crop {
		thumb, err = img.Crop(width, height)
	} else {
		thumb, err = img.Thumbnail(width, height, true)
	}
	if err != nil {
		sendError(w, err, 0)
		return
	}

	w.Write(thumb)
}

func fetchUrl(url string) ([]byte, error, int) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err, 0
	}

	defer resp.Body.Close()

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

	switch resp.StatusCode {
	case http.StatusOK, http.StatusNoContent, http.StatusForbidden, http.StatusNotFound:
		return body, nil, resp.StatusCode
	default:
		err := fmt.Errorf("Proxy received %d %s", resp.StatusCode, http.StatusText(resp.StatusCode))
		return nil, err, http.StatusBadGateway
	}
}

func parseGeometry(geometry string) (uint, uint, bool, bool) {
	g := matchGeometry.FindStringSubmatch(geometry)
	if len(g) != 4 {
		return 0, 0, false, false
	}
	width, err := strconv.Atoi(g[1])
	if err != nil || width <= 0 || width >= maxDimension {
		return 0, 0, false, false
	}
	height, err := strconv.Atoi(g[2])
	if err != nil || height <= 0 || height >= maxDimension {
		return 0, 0, false, false
	}
	crop := (g[3] == "#")
	return uint(width), uint(height), crop, true
}

func sendError(w http.ResponseWriter, err error, status int) {
	if status == 0 {
		switch err {
		case imager.UnknownFormat:
			status = http.StatusNotFound
		case imager.TooBig:
			status = http.StatusForbidden
		default:
			status = http.StatusInternalServerError
		}
	}
	if err == nil {
		err = fmt.Errorf(http.StatusText(status))
	}
	http.Error(w, err.Error(), status)
}
<|endoftext|>


<commit_before>package main

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

type karmas struct {
	karmaMap *map[string]karmaSet
}

type karmaSet struct {
	plusplus   int
	minusminus int
	plusminus  int
}

func (k karmaSet) value() int {
	return k.plusplus - k.minusminus
}

func (k karmaSet) String() string {
	return fmt.Sprintf("(%v++,%v--,%v+-)", k.plusplus, k.minusminus, k.plusminus)
}

var regex = regexp.MustCompile("([^ ]+)(\\+\\+|--|\\+-|-\\+)")
var getkarma = regexp.MustCompile("^!karma +([^ ]+)")

func main() {
	k := newKarmas()
	http.Handle("/", k)

	http.ListenAndServe(":8080", nil)
}

func newKarmas() karmas {
	m := make(map[string]karmaSet)
	return karmas{&m}
}

func (k karmas) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	text := r.Form.Get("text")
	matches := regex.FindAllStringSubmatch(text, -1)
	karma := getkarma.FindStringSubmatch(text)
	if matches != nil {
		for _, match := range matches {
			key := match[1]
			op := match[2]
			set := (*k.karmaMap)[key]
			if key != "" {
				switch op {
				case "--":
					set.minusminus++
				case "++":
					set.plusplus++
				case "-+", "+-":
					set.plusminus++
				}
				(*k.karmaMap)[key] = set
			}
		}
		fmt.Println(*k.karmaMap)
	} else if karma != nil {
		name := karma[1]
		fmt.Println("asking for", name)
		res := make(map[string]string)
		karmaset := (*k.karmaMap)[name]
		res["text"] = fmt.Sprintf("%v: %v %v", r.Form.Get("user_name"), karmaset.value(), karmaset)
		res["parse"] = "full"
		res["username"] = "dabopobo"
		resp, _ := json.Marshal(res)
		fmt.Println(string(resp))
		w.WriteHeader(200)
		w.Write(resp)
	}
}
<commit_msg>No longer processes its own messages<commit_after>package main

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

type karmas struct {
	karmaMap *map[string]karmaSet
}

type karmaSet struct {
	plusplus   int
	minusminus int
	plusminus  int
}

func (k karmaSet) value() int {
	return k.plusplus - k.minusminus
}

func (k karmaSet) String() string {
	return fmt.Sprintf("(%v++,%v--,%v+-)", k.plusplus, k.minusminus, k.plusminus)
}

var regex = regexp.MustCompile("([^ ]+)(\\+\\+|--|\\+-|-\\+)")
var getkarma = regexp.MustCompile("^!karma +([^ ]+)")

func main() {
	k := newKarmas()
	http.Handle("/", k)

	http.ListenAndServe(":8080", nil)
}

func newKarmas() karmas {
	m := make(map[string]karmaSet)
	return karmas{&m}
}

func (k karmas) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	text := r.Form.Get("text")
	matches := regex.FindAllStringSubmatch(text, -1)
	karma := getkarma.FindStringSubmatch(text)
	if matches != nil && r.Form.Get("user_name") != "slackbot" {
		for _, match := range matches {
			key := match[1]
			op := match[2]
			set := (*k.karmaMap)[key]
			if key != "" {
				switch op {
				case "--":
					set.minusminus++
				case "++":
					set.plusplus++
				case "-+", "+-":
					set.plusminus++
				}
				(*k.karmaMap)[key] = set
			}
		}
		fmt.Println(*k.karmaMap)
	} else if karma != nil {
		name := karma[1]
		fmt.Println("asking for", name)
		res := make(map[string]string)
		karmaset := (*k.karmaMap)[name]
		res["text"] = fmt.Sprintf("%v: %v %v", r.Form.Get("user_name"), karmaset.value(), karmaset)
		res["parse"] = "full"
		res["username"] = "dabopobo"
		resp, _ := json.Marshal(res)
		fmt.Println(string(resp))
		w.WriteHeader(200)
		w.Write(resp)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/Knetic/govaluate"
)

// CompositeEstimator returns a similarity function based on
// compositions of simpler similarity expressions. The user needs to provide a
// formula containing the expression of the similarity function, e.g.:
// 0.8 x BHATTACHARRYA + 0.2 CORRELATION
// Note that it is the user's responsibility to guarantee that the overall
// expression remains within the limits of the similarity expression [0,1].
type CompositeEstimator struct {
	AbstractDatasetSimilarityEstimator

	// the slice of estimators to use for the similarity evaluation
	estimators map[string]DatasetSimilarityEstimator
	// the math expression used for the estimation
	expression string
}

// Compute method constructs the Similarity Matrix
func (e *CompositeEstimator) Compute() error {
	for _, est := range e.estimators {
		est.Compute()
	}
	return datasetSimilarityEstimatorCompute(e)
}

// Similarity returns the similarity between two datasets
func (e *CompositeEstimator) Similarity(a, b *Dataset) float64 {
	expression, err := govaluate.NewEvaluableExpression(e.expression)
	if err != nil {
		log.Println(err)
		return 0.0
	}
	params := make(map[string]interface{})
	for k, est := range e.estimators {
		params[k] = est.Similarity(a, b)
	}
	result, err := expression.Evaluate(params)
	if err != nil {
		log.Println(err)
		return 0.0
	}
	if val, ok := result.(float64); ok {
		return val
	}
	return -1.0
}

// Serialize returns an array of bytes representing the Estimator.
func (e *CompositeEstimator) Serialize() []byte {
	buffer := new(bytes.Buffer)
	buffer.Write(getBytesInt(int(SimilarityTypeComposite)))

	buffer.Write(datasetSimilarityEstimatorSerialize(
		e.AbstractDatasetSimilarityEstimator))

	// serialize expression
	buffer.WriteString(e.expression + "\n")

	// serialize estimators
	buffer.Write(getBytesInt(len(e.estimators)))
	for k, est := range e.estimators {
		buffer.WriteString(k + "\n")
		temp := est.Serialize()
		buffer.Write(getBytesInt(len(temp)))
		buffer.Write(temp)
	}

	return buffer.Bytes()
}

// Deserialize constructs an Estimator object based on the byte array provided.
func (e *CompositeEstimator) Deserialize(b []byte) {
	buffer := bytes.NewBuffer(b)
	tempInt := make([]byte, 4)
	buffer.Read(tempInt) // consume estimator type
	buffer.Read(tempInt)
	absEstBytes := make([]byte, getIntBytes(tempInt))
	buffer.Read(absEstBytes)
	e.AbstractDatasetSimilarityEstimator =
		*datasetSimilarityEstimatorDeserialize(absEstBytes)

	// parse expression
	line, _ := buffer.ReadString('\n')
	e.expression = strings.TrimSpace(line)

	// parse the estimators
	buffer.Read(tempInt)
	count := getIntBytes(tempInt)
	e.estimators = make(map[string]DatasetSimilarityEstimator)
	for i := 0; i < count; i++ {
		line, _ := buffer.ReadString('\n')
		key := strings.TrimSpace(line)
		buffer.Read(tempInt)
		length := getIntBytes(tempInt)
		tempBuff := make([]byte, length)
		buffer.Read(tempBuff)
		est := DeserializeSimilarityEstimator(tempBuff)
		e.estimators[key] = est
	}
}

// Configure provides the configuration parameters needed by the Estimator
func (e *CompositeEstimator) Configure(conf map[string]string) {
	e.estimators = make(map[string]DatasetSimilarityEstimator)
	for k, v := range conf {
		if k == "concurrency" {
			val, err := strconv.ParseInt(v, 10, 32)
			if err != nil {
				log.Println(err)
			}
			e.concurrency = int(val)
		} else if k == "expression" {
			log.Println(v)
			e.expression = v
		} else {
			estConf := DeserializeConfigurationOptions(v, "|")
			if val, ok := estConf["type"]; ok {
				estType := NewDatasetSimilarityEstimatorType(val)
				if estType != nil {
					est := NewDatasetSimilarityEstimator(*estType, e.datasets)
					est.Configure(estConf)
					e.estimators[k] = est
				} else {
					log.Println("Provided operator does not exist!")
				}
			} else {
				log.Println("Cannot initialize estiamator witout type")
			}
		}
	}
}

// Options returns the applicable parameters needed by the Estimator.
func (e *CompositeEstimator) Options() map[string]string {
	return map[string]string{
		"concurrency": "max number of threads to be run in parallel",
		"expression": "the math expression that combines the estimators " +
			"e.g.: 0.2*x + 0.8*y " +
			"(x and y must be later defined)",
		"x": "the conf parameters for x, separated by | e.g." +
			"type:bhattacharyya|concurrency:10",
		"y": "the conf parameters for y, separated by | e.g." +
			"type:correlation|type:pearson",
	}
}

// SerializeConfigurationOptions is used to transform a map holding the conf
// options into a map
func SerializeConfigurationOptions(conf map[string]string, sep string) string {
	output := ""
	i := 0
	for k, v := range conf {
		output += fmt.Sprintf("%s:%s", k, v)
		if i < len(conf)-1 {
			output += sep
		}
		i++
	}
	return output
}

// DeserializeConfigurationOptions generates a map holding configuration options
// based on the serialized form.
func DeserializeConfigurationOptions(serialized, sep string) map[string]string {
	result := make(map[string]string)
	arr := strings.Split(serialized, sep)
	for i := range arr {
		temp := strings.Split(arr[i], ":")
		if len(temp) != 2 {
			return nil
		}
		result[temp[0]] = temp[1]
	}
	return result
}
<commit_msg>reduced verbosity to logs<commit_after>package core

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"

	"github.com/Knetic/govaluate"
)

// CompositeEstimator returns a similarity function based on
// compositions of simpler similarity expressions. The user needs to provide a
// formula containing the expression of the similarity function, e.g.:
// 0.8 x BHATTACHARRYA + 0.2 CORRELATION
// Note that it is the user's responsibility to guarantee that the overall
// expression remains within the limits of the similarity expression [0,1].
type CompositeEstimator struct {
	AbstractDatasetSimilarityEstimator

	// the slice of estimators to use for the similarity evaluation
	estimators map[string]DatasetSimilarityEstimator
	// the math expression used for the estimation
	expression string
}

// Compute method constructs the Similarity Matrix
func (e *CompositeEstimator) Compute() error {
	for _, est := range e.estimators {
		est.Compute()
	}
	return datasetSimilarityEstimatorCompute(e)
}

// Similarity returns the similarity between two datasets
func (e *CompositeEstimator) Similarity(a, b *Dataset) float64 {
	expression, err := govaluate.NewEvaluableExpression(e.expression)
	if err != nil {
		log.Println(err)
		return 0.0
	}
	params := make(map[string]interface{})
	for k, est := range e.estimators {
		params[k] = est.Similarity(a, b)
	}
	result, err := expression.Evaluate(params)
	if err != nil {
		log.Println(err)
		return 0.0
	}
	if val, ok := result.(float64); ok {
		return val
	}
	return -1.0
}

// Serialize returns an array of bytes representing the Estimator.
func (e *CompositeEstimator) Serialize() []byte {
	buffer := new(bytes.Buffer)
	buffer.Write(getBytesInt(int(SimilarityTypeComposite)))

	buffer.Write(datasetSimilarityEstimatorSerialize(
		e.AbstractDatasetSimilarityEstimator))

	// serialize expression
	buffer.WriteString(e.expression + "\n")

	// serialize estimators
	buffer.Write(getBytesInt(len(e.estimators)))
	for k, est := range e.estimators {
		buffer.WriteString(k + "\n")
		temp := est.Serialize()
		buffer.Write(getBytesInt(len(temp)))
		buffer.Write(temp)
	}

	return buffer.Bytes()
}

// Deserialize constructs an Estimator object based on the byte array provided.
func (e *CompositeEstimator) Deserialize(b []byte) {
	buffer := bytes.NewBuffer(b)
	tempInt := make([]byte, 4)
	buffer.Read(tempInt) // consume estimator type
	buffer.Read(tempInt)
	absEstBytes := make([]byte, getIntBytes(tempInt))
	buffer.Read(absEstBytes)
	e.AbstractDatasetSimilarityEstimator =
		*datasetSimilarityEstimatorDeserialize(absEstBytes)

	// parse expression
	line, _ := buffer.ReadString('\n')
	e.expression = strings.TrimSpace(line)

	// parse the estimators
	buffer.Read(tempInt)
	count := getIntBytes(tempInt)
	e.estimators = make(map[string]DatasetSimilarityEstimator)
	for i := 0; i < count; i++ {
		line, _ := buffer.ReadString('\n')
		key := strings.TrimSpace(line)
		buffer.Read(tempInt)
		length := getIntBytes(tempInt)
		tempBuff := make([]byte, length)
		buffer.Read(tempBuff)
		est := DeserializeSimilarityEstimator(tempBuff)
		e.estimators[key] = est
	}
}

// Configure provides the configuration parameters needed by the Estimator
func (e *CompositeEstimator) Configure(conf map[string]string) {
	e.estimators = make(map[string]DatasetSimilarityEstimator)
	for k, v := range conf {
		if k == "concurrency" {
			val, err := strconv.ParseInt(v, 10, 32)
			if err != nil {
				log.Println(err)
			}
			e.concurrency = int(val)
		} else if k == "expression" {
			e.expression = v
		} else {
			estConf := DeserializeConfigurationOptions(v, "|")
			if val, ok := estConf["type"]; ok {
				estType := NewDatasetSimilarityEstimatorType(val)
				if estType != nil {
					est := NewDatasetSimilarityEstimator(*estType, e.datasets)
					est.Configure(estConf)
					e.estimators[k] = est
				} else {
					log.Println("Provided operator does not exist!")
				}
			} else {
				// Other parameter
			}
		}
	}
}

// Options returns the applicable parameters needed by the Estimator.
func (e *CompositeEstimator) Options() map[string]string {
	return map[string]string{
		"concurrency": "max number of threads to be run in parallel",
		"expression": "the math expression that combines the estimators " +
			"e.g.: 0.2*x + 0.8*y " +
			"(x and y must be later defined)",
		"x": "the conf parameters for x, separated by | e.g." +
			"type:bhattacharyya|concurrency:10",
		"y": "the conf parameters for y, separated by | e.g." +
			"type:correlation|type:pearson",
	}
}

// SerializeConfigurationOptions is used to transform a map holding the conf
// options into a map
func SerializeConfigurationOptions(conf map[string]string, sep string) string {
	output := ""
	i := 0
	for k, v := range conf {
		output += fmt.Sprintf("%s:%s", k, v)
		if i < len(conf)-1 {
			output += sep
		}
		i++
	}
	return output
}

// DeserializeConfigurationOptions generates a map holding configuration options
// based on the serialized form.
func DeserializeConfigurationOptions(serialized, sep string) map[string]string {
	result := make(map[string]string)
	arr := strings.Split(serialized, sep)
	for i := range arr {
		temp := strings.Split(arr[i], ":")
		if len(temp) != 2 {
			return nil
		}
		result[temp[0]] = temp[1]
	}
	return result
}
<|endoftext|>


<commit_before>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter header.  Part of go-diameter.
// http://tools.ietf.org/html/rfc6733#section-3

package base

import "unsafe"

type Header struct {
	Version          uint8
	RawMessageLength [3]uint8
	CommandFlags     uint8
	RawCommandCode   [3]uint8
	ApplicationId    uint32
	HopByHopId       uint32
	EndToEndId       uint32
}

// MessageLength helper function returns RawMessageLength as int.
func (hdr *Header) MessageLength() uint32 {
	return uint24To32(hdr.RawMessageLength)
}

// UpdateLength updates RawMessageLength from an int.
func (hdr *Header) SetMessageLength(length uint32) {
	hdr.RawMessageLength = uint32To24(uint32(unsafe.Sizeof(Header{})) + length)
}

// CommandCode returns RawCommandCode as int.
func (hdr *Header) CommandCode() uint32 {
	return uint24To32(hdr.RawCommandCode)
}
<commit_msg>Cleanup<commit_after>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Diameter header.  Part of go-diameter.
// http://tools.ietf.org/html/rfc6733#section-3

package base

import "unsafe"

type Header struct {
	Version          uint8
	RawMessageLength [3]uint8
	CommandFlags     uint8
	RawCommandCode   [3]uint8
	ApplicationId    uint32
	HopByHopId       uint32
	EndToEndId       uint32
}

const hdrSize = uint32(unsafe.Sizeof(Header{}))

// MessageLength helper function returns RawMessageLength as int.
func (hdr *Header) MessageLength() uint32 {
	return uint24To32(hdr.RawMessageLength)
}

// UpdateLength updates RawMessageLength from an int.
func (hdr *Header) SetMessageLength(length uint32) {
	hdr.RawMessageLength = uint32To24(hdrSize + length)
}

// CommandCode returns RawCommandCode as int.
func (hdr *Header) CommandCode() uint32 {
	return uint24To32(hdr.RawCommandCode)
}
<|endoftext|>