<commit_before>// +build linux,have_chainfs

package chainfs

/*
extern int start_chainfs(int mode, char *mount_path);
extern void stop_chainfs(void);
extern int create_layer(char *id, char *parent_id);
extern int remove_layer(char *id);
extern int check_layer(char *id);
extern int alloc_chainfs(char *id);
extern int release_chainfs(char *id);
#cgo LDFLAGS: -lfuse -lulockmgr -lchainfs
#cgo CFLAGS: -g3
*/
import "C"

import (
	"io/ioutil"
	"os"
	"path"

	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/graph"

	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/directory"
	"github.com/docker/docker/pkg/idtools"

	"github.com/Sirupsen/logrus"
)

const (
	Name     = "chainfs"
	Type     = api.Graph
	virtPath = "/var/lib/openstorage/chainfs"
)

type Driver struct {
}

func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
	logrus.Infof("Initializing libchainfs at home: %s and storage: %v...", home, virtPath)

	cVirtPath := C.CString(virtPath)
	go C.start_chainfs(1, cVirtPath)

	d := &Driver{}

	return d, nil
}

func (d *Driver) String() string {
	return "openstorage-chainfs"
}

// Cleanup performs necessary tasks to release resources
// held by the driver, e.g., unmounting all layered filesystems
// known to this driver.
func (d *Driver) Cleanup() error {
	logrus.Infof("Stopping libchainfs at %s", virtPath)
	C.stop_chainfs()
	return nil
}

// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
func (d *Driver) Status() [][2]string {
	return [][2]string{
		{"OpenStorage FUSE", "OK"},
	}
}

// Create creates a new, empty, filesystem layer with the
// specified id and parent and mountLabel. Parent and mountLabel may be "".
func (d *Driver) Create(id string, parent string, ml string) error {
	if parent != "" {
		logrus.Infof("Creating layer %s with parent %s", id, parent)
	} else {
		logrus.Infof("Creating parent layer %s", id)
	}

	cID := C.CString(id)
	cParent := C.CString(parent)

	ret, err := C.create_layer(cID, cParent)
	if int(ret) != 0 {
		logrus.Warnf("Error while creating layer %s", id)
		return err
	}

	return nil
}

// Remove attempts to remove the filesystem layer with this id.
func (d *Driver) Remove(id string) error {
	logrus.Infof("Removing layer %s", id)

	cID := C.CString(id)

	ret, err := C.remove_layer(cID)
	if int(ret) != 0 {
		logrus.Warnf("Error while removing layer %s", id)
		return err
	}

	return nil
}

// Returns a set of key-value pairs which give low level information
// about the image/container driver is managing.
func (d *Driver) GetMetadata(id string) (map[string]string, error) {
	return nil, nil
}

// Get returns the mountpoint for the layered filesystem referred
// to by this id. You can optionally specify a mountLabel or "".
// Returns the absolute path to the mounted layered filesystem.
func (d *Driver) Get(id, mountLabel string) (string, error) {
	cID := C.CString(id)

	ret, err := C.alloc_chainfs(cID)
	if int(ret) != 0 {
		logrus.Warnf("Error while creating a chain FS for %s", id)
		return "", err
	} else {
		logrus.Debugf("Created a chain FS for %s", id)
		chainPath := path.Join(virtPath, id)

		return chainPath, err
	}
}

// Put releases the system resources for the specified id,
// e.g, unmounting layered filesystem.
func (d *Driver) Put(id string) error {
	logrus.Debugf("Releasing chain FS for %s", id)

	cID := C.CString(id)
	_, err := C.release_chainfs(cID)

	return err
}

// Exists returns whether a filesystem layer with the specified
// ID exists on this driver.
// All cache entries exist.
func (d *Driver) Exists(id string) bool {
	path := path.Join(virtPath, id)

	_, err := os.Stat(path)

	if err == nil {
		return true
	} else {
		return false
	}
}

// ApplyDiff extracts the changeset from the given diff into the
// layer with the specified id and parent, returning the size of the
// new layer in bytes.
// The archive.Reader must be an uncompressed stream.
func (d *Driver) ApplyDiff(id string, parent string, diff archive.Reader) (size int64, err error) {
	dir := path.Join(virtPath, id)
	if err := chrootarchive.UntarUncompressed(diff, dir, nil); err != nil {
		logrus.Warnf("Error while applying diff to %s: %v", id, err)
		return 0, err
	}

	// show invalid whiteouts warning.
	files, err := ioutil.ReadDir(path.Join(dir, archive.WhiteoutLinkDir))
	if err == nil && len(files) > 0 {
		logrus.Warnf("Archive contains aufs hardlink references that are not supported.")
	}

	return d.DiffSize(id, parent)
}

// Changes produces a list of changes between the specified layer
// and its parent layer. If parent is "", then all changes will be ADD changes.
func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {

	return nil, nil
}

// Diff produces an archive of the changes between the specified
// layer and its parent layer which may be "".
func (d *Driver) Diff(id, parent string) (archive.Archive, error) {
	return archive.TarWithOptions(path.Join(virtPath, id), &archive.TarOptions{
		Compression:     archive.Uncompressed,
		ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
	})
}

// DiffSize calculates the changes between the specified id
// and its parent and returns the size in bytes of the changes
// relative to its base filesystem directory.
func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
	return directory.Size(path.Join(virtPath, id))
}

func init() {
	graph.Register(Name, Init)
}
<commit_msg>Added some debug log messages<commit_after>// +build linux,have_chainfs

package chainfs

/*
extern int start_chainfs(int mode, char *mount_path);
extern void stop_chainfs(void);
extern int create_layer(char *id, char *parent_id);
extern int remove_layer(char *id);
extern int check_layer(char *id);
extern int alloc_chainfs(char *id);
extern int release_chainfs(char *id);
#cgo LDFLAGS: -lfuse -lulockmgr -lchainfs
#cgo CFLAGS: -g3
*/
import "C"

import (
	"io/ioutil"
	"os"
	"path"

	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/graph"

	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/directory"
	"github.com/docker/docker/pkg/idtools"

	"github.com/Sirupsen/logrus"
)

const (
	Name     = "chainfs"
	Type     = api.Graph
	virtPath = "/var/lib/openstorage/chainfs"
)

type Driver struct {
}

func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
	logrus.Infof("Initializing libchainfs at home: %s and storage: %v...", home, virtPath)

	cVirtPath := C.CString(virtPath)
	go C.start_chainfs(1, cVirtPath)

	d := &Driver{}

	return d, nil
}

func (d *Driver) String() string {
	return "openstorage-chainfs"
}

// Cleanup performs necessary tasks to release resources
// held by the driver, e.g., unmounting all layered filesystems
// known to this driver.
func (d *Driver) Cleanup() error {
	logrus.Infof("Stopping libchainfs at %s", virtPath)
	C.stop_chainfs()
	return nil
}

// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
func (d *Driver) Status() [][2]string {
	return [][2]string{
		{"OpenStorage FUSE", "OK"},
	}
}

// Create creates a new, empty, filesystem layer with the
// specified id and parent and mountLabel. Parent and mountLabel may be "".
func (d *Driver) Create(id string, parent string, ml string) error {
	if parent != "" {
		logrus.Infof("Creating layer %s with parent %s", id, parent)
	} else {
		logrus.Infof("Creating parent layer %s", id)
	}

	cID := C.CString(id)
	cParent := C.CString(parent)

	ret, err := C.create_layer(cID, cParent)
	if int(ret) != 0 {
		logrus.Warnf("Error while creating layer %s", id)
		return err
	}

	return nil
}

// Remove attempts to remove the filesystem layer with this id.
func (d *Driver) Remove(id string) error {
	logrus.Infof("Removing layer %s", id)

	cID := C.CString(id)

	ret, err := C.remove_layer(cID)
	if int(ret) != 0 {
		logrus.Warnf("Error while removing layer %s", id)
		return err
	}

	return nil
}

// Returns a set of key-value pairs which give low level information
// about the image/container driver is managing.
func (d *Driver) GetMetadata(id string) (map[string]string, error) {
	return nil, nil
}

// Get returns the mountpoint for the layered filesystem referred
// to by this id. You can optionally specify a mountLabel or "".
// Returns the absolute path to the mounted layered filesystem.
func (d *Driver) Get(id, mountLabel string) (string, error) {
	cID := C.CString(id)

	ret, err := C.alloc_chainfs(cID)
	if int(ret) != 0 {
		logrus.Warnf("Error while creating a chain FS for %s", id)
		return "", err
	} else {
		logrus.Debugf("Created a chain FS for %s", id)
		chainPath := path.Join(virtPath, id)

		return chainPath, err
	}
}

// Put releases the system resources for the specified id,
// e.g, unmounting layered filesystem.
func (d *Driver) Put(id string) error {
	logrus.Debugf("Releasing chain FS for %s", id)

	cID := C.CString(id)
	_, err := C.release_chainfs(cID)

	return err
}

// Exists returns whether a filesystem layer with the specified
// ID exists on this driver.
// All cache entries exist.
func (d *Driver) Exists(id string) bool {
	path := path.Join(virtPath, id)

	_, err := os.Stat(path)

	if err == nil {
		return true
	} else {
		return false
	}
}

// ApplyDiff extracts the changeset from the given diff into the
// layer with the specified id and parent, returning the size of the
// new layer in bytes.
// The archive.Reader must be an uncompressed stream.
func (d *Driver) ApplyDiff(id string, parent string, diff archive.Reader) (size int64, err error) {
	dir := path.Join(virtPath, id)

	logrus.Infof("Applying diff at path %s\n", dir)

	if err := chrootarchive.UntarUncompressed(diff, dir, nil); err != nil {
		logrus.Warnf("Error while applying diff to %s: %v", id, err)
		return 0, err
	}

	// show invalid whiteouts warning.
	files, err := ioutil.ReadDir(path.Join(dir, archive.WhiteoutLinkDir))
	if err == nil && len(files) > 0 {
		logrus.Warnf("Archive contains aufs hardlink references that are not supported.")
	}

	return d.DiffSize(id, parent)
}

// Changes produces a list of changes between the specified layer
// and its parent layer. If parent is "", then all changes will be ADD changes.
func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {

	return nil, nil
}

// Diff produces an archive of the changes between the specified
// layer and its parent layer which may be "".
func (d *Driver) Diff(id, parent string) (archive.Archive, error) {
	return archive.TarWithOptions(path.Join(virtPath, id), &archive.TarOptions{
		Compression:     archive.Uncompressed,
		ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
	})
}

// DiffSize calculates the changes between the specified id
// and its parent and returns the size in bytes of the changes
// relative to its base filesystem directory.
func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
	return directory.Size(path.Join(virtPath, id))
}

func init() {
	graph.Register(Name, Init)
}
<|endoftext|>


<commit_before>// Copyright © 2016 Casa Platform
//
// 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 casa defines interfaces and types for the casa home automation
// platform. These interfaces are subject to change without notice as casa is
// refined. Feel free to play with it now but wait until a v1 release before
// you depend on it for anything.
package casa

import "github.com/spf13/viper"

// Message represents an MQTT message
// Might be better to be an interface?
type Message struct {
	Topic   string
	Payload []byte
	Retain  bool
}

// MessageBus defines a system for passing Messages
type MessageBus interface {
	// Shutdown the MessageBus
	Close() error

	// NewClient returns a client that is connected to the MessageBus
	NewClient() MessageClient
}

// MessageClient sends and recieves Messages to a MessageBus
type MessageClient interface {
	// Register a function to call when a message or error is received
	Handle(func(msg *Message, err error))

	// Publish a pre-composed message
	PublishMessage(message Message) error

	// Subscribes to the given topic
	Subscribe(topic string) error

	// Removes subscription for the topic
	Unsubscribe(topic string) error

	// Closes the client
	Close() error
}

// Service defines a type that  can subscribe to the message bus and perform
// actions.
type Service interface {
	// Start the service. Config is the config section for that service,
	// with the global MQTT config section appended.
	Start(config *viper.Viper) error

	// Specifies the logger to be used.
	UseLogger(logger Logger)

	// Stops the service.
	Stop() error
}

// Logger represents a way to log error messages for the user.
type Logger interface {
	Log(a ...interface{})
}
<commit_msg>Fix typo<commit_after>// Copyright © 2016 Casa Platform
//
// 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 casa defines interfaces and types for the casa home automation
// platform. These interfaces are subject to change without notice as casa is
// refined. Feel free to play with it now but wait until a v1 release before
// you depend on it for anything.
package casa

