<commit_before>// Contains common structure handles errors in CausedBy way in command line
// utility applications.
//
// Service/daemon can use cmdline package to handle main goroutine's
// panic/errors, but can not handle panic/errors inside other goroutines, use
// redforks/life package to cover service goroutines.
package cmdline

import "fmt"

type exitError int

func (code exitError) Error() string {
	return fmt.Sprintf("Exit error %d", int(code))
}

// Create a new exit error. Panic with exit error or return it in MainFunc,
// Go() detect it and call os.Exit() with specific exit code.
// os.Exit() exit the application immediately without calling deferred code
// block, by using exit error we can *fix* this.
func NewExitError(code int) error {
	return exitError(code)
}

// Your application main function type.
type MainFunc func() error

// Call your application main function, handles any error returned or paniced,
// handle error by errors.CausedBy rule.
func Go(main MainFunc) {
	defer func() {
		handlePanic(recover())
	}()

	handleError(main())
}

func handlePanic(v interface{}) {
	// TODO: Maybe errors.GetCausedBy() should accept any value
}

func handleError(err error) {

}
<commit_msg>Implement cmdline support of errors package<commit_after>// Contains common structure handles errors in CausedBy way in command line
// utility applications.
//
// Service/daemon can use cmdline package to handle main goroutine's
// panic/errors, but can not handle panic/errors inside other goroutines, use
// redforks/life package to cover service goroutines.
package cmdline

import (
	"fmt"
	"os"
	"runtime/debug"

	"github.com/redforks/errors"
)

type exitError int

func (code exitError) Error() string {
	return fmt.Sprintf("Exit error %d", int(code))
}

// Create a new exit error. Panic with exit error or return it in MainFunc,
// Go() detect it and call os.Exit() with specific exit code.
// os.Exit() exit the application immediately without calling deferred code
// block, by using exit error we can *fix* this.
func NewExitError(code int) error {
	return exitError(code)
}

// Your application main function type.
type MainFunc func() error

// Call your application main function, handles any error returned or paniced,
// handle error by errors.CausedBy rule.
func Go(main MainFunc) {
	defer func() {
		handleError(recover())
	}()

	handleError(main())
}

func handleError(v interface{}) {
	if err, ok := v.(exitError); ok {
		os.Exit(int(err))
		return
	}

	switch errors.GetPanicCausedBy(v) {
	case errors.NoError:
	case errors.ByBug, errors.ByRuntime:
		fmt.Fprintln(os.Stderr, v)
		debug.PrintStack()
		os.Exit(-1)
	case errors.ByInput, errors.ByExternal:
		fmt.Println(v)
		os.Exit(1)
	default:
		panic("Unknown CausedBy")
	}
}
<|endoftext|>


<commit_before>package main

import "container/list"

type Recent struct {
	List list.List
	Held string
	Max  int
}

// Hold puts the specified path in a temporary variable. When Commit
// is called, the held path is added to the recent list.
func (r *Recent) Hold(path string) {
	r.Held = path
}

// Commit adds the held path to the list.
func (r *Recent) Commit() {
	if len(r.Held) > 0 {
		r.add(r.Held)
		r.Held = ""
	}
}

func (r *Recent) add(path string) {
	if r.contains(path) {
		return
	}

	max := r.Max
	if max == 0 {
		max = 10
	}

	r.List.PushFront(path)
	if r.List.Len() > max {
		r.List.Remove(r.List.Back())
	}
}

func (r Recent) contains(path string) bool {
	for e := r.List.Front(); e != nil; e = e.Next() {
		if e.Value == path {
			return true
		}
	}
	return false
}

func (r Recent) Slice() []string {
	result := make([]string, r.List.Len())
	i := 0
	for e := r.List.Front(); e != nil; e = e.Next() {
		result[i] = e.Value.(string)
		i += 1
	}
	return result
}
<commit_msg>Recent tracks are now sorted by date<commit_after>package main

import "container/list"

type Recent struct {
	List list.List
	Held string
	Max  int
}

// Hold puts the specified path in a temporary variable. When Commit
// is called, the held path is added to the recent list.
func (r *Recent) Hold(path string) {
	r.Held = path
}

// Commit adds the held path to the list.
func (r *Recent) Commit() {
	if len(r.Held) > 0 {
		r.add(r.Held)
		r.Held = ""
	}
}

func (r *Recent) add(path string) {
	if b, e := r.contains(path); b {
		r.List.MoveToFront(e)
		return
	}

	max := r.Max
	if max == 0 {
		max = 10
	}

	r.List.PushFront(path)
	if r.List.Len() > max {
		r.List.Remove(r.List.Back())
	}
}

func (r Recent) contains(path string) (bool, *list.Element) {
	for e := r.List.Front(); e != nil; e = e.Next() {
		if e.Value == path {
			return true, e
		}
	}
	return false, nil
}

func (r Recent) Slice() []string {
	result := make([]string, r.List.Len())
	i := 0
	for e := r.List.Front(); e != nil; e = e.Next() {
		result[i] = e.Value.(string)
		i += 1
	}
	return result
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/node_exporter/collector"
)

const subsystem = "exporter"

var (
	configFile        = flag.String("config", "", "Path to config file.")
	memProfile        = flag.String("memprofile", "", "Write memory profile to this file.")
	listeningAddress  = flag.String("listen", ":8080", "Address to listen on.")
	enabledCollectors = flag.String("enabledCollectors", "attributes,diskstats,filesystem,loadavg,meminfo,stat,time,netdev,netstat", "Comma-separated list of collectors to use.")
	printCollectors   = flag.Bool("printCollectors", false, "If true, print available collectors and exit.")
	authUser          = flag.String("auth.user", "", "Username for basic auth.")
	authPass          = flag.String("auth.pass", "", "Password for basic auth.")

	collectorLabelNames = []string{"collector", "result"}

	scrapeDurations = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: collector.Namespace,
			Subsystem: subsystem,
			Name:      "scrape_duration_seconds",
			Help:      "node_exporter: Duration of a scrape job.",
		},
		collectorLabelNames,
	)
)

// Implements Collector.
type NodeCollector struct {
	collectors map[string]collector.Collector
}

// Implements Collector.
func (n NodeCollector) Describe(ch chan<- *prometheus.Desc) {
	scrapeDurations.Describe(ch)
}

// Implements Collector.
func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {
	wg := sync.WaitGroup{}
	wg.Add(len(n.collectors))
	for name, c := range n.collectors {
		go func(name string, c collector.Collector) {
			Execute(name, c, ch)
			wg.Done()
		}(name, c)
	}
	wg.Wait()
	scrapeDurations.Collect(ch)
}

type basicAuthHandler struct {
	handler  http.HandlerFunc
	user     string
	password string
}

func (h *basicAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	user, password, ok := r.BasicAuth()
	if !ok || password != h.password || user != h.user {
		w.Header().Set("WWW-Authenticate", "Basic realm=\"metrics\"")
		http.Error(w, "Invalid username or password", http.StatusUnauthorized)
		return
	}
	h.handler(w, r)
	return
}

func Execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
	begin := time.Now()
	err := c.Update(ch)
	duration := time.Since(begin)
	var result string

	if err != nil {
		glog.Infof("ERROR: %s failed after %fs: %s", name, duration.Seconds(), err)
		result = "error"
	} else {
		glog.Infof("OK: %s success after %fs.", name, duration.Seconds())
		result = "success"
	}
	scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}

func getConfig(file string) (*collector.Config, error) {
	config := &collector.Config{}
	glog.Infof("Reading config %s", *configFile)
	bytes, err := ioutil.ReadFile(*configFile)
	if err != nil {
		return nil, err
	}
	return config, json.Unmarshal(bytes, &config)
}

func loadCollectors(file string) (map[string]collector.Collector, error) {
	collectors := map[string]collector.Collector{}
	config := &collector.Config{}
	if file != "" {
		var err error
		config, err = getConfig(file)
		if err != nil {
			return nil, fmt.Errorf("couldn't read config %s: %s", file, err)
		}
	}
	for _, name := range strings.Split(*enabledCollectors, ",") {
		fn, ok := collector.Factories[name]
		if !ok {
			return nil, fmt.Errorf("collector '%s' not available", name)
		}
		c, err := fn(*config)
		if err != nil {
			return nil, err
		}
		collectors[name] = c
	}
	return collectors, nil
}

func main() {
	flag.Parse()
	if *printCollectors {
		fmt.Printf("Available collectors:\n")
		for n, _ := range collector.Factories {
			fmt.Printf(" - %s\n", n)
		}
		return
	}
	collectors, err := loadCollectors(*configFile)
	if err != nil {
		glog.Fatalf("Couldn't load config and collectors: %s", err)
	}

	glog.Infof("Enabled collectors:")
	for n, _ := range collectors {
		glog.Infof(" - %s", n)
	}

	nodeCollector := NodeCollector{collectors: collectors}
	prometheus.MustRegister(nodeCollector)

	sigUsr1 := make(chan os.Signal)
	signal.Notify(sigUsr1, syscall.SIGUSR1)

	handler := prometheus.Handler()
	if *authUser != "" || *authPass != "" {
		if *authUser == "" || *authPass == "" {
			glog.Fatal("You need to specify -auth.user and -auth.pass to enable basic auth")
		}
		handler = &basicAuthHandler{
			handler:  prometheus.Handler().ServeHTTP,
			user:     *authUser,
			password: *authPass,
		}
	}
	go func() {
		http.Handle("/metrics", handler)
		err := http.ListenAndServe(*listeningAddress, nil)
		if err != nil {
			glog.Fatal(err)
		}
	}()

	for {
		select {
		case <-sigUsr1:
			glog.Infof("got signal")
			if *memProfile != "" {
				glog.Infof("Writing memory profile to %s", *memProfile)
				f, err := os.Create(*memProfile)
				if err != nil {
					glog.Fatal(err)
				}
				pprof.WriteHeapProfile(f)
				f.Close()
			}
		}
	}

}
<commit_msg>Add simple home page to node exporter.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/node_exporter/collector"
)

const subsystem = "exporter"

var (
	configFile        = flag.String("config", "", "Path to config file.")
	memProfile        = flag.String("memprofile", "", "Write memory profile to this file.")
	listeningAddress  = flag.String("listen", ":8080", "Address to listen on.")
	enabledCollectors = flag.String("enabledCollectors", "attributes,diskstats,filesystem,loadavg,meminfo,stat,time,netdev,netstat", "Comma-separated list of collectors to use.")
	printCollectors   = flag.Bool("printCollectors", false, "If true, print available collectors and exit.")
	authUser          = flag.String("auth.user", "", "Username for basic auth.")
	authPass          = flag.String("auth.pass", "", "Password for basic auth.")

	collectorLabelNames = []string{"collector", "result"}

	scrapeDurations = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: collector.Namespace,
			Subsystem: subsystem,
			Name:      "scrape_duration_seconds",
			Help:      "node_exporter: Duration of a scrape job.",
		},
		collectorLabelNames,
	)
)

// Implements Collector.
type NodeCollector struct {
	collectors map[string]collector.Collector
}

// Implements Collector.
func (n NodeCollector) Describe(ch chan<- *prometheus.Desc) {
	scrapeDurations.Describe(ch)
}

// Implements Collector.
func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {
	wg := sync.WaitGroup{}
	wg.Add(len(n.collectors))
	for name, c := range n.collectors {
		go func(name string, c collector.Collector) {
			Execute(name, c, ch)
			wg.Done()
		}(name, c)
	}
	wg.Wait()
	scrapeDurations.Collect(ch)
}

