<commit_before>package beater

import (
	"sync"
	"time"

	"github.com/e-travel/cloudwatchlogsbeat/config"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
	"github.com/elastic/beats/libbeat/logp"
)

type Group struct {
	Name       string
	Prospector *config.Prospector
	Client     cloudwatchlogsiface.CloudWatchLogsAPI
	Beat       *Cloudwatchlogsbeat
	Streams    map[string]*Stream
	// we'll use this mutex to synchronize access to the Streams map
	mutex *sync.RWMutex
}

func NewGroup(name string, prospector *config.Prospector, beat *Cloudwatchlogsbeat) *Group {
	return &Group{
		Name:       name,
		Prospector: prospector,
		Client:     beat.AWSClient,
		Beat:       beat,
		Streams:    make(map[string]*Stream),
		mutex:      &sync.RWMutex{},
	}
}

func (group *Group) RefreshStreams() {
	params := &cloudwatchlogs.DescribeLogStreamsInput{
		LogGroupName: aws.String(group.Name),
		Descending:   aws.Bool(true),
		OrderBy:      aws.String("LastEventTime"),
	}

	timeHorizon := time.Now().UTC().Add(-group.Prospector.StreamLastEventHorizon)

	isStreamExpired := func(lastEventTimestamp *int64) bool {
		return ToTime(*lastEventTimestamp).Before(timeHorizon)
	}

	err := group.Client.DescribeLogStreamsPages(
		params,
		func(page *cloudwatchlogs.DescribeLogStreamsOutput, lastPage bool) bool {
			for _, logStream := range page.LogStreams {
				name := aws.StringValue(logStream.LogStreamName)
				// is the stream too old?
				expired := isStreamExpired(logStream.LastEventTimestamp)
				// are we monitoring the stream already?
				group.mutex.RLock()
				stream, ok := group.Streams[name]
				group.mutex.RUnlock()
				// is this a stream that we're monitoring and it has expired?
				if ok && expired {
					stream.expired <- true
				}
				// is this a stream that we're not monitoring and it is not expired?
				if !ok && !expired {
					group.addNewStream(name)
				}
			}
			return true
		})
	if err != nil {
		logp.Err("Failed to fetch streams for group %s", group.Name)
	}
}

func (group *Group) removeStream(stream *Stream) {
	logp.Info("Stop monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	delete(group.Streams, stream.Name)
	group.mutex.Unlock()
}

func (group *Group) addNewStream(name string) {
	finished := make(chan bool)
	expired := make(chan bool)
	stream := NewStream(name, group, group.Client, group.Beat.Registry, finished, expired)
	logp.Info("Start monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	group.Streams[name] = stream
	group.mutex.Unlock()
	go stream.Monitor()
	go func() {
		<-finished
		group.removeStream(stream)
	}()
}

func (group *Group) Monitor() {
	logp.Info("Monitoring group %s", group.Name)
	for {
		group.RefreshStreams()
		time.Sleep(group.Beat.Config.StreamRefreshPeriod)
	}
}
<commit_msg>Attempts to save panic due to nil stream timestamp<commit_after>package beater

import (
	"sync"
	"time"

	"github.com/e-travel/cloudwatchlogsbeat/config"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
	"github.com/elastic/beats/libbeat/logp"
)

type Group struct {
	Name       string
	Prospector *config.Prospector
	Client     cloudwatchlogsiface.CloudWatchLogsAPI
	Beat       *Cloudwatchlogsbeat
	Streams    map[string]*Stream
	// we'll use this mutex to synchronize access to the Streams map
	mutex *sync.RWMutex
}

func NewGroup(name string, prospector *config.Prospector, beat *Cloudwatchlogsbeat) *Group {
	return &Group{
		Name:       name,
		Prospector: prospector,
		Client:     beat.AWSClient,
		Beat:       beat,
		Streams:    make(map[string]*Stream),
		mutex:      &sync.RWMutex{},
	}
}

func (group *Group) RefreshStreams() {
	params := &cloudwatchlogs.DescribeLogStreamsInput{
		LogGroupName: aws.String(group.Name),
		Descending:   aws.Bool(true),
		OrderBy:      aws.String("LastEventTime"),
	}

	timeHorizon := time.Now().UTC().Add(-group.Prospector.StreamLastEventHorizon)

	isStreamExpired := func(lastEventTimestamp *int64) bool {
		return ToTime(*lastEventTimestamp).Before(timeHorizon)
	}

	err := group.Client.DescribeLogStreamsPages(
		params,
		func(page *cloudwatchlogs.DescribeLogStreamsOutput, lastPage bool) bool {
			for _, logStream := range page.LogStreams {
				name := aws.StringValue(logStream.LogStreamName)
				if logStream.LastEventTimestamp == nil {
					logp.Critical("We have a nil stream timestamp (%s)", name)
					continue
				}
				// is the stream too old?
				expired := isStreamExpired(logStream.LastEventTimestamp)
				// are we monitoring the stream already?
				group.mutex.RLock()
				stream, ok := group.Streams[name]
				group.mutex.RUnlock()
				// is this a stream that we're monitoring and it has expired?
				if ok && expired {
					stream.expired <- true
				}
				// is this a stream that we're not monitoring and it is not expired?
				if !ok && !expired {
					group.addNewStream(name)
				}
			}
			return true
		})
	if err != nil {
		logp.Err("Failed to fetch streams for group %s", group.Name)
	}
}

func (group *Group) removeStream(stream *Stream) {
	logp.Info("Stop monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	delete(group.Streams, stream.Name)
	group.mutex.Unlock()
}

func (group *Group) addNewStream(name string) {
	finished := make(chan bool)
	expired := make(chan bool)
	stream := NewStream(name, group, group.Client, group.Beat.Registry, finished, expired)
	logp.Info("Start monitoring stream %s for group %s", stream.Name, group.Name)
	group.mutex.Lock()
	group.Streams[name] = stream
	group.mutex.Unlock()
	go stream.Monitor()
	go func() {
		<-finished
		group.removeStream(stream)
	}()
}

func (group *Group) Monitor() {
	logp.Info("Monitoring group %s", group.Name)
	for {
		group.RefreshStreams()
		time.Sleep(group.Beat.Config.StreamRefreshPeriod)
	}
}
<|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 env

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path"

	"github.com/srinandan/apigeecli/apiclient"
)

//Get
func Get(config bool) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	if config {
		u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv(), "deployedConfig")
	} else {
		u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	}
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//List
func List() (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//GetDeployments
func GetDeployments() (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv(), "deployments")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//SetEnvProperty is used to set env properties
func SetEnvProperty(name string, value string) (err error) {
	//EnvProperty contains an individual org flag or property
	type envProperty struct {
		Name  string `json:"name,omitempty"`
		Value string `json:"value,omitempty"`
	}
	//EnvProperties stores all the org feature flags and properties
	type envProperties struct {
		Property []envProperty `json:"property,omitempty"`
	}

	//Env structure
	type environment struct {
		Name           string        `json:"name,omitempty"`
		Description    string        `json:"description,omitempty"`
		CreatedAt      string        `json:"-,omitempty"`
		LastModifiedAt string        `json:"-,omitempty"`
		Properties     envProperties `json:"properties,omitempty"`
	}

	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	//get env details
	envBody, err := apiclient.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	env := environment{}
	err = json.Unmarshal(envBody, &env)
	if err != nil {
		return err
	}

	//check if the property exists
	found := false
	for i, properties := range env.Properties.Property {
		if properties.Name == name {
			fmt.Println("Property found, enabling property")
			env.Properties.Property[i].Value = value
			found = true
			break
		}
	}

	if !found {
		//set the property
		newProp := envProperty{}
		newProp.Name = name
		newProp.Value = value

		env.Properties.Property = append(env.Properties.Property, newProp)
	}

	newEnvBody, err := json.Marshal(env)
	if err != nil {
		return err
	}

	u, _ = url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	_, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), string(newEnvBody), "PUT")

	return err
}

//ClearEnvProperties is used to set env properties
func ClearEnvProperties() (err error) {
	//EnvProperty contains an individual org flag or property
	type envProperty struct {
		Name  string `json:"name,omitempty"`
		Value string `json:"value,omitempty"`
	}
	//EnvProperties stores all the org feature flags and properties
	type envProperties struct {
		Property []envProperty `json:"property,omitempty"`
	}

	//Env structure
	type environment struct {
		Name           string        `json:"name,omitempty"`
		Description    string        `json:"description,omitempty"`
		CreatedAt      string        `json:"-,omitempty"`
		LastModifiedAt string        `json:"-,omitempty"`
		Properties     envProperties `json:"-,omitempty"`
	}

	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	//get env details
	envBody, err := apiclient.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	env := environment{}
	err = json.Unmarshal(envBody, &env)
	if err != nil {
		return err
	}

	newEnv := environment{}
	newEnv.Name = env.Name
	newEnv.Description = env.Description
	newEnvBody, err := json.Marshal(newEnv)
	if err != nil {
		return err
	}

	u, _ = url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	_, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), string(newEnvBody), "PUT")

	return err
}
<commit_msg>crt and del envs<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 env

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path"
	"strings"

	"github.com/srinandan/apigeecli/apiclient"
)

//Create
func Create(name string) (respBody []byte, err error) {
	environment := []string{}
	environment = append(environment, "\"name\":\""+name+"\"")

	payload := "{" + strings.Join(environment, ",") + "}"

	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), payload)
	return respBody, err
}

//Delete
func Delete(name string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", name)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), "", "DELETE")
	return respBody, err
}