import "github.com/spf13/viper"

// Message represents an MQTT message
// Might be better to be an interface?
type Message struct {
	Topic   string
	Payload []byte
	Retain  bool
}

// MessageBus defines a system for passing Messages
type MessageBus interface {
	// Shutdown the MessageBus
	Close() error

	// NewClient returns a client that is connected to the MessageBus
	NewClient() MessageClient
}

// MessageClient sends and receives Messages to a MessageBus
type MessageClient interface {
	// Register a function to call when a message or error is received
	Handle(func(msg *Message, err error))

	// Publish a pre-composed message
	PublishMessage(message Message) error

	// Subscribes to the given topic
	Subscribe(topic string) error

	// Removes subscription for the topic
	Unsubscribe(topic string) error

	// Closes the client
	Close() error
}

// Service defines a type that  can subscribe to the message bus and perform
// actions.
type Service interface {
	// Start the service. Config is the config section for that service,
	// with the global MQTT config section appended.
	Start(config *viper.Viper) error

	// Specifies the logger to be used.
	UseLogger(logger Logger)

	// Stops the service.
	Stop() error
}

// Logger represents a way to log error messages for the user.
type Logger interface {
	Log(a ...interface{})
}
<|endoftext|>


<commit_before>package stockfighter

import (
	"fmt"
	"time"
)

type OrderType int

const (
	Limit OrderType = iota
	Market
	FillOrKill
	ImmediateOrCancel
)

type Game struct {
	Account              string
	InstanceId           uint64
	Instructions         map[string]string
	SecondsPerTradingDay uint64
	Tickers              []string
	Venues               []string
}

type GameState struct {
	Details struct {
		EndOfTheWorldDay uint64
		TradingDay       uint64
	}
	Flash struct {
		Info string
	}
	Done  bool
	Id    uint64
	State string
}

type Symbol struct {
	Symbol string
	Name   string
}

type Order struct {
	Account   string    `json:"account"`
	Venue     string    `json:"venue"`
	Stock     string    `json:"stock"`
	Price     uint64    `json:"price"`
	Quantity  uint64    `json:"qty"`
	Direction string    `json:"direction"`
	OrderType OrderType `json:"orderType"`
}

type StandingOrder struct {
	Price    uint64
	Quantity uint64 `json:"qty"`
	IsBuy    bool
}

type OrderBook struct {
	Venue     string
	Symbol    string
	Asks      []StandingOrder
	Bids      []StandingOrder
	TimeStamp time.Time `json:"ts"`
}

type Fill struct {
	Price     uint64
	Quantity  uint64    `json:"qty"`
	TimeStamp time.Time `json:"ts"`
}

type OrderState struct {
	Venue            string
	Symbol           string
	Price            uint64
	OriginalQuantity uint64 `json:"originalQty"`
	Quantity         uint64 `json:"qty"`
	Direction        string
	Type             OrderType
	Id               uint64
	Account          string
	Timestamp        time.Time `json:"ts"`
	Fills            []Fill
	TotalFilled      uint64
	Open             bool
}

type Quote struct {
	Venue     string
	Symbol    string
	Bid       uint64
	BidSize   uint64
	BidDepth  uint64
	Ask       uint64
	AskSize   uint64
	AskDepth  uint64
	Last      uint64
	LastSize  uint64
	LastTrade time.Time
	QuoteTime time.Time
}

type Execution struct {
	Account          string
	Venue            string
	Symbol           string
	Order            OrderState
	StandingId       uint64
	Price            uint64
	Filled           uint64
	FilledAt         time.Time
	StandingComplete bool
	IncomingComplete bool
}

var orderTypes = [...]string{
	Limit:             "limit",
	Market:            "market",
	FillOrKill:        "fill-or-kill",
	ImmediateOrCancel: "immediate-or-cancel",
}

func (o OrderType) MarshalText() ([]byte, error) {
	return []byte(orderTypes[o]), nil
}

var orderTypeMap = map[string]OrderType{
	"limit":               Limit,
	"market":              Market,
	"fill-or-kill":        FillOrKill,
	"immediate-or-cancel": ImmediateOrCancel,
}

func (o *OrderType) UnmarshalText(text []byte) error {
	typ, ok := orderTypeMap[string(text)]
	if ok {
		*o = typ
		return nil
	}
	return fmt.Errorf("Unknown order type: %s", text)
}
<commit_msg>Add OrderType String()<commit_after>package stockfighter

import (
	"fmt"
	"time"
)

type OrderType int

const (
	Limit OrderType = iota
	Market
	FillOrKill
	ImmediateOrCancel
)

type Game struct {
	Account              string
	InstanceId           uint64
	Instructions         map[string]string
	SecondsPerTradingDay uint64
	Tickers              []string
	Venues               []string
}

type GameState struct {
	Details struct {
		EndOfTheWorldDay uint64
		TradingDay       uint64
	}
	Flash struct {
		Info string
	}
	Done  bool
	Id    uint64
	State string
}

type Symbol struct {
	Symbol string
	Name   string
}

type Order struct {
	Account   string    `json:"account"`
	Venue     string    `json:"venue"`
	Stock     string    `json:"stock"`
	Price     uint64    `json:"price"`
	Quantity  uint64    `json:"qty"`
	Direction string    `json:"direction"`
	OrderType OrderType `json:"orderType"`
}

type StandingOrder struct {
	Price    uint64
	Quantity uint64 `json:"qty"`
	IsBuy    bool
}

type OrderBook struct {
	Venue     string
	Symbol    string
	Asks      []StandingOrder
	Bids      []StandingOrder
	TimeStamp time.Time `json:"ts"`
}

type Fill struct {
	Price     uint64
	Quantity  uint64    `json:"qty"`
	TimeStamp time.Time `json:"ts"`
}

type OrderState struct {
	Venue            string
	Symbol           string
	Price            uint64
	OriginalQuantity uint64 `json:"originalQty"`
	Quantity         uint64 `json:"qty"`
	Direction        string
	Type             OrderType
	Id               uint64
	Account          string
	Timestamp        time.Time `json:"ts"`
	Fills            []Fill
	TotalFilled      uint64
	Open             bool
}

type Quote struct {
	Venue     string
	Symbol    string
	Bid       uint64
	BidSize   uint64
	BidDepth  uint64
	Ask       uint64
	AskSize   uint64
	AskDepth  uint64
	Last      uint64
	LastSize  uint64
	LastTrade time.Time
	QuoteTime time.Time
}

type Execution struct {
	Account          string
	Venue            string
	Symbol           string
	Order            OrderState
	StandingId       uint64
	Price            uint64
	Filled           uint64
	FilledAt         time.Time
	StandingComplete bool
	IncomingComplete bool
}

var orderTypes = [...]string{
	Limit:             "limit",
	Market:            "market",
	FillOrKill:        "fill-or-kill",
	ImmediateOrCancel: "immediate-or-cancel",
}

func (o OrderType) MarshalText() ([]byte, error) {
	return []byte(orderTypes[o]), nil
}

func (o OrderType) String() string {
	return orderTypes[o]
}

var orderTypeMap = map[string]OrderType{
	"limit":               Limit,
	"market":              Market,
	"fill-or-kill":        FillOrKill,
	"immediate-or-cancel": ImmediateOrCancel,
}

func (o *OrderType) UnmarshalText(text []byte) error {
	typ, ok := orderTypeMap[string(text)]
	if ok {
		*o = typ
		return nil
	}
	return fmt.Errorf("Unknown order type: %s", text)
}
<|endoftext|>


<commit_before>package common

import (
	"bytes"
	"encoding/hex"
	"fmt"
	capn "github.com/glycerine/go-capnproto"
	"sort"
)

const (
	RMIdEmpty = RMId(0)
	KeyLen    = 20
	ClientLen = KeyLen - 8
)

type RMId uint32

func (rmId RMId) String() string {
	if rmId == RMIdEmpty {
		return "RM:Empty"
	} else {
		return fmt.Sprintf("RM:%x", uint32(rmId))
	}
}

type KeyType [KeyLen]byte

type VarUUId KeyType

func MakeVarUUId(data []byte) *VarUUId {
	uuid := VarUUId([KeyLen]byte{})
	copy(uuid[:], data)
	return &uuid
}

func MakeVarUUIdFromStr(str string) *VarUUId {
	data, err := hex.DecodeString(str)
	if err != nil {
		return nil
	}
	return MakeVarUUId(data)
}

func (vUUId VarUUId) String() string {
	h := ([]byte)(hex.EncodeToString(vUUId[:]))
	return fmt.Sprintf("VarUUId:%s", h)
}

type TxnId KeyType

func MakeTxnId(data []byte) *TxnId {
	id := TxnId([KeyLen]byte{})
	copy(id[:], data)
	return &id
}

func (txnId TxnId) String() string {
	t := txnId[:]
	client, conn, boot, rmId := hex.EncodeToString(t[0:8]), hex.EncodeToString(t[8:12]), hex.EncodeToString(t[12:16]), hex.EncodeToString(t[16:20])
	return fmt.Sprintf("TxnId:%s-%s-%s-%v", client, conn, boot, rmId)
}

func (txnId TxnId) ClientId() [ClientLen]byte {
	client := [ClientLen]byte{}
	copy(client[:], txnId[8:])
	return client
}

type Cmp int8

const (
	LT Cmp = iota - 1
	EQ
	GT
)

func (a *TxnId) Compare(b *TxnId) Cmp {
	switch {
	case a == b:
		return EQ
	case a == nil:
		return LT
	case b == nil:
		return GT
	default:
		switch cmp := bytes.Compare(a[:], b[:]); {
		case cmp < 0:
			return LT
		case cmp > 0:
			return GT
		default:
			return EQ
		}
	}
}

func (a *VarUUId) Compare(b *VarUUId) Cmp {
	switch {
	case a == b:
		return EQ
	case a == nil:
		return LT
	case b == nil:
		return GT
	default:
		switch cmp := bytes.Compare(a[:], b[:]); {
		case cmp < 0:
			return LT
		case cmp > 0:
			return GT
		default:
			return EQ
		}
	}
}

type VarUUIds []*VarUUId

func (vUUIds VarUUIds) Sort()              { sort.Sort(vUUIds) }
func (vUUIds VarUUIds) Len() int           { return len(vUUIds) }
func (vUUIds VarUUIds) Less(i, j int) bool { return vUUIds[i].Compare(vUUIds[j]) == LT }
func (vUUIds VarUUIds) Swap(i, j int)      { vUUIds[i], vUUIds[j] = vUUIds[j], vUUIds[i] }

type Positions capn.UInt8List

func (a *Positions) Equal(b *Positions) bool {
	if a == nil || b == nil {
		return a == b
	}
	aCap, bCap := (*capn.UInt8List)(a), (*capn.UInt8List)(b)
	if aCap.Len() != bCap.Len() {
		return false
	}
	for idx, l := 0, aCap.Len(); idx < l; idx++ {
		if aV, bV := aCap.At(idx), bCap.At(idx); aV != bV {
			return false
		}
	}
	return true
}

func (p *Positions) String() string {
	return fmt.Sprint((*capn.UInt8List)(p).ToArray())
}

type RMIds []RMId

func (rmIds RMIds) Sort()              { sort.Sort(rmIds) }
func (rmIds RMIds) Len() int           { return len(rmIds) }
func (rmIds RMIds) Less(i, j int) bool { return rmIds[i] < rmIds[j] }
func (rmIds RMIds) Swap(i, j int)      { rmIds[i], rmIds[j] = rmIds[j], rmIds[i] }

func (a RMIds) Equal(b RMIds) bool {
	if a == nil || b == nil {
		return a == nil && b == nil
	}
	if len(a) != len(b) {
		return false
	}
	for idx, rA := range a {
		if b[idx] != rA {
			return false
		}
	}
	return true
}

func (rmIds RMIds) EmptyLen() int {
	count := 0
	for _, rmId := range rmIds {
		if rmId == RMIdEmpty {
			count++
		}
	}
	return count
}

func (rmIds RMIds) NonEmptyLen() int {
	count := 0
	for _, rmId := range rmIds {
		if rmId != RMIdEmpty {
			count++
		}
	}
	return count
}

