<commit_before>package irc

import (
	//	"github.com/thoj/go-ircevent"
	"crypto/tls"
	"testing"
	"time"
)

func TestConnection(t *testing.T) {
	irccon1 := IRC("go-eventirc1", "go-eventirc1")
	irccon1.VerboseCallbackHandler = true
	irccon1.Debug = true
	irccon2 := IRC("go-eventirc2", "go-eventirc2")
	irccon2.VerboseCallbackHandler = true
	irccon2.Debug = true
	err := irccon1.Connect("irc.freenode.net:6667")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to freenode.")
	}
	err = irccon2.Connect("irc.freenode.net:6667")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to freenode.")
	}
	irccon1.AddCallback("001", func(e *Event) { irccon1.Join("#go-eventirc") })
	irccon2.AddCallback("001", func(e *Event) { irccon2.Join("#go-eventirc") })
	con2ok := false
	irccon1.AddCallback("366", func(e *Event) {
		t := time.NewTicker(1 * time.Second)
		i := 10
		for {
			<-t.C
			irccon1.Privmsgf("#go-eventirc", "Test Message%d\n", i)
			if con2ok {
				i -= 1
			}
			if i == 0 {
				t.Stop()
				irccon1.Quit()
			}
		}
	})

	irccon2.AddCallback("366", func(e *Event) {
		irccon2.Privmsg("#go-eventirc", "Test Message\n")
		con2ok = true
		irccon2.Nick("go-eventnewnick")
	})

	irccon2.AddCallback("PRIVMSG", func(e *Event) {
		t.Log(e.Message())
		if e.Message() == "Test Message5" {
			irccon2.Quit()
		}
	})

	irccon2.AddCallback("NICK", func(e *Event) {
		if irccon2.nickcurrent == "go-eventnewnick" {
			t.Fatal("Nick change did not work!")
		}
	})
	go irccon2.Loop()
	irccon1.Loop()
}

func TestConnectionSSL(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	err := irccon.Connect("irc.freenode.net:7000")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to freenode.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		time.Sleep(2 * time.Second)
		irccon.Quit()
	})

	irccon.Loop()
}

func TestConnectionEmtpyServer(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("")
	if err == nil {
		t.Fatal("emtpy server string not detected")
	}
}

func TestConnectionDoubleColon(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("::")
	if err == nil {
		t.Fatal("wrong number of ':' not detected")
	}
}

func TestConnectionMissingHost(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect(":6667")
	if err == nil {
		t.Fatal("missing host not detected")
	}
}

func TestConnectionMissingPort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("chat.freenode.net:")
	if err == nil {
		t.Fatal("missing port not detected")
	}
}

func TestConnectionNegativePort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("chat.freenode.net:-1")
	if err == nil {
		t.Fatal("negative port number not detected")
	}
}

func TestConnectionTooLargePort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("chat.freenode.net:65536")
	if err == nil {
		t.Fatal("too large port number not detected")
	}
}

func TestConnectionMissingLog(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.Log = nil
	err := irccon.Connect("chat.freenode.net:6667")
	if err == nil {
		t.Fatal("missing 'Log' not detected")
	}
}

func TestConnectionEmptyUser(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	// user may be changed after creation
	irccon.user = ""
	err := irccon.Connect("chat.freenode.net:6667")
	if err == nil {
		t.Fatal("empty 'user' not detected")
	}
}

func TestConnectionEmptyNick(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	// nick may be changed after creation
	irccon.nick = ""
	err := irccon.Connect("chat.freenode.net:6667")
	if err == nil {
		t.Fatal("empty 'nick' not detected")
	}
}

func TestRemoveCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	// Should remove callback at index 1
	irccon.RemoveCallback("TEST", id)

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 3) {
		t.Error("Callback 2 not removed")
	}
}

func TestWildcardCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.AddCallback("*", func(e *Event) { done <- 2 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 2) {
		t.Error("Wildcard callback not called")
	}
}

func TestClearCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 0 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.ClearCallback("TEST")
	irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 2 && results[1] == 3) {
		t.Error("Callbacks not cleared")
	}
}

func TestIRCemptyNick(t *testing.T) {
	irccon := IRC("", "go-eventirc")
	irccon = nil
	if irccon != nil {
		t.Error("empty nick didn't result in error")
		t.Fail()
	}
}

func TestIRCemptyUser(t *testing.T) {
	irccon := IRC("go-eventirc", "")
	if irccon != nil {
		t.Error("empty user didn't result in error")
	}
}
<commit_msg>Rebrand some more<commit_after>package irc

import (
	"crypto/tls"
	"testing"
	"time"
)

func TestConnection(t *testing.T) {
	irccon1 := IRC("go-eventirc1", "go-eventirc1")
	irccon1.VerboseCallbackHandler = true
	irccon1.Debug = true
	irccon2 := IRC("go-eventirc2", "go-eventirc2")
	irccon2.VerboseCallbackHandler = true
	irccon2.Debug = true
	err := irccon1.Connect("irc.yolo-swag.com:6667")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to ShadowNET.")
	}
	err = irccon2.Connect("irc.yolo-swag.com:6667")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to ShadowNET.")
	}
	irccon1.AddCallback("001", func(e *Event) { irccon1.Join("#go-eventirc") })
	irccon2.AddCallback("001", func(e *Event) { irccon2.Join("#go-eventirc") })
	con2ok := false
	irccon1.AddCallback("366", func(e *Event) {
		t := time.NewTicker(1 * time.Second)
		i := 10
		for {
			<-t.C
			irccon1.Privmsgf("#go-eventirc", "Test Message%d\n", i)
			if con2ok {
				i -= 1
			}
			if i == 0 {
				t.Stop()
				irccon1.Quit()
			}
		}
	})

	irccon2.AddCallback("366", func(e *Event) {
		irccon2.Privmsg("#go-eventirc", "Test Message\n")
		con2ok = true
		irccon2.Nick("go-eventnewnick")
	})

	irccon2.AddCallback("PRIVMSG", func(e *Event) {
		t.Log(e.Message())
		if e.Message() == "Test Message5" {
			irccon2.Quit()
		}
	})

	irccon2.AddCallback("NICK", func(e *Event) {
		if irccon2.nickcurrent == "go-eventnewnick" {
			t.Fatal("Nick change did not work!")
		}
	})
	go irccon2.Loop()
	irccon1.Loop()
}

func TestConnectionSSL(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	err := irccon.Connect("irc.yolo-swag.com:6697")
	if err != nil {
		t.Log(err.Error())
		t.Fatal("Can't connect to ShadowNET.")
	}
	irccon.AddCallback("001", func(e *Event) { irccon.Join("#go-eventirc") })

	irccon.AddCallback("366", func(e *Event) {
		irccon.Privmsg("#go-eventirc", "Test Message\n")
		time.Sleep(2 * time.Second)
		irccon.Quit()
	})

	irccon.Loop()
}

func TestConnectionEmtpyServer(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("")
	if err == nil {
		t.Fatal("emtpy server string not detected")
	}
}

func TestConnectionDoubleColon(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("::")
	if err == nil {
		t.Fatal("wrong number of ':' not detected")
	}
}

func TestConnectionMissingHost(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect(":6667")
	if err == nil {
		t.Fatal("missing host not detected")
	}
}

func TestConnectionMissingPort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("irc.yolo-swag.com:")
	if err == nil {
		t.Fatal("missing port not detected")
	}
}

func TestConnectionNegativePort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("irc.yolo-swag.com:-1")
	if err == nil {
		t.Fatal("negative port number not detected")
	}
}

func TestConnectionTooLargePort(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	err := irccon.Connect("irc.yolo-swag.com:65536")
	if err == nil {
		t.Fatal("too large port number not detected")
	}
}

func TestConnectionMissingLog(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.Log = nil
	err := irccon.Connect("irc.yolo-swag.com:6667")
	if err == nil {
		t.Fatal("missing 'Log' not detected")
	}
}

func TestConnectionEmptyUser(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	// user may be changed after creation
	irccon.user = ""
	err := irccon.Connect("irc.yolo-swag.com:6667")
	if err == nil {
		t.Fatal("empty 'user' not detected")
	}
}

func TestConnectionEmptyNick(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	// nick may be changed after creation
	irccon.nick = ""
	err := irccon.Connect("irc.yolo-swag.com:6667")
	if err == nil {
		t.Fatal("empty 'nick' not detected")
	}
}

func TestRemoveCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	id := irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	// Should remove callback at index 1
	irccon.RemoveCallback("TEST", id)

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 3) {
		t.Error("Callback 2 not removed")
	}
}

func TestWildcardCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.AddCallback("*", func(e *Event) { done <- 2 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 1 && results[1] == 2) {
		t.Error("Wildcard callback not called")
	}
}

func TestClearCallback(t *testing.T) {
	irccon := IRC("go-eventirc", "go-eventirc")
	irccon.VerboseCallbackHandler = true
	irccon.Debug = true

	done := make(chan int, 10)

	irccon.AddCallback("TEST", func(e *Event) { done <- 0 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 1 })
	irccon.ClearCallback("TEST")
	irccon.AddCallback("TEST", func(e *Event) { done <- 2 })
	irccon.AddCallback("TEST", func(e *Event) { done <- 3 })

	irccon.RunCallbacks(&Event{
		Code: "TEST",
	})

	var results []int

	results = append(results, <-done)
	results = append(results, <-done)

	if len(results) != 2 || !(results[0] == 2 && results[1] == 3) {
		t.Error("Callbacks not cleared")
	}
}

func TestIRCemptyNick(t *testing.T) {
	irccon := IRC("", "go-eventirc")
	irccon = nil
	if irccon != nil {
		t.Error("empty nick didn't result in error")
		t.Fail()
	}
}

