<commit_before>package main

import (
	"io/ioutil"
	"path"
	"testing"
)

func TestFiles(t *testing.T) {
	for _, test := range []struct {
		fn  string
		err error
	}{
		{
			fn: "normal",
		},
		{
			fn:  "nomain",
			err: errFuncNotFound,
		},
		{
			fn:  "noparse",
			err: errNoFlagParseCalls,
		},
		{
			fn:  "already_checking",
			err: errAlreadyChecking,
		},
	} {
		const basePath = "testdata"

		var got string
		{
			fn := path.Join(basePath, test.fn+"_in.go")
			s, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatalf("%s: %v", test.fn, err)
			}
			got, err = fix(fn, string(s))
			if err != test.err {
				t.Fatalf("%s: Got error %q, want %q", test.fn, err, test.err)
			}
			if err != nil {
				continue
			}
		}

		var want string
		{
			fn := path.Join(basePath, test.fn+"_out.go")
			wantb, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatalf("%s: %v", test.fn, err)
			}
			want = string(wantb)
		}

		if got != want {
			t.Errorf("Got:\n-----\n%s\n-----\nWant:\n-----\n%s\n-----\n", got, want)
		}
	}
}
<commit_msg>Add license to test file<commit_after>// Copyright 2017 Google Inc.
//
// 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 main

import (
	"io/ioutil"
	"path"
	"testing"
)

func TestFiles(t *testing.T) {
	for _, test := range []struct {
		fn  string
		err error
	}{
		{
			fn: "normal",
		},
		{
			fn:  "nomain",
			err: errFuncNotFound,
		},
		{
			fn:  "noparse",
			err: errNoFlagParseCalls,
		},
		{
			fn:  "already_checking",
			err: errAlreadyChecking,
		},
	} {
		const basePath = "testdata"

		var got string
		{
			fn := path.Join(basePath, test.fn+"_in.go")
			s, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatalf("%s: %v", test.fn, err)
			}
			got, err = fix(fn, string(s))
			if err != test.err {
				t.Fatalf("%s: Got error %q, want %q", test.fn, err, test.err)
			}
			if err != nil {
				continue
			}
		}

		var want string
		{
			fn := path.Join(basePath, test.fn+"_out.go")
			wantb, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatalf("%s: %v", test.fn, err)
			}
			want = string(wantb)
		}

		if got != want {
			t.Errorf("Got:\n-----\n%s\n-----\nWant:\n-----\n%s\n-----\n", got, want)
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-cast"
	"github.com/ninjasphere/go-cast/api"
)

type ReceiverController struct {
	interval time.Duration
	channel  *cast.Channel
}

var getStatus = cast.PayloadHeaders{Type: "GET_STATUS"}

func NewReceiverController(client *cast.Client, sourceId, destinationId string) *ReceiverController {
	controller := &ReceiverController{
		channel: client.NewChannel(sourceId, destinationId, "urn:x-cast:com.google.cast.receiver"),
	}

	controller.channel.OnMessage("RECEIVER_STATUS", controller.onStatus)

	return controller
}

func (c *ReceiverController) onStatus(message *api.CastMessage) {
	spew.Dump("Got status message", message)
}

type StatusResponse struct {
	Status *ReceiverStatus `json:"status,omitempty"`
}

type ReceiverStatus struct {
	Volume *VolumePayload `json:"volume,omitempty"`
}

type VolumePayload struct {
	cast.PayloadHeaders
	Level *float64 `json:"level,omitempty"`
	Muted *bool    `json:"muted,omitempty"`
}

func (c *ReceiverController) GetStatus(timeout time.Duration) (*api.CastMessage, error) {
	return c.channel.Request(&getStatus, timeout)
}

func (c *ReceiverController) SetVolume(volume *VolumePayload, timeout time.Duration) (*api.CastMessage, error) {
	return c.channel.Request(volume, timeout)
}

func (c *ReceiverController) GetVolume(timeout time.Duration) (*VolumePayload, error) {
	message, err := c.GetStatus(timeout)

	if err != nil {
		return nil, err
	}

	response := StatusResponse{}

	err = json.Unmarshal([]byte(*message.PayloadUtf8), &response)

	return response.Status.Volume, err
}
<commit_msg>Expose receiver status as a channel<commit_after>package controllers

import (
	"encoding/json"
	"log"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-cast"
	"github.com/ninjasphere/go-cast/api"
)

type ReceiverController struct {
	interval time.Duration
	channel  *cast.Channel
	Incoming chan *StatusResponse
}

var getStatus = cast.PayloadHeaders{Type: "GET_STATUS"}

func NewReceiverController(client *cast.Client, sourceId, destinationId string) *ReceiverController {
	controller := &ReceiverController{
		channel:  client.NewChannel(sourceId, destinationId, "urn:x-cast:com.google.cast.receiver"),
		Incoming: make(chan *StatusResponse, 0),
	}

	controller.channel.OnMessage("RECEIVER_STATUS", controller.onStatus)

	return controller
}

func (c *ReceiverController) onStatus(message *api.CastMessage) {
	spew.Dump("Got status message", message)

	response := &StatusResponse{}

	err := json.Unmarshal([]byte(*message.PayloadUtf8), response)

	if err != nil {
		log.Printf("Failed to unmarshal status message:%s - %s", err, *message.PayloadUtf8)
		return
	}

	select {
	case c.Incoming <- response:
	default:
		log.Printf("Incoming status, but we aren't listening. %v", response)
	}

}

type StatusResponse struct {
	Status *ReceiverStatus `json:"status,omitempty"`
}

type ReceiverStatus struct {
	cast.PayloadHeaders
	Volume *VolumePayload `json:"volume,omitempty"`
}

type VolumePayload struct {
	Level *float64 `json:"level,omitempty"`
	Muted *bool    `json:"muted,omitempty"`
}

func (c *ReceiverController) GetStatus(timeout time.Duration) (*api.CastMessage, error) {
	return c.channel.Request(&getStatus, timeout)
}

func (c *ReceiverController) SetVolume(volume *VolumePayload, timeout time.Duration) (*api.CastMessage, error) {
	return c.channel.Request(&ReceiverStatus{
		cast.PayloadHeaders{Type: "SET_VOLUME"}, volume,
	}, timeout)
}

func (c *ReceiverController) GetVolume(timeout time.Duration) (*VolumePayload, error) {
	message, err := c.GetStatus(timeout)

	if err != nil {
		return nil, err
	}

	response := StatusResponse{}

	err = json.Unmarshal([]byte(*message.PayloadUtf8), &response)

	return response.Status.Volume, err
}
<|endoftext|>


<commit_before>package zk

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"time"
)

type TestServer struct {
	Port int
	Path string
	Srv  *Server
}

type TestCluster struct {
	Path    string
	Servers []TestServer
}

func StartTestCluster(size int) (*TestCluster, error) {
	tmpPath, err := ioutil.TempDir("", "gozk")
	if err != nil {
		return nil, err
	}
	success := false
	startPort := int(rand.Int31n(6000) + 10000)
	cluster := &TestCluster{Path: tmpPath}
	defer func() {
		if !success {
			cluster.Stop()
		}
	}()
	for serverN := 0; serverN < size; serverN++ {
		srvPath := filepath.Join(tmpPath, fmt.Sprintf("srv%d", serverN))
		if err := os.Mkdir(srvPath, 0700); err != nil {
			return nil, err
		}
		port := startPort + serverN*3
		cfg := ServerConfig{
			ClientPort: port,
			DataDir:    srvPath,
		}
		for i := 0; i < size; i++ {
			cfg.Servers = append(cfg.Servers, ServerConfigServer{
				ID:                 i + 1,
				Host:               "127.0.0.1",
				PeerPort:           startPort + i*3 + 1,
				LeaderElectionPort: startPort + i*3 + 2,
			})
		}
		cfgPath := filepath.Join(srvPath, "zoo.cfg")
		fi, err := os.Create(cfgPath)
		if err != nil {
			return nil, err
		}
		err = cfg.Marshall(fi)
		fi.Close()
		if err != nil {
			return nil, err
		}

		fi, err = os.Create(filepath.Join(srvPath, "myid"))
		if err != nil {
			return nil, err
		}
		_, err = fmt.Fprintf(fi, "%d\n", serverN+1)
		fi.Close()
		if err != nil {
			return nil, err
		}

		srv := &Server{
			ConfigPath: cfgPath,
		}
		if err := srv.Start(); err != nil {
			fmt.Println(err)
			return nil, err
		}
		cluster.Servers = append(cluster.Servers, TestServer{
			Path: srvPath,
			Port: cfg.ClientPort,
			Srv:  srv,
		})
	}
	success = true
	time.Sleep(time.Second) // Give the server time to become active. Should probably actually attempt to connect to verify.
	return cluster, nil
}

func (ts *TestCluster) Connect(idx int) (*Conn, error) {
	zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15)
	return zk, err
}

func (ts *TestCluster) ConnectAll() (*Conn, error) {
	hosts := make([]string, len(ts.Servers))
	for i, srv := range ts.Servers {
		hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port)
	}
	zk, _, err := Connect(hosts, time.Second*15)
	return zk, err
}

func (ts *TestCluster) Stop() error {
	for _, srv := range ts.Servers {
		srv.Srv.Stop()
	}
	defer os.RemoveAll(ts.Path)
	return nil
}
<commit_msg>add test<commit_after>package zk

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"time"
)

type TestServer struct {
	Port int
	Path string
	Srv  *Server
}

type TestCluster struct {
	Path    string
	Servers []TestServer
}

func StartTestCluster(size int) (*TestCluster, error) {
	tmpPath, err := ioutil.TempDir("", "gozk")
	if err != nil {
		return nil, err
	}
	success := false
	startPort := int(rand.Int31n(6000) + 10000)
	cluster := &TestCluster{Path: tmpPath}
	defer func() {
		if !success {
			cluster.Stop()
		}
	}()
	for serverN := 0; serverN < size; serverN++ {
		srvPath := filepath.Join(tmpPath, fmt.Sprintf("srv%d", serverN))
		if err := os.Mkdir(srvPath, 0700); err != nil {
			return nil, err
		}
		port := startPort + serverN*3
		cfg := ServerConfig{
			ClientPort: port,
			DataDir:    srvPath,
		}
		for i := 0; i < size; i++ {
			cfg.Servers = append(cfg.Servers, ServerConfigServer{
				ID:                 i + 1,
				Host:               "127.0.0.1",
				PeerPort:           startPort + i*3 + 1,
				LeaderElectionPort: startPort + i*3 + 2,
			})
		}
		cfgPath := filepath.Join(srvPath, "zoo.cfg")
		fi, err := os.Create(cfgPath)
		if err != nil {
			return nil, err
		}
		err = cfg.Marshall(fi)
		fi.Close()
		if err != nil {
			return nil, err
		}

		fi, err = os.Create(filepath.Join(srvPath, "myid"))
		if err != nil {
			return nil, err
		}
		_, err = fmt.Fprintf(fi, "%d\n", serverN+1)
		fi.Close()
		if err != nil {
			return nil, err
		}

		srv := &Server{
			ConfigPath: cfgPath,
		}
		if err := srv.Start(); err != nil {
			fmt.Println(err)
			return nil, err
		}
		cluster.Servers = append(cluster.Servers, TestServer{
			Path: srvPath,
			Port: cfg.ClientPort,
			Srv:  srv,
		})
	}
	success = true
	time.Sleep(time.Second) // Give the server time to become active. Should probably actually attempt to connect to verify.
	return cluster, nil
}

