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

package dockermachine

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/drivers/rpc"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/mcnutils"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/iaas"
)

type DockerMachine struct {
	io.Closer
	client    libmachine.API
	StorePath string
	CertsPath string
	temp      bool
}

type DockerMachineConfig struct {
	CaPath    string
	OutWriter io.Writer
	ErrWriter io.Writer
	StorePath string
	IsDebug   bool
}

type DockerMachineAPI interface {
	io.Closer
	CreateMachine(CreateMachineOpts) (*Machine, error)
	DeleteMachine(*iaas.Machine) error
	RegisterMachine(RegisterMachineOpts) (*Machine, error)
	List() ([]*Machine, error)
	DeleteAll() error
}

type CreateMachineOpts struct {
	Name                   string
	DriverName             string
	Params                 map[string]interface{}
	InsecureRegistry       string
	DockerEngineInstallURL string
	RegistryMirror         string
	ArbitraryFlags         []string
}

type RegisterMachineOpts struct {
	Base          *iaas.Machine
	DriverName    string
	SSHPrivateKey []byte
}

type Machine struct {
	Base *iaas.Machine
	Host *host.Host
}

func NewDockerMachine(config DockerMachineConfig) (DockerMachineAPI, error) {
	storePath := config.StorePath
	temp := false
	if storePath == "" {
		tempPath, err := ioutil.TempDir("", "")
		if err != nil {
			return nil, errors.Wrap(err, "failed to create temp dir")
		}
		storePath = tempPath
		temp = true
	}
	certsPath := filepath.Join(storePath, "certs")
	if _, err := os.Stat(certsPath); os.IsNotExist(err) {
		err := os.MkdirAll(certsPath, 0700)
		if err != nil {
			return nil, errors.WithMessage(err, "failed to create certs dir")
		}
	}
	if config.CaPath != "" {
		err := mcnutils.CopyFile(filepath.Join(config.CaPath, "ca.pem"), filepath.Join(certsPath, "ca.pem"))
		if err != nil {
			return nil, errors.Wrap(err, "failed to copy ca file")
		}
		err = mcnutils.CopyFile(filepath.Join(config.CaPath, "ca-key.pem"), filepath.Join(certsPath, "ca-key.pem"))
		if err != nil {
			return nil, errors.Wrap(err, "failed to copy ca key file")
		}
	}
	if config.OutWriter != nil {
		log.SetOutWriter(config.OutWriter)
	} else {
		log.SetOutWriter(ioutil.Discard)
	}
	if config.ErrWriter != nil {
		log.SetOutWriter(config.ErrWriter)
	} else {
		log.SetOutWriter(ioutil.Discard)
	}
	client := libmachine.NewClient(storePath, certsPath)
	client.IsDebug = config.IsDebug
	if _, err := os.Stat(client.GetMachinesDir()); os.IsNotExist(err) {
		err := os.MkdirAll(client.GetMachinesDir(), 0700)
		if err != nil {
			return nil, errors.WithMessage(err, "failed to create machines dir")
		}
	}
	return &DockerMachine{
		StorePath: storePath,
		CertsPath: certsPath,
		client:    client,
		temp:      temp,
	}, nil
}

func (d *DockerMachine) Close() error {
	if d.temp {
		os.RemoveAll(d.StorePath)
	}
	return d.client.Close()
}

func (d *DockerMachine) CreateMachine(opts CreateMachineOpts) (*Machine, error) {
	rawDriver, err := json.Marshal(&drivers.BaseDriver{
		MachineName: opts.Name,
		StorePath:   d.StorePath,
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal base driver")
	}
	h, err := d.client.NewHost(opts.DriverName, rawDriver)
	if err != nil {
		return nil, errors.Wrap(err, "failed to initialize host")
	}
	err = configureDriver(h.Driver, opts.Params)
	if err != nil {
		return nil, errors.WithMessage(err, "failed to configure driver")
	}
	engineOpts := h.HostOptions.EngineOptions
	if opts.InsecureRegistry != "" {
		engineOpts.InsecureRegistry = []string{opts.InsecureRegistry}
	}
	if opts.DockerEngineInstallURL != "" {
		engineOpts.InstallURL = opts.DockerEngineInstallURL
	}
	if opts.RegistryMirror != "" {
		engineOpts.RegistryMirror = []string{opts.RegistryMirror}
	}
	engineOpts.ArbitraryFlags = opts.ArbitraryFlags
	if h.AuthOptions() != nil {
		h.AuthOptions().StorePath = d.StorePath
	}
	errCreate := d.client.Create(h)
	machine, err := newMachine(h)
	if errCreate != nil {
		return machine, errors.Wrap(errCreate, "failed to create host")
	}
	return machine, errors.Wrap(err, "failed to create machine")
}

func (d *DockerMachine) DeleteMachine(m *iaas.Machine) error {
	rawDriver, err := json.Marshal(m.CustomData)
	if err != nil {
		return errors.Wrap(err, "failed to marshal machine data")
	}
	host, err := d.client.NewHost(m.CreationParams["driver"], rawDriver)
	if err != nil {
		return errors.Wrap(err, "failed to initialize host")
	}
	err = host.Driver.Remove()
	if err != nil {
		return errors.Wrap(err, "failed to remove host")
	}
	return d.client.Remove(m.Id)
}

func (d *DockerMachine) DeleteAll() error {
	hosts, err := d.client.List()
	if err != nil {
		return err
	}
	for _, n := range hosts {
		h, errLoad := d.client.Load(n)
		if errLoad != nil {
			return errLoad
		}
		err = h.Driver.Remove()
		if err != nil {
			return err
		}
	}
	return os.RemoveAll(d.StorePath)
}

// RegisterMachine registers an iaas.Machine as an Machine and a host on
// the current running DockerMachine. It expects all data needed to Marshal
// the host/driver to be available on CustomData.
func (d *DockerMachine) RegisterMachine(opts RegisterMachineOpts) (*Machine, error) {
	if !d.temp {
		return nil, errors.New("register is only available without user defined StorePath")
	}
	if opts.Base.CustomData == nil {
		return nil, errors.New("custom data is required")
	}
	opts.Base.CustomData["SSHKeyPath"] = filepath.Join(d.client.GetMachinesDir(), opts.Base.Id, "id_rsa")
	rawDriver, err := json.Marshal(opts.Base.CustomData)
	if err != nil {
		return nil, errors.WithMessage(err, "failed to marshal driver data")
	}
	h, err := d.client.NewHost(opts.DriverName, rawDriver)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.Driver.GetSSHKeyPath(), opts.SSHPrivateKey, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().CaCertPath, opts.Base.CaCert, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().ClientCertPath, opts.Base.ClientCert, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().ClientKeyPath, opts.Base.ClientKey, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = d.client.Save(h)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	savedHost, err := d.client.Load(h.Name)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return &Machine{
		Base: opts.Base,
		Host: savedHost,
	}, nil
}

func (d *DockerMachine) List() ([]*Machine, error) {
	names, err := d.client.List()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	var machines []*Machine
	for _, n := range names {
		h, err := d.client.Load(n)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		m, err := newMachine(h)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		machines = append(machines, m)
	}
	return machines, nil
}

func newMachine(h *host.Host) (*Machine, error) {
	rawDriver, err := json.Marshal(h.Driver)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal host driver")
	}
	var driverData map[string]interface{}
	err = json.Unmarshal(rawDriver, &driverData)
	if err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal host driver")
	}
	m := &Machine{
		Base: &iaas.Machine{
			Id:         h.Name,
			Port:       engine.DefaultPort,
			Protocol:   "https",
			CustomData: driverData,
			CreationParams: map[string]string{
				"driver": h.DriverName,
			},
		},
		Host: h,
	}
	address, err := h.Driver.GetIP()
	if err != nil {
		return m, errors.Wrap(err, "failed to retrive host ip")
	}
	m.Base.Address = address
	if h.AuthOptions() != nil {
		m.Base.CaCert, err = ioutil.ReadFile(h.AuthOptions().CaCertPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host ca cert")
		}
		m.Base.ClientCert, err = ioutil.ReadFile(h.AuthOptions().ClientCertPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host client cert")
		}
		m.Base.ClientKey, err = ioutil.ReadFile(h.AuthOptions().ClientKeyPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host client key")
		}
	}
	return m, nil
}

func configureDriver(driver drivers.Driver, driverOpts map[string]interface{}) error {
	opts := &rpcdriver.RPCFlags{Values: driverOpts}
	for _, c := range driver.GetCreateFlags() {
		val, ok := opts.Values[c.String()]
		if !ok {
			opts.Values[c.String()] = c.Default()
			if c.Default() == nil {
				opts.Values[c.String()] = false
			}
		} else {
			if strVal, ok := val.(string); ok {
				switch c.(type) {
				case *mcnflag.StringSliceFlag, mcnflag.StringSliceFlag:
					opts.Values[c.String()] = strings.Split(strVal, ",")
				case *mcnflag.IntFlag, mcnflag.IntFlag:
					v, err := strconv.Atoi(strVal)
					if err != nil {
						return errors.Wrapf(err, "failed to set %s flag: %s is not an int", c.String(), strVal)
					}
					opts.Values[c.String()] = v
				case *mcnflag.BoolFlag, mcnflag.BoolFlag:
					v, err := strconv.ParseBool(strVal)
					if err != nil {
						return errors.Wrapf(err, "failed to set %s flag: %s is not a bool", c.String(), strVal)
					}
					opts.Values[c.String()] = v
				}
			}
		}
	}
	err := driver.SetConfigFromFlags(opts)
	return errors.Wrap(err, "failed to set driver configuration")
}
<commit_msg>iaas/dockermacine: set debug log<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dockermachine

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/drivers/rpc"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/mcnutils"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/iaas"
)

type DockerMachine struct {
	io.Closer
	client    libmachine.API
	StorePath string
	CertsPath string
	temp      bool
}

type DockerMachineConfig struct {
	CaPath    string
	OutWriter io.Writer
	ErrWriter io.Writer
	StorePath string
	IsDebug   bool
}

type DockerMachineAPI interface {
	io.Closer
	CreateMachine(CreateMachineOpts) (*Machine, error)
	DeleteMachine(*iaas.Machine) error
	RegisterMachine(RegisterMachineOpts) (*Machine, error)
	List() ([]*Machine, error)
	DeleteAll() error
}

type CreateMachineOpts struct {
	Name                   string
	DriverName             string
	Params                 map[string]interface{}
	InsecureRegistry       string
	DockerEngineInstallURL string
	RegistryMirror         string
	ArbitraryFlags         []string
}

type RegisterMachineOpts struct {
	Base          *iaas.Machine
	DriverName    string
	SSHPrivateKey []byte
}

type Machine struct {
	Base *iaas.Machine
	Host *host.Host
}

func NewDockerMachine(config DockerMachineConfig) (DockerMachineAPI, error) {
	storePath := config.StorePath
	temp := false
	if storePath == "" {
		tempPath, err := ioutil.TempDir("", "")
		if err != nil {
			return nil, errors.Wrap(err, "failed to create temp dir")
		}
		storePath = tempPath
		temp = true
	}
	certsPath := filepath.Join(storePath, "certs")
	if _, err := os.Stat(certsPath); os.IsNotExist(err) {
		err := os.MkdirAll(certsPath, 0700)
		if err != nil {
			return nil, errors.WithMessage(err, "failed to create certs dir")
		}
	}
	if config.CaPath != "" {
		err := mcnutils.CopyFile(filepath.Join(config.CaPath, "ca.pem"), filepath.Join(certsPath, "ca.pem"))
		if err != nil {
			return nil, errors.Wrap(err, "failed to copy ca file")
		}
		err = mcnutils.CopyFile(filepath.Join(config.CaPath, "ca-key.pem"), filepath.Join(certsPath, "ca-key.pem"))
		if err != nil {
			return nil, errors.Wrap(err, "failed to copy ca key file")
		}
	}
	if config.OutWriter != nil {
		log.SetOutWriter(config.OutWriter)
	} else {
		log.SetOutWriter(ioutil.Discard)
	}
	if config.ErrWriter != nil {
		log.SetOutWriter(config.ErrWriter)
	} else {
		log.SetOutWriter(ioutil.Discard)
	}
	log.SetDebug(config.IsDebug)
	client := libmachine.NewClient(storePath, certsPath)
	client.IsDebug = config.IsDebug
	if _, err := os.Stat(client.GetMachinesDir()); os.IsNotExist(err) {
		err := os.MkdirAll(client.GetMachinesDir(), 0700)
		if err != nil {
			return nil, errors.WithMessage(err, "failed to create machines dir")
		}
	}
	return &DockerMachine{
		StorePath: storePath,
		CertsPath: certsPath,
		client:    client,
		temp:      temp,
	}, nil
}

func (d *DockerMachine) Close() error {
	if d.temp {
		os.RemoveAll(d.StorePath)
	}
	return d.client.Close()
}

