<commit_before>package ionic

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

	"github.com/ion-channel/ionic/scanner"
)

const (
	scannerAnalyzeProjectEndpoint          = "v1/scanner/analyzeProject"
	scannerGetAnalysisStatusEndpoint       = "v1/scanner/getAnalysisStatus"
	scannerGetLatestAnalysisStatusEndpoint = "v1/scanner/getLatestAnalysisStatus"
	scannerAddScanEndpoint                 = "v1/scanner/addScanResult"
)

type analyzeRequest struct {
	TeamID    string `json:"team_id"`
	ProjectID string `json:"project_id"`
	Branch    string `json:"branch,omitempty"`
}

type addScanRequest struct {
	TeamID    string               `json:"team_id"`
	ProjectID string               `json:"project_id"`
	ID        string               `json:"analysis_id"`
	Status    string               `json:"status"`
	Results   scanner.ExternalScan `json:"results"`
	Type      string               `json:"scan_type"`
}

// AnalyzeProject takes a projectID, teamID, and project branch, performs an
// analysis, and returns the result status or an error encountered by the API
func (ic *IonClient) AnalyzeProject(projectID, teamID, branch, token string) (*scanner.AnalysisStatus, error) {
	request := &analyzeRequest{}
	request.TeamID = teamID
	request.ProjectID = projectID

	if branch != "" {
		request.Branch = branch
	}

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.Post(scannerAnalyzeProjectEndpoint, token, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}

//GetAnalysisStatus takes an analysisID, teamID, and projectID and returns the analysis status or an error encountered by the API
func (ic *IonClient) GetAnalysisStatus(analysisID, teamID, projectID, token string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("id", analysisID)
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.Get(scannerGetAnalysisStatusEndpoint, token, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	return &a, nil
}

//GetLatestAnalysisStatus takes a teamID, and projectID and returns the latest analysis status or an error encountered by the API
func (ic *IonClient) GetLatestAnalysisStatus(teamID, projectID, token string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.Get(scannerGetLatestAnalysisStatusEndpoint, token, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	return &a, nil
}

//AddScanResult takes a scanResultID, teamID, projectID, status, scanType, and
//client provided scan results, and adds them to the returned project analysis
//or an error encountered by the API
func (ic *IonClient) AddScanResult(scanResultID, teamID, projectID, status, scanType, token string, scanResults scanner.ExternalScan) (*scanner.AnalysisStatus, error) {
	request := &addScanRequest{}
	request.ID = scanResultID
	request.TeamID = teamID
	request.ProjectID = projectID
	request.Results = scanResults
	request.Type = scanType

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.Post(scannerAddScanEndpoint, token, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}
<commit_msg>correcting error<commit_after>package ionic

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

	"github.com/ion-channel/ionic/scanner"
)

const (
	scannerAnalyzeProjectEndpoint          = "v1/scanner/analyzeProject"
	scannerGetAnalysisStatusEndpoint       = "v1/scanner/getAnalysisStatus"
	scannerGetLatestAnalysisStatusEndpoint = "v1/scanner/getLatestAnalysisStatus"
	scannerAddScanEndpoint                 = "v1/scanner/addScanResult"
)

type analyzeRequest struct {
	TeamID    string `json:"team_id"`
	ProjectID string `json:"project_id"`
	Branch    string `json:"branch,omitempty"`
}

type addScanRequest struct {
	TeamID    string               `json:"team_id"`
	ProjectID string               `json:"project_id"`
	ID        string               `json:"analysis_id"`
	Status    string               `json:"status"`
	Results   scanner.ExternalScan `json:"results"`
	Type      string               `json:"scan_type"`
}

// AnalyzeProject takes a projectID, teamID, and project branch, performs an
// analysis, and returns the result status or an error encountered by the API
func (ic *IonClient) AnalyzeProject(projectID, teamID, branch, token string) (*scanner.AnalysisStatus, error) {
	request := &analyzeRequest{}
	request.TeamID = teamID
	request.ProjectID = projectID

	if branch != "" {
		request.Branch = branch
	}

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.Post(scannerAnalyzeProjectEndpoint, token, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}

//GetAnalysisStatus takes an analysisID, teamID, and projectID and returns the analysis status or an error encountered by the API
func (ic *IonClient) GetAnalysisStatus(analysisID, teamID, projectID, token string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("id", analysisID)
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.Get(scannerGetAnalysisStatusEndpoint, token, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}

//GetLatestAnalysisStatus takes a teamID, and projectID and returns the latest analysis status or an error encountered by the API
func (ic *IonClient) GetLatestAnalysisStatus(teamID, projectID, token string) (*scanner.AnalysisStatus, error) {
	params := &url.Values{}
	params.Set("team_id", teamID)
	params.Set("project_id", projectID)

	b, err := ic.Get(scannerGetLatestAnalysisStatusEndpoint, token, params, nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis: %v", err.Error())
	}

	return &a, nil
}

//AddScanResult takes a scanResultID, teamID, projectID, status, scanType, and
//client provided scan results, and adds them to the returned project analysis
//or an error encountered by the API
func (ic *IonClient) AddScanResult(scanResultID, teamID, projectID, status, scanType, token string, scanResults scanner.ExternalScan) (*scanner.AnalysisStatus, error) {
	request := &addScanRequest{}
	request.ID = scanResultID
	request.TeamID = teamID
	request.ProjectID = projectID
	request.Results = scanResults
	request.Type = scanType

	b, err := json.Marshal(request)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request body to JSON: %v", err.Error())
	}

	buff := bytes.NewBuffer(b)
	b, err = ic.Post(scannerAddScanEndpoint, token, nil, *buff, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to start analysis: %v", err.Error())
	}

	var a scanner.AnalysisStatus
	err = json.Unmarshal(b, &a)
	if err != nil {
		return nil, fmt.Errorf("failed to get analysis status: %v", err.Error())
	}

	return &a, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"math/cmplx"
	"sort"
)

type Collidable interface {
	// these methods are defined on type Entity
	Position() complex128
	Velocity() complex128
	SetVelocity(complex128)
	Visible() bool
	SetVisible(bool)
	Health() int
	SetHealth(int)

	// implement these methods on the concrete types
	Radius() float64
	Team() int // Objects in the same Team() will not do damage with each other
	BodyDamage() int
	AcquireExperience(int)
	RewardingExperience() int
}

func Collide(a, b Collidable) {
	dist, phi := cmplx.Polar(a.Position() - b.Position())
	rsum := a.Radius() + b.Radius()
	if dist > rsum {
		return
	}
	a.SetVelocity(a.Velocity() + cmplx.Rect((rsum-dist)/rsum+0.1, phi))
	b.SetVelocity(b.Velocity() + cmplx.Rect((dist-rsum)/rsum+0.1, phi))
	if a.Team() != b.Team() {
		Hit(a, b)
		Hit(b, a)
	}
}

func Hit(a, b Collidable) {
	hp := b.Health()
	hp -= a.BodyDamage()
	b.SetHealth(hp)
	if hp < 0 {
		log.Println(a, "killed", b)
		b.SetVisible(false)
		a.AcquireExperience(b.RewardingExperience())
	}
}

func leftBound(c Collidable) float64 {
	return real(c.Position()) - c.Radius()
}

func rightBound(c Collidable) float64 {
	return real(c.Position()) + c.Radius()
}

func topBound(c Collidable) float64 {
	return imag(c.Position()) + c.Radius()
}

func bottomBound(c Collidable) float64 {
	return imag(c.Position()) - c.Radius()
}

type ByX []Collidable

func (a ByX) Len() int           { return len(a) }
func (a ByX) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByX) Less(i, j int) bool { return leftBound(a[i]) < leftBound(a[j]) }

func DoCollision(a []Collidable) {
	sort.Sort(ByX(a))
	var pairs [][2]Collidable
	for i, left := range a {
		for j := i + 1; j < len(a); j++ {
			right := a[j]
			if leftBound(right) < rightBound(left) {
				if bottomBound(right) < topBound(left) && bottomBound(left) < topBound(right) {
					pairs = append(pairs, [2]Collidable{left, right})
				}
			} else {
				break
			}
		}
	}
	for _, pair := range pairs {
		Collide(pair[0], pair[1])
	}
}
<commit_msg>kill when hp <= 0<commit_after>package main

import (
	"log"
	"math/cmplx"
	"sort"
)

type Collidable interface {
	// these methods are defined on type Entity
	Position() complex128
	Velocity() complex128
	SetVelocity(complex128)
	Visible() bool
	SetVisible(bool)
	Health() int
	SetHealth(int)

	// implement these methods on the concrete types
	Radius() float64
	Team() int // Objects in the same Team() will not do damage with each other
	BodyDamage() int
	AcquireExperience(int)
	RewardingExperience() int
}

func Collide(a, b Collidable) {
	dist, phi := cmplx.Polar(a.Position() - b.Position())
	rsum := a.Radius() + b.Radius()
	if dist > rsum {
		return
	}
	a.SetVelocity(a.Velocity() + cmplx.Rect((rsum-dist)/rsum+0.1, phi))
	b.SetVelocity(b.Velocity() + cmplx.Rect((dist-rsum)/rsum+0.1, phi))
	if a.Team() != b.Team() {
		Hit(a, b)
		Hit(b, a)
	}
}

func Hit(a, b Collidable) {
	hp := b.Health()
	hp -= a.BodyDamage()
	b.SetHealth(hp)
	if hp <= 0 {
		log.Println(a, "killed", b)
		b.SetVisible(false)
		a.AcquireExperience(b.RewardingExperience())
	}
}

func leftBound(c Collidable) float64 {
	return real(c.Position()) - c.Radius()
}

func rightBound(c Collidable) float64 {
	return real(c.Position()) + c.Radius()
}

func topBound(c Collidable) float64 {
	return imag(c.Position()) + c.Radius()
}

func bottomBound(c Collidable) float64 {
	return imag(c.Position()) - c.Radius()
}

type ByX []Collidable

func (a ByX) Len() int           { return len(a) }
func (a ByX) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByX) Less(i, j int) bool { return leftBound(a[i]) < leftBound(a[j]) }

func DoCollision(a []Collidable) {
	sort.Sort(ByX(a))
	var pairs [][2]Collidable
	for i, left := range a {
		for j := i + 1; j < len(a); j++ {
			right := a[j]
			if leftBound(right) < rightBound(left) {
				if bottomBound(right) < topBound(left) && bottomBound(left) < topBound(right) {
					pairs = append(pairs, [2]Collidable{left, right})
				}
			} else {
				break
			}
		}
	}
	for _, pair := range pairs {
		Collide(pair[0], pair[1])
	}
}
<|endoftext|>


<commit_before>// Package seahash implements SeaHash algorithm
package seahash

import "hash"

// Size of SeaHash sum in bytes
const Size = 8

type digest struct {
	sum, a, b, c, d uint64
}

// New returns a new hash.Hash64 computing SeaHash
func New() hash.Hash64 {
	return &digest{
		0,
		0x16f11fe89b0d677c,
		0xb480a793d8e6c86c,
		0x6fe2e5aaf078ebc9,
		0x14f994a4c5259381,
	}
}

func diffuse(x uint64) uint64 {
	x *= 0x6eed0e9da4d94a4f
	x ^= (x >> 32) >> (x >> 60)
	x *= 0x6eed0e9da4d94a4f
	return x
}

func (d *digest) Write(p []byte) (n int, err error) {
	n = len(p)
	for len(p) > 0 {
		var q []byte
		if len(p) > Size {
			p, q = p[:Size], p[Size:]
		}
		var x uint64
		for i := len(p) - 1; i >= 0; i-- {
			x <<= 8
			x |= uint64(p[i])
		}
		d.a, d.b, d.c, d.d = d.b, d.c, d.d, diffuse(d.a^x)
		p = q
	}
	d.sum = diffuse(d.a ^ d.b ^ d.c ^ d.d ^ uint64(n))
	return n, nil
}

func (d *digest) Sum(b []byte) []byte {
	s := d.Sum64()
	for i := Size - 1; i >= 0; i-- {
		b = append(b, byte(s>>uint(8*i)))
	}
	return b
}

func (d *digest) Reset()         { d.sum = 0 }
func (d *digest) Size() int      { return Size }
func (d *digest) BlockSize() int { return 1 }
func (d *digest) Sum64() uint64  { return d.sum }
<commit_msg>Improve Write<commit_after>// Package seahash implements SeaHash algorithm
package seahash

import "hash"

// Size of SeaHash sum in bytes
const Size = 8

type digest struct {
	a, b, c, d uint64
	n          int
}

func (d *digest) Write(p []byte) (n int, err error) {
	n = len(p)
	for len(p) > 0 {
		var q []byte
		if len(p) > Size {
			p, q = p[:Size], p[Size:]
		}
		var x uint64
		for i := len(p) - 1; i >= 0; i-- {
			x <<= 8
			x |= uint64(p[i])
		}
		d.a, d.b, d.c, d.d = d.b, d.c, d.d, diffuse(d.a^x)
		p = q
	}
	d.n += n
	return n, nil
}

func (d *digest) Sum(b []byte) []byte {
	s := d.Sum64()
	for i := Size - 1; i >= 0; i-- {
		b = append(b, byte(s>>uint(8*i)))
	}
	return b
}

func (d *digest) Reset() {
	*d = digest{
		a: 0x16f11fe89b0d677c,
		b: 0xb480a793d8e6c86c,
		c: 0x6fe2e5aaf078ebc9,
		d: 0x14f994a4c5259381,
	}
}

func (d *digest) Size() int {
	return Size
}

func (d *digest) BlockSize() int {
	return 1
}

func (d *digest) Sum64() uint64 {
	return diffuse(d.a ^ d.b ^ d.c ^ d.d ^ uint64(d.n))
}

func diffuse(x uint64) uint64 {
	x *= 0x6eed0e9da4d94a4f
	x ^= (x >> 32) >> (x >> 60)
	x *= 0x6eed0e9da4d94a4f
	return x
}

// New returns a new hash.Hash64 computing SeaHash
func New() hash.Hash64 {
	d := &digest{}
	d.Reset()
	return d
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

// The trillian_log_signer binary runs the log signing code.
package main

import (
	"context"
	"flag"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/google/trillian/cmd"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/log"
	"github.com/google/trillian/monitoring/prometheus"
	"github.com/google/trillian/server"
	"github.com/google/trillian/storage"
	"github.com/google/trillian/util"
	"github.com/google/trillian/util/election"
	"github.com/google/trillian/util/etcd"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	// Register key ProtoHandlers
	_ "github.com/google/trillian/crypto/keys/der/proto"
	_ "github.com/google/trillian/crypto/keys/pem/proto"
	_ "github.com/google/trillian/crypto/keys/pkcs11/proto"
	// Load hashers
	_ "github.com/google/trillian/merkle/objhasher"
	_ "github.com/google/trillian/merkle/rfc6962"
)

var (
	httpEndpoint             = flag.String("http_endpoint", "localhost:8091", "Endpoint for HTTP (host:port, empty means disabled)")
	tlsCertFile              = flag.String("tls_cert_file", "", "Path to the TLS server certificate. If unset, the server will use unsecured connections.")
	tlsKeyFile               = flag.String("tls_key_file", "", "Path to the TLS server key. If unset, the server will use unsecured connections.")
	sequencerIntervalFlag    = flag.Duration("sequencer_interval", time.Second*10, "Time between each sequencing pass through all logs")
	batchSizeFlag            = flag.Int("batch_size", 50, "Max number of leaves to process per batch")
	numSeqFlag               = flag.Int("num_sequencers", 10, "Number of sequencer workers to run in parallel")
	sequencerGuardWindowFlag = flag.Duration("sequencer_guard_window", 0, "If set, the time elapsed before submitted leaves are eligible for sequencing")
	forceMaster              = flag.Bool("force_master", false, "If true, assume master for all logs")
	etcdHTTPService          = flag.String("etcd_http_service", "trillian-logsigner-http", "Service name to announce our HTTP endpoint under")
	lockDir                  = flag.String("lock_file_path", "/test/multimaster", "etcd lock file directory path")
	healthzTimeout           = flag.Duration("healthz_timeout", time.Second*5, "Timeout used during healthz checks")

	quotaIncreaseFactor = flag.Float64("quota_increase_factor", log.QuotaIncreaseFactor,
		"Increase factor for tokens replenished by sequencing-based quotas (1 means a 1:1 relationship between sequenced leaves and replenished tokens)."+
			"Only effective for --quota_system=etcd.")

	preElectionPause    = flag.Duration("pre_election_pause", 1*time.Second, "Maximum time to wait before starting elections")
	masterCheckInterval = flag.Duration("master_check_interval", 5*time.Second, "Interval between checking mastership still held")
	masterHoldInterval  = flag.Duration("master_hold_interval", 60*time.Second, "Minimum interval to hold mastership for")
	resignOdds          = flag.Int("resign_odds", 10, "Chance of resigning mastership after each check, the N in 1-in-N")

	configFile = flag.String("config", "", "Config file containing flags, file contents can be overridden by command line flags")
)

func main() {
	flag.Parse()
	defer glog.Flush()

	if *configFile != "" {
		if err := cmd.ParseFlagFile(*configFile); err != nil {
			glog.Exitf("Failed to load flags from config file %q: %s", *configFile, err)
		}
	}

	glog.CopyStandardLogTo("WARNING")
	glog.Info("**** Log Signer Starting ****")

	mf := prometheus.MetricFactory{}

	sp, err := server.NewStorageProviderFromFlags(mf)
	if err != nil {
		glog.Exitf("Failed to get storage provider: %v", err)
	}
	defer sp.Close()

	client, err := etcd.NewClient(*server.EtcdServers)
	if err != nil {
		glog.Exitf("Failed to connect to etcd at %v: %v", server.EtcdServers, err)
	}
	if client != nil {
		defer client.Close()
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go util.AwaitSignal(ctx, cancel)

	hostname, _ := os.Hostname()
	instanceID := fmt.Sprintf("%s.%d", hostname, os.Getpid())
	var electionFactory election.Factory
	switch {
	case *forceMaster:
		glog.Warning("**** Acting as master for all logs ****")
		electionFactory = election.NoopFactory{InstanceID: instanceID}
	case client != nil:
		electionFactory = etcd.NewElectionFactory(instanceID, client, *lockDir)
	default:
		glog.Exit("Either --force_master or --etcd_servers must be supplied")
	}

	qm, err := server.NewQuotaManagerFromFlags()
	if err != nil {
		glog.Exitf("Error creating quota manager: %v", err)
	}

	registry := extension.Registry{
		AdminStorage:    sp.AdminStorage(),
		LogStorage:      sp.LogStorage(),
		ElectionFactory: electionFactory,
		QuotaManager:    qm,
		MetricFactory:   mf,
	}

	// Start HTTP server (optional)
	if *httpEndpoint != "" {
		// Announce our endpoint to etcd if so configured.
		unannounceHTTP := server.AnnounceSelf(ctx, client, *etcdHTTPService, *httpEndpoint)
		defer unannounceHTTP()

		glog.Infof("Creating HTTP server starting on %v", *httpEndpoint)
		http.Handle("/metrics", promhttp.Handler())
		http.HandleFunc("/healthz", healthzFunc(sp.AdminStorage(), *healthzTimeout))
		if err := util.StartHTTPServer(*httpEndpoint, *tlsCertFile, *tlsKeyFile); err != nil {
			glog.Exitf("Failed to start HTTP server on %v: %v", *httpEndpoint, err)
		}
	}

	// Start the sequencing loop, which will run until we terminate the process. This controls
	// both sequencing and signing.
	// TODO(Martin2112): Should respect read only mode and the flags in tree control etc
	log.QuotaIncreaseFactor = *quotaIncreaseFactor
	sequencerManager := server.NewSequencerManager(registry, *sequencerGuardWindowFlag)
	info := server.LogOperationInfo{
		Registry:    registry,
		BatchSize:   *batchSizeFlag,
		NumWorkers:  *numSeqFlag,
		RunInterval: *sequencerIntervalFlag,
		TimeSource:  util.SystemTimeSource{},
		ElectionConfig: election.RunnerConfig{
			PreElectionPause:    *preElectionPause,
			MasterCheckInterval: *masterCheckInterval,
			MasterHoldInterval:  *masterHoldInterval,
			ResignOdds:          *resignOdds,
			TimeSource:          util.SystemTimeSource{},
		},
	}
	sequencerTask := server.NewLogOperationManager(info, sequencerManager)
	sequencerTask.OperationLoop(ctx)

	// Give things a few seconds to tidy up
	glog.Infof("Stopping server, about to exit")
	time.Sleep(time.Second * 5)
}

func healthzFunc(as storage.AdminStorage, deadline time.Duration) func(http.ResponseWriter, *http.Request) {
	if deadline == 0 {
		deadline = 5 * time.Second
	}
	return func(w http.ResponseWriter, req *http.Request) {
		ctx, cancel := context.WithTimeout(req.Context(), deadline)
		defer cancel()
		if err := as.CheckDatabaseAccessible(ctx); err != nil {
			w.WriteHeader(http.StatusServiceUnavailable)
			w.Write([]byte(err.Error()))
			return
		}
		w.Write([]byte("ok"))
	}
}
<commit_msg>Register pprof handlers for log_signer. (#1210)<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

// The trillian_log_signer binary runs the log signing code.
package main

import (
	"context"
	"flag"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/google/trillian/cmd"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/log"
	"github.com/google/trillian/monitoring/prometheus"
	"github.com/google/trillian/server"
	"github.com/google/trillian/storage"
	"github.com/google/trillian/util"
	"github.com/google/trillian/util/election"
	"github.com/google/trillian/util/etcd"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	// Register pprof HTTP handlers
	_ "net/http/pprof"
	// Register key ProtoHandlers
	_ "github.com/google/trillian/crypto/keys/der/proto"
	_ "github.com/google/trillian/crypto/keys/pem/proto"
	_ "github.com/google/trillian/crypto/keys/pkcs11/proto"
	// Load hashers
	_ "github.com/google/trillian/merkle/objhasher"
	_ "github.com/google/trillian/merkle/rfc6962"
)

var (
	httpEndpoint             = flag.String("http_endpoint", "localhost:8091", "Endpoint for HTTP (host:port, empty means disabled)")
	tlsCertFile              = flag.String("tls_cert_file", "", "Path to the TLS server certificate. If unset, the server will use unsecured connections.")
	tlsKeyFile               = flag.String("tls_key_file", "", "Path to the TLS server key. If unset, the server will use unsecured connections.")
	sequencerIntervalFlag    = flag.Duration("sequencer_interval", time.Second*10, "Time between each sequencing pass through all logs")
	batchSizeFlag            = flag.Int("batch_size", 50, "Max number of leaves to process per batch")
	numSeqFlag               = flag.Int("num_sequencers", 10, "Number of sequencer workers to run in parallel")
	sequencerGuardWindowFlag = flag.Duration("sequencer_guard_window", 0, "If set, the time elapsed before submitted leaves are eligible for sequencing")
	forceMaster              = flag.Bool("force_master", false, "If true, assume master for all logs")
	etcdHTTPService          = flag.String("etcd_http_service", "trillian-logsigner-http", "Service name to announce our HTTP endpoint under")
	lockDir                  = flag.String("lock_file_path", "/test/multimaster", "etcd lock file directory path")
	healthzTimeout           = flag.Duration("healthz_timeout", time.Second*5, "Timeout used during healthz checks")

	quotaIncreaseFactor = flag.Float64("quota_increase_factor", log.QuotaIncreaseFactor,
		"Increase factor for tokens replenished by sequencing-based quotas (1 means a 1:1 relationship between sequenced leaves and replenished tokens)."+
			"Only effective for --quota_system=etcd.")

	preElectionPause    = flag.Duration("pre_election_pause", 1*time.Second, "Maximum time to wait before starting elections")
	masterCheckInterval = flag.Duration("master_check_interval", 5*time.Second, "Interval between checking mastership still held")
	masterHoldInterval  = flag.Duration("master_hold_interval", 60*time.Second, "Minimum interval to hold mastership for")
	resignOdds          = flag.Int("resign_odds", 10, "Chance of resigning mastership after each check, the N in 1-in-N")

	configFile = flag.String("config", "", "Config file containing flags, file contents can be overridden by command line flags")
)

func main() {
	flag.Parse()
	defer glog.Flush()

	if *configFile != "" {
		if err := cmd.ParseFlagFile(*configFile); err != nil {
			glog.Exitf("Failed to load flags from config file %q: %s", *configFile, err)
		}
	}

	glog.CopyStandardLogTo("WARNING")
	glog.Info("**** Log Signer Starting ****")

	mf := prometheus.MetricFactory{}

	sp, err := server.NewStorageProviderFromFlags(mf)
	if err != nil {
		glog.Exitf("Failed to get storage provider: %v", err)
	}
	defer sp.Close()

	client, err := etcd.NewClient(*server.EtcdServers)
	if err != nil {
		glog.Exitf("Failed to connect to etcd at %v: %v", server.EtcdServers, err)
	}
	if client != nil {
		defer client.Close()
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go util.AwaitSignal(ctx, cancel)

	hostname, _ := os.Hostname()
	instanceID := fmt.Sprintf("%s.%d", hostname, os.Getpid())
	var electionFactory election.Factory
	switch {
	case *forceMaster:
		glog.Warning("**** Acting as master for all logs ****")
		electionFactory = election.NoopFactory{InstanceID: instanceID}
	case client != nil:
		electionFactory = etcd.NewElectionFactory(instanceID, client, *lockDir)
	default:
		glog.Exit("Either --force_master or --etcd_servers must be supplied")
	}

	qm, err := server.NewQuotaManagerFromFlags()
	if err != nil {
		glog.Exitf("Error creating quota manager: %v", err)
	}

	registry := extension.Registry{
		AdminStorage:    sp.AdminStorage(),
		LogStorage:      sp.LogStorage(),
		ElectionFactory: electionFactory,
		QuotaManager:    qm,
		MetricFactory:   mf,
	}

	// Start HTTP server (optional)
	if *httpEndpoint != "" {
		// Announce our endpoint to etcd if so configured.
		unannounceHTTP := server.AnnounceSelf(ctx, client, *etcdHTTPService, *httpEndpoint)
		defer unannounceHTTP()

		glog.Infof("Creating HTTP server starting on %v", *httpEndpoint)
		http.Handle("/metrics", promhttp.Handler())
		http.HandleFunc("/healthz", healthzFunc(sp.AdminStorage(), *healthzTimeout))
		if err := util.StartHTTPServer(*httpEndpoint, *tlsCertFile, *tlsKeyFile); err != nil {
			glog.Exitf("Failed to start HTTP server on %v: %v", *httpEndpoint, err)
		}
	}

	// Start the sequencing loop, which will run until we terminate the process. This controls
	// both sequencing and signing.
	// TODO(Martin2112): Should respect read only mode and the flags in tree control etc
	log.QuotaIncreaseFactor = *quotaIncreaseFactor
	sequencerManager := server.NewSequencerManager(registry, *sequencerGuardWindowFlag)
	info := server.LogOperationInfo{
		Registry:    registry,
		BatchSize:   *batchSizeFlag,
		NumWorkers:  *numSeqFlag,
		RunInterval: *sequencerIntervalFlag,
		TimeSource:  util.SystemTimeSource{},
		ElectionConfig: election.RunnerConfig{
			PreElectionPause:    *preElectionPause,
			MasterCheckInterval: *masterCheckInterval,
			MasterHoldInterval:  *masterHoldInterval,
			ResignOdds:          *resignOdds,
			TimeSource:          util.SystemTimeSource{},
		},
	}
	sequencerTask := server.NewLogOperationManager(info, sequencerManager)
	sequencerTask.OperationLoop(ctx)

	// Give things a few seconds to tidy up
	glog.Infof("Stopping server, about to exit")
	time.Sleep(time.Second * 5)
}

func healthzFunc(as storage.AdminStorage, deadline time.Duration) func(http.ResponseWriter, *http.Request) {
	if deadline == 0 {
		deadline = 5 * time.Second
	}
	return func(w http.ResponseWriter, req *http.Request) {
		ctx, cancel := context.WithTimeout(req.Context(), deadline)
		defer cancel()
		if err := as.CheckDatabaseAccessible(ctx); err != nil {
			w.WriteHeader(http.StatusServiceUnavailable)
			w.Write([]byte(err.Error()))
			return
		}
		w.Write([]byte("ok"))
	}
}
<|endoftext|>


<commit_before>package vcsstore

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/sourcegraph/go-vcs/vcs"
)

var (
	// RepositoryPath is called to determine the directory, relative to a
	// Config's StorageDir, to which the repository should be cloned to. The
	// default implementation stores repositories in directories of the form
	// "vcs-type/escaped-clone-url".
	RepositoryPath = func(vcsType string, cloneURL *url.URL) string {
		return filepath.Join(vcsType, url.QueryEscape(cloneURL.String()))
	}
)

// HashedRepositoryPath may be assigned to RepositoryPath to use paths
// of the form "xx/yy/zzzzzzzz" where xx and yy are the first 4 characters of
// some hash of vcsType and cloneURL, and zzzzzzzz is the full hash (minus the
// first 4 characters).
func HashedRepositoryPath(vcsType string, cloneURL *url.URL) string {
	h := sha1.New()
	h.Write([]byte(vcsType))
	h.Write([]byte(cloneURL.String()))
	s := base64.URLEncoding.EncodeToString(h.Sum(nil))
	return fmt.Sprintf("%s/%s/%s/%s", vcsType, s[:2], s[2:4], s[4:])
}

type Service interface {
	// Open opens a repository. If it doesn't exist. an
	// os.ErrNotExist-satisfying error is returned. If opening succeeds, the
	// repository is returned.
	Open(vcs string, cloneURL *url.URL) (interface{}, error)

	// Clone clones the repository if a clone doesn't yet exist locally.
	// Otherwise, it opens the repository. If no errors occur, the repository is
	// returned.
	Clone(vcs string, cloneURL *url.URL) (interface{}, error)
}

type Config struct {
	// StorageDir is where cloned repositories are stored. If empty, the current
	// working directory is used.
	StorageDir string

	Log *log.Logger

	DebugLog *log.Logger
}

func NewService(c *Config) Service {
	if c == nil {
		c = &Config{
			StorageDir: ".",
			Log:        log.New(os.Stderr, "vcsstore: ", log.LstdFlags),
			DebugLog:   log.New(ioutil.Discard, "", 0),
		}
	}
	return &service{
		Config: *c,
		repoMu: make(map[repoKey]*sync.Mutex),
	}
}

type service struct {
	Config

	// repoMu prevents more than one goroutine from simultaneously cloning the
	// same repository.
	repoMu map[repoKey]*sync.Mutex

	// repoMuMu synchronizes access to repoMu.
	repoMuMu sync.Mutex
}

type repoKey struct {
	vcsType  string
	cloneURL string
}

// CloneDir validates vcsType and cloneURL. If they are valid, cloneDir returns
// the local directory that the repository should be cloned to (which it may
// already exist at). If invalid, cloneDir returns a non-nil error.
func (s *service) CloneDir(vcsType string, cloneURL *url.URL) (string, error) {
	if !isLowercaseLetter(vcsType) {
		return "", errors.New("invalid VCS type")
	}
	if cloneURL.Scheme == "" || cloneURL.Host == "" {
		return "", errors.New("invalid clone URL")
	}

	return filepath.Join(s.StorageDir, RepositoryPath(vcsType, cloneURL)), nil
}

func (s *service) Open(vcsType string, cloneURL *url.URL) (interface{}, error) {
	cloneDir, err := s.CloneDir(vcsType, cloneURL)
	if err != nil {
		return nil, err
	}
	return s.open(vcsType, cloneDir)
}

func (s *service) open(vcsType, cloneDir string) (interface{}, error) {
	if fi, err := os.Stat(cloneDir); err != nil {
		return nil, err
	} else if !fi.Mode().IsDir() {
		return nil, fmt.Errorf("clone path %q is not a directory", cloneDir)
	}
	return vcs.OpenMirror(vcsType, cloneDir)
}

func (s *service) Clone(vcsType string, cloneURL *url.URL) (interface{}, error) {
	cloneDir, err := s.CloneDir(vcsType, cloneURL)
	if err != nil {
		return nil, err
	}

	// See if the clone directory exists and return immediately (without
	// locking) if so.
	if r, err := s.open(vcsType, cloneDir); !os.IsNotExist(err) {
		if err == nil {
			s.DebugLog.Printf("Clone(%s, %s): repository already exists at %s", vcsType, cloneURL, cloneDir)
		} else {
			s.DebugLog.Printf("Clone(%s, %s): opening existing repository at %s failed: %s", vcsType, cloneURL, cloneDir, err)
		}
		return r, err
	}

	// The local clone directory doesn't exist, so we need to clone the repository.
	mu := s.Mutex(vcsType, cloneURL)
	mu.Lock()
	defer mu.Unlock()

	// Check again after obtaining the lock, so we don't clone multiple times.
	if r, err := s.open(vcsType, cloneDir); !os.IsNotExist(err) {
		if err == nil {
			s.DebugLog.Printf("Clone(%s, %s): after obtaining clone lock, repository already exists at %s", vcsType, cloneURL, cloneDir)
		} else {
			s.DebugLog.Printf("Clone(%s, %s): after obtaining clone lock, opening existing repository at %s failed: %s", vcsType, cloneURL, cloneDir, err)
		}
		return r, err
	}

	start := time.Now()
	msg := fmt.Sprintf("%s %s to %s", vcsType, cloneURL.String(), cloneDir)
	s.Log.Print("Cloning ", msg, "...")
	defer func() {
		s.Log.Print("Finished cloning ", msg, " in ", time.Since(start))
	}()

	// "Atomically" clone the repository. First, clone it to a temporary sibling
	// directory. Once the clone is complete, "atomically"
	// rename it to the intended cloneDir.
	//
	// "Atomically" is in quotes because this operation is not really atomic. It
	// depends on the underlying FS. For now, for our purposes, it performs well
	// enough on local ext4 and on GlusterFS.
	parentDir := filepath.Dir(cloneDir)
	if err := os.MkdirAll(parentDir, 0700); err != nil {
		return nil, err
	}

	cloneTmpDir, err := ioutil.TempDir(parentDir, "_tmp_"+filepath.Base(cloneDir)+"-")
	if err != nil {
		return nil, err
	}
	s.DebugLog.Printf("Clone(%s, %s): cloning to temporary sibling dir %s", vcsType, cloneURL, cloneTmpDir)
	defer os.RemoveAll(cloneTmpDir)

	_, err = vcs.CloneMirror(vcsType, cloneURL.String(), cloneTmpDir)
	if err != nil {
		return nil, err
	}
	s.DebugLog.Printf("Clone(%s, %s): cloned to temporary sibling dir %s; now renaming to intended clone dir %s", vcsType, cloneURL, cloneTmpDir, cloneDir)

	if err := os.Rename(cloneTmpDir, cloneDir); err != nil {
		s.DebugLog.Printf("Clone(%s, %s): Rename(%s -> %s) failed: %s", vcsType, cloneURL, cloneTmpDir, cloneDir)
		return nil, err
	}

	return s.open(vcsType, cloneDir)
}

func (s *service) Mutex(vcsType string, cloneURL *url.URL) *sync.Mutex {
	s.repoMuMu.Lock()
	defer s.repoMuMu.Unlock()

	k := repoKey{vcsType, cloneURL.String()}
	if mu, ok := s.repoMu[k]; ok {
		return mu
	}
	s.repoMu[k] = &sync.Mutex{}
	return s.repoMu[k]
}

func isLowercaseLetter(s string) bool {
	return strings.IndexFunc(s, func(c rune) bool {
		return !(c >= 'a' && c <= 'z')
	}) == -1
}
<commit_msg>move CloneDir to Config so it is accessible<commit_after>package vcsstore

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/sourcegraph/go-vcs/vcs"
)

var (
	// RepositoryPath is called to determine the directory, relative to a
	// Config's StorageDir, to which the repository should be cloned to. The
	// default implementation stores repositories in directories of the form
	// "vcs-type/escaped-clone-url".
	RepositoryPath = func(vcsType string, cloneURL *url.URL) string {
		return filepath.Join(vcsType, url.QueryEscape(cloneURL.String()))
	}
)

// HashedRepositoryPath may be assigned to RepositoryPath to use paths
// of the form "xx/yy/zzzzzzzz" where xx and yy are the first 4 characters of
// some hash of vcsType and cloneURL, and zzzzzzzz is the full hash (minus the
// first 4 characters).
func HashedRepositoryPath(vcsType string, cloneURL *url.URL) string {
	h := sha1.New()
	h.Write([]byte(vcsType))
	h.Write([]byte(cloneURL.String()))
	s := base64.URLEncoding.EncodeToString(h.Sum(nil))
	return fmt.Sprintf("%s/%s/%s/%s", vcsType, s[:2], s[2:4], s[4:])
}

type Service interface {
	// Open opens a repository. If it doesn't exist. an
	// os.ErrNotExist-satisfying error is returned. If opening succeeds, the
	// repository is returned.
	Open(vcs string, cloneURL *url.URL) (interface{}, error)

	// Clone clones the repository if a clone doesn't yet exist locally.
	// Otherwise, it opens the repository. If no errors occur, the repository is
	// returned.
	Clone(vcs string, cloneURL *url.URL) (interface{}, error)
}

type Config struct {
	// StorageDir is where cloned repositories are stored. If empty, the current
	// working directory is used.
	StorageDir string

	Log *log.Logger

	DebugLog *log.Logger
}

// CloneDir validates vcsType and cloneURL. If they are valid, cloneDir returns
// the local directory that the repository should be cloned to (which it may
// already exist at). If invalid, cloneDir returns a non-nil error.
func (c *Config) CloneDir(vcsType string, cloneURL *url.URL) (string, error) {
	if !isLowercaseLetter(vcsType) {
		return "", errors.New("invalid VCS type")
	}
	if cloneURL.Scheme == "" || cloneURL.Host == "" {
		return "", errors.New("invalid clone URL")
	}

	return filepath.Join(c.StorageDir, RepositoryPath(vcsType, cloneURL)), nil
}

func NewService(c *Config) Service {
	if c == nil {
		c = &Config{
			StorageDir: ".",
			Log:        log.New(os.Stderr, "vcsstore: ", log.LstdFlags),
			DebugLog:   log.New(ioutil.Discard, "", 0),
		}
	}
	return &service{
		Config: *c,
		repoMu: make(map[repoKey]*sync.Mutex),
	}
}

type service struct {
	Config

	// repoMu prevents more than one goroutine from simultaneously cloning the
	// same repository.
	repoMu map[repoKey]*sync.Mutex

	// repoMuMu synchronizes access to repoMu.
	repoMuMu sync.Mutex
}

type repoKey struct {
	vcsType  string
	cloneURL string
}

func (s *service) Open(vcsType string, cloneURL *url.URL) (interface{}, error) {
	cloneDir, err := s.CloneDir(vcsType, cloneURL)
	if err != nil {
		return nil, err
	}
	return s.open(vcsType, cloneDir)
}

func (s *service) open(vcsType, cloneDir string) (interface{}, error) {
	if fi, err := os.Stat(cloneDir); err != nil {
		return nil, err
	} else if !fi.Mode().IsDir() {
		return nil, fmt.Errorf("clone path %q is not a directory", cloneDir)
	}
	return vcs.OpenMirror(vcsType, cloneDir)
}

func (s *service) Clone(vcsType string, cloneURL *url.URL) (interface{}, error) {
	cloneDir, err := s.CloneDir(vcsType, cloneURL)
	if err != nil {
		return nil, err
	}

	// See if the clone directory exists and return immediately (without
	// locking) if so.
	if r, err := s.open(vcsType, cloneDir); !os.IsNotExist(err) {
		if err == nil {
			s.DebugLog.Printf("Clone(%s, %s): repository already exists at %s", vcsType, cloneURL, cloneDir)
		} else {
			s.DebugLog.Printf("Clone(%s, %s): opening existing repository at %s failed: %s", vcsType, cloneURL, cloneDir, err)
		}
		return r, err
	}

	// The local clone directory doesn't exist, so we need to clone the repository.
	mu := s.Mutex(vcsType, cloneURL)
	mu.Lock()
	defer mu.Unlock()

	// Check again after obtaining the lock, so we don't clone multiple times.
	if r, err := s.open(vcsType, cloneDir); !os.IsNotExist(err) {
		if err == nil {
			s.DebugLog.Printf("Clone(%s, %s): after obtaining clone lock, repository already exists at %s", vcsType, cloneURL, cloneDir)
		} else {
			s.DebugLog.Printf("Clone(%s, %s): after obtaining clone lock, opening existing repository at %s failed: %s", vcsType, cloneURL, cloneDir, err)
		}
		return r, err
	}

	start := time.Now()
	msg := fmt.Sprintf("%s %s to %s", vcsType, cloneURL.String(), cloneDir)
	s.Log.Print("Cloning ", msg, "...")
	defer func() {
		s.Log.Print("Finished cloning ", msg, " in ", time.Since(start))
	}()

	// "Atomically" clone the repository. First, clone it to a temporary sibling
	// directory. Once the clone is complete, "atomically"
	// rename it to the intended cloneDir.
	//
	// "Atomically" is in quotes because this operation is not really atomic. It
	// depends on the underlying FS. For now, for our purposes, it performs well
	// enough on local ext4 and on GlusterFS.
	parentDir := filepath.Dir(cloneDir)
	if err := os.MkdirAll(parentDir, 0700); err != nil {
		return nil, err
	}

	cloneTmpDir, err := ioutil.TempDir(parentDir, "_tmp_"+filepath.Base(cloneDir)+"-")
	if err != nil {
		return nil, err
	}
	s.DebugLog.Printf("Clone(%s, %s): cloning to temporary sibling dir %s", vcsType, cloneURL, cloneTmpDir)
	defer os.RemoveAll(cloneTmpDir)

	_, err = vcs.CloneMirror(vcsType, cloneURL.String(), cloneTmpDir)
	if err != nil {
		return nil, err
	}
	s.DebugLog.Printf("Clone(%s, %s): cloned to temporary sibling dir %s; now renaming to intended clone dir %s", vcsType, cloneURL, cloneTmpDir, cloneDir)

	if err := os.Rename(cloneTmpDir, cloneDir); err != nil {
		s.DebugLog.Printf("Clone(%s, %s): Rename(%s -> %s) failed: %s", vcsType, cloneURL, cloneTmpDir, cloneDir)
		return nil, err
	}

	return s.open(vcsType, cloneDir)
}

func (s *service) Mutex(vcsType string, cloneURL *url.URL) *sync.Mutex {
	s.repoMuMu.Lock()
	defer s.repoMuMu.Unlock()

	k := repoKey{vcsType, cloneURL.String()}
	if mu, ok := s.repoMu[k]; ok {
		return mu
	}
	s.repoMu[k] = &sync.Mutex{}
	return s.repoMu[k]
}

func isLowercaseLetter(s string) bool {
	return strings.IndexFunc(s, func(c rune) bool {
		return !(c >= 'a' && c <= 'z')
	}) == -1
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/the-gigi/project-euler/8/go/islands"
	"github.com/the-gigi/project-euler/8/go/trivial"
	"fmt"
)

const text = `
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
`

func main() {
	result := islands.FindLargestProduct(text)
	fmt.Println("With islands:", result) // should be 23514624000

	result = trivial.FindLargestProduct(text)
	fmt.Println("Trivial:", result) // should be 23514624000
}
<commit_msg>Add call to scan algorithm to main() func<commit_after>package main

import (
	"github.com/the-gigi/project-euler/8/go/islands"
	"github.com/the-gigi/project-euler/8/go/trivial"
	"github.com/the-gigi/project-euler/8/go/scan"
	"fmt"
)

const text = `
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
`

func main() {
	result := scan.FindLargestProduct(text)
	fmt.Println("With Scan:", result) // should be 23514624000

	result = islands.FindLargestProduct(text)
	fmt.Println("With islands:", result) // should be 23514624000

	result = trivial.FindLargestProduct(text)
	fmt.Println("Trivial:", result) // should be 23514624000
}
<|endoftext|>


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

package middleware

import (
	"fmt"
	"net/url"

	"github.com/go-macaron/csrf"
	"gopkg.in/macaron.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/auth"
	"github.com/gogits/gogs/modules/base"
	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/setting"
)

type ToggleOptions struct {
	SignInRequire  bool
	SignOutRequire bool
	AdminRequire   bool
	DisableCsrf    bool
}

// AutoSignIn reads cookie and try to auto-login.
func AutoSignIn(ctx *Context) (bool, error) {
	if !models.HasEngine {
		return false, nil
	}

	uname := ctx.GetCookie(setting.CookieUserName)
	if len(uname) == 0 {
		return false, nil
	}

	isSucceed := false
	defer func() {
		if !isSucceed {
			log.Trace("auto-login cookie cleared: %s", uname)
			ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl)
			ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl)
		}
	}()

	u, err := models.GetUserByName(uname)
	if err != nil {
		if !models.IsErrUserNotExist(err) {
			return false, fmt.Errorf("GetUserByName: %v", err)
		}
		return false, nil
	}

	if val, _ := ctx.GetSuperSecureCookie(
		base.EncodeMd5(u.Rands+u.Passwd), setting.CookieRememberName); val != u.Name {
		return false, nil
	}

	isSucceed = true
	ctx.Session.Set("uid", u.Id)
	ctx.Session.Set("uname", u.Name)
	return true, nil
}

func Toggle(options *ToggleOptions) macaron.Handler {
	return func(ctx *Context) {
		// Cannot view any page before installation.
		if !setting.InstallLock {
			ctx.Redirect(setting.AppSubUrl + "/install")
			return
		}

		// Checking non-logged users landing page.
		if !ctx.IsSigned && ctx.Req.RequestURI == "/" && setting.LandingPageUrl != setting.LANDING_PAGE_HOME {
			ctx.Redirect(setting.AppSubUrl + string(setting.LandingPageUrl))
			return
		}

		// Redirect to dashboard if user tries to visit any non-login page.
		if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
			ctx.Redirect(setting.AppSubUrl + "/")
			return
		}

		if !options.SignOutRequire && !options.DisableCsrf && ctx.Req.Method == "POST" && !auth.IsAPIPath(ctx.Req.URL.Path) {
			csrf.Validate(ctx.Context, ctx.csrf)
			if ctx.Written() {
				return
			}
		}

		if options.SignInRequire {
			if !ctx.IsSigned {
				// Restrict API calls with error message.
				if auth.IsAPIPath(ctx.Req.URL.Path) {
					ctx.APIError(403, "", "Only signed in user is allowed to call APIs.")
					return
				}

				ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
				ctx.Redirect(setting.AppSubUrl + "/user/login")
				return
			} else if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
				ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
				ctx.HTML(200, "user/auth/activate")
				return
			}
		}

		// Try auto-signin when not signed in.
		if !ctx.IsSigned {
			succeed, err := AutoSignIn(ctx)
			if err != nil {
				ctx.Handle(500, "AutoSignIn", err)
				return
			} else if succeed {
				ctx.Redirect(ctx.Req.URL.Path)
				return
			}
		}

		if options.AdminRequire {
			if !ctx.User.IsAdmin {
				ctx.Error(403)
				return
			}
			ctx.Data["PageIsAdmin"] = true
		}
	}
}