func (ts *TestCluster) Connect(idx int) (*Conn, error) {
	zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15)
	return zk, err
}

func (ts *TestCluster) ConnectAll() (*Conn, error) {
	hosts := make([]string, len(ts.Servers))
	for i, srv := range ts.Servers {
		hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port)
	}
	conf := ConnConf{
		RecvTimeout:    30000,
		ConnTimeout:    3 * time.Second,
		SessionTimeout: 30000,
	}
	zk, _, err := ConnectWithConfDialer(hosts, conf, nil)
	return zk, err
}

func (ts *TestCluster) Stop() error {
	for _, srv := range ts.Servers {
		srv.Srv.Stop()
	}
	defer os.RemoveAll(ts.Path)
	return nil
}
<|endoftext|>


<commit_before>package proxy

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync"
	"time"

	fcgi "github.com/bakins/grpc-fastcgi-proxy/internal/fcgi_client"
	"github.com/pkg/errors"
)

type clientWrapper struct {
	*fcgi.FCGIClient
}

type client struct {
	sync.Mutex
	addr    string
	clients chan *clientWrapper
	server  *Server
}

type fastcgiResponse struct {
	code   int
	body   []byte
	header http.Header
}

func newClient(s *Server, addr string, num int) *client {
	p := &client{
		addr:    addr,
		server:  s,
		clients: make(chan *clientWrapper, num),
	}

	for i := 0; i < num; i++ {
		p.clients <- &clientWrapper{}
	}

	return p
}

func (c *client) acquireClient() (*clientWrapper, error) {
	w := <-c.clients

	if w.FCGIClient != nil {
		return w, nil
	}

	f, err := fcgi.DialTimeout("tcp", c.addr, 3*time.Second)
	if err != nil {
		return nil, errors.Wrap(err, "dial failed")
	}

	w.FCGIClient = f

	return w, nil
}

func (c *client) releaseClient(w *clientWrapper) {
	c.clients <- w
}

func (w *clientWrapper) close() {
	if w.FCGIClient == nil {
		return
	}

	w.FCGIClient.Close()

	w.FCGIClient = nil
}

func (c *client) request(r *http.Request, script string, env map[string]string) (*fastcgiResponse, error) {
	resp := &fastcgiResponse{}
	w, err := c.acquireClient()
	if err != nil {
		resp.code = 500
		return resp, errors.Wrap(err, "Failed to acquire client")
	}
	defer c.releaseClient(w)

	params := map[string]string{
		"SCRIPT_FILENAME":   script,
		"DOCUMENT_ROOT":     c.server.docRoot,
		"REQUEST_METHOD":    r.Method,
		"SERVER_PROTOCOL":   fmt.Sprintf("HTTP/%d.%d", r.ProtoMajor, r.ProtoMinor),
		"HTTP_HOST":         r.Host,
		"CONTENT_LENGTH":    fmt.Sprintf("%d", r.ContentLength),
		"CONTENT_TYPE":      r.Header.Get("Content-Type"),
		"REQUEST_URI":       r.RequestURI,
		"SCRIPT_NAME":       r.URL.Path,
		"GATEWAY_INTERFACE": "CGI/1.1",
		"QUERY_STRING":      r.URL.RawQuery,
	}

	for k, v := range env {
		params[k] = v
	}

	response, err := w.Request(params, r.Body)
	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to make fasctgi request")
	}

	content, err := ioutil.ReadAll(response.Body)
	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to read response from fastci")
	}

	resp.code = response.StatusCode
	resp.body = content
	resp.header = response.Header
	resp.code, err = statusFromHeaders(resp.header)

	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to get status")
	}

	return resp, nil
}

func statusFromHeaders(h http.Header) (int, error) {
	text := h.Get("Status")

	h.Del("Status")

	if text == "" {
		return 200, nil
	}

	return strconv.Atoi(text[0:3])
}
<commit_msg>lowercse error<commit_after>package proxy

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync"
	"time"

	fcgi "github.com/bakins/grpc-fastcgi-proxy/internal/fcgi_client"
	"github.com/pkg/errors"
)

type clientWrapper struct {
	*fcgi.FCGIClient
}

type client struct {
	sync.Mutex
	addr    string
	clients chan *clientWrapper
	server  *Server
}

type fastcgiResponse struct {
	code   int
	body   []byte
	header http.Header
}

func newClient(s *Server, addr string, num int) *client {
	p := &client{
		addr:    addr,
		server:  s,
		clients: make(chan *clientWrapper, num),
	}

	for i := 0; i < num; i++ {
		p.clients <- &clientWrapper{}
	}

	return p
}

func (c *client) acquireClient() (*clientWrapper, error) {
	w := <-c.clients

	if w.FCGIClient != nil {
		return w, nil
	}

	f, err := fcgi.DialTimeout("tcp", c.addr, 3*time.Second)
	if err != nil {
		return nil, errors.Wrap(err, "dial failed")
	}

	w.FCGIClient = f

	return w, nil
}

func (c *client) releaseClient(w *clientWrapper) {
	c.clients <- w
}

func (w *clientWrapper) close() {
	if w.FCGIClient == nil {
		return
	}

	w.FCGIClient.Close()

	w.FCGIClient = nil
}

func (c *client) request(r *http.Request, script string, env map[string]string) (*fastcgiResponse, error) {
	resp := &fastcgiResponse{}
	w, err := c.acquireClient()
	if err != nil {
		resp.code = 500
		return resp, errors.Wrap(err, "failed to acquire client")
	}
	defer c.releaseClient(w)

	params := map[string]string{
		"SCRIPT_FILENAME":   script,
		"DOCUMENT_ROOT":     c.server.docRoot,
		"REQUEST_METHOD":    r.Method,
		"SERVER_PROTOCOL":   fmt.Sprintf("HTTP/%d.%d", r.ProtoMajor, r.ProtoMinor),
		"HTTP_HOST":         r.Host,
		"CONTENT_LENGTH":    fmt.Sprintf("%d", r.ContentLength),
		"CONTENT_TYPE":      r.Header.Get("Content-Type"),
		"REQUEST_URI":       r.RequestURI,
		"SCRIPT_NAME":       r.URL.Path,
		"GATEWAY_INTERFACE": "CGI/1.1",
		"QUERY_STRING":      r.URL.RawQuery,
	}

	for k, v := range env {
		params[k] = v
	}

	response, err := w.Request(params, r.Body)
	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to make fasctgi request")
	}

	content, err := ioutil.ReadAll(response.Body)
	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to read response from fastci")
	}

	resp.code = response.StatusCode
	resp.body = content
	resp.header = response.Header
	resp.code, err = statusFromHeaders(resp.header)

	if err != nil {
		resp.code = 500
		w.close()
		return resp, errors.Wrap(err, "failed to get status")
	}

	return resp, nil
}

func statusFromHeaders(h http.Header) (int, error) {
	text := h.Get("Status")

	h.Del("Status")

	if text == "" {
		return 200, nil
	}

	return strconv.Atoi(text[0:3])
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"http"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"sync"
	"time"
	"xml"
)

var flagBase *string = flag.String("base", "http://www.picpix.com/kelly",
	"e.g. http://www.picpix.com/username (no trailing slash)")

var flagDest *string = flag.String("dest", "/home/bradfitz/backup/picpix/kelly", "Destination backup root")

var flagSloppy *bool = flag.Bool("sloppy", false, "Continue on errors")

var galleryMutex sync.Mutex
var galleryMap map[string]*Gallery = make(map[string]*Gallery)

// Only allow 10 fetches at a time.
var fetchGate chan bool = make(chan bool, 10)

var errorMutex sync.Mutex
var errors []string = make([]string, 0)

var galleryPattern *regexp.Regexp = regexp.MustCompile(
	"/gallery/([0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z])")

func addError(msg string) {
	errorMutex.Lock()
	defer errorMutex.Unlock()
	errors = append(errors, msg)
	if *flagSloppy {
		log.Printf("ERROR: %s", msg)
	} else {
		log.Exitf("ERROR: %s", msg)
	}
}

func startFetch() {
	// Buffered channel, will block if too many in-flight.
	fetchGate <- true
}

func endFetch() {
	<-fetchGate
}

type Gallery struct {
	key  string
}

func (g *Gallery) GalleryXmlUrl() string {
	return fmt.Sprintf("%s/gallery/%s.xml", *flagBase, g.key)
}

func (g *Gallery) Fetch() {
	startFetch()
	defer endFetch()

	galXmlFilename := fmt.Sprintf("%s/gallery-%s.xml", *flagDest, g.key)
	fi, statErr := os.Stat(galXmlFilename)
	if statErr != nil || fi.Size == 0 {
		res, _, err := http.Get(g.GalleryXmlUrl())
		if err != nil {
			addError(fmt.Sprintf("Error fetching %s: %v", g.GalleryXmlUrl(), err))
			return
		}
		defer res.Body.Close()

		galXml, err := ioutil.ReadAll(res.Body)
		if err != nil {
			addError(fmt.Sprintf("Error reading XML from %s: %v", g.GalleryXmlUrl(), err))
			return
		}

		err = ioutil.WriteFile(galXmlFilename, galXml, 0600)
 		if err != nil {
			addError(fmt.Sprintf("Error writing file %s: %v", galXmlFilename, err))
			return
		}
	}

	fetchPhotosInGallery(galXmlFilename)
}

type DigestInfo struct {
	XMLName xml.Name "digest"
	Type  string "attr"
	Value string "chardata"
}

type MediaFile struct {
	XMLName xml.Name "file"
	Digest DigestInfo
	Mime string
	Width int
	Height int
	Bytes int
	Url string  // the raw URL
}

type MediaSetItem struct {
	XMLName xml.Name "mediaSetItem"
	Title string
	Description string
	InfoURL string  // the xml URL
	File MediaFile
}

type MediaSetItemsWrapper struct {
	XMLName xml.Name "mediaSetItems"
	MediaSetItem []MediaSetItem
}

type LinkedFromSet struct {
	XMLName xml.Name "linkedFrom"
	InfoURL []string   // xml gallery URLs of 'parent' galleries (not a DAG)
}

type LinkedToSet struct {
	XMLName xml.Name "linkedTo"
	InfoURL []string   // xml gallery URLs of 'children' galleries (not a DAG)
}

type MediaSet struct {
	XMLName xml.Name "mediaSet"
	MediaSetItems MediaSetItemsWrapper
	LinkedFrom  LinkedFromSet
	LinkedTo    LinkedToSet
}

func fetchPhotosInGallery(filename string) {
	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		addError(fmt.Sprintf("Failed to open %s: %v", filename, err))
		return
	}
	defer f.Close()
	mediaSet := new(MediaSet)
	err = xml.Unmarshal(f, mediaSet)
	if err != nil {
                addError(fmt.Sprintf("Failed to unmarshal %s: %v", filename, err))
                return
        }

	// Learn about new galleries, potentially?
	for _, url := range mediaSet.LinkedFrom.InfoURL {
		noteGallery(url)
	}
	for _, url := range mediaSet.LinkedTo.InfoURL {
		noteGallery(url)
	}

	log.Printf("Parse of %s is: %q", filename, mediaSet)
	for _, item := range mediaSet.MediaSetItems.MediaSetItem {
		log.Printf("   pic: %s", item.InfoURL)
	}
}