type basicAuthHandler struct {
	handler  http.HandlerFunc
	user     string
	password string
}

func (h *basicAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	user, password, ok := r.BasicAuth()
	if !ok || password != h.password || user != h.user {
		w.Header().Set("WWW-Authenticate", "Basic realm=\"metrics\"")
		http.Error(w, "Invalid username or password", http.StatusUnauthorized)
		return
	}
	h.handler(w, r)
	return
}

func Execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
	begin := time.Now()
	err := c.Update(ch)
	duration := time.Since(begin)
	var result string

	if err != nil {
		glog.Infof("ERROR: %s failed after %fs: %s", name, duration.Seconds(), err)
		result = "error"
	} else {
		glog.Infof("OK: %s success after %fs.", name, duration.Seconds())
		result = "success"
	}
	scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}

func getConfig(file string) (*collector.Config, error) {
	config := &collector.Config{}
	glog.Infof("Reading config %s", *configFile)
	bytes, err := ioutil.ReadFile(*configFile)
	if err != nil {
		return nil, err
	}
	return config, json.Unmarshal(bytes, &config)
}

func loadCollectors(file string) (map[string]collector.Collector, error) {
	collectors := map[string]collector.Collector{}
	config := &collector.Config{}
	if file != "" {
		var err error
		config, err = getConfig(file)
		if err != nil {
			return nil, fmt.Errorf("couldn't read config %s: %s", file, err)
		}
	}
	for _, name := range strings.Split(*enabledCollectors, ",") {
		fn, ok := collector.Factories[name]
		if !ok {
			return nil, fmt.Errorf("collector '%s' not available", name)
		}
		c, err := fn(*config)
		if err != nil {
			return nil, err
		}
		collectors[name] = c
	}
	return collectors, nil
}

func main() {
	flag.Parse()
	if *printCollectors {
		fmt.Printf("Available collectors:\n")
		for n, _ := range collector.Factories {
			fmt.Printf(" - %s\n", n)
		}
		return
	}
	collectors, err := loadCollectors(*configFile)
	if err != nil {
		glog.Fatalf("Couldn't load config and collectors: %s", err)
	}

	glog.Infof("Enabled collectors:")
	for n, _ := range collectors {
		glog.Infof(" - %s", n)
	}

	nodeCollector := NodeCollector{collectors: collectors}
	prometheus.MustRegister(nodeCollector)

	sigUsr1 := make(chan os.Signal)
	signal.Notify(sigUsr1, syscall.SIGUSR1)

	handler := prometheus.Handler()
	if *authUser != "" || *authPass != "" {
		if *authUser == "" || *authPass == "" {
			glog.Fatal("You need to specify -auth.user and -auth.pass to enable basic auth")
		}
		handler = &basicAuthHandler{
			handler:  prometheus.Handler().ServeHTTP,
			user:     *authUser,
			password: *authPass,
		}
	}
	go func() {
		http.Handle("/metrics", handler)
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte(`
                       <title>Node Exporter</title>

Node Exporter

Metrics

                       `))
		})
		err := http.ListenAndServe(*listeningAddress, nil)
		if err != nil {
			glog.Fatal(err)
		}
	}()

	for {
		select {
		case <-sigUsr1:
			glog.Infof("got signal")
			if *memProfile != "" {
				glog.Infof("Writing memory profile to %s", *memProfile)
				f, err := os.Create(*memProfile)
				if err != nil {
					glog.Fatal(err)
				}
				pprof.WriteHeapProfile(f)
				f.Close()
			}
		}
	}

}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker, 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 azure

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/docker/api/azure/convert"
	"github.com/docker/api/azure/login"
	"github.com/docker/api/backend"
	"github.com/docker/api/compose"
	"github.com/docker/api/containers"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/cloud"
	"github.com/docker/api/context/store"
	"github.com/docker/api/errdefs"
)

const (
	singleContainerName       = "single--container--aci"
	composeContainerSeparator = "_"
)

// ErrNoSuchContainer is returned when the mentioned container does not exist
var ErrNoSuchContainer = errors.New("no such container")

func init() {
	backend.Register("aci", "aci", service, getCloudService)
}

func service(ctx context.Context) (backend.Service, error) {
	contextStore := store.ContextStore(ctx)
	currentContext := apicontext.CurrentContext(ctx)
	var aciContext store.AciContext

	if err := contextStore.GetEndpoint(currentContext, &aciContext); err != nil {
		return nil, err
	}

	return getAciAPIService(aciContext), nil
}

func getCloudService() (cloud.Service, error) {
	service, err := login.NewAzureLoginService()
	if err != nil {
		return nil, err
	}
	return &aciCloudService{
		loginService: service,
	}, nil
}

func getAciAPIService(aciCtx store.AciContext) *aciAPIService {
	return &aciAPIService{
		aciContainerService: &aciContainerService{
			ctx: aciCtx,
		},
		aciComposeService: &aciComposeService{
			ctx: aciCtx,
		},
	}
}

type aciAPIService struct {
	*aciContainerService
	*aciComposeService
}

func (a *aciAPIService) ContainerService() containers.Service {
	return a.aciContainerService
}

func (a *aciAPIService) ComposeService() compose.Service {
	return a.aciComposeService
}

type aciContainerService struct {
	ctx store.AciContext
}

func (cs *aciContainerService) List(ctx context.Context, _ bool) ([]containers.Container, error) {
	groupsClient, err := getContainerGroupsClient(cs.ctx.SubscriptionID)
	if err != nil {
		return nil, err
	}
	var containerGroups []containerinstance.ContainerGroup
	result, err := groupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
	if err != nil {
		return []containers.Container{}, err
	}

	for result.NotDone() {
		containerGroups = append(containerGroups, result.Values()...)
		if err := result.NextWithContext(ctx); err != nil {
			return []containers.Container{}, err
		}
	}

	var res []containers.Container
	for _, containerGroup := range containerGroups {
		group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
		if err != nil {
			return []containers.Container{}, err
		}

		for _, container := range *group.Containers {
			var containerID string
			// don't list sidecar container
			if *container.Name == convert.ComposeDNSSidecarName {
				continue
			}
			if *container.Name == singleContainerName {
				containerID = *containerGroup.Name
			} else {
				containerID = *containerGroup.Name + composeContainerSeparator + *container.Name
			}
			status := "Unknown"
			if container.InstanceView != nil && container.InstanceView.CurrentState != nil {
				status = *container.InstanceView.CurrentState.State
			}

			res = append(res, containers.Container{
				ID:     containerID,
				Image:  *container.Image,
				Status: status,
				Ports:  convert.ToPorts(group.IPAddress, *container.Ports),
			})
		}
	}

	return res, nil
}

func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
	if strings.Contains(r.ID, composeContainerSeparator) {
		return errors.New(fmt.Sprintf(`invalid container name. ACI container name cannot include "%s"`, composeContainerSeparator))
	}

	var ports []types.ServicePortConfig
	for _, p := range r.Ports {
		ports = append(ports, types.ServicePortConfig{
			Target:    p.ContainerPort,
			Published: p.HostPort,
		})
	}

	projectVolumes, serviceConfigVolumes, err := convert.GetRunVolumes(r.Volumes)
	if err != nil {
		return err
	}

	project := types.Project{
		Name: r.ID,
		Services: []types.ServiceConfig{
			{
				Name:    singleContainerName,
				Image:   r.Image,
				Ports:   ports,
				Labels:  r.Labels,
				Volumes: serviceConfigVolumes,
				Deploy: &types.DeployConfig{
					Resources: types.Resources{
						Limits: &types.Resource{
							NanoCPUs:    fmt.Sprintf("%f", r.CPULimit),
							MemoryBytes: types.UnitBytes(r.MemLimit.Value()),
						},
					},
				},
			},
		},
		Volumes: projectVolumes,
	}

	logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, project)
	if err != nil {
		return err
	}

	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciContainerService) Stop(ctx context.Context, containerName string, timeout *uint32) error {
	return errdefs.ErrNotImplemented
}

func getGroupAndContainerName(containerID string) (groupName string, containerName string) {
	tokens := strings.Split(containerID, composeContainerSeparator)
	groupName = tokens[0]
	if len(tokens) > 1 {
		containerName = tokens[len(tokens)-1]
		groupName = containerID[:len(containerID)-(len(containerName)+1)]
	} else {
		containerName = singleContainerName
	}
	return groupName, containerName
}

func (cs *aciContainerService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
	groupName, containerAciName := getGroupAndContainerName(name)
	containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, groupName, containerAciName)
	if err != nil {
		return err
	}

	return exec(
		context.Background(),
		*containerExecResponse.WebSocketURI,
		*containerExecResponse.Password,
		reader,
		writer,
	)
}

func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
	groupName, containerAciName := getGroupAndContainerName(containerName)
	var tail *int32

	if req.Follow {
		return streamLogs(ctx, cs.ctx, groupName, containerAciName, req.Writer)
	}

	if req.Tail != "all" {
		reqTail, err := strconv.Atoi(req.Tail)
		if err != nil {
			return err
		}
		i32 := int32(reqTail)
		tail = &i32
	}

	logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName, tail)
	if err != nil {
		return err
	}

	_, err = fmt.Fprint(req.Writer, logs)
	return err
}