// Contexter middleware already checks token for user sign in process.
func ApiReqToken() macaron.Handler {
	return func(ctx *Context) {
		if !ctx.IsSigned {
			ctx.Error(401)
			return
		}
	}
}

func ApiReqBasicAuth() macaron.Handler {
	return func(ctx *Context) {
		if !ctx.IsBasicAuth {
			ctx.Error(401)
			return
		}
	}
}
<commit_msg>minor fix on auto sign in<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package middleware

import (
	"fmt"
	"net/url"

	"github.com/go-macaron/csrf"
	"gopkg.in/macaron.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/auth"
	"github.com/gogits/gogs/modules/base"
	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/setting"
)

type ToggleOptions struct {
	SignInRequire  bool
	SignOutRequire bool
	AdminRequire   bool
	DisableCsrf    bool
}

// AutoSignIn reads cookie and try to auto-login.
func AutoSignIn(ctx *Context) (bool, error) {
	if !models.HasEngine {
		return false, nil
	}

	uname := ctx.GetCookie(setting.CookieUserName)
	if len(uname) == 0 {
		return false, nil
	}

	isSucceed := false
	defer func() {
		if !isSucceed {
			log.Trace("auto-login cookie cleared: %s", uname)
			ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl)
			ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl)
		}
	}()

	u, err := models.GetUserByName(uname)
	if err != nil {
		if !models.IsErrUserNotExist(err) {
			return false, fmt.Errorf("GetUserByName: %v", err)
		}
		return false, nil
	}

	if val, _ := ctx.GetSuperSecureCookie(
		base.EncodeMd5(u.Rands+u.Passwd), setting.CookieRememberName); val != u.Name {
		return false, nil
	}

	isSucceed = true
	ctx.Session.Set("uid", u.Id)
	ctx.Session.Set("uname", u.Name)
	return true, nil
}

