<commit_before>package cmd

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Params currently used:
// token - an OAuth 2.0 bearer token to use when authenticating
// username - the default username to use - if not present, $USER
// endpoint - the default endpoint to use - if not present, https://uk0.bigv.io
// auth-endpoint - the default auth API endpoint to use - if not present, https://auth.bytemark.co.uk

// A Config determines the configuration of the bigv client.
// It's responsible for handling things like the credentials to use and what endpoints to talk to.
//
// Each configuration item is read from the following places, falling back to successive places:
//
// Per-command command-line flags, global command-line flags, environment variables, configuration directory, hard-coded defaults
//
//The location of the configuration directory is read from global command-line flags, or is otherwise ~/.go-bigv
//
type Config struct {
	Dir         string
	Memo        map[string]string
	Definitions map[string]string
}

// Do I really need to have the flags passed in here?
// Yes. Doing commands will be sorted out in a different place, and I don't want to touch it here.

// NewConfig sets up a new config struct. Pass in an empty string to default to ~/.go-bigv
func NewConfig(configDir string, flags *flag.FlagSet) (config *Config) {
	config = new(Config)
	config.Memo = make(map[string]string)
	config.Dir = filepath.Join(os.Getenv("HOME"), "/.go-bigv")
	if os.Getenv("BIGV_CONFIG_DIR") != "" {
		config.Dir = os.Getenv("BIGV_CONFIG_DIR")
	}

	if configDir != "" {
		err := os.MkdirAll(configDir, 0600)
		if err != nil {
			// TODO(telyn): Better error handling here

			panic(err)
		}

		stat, err := os.Stat(configDir)
		if err != nil {
			// TODO(telyn): Better error handling here
			panic(err)
		}

		if !stat.IsDir() {
			fmt.Printf("%s is not a directory", configDir)
			panic("Cannot continue")
		}
		config.Dir = configDir
	}

	if flags != nil {
		// dump all the flags into the memo
		// should be reet...reet?
		flags.Visit(func(f *flag.Flag) {
			config.Memo[f.Name] = f.Value.String()
		})
	}
	return config
}

// GetPath joins the given string onto the end of the Config.Dir path
func (config *Config) GetPath(name string) string {
	return filepath.Join(config.Dir, name)
}
func (config *Config) GetUrl(path ...string) *url.URL {
	url, err := url.Parse(config.Get("endpoint"))
	if err != nil {
		panic("Endpoint is not a valid URL")
	}
	url.Parse("/" + strings.Join([]string(path), "/"))
	return url
}

func (config *Config) LoadDefinitions() {
	stat, err := os.Stat(config.GetPath("definitions"))

	if err != nil || time.Since(stat.ModTime()) > 24*time.Hour {
		// TODO(telyn): grab it off the internet
		//		url := config.GetUrl("definitions.json")
	} else {
		_, err := ioutil.ReadFile(config.GetPath("definitions"))
		if err != nil {
			panic("Couldn't load definitions")
		}
	}

}

func (config *Config) Get(name string) string {
	// try to read the Memo
	if val, ok := config.Memo[name]; ok {
		return val
	} else {
		return config.Read(name)
	}
	return ""
}

// TODO(telyn): write a test for Set

// Set stores the given key-value pair in config's Memo. This storage does not persist once the program terminates.
func (config *Config) Set(name string, value string) {
	config.Memo[name] = value
}

// TODO(telyn): write a test for SetPersistent

// SetPersistent writes a file to the config directory for the given key-value pair.
func (config *Config) SetPersistent(name, value string) {
	config.Set(name, value)
	// TODO(telyn): write a file here
}

func (config *Config) GetDefault(name string) string {
	// ideally most of these should just be	os.Getenv("BIGV_"+name.Upcase().Replace("-","_"))
	switch name {
	case "user":
		return FirstNotEmpty(os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_ENDPOINT"), "https://uk0.bigv.io")
	case "auth-endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_AUTH_ENDPOINT"), "https://auth.bytemark.co.uk")
	case "account":
		return FirstNotEmpty(os.Getenv("BIGV_ACCOUNT"), os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "debug-level":
		return FirstNotEmpty(os.Getenv("BIGV_DEBUG_LEVEL"), "0")
	}
	return ""
}

func (config *Config) Read(name string) string {
	contents, err := ioutil.ReadFile(config.GetPath(name))
	if err != nil {
		if os.IsNotExist(err) {
			return config.GetDefault(name)
		}
		fmt.Printf("Couldn't read config for %s", name)
		panic(err)
	}

	return string(contents)
}
<commit_msg>Implement SetPersistent<commit_after>package cmd

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Params currently used:
// token - an OAuth 2.0 bearer token to use when authenticating
// username - the default username to use - if not present, $USER
// endpoint - the default endpoint to use - if not present, https://uk0.bigv.io
// auth-endpoint - the default auth API endpoint to use - if not present, https://auth.bytemark.co.uk

// A Config determines the configuration of the bigv client.
// It's responsible for handling things like the credentials to use and what endpoints to talk to.
//
// Each configuration item is read from the following places, falling back to successive places:
//
// Per-command command-line flags, global command-line flags, environment variables, configuration directory, hard-coded defaults
//
//The location of the configuration directory is read from global command-line flags, or is otherwise ~/.go-bigv
//
type Config struct {
	Dir         string
	Memo        map[string]string
	Definitions map[string]string
}

// Do I really need to have the flags passed in here?
// Yes. Doing commands will be sorted out in a different place, and I don't want to touch it here.

// NewConfig sets up a new config struct. Pass in an empty string to default to ~/.go-bigv
func NewConfig(configDir string, flags *flag.FlagSet) (config *Config) {
	config = new(Config)
	config.Memo = make(map[string]string)
	config.Dir = filepath.Join(os.Getenv("HOME"), "/.go-bigv")
	if os.Getenv("BIGV_CONFIG_DIR") != "" {
		config.Dir = os.Getenv("BIGV_CONFIG_DIR")
	}

	if configDir != "" {
		err := os.MkdirAll(configDir, 0600)
		if err != nil {
			// TODO(telyn): Better error handling here

			panic(err)
		}

		stat, err := os.Stat(configDir)
		if err != nil {
			// TODO(telyn): Better error handling here
			panic(err)
		}

		if !stat.IsDir() {
			fmt.Printf("%s is not a directory", configDir)
			panic("Cannot continue")
		}
		config.Dir = configDir
	}

	if flags != nil {
		// dump all the flags into the memo
		// should be reet...reet?
		flags.Visit(func(f *flag.Flag) {
			config.Memo[f.Name] = f.Value.String()
		})
	}
	return config
}

// GetPath joins the given string onto the end of the Config.Dir path
func (config *Config) GetPath(name string) string {
	return filepath.Join(config.Dir, name)
}
func (config *Config) GetUrl(path ...string) *url.URL {
	url, err := url.Parse(config.Get("endpoint"))
	if err != nil {
		panic("Endpoint is not a valid URL")
	}
	url.Parse("/" + strings.Join([]string(path), "/"))
	return url
}

func (config *Config) LoadDefinitions() {
	stat, err := os.Stat(config.GetPath("definitions"))

	if err != nil || time.Since(stat.ModTime()) > 24*time.Hour {
		// TODO(telyn): grab it off the internet
		//		url := config.GetUrl("definitions.json")
	} else {
		_, err := ioutil.ReadFile(config.GetPath("definitions"))
		if err != nil {
			panic("Couldn't load definitions")
		}
	}

}

func (config *Config) Get(name string) string {
	// try to read the Memo
	if val, ok := config.Memo[name]; ok {
		return val
	} else {
		return config.Read(name)
	}
	return ""
}

// TODO(telyn): write a test for Set

// Set stores the given key-value pair in config's Memo. This storage does not persist once the program terminates.
func (config *Config) Set(name string, value string) {
	config.Memo[name] = value
}

// TODO(telyn): write a test for SetPersistent

// SetPersistent writes a file to the config directory for the given key-value pair.
func (config *Config) SetPersistent(name, value string) {
	config.Set(name, value)
	err := ioutil.WriteFile(config.GetPath("user"), []byte(value), 0600)
	if err != nil {
		fmt.Println("Couldn't write to config directory " + config.Dir)
		panic(err)
	}
}

func (config *Config) GetDefault(name string) string {
	// ideally most of these should just be	os.Getenv("BIGV_"+name.Upcase().Replace("-","_"))
	switch name {
	case "user":
		return FirstNotEmpty(os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_ENDPOINT"), "https://uk0.bigv.io")
	case "auth-endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_AUTH_ENDPOINT"), "https://auth.bytemark.co.uk")
	case "account":
		return FirstNotEmpty(os.Getenv("BIGV_ACCOUNT"), os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "debug-level":
		return FirstNotEmpty(os.Getenv("BIGV_DEBUG_LEVEL"), "0")
	}
	return ""
}

func (config *Config) Read(name string) string {
	contents, err := ioutil.ReadFile(config.GetPath(name))
	if err != nil {
		if os.IsNotExist(err) {
			return config.GetDefault(name)
		}
		fmt.Printf("Couldn't read config for %s", name)
		panic(err)
	}

	return string(contents)
}
<|endoftext|>


<commit_before>package coal

import (
	"context"
	"net/url"
	"strings"
	"sync"
	"time"

	"github.com/256dpi/lungo"
	"github.com/256dpi/xo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readconcern"
	"go.mongodb.org/mongo-driver/mongo/writeconcern"
)

// MustConnect will call Connect and panic on errors.
func MustConnect(uri string) *Store {
	// connect store
	store, err := Connect(uri)
	if err != nil {
		panic(err)
	}

	return store
}

// Connect will connect to the specified database and return a new store. The
// read and write concern is set to majority by default.
//
// In summary, queries may return data that has bas been committed but may not
// be the most recent committed data. Also, long running cursors on indexed
// fields may return duplicate or missing documents due to the documents moving
// within the index. For operations involving multiple documents a transaction
// must be used to ensure atomicity, consistency and isolation.
func Connect(uri string) (*Store, error) {
	// parse url
	parsedURL, err := url.Parse(uri)
	if err != nil {
		return nil, xo.W(err)
	}

	// get default db
	defaultDB := strings.Trim(parsedURL.Path, "/")

	// prepare options
	opts := options.Client().ApplyURI(uri)
	opts.SetReadConcern(readconcern.Linearizable())
	opts.SetWriteConcern(writeconcern.New(writeconcern.WMajority()))

	// create client
	client, err := lungo.Connect(nil, opts)
	if err != nil {
		return nil, xo.W(err)
	}

	// ping server
	err = client.Ping(nil, nil)
	if err != nil {
		return nil, xo.W(err)
	}

	return NewStore(client, defaultDB, nil), nil
}

// MustOpen will call Open and panic on errors.
func MustOpen(store lungo.Store, defaultDB string, reporter func(error)) *Store {
	// open store
	s, err := Open(store, defaultDB, reporter)
	if err != nil {
		panic(err)
	}

	return s
}

// Open will open the database using the provided lungo store. If the store is
// missing an in-memory store will be created.
func Open(store lungo.Store, defaultDB string, reporter func(error)) (*Store, error) {
	// set default memory store
	if store == nil {
		store = lungo.NewMemoryStore()
	}

	// create client
	client, engine, err := lungo.Open(nil, lungo.Options{
		Store:          store,
		ExpireInterval: time.Minute,
		ExpireErrors:   reporter,
	})
	if err != nil {
		return nil, xo.W(err)
	}

	return NewStore(client, defaultDB, engine), nil
}