func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _ bool) error {
	groupName, containerName := getGroupAndContainerName(containerID)
	if groupName != containerID {
		return errors.New(fmt.Sprintf(`cannot delete service "%s" from compose app "%s", you must delete the entire compose app with docker compose down`, containerName, groupName))
	}
	cg, err := deleteACIContainerGroup(ctx, cs.ctx, groupName)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

func (cs *aciContainerService) Inspect(ctx context.Context, containerID string) (containers.Container, error) {
	groupName, containerName := getGroupAndContainerName(containerID)

	cg, err := getACIContainerGroup(ctx, cs.ctx, groupName)
	if err != nil {
		return containers.Container{}, err
	}
	if cg.StatusCode == http.StatusNoContent {
		return containers.Container{}, ErrNoSuchContainer
	}

	var cc containerinstance.Container
	var found = false
	for _, c := range *cg.Containers {
		if to.String(c.Name) == containerName {
			cc = c
			found = true
			break
		}
	}
	if !found {
		return containers.Container{}, ErrNoSuchContainer
	}

	return convert.ContainerGroupToContainer(containerID, cg, cc)
}

type aciComposeService struct {
	ctx store.AciContext
}

func (cs *aciComposeService) Up(ctx context.Context, opts cli.ProjectOptions) error {
	project, err := cli.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Up on project with name %q\n", project.Name)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project)

	if err != nil {
		return err
	}
	return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciComposeService) Down(ctx context.Context, opts cli.ProjectOptions) error {
	var project types.Project

	if opts.Name != "" {
		project = types.Project{Name: opts.Name}
	} else {
		fullProject, err := cli.ProjectFromOptions(&opts)
		if err != nil {
			return err
		}
		project = *fullProject
	}
	logrus.Debugf("Down on project with name %q\n", project.Name)

	cg, err := deleteACIContainerGroup(ctx, cs.ctx, project.Name)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciCloudService struct {
	loginService login.AzureLoginService
}

func (cs *aciCloudService) Login(ctx context.Context, params map[string]string) error {
	return cs.loginService.Login(ctx, params[login.TenantIDLoginParam])
}

func (cs *aciCloudService) CreateContextData(ctx context.Context, params map[string]string) (interface{}, string, error) {
	contextHelper := newContextCreateHelper()
	return contextHelper.createContextData(ctx, params)
}
<commit_msg>Use %q instead of \"%s\"<commit_after>/*
   Copyright 2020 Docker, 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 azure

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/docker/api/azure/convert"
	"github.com/docker/api/azure/login"
	"github.com/docker/api/backend"
	"github.com/docker/api/compose"
	"github.com/docker/api/containers"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/cloud"
	"github.com/docker/api/context/store"
	"github.com/docker/api/errdefs"
)

const (
	singleContainerName       = "single--container--aci"
	composeContainerSeparator = "_"
)

// ErrNoSuchContainer is returned when the mentioned container does not exist
var ErrNoSuchContainer = errors.New("no such container")

func init() {
	backend.Register("aci", "aci", service, getCloudService)
}

func service(ctx context.Context) (backend.Service, error) {
	contextStore := store.ContextStore(ctx)
	currentContext := apicontext.CurrentContext(ctx)
	var aciContext store.AciContext

	if err := contextStore.GetEndpoint(currentContext, &aciContext); err != nil {
		return nil, err
	}

	return getAciAPIService(aciContext), nil
}

func getCloudService() (cloud.Service, error) {
	service, err := login.NewAzureLoginService()
	if err != nil {
		return nil, err
	}
	return &aciCloudService{
		loginService: service,
	}, nil
}

func getAciAPIService(aciCtx store.AciContext) *aciAPIService {
	return &aciAPIService{
		aciContainerService: &aciContainerService{
			ctx: aciCtx,
		},
		aciComposeService: &aciComposeService{
			ctx: aciCtx,
		},
	}
}

type aciAPIService struct {
	*aciContainerService
	*aciComposeService
}

func (a *aciAPIService) ContainerService() containers.Service {
	return a.aciContainerService
}

func (a *aciAPIService) ComposeService() compose.Service {
	return a.aciComposeService
}

type aciContainerService struct {
	ctx store.AciContext
}

func (cs *aciContainerService) List(ctx context.Context, _ bool) ([]containers.Container, error) {
	groupsClient, err := getContainerGroupsClient(cs.ctx.SubscriptionID)
	if err != nil {
		return nil, err
	}
	var containerGroups []containerinstance.ContainerGroup
	result, err := groupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
	if err != nil {
		return []containers.Container{}, err
	}

	for result.NotDone() {
		containerGroups = append(containerGroups, result.Values()...)
		if err := result.NextWithContext(ctx); err != nil {
			return []containers.Container{}, err
		}
	}

	var res []containers.Container
	for _, containerGroup := range containerGroups {
		group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
		if err != nil {
			return []containers.Container{}, err
		}

		for _, container := range *group.Containers {
			var containerID string
			// don't list sidecar container
			if *container.Name == convert.ComposeDNSSidecarName {
				continue
			}
			if *container.Name == singleContainerName {
				containerID = *containerGroup.Name
			} else {
				containerID = *containerGroup.Name + composeContainerSeparator + *container.Name
			}
			status := "Unknown"
			if container.InstanceView != nil && container.InstanceView.CurrentState != nil {
				status = *container.InstanceView.CurrentState.State
			}

			res = append(res, containers.Container{
				ID:     containerID,
				Image:  *container.Image,
				Status: status,
				Ports:  convert.ToPorts(group.IPAddress, *container.Ports),
			})
		}
	}

	return res, nil
}

func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
	if strings.Contains(r.ID, composeContainerSeparator) {
		return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator))
	}

	var ports []types.ServicePortConfig
	for _, p := range r.Ports {
		ports = append(ports, types.ServicePortConfig{
			Target:    p.ContainerPort,
			Published: p.HostPort,
		})
	}

	projectVolumes, serviceConfigVolumes, err := convert.GetRunVolumes(r.Volumes)
	if err != nil {
		return err
	}

	project := types.Project{
		Name: r.ID,
		Services: []types.ServiceConfig{
			{
				Name:    singleContainerName,
				Image:   r.Image,
				Ports:   ports,
				Labels:  r.Labels,
				Volumes: serviceConfigVolumes,
				Deploy: &types.DeployConfig{
					Resources: types.Resources{
						Limits: &types.Resource{
							NanoCPUs:    fmt.Sprintf("%f", r.CPULimit),
							MemoryBytes: types.UnitBytes(r.MemLimit.Value()),
						},
					},
				},
			},
		},
		Volumes: projectVolumes,
	}

	logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, project)
	if err != nil {
		return err
	}

	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciContainerService) Stop(ctx context.Context, containerName string, timeout *uint32) error {
	return errdefs.ErrNotImplemented
}

func getGroupAndContainerName(containerID string) (groupName string, containerName string) {
	tokens := strings.Split(containerID, composeContainerSeparator)
	groupName = tokens[0]
	if len(tokens) > 1 {
		containerName = tokens[len(tokens)-1]
		groupName = containerID[:len(containerID)-(len(containerName)+1)]
	} else {
		containerName = singleContainerName
	}
	return groupName, containerName
}

func (cs *aciContainerService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
	groupName, containerAciName := getGroupAndContainerName(name)
	containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, groupName, containerAciName)
	if err != nil {
		return err
	}

	return exec(
		context.Background(),
		*containerExecResponse.WebSocketURI,
		*containerExecResponse.Password,
		reader,
		writer,
	)
}

func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
	groupName, containerAciName := getGroupAndContainerName(containerName)
	var tail *int32

	if req.Follow {
		return streamLogs(ctx, cs.ctx, groupName, containerAciName, req.Writer)
	}

	if req.Tail != "all" {
		reqTail, err := strconv.Atoi(req.Tail)
		if err != nil {
			return err
		}
		i32 := int32(reqTail)
		tail = &i32
	}

	logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName, tail)
	if err != nil {
		return err
	}

	_, err = fmt.Fprint(req.Writer, logs)
	return err
}