func Toggle(options *ToggleOptions) macaron.Handler {
	return func(ctx *Context) {
		// Cannot view any page before installation.
		if !setting.InstallLock {
			ctx.Redirect(setting.AppSubUrl + "/install")
			return
		}

		// Checking non-logged users landing page.
		if !ctx.IsSigned && ctx.Req.RequestURI == "/" && setting.LandingPageUrl != setting.LANDING_PAGE_HOME {
			ctx.Redirect(setting.AppSubUrl + string(setting.LandingPageUrl))
			return
		}

		// Redirect to dashboard if user tries to visit any non-login page.
		if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
			ctx.Redirect(setting.AppSubUrl + "/")
			return
		}

		if !options.SignOutRequire && !options.DisableCsrf && ctx.Req.Method == "POST" && !auth.IsAPIPath(ctx.Req.URL.Path) {
			csrf.Validate(ctx.Context, ctx.csrf)
			if ctx.Written() {
				return
			}
		}

		if options.SignInRequire {
			if !ctx.IsSigned {
				// Restrict API calls with error message.
				if auth.IsAPIPath(ctx.Req.URL.Path) {
					ctx.APIError(403, "", "Only signed in user is allowed to call APIs.")
					return
				}

				ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
				ctx.Redirect(setting.AppSubUrl + "/user/login")
				return
			} else if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
				ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
				ctx.HTML(200, "user/auth/activate")
				return
			}
		}

		// Try auto-signin when not signed in.
		if !options.SignOutRequire && !ctx.IsSigned && !auth.IsAPIPath(ctx.Req.URL.Path) {
			succeed, err := AutoSignIn(ctx)
			if err != nil {
				ctx.Handle(500, "AutoSignIn", err)
				return
			} else if succeed {
				ctx.Redirect(setting.AppSubUrl + ctx.Req.RequestURI)
				return
			}
		}

		if options.AdminRequire {
			if !ctx.User.IsAdmin {
				ctx.Error(403)
				return
			}
			ctx.Data["PageIsAdmin"] = true
		}
	}
}