func TestIRCemptyUser(t *testing.T) {
	irccon := IRC("go-eventirc", "")
	if irccon != nil {
		t.Error("empty user didn't result in error")
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

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

	"launchpad.net/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/utils"
)

var logger = loggo.GetLogger("juju.environs.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var provider environProvider

func init() {
	environs.RegisterProvider("local", &environProvider{})
}

var (
	defaultRootDir = "/var/lib/juju/"
)

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	environ := &localEnviron{name: cfg.Name()}
	err := environ.SetConfig(cfg)
	if err != nil {
		logger.Errorf("failure setting config: %v", err)
		return nil, err
	}
	return environ, nil
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil)
	if err != nil {
		return nil, err
	}
	localConfig := newEnvironConfig(cfg, v.(map[string]interface{}))
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
	}
	dir := utils.NormalizePath(localConfig.rootDir())
	if dir == "." {
		dir = filepath.Join(defaultRootDir, localConfig.namespace())
		localConfig.attrs["root-dir"] = dir
	}
	logger.Tracef("ensure root dir %s exists", dir)
	if err := os.MkdirAll(dir, 0755); err != nil {
		logger.Errorf("failed to make directory for shared storage at %s: %v", dir, err)
		return nil, err
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
## https://juju.ubuntu.com/get-started/local/
local:
  type: local
  # Override the directory that is used for the storage files and mongo database.
  # The default location is /var/lib/juju/<USER>-<ENV>
  # root-dir: ~/.juju/local

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]interface{}, error) {
	// don't have any secret attrs
	return nil, nil
}

// Location specific methods that are able to be called by any instance that
// has been created by this provider type.  So a machine agent may well call
// these methods to find out its own address or instance id.

// PublicAddress implements environs.EnvironProvider.PublicAddress.
func (environProvider) PublicAddress() (string, error) {
	return "", fmt.Errorf("not implemented")
}

// PrivateAddress implements environs.EnvironProvider.PrivateAddress.
func (environProvider) PrivateAddress() (string, error) {
	return "", fmt.Errorf("not implemented")
}

// InstanceId implements environs.EnvironProvider.InstanceId.
func (environProvider) InstanceId() (instance.Id, error) {
	return "", fmt.Errorf("not implemented")
}

func (environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := provider.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<commit_msg>Don't make the directories during the creation of the config.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"path/filepath"

	"launchpad.net/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/utils"
)

var logger = loggo.GetLogger("juju.environs.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var provider environProvider

func init() {
	environs.RegisterProvider("local", &environProvider{})
}

var (
	defaultRootDir = "/var/lib/juju/"
)

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	environ := &localEnviron{name: cfg.Name()}
	err := environ.SetConfig(cfg)
	if err != nil {
		logger.Errorf("failure setting config: %v", err)
		return nil, err
	}
	return environ, nil
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil)
	if err != nil {
		return nil, err
	}
	localConfig := newEnvironConfig(cfg, v.(map[string]interface{}))
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
	}
	dir := utils.NormalizePath(localConfig.rootDir())
	if dir == "." {
		dir = filepath.Join(defaultRootDir, localConfig.namespace())
		localConfig.attrs["root-dir"] = dir
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
## https://juju.ubuntu.com/get-started/local/
local:
  type: local
  # Override the directory that is used for the storage files and mongo database.
  # The default location is /var/lib/juju/<USER>-<ENV>
  # root-dir: ~/.juju/local

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]interface{}, error) {
	// don't have any secret attrs
	return nil, nil
}

// Location specific methods that are able to be called by any instance that
// has been created by this provider type.  So a machine agent may well call
// these methods to find out its own address or instance id.

// PublicAddress implements environs.EnvironProvider.PublicAddress.
func (environProvider) PublicAddress() (string, error) {
	return "", fmt.Errorf("not implemented")
}

// PrivateAddress implements environs.EnvironProvider.PrivateAddress.
func (environProvider) PrivateAddress() (string, error) {
	return "", fmt.Errorf("not implemented")
}

// InstanceId implements environs.EnvironProvider.InstanceId.
func (environProvider) InstanceId() (instance.Id, error) {
	return "", fmt.Errorf("not implemented")
}

func (environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := provider.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<|endoftext|>


<commit_before>package irma

import (
	"math/big"
	"strings"
	"time"
)

// CredentialInfo contains all information of an IRMA credential.
type CredentialInfo struct {
	CredentialTypeID CredentialTypeIdentifier // e.g., "irma-demo.RU.studentCard"
	Name             string                   // e.g., "studentCard"
	IssuerID         IssuerIdentifier         // e.g., "RU"
	SchemeManagerID  SchemeManagerIdentifier  // e.g., "irma-demo"
	Index            int                      // This is the Index-th credential instance of this type
	SignedOn         Timestamp                // Unix timestamp
	Expires          Timestamp                // Unix timestamp
	Attributes       []TranslatedString       // Human-readable rendered attributes
	Logo             string                   // Path to logo on storage
	Hash             string                   // SHA256 hash over the attributes
}

// A CredentialInfoList is a list of credentials (implements sort.Interface).
type CredentialInfoList []*CredentialInfo

func NewCredentialInfo(ints []*big.Int, conf *Configuration) *CredentialInfo {
	meta := MetadataFromInt(ints[0], conf)
	credtype := meta.CredentialType()
	if credtype == nil {
		return nil
	}

	attrs := NewAttributeListFromInts(ints, conf)
	id := credtype.Identifier()
	issid := id.IssuerIdentifier()
	return &CredentialInfo{
		CredentialTypeID: NewCredentialTypeIdentifier(id.String()),
		Name:             id.Name(),
		IssuerID:         NewIssuerIdentifier(issid.Name()),
		SchemeManagerID:  NewSchemeManagerIdentifier(issid.SchemeManagerIdentifier().String()),
		SignedOn:         Timestamp(meta.SigningDate()),
		Expires:          Timestamp(meta.Expiry()),
		Attributes:       attrs.Strings(),
		Logo:             credtype.Logo(conf),
		Hash:             attrs.Hash(),
	}
}

func (ci CredentialInfo) GetCredentialType(conf *Configuration) *CredentialType {
	return conf.CredentialTypes[ci.CredentialTypeID]
}

// Returns true if credential is expired at moment of calling this function
func (ci CredentialInfo) IsExpired() bool {
	return ci.Expires.Before(Timestamp(time.Now()))
}

// Len implements sort.Interface.
func (cl CredentialInfoList) Len() int {
	return len(cl)
}

// Swap implements sort.Interface.
func (cl CredentialInfoList) Swap(i, j int) {
	cl[i], cl[j] = cl[j], cl[i]
}

// Less implements sort.Interface.
func (cl CredentialInfoList) Less(i, j int) bool {
	// TODO Decide on sorting, and if it depends on a irmago.TranslatedString, allow language choosing
	return strings.Compare(cl[i].Name, cl[j].Name) > 0
}
<commit_msg>Make CredentialInfo field names more consistent<commit_after>package irma

import (
	"math/big"
	"strings"
	"time"
)

// CredentialInfo contains all information of an IRMA credential.
type CredentialInfo struct {
	ID               string                   // e.g., "studentCard"
	CredentialTypeID CredentialTypeIdentifier // e.g., "irma-demo.RU.studentCard"
	IssuerID         IssuerIdentifier         // e.g., "irma-demo.RU"
	SchemeManagerID  SchemeManagerIdentifier  // e.g., "irma-demo"
	Index            int                      // This is the Index-th credential instance of this type
	SignedOn         Timestamp                // Unix timestamp
	Expires          Timestamp                // Unix timestamp
	Attributes       []TranslatedString       // Human-readable rendered attributes
	Logo             string                   // Path to logo on storage
	Hash             string                   // SHA256 hash over the attributes
}

// A CredentialInfoList is a list of credentials (implements sort.Interface).
type CredentialInfoList []*CredentialInfo

func NewCredentialInfo(ints []*big.Int, conf *Configuration) *CredentialInfo {
	meta := MetadataFromInt(ints[0], conf)
	credtype := meta.CredentialType()
	if credtype == nil {
		return nil
	}

	attrs := NewAttributeListFromInts(ints, conf)
	id := credtype.Identifier()
	issid := id.IssuerIdentifier()
	return &CredentialInfo{
		CredentialTypeID: NewCredentialTypeIdentifier(id.String()),
		ID:               id.Name(),
		IssuerID:         issid,
		SchemeManagerID:  issid.SchemeManagerIdentifier(),
		SignedOn:         Timestamp(meta.SigningDate()),
		Expires:          Timestamp(meta.Expiry()),
		Attributes:       attrs.Strings(),
		Logo:             credtype.Logo(conf),
		Hash:             attrs.Hash(),
	}
}

func (ci CredentialInfo) GetCredentialType(conf *Configuration) *CredentialType {
	return conf.CredentialTypes[ci.CredentialTypeID]
}

// Returns true if credential is expired at moment of calling this function
func (ci CredentialInfo) IsExpired() bool {
	return ci.Expires.Before(Timestamp(time.Now()))
}

// Len implements sort.Interface.
func (cl CredentialInfoList) Len() int {
	return len(cl)
}

// Swap implements sort.Interface.
func (cl CredentialInfoList) Swap(i, j int) {
	cl[i], cl[j] = cl[j], cl[i]
}

// Less implements sort.Interface.
func (cl CredentialInfoList) Less(i, j int) bool {
	// TODO Decide on sorting, and if it depends on a irmago.TranslatedString, allow language choosing
	return strings.Compare(cl[i].ID, cl[j].ID) > 0
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"strconv"
	"strings"
	"time"
)

var (
	twitterBot *TwitterBot
)

// TwitterBot ...
type TwitterBot struct {
	ID      string
	ImgPath string
	Client  *twitter.Client
	Follows map[string]string
}

// NewTwitterBot ...
func NewTwitterBot(cfg *TwitterConfig) *TwitterBot {
	config := oauth1.NewConfig(cfg.ConsumerKey, cfg.ConsumerSecret)
	token := oauth1.NewToken(cfg.AccessToken, cfg.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)
	bot := &TwitterBot{
		ID:      cfg.SelfID,
		ImgPath: cfg.ImgPath,
		Client:  client,
		Follows: map[string]string{
			"KanColle_STAFF": "294025417",
			"komatan":        "96604067",
			"maesanpicture":  "2381595966",
			"Strangestone":   "93332575",
			"kazuharukina":   "28787294",
		},
	}
	return bot
}

func hasHashTags(s string, tags []twitter.HashtagEntity) bool {
	for _, tag := range tags {
		if s == tag.Text {
			return true
		}
	}
	return false
}

func getMedias(tweet *twitter.Tweet) []twitter.MediaEntity {
	if tweet.Truncated {
		return tweet.ExtendedEntities.Media
	}
	return tweet.Entities.Media
}

func sendPics(medias []twitter.MediaEntity) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			go qqBot.SendPics(qqBot.SendGroupMsg, media.MediaURLHttps)
		}
	}
}