func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _ bool) error {
	groupName, containerName := getGroupAndContainerName(containerID)
	if groupName != containerID {
		return errors.New(fmt.Sprintf(`cannot delete service "%s" from compose app "%s", you must delete the entire compose app with docker compose down`, containerName, groupName))
	}
	cg, err := deleteACIContainerGroup(ctx, cs.ctx, groupName)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

func (cs *aciContainerService) Inspect(ctx context.Context, containerID string) (containers.Container, error) {
	groupName, containerName := getGroupAndContainerName(containerID)

	cg, err := getACIContainerGroup(ctx, cs.ctx, groupName)
	if err != nil {
		return containers.Container{}, err
	}
	if cg.StatusCode == http.StatusNoContent {
		return containers.Container{}, ErrNoSuchContainer
	}

	var cc containerinstance.Container
	var found = false
	for _, c := range *cg.Containers {
		if to.String(c.Name) == containerName {
			cc = c
			found = true
			break
		}
	}
	if !found {
		return containers.Container{}, ErrNoSuchContainer
	}

	return convert.ContainerGroupToContainer(containerID, cg, cc)
}

type aciComposeService struct {
	ctx store.AciContext
}

func (cs *aciComposeService) Up(ctx context.Context, opts cli.ProjectOptions) error {
	project, err := cli.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Up on project with name %q\n", project.Name)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project)

	if err != nil {
		return err
	}
	return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciComposeService) Down(ctx context.Context, opts cli.ProjectOptions) error {
	var project types.Project

	if opts.Name != "" {
		project = types.Project{Name: opts.Name}
	} else {
		fullProject, err := cli.ProjectFromOptions(&opts)
		if err != nil {
			return err
		}
		project = *fullProject
	}
	logrus.Debugf("Down on project with name %q\n", project.Name)

	cg, err := deleteACIContainerGroup(ctx, cs.ctx, project.Name)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciCloudService struct {
	loginService login.AzureLoginService
}

func (cs *aciCloudService) Login(ctx context.Context, params map[string]string) error {
	return cs.loginService.Login(ctx, params[login.TenantIDLoginParam])
}

func (cs *aciCloudService) CreateContextData(ctx context.Context, params map[string]string) (interface{}, string, error) {
	contextHelper := newContextCreateHelper()
	return contextHelper.createContextData(ctx, params)
}
<|endoftext|>


<commit_before>package image

import (
	"encoding/binary"
	"image"
	"math"
	"sort"

	"github.com/nfnt/resize"
)

const (
	dctSize = 32
)

func PerceptualHash0(im image.Image) ([]byte, []float32) {
	gray := dctResize(im)
	arr := image2Array(gray)
	dcts := dct2d(arr)
	hash, inputs := phash0(dcts)
	outputs := make([]float32, len(inputs))
	for i, input := range inputs {
		outputs[i] = float32(input)
	}
	hashBytes := make([]byte, 8)
	binary.BigEndian.PutUint64(hashBytes, hash)

	return hashBytes, outputs
}

// This approach is riddled with inefficiencies.
func phash0(vals [][]float64) (uint64, []float64) {
	inputs := make([]float64, 0, 64)
	flatvals := make([]float64, 0, len(inputs))
	for y := 1; y < 9; y++ {
		for x := 1; x < 9; x++ {
			inputs = append(inputs, vals[y][x])
			flatvals = append(flatvals, vals[y][x])
		}
	}

	sort.Float64s(flatvals)
	mid := len(flatvals) / 2
	median := (flatvals[mid-1] + flatvals[mid]) / 2
	var hash uint64

	for i, val := range flatvals {
		if val > median {
			hash |= 1 << uint(i)
		}
	}

	return hash, inputs
}

func dctResize(im image.Image) *image.Gray {
	small := resize.Resize(dctSize, dctSize, im, resize.Lanczos2)

	// TODO: do colorspace conversion in Lab colorspace
	gray := image.NewGray(small.Bounds())
	for y := gray.Bounds().Min.Y; y < gray.Bounds().Max.Y; y++ {
		for x := gray.Bounds().Min.X; x < gray.Bounds().Max.X; x++ {
			gray.Set(x, y, small.At(x, y))
		}
	}
	return gray
}

func image2Array(im *image.Gray) [][]float64 {
	arr := make([][]float64, im.Bounds().Dy())
	for y := 0; y < len(arr); y++ {
		arr[y] = make([]float64, im.Bounds().Dx())
	}
	for y := 0; y < len(arr); y++ {
		for x := 0; x < len(arr[y]); x++ {
			arr[y][x] = float64(im.GrayAt(x, y).Y) - 128
		}
	}
	return arr
}

// this whole function could be faster.
func dct2d(s [][]float64) [][]float64 {
	n := len(s) // row count
	S := make([][]float64, n)
	for v, d := range s {
		if len(d) != n {
			panic("Non square matrix")
		}
		S[v] = make([]float64, n)
		copy(S[v], d)
	}

	// rows
	for y := 0; y < n; y++ {
		S[y] = dct(S[y])
	}

	transpose(S)
	// columns
	for x := 0; x < n; x++ {
		S[x] = dct(S[x])
	}

	transpose(S)
	return S
}

func transpose(s [][]float64) {
	for i := 0; i < len(s); i++ {
		for k := i + 1; k < len(s); k++ {
			s[i][k], s[k][i] = s[k][i], s[i][k]
		}
	}
}

func dct(s []float64) []float64 {
	n := len(s)
	N := float64(n)
	S := make([]float64, n)

	for k := 0; k < n; k++ {
		for i := 0; i < n; i++ {
			S[k] += s[i] * Cos(i, k, n)
		}
		S[k] *= math.Sqrt(2/N) * C(k)
	}

	return S
}

func C(x int) float64 {
	if x == 0 {
		return 1 / math.Sqrt2
	}
	return 1
}

func Cos(y, v, n int) float64 {
	Y, V, N := float64(y), float64(v), float64(n)
	PI := math.Pi

	return math.Cos((2*Y + 1) * V * PI / (2 * N))
}

func idct2d(S [][]float64) [][]float64 {
	n := len(S) // row count
	N := float64(n)
	s := make([][]float64, n)
	for v, d := range S {
		if len(d) != n {
			panic("Non square matrix")
		}
		s[v] = make([]float64, n)
	}

	for y := 0; y < n; y++ {
		for x := 0; x < n; x++ {
			var sum float64

			for v := 0; v < n; v++ {
				for u := 0; u < n; u++ {
					sum += S[v][u] * C(v) * C(u) * Cos2(y, x, v, u, n)
				}
			}

			s[y][x] = sum * (2 / N)
		}
	}

	return s
}

func Cos2(y, x, v, u, n int) float64 {
	Y, X, V, U, N := float64(y), float64(x), float64(v), float64(u), float64(n)
	PI := math.Pi

	return math.Cos((2*Y+1)*V*PI/(2*N)) * math.Cos((2*X+1)*U*PI/(2*N))
}
<commit_msg>Fix minor bug with phash<commit_after>package image

import (
	"encoding/binary"
	"image"
	"math"
	"sort"

	"github.com/nfnt/resize"
)

const (
	dctSize = 32
)

func PerceptualHash0(im image.Image) ([]byte, []float32) {
	gray := dctResize(im)
	arr := image2Array(gray)
	dcts := dct2d(arr)
	hash, inputs := phash0(dcts)
	outputs := make([]float32, len(inputs))
	for i, input := range inputs {
		outputs[i] = float32(input)
	}
	hashBytes := make([]byte, 8)
	binary.BigEndian.PutUint64(hashBytes, hash)

	return hashBytes, outputs
}

// This approach is riddled with inefficiencies.
func phash0(vals [][]float64) (uint64, []float64) {
	inputs := make([]float64, 0, 64)
	flatvals := make([]float64, 0, len(inputs))
	for y := 1; y < 9; y++ {
		for x := 1; x < 9; x++ {
			inputs = append(inputs, vals[y][x])
			flatvals = append(flatvals, vals[y][x])
		}
	}

	sort.Float64s(flatvals)
	mid := len(flatvals) / 2
	median := (flatvals[mid-1] + flatvals[mid]) / 2
	var hash uint64

	for i, val := range inputs {
		if val > median {
			hash |= 1 << uint(i)
		}
	}

	return hash, inputs
}

func dctResize(im image.Image) *image.Gray {
	small := resize.Resize(dctSize, dctSize, im, resize.Lanczos2)

	// TODO: do colorspace conversion in Lab colorspace
	gray := image.NewGray(small.Bounds())
	for y := gray.Bounds().Min.Y; y < gray.Bounds().Max.Y; y++ {
		for x := gray.Bounds().Min.X; x < gray.Bounds().Max.X; x++ {
			gray.Set(x, y, small.At(x, y))
		}
	}
	return gray
}

func image2Array(im *image.Gray) [][]float64 {
	arr := make([][]float64, im.Bounds().Dy())
	for y := 0; y < len(arr); y++ {
		arr[y] = make([]float64, im.Bounds().Dx())
	}
	for y := 0; y < len(arr); y++ {
		for x := 0; x < len(arr[y]); x++ {
			arr[y][x] = float64(im.GrayAt(x, y).Y) - 128
		}
	}
	return arr
}

// this whole function could be faster.
func dct2d(s [][]float64) [][]float64 {
	n := len(s) // row count
	S := make([][]float64, n)
	for v, d := range s {
		if len(d) != n {
			panic("Non square matrix")
		}
		S[v] = make([]float64, n)
		copy(S[v], d)
	}

	// rows
	for y := 0; y < n; y++ {
		S[y] = dct(S[y])
	}

	transpose(S)
	// columns
	for x := 0; x < n; x++ {
		S[x] = dct(S[x])
	}

	transpose(S)
	return S
}

func transpose(s [][]float64) {
	for i := 0; i < len(s); i++ {
		for k := i + 1; k < len(s); k++ {
			s[i][k], s[k][i] = s[k][i], s[i][k]
		}
	}
}

func dct(s []float64) []float64 {
	n := len(s)
	N := float64(n)
	S := make([]float64, n)

	for k := 0; k < n; k++ {
		for i := 0; i < n; i++ {
			S[k] += s[i] * Cos(i, k, n)
		}
		S[k] *= math.Sqrt(2/N) * C(k)
	}

	return S
}

func C(x int) float64 {
	if x == 0 {
		return 1 / math.Sqrt2
	}
	return 1
}

func Cos(y, v, n int) float64 {
	Y, V, N := float64(y), float64(v), float64(n)
	PI := math.Pi

	return math.Cos((2*Y + 1) * V * PI / (2 * N))
}

func idct2d(S [][]float64) [][]float64 {
	n := len(S) // row count
	N := float64(n)
	s := make([][]float64, n)
	for v, d := range S {
		if len(d) != n {
			panic("Non square matrix")
		}
		s[v] = make([]float64, n)
	}

	for y := 0; y < n; y++ {
		for x := 0; x < n; x++ {
			var sum float64

			for v := 0; v < n; v++ {
				for u := 0; u < n; u++ {
					sum += S[v][u] * C(v) * C(u) * Cos2(y, x, v, u, n)
				}
			}

			s[y][x] = sum * (2 / N)
		}
	}

	return s
}

func Cos2(y, x, v, u, n int) float64 {
	Y, X, V, U, N := float64(y), float64(x), float64(v), float64(u), float64(n)
	PI := math.Pi

	return math.Cos((2*Y+1)*V*PI/(2*N)) * math.Cos((2*X+1)*U*PI/(2*N))
}
<|endoftext|>


<commit_before>package ocrworker

import (
  "fmt"
  "io/ioutil"
  "os"
  "os/exec"

  "github.com/couchbaselabs/logg"
)

type ImageProcessing struct {
}

func (s ImageProcessing) preprocess(ocrRequest *OcrRequest) error {

  // write bytes to a temp file

  tmpFileNameInput, err := createTempFileName()
  tmpFileNameInput = fmt.Sprintf("%s.png", tmpFileNameInput)
  if err != nil {
    return err
  }
  defer os.Remove(tmpFileNameInput)

  tmpFileNameOutput, err := createTempFileName()
  tmpFileNameOutput = fmt.Sprintf("%s.png", tmpFileNameOutput)
  if err != nil {
    return err
  }
  defer os.Remove(tmpFileNameOutput)

  err = saveBytesToFileName(ocrRequest.ImgBytes, tmpFileNameInput)
  if err != nil {
    return err
  }

  logg.LogTo(
    "PREPROCESSOR_WORKER",
    "Image Processing on %s -> %s",
    tmpFileNameInput,
    tmpFileNameOutput,
  )

  dir, errtest := os.Getwd()
  logg.LogTo(
    "PREPROCESSOR_WORKER",
    "Current dir is %s",
    dir,
  )

  out1, err1 := exec.Command(
    "ls",
  ).CombinedOutput()
  if err != nil {
    logg.LogFatal("Error running command: %s.  out: %s", err1, out1)
  }
  logg.LogTo("PREPROCESSOR_WORKER", "output: %v", string(out1))

  out, err := exec.Command(
    "python",
    "resizeimg.py",
    tmpFileNameInput,
    tmpFileNameOutput,
  ).CombinedOutput()
  if err != nil {
    logg.LogFatal("Error running command: %s.  out: %s", err, out)
  }
  logg.LogTo("PREPROCESSOR_WORKER", "output: %v", string(out))

  // read bytes from output file into ocrRequest.ImgBytes
  resultBytes, err := ioutil.ReadFile(tmpFileNameOutput)
  if err != nil {
    return err
  }

  ocrRequest.ImgBytes = resultBytes

  return nil
}
<commit_msg>add error log<commit_after>package ocrworker

import (
  "fmt"
  "io/ioutil"
  "os"
  "os/exec"

  "github.com/couchbaselabs/logg"
)

type ImageProcessing struct {
}

func (s ImageProcessing) preprocess(ocrRequest *OcrRequest) error {

  // write bytes to a temp file

  tmpFileNameInput, err := createTempFileName()
  tmpFileNameInput = fmt.Sprintf("%s.png", tmpFileNameInput)
  if err != nil {
    return err
  }
  defer os.Remove(tmpFileNameInput)

  tmpFileNameOutput, err := createTempFileName()
  tmpFileNameOutput = fmt.Sprintf("%s.png", tmpFileNameOutput)
  if err != nil {
    return err
  }
  defer os.Remove(tmpFileNameOutput)

  err = saveBytesToFileName(ocrRequest.ImgBytes, tmpFileNameInput)
  if err != nil {
    return err
  }

  logg.LogTo(
    "PREPROCESSOR_WORKER",
    "Image Processing on %s -> %s",
    tmpFileNameInput,
    tmpFileNameOutput,
  )

  dir, errtest := os.Getwd()
  logg.LogTo(
    "PREPROCESSOR_WORKER",
    "Current dir is %s",
    dir,
  )
  if errtest != nil {
    logg.LogFatal("Error running command: %s.  out: %s", errtest, dir)
  }

  out1, err1 := exec.Command(
    "ls",
  ).CombinedOutput()
  if err != nil {
    logg.LogFatal("Error running command: %s.  out: %s", err1, out1)
  }
  logg.LogTo("PREPROCESSOR_WORKER", "output: %v", string(out1))

  out, err := exec.Command(
    "python",
    "resizeimg.py",
    tmpFileNameInput,
    tmpFileNameOutput,
  ).CombinedOutput()
  if err != nil {
    logg.LogFatal("Error running command: %s.  out: %s", err, out)
  }
  logg.LogTo("PREPROCESSOR_WORKER", "output: %v", string(out))

  // read bytes from output file into ocrRequest.ImgBytes
  resultBytes, err := ioutil.ReadFile(tmpFileNameOutput)
  if err != nil {
    return err
  }

  ocrRequest.ImgBytes = resultBytes

  return nil
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"encoding/json"
	"io"
	"log"
	"math"
	"net/http"
	"os"
	"sort"
	"strings"
	"time"
)

var bsn bikeShareNetwork

func main() {
	log.Println("starting seagull")
	var err error
	bsn, err = getSeedData()
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir("../frontend/www")))
	http.HandleFunc("/api/networks", GzipFunc(listNetworksHandler))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}

}

func listNetworksHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("listNetworks", r.RemoteAddr, r.RequestURI)

	type Shortnet struct {
		ID       string `json:"id"`
		Name     string `json:"name"`
		Location `json:"location"`
	}

	type Response struct {
		Networks []Shortnet `json:"networks"`
	}

	var networks Response
	for _, v := range bsn.Networks {
		short := Shortnet{
			ID:       v.ID,
			Name:     v.Name,
			Location: v.Location,
		}
		networks.Networks = append(networks.Networks, short)

	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(networks); err != nil {
		log.Println(err)
	}

}