func knownGalleries() int {
	galleryMutex.Lock()
	defer galleryMutex.Unlock()
	return len(galleryMap)
}

func noteGallery(keyOrUrl string) {
	var key string

	if len(keyOrUrl) == 8 {
		key = keyOrUrl
	} else {
		matches := galleryPattern.FindAllStringSubmatch(keyOrUrl, -1)
		if len(matches) == 1 {
			key = matches[0][1]
		} else {
			addError("Bogus noted gallery: " + key)
			return
		}
	}
	galleryMutex.Lock()
	defer galleryMutex.Unlock()
	if _, known := galleryMap[key]; known {
		return
	}
	gallery := &Gallery{key}
	galleryMap[key] = gallery
	go gallery.Fetch()
}

func fetchGalleryPage(page int) {
	log.Printf("Fetching gallery page %d", page)
	res, finalUrl, err := http.Get(fmt.Sprintf("%s/?sort=alpha&page=%d",
		*flagBase, page))
	if err != nil {
		log.Exitf("Error fetching gallery page %d: %v", page, err)
	}
	log.Printf("Fetched page %d: %s", page, finalUrl)
	htmlBytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Exitf("Error reading gallery page %d's HTML: %v", page, err)
	}
	res.Body.Close()

	html := string(htmlBytes)
	log.Printf("read %d bytes", len(html))

	matches := galleryPattern.FindAllStringSubmatch(html, -1)
	log.Printf("Matched: %q", matches)
	for _, match := range matches {
		noteGallery(match[1])
	}
}

func main() {
	flag.Parse()
	log.Printf("Starting.")

	page := 1
	for {
		countBefore := knownGalleries()
		fetchGalleryPage(page)
		countAfter := knownGalleries()
		log.Printf("Galleries known: %d", countAfter)
		if countAfter == countBefore {
			log.Printf("No new galleries, stopping.")
			break
		}
		page++
	}

	for len(fetchGate) > 0 {
		log.Printf("Picture downloads in-flight.  Waiting.")
		time.Sleep(5 * 1e9)
	}
	log.Printf("Done.")
}<commit_msg>re-do operation tracking<commit_after>package main

import (
	"flag"
	"fmt"
	"http"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"sync"
	"time"
	"xml"
)

var flagBase *string = flag.String("base", "http://www.picpix.com/kelly",
	"e.g. http://www.picpix.com/username (no trailing slash)")

var flagDest *string = flag.String("dest", "/home/bradfitz/backup/picpix/kelly", "Destination backup root")

var flagSloppy *bool = flag.Bool("sloppy", false, "Continue on errors")

var galleryMutex sync.Mutex
var galleryMap map[string]*Gallery = make(map[string]*Gallery)

// Only allow 10 fetches at a time.
var fetchGate chan bool = make(chan bool, 10)

var opsMutex sync.Mutex
var opsInFlight int

var errorMutex sync.Mutex
var errors []string = make([]string, 0)

var galleryPattern *regexp.Regexp = regexp.MustCompile(
	"/gallery/([0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z])")

func addError(msg string) {
	errorMutex.Lock()
	defer errorMutex.Unlock()
	errors = append(errors, msg)
	if *flagSloppy {
		log.Printf("ERROR: %s", msg)
	} else {
		log.Exitf("ERROR: %s", msg)
	}
}

type Operation interface {
	Done()
}

type NetworkOperation int
type LocalOperation int

func NewLocalOperation() Operation {
	opsMutex.Lock()
	defer opsMutex.Unlock()
	opsInFlight++
	return LocalOperation(0)
}

func NewNetworkOperation() Operation {
	opsMutex.Lock()
	defer opsMutex.Unlock()
	opsInFlight++
	// Buffered channel, will block if too many in-flight.
        fetchGate <- true
	return NetworkOperation(0)
}

func (o LocalOperation) Done() {
	opsMutex.Lock()
        defer opsMutex.Unlock()
	opsInFlight--
}

func (o NetworkOperation) Done() {
	opsMutex.Lock()
        defer opsMutex.Unlock()
	opsInFlight--
	<-fetchGate
}

func AreOperationsInFlight() bool {
	opsMutex.Lock()
        defer opsMutex.Unlock()
	return opsInFlight > 0
}

type Gallery struct {
	key  string
}

func (g *Gallery) GalleryXmlUrl() string {
	return fmt.Sprintf("%s/gallery/%s.xml", *flagBase, g.key)
}

func (g *Gallery) Fetch(op Operation) {
	defer op.Done()

	galXmlFilename := fmt.Sprintf("%s/gallery-%s.xml", *flagDest, g.key)
	fi, statErr := os.Stat(galXmlFilename)
	if statErr != nil || fi.Size == 0 {
		netop := NewNetworkOperation()
		res, _, err := http.Get(g.GalleryXmlUrl())
		if err != nil {
			addError(fmt.Sprintf("Error fetching %s: %v", g.GalleryXmlUrl(), err))
			return
		}
		defer res.Body.Close()

		galXml, err := ioutil.ReadAll(res.Body)
		netop.Done()
		if err != nil {
			addError(fmt.Sprintf("Error reading XML from %s: %v", g.GalleryXmlUrl(), err))
			return
		}

		err = ioutil.WriteFile(galXmlFilename, galXml, 0600)
 		if err != nil {
			addError(fmt.Sprintf("Error writing file %s: %v", galXmlFilename, err))
			return
		}
	}

	go fetchPhotosInGallery(galXmlFilename, NewLocalOperation())
}

type DigestInfo struct {
	XMLName xml.Name "digest"
	Type  string "attr"
	Value string "chardata"
}

type MediaFile struct {
	XMLName xml.Name "file"
	Digest DigestInfo
	Mime string
	Width int
	Height int
	Bytes int
	Url string  // the raw URL
}

type MediaSetItem struct {
	XMLName xml.Name "mediaSetItem"
	Title string
	Description string
	InfoURL string  // the xml URL
	File MediaFile
}

type MediaSetItemsWrapper struct {
	XMLName xml.Name "mediaSetItems"
	MediaSetItem []MediaSetItem
}

type LinkedFromSet struct {
	XMLName xml.Name "linkedFrom"
	InfoURL []string   // xml gallery URLs of 'parent' galleries (not a DAG)
}

type LinkedToSet struct {
	XMLName xml.Name "linkedTo"
	InfoURL []string   // xml gallery URLs of 'children' galleries (not a DAG)
}

type MediaSet struct {
	XMLName xml.Name "mediaSet"
	MediaSetItems MediaSetItemsWrapper
	LinkedFrom  LinkedFromSet
	LinkedTo    LinkedToSet
}

func fetchPhotosInGallery(filename string, op Operation) {
	defer op.Done()

	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		addError(fmt.Sprintf("Failed to open %s: %v", filename, err))
		return
	}
	defer f.Close()
	mediaSet := new(MediaSet)
	err = xml.Unmarshal(f, mediaSet)
	if err != nil {
                addError(fmt.Sprintf("Failed to unmarshal %s: %v", filename, err))
                return
        }

	// Learn about new galleries, potentially?
	for _, url := range mediaSet.LinkedFrom.InfoURL {
		noteGallery(url)
	}
	for _, url := range mediaSet.LinkedTo.InfoURL {
		noteGallery(url)
	}

	log.Printf("Parse of %s is: %q", filename, mediaSet)
	for _, item := range mediaSet.MediaSetItems.MediaSetItem {
		log.Printf("   pic: %s", item.InfoURL)
	}
}

func knownGalleries() int {
	galleryMutex.Lock()
	defer galleryMutex.Unlock()
	return len(galleryMap)
}

func noteGallery(keyOrUrl string) {
	var key string

	if len(keyOrUrl) == 8 {
		key = keyOrUrl
	} else {
		matches := galleryPattern.FindAllStringSubmatch(keyOrUrl, -1)
		if len(matches) == 1 {
			key = matches[0][1]
		} else {
			addError("Bogus noted gallery: " + key)
			return
		}
	}
	galleryMutex.Lock()
	defer galleryMutex.Unlock()
	if _, known := galleryMap[key]; known {
		return
	}
	gallery := &Gallery{key}
	galleryMap[key] = gallery

	op := NewLocalOperation()
	go gallery.Fetch(op)
}

func fetchGalleryPage(page int) {
	log.Printf("Fetching gallery page %d", page)
	res, finalUrl, err := http.Get(fmt.Sprintf("%s/?sort=alpha&page=%d",
		*flagBase, page))
	if err != nil {
		log.Exitf("Error fetching gallery page %d: %v", page, err)
	}
	log.Printf("Fetched page %d: %s", page, finalUrl)
	htmlBytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Exitf("Error reading gallery page %d's HTML: %v", page, err)
	}
	res.Body.Close()

	html := string(htmlBytes)
	log.Printf("read %d bytes", len(html))

	matches := galleryPattern.FindAllStringSubmatch(html, -1)
	log.Printf("Matched: %q", matches)
	for _, match := range matches {
		noteGallery(match[1])
	}
}

func main() {
	flag.Parse()
	log.Printf("Starting.")

	page := 1
	for {
		countBefore := knownGalleries()
		fetchGalleryPage(page)
		countAfter := knownGalleries()
		log.Printf("Galleries known: %d", countAfter)
		if countAfter == countBefore {
			log.Printf("No new galleries, stopping.")
			break
		}
		page++
	}

	for AreOperationsInFlight() {
		log.Printf("Operations in-flight.  Waiting.")
		time.Sleep(5 * 1e9)
	}
	log.Printf("Done.")
}<|endoftext|>


<commit_before>package collector

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
)

type descMap map[string]*prometheus.Desc

const (
	namespace = "squid"
	timeout   = 10 * time.Second
)

var (
	counters descMap
)

/*Exporter entry point to squid exporter */
type Exporter struct {
	client SquidClient

	hostname string
	port     int

	up *prometheus.GaugeVec
}

/*New initializes a new exporter */
func New(hostname string, port int, login string, password string) *Exporter {
	c := NewCacheObjectClient(hostname, port, login, password)

	return &Exporter{
		c,

		hostname,
		port,

		prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "up",
			Help:      "Was the last query of squid successful?",
		}, []string{"region"}),
	}
}

// Describe describes all the metrics ever exported by the ECS exporter. It
// implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.up.Describe(ch)

	for _, v := range counters {
		ch <- v
	}

}

/*Collect fetches metrics from squid manager and pushes them to promethus */
func (e *Exporter) Collect(c chan<- prometheus.Metric) {
	insts, err := e.client.GetCounters()

	if err == nil {
		e.up.With(prometheus.Labels{"region": e.hostname}).Set(1)
		for i := range insts {
			if d, ok := counters[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, insts[i].Value)
			}
		}
	} else {
		e.up.With(prometheus.Labels{"region": e.hostname}).Set(0)
		log.Println("Could not fetch metrics from squid instance: ", err)
	}
	e.up.Collect(c)
}