//Get
func Get(config bool) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	if config {
		u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv(), "deployedConfig")
	} else {
		u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	}
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//List
func List() (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//GetDeployments
func GetDeployments() (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv(), "deployments")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//SetEnvProperty is used to set env properties
func SetEnvProperty(name string, value string) (err error) {
	//EnvProperty contains an individual org flag or property
	type envProperty struct {
		Name  string `json:"name,omitempty"`
		Value string `json:"value,omitempty"`
	}
	//EnvProperties stores all the org feature flags and properties
	type envProperties struct {
		Property []envProperty `json:"property,omitempty"`
	}

	//Env structure
	type environment struct {
		Name           string        `json:"name,omitempty"`
		Description    string        `json:"description,omitempty"`
		CreatedAt      string        `json:"-,omitempty"`
		LastModifiedAt string        `json:"-,omitempty"`
		Properties     envProperties `json:"properties,omitempty"`
	}

	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	//get env details
	envBody, err := apiclient.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	env := environment{}
	err = json.Unmarshal(envBody, &env)
	if err != nil {
		return err
	}

	//check if the property exists
	found := false
	for i, properties := range env.Properties.Property {
		if properties.Name == name {
			fmt.Println("Property found, enabling property")
			env.Properties.Property[i].Value = value
			found = true
			break
		}
	}

	if !found {
		//set the property
		newProp := envProperty{}
		newProp.Name = name
		newProp.Value = value

		env.Properties.Property = append(env.Properties.Property, newProp)
	}

	newEnvBody, err := json.Marshal(env)
	if err != nil {
		return err
	}

	u, _ = url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	_, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), string(newEnvBody), "PUT")

	return err
}

//ClearEnvProperties is used to set env properties
func ClearEnvProperties() (err error) {
	//EnvProperty contains an individual org flag or property
	type envProperty struct {
		Name  string `json:"name,omitempty"`
		Value string `json:"value,omitempty"`
	}
	//EnvProperties stores all the org feature flags and properties
	type envProperties struct {
		Property []envProperty `json:"property,omitempty"`
	}

	//Env structure
	type environment struct {
		Name           string        `json:"name,omitempty"`
		Description    string        `json:"description,omitempty"`
		CreatedAt      string        `json:"-,omitempty"`
		LastModifiedAt string        `json:"-,omitempty"`
		Properties     envProperties `json:"-,omitempty"`
	}

	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	//get env details
	envBody, err := apiclient.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	env := environment{}
	err = json.Unmarshal(envBody, &env)
	if err != nil {
		return err
	}

	newEnv := environment{}
	newEnv.Name = env.Name
	newEnv.Description = env.Description
	newEnvBody, err := json.Marshal(newEnv)
	if err != nil {
		return err
	}

	u, _ = url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "environments", apiclient.GetApigeeEnv())
	_, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), string(newEnvBody), "PUT")

	return err
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/base32"
	"sync"
	"time"
)

var (
	DefaultAuth = NewAuth()
)

func genAccount(id string) *Account {
	// return a pseudo account
	return &Account{
		Id:       id,
		Token:    base32.StdEncoding.EncodeToString([]byte(id)),
		Created:  time.Now(),
		Expiry:   time.Now().Add(time.Hour * 24),
		Metadata: make(map[string]string),
	}
}

// NewAuth returns a new default registry which is memory
func NewAuth(opts ...Option) Auth {
	var options Options
	for _, o := range opts {
		o(&options)
	}

	return &memory{
		accounts: make(map[string]*Account),
		opts:     options,
	}
}

// TODO: replace with https://github.com/nats-io/nkeys
// We'll then register public key in registry to use
type memory struct {
	opts Options
	// accounts
	sync.RWMutex
	accounts map[string]*Account
}

func (n *memory) Init(opts ...Option) error {
	for _, o := range opts {
		o(&n.opts)
	}
	return nil
}

func (n *memory) Options() Options {
	return n.opts
}

func (n *memory) Generate(id string, opts ...GenerateOption) (*Account, error) {
	var options GenerateOptions
	for _, o := range opts {
		o(&options)
	}

	// return a pseudo account
	acc := genAccount(id)

	// set opts
	if len(options.Roles) > 0 {
		acc.Roles = options.Roles
	}
	if options.Metadata != nil {
		acc.Metadata = options.Metadata
	}

	// TODO: don't overwrite
	n.Lock()
	// maybe save by account id?
	n.accounts[acc.Token] = acc
	n.Unlock()

	return acc, nil
}

func (n *memory) Revoke(token string) error {
	n.Lock()
	delete(n.accounts, token)
	n.Unlock()
	return nil
}

func (n *memory) Verify(token string) (*Account, error) {
	n.RLock()
	defer n.RUnlock()

	if len(token) == 0 {
		// pseudo account?
		return genAccount(""), nil
	}

	// try get the local account if it exists
	if acc, ok := n.accounts[token]; ok {
		return acc, nil
	}

	// decode the token otherwise
	b, err := base32.StdEncoding.DecodeString(token)
	if err != nil {
		return nil, err
	}

	// return a pseudo account based on token/id
	return &Account{
		Id:       string(b),
		Token:    token,
		Created:  time.Now(),
		Expiry:   time.Now().Add(time.Hour * 24),
		Metadata: make(map[string]string),
	}, nil
}

func (n *memory) String() string {
	return "memory"
}
<commit_msg>gen account on base32 decode failure (#1269)<commit_after>package auth

import (
	"encoding/base32"
	"sync"
	"time"
)

var (
	DefaultAuth = NewAuth()
)

func genAccount(id string) *Account {
	// return a pseudo account
	return &Account{
		Id:       id,
		Token:    base32.StdEncoding.EncodeToString([]byte(id)),
		Created:  time.Now(),
		Expiry:   time.Now().Add(time.Hour * 24),
		Metadata: make(map[string]string),
	}
}

// NewAuth returns a new default registry which is memory
func NewAuth(opts ...Option) Auth {
	var options Options
	for _, o := range opts {
		o(&options)
	}

	return &memory{
		accounts: make(map[string]*Account),
		opts:     options,
	}
}

// TODO: replace with https://github.com/nats-io/nkeys
// We'll then register public key in registry to use
type memory struct {
	opts Options
	// accounts
	sync.RWMutex
	accounts map[string]*Account
}

func (n *memory) Init(opts ...Option) error {
	for _, o := range opts {
		o(&n.opts)
	}
	return nil
}

func (n *memory) Options() Options {
	return n.opts
}

func (n *memory) Generate(id string, opts ...GenerateOption) (*Account, error) {
	var options GenerateOptions
	for _, o := range opts {
		o(&options)
	}

	// return a pseudo account
	acc := genAccount(id)

	// set opts
	if len(options.Roles) > 0 {
		acc.Roles = options.Roles
	}
	if options.Metadata != nil {
		acc.Metadata = options.Metadata
	}

	// TODO: don't overwrite
	n.Lock()
	// maybe save by account id?
	n.accounts[acc.Token] = acc
	n.Unlock()

	return acc, nil
}

func (n *memory) Revoke(token string) error {
	n.Lock()
	delete(n.accounts, token)
	n.Unlock()
	return nil
}

func (n *memory) Verify(token string) (*Account, error) {
	n.RLock()
	defer n.RUnlock()

	if len(token) == 0 {
		// pseudo account?
		return genAccount(""), nil
	}

	// try get the local account if it exists
	if acc, ok := n.accounts[token]; ok {
		return acc, nil
	}

	// decode the token otherwise
	b, err := base32.StdEncoding.DecodeString(token)
	if err != nil {
		return genAccount(""), nil
	}

	// return a pseudo account based on token/id
	return &Account{
		Id:       string(b),
		Token:    token,
		Created:  time.Now(),
		Expiry:   time.Now().Add(time.Hour * 24),
		Metadata: make(map[string]string),
	}, nil
}

func (n *memory) String() string {
	return "memory"
}
<|endoftext|>


<commit_before>package blend

import (
	"image/color"
	"math"
)

const (
	max = 65535.0 // equals to 0xFFFF uint16 max range of color.Color
	mid = max / 2.0
)

type BlendFunc func(src color.Color, dst color.Color) color.Color

func blend_per_channel(src, dst color.Color, bf func(float64, float64) float64) color.Color {
	s, d := color2rgbaf64(src), color2rgbaf64(dst)
	return rgbaf64{bf(s.r, d.r), bf(s.g, d.g), bf(s.b, d.b), d.a}
}

// ADD
func ADD(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, add)
}
func add(s, d float64) float64 {
	if s+d > max {
		return max
	}
	return s + d
}

// SUBSTRACT
func SUBSTRACT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, substract)
}
func substract(s, d float64) float64 {
	if s-d < 0.0 {
		return 0.0
	}
	return s - d
}

// DIVIDE
func DIVIDE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, divide)
}
func divide(s, d float64) float64 {
	return s / d
}

// MULTIPLY
func MULTIPLY(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, multiply)
}
func multiply(s, d float64) float64 {
	return s * d / max
}

// SCREEN
func SCREEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, screen)
}
func screen(s, d float64) float64 {
	return s + d - s*d/max
}

// OVERLAY
func OVERLAY(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, overlay)
}
func overlay(s, d float64) float64 {
	if d < mid {
		return 2 * s * d / max
	}
	return max - 2*(max-s)*(max-d)/max
}

// SOFT LIGHT
func SOFT_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, soft_light)
}
func soft_light(s, d float64) float64 {
	if s > mid {
		return d + (max-d)*((s-mid)/mid)*(0.5-math.Abs(d-mid)/max)
	}
	return d - d*((mid-s)/mid)*(0.5-math.Abs(d-mid)/max)
}

// HARD LIGHT
func HARD_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, hard_light)
}
func hard_light(s, d float64) float64 {
	if s > mid {
		return d + (max-d)*((s-mid)/mid)
	}
	return d * s / mid
}

// COLOR DODGE
func COLOR_DODGE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, color_dodge)
}
func color_dodge(s, d float64) float64 {
	if s == max {
		return s
	}
	return math.Min(max, (d * max / (max - s)))
}

// COLOR BURN
func COLOR_BURN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, color_burn)
}
func color_burn(s, d float64) float64 {
	if s == 0.0 {
		return s
	}
	return math.Max(0.0, max-((max-d)*max/s))
}

// LINEAR DODGE
func LINEAR_DODGE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_dodge)
}
func linear_dodge(s, d float64) float64 {
	return math.Min(s+d, max)
}

// LINEAR BURN
func LINEAR_BURN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_burn)
}
func linear_burn(s, d float64) float64 {
	if (s + d) < max {
		return 0.0
	}
	return s + d - max
}

// DARKEN
func DARKEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, darken)
}
func darken(s, d float64) float64 {
	return math.Min(s, d)
}