func getSeedData() (bikeShareNetwork, error) {

	// check if we have it first
	if _, err := os.Stat("bsn.json"); os.IsNotExist(err) {
		const bikeShareAPI = "http://api.citybik.es/v2/networks"

		var bsn bikeShareNetwork
		resp, err := http.Get(bikeShareAPI)
		if err != nil {
			return bsn, err
		}
		defer resp.Body.Close()

		dec := json.NewDecoder(resp.Body)
		if err := dec.Decode(&bsn); err != nil {
			return bsn, err
		}
		networks := len(bsn.Networks)
		for k, v := range bsn.Networks {
			log.Printf("(%3d of %3d) detail of %s, \n", k+1, networks, v.ID)
			var detail networkDetail
			resp, err := http.Get(bikeShareAPI + "/" + v.ID)
			if err != nil {
				log.Printf("error reading network detail for %s: %v", v.ID, err)
				break
			}
			defer resp.Body.Close()
			dec := json.NewDecoder(resp.Body)
			if err := dec.Decode(&detail); err != nil {
				log.Printf("error decoding detail json for %s: %v", v.ID, err)
				break
			}
			bsn.Networks[k] = detail.Detail
		}

		out, err := os.Create("bsn.json")
		if err != nil {
			log.Fatal(err)
		}
		defer out.Close()

		enc := json.NewEncoder(out)
		err = enc.Encode(bsn)
		if err != nil {
			log.Println(err)
		}

	}

	var bsn bikeShareNetwork

	in, err := os.Open("bsn.json")
	if err != nil {
		return bsn, err
	}

	dec := json.NewDecoder(in)
	if err := dec.Decode(&bsn); err != nil {
		return bsn, err
	}
	// get data from file

	return bsn, nil

}

type bikeShareNetwork struct {
	Networks []Network `json:"networks"`
}

type Network struct {
	Company  []string `json:"company"`
	Href     string   `json:"href"`
	ID       string   `json:"id"`
	Location `json:"location"`
	Name     string    `json:"name"`
	Stations []Station `json:"stations,omitempty"`
}

type networkDetail struct {
	Detail Network `json:"network"`
}

type Station struct {
	EmptySlots int       `json:"empty_slots"`
	FreeBikes  int       `json:"free_bikes"`
	ID         string    `json:"id"`
	Latitude   float64   `json:"latitude"`
	Longitude  float64   `json:"longitude"`
	Name       string    ` json:"name"`
	Timestamp  time.Time `json:"timestamp"` // look up local offset at location
}

type Location struct {
	City      string  `json:"city"`
	Country   string  `json:"country"`
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

func (n *Network) UnmarshalJSON(data []byte) error {
	// Need too handle the one case company strings vs []string
	type ServerNetworks Network
	aux := &struct {
		Company interface{} `json:"company"`
		*ServerNetworks
	}{
		ServerNetworks: (*ServerNetworks)(n),
	}
	err := json.Unmarshal(data, &aux)
	if err != nil {
		return err
	}

	switch aux.Company.(type) {
	case string:
		c, ok := aux.Company.(string)
		if ok {
			n.Company = append(n.Company, c)
		}
	case []interface{}:
		cc, ok := aux.Company.([]interface{})
		if ok {
			for _, vv := range cc {
				switch vv.(type) {
				case string:
					c, ok := vv.(string)
					if ok {
						n.Company = append(n.Company, c)
					} else {
						log.Println("failed conversion to string")
					}
				}
			}
		}
	}
	return nil
}

type stations []Station

func (ss stations) within(lat, lng, dist float64) stations {

	sort.Slice(ss, func(i, j int) bool {
		return ss[i].distance(lat, lng) < ss[j].distance(lat, lng)
	})

	var abriged []Station
	for _, v := range ss {
		if v.distance(lat, lng) < dist {
			abriged = append(abriged, v)
		} else {
			return abriged
		}
	}
	return abriged
}

func (s *Station) distance(lat, lng float64) float64 {
	// http://www.movable-type.co.uk/scripts/latlong.html
	R := 6371e3 // radius

	φ1 := (math.Pi * lat) / 180
	φ2 := (math.Pi * lng) / 180

	Δφ := (s.Latitude - lat) * math.Pi / 180
	Δλ := (s.Longitude - lng) * math.Pi / 180

	a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +
		math.Cos(φ1)*math.Cos(φ2)*
			math.Sin(Δλ/2)*math.Sin(Δλ/2)
	return R * 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
}

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func GzipFunc(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			w.Header().Set("Pragma", "no-cache")
			w.Header().Set("Content-Type", "application/json")
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		w.Header().Set("Pragma", "no-cache")
		w.Header().Set("Content-Type", "application/json")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.Writer.Write(b)
}
<commit_msg>add location to network list<commit_after>package main

import (
	"compress/gzip"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

var bsn bikeShareNetwork

func main() {
	log.Println("starting seagull")
	var err error
	bsn, err = getSeedData()
	if err != nil {
		log.Fatal(err)
	}

	http.Handle("/", http.FileServer(http.Dir("../frontend/www")))
	http.HandleFunc("/api/networks", GzipFunc(listNetworksHandler))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}

}

type Shortnet struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Location `json:"location"`
	distance float64 `json:"distance"`
}

func (l Location) distance(lat, lng float64) float64 {
	R := 6371e3 // radius

	φ1 := (math.Pi * lat) / 180
	φ2 := (math.Pi * lng) / 180

	Δφ := (l.Latitude - lat) * math.Pi / 180
	Δλ := (l.Longitude - lng) * math.Pi / 180

	a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +
		math.Cos(φ1)*math.Cos(φ2)*
			math.Sin(Δλ/2)*math.Sin(Δλ/2)
	return R * 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
}

func parseNetworksQuery(u url.Values) (float64, float64, float64, error) {
	_, latok := u["lat"]
	_, lngok := u["lng"]
	_, rngok := u["rng"]
	if !latok || !lngok || !rngok {
		return 0, 0, 0, errors.New("invalid")
	}

	lat, err := strconv.ParseFloat(u["lat"][0], 10)
	if err != nil {
		return 0, 0, 0, err
	}

	lng, err := strconv.ParseFloat(u["lng"][0], 10)
	if err != nil {
		return 0, 0, 0, err
	}

	rng, err := strconv.ParseFloat(u["rng"][0], 10)
	if err != nil {
		return 0, 0, 0, err
	}

	return lat, lng, rng, nil
}

func listNetworksHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("listNetworks", r.RemoteAddr, r.RequestURI)

	type Response struct {
		Networks []Shortnet `json:"networks"`
	}

	var networks Response
	for _, v := range bsn.Networks {
		short := Shortnet{
			ID:       v.ID,
			Name:     v.Name,
			Location: v.Location,
		}
		networks.Networks = append(networks.Networks, short)
	}

	q := r.URL.Query()
	lat, lng, rng, err := parseNetworksQuery(q)

	if err != nil {
		log.Println("oops", err)
		enc := json.NewEncoder(w)
		if err := enc.Encode(networks); err != nil {
			log.Println(err)
		}
		return
	}

	sort.Slice(networks.Networks, func(i, j int) bool {
		return networks.Networks[i].Location.distance(lat, lng) < networks.Networks[j].Location.distance(lat, lng)
	})

	var within Response
	for _, v := range networks.Networks {
		if v.Location.distance(lat, lng) < rng {
			within.Networks = append(within.Networks, v)
		} else {
			break
		}
	}

	fmt.Println(within)
	enc := json.NewEncoder(w)
	if err := enc.Encode(within); err != nil {
		log.Println(err)
	}
	// for k, v, range :=

}

func getSeedData() (bikeShareNetwork, error) {

	// check if we have it first
	if _, err := os.Stat("bsn.json"); os.IsNotExist(err) {
		const bikeShareAPI = "http://api.citybik.es/v2/networks"

		var bsn bikeShareNetwork
		resp, err := http.Get(bikeShareAPI)
		if err != nil {
			return bsn, err
		}
		defer resp.Body.Close()

		dec := json.NewDecoder(resp.Body)
		if err := dec.Decode(&bsn); err != nil {
			return bsn, err
		}
		networks := len(bsn.Networks)
		for k, v := range bsn.Networks {
			log.Printf("(%3d of %3d) detail of %s, \n", k+1, networks, v.ID)
			var detail networkDetail
			resp, err := http.Get(bikeShareAPI + "/" + v.ID)
			if err != nil {
				log.Printf("error reading network detail for %s: %v", v.ID, err)
				break
			}
			defer resp.Body.Close()
			dec := json.NewDecoder(resp.Body)
			if err := dec.Decode(&detail); err != nil {
				log.Printf("error decoding detail json for %s: %v", v.ID, err)
				break
			}
			bsn.Networks[k] = detail.Detail
		}

		out, err := os.Create("bsn.json")
		if err != nil {
			log.Fatal(err)
		}
		defer out.Close()

		enc := json.NewEncoder(out)
		err = enc.Encode(bsn)
		if err != nil {
			log.Println(err)
		}

	}

	var bsn bikeShareNetwork

	in, err := os.Open("bsn.json")
	if err != nil {
		return bsn, err
	}

	dec := json.NewDecoder(in)
	if err := dec.Decode(&bsn); err != nil {
		return bsn, err
	}
	// get data from file

	return bsn, nil

}

type bikeShareNetwork struct {
	Networks []Network `json:"networks"`
}

type Network struct {
	Company  []string `json:"company"`
	Href     string   `json:"href"`
	ID       string   `json:"id"`
	Location `json:"location"`
	Name     string    `json:"name"`
	Stations []Station `json:"stations,omitempty"`
}

type networkDetail struct {
	Detail Network `json:"network"`
}

type Station struct {
	EmptySlots int       `json:"empty_slots"`
	FreeBikes  int       `json:"free_bikes"`
	ID         string    `json:"id"`
	Latitude   float64   `json:"latitude"`
	Longitude  float64   `json:"longitude"`
	Name       string    ` json:"name"`
	Timestamp  time.Time `json:"timestamp"` // look up local offset at location
}