func logAllTrack(msg interface{}) {
	logger.Debug(msg)
}

func (t *TwitterBot) trackTweet(tweet *twitter.Tweet) {
	if tweet.RetweetedStatus != nil {
		// logger.Debugf("ignore retweet (%s):{%s}", tweet.User.Name, tweet.Text)
		return
	}
	msg := tweet.Text
	if tweet.Truncated {
		if tweet.ExtendedTweet != nil {
			msg = tweet.ExtendedTweet.FullText
		}
		logger.Debugf("no ExtendedTweet: %+v", tweet)
	}
	flattenedText := strconv.Quote(msg)

	medias := getMedias(tweet)
	switch tweet.User.IDStr {
	case t.Follows["KanColle_STAFF"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))

		err := redisClient.Get("forward_kancolle").Err()
		if err != nil {
			sendPics(medias)
			return
		}

		t := tweet.CreatedAt
		ct, err := tweet.CreatedAtTime()
		if err == nil {
			tz, err := time.LoadLocation("Asia/Tokyo")
			if err == nil {
				t = ct.In(tz).String()
			}
		}
		qqBot.SendGroupMsg(tweet.User.Name + "\n" + t + "\n\n" + msg)

	case t.Follows["komatan"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		sendPics(medias)

	case t.Follows["maesanpicture"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("毎日五月雨", tweet.Entities.Hashtags) {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	case t.Follows["Strangestone"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if strings.HasPrefix(msg, "月曜日のたわわ") {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	case t.Follows["kazuharukina"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("和遥キナ毎日JK企画", tweet.Entities.Hashtags) {
			sendPics(medias)
		}

	default:
		// logger.Debugf("(%s):{%s}", tweet.User.Name, flattenedText)
	}
}

func (t *TwitterBot) selfProceedPics(medias []twitter.MediaEntity, action int) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			switch action {
			case 1:
				downloadFile(media.MediaURLHttps, t.ImgPath)
				go qqBot.SendPics(qqBot.SendSelfMsg, media.MediaURLHttps)
			case -1:
				removeFile(media.MediaURLHttps, t.ImgPath)
			}
		}
	}
}

func (t *TwitterBot) selfEvent(event *twitter.Event) {
	if event.Source.IDStr != t.ID {
		logger.Debugf("%s: (%s)", event.Event, event.Source.Name)
		return
	}
	switch event.Event {
	case "favorite":
		medias := getMedias(event.TargetObject)
		logger.Infof("favorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedPics(medias, 1)
	case "unfavorite":
		medias := getMedias(event.TargetObject)
		logger.Debugf("unfavorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedPics(medias, -1)
	default:
		logger.Debug(event.Event)
	}
}

func (t *TwitterBot) selfTweet(tweet *twitter.Tweet) {
	if qqBot.Config.GroupName != "" {
		if hasHashTags(qqBot.Config.GroupName, tweet.Entities.Hashtags) {
			if tweet.QuotedStatus != nil {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.QuotedStatus.Text))
				sendPics(getMedias(tweet.QuotedStatus))
			} else {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.Text))
				sendPics(getMedias(tweet))
			}
		}
	}
}

// Track ...
func (t *TwitterBot) Track() {
	follows := []string{}
	for _, value := range t.Follows {
		follows = append(follows, value)
	}
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Tweet = t.trackTweet
		filterParams := &twitter.StreamFilterParams{
			Follow: follows,
		}
		stream, err := t.Client.Streams.Filter(filterParams)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}

// Self ...
func (t *TwitterBot) Self() {
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Event = t.selfEvent
		demux.Tweet = t.selfTweet
		userParams := &twitter.StreamUserParams{
			With: t.ID,
		}
		stream, err := t.Client.Streams.User(userParams)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}
<commit_msg>git media from extendedtweet if truncated<commit_after>package main

import (
	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"strconv"
	"strings"
	"time"
)

var (
	twitterBot *TwitterBot
)

// TwitterBot ...
type TwitterBot struct {
	ID      string
	ImgPath string
	Client  *twitter.Client
	Follows map[string]string
}

// NewTwitterBot ...
func NewTwitterBot(cfg *TwitterConfig) *TwitterBot {
	config := oauth1.NewConfig(cfg.ConsumerKey, cfg.ConsumerSecret)
	token := oauth1.NewToken(cfg.AccessToken, cfg.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)
	bot := &TwitterBot{
		ID:      cfg.SelfID,
		ImgPath: cfg.ImgPath,
		Client:  client,
		Follows: map[string]string{
			"KanColle_STAFF": "294025417",
			"komatan":        "96604067",
			"maesanpicture":  "2381595966",
			"Strangestone":   "93332575",
			"kazuharukina":   "28787294",
		},
	}
	return bot
}

func hasHashTags(s string, tags []twitter.HashtagEntity) bool {
	for _, tag := range tags {
		if s == tag.Text {
			return true
		}
	}
	return false
}

func getMedias(tweet *twitter.Tweet) []twitter.MediaEntity {
	if tweet.ExtendedEntities != nil {
		return tweet.ExtendedEntities.Media
	}
	return tweet.Entities.Media
}

func sendPics(medias []twitter.MediaEntity) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			go qqBot.SendPics(qqBot.SendGroupMsg, media.MediaURLHttps)
		}
	}
}

func logAllTrack(msg interface{}) {
	logger.Debug(msg)
}

func (t *TwitterBot) trackTweet(tweet *twitter.Tweet) {
	if tweet.RetweetedStatus != nil {
		// logger.Debugf("ignore retweet (%s):{%s}", tweet.User.Name, tweet.Text)
		return
	}
	msg := tweet.Text
	medias := getMedias(tweet)
	if tweet.Truncated {
		if tweet.ExtendedTweet != nil {
			msg = tweet.ExtendedTweet.FullText
			medias := getMedias(tweet.ExtendedTweet)
		}
		logger.Debugf("no ExtendedTweet: %+v", tweet)
	}
	flattenedText := strconv.Quote(msg)

	switch tweet.User.IDStr {
	case t.Follows["KanColle_STAFF"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))

		err := redisClient.Get("forward_kancolle").Err()
		if err != nil {
			sendPics(medias)
			return
		}

		t := tweet.CreatedAt
		ct, err := tweet.CreatedAtTime()
		if err == nil {
			tz, err := time.LoadLocation("Asia/Tokyo")
			if err == nil {
				t = ct.In(tz).String()
			}
		}
		qqBot.SendGroupMsg(tweet.User.Name + "\n" + t + "\n\n" + msg)

	case t.Follows["komatan"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		sendPics(medias)

	case t.Follows["maesanpicture"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("毎日五月雨", tweet.Entities.Hashtags) {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	case t.Follows["Strangestone"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if strings.HasPrefix(msg, "月曜日のたわわ") {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	case t.Follows["kazuharukina"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("和遥キナ毎日JK企画", tweet.Entities.Hashtags) {
			sendPics(medias)
		}

	default:
		// logger.Debugf("(%s):{%s}", tweet.User.Name, flattenedText)
	}
}

func (t *TwitterBot) selfProceedPics(medias []twitter.MediaEntity, action int) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			switch action {
			case 1:
				downloadFile(media.MediaURLHttps, t.ImgPath)
				go qqBot.SendPics(qqBot.SendSelfMsg, media.MediaURLHttps)
			case -1:
				removeFile(media.MediaURLHttps, t.ImgPath)
			}
		}
	}
}

func (t *TwitterBot) selfEvent(event *twitter.Event) {
	if event.Source.IDStr != t.ID {
		logger.Debugf("%s: (%s)", event.Event, event.Source.Name)
		return
	}
	switch event.Event {
	case "favorite":
		medias := getMedias(event.TargetObject)
		logger.Infof("favorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedPics(medias, 1)
	case "unfavorite":
		medias := getMedias(event.TargetObject)
		logger.Debugf("unfavorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedPics(medias, -1)
	default:
		logger.Debug(event.Event)
	}
}

func (t *TwitterBot) selfTweet(tweet *twitter.Tweet) {
	if qqBot.Config.GroupName != "" {
		if hasHashTags(qqBot.Config.GroupName, tweet.Entities.Hashtags) {
			if tweet.QuotedStatus != nil {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.QuotedStatus.Text))
				sendPics(getMedias(tweet.QuotedStatus))
			} else {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.Text))
				sendPics(getMedias(tweet))
			}
		}
	}
}

// Track ...
func (t *TwitterBot) Track() {
	follows := []string{}
	for _, value := range t.Follows {
		follows = append(follows, value)
	}
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Tweet = t.trackTweet
		filterParams := &twitter.StreamFilterParams{
			Follow: follows,
		}
		stream, err := t.Client.Streams.Filter(filterParams)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}

// Self ...
func (t *TwitterBot) Self() {
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Event = t.selfEvent
		demux.Tweet = t.selfTweet
		userParams := &twitter.StreamUserParams{
			With: t.ID,
		}
		stream, err := t.Client.Streams.User(userParams)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}
<|endoftext|>


<commit_before>package estafette

import (
	"sync"

	"github.com/estafette/estafette-ci-api/cockroach"
	"github.com/rs/zerolog/log"
)

// EventWorker processes events pushed to channels
type EventWorker interface {
	ListenToEventChannels()
	RemoveJobForEstafetteBuild(CiBuilderEvent)
	InsertLogs(cockroach.BuildJobLogs)
}

type eventWorkerImpl struct {
	waitGroup              *sync.WaitGroup
	stopChannel            <-chan struct{}
	ciBuilderClient        CiBuilderClient
	cockroachDBClient      cockroach.DBClient
	ciBuilderEventsChannel chan CiBuilderEvent
	buildJobLogsChannel    chan cockroach.BuildJobLogs
}

// NewEstafetteEventWorker returns a new estafette.EventWorker
func NewEstafetteEventWorker(stopChannel <-chan struct{}, waitGroup *sync.WaitGroup, ciBuilderClient CiBuilderClient, cockroachDBClient cockroach.DBClient, ciBuilderEventsChannel chan CiBuilderEvent, buildJobLogsChannel chan cockroach.BuildJobLogs) EventWorker {
	return &eventWorkerImpl{
		waitGroup:              waitGroup,
		stopChannel:            stopChannel,
		ciBuilderClient:        ciBuilderClient,
		cockroachDBClient:      cockroachDBClient,
		ciBuilderEventsChannel: ciBuilderEventsChannel,
		buildJobLogsChannel:    buildJobLogsChannel,
	}
}