func (d *DockerMachine) CreateMachine(opts CreateMachineOpts) (*Machine, error) {
	rawDriver, err := json.Marshal(&drivers.BaseDriver{
		MachineName: opts.Name,
		StorePath:   d.StorePath,
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal base driver")
	}
	h, err := d.client.NewHost(opts.DriverName, rawDriver)
	if err != nil {
		return nil, errors.Wrap(err, "failed to initialize host")
	}
	err = configureDriver(h.Driver, opts.Params)
	if err != nil {
		return nil, errors.WithMessage(err, "failed to configure driver")
	}
	engineOpts := h.HostOptions.EngineOptions
	if opts.InsecureRegistry != "" {
		engineOpts.InsecureRegistry = []string{opts.InsecureRegistry}
	}
	if opts.DockerEngineInstallURL != "" {
		engineOpts.InstallURL = opts.DockerEngineInstallURL
	}
	if opts.RegistryMirror != "" {
		engineOpts.RegistryMirror = []string{opts.RegistryMirror}
	}
	engineOpts.ArbitraryFlags = opts.ArbitraryFlags
	if h.AuthOptions() != nil {
		h.AuthOptions().StorePath = d.StorePath
	}
	errCreate := d.client.Create(h)
	machine, err := newMachine(h)
	if errCreate != nil {
		return machine, errors.Wrap(errCreate, "failed to create host")
	}
	return machine, errors.Wrap(err, "failed to create machine")
}

func (d *DockerMachine) DeleteMachine(m *iaas.Machine) error {
	rawDriver, err := json.Marshal(m.CustomData)
	if err != nil {
		return errors.Wrap(err, "failed to marshal machine data")
	}
	host, err := d.client.NewHost(m.CreationParams["driver"], rawDriver)
	if err != nil {
		return errors.Wrap(err, "failed to initialize host")
	}
	err = host.Driver.Remove()
	if err != nil {
		return errors.Wrap(err, "failed to remove host")
	}
	return d.client.Remove(m.Id)
}

func (d *DockerMachine) DeleteAll() error {
	hosts, err := d.client.List()
	if err != nil {
		return err
	}
	for _, n := range hosts {
		h, errLoad := d.client.Load(n)
		if errLoad != nil {
			return errLoad
		}
		err = h.Driver.Remove()
		if err != nil {
			return err
		}
	}
	return os.RemoveAll(d.StorePath)
}

// RegisterMachine registers an iaas.Machine as an Machine and a host on
// the current running DockerMachine. It expects all data needed to Marshal
// the host/driver to be available on CustomData.
func (d *DockerMachine) RegisterMachine(opts RegisterMachineOpts) (*Machine, error) {
	if !d.temp {
		return nil, errors.New("register is only available without user defined StorePath")
	}
	if opts.Base.CustomData == nil {
		return nil, errors.New("custom data is required")
	}
	opts.Base.CustomData["SSHKeyPath"] = filepath.Join(d.client.GetMachinesDir(), opts.Base.Id, "id_rsa")
	rawDriver, err := json.Marshal(opts.Base.CustomData)
	if err != nil {
		return nil, errors.WithMessage(err, "failed to marshal driver data")
	}
	h, err := d.client.NewHost(opts.DriverName, rawDriver)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.Driver.GetSSHKeyPath(), opts.SSHPrivateKey, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().CaCertPath, opts.Base.CaCert, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().ClientCertPath, opts.Base.ClientCert, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = ioutil.WriteFile(h.AuthOptions().ClientKeyPath, opts.Base.ClientKey, 0700)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	err = d.client.Save(h)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	savedHost, err := d.client.Load(h.Name)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return &Machine{
		Base: opts.Base,
		Host: savedHost,
	}, nil
}

func (d *DockerMachine) List() ([]*Machine, error) {
	names, err := d.client.List()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	var machines []*Machine
	for _, n := range names {
		h, err := d.client.Load(n)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		m, err := newMachine(h)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		machines = append(machines, m)
	}
	return machines, nil
}

func newMachine(h *host.Host) (*Machine, error) {
	rawDriver, err := json.Marshal(h.Driver)
	if err != nil {
		return nil, errors.Wrap(err, "failed to marshal host driver")
	}
	var driverData map[string]interface{}
	err = json.Unmarshal(rawDriver, &driverData)
	if err != nil {
		return nil, errors.Wrap(err, "failed to unmarshal host driver")
	}
	m := &Machine{
		Base: &iaas.Machine{
			Id:         h.Name,
			Port:       engine.DefaultPort,
			Protocol:   "https",
			CustomData: driverData,
			CreationParams: map[string]string{
				"driver": h.DriverName,
			},
		},
		Host: h,
	}
	address, err := h.Driver.GetIP()
	if err != nil {
		return m, errors.Wrap(err, "failed to retrive host ip")
	}
	m.Base.Address = address
	if h.AuthOptions() != nil {
		m.Base.CaCert, err = ioutil.ReadFile(h.AuthOptions().CaCertPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host ca cert")
		}
		m.Base.ClientCert, err = ioutil.ReadFile(h.AuthOptions().ClientCertPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host client cert")
		}
		m.Base.ClientKey, err = ioutil.ReadFile(h.AuthOptions().ClientKeyPath)
		if err != nil {
			return m, errors.Wrap(err, "failed to read host client key")
		}
	}
	return m, nil
}

func configureDriver(driver drivers.Driver, driverOpts map[string]interface{}) error {
	opts := &rpcdriver.RPCFlags{Values: driverOpts}
	for _, c := range driver.GetCreateFlags() {
		val, ok := opts.Values[c.String()]
		if !ok {
			opts.Values[c.String()] = c.Default()
			if c.Default() == nil {
				opts.Values[c.String()] = false
			}
		} else {
			if strVal, ok := val.(string); ok {
				switch c.(type) {
				case *mcnflag.StringSliceFlag, mcnflag.StringSliceFlag:
					opts.Values[c.String()] = strings.Split(strVal, ",")
				case *mcnflag.IntFlag, mcnflag.IntFlag:
					v, err := strconv.Atoi(strVal)
					if err != nil {
						return errors.Wrapf(err, "failed to set %s flag: %s is not an int", c.String(), strVal)
					}
					opts.Values[c.String()] = v
				case *mcnflag.BoolFlag, mcnflag.BoolFlag:
					v, err := strconv.ParseBool(strVal)
					if err != nil {
						return errors.Wrapf(err, "failed to set %s flag: %s is not a bool", c.String(), strVal)
					}
					opts.Values[c.String()] = v
				}
			}
		}
	}
	err := driver.SetConfigFromFlags(opts)
	return errors.Wrap(err, "failed to set driver configuration")
}
<|endoftext|>


<commit_before>//+build windows

package dbus

const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"

func getSystemBusPlatformAddress() string {
	address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
	if address != "" {
		return address
	}
	return defaultSystemBusAddress
}<commit_msg>Import "os" in conn_windows.go<commit_after>//+build windows

package dbus

import "os"

const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"

func getSystemBusPlatformAddress() string {
	address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
	if address != "" {
		return address
	}
	return defaultSystemBusAddress
}
<|endoftext|>


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

package app

/*
#cgo android LDFLAGS: -llog -landroid -lEGL -lGLESv2
#include <android/log.h>
#include <android/native_activity.h>
#include <android/input.h>
#include <EGL/egl.h>
#include <GLES/gl.h>

// TODO(crawshaw): Test configuration on more devices.
const EGLint RGB_888[] = {
	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
	EGL_BLUE_SIZE, 8,
	EGL_GREEN_SIZE, 8,
	EGL_RED_SIZE, 8,
	EGL_DEPTH_SIZE, 16,
	EGL_CONFIG_CAVEAT, EGL_NONE,
	EGL_NONE
};

EGLint windowWidth;
EGLint windowHeight;
EGLDisplay display;
EGLSurface surface;

#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, "Go", __VA_ARGS__)

void createEGLWindow(ANativeWindow* window) {
	EGLint numConfigs, format;
	EGLConfig config;
	EGLContext context;

	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	if (!eglInitialize(display, 0, 0)) {
		LOG_ERROR("EGL initialize failed");
		return;
	}

	if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
		LOG_ERROR("EGL choose RGB_888 config failed");
		return;
	}
	if (numConfigs <= 0) {
		LOG_ERROR("EGL no config found");
		return;
	}

	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
	if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
		LOG_ERROR("EGL set buffers geometry failed");
		return;
	}

	surface = eglCreateWindowSurface(display, config, window, NULL);
	if (surface == EGL_NO_SURFACE) {
		LOG_ERROR("EGL create surface failed");
		return;
	}

	const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);

	if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
		LOG_ERROR("eglMakeCurrent failed");
		return;
	}

	eglQuerySurface(display, surface, EGL_WIDTH, &windowWidth);
	eglQuerySurface(display, surface, EGL_HEIGHT, &windowHeight);
}

#undef LOG_ERROR
*/
import "C"
import (
	"log"

	"golang.org/x/mobile/event"
	"golang.org/x/mobile/geom"
	"golang.org/x/mobile/gl"
)

func windowDrawLoop(cb Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
	C.createEGLWindow(w)

	gl.Enable(gl.CULL_FACE)
	// TODO: is the library or the app responsible for clearing the buffers?
	gl.ClearColor(0, 0, 0, 1)
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	C.eglSwapBuffers(C.display, C.surface)

	if errv := gl.GetError(); errv != gl.NO_ERROR {
		log.Printf("GL initialization error: %s", errv)
	}

	geom.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
	geom.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)

	for {
		processEvents(cb, queue)
		select {
		case <-windowDestroyed:
			return
		default:
			if cb.Draw != nil {
				cb.Draw()
			}
			C.eglSwapBuffers(C.display, C.surface)
		}
	}
}

func processEvents(cb Callbacks, queue *C.AInputQueue) {
	var event *C.AInputEvent
	for C.AInputQueue_getEvent(queue, &event) >= 0 {
		if C.AInputQueue_preDispatchEvent(queue, event) != 0 {
			continue
		}
		processEvent(cb, event)
		C.AInputQueue_finishEvent(queue, event, 0)
	}
}

func processEvent(cb Callbacks, e *C.AInputEvent) {
	switch C.AInputEvent_getType(e) {
	case C.AINPUT_EVENT_TYPE_KEY:
		log.Printf("TODO input event: key")
	case C.AINPUT_EVENT_TYPE_MOTION:
		if cb.Touch == nil {
			return
		}
		x := C.AMotionEvent_getX(e, 0)
		y := C.AMotionEvent_getY(e, 0)

		var ty event.TouchType
		switch C.AMotionEvent_getAction(e) {
		case C.AMOTION_EVENT_ACTION_DOWN:
			ty = event.TouchStart
		case C.AMOTION_EVENT_ACTION_MOVE:
			ty = event.TouchMove
		case C.AMOTION_EVENT_ACTION_UP:
			ty = event.TouchEnd
		}
		cb.Touch(event.Touch{
			Type: ty,
			Loc: geom.Point{
				X: geom.Pt(float32(x) / geom.PixelsPerPt),
				Y: geom.Pt(float32(y) / geom.PixelsPerPt),
			},
		})
	default:
		log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
	}
}
<commit_msg>x/mobile/app: remove gl.CULL_FACE<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package app

/*
#cgo android LDFLAGS: -llog -landroid -lEGL -lGLESv2
#include <android/log.h>
#include <android/native_activity.h>
#include <android/input.h>
#include <EGL/egl.h>
#include <GLES/gl.h>

// TODO(crawshaw): Test configuration on more devices.
const EGLint RGB_888[] = {
	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
	EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
	EGL_BLUE_SIZE, 8,
	EGL_GREEN_SIZE, 8,
	EGL_RED_SIZE, 8,
	EGL_DEPTH_SIZE, 16,
	EGL_CONFIG_CAVEAT, EGL_NONE,
	EGL_NONE
};

EGLint windowWidth;
EGLint windowHeight;
EGLDisplay display;
EGLSurface surface;

#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, "Go", __VA_ARGS__)

void createEGLWindow(ANativeWindow* window) {
	EGLint numConfigs, format;
	EGLConfig config;
	EGLContext context;

	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	if (!eglInitialize(display, 0, 0)) {
		LOG_ERROR("EGL initialize failed");
		return;
	}

	if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
		LOG_ERROR("EGL choose RGB_888 config failed");
		return;
	}
	if (numConfigs <= 0) {
		LOG_ERROR("EGL no config found");
		return;
	}

	eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
	if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
		LOG_ERROR("EGL set buffers geometry failed");
		return;
	}

	surface = eglCreateWindowSurface(display, config, window, NULL);
	if (surface == EGL_NO_SURFACE) {
		LOG_ERROR("EGL create surface failed");
		return;
	}

	const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);

	if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
		LOG_ERROR("eglMakeCurrent failed");
		return;
	}

	eglQuerySurface(display, surface, EGL_WIDTH, &windowWidth);
	eglQuerySurface(display, surface, EGL_HEIGHT, &windowHeight);
}

#undef LOG_ERROR
*/
import "C"
import (
	"log"

	"golang.org/x/mobile/event"
	"golang.org/x/mobile/geom"
	"golang.org/x/mobile/gl"
)