func init() {
	prometheus.MustRegister(version.NewCollector("squid_exporter"))

	counters = generateSquidCounters()
}
<commit_msg>Change region to host<commit_after>package collector

import (
	"log"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/version"
)

type descMap map[string]*prometheus.Desc

const (
	namespace = "squid"
	timeout   = 10 * time.Second
)

var (
	counters descMap
)

/*Exporter entry point to squid exporter */
type Exporter struct {
	client SquidClient

	hostname string
	port     int

	up *prometheus.GaugeVec
}

/*New initializes a new exporter */
func New(hostname string, port int, login string, password string) *Exporter {
	c := NewCacheObjectClient(hostname, port, login, password)

	return &Exporter{
		c,

		hostname,
		port,

		prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "up",
			Help:      "Was the last query of squid successful?",
		}, []string{"host"}),
	}
}

// Describe describes all the metrics ever exported by the ECS exporter. It
// implements prometheus.Collector.
func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.up.Describe(ch)

	for _, v := range counters {
		ch <- v
	}

}

/*Collect fetches metrics from squid manager and pushes them to promethus */
func (e *Exporter) Collect(c chan<- prometheus.Metric) {
	insts, err := e.client.GetCounters()

	if err == nil {
		e.up.With(prometheus.Labels{"host": e.hostname}).Set(1)
		for i := range insts {
			if d, ok := counters[insts[i].Key]; ok {
				c <- prometheus.MustNewConstMetric(d, prometheus.CounterValue, insts[i].Value)
			}
		}
	} else {
		e.up.With(prometheus.Labels{"host": e.hostname}).Set(0)
		log.Println("Could not fetch metrics from squid instance: ", err)
	}
	e.up.Collect(c)
}

func init() {
	prometheus.MustRegister(version.NewCollector("squid_exporter"))

	counters = generateSquidCounters()
}
<|endoftext|>


<commit_before>package main

import "github.com/codeclimate/cc-engine-go/engine"
import "sourcegraph.com/sourcegraph/go-diff/diff"
import "os/exec"
import "strconv"
import "os"
import "strings"

func main() {
	rootPath := "/code/"

	config, err := engine.LoadConfig()
	if err != nil {
		os.Exit(1)
	}

	analysisFiles, err := engine.GoFileWalk(rootPath, engine.IncludePaths(rootPath, config))
	if err != nil {
		os.Exit(1)
	}

	for _, path := range analysisFiles {
		cmd := exec.Command("/usr/src/app/bin/gofmt", "-d", path)
		out, err := cmd.CombinedOutput()
		if err != nil {
			return
		}

		diffs, err := diff.ParseMultiFileDiff(out)
		if err != nil {
			return
		}

		if diffs != nil && diffs[0] != nil && len(diffs[0].Hunks) > 0 {
			numHunks := strconv.Itoa((len(diffs[0].Hunks)))
			path := strings.SplitAfter(path, rootPath)[1]

			issue := &engine.Issue{
				Type:              "issue",
				Check:             "GoFmt/Style/GoFmt",
				Description:       "Your code does not pass gofmt in " + numHunks + " places. Go fmt your code!",
				RemediationPoints: int32(50000 * len(diffs[0].Hunks)),
				Categories:        []string{"Style"},
				Location: &engine.Location{
					Path: path,
					Lines: &engine.LinesOnlyPosition{
						Begin: 1,
						End:   1,
					},
				},
			}
			engine.PrintIssue(issue)
		}
	}

	os.Exit(0)
}
<commit_msg>Add support for logging errors<commit_after>package main

import (
	"github.com/codeclimate/cc-engine-go/engine"
	"sourcegraph.com/sourcegraph/go-diff/diff"
	"os/exec"
	"strconv"
	"os"
	"strings"
	"fmt"
)

func main() {
	rootPath := "/code/"

	config, err := engine.LoadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error loading config: %s", err)
		os.Exit(1)
	}

	analysisFiles, err := engine.GoFileWalk(rootPath, engine.IncludePaths(rootPath, config))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error initializing: %s", err)
		os.Exit(1)
	}

	for _, path := range analysisFiles {
		cmd := exec.Command("/usr/src/app/bin/gofmt", "-d", path)
		out, err := cmd.CombinedOutput()
		if err != nil {
			return
		}

		diffs, err := diff.ParseMultiFileDiff(out)
		if err != nil {
			return
		}

		if diffs != nil && diffs[0] != nil && len(diffs[0].Hunks) > 0 {
			numHunks := strconv.Itoa((len(diffs[0].Hunks)))
			path := strings.SplitAfter(path, rootPath)[1]

			issue := &engine.Issue{
				Type:              "issue",
				Check:             "GoFmt/Style/GoFmt",
				Description:       "Your code does not pass gofmt in " + numHunks + " places. Go fmt your code!",
				RemediationPoints: int32(50000 * len(diffs[0].Hunks)),
				Categories:        []string{"Style"},
				Location: &engine.Location{
					Path: path,
					Lines: &engine.LinesOnlyPosition{
						Begin: 1,
						End:   1,
					},
				},
			}
			engine.PrintIssue(issue)
		}
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package combiner

import (
  "time"
  "log"
  "fmt"
  "io/ioutil"
  "errors"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
  "pdfcombiner/cpdf"
)

var (
  verbose = true
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  defdocs = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf",
                     "100035.pdf","100037.pdf","100038.pdf","100093.pdf"}
)

type Job struct {
  BucketName string
  EmployerId int
  DocList    []string
  Callback   string
  Errors     []error
  Bucket     *s3.Bucket
}

type stat struct {
  filename string
  size     int
  dlSecs   time.Duration
}

func (j *Job) IsValid() bool {
 return (j.BucketName != "") &&
        (j.Callback   != "") &&
        (j.EmployerId > 0)   &&
        (j.DocCount() > 0)
}

func (j *Job) DocCount() int {
  return len(j.DocList)
}

func (j *Job) AddError(newErr error) {
  log.Println(newErr)
  j.Errors = append(j.Errors, newErr)
}

func (j *Job) connect() {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  j.Bucket = s.Bucket(bucketName)
}

func (j *Job) getFile(docname string, c chan stat, e chan error) {
  start := time.Now()
  data, err := j.Bucket.Get(j.s3Path(docname))
  if err != nil {
    e <- fmt.Errorf("%v: %v", docname, err)
    return
  }
  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil {
    e <- err; return
    return
  }
  c <- stat{ filename: docname,
             size: len(data),
             dlSecs: time.Since(start) }
}

func (j *Job) s3Path(docname string) string {
  return fmt.Sprintf("%d/docs/%s", j.EmployerId, docname)
}

func (j *Job) getAllFiles() {
  start := time.Now()
  j.connect()
  c := make(chan stat)
  e := make(chan error)
  for _,doc := range j.DocList{
    go j.getFile(doc,c,e)
  }

  totalBytes := j.waitForDownloads(c,e)
  printSummary(start, totalBytes, j.DocCount())
}

func (j *Job) waitForDownloads(c chan stat, e chan error) (totalBytes int) {
  for _,_ = range j.DocList{
    select {
      case packet := <-c:
        if verbose { log.Printf("%s was %d bytes\n", packet.filename,packet.size) }
        totalBytes += packet.size
      case err := <-e:
        j.AddError(err)
      case <-time.After(2 * time.Minute):
        j.AddError(errors.New("Timed out while downloading"))
        return
    }
  }
  return
}

func printSummary(start time.Time, bytes int, count int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, count, seconds, mbps)
}

func (j *Job) postToCallback(){
  log.Println("work complete, posting success to callback:",j.Callback)
  log.Println(j)
}

func (j *Job) Combine() bool {
  defer j.postToCallback()
  j.getAllFiles()
  if len(j.Errors) > 0 {
    cpdf.Merge(j.DocList)
  }
  return true
}

<commit_msg>Maintain a separate list of downloaded docs<commit_after>package combiner

import (
  "time"
  "log"
  "fmt"
  "io/ioutil"
  "errors"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
  "pdfcombiner/cpdf"
)

var (
  verbose = true
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  defdocs = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf",
                     "100035.pdf","100037.pdf","100038.pdf","100093.pdf"}
)

type Job struct {
  BucketName string
  EmployerId int
  DocList    []string
  Downloaded []string
  Callback   string
  Errors     []error
  Bucket     *s3.Bucket
}

type stat struct {
  filename string
  size     int
  dlSecs   time.Duration
}

func (j *Job) IsValid() bool {
 return (j.BucketName != "") &&
        (j.Callback   != "") &&
        (j.EmployerId > 0)   &&
        (j.DocCount() > 0)
}

func (j *Job) DocCount() int {
  return len(j.DocList)
}

func (j *Job) markComplete(newdoc string) {
  j.Downloaded = append(j.Downloaded, newdoc)
}

func (j *Job) hasDownloadedDocs() bool {
  return len(j.Downloaded) > 0
}

func (j *Job) AddError(newErr error) {
  log.Println(newErr)
  j.Errors = append(j.Errors, newErr)
}

func (j *Job) connect() {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  j.Bucket = s.Bucket(bucketName)
}

func (j *Job) getFile(docname string, c chan stat, e chan error) {
  start := time.Now()
  data, err := j.Bucket.Get(j.s3Path(docname))
  if err != nil {
    e <- fmt.Errorf("%v: %v", docname, err)
    return
  }
  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil {
    e <- err; return
    return
  }
  c <- stat{ filename: docname,
             size: len(data),
             dlSecs: time.Since(start) }
}

func (j *Job) s3Path(docname string) string {
  return fmt.Sprintf("%d/docs/%s", j.EmployerId, docname)
}

func (j *Job) getAllFiles() {
  start := time.Now()
  j.connect()
  c := make(chan stat)
  e := make(chan error)
  for _,doc := range j.DocList{
    go j.getFile(doc,c,e)
  }

  totalBytes := j.waitForDownloads(c,e)
  printSummary(start, totalBytes, j.DocCount())
}

func (j *Job) waitForDownloads(c chan stat, e chan error) (totalBytes int) {
  for _,_ = range j.DocList{
    select {
      case packet := <-c:
        if verbose { log.Printf("%s was %d bytes\n", packet.filename,packet.size) }
        totalBytes += packet.size
        j.markComplete(packet.filename)
      case err := <-e:
        j.AddError(err)
      case <-time.After(2 * time.Minute):
        j.AddError(errors.New("Timed out while downloading"))
        return
    }
  }
  return
}

func printSummary(start time.Time, bytes int, count int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, count, seconds, mbps)
}

func (j *Job) postToCallback(){
  log.Println("work complete, posting success to callback:",j.Callback)
  log.Println(j)
}

func (j *Job) Combine() bool {
  defer j.postToCallback()
  j.getAllFiles()
  if j.hasDownloadedDocs() {
    cpdf.Merge(j.Downloaded)
  }
  return true
}

<|endoftext|>


<commit_before>package errors

import (
	"runtime"

	"github.com/pkg/errors"
)

var (
	New       = errors.New
	Errorf    = errors.Errorf
	Wrap      = errors.Wrap
	Wrapf     = errors.Wrapf
	WithStack = errors.WithStack
)