func (rmIds RMIds) NonEmpty() RMIds {
	nel := rmIds.NonEmptyLen()
	if nel == len(rmIds) {
		return rmIds
	}
	nonEmpty := make([]RMId, 0, nel)
	for _, rmId := range rmIds {
		if rmId != RMIdEmpty {
			nonEmpty = append(nonEmpty, rmId)
		}
	}
	return nonEmpty
}
<commit_msg>Whoops, forgot to add these yesterday. Ref T6.<commit_after>package common

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	capn "github.com/glycerine/go-capnproto"
	"sort"
)

const (
	RMIdEmpty = RMId(0)
	KeyLen    = 20
	ClientLen = KeyLen - 8
)

type RMId uint32

func (rmId RMId) String() string {
	if rmId == RMIdEmpty {
		return "RM:Empty"
	} else {
		return fmt.Sprintf("RM:%x", uint32(rmId))
	}
}

type KeyType [KeyLen]byte

type VarUUId KeyType

func MakeVarUUId(data []byte) *VarUUId {
	uuid := VarUUId([KeyLen]byte{})
	copy(uuid[:], data)
	return &uuid
}

func MakeVarUUIdFromStr(str string) *VarUUId {
	data, err := hex.DecodeString(str)
	if err != nil {
		return nil
	}
	return MakeVarUUId(data)
}

func (vUUId VarUUId) String() string {
	h := ([]byte)(hex.EncodeToString(vUUId[:]))
	return fmt.Sprintf("VarUUId:%s", h)
}

func (vUUId VarUUId) ConnectionCount() uint32 {
	return binary.BigEndian.Uint32(vUUId[8:12])
}

func (vUUId VarUUId) BootCount() uint32 {
	return binary.BigEndian.Uint32(vUUId[12:16])
}

func (vUUId VarUUId) RMId() RMId {
	return RMId(binary.BigEndian.Uint32(vUUId[16:20]))
}

type TxnId KeyType

func MakeTxnId(data []byte) *TxnId {
	id := TxnId([KeyLen]byte{})
	copy(id[:], data)
	return &id
}

func (txnId TxnId) String() string {
	t := txnId[:]
	client, conn, boot, rmId := hex.EncodeToString(t[0:8]), hex.EncodeToString(t[8:12]), hex.EncodeToString(t[12:16]), hex.EncodeToString(t[16:20])
	return fmt.Sprintf("TxnId:%s-%s-%s-%v", client, conn, boot, rmId)
}

func (txnId TxnId) ClientId() [ClientLen]byte {
	client := [ClientLen]byte{}
	copy(client[:], txnId[8:])
	return client
}

func (txnId TxnId) ConnectionCount() uint32 {
	return binary.BigEndian.Uint32(txnId[8:12])
}

func (txnId TxnId) BootCount() uint32 {
	return binary.BigEndian.Uint32(txnId[12:16])
}

func (txnId TxnId) RMId() RMId {
	return RMId(binary.BigEndian.Uint32(txnId[16:20]))
}

type Cmp int8

const (
	LT Cmp = iota - 1
	EQ
	GT
)

func (a *TxnId) Compare(b *TxnId) Cmp {
	switch {
	case a == b:
		return EQ
	case a == nil:
		return LT
	case b == nil:
		return GT
	default:
		switch cmp := bytes.Compare(a[:], b[:]); {
		case cmp < 0:
			return LT
		case cmp > 0:
			return GT
		default:
			return EQ
		}
	}
}

func (a *VarUUId) Compare(b *VarUUId) Cmp {
	switch {
	case a == b:
		return EQ
	case a == nil:
		return LT
	case b == nil:
		return GT
	default:
		switch cmp := bytes.Compare(a[:], b[:]); {
		case cmp < 0:
			return LT
		case cmp > 0:
			return GT
		default:
			return EQ
		}
	}
}

type VarUUIds []*VarUUId

func (vUUIds VarUUIds) Sort()              { sort.Sort(vUUIds) }
func (vUUIds VarUUIds) Len() int           { return len(vUUIds) }
func (vUUIds VarUUIds) Less(i, j int) bool { return vUUIds[i].Compare(vUUIds[j]) == LT }
func (vUUIds VarUUIds) Swap(i, j int)      { vUUIds[i], vUUIds[j] = vUUIds[j], vUUIds[i] }

type Positions capn.UInt8List

func (a *Positions) Equal(b *Positions) bool {
	if a == nil || b == nil {
		return a == b
	}
	aCap, bCap := (*capn.UInt8List)(a), (*capn.UInt8List)(b)
	if aCap.Len() != bCap.Len() {
		return false
	}
	for idx, l := 0, aCap.Len(); idx < l; idx++ {
		if aV, bV := aCap.At(idx), bCap.At(idx); aV != bV {
			return false
		}
	}
	return true
}

func (p *Positions) String() string {
	return fmt.Sprint((*capn.UInt8List)(p).ToArray())
}

type RMIds []RMId

func (rmIds RMIds) Sort()              { sort.Sort(rmIds) }
func (rmIds RMIds) Len() int           { return len(rmIds) }
func (rmIds RMIds) Less(i, j int) bool { return rmIds[i] < rmIds[j] }
func (rmIds RMIds) Swap(i, j int)      { rmIds[i], rmIds[j] = rmIds[j], rmIds[i] }

func (a RMIds) Equal(b RMIds) bool {
	if a == nil || b == nil {
		return a == nil && b == nil
	}
	if len(a) != len(b) {
		return false
	}
	for idx, rA := range a {
		if b[idx] != rA {
			return false
		}
	}
	return true
}

func (rmIds RMIds) EmptyLen() int {
	count := 0
	for _, rmId := range rmIds {
		if rmId == RMIdEmpty {
			count++
		}
	}
	return count
}

func (rmIds RMIds) NonEmptyLen() int {
	count := 0
	for _, rmId := range rmIds {
		if rmId != RMIdEmpty {
			count++
		}
	}
	return count
}

func (rmIds RMIds) NonEmpty() RMIds {
	nel := rmIds.NonEmptyLen()
	if nel == len(rmIds) {
		return rmIds
	}
	nonEmpty := make([]RMId, 0, nel)
	for _, rmId := range rmIds {
		if rmId != RMIdEmpty {
			nonEmpty = append(nonEmpty, rmId)
		}
	}
	return nonEmpty
}
<|endoftext|>


<commit_before>package gorill

import (
	"bytes"
	"io"
	"time"
)

// ErrWriteAfterClose is returned if a Write is attempted after Close called.
type ErrWriteAfterClose struct{}

// Error returns a string representation of a ErrWriteAfterClose error instance.
func (e ErrWriteAfterClose) Error() string {
	return "cannot write; already closed"
}

////////////////////////////////////////

type nopCloseWriter struct{ io.Writer }

func (nopCloseWriter) Close() error { return nil }

// NopCloseWriter returns a structure that implements io.WriteCloser, but provides a no-op Close
// method.  It is useful when you have an io.Writer that you must pass to a method that requires an
// io.WriteCloser.  It is the counter-part to ioutil.NopCloser, but for io.Writer.
//
//   iowc := gorill.NopCloseWriter(iow)
//   iowc.Close() // does nothing
func NopCloseWriter(iow io.Writer) io.WriteCloser { return nopCloseWriter{iow} }

////////////////////////////////////////

type nopCloseReader struct{ io.Reader }

func (nopCloseReader) Close() error { return nil }

// NopCloseReader returns a structure that implements io.ReadCloser, but provides a no-op Close
// method.  It is useful when you have an io.Reader that you must pass to a method that requires an
// io.ReadCloser.  It is the same as ioutil.NopCloser, but for provided here for symmetry with
// NopCloseWriter.
//
//   iorc := gorill.NopCloseReader(ior)
//   iorc.Close() // does nothing
func NopCloseReader(ior io.Reader) io.ReadCloser { return nopCloseReader{ior} }

////////////////////////////////////////

type writeJob struct {
	data    []byte
	results chan writeResult
}

type writeResult struct {
	n   int
	err error
}

////////////////////////////////////////

// NopCloseBuffer is a structure that wraps a buffer, but also provides a no-op Close method.
type NopCloseBuffer struct {
	*bytes.Buffer
	closed bool
}

// Close returns nil error.
func (m *NopCloseBuffer) Close() error { m.closed = true; return nil }

// IsClosed returns false, unless NopCloseBuffer's Close method has been invoked
func (m *NopCloseBuffer) IsClosed() bool { return m.closed }

// NewNopCloseBuffer returns a structure that wraps bytes.Buffer with a no-op Close method.  It can
// be used in tests that need a bytes.Buffer.
//
//   bb := gorill.NopCloseBuffer()
//   bb.Write([]byte("example"))
//   bb.Close() // does nothing
func NewNopCloseBuffer() *NopCloseBuffer {
	return &NopCloseBuffer{Buffer: new(bytes.Buffer), closed: false}
}

////////////////////////////////////////

type shortWriter struct {
	iow io.Writer
	max int
}

func (s shortWriter) Write(data []byte) (int, error) {
	index := len(data)
	if index > s.max {
		index = s.max
	}
	n, err := s.iow.Write(data[:index])
	if err != nil {
		return n, err
	}
	return n, io.ErrShortWrite
}

// ShortWriter returns a structure that wraps an io.Writer, but returns io.ErrShortWrite when the
// number of bytes to write exceeds a preset limit.
//
//   bb := gorill.NopCloseBuffer()
//   sw := gorill.ShortWriter(bb, 16)
//
//   n, err := sw.Write([]byte("short write"))
//   // n == 11, err == nil
//
//   n, err := sw.Write([]byte("a somewhat longer write"))
//   // n == 16, err == io.ErrShortWrite
func ShortWriter(iow io.Writer, size int) io.Writer { return shortWriter{iow, size} }

////////////////////////////////////////

type slowWriter struct {
	d time.Duration
	w io.Writer
}

func (s *slowWriter) Write(data []byte) (int, error) {
	time.Sleep(s.d)
	return s.w.Write(data)
}

// SlowWriter returns a structure that wraps an io.Writer, but sleeps prior to writing data to the
// underlying io.Writer.
//
//   bb := gorill.NopCloseBuffer()
//   sw := gorill.SlowWriter(bb, 10*time.Second)
//
//   n, err := sw.Write([]byte("example")) // this call takes at least 10 seconds to return
//   // n == 7, err == nil
func SlowWriter(w io.Writer, d time.Duration) io.Writer {
	return &slowWriter{d: d, w: w}
}
<commit_msg>NopCloseBufferSize function creates NopCloseBuffer with specified size<commit_after>package gorill

import (
	"bytes"
	"io"
	"time"
)

// ErrWriteAfterClose is returned if a Write is attempted after Close called.
type ErrWriteAfterClose struct{}

// Error returns a string representation of a ErrWriteAfterClose error instance.
func (e ErrWriteAfterClose) Error() string {
	return "cannot write; already closed"
}

////////////////////////////////////////

type nopCloseWriter struct{ io.Writer }

func (nopCloseWriter) Close() error { return nil }

// NopCloseWriter returns a structure that implements io.WriteCloser, but provides a no-op Close
// method.  It is useful when you have an io.Writer that you must pass to a method that requires an
// io.WriteCloser.  It is the counter-part to ioutil.NopCloser, but for io.Writer.
//
//   iowc := gorill.NopCloseWriter(iow)
//   iowc.Close() // does nothing
func NopCloseWriter(iow io.Writer) io.WriteCloser { return nopCloseWriter{iow} }

////////////////////////////////////////

type nopCloseReader struct{ io.Reader }

func (nopCloseReader) Close() error { return nil }

// NopCloseReader returns a structure that implements io.ReadCloser, but provides a no-op Close
// method.  It is useful when you have an io.Reader that you must pass to a method that requires an
// io.ReadCloser.  It is the same as ioutil.NopCloser, but for provided here for symmetry with
// NopCloseWriter.
//
//   iorc := gorill.NopCloseReader(ior)
//   iorc.Close() // does nothing
func NopCloseReader(ior io.Reader) io.ReadCloser { return nopCloseReader{ior} }

////////////////////////////////////////

type writeJob struct {
	data    []byte
	results chan writeResult
}

type writeResult struct {
	n   int
	err error
}

////////////////////////////////////////

// NopCloseBuffer is a structure that wraps a buffer, but also provides a no-op Close method.
type NopCloseBuffer struct {
	*bytes.Buffer
	closed bool
}

// Close returns nil error.
func (m *NopCloseBuffer) Close() error { m.closed = true; return nil }

// IsClosed returns false, unless NopCloseBuffer's Close method has been invoked
func (m *NopCloseBuffer) IsClosed() bool { return m.closed }