// Contexter middleware already checks token for user sign in process.
func ApiReqToken() macaron.Handler {
	return func(ctx *Context) {
		if !ctx.IsSigned {
			ctx.Error(401)
			return
		}
	}
}

func ApiReqBasicAuth() macaron.Handler {
	return func(ctx *Context) {
		if !ctx.IsBasicAuth {
			ctx.Error(401)
			return
		}
	}
}
<|endoftext|>


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

package metrics

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"gopkg.in/zorkian/go-datadog-api.v2"

	"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
	"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/utils/cache"
)

func TestNewMetric(t *testing.T) {
	name := "test.metric"
	ts := uint64(1e9)
	value := 2.0
	tags := []string{"tag:value"}

	metric := newMetric(name, ts, value, tags)

	assert.Equal(t, "test.metric", *metric.Metric)
	// Assert timestamp conversion from uint64 ns to float64 s
	assert.Equal(t, 1.0, *metric.Points[0][0])
	// Assert value
	assert.Equal(t, 2.0, *metric.Points[0][1])
	// Assert tags
	assert.Equal(t, []string{"tag:value"}, metric.Tags)
}

func TestNewType(t *testing.T) {
	name := "test.metric"
	ts := uint64(1e9)
	value := 2.0
	tags := []string{"tag:value"}

	gauge := NewGauge(name, ts, value, tags)
	assert.Equal(t, gauge.GetType(), Gauge)

	count := NewCount(name, ts, value, tags)
	assert.Equal(t, count.GetType(), Count)

}