// Callers returns an errors.StackTrace for the place at which it's called.
func Callers() errors.StackTrace {
	const depth = 32
	var pcs [depth]uintptr
	// 2 skips runtime.Callers and this function
	n := runtime.Callers(2, pcs[:])
	st := make(errors.StackTrace, n)
	for i, pc := range pcs[0:n] {
		st[i] = errors.Frame(pc)
	}
	return st
}

// StackTracer is an interface for errors that can return stack traces.
// Unfortuantely github.com/pkg/errors makes us define this ourselves rather
// than defining it for us.
type StackTracer interface {
	StackTrace() errors.StackTrace
}
<commit_msg>Make lint happy.<commit_after>package errors

import (
	"runtime"

	"github.com/pkg/errors"
)

var (
	// New returns an error with the supplied message.
	// New also records the stack trace at the point it was called.
	New = errors.New
	// Errorf formats according to a format specifier and returns the string
	// as a value that satisfies error.
	// Errorf also records the stack trace at the point it was called.
	Errorf = errors.Errorf
	// Wrap returns an error annotating err with a stack trace
	// at the point Wrap is called, and the supplied message.
	// If err is nil, Wrap returns nil.
	Wrap = errors.Wrap
	// Wrapf returns an error annotating err with a stack trace
	// at the point Wrapf is called, and the format specifier.
	// If err is nil, Wrapf returns nil.
	Wrapf = errors.Wrapf
	// WithStack annotates err with a stack trace at the point WithStack was called.
	// If err is nil, WithStack returns nil.
	WithStack = errors.WithStack
)

// Callers returns an errors.StackTrace for the place at which it's called.
func Callers() errors.StackTrace {
	const depth = 32
	var pcs [depth]uintptr
	// 2 skips runtime.Callers and this function
	n := runtime.Callers(2, pcs[:])
	st := make(errors.StackTrace, n)
	for i, pc := range pcs[0:n] {
		st[i] = errors.Frame(pc)
	}
	return st
}

// StackTracer is an interface for errors that can return stack traces.
// Unfortuantely github.com/pkg/errors makes us define this ourselves rather
// than defining it for us.
type StackTracer interface {
	StackTrace() errors.StackTrace
}
<|endoftext|>


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

package commands

import (
	"os"
	"runtime"
	"strings"

	"github.com/bogem/nehm/applescript"
	"github.com/bogem/nehm/config"
	"github.com/bogem/nehm/ui"
	"github.com/bogem/nehm/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var RootCmd = listCommand

// Variables used in flags
var (
	limit, offset                       uint
	dlFolder, itunesPlaylist, permalink string
)

func Execute() {
	RootCmd.AddCommand(getCommand)
	RootCmd.AddCommand(searchCommand)
	RootCmd.AddCommand(versionCommand)
	RootCmd.Execute()
}

// addCommonFlags adds common flags related to download tracks.
func addCommonFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&dlFolder, "dlFolder", "f", "", "filesystem path to download folder")

	if runtime.GOOS == "darwin" {
		cmd.Flags().StringVarP(&itunesPlaylist, "itunesPlaylist", "i", "", "name of iTunes playlist")
	}
}

func addLimitFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&limit, "limit", "l", 10, "count of tracks on each page")
}

func addOffsetFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&offset, "offset", "o", 0, "offset relative to first like")
}

func addPermalinkFlag(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&permalink, "permalink", "p", "", "user's permalink")
}

// initializeConfig initializes a config with flags.
func initializeConfig(cmd *cobra.Command) {
	err := config.ReadInConfig()
	if err == config.ErrNotExist {
		ui.Warning("There is no config file. Read README to configure nehm")
	} else {
		ui.Term("", err)
	}

	loadDefaultSettings()

	initializeDlFolder(cmd)
	initializePermalink(cmd)
	if runtime.GOOS == "darwin" {
		initializeItunesPlaylist(cmd)
	}
}

func loadDefaultSettings() {
	config.SetDefault("dlFolder", os.Getenv("HOME"))
	config.SetDefault("itunesPlaylist", "")
}

func flagChanged(fs *pflag.FlagSet, key string) bool {
	flag := fs.Lookup(key)
	if flag == nil {
		return false
	}
	return flag.Changed
}

// initializeDlFolder initializes dlFolder value. If there is no dlFolder
// set up, then dlFolder is set to HOME env variable.
func initializeDlFolder(cmd *cobra.Command) {
	var df string
	if flagChanged(cmd.Flags(), "dlFolder") {
		df = dlFolder
	} else {
		df = config.Get("dlFolder")
	}
	config.Set("dlFolder", util.SanitizePath(df))
}

// initializePermalink initializes permalink value. If there is no permalink
// set up, then program is terminating.
func initializePermalink(cmd *cobra.Command) {
	if flagChanged(cmd.Flags(), "permalink") {
		config.Set("permalink", permalink)
	} else if config.Get("permalink") == "" {
		ui.Term("You didn't set a permalink. Use flag '-p' or set permalink in config file.\nTo know, what is permalink, read FAQ.", nil)
	}
}

// initializeItunesPlaylist initializes itunesPlaylist value. If there is no
// itunesPlaylist set up, then itunesPlaylist set up to blank string. Blank
// string is the sign, what tracks should not to be added to iTunes.
func initializeItunesPlaylist(cmd *cobra.Command) {
	var playlist string
	if flagChanged(cmd.Flags(), "itunesPlaylist") {
		playlist = itunesPlaylist
	} else {
		playlist = config.Get("itunesPlaylist")
	}
	if playlist != "" {
		playlistsList, err := applescript.ListOfPlaylists()
		if err != nil {
			ui.Term("Couldn't get list of playlists", err)
		}
		if !strings.Contains(playlistsList, playlist) {
			ui.Term("Playlist "+playlist+" doesn't exist. Please enter correct name.", nil)
		}
	}
	config.Set("itunesPlaylist", playlist)
}
<commit_msg>Fix bug when nehm commands dont work<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package commands

import (
	"os"
	"runtime"
	"strings"

	"github.com/bogem/nehm/applescript"
	"github.com/bogem/nehm/config"
	"github.com/bogem/nehm/ui"
	"github.com/bogem/nehm/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var RootCmd = listCommand

// Variables used in flags
var (
	limit, offset                       uint
	dlFolder, itunesPlaylist, permalink string
)

func Execute() {
	RootCmd.AddCommand(getCommand)
	RootCmd.AddCommand(searchCommand)
	RootCmd.AddCommand(versionCommand)
	RootCmd.Execute()
}

// addCommonFlags adds common flags related to download tracks.
func addCommonFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&dlFolder, "dlFolder", "f", "", "filesystem path to download folder")

	if runtime.GOOS == "darwin" {
		cmd.Flags().StringVarP(&itunesPlaylist, "itunesPlaylist", "i", "", "name of iTunes playlist")
	}
}

func addLimitFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&limit, "limit", "l", 10, "count of tracks on each page")
}

func addOffsetFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&offset, "offset", "o", 0, "offset relative to first like")
}

func addPermalinkFlag(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&permalink, "permalink", "p", "", "user's permalink")
}

// initializeConfig initializes a config with flags.
func initializeConfig(cmd *cobra.Command) {
	err := config.ReadInConfig()
	if err == config.ErrNotExist {
		ui.Warning("There is no config file. Read README to configure nehm")
	} else if err != nil {
		ui.Term("", err)
	}

	loadDefaultSettings()

	initializeDlFolder(cmd)
	initializePermalink(cmd)
	if runtime.GOOS == "darwin" {
		initializeItunesPlaylist(cmd)
	}
}

func loadDefaultSettings() {
	config.SetDefault("dlFolder", os.Getenv("HOME"))
	config.SetDefault("itunesPlaylist", "")
}

func flagChanged(fs *pflag.FlagSet, key string) bool {
	flag := fs.Lookup(key)
	if flag == nil {
		return false
	}
	return flag.Changed
}

// initializeDlFolder initializes dlFolder value. If there is no dlFolder
// set up, then dlFolder is set to HOME env variable.
func initializeDlFolder(cmd *cobra.Command) {
	var df string
	if flagChanged(cmd.Flags(), "dlFolder") {
		df = dlFolder
	} else {
		df = config.Get("dlFolder")
	}
	config.Set("dlFolder", util.SanitizePath(df))
}

// initializePermalink initializes permalink value. If there is no permalink
// set up, then program is terminating.
func initializePermalink(cmd *cobra.Command) {
	if flagChanged(cmd.Flags(), "permalink") {
		config.Set("permalink", permalink)
	} else if config.Get("permalink") == "" {
		ui.Term("You didn't set a permalink. Use flag '-p' or set permalink in config file.\nTo know, what is permalink, read FAQ.", nil)
	}
}

// initializeItunesPlaylist initializes itunesPlaylist value. If there is no
// itunesPlaylist set up, then itunesPlaylist set up to blank string. Blank
// string is the sign, what tracks should not to be added to iTunes.
func initializeItunesPlaylist(cmd *cobra.Command) {
	var playlist string
	if flagChanged(cmd.Flags(), "itunesPlaylist") {
		playlist = itunesPlaylist
	} else {
		playlist = config.Get("itunesPlaylist")
	}
	if playlist != "" {
		playlistsList, err := applescript.ListOfPlaylists()
		if err != nil {
			ui.Term("Couldn't get list of playlists", err)
		}
		if !strings.Contains(playlistsList, playlist) {
			ui.Term("Playlist "+playlist+" doesn't exist. Please enter correct name.", nil)
		}
	}
	config.Set("itunesPlaylist", playlist)
}
<|endoftext|>


<commit_before>package boltdb

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"

	"github.com/Workiva/go-datastructures/augmentedtree"
	region "github.com/akhenakh/regionagogo"
	"github.com/akhenakh/regionagogo/geostore"
	"github.com/boltdb/bolt"
	"github.com/golang/geo/s2"
	"github.com/golang/protobuf/proto"
	lru "github.com/hashicorp/golang-lru"
)

const (
	loopBucket  = "loop"
	coverBucket = "cover"
)

// GeoFenceBoltDB provides an in memory index and boltdb query engine for fences lookup
type GeoFenceBoltDB struct {
	augmentedtree.Tree
	*bolt.DB
	cache *lru.Cache
	debug bool
}

// GeoSearchOption used to pass options to NewGeoSearch
type GeoFenceBoltDBOption func(*geoFenceBoltDBOptions)

type geoFenceBoltDBOptions struct {
	maxCachedEntries uint
	debug            bool
	ro               bool
}

// WithCachedEntries enable an LRU cache default is disabled
func WithCachedEntries(maxCachedEntries uint) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.maxCachedEntries = maxCachedEntries
	}
}

// WithDebug enable debug
func WithDebug(debug bool) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.debug = debug
	}
}

// WithReadOnly enable read only db
func WithReadOnly(ro bool) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.ro = ro
	}
}