// LIGHTEN
func LIGHTEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, lighten)
}
func lighten(s, d float64) float64 {
	return math.Max(s, d)
}

// DIFFERENCE
func DIFFERENCE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, difference)
}
func difference(s, d float64) float64 {
	return math.Abs(s - d)
}

// EXCLUSION
func EXCLUSION(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, exclusion)
}
func exclusion(s, d float64) float64 {
	return s + d - s*d/mid
}

// REFLEX
func REFLEX(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, reflex)
}
func reflex(s, d float64) float64 {
	if s == max {
		return s
	}
	return math.Min(max, (d * d / (max - s)))
}

// LINEAR LIGHT
func LINEAR_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_light)
}
func linear_light(s, d float64) float64 {
	if s < mid {
		return linear_burn(d, (2 * s))
	}
	return linear_dodge(d, (2 * (s - mid)))
}

// PIN LIGHT
func PIN_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, pin_light)
}
func pin_light(s, d float64) float64 {
	if s < mid {
		return darken(d, (2 * s))
	}
	return lighten(d, (2 * (s - mid)))
}

// VIVID LIGHT
func VIVID_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, vivid_light)
}
func vivid_light(s, d float64) float64 {
	if s < mid {
		return color_burn(d, (2 * s))
	}
	return color_dodge(d, (2 * (s - mid)))
}

// HARD MIX
func HARD_MIX(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, hard_mix)
}
func hard_mix(s, d float64) float64 {
	if vivid_light(s, d) < mid {
		return 0.0
	}
	return max
}
<commit_msg>Invert values in SUB DIV modes.<commit_after>package blend

import (
	"image/color"
	"math"
)

const (
	max = 65535.0 // equals to 0xFFFF uint16 max range of color.Color
	mid = max / 2.0
)

type BlendFunc func(src color.Color, dst color.Color) color.Color

func blend_per_channel(src, dst color.Color, bf func(float64, float64) float64) color.Color {
	s, d := color2rgbaf64(src), color2rgbaf64(dst)
	return rgbaf64{bf(s.r, d.r), bf(s.g, d.g), bf(s.b, d.b), d.a}
}

// ADD
func ADD(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, add)
}
func add(s, d float64) float64 {
	if s+d > max {
		return max
	}
	return s + d
}

// SUBSTRACT
func SUBSTRACT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, substract)
}
func substract(s, d float64) float64 {
	if d-s < 0.0 {
		return 0.0
	}
	return d - s
}

// DIVIDE
func DIVIDE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, divide)
}
func divide(s, d float64) float64 {
	return d / s
}

// MULTIPLY
func MULTIPLY(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, multiply)
}
func multiply(s, d float64) float64 {
	return s * d / max
}

// SCREEN
func SCREEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, screen)
}
func screen(s, d float64) float64 {
	return s + d - s*d/max
}

// OVERLAY
func OVERLAY(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, overlay)
}
func overlay(s, d float64) float64 {
	if d < mid {
		return 2 * s * d / max
	}
	return max - 2*(max-s)*(max-d)/max
}

// SOFT LIGHT
func SOFT_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, soft_light)
}
func soft_light(s, d float64) float64 {
	if s > mid {
		return d + (max-d)*((s-mid)/mid)*(0.5-math.Abs(d-mid)/max)
	}
	return d - d*((mid-s)/mid)*(0.5-math.Abs(d-mid)/max)
}

// HARD LIGHT
func HARD_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, hard_light)
}
func hard_light(s, d float64) float64 {
	if s > mid {
		return d + (max-d)*((s-mid)/mid)
	}
	return d * s / mid
}

// COLOR DODGE
func COLOR_DODGE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, color_dodge)
}
func color_dodge(s, d float64) float64 {
	if s == max {
		return s
	}
	return math.Min(max, (d * max / (max - s)))
}

// COLOR BURN
func COLOR_BURN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, color_burn)
}
func color_burn(s, d float64) float64 {
	if s == 0.0 {
		return s
	}
	return math.Max(0.0, max-((max-d)*max/s))
}

// LINEAR DODGE
func LINEAR_DODGE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_dodge)
}
func linear_dodge(s, d float64) float64 {
	return math.Min(s+d, max)
}

// LINEAR BURN
func LINEAR_BURN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_burn)
}
func linear_burn(s, d float64) float64 {
	if (s + d) < max {
		return 0.0
	}
	return s + d - max
}

// DARKEN
func DARKEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, darken)
}
func darken(s, d float64) float64 {
	return math.Min(s, d)
}

// LIGHTEN
func LIGHTEN(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, lighten)
}
func lighten(s, d float64) float64 {
	return math.Max(s, d)
}

// DIFFERENCE
func DIFFERENCE(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, difference)
}
func difference(s, d float64) float64 {
	return math.Abs(s - d)
}

// EXCLUSION
func EXCLUSION(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, exclusion)
}
func exclusion(s, d float64) float64 {
	return s + d - s*d/mid
}

// REFLEX
func REFLEX(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, reflex)
}
func reflex(s, d float64) float64 {
	if s == max {
		return s
	}
	return math.Min(max, (d * d / (max - s)))
}

// LINEAR LIGHT
func LINEAR_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, linear_light)
}
func linear_light(s, d float64) float64 {
	if s < mid {
		return linear_burn(d, (2 * s))
	}
	return linear_dodge(d, (2 * (s - mid)))
}

// PIN LIGHT
func PIN_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, pin_light)
}
func pin_light(s, d float64) float64 {
	if s < mid {
		return darken(d, (2 * s))
	}
	return lighten(d, (2 * (s - mid)))
}

// VIVID LIGHT
func VIVID_LIGHT(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, vivid_light)
}
func vivid_light(s, d float64) float64 {
	if s < mid {
		return color_burn(d, (2 * s))
	}
	return color_dodge(d, (2 * (s - mid)))
}

// HARD MIX
func HARD_MIX(src color.Color, dst color.Color) color.Color {
	return blend_per_channel(src, dst, hard_mix)
}
func hard_mix(s, d float64) float64 {
	if vivid_light(s, d) < mid {
		return 0.0
	}
	return max
}
<|endoftext|>


<commit_before>// Copyright 2019 ETH Zurich, Anapaya Systems
//
// 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 rpc implements SCION Infra RPC calls over QUIC.
package rpc

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"

	quic "github.com/lucas-clemente/quic-go"
	capnp "zombiezen.com/go/capnproto2"

	"github.com/scionproto/scion/go/lib/log"
	"github.com/scionproto/scion/go/lib/serrors"
	"github.com/scionproto/scion/go/lib/snet"
	"github.com/scionproto/scion/go/proto"
)

const (
	// CtxTimedOutError is a custom QUIC error code that is used when canceling
	// writes due to context expiration.
	CtxTimedOutError = iota + 1
)

// Server is the configuration for a QUIC RPC server. Messages are SCION Infra
// Signed Control Payloads. For each accepted connection, the server parses the
// message from the client and passes it to the handler.
type Server struct {
	// Conn is the connection to listen on. It can be shared with Clients,
	// because QUIC connection IDs are used to demux the packets.
	Conn net.PacketConn
	// TLSConfig is the server's TLS configuration for starting QUIC connections.
	TLSConfig *tls.Config
	// QUICConfig is the server's QUIC configuration.
	QUICConfig *quic.Config
	// Handler is called for every RPC Request receivd by the server.
	Handler Handler

	mu sync.Mutex
	// listener is the conn to accept connections on.
	listener quic.Listener
}

func (s *Server) ListenAndServe() error {
	if err := s.initListener(); err != nil {
		return err
	}
	for {
		session, err := s.listener.Accept()
		if err != nil {
			if strings.Contains(err.Error(), "server closed") {
				return err
			}
			log.Warn("[quic] server accept error", "err", err)
			continue
		}
		if err := s.handleQUICSession(session); err != nil {
			log.Warn("[quic] server handler exited with error", "err", err)
		}
	}
}

func (s *Server) initListener() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.listener != nil {
		return serrors.New("cannot listen on same server twice")
	}
	listener, err := quic.Listen(s.Conn, s.TLSConfig, s.QUICConfig)
	if err != nil {
		return err
	}
	s.listener = listener
	return nil
}

// Close closes the Server's listener. All active QUIC connections are
// immediately torn down. It is safe to call close multiple times.
func (s *Server) Close() error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.listener == nil {
		// Close on non-listening server is a no-op
		return nil
	}
	return s.listener.Close()
}

func (s *Server) handleQUICSession(session quic.Session) error {
	stream, err := session.AcceptStream()
	if err != nil {
		return err
	}
	msg, err := proto.SafeDecode(capnp.NewDecoder(stream))
	if err != nil {
		return err
	}
	rw := &replyWriter{stream: stream}
	request := &Request{
		Message: msg,
		Address: session.RemoteAddr(),
	}
	go func() {
		defer log.LogPanicAndExit()
		s.Handler.ServeRPC(rw, request)
	}()
	return nil
}

type Client struct {
	// Conn is the connection to initiate QUIC Sessions on. It can be shared
	// with Servers, because QUIC connection IDs are used to demux the packets.
	Conn net.PacketConn
	// TLSConfig is the client's TLS configuration for starting QUIC connections.
	TLSConfig *tls.Config
	// QUICConfig is the client's QUIC configuration.
	QUICConfig *quic.Config
}

// Request sends the request to the host described by address, and blocks until
// a reply is received (or the context times out). If a reply is received, it
// is returned.
func (c *Client) Request(ctx context.Context, request *Request, address net.Addr) (*Reply, error) {
	addressStr := computeAddressStr(address)

	session, err := quic.DialContext(ctx, c.Conn, address, addressStr,
		c.TLSConfig, c.QUICConfig)
	if err != nil {
		return nil, err
	}

	stream, err := session.OpenStream()
	if err != nil {
		return nil, err
	}
	go func() {
		defer log.LogPanicAndExit()
		<-ctx.Done()
		stream.CancelRead(CtxTimedOutError)
		stream.CancelWrite(CtxTimedOutError)
	}()

	err = capnp.NewEncoder(stream).Encode(request.Message)
	if err != nil {
		return nil, err
	}
	msg, err := proto.SafeDecode(capnp.NewDecoder(stream))
	if err != nil {
		// if we have a timeout make it visible.
		if strings.Contains(err.Error(),
			fmt.Sprintf("canceled with error code %d", CtxTimedOutError)) && ctx.Err() != nil {
			return nil, ctx.Err()
		}
		return nil, err
	}

	if err := stream.Close(); err != nil {
		return nil, err
	}
	if err := session.Close(); err != nil {
		return nil, err
	}
	return &Reply{Message: msg}, nil
}