func (w *eventWorkerImpl) ListenToEventChannels() {
	go func() {
		// handle estafette events via channels
		log.Debug().Msg("Listening to Estafette events channels...")
		for {
			select {
			case ciBuilderEvent := <-w.ciBuilderEventsChannel:
				go func() {
					w.waitGroup.Add(1)
					w.RemoveJobForEstafetteBuild(ciBuilderEvent)
					w.waitGroup.Done()
				}()
			case buildJobLogs := <-w.buildJobLogsChannel:
				go func() {
					w.waitGroup.Add(1)
					w.InsertLogs(buildJobLogs)
					w.waitGroup.Done()
				}()
			case <-w.stopChannel:
				log.Debug().Msg("Stopping Estafette event worker...")
				return
			}
		}
	}()
}

func (w *eventWorkerImpl) RemoveJobForEstafetteBuild(ciBuilderEvent CiBuilderEvent) {

	// create ci builder job
	err := w.ciBuilderClient.RemoveCiBuilderJob(ciBuilderEvent.JobName)
	if err != nil {
		log.Error().Err(err).
			Str("jobName", ciBuilderEvent.JobName).
			Msgf("Removing ci-builder job %v failed", ciBuilderEvent.JobName)

		return
	}

	log.Info().
		Str("jobName", ciBuilderEvent.JobName).
		Msgf("Removed ci-builder job %v", ciBuilderEvent.JobName)
}

func (w *eventWorkerImpl) InsertLogs(buildJobLogs cockroach.BuildJobLogs) {

	err := w.cockroachDBClient.InsertBuildJobLogs(buildJobLogs)
	if err != nil {
		log.Error().Err(err).
			Interface("buildJobLogs", buildJobLogs).
			Msgf("Inserting logs for %v failed", buildJobLogs.RepoFullName)

		return
	}

	log.Info().
		Str("repoFullName", buildJobLogs.RepoFullName).
		Msgf("Inserted logs for %v", buildJobLogs.RepoFullName)
}
<commit_msg>log full buildjoblogs object<commit_after>package estafette

import (
	"sync"

	"github.com/estafette/estafette-ci-api/cockroach"
	"github.com/rs/zerolog/log"
)

// EventWorker processes events pushed to channels
type EventWorker interface {
	ListenToEventChannels()
	RemoveJobForEstafetteBuild(CiBuilderEvent)
	InsertLogs(cockroach.BuildJobLogs)
}

type eventWorkerImpl struct {
	waitGroup              *sync.WaitGroup
	stopChannel            <-chan struct{}
	ciBuilderClient        CiBuilderClient
	cockroachDBClient      cockroach.DBClient
	ciBuilderEventsChannel chan CiBuilderEvent
	buildJobLogsChannel    chan cockroach.BuildJobLogs
}

// NewEstafetteEventWorker returns a new estafette.EventWorker
func NewEstafetteEventWorker(stopChannel <-chan struct{}, waitGroup *sync.WaitGroup, ciBuilderClient CiBuilderClient, cockroachDBClient cockroach.DBClient, ciBuilderEventsChannel chan CiBuilderEvent, buildJobLogsChannel chan cockroach.BuildJobLogs) EventWorker {
	return &eventWorkerImpl{
		waitGroup:              waitGroup,
		stopChannel:            stopChannel,
		ciBuilderClient:        ciBuilderClient,
		cockroachDBClient:      cockroachDBClient,
		ciBuilderEventsChannel: ciBuilderEventsChannel,
		buildJobLogsChannel:    buildJobLogsChannel,
	}
}

func (w *eventWorkerImpl) ListenToEventChannels() {
	go func() {
		// handle estafette events via channels
		log.Debug().Msg("Listening to Estafette events channels...")
		for {
			select {
			case ciBuilderEvent := <-w.ciBuilderEventsChannel:
				go func() {
					w.waitGroup.Add(1)
					w.RemoveJobForEstafetteBuild(ciBuilderEvent)
					w.waitGroup.Done()
				}()
			case buildJobLogs := <-w.buildJobLogsChannel:
				go func() {
					w.waitGroup.Add(1)
					w.InsertLogs(buildJobLogs)
					w.waitGroup.Done()
				}()
			case <-w.stopChannel:
				log.Debug().Msg("Stopping Estafette event worker...")
				return
			}
		}
	}()
}

func (w *eventWorkerImpl) RemoveJobForEstafetteBuild(ciBuilderEvent CiBuilderEvent) {

	// create ci builder job
	err := w.ciBuilderClient.RemoveCiBuilderJob(ciBuilderEvent.JobName)
	if err != nil {
		log.Error().Err(err).
			Str("jobName", ciBuilderEvent.JobName).
			Msgf("Removing ci-builder job %v failed", ciBuilderEvent.JobName)

		return
	}

	log.Info().
		Str("jobName", ciBuilderEvent.JobName).
		Msgf("Removed ci-builder job %v", ciBuilderEvent.JobName)
}

func (w *eventWorkerImpl) InsertLogs(buildJobLogs cockroach.BuildJobLogs) {

	err := w.cockroachDBClient.InsertBuildJobLogs(buildJobLogs)
	if err != nil {
		log.Error().Err(err).
			Interface("buildJobLogs", buildJobLogs).
			Msgf("Inserting logs for %v failed", buildJobLogs.RepoFullName)

		return
	}

	log.Info().
		Interface("buildJobLogs", buildJobLogs).
		Msgf("Inserted logs for %v", buildJobLogs.RepoFullName)
}
<|endoftext|>


<commit_before>package google

import (
	"encoding/json"
	"fmt"
	"github.com/go-errors/errors"
	"golang.org/x/oauth2"
	gauth "golang.org/x/oauth2/google"
	. "github.com/ory-am/hydra/oauth/provider"
	"net/http"
)

type google struct {
	id   string
	api  string
	conf *oauth2.Config
}

func New(id, client, secret, redirectURL string) *google {
	return &google{
		id:  id,
		api: "https://www.googleapis.com",
		conf: &oauth2.Config{
			ClientID:     client,
			ClientSecret: secret,
			Scopes: []string{
				"email",
				"profile",
				"https://www.googleapis.com/auth/plus.login",
				"https://www.googleapis.com/auth/plus.me",
			},
			RedirectURL: redirectURL,
			Endpoint:    gauth.Endpoint,
		},
	}
}

func (d *google) GetAuthenticationURL(state string) string {
	return d.conf.AuthCodeURL(state)
}

func (d *google) FetchSession(code string) (Session, error) {
	conf := *d.conf
	token, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		return nil, err
	}

	if !token.Valid() {
		return nil, errors.Errorf("Token is not valid: %v", token)
	}

	c := conf.Client(oauth2.NoContext, token)
	req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", d.api, "plus/v1/people/me"), nil)
	resp, err := c.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("Could not fetch account data because %s", err)
	}

	var profile map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&profile); err != nil {
		return nil, errors.Errorf("Could not validate id token because %s", err)
	}

	return &DefaultSession{
		RemoteSubject: fmt.Sprintf("%s", profile["id"]),
		Extra:         profile,
	}, nil
}

func (d *google) GetID() string {
	return d.id
}
<commit_msg>oauth/google: fixed status code error message<commit_after>package google

import (
	"encoding/json"
	"fmt"
	"github.com/go-errors/errors"
	"golang.org/x/oauth2"
	gauth "golang.org/x/oauth2/google"
	. "github.com/ory-am/hydra/oauth/provider"
	"net/http"
)

type google struct {
	id   string
	api  string
	conf *oauth2.Config
}

func New(id, client, secret, redirectURL string) *google {
	return &google{
		id:  id,
		api: "https://www.googleapis.com",
		conf: &oauth2.Config{
			ClientID:     client,
			ClientSecret: secret,
			Scopes: []string{
				"email",
				"profile",
				"https://www.googleapis.com/auth/plus.login",
				"https://www.googleapis.com/auth/plus.me",
			},
			RedirectURL: redirectURL,
			Endpoint:    gauth.Endpoint,
		},
	}
}

func (d *google) GetAuthenticationURL(state string) string {
	return d.conf.AuthCodeURL(state)
}

func (d *google) FetchSession(code string) (Session, error) {
	conf := *d.conf
	token, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		return nil, err
	}

	if !token.Valid() {
		return nil, errors.Errorf("Token is not valid: %v", token)
	}

	c := conf.Client(oauth2.NoContext, token)
	req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", d.api, "plus/v1/people/me"), nil)
	resp, err := c.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("Could not fetch account data because got status code %d", resp.StatusCode)
	}

	var profile map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&profile); err != nil {
		return nil, errors.Errorf("Could not validate id token because %s", err)
	}

	return &DefaultSession{
		RemoteSubject: fmt.Sprintf("%s", profile["id"]),
		Extra:         profile,
	}, nil
}

func (d *google) GetID() string {
	return d.id
}
<|endoftext|>


<commit_before>// Copyright © 2016 See CONTRIBUTORS <ignasi.fosch@gmail.com>
//
// 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 reviewer