func windowDrawLoop(cb Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
	C.createEGLWindow(w)

	// TODO: is the library or the app responsible for clearing the buffers?
	gl.ClearColor(0, 0, 0, 1)
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	C.eglSwapBuffers(C.display, C.surface)

	if errv := gl.GetError(); errv != gl.NO_ERROR {
		log.Printf("GL initialization error: %s", errv)
	}

	geom.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
	geom.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)

	for {
		processEvents(cb, queue)
		select {
		case <-windowDestroyed:
			return
		default:
			if cb.Draw != nil {
				cb.Draw()
			}
			C.eglSwapBuffers(C.display, C.surface)
		}
	}
}

func processEvents(cb Callbacks, queue *C.AInputQueue) {
	var event *C.AInputEvent
	for C.AInputQueue_getEvent(queue, &event) >= 0 {
		if C.AInputQueue_preDispatchEvent(queue, event) != 0 {
			continue
		}
		processEvent(cb, event)
		C.AInputQueue_finishEvent(queue, event, 0)
	}
}

func processEvent(cb Callbacks, e *C.AInputEvent) {
	switch C.AInputEvent_getType(e) {
	case C.AINPUT_EVENT_TYPE_KEY:
		log.Printf("TODO input event: key")
	case C.AINPUT_EVENT_TYPE_MOTION:
		if cb.Touch == nil {
			return
		}
		x := C.AMotionEvent_getX(e, 0)
		y := C.AMotionEvent_getY(e, 0)

		var ty event.TouchType
		switch C.AMotionEvent_getAction(e) {
		case C.AMOTION_EVENT_ACTION_DOWN:
			ty = event.TouchStart
		case C.AMOTION_EVENT_ACTION_MOVE:
			ty = event.TouchMove
		case C.AMOTION_EVENT_ACTION_UP:
			ty = event.TouchEnd
		}
		cb.Touch(event.Touch{
			Type: ty,
			Loc: geom.Point{
				X: geom.Pt(float32(x) / geom.PixelsPerPt),
				Y: geom.Pt(float32(y) / geom.PixelsPerPt),
			},
		})
	default:
		log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
	}
}
<|endoftext|>


<commit_before>// Package mpd implements parsing and generating of MPEG-DASH Media Presentation Description (MPD) files.
package mpd

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"regexp"
	"strconv"
)

// http://mpeg.chiariglione.org/standards/mpeg-dash
// https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
// http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd

var emptyElementRE = regexp.MustCompile(`></[A-Za-z]+>`)

// ConditionalUint (ConditionalUintType) defined in XSD as a union of unsignedInt and boolean.
type ConditionalUint struct {
	u *uint64
	b *bool
}

// MarshalXMLAttr encodes ConditionalUint.
func (c ConditionalUint) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	if c.u != nil {
		return xml.Attr{Name: name, Value: strconv.FormatUint(*c.u, 10)}, nil
	}

	if c.b != nil {
		return xml.Attr{Name: name, Value: strconv.FormatBool(*c.b)}, nil
	}

	// both are nil - no attribute, client will threat it like "false"
	return xml.Attr{}, nil
}

// UnmarshalXMLAttr decodes ConditionalUint.
func (c *ConditionalUint) UnmarshalXMLAttr(attr xml.Attr) error {
	u, err := strconv.ParseUint(attr.Value, 10, 64)
	if err == nil {
		c.u = &u
		return nil
	}

	b, err := strconv.ParseBool(attr.Value)
	if err == nil {
		c.b = &b
		return nil
	}

	return fmt.Errorf("ConditionalUint: can't UnmarshalXMLAttr %#v", attr)
}

// check interfaces
var (
	_ xml.MarshalerAttr   = ConditionalUint{}
	_ xml.UnmarshalerAttr = &ConditionalUint{}
)

// MPD represents root XML element.
type MPD struct {
	XMLNS                      *string `xml:"xmlns,attr"`
	Type                       *string `xml:"type,attr"`
	MinimumUpdatePeriod        *string `xml:"minimumUpdatePeriod,attr"`
	AvailabilityStartTime      *string `xml:"availabilityStartTime,attr"`
	MediaPresentationDuration  *string `xml:"mediaPresentationDuration,attr"`
	MinBufferTime              *string `xml:"minBufferTime,attr"`
	SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"`
	TimeShiftBufferDepth       *string `xml:"timeShiftBufferDepth,attr"`
	PublishTime                *string `xml:"publishTime,attr"`
	Profiles                   string  `xml:"profiles,attr"`
	Period                     *Period `xml:"Period,omitempty"`
}

// Do not try to use encoding.TextMarshaler and encoding.TextUnmarshaler:
// https://github.com/golang/go/issues/6859#issuecomment-118890463

// Encode generates MPD XML.
func (m *MPD) Encode() ([]byte, error) {
	x := new(bytes.Buffer)
	e := xml.NewEncoder(x)
	e.Indent("", "  ")
	err := e.Encode(m)
	if err != nil {
		return nil, err
	}

	// hacks for self-closing tags
	res := new(bytes.Buffer)
	res.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
	res.WriteByte('\n')
	for {
		s, err := x.ReadString('\n')
		if s != "" {
			s = emptyElementRE.ReplaceAllString(s, `/>`)
			res.WriteString(s)
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
	}
	res.WriteByte('\n')
	return res.Bytes(), err
}

// Decode parses MPD XML.
func (m *MPD) Decode(b []byte) error {
	return xml.Unmarshal(b, m)
}

// Period represents XSD's PeriodType.
type Period struct {
	Start          *string          `xml:"start,attr"`
	ID             *string          `xml:"id,attr"`
	Duration       *string          `xml:"duration,attr"`
	AdaptationSets []*AdaptationSet `xml:"AdaptationSet,omitempty"`
}

// AdaptationSet represents XSD's AdaptationSetType.
type AdaptationSet struct {
	MimeType                string           `xml:"mimeType,attr"`
	SegmentAlignment        ConditionalUint  `xml:"segmentAlignment,attr"`
	SubsegmentAlignment     ConditionalUint  `xml:"subsegmentAlignment,attr"`
	StartWithSAP            *uint64          `xml:"startWithSAP,attr"`
	SubsegmentStartsWithSAP *uint64          `xml:"subsegmentStartsWithSAP,attr"`
	BitstreamSwitching      *bool            `xml:"bitstreamSwitching,attr"`
	Lang                    *string          `xml:"lang,attr"`
	ContentProtections      []Descriptor     `xml:"ContentProtection,omitempty"`
	Representations         []Representation `xml:"Representation,omitempty"`
	Codecs                  *string          `xml:"codecs,attr"`
}

// Representation represents XSD's RepresentationType.
type Representation struct {
	ID                 *string          `xml:"id,attr"`
	Width              *uint64          `xml:"width,attr"`
	Height             *uint64          `xml:"height,attr"`
	FrameRate          *string          `xml:"frameRate,attr"`
	Bandwidth          *uint64          `xml:"bandwidth,attr"`
	AudioSamplingRate  *string          `xml:"audioSamplingRate,attr"`
	Codecs             *string          `xml:"codecs,attr"`
	ContentProtections []Descriptor     `xml:"ContentProtection,omitempty"`
	SegmentTemplate    *SegmentTemplate `xml:"SegmentTemplate,omitempty"`
}

// Descriptor represents XSD's DescriptorType.
type Descriptor struct {
	SchemeIDURI *string `xml:"schemeIdUri,attr"`
	Value       *string `xml:"value,attr"`
}

// SegmentTemplate represents XSD's SegmentTemplateType.
type SegmentTemplate struct {
	Timescale              *uint64            `xml:"timescale,attr"`
	Media                  *string            `xml:"media,attr"`
	Initialization         *string            `xml:"initialization,attr"`
	StartNumber            *uint64            `xml:"startNumber,attr"`
	PresentationTimeOffset *uint64            `xml:"presentationTimeOffset,attr"`
	SegmentTimelineS       []SegmentTimelineS `xml:"SegmentTimeline>S,omitempty"`
}

// SegmentTimelineS represents XSD's SegmentTimelineType's inner S elements.
type SegmentTimelineS struct {
	T *uint64 `xml:"t,attr"`
	D uint64  `xml:"d,attr"`
	R *int64  `xml:"r,attr"`
}
<commit_msg>add CencPssh struct<commit_after>// Package mpd implements parsing and generating of MPEG-DASH Media Presentation Description (MPD) files.
package mpd

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"regexp"
	"strconv"
)

// http://mpeg.chiariglione.org/standards/mpeg-dash
// https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
// http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd

var emptyElementRE = regexp.MustCompile(`></[A-Za-z]+>`)

// ConditionalUint (ConditionalUintType) defined in XSD as a union of unsignedInt and boolean.
type ConditionalUint struct {
	u *uint64
	b *bool
}

// MarshalXMLAttr encodes ConditionalUint.
func (c ConditionalUint) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	if c.u != nil {
		return xml.Attr{Name: name, Value: strconv.FormatUint(*c.u, 10)}, nil
	}

	if c.b != nil {
		return xml.Attr{Name: name, Value: strconv.FormatBool(*c.b)}, nil
	}

	// both are nil - no attribute, client will threat it like "false"
	return xml.Attr{}, nil
}

// UnmarshalXMLAttr decodes ConditionalUint.
func (c *ConditionalUint) UnmarshalXMLAttr(attr xml.Attr) error {
	u, err := strconv.ParseUint(attr.Value, 10, 64)
	if err == nil {
		c.u = &u
		return nil
	}

	b, err := strconv.ParseBool(attr.Value)
	if err == nil {
		c.b = &b
		return nil
	}

	return fmt.Errorf("ConditionalUint: can't UnmarshalXMLAttr %#v", attr)
}

// check interfaces
var (
	_ xml.MarshalerAttr   = ConditionalUint{}
	_ xml.UnmarshalerAttr = &ConditionalUint{}
)

// MPD represents root XML element.
type MPD struct {
	XMLNS                      *string `xml:"xmlns,attr"`
	Type                       *string `xml:"type,attr"`
	MinimumUpdatePeriod        *string `xml:"minimumUpdatePeriod,attr"`
	AvailabilityStartTime      *string `xml:"availabilityStartTime,attr"`
	MediaPresentationDuration  *string `xml:"mediaPresentationDuration,attr"`
	MinBufferTime              *string `xml:"minBufferTime,attr"`
	SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"`
	TimeShiftBufferDepth       *string `xml:"timeShiftBufferDepth,attr"`
	PublishTime                *string `xml:"publishTime,attr"`
	Profiles                   string  `xml:"profiles,attr"`
	Period                     *Period `xml:"Period,omitempty"`
}

// Do not try to use encoding.TextMarshaler and encoding.TextUnmarshaler:
// https://github.com/golang/go/issues/6859#issuecomment-118890463