func (c *Client) sendRequest() error {
	return nil
}

// computeAddressStr returns a parseable version of the SCION address for use
// with QUIC SNI.
func computeAddressStr(address net.Addr) string {
	if v, ok := address.(*snet.UDPAddr); ok {
		return fmt.Sprintf("%s:%d", v.Host.IP, v.Host.Port)
	}
	return address.String()
}

// Handler is called by RPC servers whenever a new request arrives.
// Implementations should write replies to rw.
type Handler interface {
	ServeRPC(rw ReplyWriter, request *Request)
}

// ReplyWriter provides handlers a way to respond to requests. ReplyWriter
// keeps a connection alive for replying. Method WriteReply can block; to
// unblock the method (and to close the connection ahead of time), call
// Close.  ReplyWriter implementations must also close the connection whenever
// they return from WriteReply.
type ReplyWriter interface {
	// WriteReply blocks until the Reply is sent back to the peer. The
	// underlying connection is always closed before WriteReply returns.
	WriteReply(*Reply) error
	// Close closes any connections kept open by this writer, and unblocks an
	// ongoing WriteReply. It is safe to call Close concurrently with
	// WriteReply. Close can be safely called multiple times.
	io.Closer
}

type replyWriter struct {
	stream quic.Stream
}

func (rw *replyWriter) WriteReply(reply *Reply) error {
	if err := capnp.NewEncoder(rw.stream).Encode(reply.Message); err != nil {
		return err
	}
	if err := rw.stream.Close(); err != nil {
		return err
	}
	return nil
}

func (rw *replyWriter) Close() error {
	return rw.stream.Close()
}
<commit_msg>Fix address string for IPv6 for QUIC Infra RPC (#3452)<commit_after>// Copyright 2019 ETH Zurich, Anapaya Systems
//
// 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 rpc implements SCION Infra RPC calls over QUIC.
package rpc

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"strings"
	"sync"

	quic "github.com/lucas-clemente/quic-go"
	capnp "zombiezen.com/go/capnproto2"

	"github.com/scionproto/scion/go/lib/log"
	"github.com/scionproto/scion/go/lib/serrors"
	"github.com/scionproto/scion/go/lib/snet"
	"github.com/scionproto/scion/go/proto"
)

const (
	// CtxTimedOutError is a custom QUIC error code that is used when canceling
	// writes due to context expiration.
	CtxTimedOutError = iota + 1
)

// Server is the configuration for a QUIC RPC server. Messages are SCION Infra
// Signed Control Payloads. For each accepted connection, the server parses the
// message from the client and passes it to the handler.
type Server struct {
	// Conn is the connection to listen on. It can be shared with Clients,
	// because QUIC connection IDs are used to demux the packets.
	Conn net.PacketConn
	// TLSConfig is the server's TLS configuration for starting QUIC connections.
	TLSConfig *tls.Config
	// QUICConfig is the server's QUIC configuration.
	QUICConfig *quic.Config
	// Handler is called for every RPC Request receivd by the server.
	Handler Handler

	mu sync.Mutex
	// listener is the conn to accept connections on.
	listener quic.Listener
}

func (s *Server) ListenAndServe() error {
	if err := s.initListener(); err != nil {
		return err
	}
	for {
		session, err := s.listener.Accept()
		if err != nil {
			if strings.Contains(err.Error(), "server closed") {
				return err
			}
			log.Warn("[quic] server accept error", "err", err)
			continue
		}
		if err := s.handleQUICSession(session); err != nil {
			log.Warn("[quic] server handler exited with error", "err", err)
		}
	}
}

func (s *Server) initListener() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.listener != nil {
		return serrors.New("cannot listen on same server twice")
	}
	listener, err := quic.Listen(s.Conn, s.TLSConfig, s.QUICConfig)
	if err != nil {
		return err
	}
	s.listener = listener
	return nil
}

// Close closes the Server's listener. All active QUIC connections are
// immediately torn down. It is safe to call close multiple times.
func (s *Server) Close() error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.listener == nil {
		// Close on non-listening server is a no-op
		return nil
	}
	return s.listener.Close()
}

func (s *Server) handleQUICSession(session quic.Session) error {
	stream, err := session.AcceptStream()
	if err != nil {
		return err
	}
	msg, err := proto.SafeDecode(capnp.NewDecoder(stream))
	if err != nil {
		return err
	}
	rw := &replyWriter{stream: stream}
	request := &Request{
		Message: msg,
		Address: session.RemoteAddr(),
	}
	go func() {
		defer log.LogPanicAndExit()
		s.Handler.ServeRPC(rw, request)
	}()
	return nil
}

type Client struct {
	// Conn is the connection to initiate QUIC Sessions on. It can be shared
	// with Servers, because QUIC connection IDs are used to demux the packets.
	Conn net.PacketConn
	// TLSConfig is the client's TLS configuration for starting QUIC connections.
	TLSConfig *tls.Config
	// QUICConfig is the client's QUIC configuration.
	QUICConfig *quic.Config
}

// Request sends the request to the host described by address, and blocks until
// a reply is received (or the context times out). If a reply is received, it
// is returned.
func (c *Client) Request(ctx context.Context, request *Request, address net.Addr) (*Reply, error) {
	addressStr := computeAddressStr(address)

	session, err := quic.DialContext(ctx, c.Conn, address, addressStr,
		c.TLSConfig, c.QUICConfig)
	if err != nil {
		return nil, err
	}

	stream, err := session.OpenStream()
	if err != nil {
		return nil, err
	}
	go func() {
		defer log.LogPanicAndExit()
		<-ctx.Done()
		stream.CancelRead(CtxTimedOutError)
		stream.CancelWrite(CtxTimedOutError)
	}()

	err = capnp.NewEncoder(stream).Encode(request.Message)
	if err != nil {
		return nil, err
	}
	msg, err := proto.SafeDecode(capnp.NewDecoder(stream))
	if err != nil {
		// if we have a timeout make it visible.
		if strings.Contains(err.Error(),
			fmt.Sprintf("canceled with error code %d", CtxTimedOutError)) && ctx.Err() != nil {
			return nil, ctx.Err()
		}
		return nil, err
	}

	if err := stream.Close(); err != nil {
		return nil, err
	}
	if err := session.Close(); err != nil {
		return nil, err
	}
	return &Reply{Message: msg}, nil
}

func (c *Client) sendRequest() error {
	return nil
}

// computeAddressStr returns a parseable version of the SCION address for use
// with QUIC SNI.
func computeAddressStr(address net.Addr) string {
	if v, ok := address.(*snet.UDPAddr); ok {
		return fmt.Sprintf("[%s]:%d", v.Host.IP, v.Host.Port)
	}
	return address.String()
}

// Handler is called by RPC servers whenever a new request arrives.
// Implementations should write replies to rw.
type Handler interface {
	ServeRPC(rw ReplyWriter, request *Request)
}

// ReplyWriter provides handlers a way to respond to requests. ReplyWriter
// keeps a connection alive for replying. Method WriteReply can block; to
// unblock the method (and to close the connection ahead of time), call
// Close.  ReplyWriter implementations must also close the connection whenever
// they return from WriteReply.
type ReplyWriter interface {
	// WriteReply blocks until the Reply is sent back to the peer. The
	// underlying connection is always closed before WriteReply returns.
	WriteReply(*Reply) error
	// Close closes any connections kept open by this writer, and unblocks an
	// ongoing WriteReply. It is safe to call Close concurrently with
	// WriteReply. Close can be safely called multiple times.
	io.Closer
}

type replyWriter struct {
	stream quic.Stream
}

func (rw *replyWriter) WriteReply(reply *Reply) error {
	if err := capnp.NewEncoder(rw.stream).Encode(reply.Message); err != nil {
		return err
	}
	if err := rw.stream.Close(); err != nil {
		return err
	}
	return nil
}

func (rw *replyWriter) Close() error {
	return rw.stream.Close()
}
<|endoftext|>


<commit_before>package libkb

import (
	"encoding/hex"
	"time"

	keybase1 "github.com/keybase/client/protocol/go"
	jsonw "github.com/keybase/go-jsonw"
)

// Delegator
//
// Delegates authority to another key.
//

type Delegator struct {
	Contextified

	// Set these fields
	NewKey            GenericKey
	ExistingKey       GenericKey
	ExistingKID       keybase1.KID // may be empty
	EldestKID         keybase1.KID
	Me                *User
	Sibkey            bool
	Expire            int
	Device            *Device
	RevSig            string
	ServerHalf        []byte
	EncodedPrivateKey string
	Ctime             int64
	PushType          string
	Aggregated        bool // During aggregation we skip some steps (posting, updating some state)

	// Internal fields
	isEldest     bool
	signingKey   GenericKey
	sig          string
	sigID        keybase1.SigID
	merkleTriple MerkleTriple
	postArg      APIArg
}

func (d Delegator) getSigningKID() keybase1.KID { return d.signingKey.GetKID() }

func (d Delegator) getExistingKID() (kid keybase1.KID) {
	if d.ExistingKey == nil {
		return
	}
	return d.ExistingKey.GetKID()
}

func (d Delegator) GetExistingKeyKID() (ret keybase1.KID) {
	if d.ExistingKey != nil {
		kid := d.ExistingKey.GetKID()
		return kid
	}
	return d.ExistingKID
}

// Sometime our callers don't set Sibkey=true for eldest keys, so
// we workaround that here.
func (d Delegator) IsSibkey() bool { return d.Sibkey || d.isEldest }

// GetMerkleTriple gets the new MerkleTriple that came about as a result
// of performing the key delegation.
func (d Delegator) GetMerkleTriple() MerkleTriple { return d.merkleTriple }