import (
	reviewer "."

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

// token contains the GH token.
var token = "GITHUB_USERS_TOKEN"

// mockChangesService is a mock for github.PullRequestsService.
type mockChangesService struct {
	listPullRequests []github.PullRequest
}

// newMockChangesService creates a new ChangesService implementation.
func newMockChangesService(listPR []github.PullRequest) *mockChangesService {
	return &mockChangesService{
		listPullRequests: listPR,
	}
}

// mockChangesService's List implementation.
func (m *mockChangesService) List(owner string, repo string, opt *github.PullRequestListOptions) ([]github.PullRequest, *github.Response, error) {
	return m.listPullRequests, nil, nil
}

// mockTicketsService is a mock for github.PullRequestsService.
type mockTicketsService struct {}

// newMockTicketsService creates a new TicketsService implementation.
func newMockTicketsService() *mockTicketsService {
	return &mockTicketsService{}
}

// mockTicketsService's List implementation.
func (m *mockTicketsService) ListComments(owner string, repo string, number int, opt *github.IssueListCommentsOptions) ([]github.IssueComment, *github.Response, error) {
	return nil, nil, nil
}

// Constructor for mockGHClient.
func newMockGHClient(listPR []github.PullRequest) *reviewer.GHClient {
	client := &reviewer.GHClient{}
	client.Changes = newMockChangesService(listPR)
	client.Tickets = newMockTicketsService()
	return client
}

func mockGetString(k string) string {
	if k == "authorization.token" {
		return token
	}
	return ""
}

func TestGetGHAuth(t *testing.T) {
	reviewer.GetString = mockGetString

	var result interface{}
	var errClient error
	result, errClient = reviewer.GetClient()

	if errClient != nil {
		t.Fatalf("GetClient returned error(%s) when everything was ok", errClient)
	}
	v, err := result.(reviewer.GHClient)
	if err {
		t.Fatalf("GetClient returned %s instead of github.Client", reflect.TypeOf(v))
	}
}

func TestCommentSuccessScore(t *testing.T) {

	testScore := func(comment string, expected int) {
		score := getCommentSuccessScore(comment)
		if expected != score {
			t.Fatalf("Bad score %v (expected %v) for comment %v", score, expected, comment)
		}
	}

	testScore("Don't do it", 0)
	testScore("Yes +1", 1)
	testScore(":+1", 1)
	testScore("-1", -1)
	testScore("Oops +1 :-1: +1", 0)
}

func TestGetPullRequestsInfo(t *testing.T) {
	emptyListPR := make([]github.PullRequest, 0)
	client := newMockGHClient(emptyListPR)

	var result []reviewer.PullRequestInfo
	var err error
	result, err = reviewer.GetPullRequestInfos(client, "user", "repo")

	if err != nil {
		t.Fatalf("Something went wrong when getting PR information")
	}
	if len(result) != 0 {
		t.Fatal("Got an empty list of PRInfos")
	}
}
<commit_msg>Fixes declaration of empty PullRequest list in test<commit_after>// Copyright © 2016 See CONTRIBUTORS <ignasi.fosch@gmail.com>
//
// 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 reviewer

import (
	reviewer "."

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

// token contains the GH token.
var token = "GITHUB_USERS_TOKEN"

// mockChangesService is a mock for github.PullRequestsService.
type mockChangesService struct {
	listPullRequests []github.PullRequest
}

// newMockChangesService creates a new ChangesService implementation.
func newMockChangesService(listPR []github.PullRequest) *mockChangesService {
	return &mockChangesService{
		listPullRequests: listPR,
	}
}

// mockChangesService's List implementation.
func (m *mockChangesService) List(owner string, repo string, opt *github.PullRequestListOptions) ([]github.PullRequest, *github.Response, error) {
	return m.listPullRequests, nil, nil
}

// mockTicketsService is a mock for github.PullRequestsService.
type mockTicketsService struct {}

// newMockTicketsService creates a new TicketsService implementation.
func newMockTicketsService() *mockTicketsService {
	return &mockTicketsService{}
}

// mockTicketsService's List implementation.
func (m *mockTicketsService) ListComments(owner string, repo string, number int, opt *github.IssueListCommentsOptions) ([]github.IssueComment, *github.Response, error) {
	return nil, nil, nil
}

// Constructor for mockGHClient.
func newMockGHClient(listPR []github.PullRequest) *reviewer.GHClient {
	client := &reviewer.GHClient{}
	client.Changes = newMockChangesService(listPR)
	client.Tickets = newMockTicketsService()
	return client
}

func mockGetString(k string) string {
	if k == "authorization.token" {
		return token
	}
	return ""
}

func TestGetGHAuth(t *testing.T) {
	reviewer.GetString = mockGetString

	var result interface{}
	var errClient error
	result, errClient = reviewer.GetClient()

	if errClient != nil {
		t.Fatalf("GetClient returned error(%s) when everything was ok", errClient)
	}
	v, err := result.(reviewer.GHClient)
	if err {
		t.Fatalf("GetClient returned %s instead of github.Client", reflect.TypeOf(v))
	}
}

func TestCommentSuccessScore(t *testing.T) {

	testScore := func(comment string, expected int) {
		score := getCommentSuccessScore(comment)
		if expected != score {
			t.Fatalf("Bad score %v (expected %v) for comment %v", score, expected, comment)
		}
	}

	testScore("Don't do it", 0)
	testScore("Yes +1", 1)
	testScore(":+1", 1)
	testScore("-1", -1)
	testScore("Oops +1 :-1: +1", 0)
}

func TestGetPullRequestsInfo(t *testing.T) {
	var emptyListPR []github.PullRequest
	emptyListPR = make([]github.PullRequest, 0, 1)
	client := newMockGHClient(emptyListPR)

	var result []reviewer.PullRequestInfo
	var err error
	result, err = reviewer.GetPullRequestInfos(client, "user", "repo")

	if err != nil {
		t.Fatalf("Something went wrong when getting PR information")
	}
	if len(result) != 0 {
		t.Fatal("Got an empty list of PRInfos")
	}
}
<|endoftext|>


<commit_before>package scaleway

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
	"github.com/scaleway/scaleway-cli/pkg/api"
	"github.com/scaleway/scaleway-cli/pkg/config"
)

const (
	// VERSION represents the semver version of the package
	VERSION           = "v1.0.0+dev"
	defaultImage      = "ubuntu-xenial"
	defaultBootscript = "docker"
)

var scwAPI *api.ScalewayAPI

// Driver represents the docker driver interface
type Driver struct {
	*drivers.BaseDriver
	ServerID       string
	Organization   string
	IPID           string
	Token          string
	commercialType string
	name           string
	image          string
	stopping       bool
	// size         string
	// userDataFile string
	// ipv6         bool
}

// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
	return "scaleway"
}

func (d *Driver) getClient() (cl *api.ScalewayAPI, err error) {
	if scwAPI == nil {
		scwAPI, err = api.NewScalewayAPI(d.Organization, d.Token, "docker-machine-driver-scaleway/%v"+VERSION)
	}
	cl = scwAPI
	return
}

// SetConfigFromFlags sets the flags
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) (err error) {
	if flags.Bool("scaleway-debug") {
		logrus.SetOutput(os.Stderr)
		logrus.SetLevel(logrus.DebugLevel)
	}

	d.Token, d.Organization = flags.String("scaleway-token"), flags.String("scaleway-organization")
	if d.Token == "" || d.Organization == "" {
		config, cfgErr := config.GetConfig()
		if cfgErr == nil {
			if d.Token == "" {
				d.Token = config.Token
			}
			if d.Organization == "" {
				d.Organization = config.Organization
			}
		} else {
			return fmt.Errorf("You must provide organization and token")
		}
	}
	d.commercialType = flags.String("scaleway-commercial-type")
	d.name = flags.String("scaleway-name")
	d.image = flags.String("scaleway-image")
	return
}

// NewDriver returns a new driver
func NewDriver(hostName, storePath string) *Driver {
	return &Driver{
		BaseDriver: &drivers.BaseDriver{},
	}
}

// GetCreateFlags registers the flags
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return []mcnflag.Flag{
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_TOKEN",
			Name:   "scaleway-token",
			Usage:  "Scaleway token",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_ORGANIZATION",
			Name:   "scaleway-organization",
			Usage:  "Scaleway organization",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_NAME",
			Name:   "scaleway-name",
			Usage:  "Assign a name",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_COMMERCIAL_TYPE",
			Name:   "scaleway-commercial-type",
			Usage:  "Specifies the commercial type",
			Value:  "VC1S",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_IMAGE",
			Name:   "scaleway-image",
			Usage:  "Specifies the image",
			Value:  defaultImage,
		},
		mcnflag.BoolFlag{
			EnvVar: "SCALEWAY_DEBUG",
			Name:   "scaleway-debug",
			Usage:  "Enables Scaleway client debugging",
		},
		// mcnflag.StringFlag{
		//     EnvVar: "SCALEWAY_USERDATA",
		//     Name:   "scaleway-userdata",
		//     Usage:  "Path to file with user-data",
		// },
		// mcnflag.BoolFlag{
		// 	EnvVar: "SCALEWAY_IPV6",
		// 	Name:   "scaleway-ipv6",
		// 	Usage:  "Enable ipv6",
		// },
	}
}

// Create configures and starts a scaleway server
func (d *Driver) Create() (err error) {
	var publicKey []byte
	var cl *api.ScalewayAPI
	var ip *api.ScalewayGetIP

	log.Infof("Creating SSH key...")
	if err = ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return err
	}
	publicKey, err = ioutil.ReadFile(d.GetSSHKeyPath() + ".pub")
	if err != nil {
		return
	}
	log.Infof("Creating server...")
	cl, err = d.getClient()
	if err != nil {
		return
	}
	ip, err = cl.NewIP()
	if err != nil {
		return
	}
	d.IPAddress = ip.IP.Address
	d.IPID = ip.IP.ID
	d.ServerID, err = api.CreateServer(cl, &api.ConfigCreateServer{
		ImageName:      d.image,
		CommercialType: d.commercialType,
		Name:           d.name,
		Bootscript:     defaultBootscript,
		IP:             ip.IP.ID,
		Env: strings.Join([]string{"AUTHORIZED_KEY",
			strings.Replace(string(publicKey[:len(publicKey)-1]), " ", "_", -1)}, "="),
	})
	if err != nil {
		return
	}
	log.Infof("Starting server...")
	err = api.StartServer(cl, d.ServerID, false)
	return
}

// GetSSHHostname returns the IP of the server
func (d *Driver) GetSSHHostname() (string, error) {
	return d.IPAddress, nil
}

// GetState returns the state of the server
func (d *Driver) GetState() (st state.State, err error) {
	var server *api.ScalewayServer
	var cl *api.ScalewayAPI

	st = state.Error
	cl, err = d.getClient()
	if err != nil {
		return
	}
	server, err = cl.GetServer(d.ServerID)
	if err != nil {
		return
	}
	st = state.None
	switch server.State {
	case "starting":
		st = state.Starting
	case "running":
		st = state.Running
	case "stopping":
		st = state.Stopping
	case "stopped":
		st = state.Stopped
	}
	if d.stopping {
		time.Sleep(5 * time.Second)
	}
	return
}

// GetURL returns IP + docker port
func (d *Driver) GetURL() (string, error) {
	if err := drivers.MustBeRunning(d); err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s", net.JoinHostPort(d.IPAddress, "2376")), nil
}

func (d *Driver) postAction(action string) (err error) {
	var cl *api.ScalewayAPI

	cl, err = d.getClient()
	if err != nil {
		return
	}
	err = cl.PostServerAction(d.ServerID, action)
	return
}