// Encode generates MPD XML.
func (m *MPD) Encode() ([]byte, error) {
	x := new(bytes.Buffer)
	e := xml.NewEncoder(x)
	e.Indent("", "  ")
	err := e.Encode(m)
	if err != nil {
		return nil, err
	}

	// hacks for self-closing tags
	res := new(bytes.Buffer)
	res.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
	res.WriteByte('\n')
	for {
		s, err := x.ReadString('\n')
		if s != "" {
			s = emptyElementRE.ReplaceAllString(s, `/>`)
			res.WriteString(s)
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
	}
	res.WriteByte('\n')
	return res.Bytes(), err
}

// Decode parses MPD XML.
func (m *MPD) Decode(b []byte) error {
	return xml.Unmarshal(b, m)
}

// Period represents XSD's PeriodType.
type Period struct {
	Start          *string          `xml:"start,attr"`
	ID             *string          `xml:"id,attr"`
	Duration       *string          `xml:"duration,attr"`
	AdaptationSets []*AdaptationSet `xml:"AdaptationSet,omitempty"`
}

// AdaptationSet represents XSD's AdaptationSetType.
type AdaptationSet struct {
	MimeType                string           `xml:"mimeType,attr"`
	SegmentAlignment        ConditionalUint  `xml:"segmentAlignment,attr"`
	SubsegmentAlignment     ConditionalUint  `xml:"subsegmentAlignment,attr"`
	StartWithSAP            *uint64          `xml:"startWithSAP,attr"`
	SubsegmentStartsWithSAP *uint64          `xml:"subsegmentStartsWithSAP,attr"`
	BitstreamSwitching      *bool            `xml:"bitstreamSwitching,attr"`
	Lang                    *string          `xml:"lang,attr"`
	ContentProtections      []Descriptor     `xml:"ContentProtection,omitempty"`
	Representations         []Representation `xml:"Representation,omitempty"`
	Codecs                  *string          `xml:"codecs,attr"`
}

// Representation represents XSD's RepresentationType.
type Representation struct {
	ID                 *string          `xml:"id,attr"`
	Width              *uint64          `xml:"width,attr"`
	Height             *uint64          `xml:"height,attr"`
	FrameRate          *string          `xml:"frameRate,attr"`
	Bandwidth          *uint64          `xml:"bandwidth,attr"`
	AudioSamplingRate  *string          `xml:"audioSamplingRate,attr"`
	Codecs             *string          `xml:"codecs,attr"`
	ContentProtections []Descriptor     `xml:"ContentProtection,omitempty"`
	SegmentTemplate    *SegmentTemplate `xml:"SegmentTemplate,omitempty"`
}

// Descriptor represents XSD's DescriptorType.
type Descriptor struct {
	SchemeIDURI *string `xml:"schemeIdUri,attr"`
	Value       *string `xml:"value,attr"`
	CencPssh    *CencPssh
}

// CencPssh represents XSD's CencPsshType .
type CencPssh struct {
	XmlnsCenc *string `xml:"xmlns:cenc=,attr"`
	Value     *string `xml:cenc:pssh,omitempty`
}

// SegmentTemplate represents XSD's SegmentTemplateType.
type SegmentTemplate struct {
	Timescale              *uint64            `xml:"timescale,attr"`
	Media                  *string            `xml:"media,attr"`
	Initialization         *string            `xml:"initialization,attr"`
	StartNumber            *uint64            `xml:"startNumber,attr"`
	PresentationTimeOffset *uint64            `xml:"presentationTimeOffset,attr"`
	SegmentTimelineS       []SegmentTimelineS `xml:"SegmentTimeline>S,omitempty"`
}

// SegmentTimelineS represents XSD's SegmentTimelineType's inner S elements.
type SegmentTimelineS struct {
	T *uint64 `xml:"t,attr"`
	D uint64  `xml:"d,attr"`
	R *int64  `xml:"r,attr"`
}
<|endoftext|>


<commit_before>// This file is part of fs1up.
// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL-2

// Package nbd uses the Linux NBD layer to emulate a block device in user space
package nbd

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"runtime"
	"syscall"
)

const (
	// Defined in <linux/fs.h>:
	BLKROSET = 4701
	// Defined in <linux/nbd.h>:
	NBD_SET_SOCK        = 43776
	NBD_SET_BLKSIZE     = 43777
	NBD_SET_SIZE        = 43778
	NBD_DO_IT           = 43779
	NBD_CLEAR_SOCK      = 43780
	NBD_CLEAR_QUE       = 43781
	NBD_PRINT_DEBUG     = 43782
	NBD_SET_SIZE_BLOCKS = 43783
	NBD_DISCONNECT      = 43784
	NBD_SET_TIMEOUT     = 43785
	NBD_SET_FLAGS       = 43786
	// enum
	NBD_CMD_READ  = 0
	NBD_CMD_WRITE = 1
	NBD_CMD_DISC  = 2
	NBD_CMD_FLUSH = 3
	NBD_CMD_TRIM  = 4
	// values for flags field
	NBD_FLAG_HAS_FLAGS  = (1 << 0) // nbd-server supports flags
	NBD_FLAG_READ_ONLY  = (1 << 1) // device is read-only
	NBD_FLAG_SEND_FLUSH = (1 << 2) // can flush writeback cache
	// there is a gap here to match userspace
	NBD_FLAG_SEND_TRIM = (1 << 5) // send trim/discard
	// These are sent over the network in the request/reply magic fields
	NBD_REQUEST_MAGIC = 0x25609513
	NBD_REPLY_MAGIC   = 0x67446698
	// Do *not* use magics: 0x12560953 0x96744668.
)

// Device interface is a subset of os.File.
type Device interface {
	ReadAt(b []byte, off int64) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
}

type request struct {
	magic  uint32
	typus  uint32
	handle uint64
	from   uint64
	len    uint32
}

func handle(fd int) {
	buf := make([]byte, 1024)

	var x request

	for {
		n, _ := syscall.Read(fd, buf)
		b := bytes.NewReader(buf[0:n])
		binary.Read(b, binary.BigEndian, &x.magic)
		binary.Read(b, binary.BigEndian, &x.typus)
		binary.Read(b, binary.BigEndian, &x.handle)
		binary.Read(b, binary.BigEndian, &x.from)
		binary.Read(b, binary.BigEndian, &x.len)
		fmt.Println("read", buf[0:n], x)
		// syscall.Write(fd, buf[0:n])
		// fmt.Println("wrote", buf[0:n])
	}
}

func Client(d Device, offset int64, size int64) {
	nbd, _ := os.Open("/dev/nbd0") // TODO: find a free one
	fd, _ := syscall.Socketpair(syscall.SOCK_STREAM, syscall.AF_UNIX, 0)
	go handle(fd[1])
	runtime.LockOSThread()
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SOCK, uintptr(fd[0]))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_BLKSIZE, 4096)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SIZE_BLOCKS, uintptr(size/4096))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_FLAGS, 1)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), BLKROSET, 0)  // || 1
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DO_IT, 0) // doesn't return
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DISCONNECT, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_CLEAR_SOCK, 0)
	runtime.UnlockOSThread()
}
<commit_msg>reading incomplete<commit_after>// This file is part of fs1up.
// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL-2

// Package nbd uses the Linux NBD layer to emulate a block device in user space
package nbd

import (
	"encoding/binary"
	"fmt"
	"os"
	"runtime"
	"syscall"
)

const (
	// Defined in <linux/fs.h>:
	BLKROSET = 4701
	// Defined in <linux/nbd.h>:
	NBD_SET_SOCK        = 43776
	NBD_SET_BLKSIZE     = 43777
	NBD_SET_SIZE        = 43778
	NBD_DO_IT           = 43779
	NBD_CLEAR_SOCK      = 43780
	NBD_CLEAR_QUE       = 43781
	NBD_PRINT_DEBUG     = 43782
	NBD_SET_SIZE_BLOCKS = 43783
	NBD_DISCONNECT      = 43784
	NBD_SET_TIMEOUT     = 43785
	NBD_SET_FLAGS       = 43786
	// enum
	NBD_CMD_READ  = 0
	NBD_CMD_WRITE = 1
	NBD_CMD_DISC  = 2
	NBD_CMD_FLUSH = 3
	NBD_CMD_TRIM  = 4
	// values for flags field
	NBD_FLAG_HAS_FLAGS  = (1 << 0) // nbd-server supports flags
	NBD_FLAG_READ_ONLY  = (1 << 1) // device is read-only
	NBD_FLAG_SEND_FLUSH = (1 << 2) // can flush writeback cache
	// there is a gap here to match userspace
	NBD_FLAG_SEND_TRIM = (1 << 5) // send trim/discard
	// These are sent over the network in the request/reply magic fields
	NBD_REQUEST_MAGIC = 0x25609513
	NBD_REPLY_MAGIC   = 0x67446698
	// Do *not* use magics: 0x12560953 0x96744668.
)

// Device interface is a subset of os.File.
type Device interface {
	ReadAt(b []byte, off int64) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
}

type request struct {
	magic  uint32
	typus  uint32
	handle uint64
	from   uint64
	len    uint32
}

func handle(fd int, d Device) {
	buf := make([]byte, 2<<19)
	var x request

	for {
		syscall.Read(fd, buf)
		x.magic = binary.BigEndian.Uint32(buf)
		x.typus = binary.BigEndian.Uint32(buf[4:8])
		x.handle = binary.BigEndian.Uint64(buf[8:16])
		x.from = binary.BigEndian.Uint64(buf[16:24])
		x.len = binary.BigEndian.Uint32(buf[24:28])

		fmt.Println("read", x)

		switch x.magic {
		case NBD_REPLY_MAGIC:
			fallthrough
		case NBD_REQUEST_MAGIC:
			switch x.typus {
			case NBD_CMD_READ:
				n, _ := d.ReadAt(buf[16:16+x.len], int64(x.from))
				fmt.Println("got", n, "bytes to send back")
				binary.BigEndian.PutUint32(buf[0:4], NBD_REPLY_MAGIC)
				binary.BigEndian.PutUint32(buf[4:8], 0)
				n, _ = syscall.Write(fd, buf[0:16+x.len])
				fmt.Println("actually wrote", n-16)
			case NBD_CMD_WRITE:
				fmt.Println("write", x)
			case NBD_CMD_DISC:
				panic("Disconnect")
			case NBD_CMD_FLUSH:
				fmt.Println("flush", x)
			case NBD_CMD_TRIM:
				fmt.Println("trim", x)
			default:
				panic("unknown command")
			}
		default:
			panic("Invalid packet")
		}

		// syscall.Write(fd, buf[0:n])
		// fmt.Println("wrote", buf[0:n])
	}
}

func Client(d Device, offset int64, size int64) {
	nbd, _ := os.Open("/dev/nbd0") // TODO: find a free one
	fd, _ := syscall.Socketpair(syscall.SOCK_STREAM, syscall.AF_INET, 0)
	go handle(fd[1], d)
	runtime.LockOSThread()
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SOCK, uintptr(fd[0]))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_BLKSIZE, 4096)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SIZE_BLOCKS, uintptr(size/4096))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_FLAGS, 1)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), BLKROSET, 0)  // || 1
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DO_IT, 0) // doesn't return
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DISCONNECT, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_CLEAR_SOCK, 0)
	runtime.UnlockOSThread()
}
<|endoftext|>


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

package frankenstein

import (
	"bytes"
	"fmt"
	"net/http"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/prometheus/common/expfmt"
	"github.com/prometheus/common/model"
	"golang.org/x/net/context"

	"github.com/prometheus/prometheus/storage/metric"
	"github.com/prometheus/prometheus/storage/remote/generic"
)

type IngesterClient struct {
	hostname string
	client   http.Client
}

// NewIngesterClient makes a new IngesterClient.  This client is careful to
// propagate the user ID from Distributor -> Ingestor.
func NewIngesterClient(hostname string, timeout time.Duration) *IngesterClient {
	client := http.Client{
		Timeout: timeout,
	}
	return &IngesterClient{
		hostname: hostname,
		client:   client,
	}
}

func (c *IngesterClient) Append(ctx context.Context, samples []*model.Sample) error {
	req := &generic.GenericWriteRequest{}
	for _, s := range samples {
		ts := &generic.TimeSeries{
			Name: proto.String(string(s.Metric[model.MetricNameLabel])),
		}
		for k, v := range s.Metric {
			if k != model.MetricNameLabel {
				ts.Labels = append(ts.Labels,
					&generic.LabelPair{
						Name:  proto.String(string(k)),
						Value: proto.String(string(v)),
					})
			}
		}
		ts.Samples = []*generic.Sample{
			&generic.Sample{
				Value:       proto.Float64(float64(s.Value)),
				TimestampMs: proto.Int64(int64(s.Timestamp)),
			},
		}
		req.Timeseries = append(req.Timeseries, ts)
	}
	return c.doRequest(ctx, "/push", req, nil)
}

// Query implements Querier.
func (c *IngesterClient) Query(ctx context.Context, from, to model.Time, matchers ...*metric.LabelMatcher) (model.Matrix, error) {
	req := &generic.GenericReadRequest{
		StartTimestampMs: proto.Int64(int64(from)),
		EndTimestampMs:   proto.Int64(int64(to)),
	}
	for _, matcher := range matchers {
		var mType generic.MatchType
		switch matcher.Type {
		case metric.Equal:
			mType = generic.MatchType_EQUAL
		case metric.NotEqual:
			mType = generic.MatchType_NOT_EQUAL
		case metric.RegexMatch:
			mType = generic.MatchType_REGEX_MATCH
		case metric.RegexNoMatch:
			mType = generic.MatchType_REGEX_NO_MATCH
		default:
			panic("invalid matcher type")
		}
		req.Matchers = append(req.Matchers, &generic.LabelMatcher{
			Type:  &mType,
			Name:  proto.String(string(matcher.Name)),
			Value: proto.String(string(matcher.Value)),
		})
	}

	resp := &generic.GenericReadResponse{}
	err := c.doRequest(ctx, "/query", req, resp)
	if err != nil {
		return nil, err
	}

	m := make(model.Matrix, 0, len(resp.Timeseries))
	for _, ts := range resp.Timeseries {
		var ss model.SampleStream
		ss.Metric = model.Metric{}
		if ts.Name != nil {
			ss.Metric[model.MetricNameLabel] = model.LabelValue(ts.GetName())
		}
		for _, l := range ts.Labels {
			ss.Metric[model.LabelName(l.GetName())] = model.LabelValue(l.GetValue())
		}

		ss.Values = make([]model.SamplePair, 0, len(ts.Samples))
		for _, s := range ts.Samples {
			ss.Values = append(ss.Values, model.SamplePair{
				Value:     model.SampleValue(s.GetValue()),
				Timestamp: model.Time(s.GetTimestampMs()),
			})
		}
		m = append(m, &ss)
	}
	fmt.Println("Query", m)

	return m, nil
}