func (d *Delegator) CheckArgs() (err error) {

	G.Log.Debug("+ Delegator::checkArgs()")

	if d.NewKey == nil {
		err = NoSecretKeyError{}
		return
	}

	if d.signingKey = d.ExistingKey; d.signingKey != nil {
		G.Log.Debug("| Picked passed-in signing key")
	} else {
		G.Log.Debug("| Picking new key for an eldest self-sig")
		d.signingKey = d.NewKey
		d.isEldest = true
	}

	if d.EldestKID.Exists() || d.isEldest {
	} else if kid := d.Me.GetEldestKID(); kid.IsNil() {
		err = NoEldestKeyError{}
		return err
	} else {
		d.EldestKID = kid
	}

	G.Log.Debug("| Picked key %s for signing", d.signingKey.GetKID())
	G.Log.Debug("- Delegator::checkArgs()")

	return nil
}

// LoadSigningKey can be called before Run() to load the signing key into
// the delegator. This will check the given key first, then a device Key if we have one,
// and otherwise will leave the signing key unset so that we will set it
// as the eldest key on upload.
// lctx can be nil.
func (d *Delegator) LoadSigningKey(lctx LoginContext, ui SecretUI) (err error) {

	G.Log.Debug("+ Delegator::LoadSigningKey")
	defer func() {
		G.Log.Debug("+ Delegator::LoadSigningKey -> %s, (found=%v)", ErrToOk(err), (d.signingKey != nil))
	}()

	if d.ExistingKey != nil {
		G.Log.Debug("| Was set ahead of time")
		return
	}

	if d.Me == nil {
		d.Me, err = LoadMe(LoadUserArg{PublicKeyOptional: true})
		if err != nil {
			return
		} else if d.Me == nil {
			G.Log.Debug("| Me didn't load")
			return
		}
	}

	if !d.Me.HasActiveKey() {
		G.Log.Debug("| PGPKeyImportEngine: no active key found, so assuming set of eldest key")
		return
	}

	d.ExistingKey, _, err = d.G().Keyrings.GetSecretKeyWithPrompt(lctx, SecretKeyArg{
		Me:      d.Me,
		KeyType: DeviceSigningKeyType,
	}, ui, "sign new key")

	return err
}

// Run the Delegator, performing all necessary internal operations.  Return err
// on failure and nil on success.
func (d *Delegator) Run(lctx LoginContext) (err error) {
	var jw *jsonw.Wrapper

	G.Log.Debug("+ Delegator.Run()")
	defer func() {
		G.Log.Debug("- Delegator.Run() -> %s", ErrToOk(err))
	}()

	if err = d.CheckArgs(); err != nil {
		return
	}

	// We'll need to generate two proofs, so set the Ctime
	// so that we get the same time both times
	d.Ctime = time.Now().Unix()

	// For a sibkey signature, we first sign the blob with the
	// sibkey, and then embed that signature for the delegating key
	if d.Sibkey {
		if jw, _, err = d.Me.KeyProof(*d); err != nil {
			G.Log.Debug("| Failure in intermediate KeyProof()")
			return err
		}

		if d.RevSig, _, _, err = SignJSON(jw, d.NewKey); err != nil {
			G.Log.Debug("| Failure in intermediate SignJson()")
			return err
		}
	}

	if jw, d.PushType, err = d.Me.KeyProof(*d); err != nil {
		G.Log.Debug("| Failure in KeyProof()")
		return
	}

	return d.SignAndPost(lctx, jw)
}

func (d *Delegator) SignAndPost(lctx LoginContext, jw *jsonw.Wrapper) (err error) {

	var linkid LinkID

	if d.sig, d.sigID, linkid, err = SignJSON(jw, d.signingKey); err != nil {
		G.Log.Debug("| Failure in SignJson()")
		return err
	}

	if err = d.post(lctx); err != nil {
		G.Log.Debug("| Failure in post()")
		return
	}

	if err = d.updateLocalState(linkid); err != nil {
		return
	}

	return nil
}

func (d *Delegator) updateLocalState(linkid LinkID) (err error) {
	d.Me.SigChainBump(linkid, d.sigID)
	d.merkleTriple = MerkleTriple{LinkID: linkid, SigID: d.sigID}

	return d.Me.localDelegateKey(d.NewKey, d.sigID, d.getExistingKID(), d.IsSibkey(), d.isEldest)
}

func (d *Delegator) post(lctx LoginContext) (err error) {
	var pub string
	if pub, err = d.NewKey.Encode(); err != nil {
		return
	}

	hargs := HTTPArgs{
		"sig_id_base":     S{Val: d.sigID.ToString(false)},
		"sig_id_short":    S{Val: d.sigID.ToShortID()},
		"sig":             S{Val: d.sig},
		"type":            S{Val: d.PushType},
		"is_remote_proof": B{Val: false},
		"public_key":      S{Val: pub},
		"server_half":     S{Val: hex.EncodeToString(d.ServerHalf)},
	}
	if d.isEldest {
		hargs["is_primary"] = I{Val: 1}
	} else {
		hargs["eldest_kid"] = d.EldestKID
		hargs["signing_kid"] = d.getSigningKID()
	}
	if len(d.EncodedPrivateKey) > 0 {
		hargs["private_key"] = S{Val: d.EncodedPrivateKey}
	}

	G.Log.Debug("Post NewKey: %v", hargs)
	arg := APIArg{
		Endpoint:     "key/add",
		NeedSession:  true,
		Args:         hargs,
		Contextified: NewContextified(d.G()),
	}
	if lctx != nil {
		arg.SessionR = lctx.LocalSession()
	}

	if d.Aggregated {
		d.postArg = arg
		return nil
	}
	_, err = d.G().API.Post(arg)
	return err
}
<commit_msg>only send server half if we have one<commit_after>package libkb

import (
	"encoding/hex"
	"time"

	keybase1 "github.com/keybase/client/protocol/go"
	jsonw "github.com/keybase/go-jsonw"
)

// Delegator
//
// Delegates authority to another key.
//

type Delegator struct {
	Contextified

	// Set these fields
	NewKey            GenericKey
	ExistingKey       GenericKey
	ExistingKID       keybase1.KID // may be empty
	EldestKID         keybase1.KID
	Me                *User
	Sibkey            bool
	Expire            int
	Device            *Device
	RevSig            string
	ServerHalf        []byte
	EncodedPrivateKey string
	Ctime             int64
	PushType          string
	Aggregated        bool // During aggregation we skip some steps (posting, updating some state)

	// Internal fields
	isEldest     bool
	signingKey   GenericKey
	sig          string
	sigID        keybase1.SigID
	merkleTriple MerkleTriple
	postArg      APIArg
}

func (d Delegator) getSigningKID() keybase1.KID { return d.signingKey.GetKID() }

func (d Delegator) getExistingKID() (kid keybase1.KID) {
	if d.ExistingKey == nil {
		return
	}
	return d.ExistingKey.GetKID()
}

func (d Delegator) GetExistingKeyKID() (ret keybase1.KID) {
	if d.ExistingKey != nil {
		kid := d.ExistingKey.GetKID()
		return kid
	}
	return d.ExistingKID
}

// Sometime our callers don't set Sibkey=true for eldest keys, so
// we workaround that here.
func (d Delegator) IsSibkey() bool { return d.Sibkey || d.isEldest }

// GetMerkleTriple gets the new MerkleTriple that came about as a result
// of performing the key delegation.
func (d Delegator) GetMerkleTriple() MerkleTriple { return d.merkleTriple }

func (d *Delegator) CheckArgs() (err error) {

	G.Log.Debug("+ Delegator::checkArgs()")

	if d.NewKey == nil {
		err = NoSecretKeyError{}
		return
	}

	if d.signingKey = d.ExistingKey; d.signingKey != nil {
		G.Log.Debug("| Picked passed-in signing key")
	} else {
		G.Log.Debug("| Picking new key for an eldest self-sig")
		d.signingKey = d.NewKey
		d.isEldest = true
	}

	if d.EldestKID.Exists() || d.isEldest {
	} else if kid := d.Me.GetEldestKID(); kid.IsNil() {
		err = NoEldestKeyError{}
		return err
	} else {
		d.EldestKID = kid
	}

	G.Log.Debug("| Picked key %s for signing", d.signingKey.GetKID())
	G.Log.Debug("- Delegator::checkArgs()")

	return nil
}

// LoadSigningKey can be called before Run() to load the signing key into
// the delegator. This will check the given key first, then a device Key if we have one,
// and otherwise will leave the signing key unset so that we will set it
// as the eldest key on upload.
// lctx can be nil.
func (d *Delegator) LoadSigningKey(lctx LoginContext, ui SecretUI) (err error) {

	G.Log.Debug("+ Delegator::LoadSigningKey")
	defer func() {
		G.Log.Debug("+ Delegator::LoadSigningKey -> %s, (found=%v)", ErrToOk(err), (d.signingKey != nil))
	}()

	if d.ExistingKey != nil {
		G.Log.Debug("| Was set ahead of time")
		return
	}

	if d.Me == nil {
		d.Me, err = LoadMe(LoadUserArg{PublicKeyOptional: true})
		if err != nil {
			return
		} else if d.Me == nil {
			G.Log.Debug("| Me didn't load")
			return
		}
	}

	if !d.Me.HasActiveKey() {
		G.Log.Debug("| PGPKeyImportEngine: no active key found, so assuming set of eldest key")
		return
	}

	d.ExistingKey, _, err = d.G().Keyrings.GetSecretKeyWithPrompt(lctx, SecretKeyArg{
		Me:      d.Me,
		KeyType: DeviceSigningKeyType,
	}, ui, "sign new key")

	return err
}