// NewStore creates a store that uses the specified client, default database and
// engine. The engine may be nil if no lungo database is used.
func NewStore(client lungo.IClient, defaultDB string, engine *lungo.Engine) *Store {
	return &Store{
		client: client,
		defDB:  defaultDB,
		engine: engine,
	}
}

// A Store manages the usage of a database client.
type Store struct {
	client   lungo.IClient
	defDB    string
	engine   *lungo.Engine
	colls    sync.Map
	managers sync.Map
}

// Client returns the client used by this store.
func (s *Store) Client() lungo.IClient {
	return s.client
}

// DB returns the database used by this store.
func (s *Store) DB() lungo.IDatabase {
	return s.client.Database(s.defDB)
}

// C will return the collection for the specified model. The collection is just
// a thin wrapper around the driver collection API to integrate tracing. Since
// it does not perform any checks, it is recommended to use the manager to
// perform safe CRUD operations.
func (s *Store) C(model Model) *Collection {
	// get name
	name := GetMeta(model).Collection

	// check cache
	val, ok := s.colls.Load(name)
	if ok {
		return val.(*Collection)
	}

	// create collection
	coll := &Collection{
		coll: s.DB().Collection(name),
	}

	// cache collection
	s.colls.Store(name, coll)

	return coll
}

// M will return the manager for the specified model. The manager will translate
// query and update documents as well as perform extensive checks before running
// operations to ensure they are as safe as possible.
func (s *Store) M(model Model) *Manager {
	// get meta
	meta := GetMeta(model)

	// check cache
	val, ok := s.managers.Load(meta)
	if ok {
		return val.(*Manager)
	}

	// create manager
	manager := &Manager{
		meta:  meta,
		coll:  s.C(model),
		trans: NewTranslator(model),
	}

	// cache collection
	s.managers.Store(meta, manager)

	return manager
}

// T will create a transaction around the specified callback. If the callback
// returns no error the transaction will be committed. If T itself does not
// return an error the transaction has been committed. The created context must
// be used with all operations that should be included in the transaction.
//
// A transaction has the effect that the read concern is upgraded to "snapshot"
// which results in isolated and linearizable reads and writes of the data that
// has been committed prior to the start of the transaction:
//
// - Writes that conflict with other transactional writes will return an error.
//   Non-transactional writes will wait until the transaction has completed.
// - Reads are not guaranteed to be stable, another transaction may delete or
//   modify the document an also commit concurrently. Therefore, documents that
//   must "survive" the transaction and cause transactional writes to abort,
//   must be locked by incrementing or changing a field to a new value.
func (s *Store) T(ctx context.Context, fn func(context.Context) error) error {
	// set context background
	if ctx == nil {
		ctx = context.Background()
	}

	// check if transaction already exists
	if HasTransaction(ctx) {
		return fn(ctx)
	}

	// trace
	ctx, span := xo.Trace(ctx, "coal/Store.T")
	defer span.End()

	// prepare options
	opts := options.Session().
		SetCausalConsistency(true).
		SetDefaultReadConcern(readconcern.Snapshot())

	// start transaction
	return xo.W(s.client.UseSessionWithOptions(ctx, opts, func(sc lungo.ISessionContext) error {
		// start transaction
		err := sc.StartTransaction()
		if err != nil {
			return xo.W(err)
		}

		// call function
		err = fn(withKey(sc, hasTransaction))
		if err != nil {
			_ = sc.AbortTransaction(sc)
			return xo.W(err)
		}

		// commit transaction
		err = sc.CommitTransaction(sc)
		if err != nil {
			return xo.W(err)
		}

		return nil
	}))
}

// Close will close the store and its associated client.
func (s *Store) Close() error {
	// disconnect client
	err := s.client.Disconnect(nil)
	if err != nil {
		return xo.W(err)
	}

	// close engine
	if s.engine != nil {
		s.engine.Close()
	}

	return nil
}

type contextKey struct{}

var hasTransaction = contextKey{}

func withKey(ctx context.Context, key interface{}) context.Context {
	return context.WithValue(ctx, key, true)
}

func getKey(ctx context.Context, key interface{}) bool {
	if ctx != nil {
		ok, _ := ctx.Value(key).(bool)
		return ok
	}

	return false
}

// HasTransaction will return whether the context carries a transaction.
func HasTransaction(ctx context.Context) bool {
	return getKey(ctx, hasTransaction)
}
<commit_msg>use meta as key<commit_after>package coal

import (
	"context"
	"net/url"
	"strings"
	"sync"
	"time"

	"github.com/256dpi/lungo"
	"github.com/256dpi/xo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readconcern"
	"go.mongodb.org/mongo-driver/mongo/writeconcern"
)

// MustConnect will call Connect and panic on errors.
func MustConnect(uri string) *Store {
	// connect store
	store, err := Connect(uri)
	if err != nil {
		panic(err)
	}

	return store
}

// Connect will connect to the specified database and return a new store. The
// read and write concern is set to majority by default.
//
// In summary, queries may return data that has bas been committed but may not
// be the most recent committed data. Also, long running cursors on indexed
// fields may return duplicate or missing documents due to the documents moving
// within the index. For operations involving multiple documents a transaction
// must be used to ensure atomicity, consistency and isolation.
func Connect(uri string) (*Store, error) {
	// parse url
	parsedURL, err := url.Parse(uri)
	if err != nil {
		return nil, xo.W(err)
	}

	// get default db
	defaultDB := strings.Trim(parsedURL.Path, "/")

	// prepare options
	opts := options.Client().ApplyURI(uri)
	opts.SetReadConcern(readconcern.Linearizable())
	opts.SetWriteConcern(writeconcern.New(writeconcern.WMajority()))

	// create client
	client, err := lungo.Connect(nil, opts)
	if err != nil {
		return nil, xo.W(err)
	}

	// ping server
	err = client.Ping(nil, nil)
	if err != nil {
		return nil, xo.W(err)
	}

	return NewStore(client, defaultDB, nil), nil
}

// MustOpen will call Open and panic on errors.
func MustOpen(store lungo.Store, defaultDB string, reporter func(error)) *Store {
	// open store
	s, err := Open(store, defaultDB, reporter)
	if err != nil {
		panic(err)
	}

	return s
}

// Open will open the database using the provided lungo store. If the store is
// missing an in-memory store will be created.
func Open(store lungo.Store, defaultDB string, reporter func(error)) (*Store, error) {
	// set default memory store
	if store == nil {
		store = lungo.NewMemoryStore()
	}

	// create client
	client, engine, err := lungo.Open(nil, lungo.Options{
		Store:          store,
		ExpireInterval: time.Minute,
		ExpireErrors:   reporter,
	})
	if err != nil {
		return nil, xo.W(err)
	}

	return NewStore(client, defaultDB, engine), nil
}

// NewStore creates a store that uses the specified client, default database and
// engine. The engine may be nil if no lungo database is used.
func NewStore(client lungo.IClient, defaultDB string, engine *lungo.Engine) *Store {
	return &Store{
		client: client,
		defDB:  defaultDB,
		engine: engine,
	}
}

// A Store manages the usage of a database client.
type Store struct {
	client   lungo.IClient
	defDB    string
	engine   *lungo.Engine
	colls    sync.Map
	managers sync.Map
}

// Client returns the client used by this store.
func (s *Store) Client() lungo.IClient {
	return s.client
}

// DB returns the database used by this store.
func (s *Store) DB() lungo.IDatabase {
	return s.client.Database(s.defDB)
}

// C will return the collection for the specified model. The collection is just
// a thin wrapper around the driver collection API to integrate tracing. Since
// it does not perform any checks, it is recommended to use the manager to
// perform safe CRUD operations.
func (s *Store) C(model Model) *Collection {
	// get meta
	meta := GetMeta(model)

	// check cache
	val, ok := s.colls.Load(meta)
	if ok {
		return val.(*Collection)
	}

	// create collection
	coll := &Collection{
		coll: s.DB().Collection(meta.Collection),
	}

	// cache collection
	s.colls.Store(meta, coll)

	return coll
}

// M will return the manager for the specified model. The manager will translate
// query and update documents as well as perform extensive checks before running
// operations to ensure they are as safe as possible.
func (s *Store) M(model Model) *Manager {
	// get meta
	meta := GetMeta(model)

	// check cache
	val, ok := s.managers.Load(meta)
	if ok {
		return val.(*Manager)
	}

	// create manager
	manager := &Manager{
		meta:  meta,
		coll:  s.C(model),
		trans: NewTranslator(model),
	}

	// cache collection
	s.managers.Store(meta, manager)

	return manager
}

// T will create a transaction around the specified callback. If the callback
// returns no error the transaction will be committed. If T itself does not
// return an error the transaction has been committed. The created context must
// be used with all operations that should be included in the transaction.
//
// A transaction has the effect that the read concern is upgraded to "snapshot"
// which results in isolated and linearizable reads and writes of the data that
// has been committed prior to the start of the transaction:
//
// - Writes that conflict with other transactional writes will return an error.
//   Non-transactional writes will wait until the transaction has completed.
// - Reads are not guaranteed to be stable, another transaction may delete or
//   modify the document an also commit concurrently. Therefore, documents that
//   must "survive" the transaction and cause transactional writes to abort,
//   must be locked by incrementing or changing a field to a new value.
func (s *Store) T(ctx context.Context, fn func(context.Context) error) error {
	// set context background
	if ctx == nil {
		ctx = context.Background()
	}

	// check if transaction already exists
	if HasTransaction(ctx) {
		return fn(ctx)
	}

	// trace
	ctx, span := xo.Trace(ctx, "coal/Store.T")
	defer span.End()

	// prepare options
	opts := options.Session().
		SetCausalConsistency(true).
		SetDefaultReadConcern(readconcern.Snapshot())

	// start transaction
	return xo.W(s.client.UseSessionWithOptions(ctx, opts, func(sc lungo.ISessionContext) error {
		// start transaction
		err := sc.StartTransaction()
		if err != nil {
			return xo.W(err)
		}

		// call function
		err = fn(withKey(sc, hasTransaction))
		if err != nil {
			_ = sc.AbortTransaction(sc)
			return xo.W(err)
		}

		// commit transaction
		err = sc.CommitTransaction(sc)
		if err != nil {
			return xo.W(err)
		}

		return nil
	}))
}

// Close will close the store and its associated client.
func (s *Store) Close() error {
	// disconnect client
	err := s.client.Disconnect(nil)
	if err != nil {
		return xo.W(err)
	}

	// close engine
	if s.engine != nil {
		s.engine.Close()
	}

	return nil
}

type contextKey struct{}

var hasTransaction = contextKey{}

func withKey(ctx context.Context, key interface{}) context.Context {
	return context.WithValue(ctx, key, true)
}

func getKey(ctx context.Context, key interface{}) bool {
	if ctx != nil {
		ok, _ := ctx.Value(key).(bool)
		return ok
	}

	return false
}

// HasTransaction will return whether the context carries a transaction.
func HasTransaction(ctx context.Context) bool {
	return getKey(ctx, hasTransaction)
}
<|endoftext|>


<commit_before>package common

func Bin(input []byte, key_size int) [][]byte {
	if len(input) < key_size {
		panic("length of input cannot be smaller than key size")
	}

	input_len := len(input)
	bin_length :=  ((input_len - 1) / key_size) + 1

	bins := make([][]byte, bin_length)

	for i := 0; i < bin_length; i++ {
		bin := input[(i*key_size):min(input_len, (i+1)*key_size)]

		bin_copied := make([]byte, len(bin))
		copy(bin_copied, bin)

		bins[i] = bin_copied
	}

	return bins
}