type Location struct {
	City      string  `json:"city"`
	Country   string  `json:"country"`
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

func (n *Network) UnmarshalJSON(data []byte) error {
	// Need too handle the one case company strings vs []string
	type ServerNetworks Network
	aux := &struct {
		Company interface{} `json:"company"`
		*ServerNetworks
	}{
		ServerNetworks: (*ServerNetworks)(n),
	}
	err := json.Unmarshal(data, &aux)
	if err != nil {
		return err
	}

	switch aux.Company.(type) {
	case string:
		c, ok := aux.Company.(string)
		if ok {
			n.Company = append(n.Company, c)
		}
	case []interface{}:
		cc, ok := aux.Company.([]interface{})
		if ok {
			for _, vv := range cc {
				switch vv.(type) {
				case string:
					c, ok := vv.(string)
					if ok {
						n.Company = append(n.Company, c)
					} else {
						log.Println("failed conversion to string")
					}
				}
			}
		}
	}
	return nil
}

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func GzipFunc(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			w.Header().Set("Pragma", "no-cache")
			w.Header().Set("Content-Type", "application/json")
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		w.Header().Set("Pragma", "no-cache")
		w.Header().Set("Content-Type", "application/json")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.Writer.Write(b)
}
<|endoftext|>


<commit_before>package gow

import (
	"log"
	"regexp"
	"sync"
)

type BackendPool struct {
	backends map[string]*Backend
	mtx      *sync.Mutex
}

func NewBackendPool() *BackendPool {
	return &BackendPool{backends: make(map[string]*Backend)}
}

func (p *BackendPool) Select(host string) (string, error) {
	// Yes, we are this crazy. Lock the mutex during the entire lookup time, which could potentially include
	// (re)spawning an application. Serialize all of this so that we never have to deal with thundering-herd
	// spawns and such.
	p.mtx.Lock()
	defer p.mtx.Unlock()

	name := appNameFromHost(host)
	var err error
	p.restartIfRequested(name)

	backend := p.backends[name]

	if backend == nil {
		backend, err = SpawnBackend(name)

		if err == nil {
			p.backends[name] = backend
		} else {
			return "", err
		}
	}

	backend.Touch()

	return backend.Address(), nil
}

func (p *BackendPool) restartIfRequested(name string) error {
	if p.backends[name] == nil || !p.backends[name].IsRestartRequested() {
		return nil
	}
	log.Println("restarting", name)

	p.backends[name].Close()

	refreshed_backend, err := SpawnBackend(name)

	if err != nil {
		return err
	}

	p.backends[name] = refreshed_backend

	return nil
}

func (p *BackendPool) Close() {
	for k := range p.backends {
		p.backends[k].Close()
	}
}

var hostRegex = regexp.MustCompile("([a-z_\\-0-9A-Z]+)")

func appNameFromHost(host string) string {
	return hostRegex.FindString(host)
}
<commit_msg>fix crash on nil pointer to mutex<commit_after>package gow

import (
	"log"
	"regexp"
	"sync"
)

type BackendPool struct {
	backends map[string]*Backend
	mtx      sync.Mutex
}

func NewBackendPool() *BackendPool {
	return &BackendPool{backends: make(map[string]*Backend)}
}

func (p *BackendPool) Select(host string) (string, error) {
	// Yes, we are this crazy. Lock the mutex during the entire lookup time, which could potentially include
	// (re)spawning an application. Serialize all of this so that we never have to deal with thundering-herd
	// spawns and such.
	p.mtx.Lock()
	defer p.mtx.Unlock()

	name := appNameFromHost(host)
	var err error
	p.restartIfRequested(name)

	backend := p.backends[name]

	if backend == nil {
		backend, err = SpawnBackend(name)

		if err == nil {
			p.backends[name] = backend
		} else {
			return "", err
		}
	}

	backend.Touch()

	return backend.Address(), nil
}

func (p *BackendPool) restartIfRequested(name string) error {
	if p.backends[name] == nil || !p.backends[name].IsRestartRequested() {
		return nil
	}
	log.Println("restarting", name)

	p.backends[name].Close()

	refreshed_backend, err := SpawnBackend(name)

	if err != nil {
		return err
	}

	p.backends[name] = refreshed_backend

	return nil
}

func (p *BackendPool) Close() {
	for k := range p.backends {
		p.backends[k].Close()
	}
}

var hostRegex = regexp.MustCompile("([a-z_\\-0-9A-Z]+)")

func appNameFromHost(host string) string {
	return hostRegex.FindString(host)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"io/ioutil"
	"log"
	"os"

	"github.com/caoimhechaos/go-serialdata"
	"github.com/golang/protobuf/proto"
	"github.com/starshipfactory/membersys"
	"github.com/starshipfactory/membersys/config"
	"github.com/starshipfactory/membersys/db"
)

func main() {
	var ctx context.Context
	var configData config.DatabaseConfig
	var configContents []byte
	var configPath string
	var chdirPath string
	var database membersys.MembershipDB
	var verbose bool

	var memberAgreementStream chan *membersys.MembershipAgreementWithKey = make(chan *membersys.MembershipAgreementWithKey)
	var memberStream chan *membersys.Member = make(chan *membersys.Member)
	var errorStream chan error = make(chan error)
	var moreData bool

	var out *os.File
	var writer *serialdata.SerialDataWriter
	var err error

	flag.StringVar(&configPath, "config", "",
		"Path to a configuration file for the backup tool.")
	flag.StringVar(&chdirPath, "chdir", "",
		"Path to change directory to before backup.")
	flag.BoolVar(&verbose, "verbose", false,
		"Verbosely display backup progress.")
	flag.Parse()

	if len(configPath) == 0 {
		flag.Usage()
		return
	}

	if chdirPath != "" {
		err = os.Chdir(chdirPath)
		if err != nil {
			log.Fatal("Unable to change directory to ", chdirPath,
				": ", err)
		}
	}

	configContents, err = ioutil.ReadFile(configPath)
	if err != nil {
		log.Fatal("Unable to read ", configPath, ": ", err)
	}

	if verbose {
		log.Print("Read ", len(configContents), " bytes from config")
	}

	err = proto.Unmarshal(configContents, &configData)
	if err != nil {
		err = proto.UnmarshalText(string(configContents), &configData)
	}
	if err != nil {
		log.Fatal("Unable to parse ", configPath, ": ", err)
	}

	// Back up all members.
	out, err = os.Create("members.pb")
	if err != nil {
		log.Fatal("Error opening members.pb for writing: ", err)
	}
	writer = serialdata.NewSerialDataWriter(out)

	database, err = db.New(&configData)
	if err != nil {
		log.Fatal("Error connecting to database: ", err)
	}

	ctx = context.Background()

	go database.StreamingEnumerateMembers(ctx, "", 0, memberStream, errorStream)

	moreData = true
	for moreData {
		var member *membersys.Member
		select {
		case member = <-memberStream:
			if verbose {
				log.Print("Backing up member ", member.GetName())
			}
			err = writer.WriteMessage(member)
			if err != nil {
				log.Fatal("Error writing record to members.pb: ", err)
			}
		case err = <-errorStream:
			log.Fatal("Error enumerating members: ", err)
		default:
			log.Print("All members backed up.")
			moreData = false
			break
		}
	}

	err = out.Close()
	if err != nil {
		log.Fatal("Error closing members.pb: ", err)
	}

	// Back up all membership requests
	out, err = os.Create("membership_requests.pb")
	if err != nil {
		log.Fatal("Error opening membership_requests.pb for writing: ", err)
	}
	writer = serialdata.NewSerialDataWriter(out)

	go database.StreamingEnumerateMembershipRequests(
		ctx, "", "", 0, memberAgreementStream, errorStream)

	moreData = true
	for moreData {
		var memberAgreement *membersys.MembershipAgreementWithKey
		select {
		case memberAgreement = <-memberAgreementStream:
			if verbose {
				log.Print("Backing up membership request for ",
					memberAgreement.MemberData.GetName())
			}
			err = writer.WriteMessage(memberAgreement)
			if err != nil {
				log.Fatal("Error writing record to membership_requests.pb: ", err)
			}

		case err = <-errorStream:
			log.Fatal("Error enumerating membership agreements: ", err)
		default:
			log.Print("All membership agreements backed up.")
			moreData = false
			break
		}
	}

	err = out.Close()
	if err != nil {
		log.Fatal("Error closing membership_requests.pb: ", err)
	}
}
<commit_msg>Handle errors from database queries in a separate goroutine.<commit_after>package main

import (
	"context"
	"flag"
	"io/ioutil"
	"log"
	"os"

	"github.com/caoimhechaos/go-serialdata"
	"github.com/golang/protobuf/proto"
	"github.com/starshipfactory/membersys"
	"github.com/starshipfactory/membersys/config"
	"github.com/starshipfactory/membersys/db"
)

func handleErrors(errors <-chan error) {
	var err error

	for err = range errors {
		log.Fatal("Error: ", err)
	}

	log.Print("No errors detected")
}

func main() {
	var ctx context.Context
	var configData config.DatabaseConfig
	var configContents []byte
	var configPath string
	var chdirPath string
	var database membersys.MembershipDB
	var verbose bool

	var memberAgreementStream chan *membersys.MembershipAgreementWithKey = make(chan *membersys.MembershipAgreementWithKey)
	var memberStream chan *membersys.Member = make(chan *membersys.Member)
	var member *membersys.Member
	var memberAgreement *membersys.MembershipAgreementWithKey
	var errorStream chan error = make(chan error)

	var out *os.File
	var writer *serialdata.SerialDataWriter
	var err error

	flag.StringVar(&configPath, "config", "",
		"Path to a configuration file for the backup tool.")
	flag.StringVar(&chdirPath, "chdir", "",
		"Path to change directory to before backup.")
	flag.BoolVar(&verbose, "verbose", false,
		"Verbosely display backup progress.")
	flag.Parse()

	if len(configPath) == 0 {
		flag.Usage()
		return
	}

	if chdirPath != "" {
		err = os.Chdir(chdirPath)
		if err != nil {
			log.Fatal("Unable to change directory to ", chdirPath,
				": ", err)
		}
	}

	configContents, err = ioutil.ReadFile(configPath)
	if err != nil {
		log.Fatal("Unable to read ", configPath, ": ", err)
	}

	if verbose {
		log.Print("Read ", len(configContents), " bytes from config")
	}

	err = proto.Unmarshal(configContents, &configData)
	if err != nil {
		err = proto.UnmarshalText(string(configContents), &configData)
	}
	if err != nil {
		log.Fatal("Unable to parse ", configPath, ": ", err)
	}

	// Back up all members.
	out, err = os.Create("members.pb")
	if err != nil {
		log.Fatal("Error opening members.pb for writing: ", err)
	}
	writer = serialdata.NewSerialDataWriter(out)

	database, err = db.New(&configData)
	if err != nil {
		log.Fatal("Error connecting to database: ", err)
	}
	if database == nil {
		log.Fatal("database = nil")
	}

	if verbose {
		log.Print("Database connection established")
	}

	ctx = context.Background()

	go database.StreamingEnumerateMembers(ctx, "", 0, memberStream, errorStream)
	go handleErrors(errorStream)

	for member = range memberStream {
		if member == nil {
			log.Print("Received nil member")
			continue
		}
		if verbose {
			log.Print("Backing up member ", member.GetName())
		}
		err = writer.WriteMessage(member)
		if err != nil {
			log.Fatal("Error writing record to members.pb: ", err)
		}
	}

	err = out.Close()
	if err != nil {
		log.Fatal("Error closing members.pb: ", err)
	}

	// Back up all membership requests
	out, err = os.Create("membership_requests.pb")
	if err != nil {
		log.Fatal("Error opening membership_requests.pb for writing: ", err)
	}
	writer = serialdata.NewSerialDataWriter(out)

	errorStream = make(chan error)
	go database.StreamingEnumerateMembershipRequests(
		ctx, "", "", 0, memberAgreementStream, errorStream)
	go handleErrors(errorStream)

	for memberAgreement = range memberAgreementStream {
		if memberAgreement == nil {
			log.Print("Received nil membership agreement")
		}
		if verbose {
			log.Print("Backing up membership request for ",
				memberAgreement.MemberData.GetName())
		}
		err = writer.WriteMessage(memberAgreement)
		if err != nil {
			log.Fatal("Error writing record to membership_requests.pb: ", err)
		}
	}

	err = out.Close()
	if err != nil {
		log.Fatal("Error closing membership_requests.pb: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"

	"github.com/gorilla/websocket"
	sm "github.com/ifn/go-statemachine"
)

type DeskMsg struct {
	Desk [][]string `json:"desk"`
}

type PlayerMsg struct {
	Cmd  sm.EventType `json:"command"`
	Card string       `json:"card"`
}

//

var Order map[string]int = map[string]int{
	"6": 6, "7": 7, "8": 8, "9": 9, "10": 10,
	"J": 11,
	"Q": 12,
	"K": 13,
	"A": 14,
}

func higher(c0, c1, t string) int {
	// c0 and c1 have the same suit
	if c0[0] == c1[0] {
		if Order[c0[1:]] > Order[c1[1:]] {
			return 1
		}
		if Order[c0[1:]] < Order[c1[1:]] {
			return -1
		}
		return 0
	}
	// c0 is trump, c1 is not
	if c0[:1] == t {
		return 1
	}
	// c1 is trump, c0 is not
	if c1[:1] == t {
		return -1
	}
	// suits are different, both are not trump
	return -2
}

var CardRE *regexp.Regexp = regexp.MustCompile(`[SCHD]([6-9JQKA]|10)`)

func isValid(c string) bool {
	return CardRE.MatchString(c)
}

//

const (
	cmdStart sm.EventType = iota
	cmdMove

	cmdCount
)

const (
	stateCollection sm.State = iota

	stateAttack
	stateDefense

	stateCount
)

type roundResult bool

const (
	Beat roundResult = true
)

func stateToString(s sm.State) string {
	return [...]string{
		stateCollection: "COLLECTION",
		stateDefense:    "DEFENSE",
		stateAttack:     "ATTACK",
	}[s]
}

func cmdToString(t sm.EventType) string {
	return [...]string{
		cmdStart: "START",
		cmdMove:  "MOVE",
	}[t]
}

//

type cmdArgs struct {
	conn *playerConn
	card string
}

//

func logOutOfTurn(pconn *playerConn) {
	log.Printf("out of turn: %v", pconn.conn.RemoteAddr())
}

func logWontBeat(c1, c2, t string) {
	log.Printf("%v won't bit %v, trump is ", c1, c2, t)
}

//

type gameState struct {
	// 1. fields that don't change during a game

	sm  *sm.StateMachine
	hub *hub

	// trump suit
	trump string

	// 2. fields that don't change during a round

	// attacker that started a round
	aconnStart *playerConn
	// defender
	dconn *playerConn

	// 3. fields that change during a round

	// attacker
	aconn *playerConn
	// card that should be beaten
	cardToBeat string
}

func (self *gameState) nextPlayer(c *playerConn) *playerConn {
	return self.hub.conns.(*mapRing).Next(c).(*playerConn)
}

func (self *gameState) finishRound(res roundResult) {
	switch res {
	case Beat:
		self.aconn = self.dconn
	case !Beat:
		self.aconn = self.nextPlayer(self.dconn)
	}
	self.dconn = self.nextPlayer(self.aconn)

	self.aconnStart = self.aconn

	self.dealCards()
}

func (self *gameState) dealCards() {
	for pc := range self.hub.conns.Enumerate() {
		log.Println(pc)
		//give card
	}
}

// event handlers
// event handlers are actually transition functions.
// in case error event handler should neither change the gameState,
// nor return the state value different from passed to it as an argument.

func (self *gameState) handleStartInCollection(s sm.State, e *sm.Event) sm.State {
	self.dealCards()

	//init round
	//self.chooseStarting()
	//and set dconn

	return stateAttack
}

func (self *gameState) handleMoveInAttack(s sm.State, e *sm.Event) sm.State {
	conn := e.Data.(cmdArgs).conn
	card := e.Data.(cmdArgs).card

	// check that it's conn's turn to move
	if conn != self.aconn {
		logOutOfTurn(conn)
		return s
	}

	// attacker sent the card
	if card != "" {
		self.cardToBeat = card
		return stateDefense
	}

	// attacker sent no card

	aconn := self.nextPlayer(self.aconn)
	if aconn == self.dconn {
		aconn = self.nextPlayer(aconn)
	}

	// check if all attackers have been polled
	if aconn == self.aconnStart {
		self.finishRound(Beat)
		return stateAttack
	}

	self.aconn = aconn
	return stateAttack
}

func (self *gameState) handleMoveInDefense(s sm.State, e *sm.Event) sm.State {
	conn := e.Data.(cmdArgs).conn
	card := e.Data.(cmdArgs).card

	// check that it's conn's turn to move
	if conn != self.dconn {
		logOutOfTurn(conn)
		return s
	}

	// defender takes the cards
	if card == "" {
		self.finishRound(!Beat)
		return stateAttack
	}

	// check that the sent card is capable to beat
	if higher(card, self.cardToBeat, self.trump) != 1 {
		logWontBeat(card, self.cardToBeat, self.trump)
		return s
	}

	return stateAttack
}

func (self *gameState) showDesk(s sm.State, e *sm.Event) sm.State {
	desk, err := json.Marshal(DeskMsg{})
	if err != nil {
		log.Println(err)
		return s
	}

	self.hub.bcastChan <- desk

	return s
}

//

func NewGameState() *gameState {
	gst := new(gameState)

	gst.sm = sm.New(stateCollection, uint(stateCount), uint(cmdCount))

	gst.sm.On(cmdStart,
		[]sm.State{stateCollection},
		gst.handleStartInCollection,
	)

	gst.sm.On(cmdMove,
		[]sm.State{stateAttack},
		gst.handleMoveInAttack,
	)
	gst.sm.On(cmdMove,
		[]sm.State{stateDefense},
		gst.handleMoveInDefense,
	)

	gst.sm.On(cmdMove,
		[]sm.State{stateAttack, stateDefense},
		gst.showDesk,
	)

	gst.hub = NewHub()

	return gst
}

//

type playerConn struct {
	gst *gameState

	conn      *websocket.Conn
	hubToConn chan []byte
}

func (self *playerConn) write() {
	defer func() {
		err := self.conn.Close()
		if err != nil {
			log.Println(err)
		}
	}()

	for {
		select {
		case m, ok := <-self.hubToConn:
			if !ok {
				return
			}
			//TODO: text or binary?
			err := self.conn.WriteMessage(websocket.TextMessage, m)
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

func (self *playerConn) read() {
	defer func() {
		err := self.conn.Close()
		if err != nil {
			log.Println(err)
		}
	}()

	var m PlayerMsg

	for {
		err := self.conn.ReadJSON(&m)
		if err != nil {
			log.Println(err)
			return
		}

		var event *sm.Event
		switch m.Cmd {
		case cmdStart:
			event = &sm.Event{cmdStart, nil}
		case cmdMove:
			event = &sm.Event{cmdMove, cmdArgs{self, m.Card}}
		default:
			log.Printf("unknown command: %v", m.Cmd)
			continue
		}

		err = self.gst.sm.Emit(event)
		if err != nil {
			log.Println(err)
		}
	}
}

//

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func playerHandler(gst *gameState) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			log.Println(err)
			return
		}

		p := &playerConn{gst, conn, make(chan []byte)}

		gst.hub.regChan <- p
		defer func() {
			gst.hub.unregChan <- p
		}()

		go p.write()
		p.read()
	}
}

//

func startDurakSrv() error {
	gst := NewGameState()

	http.HandleFunc("/", playerHandler(gst))

	return http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func main() {
	err := startDurakSrv()
	if err != nil {
		log.Fatal(err)
	}
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<commit_msg>detached setRoles<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"

	"github.com/gorilla/websocket"
	sm "github.com/ifn/go-statemachine"
)

type DeskMsg struct {
	Desk [][]string `json:"desk"`
}

type PlayerMsg struct {
	Cmd  sm.EventType `json:"command"`
	Card string       `json:"card"`
}

//

var Order map[string]int = map[string]int{
	"6": 6, "7": 7, "8": 8, "9": 9, "10": 10,
	"J": 11,
	"Q": 12,
	"K": 13,
	"A": 14,
}

func higher(c0, c1, t string) int {
	// c0 and c1 have the same suit
	if c0[0] == c1[0] {
		if Order[c0[1:]] > Order[c1[1:]] {
			return 1
		}
		if Order[c0[1:]] < Order[c1[1:]] {
			return -1
		}
		return 0
	}
	// c0 is trump, c1 is not
	if c0[:1] == t {
		return 1
	}
	// c1 is trump, c0 is not
	if c1[:1] == t {
		return -1
	}
	// suits are different, both are not trump
	return -2
}

var CardRE *regexp.Regexp = regexp.MustCompile(`[SCHD]([6-9JQKA]|10)`)

func isValid(c string) bool {
	return CardRE.MatchString(c)
}

//

const (
	cmdStart sm.EventType = iota
	cmdMove

	cmdCount
)

const (
	stateCollection sm.State = iota

	stateAttack
	stateDefense

	stateCount
)

type roundResult int

const (
	None roundResult = iota
	Beat
	NotBeat
)

func stateToString(s sm.State) string {
	return [...]string{
		stateCollection: "COLLECTION",
		stateDefense:    "DEFENSE",
		stateAttack:     "ATTACK",
	}[s]
}

func cmdToString(t sm.EventType) string {
	return [...]string{
		cmdStart: "START",
		cmdMove:  "MOVE",
	}[t]
}

//

type cmdArgs struct {
	conn *playerConn
	card string
}

//

func logOutOfTurn(pconn *playerConn) {
	log.Printf("out of turn: %v", pconn.conn.RemoteAddr())
}

func logWontBeat(c1, c2, t string) {
	log.Printf("%v won't bit %v, trump is ", c1, c2, t)
}

//

type gameState struct {
	// 1. fields that don't change during a game

	sm  *sm.StateMachine
	hub *hub

	// trump suit
	trump string

	// 2. fields that don't change during a round

	// attacker that started a round
	aconnStart *playerConn
	// defender
	dconn *playerConn

	// 3. fields that change during a round

	// attacker
	aconn *playerConn
	// card that should be beaten
	cardToBeat string
}

func (self *gameState) nextPlayer(c *playerConn) *playerConn {
	return self.hub.conns.(*mapRing).Next(c).(*playerConn)
}

func (self *gameState) chooseStarting() *playerConn {
	return nil
}

func (self *gameState) setRoles(res roundResult) {
	switch res {
	case None:
		self.aconn = self.chooseStarting()
	case Beat:
		self.aconn = self.dconn
	case NotBeat:
		self.aconn = self.nextPlayer(self.dconn)
	}
	self.dconn = self.nextPlayer(self.aconn)
	self.aconnStart = self.aconn
}

func (self *gameState) dealCards() {
	for pc := range self.hub.conns.Enumerate() {
		log.Println(pc)
		//give card
	}
}

func (self *gameState) newRound(res roundResult) {
	self.setRoles(res)
	self.dealCards()
}

// event handlers
// event handlers are actually transition functions.
// in case error event handler should neither change the gameState,
// nor return the state value different from passed to it as an argument.

func (self *gameState) handleStartInCollection(s sm.State, e *sm.Event) sm.State {
	self.dealCards()
	self.setRoles(None)

	return stateAttack
}

func (self *gameState) handleMoveInAttack(s sm.State, e *sm.Event) sm.State {
	conn := e.Data.(cmdArgs).conn
	card := e.Data.(cmdArgs).card

	// check that it's conn's turn to move
	if conn != self.aconn {
		logOutOfTurn(conn)
		return s
	}

	// attacker sent the card
	if card != "" {
		self.cardToBeat = card
		return stateDefense
	}

	// attacker sent no card

	aconn := self.nextPlayer(self.aconn)
	if aconn == self.dconn {
		aconn = self.nextPlayer(aconn)
	}

	// check if all attackers have been polled
	if aconn == self.aconnStart {
		self.newRound(Beat)
		return stateAttack
	}

	self.aconn = aconn
	return stateAttack
}

func (self *gameState) handleMoveInDefense(s sm.State, e *sm.Event) sm.State {
	conn := e.Data.(cmdArgs).conn
	card := e.Data.(cmdArgs).card

	// check that it's conn's turn to move
	if conn != self.dconn {
		logOutOfTurn(conn)
		return s
	}

	// defender takes the cards
	if card == "" {
		self.newRound(NotBeat)
		return stateAttack
	}

	// check that the sent card is capable to beat
	if higher(card, self.cardToBeat, self.trump) != 1 {
		logWontBeat(card, self.cardToBeat, self.trump)
		return s
	}

	return stateAttack
}

func (self *gameState) showDesk(s sm.State, e *sm.Event) sm.State {
	desk, err := json.Marshal(DeskMsg{})
	if err != nil {
		log.Println(err)
		return s
	}

	self.hub.bcastChan <- desk

	return s
}

//

func NewGameState() *gameState {
	gst := new(gameState)

	gst.sm = sm.New(stateCollection, uint(stateCount), uint(cmdCount))

	gst.sm.On(cmdStart,
		[]sm.State{stateCollection},
		gst.handleStartInCollection,
	)

	gst.sm.On(cmdMove,
		[]sm.State{stateAttack},
		gst.handleMoveInAttack,
	)
	gst.sm.On(cmdMove,
		[]sm.State{stateDefense},
		gst.handleMoveInDefense,
	)

	gst.sm.On(cmdMove,
		[]sm.State{stateAttack, stateDefense},
		gst.showDesk,
	)

	gst.hub = NewHub()

	return gst
}

//

type playerConn struct {
	gst *gameState

	conn      *websocket.Conn
	hubToConn chan []byte
}

func (self *playerConn) write() {
	defer func() {
		err := self.conn.Close()
		if err != nil {
			log.Println(err)
		}
	}()

	for {
		select {
		case m, ok := <-self.hubToConn:
			if !ok {
				return
			}
			//TODO: text or binary?
			err := self.conn.WriteMessage(websocket.TextMessage, m)
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

func (self *playerConn) read() {
	defer func() {
		err := self.conn.Close()
		if err != nil {
			log.Println(err)
		}
	}()

	var m PlayerMsg

	for {
		err := self.conn.ReadJSON(&m)
		if err != nil {
			log.Println(err)
			return
		}

		var event *sm.Event
		switch m.Cmd {
		case cmdStart:
			event = &sm.Event{cmdStart, nil}
		case cmdMove:
			event = &sm.Event{cmdMove, cmdArgs{self, m.Card}}
		default:
			log.Printf("unknown command: %v", m.Cmd)
			continue
		}

		err = self.gst.sm.Emit(event)
		if err != nil {
			log.Println(err)
		}
	}
}

//

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func playerHandler(gst *gameState) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)
		if err != nil {
			log.Println(err)
			return
		}

		p := &playerConn{gst, conn, make(chan []byte)}

		gst.hub.regChan <- p
		defer func() {
			gst.hub.unregChan <- p
		}()

		go p.write()
		p.read()
	}
}

//

func startDurakSrv() error {
	gst := NewGameState()

	http.HandleFunc("/", playerHandler(gst))

	return http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func main() {
	err := startDurakSrv()
	if err != nil {
		log.Fatal(err)
	}
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<|endoftext|>


<commit_before>// Package emoji terminal output.
package emoji

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"regexp"
	"unicode"
)

//go:generate generateEmojiCodeMap -pkg emoji

// Replace Padding character for emoji.
const (
	ReplacePadding = " "
)

// CodeMap gets the underlying map of emoji.
func CodeMap() map[string]string {
	return emojiCodeMap
}

// RevCodeMap gets the underlying map of emoji.
func RevCodeMap() map[string][]string {
	return emojiRevCodeMap
}

func AliasList(shortCode string) []string {
	return emojiRevCodeMap[emojiCodeMap[shortCode]]
}

// HasAlias flags if the given `shortCode` has multiple aliases with other
// codes.
func HasAlias(shortCode string) bool {
	return len(AliasList(shortCode)) > 1
}

// NormalizeShortCode normalizes a given `shortCode` to a deterministic alias.
func NormalizeShortCode(shortCode string) string {
	shortLists := AliasList(shortCode)
	if len(shortLists) == 0 {
		return shortCode
	}
	return shortLists[0]
}

// regular expression that matches :flag-[countrycode]:
var flagRegexp = regexp.MustCompile(":flag-([a-z]{2}):")

func emojize(x string) string {
	str, ok := emojiCodeMap[x]
	if ok {
		return str + ReplacePadding
	}
	if match := flagRegexp.FindStringSubmatch(x); len(match) == 2 {
		return regionalIndicator(match[1][0]) + regionalIndicator(match[1][1])
	}
	return x
}

// regionalIndicator maps a lowercase letter to a unicode regional indicator
func regionalIndicator(i byte) string {
	return string('\U0001F1E6' + rune(i) - 'a')
}

func replaseEmoji(input *bytes.Buffer) string {
	emoji := bytes.NewBufferString(":")
	for {
		i, _, err := input.ReadRune()
		if err != nil {
			// not replase
			return emoji.String()
		}

		if i == ':' && emoji.Len() == 1 {
			return emoji.String() + replaseEmoji(input)
		}

		emoji.WriteRune(i)
		switch {
		case unicode.IsSpace(i):
			return emoji.String()
		case i == ':':
			return emojize(emoji.String())
		}
	}
}

func compile(x string) string {
	if x == "" {
		return ""
	}

	input := bytes.NewBufferString(x)
	output := bytes.NewBufferString("")

	for {
		i, _, err := input.ReadRune()
		if err != nil {
			break
		}
		switch i {
		default:
			output.WriteRune(i)
		case ':':
			output.WriteString(replaseEmoji(input))
		}
	}
	return output.String()
}

// Print is fmt.Print which supports emoji
func Print(a ...interface{}) (int, error) {
	return fmt.Print(compile(fmt.Sprint(a...)))
}

// Println is fmt.Println which supports emoji
func Println(a ...interface{}) (int, error) {
	return fmt.Println(compile(fmt.Sprint(a...)))
}

// Printf is fmt.Printf which supports emoji
func Printf(format string, a ...interface{}) (int, error) {
	return fmt.Print(compile(fmt.Sprintf(format, a...)))
}

// Fprint is fmt.Fprint which supports emoji
func Fprint(w io.Writer, a ...interface{}) (int, error) {
	return fmt.Fprint(w, compile(fmt.Sprint(a...)))
}

// Fprintln is fmt.Fprintln which supports emoji
func Fprintln(w io.Writer, a ...interface{}) (int, error) {
	return fmt.Fprintln(w, compile(fmt.Sprint(a...)))
}

// Fprintf is fmt.Fprintf which supports emoji
func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) {
	return fmt.Fprint(w, compile(fmt.Sprintf(format, a...)))
}

// Sprint is fmt.Sprint which supports emoji
func Sprint(a ...interface{}) string {
	return compile(fmt.Sprint(a...))
}

// Sprintf is fmt.Sprintf which supports emoji
func Sprintf(format string, a ...interface{}) string {
	return compile(fmt.Sprintf(format, a...))
}

// Errorf is fmt.Errorf which supports emoji
func Errorf(format string, a ...interface{}) error {
	return errors.New(compile(Sprintf(format, a...)))
}
<commit_msg>Change ReplacePadding to option (#44)<commit_after>// Package emoji terminal output.
package emoji

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"regexp"
	"unicode"
)

//go:generate generateEmojiCodeMap -pkg emoji

// Replace Padding character for emoji.
var (
	ReplacePadding = " "
)

// CodeMap gets the underlying map of emoji.
func CodeMap() map[string]string {
	return emojiCodeMap
}

// RevCodeMap gets the underlying map of emoji.
func RevCodeMap() map[string][]string {
	return emojiRevCodeMap
}

func AliasList(shortCode string) []string {
	return emojiRevCodeMap[emojiCodeMap[shortCode]]
}

// HasAlias flags if the given `shortCode` has multiple aliases with other
// codes.
func HasAlias(shortCode string) bool {
	return len(AliasList(shortCode)) > 1
}

// NormalizeShortCode normalizes a given `shortCode` to a deterministic alias.
func NormalizeShortCode(shortCode string) string {
	shortLists := AliasList(shortCode)
	if len(shortLists) == 0 {
		return shortCode
	}
	return shortLists[0]
}

// regular expression that matches :flag-[countrycode]:
var flagRegexp = regexp.MustCompile(":flag-([a-z]{2}):")

func emojize(x string) string {
	str, ok := emojiCodeMap[x]
	if ok {
		return str + ReplacePadding
	}
	if match := flagRegexp.FindStringSubmatch(x); len(match) == 2 {
		return regionalIndicator(match[1][0]) + regionalIndicator(match[1][1])
	}
	return x
}

// regionalIndicator maps a lowercase letter to a unicode regional indicator
func regionalIndicator(i byte) string {
	return string('\U0001F1E6' + rune(i) - 'a')
}

func replaseEmoji(input *bytes.Buffer) string {
	emoji := bytes.NewBufferString(":")
	for {
		i, _, err := input.ReadRune()
		if err != nil {
			// not replase
			return emoji.String()
		}

		if i == ':' && emoji.Len() == 1 {
			return emoji.String() + replaseEmoji(input)
		}

		emoji.WriteRune(i)
		switch {
		case unicode.IsSpace(i):
			return emoji.String()
		case i == ':':
			return emojize(emoji.String())
		}
	}
}

func compile(x string) string {
	if x == "" {
		return ""
	}

	input := bytes.NewBufferString(x)
	output := bytes.NewBufferString("")

	for {
		i, _, err := input.ReadRune()
		if err != nil {
			break
		}
		switch i {
		default:
			output.WriteRune(i)
		case ':':
			output.WriteString(replaseEmoji(input))
		}
	}
	return output.String()
}

// Print is fmt.Print which supports emoji
func Print(a ...interface{}) (int, error) {
	return fmt.Print(compile(fmt.Sprint(a...)))
}

// Println is fmt.Println which supports emoji
func Println(a ...interface{}) (int, error) {
	return fmt.Println(compile(fmt.Sprint(a...)))
}

// Printf is fmt.Printf which supports emoji
func Printf(format string, a ...interface{}) (int, error) {
	return fmt.Print(compile(fmt.Sprintf(format, a...)))
}

// Fprint is fmt.Fprint which supports emoji
func Fprint(w io.Writer, a ...interface{}) (int, error) {
	return fmt.Fprint(w, compile(fmt.Sprint(a...)))
}

// Fprintln is fmt.Fprintln which supports emoji
func Fprintln(w io.Writer, a ...interface{}) (int, error) {
	return fmt.Fprintln(w, compile(fmt.Sprint(a...)))
}

// Fprintf is fmt.Fprintf which supports emoji
func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) {
	return fmt.Fprint(w, compile(fmt.Sprintf(format, a...)))
}

// Sprint is fmt.Sprint which supports emoji
func Sprint(a ...interface{}) string {
	return compile(fmt.Sprint(a...))
}

// Sprintf is fmt.Sprintf which supports emoji
func Sprintf(format string, a ...interface{}) string {
	return compile(fmt.Sprintf(format, a...))
}

// Errorf is fmt.Errorf which supports emoji
func Errorf(format string, a ...interface{}) error {
	return errors.New(compile(Sprintf(format, a...)))
}
<|endoftext|>