// Run the Delegator, performing all necessary internal operations.  Return err
// on failure and nil on success.
func (d *Delegator) Run(lctx LoginContext) (err error) {
	var jw *jsonw.Wrapper

	G.Log.Debug("+ Delegator.Run()")
	defer func() {
		G.Log.Debug("- Delegator.Run() -> %s", ErrToOk(err))
	}()

	if err = d.CheckArgs(); err != nil {
		return
	}

	// We'll need to generate two proofs, so set the Ctime
	// so that we get the same time both times
	d.Ctime = time.Now().Unix()

	// For a sibkey signature, we first sign the blob with the
	// sibkey, and then embed that signature for the delegating key
	if d.Sibkey {
		if jw, _, err = d.Me.KeyProof(*d); err != nil {
			G.Log.Debug("| Failure in intermediate KeyProof()")
			return err
		}

		if d.RevSig, _, _, err = SignJSON(jw, d.NewKey); err != nil {
			G.Log.Debug("| Failure in intermediate SignJson()")
			return err
		}
	}

	if jw, d.PushType, err = d.Me.KeyProof(*d); err != nil {
		G.Log.Debug("| Failure in KeyProof()")
		return
	}

	return d.SignAndPost(lctx, jw)
}

func (d *Delegator) SignAndPost(lctx LoginContext, jw *jsonw.Wrapper) (err error) {

	var linkid LinkID

	if d.sig, d.sigID, linkid, err = SignJSON(jw, d.signingKey); err != nil {
		G.Log.Debug("| Failure in SignJson()")
		return err
	}

	if err = d.post(lctx); err != nil {
		G.Log.Debug("| Failure in post()")
		return
	}

	if err = d.updateLocalState(linkid); err != nil {
		return
	}

	return nil
}

func (d *Delegator) updateLocalState(linkid LinkID) (err error) {
	d.Me.SigChainBump(linkid, d.sigID)
	d.merkleTriple = MerkleTriple{LinkID: linkid, SigID: d.sigID}

	return d.Me.localDelegateKey(d.NewKey, d.sigID, d.getExistingKID(), d.IsSibkey(), d.isEldest)
}

func (d *Delegator) post(lctx LoginContext) (err error) {
	var pub string
	if pub, err = d.NewKey.Encode(); err != nil {
		return
	}

	hargs := HTTPArgs{
		"sig_id_base":     S{Val: d.sigID.ToString(false)},
		"sig_id_short":    S{Val: d.sigID.ToShortID()},
		"sig":             S{Val: d.sig},
		"type":            S{Val: d.PushType},
		"is_remote_proof": B{Val: false},
		"public_key":      S{Val: pub},
	}

	if len(string(d.ServerHalf)) > 0 {
		hargs["server_half"] = S{Val: hex.EncodeToString(d.ServerHalf)}
	}

	if d.isEldest {
		hargs["is_primary"] = I{Val: 1}
	} else {
		hargs["eldest_kid"] = d.EldestKID
		hargs["signing_kid"] = d.getSigningKID()
	}
	if len(d.EncodedPrivateKey) > 0 {
		hargs["private_key"] = S{Val: d.EncodedPrivateKey}
	}

	G.Log.Debug("Post NewKey: %v", hargs)
	arg := APIArg{
		Endpoint:     "key/add",
		NeedSession:  true,
		Args:         hargs,
		Contextified: NewContextified(d.G()),
	}
	if lctx != nil {
		arg.SessionR = lctx.LocalSession()
	}

	if d.Aggregated {
		d.postArg = arg
		return nil
	}
	_, err = d.G().API.Post(arg)
	return err
}
<|endoftext|>


<commit_before>// 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 testutil

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/golang/protobuf/proto"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

func tinkRootPath() (string, error) {
	root := os.Getenv("TEST_SRCDIR")
	if root == "" {
		return "", errors.New("TEST_SRCDIR not found")
	}
	path := root + "/google3/third_party/tink"
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		return path, nil
	}
	path2 := root + "/tink_base"
	if _, err := os.Stat(path2); !os.IsNotExist(err) {
		return path2, nil
	}
	return "", errors.New("Tink root path not found")
}

// KeyTemplateProto reads a KeyTemplate from tink/testdata/templates.
func KeyTemplateProto(dir string, name string) (*tinkpb.KeyTemplate, error) {
	root, err := tinkRootPath()
	if err != nil {
		return nil, err
	}
	data, err := ioutil.ReadFile(root + "/testdata/templates/" + dir + "/" + name)
	if err != nil {
		return nil, err
	}
	template := &tinkpb.KeyTemplate{}
	err = proto.UnmarshalText(string(data), template)
	if err != nil {
		return nil, err
	}
	return template, nil
}
<commit_msg>It is a bit cleaner to use os.LookupEnv than os.Getenv.<commit_after>// 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 testutil

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/golang/protobuf/proto"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

func tinkRootPath() (string, error) {
	root, ok := os.LookupEnv("TEST_SRCDIR")
	if !ok {
		return "", errors.New("TEST_SRCDIR not found")
	}
	path := root + "/google3/third_party/tink"
	if _, err := os.Stat(path); !os.IsNotExist(err) {
		return path, nil
	}
	path2 := root + "/tink_base"
	if _, err := os.Stat(path2); !os.IsNotExist(err) {
		return path2, nil
	}
	return "", errors.New("Tink root path not found")
}

// KeyTemplateProto reads a KeyTemplate from tink/testdata/templates.
func KeyTemplateProto(dir string, name string) (*tinkpb.KeyTemplate, error) {
	root, err := tinkRootPath()
	if err != nil {
		return nil, err
	}
	data, err := ioutil.ReadFile(root + "/testdata/templates/" + dir + "/" + name)
	if err != nil {
		return nil, err
	}
	template := &tinkpb.KeyTemplate{}
	err = proto.UnmarshalText(string(data), template)
	if err != nil {
		return nil, err
	}
	return template, nil
}
<|endoftext|>


<commit_before>package clusterconf

import (
	"encoding/json"
	"net"
	"net/url"
	"time"

	"github.com/cerana/cerana/acomm"
	"github.com/cerana/cerana/pkg/errors"
)

const dhcpPrefix string = "dhcp"

// DHCPConfig represents the dhcp settings for the cluster.
type DHCPConfig struct {
	DNS      []net.IP      `json:"dns"`
	Duration time.Duration `json:"duration"`
	Gateway  net.IP        `json:"gateway"`
	Net      net.IPNet     `json:"net"`
}

// Validate validates the DHCPConfig settings.
func (c *DHCPConfig) Validate() error {
	if c.Duration < 1*time.Hour || c.Duration > 24*time.Hour {
		return errors.Newv("duration is invalid", map[string]interface{}{"duration": c.Duration})
	}
	if c.Net.IP == nil {
		return errors.New("net.IP is required")
	}
	c.Net.IP = c.Net.IP.To4()
	if c.Net.IP == nil {
		return errors.Newv("net.IP must be IPv4", map[string]interface{}{"ip": c.Net.IP})
	}
	if c.Net.IP.Equal(net.IPv4zero) {
		return errors.New("net.IP must not be 0.0.0.0")
	}
	if c.Net.Mask == nil {
		return errors.New("net.Mask is required")
	}
	if c.Gateway != nil {
		if !c.Net.Contains(c.Gateway) {
			return errors.Newv("gateway is unreachable", map[string]interface{}{"net": c.Net, "gateway": c.Gateway})
		}
	}
	return nil
}

// GetDHCP retrieves the current cluster DHCP settings.
func (c *ClusterConf) GetDHCP(*acomm.Request) (interface{}, *url.URL, error) {
	value, err := c.kvGet(dhcpPrefix)
	if err != nil {
		return nil, nil, err
	}

	config := DHCPConfig{}
	if err := json.Unmarshal(value.Data, &config); err != nil {
		return nil, nil, errors.Wrapv(err, map[string]interface{}{"json": string(value.Data)})
	}
	return config, nil, nil
}

// SetDHCP updates the cluster DHCP settings.
func (c *ClusterConf) SetDHCP(req *acomm.Request) (interface{}, *url.URL, error) {
	conf := &DHCPConfig{}
	if err := req.UnmarshalArgs(conf); err != nil {
		return nil, nil, err
	}

	if err := conf.Validate(); err != nil {
		return nil, nil, err
	}

	index := uint64(0)
	value, err := c.kvGet(dhcpPrefix)
	if err == nil {
		index = value.Index
	}

	_, err = c.kvUpdate(dhcpPrefix, conf, index)
	return nil, nil, err
}
<commit_msg>providers/clusterconf: use non-pointer DHCPConfig<commit_after>package clusterconf

import (
	"encoding/json"
	"net"
	"net/url"
	"time"

	"github.com/cerana/cerana/acomm"
	"github.com/cerana/cerana/pkg/errors"
)

const dhcpPrefix string = "dhcp"

// DHCPConfig represents the dhcp settings for the cluster.
type DHCPConfig struct {
	DNS      []net.IP      `json:"dns"`
	Duration time.Duration `json:"duration"`
	Gateway  net.IP        `json:"gateway"`
	Net      net.IPNet     `json:"net"`
}

// Validate validates the DHCPConfig settings.
func (c *DHCPConfig) Validate() error {
	if c.Duration < 1*time.Hour || c.Duration > 24*time.Hour {
		return errors.Newv("duration is invalid", map[string]interface{}{"duration": c.Duration})
	}
	if c.Net.IP == nil {
		return errors.New("net.IP is required")
	}
	c.Net.IP = c.Net.IP.To4()
	if c.Net.IP == nil {
		return errors.Newv("net.IP must be IPv4", map[string]interface{}{"ip": c.Net.IP})
	}
	if c.Net.IP.Equal(net.IPv4zero) {
		return errors.New("net.IP must not be 0.0.0.0")
	}
	if c.Net.Mask == nil {
		return errors.New("net.Mask is required")
	}
	if c.Gateway != nil {
		if !c.Net.Contains(c.Gateway) {
			return errors.Newv("gateway is unreachable", map[string]interface{}{"net": c.Net, "gateway": c.Gateway})
		}
	}
	return nil
}

// GetDHCP retrieves the current cluster DHCP settings.
func (c *ClusterConf) GetDHCP(*acomm.Request) (interface{}, *url.URL, error) {
	value, err := c.kvGet(dhcpPrefix)
	if err != nil {
		return nil, nil, err
	}

	conf := DHCPConfig{}
	if err := json.Unmarshal(value.Data, &conf); err != nil {
		return nil, nil, errors.Wrapv(err, map[string]interface{}{"json": string(value.Data)})
	}

	return conf, nil, nil
}