// LabelValuesForLabelName returns all of the label values that are associated with a given label name.
func (c *IngesterClient) LabelValuesForLabelName(ctx context.Context, ln model.LabelName) (model.LabelValues, error) {
	req := &generic.GenericLabelValuesRequest{
		LabelName: proto.String(string(ln)),
	}
	resp := &generic.GenericLabelValuesResponse{}
	err := c.doRequest(ctx, "/label_values", req, resp)
	if err != nil {
		return nil, err
	}

	values := make(model.LabelValues, 0, len(resp.LabelValues))
	for _, v := range resp.LabelValues {
		values = append(values, model.LabelValue(v))
	}
	fmt.Println("LabelValuesForLabelName", values)
	return values, nil
}

func (c *IngesterClient) doRequest(ctx context.Context, endpoint string, req proto.Message, resp proto.Message) error {
	userID, err := userID(ctx)
	if err != nil {
		return err
	}

	data, err := proto.Marshal(req)
	if err != nil {
		return fmt.Errorf("unable to marshal request: %v", err)
	}
	buf := bytes.NewBuffer(data)

	httpReq, err := http.NewRequest("POST", fmt.Sprintf("http://%s%s", c.hostname, endpoint), buf)
	if err != nil {
		return fmt.Errorf("unable to create request: %v", err)
	}
	httpReq.Header.Add(userIDHeaderName, userID)
	// TODO: This isn't actually the correct Content-type.
	httpReq.Header.Set("Content-Type", string(expfmt.FmtProtoDelim))
	httpResp, err := c.client.Do(httpReq)
	if err != nil {
		return fmt.Errorf("error sending request: %v", err)
	}
	defer httpResp.Body.Close()
	if httpResp.StatusCode/100 != 2 {
		return fmt.Errorf("server returned HTTP status %s", httpResp.Status)
	}

	if resp == nil {
		return nil
	}

	buf.Reset()
	_, err = buf.ReadFrom(httpResp.Body)
	if err != nil {
		return fmt.Errorf("unable to read response body: %v", err)
	}
	err = proto.Unmarshal(buf.Bytes(), resp)
	if err != nil {
		return fmt.Errorf("unable to unmarshal response body: %v", err)
	}
	return nil
}
<commit_msg>Remove spurious fmt.Println()s. (#52)<commit_after>// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package frankenstein

import (
	"bytes"
	"fmt"
	"net/http"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/prometheus/common/expfmt"
	"github.com/prometheus/common/model"
	"golang.org/x/net/context"

	"github.com/prometheus/prometheus/storage/metric"
	"github.com/prometheus/prometheus/storage/remote/generic"
)

type IngesterClient struct {
	hostname string
	client   http.Client
}

// NewIngesterClient makes a new IngesterClient.  This client is careful to
// propagate the user ID from Distributor -> Ingestor.
func NewIngesterClient(hostname string, timeout time.Duration) *IngesterClient {
	client := http.Client{
		Timeout: timeout,
	}
	return &IngesterClient{
		hostname: hostname,
		client:   client,
	}
}

func (c *IngesterClient) Append(ctx context.Context, samples []*model.Sample) error {
	req := &generic.GenericWriteRequest{}
	for _, s := range samples {
		ts := &generic.TimeSeries{
			Name: proto.String(string(s.Metric[model.MetricNameLabel])),
		}
		for k, v := range s.Metric {
			if k != model.MetricNameLabel {
				ts.Labels = append(ts.Labels,
					&generic.LabelPair{
						Name:  proto.String(string(k)),
						Value: proto.String(string(v)),
					})
			}
		}
		ts.Samples = []*generic.Sample{
			&generic.Sample{
				Value:       proto.Float64(float64(s.Value)),
				TimestampMs: proto.Int64(int64(s.Timestamp)),
			},
		}
		req.Timeseries = append(req.Timeseries, ts)
	}
	return c.doRequest(ctx, "/push", req, nil)
}

// Query implements Querier.
func (c *IngesterClient) Query(ctx context.Context, from, to model.Time, matchers ...*metric.LabelMatcher) (model.Matrix, error) {
	req := &generic.GenericReadRequest{
		StartTimestampMs: proto.Int64(int64(from)),
		EndTimestampMs:   proto.Int64(int64(to)),
	}
	for _, matcher := range matchers {
		var mType generic.MatchType
		switch matcher.Type {
		case metric.Equal:
			mType = generic.MatchType_EQUAL
		case metric.NotEqual:
			mType = generic.MatchType_NOT_EQUAL
		case metric.RegexMatch:
			mType = generic.MatchType_REGEX_MATCH
		case metric.RegexNoMatch:
			mType = generic.MatchType_REGEX_NO_MATCH
		default:
			panic("invalid matcher type")
		}
		req.Matchers = append(req.Matchers, &generic.LabelMatcher{
			Type:  &mType,
			Name:  proto.String(string(matcher.Name)),
			Value: proto.String(string(matcher.Value)),
		})
	}

	resp := &generic.GenericReadResponse{}
	err := c.doRequest(ctx, "/query", req, resp)
	if err != nil {
		return nil, err
	}

	m := make(model.Matrix, 0, len(resp.Timeseries))
	for _, ts := range resp.Timeseries {
		var ss model.SampleStream
		ss.Metric = model.Metric{}
		if ts.Name != nil {
			ss.Metric[model.MetricNameLabel] = model.LabelValue(ts.GetName())
		}
		for _, l := range ts.Labels {
			ss.Metric[model.LabelName(l.GetName())] = model.LabelValue(l.GetValue())
		}

		ss.Values = make([]model.SamplePair, 0, len(ts.Samples))
		for _, s := range ts.Samples {
			ss.Values = append(ss.Values, model.SamplePair{
				Value:     model.SampleValue(s.GetValue()),
				Timestamp: model.Time(s.GetTimestampMs()),
			})
		}
		m = append(m, &ss)
	}

	return m, nil
}

// LabelValuesForLabelName returns all of the label values that are associated with a given label name.
func (c *IngesterClient) LabelValuesForLabelName(ctx context.Context, ln model.LabelName) (model.LabelValues, error) {
	req := &generic.GenericLabelValuesRequest{
		LabelName: proto.String(string(ln)),
	}
	resp := &generic.GenericLabelValuesResponse{}
	err := c.doRequest(ctx, "/label_values", req, resp)
	if err != nil {
		return nil, err
	}

	values := make(model.LabelValues, 0, len(resp.LabelValues))
	for _, v := range resp.LabelValues {
		values = append(values, model.LabelValue(v))
	}
	return values, nil
}

func (c *IngesterClient) doRequest(ctx context.Context, endpoint string, req proto.Message, resp proto.Message) error {
	userID, err := userID(ctx)
	if err != nil {
		return err
	}

	data, err := proto.Marshal(req)
	if err != nil {
		return fmt.Errorf("unable to marshal request: %v", err)
	}
	buf := bytes.NewBuffer(data)

	httpReq, err := http.NewRequest("POST", fmt.Sprintf("http://%s%s", c.hostname, endpoint), buf)
	if err != nil {
		return fmt.Errorf("unable to create request: %v", err)
	}
	httpReq.Header.Add(userIDHeaderName, userID)
	// TODO: This isn't actually the correct Content-type.
	httpReq.Header.Set("Content-Type", string(expfmt.FmtProtoDelim))
	httpResp, err := c.client.Do(httpReq)
	if err != nil {
		return fmt.Errorf("error sending request: %v", err)
	}
	defer httpResp.Body.Close()
	if httpResp.StatusCode/100 != 2 {
		return fmt.Errorf("server returned HTTP status %s", httpResp.Status)
	}

	if resp == nil {
		return nil
	}

	buf.Reset()
	_, err = buf.ReadFrom(httpResp.Body)
	if err != nil {
		return fmt.Errorf("unable to read response body: %v", err)
	}
	err = proto.Unmarshal(buf.Bytes(), resp)
	if err != nil {
		return fmt.Errorf("unable to unmarshal response body: %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/raintank/raintank-metric/metricdef"
	"github.com/raintank/raintank-metric/schema"
	"log"
	"os"
	"time"
)

type Hit struct {
	Index  string                  `json:"_index"`
	Type   string                  `json:"_type"`
	Id     string                  `json:"_id"`
	Score  float64                 `json:"_score"`
	Source schema.MetricDefinition `json:"_source"`
}

type EsResult struct {
	Took     int
	TimedOut bool
	_shards  struct {
		total      int
		successful int
		failed     int
	}
	Hits struct {
		Total    int
		MaxScore int
		Hits     []Hit
	}
}

func perror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

var esAddr = flag.String("es-addr", "localhost:9200", "elasticsearch address")
var esIndex = flag.String("es-index", "metrictank", "elasticsearch index to query")
var format = flag.String("format", "list", "format: list|vegeta-graphite|vegeta-mt")
var maxAge = flag.Int("max-age", 3600, "max age (last update diff with now) of metricdefs. use 0 to disable")
var from = flag.String("from", "30min", "from. eg '30min', '5h', '14d', etc")
var silent = flag.Bool("silent", false, "silent mode (don't print number of metrics loaded to stderr)")
var fromS uint32
var total int

func showList(ds []*schema.MetricDefinition) {
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Println(d.OrgId, d.Name)
		}
	}
}
func showVegetaGraphite(ds []*schema.MetricDefinition) {
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Printf("GET http://localhost:8888/render?target=%s&from=-%s\nX-Org-Id: %d\n", d.Name, *from, d.OrgId)
		}
	}
}
func showVegetaMT(ds []*schema.MetricDefinition) {
	from := time.Now().Add(-time.Duration(fromS) * time.Second)
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Printf("GET http://localhost:18763/get?target=%s&from=%d\n", d.Id, from.Unix())
		}
	}
}

func main() {
	flag.Parse()
	var show func(ds []*schema.MetricDefinition)
	switch *format {
	case "list":
		show = showList
	case "vegeta-graphite":
		show = showVegetaGraphite
	case "vegeta-mt":
		show = showVegetaMT
	default:
		log.Fatal("invalid format")
	}
	var err error
	fromS, err = inSeconds(*from)
	perror(err)
	defs, err := metricdef.NewDefsEs(*esAddr, "", "", *esIndex)
	perror(err)
	met, scroll_id, err := defs.GetMetrics("")
	perror(err)
	show(met)
	for scroll_id != "" {
		met, scroll_id, err = defs.GetMetrics(scroll_id)
		perror(err)
		show(met)
	}
	if !*silent {
		fmt.Fprintf(os.Stderr, "listed %d metrics\n", total)
	}
}
<commit_msg>default to maxage 6.5 hours. matches with MT update behavior<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/raintank/raintank-metric/metricdef"
	"github.com/raintank/raintank-metric/schema"
	"log"
	"os"
	"time"
)

type Hit struct {
	Index  string                  `json:"_index"`
	Type   string                  `json:"_type"`
	Id     string                  `json:"_id"`
	Score  float64                 `json:"_score"`
	Source schema.MetricDefinition `json:"_source"`
}

type EsResult struct {
	Took     int
	TimedOut bool
	_shards  struct {
		total      int
		successful int
		failed     int
	}
	Hits struct {
		Total    int
		MaxScore int
		Hits     []Hit
	}
}

func perror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

var esAddr = flag.String("es-addr", "localhost:9200", "elasticsearch address")
var esIndex = flag.String("es-index", "metrictank", "elasticsearch index to query")
var format = flag.String("format", "list", "format: list|vegeta-graphite|vegeta-mt")
var maxAge = flag.Int("max-age", 23400, "max age (last update diff with now) of metricdefs. defaults to 6.5hr. use 0 to disable")
var from = flag.String("from", "30min", "from. eg '30min', '5h', '14d', etc")
var silent = flag.Bool("silent", false, "silent mode (don't print number of metrics loaded to stderr)")
var fromS uint32
var total int

func showList(ds []*schema.MetricDefinition) {
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Println(d.OrgId, d.Name)
		}
	}
}
func showVegetaGraphite(ds []*schema.MetricDefinition) {
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Printf("GET http://localhost:8888/render?target=%s&from=-%s\nX-Org-Id: %d\n", d.Name, *from, d.OrgId)
		}
	}
}
func showVegetaMT(ds []*schema.MetricDefinition) {
	from := time.Now().Add(-time.Duration(fromS) * time.Second)
	for _, d := range ds {
		if *maxAge != 0 && d.LastUpdate > time.Now().Unix()-int64(*maxAge) {
			total += 1
			fmt.Printf("GET http://localhost:18763/get?target=%s&from=%d\n", d.Id, from.Unix())
		}
	}
}