// NewNopCloseBuffer returns a structure that wraps bytes.Buffer with a no-op Close method.  It can
// be used in tests that need a bytes.Buffer.
//
//   bb := gorill.NopCloseBuffer()
//   bb.Write([]byte("example"))
//   bb.Close() // does nothing
func NewNopCloseBuffer() *NopCloseBuffer {
	return &NopCloseBuffer{Buffer: new(bytes.Buffer), closed: false}
}

func NewNopCloseBufferSize(size int) *NopCloseBuffer {
	return &NopCloseBuffer{Buffer: bytes.NewBuffer(make([]byte, 0, size)), closed: false}
}

////////////////////////////////////////

type shortWriter struct {
	iow io.Writer
	max int
}

func (s shortWriter) Write(data []byte) (int, error) {
	index := len(data)
	if index > s.max {
		index = s.max
	}
	n, err := s.iow.Write(data[:index])
	if err != nil {
		return n, err
	}
	return n, io.ErrShortWrite
}

// ShortWriter returns a structure that wraps an io.Writer, but returns io.ErrShortWrite when the
// number of bytes to write exceeds a preset limit.
//
//   bb := gorill.NopCloseBuffer()
//   sw := gorill.ShortWriter(bb, 16)
//
//   n, err := sw.Write([]byte("short write"))
//   // n == 11, err == nil
//
//   n, err := sw.Write([]byte("a somewhat longer write"))
//   // n == 16, err == io.ErrShortWrite
func ShortWriter(iow io.Writer, size int) io.Writer { return shortWriter{iow, size} }

////////////////////////////////////////

type slowWriter struct {
	d time.Duration
	w io.Writer
}

func (s *slowWriter) Write(data []byte) (int, error) {
	time.Sleep(s.d)
	return s.w.Write(data)
}

// SlowWriter returns a structure that wraps an io.Writer, but sleeps prior to writing data to the
// underlying io.Writer.
//
//   bb := gorill.NopCloseBuffer()
//   sw := gorill.SlowWriter(bb, 10*time.Second)
//
//   n, err := sw.Write([]byte("example")) // this call takes at least 10 seconds to return
//   // n == 7, err == nil
func SlowWriter(w io.Writer, d time.Duration) io.Writer {
	return &slowWriter{d: d, w: w}
}
<|endoftext|>


<commit_before>/*
 Commonly used types in a single place. Purely for organisation purposes.
*/

package main

// Board stores board metadata and the OPs of all threads
type Board struct {
	Ctr     int      `json:"ctr",gorethink:"ctr"`
	Threads []Thread `json:"threads",gorethink:"threads"`
}

// Thread stores the metadata and posts of a single thread
type Thread struct {
	ID       int             `json:"id,omitempty",gorethink:"id"`
	IP       string          `json:"-",gorethink:"ip"`
	Board    string          `json:"board,omitempty",gorethink:"board"`
	Time     int             `json:"time,omitempty",gorethink:"time"`
	BumpTime int             `json:"bumpTime,omitempty",gorethink:"bumpTime"`
	Nonce    string          `json:"-",gorethink:"nonce"`
	Posts    map[string]Post `json:"posts,omitempty",gorethink:"posts"`
	History  []Message       `json:"-",gorethink:"history"`
	HistCtr  int             `json:"histCtr,omitempty",gorethink:"histCtr"`
	ReplyCtr int             `json:"replyCtr,omitempty",gorethink:"replyCtr"`
	ImageCtr int             `json:"imageCtr,omitempty",gorethink:"imageCtr"`
	OP       Post            `json:"-",gorethink:"op"` // For internal use
}

// Message is the universal transport container of all live updates through
// websockets
type Message struct {
	Type string `json:"type",gorethink:"type"`

	// If present, determines a priviledged access level, the client has to
	// have, to recieve this message
	Priv string `json:"priv,omitempty",gorethink:"priv,omitempty"`

	// The actual contents of the message. Very variadic, thus interface{}.
	Msg interface{} `json:"msg,omitempty",gorethink:"msg,omitempty"`
}

// Post is a generic post. Either OP or reply.
type Post struct {
	ID         int            `json:"id,omitempty",gorethink:"id"`
	IP         string         `json:"-",gorethink:"ip"`
	OP         int            `json:"op,omitempty",gorethink:"op"`
	Board      string         `json:"board,omitempty",gorethink:"board"`
	Time       int            `json:"time,omitempty",gorethink:"time"`
	Nonce      string         `json:"-",gorethink:"nonce"`
	Editing    bool           `json:"editing,omitempty",gorethink:"editing,omitempty"`
	Body       string         `json:"body,omitempty",gorethink:"body"`
	Deleted    bool           `json:"-",gorethink:"deleted"`
	ImgDeleted bool           `json:"-",gorethink:"imgDeleted"`
	Image      Image          `json:"image,omitempty",gorethink:"image,omitempty"`
	Name       string         `json:"name,omitempty",gorethink:"name,omitempty"`
	Trip       string         `json:"trip,omitempty",gorethink:"trip,omitempty"`
	Email      string         `json:"email,omitempty",gorethink:"email,omitempty"`
	Auth       string         `json:"auth,omitempty",gorethink:"auth,omitempty"`
	Dice       Dice           `json:"dice,omitempty",gorethink:"dice,omitempty"`
	Links      LinkMap        `json:"links,omitempty",gorethink:"links,omitempty"`
	Backlinks  LinkMap        `json:"backlinks,omitempty",gorethink:"backlinks,omitempty"`
	Mod        ModerationList `json:"mod,omitempty",gorethink:"mod,omitempty"`
}

// Image contains a post's image and thumbanail data
type Image struct {
	Src     string `json:"src,omitempty",gorethink:"src"`
	Thumb   string `json:"thumb,omitempty",gorethink:"thumb,omitempty"`
	Mid     string `json:"mid,omitempty",gorethink:"mid,omitempty"`
	Dims    []int  `json:"dims,omitempty",gorethink:"dims"`
	Ext     string `json:"ext,omitempty",gorethink:"ext"`
	Size    int    `json:"size,omitempty",gorethink:"size"`
	MD5     string `json:",omitempty"`
	SHA1    string `json:",omitempty"`
	Imgnm   string `json:"imgnm,omitempty",gorethink:"imgnm,omitempty"`
	Spoiler int    `json:"spoiler,omitempty",gorethink:"spoiler,omitempty"`
	APNG    bool   `json:"apng,omitempty",gorethink:"apng,omitempty"`
	Audio   bool   `json:"audio,omitempty",gorethink:"audio,omitempty"`
	Length  string `json:"lenght,omitempty",gorethink:"lenght,omitempty"`
}

// Dice stores # command information of the post in exectution order
type Dice []Roll

// Roll represents a single hash command. It always contains the Type field,
// which determines, which of the other fields are present.
type Roll struct {
	Type   string `json:"type",gorethink:"type"`
	Bool   bool   `json:"bool,omitempty",gorethink:"bool,omitempty"`
	Int    int    `json:"int,omitempty",gorethink:"int,omitempty"`
	Ints   []int  `json:"ints,omitempty",gorethink:"ints,omitempty"`
	String string `json:"string,omitempty",gorethink:"string,omitempty"`
}

// LinkMap contains a map of post numbers, this tread is linking, to
// corresponding Link tuples
type LinkMap map[string]Link

// Link stores the target post's parent board and parent thread
type Link struct {
	Board string `json:"board",gorethink:"board"`
	OP    int    `json:"op",gorethink:"op"`
}

// Ident is used to verify a client's access and write permissions
type Ident struct {
	// Indicates priveledged access rights for staff.
	Auth   string
	Banned bool
	IP     string
}

// ModerationList contains modration acts commited on this post.
// TEMP
type ModerationList []interface{}
<commit_msg>Always pass thread counters in JSON<commit_after>/*
 Commonly used types in a single place. Purely for organisation purposes.
*/

package main

// Board stores board metadata and the OPs of all threads
type Board struct {
	Ctr     int      `json:"ctr",gorethink:"ctr"`
	Threads []Thread `json:"threads",gorethink:"threads"`
}

// Thread stores the metadata and posts of a single thread
type Thread struct {
	ID       int             `json:"id,omitempty",gorethink:"id"`
	IP       string          `json:"-",gorethink:"ip"`
	Board    string          `json:"board,omitempty",gorethink:"board"`
	Time     int             `json:"time,omitempty",gorethink:"time"`
	BumpTime int             `json:"bumpTime,omitempty",gorethink:"bumpTime"`
	Nonce    string          `json:"-",gorethink:"nonce"`
	Posts    map[string]Post `json:"posts,omitempty",gorethink:"posts"`
	History  []Message       `json:"-",gorethink:"history"`
	HistCtr  int             `json:"histCtr",gorethink:"histCtr"`
	ReplyCtr int             `json:"replyCtr",gorethink:"replyCtr"`
	ImageCtr int             `json:"imageCtr",gorethink:"imageCtr"`
	OP       Post            `json:"-",gorethink:"op"` // For internal use
}

// Message is the universal transport container of all live updates through
// websockets
type Message struct {
	Type string `json:"type",gorethink:"type"`

	// If present, determines a priviledged access level, the client has to
	// have, to recieve this message
	Priv string `json:"priv,omitempty",gorethink:"priv,omitempty"`

	// The actual contents of the message. Very variadic, thus interface{}.
	Msg interface{} `json:"msg,omitempty",gorethink:"msg,omitempty"`
}

// Post is a generic post. Either OP or reply.
type Post struct {
	ID         int            `json:"id,omitempty",gorethink:"id"`
	IP         string         `json:"-",gorethink:"ip"`
	OP         int            `json:"op,omitempty",gorethink:"op"`
	Board      string         `json:"board,omitempty",gorethink:"board"`
	Time       int            `json:"time,omitempty",gorethink:"time"`
	Nonce      string         `json:"-",gorethink:"nonce"`
	Editing    bool           `json:"editing,omitempty",gorethink:"editing,omitempty"`
	Body       string         `json:"body,omitempty",gorethink:"body"`
	Deleted    bool           `json:"-",gorethink:"deleted"`
	ImgDeleted bool           `json:"-",gorethink:"imgDeleted"`
	Image      Image          `json:"image,omitempty",gorethink:"image,omitempty"`
	Name       string         `json:"name,omitempty",gorethink:"name,omitempty"`
	Trip       string         `json:"trip,omitempty",gorethink:"trip,omitempty"`
	Email      string         `json:"email,omitempty",gorethink:"email,omitempty"`
	Auth       string         `json:"auth,omitempty",gorethink:"auth,omitempty"`
	Dice       Dice           `json:"dice,omitempty",gorethink:"dice,omitempty"`
	Links      LinkMap        `json:"links,omitempty",gorethink:"links,omitempty"`
	Backlinks  LinkMap        `json:"backlinks,omitempty",gorethink:"backlinks,omitempty"`
	Mod        ModerationList `json:"mod,omitempty",gorethink:"mod,omitempty"`
}

// Image contains a post's image and thumbanail data
type Image struct {
	Src     string `json:"src,omitempty",gorethink:"src"`
	Thumb   string `json:"thumb,omitempty",gorethink:"thumb,omitempty"`
	Mid     string `json:"mid,omitempty",gorethink:"mid,omitempty"`
	Dims    []int  `json:"dims,omitempty",gorethink:"dims"`
	Ext     string `json:"ext,omitempty",gorethink:"ext"`
	Size    int    `json:"size,omitempty",gorethink:"size"`
	MD5     string `json:",omitempty"`
	SHA1    string `json:",omitempty"`
	Imgnm   string `json:"imgnm,omitempty",gorethink:"imgnm,omitempty"`
	Spoiler int    `json:"spoiler,omitempty",gorethink:"spoiler,omitempty"`
	APNG    bool   `json:"apng,omitempty",gorethink:"apng,omitempty"`
	Audio   bool   `json:"audio,omitempty",gorethink:"audio,omitempty"`
	Length  string `json:"lenght,omitempty",gorethink:"lenght,omitempty"`
}

// Dice stores # command information of the post in exectution order
type Dice []Roll

// Roll represents a single hash command. It always contains the Type field,
// which determines, which of the other fields are present.
type Roll struct {
	Type   string `json:"type",gorethink:"type"`
	Bool   bool   `json:"bool,omitempty",gorethink:"bool,omitempty"`
	Int    int    `json:"int,omitempty",gorethink:"int,omitempty"`
	Ints   []int  `json:"ints,omitempty",gorethink:"ints,omitempty"`
	String string `json:"string,omitempty",gorethink:"string,omitempty"`
}