func TestDefaultMetrics(t *testing.T) {
	logger := zap.NewNop()
	cfg := &config.Config{}

	ms := DefaultMetrics("metrics", uint64(2e9))
	ProcessMetrics(ms, logger, cfg)

	assert.Equal(t, "otel.datadog_exporter.metrics.running", *ms[0].Metric)
	// Assert metrics list length (should be 1)
	assert.Equal(t, 1, len(ms))
	// Assert timestamp
	assert.Equal(t, 2.0, *ms[0].Points[0][0])
	// Assert value (should always be 1.0)
	assert.Equal(t, 1.0, *ms[0].Points[0][1])
}

func TestProcessMetrics(t *testing.T) {
	logger := zap.NewNop()

	// Reset hostname cache
	cache.Cache.Flush()

	cfg := &config.Config{
		// Global tags should be ignored and sent as metadata
		TagsConfig: config.TagsConfig{
			Hostname: "test-host",
			Env:      "test_env",
			Tags:     []string{"key:val"},
		},
	}
	cfg.Sanitize()

	ms := []datadog.Metric{
		NewGauge(
			"metric_name",
			0,
			0,
			[]string{"key2:val2"},
		),
	}

	ProcessMetrics(ms, logger, cfg)

	assert.Equal(t, "test-host", *ms[0].Host)
	assert.Equal(t, "otel.metric_name", *ms[0].Metric)
	assert.ElementsMatch(t,
		[]string{"key2:val2"},
		ms[0].Tags,
	)

}