func main() {
	flag.Parse()
	var show func(ds []*schema.MetricDefinition)
	switch *format {
	case "list":
		show = showList
	case "vegeta-graphite":
		show = showVegetaGraphite
	case "vegeta-mt":
		show = showVegetaMT
	default:
		log.Fatal("invalid format")
	}
	var err error
	fromS, err = inSeconds(*from)
	perror(err)
	defs, err := metricdef.NewDefsEs(*esAddr, "", "", *esIndex)
	perror(err)
	met, scroll_id, err := defs.GetMetrics("")
	perror(err)
	show(met)
	for scroll_id != "" {
		met, scroll_id, err = defs.GetMetrics(scroll_id)
		perror(err)
		show(met)
	}
	if !*silent {
		fmt.Fprintf(os.Stderr, "listed %d metrics\n", total)
	}
}
<|endoftext|>


<commit_before>/*
file: nnc.go
author: alemedeiros <alexandre.n.medeiros _at_ gmail.com>

A n-sized noughts and crosses game library.

It is a generalization of noughts and crosses, with a n x n board.
To win, you have to fill a line, column or diagonal with your symbol.
*/

// Package nnc implements a n-sized noughts and crosses game.
package nnc

import "errors"

// Empty is an unplayed square;
// Cross is a 'X';
// Nought is a 'O';
const (
	Empty  byte = ' '
	Cross  byte = 'X'
	Nought byte = 'O'
)

// A Game is a game board, use New function to initialize a Game.
type Game struct {
	board      [][]byte
	size       int
	count      int
	currPlayer byte
}

// Structure to save the move and its value.
type move struct {
	value, i, j int
}

// CurrentPlayer method returns the player that should play.
func (g Game) CurrentPlayer() byte {
	return g.currPlayer
}

// Board method returns a copy of the current state of the board.
func (g Game) Board() (board [][]byte) {
	board = make([][]byte, g.size)

	for i := range board {
		board[i] = make([]byte, g.size)
		copy(board[i], g.board[i])
	}

	return
}

// Get the minimum weighted playing position.
func min(a, b move) move {
	if a.value <= b.value {
		return a
	} else {
		return b
	}
}

// Get the maximum weighted playing position.
func max(a, b move) move {
	if a.value >= b.value {
		return a
	} else {
		return b
	}
}

// New function Initializes a game structure with a sz-sized board.
// First player is always Cross.
func New(sz int) (g Game) {
	// Allocate a new Game structure
	g = Game{
		board:      make([][]byte, sz),
		size:       sz,
		count:      sz * sz,
		currPlayer: Cross, // First player is Cross
	}

	// Initialize board.
	for i := range g.board {
		g.board[i] = make([]byte, sz)
		for j := range g.board[i] {
			g.board[i][j] = Empty
		}
	}

	return
}

// Return a copy of the current game.
func (g Game) copyGame() (ng Game) {
	// Allocate a new Game structure
	ng = Game{
		board:      make([][]byte, g.size),
		size:       g.size,
		count:      g.count,
		currPlayer: g.currPlayer,
	}

	// Copy board.
	for i := range ng.board {
		ng.board[i] = make([]byte, g.size)
		for j := range ng.board[i] {
			ng.board[i][j] = g.board[i][j]
		}
	}

	return
}

// Play method checks if the coordinates are inside the board and if it is the
// given player's turn.
//
// Return true and winner (Empty means draw) if the move ended the game.
func (g *Game) Play(x, y int, player byte) (done bool, winner byte, err error) {
	// Validation check
	if g.currPlayer != player {
		return false, Empty, errors.New("not player's turn")
	}
	if x < 0 || g.size <= x || y < 0 || g.size <= y {
		return false, Empty, errors.New("invalid position")
	}
	if g.board[x][y] != Empty {
		print("error position: ", x, " ", y, "\n")
		return false, Empty, errors.New("cell already played")
	}

	// Move is valid, do it!
	g.board[x][y] = player

	// Check if move ended the game
	isDone, winner := g.isDone()

	g.updateTurn()
	g.count -= 1

	return isDone, winner, nil
}

// PlayAI method checks if is the given player's turn, if so, it makes a move as
// that player.
//
// Return true and winner (Empty means draw) if the move ended the game.
func (g *Game) PlayAI(player byte) (done bool, winner byte, err error) {
	// Validation check
	if g.currPlayer != player {
		return false, Empty, errors.New("not player's turn")
	}

	// A value greater than the maximum value possible for a game.
	lim := g.size * g.size * 10

	// Serial alpha-beta pruning
	m := alphaBetaPruningSerial(*g, g.size*g.size, -lim, lim, -1, -1, player)

	//res := make(chan move)
	//prune := make(chan struct{})
	//defer close(prune)

	//go alphaBetaPruning(*g, g.size*g.size, -lim, lim, -1, -1, player, res, prune)

	//// Wait for result.
	//m := <-res

	return g.Play(m.i, m.j, player)
}

// Serial implementation of Alpha-Beta Pruning algorithm.
// TODO: Try not to copy the entire game structure
func alphaBetaPruningSerial(g Game, depth int, alpha, beta int, x, y int, player byte) move {
	// Check for depth limit or if game is over
	if depth == 0 {
		return move{g.outcome(player), x, y}
	}
	if done, _ := g.isDone(); done {
		return move{g.outcome(player), x, y}
	}

	// Check for whose turn it is
	if curr := g.currPlayer; curr == player {
		p := move{alpha, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, player)

				m := alphaBetaPruningSerial(ng, depth-1, alpha, beta, i, j, player)
				m.i = i
				m.j = j

				// Update alpha
				p = max(p, m)
				alpha = p.value

				// Beta cut-off
				if beta <= alpha {
					return m
				}
			}
		}
		return p
	} else {
		p := move{beta, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, curr)

				m := alphaBetaPruningSerial(ng, depth-1, alpha, beta, i, j, player)
				m.i = i
				m.j = j

				// Update beta
				p = min(p, m)
				beta = p.value

				// Alpha cut-off
				if beta <= alpha {
					return m
				}
			}
		}
		return p
	}
}

// updateTurn method updates whose turn it is.
//
// Assumes the turn was correctly set before call.
func (g *Game) updateTurn() error {
	switch g.currPlayer {
	case Cross:
		g.currPlayer = Nought
	case Nought:
		g.currPlayer = Cross
	default:
		return errors.New("invalid player turn value")
	}

	return nil
}

func opponent(player byte) byte {
	switch player {
	case Cross:
		return Nought
	case Nought:
		return Cross
	default:
		return 0
	}
}

// isDone method determines if the game is over, and if it is, its winner.
// If winner is Empty, the it was a draw.
func (g Game) isDone() (done bool, winner byte) {
	winner = Empty
	done = true
	var local bool
	var init byte

	// Check for winner
	for i, sz := 0, g.size; i < sz; i++ {
		// Lines
		local = true
		init = Empty
		for j := 0; j < sz && local; j++ {
			if j == 0 {
				init = g.board[i][j]
			}

			if g.board[i][j] == Empty || g.board[i][j] != init {
				local = false
			}
		}

		// Return if someone won
		if local {
			return local, init
		}

		// Columns
		local = true
		init = Empty
		for j := 0; j < sz && local; j++ {
			if j == 0 {
				init = g.board[j][i]
			}

			if g.board[j][i] == Empty || g.board[j][i] != init {
				local = false
			}
		}

		// Return if someone won
		if local {
			return local, init
		}
	}

	// Diagonal
	local = true
	init = Empty
	for i, sz := 0, g.size; i < sz && local; i++ {
		if i == 0 {
			init = g.board[i][i]
		}

		if g.board[i][i] == Empty || g.board[i][i] != init {
			local = false
		}
	}

	// Return if someone won
	if local {
		return local, init
	}

	// Anti-diagonal
	local = true
	init = Empty
	for i, sz := 0, g.size; i < sz && local; i++ {
		if i == 0 {
			init = g.board[i][sz-1-i]
		}

		if g.board[i][sz-1-i] == Empty || g.board[i][sz-1-i] != init {
			local = false
		}
	}

	// Return if someone won
	if local {
		return local, init
	}

	// Check for draw
outerFor:
	for i := range g.board {
		for _, p := range g.board[i] {
			if p == Empty {
				done = false
				break outerFor
			}
		}
	}

	return
}

// Outcome calculates the outcome function for a player (Nought/Cross) for the
// current game.
func (g Game) outcome(player byte) (sum int) {
	if player != Nought && player != Cross {
		return
	}

	for i, sz := 0, g.size; i < sz; i++ {
		// Lines
		linit, lsum := Empty, 0
		for j := 0; j < sz; j++ {
			// Empty squares don't change the outcome function.
			if g.board[i][j] == Empty {
				continue
			}

			// Initialize initial symbol.
			if linit == Empty {
				linit = g.board[i][j]
			}

			// Different symbols means line sum is 0.
			if g.board[i][j] != linit {
				lsum = 0
				break
			}

			if g.board[i][j] == player {
				lsum += 1 // Increment for player
			} else {
				lsum -= 1 // Decrement for opponent
			}
		}

		// Colums
		cinit, csum := Empty, 0
		for j := 0; j < sz; j++ {
			// Empty squares don't change the outcome function.
			if g.board[j][i] == Empty {
				continue
			}

			// Initialize initial symbol.
			if cinit == Empty {
				cinit = g.board[j][i]
			}

			// Different symbols means column sum is 0.
			if g.board[j][i] != cinit {
				csum = 0
				break
			}

			if g.board[j][i] == player {
				csum += 1 // Increment for player
			} else {
				csum -= 1 // Decrement for opponent
			}
		}

		if lsum == sz || csum == sz {
			return 3 * sz * sz
		} else if lsum == -sz || csum == -sz {
			return -(3 * sz * sz)
		}

		sum += lsum + csum
	}

	// Diagonal
	dinit, dsum := Empty, 0
	for i, sz := 0, g.size; i < sz; i++ {

		// Empty squares don't change the outcome function.
		if g.board[i][i] == Empty {
			continue
		}

		// Initialize initial symbol.
		if dinit == Empty {
			dinit = g.board[i][i]
		}

		// Different symbols means diagonal sum is 0.
		if g.board[i][i] != dinit {
			dsum = 0
			break
		}

		if g.board[i][i] == player {
			dsum += 1 // Increment for player
		} else {
			dsum -= 1 // Decrement for opponent
		}
	}

	if dsum == g.size {
		return 3 * g.size * g.size
	} else if dsum == -g.size {
		return -(3 * g.size * g.size)
	}

	sum += dsum

	// Anti-Diagonal
	adinit, adsum := Empty, 0
	for i, sz := 0, g.size; i < sz; i++ {
		// Empty squares don't change the outcome function.
		if g.board[i][sz-1-i] == Empty {
			continue
		}

		// Initialize initial symbol.
		if adinit == Empty {
			adinit = g.board[i][sz-1-i]
		}

		// Different symbols means anti-diagonal sum is 0.
		if g.board[i][sz-1-i] != adinit {
			adsum = 0
			break
		}

		if g.board[i][sz-1-i] == player {
			adsum += 1 // Increment for player
		} else {
			adsum -= 1 // Decrement for opponent
		}
	}

	if adsum == g.size {
		return 3 * g.size * g.size
	} else if adsum == -g.size {
		return -(3 * g.size * g.size)
	}

	sum += adsum

	return
}
<commit_msg>add alphaBetaPruning with locks (initial parallel implementation)<commit_after>/*
file: nnc.go
author: alemedeiros <alexandre.n.medeiros _at_ gmail.com>

A n-sized noughts and crosses game library.

It is a generalization of noughts and crosses, with a n x n board.
To win, you have to fill a line, column or diagonal with your symbol.
*/

// Package nnc implements a n-sized noughts and crosses game.
package nnc

import (
	"errors"
	"sync"
)

// Empty is an unplayed square;
// Cross is a 'X';
// Nought is a 'O';
const (
	Empty  byte = ' '
	Cross  byte = 'X'
	Nought byte = 'O'
)

// A Game is a game board, use New function to initialize a Game.
type Game struct {
	board      [][]byte
	size       int
	count      int
	currPlayer byte
}

// Structure to save the move and its value.
type move struct {
	value, i, j int
}

type bound struct {
	val  int
	lock *sync.Mutex
}

// CurrentPlayer method returns the player that should play.
func (g Game) CurrentPlayer() byte {
	return g.currPlayer
}

// Board method returns a copy of the current state of the board.
func (g Game) Board() (board [][]byte) {
	board = make([][]byte, g.size)

	for i := range board {
		board[i] = make([]byte, g.size)
		copy(board[i], g.board[i])
	}

	return
}

// Get the minimum weighted playing position.
func min(a, b move) move {
	if a.value <= b.value {
		return a
	} else {
		return b
	}
}