// LinkMap contains a map of post numbers, this tread is linking, to
// corresponding Link tuples
type LinkMap map[string]Link

// Link stores the target post's parent board and parent thread
type Link struct {
	Board string `json:"board",gorethink:"board"`
	OP    int    `json:"op",gorethink:"op"`
}

// Ident is used to verify a client's access and write permissions
type Ident struct {
	// Indicates priveledged access rights for staff.
	Auth   string
	Banned bool
	IP     string
}

// ModerationList contains modration acts commited on this post.
// TEMP
type ModerationList []interface{}
<|endoftext|>


<commit_before>package vsolver

type ProjectName string

type ProjectAtom struct {
	Name    ProjectName
	Version Version
}

var emptyProjectAtom ProjectAtom

type ProjectDep struct {
	Name       ProjectName
	Constraint Constraint
}

type Dependency struct {
	Depender ProjectAtom
	Dep      ProjectDep
}

// ProjectInfo holds the spec and lock information for a given ProjectAtom
type ProjectInfo struct {
	pa ProjectAtom
	Manifest
	Lock
}

// LockedProject is a single project entry from a lock file. It expresses the
// project's name, one or both of version and underlying revision, the URI for
// accessing it, and the path at which it should be placed within a vendor
// directory.
//
// TODO note that sometime soon, we also plan to allow pkgs. this'll change
type LockedProject struct {
	n         ProjectName
	v         UnpairedVersion
	r         Revision
	path, uri string
}

// NewLockedProject creates a new LockedProject struct with a given name,
// version, upstream repository URI, and on-disk path at which the project is to
// be checked out under a vendor directory.
//
// Note that passing a nil version will cause a panic. This is a correctness
// measure to ensure that the solver is never exposed to a version-less lock
// entry. Such a case would be meaningless - the solver would have no choice but
// to simply dismiss that project. By creating a hard failure case via panic
// instead, we are trying to avoid inflicting the resulting pain on the user by
// instead forcing a decision on the Analyzer implementation.
func NewLockedProject(n ProjectName, v Version, uri, path string) LockedProject {
	if v == nil {
		panic("must provide a non-nil version to create a LockedProject")
	}

	lp := LockedProject{
		n:    n,
		uri:  uri,
		path: path,
	}

	switch tv := v.(type) {
	case Revision:
		lp.r = tv
	case branchVersion:
		lp.v = tv
	case semVersion:
		lp.v = tv
	case plainVersion:
		lp.v = tv
	case versionPair:
		lp.r = tv.r
		lp.v = tv.v
	}

	return lp
}

// Name returns the name of the locked project.
func (lp LockedProject) Name() ProjectName {
	return lp.n
}

// Version assembles together whatever version and/or revision data is
// available into a single Version.
func (lp LockedProject) Version() Version {
	if lp.r == "" {
		return lp.v
	}

	if lp.v == nil {
		return lp.r
	}

	return lp.v.Is(lp.r)
}

// URI returns the upstream URI of the locked project.
func (lp LockedProject) URI() string {
	return lp.uri
}

// Path returns the path relative to the vendor directory to which the locked
// project should be checked out.
func (lp LockedProject) Path() string {
	return lp.path
}

func (lp LockedProject) toAtom() ProjectAtom {
	pa := ProjectAtom{
		Name: lp.n,
	}

	if lp.v == nil {
		pa.Version = lp.r
	} else if lp.r != "" {
		pa.Version = lp.v.Is(lp.r)
	} else {
		pa.Version = lp.v
	}

	return pa
}

// Manifest represents the data from a manifest file (or however the
// implementing tool chooses to store it) at a particular version that is
// relevant to the satisfiability solving process:
//
// - A list of dependencies: project name, and a constraint
// - A list of development-time dependencies (e.g. for testing - only
// the root project's are incorporated)
//
// Finding a solution that satisfies the constraints expressed by all of these
// dependencies (and those from all other projects, transitively), is what the
// solver does.
//
// Note that vsolver does perform static analysis on all projects' codebases;
// if dependencies it finds through that analysis are missing from what the
// Manifest lists, it is considered an error that will eliminate that version
// from consideration in the solving algorithm.
type Manifest interface {
	Name() ProjectName
	GetDependencies() []ProjectDep
	GetDevDependencies() []ProjectDep
}

// Lock represents data from a lock file (or however the implementing tool
// chooses to store it) at a particular version that is relevant to the
// satisfiability solving process.
//
// In general, the information produced by vsolver on finding a successful
// solution is all that would be necessary to constitute a lock file, though
// tools can include whatever other information they want in their storage.
type Lock interface {
	// Indicates the version of the solver used to generate this lock data
	//SolverVersion() string

	// The hash of inputs to vsolver that resulted in this lock data
	InputHash() []byte

	// Projects returns the list of LockedProjects contained in the lock data.
	Projects() []LockedProject
}

// SimpleLock is a helper for tools to simply enumerate lock data when they know
// that no hash, or other complex information, is available.
type SimpleLock []LockedProject

var _ Lock = SimpleLock{}

// InputHash always returns an empty string for SimpleLock. This makes it useless
// as a stable lock to be written to disk, but still useful for some ephemeral
// purposes.
func (SimpleLock) InputHash() []byte {
	return nil
}

// Projects returns the entire contents of the SimpleLock.
func (l SimpleLock) Projects() []LockedProject {
	return l
}

// SimpleManifest is a helper for tools to enumerate manifest data. It's
// intended for ephemeral manifests, such as those created by Analyzers on the
// fly.
type SimpleManifest struct {
	N  ProjectName
	P  []ProjectDep
	DP []ProjectDep
}

var _ Manifest = SimpleManifest{}

// Name returns the name of the project described by the manifest.
func (m SimpleManifest) Name() ProjectName {
	return m.N
}

// GetDependencies returns the project's dependencies.
func (m SimpleManifest) GetDependencies() []ProjectDep {
	return m.P
}

// GetDependencies returns the project's test dependencies.
func (m SimpleManifest) GetDevDependencies() []ProjectDep {
	return m.DP
}
<commit_msg>Maybe the new struct<commit_after>package vsolver

type ProjectIdentifier struct {
	Name       ProjectName
	NetworkURI string
}

type ProjectName string

type ProjectAtom struct {
	Name    ProjectName // TODO to ProjectIdentifier
	Version Version
}

var emptyProjectAtom ProjectAtom

type ProjectDep struct {
	Name       ProjectName // TODO to ProjectIdentifier
	Constraint Constraint
}

type Dependency struct {
	Depender ProjectAtom
	Dep      ProjectDep
}

// ProjectInfo holds the spec and lock information for a given ProjectAtom
type ProjectInfo struct {
	pa ProjectAtom
	Manifest
	Lock
}

// LockedProject is a single project entry from a lock file. It expresses the
// project's name, one or both of version and underlying revision, the URI for
// accessing it, and the path at which it should be placed within a vendor
// directory.
//
// TODO note that sometime soon, we also plan to allow pkgs. this'll change
type LockedProject struct {
	n         ProjectName
	v         UnpairedVersion
	r         Revision
	path, uri string
}

// NewLockedProject creates a new LockedProject struct with a given name,
// version, upstream repository URI, and on-disk path at which the project is to
// be checked out under a vendor directory.
//
// Note that passing a nil version will cause a panic. This is a correctness
// measure to ensure that the solver is never exposed to a version-less lock
// entry. Such a case would be meaningless - the solver would have no choice but
// to simply dismiss that project. By creating a hard failure case via panic
// instead, we are trying to avoid inflicting the resulting pain on the user by
// instead forcing a decision on the Analyzer implementation.
func NewLockedProject(n ProjectName, v Version, uri, path string) LockedProject {
	if v == nil {
		panic("must provide a non-nil version to create a LockedProject")
	}

	lp := LockedProject{
		n:    n,
		uri:  uri,
		path: path,
	}

	switch tv := v.(type) {
	case Revision:
		lp.r = tv
	case branchVersion:
		lp.v = tv
	case semVersion:
		lp.v = tv
	case plainVersion:
		lp.v = tv
	case versionPair:
		lp.r = tv.r
		lp.v = tv.v
	}

	return lp
}

// Name returns the name of the locked project.
func (lp LockedProject) Name() ProjectName {
	return lp.n
}

// Version assembles together whatever version and/or revision data is
// available into a single Version.
func (lp LockedProject) Version() Version {
	if lp.r == "" {
		return lp.v
	}

	if lp.v == nil {
		return lp.r
	}

	return lp.v.Is(lp.r)
}

// URI returns the upstream URI of the locked project.
func (lp LockedProject) URI() string {
	return lp.uri
}

// Path returns the path relative to the vendor directory to which the locked
// project should be checked out.
func (lp LockedProject) Path() string {
	return lp.path
}

func (lp LockedProject) toAtom() ProjectAtom {
	pa := ProjectAtom{
		Name: lp.n,
	}

	if lp.v == nil {
		pa.Version = lp.r
	} else if lp.r != "" {
		pa.Version = lp.v.Is(lp.r)
	} else {
		pa.Version = lp.v
	}

	return pa
}

// Manifest represents the data from a manifest file (or however the
// implementing tool chooses to store it) at a particular version that is
// relevant to the satisfiability solving process:
//
// - A list of dependencies: project name, and a constraint
// - A list of development-time dependencies (e.g. for testing - only
// the root project's are incorporated)
//
// Finding a solution that satisfies the constraints expressed by all of these
// dependencies (and those from all other projects, transitively), is what the
// solver does.
//
// Note that vsolver does perform static analysis on all projects' codebases;
// if dependencies it finds through that analysis are missing from what the
// Manifest lists, it is considered an error that will eliminate that version
// from consideration in the solving algorithm.
type Manifest interface {
	Name() ProjectName
	GetDependencies() []ProjectDep
	GetDevDependencies() []ProjectDep
}

// Lock represents data from a lock file (or however the implementing tool
// chooses to store it) at a particular version that is relevant to the
// satisfiability solving process.
//
// In general, the information produced by vsolver on finding a successful
// solution is all that would be necessary to constitute a lock file, though
// tools can include whatever other information they want in their storage.
type Lock interface {
	// Indicates the version of the solver used to generate this lock data
	//SolverVersion() string

	// The hash of inputs to vsolver that resulted in this lock data
	InputHash() []byte

	// Projects returns the list of LockedProjects contained in the lock data.
	Projects() []LockedProject
}

// SimpleLock is a helper for tools to simply enumerate lock data when they know
// that no hash, or other complex information, is available.
type SimpleLock []LockedProject

var _ Lock = SimpleLock{}

// InputHash always returns an empty string for SimpleLock. This makes it useless
// as a stable lock to be written to disk, but still useful for some ephemeral
// purposes.
func (SimpleLock) InputHash() []byte {
	return nil
}

// Projects returns the entire contents of the SimpleLock.
func (l SimpleLock) Projects() []LockedProject {
	return l
}

// SimpleManifest is a helper for tools to enumerate manifest data. It's
// intended for ephemeral manifests, such as those created by Analyzers on the
// fly.
type SimpleManifest struct {
	N  ProjectName
	P  []ProjectDep
	DP []ProjectDep
}

var _ Manifest = SimpleManifest{}

// Name returns the name of the project described by the manifest.
func (m SimpleManifest) Name() ProjectName {
	return m.N
}

// GetDependencies returns the project's dependencies.
func (m SimpleManifest) GetDependencies() []ProjectDep {
	return m.P
}

// GetDependencies returns the project's test dependencies.
func (m SimpleManifest) GetDevDependencies() []ProjectDep {
	return m.DP
}
<|endoftext|>


<commit_before>//Copyright 2014 Aaron Goldman. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file

//Package web implements a web interface
//It is started by calling web.Start
package web

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/AaronGoldman/ccfs/objects"
	"github.com/AaronGoldman/ccfs/services"
)

//BlobServerStart starts a server for the content services
func BlobServerStart() {
	http.Handle(
		"/b/",
		http.StripPrefix(
			"/b/",
			http.FileServer(http.Dir("bin/blobs")),
		),
	)
	http.Handle(
		"/t/",
		http.StripPrefix(
			"/t/",
			http.FileServer(http.Dir("bin/tags")),
		),
	)
	http.Handle(
		"/c/",
		http.StripPrefix("/c/",
			http.FileServer(http.Dir("bin/commits")),
		),
	)
	http.ListenAndServe(":8080", nil)
}