// NewGeoFenceBoltDB creates a new geo database, needs a writable path for BoltDB
func NewGeoFenceBoltDB(dbpath string, opts ...GeoFenceBoltDBOption) (*GeoFenceBoltDB, error) {
	var geoOpts geoFenceBoltDBOptions

	for _, opt := range opts {
		opt(&geoOpts)
	}

	db, err := bolt.Open(dbpath, 0600, &bolt.Options{ReadOnly: geoOpts.ro})
	if err != nil {
		return nil, err
	}

	// create bucket if we have write permission
	if !geoOpts.ro {
		if errdb := db.Update(func(tx *bolt.Tx) error {
			if _, errtx := tx.CreateBucketIfNotExists([]byte(loopBucket)); errtx != nil {
				return fmt.Errorf("create bucket: %s", errtx)
			}
			if _, errtx := tx.CreateBucketIfNotExists([]byte(coverBucket)); errtx != nil {
				return fmt.Errorf("create bucket: %s", errtx)
			}
			return nil
		}); errdb != nil {
			return nil, errdb
		}
	}

	gs := &GeoFenceBoltDB{
		Tree:  augmentedtree.New(1),
		DB:    db,
		debug: geoOpts.debug,
	}

	if geoOpts.maxCachedEntries != 0 {
		cache, err := lru.New(int(geoOpts.maxCachedEntries))
		if err != nil {
			return nil, err
		}
		gs.cache = cache
	}

	if err := gs.importGeoData(); err != nil {
		return nil, err
	}

	return gs, nil
}

// index indexes each cells of the cover and set its loopID
func (gs *GeoFenceBoltDB) index(fc *geostore.FenceCover, loopID uint64) {
	for _, cell := range fc.Cellunion {
		s2interval := &region.S2Interval{CellID: s2.CellID(cell)}
		intervals := gs.Query(s2interval)
		found := false

		if len(intervals) != 0 {
			for _, existInterval := range intervals {
				if existInterval.LowAtDimension(1) == s2interval.LowAtDimension(1) &&
					existInterval.HighAtDimension(1) == s2interval.HighAtDimension(1) {
					// update existing interval
					existS2Interval := existInterval.(*region.S2Interval)
					if gs.debug {
						log.Printf("added %d to existing interval %s containing %v", loopID, existS2Interval, existS2Interval.LoopIDs)
					}

					existS2Interval.LoopIDs = append(existS2Interval.LoopIDs, loopID)
					found = true
					break
				}
			}
		}

		if !found {
			// create new interval with current loop
			s2interval.LoopIDs = []uint64{loopID}
			gs.Add(s2interval)
			if gs.debug {
				log.Printf("added %v to new interval %s", s2interval.LoopIDs, s2interval)
			}
		}
	}
}

// importGeoData loads all existing cells into the segment tree
func (gs *GeoFenceBoltDB) importGeoData() error {
	var count int
	err := gs.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(coverBucket))
		cur := b.Cursor()

		// load the cell ranges into the tree
		var fc geostore.FenceCover
		for k, v := cur.First(); k != nil; k, v = cur.Next() {
			count++
			err := proto.Unmarshal(v, &fc)
			if err != nil {
				return err
			}
			if gs.debug {
				log.Println("read", fc.Cellunion)
			}

			// read back the loopID from the key
			var loopID uint64
			buf := bytes.NewBuffer(k)
			err = binary.Read(buf, binary.BigEndian, &loopID)
			if err != nil {
				return err
			}

			gs.index(&fc, loopID)
		}

		return nil
	})
	if err != nil {
		return err
	}

	if count != 0 {
		log.Println("loaded", count, "existing fences")
	} else {
		log.Println("initialized database")
	}

	return nil
}

// FenceByID returns a region from DB by its id
func (gs *GeoFenceBoltDB) FenceByID(loopID uint64) *region.Fence {
	// TODO: refactor as Fence ?
	if gs.cache != nil {
		if val, ok := gs.cache.Get(loopID); ok {
			r, _ := val.(*region.Fence)
			return r
		}
	}
	var rs *geostore.FenceStorage
	err := gs.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(loopBucket))
		v := b.Get(itob(loopID))

		var frs geostore.FenceStorage
		err := proto.Unmarshal(v, &frs)
		if err != nil {
			return err
		}
		rs = &frs
		return nil
	})
	if err != nil {
		return nil
	}
	r := region.NewFenceFromStorage(rs)
	if gs.cache != nil && r != nil {
		gs.cache.Add(loopID, r)
	}
	return r
}

// StubbingQuery returns the fence for the corresponding lat, lng point
func (gs *GeoFenceBoltDB) StubbingQuery(lat, lng float64) *region.Fence {
	// the CellID at L30
	q := s2.CellIDFromLatLng(s2.LatLngFromDegrees(lat, lng))

	i := &region.S2Interval{CellID: q}

	if gs.debug {
		log.Println("lookup", lat, lng, q)
	}
	r := gs.Tree.Query(i)

	var foundFence *region.Fence

	for _, itv := range r {
		sitv := itv.(*region.S2Interval)
		if gs.debug {
			log.Println("found possible solution", sitv, sitv.LoopIDs)
		}

		// a fence can include a smaller fence
		// return only the one that is contained in the other
		for _, loopID := range sitv.LoopIDs {
			fence := gs.FenceByID(loopID)
			if fence != nil && fence.Loop.ContainsPoint(q.Point()) {
				if foundFence == nil {
					if gs.debug {
						log.Println("found matching fence", sitv, sitv.LoopIDs, fence.Loop.NumEdges())
					}
					foundFence = fence
					continue
				}

				// we take the 1st vertex of the fence.Loop if it is contained in previousLoop
				// region loop  is more precise
				if foundFence.Loop.ContainsPoint(fence.Loop.Vertex(0)) {
					foundFence = fence
				}
			}
		}
	}

	return foundFence
}

// RectQuery perform rectangular query ur upper right bl bottom left
func (gs *GeoFenceBoltDB) RectQuery(urlat, urlng, bllat, bllng float64, limit int) (region.Fences, error) {
	rect := s2.RectFromLatLng(s2.LatLngFromDegrees(bllat, bllng))
	rect = rect.AddPoint(s2.LatLngFromDegrees(urlat, urlng))

	rc := &s2.RegionCoverer{MaxLevel: 30, MaxCells: 1}
	covering := rc.Covering(rect)
	if len(covering) != 1 {
		return nil, errors.New("impossible covering")
	}
	i := &region.S2Interval{CellID: covering[0]}
	r := gs.Tree.Query(i)

	fences := make(map[uint64]*region.Fence)

	for _, itv := range r {
		sitv := itv.(*region.S2Interval)
		for _, loopID := range sitv.LoopIDs {
			var region *region.Fence
			if v, ok := fences[loopID]; ok {
				region = v
			} else {
				region = gs.FenceByID(loopID)
			}
			// testing the found loop is actually inside the rect
			// (since we are using only one large cover it may be outside)
			if rect.Contains(region.Loop.RectBound()) {
				fences[loopID] = region
			}
		}
	}

	var res []*region.Fence
	for _, v := range fences {
		res = append(res, v)
	}
	return region.Fences(res), nil
}

// StoreFence stores a fence into the database and load its index in memory
func (gs *GeoFenceBoltDB) StoreFence(fs *geostore.FenceStorage, cover []uint64) error {
	return gs.Update(func(tx *bolt.Tx) error {
		loopB := tx.Bucket([]byte(loopBucket))
		coverBucket := tx.Bucket([]byte(coverBucket))

		loopID, err := loopB.NextSequence()
		if err != nil {
			return err
		}

		buf, err := proto.Marshal(fs)
		if err != nil {
			return err
		}

		if gs.debug {
			log.Println("inserted", loopID, fs.Data, cover)
		}

		// convert our loopID to bigendian to be used as key
		k := itob(loopID)

		err = loopB.Put(k, buf)
		if err != nil {
			return err
		}

		// inserting into cover index using the same key
		fc := &geostore.FenceCover{Cellunion: cover}
		bufc, err := proto.Marshal(fc)
		if err != nil {
			return err
		}

		// also load into memory
		gs.index(fc, loopID)

		return coverBucket.Put(k, bufc)
	})
}

// itob returns an 8-byte big endian representation of v.
func itob(v uint64) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, v)
	return b
}
<commit_msg>rect optimization<commit_after>package boltdb

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"

	"github.com/Workiva/go-datastructures/augmentedtree"
	region "github.com/akhenakh/regionagogo"
	"github.com/akhenakh/regionagogo/geostore"
	"github.com/boltdb/bolt"
	"github.com/golang/geo/s2"
	"github.com/golang/protobuf/proto"
	lru "github.com/hashicorp/golang-lru"
)

const (
	loopBucket  = "loop"
	coverBucket = "cover"
)

// GeoFenceBoltDB provides an in memory index and boltdb query engine for fences lookup
type GeoFenceBoltDB struct {
	augmentedtree.Tree
	*bolt.DB
	cache *lru.Cache
	debug bool
}

// GeoSearchOption used to pass options to NewGeoSearch
type GeoFenceBoltDBOption func(*geoFenceBoltDBOptions)

type geoFenceBoltDBOptions struct {
	maxCachedEntries uint
	debug            bool
	ro               bool
}

// WithCachedEntries enable an LRU cache default is disabled
func WithCachedEntries(maxCachedEntries uint) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.maxCachedEntries = maxCachedEntries
	}
}

// WithDebug enable debug
func WithDebug(debug bool) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.debug = debug
	}
}

// WithReadOnly enable read only db
func WithReadOnly(ro bool) GeoFenceBoltDBOption {
	return func(o *geoFenceBoltDBOptions) {
		o.ro = ro
	}
}

// NewGeoFenceBoltDB creates a new geo database, needs a writable path for BoltDB
func NewGeoFenceBoltDB(dbpath string, opts ...GeoFenceBoltDBOption) (*GeoFenceBoltDB, error) {
	var geoOpts geoFenceBoltDBOptions

	for _, opt := range opts {
		opt(&geoOpts)
	}

	db, err := bolt.Open(dbpath, 0600, &bolt.Options{ReadOnly: geoOpts.ro})
	if err != nil {
		return nil, err
	}

	// create bucket if we have write permission
	if !geoOpts.ro {
		if errdb := db.Update(func(tx *bolt.Tx) error {
			if _, errtx := tx.CreateBucketIfNotExists([]byte(loopBucket)); errtx != nil {
				return fmt.Errorf("create bucket: %s", errtx)
			}
			if _, errtx := tx.CreateBucketIfNotExists([]byte(coverBucket)); errtx != nil {
				return fmt.Errorf("create bucket: %s", errtx)
			}
			return nil
		}); errdb != nil {
			return nil, errdb
		}
	}

	gs := &GeoFenceBoltDB{
		Tree:  augmentedtree.New(1),
		DB:    db,
		debug: geoOpts.debug,
	}

	if geoOpts.maxCachedEntries != 0 {
		cache, err := lru.New(int(geoOpts.maxCachedEntries))
		if err != nil {
			return nil, err
		}
		gs.cache = cache
	}

	if err := gs.importGeoData(); err != nil {
		return nil, err
	}

	return gs, nil
}