func TestAddHostname(t *testing.T) {
	logger := zap.NewNop()

	// Reset hostname cache
	cache.Cache.Flush()

	// With hostname in config
	cfg := &config.Config{
		TagsConfig: config.TagsConfig{
			Hostname: "thishost",
		},
	}

	ms := []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
		NewGauge("test.metric2", 0, 2.0, []string{}),
	}

	hostname := "thathost"

	ms[0].Host = &hostname

	addHostname(ms, logger, cfg)

	// Check that all hostnames are set to the config's hostname
	assert.Equal(t, "thishost", *ms[0].Host)
	assert.Equal(t, "thishost", *ms[1].Host)

	// Reset hostname cache
	cache.Cache.Flush()

	// Without hostname in config
	cfg = &config.Config{}

	ms = []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
	}

	ms[0].Host = &hostname

	addHostname(ms, logger, cfg)

	// Check that the already set host remains set
	assert.Equal(t, "thathost", *ms[0].Host)
}

func TestAddNamespace(t *testing.T) {
	ms := []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
		NewGauge("test.metric2", 0, 2.0, []string{}),
	}

	addNamespace(ms, "namespace")

	assert.Equal(t, "namespace.test.metric", *ms[0].Metric)
	assert.Equal(t, "namespace.test.metric2", *ms[1].Metric)
}
<commit_msg>Test that default metrics have no tags set other than hostname (#2014)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metrics

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"gopkg.in/zorkian/go-datadog-api.v2"

	"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/config"
	"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter/utils/cache"
)

func TestNewMetric(t *testing.T) {
	name := "test.metric"
	ts := uint64(1e9)
	value := 2.0
	tags := []string{"tag:value"}

	metric := newMetric(name, ts, value, tags)

	assert.Equal(t, "test.metric", *metric.Metric)
	// Assert timestamp conversion from uint64 ns to float64 s
	assert.Equal(t, 1.0, *metric.Points[0][0])
	// Assert value
	assert.Equal(t, 2.0, *metric.Points[0][1])
	// Assert tags
	assert.Equal(t, []string{"tag:value"}, metric.Tags)
}

func TestNewType(t *testing.T) {
	name := "test.metric"
	ts := uint64(1e9)
	value := 2.0
	tags := []string{"tag:value"}

	gauge := NewGauge(name, ts, value, tags)
	assert.Equal(t, gauge.GetType(), Gauge)

	count := NewCount(name, ts, value, tags)
	assert.Equal(t, count.GetType(), Count)

}

func TestDefaultMetrics(t *testing.T) {
	logger := zap.NewNop()
	cfg := &config.Config{
		// Global tags should be ignored and sent as metadata
		TagsConfig: config.TagsConfig{
			Hostname: "test-host",
			Env:      "test_env",
			Tags:     []string{"key:val"},
		},
	}

	ms := DefaultMetrics("metrics", uint64(2e9))
	ProcessMetrics(ms, logger, cfg)

	assert.Equal(t, "otel.datadog_exporter.metrics.running", *ms[0].Metric)
	// Assert metrics list length (should be 1)
	assert.Equal(t, 1, len(ms))
	// Assert timestamp
	assert.Equal(t, 2.0, *ms[0].Points[0][0])
	// Assert value (should always be 1.0)
	assert.Equal(t, 1.0, *ms[0].Points[0][1])
	// Assert hostname tag is set
	assert.Equal(t, "test-host", *ms[0].Host)
	// Assert no other tags are set
	assert.ElementsMatch(t, []string{}, ms[0].Tags)
}

func TestProcessMetrics(t *testing.T) {
	logger := zap.NewNop()

	// Reset hostname cache
	cache.Cache.Flush()

	cfg := &config.Config{
		// Global tags should be ignored and sent as metadata
		TagsConfig: config.TagsConfig{
			Hostname: "test-host",
			Env:      "test_env",
			Tags:     []string{"key:val"},
		},
	}
	cfg.Sanitize()

	ms := []datadog.Metric{
		NewGauge(
			"metric_name",
			0,
			0,
			[]string{"key2:val2"},
		),
	}

	ProcessMetrics(ms, logger, cfg)

	assert.Equal(t, "test-host", *ms[0].Host)
	assert.Equal(t, "otel.metric_name", *ms[0].Metric)
	assert.ElementsMatch(t,
		[]string{"key2:val2"},
		ms[0].Tags,
	)

}

func TestAddHostname(t *testing.T) {
	logger := zap.NewNop()

	// Reset hostname cache
	cache.Cache.Flush()

	// With hostname in config
	cfg := &config.Config{
		TagsConfig: config.TagsConfig{
			Hostname: "thishost",
		},
	}

	ms := []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
		NewGauge("test.metric2", 0, 2.0, []string{}),
	}

	hostname := "thathost"

	ms[0].Host = &hostname

	addHostname(ms, logger, cfg)

	// Check that all hostnames are set to the config's hostname
	assert.Equal(t, "thishost", *ms[0].Host)
	assert.Equal(t, "thishost", *ms[1].Host)

	// Reset hostname cache
	cache.Cache.Flush()

	// Without hostname in config
	cfg = &config.Config{}

	ms = []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
	}

	ms[0].Host = &hostname

	addHostname(ms, logger, cfg)

	// Check that the already set host remains set
	assert.Equal(t, "thathost", *ms[0].Host)
}

func TestAddNamespace(t *testing.T) {
	ms := []datadog.Metric{
		NewGauge("test.metric", 0, 1.0, []string{}),
		NewGauge("test.metric2", 0, 2.0, []string{}),
	}

	addNamespace(ms, "namespace")

	assert.Equal(t, "namespace.test.metric", *ms[0].Metric)
	assert.Equal(t, "namespace.test.metric2", *ms[1].Metric)
}
<|endoftext|>


<commit_before>package renter