//CollectionServerStart starts a server for full CCFS queries HKID/path
func CollectionServerStart() {
	http.HandleFunc("/r/", webRepositoryHandler)
	http.HandleFunc("/d/", webDomainHandler)
}

func webRepositoryHandler(w http.ResponseWriter, r *http.Request) {
	parts := strings.SplitN(r.RequestURI[3:], "/", 2)
	hkidhex := parts[0]
	path := ""
	if len(parts) > 1 {
		path = parts[1]
	}
	err := error(nil)
	if len(hkidhex) == 64 {
		h, err := objects.HkidFromHex(hkidhex)
		if err == nil {
			b, err := services.Get(h, path)
			if err == nil {
				w.Write(b.Bytes())
				return
			}
			http.Error(w, fmt.Sprint(
				"HTTP Error 500 Internal server error\n\n", err), 500)
		}
	}
	w.Write([]byte(fmt.Sprintf("Invalid HKID\nerr: %v", err)))
	return
}
func webDomainHandler(w http.ResponseWriter, r *http.Request) {
	parts := strings.SplitN(r.RequestURI[3:], "/", 2)
	hkidhex := parts[0]
	path := ""
	if len(parts) > 1 {
		path = parts[1]
	}
	err := error(nil)
	if len(hkidhex) == 64 {
		h, err := objects.HkidFromHex(hkidhex)
		if err == nil {
			b, err := services.GetD(h, path)
			if err == nil {
				w.Write(b.Bytes())
				return
			}
			http.Error(w, fmt.Sprint(
				"HTTP Error 500 Internal server error\n\n", err), 500)
		}
	}
	w.Write([]byte(fmt.Sprintf("Invalid HKID\nerr: %v", err)))
	return
}

func composeQuery(typestring string, hash objects.HKID, namesegment string) (message string) {
	message = fmt.Sprintf("%s,%s", typestring, hash.String())
	if namesegment != "" {
		message = fmt.Sprintf("%s,%s", message, namesegment)
	}
	return message

}

func parseQuery(message string) (typestring string, hash objects.HKID, namesegment string) {
	arrMessage := strings.SplitN(message, ",", 3)
	if len(arrMessage) < 2 {
		panic("error: malformed parseQuery")
	}
	typestring = arrMessage[0]

	hash, err := objects.HkidFromHex(arrMessage[1])
	if err != nil {
		panic("error: malformed hexadecimal")
	}
	if len(arrMessage) > 2 {
		namesegment = arrMessage[2]
	} else {
		namesegment = ""
	}
	fmt.Println("Error")
	return typestring, hash, namesegment
}

//Start begins the listening for web reqwests on 8080
func Start() {
	go BlobServerStart()
	go CollectionServerStart()
}
<commit_msg>diplay the port the server is started on<commit_after>//Copyright 2014 Aaron Goldman. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file

//Package web implements a web interface
//It is started by calling web.Start
package web

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/AaronGoldman/ccfs/objects"
	"github.com/AaronGoldman/ccfs/services"
)

//BlobServerStart starts a server for the content services
func BlobServerStart() {
	http.Handle(
		"/b/",
		http.StripPrefix(
			"/b/",
			http.FileServer(http.Dir("bin/blobs")),
		),
	)
	http.Handle(
		"/t/",
		http.StripPrefix(
			"/t/",
			http.FileServer(http.Dir("bin/tags")),
		),
	)
	http.Handle(
		"/c/",
		http.StripPrefix("/c/",
			http.FileServer(http.Dir("bin/commits")),
		),
	)
	http.ListenAndServe(":8080", nil)
	fmt.Println("Listening on :8080")
}

//CollectionServerStart starts a server for full CCFS queries HKID/path
func CollectionServerStart() {
	http.HandleFunc("/r/", webRepositoryHandler)
	http.HandleFunc("/d/", webDomainHandler)
}

func webRepositoryHandler(w http.ResponseWriter, r *http.Request) {
	parts := strings.SplitN(r.RequestURI[3:], "/", 2)
	hkidhex := parts[0]
	path := ""
	if len(parts) > 1 {
		path = parts[1]
	}
	err := error(nil)
	if len(hkidhex) == 64 {
		h, err := objects.HkidFromHex(hkidhex)
		if err == nil {
			b, err := services.Get(h, path)
			if err == nil {
				w.Write(b.Bytes())
				return
			}
			http.Error(w, fmt.Sprint(
				"HTTP Error 500 Internal server error\n\n", err), 500)
		}
	}
	w.Write([]byte(fmt.Sprintf("Invalid HKID\nerr: %v", err)))
	return
}
func webDomainHandler(w http.ResponseWriter, r *http.Request) {
	parts := strings.SplitN(r.RequestURI[3:], "/", 2)
	hkidhex := parts[0]
	path := ""
	if len(parts) > 1 {
		path = parts[1]
	}
	err := error(nil)
	if len(hkidhex) == 64 {
		h, err := objects.HkidFromHex(hkidhex)
		if err == nil {
			b, err := services.GetD(h, path)
			if err == nil {
				w.Write(b.Bytes())
				return
			}
			http.Error(w, fmt.Sprint(
				"HTTP Error 500 Internal server error\n\n", err), 500)
		}
	}
	w.Write([]byte(fmt.Sprintf("Invalid HKID\nerr: %v", err)))
	return
}

func composeQuery(typestring string, hash objects.HKID, namesegment string) (message string) {
	message = fmt.Sprintf("%s,%s", typestring, hash.String())
	if namesegment != "" {
		message = fmt.Sprintf("%s,%s", message, namesegment)
	}
	return message

}

func parseQuery(message string) (typestring string, hash objects.HKID, namesegment string) {
	arrMessage := strings.SplitN(message, ",", 3)
	if len(arrMessage) < 2 {
		panic("error: malformed parseQuery")
	}
	typestring = arrMessage[0]

	hash, err := objects.HkidFromHex(arrMessage[1])
	if err != nil {
		panic("error: malformed hexadecimal")
	}
	if len(arrMessage) > 2 {
		namesegment = arrMessage[2]
	} else {
		namesegment = ""
	}
	fmt.Println("Error")
	return typestring, hash, namesegment
}

//Start begins the listening for web reqwests on 8080
func Start() {
	go BlobServerStart()
	go CollectionServerStart()
}
<|endoftext|>


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

package database

import (
	"context"
	"sort"
	"testing"
	"time"

	"github.com/google/exposure-notifications-server/internal/model"
	"github.com/google/go-cmp/cmp"
)

func TestAddExportConfig(t *testing.T) {
	if testDB == nil {
		t.Skip("no test DB")
	}
	defer resetTestDB(t)
	ctx := context.Background()

	fromTime := time.Now().UTC()
	thruTime := fromTime.Add(6 * time.Hour)
	want := &model.ExportConfig{
		FilenameRoot: "root",
		Period:       3 * time.Hour,
		Region:       "i1",
		From:         fromTime,
		Thru:         thruTime,
	}
	if err := testDB.AddExportConfig(ctx, want); err != nil {
		t.Fatal(err)
	}
	conn, err := testDB.pool.Acquire(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Release()
	var (
		got   model.ExportConfig
		psecs int
	)
	err = conn.QueryRow(ctx, `
		SELECT
			config_id, filename_root, period_seconds, region, from_timestamp, thru_timestamp
		FROM
			ExportConfig
		WHERE
			config_id = $1
	`, want.ConfigID).Scan(&got.ConfigID, &got.FilenameRoot, &psecs, &got.Region, &got.From, &got.Thru)
	if err != nil {
		t.Fatal(err)
	}
	got.Period = time.Duration(psecs) * time.Second

	want.From = want.From.Truncate(time.Microsecond)
	want.Thru = want.Thru.Truncate(time.Microsecond)
	if diff := cmp.Diff(want, &got); diff != "" {
		t.Errorf("mismatch (-want, +got):\n%s", diff)
	}
}

func TestIterateExportConfigs(t *testing.T) {
	if testDB == nil {
		t.Skip("no test DB")
	}
	defer resetTestDB(t)
	ctx := context.Background()

	now := time.Now().Truncate(time.Microsecond)
	ecs := []*model.ExportConfig{
		{
			FilenameRoot: "active 1",
			From:         now.Add(-time.Minute),
			Thru:         now.Add(time.Minute),
		},
		{
			FilenameRoot: "active 2",
			From:         now.Add(-time.Minute),
		},
		{
			FilenameRoot: "done",
			From:         now.Add(-time.Hour),
			Thru:         now.Add(-time.Minute),
		},
		{
			FilenameRoot: "not yet",
			From:         now.Add(time.Minute),
			Thru:         now.Add(time.Hour),
		},
	}
	for _, ec := range ecs {
		ec.Period = time.Hour
		ec.Region = "R"
		if err := testDB.AddExportConfig(ctx, ec); err != nil {
			t.Fatal(err)
		}
	}

	iter, err := testDB.IterateExportConfigs(ctx, now)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := iter.Close(); err != nil {
			t.Fatal(err)
		}
	}()

	var got []*model.ExportConfig
	for {
		ec, done, err := iter.Next()
		if err != nil {
			t.Fatal(err)
		}
		if done {
			break
		}
		got = append(got, ec)
	}
	want := ecs[0:2]
	sort.Slice(got, func(i, j int) bool { return got[i].FilenameRoot < got[j].FilenameRoot })
	if diff := cmp.Diff(want, got); diff != "" {
		t.Errorf("mismatch (-want, +got):\n%s", diff)
	}
}
<commit_msg>internal/database: add ExportBatch tests (#103)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package database

import (
	"context"
	"sort"
	"testing"
	"time"

	"github.com/google/exposure-notifications-server/internal/model"
	"github.com/google/go-cmp/cmp"
	pgx "github.com/jackc/pgx/v4"
)

func TestAddExportConfig(t *testing.T) {
	if testDB == nil {
		t.Skip("no test DB")
	}
	defer resetTestDB(t)
	ctx := context.Background()

	fromTime := time.Now().UTC()
	thruTime := fromTime.Add(6 * time.Hour)
	want := &model.ExportConfig{
		FilenameRoot: "root",
		Period:       3 * time.Hour,
		Region:       "i1",
		From:         fromTime,
		Thru:         thruTime,
	}
	if err := testDB.AddExportConfig(ctx, want); err != nil {
		t.Fatal(err)
	}
	conn, err := testDB.pool.Acquire(ctx)
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Release()
	var (
		got   model.ExportConfig
		psecs int
	)
	err = conn.QueryRow(ctx, `
		SELECT
			config_id, filename_root, period_seconds, region, from_timestamp, thru_timestamp
		FROM
			ExportConfig
		WHERE
			config_id = $1
	`, want.ConfigID).Scan(&got.ConfigID, &got.FilenameRoot, &psecs, &got.Region, &got.From, &got.Thru)
	if err != nil {
		t.Fatal(err)
	}
	got.Period = time.Duration(psecs) * time.Second

	want.From = want.From.Truncate(time.Microsecond)
	want.Thru = want.Thru.Truncate(time.Microsecond)
	if diff := cmp.Diff(want, &got); diff != "" {
		t.Errorf("mismatch (-want, +got):\n%s", diff)
	}
}

func TestIterateExportConfigs(t *testing.T) {
	if testDB == nil {
		t.Skip("no test DB")
	}
	defer resetTestDB(t)
	ctx := context.Background()

	now := time.Now().Truncate(time.Microsecond)
	ecs := []*model.ExportConfig{
		{
			FilenameRoot: "active 1",
			From:         now.Add(-time.Minute),
			Thru:         now.Add(time.Minute),
		},
		{
			FilenameRoot: "active 2",
			From:         now.Add(-time.Minute),
		},
		{
			FilenameRoot: "done",
			From:         now.Add(-time.Hour),
			Thru:         now.Add(-time.Minute),
		},
		{
			FilenameRoot: "not yet",
			From:         now.Add(time.Minute),
			Thru:         now.Add(time.Hour),
		},
	}
	for _, ec := range ecs {
		ec.Period = time.Hour
		ec.Region = "R"
		if err := testDB.AddExportConfig(ctx, ec); err != nil {
			t.Fatal(err)
		}
	}

	iter, err := testDB.IterateExportConfigs(ctx, now)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := iter.Close(); err != nil {
			t.Fatal(err)
		}
	}()

	var got []*model.ExportConfig
	for {
		ec, done, err := iter.Next()
		if err != nil {
			t.Fatal(err)
		}
		if done {
			break
		}
		got = append(got, ec)
	}
	want := ecs[0:2]
	sort.Slice(got, func(i, j int) bool { return got[i].FilenameRoot < got[j].FilenameRoot })
	if diff := cmp.Diff(want, got); diff != "" {
		t.Errorf("mismatch (-want, +got):\n%s", diff)
	}
}