// Get the maximum weighted playing position.
func max(a, b move) move {
	if a.value >= b.value {
		return a
	} else {
		return b
	}
}

// New function Initializes a game structure with a sz-sized board.
// First player is always Cross.
func New(sz int) (g Game) {
	// Allocate a new Game structure
	g = Game{
		board:      make([][]byte, sz),
		size:       sz,
		count:      sz * sz,
		currPlayer: Cross, // First player is Cross
	}

	// Initialize board.
	for i := range g.board {
		g.board[i] = make([]byte, sz)
		for j := range g.board[i] {
			g.board[i][j] = Empty
		}
	}

	return
}

// Return a copy of the current game.
func (g Game) copyGame() (ng Game) {
	// Allocate a new Game structure
	ng = Game{
		board:      make([][]byte, g.size),
		size:       g.size,
		count:      g.count,
		currPlayer: g.currPlayer,
	}

	// Copy board.
	for i := range ng.board {
		ng.board[i] = make([]byte, g.size)
		for j := range ng.board[i] {
			ng.board[i][j] = g.board[i][j]
		}
	}

	return
}

// Play method checks if the coordinates are inside the board and if it is the
// given player's turn.
//
// Return true and winner (Empty means draw) if the move ended the game.
func (g *Game) Play(x, y int, player byte) (done bool, winner byte, err error) {
	// Validation check
	if g.currPlayer != player {
		return false, Empty, errors.New("not player's turn")
	}
	if x < 0 || g.size <= x || y < 0 || g.size <= y {
		return false, Empty, errors.New("invalid position")
	}
	if g.board[x][y] != Empty {
		print("error position: ", x, " ", y, "\n")
		return false, Empty, errors.New("cell already played")
	}

	// Move is valid, do it!
	g.board[x][y] = player

	// Check if move ended the game
	isDone, winner := g.isDone()

	g.updateTurn()
	g.count -= 1

	return isDone, winner, nil
}

// PlayAI method checks if is the given player's turn, if so, it makes a move as
// that player.
//
// Return true and winner (Empty means draw) if the move ended the game.
func (g *Game) PlayAI(player byte) (done bool, winner byte, err error) {
	// Validation check
	if g.currPlayer != player {
		return false, Empty, errors.New("not player's turn")
	}

	// A value greater than the maximum value possible for a game.
	lim := g.size * g.size * 10

	a := bound{-lim, &sync.Mutex{}}
	b := bound{lim, &sync.Mutex{}}
	m := alphaBetaPruning(*g, g.size*g.size, &a, &b, -1, -1, player)

	// Serial alpha-beta pruning
	//m := alphaBetaPruningSerial(*g, g.size*g.size, -lim, lim, -1, -1, player)

	//res := make(chan move)
	//prune := make(chan struct{})
	//defer close(prune)

	//go alphaBetaPruning(*g, g.size*g.size, -lim, lim, -1, -1, player, res, prune)

	//// Wait for result.
	//m := <-res

	return g.Play(m.i, m.j, player)
}

// Serial implementation of Alpha-Beta Pruning algorithm.
// TODO: Try not to copy the entire game structure
func alphaBetaPruningSerial(g Game, depth int, alpha, beta int, x, y int, player byte) move {
	// Check for depth limit or if game is over
	if depth == 0 {
		return move{g.outcome(player), x, y}
	}
	if done, _ := g.isDone(); done {
		return move{g.outcome(player), x, y}
	}

	// Check for whose turn it is
	if curr := g.currPlayer; curr == player {
		p := move{alpha, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, player)

				m := alphaBetaPruningSerial(ng, depth-1, alpha, beta, i, j, player)
				m.i = i
				m.j = j

				// Update alpha
				p = max(p, m)
				alpha = p.value

				// Beta cut-off
				if beta <= alpha {
					return m
				}
			}
		}
		return p
	} else {
		p := move{beta, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, curr)

				m := alphaBetaPruningSerial(ng, depth-1, alpha, beta, i, j, player)
				m.i = i
				m.j = j

				// Update beta
				p = min(p, m)
				beta = p.value

				// Alpha cut-off
				if beta <= alpha {
					return m
				}
			}
		}
		return p
	}
}

// Parallel implementation of Alpha-Beta Pruning algorithm.
// TODO: Try not to copy the entire game structure
func alphaBetaPruning(g Game, depth int, alpha, beta *bound, x, y int, player byte) move {
	// Check for depth limit or if game is over
	if depth == 0 {
		return move{g.outcome(player), x, y}
	}
	if done, _ := g.isDone(); done {
		return move{g.outcome(player), x, y}
	}

	cAlpha := bound{alpha.val, &sync.Mutex{}}
	cBeta := bound{beta.val, &sync.Mutex{}}

	// Check for whose turn it is
	if curr := g.currPlayer; curr == player {
		p := move{cAlpha.val, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, player)

				m := alphaBetaPruning(ng, depth-1, &cAlpha, &cBeta, i, j, player)
				m.i = i
				m.j = j

				// Update alpha
				p = max(p, m)
				if cAlpha.val < p.value {
					cAlpha.lock.Lock()
					// Check again
					if cAlpha.val < p.value {
						cAlpha.val = p.value
					}
					cAlpha.lock.Unlock()
				}

				// Beta cut-off
				if cBeta.val <= cAlpha.val {
					return p
				}
			}
		}
		return p
	} else {
		p := move{cBeta.val, x, y}

		for i, l := range g.board {
			for j, e := range l {
				// Check for possible move
				if e != Empty {
					continue
				}

				// Generate updated game
				ng := g.copyGame()
				ng.Play(i, j, curr)

				m := alphaBetaPruning(ng, depth-1, &cAlpha, &cBeta, i, j, player)
				m.i = i
				m.j = j

				// Update beta
				p = min(p, m)
				if cBeta.val > p.value {
					cBeta.lock.Lock()
					// Check again
					if cBeta.val > p.value {
						cBeta.val = p.value
					}
					cBeta.lock.Unlock()
				}

				// Alpha cut-off
				if cBeta.val <= cAlpha.val {
					return p
				}
			}
		}
		return p
	}
}

// updateTurn method updates whose turn it is.
//
// Assumes the turn was correctly set before call.
func (g *Game) updateTurn() error {
	switch g.currPlayer {
	case Cross:
		g.currPlayer = Nought
	case Nought:
		g.currPlayer = Cross
	default:
		return errors.New("invalid player turn value")
	}

	return nil
}

func opponent(player byte) byte {
	switch player {
	case Cross:
		return Nought
	case Nought:
		return Cross
	default:
		return 0
	}
}

// isDone method determines if the game is over, and if it is, its winner.
// If winner is Empty, the it was a draw.
func (g Game) isDone() (done bool, winner byte) {
	winner = Empty
	done = true
	var local bool
	var init byte

	// Check for winner
	for i, sz := 0, g.size; i < sz; i++ {
		// Lines
		local = true
		init = Empty
		for j := 0; j < sz && local; j++ {
			if j == 0 {
				init = g.board[i][j]
			}

			if g.board[i][j] == Empty || g.board[i][j] != init {
				local = false
			}
		}

		// Return if someone won
		if local {
			return local, init
		}

		// Columns
		local = true
		init = Empty
		for j := 0; j < sz && local; j++ {
			if j == 0 {
				init = g.board[j][i]
			}

			if g.board[j][i] == Empty || g.board[j][i] != init {
				local = false
			}
		}

		// Return if someone won
		if local {
			return local, init
		}
	}

	// Diagonal
	local = true
	init = Empty
	for i, sz := 0, g.size; i < sz && local; i++ {
		if i == 0 {
			init = g.board[i][i]
		}

		if g.board[i][i] == Empty || g.board[i][i] != init {
			local = false
		}
	}

	// Return if someone won
	if local {
		return local, init
	}

	// Anti-diagonal
	local = true
	init = Empty
	for i, sz := 0, g.size; i < sz && local; i++ {
		if i == 0 {
			init = g.board[i][sz-1-i]
		}

		if g.board[i][sz-1-i] == Empty || g.board[i][sz-1-i] != init {
			local = false
		}
	}

	// Return if someone won
	if local {
		return local, init
	}

	// Check for draw
outerFor:
	for i := range g.board {
		for _, p := range g.board[i] {
			if p == Empty {
				done = false
				break outerFor
			}
		}
	}

	return
}