// Kill does nothing
func (d *Driver) Kill() error {
	return errors.New("scaleway driver does not support kill")
}

// Remove shutdowns the server and removes the IP
func (d *Driver) Remove() (err error) {
	var cl *api.ScalewayAPI

	cl, err = d.getClient()
	if err != nil {
		return
	}
	err = cl.PostServerAction(d.ServerID, "terminate")
	if err != nil {
		return
	}
	for {
		_, err = cl.GetServer(d.ServerID)
		if err != nil {
			break
		}
	}
	err = cl.DeleteIP(d.IPID)
	return
}

// Restart reboots the server
func (d *Driver) Restart() error {
	return d.postAction("reboot")
}

// Start starts the server
func (d *Driver) Start() error {
	return d.postAction("poweron")
}

// Stop stops the server
func (d *Driver) Stop() error {
	d.stopping = true
	return d.postAction("poweroff")
}
<commit_msg>Bump missing VERSION variable<commit_after>package scaleway

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
	"github.com/scaleway/scaleway-cli/pkg/api"
	"github.com/scaleway/scaleway-cli/pkg/config"
)

const (
	// VERSION represents the semver version of the package
	VERSION           = "v1.0.2+dev"
	defaultImage      = "ubuntu-xenial"
	defaultBootscript = "docker"
)

var scwAPI *api.ScalewayAPI

// Driver represents the docker driver interface
type Driver struct {
	*drivers.BaseDriver
	ServerID       string
	Organization   string
	IPID           string
	Token          string
	commercialType string
	name           string
	image          string
	stopping       bool
	// size         string
	// userDataFile string
	// ipv6         bool
}

// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
	return "scaleway"
}

func (d *Driver) getClient() (cl *api.ScalewayAPI, err error) {
	if scwAPI == nil {
		scwAPI, err = api.NewScalewayAPI(d.Organization, d.Token, "docker-machine-driver-scaleway/%v"+VERSION)
	}
	cl = scwAPI
	return
}

// SetConfigFromFlags sets the flags
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) (err error) {
	if flags.Bool("scaleway-debug") {
		logrus.SetOutput(os.Stderr)
		logrus.SetLevel(logrus.DebugLevel)
	}

	d.Token, d.Organization = flags.String("scaleway-token"), flags.String("scaleway-organization")
	if d.Token == "" || d.Organization == "" {
		config, cfgErr := config.GetConfig()
		if cfgErr == nil {
			if d.Token == "" {
				d.Token = config.Token
			}
			if d.Organization == "" {
				d.Organization = config.Organization
			}
		} else {
			return fmt.Errorf("You must provide organization and token")
		}
	}
	d.commercialType = flags.String("scaleway-commercial-type")
	d.name = flags.String("scaleway-name")
	d.image = flags.String("scaleway-image")
	return
}

// NewDriver returns a new driver
func NewDriver(hostName, storePath string) *Driver {
	return &Driver{
		BaseDriver: &drivers.BaseDriver{},
	}
}

// GetCreateFlags registers the flags
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return []mcnflag.Flag{
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_TOKEN",
			Name:   "scaleway-token",
			Usage:  "Scaleway token",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_ORGANIZATION",
			Name:   "scaleway-organization",
			Usage:  "Scaleway organization",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_NAME",
			Name:   "scaleway-name",
			Usage:  "Assign a name",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_COMMERCIAL_TYPE",
			Name:   "scaleway-commercial-type",
			Usage:  "Specifies the commercial type",
			Value:  "VC1S",
		},
		mcnflag.StringFlag{
			EnvVar: "SCALEWAY_IMAGE",
			Name:   "scaleway-image",
			Usage:  "Specifies the image",
			Value:  defaultImage,
		},
		mcnflag.BoolFlag{
			EnvVar: "SCALEWAY_DEBUG",
			Name:   "scaleway-debug",
			Usage:  "Enables Scaleway client debugging",
		},
		// mcnflag.StringFlag{
		//     EnvVar: "SCALEWAY_USERDATA",
		//     Name:   "scaleway-userdata",
		//     Usage:  "Path to file with user-data",
		// },
		// mcnflag.BoolFlag{
		// 	EnvVar: "SCALEWAY_IPV6",
		// 	Name:   "scaleway-ipv6",
		// 	Usage:  "Enable ipv6",
		// },
	}
}

// Create configures and starts a scaleway server
func (d *Driver) Create() (err error) {
	var publicKey []byte
	var cl *api.ScalewayAPI
	var ip *api.ScalewayGetIP

	log.Infof("Creating SSH key...")
	if err = ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return err
	}
	publicKey, err = ioutil.ReadFile(d.GetSSHKeyPath() + ".pub")
	if err != nil {
		return
	}
	log.Infof("Creating server...")
	cl, err = d.getClient()
	if err != nil {
		return
	}
	ip, err = cl.NewIP()
	if err != nil {
		return
	}
	d.IPAddress = ip.IP.Address
	d.IPID = ip.IP.ID
	d.ServerID, err = api.CreateServer(cl, &api.ConfigCreateServer{
		ImageName:      d.image,
		CommercialType: d.commercialType,
		Name:           d.name,
		Bootscript:     defaultBootscript,
		IP:             ip.IP.ID,
		Env: strings.Join([]string{"AUTHORIZED_KEY",
			strings.Replace(string(publicKey[:len(publicKey)-1]), " ", "_", -1)}, "="),
	})
	if err != nil {
		return
	}
	log.Infof("Starting server...")
	err = api.StartServer(cl, d.ServerID, false)
	return
}

// GetSSHHostname returns the IP of the server
func (d *Driver) GetSSHHostname() (string, error) {
	return d.IPAddress, nil
}

// GetState returns the state of the server
func (d *Driver) GetState() (st state.State, err error) {
	var server *api.ScalewayServer
	var cl *api.ScalewayAPI

	st = state.Error
	cl, err = d.getClient()
	if err != nil {
		return
	}
	server, err = cl.GetServer(d.ServerID)
	if err != nil {
		return
	}
	st = state.None
	switch server.State {
	case "starting":
		st = state.Starting
	case "running":
		st = state.Running
	case "stopping":
		st = state.Stopping
	case "stopped":
		st = state.Stopped
	}
	if d.stopping {
		time.Sleep(5 * time.Second)
	}
	return
}

// GetURL returns IP + docker port
func (d *Driver) GetURL() (string, error) {
	if err := drivers.MustBeRunning(d); err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s", net.JoinHostPort(d.IPAddress, "2376")), nil
}

func (d *Driver) postAction(action string) (err error) {
	var cl *api.ScalewayAPI

	cl, err = d.getClient()
	if err != nil {
		return
	}
	err = cl.PostServerAction(d.ServerID, action)
	return
}

// Kill does nothing
func (d *Driver) Kill() error {
	return errors.New("scaleway driver does not support kill")
}

// Remove shutdowns the server and removes the IP
func (d *Driver) Remove() (err error) {
	var cl *api.ScalewayAPI

	cl, err = d.getClient()
	if err != nil {
		return
	}
	err = cl.PostServerAction(d.ServerID, "terminate")
	if err != nil {
		return
	}
	for {
		_, err = cl.GetServer(d.ServerID)
		if err != nil {
			break
		}
	}
	err = cl.DeleteIP(d.IPID)
	return
}

// Restart reboots the server
func (d *Driver) Restart() error {
	return d.postAction("reboot")
}

// Start starts the server
func (d *Driver) Start() error {
	return d.postAction("poweron")
}

// Stop stops the server
func (d *Driver) Stop() error {
	d.stopping = true
	return d.postAction("poweroff")
}
<|endoftext|>


<commit_before>package archive

import (
	// Note - I'm using a patched version of the google-api-go-client library
	// because of this bug -
	// https://code.google.com/p/google-api-go-client/issues/detail?id=52
	bigquery "code.google.com/p/ox-google-api-go-client/bigquery/v2"
	"github.com/getlantern/statshub/statshub"
	"github.com/oxtoacart/oauther/oauth"
	"log"
	"os"
	"sort"
	"time"
)

const (
	OAUTH_CONFIG = "OAUTH_CONFIG"

	TIMESTAMP = "TIMESTAMP"
	RECORD    = "RECORD"
	INTEGER   = "INTEGER"
	STRING    = "STRING"
	global    = "global"
	counter   = "counter"
	gauge     = "gauge"
	_ts       = "_ts"
	_dim      = "_dim"

	ROWS_PER_INSERT = 1000
)

// StatsTable is a table that holds statistics from statshub
type StatsTable struct {
	service   *bigquery.Service
	tables    *bigquery.TablesService
	tabledata *bigquery.TabledataService
	dataset   *bigquery.Dataset
	table     *bigquery.Table
}

func NewStatsTable(projectId string, datasetId string, tableId string) (statsTable *StatsTable, err error) {
	statsTable = &StatsTable{
		table: &bigquery.Table{
			TableReference: &bigquery.TableReference{
				ProjectId: projectId,
				DatasetId: datasetId,
				TableId:   tableId,
			},
		},
	}
	var oauther *oauth.OAuther
	if oauther, err = oauth.FromJSON([]byte(os.Getenv(OAUTH_CONFIG))); err != nil {
		return
	} else if statsTable.service, err = bigquery.New(oauther.Transport().Client()); err != nil {
		return
	} else {
		statsTable.tables = bigquery.NewTablesService(statsTable.service)
		statsTable.tabledata = bigquery.NewTabledataService(statsTable.service)
		datasets := bigquery.NewDatasetsService(statsTable.service)
		statsTable.dataset, err = datasets.Get(projectId, datasetId).Do()
		return
	}
}

func (statsTable *StatsTable) WriteStats(dimStats map[string]*statshub.Stats, now time.Time) (err error) {
	if err = statsTable.createOrUpdateSchema(dimStats); err != nil {
		return
	}
	err = statsTable.insertRows(dimStats, now)
	return
}