func TestBatches(t *testing.T) {
	if testDB == nil {
		t.Skip("no test DB")
	}
	defer resetTestDB(t)
	ctx := context.Background()

	now := time.Now().Truncate(time.Microsecond)
	config := &model.ExportConfig{
		FilenameRoot: "root",
		Period:       time.Hour,
		Region:       "R",
		From:         now,
		Thru:         now.Add(time.Hour),
	}
	if err := testDB.AddExportConfig(ctx, config); err != nil {
		t.Fatal(err)
	}
	var batches []*model.ExportBatch
	var wantLatest time.Time
	for i := 0; i < 4; i++ {
		start := now.Add(time.Duration(i) * time.Minute)
		end := start.Add(time.Minute)
		wantLatest = end
		batches = append(batches, &model.ExportBatch{
			ConfigID:       config.ConfigID,
			FilenameRoot:   config.FilenameRoot,
			Region:         config.Region,
			Status:         model.ExportBatchOpen,
			StartTimestamp: start,
			EndTimestamp:   end,
		})
	}
	if err := testDB.AddExportBatches(ctx, batches); err != nil {
		t.Fatal(err)
	}

	gotLatest, err := testDB.LatestExportBatchEnd(ctx, config)
	if err != nil {
		t.Fatal(err)
	}
	if !gotLatest.Equal(wantLatest) {
		t.Errorf("LatestExportBatchEnd: got %s, want %s", gotLatest, wantLatest)
	}

	leaseBatches := func() int64 {
		t.Helper()
		var batchID int64
		// Lease all the batches.
		for range batches {
			got, err := testDB.LeaseBatch(ctx, time.Hour, now)
			if err != nil {
				t.Fatal(err)
			}
			if got == nil {
				t.Fatal("could not lease a batch")
			}
			if got.ConfigID != config.ConfigID || got.FilenameRoot != config.FilenameRoot || got.Region != config.Region {
				t.Errorf("LeaseBatch: got (%d, %q, %q), want (%d, %q, %q)",
					got.ConfigID, got.FilenameRoot, got.Region,
					config.ConfigID, config.FilenameRoot, config.Region)
			}
			if got.Status != model.ExportBatchPending {
				t.Errorf("LeaseBatch: got status %q, want pending", got.Status)
			}
			wantExpires := now.Add(time.Hour)
			if got.LeaseExpires.Before(wantExpires) || got.LeaseExpires.After(wantExpires.Add(time.Minute)) {
				t.Errorf("LeaseBatch: expires at %s, wanted a time close to %s", got.LeaseExpires, wantExpires)
			}
			batchID = got.BatchID
		}
		// Every batch is leased.
		got, err := testDB.LeaseBatch(ctx, time.Hour, now)
		if got != nil || err != nil {
			t.Errorf("all leased: got (%v, %v), want (nil, nil)", got, err)
		}
		return batchID
	}
	// Now, all end times are in the future, so no batches can be leased.
	got, err := testDB.LeaseBatch(ctx, time.Hour, now)
	if got != nil || err != nil {
		t.Errorf("got (%v, %v), want (nil, nil)", got, err)
	}

	// One hour later, all batches' end times are in the past, so they can be leased.
	now = now.Add(time.Hour)
	leaseBatches()
	// Two hours later all the batches have expired, so we can lease them again.
	now = now.Add(2 * time.Hour)
	batchID := leaseBatches()

	// Complete a batch.
	err = testDB.inTx(ctx, pgx.Serializable, func(tx pgx.Tx) error { return completeBatch(ctx, tx, batchID) })
	if err != nil {
		t.Fatal(err)
	}
	got, err = testDB.LookupExportBatch(ctx, batchID)
	if err != nil {
		t.Fatal(err)
	}
	if got.Status != model.ExportBatchComplete {
		t.Errorf("after completion: got status %q, want complete", got.Status)
	}
}
<|endoftext|>


<commit_before>package mackerel

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

// User information
type User struct {
	ID         string `json:"id,omitempty"`
	ScreenName string `json:"screenName,omitempty"`
	Email      string `json:"email,omitempty"`
	Authority  string `json:"authority,omitempty"`

	IsInRegistrationProcess bool     `json:"isInRegistrationProcess,omitempty"`
	IsMFAEnabled            bool     `json:"isMFAEnabled,omitempty"`
	AuthenticationMethods   []string `json:"authenticationMethods,omitempty"`
	JoinedAt                int64    `json:"joinedAt,omitempty"`
}