// Outcome calculates the outcome function for a player (Nought/Cross) for the
// current game.
func (g Game) outcome(player byte) (sum int) {
	if player != Nought && player != Cross {
		return
	}

	for i, sz := 0, g.size; i < sz; i++ {
		// Lines
		linit, lsum := Empty, 0
		for j := 0; j < sz; j++ {
			// Empty squares don't change the outcome function.
			if g.board[i][j] == Empty {
				continue
			}

			// Initialize initial symbol.
			if linit == Empty {
				linit = g.board[i][j]
			}

			// Different symbols means line sum is 0.
			if g.board[i][j] != linit {
				lsum = 0
				break
			}

			if g.board[i][j] == player {
				lsum += 1 // Increment for player
			} else {
				lsum -= 1 // Decrement for opponent
			}
		}

		// Colums
		cinit, csum := Empty, 0
		for j := 0; j < sz; j++ {
			// Empty squares don't change the outcome function.
			if g.board[j][i] == Empty {
				continue
			}

			// Initialize initial symbol.
			if cinit == Empty {
				cinit = g.board[j][i]
			}

			// Different symbols means column sum is 0.
			if g.board[j][i] != cinit {
				csum = 0
				break
			}

			if g.board[j][i] == player {
				csum += 1 // Increment for player
			} else {
				csum -= 1 // Decrement for opponent
			}
		}

		if lsum == sz || csum == sz {
			return 3 * sz * sz
		} else if lsum == -sz || csum == -sz {
			return -(3 * sz * sz)
		}

		sum += lsum + csum
	}

	// Diagonal
	dinit, dsum := Empty, 0
	for i, sz := 0, g.size; i < sz; i++ {

		// Empty squares don't change the outcome function.
		if g.board[i][i] == Empty {
			continue
		}

		// Initialize initial symbol.
		if dinit == Empty {
			dinit = g.board[i][i]
		}

		// Different symbols means diagonal sum is 0.
		if g.board[i][i] != dinit {
			dsum = 0
			break
		}

		if g.board[i][i] == player {
			dsum += 1 // Increment for player
		} else {
			dsum -= 1 // Decrement for opponent
		}
	}

	if dsum == g.size {
		return 3 * g.size * g.size
	} else if dsum == -g.size {
		return -(3 * g.size * g.size)
	}

	sum += dsum

	// Anti-Diagonal
	adinit, adsum := Empty, 0
	for i, sz := 0, g.size; i < sz; i++ {
		// Empty squares don't change the outcome function.
		if g.board[i][sz-1-i] == Empty {
			continue
		}

		// Initialize initial symbol.
		if adinit == Empty {
			adinit = g.board[i][sz-1-i]
		}

		// Different symbols means anti-diagonal sum is 0.
		if g.board[i][sz-1-i] != adinit {
			adsum = 0
			break
		}

		if g.board[i][sz-1-i] == player {
			adsum += 1 // Increment for player
		} else {
			adsum -= 1 // Decrement for opponent
		}
	}

	if adsum == g.size {
		return 3 * g.size * g.size
	} else if adsum == -g.size {
		return -(3 * g.size * g.size)
	}

	sum += adsum

	return
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-logger Authors. All rights reserved.
// This code is MIT licensed. See the LICENSE file for more info.

package log

import (
	"bytes"
	"fmt"
	"io"
	"math/rand"
	"os"
	"path/filepath"
	"testing"
	"runtime"
	"time"
)

func TestStream(t *testing.T) {
	var buf bytes.Buffer
	logr := New(LEVEL_CRITICAL, os.Stdout, &buf)
	logr.Streams[1] = &buf
	if out := logr.Streams[1]; out != &buf {
		t.Errorf("Stream = %p, want %p", out, &buf)
	}
}

func TestMultiStreams(t *testing.T) {
	rand.Seed(time.Now().UnixNano())
	fPath := filepath.Join(os.TempDir(), fmt.Sprint("go_test_",
		rand.Int()))
	file, err := os.Create(fPath)
	if err != nil {
		t.Error("Create(%q) = %v; want: nil", fPath, err)
	}
	defer file.Close()
	var buf bytes.Buffer
	eLen := 55
	logr := New(LEVEL_DEBUG, file, &buf)
	logr.Debugln("Testing debug output!")
	b := make([]byte, eLen)
	n, err := file.ReadAt(b, 0)
	if n != eLen || err != nil {
		t.Errorf("Read(%d) = %d, %v; want: %d, nil", eLen, n, err,
			eLen)
	}
	if buf.Len() != eLen {
		t.Errorf("buf.Len() = %d; want: %d", buf.Len(), eLen)
	}
}

func TestLongFileFlag(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LlongFileName)

	Debugln("Test long file flag")

	_, file, _, _ := runtime.Caller(0)

	expect := fmt.Sprintf("[DEBUG] %s: Test long file flag\n", file)

	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestShortFileFlag(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LshortFileName)

	Debugln("Test short file flag")

	_, file, _, _ := runtime.Caller(0)

	short := file
	for i := len(file) - 1; i > 0; i-- {
		if file[i] == '/' {
			short = file[i+1:]
			break
		}
	}
	file = short

	expect := fmt.Sprintf("[DEBUG] %s: Test short file flag\n", file)

	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

var (
	boldPrefix  = AnsiEscape(ANSI_BOLD, "TEST>", ANSI_OFF)
	colorPrefix = AnsiEscape(ANSI_BOLD, ANSI_RED, "TEST>", ANSI_OFF)
	date        = "Mon 20060102 15:04:05"
)

var outputTests = []struct {
	template   string
	prefix     string
	level      level
	dateFormat string
	flags      int
	text       string
	want       string
	wantErr    bool
}{

	// The %s format specifier is the placeholder for the date.
	{logFmt, boldPrefix, LEVEL_ALL, date, LstdFlags, "test number 1",
		"%s \x1b[1mTEST>\x1b[0m test number 1", false},

	{logFmt, colorPrefix, LEVEL_ALL, date, LstdFlags, "test number 2",
		"%s \x1b[1m\x1b[31mTEST>\x1b[0m test number 2", false},

	// Test output with coloring turned off
	{logFmt, AnsiEscape(ANSI_BOLD, "::", ANSI_OFF), LEVEL_ALL, date, Ldate,
		"test number 3", "%s :: test number 3", false},

	{logFmt, defaultPrefixColor, LEVEL_DEBUG, time.RubyDate, LstdFlags,
		"test number 4",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[37m[DEBUG]\x1b[0m test number 4",
		false},

	{logFmt, defaultPrefixColor, LEVEL_INFO, time.RubyDate, LstdFlags,
		"test number 5",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[32m[INFO]\x1b[0m test number 5",
		false},

	{logFmt, defaultPrefixColor, LEVEL_WARNING, time.RubyDate, LstdFlags,
		"test number 6",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[33m[WARNING]\x1b[0m test number 6",
		false},

	{logFmt, defaultPrefixColor, LEVEL_ERROR, time.RubyDate, LstdFlags,
		"test number 7",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[35m[ERROR]\x1b[0m test number 7",
		false},

	{logFmt, defaultPrefixColor, LEVEL_CRITICAL, time.RubyDate, LstdFlags,
		"test number 8",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[31m[CRITICAL]\x1b[0m test number 8",
		false},

	// Test date format
	{logFmt, defaultPrefixColor, LEVEL_ALL, "Mon 20060102 15:04:05",
		Ldate, "test number 9",
		"%s :: test number 9", false},
}

func TestOutput(t *testing.T) {
	for i, k := range outputTests {
		var buf bytes.Buffer
		logr := New(LEVEL_DEBUG, &buf)
		logr.Prefix = k.prefix
		logr.DateFormat = k.dateFormat
		logr.Flags = k.flags
		logr.Level = k.level
		d := time.Now().Format(logr.DateFormat)
		n, err := logr.Fprint(k.level, 1, k.text, &buf)
		if n != buf.Len() {
			t.Error("Error: ", io.ErrShortWrite)
		}
		want := fmt.Sprintf(k.want, d)
		if buf.String() != want || err != nil && !k.wantErr {
			t.Errorf("Print test %d failed, \ngot:  %q\nwant: "+
				"%q", i+1, buf.String(), want)
			continue
		}
	}
}

func TestLevel(t *testing.T) {
	var buf bytes.Buffer
	logr := New(LEVEL_CRITICAL, &buf)
	logr.Debug("This level should produce no output")
	if buf.Len() != 0 {
		t.Errorf("Debug() produced output at LEVEL_CRITICAL logging level")
	}
	logr.Level = LEVEL_DEBUG
	logr.Debug("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the LEVEL_DEBUG logging level")
	}
	buf.Reset()
	logr.Level = LEVEL_CRITICAL
	logr.Println("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the ALL logging level")
	}
	buf.Reset()
	logr.Level = LEVEL_ALL
	logr.Debug("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the ALL logging level")
	}
}

func TestPrefixNewline(t *testing.T) {
	var buf bytes.Buffer

	c, err := buf.ReadString('\n')

	// If text sent with the logging functions is prepended with newlines,
	// these newlines must be prepended to the output and stripped from the
	// text. First we will make sure the two nl's are at the beginning of
	// the output.
	if c[0] != '\n' {
		t.Errorf(`First byte should be "\n", found "%s"`, string(c[0]))
	}

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)

	c, err = buf.ReadString('\n')
	if err != nil {
		t.Error("ReadString unexpected EOF")
	}

	// Since nl should be stripped from the text and prepended to the
	// output, we must make sure the nl is still not in the middle where it
	// would be if it had not been stripped.
	nlPos := strings.Index(buf.String(), "] ") + 1
	if buf.Bytes()[nlPos+1] == '\n' {
		t.Errorf(`"\n" found at position %d.`, nlPos+1)
	}
}

func TestFlagsLdate(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)

	Debugln("This output should not have a date.")

	expect := "[DEBUG] This output should not have a date.\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestFlagsLfunctionName(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LfunctionName)

	Debugln("This output should have a function name.")

	expect := "[DEBUG] TestFlagsLfunctionName: This output should have a function name.\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestFlagsNoLansiWithNewlinePadding(t *testing.T) {
	var buf bytes.Buffer
	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)
	Debug("\n\nThis output should be padded with newlines and not colored.\n\n")
	expect := "\n\n[DEBUG] This output should be padded with newlines and not colored.\n\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}
<commit_msg>logger_test.go: Refactor TestPrefixNewline<commit_after>// Copyright 2013 The go-logger Authors. All rights reserved.
// This code is MIT licensed. See the LICENSE file for more info.

package log

import (
	"bytes"
	"fmt"
	"io"
	"math/rand"
	"os"
	"path/filepath"
	"testing"
	"runtime"
	"time"
)

func TestStream(t *testing.T) {
	var buf bytes.Buffer
	logr := New(LEVEL_CRITICAL, os.Stdout, &buf)
	logr.Streams[1] = &buf
	if out := logr.Streams[1]; out != &buf {
		t.Errorf("Stream = %p, want %p", out, &buf)
	}
}

func TestMultiStreams(t *testing.T) {
	rand.Seed(time.Now().UnixNano())
	fPath := filepath.Join(os.TempDir(), fmt.Sprint("go_test_",
		rand.Int()))
	file, err := os.Create(fPath)
	if err != nil {
		t.Error("Create(%q) = %v; want: nil", fPath, err)
	}
	defer file.Close()
	var buf bytes.Buffer
	eLen := 55
	logr := New(LEVEL_DEBUG, file, &buf)
	logr.Debugln("Testing debug output!")
	b := make([]byte, eLen)
	n, err := file.ReadAt(b, 0)
	if n != eLen || err != nil {
		t.Errorf("Read(%d) = %d, %v; want: %d, nil", eLen, n, err,
			eLen)
	}
	if buf.Len() != eLen {
		t.Errorf("buf.Len() = %d; want: %d", buf.Len(), eLen)
	}
}

func TestLongFileFlag(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LlongFileName)

	Debugln("Test long file flag")

	_, file, _, _ := runtime.Caller(0)

	expect := fmt.Sprintf("[DEBUG] %s: Test long file flag\n", file)

	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestShortFileFlag(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LshortFileName)

	Debugln("Test short file flag")

	_, file, _, _ := runtime.Caller(0)

	short := file
	for i := len(file) - 1; i > 0; i-- {
		if file[i] == '/' {
			short = file[i+1:]
			break
		}
	}
	file = short

	expect := fmt.Sprintf("[DEBUG] %s: Test short file flag\n", file)

	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

var (
	boldPrefix  = AnsiEscape(ANSI_BOLD, "TEST>", ANSI_OFF)
	colorPrefix = AnsiEscape(ANSI_BOLD, ANSI_RED, "TEST>", ANSI_OFF)
	date        = "Mon 20060102 15:04:05"
)

var outputTests = []struct {
	template   string
	prefix     string
	level      level
	dateFormat string
	flags      int
	text       string
	want       string
	wantErr    bool
}{

	// The %s format specifier is the placeholder for the date.
	{logFmt, boldPrefix, LEVEL_ALL, date, LstdFlags, "test number 1",
		"%s \x1b[1mTEST>\x1b[0m test number 1", false},

	{logFmt, colorPrefix, LEVEL_ALL, date, LstdFlags, "test number 2",
		"%s \x1b[1m\x1b[31mTEST>\x1b[0m test number 2", false},

	// Test output with coloring turned off
	{logFmt, AnsiEscape(ANSI_BOLD, "::", ANSI_OFF), LEVEL_ALL, date, Ldate,
		"test number 3", "%s :: test number 3", false},

	{logFmt, defaultPrefixColor, LEVEL_DEBUG, time.RubyDate, LstdFlags,
		"test number 4",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[37m[DEBUG]\x1b[0m test number 4",
		false},

	{logFmt, defaultPrefixColor, LEVEL_INFO, time.RubyDate, LstdFlags,
		"test number 5",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[32m[INFO]\x1b[0m test number 5",
		false},

	{logFmt, defaultPrefixColor, LEVEL_WARNING, time.RubyDate, LstdFlags,
		"test number 6",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[33m[WARNING]\x1b[0m test number 6",
		false},

	{logFmt, defaultPrefixColor, LEVEL_ERROR, time.RubyDate, LstdFlags,
		"test number 7",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[35m[ERROR]\x1b[0m test number 7",
		false},

	{logFmt, defaultPrefixColor, LEVEL_CRITICAL, time.RubyDate, LstdFlags,
		"test number 8",
		"%s \x1b[1m\x1b[32m::\x1b[0m \x1b[1m\x1b[31m[CRITICAL]\x1b[0m test number 8",
		false},

	// Test date format
	{logFmt, defaultPrefixColor, LEVEL_ALL, "Mon 20060102 15:04:05",
		Ldate, "test number 9",
		"%s :: test number 9", false},
}

func TestOutput(t *testing.T) {
	for i, k := range outputTests {
		var buf bytes.Buffer
		logr := New(LEVEL_DEBUG, &buf)
		logr.Prefix = k.prefix
		logr.DateFormat = k.dateFormat
		logr.Flags = k.flags
		logr.Level = k.level
		d := time.Now().Format(logr.DateFormat)
		n, err := logr.Fprint(k.level, 1, k.text, &buf)
		if n != buf.Len() {
			t.Error("Error: ", io.ErrShortWrite)
		}
		want := fmt.Sprintf(k.want, d)
		if buf.String() != want || err != nil && !k.wantErr {
			t.Errorf("Print test %d failed, \ngot:  %q\nwant: "+
				"%q", i+1, buf.String(), want)
			continue
		}
	}
}

func TestLevel(t *testing.T) {
	var buf bytes.Buffer
	logr := New(LEVEL_CRITICAL, &buf)
	logr.Debug("This level should produce no output")
	if buf.Len() != 0 {
		t.Errorf("Debug() produced output at LEVEL_CRITICAL logging level")
	}
	logr.Level = LEVEL_DEBUG
	logr.Debug("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the LEVEL_DEBUG logging level")
	}
	buf.Reset()
	logr.Level = LEVEL_CRITICAL
	logr.Println("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the ALL logging level")
	}
	buf.Reset()
	logr.Level = LEVEL_ALL
	logr.Debug("This level should produce output")
	if buf.Len() == 0 {
		t.Errorf("Debug() did not produce output at the ALL logging level")
	}
}

func TestPrefixNewline(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)

	Debug("\n\nThis line should be padded with newlines.\n\n")

	expect := "\n\n[DEBUG] This line should be padded with newlines.\n\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n%q\nGot:\n%q\n", expect, buf.String())
	}
}

func TestFlagsLdate(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)

	Debugln("This output should not have a date.")

	expect := "[DEBUG] This output should not have a date.\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestFlagsLfunctionName(t *testing.T) {
	var buf bytes.Buffer

	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix | LfunctionName)

	Debugln("This output should have a function name.")

	expect := "[DEBUG] TestFlagsLfunctionName: This output should have a function name.\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}

func TestFlagsNoLansiWithNewlinePadding(t *testing.T) {
	var buf bytes.Buffer
	SetStreams(&buf)
	SetLevel(LEVEL_DEBUG)
	SetFlags(LnoPrefix)
	Debug("\n\nThis output should be padded with newlines and not colored.\n\n")
	expect := "\n\n[DEBUG] This output should be padded with newlines and not colored.\n\n"
	if buf.String() != expect {
		t.Errorf("\nExpect:\n\t%q\nGot:\n\t%q\n", expect, buf.String())
	}
}
<|endoftext|>