// SetDHCP updates the cluster DHCP settings.
func (c *ClusterConf) SetDHCP(req *acomm.Request) (interface{}, *url.URL, error) {
	conf := DHCPConfig{}
	if err := req.UnmarshalArgs(&conf); err != nil {
		return nil, nil, err
	}

	if err := conf.Validate(); err != nil {
		return nil, nil, err
	}

	index := uint64(0)
	value, err := c.kvGet(dhcpPrefix)
	if err == nil {
		index = value.Index
	}

	_, err = c.kvUpdate(dhcpPrefix, conf, index)
	return nil, nil, err
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"html/template"
	"net/url"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/authorship"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/person"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
)

type SymbolsService interface {
	Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

type SymbolSpec struct {
	SID int64

	Repo     string
	UnitType string
	Unit     string
	Path     string
}

func (s *SymbolSpec) SymbolKey() graph.SymbolKey {
	return graph.SymbolKey{
		Repo:     repo.URI(s.Repo),
		UnitType: s.UnitType,
		Unit:     s.Unit,
		Path:     graph.SymbolPath(s.Path),
	}
}

func NewSymbolSpecFromSymbolKey(key graph.SymbolKey) SymbolSpec {
	return SymbolSpec{
		Repo:     string(key.Repo),
		UnitType: key.UnitType,
		Unit:     key.Unit,
		Path:     string(key.Path),
	}
}

type symbolsService struct {
	client *Client
}

var _ SymbolsService = &symbolsService{}

type Symbol struct {
	graph.Symbol

	Stat map[graph.StatType]int `json:",omitempty"`

	Doc      string           `json:",omitempty"`
	DefHTML  template.HTML    `json:",omitempty"`
	DocPages []*graph.DocPage `json:",omitempty"`
}

func (s *Symbol) XRefs() int     { return s.Stat["xrefs"] }
func (s *Symbol) RRefs() int     { return s.Stat["rrefs"] }
func (s *Symbol) URefs() int     { return s.Stat["urefs"] }
func (s *Symbol) TotalRefs() int { return s.XRefs() + s.RRefs() + s.URefs() }

type GetSymbolOptions struct {
	Annotate bool `url:",omitempty"`
	DocPages bool `url:",omitempty"`
}

func (s *symbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	var url *url.URL
	var err error
	if symbol.SID != 0 {
		url, err = s.client.url(api_router.SymbolBySID, map[string]string{"SID": fmt.Sprintf("%d", symbol.SID)}, opt)
	} else {
		url, err = s.client.url(api_router.Symbol, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	}
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbol_ *Symbol
	resp, err := s.client.Do(req, &symbol_)
	if err != nil {
		return nil, resp, err
	}

	return symbol_, resp, nil
}

type SymbolListOptions struct {
	RepositoryURI string `url:",omitempty"`
	Query         string `url:",omitempty"`

	Sort      string `url:",omitempty"`
	Direction string `url:",omitempty"`

	Kinds        []string `url:",omitempty,comma"`
	SpecificKind string   `url:",omitempty"`

	Scope     string `url:",omitempty"`
	Recursive bool   `url:",omitempty"`
	Exported  bool   `url:",omitempty"`
	Doc       bool   `url:",omitempty"`

	ListOptions
}

func (s *symbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.Symbols, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type Example struct {
	graph.Ref
	SrcHTML template.HTML
}

type Examples []*Example

func (r *Example) sortKey() string     { return fmt.Sprintf("%+v", r) }
func (vs Examples) Len() int           { return len(vs) }
func (vs Examples) Swap(i, j int)      { vs[i], vs[j] = vs[j], vs[i] }
func (vs Examples) Less(i, j int) bool { return vs[i].sortKey() < vs[j].sortKey() }

type SymbolExampleListOptions struct {
	Annotate bool

	ListOptions
}

func (s *symbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	url, err := s.client.url(api_router.SymbolExamples, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var examples []*Example
	resp, err := s.client.Do(req, &examples)
	if err != nil {
		return nil, resp, err
	}

	return examples, resp, nil
}

type AugmentedSymbolAuthor struct {
	User *person.User
	*authorship.SymbolAuthor
}

type SymbolAuthorListOptions struct {
	ListOptions
}

func (s *symbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	url, err := s.client.url(api_router.SymbolAuthors, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var authors []*AugmentedSymbolAuthor
	resp, err := s.client.Do(req, &authors)
	if err != nil {
		return nil, resp, err
	}

	return authors, resp, nil
}

type AugmentedSymbolClient struct {
	User *person.User
	*authorship.SymbolClient
}

type SymbolClientListOptions struct {
	ListOptions
}

func (s *symbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	url, err := s.client.url(api_router.SymbolClients, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var clients []*AugmentedSymbolClient
	resp, err := s.client.Do(req, &clients)
	if err != nil {
		return nil, resp, err
	}

	return clients, resp, nil
}

type AugmentedRepoRef struct {
	Repo  *repo.Repository
	Count int
}

type SymbolDependentRepositoryListOptions struct {
	ListOptions
}

func (s *symbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	url, err := s.client.url(api_router.SymbolDependents, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var dependents []*AugmentedRepoRef
	resp, err := s.client.Do(req, &dependents)
	if err != nil {
		return nil, resp, err
	}

	return dependents, resp, nil
}

type SymbolListImplementationsOptions struct {
	ListOptions
}

func (s *symbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolImplementations, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type SymbolListInterfacesOptions struct {
	ListOptions
}

func (s *symbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolInterfaces, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

func (s *symbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	url, err := s.client.url(api_router.RepositorySymbolCounts, map[string]string{"RepoURI": repo.URI}, nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var counts *graph.SymbolCounts
	resp, err := s.client.Do(req, &counts)
	if err != nil {
		return nil, resp, err
	}

	return counts, resp, nil
}

type MockSymbolsService struct {
	Get_                       func(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List_                      func(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples_              func(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors_               func(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients_               func(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories_ func(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations_       func(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces_            func(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository_         func(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

var _ SymbolsService = MockSymbolsService{}

func (s MockSymbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	if s.Get_ == nil {
		return nil, &Response{}, nil
	}
	return s.Get_(symbol, opt)
}

func (s MockSymbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	if s.List_ == nil {
		return nil, &Response{}, nil
	}
	return s.List_(opt)
}

func (s MockSymbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	if s.ListExamples_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListExamples_(symbol, opt)
}

func (s MockSymbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	if s.ListAuthors_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListAuthors_(symbol, opt)
}

func (s MockSymbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	if s.ListClients_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListClients_(symbol, opt)
}

func (s MockSymbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	if s.ListDependentRepositories_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListDependentRepositories_(symbol, opt)
}

func (s MockSymbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	if s.ListImplementations_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListImplementations_(symbol, opt)
}

func (s MockSymbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	if s.ListInterfaces_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListInterfaces_(symbol, opt)
}

func (s MockSymbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	if s.CountByRepository_ == nil {
		return &graph.SymbolCounts{}, &Response{}, nil
	}
	return s.CountByRepository_(repo)
}
<commit_msg>SymbolSpec method<commit_after>package client

import (
	"fmt"
	"html/template"
	"net/url"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/authorship"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/person"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
)

type SymbolsService interface {
	Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

type SymbolSpec struct {
	SID int64

	Repo     string
	UnitType string
	Unit     string
	Path     string
}

func (s *SymbolSpec) SymbolKey() graph.SymbolKey {
	return graph.SymbolKey{
		Repo:     repo.URI(s.Repo),
		UnitType: s.UnitType,
		Unit:     s.Unit,
		Path:     graph.SymbolPath(s.Path),
	}
}

func NewSymbolSpecFromSymbolKey(key graph.SymbolKey) SymbolSpec {
	return SymbolSpec{
		Repo:     string(key.Repo),
		UnitType: key.UnitType,
		Unit:     key.Unit,
		Path:     string(key.Path),
	}
}

type symbolsService struct {
	client *Client
}

var _ SymbolsService = &symbolsService{}

type Symbol struct {
	graph.Symbol

	Stat map[graph.StatType]int `json:",omitempty"`

	Doc      string           `json:",omitempty"`
	DefHTML  template.HTML    `json:",omitempty"`
	DocPages []*graph.DocPage `json:",omitempty"`
}

func (s *Symbol) SymbolSpec() SymbolSpec {
	spec := NewSymbolSpecFromSymbolKey(s.Symbol.SymbolKey)
	spec.SID = int64(s.Symbol.SID)
	return spec
}

func (s *Symbol) XRefs() int     { return s.Stat["xrefs"] }
func (s *Symbol) RRefs() int     { return s.Stat["rrefs"] }
func (s *Symbol) URefs() int     { return s.Stat["urefs"] }
func (s *Symbol) TotalRefs() int { return s.XRefs() + s.RRefs() + s.URefs() }

type GetSymbolOptions struct {
	Annotate bool `url:",omitempty"`
	DocPages bool `url:",omitempty"`
}

func (s *symbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	var url *url.URL
	var err error
	if symbol.SID != 0 {
		url, err = s.client.url(api_router.SymbolBySID, map[string]string{"SID": fmt.Sprintf("%d", symbol.SID)}, opt)
	} else {
		url, err = s.client.url(api_router.Symbol, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	}
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbol_ *Symbol
	resp, err := s.client.Do(req, &symbol_)
	if err != nil {
		return nil, resp, err
	}

	return symbol_, resp, nil
}

type SymbolListOptions struct {
	RepositoryURI string `url:",omitempty"`
	Query         string `url:",omitempty"`

	Sort      string `url:",omitempty"`
	Direction string `url:",omitempty"`

	Kinds        []string `url:",omitempty,comma"`
	SpecificKind string   `url:",omitempty"`

	Scope     string `url:",omitempty"`
	Recursive bool   `url:",omitempty"`
	Exported  bool   `url:",omitempty"`
	Doc       bool   `url:",omitempty"`

	ListOptions
}

func (s *symbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.Symbols, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type Example struct {
	graph.Ref
	SrcHTML template.HTML
}

type Examples []*Example

func (r *Example) sortKey() string     { return fmt.Sprintf("%+v", r) }
func (vs Examples) Len() int           { return len(vs) }
func (vs Examples) Swap(i, j int)      { vs[i], vs[j] = vs[j], vs[i] }
func (vs Examples) Less(i, j int) bool { return vs[i].sortKey() < vs[j].sortKey() }

type SymbolExampleListOptions struct {
	Annotate bool

	ListOptions
}

func (s *symbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	url, err := s.client.url(api_router.SymbolExamples, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var examples []*Example
	resp, err := s.client.Do(req, &examples)
	if err != nil {
		return nil, resp, err
	}

	return examples, resp, nil
}

type AugmentedSymbolAuthor struct {
	User *person.User
	*authorship.SymbolAuthor
}

type SymbolAuthorListOptions struct {
	ListOptions
}

func (s *symbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	url, err := s.client.url(api_router.SymbolAuthors, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var authors []*AugmentedSymbolAuthor
	resp, err := s.client.Do(req, &authors)
	if err != nil {
		return nil, resp, err
	}

	return authors, resp, nil
}

type AugmentedSymbolClient struct {
	User *person.User
	*authorship.SymbolClient
}

type SymbolClientListOptions struct {
	ListOptions
}

func (s *symbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	url, err := s.client.url(api_router.SymbolClients, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var clients []*AugmentedSymbolClient
	resp, err := s.client.Do(req, &clients)
	if err != nil {
		return nil, resp, err
	}

	return clients, resp, nil
}

type AugmentedRepoRef struct {
	Repo  *repo.Repository
	Count int
}

type SymbolDependentRepositoryListOptions struct {
	ListOptions
}

func (s *symbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	url, err := s.client.url(api_router.SymbolDependents, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var dependents []*AugmentedRepoRef
	resp, err := s.client.Do(req, &dependents)
	if err != nil {
		return nil, resp, err
	}

	return dependents, resp, nil
}

type SymbolListImplementationsOptions struct {
	ListOptions
}

func (s *symbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolImplementations, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type SymbolListInterfacesOptions struct {
	ListOptions
}

func (s *symbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolInterfaces, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

func (s *symbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	url, err := s.client.url(api_router.RepositorySymbolCounts, map[string]string{"RepoURI": repo.URI}, nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var counts *graph.SymbolCounts
	resp, err := s.client.Do(req, &counts)
	if err != nil {
		return nil, resp, err
	}

	return counts, resp, nil
}

type MockSymbolsService struct {
	Get_                       func(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List_                      func(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples_              func(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors_               func(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients_               func(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories_ func(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations_       func(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces_            func(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository_         func(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

var _ SymbolsService = MockSymbolsService{}

func (s MockSymbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	if s.Get_ == nil {
		return nil, &Response{}, nil
	}
	return s.Get_(symbol, opt)
}

func (s MockSymbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	if s.List_ == nil {
		return nil, &Response{}, nil
	}
	return s.List_(opt)
}

func (s MockSymbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	if s.ListExamples_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListExamples_(symbol, opt)
}

func (s MockSymbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	if s.ListAuthors_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListAuthors_(symbol, opt)
}

func (s MockSymbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	if s.ListClients_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListClients_(symbol, opt)
}

func (s MockSymbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	if s.ListDependentRepositories_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListDependentRepositories_(symbol, opt)
}

func (s MockSymbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	if s.ListImplementations_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListImplementations_(symbol, opt)
}

func (s MockSymbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	if s.ListInterfaces_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListInterfaces_(symbol, opt)
}

func (s MockSymbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	if s.CountByRepository_ == nil {
		return &graph.SymbolCounts{}, &Response{}, nil
	}
	return s.CountByRepository_(repo)
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"net/http"
	"time"

	retryablehttp "github.com/hashicorp/go-retryablehttp"
)

// ClientOptionFunc can be used to customize a new GitLab API client.
type ClientOptionFunc func(*Client) error

// WithBaseURL sets the base URL for API requests to a custom endpoint.
func WithBaseURL(urlStr string) ClientOptionFunc {
	return func(c *Client) error {
		return c.setBaseURL(urlStr)
	}
}

// WithCustomBackoff can be used to configure a custom backoff policy.
func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Backoff = backoff
		return nil
	}
}

// WithCustomLeveledLogger can be used to configure a custom retryablehttp
// leveled logger.
func WithCustomLeveledLogger(leveledLogger retryablehttp.LeveledLogger) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Logger = leveledLogger
		return nil
	}
}

// WithCustomLimiter injects a custom rate limiter to the client.
func WithCustomLimiter(limiter RateLimiter) ClientOptionFunc {
	return func(c *Client) error {
		c.configureLimiterOnce.Do(func() {
			c.limiter = limiter
		})
		return nil
	}
}

// WithCustomLogger can be used to configure a custom retryablehttp logger.
func WithCustomLogger(logger retryablehttp.Logger) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Logger = logger
		return nil
	}
}

// WithCustomRetry can be used to configure a custom retry policy.
func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc {
	return func(c *Client) error {
		c.client.CheckRetry = checkRetry
		return nil
	}
}

// WithCustomRetryMax can be used to configure a custom maximum number of retries.
func WithCustomRetryMax(retryMax int) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RetryMax = retryMax
		return nil
	}
}

// WithCustomRetryWaitMinMax can be used to configure a custom maximum and minimum time to wait between retries.
func WithCustomRetryWaitMinMax(waitMin, waitMax time.Duration) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RetryWaitMin = waitMin
		c.client.RetryWaitMax = waitMax
		return nil
	}
}

// WithHTTPClient can be used to configure a custom HTTP client.
func WithHTTPClient(httpClient *http.Client) ClientOptionFunc {
	return func(c *Client) error {
		c.client.HTTPClient = httpClient
		return nil
	}
}

// WithRequestLogHook can be used to configure a custom request log hook.
func WithRequestLogHook(hook retryablehttp.RequestLogHook) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RequestLogHook = hook
		return nil
	}
}

// WithResponseLogHook can be used to configure a custom response log hook.
func WithResponseLogHook(hook retryablehttp.ResponseLogHook) ClientOptionFunc {
	return func(c *Client) error {
		c.client.ResponseLogHook = hook
		return nil
	}
}

// WithoutRetries disables the default retry logic.
func WithoutRetries() ClientOptionFunc {
	return func(c *Client) error {
		c.disableRetries = true
		return nil
	}
}
<commit_msg>Update client_options.go<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"net/http"
	"time"

	retryablehttp "github.com/hashicorp/go-retryablehttp"
)

// ClientOptionFunc can be used to customize a new GitLab API client.
type ClientOptionFunc func(*Client) error

// WithBaseURL sets the base URL for API requests to a custom endpoint.
func WithBaseURL(urlStr string) ClientOptionFunc {
	return func(c *Client) error {
		return c.setBaseURL(urlStr)
	}
}

// WithCustomBackoff can be used to configure a custom backoff policy.
func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Backoff = backoff
		return nil
	}
}

// WithCustomLeveledLogger can be used to configure a custom retryablehttp
// leveled logger.
func WithCustomLeveledLogger(leveledLogger retryablehttp.LeveledLogger) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Logger = leveledLogger
		return nil
	}
}

// WithCustomLimiter injects a custom rate limiter to the client.
func WithCustomLimiter(limiter RateLimiter) ClientOptionFunc {
	return func(c *Client) error {
		c.configureLimiterOnce.Do(func() {
			c.limiter = limiter
		})
		return nil
	}
}

// WithCustomLogger can be used to configure a custom retryablehttp logger.
func WithCustomLogger(logger retryablehttp.Logger) ClientOptionFunc {
	return func(c *Client) error {
		c.client.Logger = logger
		return nil
	}
}

// WithCustomRetry can be used to configure a custom retry policy.
func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc {
	return func(c *Client) error {
		c.client.CheckRetry = checkRetry
		return nil
	}
}

// WithCustomRetryMax can be used to configure a custom maximum number of retries.
func WithCustomRetryMax(retryMax int) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RetryMax = retryMax
		return nil
	}
}

// WithCustomRetryWaitMinMax can be used to configure a custom minimum and
// maximum time to wait between retries.
func WithCustomRetryWaitMinMax(waitMin, waitMax time.Duration) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RetryWaitMin = waitMin
		c.client.RetryWaitMax = waitMax
		return nil
	}
}

// WithHTTPClient can be used to configure a custom HTTP client.
func WithHTTPClient(httpClient *http.Client) ClientOptionFunc {
	return func(c *Client) error {
		c.client.HTTPClient = httpClient
		return nil
	}
}

// WithRequestLogHook can be used to configure a custom request log hook.
func WithRequestLogHook(hook retryablehttp.RequestLogHook) ClientOptionFunc {
	return func(c *Client) error {
		c.client.RequestLogHook = hook
		return nil
	}
}

// WithResponseLogHook can be used to configure a custom response log hook.
func WithResponseLogHook(hook retryablehttp.ResponseLogHook) ClientOptionFunc {
	return func(c *Client) error {
		c.client.ResponseLogHook = hook
		return nil
	}
}

// WithoutRetries disables the default retry logic.
func WithoutRetries() ClientOptionFunc {
	return func(c *Client) error {
		c.disableRetries = true
		return nil
	}
}
<|endoftext|>


<commit_before>package cluster

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"io"
)

func RandomJobID(prefix string) string { return prefix + randomID() }

func randomID() string {
	b := make([]byte, 16)
	enc := make([]byte, 24)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		panic(err) // This shouldn't ever happen, right?
	}
	base64.URLEncoding.Encode(enc, b)
	return string(bytes.TrimRight(enc, "="))
}
<commit_msg>pkg: Use UUIDv4 for random job ids<commit_after>package cluster

import (
	"crypto/rand"
	"encoding/hex"
	"io"
)

func RandomJobID(prefix string) string { return prefix + randomID() }

// generate a UUIDv4
func randomID() string {
	id := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, id)
	if err != nil {
		panic(err) // This shouldn't ever happen, right?
	}
	id[6] &= 0x0F // clear version
	id[6] |= 0x40 // set version to 4 (random uuid)
	id[8] &= 0x3F // clear variant
	id[8] |= 0x80 // set to IETF variant
	return hex.EncodeToString(id)
}
<|endoftext|>