func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}<commit_msg>Rename input var<commit_after>package common

// Bin the input given the size
// This function copies the input array
func Bin(input []byte, bin_size int) [][]byte {
	if len(input) < bin_size {
		panic("length of input cannot be smaller than key size")
	}

	input_len := len(input)
	bin_length :=  ((input_len - 1) / bin_size) + 1

	bins := make([][]byte, bin_length)

	for i := 0; i < bin_length; i++ {
		bin := input[(i* bin_size):min(input_len, (i+1)*bin_size)]

		bin_copied := make([]byte, len(bin))
		copy(bin_copied, bin)

		bins[i] = bin_copied
	}

	return bins
}

func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}<|endoftext|>


<commit_before>package project

import (
	"golang.org/x/net/context"

	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project/events"
	"github.com/docker/libcompose/project/options"
)

// this ensures EmptyService implements Service
// useful since it's easy to forget adding new functions to EmptyService
var _ Service = &EmptyService{}

// EmptyService is a struct that implements Service but does nothing.
type EmptyService struct {
}

// Create implements Service.Create but does nothing.
func (e *EmptyService) Create(ctx context.Context, options options.Create) error {
	return nil
}

// Build implements Service.Build but does nothing.
func (e *EmptyService) Build(ctx context.Context, buildOptions options.Build) error {
	return nil
}

// Up implements Service.Up but does nothing.
func (e *EmptyService) Up(ctx context.Context, options options.Up) error {
	return nil
}

// Start implements Service.Start but does nothing.
func (e *EmptyService) Start(ctx context.Context) error {
	return nil
}

// Stop implements Service.Stop() but does nothing.
func (e *EmptyService) Stop(ctx context.Context, timeout int) error {
	return nil
}

// Delete implements Service.Delete but does nothing.
func (e *EmptyService) Delete(ctx context.Context, options options.Delete) error {
	return nil
}

// Restart implements Service.Restart but does nothing.
func (e *EmptyService) Restart(ctx context.Context, timeout int) error {
	return nil
}

// Log implements Service.Log but does nothing.
func (e *EmptyService) Log(ctx context.Context, follow bool) error {
	return nil
}

// Pull implements Service.Pull but does nothing.
func (e *EmptyService) Pull(ctx context.Context) error {
	return nil
}

// Kill implements Service.Kill but does nothing.
func (e *EmptyService) Kill(ctx context.Context, signal string) error {
	return nil
}

// Containers implements Service.Containers but does nothing.
func (e *EmptyService) Containers(ctx context.Context) ([]Container, error) {
	return []Container{}, nil
}

// Scale implements Service.Scale but does nothing.
func (e *EmptyService) Scale(ctx context.Context, count int, timeout int) error {
	return nil
}

// Info implements Service.Info but does nothing.
func (e *EmptyService) Info(ctx context.Context, qFlag bool) (InfoSet, error) {
	return InfoSet{}, nil
}

// Pause implements Service.Pause but does nothing.
func (e *EmptyService) Pause(ctx context.Context) error {
	return nil
}

// Unpause implements Service.Pause but does nothing.
func (e *EmptyService) Unpause(ctx context.Context) error {
	return nil
}

// Run implements Service.Run but does nothing.
func (e *EmptyService) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
	return 0, nil
}

// RemoveImage implements Service.RemoveImage but does nothing.
func (e *EmptyService) RemoveImage(ctx context.Context, imageType options.ImageType) error {
	return nil
}

// Events implements Service.Events but does nothing.
func (e *EmptyService) Events(ctx context.Context, events chan events.ContainerEvent) error {
	return nil
}

// DependentServices implements Service.DependentServices with empty slice.
func (e *EmptyService) DependentServices() []ServiceRelationship {
	return []ServiceRelationship{}
}

// Config implements Service.Config with empty config.
func (e *EmptyService) Config() *config.ServiceConfig {
	return &config.ServiceConfig{}
}

// Name implements Service.Name with empty name.
func (e *EmptyService) Name() string {
	return ""
}
<commit_msg>Add EmptyNetworks struct<commit_after>package project

import (
	"golang.org/x/net/context"

	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project/events"
	"github.com/docker/libcompose/project/options"
)

// this ensures EmptyService implements Service
// useful since it's easy to forget adding new functions to EmptyService
var _ Service = (*EmptyService)(nil)

// EmptyService is a struct that implements Service but does nothing.
type EmptyService struct {
}

// Create implements Service.Create but does nothing.
func (e *EmptyService) Create(ctx context.Context, options options.Create) error {
	return nil
}

// Build implements Service.Build but does nothing.
func (e *EmptyService) Build(ctx context.Context, buildOptions options.Build) error {
	return nil
}

// Up implements Service.Up but does nothing.
func (e *EmptyService) Up(ctx context.Context, options options.Up) error {
	return nil
}

// Start implements Service.Start but does nothing.
func (e *EmptyService) Start(ctx context.Context) error {
	return nil
}

// Stop implements Service.Stop() but does nothing.
func (e *EmptyService) Stop(ctx context.Context, timeout int) error {
	return nil
}

// Delete implements Service.Delete but does nothing.
func (e *EmptyService) Delete(ctx context.Context, options options.Delete) error {
	return nil
}

// Restart implements Service.Restart but does nothing.
func (e *EmptyService) Restart(ctx context.Context, timeout int) error {
	return nil
}

// Log implements Service.Log but does nothing.
func (e *EmptyService) Log(ctx context.Context, follow bool) error {
	return nil
}

// Pull implements Service.Pull but does nothing.
func (e *EmptyService) Pull(ctx context.Context) error {
	return nil
}

// Kill implements Service.Kill but does nothing.
func (e *EmptyService) Kill(ctx context.Context, signal string) error {
	return nil
}

// Containers implements Service.Containers but does nothing.
func (e *EmptyService) Containers(ctx context.Context) ([]Container, error) {
	return []Container{}, nil
}

// Scale implements Service.Scale but does nothing.
func (e *EmptyService) Scale(ctx context.Context, count int, timeout int) error {
	return nil
}

// Info implements Service.Info but does nothing.
func (e *EmptyService) Info(ctx context.Context, qFlag bool) (InfoSet, error) {
	return InfoSet{}, nil
}

// Pause implements Service.Pause but does nothing.
func (e *EmptyService) Pause(ctx context.Context) error {
	return nil
}

// Unpause implements Service.Pause but does nothing.
func (e *EmptyService) Unpause(ctx context.Context) error {
	return nil
}

// Run implements Service.Run but does nothing.
func (e *EmptyService) Run(ctx context.Context, commandParts []string, options options.Run) (int, error) {
	return 0, nil
}

// RemoveImage implements Service.RemoveImage but does nothing.
func (e *EmptyService) RemoveImage(ctx context.Context, imageType options.ImageType) error {
	return nil
}

// Events implements Service.Events but does nothing.
func (e *EmptyService) Events(ctx context.Context, events chan events.ContainerEvent) error {
	return nil
}

// DependentServices implements Service.DependentServices with empty slice.
func (e *EmptyService) DependentServices() []ServiceRelationship {
	return []ServiceRelationship{}
}

// Config implements Service.Config with empty config.
func (e *EmptyService) Config() *config.ServiceConfig {
	return &config.ServiceConfig{}
}

// Name implements Service.Name with empty name.
func (e *EmptyService) Name() string {
	return ""
}

// this ensures EmptyNetworks implements Networks
var _ Networks = (*EmptyNetworks)(nil)

// EmptyNetworks is a struct that implements Networks but does nothing.
type EmptyNetworks struct {
}

// Initialize implements Networks.Initialize but does nothing.
func (e *EmptyNetworks) Initialize(ctx context.Context) error {
	return nil
}

// Initialize implements Networks.Remove but does nothing.
func (e *EmptyNetworks) Remove(ctx context.Context) error {
	return nil
}
<|endoftext|>


<commit_before>// Code generated by protoc-gen-go.
// source: messages.proto
// DO NOT EDIT!

/*
Package dht is a generated protocol buffer package.

It is generated from these files:
	messages.proto

It has these top-level messages:
	Message
*/
package dht

import proto "code.google.com/p/goprotobuf/proto"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf

type Message_MessageType int32

const (
	Message_PUT_VALUE     Message_MessageType = 0
	Message_GET_VALUE     Message_MessageType = 1
	Message_ADD_PROVIDER  Message_MessageType = 2
	Message_GET_PROVIDERS Message_MessageType = 3
	Message_FIND_NODE     Message_MessageType = 4
	Message_PING          Message_MessageType = 5
)

var Message_MessageType_name = map[int32]string{
	0: "PUT_VALUE",
	1: "GET_VALUE",
	2: "ADD_PROVIDER",
	3: "GET_PROVIDERS",
	4: "FIND_NODE",
	5: "PING",
}
var Message_MessageType_value = map[string]int32{
	"PUT_VALUE":     0,
	"GET_VALUE":     1,
	"ADD_PROVIDER":  2,
	"GET_PROVIDERS": 3,
	"FIND_NODE":     4,
	"PING":          5,
}

func (x Message_MessageType) Enum() *Message_MessageType {
	p := new(Message_MessageType)
	*p = x
	return p
}
func (x Message_MessageType) String() string {
	return proto.EnumName(Message_MessageType_name, int32(x))
}
func (x *Message_MessageType) UnmarshalJSON(data []byte) error {
	value, err := proto.UnmarshalJSONEnum(Message_MessageType_value, data, "Message_MessageType")
	if err != nil {
		return err
	}
	*x = Message_MessageType(value)
	return nil
}

type Message struct {
	// defines what type of message it is.
	Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=dht.Message_MessageType" json:"type,omitempty"`
	// defines what coral cluster level this query/response belongs to.
	ClusterLevelRaw *int32 `protobuf:"varint,10,opt,name=clusterLevelRaw" json:"clusterLevelRaw,omitempty"`
	// Used to specify the key associated with this message.
	// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
	Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"`
	// Used to return a value
	// PUT_VALUE, GET_VALUE
	Value []byte `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"`
	// Used to return peers closer to a key in a query
	// GET_VALUE, GET_PROVIDERS, FIND_NODE
	CloserPeers []*Message_Peer `protobuf:"bytes,8,rep,name=closerPeers" json:"closerPeers,omitempty"`
	// Used to return Providers
	// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
	ProviderPeers    []*Message_Peer `protobuf:"bytes,9,rep,name=providerPeers" json:"providerPeers,omitempty"`
	XXX_unrecognized []byte          `json:"-"`
}