func (statsTable *StatsTable) createOrUpdateSchema(dimStats map[string]*statshub.Stats) (err error) {
	var originalTable *bigquery.Table
	statsTable.table.Schema = schemaForStats(dimStats)
	if originalTable, err = statsTable.tables.Get(
		statsTable.table.TableReference.ProjectId,
		statsTable.table.TableReference.DatasetId,
		statsTable.table.TableReference.TableId,
	).Do(); err != nil {
		log.Printf("Creating table: %s", statsTable.table.TableReference.TableId)

		if statsTable.table, err = statsTable.tables.Insert(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table).Do(); err != nil {
			log.Printf("Error creating table: %s", err)
			return
		}
	} else {
		// TODO: the patch should only apply new columns, not remove old ones
		log.Printf("Patching table schema: %s", statsTable.table.TableReference.TableId)
		statsTable.mergeSchema(originalTable.Schema)

		if statsTable.table, err = statsTable.tables.Patch(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table.TableReference.TableId,
			statsTable.table).Do(); err != nil {
			log.Printf("Error patching table: %s", err)
			return
		}
	}

	return
}

func (statsTable *StatsTable) mergeSchema(schema *bigquery.TableSchema) {
	statsTable.table.Schema.Fields = consolidateFields(statsTable.table.Schema.Fields, schema.Fields)
}

func (statsTable *StatsTable) insertRows(dimStats map[string]*statshub.Stats, now time.Time) error {
	doInsert := func(rows []*bigquery.TableDataInsertAllRequestRows) error {
		insertRequest := &bigquery.TableDataInsertAllRequest{Rows: rows}
		_, err := statsTable.tabledata.InsertAll(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table.TableReference.TableId,
			insertRequest).Do()
		if err == nil {
			log.Printf("Inserted %d rows into: %s", len(rows), statsTable.table.TableReference.TableId)
		}
		return nil
	}

	rows := make([]*bigquery.TableDataInsertAllRequestRows, ROWS_PER_INSERT)
	i := 0

	// Set up
	for dim, stats := range dimStats {
		rows[i] = &bigquery.TableDataInsertAllRequestRows{
			Json: rowFromStats(dim, stats, now),
		}
		i++
		if i == ROWS_PER_INSERT {
			// To deal with rate limiting, insert every 1000 rows
			if err := doInsert(rows); err != nil {
				return err
			}
			i = 0
		}
	}

	if i != 0 {
		// Insert the remaining rows
		return doInsert(rows[0:i])
	} else {
		return nil
	}
}

func schemaForStats(dimStats map[string]*statshub.Stats) *bigquery.TableSchema {
	fields := make([]*bigquery.TableFieldSchema, 2)
	fields[0] = &bigquery.TableFieldSchema{
		Type: TIMESTAMP,
		Name: _ts,
	}
	fields[1] = &bigquery.TableFieldSchema{
		Type: STRING,
		Name: _dim,
	}
	// Build fields based on stats for total
	dimFields := fieldsForStats(dimStats["total"])
	for _, dimField := range dimFields {
		fields = append(fields, dimField)
	}
	return &bigquery.TableSchema{
		Fields: fields,
	}
}

func fieldsForStats(stats *statshub.Stats) (fields []*bigquery.TableFieldSchema) {
	fields = make([]*bigquery.TableFieldSchema, 0)
	if len(stats.Counters) > 0 {
		fields = append(fields, &bigquery.TableFieldSchema{
			Type:   RECORD,
			Name:   counter,
			Fields: fieldsFor(stats.Counters),
		})
	}
	if len(stats.Gauges) > 0 {
		fields = append(fields, &bigquery.TableFieldSchema{
			Type:   RECORD,
			Name:   gauge,
			Fields: fieldsFor(stats.Gauges),
		})
	}
	return
}

func fieldsFor(m map[string]int64) (fields []*bigquery.TableFieldSchema) {
	keys := make([]string, len(m))
	i := 0
	for key, _ := range m {
		keys[i] = key
		i++
	}
	// Sort keys alphabetically
	sort.Strings(keys)
	fields = make([]*bigquery.TableFieldSchema, len(keys))
	for i, key := range keys {
		fields[i] = &bigquery.TableFieldSchema{
			Type: INTEGER,
			Name: key,
		}
	}
	return
}

// consolidateFields consolidates two lists of TableFieldSchemas into a single list
func consolidateFields(a []*bigquery.TableFieldSchema, b []*bigquery.TableFieldSchema) (consolidated []*bigquery.TableFieldSchema) {
	allFields := make(map[string]*bigquery.TableFieldSchema)

	for _, field := range a {
		allFields[field.Name] = field
	}
	for _, field := range b {
		matching, found := allFields[field.Name]
		if found {
			if matching.Type == RECORD {
				// For RECORD fields, consolidate their lists of fields
				matching.Fields = consolidateFields(field.Fields, matching.Fields)
			}
		} else {
			// No matching field found, add field
			allFields[field.Name] = field
		}
	}

	keys := make([]string, len(allFields))
	i := 0
	for key, _ := range allFields {
		keys[i] = key
		i++
	}

	// Sort keys alphabetically
	sort.Strings(keys)
	consolidated = make([]*bigquery.TableFieldSchema, len(keys))
	for i, key := range keys {
		consolidated[i] = allFields[key]
	}

	return
}

func rowFromStats(dim string, stats *statshub.Stats, now time.Time) (row map[string]interface{}) {
	row = statsAsMap(stats)
	row[_ts] = now.Unix()
	row[_dim] = dim
	return
}

func statsAsMap(stats *statshub.Stats) (m map[string]interface{}) {
	m = make(map[string]interface{})
	m[counter] = stats.Counters
	m[gauge] = stats.Gauges
	return
}
<commit_msg>Added test for archiving<commit_after>package archive

import (
	// Note - I'm using a patched version of the google-api-go-client library
	// because of this bug -
	// https://code.google.com/p/google-api-go-client/issues/detail?id=52
	bigquery "code.google.com/p/ox-google-api-go-client/bigquery/v2"
	"github.com/getlantern/statshub/statshub"
	"github.com/oxtoacart/oauther/oauth"
	"log"
	"os"
	"sort"
	"time"
)

const (
	OAUTH_CONFIG = "OAUTH_CONFIG"

	TIMESTAMP = "TIMESTAMP"
	RECORD    = "RECORD"
	INTEGER   = "INTEGER"
	STRING    = "STRING"
	global    = "global"
	counter   = "counter"
	gauge     = "gauge"
	_ts       = "_ts"
	_dim      = "_dim"

	ROWS_PER_INSERT = 1000
)

// StatsTable is a table that holds statistics from statshub
type StatsTable struct {
	service   *bigquery.Service
	tables    *bigquery.TablesService
	tabledata *bigquery.TabledataService
	dataset   *bigquery.Dataset
	table     *bigquery.Table
}

func NewStatsTable(projectId string, datasetId string, tableId string) (statsTable *StatsTable, err error) {
	statsTable = &StatsTable{
		table: &bigquery.Table{
			TableReference: &bigquery.TableReference{
				ProjectId: projectId,
				DatasetId: datasetId,
				TableId:   tableId,
			},
		},
	}
	var oauther *oauth.OAuther
	if oauther, err = oauth.FromJSON([]byte(os.Getenv(OAUTH_CONFIG))); err != nil {
		return
	} else if statsTable.service, err = bigquery.New(oauther.Transport().Client()); err != nil {
		return
	} else {
		statsTable.tables = bigquery.NewTablesService(statsTable.service)
		statsTable.tabledata = bigquery.NewTabledataService(statsTable.service)
		datasets := bigquery.NewDatasetsService(statsTable.service)
		statsTable.dataset, err = datasets.Get(projectId, datasetId).Do()
		return
	}
}

func (statsTable *StatsTable) WriteStats(dimStats map[string]*statshub.Stats, now time.Time) (err error) {
	if err = statsTable.createOrUpdateSchema(dimStats); err != nil {
		return
	}
	err = statsTable.insertRows(dimStats, now)
	return
}

func (statsTable *StatsTable) createOrUpdateSchema(dimStats map[string]*statshub.Stats) (err error) {
	var originalTable *bigquery.Table
	statsTable.table.Schema = schemaForStats(dimStats)
	if originalTable, err = statsTable.tables.Get(
		statsTable.table.TableReference.ProjectId,
		statsTable.table.TableReference.DatasetId,
		statsTable.table.TableReference.TableId,
	).Do(); err != nil {
		log.Printf("Creating table: %s", statsTable.table.TableReference.TableId)

		if statsTable.table, err = statsTable.tables.Insert(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table).Do(); err != nil {
			log.Printf("Error creating table: %s", err)
			return
		}
	} else {
		// TODO: the patch should only apply new columns, not remove old ones
		log.Printf("Patching table schema: %s", statsTable.table.TableReference.TableId)
		statsTable.mergeSchema(originalTable.Schema)

		if statsTable.table, err = statsTable.tables.Patch(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table.TableReference.TableId,
			statsTable.table).Do(); err != nil {
			log.Printf("Error patching table: %s", err)
			return
		}
	}

	return
}

func (statsTable *StatsTable) mergeSchema(schema *bigquery.TableSchema) {
	statsTable.table.Schema.Fields = consolidateFields(statsTable.table.Schema.Fields, schema.Fields)
}

func (statsTable *StatsTable) insertRows(dimStats map[string]*statshub.Stats, now time.Time) error {
	doInsert := func(rows []*bigquery.TableDataInsertAllRequestRows) error {
		insertRequest := &bigquery.TableDataInsertAllRequest{Rows: rows}
		_, err := statsTable.tabledata.InsertAll(
			statsTable.table.TableReference.ProjectId,
			statsTable.table.TableReference.DatasetId,
			statsTable.table.TableReference.TableId,
			insertRequest).Do()
		if err == nil {
			log.Printf("Inserted %d rows into: %s", len(rows), statsTable.table.TableReference.TableId)
		}
		return nil
	}

	rows := make([]*bigquery.TableDataInsertAllRequestRows, ROWS_PER_INSERT)
	i := 0

	// Set up
	for dim, stats := range dimStats {
		rows[i] = &bigquery.TableDataInsertAllRequestRows{
			Json: rowFromStats(dim, stats, now),
		}
		i++
		if i == ROWS_PER_INSERT {
			// To deal with rate limiting, insert every 1000 rows
			if err := doInsert(rows); err != nil {
				return err
			}
			i = 0
		}
	}

	if i != 0 {
		// Insert the remaining rows
		return doInsert(rows[0:i])
	} else {
		return nil
	}
}