// FindUsers find users.
func (c *Client) FindUsers() ([]*User, error) {
	req, err := http.NewRequest("GET", c.urlFor(fmt.Sprintf("/api/v0/users")).String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Users []*User `json:"users"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return data.Users, err
}

// DeleteUser delete users.
func (c *Client) DeleteUser(userID string) (*User, error) {
	req, err := http.NewRequest("DELETE", c.urlFor(fmt.Sprintf("/api/v0/users/%s", userID)).String(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	user := &User{}
	err = json.NewDecoder(resp.Body).Decode(user)
	if err != nil {
		return nil, err
	}
	return user, nil
}
<commit_msg>delete unnecessary string conversion<commit_after>package mackerel

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

// User information
type User struct {
	ID         string `json:"id,omitempty"`
	ScreenName string `json:"screenName,omitempty"`
	Email      string `json:"email,omitempty"`
	Authority  string `json:"authority,omitempty"`

	IsInRegistrationProcess bool     `json:"isInRegistrationProcess,omitempty"`
	IsMFAEnabled            bool     `json:"isMFAEnabled,omitempty"`
	AuthenticationMethods   []string `json:"authenticationMethods,omitempty"`
	JoinedAt                int64    `json:"joinedAt,omitempty"`
}

// FindUsers find users.
func (c *Client) FindUsers() ([]*User, error) {
	req, err := http.NewRequest("GET", c.urlFor("/api/v0/users").String(), nil)
	if err != nil {
		return nil, err
	}
	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	var data struct {
		Users []*User `json:"users"`
	}
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return data.Users, err
}

// DeleteUser delete users.
func (c *Client) DeleteUser(userID string) (*User, error) {
	req, err := http.NewRequest("DELETE", c.urlFor(fmt.Sprintf("/api/v0/users/%s", userID)).String(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := c.Request(req)
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}

	user := &User{}
	err = json.NewDecoder(resp.Body).Decode(user)
	if err != nil {
		return nil, err
	}
	return user, nil
}
<|endoftext|>


<commit_before>package somaproto

import (
	"github.com/satori/go.uuid"
)

type ProtoRequestUser struct {
	User        ProtoUser            `json:"user,omitempty"`
	Credentials ProtoUserCredentials `json:"credentials,omitempty"`
	Restore     bool                 `json:"purge,omitempty"`
	Purge       bool                 `json:"purge,omitempty"`
}

type ProtoResultUser struct {
	Code   uint16      `json:"code,omitempty"`
	Status string      `json:"status,omitempty"`
	Text   []string    `json:"text,omitempty"`
	Users  []ProtoUser `json:"users,omitempty"`
}

type ProtoUser struct {
	Id             uuid.UUID        `json:"id,omitempty"`
	UserName       string           `json:"username,omitempty"`
	FirstName      string           `json:"firstname,omitempty"`
	LastName       string           `json:"lastname,omitempty"`
	EmployeeNumber string           `json:"employeenumber,omitempty"`
	MailAddress    string           `json:"mailaddress,omitempty"`
	IsActive       bool             `json:"active,omitempty"`
	IsSystem       bool             `json:"system,omitempty"`
	Team           string           `json:"team,omitempty"`
	Details        ProtoUserDetails `json:"details,omitempty"`
}

type ProtoUserCredentials struct {
	Reset    bool `json:"reset,omitempty"`
	Password bool `json:"password,omitempty"`
}

type ProtoUserDetails struct {
	CreatedAt string `json:"createdat,omitempty"`
	CreatedBy string `json:"createdby,omitempty"`
}

type ProtoUserFilter struct {
	UserName  string `json:"username,omitempty"`
	IsActive  bool   `json:"active,omitempty"`
	IsSystem  bool   `json:"system,omitempty"`
	IsDeleted bool   `json:"deleted,omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Add IsDeleted to ProtoUser struct, fix Restore<commit_after>package somaproto

import (
	"github.com/satori/go.uuid"
)

type ProtoRequestUser struct {
	User        ProtoUser            `json:"user,omitempty"`
	Credentials ProtoUserCredentials `json:"credentials,omitempty"`
	Restore     bool                 `json:"restore,omitempty"`
	Purge       bool                 `json:"purge,omitempty"`
}

type ProtoResultUser struct {
	Code   uint16      `json:"code,omitempty"`
	Status string      `json:"status,omitempty"`
	Text   []string    `json:"text,omitempty"`
	Users  []ProtoUser `json:"users,omitempty"`
}

type ProtoUser struct {
	Id             uuid.UUID        `json:"id,omitempty"`
	UserName       string           `json:"username,omitempty"`
	FirstName      string           `json:"firstname,omitempty"`
	LastName       string           `json:"lastname,omitempty"`
	EmployeeNumber string           `json:"employeenumber,omitempty"`
	MailAddress    string           `json:"mailaddress,omitempty"`
	IsActive       bool             `json:"active,omitempty"`
	IsSystem       bool             `json:"system,omitempty"`
	IsDeleted      bool             `json:"deleted,omitempty"`
	Team           string           `json:"team,omitempty"`
	Details        ProtoUserDetails `json:"details,omitempty"`
}

type ProtoUserCredentials struct {
	Reset    bool `json:"reset,omitempty"`
	Password bool `json:"password,omitempty"`
}

type ProtoUserDetails struct {
	CreatedAt string `json:"createdat,omitempty"`
	CreatedBy string `json:"createdby,omitempty"`
}

type ProtoUserFilter struct {
	UserName  string `json:"username,omitempty"`
	IsActive  bool   `json:"active,omitempty"`
	IsSystem  bool   `json:"system,omitempty"`
	IsDeleted bool   `json:"deleted,omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package builtins

type ArrayClass struct {
	valueStub
}

func NewArrayClass() Value {
	a := &ArrayClass{}
	a.class = NewClassValue().(Class)
	a.initialize()
	return a
}

func (klass *ArrayClass) New() Value {
	a := &Array{}
	a.initialize()
	a.class = klass

	a.AddMethod(NewMethod("shift", func(args ...Value) (Value, error) {
		if len(a.members) == 0 {
			return Nil(), nil
		}

		val := a.members[0]
		a.members = a.members[1:]
		return val, nil
	}))
	a.AddMethod(NewMethod("include?", func(args ...Value) (Value, error) {
		for _, m := range a.members {
			if m == args[0] {
				return NewTrueClass().(Class).New(), nil
			}
		}

		return NewFalseClass().(Class).New(), nil
	}))

	return a
}

func (array *ArrayClass) String() string {
	return "Array"
}

type Array struct {
	valueStub
	members []Value
}

func (array *Array) Append(v Value) {
	array.members = append(array.members, v)
}

func (array *Array) Members() []Value {
	return array.members
}

func (array *Array) String() string {
	return "Array"
}
<commit_msg>Implement Array#unshift for rubyspec<commit_after>package builtins

type ArrayClass struct {
	valueStub
}

func NewArrayClass() Value {
	a := &ArrayClass{}
	a.class = NewClassValue().(Class)
	a.initialize()
	return a
}

func (klass *ArrayClass) New() Value {
	a := &Array{}
	a.initialize()
	a.class = klass

	a.AddMethod(NewMethod("shift", func(args ...Value) (Value, error) {
		if len(a.members) == 0 {
			return Nil(), nil
		}

		val := a.members[0]
		a.members = a.members[1:]
		return val, nil
	}))

	a.AddMethod(NewMethod("unshift", func(args ...Value) (Value, error) {
		a.members = append([]Value{args[0]}, a.members[0:]...)
		return a, nil
	}))

	a.AddMethod(NewMethod("include?", func(args ...Value) (Value, error) {
		for _, m := range a.members {
			if m == args[0] {
				return NewTrueClass().(Class).New(), nil
			}
		}

		return NewFalseClass().(Class).New(), nil
	}))

	return a
}

func (array *ArrayClass) String() string {
	return "Array"
}

type Array struct {
	valueStub
	members []Value
}

func (array *Array) Append(v Value) {
	array.members = append(array.members, v)
}

func (array *Array) Members() []Value {
	return array.members
}

func (array *Array) String() string {
	return "Array"
}
<|endoftext|>


<commit_before>package borm

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

	"github.com/boltdb/bolt"
)

func createBucket(tx *bolt.Tx, buckets []string) (b *bolt.Bucket, err error) {
	b, err = tx.CreateBucketIfNotExists([]byte(buckets[0]))
	if err != nil {
		return
	}
	if len(buckets) > 1 {
		for _, v := range buckets[1:] {
			b, err = b.CreateBucketIfNotExists([]byte(v))
			if err != nil {
				return
			}
		}
	}
	return
}

func getBucket(tx *bolt.Tx, buckets []string) (b *bolt.Bucket) {
	b = tx.Bucket([]byte(buckets[0]))
	if b != nil {
		if len(buckets) > 1 {
			for _, v := range buckets[1:] {
				if b == nil {
					return nil
				}
				b = b.Bucket([]byte(v))
			}
		}
	}
	return
}

func unmarshal(data []byte, i interface{}) error {
	err := json.Unmarshal(data, i)
	if err != nil {
		return err
	}
	return nil
}

func marshal(i interface{}) ([]byte, error) {
	enc, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}
	return enc, nil
}

func nextID(b *bolt.Bucket) string {
	id, _ := b.NextSequence()
	return fmt.Sprint(id)
}

// deref is Indirect for reflect.Types
func deref(t reflect.Type) reflect.Type {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
	t = deref(t)
	if t.Kind() != expected {
		return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind())
	}
	return t, nil
}

func checkID(b *bolt.Bucket, m mod) (id string, newItem bool) {
	id = m.GetID()
	if id == "" {
		newItem = true
		id = nextID(b)
		m.setID(id)
		if m1, ok := m.(modCreate); ok {
			m1.setCreation()
		}
		if m1, ok := m.(modUpdate); ok {
			m1.touchModel()
		}
	} else {
		if m1, ok := m.(modUpdate); ok {
			m1.touchModel()
		}
	}
	return
}

func typeName(i interface{}) string {
	return reflect.TypeOf(i).Elem().Name()
}

var addEvent = func(name string, m mod) {
	go Events.Pub(eventName(name, m), m)
}

func eventName(name string, m mod) string {
	return typeName(m) + name
}
<commit_msg>adding cursor methods<commit_after>package borm

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

	"github.com/boltdb/bolt"
)

func createBucket(tx *bolt.Tx, buckets []string) (b *bolt.Bucket, err error) {
	b, err = tx.CreateBucketIfNotExists([]byte(buckets[0]))
	if err != nil {
		return
	}
	if len(buckets) > 1 {
		for _, v := range buckets[1:] {
			b, err = b.CreateBucketIfNotExists([]byte(v))
			if err != nil {
				return
			}
		}
	}
	return
}

func getBucket(tx *bolt.Tx, buckets []string) (b *bolt.Bucket) {
	b = tx.Bucket([]byte(buckets[0]))
	if b != nil {
		if len(buckets) > 1 {
			for _, v := range buckets[1:] {
				if b == nil {
					return nil
				}
				b = b.Bucket([]byte(v))
			}
		}
	}
	return
}

func unmarshal(data []byte, i interface{}) error {
	err := json.Unmarshal(data, i)
	if err != nil {
		return err
	}
	return nil
}

func marshal(i interface{}) ([]byte, error) {
	enc, err := json.Marshal(i)
	if err != nil {
		return nil, err
	}
	return enc, nil
}

func nextID(b *bolt.Bucket) string {
	id, _ := b.NextSequence()
	return fmt.Sprint(id)
}

// deref is Indirect for reflect.Types
func deref(t reflect.Type) reflect.Type {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
	t = deref(t)
	if t.Kind() != expected {
		return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind())
	}
	return t, nil
}

func checkID(b *bolt.Bucket, m mod) (id string, newItem bool) {
	id = m.GetID()
	if id == "" {
		newItem = true
		id = nextID(b)
		m.setID(id)
		if m1, ok := m.(modCreate); ok {
			m1.setCreation()
		}
		if m1, ok := m.(modUpdate); ok {
			m1.touchModel()
		}
	} else {
		if m1, ok := m.(modUpdate); ok {
			m1.touchModel()
		}
	}
	return
}

func typeName(i interface{}) string {
	return reflect.TypeOf(i).Elem().Name()
}

var addEvent = func(name string, m mod) {
	go Events.Pub(eventName(name, m), m)
}

func eventName(name string, m mod) string {
	return typeName(m) + name
}

func cursorStart(c *bolt.Cursor, rev bool) (k []byte, v []byte) {
	if rev {
		return c.Last()
	}
	return c.First()
}

func cursorNext(c *bolt.Cursor, rev bool) (k []byte, v []byte) {
	if rev {
		return c.Prev()
	}
	return c.Next()
}
<|endoftext|>


<commit_before>/*
matrixutils provides utilities for working with dsputils and fft packages found at
github.com/mjibson/go-dsp/dsputils and github.com/mjibson/go-dsp/fft, respectively.
*/
package matrixutils

import (
	"fmt"
	"math"

	"github.com/mjibson/go-dsp/dsputils"
)

func positiveMod(n, k int) int {
	if n < 0 {
		return k - ((-1 * n) % k)
	}

	return n % k
}

// Using degrees, not radians
func PolarToCartesian(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()
	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Clarify size of each dimension
	lenX, lenY, _ := func() (int, int, int) {
		// Reminder: matrices are matrix[y][x]
		return dims[1], dims[0], int(math.Hypot(float64(dims[0]), float64(dims[1])))
	}()

	cartesianMatrix := dsputils.MakeEmptyMatrix([]int{lenY, lenX})

	// Reminder: matrices are matrix[y][x]
	for cartesianY := 0; cartesianY < lenY; cartesianY++ {
		for cartesianX := 0; cartesianX < lenX; cartesianX++ {

			polarX := int(float64(cartesianX) * math.Cos(float64(cartesianY)*0.5*math.Pi/float64(lenY)))
			polarY := int(float64(cartesianX) * math.Sin(float64(cartesianY)*0.5*math.Pi/float64(lenY)))

			value := matrix.Value([]int{positiveMod(polarY, lenY), positiveMod(polarX, lenX)})

			cartesianMatrix.SetValue(value, []int{cartesianY, cartesianX})
		}
	}

	return cartesianMatrix, nil
}

// Using degrees, not radians
func CartesianToPolar(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()
	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Clarify size of each dimension
	lenX, lenY, _ := func() (int, int, int) {
		// Reminder: matrices are matrix[y][x]
		return dims[1], dims[0], int(math.Hypot(float64(dims[0]), float64(dims[1])))
	}()

	polarMatrix := dsputils.MakeEmptyMatrix([]int{lenY, lenX})

	// Reminder: matrices are matrix[y][x]
	for polarY := 0; polarY < lenY; polarY++ {
		for polarX := 0; polarX < lenX; polarX++ {

			cartesianX := int(math.Hypot(float64(polarX), float64(polarY)))
			cartesianY := int(math.Atan2(float64(polarY), float64(polarX)) * 2.0 / math.Pi * float64(lenY))

			value := matrix.Value([]int{positiveMod(cartesianY, lenY), positiveMod(cartesianX, lenX)})

			polarMatrix.SetValue(value, []int{polarY, polarX})
		}
	}

	return polarMatrix, nil
}

func Translate(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()

	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Convert matrix to polar coordinates
	translatedMatrix := dsputils.MakeEmptyMatrix([]int{dims[0], dims[1]})

	for i := 0; i < dims[0]; i++ {
		for j := 0; j < dims[1]; j++ {
			oldX := (dims[0] + i + dims[0]/2) % dims[0]
			oldY := (dims[1] + j - dims[1]/2) % dims[1]

			translatedMatrix.SetValue(matrix.Value([]int{oldX, oldY}), []int{i, j})
		}
	}

	return translatedMatrix, nil
}
<commit_msg>Raster to cartesian<commit_after>/*
matrixutils provides utilities for working with dsputils and fft packages found at
github.com/mjibson/go-dsp/dsputils and github.com/mjibson/go-dsp/fft, respectively.
*/
package matrixutils

import (
	"fmt"
	"math"

	"github.com/mjibson/go-dsp/dsputils"
)

func positiveMod(n, k int) int {
	if n < 0 {
		return k - ((-1 * n) % k)
	}

	return n % k
}

func RasterToCartesian(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()
	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Clarify size of each dimension
	lenX, lenY, _ := func() (int, int, int) {
		// Reminder: matrices are matrix[y][x]
		return dims[1], dims[0], int(math.Hypot(float64(dims[0]), float64(dims[1])))
	}()

	cartesianMatrix := dsputils.MakeEmptyMatrix([]int{lenY, lenX})

	// Reminder: matrices are matrix[y][x]
	for y := 0; y < lenY; y++ {
		for x := 0; x < lenX; x++ {

			cartesianX := x - lenX/2
			cartesianY := lenY/2 - y

			value := matrix.Value([]int{positiveMod(cartesianY, lenY), positiveMod(cartesianX, lenX)})

			cartesianMatrix.SetValue(value, []int{y, x})
		}
	}

	return cartesianMatrix, nil
}

// Using degrees, not radians
func PolarToCartesian(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()
	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Clarify size of each dimension
	lenX, lenY, _ := func() (int, int, int) {
		// Reminder: matrices are matrix[y][x]
		return dims[1], dims[0], int(math.Hypot(float64(dims[0]), float64(dims[1])))
	}()

	cartesianMatrix := dsputils.MakeEmptyMatrix([]int{lenY, lenX})

	// Reminder: matrices are matrix[y][x]
	for cartesianY := 0; cartesianY < lenY; cartesianY++ {
		for cartesianX := 0; cartesianX < lenX; cartesianX++ {

			polarX := int(float64(cartesianX) * math.Cos(float64(cartesianY)*0.5*math.Pi/float64(lenY)))
			polarY := int(float64(cartesianX) * math.Sin(float64(cartesianY)*0.5*math.Pi/float64(lenY)))

			value := matrix.Value([]int{positiveMod(polarY, lenY), positiveMod(polarX, lenX)})

			cartesianMatrix.SetValue(value, []int{cartesianY, cartesianX})
		}
	}

	return cartesianMatrix, nil
}

// Using degrees, not radians
func CartesianToPolar(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()
	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Clarify size of each dimension
	lenX, lenY, _ := func() (int, int, int) {
		// Reminder: matrices are matrix[y][x]
		return dims[1], dims[0], int(math.Hypot(float64(dims[0]), float64(dims[1])))
	}()

	polarMatrix := dsputils.MakeEmptyMatrix([]int{lenY, lenX})

	// Reminder: matrices are matrix[y][x]
	for polarY := 0; polarY < lenY; polarY++ {
		for polarX := 0; polarX < lenX; polarX++ {

			cartesianX := int(math.Hypot(float64(polarX), float64(polarY)))
			cartesianY := int(math.Atan2(float64(polarY), float64(polarX)) * 2.0 / math.Pi * float64(lenY))

			value := matrix.Value([]int{positiveMod(cartesianY, lenY), positiveMod(cartesianX, lenX)})

			polarMatrix.SetValue(value, []int{polarY, polarX})
		}
	}

	return polarMatrix, nil
}

func Translate(matrix *dsputils.Matrix) (*dsputils.Matrix, error) {
	dims := matrix.Dimensions()

	if len(dims) > 2 {
		return nil, fmt.Errorf("CartesianToPolar expects 2 dimensions, found %d", len(dims))
	}

	// Convert matrix to polar coordinates
	translatedMatrix := dsputils.MakeEmptyMatrix([]int{dims[0], dims[1]})

	for i := 0; i < dims[0]; i++ {
		for j := 0; j < dims[1]; j++ {
			oldX := (dims[0] + i + dims[0]/2) % dims[0]
			oldY := (dims[1] + j - dims[1]/2) % dims[1]

			translatedMatrix.SetValue(matrix.Value([]int{oldX, oldY}), []int{i, j})
		}
	}

	return translatedMatrix, nil
}
<|endoftext|>