// index indexes each cells of the cover and set its loopID
func (gs *GeoFenceBoltDB) index(fc *geostore.FenceCover, loopID uint64) {
	for _, cell := range fc.Cellunion {
		s2interval := &region.S2Interval{CellID: s2.CellID(cell)}
		intervals := gs.Query(s2interval)
		found := false

		if len(intervals) != 0 {
			for _, existInterval := range intervals {
				if existInterval.LowAtDimension(1) == s2interval.LowAtDimension(1) &&
					existInterval.HighAtDimension(1) == s2interval.HighAtDimension(1) {
					// update existing interval
					existS2Interval := existInterval.(*region.S2Interval)
					if gs.debug {
						log.Printf("added %d to existing interval %s containing %v", loopID, existS2Interval, existS2Interval.LoopIDs)
					}

					existS2Interval.LoopIDs = append(existS2Interval.LoopIDs, loopID)
					found = true
					break
				}
			}
		}

		if !found {
			// create new interval with current loop
			s2interval.LoopIDs = []uint64{loopID}
			gs.Add(s2interval)
			if gs.debug {
				log.Printf("added %v to new interval %s", s2interval.LoopIDs, s2interval)
			}
		}
	}
}

// importGeoData loads all existing cells into the segment tree
func (gs *GeoFenceBoltDB) importGeoData() error {
	var count int
	err := gs.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(coverBucket))
		cur := b.Cursor()

		// load the cell ranges into the tree
		var fc geostore.FenceCover
		for k, v := cur.First(); k != nil; k, v = cur.Next() {
			count++
			err := proto.Unmarshal(v, &fc)
			if err != nil {
				return err
			}
			if gs.debug {
				log.Println("read", fc.Cellunion)
			}

			// read back the loopID from the key
			var loopID uint64
			buf := bytes.NewBuffer(k)
			err = binary.Read(buf, binary.BigEndian, &loopID)
			if err != nil {
				return err
			}

			gs.index(&fc, loopID)
		}

		return nil
	})
	if err != nil {
		return err
	}

	if count != 0 {
		log.Println("loaded", count, "existing fences")
	} else {
		log.Println("initialized database")
	}

	return nil
}

// FenceByID returns a region from DB by its id
func (gs *GeoFenceBoltDB) FenceByID(loopID uint64) *region.Fence {
	// TODO: refactor as Fence ?
	if gs.cache != nil {
		if val, ok := gs.cache.Get(loopID); ok {
			r, _ := val.(*region.Fence)
			return r
		}
	}
	var rs *geostore.FenceStorage
	err := gs.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(loopBucket))
		v := b.Get(itob(loopID))

		var frs geostore.FenceStorage
		err := proto.Unmarshal(v, &frs)
		if err != nil {
			return err
		}
		rs = &frs
		return nil
	})
	if err != nil {
		return nil
	}
	r := region.NewFenceFromStorage(rs)
	if gs.cache != nil && r != nil {
		gs.cache.Add(loopID, r)
	}
	return r
}

// StubbingQuery returns the fence for the corresponding lat, lng point
func (gs *GeoFenceBoltDB) StubbingQuery(lat, lng float64) *region.Fence {
	// the CellID at L30
	q := s2.CellIDFromLatLng(s2.LatLngFromDegrees(lat, lng))

	i := &region.S2Interval{CellID: q}

	if gs.debug {
		log.Println("lookup", lat, lng, q)
	}
	r := gs.Tree.Query(i)

	var foundFence *region.Fence

	for _, itv := range r {
		sitv := itv.(*region.S2Interval)
		if gs.debug {
			log.Println("found possible solution", sitv, sitv.LoopIDs)
		}

		// a fence can include a smaller fence
		// return only the one that is contained in the other
		for _, loopID := range sitv.LoopIDs {
			fence := gs.FenceByID(loopID)
			if fence != nil && fence.Loop.ContainsPoint(q.Point()) {
				if foundFence == nil {
					if gs.debug {
						log.Println("found matching fence", sitv, sitv.LoopIDs, fence.Loop.NumEdges())
					}
					foundFence = fence
					continue
				}

				// we take the 1st vertex of the fence.Loop if it is contained in previousLoop
				// region loop  is more precise
				if foundFence.Loop.ContainsPoint(fence.Loop.Vertex(0)) {
					foundFence = fence
				}
			}
		}
	}

	return foundFence
}

// RectQuery perform rectangular query ur upper right bl bottom left
func (gs *GeoFenceBoltDB) RectQuery(urlat, urlng, bllat, bllng float64, limit int) (region.Fences, error) {
	rect := s2.RectFromLatLng(s2.LatLngFromDegrees(bllat, bllng))
	rect = rect.AddPoint(s2.LatLngFromDegrees(urlat, urlng))

	rc := &s2.RegionCoverer{MaxLevel: 30, MaxCells: 1}
	covering := rc.Covering(rect)
	if len(covering) != 1 {
		return nil, errors.New("impossible covering")
	}
	i := &region.S2Interval{CellID: covering[0]}
	r := gs.Tree.Query(i)

	fences := make(map[uint64]*region.Fence)

	for _, itv := range r {
		sitv := itv.(*region.S2Interval)
		for _, loopID := range sitv.LoopIDs {
			var region *region.Fence
			if v, ok := fences[loopID]; ok {
				region = v
			} else {
				region = gs.FenceByID(loopID)
				// testing the found loop is actually inside the rect
				// (since we are using only one large cover it may be outside)
				if rect.Contains(region.Loop.RectBound()) {
					fences[loopID] = region
				}
			}

		}
	}

	var res []*region.Fence
	for _, v := range fences {
		res = append(res, v)
	}
	return region.Fences(res), nil
}

// StoreFence stores a fence into the database and load its index in memory
func (gs *GeoFenceBoltDB) StoreFence(fs *geostore.FenceStorage, cover []uint64) error {
	return gs.Update(func(tx *bolt.Tx) error {
		loopB := tx.Bucket([]byte(loopBucket))
		coverBucket := tx.Bucket([]byte(coverBucket))

		loopID, err := loopB.NextSequence()
		if err != nil {
			return err
		}

		buf, err := proto.Marshal(fs)
		if err != nil {
			return err
		}

		if gs.debug {
			log.Println("inserted", loopID, fs.Data, cover)
		}

		// convert our loopID to bigendian to be used as key
		k := itob(loopID)

		err = loopB.Put(k, buf)
		if err != nil {
			return err
		}

		// inserting into cover index using the same key
		fc := &geostore.FenceCover{Cellunion: cover}
		bufc, err := proto.Marshal(fc)
		if err != nil {
			return err
		}

		// also load into memory
		gs.index(fc, loopID)

		return coverBucket.Put(k, bufc)
	})
}

// itob returns an 8-byte big endian representation of v.
func itob(v uint64) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, v)
	return b
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors 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.
*/

package core

import (
	"fmt"
	"io/ioutil"
	"reflect"
	"strings"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util/yaml"
	"k8s.io/kubernetes/pkg/watch"
)

// ObjectRetriever abstracts the implementation for retrieving or setting generic
// objects. It is intended to be used to fake calls to a server by returning
// objects based on their kind and name.
type ObjectRetriever interface {
	// Kind should return a resource or a list of resources (depending on the provided kind and
	// name). It should return an error if the caller should communicate an error to the server.
	Kind(gvk unversioned.GroupVersionKind, name string) (runtime.Object, error)
	// Add adds a runtime object for test purposes into this object.
	Add(runtime.Object) error
}

// ObjectScheme abstracts the implementation of common operations on objects.
type ObjectScheme interface {
	runtime.ObjectCreater
	runtime.ObjectCopier
	runtime.ObjectTyper
}

// ObjectReaction returns a ReactionFunc that takes a generic action string of the form
// <verb>-<resource> or <verb>-<subresource>-<resource> and attempts to return a runtime
// Object or error that matches the requested action. For instance, list-replicationControllers
// should attempt to return a list of replication controllers. This method delegates to the
// ObjectRetriever interface to satisfy retrieval of lists or retrieval of single items.
// TODO: add support for sub resources
func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {

	return func(action Action) (bool, runtime.Object, error) {
		kind, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: action.GetResource()})
		if err != nil {
			return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err)
		}

		// TODO: have mapper return a Kind for a subresource?
		switch castAction := action.(type) {
		case ListAction:
			kind.Kind += "List"
			resource, err := o.Kind(kind, "")
			return true, resource, err

		case GetAction:
			resource, err := o.Kind(kind, castAction.GetName())
			return true, resource, err

		case DeleteAction:
			resource, err := o.Kind(kind, castAction.GetName())
			return true, resource, err

		case CreateAction:
			meta, err := api.ObjectMetaFor(castAction.GetObject())
			if err != nil {
				return true, nil, err
			}
			resource, err := o.Kind(kind, meta.Name)
			return true, resource, err

		case UpdateAction:
			meta, err := api.ObjectMetaFor(castAction.GetObject())
			if err != nil {
				return true, nil, err
			}
			resource, err := o.Kind(kind, meta.Name)
			return true, resource, err

		default:
			return false, nil, fmt.Errorf("no reaction implemented for %s", action)
		}

		return true, nil, nil
	}
}

// AddObjectsFromPath loads the JSON or YAML file containing Kubernetes API resources
// and adds them to the provided ObjectRetriever.
func AddObjectsFromPath(path string, o ObjectRetriever, decoder runtime.Decoder) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	data, err = yaml.ToJSON(data)
	if err != nil {
		return err
	}
	obj, err := runtime.Decode(decoder, data)
	if err != nil {
		return err
	}
	if err := o.Add(obj); err != nil {
		return err
	}
	return nil
}

type objects struct {
	types   map[string][]runtime.Object
	last    map[string]int
	scheme  ObjectScheme
	decoder runtime.Decoder
}

var _ ObjectRetriever = &objects{}

// NewObjects implements the ObjectRetriever interface by introspecting the
// objects provided to Add() and returning them when the Kind method is invoked.
// If an api.List object is provided to Add(), each child item is added. If an
// object is added that is itself a list (PodList, ServiceList) then that is added
// to the "PodList" kind. If no PodList is added, the retriever will take any loaded
// Pods and return them in a list. If an api.Status is added, and the Details.Kind field
// is set, that status will be returned instead (as an error if Status != Success, or
// as a runtime.Object if Status == Success).  If multiple PodLists are provided, they
// will be returned in order by the Kind call, and the last PodList will be reused for
// subsequent calls.
func NewObjects(scheme ObjectScheme, decoder runtime.Decoder) ObjectRetriever {
	return objects{
		types:   make(map[string][]runtime.Object),
		last:    make(map[string]int),
		scheme:  scheme,
		decoder: decoder,
	}
}