import (
	"errors"
	"io"
	"net"
	"os"
	"sync/atomic"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

var (
	errInsufficientHosts  = errors.New("insufficient hosts to recover file")
	errInsufficientPieces = errors.New("couldn't fetch enough pieces to recover data")
)

// A fetcher fetches pieces from a host. This interface exists to facilitate
// easy testing.
type fetcher interface {
	// pieces returns the set of pieces corresponding to a given chunk.
	pieces(chunk uint64) []pieceData

	// fetch returns the data specified by piece metadata.
	fetch(pieceData) ([]byte, error)
}

// A hostFetcher fetches pieces from a host. It implements the fetcher
// interface.
type hostFetcher struct {
	conn      net.Conn
	pieceMap  map[uint64][]pieceData
	pieceSize uint64
	masterKey crypto.TwofishKey
}

// pieces returns the pieces stored on this host that are part of a given
// chunk.
func (hf *hostFetcher) pieces(chunk uint64) []pieceData {
	return hf.pieceMap[chunk]
}

// fetch downloads the piece specified by p.
func (hf *hostFetcher) fetch(p pieceData) ([]byte, error) {
	hf.conn.SetDeadline(time.Now().Add(1 * time.Minute)) // sufficient to transfer 4 MB over 500 kbps
	defer hf.conn.SetDeadline(time.Time{})
	// request piece
	err := encoding.WriteObject(hf.conn, modules.DownloadRequest{p.Offset, hf.pieceSize})
	if err != nil {
		return nil, err
	}

	// download piece
	data := make([]byte, hf.pieceSize)
	_, err = io.ReadFull(hf.conn, data)
	if err != nil {
		return nil, err
	}

	// generate decryption key
	key := deriveKey(hf.masterKey, p.Chunk, p.Piece)

	// decrypt and return
	return key.DecryptBytes(data)
}

func (hf *hostFetcher) Close() error {
	// ignore error; we'll need to close conn anyway
	encoding.WriteObject(hf.conn, modules.DownloadRequest{0, 0})
	return hf.conn.Close()
}

// newHostFetcher creates a new hostFetcher by connecting to a host.
// TODO: We may not wind up requesting data from this, which means we will
// connect and then disconnect without making any actual requests (but holding
// the connection open the entire time). This is wasteful of host resources.
// Consider only opening the connection after the first request has been made.
func newHostFetcher(fc fileContract, pieceSize uint64, masterKey crypto.TwofishKey) (*hostFetcher, error) {
	conn, err := net.DialTimeout("tcp", string(fc.IP), 15*time.Second)
	if err != nil {
		return nil, err
	}
	conn.SetDeadline(time.Now().Add(15 * time.Second))
	defer conn.SetDeadline(time.Time{})

	// send RPC
	err = encoding.WriteObject(conn, modules.RPCDownload)
	if err != nil {
		return nil, err
	}

	// send contract ID
	err = encoding.WriteObject(conn, fc.ID)
	if err != nil {
		return nil, err
	}

	// make piece map
	pieceMap := make(map[uint64][]pieceData)
	for _, p := range fc.Pieces {
		pieceMap[p.Chunk] = append(pieceMap[p.Chunk], p)
	}
	return &hostFetcher{
		conn:      conn,
		pieceMap:  pieceMap,
		pieceSize: pieceSize + crypto.TwofishOverhead,
		masterKey: masterKey,
	}, nil
}

// checkHosts checks that a set of hosts is sufficient to download a file.
func checkHosts(hosts []fetcher, minPieces int, numChunks uint64) error {
	for i := uint64(0); i < numChunks; i++ {
		pieces := 0
		for _, h := range hosts {
			pieces += len(h.pieces(i))
		}
		if pieces < minPieces {
			return errInsufficientHosts
		}
	}
	return nil
}

// A download is a file download that has been queued by the renter. It
// implements the modules.DownloadInfo interface.
type download struct {
	// NOTE: received is the first field to ensure 64-bit alignment, which is
	// required for atomic operations.
	received uint64

	startTime   time.Time
	nickname    string
	destination string

	erasureCode modules.ErasureCoder
	chunkSize   uint64
	fileSize    uint64
	hosts       []fetcher
}

// StartTime is when the download was initiated.
func (d *download) StartTime() time.Time {
	return d.startTime
}

// Filesize is the size of the file being downloaded.
func (d *download) Filesize() uint64 {
	return d.fileSize
}

// Received is the number of bytes downloaded so far.
func (d *download) Received() uint64 {
	return atomic.LoadUint64(&d.received)
}

// Destination is the filepath that the file was downloaded into.
func (d *download) Destination() string {
	return d.destination
}

// Nickname is the identifier assigned to the file when it was uploaded.
func (d *download) Nickname() string {
	return d.nickname
}

// getPiece locates and downloads a specific piece.
func (d *download) getPiece(chunkIndex, pieceIndex uint64) []byte {
	for _, h := range d.hosts {
		for _, p := range h.pieces(chunkIndex) {
			if p.Piece == pieceIndex {
				data, err := h.fetch(p)
				if err != nil {
					break // try next host
				}
				return data
			}
		}
	}
	return nil
}

// run performs the actual download. It spawns one worker per host, and
// instructs them to sequentially download chunks. It then writes the
// recovered chunks to w.
func (d *download) run(w io.Writer) error {
	var received uint64
	for i := uint64(0); received < d.fileSize; i++ {
		// load pieces into chunk
		chunk := make([][]byte, d.erasureCode.NumPieces())
		left := d.erasureCode.MinPieces()
		// pick hosts at random
		for _, j := range crypto.Perm(len(chunk)) {
			chunk[j] = d.getPiece(i, uint64(j))
			if chunk[j] != nil {
				left--
			}
			if left == 0 {
				break
			}
		}
		if left != 0 {
			return errInsufficientPieces
		}

		// Write pieces to w. We always write chunkSize bytes unless this is
		// the last chunk; in that case, we write the remainder.
		n := d.chunkSize
		if n > d.fileSize-received {
			n = d.fileSize - received
		}
		err := d.erasureCode.Recover(chunk, uint64(n), w)
		if err != nil {
			return err
		}
		received += n
		atomic.AddUint64(&d.received, n)
	}

	return nil
}

// newDownload initializes and returns a download object.
func (f *file) newDownload(hosts []fetcher, destination string) *download {
	return &download{
		erasureCode: f.erasureCode,
		chunkSize:   f.chunkSize(),
		fileSize:    f.size,
		hosts:       hosts,

		startTime:   time.Now(),
		received:    0,
		nickname:    f.name,
		destination: destination,
	}
}

// Download downloads a file, identified by its nickname, to the destination
// specified.
func (r *Renter) Download(nickname, destination string) error {
	// Lookup the file associated with the nickname.
	lockID := r.mu.Lock()
	file, exists := r.files[nickname]
	r.mu.Unlock(lockID)
	if !exists {
		return errors.New("no file of that nickname")
	}

	// Initiate connections to each host.
	var hosts []fetcher
	for _, fc := range file.contracts {
		// TODO: connect in parallel
		hf, err := newHostFetcher(fc, file.pieceSize, file.masterKey)
		if err != nil {
			continue
		}
		defer hf.Close()
		hosts = append(hosts, hf)
	}

	// Check that this host set is sufficient to download the file.
	err := checkHosts(hosts, file.erasureCode.MinPieces(), file.numChunks())
	if err != nil {
		return err
	}

	// Create file on disk with the correct permissions.
	perm := os.FileMode(file.mode)
	if perm == 0 {
		// sane default
		perm = 0666
	}
	f, err := os.OpenFile(destination, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	defer f.Close()

	// Create the download object.
	d := file.newDownload(hosts, destination)

	// Add the download to the download queue.
	lockID = r.mu.Lock()
	r.downloadQueue = append(r.downloadQueue, d)
	r.mu.Unlock(lockID)

	// Perform download.
	err = d.run(f)
	if err != nil {
		// File could not be downloaded; delete the copy on disk.
		os.Remove(destination)
		return err
	}

	return nil
}

// DownloadQueue returns the list of downloads in the queue.
func (r *Renter) DownloadQueue() []modules.DownloadInfo {
	lockID := r.mu.RLock()
	defer r.mu.RUnlock(lockID)

	// order from most recent to least recent
	downloads := make([]modules.DownloadInfo, len(r.downloadQueue))
	for i := range r.downloadQueue {
		downloads[i] = r.downloadQueue[len(r.downloadQueue)-i-1]
	}
	return downloads
}
<commit_msg>increase download deadline<commit_after>package renter

import (
	"errors"
	"io"
	"net"
	"os"
	"sync/atomic"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

var (
	errInsufficientHosts  = errors.New("insufficient hosts to recover file")
	errInsufficientPieces = errors.New("couldn't fetch enough pieces to recover data")
)

// A fetcher fetches pieces from a host. This interface exists to facilitate
// easy testing.
type fetcher interface {
	// pieces returns the set of pieces corresponding to a given chunk.
	pieces(chunk uint64) []pieceData

	// fetch returns the data specified by piece metadata.
	fetch(pieceData) ([]byte, error)
}

// A hostFetcher fetches pieces from a host. It implements the fetcher
// interface.
type hostFetcher struct {
	conn      net.Conn
	pieceMap  map[uint64][]pieceData
	pieceSize uint64
	masterKey crypto.TwofishKey
}

// pieces returns the pieces stored on this host that are part of a given
// chunk.
func (hf *hostFetcher) pieces(chunk uint64) []pieceData {
	return hf.pieceMap[chunk]
}

// fetch downloads the piece specified by p.
func (hf *hostFetcher) fetch(p pieceData) ([]byte, error) {
	hf.conn.SetDeadline(time.Now().Add(2 * time.Minute)) // sufficient to transfer 4 MB over 250 kbps
	defer hf.conn.SetDeadline(time.Time{})
	// request piece
	err := encoding.WriteObject(hf.conn, modules.DownloadRequest{p.Offset, hf.pieceSize})
	if err != nil {
		return nil, err
	}

	// download piece
	data := make([]byte, hf.pieceSize)
	_, err = io.ReadFull(hf.conn, data)
	if err != nil {
		return nil, err
	}

	// generate decryption key
	key := deriveKey(hf.masterKey, p.Chunk, p.Piece)

	// decrypt and return
	return key.DecryptBytes(data)
}

func (hf *hostFetcher) Close() error {
	// ignore error; we'll need to close conn anyway
	encoding.WriteObject(hf.conn, modules.DownloadRequest{0, 0})
	return hf.conn.Close()
}

// newHostFetcher creates a new hostFetcher by connecting to a host.
// TODO: We may not wind up requesting data from this, which means we will
// connect and then disconnect without making any actual requests (but holding
// the connection open the entire time). This is wasteful of host resources.
// Consider only opening the connection after the first request has been made.
func newHostFetcher(fc fileContract, pieceSize uint64, masterKey crypto.TwofishKey) (*hostFetcher, error) {
	conn, err := net.DialTimeout("tcp", string(fc.IP), 15*time.Second)
	if err != nil {
		return nil, err
	}
	conn.SetDeadline(time.Now().Add(15 * time.Second))
	defer conn.SetDeadline(time.Time{})

	// send RPC
	err = encoding.WriteObject(conn, modules.RPCDownload)
	if err != nil {
		return nil, err
	}

	// send contract ID
	err = encoding.WriteObject(conn, fc.ID)
	if err != nil {
		return nil, err
	}

	// make piece map
	pieceMap := make(map[uint64][]pieceData)
	for _, p := range fc.Pieces {
		pieceMap[p.Chunk] = append(pieceMap[p.Chunk], p)
	}
	return &hostFetcher{
		conn:      conn,
		pieceMap:  pieceMap,
		pieceSize: pieceSize + crypto.TwofishOverhead,
		masterKey: masterKey,
	}, nil
}

// checkHosts checks that a set of hosts is sufficient to download a file.
func checkHosts(hosts []fetcher, minPieces int, numChunks uint64) error {
	for i := uint64(0); i < numChunks; i++ {
		pieces := 0
		for _, h := range hosts {
			pieces += len(h.pieces(i))
		}
		if pieces < minPieces {
			return errInsufficientHosts
		}
	}
	return nil
}

// A download is a file download that has been queued by the renter. It
// implements the modules.DownloadInfo interface.
type download struct {
	// NOTE: received is the first field to ensure 64-bit alignment, which is
	// required for atomic operations.
	received uint64

	startTime   time.Time
	nickname    string
	destination string

	erasureCode modules.ErasureCoder
	chunkSize   uint64
	fileSize    uint64
	hosts       []fetcher
}

// StartTime is when the download was initiated.
func (d *download) StartTime() time.Time {
	return d.startTime
}

// Filesize is the size of the file being downloaded.
func (d *download) Filesize() uint64 {
	return d.fileSize
}

// Received is the number of bytes downloaded so far.
func (d *download) Received() uint64 {
	return atomic.LoadUint64(&d.received)
}

// Destination is the filepath that the file was downloaded into.
func (d *download) Destination() string {
	return d.destination
}

// Nickname is the identifier assigned to the file when it was uploaded.
func (d *download) Nickname() string {
	return d.nickname
}

// getPiece locates and downloads a specific piece.
func (d *download) getPiece(chunkIndex, pieceIndex uint64) []byte {
	for _, h := range d.hosts {
		for _, p := range h.pieces(chunkIndex) {
			if p.Piece == pieceIndex {
				data, err := h.fetch(p)
				if err != nil {
					break // try next host
				}
				return data
			}
		}
	}
	return nil
}

// run performs the actual download. It spawns one worker per host, and
// instructs them to sequentially download chunks. It then writes the
// recovered chunks to w.
func (d *download) run(w io.Writer) error {
	var received uint64
	for i := uint64(0); received < d.fileSize; i++ {
		// load pieces into chunk
		chunk := make([][]byte, d.erasureCode.NumPieces())
		left := d.erasureCode.MinPieces()
		// pick hosts at random
		for _, j := range crypto.Perm(len(chunk)) {
			chunk[j] = d.getPiece(i, uint64(j))
			if chunk[j] != nil {
				left--
			}
			if left == 0 {
				break
			}
		}
		if left != 0 {
			return errInsufficientPieces
		}

		// Write pieces to w. We always write chunkSize bytes unless this is
		// the last chunk; in that case, we write the remainder.
		n := d.chunkSize
		if n > d.fileSize-received {
			n = d.fileSize - received
		}
		err := d.erasureCode.Recover(chunk, uint64(n), w)
		if err != nil {
			return err
		}
		received += n
		atomic.AddUint64(&d.received, n)
	}

	return nil
}

// newDownload initializes and returns a download object.
func (f *file) newDownload(hosts []fetcher, destination string) *download {
	return &download{
		erasureCode: f.erasureCode,
		chunkSize:   f.chunkSize(),
		fileSize:    f.size,
		hosts:       hosts,

		startTime:   time.Now(),
		received:    0,
		nickname:    f.name,
		destination: destination,
	}
}

// Download downloads a file, identified by its nickname, to the destination
// specified.
func (r *Renter) Download(nickname, destination string) error {
	// Lookup the file associated with the nickname.
	lockID := r.mu.Lock()
	file, exists := r.files[nickname]
	r.mu.Unlock(lockID)
	if !exists {
		return errors.New("no file of that nickname")
	}

	// Initiate connections to each host.
	var hosts []fetcher
	for _, fc := range file.contracts {
		// TODO: connect in parallel
		hf, err := newHostFetcher(fc, file.pieceSize, file.masterKey)
		if err != nil {
			continue
		}
		defer hf.Close()
		hosts = append(hosts, hf)
	}

	// Check that this host set is sufficient to download the file.
	err := checkHosts(hosts, file.erasureCode.MinPieces(), file.numChunks())
	if err != nil {
		return err
	}

	// Create file on disk with the correct permissions.
	perm := os.FileMode(file.mode)
	if perm == 0 {
		// sane default
		perm = 0666
	}
	f, err := os.OpenFile(destination, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	defer f.Close()

	// Create the download object.
	d := file.newDownload(hosts, destination)

	// Add the download to the download queue.
	lockID = r.mu.Lock()
	r.downloadQueue = append(r.downloadQueue, d)
	r.mu.Unlock(lockID)

	// Perform download.
	err = d.run(f)
	if err != nil {
		// File could not be downloaded; delete the copy on disk.
		os.Remove(destination)
		return err
	}

	return nil
}

// DownloadQueue returns the list of downloads in the queue.
func (r *Renter) DownloadQueue() []modules.DownloadInfo {
	lockID := r.mu.RLock()
	defer r.mu.RUnlock(lockID)

	// order from most recent to least recent
	downloads := make([]modules.DownloadInfo, len(r.downloadQueue))
	for i := range r.downloadQueue {
		downloads[i] = r.downloadQueue[len(r.downloadQueue)-i-1]
	}
	return downloads
}
<|endoftext|>


<commit_before>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package twitter

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"net/url"
	"strconv"
	"strings"
)

type Module struct {
	api               *anaconda.TwitterApi
	ReadOnly          bool   `json:"read_only"`
	ConsumerKey       string `json:"consumer_key"`
	ConsumerSecret    string `json:"consumer_secret"`
	AccessToken       string `json:"access_token"`
	AccessTokenSecret string `json:"access_token_secret"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "twitter"
}

func (m *Module) Help() string {
	return "USAGE: !tweet TEXT || !reply ID TEXT || !retweet ID || !favorite ID"
}

func (m *Module) Defaults() {
	m.ReadOnly = false
}

func (m *Module) Load(client *irc.Client) error {
	anaconda.SetConsumerKey(m.ConsumerKey)
	anaconda.SetConsumerSecret(m.ConsumerSecret)
	m.api = anaconda.NewTwitterApi(m.AccessToken, m.AccessTokenSecret)

	if !m.ReadOnly {
		client.CmdHook("privmsg", m.tweetCmd)
		client.CmdHook("privmsg", m.replyCmd)
		client.CmdHook("privmsg", m.retweetCmd)
		client.CmdHook("privmsg", m.favoriteCmd)
	}

	values := url.Values{}
	values.Add("replies", "all")
	values.Add("with", "user")

	go func(client *irc.Client, values url.Values) {
		for {
			m.streamHandler(client, values)
		}
	}(client, values)

	return nil
}

func (m *Module) tweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!tweet" || !client.Connected(msg.Receiver) {
		return nil
	}

	status := strings.Join(splited[1:], " ")
	if _, err := m.api.PostTweet(status, url.Values{}); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) replyCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 3 || splited[0] != "!reply" || !client.Connected(msg.Receiver) {
		return nil
	}

	values := url.Values{}
	values.Add("in_reply_to_status_id", splited[1])

	status := strings.Join(splited[2:], " ")
	if !strings.Contains(status, "@") {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, "A reply must contain a @mention")
	}

	if _, err := m.api.PostTweet(status, values); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) retweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!retweet" || !client.Connected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Retweet(int64(id), false); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) favoriteCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!favorite" || !client.Connected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Favorite(int64(id)); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) streamHandler(client *irc.Client, values url.Values) {
	stream := m.api.UserStream(values)
	for {
		select {
		case event := <-stream.C:
			if t := m.formatEvent(event); len(t) > 0 {
				m.notify(client, t)
			}
		case <-stream.Quit:
			break
		}
	}
}

func (m *Module) formatEvent(event interface{}) string {
	var msg string
	switch t := event.(type) {
	case anaconda.ApiError:
		msg = fmt.Sprintf("Twitter API error %d: %s", t.StatusCode, t.Decoded.Error())
	case anaconda.StatusDeletionNotice:
		msg = fmt.Sprintf("Tweet %d has been deleted", t.Id)
	case anaconda.Tweet:
		msg = fmt.Sprintf("Tweet %d by %s: %s", t.Id, t.User.ScreenName,
			html.UnescapeString(t.Text))
	case anaconda.EventTweet:
		if t.Event.Event != "favorite" {
			break
		}

		text := html.UnescapeString(t.TargetObject.Text)
		msg = fmt.Sprintf("%s favorited tweet %d by %s: %s",
			t.Source.ScreenName, t.TargetObject.Id, t.Target.ScreenName, text)
	}

	return msg
}

func (m *Module) notify(client *irc.Client, text string) {
	for _, ch := range client.Channels {
		client.Write("NOTICE %s :%s", ch, html.UnescapeString(text))
	}
}
<commit_msg>twitter: add support for DM notifications<commit_after>// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

package twitter

import (
	"fmt"
	"github.com/ChimeraCoder/anaconda"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"html"
	"net/url"
	"strconv"
	"strings"
)

type Module struct {
	api               *anaconda.TwitterApi
	ReadOnly          bool   `json:"read_only"`
	ConsumerKey       string `json:"consumer_key"`
	ConsumerSecret    string `json:"consumer_secret"`
	AccessToken       string `json:"access_token"`
	AccessTokenSecret string `json:"access_token_secret"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "twitter"
}

func (m *Module) Help() string {
	return "USAGE: !tweet TEXT || !reply ID TEXT || !retweet ID || !favorite ID"
}

func (m *Module) Defaults() {
	m.ReadOnly = false
}

func (m *Module) Load(client *irc.Client) error {
	anaconda.SetConsumerKey(m.ConsumerKey)
	anaconda.SetConsumerSecret(m.ConsumerSecret)
	m.api = anaconda.NewTwitterApi(m.AccessToken, m.AccessTokenSecret)

	if !m.ReadOnly {
		client.CmdHook("privmsg", m.tweetCmd)
		client.CmdHook("privmsg", m.replyCmd)
		client.CmdHook("privmsg", m.retweetCmd)
		client.CmdHook("privmsg", m.favoriteCmd)
	}

	values := url.Values{}
	values.Add("replies", "all")
	values.Add("with", "user")

	go func(client *irc.Client, values url.Values) {
		for {
			m.streamHandler(client, values)
		}
	}(client, values)

	return nil
}

func (m *Module) tweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!tweet" || !client.Connected(msg.Receiver) {
		return nil
	}

	status := strings.Join(splited[1:], " ")
	if _, err := m.api.PostTweet(status, url.Values{}); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) replyCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 3 || splited[0] != "!reply" || !client.Connected(msg.Receiver) {
		return nil
	}

	values := url.Values{}
	values.Add("in_reply_to_status_id", splited[1])

	status := strings.Join(splited[2:], " ")
	if !strings.Contains(status, "@") {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, "A reply must contain a @mention")
	}

	if _, err := m.api.PostTweet(status, values); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) retweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!retweet" || !client.Connected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Retweet(int64(id), false); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) favoriteCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!favorite" || !client.Connected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Favorite(int64(id)); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) streamHandler(client *irc.Client, values url.Values) {
	stream := m.api.UserStream(values)
	for {
		select {
		case event := <-stream.C:
			if t := m.formatEvent(event); len(t) > 0 {
				m.notify(client, t)
			}
		case <-stream.Quit:
			break
		}
	}
}