func (m *Message) Reset()         { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage()    {}

func (m *Message) GetType() Message_MessageType {
	if m != nil && m.Type != nil {
		return *m.Type
	}
	return Message_PUT_VALUE
}

func (m *Message) GetClusterLevelRaw() int32 {
	if m != nil && m.ClusterLevelRaw != nil {
		return *m.ClusterLevelRaw
	}
	return 0
}

func (m *Message) GetKey() string {
	if m != nil && m.Key != nil {
		return *m.Key
	}
	return ""
}

func (m *Message) GetValue() []byte {
	if m != nil {
		return m.Value
	}
	return nil
}

func (m *Message) GetCloserPeers() []*Message_Peer {
	if m != nil {
		return m.CloserPeers
	}
	return nil
}

func (m *Message) GetProviderPeers() []*Message_Peer {
	if m != nil {
		return m.ProviderPeers
	}
	return nil
}

type Message_Peer struct {
	Id               *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
	Addr             *string `protobuf:"bytes,2,opt,name=addr" json:"addr,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (m *Message_Peer) Reset()         { *m = Message_Peer{} }
func (m *Message_Peer) String() string { return proto.CompactTextString(m) }
func (*Message_Peer) ProtoMessage()    {}

func (m *Message_Peer) GetId() string {
	if m != nil && m.Id != nil {
		return *m.Id
	}
	return ""
}

func (m *Message_Peer) GetAddr() string {
	if m != nil && m.Addr != nil {
		return *m.Addr
	}
	return ""
}

func init() {
	proto.RegisterEnum("dht.Message_MessageType", Message_MessageType_name, Message_MessageType_value)
}
<commit_msg>make vendor<commit_after>// Code generated by protoc-gen-go.
// source: messages.proto
// DO NOT EDIT!

/*
Package dht is a generated protocol buffer package.

It is generated from these files:
	messages.proto

It has these top-level messages:
	Message
*/
package dht

import proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = math.Inf

type Message_MessageType int32

const (
	Message_PUT_VALUE     Message_MessageType = 0
	Message_GET_VALUE     Message_MessageType = 1
	Message_ADD_PROVIDER  Message_MessageType = 2
	Message_GET_PROVIDERS Message_MessageType = 3
	Message_FIND_NODE     Message_MessageType = 4
	Message_PING          Message_MessageType = 5
)

var Message_MessageType_name = map[int32]string{
	0: "PUT_VALUE",
	1: "GET_VALUE",
	2: "ADD_PROVIDER",
	3: "GET_PROVIDERS",
	4: "FIND_NODE",
	5: "PING",
}
var Message_MessageType_value = map[string]int32{
	"PUT_VALUE":     0,
	"GET_VALUE":     1,
	"ADD_PROVIDER":  2,
	"GET_PROVIDERS": 3,
	"FIND_NODE":     4,
	"PING":          5,
}

func (x Message_MessageType) Enum() *Message_MessageType {
	p := new(Message_MessageType)
	*p = x
	return p
}
func (x Message_MessageType) String() string {
	return proto.EnumName(Message_MessageType_name, int32(x))
}
func (x *Message_MessageType) UnmarshalJSON(data []byte) error {
	value, err := proto.UnmarshalJSONEnum(Message_MessageType_value, data, "Message_MessageType")
	if err != nil {
		return err
	}
	*x = Message_MessageType(value)
	return nil
}

type Message struct {
	// defines what type of message it is.
	Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=dht.Message_MessageType" json:"type,omitempty"`
	// defines what coral cluster level this query/response belongs to.
	ClusterLevelRaw *int32 `protobuf:"varint,10,opt,name=clusterLevelRaw" json:"clusterLevelRaw,omitempty"`
	// Used to specify the key associated with this message.
	// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
	Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"`
	// Used to return a value
	// PUT_VALUE, GET_VALUE
	Value []byte `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"`
	// Used to return peers closer to a key in a query
	// GET_VALUE, GET_PROVIDERS, FIND_NODE
	CloserPeers []*Message_Peer `protobuf:"bytes,8,rep,name=closerPeers" json:"closerPeers,omitempty"`
	// Used to return Providers
	// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
	ProviderPeers    []*Message_Peer `protobuf:"bytes,9,rep,name=providerPeers" json:"providerPeers,omitempty"`
	XXX_unrecognized []byte          `json:"-"`
}

func (m *Message) Reset()         { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage()    {}

func (m *Message) GetType() Message_MessageType {
	if m != nil && m.Type != nil {
		return *m.Type
	}
	return Message_PUT_VALUE
}

func (m *Message) GetClusterLevelRaw() int32 {
	if m != nil && m.ClusterLevelRaw != nil {
		return *m.ClusterLevelRaw
	}
	return 0
}

func (m *Message) GetKey() string {
	if m != nil && m.Key != nil {
		return *m.Key
	}
	return ""
}

func (m *Message) GetValue() []byte {
	if m != nil {
		return m.Value
	}
	return nil
}

func (m *Message) GetCloserPeers() []*Message_Peer {
	if m != nil {
		return m.CloserPeers
	}
	return nil
}

func (m *Message) GetProviderPeers() []*Message_Peer {
	if m != nil {
		return m.ProviderPeers
	}
	return nil
}

type Message_Peer struct {
	Id               *string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
	Addr             *string `protobuf:"bytes,2,opt,name=addr" json:"addr,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (m *Message_Peer) Reset()         { *m = Message_Peer{} }
func (m *Message_Peer) String() string { return proto.CompactTextString(m) }
func (*Message_Peer) ProtoMessage()    {}

func (m *Message_Peer) GetId() string {
	if m != nil && m.Id != nil {
		return *m.Id
	}
	return ""
}

func (m *Message_Peer) GetAddr() string {
	if m != nil && m.Addr != nil {
		return *m.Addr
	}
	return ""
}

func init() {
	proto.RegisterEnum("dht.Message_MessageType", Message_MessageType_name, Message_MessageType_value)
}
<|endoftext|>


<commit_before>package query

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/yuuki/dynamond/model"
)

func TestGcd(t *testing.T) {
	assert.Equal(t, 32, gcd(128, 32))
	assert.Equal(t, 3, gcd(237, 9))
}

func TestLcm(t *testing.T) {
	assert.Equal(t, 24, lcm(12, 24))
	assert.Equal(t, 756, lcm(27, 28))
}

func TestFormatSeries_Uniq(t *testing.T) {
	seriesList := []*model.Metric{
		&model.Metric{Name: "server1.cpu.system"},
		&model.Metric{Name: "server2.cpu.system"},
		&model.Metric{Name: "server3.cpu.system"},
	}
	format := formatSeries(seriesList)
	assert.Equal(t, "server1.cpu.system,server2.cpu.system,server3.cpu.system", format)
}

func TestFormatSeries_NotUniq(t *testing.T) {
	seriesList := []*model.Metric{
		&model.Metric{Name: "server3.cpu.system"},
		&model.Metric{Name: "server1.cpu.system"},
		&model.Metric{Name: "server2.cpu.system"},
		&model.Metric{Name: "server1.cpu.system"},
	}
	format := formatSeries(seriesList)
	assert.Equal(t, "server1.cpu.system,server2.cpu.system,server3.cpu.system", format)
}

func TestNormalize_Empty(t *testing.T) {
	seriesList, start, end, step := normalize([]*model.Metric{})
	assert.Equal(t, 0, len(seriesList))
	assert.Equal(t, int32(0), start)
	assert.Equal(t, int32(0), end)
	assert.Equal(t, 0, step)
}

func TestNormalize_NonValues(t *testing.T) {
	seriesList, start, end, step := normalize([]*model.Metric{
		&model.Metric{
			Name: "collectd.test-db{0}.load.value",
			Step: 1,
			Start: int32(1),
			End: int32(5),
		},
	})
	assert.Equal(t, "collectd.test-db{0}.load.value", seriesList[0].Name)
	assert.Equal(t, int32(1), start)
	assert.Equal(t, int32(5), end)
	assert.Equal(t, 1, step)
}

func TestAlias(t *testing.T) {
	seriesList := []*model.Metric{
		model.NewMetric(
			"Sales.widgets.largeBlue",
			[]*model.DataPoint{
				&model.DataPoint{1465516810, 10.0},
			},
			60,
		),
		model.NewMetric(
			"Servers.web01.sda1.free_space",
			[]*model.DataPoint{
				&model.DataPoint{1465516810, 10.0},
			},
			60,
		),
	}
	metricList := alias(seriesList, "Large Blue Widgets")
	assert.Equal(t, 2, len(metricList))
	assert.Equal(t, metricList[0].Name, "Large Blue Widgets")
	assert.Equal(t, metricList[1].Name, "Large Blue Widgets")
}
<commit_msg>Add generateSeriesList() as test helper<commit_after>package query

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/yuuki/dynamond/model"
)

func TestGcd(t *testing.T) {
	assert.Equal(t, 32, gcd(128, 32))
	assert.Equal(t, 3, gcd(237, 9))
}

func TestLcm(t *testing.T) {
	assert.Equal(t, 24, lcm(12, 24))
	assert.Equal(t, 756, lcm(27, 28))
}

func generateSeriesList() []*model.Metric {
	step := 1
	datapoints1 := make([]*model.DataPoint, 0, 100)
	for i := 0; i < 100; i++ {
		datapoints1 = append(datapoints1, &model.DataPoint{Timestamp: int32(step*i), Value: float64(i+1)})
	}
	datapoints2 := make([]*model.DataPoint, 0, 100)
	for i := 0; i < 100; i++ {
		datapoints2 = append(datapoints2, &model.DataPoint{Timestamp: int32(step*i), Value: float64(i+1)})
	}
	datapoints3 := make([]*model.DataPoint, 0, 1)
	datapoints3 = append(datapoints3, &model.DataPoint{Timestamp: 0, Value: float64(1)})

	seriesList := make([]*model.Metric, 3)
	seriesList[0] = model.NewMetric(fmt.Sprintf("collectd.test-db%d.load.value", 0), datapoints1, 1)
	seriesList[1] = model.NewMetric(fmt.Sprintf("collectd.test-db%d.load.value", 1), datapoints2, 1)
	seriesList[2] = model.NewMetric(fmt.Sprintf("collectd.test-db%d.load.value", 2), datapoints3, 1)

        return seriesList
}

func TestFormatSeries_Uniq(t *testing.T) {
	seriesList := []*model.Metric{
		&model.Metric{Name: "server1.cpu.system"},
		&model.Metric{Name: "server2.cpu.system"},
		&model.Metric{Name: "server3.cpu.system"},
	}
	format := formatSeries(seriesList)
	assert.Equal(t, "server1.cpu.system,server2.cpu.system,server3.cpu.system", format)
}

func TestFormatSeries_NotUniq(t *testing.T) {
	seriesList := []*model.Metric{
		&model.Metric{Name: "server3.cpu.system"},
		&model.Metric{Name: "server1.cpu.system"},
		&model.Metric{Name: "server2.cpu.system"},
		&model.Metric{Name: "server1.cpu.system"},
	}
	format := formatSeries(seriesList)
	assert.Equal(t, "server1.cpu.system,server2.cpu.system,server3.cpu.system", format)
}

func TestNormalize_Empty(t *testing.T) {
	seriesList, start, end, step := normalize([]*model.Metric{})
	assert.Equal(t, 0, len(seriesList))
	assert.Equal(t, int32(0), start)
	assert.Equal(t, int32(0), end)
	assert.Equal(t, 0, step)
}

func TestNormalize_NonValues(t *testing.T) {
	seriesList, start, end, step := normalize([]*model.Metric{
		&model.Metric{
			Name: "collectd.test-db{0}.load.value",
			Step: 1,
			Start: int32(1),
			End: int32(5),
		},
	})
	assert.Equal(t, "collectd.test-db{0}.load.value", seriesList[0].Name)
	assert.Equal(t, int32(1), start)
	assert.Equal(t, int32(5), end)
	assert.Equal(t, 1, step)
}

func TestAlias(t *testing.T) {
	seriesList := []*model.Metric{
		model.NewMetric(
			"Sales.widgets.largeBlue",
			[]*model.DataPoint{
				&model.DataPoint{1465516810, 10.0},
			},
			60,
		),
		model.NewMetric(
			"Servers.web01.sda1.free_space",
			[]*model.DataPoint{
				&model.DataPoint{1465516810, 10.0},
			},
			60,
		),
	}
	metricList := alias(seriesList, "Large Blue Widgets")
	assert.Equal(t, 2, len(metricList))
	assert.Equal(t, metricList[0].Name, "Large Blue Widgets")
	assert.Equal(t, metricList[1].Name, "Large Blue Widgets")
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"
)

type FailureFunc func(int, string)
type SuccessNewFunc func(int64)
type SuccessPutFunc func(js.Object)

func UnpackJson(ptrToStruct interface{}, jsonBlob js.Object) error {
	t := reflect.TypeOf(ptrToStruct)
	if t.Kind() != reflect.Ptr {
		return fmt.Errorf("expected pointer to struct, but got %v", t.Kind())
	}
	elem := t.Elem()
	if elem.Kind() != reflect.Struct {
		return fmt.Errorf("expected pointer to struct, but got pointer to  %v", elem.Kind())

	}
	v := reflect.ValueOf(ptrToStruct)
	v = v.Elem()
	for i := 0; i < elem.NumField(); i++ {
		f := v.Field(i)
		name := elem.Field(i).Tag.Get("json")
		if jsonBlob.Get(name).IsUndefined() || jsonBlob.Get(name).IsNull() {
			continue
		}
		switch f.Type().Kind() {
		case reflect.Int64:
			f.SetInt(jsonBlob.Get(name).Int64())
		case reflect.String:
			f.SetString(jsonBlob.Get(name).Str())
		case reflect.Float64:
			f.SetFloat(jsonBlob.Get(name).Float())
		case reflect.Bool:
			f.SetBool(jsonBlob.Get(name).Bool())
		default:
			print("warning: %s", name, " has a type other than int64, string, float64 or bool")
		}
	}
	return nil
}

//PutExisting sends a new version of the object given by id to the server.
//It returns an error only if the put could not be started, otherwise success
//or failure are communicated throught the callback functions.  The root should
//be the root of the rest heirarchy, probably "/rest".  The id is not examined
//by this routine, it can be the string representation of an integer or a UDID.
func PutExisting(i interface{}, root string, id string,
	success SuccessPutFunc, failure FailureFunc) error {

	var w bytes.Buffer
	enc := json.NewEncoder(&w)
	err := enc.Encode(i)
	if err != nil {
		return fmt.Errorf("error encoding put msg: %v ", err)
	}

	urlname := typeToUrlName(i)
	jquery.Ajax(
		map[string]interface{}{
			"contentType": "application/json",
			"dataType":    "json",
			"type":        "PUT",
			"url":         fmt.Sprintf("%s/%s/%s", root, urlname, id),
			"data":        w.String(),
			"cache":       false,
		}).
		Then(func(v js.Object) {
		success(v)
	}).
		Fail(func(p1 js.Object) {
		if failure != nil {
			failure(p1.Get("status").Int(), p1.Get("responseText").Str())
		}
	})

	return nil
}
func typeToUrlName(i interface{}) string {
	name := fmt.Sprintf("%T", i)
	pair := strings.Split(name, ".")
	if len(pair) != 2 {
		panic(fmt.Sprintf("unable to understand type name: %s", name))
	}
	return strings.ToLower(pair[1])
}

//PostNew sends an instance of a wire type to the server.  It returns an error
//only if the Post could not be sent.  The success or failure are indications are
//communicated through the callback functions.
func PostNew(i interface{}, root string, success SuccessNewFunc, failure FailureFunc) error {
	var w bytes.Buffer
	enc := json.NewEncoder(&w)
	err := enc.Encode(i)
	if err != nil {
		return fmt.Errorf("error encoding post msg: %v ", err)
	}
	urlname := typeToUrlName(i)
	jquery.Ajax(
		map[string]interface{}{
			"contentType": "application/json",
			"dataType":    "json",
			"type":        "POST",
			"url":         fmt.Sprintf("%s/%s", root, urlname),
			"data":        w.String(),
			"cache":       false,
		}).
		Then(func(valueCreated js.Object) {
		id := valueCreated.Get("Id").Int64()
		if success != nil {
			success(id)
		}
	}).
		Fail(func(p1 js.Object) {
		if failure != nil {
			failure(p1.Get("status").Int(), p1.Get("responseText").Str())
		}
	})

	return nil
}
<commit_msg>improved json tag handling<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"
)

type FailureFunc func(int, string)
type SuccessNewFunc func(int64)
type SuccessPutFunc func(js.Object)

func getFieldName(f reflect.StructField) string {
	name := f.Tag.Get("json")
	jsonPreferred := ""
	if name != "" {
		parts := strings.Split(name, ",")
		for _, part := range parts {
			if part == "-" {
				return "-"
			}
			if part == "omitempty" {
				continue
			}
			jsonPreferred = part
		}
	}
	if jsonPreferred != "" {
		return jsonPreferred
	}
	return f.Name
}
func UnpackJson(ptrToStruct interface{}, jsonBlob js.Object) error {
	t := reflect.TypeOf(ptrToStruct)
	if t.Kind() != reflect.Ptr {
		return fmt.Errorf("expected pointer to struct, but got %v", t.Kind())
	}
	elem := t.Elem()
	if elem.Kind() != reflect.Struct {
		return fmt.Errorf("expected pointer to struct, but got pointer to  %v", elem.Kind())

	}
	v := reflect.ValueOf(ptrToStruct)
	v = v.Elem()
	for i := 0; i < elem.NumField(); i++ {
		f := v.Field(i)
		fn := getFieldName(elem.Field(i))
		print("fn is ", fn)
		if fn == "-" || jsonBlob.Get(fn).IsUndefined() || jsonBlob.Get(fn).IsNull() {
			continue
		}
		switch f.Type().Kind() {
		case reflect.Int64:
			f.SetInt(jsonBlob.Get(fn).Int64())
		case reflect.String:
			f.SetString(jsonBlob.Get(fn).Str())
		case reflect.Float64:
			f.SetFloat(jsonBlob.Get(fn).Float())
		case reflect.Bool:
			f.SetBool(jsonBlob.Get(fn).Bool())
		default:
			print("warning: %s", fn, " has a type other than int64, string, float64 or bool")
		}
	}
	return nil
}

//PutExisting sends a new version of the object given by id to the server.
//It returns an error only if the put could not be started, otherwise success
//or failure are communicated throught the callback functions.  The root should
//be the root of the rest heirarchy, probably "/rest".  The id is not examined
//by this routine, it can be the string representation of an integer or a UDID.
func PutExisting(i interface{}, root string, id string,
	success SuccessPutFunc, failure FailureFunc) error {

	var w bytes.Buffer
	enc := json.NewEncoder(&w)
	err := enc.Encode(i)
	if err != nil {
		return fmt.Errorf("error encoding put msg: %v ", err)
	}

	urlname := typeToUrlName(i)
	jquery.Ajax(
		map[string]interface{}{
			"contentType": "application/json",
			"dataType":    "json",
			"type":        "PUT",
			"url":         fmt.Sprintf("%s/%s/%s", root, urlname, id),
			"data":        w.String(),
			"cache":       false,
		}).
		Then(func(v js.Object) {
		success(v)
	}).
		Fail(func(p1 js.Object) {
		if failure != nil {
			failure(p1.Get("status").Int(), p1.Get("responseText").Str())
		}
	})

	return nil
}
func typeToUrlName(i interface{}) string {
	name := fmt.Sprintf("%T", i)
	pair := strings.Split(name, ".")
	if len(pair) != 2 {
		panic(fmt.Sprintf("unable to understand type name: %s", name))
	}
	return strings.ToLower(pair[1])
}

//PostNew sends an instance of a wire type to the server.  It returns an error
//only if the Post could not be sent.  The success or failure are indications are
//communicated through the callback functions.
func PostNew(i interface{}, root string, success SuccessNewFunc, failure FailureFunc) error {
	var w bytes.Buffer
	enc := json.NewEncoder(&w)
	err := enc.Encode(i)
	if err != nil {
		return fmt.Errorf("error encoding post msg: %v ", err)
	}
	urlname := typeToUrlName(i)
	jquery.Ajax(
		map[string]interface{}{
			"contentType": "application/json",
			"dataType":    "json",
			"type":        "POST",
			"url":         fmt.Sprintf("%s/%s", root, urlname),
			"data":        w.String(),
			"cache":       false,
		}).
		Then(func(valueCreated js.Object) {
		id := valueCreated.Get("Id").Int64()
		if success != nil {
			success(id)
		}
	}).
		Fail(func(p1 js.Object) {
		if failure != nil {
			failure(p1.Get("status").Int(), p1.Get("responseText").Str())
		}
	})

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package client

import (
	"errors"
	"fmt"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/util/caller"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/cockroachdb/cockroach/util/retry"
	gogoproto "github.com/gogo/protobuf/proto"
	"golang.org/x/net/context"
)

var (
	// DefaultTxnRetryOptions are the standard retry options used
	// for transactions.
	// This is exported for testing purposes only.
	DefaultTxnRetryOptions = retry.Options{
		InitialBackoff: 50 * time.Millisecond,
		MaxBackoff:     5 * time.Second,
		Multiplier:     2,
	}
	errMultipleEndTxn = errors.New("cannot end transaction multiple times")
)

// txnSender implements the Sender interface and is used to keep the Send
// method out of the Txn method set.
type txnSender Txn

func (ts *txnSender) Send(ctx context.Context, call proto.Call) {
	// Send call through wrapped sender.
	call.Args.Header().Txn = &ts.txn
	ts.wrapped.Send(ctx, call)
	ts.txn.Update(call.Reply.Header().Txn)

	if err, ok := call.Reply.Header().GoError().(*proto.TransactionAbortedError); ok {
		// On Abort, reset the transaction so we start anew on restart.
		ts.txn = proto.Transaction{
			Name:      ts.txn.Name,
			Isolation: ts.txn.Isolation,
			Priority:  err.Txn.Priority, // acts as a minimum priority on restart
		}
	}
}

// Txn is an in-progress distributed database transaction. A Txn is not safe for
// concurrent use by multiple goroutines.
type Txn struct {
	db           DB
	wrapped      Sender
	txn          proto.Transaction
	haveTxnWrite bool // True if there were transactional writes
	haveEndTxn   bool // True if there was an explicit EndTransaction
}

func newTxn(db DB, depth int) *Txn {
	txn := &Txn{
		db:      db,
		wrapped: db.Sender,
	}
	txn.db.Sender = (*txnSender)(txn)

	file, line, fun := caller.Lookup(depth + 1)
	txn.txn.Name = fmt.Sprintf("%s:%d %s", file, line, fun)
	return txn
}

// SetDebugName sets the debug name associated with the transaction which will
// appear in log files and the web UI. Each transaction starts out with an
// automatically assigned debug name composed of the file and line number where
// the transaction was created.
func (txn *Txn) SetDebugName(name string) {
	file, line, _ := caller.Lookup(1)
	txn.txn.Name = fmt.Sprintf("%s:%d %s", file, line, name)
}

// DebugName returns the debug name associated with the transaction.
func (txn *Txn) DebugName() string {
	return txn.txn.Name
}

// SetSnapshotIsolation sets the transaction's isolation type to
// snapshot. Transactions default to serializable isolation. The
// isolation must be set before any operations are performed on the
// transaction.
//
// TODO(pmattis): This isn't tested yet but will be as part of the
// conversion of client_test.go.
func (txn *Txn) SetSnapshotIsolation() {
	// TODO(pmattis): Panic if the transaction has already had
	// operations run on it. Needs to tie into the Txn reset in case of
	// retries.
	txn.txn.Isolation = proto.SNAPSHOT
}

// InternalSetPriority sets the transaction priority. It is intended for
// internal (testing) use only.
func (txn *Txn) InternalSetPriority(priority int32) {
	// The negative user priority is translated on the server into a positive,
	// non-randomized, priority for the transaction.
	txn.db.userPriority = -priority
}

// NewBatch creates and returns a new empty batch object for use with the Txn.
func (txn *Txn) NewBatch() *Batch {
	return &Batch{DB: &txn.db}
}

// Get retrieves the value for a key, returning the retrieved key/value or an
// error.
//
//   r, err := db.Get("a")
//   // string(r.Key) == "a"
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Get(key interface{}) (KeyValue, error) {
	b := txn.NewBatch()
	b.Get(key)
	return runOneRow(txn, b)
}

// GetProto retrieves the value for a key and decodes the result as a proto
// message.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) GetProto(key interface{}, msg gogoproto.Message) error {
	r, err := txn.Get(key)
	if err != nil {
		return err
	}
	return r.ValueProto(msg)
}

// Put sets the value for a key
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler. value can be any key type or a proto.Message.
func (txn *Txn) Put(key, value interface{}) error {
	b := txn.NewBatch()
	b.Put(key, value)
	_, err := runOneResult(txn, b)
	return err
}

// CPut conditionally sets the value for a key if the existing value is equal
// to expValue. To conditionally set a value only if there is no existing entry
// pass nil for expValue.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler. value can be any key type or a proto.Message.
func (txn *Txn) CPut(key, value, expValue interface{}) error {
	b := txn.NewBatch()
	b.CPut(key, value, expValue)
	_, err := runOneResult(txn, b)
	return err
}

// Inc increments the integer value at key. If the key does not exist it will
// be created with an initial value of 0 which will then be incremented. If the
// key exists but was set using Put or CPut an error will be returned.
//
// The returned Result will contain a single row and Result.Err will indicate
// success or failure.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Inc(key interface{}, value int64) (KeyValue, error) {
	b := txn.NewBatch()
	b.Inc(key, value)
	return runOneRow(txn, b)
}

func (txn *Txn) scan(begin, end interface{}, maxRows int64, isReverse bool) ([]KeyValue, error) {
	b := txn.NewBatch()
	if !isReverse {
		b.Scan(begin, end, maxRows)
	} else {
		b.ReverseScan(begin, end, maxRows)
	}
	r, err := runOneResult(txn, b)
	return r.Rows, err
}

// Scan retrieves the rows between begin (inclusive) and end (exclusive) in
// ascending order.
//
// The returned []KeyValue will contain up to maxRows elements.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Scan(begin, end interface{}, maxRows int64) ([]KeyValue, error) {
	return txn.scan(begin, end, maxRows, false)
}

// ReverseScan retrieves the rows between begin (inclusive) and end (exclusive)
// in descending order.
//
// The returned []KeyValue will contain up to maxRows elements.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) ReverseScan(begin, end interface{}, maxRows int64) ([]KeyValue, error) {
	return txn.scan(begin, end, maxRows, true)
}

// Del deletes one or more keys.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Del(keys ...interface{}) error {
	b := txn.NewBatch()
	b.Del(keys...)
	_, err := runOneResult(txn, b)
	return err
}

// DelRange deletes the rows between begin (inclusive) and end (exclusive).
//
// The returned Result will contain 0 rows and Result.Err will indicate success
// or failure.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) DelRange(begin, end interface{}) error {
	b := txn.NewBatch()
	b.DelRange(begin, end)
	_, err := runOneResult(txn, b)
	return err
}

// Run executes the operations queued up within a batch. Before executing any
// of the operations the batch is first checked to see if there were any errors
// during its construction (e.g. failure to marshal a proto message).
//
// The operations within a batch are run in parallel and the order is
// non-deterministic. It is an unspecified behavior to modify and retrieve the
// same key within a batch.
//
// Upon completion, Batch.Results will contain the results for each
// operation. The order of the results matches the order the operations were
// added to the batch.
func (txn *Txn) Run(b *Batch) error {
	if err := b.prepare(); err != nil {
		return err
	}
	if err := txn.send(b.calls...); err != nil {
		return err
	}
	return b.fillResults()
}

// CommitInBatch executes the operations queued up within a batch and
// commits the transaction. Explicitly committing a transaction is
// optional, but more efficient than relying on the implicit commit
// performed when the transaction function returns without error.
func (txn *Txn) CommitInBatch(b *Batch) error {
	b.calls = append(b.calls, endTxnCall(true /* commit */))
	b.initResult(1, 0, nil)
	return txn.Run(b)
}

// Commit sends an EndTransactionRequest with Commit=true.
func (txn *Txn) Commit() error {
	return txn.sendEndTxnCall(true /* commit */)
}

// Rollback sends an EndTransactionRequest with Commit=false.
func (txn *Txn) Rollback() error {
	return txn.sendEndTxnCall(false /* commit */)
}

func (txn *Txn) sendEndTxnCall(commit bool) error {
	return txn.send(endTxnCall(commit))
}

func endTxnCall(commit bool) proto.Call {
	return proto.Call{
		Args:  &proto.EndTransactionRequest{Commit: commit},
		Reply: &proto.EndTransactionResponse{},
	}
}

func (txn *Txn) exec(retryable func(txn *Txn) error) (err error) {
	// Run retryable in a retry loop until we encounter a success or
	// error condition this loop isn't capable of handling.
	for r := retry.Start(txn.db.txnRetryOptions); r.Next(); {
		txn.haveTxnWrite, txn.haveEndTxn = false, false // always reset before [re]starting txn
		if err = retryable(txn); err == nil {
			if !txn.haveEndTxn && txn.haveTxnWrite {
				// If there were no errors running retryable, commit the txn. This
				// may block waiting for outstanding writes to complete in case
				// retryable didn't -- we need the most recent of all response
				// timestamps in order to commit.
				err = txn.Commit()
			}
		}
		if restartErr, ok := err.(proto.TransactionRestartError); ok {
			if log.V(2) {
				log.Warning(err)
			}
			if restartErr.CanRestartTransaction() == proto.TransactionRestart_IMMEDIATE {
				r.Reset()
				continue
			} else if restartErr.CanRestartTransaction() == proto.TransactionRestart_BACKOFF {
				continue
			}
			// By default, fall through and break.
		}
		break
	}
	if err != nil && txn.haveTxnWrite {
		txn.haveEndTxn = false // if we sent one, it didn't succeed
		if replyErr := txn.Rollback(); replyErr != nil {
			log.Errorf("failure aborting transaction: %s; abort caused by: %s", replyErr, err)
		}
	}
	return
}

// send runs the specified calls synchronously in a single batch and
// returns any errors.
func (txn *Txn) send(calls ...proto.Call) error {
	if len(calls) == 0 {
		return nil
	}
	if err := txn.updateState(calls); err != nil {
		return err
	}

	// If the transaction record indicates that the coordinator never wrote
	// an intent (and the client doesn't have one lined up), then there's no
	// need to send EndTransaction. If there is one anyways, cut it off.
	if txn.haveEndTxn && !(txn.txn.Writing || txn.haveTxnWrite) {
		// There's always a call if we get here.
		lastIndex := len(calls) - 1
		if calls[lastIndex].Method() != proto.EndTransaction {
			panic("EndTransaction not sent as last call")
		}
		calls = calls[0:lastIndex]
	}
	return txn.db.send(calls...)
}

func (txn *Txn) updateState(calls []proto.Call) error {
	for _, c := range calls {
		if b, ok := c.Args.(*proto.BatchRequest); ok {
			for _, br := range b.Requests {
				if err := txn.updateStateForRequest(br.GetValue().(proto.Request)); err != nil {
					return err
				}
			}
			continue
		}
		if err := txn.updateStateForRequest(c.Args); err != nil {
			return err
		}
	}
	return nil
}

func (txn *Txn) updateStateForRequest(r proto.Request) error {
	if !txn.haveTxnWrite {
		txn.haveTxnWrite = proto.IsTransactionWrite(r)
	}
	if _, ok := r.(*proto.EndTransactionRequest); ok {
		if txn.haveEndTxn {
			return errMultipleEndTxn
		}
		txn.haveEndTxn = true
	}
	return nil
}
<commit_msg>clarify txn.haveTxnWrite<commit_after>// Copyright 2015 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package client

import (
	"errors"
	"fmt"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/util/caller"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/cockroachdb/cockroach/util/retry"
	gogoproto "github.com/gogo/protobuf/proto"
	"golang.org/x/net/context"
)

var (
	// DefaultTxnRetryOptions are the standard retry options used
	// for transactions.
	// This is exported for testing purposes only.
	DefaultTxnRetryOptions = retry.Options{
		InitialBackoff: 50 * time.Millisecond,
		MaxBackoff:     5 * time.Second,
		Multiplier:     2,
	}
	errMultipleEndTxn = errors.New("cannot end transaction multiple times")
)

// txnSender implements the Sender interface and is used to keep the Send
// method out of the Txn method set.
type txnSender Txn

func (ts *txnSender) Send(ctx context.Context, call proto.Call) {
	// Send call through wrapped sender.
	call.Args.Header().Txn = &ts.txn
	ts.wrapped.Send(ctx, call)
	ts.txn.Update(call.Reply.Header().Txn)

	if err, ok := call.Reply.Header().GoError().(*proto.TransactionAbortedError); ok {
		// On Abort, reset the transaction so we start anew on restart.
		ts.txn = proto.Transaction{
			Name:      ts.txn.Name,
			Isolation: ts.txn.Isolation,
			Priority:  err.Txn.Priority, // acts as a minimum priority on restart
		}
	}
}

// Txn is an in-progress distributed database transaction. A Txn is not safe for
// concurrent use by multiple goroutines.
type Txn struct {
	db      DB
	wrapped Sender
	txn     proto.Transaction
	// haveTxnWrite is true as soon as the current attempt contains a write
	// (prior to sending). This is in contrast to txn.Writing, which is set
	// by the coordinator when the first intent has been created, and which
	// does not reset in-between retries. As such, haveTxnWrite helps deter-
	// mine whether it makes sense to add an EndTransaction when txn.Writing
	// is (still) unset.
	haveTxnWrite bool
	haveEndTxn   bool // True if there was an explicit EndTransaction
}

func newTxn(db DB, depth int) *Txn {
	txn := &Txn{
		db:      db,
		wrapped: db.Sender,
	}
	txn.db.Sender = (*txnSender)(txn)

	file, line, fun := caller.Lookup(depth + 1)
	txn.txn.Name = fmt.Sprintf("%s:%d %s", file, line, fun)
	return txn
}

// SetDebugName sets the debug name associated with the transaction which will
// appear in log files and the web UI. Each transaction starts out with an
// automatically assigned debug name composed of the file and line number where
// the transaction was created.
func (txn *Txn) SetDebugName(name string) {
	file, line, _ := caller.Lookup(1)
	txn.txn.Name = fmt.Sprintf("%s:%d %s", file, line, name)
}

// DebugName returns the debug name associated with the transaction.
func (txn *Txn) DebugName() string {
	return txn.txn.Name
}

// SetSnapshotIsolation sets the transaction's isolation type to
// snapshot. Transactions default to serializable isolation. The
// isolation must be set before any operations are performed on the
// transaction.
//
// TODO(pmattis): This isn't tested yet but will be as part of the
// conversion of client_test.go.
func (txn *Txn) SetSnapshotIsolation() {
	// TODO(pmattis): Panic if the transaction has already had
	// operations run on it. Needs to tie into the Txn reset in case of
	// retries.
	txn.txn.Isolation = proto.SNAPSHOT
}

// InternalSetPriority sets the transaction priority. It is intended for
// internal (testing) use only.
func (txn *Txn) InternalSetPriority(priority int32) {
	// The negative user priority is translated on the server into a positive,
	// non-randomized, priority for the transaction.
	txn.db.userPriority = -priority
}

// NewBatch creates and returns a new empty batch object for use with the Txn.
func (txn *Txn) NewBatch() *Batch {
	return &Batch{DB: &txn.db}
}

// Get retrieves the value for a key, returning the retrieved key/value or an
// error.
//
//   r, err := db.Get("a")
//   // string(r.Key) == "a"
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Get(key interface{}) (KeyValue, error) {
	b := txn.NewBatch()
	b.Get(key)
	return runOneRow(txn, b)
}

// GetProto retrieves the value for a key and decodes the result as a proto
// message.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) GetProto(key interface{}, msg gogoproto.Message) error {
	r, err := txn.Get(key)
	if err != nil {
		return err
	}
	return r.ValueProto(msg)
}

// Put sets the value for a key
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler. value can be any key type or a proto.Message.
func (txn *Txn) Put(key, value interface{}) error {
	b := txn.NewBatch()
	b.Put(key, value)
	_, err := runOneResult(txn, b)
	return err
}

// CPut conditionally sets the value for a key if the existing value is equal
// to expValue. To conditionally set a value only if there is no existing entry
// pass nil for expValue.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler. value can be any key type or a proto.Message.
func (txn *Txn) CPut(key, value, expValue interface{}) error {
	b := txn.NewBatch()
	b.CPut(key, value, expValue)
	_, err := runOneResult(txn, b)
	return err
}

// Inc increments the integer value at key. If the key does not exist it will
// be created with an initial value of 0 which will then be incremented. If the
// key exists but was set using Put or CPut an error will be returned.
//
// The returned Result will contain a single row and Result.Err will indicate
// success or failure.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Inc(key interface{}, value int64) (KeyValue, error) {
	b := txn.NewBatch()
	b.Inc(key, value)
	return runOneRow(txn, b)
}

func (txn *Txn) scan(begin, end interface{}, maxRows int64, isReverse bool) ([]KeyValue, error) {
	b := txn.NewBatch()
	if !isReverse {
		b.Scan(begin, end, maxRows)
	} else {
		b.ReverseScan(begin, end, maxRows)
	}
	r, err := runOneResult(txn, b)
	return r.Rows, err
}

// Scan retrieves the rows between begin (inclusive) and end (exclusive) in
// ascending order.
//
// The returned []KeyValue will contain up to maxRows elements.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Scan(begin, end interface{}, maxRows int64) ([]KeyValue, error) {
	return txn.scan(begin, end, maxRows, false)
}

// ReverseScan retrieves the rows between begin (inclusive) and end (exclusive)
// in descending order.
//
// The returned []KeyValue will contain up to maxRows elements.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) ReverseScan(begin, end interface{}, maxRows int64) ([]KeyValue, error) {
	return txn.scan(begin, end, maxRows, true)
}

// Del deletes one or more keys.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) Del(keys ...interface{}) error {
	b := txn.NewBatch()
	b.Del(keys...)
	_, err := runOneResult(txn, b)
	return err
}

// DelRange deletes the rows between begin (inclusive) and end (exclusive).
//
// The returned Result will contain 0 rows and Result.Err will indicate success
// or failure.
//
// key can be either a byte slice, a string, a fmt.Stringer or an
// encoding.BinaryMarshaler.
func (txn *Txn) DelRange(begin, end interface{}) error {
	b := txn.NewBatch()
	b.DelRange(begin, end)
	_, err := runOneResult(txn, b)
	return err
}

// Run executes the operations queued up within a batch. Before executing any
// of the operations the batch is first checked to see if there were any errors
// during its construction (e.g. failure to marshal a proto message).
//
// The operations within a batch are run in parallel and the order is
// non-deterministic. It is an unspecified behavior to modify and retrieve the
// same key within a batch.
//
// Upon completion, Batch.Results will contain the results for each
// operation. The order of the results matches the order the operations were
// added to the batch.
func (txn *Txn) Run(b *Batch) error {
	if err := b.prepare(); err != nil {
		return err
	}
	if err := txn.send(b.calls...); err != nil {
		return err
	}
	return b.fillResults()
}

// CommitInBatch executes the operations queued up within a batch and
// commits the transaction. Explicitly committing a transaction is
// optional, but more efficient than relying on the implicit commit
// performed when the transaction function returns without error.
func (txn *Txn) CommitInBatch(b *Batch) error {
	b.calls = append(b.calls, endTxnCall(true /* commit */))
	b.initResult(1, 0, nil)
	return txn.Run(b)
}

// Commit sends an EndTransactionRequest with Commit=true.
func (txn *Txn) Commit() error {
	return txn.sendEndTxnCall(true /* commit */)
}

// Rollback sends an EndTransactionRequest with Commit=false.
func (txn *Txn) Rollback() error {
	return txn.sendEndTxnCall(false /* commit */)
}

func (txn *Txn) sendEndTxnCall(commit bool) error {
	return txn.send(endTxnCall(commit))
}

func endTxnCall(commit bool) proto.Call {
	return proto.Call{
		Args:  &proto.EndTransactionRequest{Commit: commit},
		Reply: &proto.EndTransactionResponse{},
	}
}

func (txn *Txn) exec(retryable func(txn *Txn) error) (err error) {
	// Run retryable in a retry loop until we encounter a success or
	// error condition this loop isn't capable of handling.
	for r := retry.Start(txn.db.txnRetryOptions); r.Next(); {
		txn.haveTxnWrite, txn.haveEndTxn = false, false // always reset before [re]starting txn
		if err = retryable(txn); err == nil {
			if !txn.haveEndTxn && txn.haveTxnWrite {
				// If there were no errors running retryable, commit the txn. This
				// may block waiting for outstanding writes to complete in case
				// retryable didn't -- we need the most recent of all response
				// timestamps in order to commit.
				err = txn.Commit()
			}
		}
		if restartErr, ok := err.(proto.TransactionRestartError); ok {
			if log.V(2) {
				log.Warning(err)
			}
			if restartErr.CanRestartTransaction() == proto.TransactionRestart_IMMEDIATE {
				r.Reset()
				continue
			} else if restartErr.CanRestartTransaction() == proto.TransactionRestart_BACKOFF {
				continue
			}
			// By default, fall through and break.
		}
		break
	}
	if err != nil && txn.haveTxnWrite {
		txn.haveEndTxn = false // if we sent one, it didn't succeed
		if replyErr := txn.Rollback(); replyErr != nil {
			log.Errorf("failure aborting transaction: %s; abort caused by: %s", replyErr, err)
		}
	}
	return
}

// send runs the specified calls synchronously in a single batch and
// returns any errors.
func (txn *Txn) send(calls ...proto.Call) error {
	if len(calls) == 0 {
		return nil
	}
	if err := txn.updateState(calls); err != nil {
		return err
	}

	// If the transaction record indicates that the coordinator never wrote
	// an intent (and the client doesn't have one lined up), then there's no
	// need to send EndTransaction. If there is one anyways, cut it off.
	if txn.haveEndTxn && !(txn.txn.Writing || txn.haveTxnWrite) {
		// There's always a call if we get here.
		lastIndex := len(calls) - 1
		if calls[lastIndex].Method() != proto.EndTransaction {
			panic("EndTransaction not sent as last call")
		}
		calls = calls[0:lastIndex]
	}
	return txn.db.send(calls...)
}

func (txn *Txn) updateState(calls []proto.Call) error {
	for _, c := range calls {
		if b, ok := c.Args.(*proto.BatchRequest); ok {
			for _, br := range b.Requests {
				if err := txn.updateStateForRequest(br.GetValue().(proto.Request)); err != nil {
					return err
				}
			}
			continue
		}
		if err := txn.updateStateForRequest(c.Args); err != nil {
			return err
		}
	}
	return nil
}

func (txn *Txn) updateStateForRequest(r proto.Request) error {
	if !txn.haveTxnWrite {
		txn.haveTxnWrite = proto.IsTransactionWrite(r)
	}
	if _, ok := r.(*proto.EndTransactionRequest); ok {
		if txn.haveEndTxn {
			return errMultipleEndTxn
		}
		txn.haveEndTxn = true
	}
	return nil
}
<|endoftext|>


<commit_before>package ultralist

import (
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/fatih/color"
)

type ScreenPrinter struct {
	Writer *tabwriter.Writer
}

func NewScreenPrinter() *ScreenPrinter {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	formatter := &ScreenPrinter{Writer: w}
	return formatter
}

func (f *ScreenPrinter) Print(groupedTodos *GroupedTodos, printNotes bool) {
	cyan := color.New(color.FgCyan).SprintFunc()

	var keys []string
	for key := range groupedTodos.Groups {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	for _, key := range keys {
		fmt.Fprintf(f.Writer, "\n %s\n", cyan(key))
		for _, todo := range groupedTodos.Groups[key] {
			f.printTodo(todo)
			if printNotes {
				for nid, note := range todo.Notes {
					fmt.Fprintf(f.Writer, "   %s\t\t\t%s\t\n",
						cyan(strconv.Itoa(nid)), note)
				}
			}
		}
	}
	f.Writer.Flush()
}

func (f *ScreenPrinter) printTodo(todo *Todo) {
	yellow := color.New(color.FgYellow)
	if todo.IsPriority {
		yellow.Add(color.Bold, color.Italic)
	}
	fmt.Fprintf(f.Writer, " %s\t%s\t%s\t%s\t\n",
		yellow.SprintFunc()(strconv.Itoa(todo.Id)),
		f.formatCompleted(todo.Completed),
		f.formatDue(todo.Due, todo.IsPriority, todo.Completed),
		f.formatSubject(todo.Subject, todo.IsPriority))
}

func (f *ScreenPrinter) formatDue(due string, isPriority bool, completed bool) string {
	blue := color.New(color.FgBlue)
	red := color.New(color.FgRed)

	if isPriority {
		blue.Add(color.Bold, color.Italic)
		red.Add(color.Bold, color.Italic)
	}

	if due == "" {
		return blue.SprintFunc()("          ")
	}
	dueTime, err := time.Parse("2006-01-02", due)

	if err != nil {
		fmt.Println(err)
		fmt.Println("This may due to the corruption of .todos.json file.")
		os.Exit(-1)
	}

	if isToday(dueTime) {
		return blue.SprintFunc()("today     ")
	} else if isTomorrow(dueTime) {
		return blue.SprintFunc()("tomorrow  ")
	} else if isPastDue(dueTime) && !completed {
		return red.SprintFunc()(dueTime.Format("Mon Jan 02"))
	} else {
		return blue.SprintFunc()(dueTime.Format("Mon Jan 02"))
	}
}

func (f *ScreenPrinter) formatSubject(subject string, isPriority bool) string {

	red := color.New(color.FgRed)
	magenta := color.New(color.FgMagenta)
	white := color.New(color.FgWhite)

	if isPriority {
		red.Add(color.Bold, color.Italic)
		magenta.Add(color.Bold, color.Italic)
		white.Add(color.Bold, color.Italic)
	}

	splitted := strings.Split(subject, " ")
	projectRegex, _ := regexp.Compile(`\+[\p{L}\d_]+`)
	contextRegex, _ := regexp.Compile(`\@[\p{L}\d_]+`)

	coloredWords := []string{}

	for _, word := range splitted {
		if projectRegex.MatchString(word) {
			coloredWords = append(coloredWords, magenta.SprintFunc()(word))
		} else if contextRegex.MatchString(word) {
			coloredWords = append(coloredWords, red.SprintFunc()(word))
		} else {
			coloredWords = append(coloredWords, white.SprintFunc()(word))
		}
	}
	return strings.Join(coloredWords, " ")

}

func (f *ScreenPrinter) formatCompleted(completed bool) string {
	if completed {
		return "[x]"
	} else {
		return "[ ]"
	}
}
<commit_msg>Fixing screen printer output for a todo with no due date but priority.<commit_after>package ultralist

import (
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/fatih/color"
)

type ScreenPrinter struct {
	Writer *tabwriter.Writer
}

func NewScreenPrinter() *ScreenPrinter {
	w := new(tabwriter.Writer)
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)
	formatter := &ScreenPrinter{Writer: w}
	return formatter
}

func (f *ScreenPrinter) Print(groupedTodos *GroupedTodos, printNotes bool) {
	cyan := color.New(color.FgCyan).SprintFunc()

	var keys []string
	for key := range groupedTodos.Groups {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	for _, key := range keys {
		fmt.Fprintf(f.Writer, "\n %s\n", cyan(key))
		for _, todo := range groupedTodos.Groups[key] {
			f.printTodo(todo)
			if printNotes {
				for nid, note := range todo.Notes {
					fmt.Fprintf(f.Writer, "   %s\t\t\t%s\t\n",
						cyan(strconv.Itoa(nid)), note)
				}
			}
		}
	}
	f.Writer.Flush()
}

func (f *ScreenPrinter) printTodo(todo *Todo) {
	yellow := color.New(color.FgYellow)
	if todo.IsPriority {
		yellow.Add(color.Bold, color.Italic)
	}
	fmt.Fprintf(f.Writer, " %s\t%s\t%s\t%s\t\n",
		yellow.SprintFunc()(strconv.Itoa(todo.Id)),
		f.formatCompleted(todo.Completed),
		f.formatDue(todo.Due, todo.IsPriority, todo.Completed),
		f.formatSubject(todo.Subject, todo.IsPriority))
}

func (f *ScreenPrinter) formatDue(due string, isPriority bool, completed bool) string {
	blue := color.New(color.FgBlue)
	red := color.New(color.FgRed)

	if isPriority {
		blue.Add(color.Bold, color.Italic)
		red.Add(color.Bold, color.Italic)
	}

	if due == "" {
		return color.New().SprintFunc()("          ")
	}
	dueTime, err := time.Parse("2006-01-02", due)

	if err != nil {
		fmt.Println(err)
		fmt.Println("This may due to the corruption of .todos.json file.")
		os.Exit(-1)
	}

	if isToday(dueTime) {
		return blue.SprintFunc()("today     ")
	} else if isTomorrow(dueTime) {
		return blue.SprintFunc()("tomorrow  ")
	} else if isPastDue(dueTime) && !completed {
		return red.SprintFunc()(dueTime.Format("Mon Jan 02"))
	} else {
		return blue.SprintFunc()(dueTime.Format("Mon Jan 02"))
	}
}

func (f *ScreenPrinter) formatSubject(subject string, isPriority bool) string {

	red := color.New(color.FgRed)
	magenta := color.New(color.FgMagenta)
	white := color.New(color.FgWhite)

	if isPriority {
		red.Add(color.Bold, color.Italic)
		magenta.Add(color.Bold, color.Italic)
		white.Add(color.Bold, color.Italic)
	}

	splitted := strings.Split(subject, " ")
	projectRegex, _ := regexp.Compile(`\+[\p{L}\d_]+`)
	contextRegex, _ := regexp.Compile(`\@[\p{L}\d_]+`)

	coloredWords := []string{}

	for _, word := range splitted {
		if projectRegex.MatchString(word) {
			coloredWords = append(coloredWords, magenta.SprintFunc()(word))
		} else if contextRegex.MatchString(word) {
			coloredWords = append(coloredWords, red.SprintFunc()(word))
		} else {
			coloredWords = append(coloredWords, white.SprintFunc()(word))
		}
	}
	return strings.Join(coloredWords, " ")

}

func (f *ScreenPrinter) formatCompleted(completed bool) string {
	if completed {
		return "[x]"
	} else {
		return "[ ]"
	}
}
<|endoftext|>


<commit_before>package main

import (
	"path/filepath"
	"testing"
	"time"
)

var FILES map[string]string

func init() {
	FILES = make(map[string]string)
	folder := "tests/"

	FILES["black"] = "black.png"
	FILES["white"] = "white.png"
	FILES["g"] = "google_query_screenshot.png"
	FILES["g_transparent"] = "google_query_transparent.png"
	FILES["grmlforensic_website"] = "grmlforensic_contact_website.png"
	FILES["grml_kB"] = "grml_booting_totalmemory_kB.png"
	FILES["grml_MB"] = "grml_booting_totalmemory_MB.png"
	FILES["grmlf_bo_back"] = "grmlforensic_bootoptions_backtomainmenu.png"
	FILES["grmlf_bo_debug"] = "grmlforensic_bootoptions_debugmode.png"
	FILES["grmlf_bs_23"] = "grmlforensic_bootsplash_23sec.png"
	FILES["grmlf_bs_30"] = "grmlforensic_bootsplash_30sec.png"
	FILES["grmlf_bs_graphical"] = "grmlforensic_bootsplash_graphicalmode.png"
	FILES["grmlf_bs_transparent"] = "grmlforensic_bootsplash_selection_transparent.png"

	if folder != "" {
		for k, v := range FILES {
			FILES[k] = filepath.Join(folder, v)
		}
	}
}

func defaultSettings() Settings {
	return Settings{ColorSpace: "RGB", Timeout: time.Duration(0), Wait: time.Hour * 24}
}

func TestDurationSpecifier(t *testing.T) {
	test := func(teststr string, expected time.Duration) {
		dur, err := readDurationSpecifier(teststr)
		if err != nil {
			t.Log(err)
		}
		if dur != expected {
			t.Fatalf("'%s' was not recognized by duration specifier parser", teststr)
		}
	}

	// must not throw exception
	readDurationSpecifier("")

	test("1s", time.Second*1)
	test("30s", time.Second*30)
	test("500i", time.Millisecond*500)
	test("1000i", time.Second)
	test("30m", time.Minute*30)
	test("2h", time.Hour*2)
	test("5", time.Second*5)
}

func TestEqualImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["g"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff > 0.01 {
		t.Fatalf("Same image must return difference %f; got %f", 0.0, diff)
	}
}

func TestDifferentImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["grmlforensic_website"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff <= 0.1 {
		t.Fatalf("Different images must return high difference; got %f", diff)
	}
}

func TestTotallyDifferentImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["black"]
	s.RefImg = FILES["white"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff <= 0.9 {
		t.Fatalf("Totally different images must return very high difference; got %f", diff)
	}
}

func TestRGBAndYUV(t *testing.T) {
	s := defaultSettings()
	s.ColorSpace = "RGB"
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["grmlforensic_website"]
	diffRGB, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}

	s.ColorSpace = "Y'UV"
	diffYUV, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}

	// I only expect them to be different
	if diffRGB != diffYUV {
		t.Fatalf("Different images must return high difference; got %f", diff)
	}
}

func TestTransparency(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["g_transparent"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff > 0.01 {
		t.Fatalf("Base image must match given transparent reference image; got difference of %f", diff)
	}
}
<commit_msg>Fix TestRGBAndYUV<commit_after>package main

import (
	"path/filepath"
	"testing"
	"time"
)

var FILES map[string]string

func init() {
	FILES = make(map[string]string)
	folder := "tests/"

	FILES["black"] = "black.png"
	FILES["white"] = "white.png"
	FILES["g"] = "google_query_screenshot.png"
	FILES["g_transparent"] = "google_query_transparent.png"
	FILES["grmlforensic_website"] = "grmlforensic_contact_website.png"
	FILES["grml_kB"] = "grml_booting_totalmemory_kB.png"
	FILES["grml_MB"] = "grml_booting_totalmemory_MB.png"
	FILES["grmlf_bo_back"] = "grmlforensic_bootoptions_backtomainmenu.png"
	FILES["grmlf_bo_debug"] = "grmlforensic_bootoptions_debugmode.png"
	FILES["grmlf_bs_23"] = "grmlforensic_bootsplash_23sec.png"
	FILES["grmlf_bs_30"] = "grmlforensic_bootsplash_30sec.png"
	FILES["grmlf_bs_graphical"] = "grmlforensic_bootsplash_graphicalmode.png"
	FILES["grmlf_bs_transparent"] = "grmlforensic_bootsplash_selection_transparent.png"

	if folder != "" {
		for k, v := range FILES {
			FILES[k] = filepath.Join(folder, v)
		}
	}
}

func defaultSettings() Settings {
	return Settings{ColorSpace: "RGB", Timeout: time.Duration(0), Wait: time.Hour * 24}
}

func TestDurationSpecifier(t *testing.T) {
	test := func(teststr string, expected time.Duration) {
		dur, err := readDurationSpecifier(teststr)
		if err != nil {
			t.Log(err)
		}
		if dur != expected {
			t.Fatalf("'%s' was not recognized by duration specifier parser", teststr)
		}
	}

	// must not throw exception
	readDurationSpecifier("")

	test("1s", time.Second*1)
	test("30s", time.Second*30)
	test("500i", time.Millisecond*500)
	test("1000i", time.Second)
	test("30m", time.Minute*30)
	test("2h", time.Hour*2)
	test("5", time.Second*5)
}

func TestEqualImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["g"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff > 0.01 {
		t.Fatalf("Same image must return difference %f; got %f", 0.0, diff)
	}
}

func TestDifferentImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["grmlforensic_website"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff <= 0.1 {
		t.Fatalf("Different images must return high difference; got %f", diff)
	}
}

func TestTotallyDifferentImages(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["black"]
	s.RefImg = FILES["white"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff <= 0.9 {
		t.Fatalf("Totally different images must return very high difference; got %f", diff)
	}
}

func TestRGBAndYUV(t *testing.T) {
	s := defaultSettings()
	s.ColorSpace = "RGB"
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["grmlforensic_website"]
	diffRGB, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}

	s.ColorSpace = "Y'UV"
	diffYUV, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}

	// I only expect them to be different
	if diffRGB == diffYUV {
		t.Fatalf("Expecting a difference between RGB and Y'UV; got %f and %f", diffRGB, diffYUV)
	}
}

func TestTransparency(t *testing.T) {
	s := defaultSettings()
	s.BaseImg = FILES["g"]
	s.RefImg = FILES["g_transparent"]
	diff, err := CompareImages(s)
	if err != nil {
		t.Log(err)
	}
	if diff > 0.01 {
		t.Fatalf("Base image must match given transparent reference image; got difference of %f", diff)
	}
}
<|endoftext|>