func schemaForStats(dimStats map[string]*statshub.Stats) *bigquery.TableSchema {
	fields := make([]*bigquery.TableFieldSchema, 2)
	fields[0] = &bigquery.TableFieldSchema{
		Type: STRING,
		Name: _dim,
	}
	fields[1] = &bigquery.TableFieldSchema{
		Type: TIMESTAMP,
		Name: _ts,
	}
	// Build fields based on stats for total
	dimFields := fieldsForStats(dimStats["total"])
	for _, dimField := range dimFields {
		fields = append(fields, dimField)
	}
	return &bigquery.TableSchema{
		Fields: fields,
	}
}

func fieldsForStats(stats *statshub.Stats) (fields []*bigquery.TableFieldSchema) {
	fields = make([]*bigquery.TableFieldSchema, 0)
	if len(stats.Counters) > 0 {
		fields = append(fields, &bigquery.TableFieldSchema{
			Type:   RECORD,
			Name:   counter,
			Fields: fieldsFor(stats.Counters),
		})
	}
	if len(stats.Gauges) > 0 {
		fields = append(fields, &bigquery.TableFieldSchema{
			Type:   RECORD,
			Name:   gauge,
			Fields: fieldsFor(stats.Gauges),
		})
	}
	return
}

func fieldsFor(m map[string]int64) (fields []*bigquery.TableFieldSchema) {
	keys := make([]string, len(m))
	i := 0
	for key, _ := range m {
		keys[i] = key
		i++
	}
	// Sort keys alphabetically
	sort.Strings(keys)
	fields = make([]*bigquery.TableFieldSchema, len(keys))
	for i, key := range keys {
		fields[i] = &bigquery.TableFieldSchema{
			Type: INTEGER,
			Name: key,
		}
	}
	return
}

// consolidateFields consolidates two lists of TableFieldSchemas into a single list
func consolidateFields(a []*bigquery.TableFieldSchema, b []*bigquery.TableFieldSchema) (consolidated []*bigquery.TableFieldSchema) {
	allFields := make(map[string]*bigquery.TableFieldSchema)

	for _, field := range a {
		allFields[field.Name] = field
	}
	for _, field := range b {
		matching, found := allFields[field.Name]
		if found {
			if matching.Type == RECORD {
				// For RECORD fields, consolidate their lists of fields
				matching.Fields = consolidateFields(field.Fields, matching.Fields)
			}
		} else {
			// No matching field found, add field
			allFields[field.Name] = field
		}
	}

	keys := make([]string, len(allFields))
	i := 0
	for key, _ := range allFields {
		keys[i] = key
		i++
	}

	// Sort keys alphabetically
	sort.Strings(keys)
	consolidated = make([]*bigquery.TableFieldSchema, len(keys))
	for i, key := range keys {
		consolidated[i] = allFields[key]
	}

	return
}

func rowFromStats(dim string, stats *statshub.Stats, now time.Time) (row map[string]interface{}) {
	row = statsAsMap(stats)
	row[_ts] = now.Unix()
	row[_dim] = dim
	return
}

func statsAsMap(stats *statshub.Stats) (m map[string]interface{}) {
	m = make(map[string]interface{})
	m[counter] = stats.Counters
	m[gauge] = stats.Gauges
	return
}
<|endoftext|>


<commit_before>// +build linux

package arp

import (
	"errors"
	"fmt"
	"net"
	"os/exec"
	"regexp"
	"strconv"
)

var lineMatch = regexp.MustCompile(`\?\s+\(([0-9\.]+)\)\s+at\s+([0-9a-f:]+).+on\s+([^\s]+)`)

func hexToInt(h string) uint8 {
	v, _ := strconv.ParseInt(h, 16, 16)
	return uint8(v)
}

func doARPLookup(ip string) (*Address, error) {
	ping := exec.Command("ping", "-c1", "-t1", ip)
	ping.Run() // TODO: manually inject arp who has packet.
	ping.Wait()

	cmd := exec.Command("arp", "-an", ip)
	out, err := cmd.Output()
	if err != nil {
		return nil, errors.New("No entry")
	}

	matches := lineMatch.FindAllStringSubmatch(string(out), 1)
	if len(matches) > 0 && len(matches[0]) > 3 {
		ipAddr := net.ParseIP(matches[0][1])

		macAddrString := matches[0][2]

		macAddr, err := net.ParseMAC(macAddrString)
		if err != nil {
			return nil, fmt.Errorf("ParseMAC: %v", err)
		}

		iface, err := net.InterfaceByName(matches[0][3])
		if err != nil {
			return nil, fmt.Errorf("InterfaceByName: %v", err)
		}

		localAddr := Address{
			IP:           ipAddr,
			HardwareAddr: macAddr,
			Interface:    *iface,
		}
		return &localAddr, nil
	}
	return nil, errors.New("Lookup failed.")
}
<commit_msg>Change arp command to ip for the ARPLookup<commit_after>// +build linux

package arp

import (
	"errors"
	"fmt"
	"net"
	"os/exec"
	"regexp"
	"strconv"
)

var lineMatch = regexp.MustCompile(`([0-9\.]+)\s+dev\s+([^\s]+)\s+lladdr\s+([0-9a-f:]+)`)

func hexToInt(h string) uint8 {
	v, _ := strconv.ParseInt(h, 16, 16)
	return uint8(v)
}

func doARPLookup(ip string) (*Address, error) {
	ping := exec.Command("ping", "-c1", "-t1", ip)
	ping.Run() // TODO: manually inject arp who has packet.
	ping.Wait()

	cmd := exec.Command("ip", "n", "show", ip)
	out, err := cmd.Output()
	if err != nil {
		return nil, errors.New("No entry")
	}

	matches := lineMatch.FindAllStringSubmatch(string(out), 1)
	if len(matches) > 0 && len(matches[0]) > 3 {
		ipAddr := net.ParseIP(matches[0][1])

		macAddrString := matches[0][3]

		macAddr, err := net.ParseMAC(macAddrString)
		if err != nil {
			return nil, fmt.Errorf("ParseMAC: %v", err)
		}

		iface, err := net.InterfaceByName(matches[0][2])
		if err != nil {
			return nil, fmt.Errorf("InterfaceByName: %v", err)
		}

		localAddr := Address{
			IP:           ipAddr,
			HardwareAddr: macAddr,
			Interface:    *iface,
		}
		return &localAddr, nil
	}
	return nil, errors.New("Lookup failed.")
}
<|endoftext|>


<commit_before>// Tideland Go Cells - Example - Cells Environment
//
// Copyright (C) 2010-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package main

//--------------------
// IMPORTS
//--------------------

import (
	"context"

	"github.com/tideland/gocells/cells"
	"github.com/tideland/gocells/example/behaviors"
)

//--------------------
// ENVIRONMENT
//--------------------

// InitEnvironment creates a new cells environment and
// its behaviors and subscriptions.
func InitEnvironment(ctx context.Context) (cells.Environment, error) {
	env := cells.NewEnvironment("cells-example")

	// Start initial cells.
	env.StartCell("raw-coins", behaviors.MakeRawCoinsConverter())
	env.StartCell("coins-splitter", behaviors.MakeCoinsSplitter())
	env.StartCell("coins-counter", behaviors.MakeCoinsCounter())
	env.StartCell("avg-percent-change-1h", behaviors.MakeAvgPercentChange1h())
	env.StartCell("top-coins", behaviors.MakeTopPercentChange1hCoins())
	env.StartCell("top-counter", behaviors.MakeTopCounter())
	env.StartCell("avg-marketcap", behaviors.MakeAvgMarketCapEvaluator())
	env.StartCell("avg-marketcap-up", behaviors.MakeAvgMarketCapRater(true))
	env.StartCell("avg-marketcap-down", behaviors.MakeAvgMarketCapRater(false))
	env.StartCell("logger", behaviors.MakeLogger())

	// Establish initial subscriptions.
	env.Subscribe("raw-coins", "coins-splitter")

	// PercentChange1h analysis.
	env.Subscribe("raw-coins", "avg-percent-change-1h", "top-coins")
	env.Subscribe("avg-percent-change-1h", "top-coins")
	env.Subscribe("top-coins", "top-counter", "logger")

	// MarketCap analysis.
	env.Subscribe("raw-coins", "avg-marketcap")
	env.Subscribe("avg-marketcap", "avg-marketcap-up", "avg-marketcap-down")
	env.Subscribe("avg-marketcap-up", "logger")
	env.Subscribe("avg-marketcap-down", "logger")

	return env, nil
}

// EOF
<commit_msg>Changed logging<commit_after>// Tideland Go Cells - Example - Cells Environment
//
// Copyright (C) 2010-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package main

//--------------------
// IMPORTS
//--------------------

import (
	"context"

	"github.com/tideland/gocells/cells"
	"github.com/tideland/gocells/example/behaviors"
)

//--------------------
// ENVIRONMENT
//--------------------

// InitEnvironment creates a new cells environment and
// its behaviors and subscriptions.
func InitEnvironment(ctx context.Context) (cells.Environment, error) {
	env := cells.NewEnvironment("cells-example")

	// Start initial cells.
	env.StartCell("raw-coins", behaviors.MakeRawCoinsConverter())
	env.StartCell("coins-splitter", behaviors.MakeCoinsSplitter())
	env.StartCell("coins-counter", behaviors.MakeCoinsCounter())
	env.StartCell("avg-percent-change-1h", behaviors.MakeAvgPercentChange1h())
	env.StartCell("top-coins", behaviors.MakeTopPercentChange1hCoins())
	env.StartCell("top-counter", behaviors.MakeTopCounter())
	env.StartCell("avg-marketcap", behaviors.MakeAvgMarketCapEvaluator())
	env.StartCell("avg-marketcap-up", behaviors.MakeAvgMarketCapRater(true))
	env.StartCell("avg-marketcap-down", behaviors.MakeAvgMarketCapRater(false))
	env.StartCell("logger", behaviors.MakeLogger())

	// Establish initial subscriptions.
	env.Subscribe("raw-coins", "coins-splitter")

	// PercentChange1h analysis.
	env.Subscribe("raw-coins", "avg-percent-change-1h", "top-coins")
	env.Subscribe("avg-percent-change-1h", "top-coins")
	env.Subscribe("top-coins", "top-counter")
	env.Subscribe("top-counter", "logger")

	// MarketCap analysis.
	env.Subscribe("raw-coins", "avg-marketcap")
	env.Subscribe("avg-marketcap", "avg-marketcap-up", "avg-marketcap-down")
	env.Subscribe("avg-marketcap-up", "logger")
	env.Subscribe("avg-marketcap-down", "logger")

	return env, nil
}

// EOF
<|endoftext|>