func (m *Module) formatEvent(event interface{}) string {
	var msg string
	switch t := event.(type) {
	case anaconda.ApiError:
		msg = fmt.Sprintf("Twitter API error %d: %s", t.StatusCode, t.Decoded.Error())
	case anaconda.StatusDeletionNotice:
		msg = fmt.Sprintf("Tweet %d has been deleted", t.Id)
	case anaconda.DirectMessage:
		msg = fmt.Sprintf("Direct message %d by %s: %s", t.Id,
			t.SenderScreenName, t.Text)
	case anaconda.Tweet:
		msg = fmt.Sprintf("Tweet %d by %s: %s", t.Id, t.User.ScreenName,
			html.UnescapeString(t.Text))
	case anaconda.EventTweet:
		if t.Event.Event != "favorite" {
			break
		}

		text := html.UnescapeString(t.TargetObject.Text)
		msg = fmt.Sprintf("%s favorited tweet %d by %s: %s",
			t.Source.ScreenName, t.TargetObject.Id, t.Target.ScreenName, text)
	}

	return msg
}

func (m *Module) notify(client *irc.Client, text string) {
	for _, ch := range client.Channels {
		client.Write("NOTICE %s :%s", ch, html.UnescapeString(text))
	}
}
<|endoftext|>


<commit_before>package fastconnect

import (
	"github.com/Jeffail/gabs"
	"github.com/TobiEiss/fiGo"
)

// RetrieveAllTransactions retrieves all transacions of all accounts
func RetrieveAllTransactions(connection fiGo.IConnection, accessToken string) ([]interface{}, error) {
	var transactions []interface{}

	// get transactions
	answerByte, err := connection.RetrieveTransactionsOfAllAccounts(accessToken)
	if err != nil {
		return transactions, err
	}

	// try to get accessToken
	jsonParsed, err := gabs.ParseJSON(answerByte)
	transactions, ok := jsonParsed.Search("transactions").Data().([]interface{})
	if !ok {
		return transactions, err
	}
	return transactions, nil
}
<commit_msg>fastconnect: use transactionOptions<commit_after>package fastconnect

import (
	"github.com/Jeffail/gabs"
	"github.com/TobiEiss/fiGo"
)

// RetrieveAllTransactions retrieves all transacions of all accounts
func RetrieveAllTransactions(connection fiGo.IConnection, accessToken string, options ...fiGo.TransactionOption) ([]interface{}, error) {
	var transactions []interface{}

	// get transactions
	answerByte, err := connection.RetrieveTransactionsOfAllAccounts(accessToken, options...)
	if err != nil {
		return transactions, err
	}

	// try to get accessToken
	jsonParsed, err := gabs.ParseJSON(answerByte)
	transactions, ok := jsonParsed.Search("transactions").Data().([]interface{})
	if !ok {
		return transactions, err
	}
	return transactions, nil
}
<|endoftext|>