func (o objects) Kind(kind unversioned.GroupVersionKind, name string) (runtime.Object, error) {
	// TODO our test clients deal in internal versions.  We need to plumb that knowledge down here
	// we might do this via an extra function to the scheme to allow getting internal group versions
	// I'm punting for now
	kind.Version = ""

	empty, _ := o.scheme.New(kind)
	nilValue := reflect.Zero(reflect.TypeOf(empty)).Interface().(runtime.Object)

	arr, ok := o.types[kind.Kind]
	if !ok {
		if strings.HasSuffix(kind.Kind, "List") {
			itemKind := kind.Kind[:len(kind.Kind)-4]
			arr, ok := o.types[itemKind]
			if !ok {
				return empty, nil
			}
			out, err := o.scheme.New(kind)
			if err != nil {
				return nilValue, err
			}
			if err := meta.SetList(out, arr); err != nil {
				return nilValue, err
			}
			if out, err = o.scheme.Copy(out); err != nil {
				return nilValue, err
			}
			return out, nil
		}
		return nilValue, errors.NewNotFound(unversioned.GroupResource{Group: kind.Group, Resource: kind.Kind}, name)
	}

	index := o.last[kind.Kind]
	if index >= len(arr) {
		index = len(arr) - 1
	}
	if index < 0 {
		return nilValue, errors.NewNotFound(unversioned.GroupResource{Group: kind.Group, Resource: kind.Kind}, name)
	}
	out, err := o.scheme.Copy(arr[index])
	if err != nil {
		return nilValue, err
	}
	o.last[kind.Kind] = index + 1

	if status, ok := out.(*unversioned.Status); ok {
		if status.Details != nil {
			status.Details.Kind = kind.Kind
		}
		if status.Status != unversioned.StatusSuccess {
			return nilValue, &errors.StatusError{ErrStatus: *status}
		}
	}

	return out, nil
}

func (o objects) Add(obj runtime.Object) error {
	gvk, err := o.scheme.ObjectKind(obj)
	if err != nil {
		return err
	}
	kind := gvk.Kind

	switch {
	case meta.IsListType(obj):
		if kind != "List" {
			o.types[kind] = append(o.types[kind], obj)
		}

		list, err := meta.ExtractList(obj)
		if err != nil {
			return err
		}
		if errs := runtime.DecodeList(list, o.decoder); len(errs) > 0 {
			return errs[0]
		}
		for _, obj := range list {
			if err := o.Add(obj); err != nil {
				return err
			}
		}
	default:
		if status, ok := obj.(*unversioned.Status); ok && status.Details != nil {
			kind = status.Details.Kind
		}
		o.types[kind] = append(o.types[kind], obj)
	}

	return nil
}

func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc {
	return func(action Action) (bool, watch.Interface, error) {
		return true, watchInterface, err
	}
}

// SimpleReactor is a Reactor.  Each reaction function is attached to a given verb,resource tuple.  "*" in either field matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
type SimpleReactor struct {
	Verb     string
	Resource string

	Reaction ReactionFunc
}

func (r *SimpleReactor) Handles(action Action) bool {
	verbCovers := r.Verb == "*" || r.Verb == action.GetVerb()
	if !verbCovers {
		return false
	}
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) {
	return r.Reaction(action)
}

// SimpleWatchReactor is a WatchReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
type SimpleWatchReactor struct {
	Resource string

	Reaction WatchReactionFunc
}

func (r *SimpleWatchReactor) Handles(action Action) bool {
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) {
	return r.Reaction(action)
}

// SimpleProxyReactor is a ProxyReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions.
type SimpleProxyReactor struct {
	Resource string

	Reaction ProxyReactionFunc
}

func (r *SimpleProxyReactor) Handles(action Action) bool {
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleProxyReactor) React(action Action) (bool, client.ResponseWrapper, error) {
	return r.Reaction(action)
}
<commit_msg>fix fixture for #17922<commit_after>/*
Copyright 2015 The Kubernetes Authors 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.
*/

package core

import (
	"fmt"
	"io/ioutil"
	"reflect"
	"strings"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util/yaml"
	"k8s.io/kubernetes/pkg/watch"
)

// ObjectRetriever abstracts the implementation for retrieving or setting generic
// objects. It is intended to be used to fake calls to a server by returning
// objects based on their kind and name.
type ObjectRetriever interface {
	// Kind should return a resource or a list of resources (depending on the provided kind and
	// name). It should return an error if the caller should communicate an error to the server.
	Kind(gvk unversioned.GroupVersionKind, name string) (runtime.Object, error)
	// Add adds a runtime object for test purposes into this object.
	Add(runtime.Object) error
}

// ObjectScheme abstracts the implementation of common operations on objects.
type ObjectScheme interface {
	runtime.ObjectCreater
	runtime.ObjectCopier
	runtime.ObjectTyper
}

// ObjectReaction returns a ReactionFunc that takes a generic action string of the form
// <verb>-<resource> or <verb>-<subresource>-<resource> and attempts to return a runtime
// Object or error that matches the requested action. For instance, list-replicationControllers
// should attempt to return a list of replication controllers. This method delegates to the
// ObjectRetriever interface to satisfy retrieval of lists or retrieval of single items.
// TODO: add support for sub resources
func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc {

	return func(action Action) (bool, runtime.Object, error) {
		kind, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: action.GetResource()})
		if err != nil {
			return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err)
		}

		// TODO: have mapper return a Kind for a subresource?
		switch castAction := action.(type) {
		case ListAction:
			kind.Kind += "List"
			resource, err := o.Kind(kind, "")
			return true, resource, err

		case GetAction:
			resource, err := o.Kind(kind, castAction.GetName())
			return true, resource, err

		case DeleteAction:
			resource, err := o.Kind(kind, castAction.GetName())
			return true, resource, err

		case CreateAction:
			meta, err := api.ObjectMetaFor(castAction.GetObject())
			if err != nil {
				return true, nil, err
			}
			resource, err := o.Kind(kind, meta.Name)
			return true, resource, err

		case UpdateAction:
			meta, err := api.ObjectMetaFor(castAction.GetObject())
			if err != nil {
				return true, nil, err
			}
			resource, err := o.Kind(kind, meta.Name)
			return true, resource, err

		default:
			return false, nil, fmt.Errorf("no reaction implemented for %s", action)
		}

		return true, nil, nil
	}
}

// AddObjectsFromPath loads the JSON or YAML file containing Kubernetes API resources
// and adds them to the provided ObjectRetriever.
func AddObjectsFromPath(path string, o ObjectRetriever, decoder runtime.Decoder) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	data, err = yaml.ToJSON(data)
	if err != nil {
		return err
	}
	obj, err := runtime.Decode(decoder, data)
	if err != nil {
		return err
	}
	if err := o.Add(obj); err != nil {
		return err
	}
	return nil
}

type objects struct {
	types   map[string][]runtime.Object
	last    map[string]int
	scheme  ObjectScheme
	decoder runtime.Decoder
}

var _ ObjectRetriever = &objects{}

// NewObjects implements the ObjectRetriever interface by introspecting the
// objects provided to Add() and returning them when the Kind method is invoked.
// If an api.List object is provided to Add(), each child item is added. If an
// object is added that is itself a list (PodList, ServiceList) then that is added
// to the "PodList" kind. If no PodList is added, the retriever will take any loaded
// Pods and return them in a list. If an api.Status is added, and the Details.Kind field
// is set, that status will be returned instead (as an error if Status != Success, or
// as a runtime.Object if Status == Success).  If multiple PodLists are provided, they
// will be returned in order by the Kind call, and the last PodList will be reused for
// subsequent calls.
func NewObjects(scheme ObjectScheme, decoder runtime.Decoder) ObjectRetriever {
	return objects{
		types:   make(map[string][]runtime.Object),
		last:    make(map[string]int),
		scheme:  scheme,
		decoder: decoder,
	}
}

func (o objects) Kind(kind unversioned.GroupVersionKind, name string) (runtime.Object, error) {
	kind.Version = runtime.APIVersionInternal
	empty, err := o.scheme.New(kind)
	nilValue := reflect.Zero(reflect.TypeOf(empty)).Interface().(runtime.Object)

	arr, ok := o.types[kind.Kind]
	if !ok {
		if strings.HasSuffix(kind.Kind, "List") {
			itemKind := kind.Kind[:len(kind.Kind)-4]
			arr, ok := o.types[itemKind]
			if !ok {
				return empty, nil
			}
			out, err := o.scheme.New(kind)
			if err != nil {
				return nilValue, err
			}
			if err := meta.SetList(out, arr); err != nil {
				return nilValue, err
			}
			if out, err = o.scheme.Copy(out); err != nil {
				return nilValue, err
			}
			return out, nil
		}
		return nilValue, errors.NewNotFound(unversioned.GroupResource{Group: kind.Group, Resource: kind.Kind}, name)
	}

	index := o.last[kind.Kind]
	if index >= len(arr) {
		index = len(arr) - 1
	}
	if index < 0 {
		return nilValue, errors.NewNotFound(unversioned.GroupResource{Group: kind.Group, Resource: kind.Kind}, name)
	}
	out, err := o.scheme.Copy(arr[index])
	if err != nil {
		return nilValue, err
	}
	o.last[kind.Kind] = index + 1

	if status, ok := out.(*unversioned.Status); ok {
		if status.Details != nil {
			status.Details.Kind = kind.Kind
		}
		if status.Status != unversioned.StatusSuccess {
			return nilValue, &errors.StatusError{ErrStatus: *status}
		}
	}

	return out, nil
}

func (o objects) Add(obj runtime.Object) error {
	gvk, err := o.scheme.ObjectKind(obj)
	if err != nil {
		return err
	}
	kind := gvk.Kind

	switch {
	case meta.IsListType(obj):
		if kind != "List" {
			o.types[kind] = append(o.types[kind], obj)
		}

		list, err := meta.ExtractList(obj)
		if err != nil {
			return err
		}
		if errs := runtime.DecodeList(list, o.decoder); len(errs) > 0 {
			return errs[0]
		}
		for _, obj := range list {
			if err := o.Add(obj); err != nil {
				return err
			}
		}
	default:
		if status, ok := obj.(*unversioned.Status); ok && status.Details != nil {
			kind = status.Details.Kind
		}
		o.types[kind] = append(o.types[kind], obj)
	}

	return nil
}

func DefaultWatchReactor(watchInterface watch.Interface, err error) WatchReactionFunc {
	return func(action Action) (bool, watch.Interface, error) {
		return true, watchInterface, err
	}
}

// SimpleReactor is a Reactor.  Each reaction function is attached to a given verb,resource tuple.  "*" in either field matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
type SimpleReactor struct {
	Verb     string
	Resource string

	Reaction ReactionFunc
}

func (r *SimpleReactor) Handles(action Action) bool {
	verbCovers := r.Verb == "*" || r.Verb == action.GetVerb()
	if !verbCovers {
		return false
	}
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleReactor) React(action Action) (bool, runtime.Object, error) {
	return r.Reaction(action)
}

// SimpleWatchReactor is a WatchReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions
type SimpleWatchReactor struct {
	Resource string

	Reaction WatchReactionFunc
}

func (r *SimpleWatchReactor) Handles(action Action) bool {
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleWatchReactor) React(action Action) (bool, watch.Interface, error) {
	return r.Reaction(action)
}

// SimpleProxyReactor is a ProxyReactor.  Each reaction function is attached to a given resource.  "*" matches everything for that value.
// For instance, *,pods matches all verbs on pods.  This allows for easier composition of reaction functions.
type SimpleProxyReactor struct {
	Resource string

	Reaction ProxyReactionFunc
}

func (r *SimpleProxyReactor) Handles(action Action) bool {
	resourceCovers := r.Resource == "*" || r.Resource == action.GetResource()
	if !resourceCovers {
		return false
	}

	return true
}

func (r *SimpleProxyReactor) React(action Action) (bool, client.ResponseWrapper, error) {
	return r.Reaction(action)
}
<|endoftext|>