<commit_before>// Package local provides the default implementation for volumes. It
// is used to mount data volume containers and directories local to
// the host server.
package local

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sync"

	"github.com/pkg/errors"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/idtools"
	"github.com/docker/docker/pkg/mount"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/volume"
)

// VolumeDataPathName is the name of the directory where the volume data is stored.
// It uses a very distinctive name to avoid collisions migrating data between
// Docker versions.
const (
	VolumeDataPathName = "_data"
	volumesPathName    = "volumes"
)

var (
	// ErrNotFound is the typed error returned when the requested volume name can't be found
	ErrNotFound = fmt.Errorf("volume not found")
	// volumeNameRegex ensures the name assigned for the volume is valid.
	// This name is used to create the bind directory, so we need to avoid characters that
	// would make the path to escape the root directory.
	volumeNameRegex = utils.RestrictedVolumeNamePattern
)

type validationError struct {
	error
}

func (validationError) IsValidationError() bool {
	return true
}

type activeMount struct {
	count   uint64
	mounted bool
}

// New instantiates a new Root instance with the provided scope. Scope
// is the base path that the Root instance uses to store its
// volumes. The base path is created here if it does not exist.
func New(scope string, rootUID, rootGID int) (*Root, error) {
	rootDirectory := filepath.Join(scope, volumesPathName)

	if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil {
		return nil, err
	}

	r := &Root{
		scope:   scope,
		path:    rootDirectory,
		volumes: make(map[string]*localVolume),
		rootUID: rootUID,
		rootGID: rootGID,
	}

	dirs, err := ioutil.ReadDir(rootDirectory)
	if err != nil {
		return nil, err
	}

	mountInfos, err := mount.GetMounts()
	if err != nil {
		logrus.Debugf("error looking up mounts for local volume cleanup: %v", err)
	}

	for _, d := range dirs {
		if !d.IsDir() {
			continue
		}

		name := filepath.Base(d.Name())
		v := &localVolume{
			driverName: r.Name(),
			name:       name,
			path:       r.DataPath(name),
		}
		r.volumes[name] = v
		optsFilePath := filepath.Join(rootDirectory, name, "opts.json")
		if b, err := ioutil.ReadFile(optsFilePath); err == nil {
			opts := optsConfig{}
			if err := json.Unmarshal(b, &opts); err != nil {
				return nil, errors.Wrapf(err, "error while unmarshaling volume options for volume: %s", name)
			}
			// Make sure this isn't an empty optsConfig.
			// This could be empty due to buggy behavior in older versions of Docker.
			if !reflect.DeepEqual(opts, optsConfig{}) {
				v.opts = &opts
			}

			// unmount anything that may still be mounted (for example, from an unclean shutdown)
			for _, info := range mountInfos {
				if info.Mountpoint == v.path {
					mount.Unmount(v.path)
					break
				}
			}
		}
	}

	return r, nil
}

// Root implements the Driver interface for the volume package and
// manages the creation/removal of volumes. It uses only standard vfs
// commands to create/remove dirs within its provided scope.
type Root struct {
	m       sync.Mutex
	scope   string
	path    string
	volumes map[string]*localVolume
	rootUID int
	rootGID int
}

// List lists all the volumes
func (r *Root) List() ([]volume.Volume, error) {
	var ls []volume.Volume
	r.m.Lock()
	for _, v := range r.volumes {
		ls = append(ls, v)
	}
	r.m.Unlock()
	return ls, nil
}

// DataPath returns the constructed path of this volume.
func (r *Root) DataPath(volumeName string) string {
	return filepath.Join(r.path, volumeName, VolumeDataPathName)
}

// Name returns the name of Root, defined in the volume package in the DefaultDriverName constant.
func (r *Root) Name() string {
	return volume.DefaultDriverName
}

// Create creates a new volume.Volume with the provided name, creating
// the underlying directory tree required for this volume in the
// process.
func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error) {
	if err := r.validateName(name); err != nil {
		return nil, err
	}

	r.m.Lock()
	defer r.m.Unlock()

	v, exists := r.volumes[name]
	if exists {
		return v, nil
	}

	path := r.DataPath(name)
	if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil {
		if os.IsExist(err) {
			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
		}
		return nil, errors.Wrapf(err, "error while creating volume path '%s'", path)
	}

	var err error
	defer func() {
		if err != nil {
			os.RemoveAll(filepath.Dir(path))
		}
	}()

	v = &localVolume{
		driverName: r.Name(),
		name:       name,
		path:       path,
	}

	if len(opts) != 0 {
		if err = setOpts(v, opts); err != nil {
			return nil, err
		}
		var b []byte
		b, err = json.Marshal(v.opts)
		if err != nil {
			return nil, err
		}
		if err = ioutil.WriteFile(filepath.Join(filepath.Dir(path), "opts.json"), b, 600); err != nil {
			return nil, errors.Wrap(err, "error while persisting volume options")
		}
	}

	r.volumes[name] = v
	return v, nil
}

// Remove removes the specified volume and all underlying data. If the
// given volume does not belong to this driver and an error is
// returned. The volume is reference counted, if all references are
// not released then the volume is not removed.
func (r *Root) Remove(v volume.Volume) error {
	r.m.Lock()
	defer r.m.Unlock()

	lv, ok := v.(*localVolume)
	if !ok {
		return fmt.Errorf("unknown volume type %T", v)
	}

	realPath, err := filepath.EvalSymlinks(lv.path)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		realPath = filepath.Dir(lv.path)
	}

	if !r.scopedPath(realPath) {
		return fmt.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)
	}

	if err := removePath(realPath); err != nil {
		return err
	}

	delete(r.volumes, lv.name)
	return removePath(filepath.Dir(lv.path))
}

func removePath(path string) error {
	if err := os.RemoveAll(path); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return errors.Wrapf(err, "error removing volume path '%s'", path)
	}
	return nil
}

// Get looks up the volume for the given name and returns it if found
func (r *Root) Get(name string) (volume.Volume, error) {
	r.m.Lock()
	v, exists := r.volumes[name]
	r.m.Unlock()
	if !exists {
		return nil, ErrNotFound
	}
	return v, nil
}

// Scope returns the local volume scope
func (r *Root) Scope() string {
	return volume.LocalScope
}

func (r *Root) validateName(name string) error {
	if len(name) == 1 {
		return validationError{fmt.Errorf("volume name is too short, names should be at least two alphanumeric characters")}
	}
	if !volumeNameRegex.MatchString(name) {
		return validationError{fmt.Errorf("%q includes invalid characters for a local volume name, only %q are allowed. If you intented to pass host directory use absolute path starting with /", name, utils.RestrictedNameChars)}
	}
	return nil
}

// localVolume implements the Volume interface from the volume package and
// represents the volumes created by Root.
type localVolume struct {
	m sync.Mutex
	// unique name of the volume
	name string
	// path is the path on the host where the data lives
	path string
	// driverName is the name of the driver that created the volume.
	driverName string
	// opts is the parsed list of options used to create the volume
	opts *optsConfig
	// active refcounts the active mounts
	active activeMount
}

// Name returns the name of the given Volume.
func (v *localVolume) Name() string {
	return v.name
}

// DriverName returns the driver that created the given Volume.
func (v *localVolume) DriverName() string {
	return v.driverName
}

// Path returns the data location.
func (v *localVolume) Path() string {
	return v.path
}

// Mount implements the localVolume interface, returning the data location.
func (v *localVolume) Mount(id string) (string, error) {
	v.m.Lock()
	defer v.m.Unlock()
	if v.opts != nil {
		if !v.active.mounted {
			if err := v.mount(); err != nil {
				return "", err
			}
			v.active.mounted = true
		}
		v.active.count++
	}
	return v.path, nil
}

// Umount is for satisfying the localVolume interface and does not do anything in this driver.
func (v *localVolume) Unmount(id string) error {
	v.m.Lock()
	defer v.m.Unlock()
	if v.opts != nil {
		v.active.count--
		if v.active.count == 0 {
			if err := mount.Unmount(v.path); err != nil {
				v.active.count++
				return errors.Wrapf(err, "error while unmounting volume path '%s'", v.path)
			}
			v.active.mounted = false
		}
	}
	return nil
}

func validateOpts(opts map[string]string) error {
	for opt := range opts {
		if !validOpts[opt] {
			return validationError{fmt.Errorf("invalid option key: %q", opt)}
		}
	}
	return nil
}

func (v *localVolume) Status() map[string]interface{} {
	return nil
}
<commit_msg>remove "starting with /"<commit_after>// Package local provides the default implementation for volumes. It
// is used to mount data volume containers and directories local to
// the host server.
package local

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sync"

	"github.com/pkg/errors"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/idtools"
	"github.com/docker/docker/pkg/mount"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/volume"
)

// VolumeDataPathName is the name of the directory where the volume data is stored.
// It uses a very distinctive name to avoid collisions migrating data between
// Docker versions.
const (
	VolumeDataPathName = "_data"
	volumesPathName    = "volumes"
)

var (
	// ErrNotFound is the typed error returned when the requested volume name can't be found
	ErrNotFound = fmt.Errorf("volume not found")
	// volumeNameRegex ensures the name assigned for the volume is valid.
	// This name is used to create the bind directory, so we need to avoid characters that
	// would make the path to escape the root directory.
	volumeNameRegex = utils.RestrictedVolumeNamePattern
)

type validationError struct {
	error
}

func (validationError) IsValidationError() bool {
	return true
}

type activeMount struct {
	count   uint64
	mounted bool
}

// New instantiates a new Root instance with the provided scope. Scope
// is the base path that the Root instance uses to store its
// volumes. The base path is created here if it does not exist.
func New(scope string, rootUID, rootGID int) (*Root, error) {
	rootDirectory := filepath.Join(scope, volumesPathName)

	if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil {
		return nil, err
	}

	r := &Root{
		scope:   scope,
		path:    rootDirectory,
		volumes: make(map[string]*localVolume),
		rootUID: rootUID,
		rootGID: rootGID,
	}

	dirs, err := ioutil.ReadDir(rootDirectory)
	if err != nil {
		return nil, err
	}

	mountInfos, err := mount.GetMounts()
	if err != nil {
		logrus.Debugf("error looking up mounts for local volume cleanup: %v", err)
	}

	for _, d := range dirs {
		if !d.IsDir() {
			continue
		}

		name := filepath.Base(d.Name())
		v := &localVolume{
			driverName: r.Name(),
			name:       name,
			path:       r.DataPath(name),
		}
		r.volumes[name] = v
		optsFilePath := filepath.Join(rootDirectory, name, "opts.json")
		if b, err := ioutil.ReadFile(optsFilePath); err == nil {
			opts := optsConfig{}
			if err := json.Unmarshal(b, &opts); err != nil {
				return nil, errors.Wrapf(err, "error while unmarshaling volume options for volume: %s", name)
			}
			// Make sure this isn't an empty optsConfig.
			// This could be empty due to buggy behavior in older versions of Docker.
			if !reflect.DeepEqual(opts, optsConfig{}) {
				v.opts = &opts
			}

			// unmount anything that may still be mounted (for example, from an unclean shutdown)
			for _, info := range mountInfos {
				if info.Mountpoint == v.path {
					mount.Unmount(v.path)
					break
				}
			}
		}
	}

	return r, nil
}

// Root implements the Driver interface for the volume package and
// manages the creation/removal of volumes. It uses only standard vfs
// commands to create/remove dirs within its provided scope.
type Root struct {
	m       sync.Mutex
	scope   string
	path    string
	volumes map[string]*localVolume
	rootUID int
	rootGID int
}

// List lists all the volumes
func (r *Root) List() ([]volume.Volume, error) {
	var ls []volume.Volume
	r.m.Lock()
	for _, v := range r.volumes {
		ls = append(ls, v)
	}
	r.m.Unlock()
	return ls, nil
}

// DataPath returns the constructed path of this volume.
func (r *Root) DataPath(volumeName string) string {
	return filepath.Join(r.path, volumeName, VolumeDataPathName)
}

// Name returns the name of Root, defined in the volume package in the DefaultDriverName constant.
func (r *Root) Name() string {
	return volume.DefaultDriverName
}

// Create creates a new volume.Volume with the provided name, creating
// the underlying directory tree required for this volume in the
// process.
func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error) {
	if err := r.validateName(name); err != nil {
		return nil, err
	}

	r.m.Lock()
	defer r.m.Unlock()

	v, exists := r.volumes[name]
	if exists {
		return v, nil
	}

	path := r.DataPath(name)
	if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil {
		if os.IsExist(err) {
			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
		}
		return nil, errors.Wrapf(err, "error while creating volume path '%s'", path)
	}

	var err error
	defer func() {
		if err != nil {
			os.RemoveAll(filepath.Dir(path))
		}
	}()

	v = &localVolume{
		driverName: r.Name(),
		name:       name,
		path:       path,
	}

	if len(opts) != 0 {
		if err = setOpts(v, opts); err != nil {
			return nil, err
		}
		var b []byte
		b, err = json.Marshal(v.opts)
		if err != nil {
			return nil, err
		}
		if err = ioutil.WriteFile(filepath.Join(filepath.Dir(path), "opts.json"), b, 600); err != nil {
			return nil, errors.Wrap(err, "error while persisting volume options")
		}
	}

	r.volumes[name] = v
	return v, nil
}

// Remove removes the specified volume and all underlying data. If the
// given volume does not belong to this driver and an error is
// returned. The volume is reference counted, if all references are
// not released then the volume is not removed.
func (r *Root) Remove(v volume.Volume) error {
	r.m.Lock()
	defer r.m.Unlock()

	lv, ok := v.(*localVolume)
	if !ok {
		return fmt.Errorf("unknown volume type %T", v)
	}

	realPath, err := filepath.EvalSymlinks(lv.path)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		realPath = filepath.Dir(lv.path)
	}

	if !r.scopedPath(realPath) {
		return fmt.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)
	}

	if err := removePath(realPath); err != nil {
		return err
	}

	delete(r.volumes, lv.name)
	return removePath(filepath.Dir(lv.path))
}

func removePath(path string) error {
	if err := os.RemoveAll(path); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return errors.Wrapf(err, "error removing volume path '%s'", path)
	}
	return nil
}

// Get looks up the volume for the given name and returns it if found
func (r *Root) Get(name string) (volume.Volume, error) {
	r.m.Lock()
	v, exists := r.volumes[name]
	r.m.Unlock()
	if !exists {
		return nil, ErrNotFound
	}
	return v, nil
}

// Scope returns the local volume scope
func (r *Root) Scope() string {
	return volume.LocalScope
}

func (r *Root) validateName(name string) error {
	if len(name) == 1 {
		return validationError{fmt.Errorf("volume name is too short, names should be at least two alphanumeric characters")}
	}
	if !volumeNameRegex.MatchString(name) {
		return validationError{fmt.Errorf("%q includes invalid characters for a local volume name, only %q are allowed. If you intented to pass a host directory, use absolute path.", name, utils.RestrictedNameChars)}
	}
	return nil
}

// localVolume implements the Volume interface from the volume package and
// represents the volumes created by Root.
type localVolume struct {
	m sync.Mutex
	// unique name of the volume
	name string
	// path is the path on the host where the data lives
	path string
	// driverName is the name of the driver that created the volume.
	driverName string
	// opts is the parsed list of options used to create the volume
	opts *optsConfig
	// active refcounts the active mounts
	active activeMount
}

// Name returns the name of the given Volume.
func (v *localVolume) Name() string {
	return v.name
}

// DriverName returns the driver that created the given Volume.
func (v *localVolume) DriverName() string {
	return v.driverName
}

// Path returns the data location.
func (v *localVolume) Path() string {
	return v.path
}

// Mount implements the localVolume interface, returning the data location.
func (v *localVolume) Mount(id string) (string, error) {
	v.m.Lock()
	defer v.m.Unlock()
	if v.opts != nil {
		if !v.active.mounted {
			if err := v.mount(); err != nil {
				return "", err
			}
			v.active.mounted = true
		}
		v.active.count++
	}
	return v.path, nil
}

// Umount is for satisfying the localVolume interface and does not do anything in this driver.
func (v *localVolume) Unmount(id string) error {
	v.m.Lock()
	defer v.m.Unlock()
	if v.opts != nil {
		v.active.count--
		if v.active.count == 0 {
			if err := mount.Unmount(v.path); err != nil {
				v.active.count++
				return errors.Wrapf(err, "error while unmounting volume path '%s'", v.path)
			}
			v.active.mounted = false
		}
	}
	return nil
}

func validateOpts(opts map[string]string) error {
	for opt := range opts {
		if !validOpts[opt] {
			return validationError{fmt.Errorf("invalid option key: %q", opt)}
		}
	}
	return nil
}

func (v *localVolume) Status() map[string]interface{} {
	return nil
}
<|endoftext|>


<commit_before>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "encoding/json"
  "strings"
  "strconv"
  "reflect"
)

type SetConfigCommand struct {
}

func (c *SetConfigCommand) Name() string {
  return "SetConfig";
}
func (c *SetConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  if len(args) < 1 {
    return "```No configuration parameter to look for!```", false
  }
  if len(args) < 2 {
    return "```No value to set!```", false
  }
  n, ok := info.SetConfig(args[0], args[1], args[2:]...)
  info.SaveConfig()
  if ok {
    return "```Successfully set " + args[0] + " to " + n + ".```", false
  }
  return "```" + n + "```", false
}
func (c *SetConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "[config parameter] [value]", "Attempts to set the configuration value matching [config parameter] (not case-sensitive) to [value]. Will only save the new configuration if it succeeds, and returns the new value upon success.")
}
func (c *SetConfigCommand) UsageShort() string { return "Sets a config value and saves the new configuration." }

type GetConfigCommand struct {
}

func (c *GetConfigCommand) Name() string {
  return "GetConfig";
}
func (c *GetConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  t := reflect.ValueOf(&info.config).Elem()
  n := t.NumField()
  if len(args) < 1 {
    s := make([]string, 0, n)
    for i := 0; i < n; i++ {
      s = append(s, strings.ToLower(t.Type().Field(i).Name))
    }
    return "```Choose a config option to display:\n" + strings.Join(s, "\n") + "```", false
  }
  arg := args[0]
  for i := 0; i < n; i++ {
    if strings.ToLower(t.Type().Field(i).Name) == arg {
      data, err := json.Marshal(t.Field(i).Interface())
      s := string(data);
      s = strings.Replace(s,"`","",-1)
      s = strings.Replace(s, "[](/", "[\u200B](/", -1)
      s = strings.Replace(s, "http://", "http\u200B://", -1)
      s = strings.Replace(s, "https://", "https\u200B://", -1)
      if err == nil {
        return "```" + s + "```", false
      }
      info.log.Log("JSON error: ", err.Error())
      return "```Failed to marshal JSON :C```", false
    }
  }

  return "```That's not a recognized config option! Type !getconfig without any arguments to list all possible config options```", false
}
func (c *GetConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "", "Returns the current configuration as a JSON string.")
}
func (c *GetConfigCommand) UsageShort() string { return "Returns the current configuration." }

type QuickConfigCommand struct {
}

func (c *QuickConfigCommand) Name() string {
  return "QuickConfig";
}
func (c *QuickConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  if msg.Author.ID != info.Guild.OwnerID {
    return "```Only the owner of this server can use this command!```", false
  }
  if len(args) < 5 {
    return "```You must provide all 5 parameters to this function. Carefully review each one and make sure it is accurate.```", false
  }

  log := StripPing(args[0])
  mod := StripPing(args[1])
  modchannel := StripPing(args[2])
  free := StripPing(args[3])
  silent := StripPing(args[4])

  info.config.LogChannel = SBatoi(log)
  info.config.AlertRole = SBatoi(mod)
  info.config.ModChannel = SBatoi(modchannel)
  info.config.FreeChannels = make(map[string]bool)
  info.config.FreeChannels[strconv.FormatUint(SBatoi(free), 10)] = true
  info.config.SilentRole = SBatoi(silent)

  sensitive := []string { "add", "addgroup", "addwit", "ban", "disable", "dumptables", "echo", "enable", "getconfig", "purgegroup", "remove", "removewit", "setconfig", "setstatus", "update", "announce" }
  modint := strconv.FormatUint(info.config.AlertRole, 10)

  for _, v := range sensitive {
    info.config.Command_roles[v] = make(map[string]bool)
    info.config.Command_roles[v][modint] = true
  }

  info.config.Command_disabled = make(map[string]bool)
  info.config.Module_disabled = make(map[string]bool)
  info.SaveConfig()
  return "```Server configured! \nLog Channel: " + log + "\nModerator Role: " + mod + "\nMod Channel: " + modchannel + "\nFree Channel: " + free + "\nSilent Role: " + silent + "```", false
}
func (c *QuickConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "[Log Channel] [Moderator Role] [Mod Channel] [Free Channel] [Silent Role]", "Quickly performs basic configuration on the server and restricts all sensitive commands to [Moderator Role], then enables all commands and all modules.")
}
func (c *QuickConfigCommand) UsageShort() string { return "Quickly performs basic configuration." }
<commit_msg>have quickconfig set bored channel<commit_after>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "encoding/json"
  "strings"
  "strconv"
  "reflect"
)

type SetConfigCommand struct {
}

func (c *SetConfigCommand) Name() string {
  return "SetConfig";
}
func (c *SetConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  if len(args) < 1 {
    return "```No configuration parameter to look for!```", false
  }
  if len(args) < 2 {
    return "```No value to set!```", false
  }
  n, ok := info.SetConfig(args[0], args[1], args[2:]...)
  info.SaveConfig()
  if ok {
    return "```Successfully set " + args[0] + " to " + n + ".```", false
  }
  return "```" + n + "```", false
}
func (c *SetConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "[config parameter] [value]", "Attempts to set the configuration value matching [config parameter] (not case-sensitive) to [value]. Will only save the new configuration if it succeeds, and returns the new value upon success.")
}
func (c *SetConfigCommand) UsageShort() string { return "Sets a config value and saves the new configuration." }

type GetConfigCommand struct {
}

func (c *GetConfigCommand) Name() string {
  return "GetConfig";
}
func (c *GetConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  t := reflect.ValueOf(&info.config).Elem()
  n := t.NumField()
  if len(args) < 1 {
    s := make([]string, 0, n)
    for i := 0; i < n; i++ {
      s = append(s, strings.ToLower(t.Type().Field(i).Name))
    }
    return "```Choose a config option to display:\n" + strings.Join(s, "\n") + "```", false
  }
  arg := args[0]
  for i := 0; i < n; i++ {
    if strings.ToLower(t.Type().Field(i).Name) == arg {
      data, err := json.Marshal(t.Field(i).Interface())
      s := string(data);
      s = strings.Replace(s,"`","",-1)
      s = strings.Replace(s, "[](/", "[\u200B](/", -1)
      s = strings.Replace(s, "http://", "http\u200B://", -1)
      s = strings.Replace(s, "https://", "https\u200B://", -1)
      if err == nil {
        return "```" + s + "```", false
      }
      info.log.Log("JSON error: ", err.Error())
      return "```Failed to marshal JSON :C```", false
    }
  }

  return "```That's not a recognized config option! Type !getconfig without any arguments to list all possible config options```", false
}
func (c *GetConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "", "Returns the current configuration as a JSON string.")
}
func (c *GetConfigCommand) UsageShort() string { return "Returns the current configuration." }

type QuickConfigCommand struct {
}

func (c *QuickConfigCommand) Name() string {
  return "QuickConfig";
}
func (c *QuickConfigCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
  if msg.Author.ID != info.Guild.OwnerID {
    return "```Only the owner of this server can use this command!```", false
  }
  if len(args) < 5 {
    return "```You must provide all 6 parameters to this function. Carefully review each one and make sure it is accurate.```", false
  }

  log := StripPing(args[0])
  mod := StripPing(args[1])
  modchannel := StripPing(args[2])
  free := StripPing(args[3])
  silent := StripPing(args[4])
  boredchannel := StripPing(args[5])

  info.config.LogChannel = SBatoi(log)
  info.config.AlertRole = SBatoi(mod)
  info.config.ModChannel = SBatoi(modchannel)
  info.config.FreeChannels = make(map[string]bool)
  info.config.FreeChannels[strconv.FormatUint(SBatoi(free), 10)] = true

  sensitive := []string { "add", "addgroup", "addwit", "ban", "disable", "dumptables", "echo", "enable", "getconfig", "purgegroup", "remove", "removewit", "setconfig", "setstatus", "update", "announce" }
  modint := strconv.FormatUint(info.config.AlertRole, 10)

  for _, v := range sensitive {
    info.config.Command_roles[v] = make(map[string]bool)
    info.config.Command_roles[v][modint] = true
  }

  info.config.Command_disabled = make(map[string]bool)
  info.config.Module_disabled = make(map[string]bool)

  silentint := SBatoi(silent)
  if silentint > 0 {
    info.config.Module_channels["bored"] = map[string]bool { strconv.FormatUint(silentint, 10) : true }
  } else {
    info.config.Module_disabled["bored"] = true
  }

  info.SaveConfig()
  return "```Server configured! \nLog Channel: " + log + "\nModerator Role: " + mod + "\nMod Channel: " + modchannel + "\nFree Channel: " + free + "\nSilent Role: " + silent + "```", false
}
func (c *QuickConfigCommand) Usage(info *GuildInfo) string {
  return info.FormatUsage(c, "[Log Channel] [Moderator Role] [Mod Channel] [Free Channel] [Silent Role] [Bored Channel]", "Quickly performs basic configuration on the server and restricts all sensitive commands to [Moderator Role], then enables all commands and all modules. If [bored channel] is not zero, it restricts the bored module to that channel. Otherwise it disables the bored module to prevent the bot from spamming inactive channels.")
}
func (c *QuickConfigCommand) UsageShort() string { return "Quickly performs basic configuration." }
<|endoftext|>


<commit_before>package funcs

import (
	"github.com/freedomkk-qfeng/sw"
	"github.com/freedomkk-qfeng/swcollector/g"
	"github.com/open-falcon/common/model"
	"log"
	"time"
)

type SwConn struct {
	Ip       string
	ConnectionStat int
}

func ConnMetrics() (L []*model.MetricValue) {

	chs := make([]chan SwConn, len(AliveIp))
	for i, ip := range AliveIp {
		if ip != "" {
			chs[i] = make(chan SwConn)
			go connMetrics(ip, chs[i])
		}
	}

	for _, ch := range chs {
		swConn := <-ch
		L = append(L, GaugeValueIp(time.Now().Unix(), swConn.Ip, "switch.ConnectionStat", swConn.ConnectionStat))
	}

	return L
}

func connMetrics(ip string, ch chan SwConn) {
	var swConn SwConn
	vendor, _ := sw.SysVendor(ip, community, snmpTimeout)
	if vendor != "Cisco_ASA"{
		return
	}
	ConnectionStat, err := sw.ConnectionStat(ip, g.Config().Switch.Community, g.Config().Switch.SnmpTimeout, g.Config().Switch.SnmpRetry)
	if err != nil {
		log.Println(err)
	}

	swConn.Ip = ip
	swConn.ConnectionStat = ConnectionStat
	ch <- swConn

	return
}
<commit_msg>fix bug<commit_after>package funcs

import (
	"github.com/freedomkk-qfeng/sw"
	"github.com/freedomkk-qfeng/swcollector/g"
	"github.com/open-falcon/common/model"
	"log"
	"time"
)

type SwConn struct {
	Ip       string
	ConnectionStat int
}

func ConnMetrics() (L []*model.MetricValue) {

	chs := make([]chan SwConn, len(AliveIp))
	for i, ip := range AliveIp {
		if ip != "" {
			chs[i] = make(chan SwConn)
			go connMetrics(ip, chs[i])
		}
	}

	for _, ch := range chs {
		swConn := <-ch
		L = append(L, GaugeValueIp(time.Now().Unix(), swConn.Ip, "switch.ConnectionStat", swConn.ConnectionStat))
	}

	return L
}

func connMetrics(ip string, ch chan SwConn) {
	var swConn SwConn
	vendor, _ := sw.SysVendor(ip, community, snmpTimeout)
	if vendor != "Cisco_ASA"{
		ch <- swConn
		return
	}
	ConnectionStat, err := sw.ConnectionStat(ip, g.Config().Switch.Community, g.Config().Switch.SnmpTimeout, g.Config().Switch.SnmpRetry)
	if err != nil {
		log.Println(err)
	}

	swConn.Ip = ip
	swConn.ConnectionStat = ConnectionStat
	ch <- swConn

	return
}
<|endoftext|>


<commit_before>package geojson

import (
	"bytes"
	"strconv"

	"github.com/tidwall/tile38/geojson/geo"
	"github.com/tidwall/tile38/geojson/poly"
)

// BBox is a bounding box
type BBox struct {
	Min Position
	Max Position
}

// New2DBBox creates a new bounding box
func New2DBBox(minX, minY, maxX, maxY float64) BBox {
	return BBox{Min: Position{X: minX, Y: minY, Z: 0}, Max: Position{X: maxX, Y: maxY, Z: 0}}
}

func fillBBox(m map[string]interface{}) (*BBox, error) {
	var bbox *BBox
	var ok bool
	switch v := m["bbox"].(type) {
	default:
		return nil, errBBoxInvalidType
	case nil:
	case []interface{}:
		if !(len(v) == 4 || len(v) == 6) {
			return nil, errBBoxInvalidNumberOfValues
		}
		bbox = &BBox{}
		if bbox.Min.X, ok = v[0].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if bbox.Min.Y, ok = v[1].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		i := 2
		if len(v) == 6 {
			if bbox.Min.Z, ok = v[2].(float64); !ok {
				return nil, errBBoxInvalidValue
			}
			i = 3
		} else {
			bbox.Min.Z = nilz
		}
		if bbox.Max.X, ok = v[i+0].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if bbox.Max.Y, ok = v[i+1].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if len(v) == 6 {
			if bbox.Max.Z, ok = v[i+2].(float64); !ok {
				return nil, errBBoxInvalidValue
			}
		} else {
			bbox.Max.Z = nilz
		}
	}
	return bbox, nil
}

func (b *BBox) isCordZDefined() bool {
	return b != nil && (b.Min.Z != nilz || b.Max.Z != nilz)
}

func (b *BBox) write(buf *bytes.Buffer) {
	if b == nil {
		return
	}
	hasZ := b.Min.Z != nilz && b.Max.Z != nilz
	buf.WriteString(`,"bbox":[`)
	buf.WriteString(strconv.FormatFloat(b.Min.X, 'f', -1, 64))
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Min.Y, 'f', -1, 64))
	if hasZ {
		buf.WriteByte(',')
		buf.WriteString(strconv.FormatFloat(b.Min.Z, 'f', -1, 64))
	}
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Max.X, 'f', -1, 64))
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Max.Y, 'f', -1, 64))
	if hasZ {
		buf.WriteByte(',')
		buf.WriteString(strconv.FormatFloat(b.Max.Z, 'f', -1, 64))
	}
	buf.WriteByte(']')
}

func (b BBox) center() Position {
	return Position{
		(b.Max.X-b.Min.X)/2 + b.Min.X,
		(b.Max.Y-b.Min.Y)/2 + b.Min.Y,
		0,
	}
}

func (b BBox) union(bbox BBox) BBox {
	if bbox.Min.X < b.Min.X {
		b.Min.X = bbox.Min.X
	}
	if bbox.Min.Y < b.Min.Y {
		b.Min.Y = bbox.Min.Y
	}
	if bbox.Max.X > b.Max.X {
		b.Max.X = bbox.Max.X
	}
	if bbox.Max.Y > b.Max.Y {
		b.Max.Y = bbox.Max.Y
	}
	return b
}

func (b BBox) exterior() []Position {
	return []Position{
		{b.Min.X, b.Min.Y, 0},
		{b.Min.X, b.Max.Y, 0},
		{b.Max.X, b.Max.Y, 0},
		{b.Max.X, b.Min.Y, 0},
		{b.Min.X, b.Min.Y, 0},
	}
}

func rectBBox(bbox BBox) poly.Rect {
	return poly.Rect{
		Min: poly.Point{X: bbox.Min.X, Y: bbox.Min.Y, Z: 0},
		Max: poly.Point{X: bbox.Max.X, Y: bbox.Max.Y, Z: 0},
	}
}

// ExternalJSON is the simple json representation of the bounding box used for external applications.
func (b BBox) ExternalJSON() string {
	sw, ne := b.Min, b.Max
	sw.Z, ne.Z = 0, 0
	return `{"sw":` + sw.ExternalJSON() + `,"ne":` + ne.ExternalJSON() + `}`
}

// Sparse returns back an evenly distributed number of sub bboxs.
func (b BBox) Sparse(amount byte) []BBox {
	if amount == 0 {
		return []BBox{b}
	}
	var bboxes []BBox
	split := 1 << amount
	var xsize, ysize float64
	if b.Max.X < b.Min.X {
		// crosses the prime meridian
		xsize = (b.Min.X - b.Max.X) / float64(split)
	} else {
		xsize = (b.Max.X - b.Min.X) / float64(split)
	}
	if b.Max.Y < b.Min.Y {
		// crosses the equator
		ysize = (b.Min.Y - b.Max.Y) / float64(split)
	} else {
		ysize = (b.Max.Y - b.Min.Y) / float64(split)
	}

	for y := b.Min.Y; y < b.Max.Y; y += ysize {
		for x := b.Min.X; x < b.Max.X; x += xsize {
			bboxes = append(bboxes, BBox{
				Min: Position{X: x, Y: y, Z: b.Min.Z},
				Max: Position{X: x + xsize, Y: y + ysize, Z: b.Max.Z},
			})
		}
	}
	return bboxes
}

// BBoxesFromCenter calculates the bounding box surrounding a circle.
func BBoxesFromCenter(lat, lon, meters float64) (outer BBox) {
	outer.Max.Y, _ = geo.DestinationPoint(lat, lon, meters, 0)
	outer.Min.Y, _ = geo.DestinationPoint(lat, lon, meters, 180)
	_, outer.Min.X = geo.DestinationPoint(lat, lon, meters, 270)
	_, outer.Max.X = geo.DestinationPoint(lat, lon, meters, 90)
	if outer.Min.X > outer.Max.X {
		outer.Min.X = -(360 - outer.Min.X)
	}
	return outer
}
<commit_msg>Fix incorrect query boundaries when using large radii<commit_after>package geojson

import (
	"bytes"
	"strconv"
	"math"

	"github.com/tidwall/tile38/geojson/poly"
)

// BBox is a bounding box
type BBox struct {
	Min Position
	Max Position
}

// New2DBBox creates a new bounding box
func New2DBBox(minX, minY, maxX, maxY float64) BBox {
	return BBox{Min: Position{X: minX, Y: minY, Z: 0}, Max: Position{X: maxX, Y: maxY, Z: 0}}
}

func fillBBox(m map[string]interface{}) (*BBox, error) {
	var bbox *BBox
	var ok bool
	switch v := m["bbox"].(type) {
	default:
		return nil, errBBoxInvalidType
	case nil:
	case []interface{}:
		if !(len(v) == 4 || len(v) == 6) {
			return nil, errBBoxInvalidNumberOfValues
		}
		bbox = &BBox{}
		if bbox.Min.X, ok = v[0].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if bbox.Min.Y, ok = v[1].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		i := 2
		if len(v) == 6 {
			if bbox.Min.Z, ok = v[2].(float64); !ok {
				return nil, errBBoxInvalidValue
			}
			i = 3
		} else {
			bbox.Min.Z = nilz
		}
		if bbox.Max.X, ok = v[i+0].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if bbox.Max.Y, ok = v[i+1].(float64); !ok {
			return nil, errBBoxInvalidValue
		}
		if len(v) == 6 {
			if bbox.Max.Z, ok = v[i+2].(float64); !ok {
				return nil, errBBoxInvalidValue
			}
		} else {
			bbox.Max.Z = nilz
		}
	}
	return bbox, nil
}

func (b *BBox) isCordZDefined() bool {
	return b != nil && (b.Min.Z != nilz || b.Max.Z != nilz)
}

func (b *BBox) write(buf *bytes.Buffer) {
	if b == nil {
		return
	}
	hasZ := b.Min.Z != nilz && b.Max.Z != nilz
	buf.WriteString(`,"bbox":[`)
	buf.WriteString(strconv.FormatFloat(b.Min.X, 'f', -1, 64))
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Min.Y, 'f', -1, 64))
	if hasZ {
		buf.WriteByte(',')
		buf.WriteString(strconv.FormatFloat(b.Min.Z, 'f', -1, 64))
	}
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Max.X, 'f', -1, 64))
	buf.WriteByte(',')
	buf.WriteString(strconv.FormatFloat(b.Max.Y, 'f', -1, 64))
	if hasZ {
		buf.WriteByte(',')
		buf.WriteString(strconv.FormatFloat(b.Max.Z, 'f', -1, 64))
	}
	buf.WriteByte(']')
}

func (b BBox) center() Position {
	return Position{
		(b.Max.X-b.Min.X)/2 + b.Min.X,
		(b.Max.Y-b.Min.Y)/2 + b.Min.Y,
		0,
	}
}

func (b BBox) union(bbox BBox) BBox {
	if bbox.Min.X < b.Min.X {
		b.Min.X = bbox.Min.X
	}
	if bbox.Min.Y < b.Min.Y {
		b.Min.Y = bbox.Min.Y
	}
	if bbox.Max.X > b.Max.X {
		b.Max.X = bbox.Max.X
	}
	if bbox.Max.Y > b.Max.Y {
		b.Max.Y = bbox.Max.Y
	}
	return b
}

func (b BBox) exterior() []Position {
	return []Position{
		{b.Min.X, b.Min.Y, 0},
		{b.Min.X, b.Max.Y, 0},
		{b.Max.X, b.Max.Y, 0},
		{b.Max.X, b.Min.Y, 0},
		{b.Min.X, b.Min.Y, 0},
	}
}

func rectBBox(bbox BBox) poly.Rect {
	return poly.Rect{
		Min: poly.Point{X: bbox.Min.X, Y: bbox.Min.Y, Z: 0},
		Max: poly.Point{X: bbox.Max.X, Y: bbox.Max.Y, Z: 0},
	}
}

// ExternalJSON is the simple json representation of the bounding box used for external applications.
func (b BBox) ExternalJSON() string {
	sw, ne := b.Min, b.Max
	sw.Z, ne.Z = 0, 0
	return `{"sw":` + sw.ExternalJSON() + `,"ne":` + ne.ExternalJSON() + `}`
}

// Sparse returns back an evenly distributed number of sub bboxs.
func (b BBox) Sparse(amount byte) []BBox {
	if amount == 0 {
		return []BBox{b}
	}
	var bboxes []BBox
	split := 1 << amount
	var xsize, ysize float64
	if b.Max.X < b.Min.X {
		// crosses the prime meridian
		xsize = (b.Min.X - b.Max.X) / float64(split)
	} else {
		xsize = (b.Max.X - b.Min.X) / float64(split)
	}
	if b.Max.Y < b.Min.Y {
		// crosses the equator
		ysize = (b.Min.Y - b.Max.Y) / float64(split)
	} else {
		ysize = (b.Max.Y - b.Min.Y) / float64(split)
	}

	for y := b.Min.Y; y < b.Max.Y; y += ysize {
		for x := b.Min.X; x < b.Max.X; x += xsize {
			bboxes = append(bboxes, BBox{
				Min: Position{X: x, Y: y, Z: b.Min.Z},
				Max: Position{X: x + xsize, Y: y + ysize, Z: b.Max.Z},
			})
		}
	}
	return bboxes
}

// BBoxesFromCenter calculates the bounding box surrounding a circle.
func BBoxesFromCenter(lat, lon, meters float64) (outer BBox) {

	outer.Min.Y, outer.Min.X, outer.Max.Y, outer.Max.X = BBoxBounds(lat, lon, meters)
	if outer.Min.X == outer.Max.X {
		switch outer.Min.X {
		case -180:
			outer.Max.X = 180
		case 180:
			outer.Min.X = -180
		}
	}

	return outer
}

func BBoxBounds(lat, lon, meters float64) (float64, float64, float64, float64) {

	// see http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#Latitude
	r := meters / earthRadius // angular radius

	φ1 := toRadians(lat)
	λ1 := toRadians(lon)

	latMin := φ1 - r
	latMax := φ1 + r

	latT   := math.Asin(math.Sin(φ1) / math.Cos(r))
	lonΔ   := math.Acos(( math.Cos(r) - math.Sin(latT) * math.Sin(φ1)) / (math.Cos(latT) * math.Cos(φ1) ))

	lonMin := λ1 - lonΔ
	lonMax := λ1 + lonΔ

	// Adjust for north poll
	if latMax > math.Pi/2 {

		lonMin = -math.Pi

		latMax = math.Pi/2
		lonMax = math.Pi
	}

	// Adjust for south poll
	if latMin < -math.Pi/2 {

		latMin = -math.Pi/2
		lonMin = -math.Pi

		lonMax = math.Pi
	}

	if lonMin < -math.Pi || lonMax > math.Pi {
		lonMin = -math.Pi
		lonMax = math.Pi
	}

/*
	// Consider splitting into two bboxes and using the below checks and erasing above block for performance. See http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#PolesAnd180thMeridian

	if lonMin < -math.Pi {
// box 1:
		latMin = latMin
		latMax = latMax
		lonMin += 2*math.Pi
		lonMax = math.Pi
// box 2:
		latMin = latMin
		latMax = latMax
		lonMin = -math.Pi
		lonMax = lonMax
	}

	if lonMax > math.Pi {
// box 1:
		lonMax = -math.Pi
// box 2:
		lonMin = -math.Pi
		lonMax -= 2*math.Pi
	}
*/

	lonMin = math.Mod(lonMin+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180°
	lonMax = math.Mod(lonMax+3*math.Pi, 2*math.Pi) - math.Pi

	return toDegrees(latMin), toDegrees(lonMin), toDegrees(latMax), toDegrees(lonMax)
}
<|endoftext|>


<commit_before>/*
 Copyright 2018 Padduck, LLC

 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 environments

import (
	"github.com/pufferpanel/pufferd/v2/environments/envs"
	"github.com/pufferpanel/pufferd/v2/environments/impl/lxd"
	"github.com/pufferpanel/pufferd/v2/environments/impl/tty"
)

func loadAdditionalModules(mapping map[string]envs.EnvironmentFactory) {
	mapping["tty"] = tty.EnvironmentFactory{}
	mapping["lxd"] = lxd.EnvironmentFactory{}
}
<commit_msg>And disable lxc so it doesn't hold up 2.0<commit_after>/*
 Copyright 2018 Padduck, LLC

 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 environments

import (
	"github.com/pufferpanel/pufferd/v2/environments/envs"
	"github.com/pufferpanel/pufferd/v2/environments/impl/tty"
)

func loadAdditionalModules(mapping map[string]envs.EnvironmentFactory) {
	mapping["tty"] = tty.EnvironmentFactory{}
	//mapping["lxd"] = lxd.EnvironmentFactory{}
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// +build !race

// Package atomic provides low-level atomic memory primitives
// useful for implementing synchronization algorithms.
//
// These functions require great care to be used correctly.
// Except for special, low-level applications, synchronization is better
// done with channels or the facilities of the sync package.
// Share memory by communicating;
// don't communicate by sharing memory.
//
// The compare-and-swap operation, implemented by the CompareAndSwapT
// functions, is the atomic equivalent of:
//
//	if *addr == old {
//		*addr = new
//		return true
//	}
//	return false
//
// The add operation, implemented by the AddT functions, is the atomic
// equivalent of:
//
//	*addr += delta
//	return *addr
//
// The load and store operations, implemented by the LoadT and StoreT
// functions, are the atomic equivalents of "return *addr" and
// "*addr = val".
//
package atomic

import (
	"unsafe"
)

// BUG(rsc): On ARM, the 64-bit functions use instructions unavailable before ARM 11.
//
// On x86-32, the 64-bit functions use instructions unavailable before the Pentium MMX.

// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)

// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)

// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)

// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)

// AddUint32 atomically adds delta to *addr and returns the new value.
func AddUint32(addr *uint32, delta uint32) (new uint32)

// AddInt64 atomically adds delta to *addr and returns the new value.
func AddInt64(addr *int64, delta int64) (new int64)

// AddUint64 atomically adds delta to *addr and returns the new value.
func AddUint64(addr *uint64, delta uint64) (new uint64)

// AddUintptr atomically adds delta to *addr and returns the new value.
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)

// LoadInt64 atomically loads *addr.
func LoadInt64(addr *int64) (val int64)

// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)

// LoadUint64 atomically loads *addr.
func LoadUint64(addr *uint64) (val uint64)

// LoadUintptr atomically loads *addr.
func LoadUintptr(addr *uintptr) (val uintptr)

// LoadPointer atomically loads *addr.
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)

// StoreInt64 atomically stores val into *addr.
func StoreInt64(addr *int64, val int64)

// StoreUint32 atomically stores val into *addr.
func StoreUint32(addr *uint32, val uint32)

// StoreUint64 atomically stores val into *addr.
func StoreUint64(addr *uint64, val uint64)

// StoreUintptr atomically stores val into *addr.
func StoreUintptr(addr *uintptr, val uintptr)

// StorePointer atomically stores val into *addr.
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

// Helper for ARM.  Linker will discard on other systems
func panic64() {
	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
}
<commit_msg>sync/atomic: document that users must deal with 64-bit alignment<commit_after>// Copyright 2011 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.

// +build !race

// Package atomic provides low-level atomic memory primitives
// useful for implementing synchronization algorithms.
//
// These functions require great care to be used correctly.
// Except for special, low-level applications, synchronization is better
// done with channels or the facilities of the sync package.
// Share memory by communicating;
// don't communicate by sharing memory.
//
// The compare-and-swap operation, implemented by the CompareAndSwapT
// functions, is the atomic equivalent of:
//
//	if *addr == old {
//		*addr = new
//		return true
//	}
//	return false
//
// The add operation, implemented by the AddT functions, is the atomic
// equivalent of:
//
//	*addr += delta
//	return *addr
//
// The load and store operations, implemented by the LoadT and StoreT
// functions, are the atomic equivalents of "return *addr" and
// "*addr = val".
//
package atomic

import (
	"unsafe"
)

// BUG(rsc): On x86-32, the 64-bit functions use instructions unavailable before the Pentium MMX.
//
// On both ARM and x86-32, it is the caller's responsibility to arrange for 64-bit
// alignment of 64-bit words accessed atomically. The first word in a global
// variable or in an allocated struct or slice can be relied upon to be
// 64-bit aligned.

// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)

// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)

// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)

// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)

// AddUint32 atomically adds delta to *addr and returns the new value.
func AddUint32(addr *uint32, delta uint32) (new uint32)

// AddInt64 atomically adds delta to *addr and returns the new value.
func AddInt64(addr *int64, delta int64) (new int64)

// AddUint64 atomically adds delta to *addr and returns the new value.
func AddUint64(addr *uint64, delta uint64) (new uint64)

// AddUintptr atomically adds delta to *addr and returns the new value.
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)

// LoadInt64 atomically loads *addr.
func LoadInt64(addr *int64) (val int64)

// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)

// LoadUint64 atomically loads *addr.
func LoadUint64(addr *uint64) (val uint64)

// LoadUintptr atomically loads *addr.
func LoadUintptr(addr *uintptr) (val uintptr)

// LoadPointer atomically loads *addr.
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)

// StoreInt64 atomically stores val into *addr.
func StoreInt64(addr *int64, val int64)

// StoreUint32 atomically stores val into *addr.
func StoreUint32(addr *uint32, val uint32)

// StoreUint64 atomically stores val into *addr.
func StoreUint64(addr *uint64, val uint64)

// StoreUintptr atomically stores val into *addr.
func StoreUintptr(addr *uintptr, val uintptr)

// StorePointer atomically stores val into *addr.
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

// Helper for ARM.  Linker will discard on other systems
func panic64() {
	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// +build !race

// Package atomic provides low-level atomic memory primitives
// useful for implementing synchronization algorithms.
//
// These functions require great care to be used correctly.
// Except for special, low-level applications, synchronization is better
// done with channels or the facilities of the sync package.
// Share memory by communicating;
// don't communicate by sharing memory.
//
// The swap operation, implemented by the SwapT functions, is the atomic
// equivalent of:
//
//	old = *addr
//	*addr = new
//	return old
//
// The compare-and-swap operation, implemented by the CompareAndSwapT
// functions, is the atomic equivalent of:
//
//	if *addr == old {
//		*addr = new
//		return true
//	}
//	return false
//
// The add operation, implemented by the AddT functions, is the atomic
// equivalent of:
//
//	*addr += delta
//	return *addr
//
// The load and store operations, implemented by the LoadT and StoreT
// functions, are the atomic equivalents of "return *addr" and
// "*addr = val".
//
package atomic

import (
	"unsafe"
)

// BUG(rsc): On x86-32, the 64-bit functions use instructions unavailable before the Pentium MMX.
//
// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.
//
// On both ARM and x86-32, it is the caller's responsibility to arrange for 64-bit
// alignment of 64-bit words accessed atomically. The first word in a global
// variable or in an allocated struct or slice can be relied upon to be
// 64-bit aligned.

// SwapInt32 atomically stores new into *addr and returns the previous *addr value.
func SwapInt32(addr *int32, new int32) (old int32)

// SwapInt64 atomically stores new into *addr and returns the previous *addr value.
func SwapInt64(addr *int64, new int64) (old int64)

// SwapUint32 atomically stores new into *addr and returns the previous *addr value.
func SwapUint32(addr *uint32, new uint32) (old uint32)

// SwapUint64 atomically stores new into *addr and returns the previous *addr value.
func SwapUint64(addr *uint64, new uint64) (old uint64)

// SwapUintptr atomically stores new into *addr and returns the previous *addr value.
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)

// SwapPointer atomically stores new into *addr and returns the previous *addr value.
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)

// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)

// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)

// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)

// AddUint32 atomically adds delta to *addr and returns the new value.
func AddUint32(addr *uint32, delta uint32) (new uint32)

// AddInt64 atomically adds delta to *addr and returns the new value.
func AddInt64(addr *int64, delta int64) (new int64)

// AddUint64 atomically adds delta to *addr and returns the new value.
func AddUint64(addr *uint64, delta uint64) (new uint64)

// AddUintptr atomically adds delta to *addr and returns the new value.
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)

// LoadInt64 atomically loads *addr.
func LoadInt64(addr *int64) (val int64)

// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)

// LoadUint64 atomically loads *addr.
func LoadUint64(addr *uint64) (val uint64)

// LoadUintptr atomically loads *addr.
func LoadUintptr(addr *uintptr) (val uintptr)

// LoadPointer atomically loads *addr.
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)

// StoreInt64 atomically stores val into *addr.
func StoreInt64(addr *int64, val int64)

// StoreUint32 atomically stores val into *addr.
func StoreUint32(addr *uint32, val uint32)

// StoreUint64 atomically stores val into *addr.
func StoreUint64(addr *uint64, val uint64)

// StoreUintptr atomically stores val into *addr.
func StoreUintptr(addr *uintptr, val uintptr)

// StorePointer atomically stores val into *addr.
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

// Helper for ARM.  Linker will discard on other systems
func panic64() {
	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
}
<commit_msg>sync/atomic: explain how to subtract an unsigned constant Explain for those unfamiliar with twos-complement arithmetic how to implement negation of signed positive constant. Fixes issue 6408.<commit_after>// Copyright 2011 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.

// +build !race

// Package atomic provides low-level atomic memory primitives
// useful for implementing synchronization algorithms.
//
// These functions require great care to be used correctly.
// Except for special, low-level applications, synchronization is better
// done with channels or the facilities of the sync package.
// Share memory by communicating;
// don't communicate by sharing memory.
//
// The swap operation, implemented by the SwapT functions, is the atomic
// equivalent of:
//
//	old = *addr
//	*addr = new
//	return old
//
// The compare-and-swap operation, implemented by the CompareAndSwapT
// functions, is the atomic equivalent of:
//
//	if *addr == old {
//		*addr = new
//		return true
//	}
//	return false
//
// The add operation, implemented by the AddT functions, is the atomic
// equivalent of:
//
//	*addr += delta
//	return *addr
//
// The load and store operations, implemented by the LoadT and StoreT
// functions, are the atomic equivalents of "return *addr" and
// "*addr = val".
//
package atomic

import (
	"unsafe"
)

// BUG(rsc): On x86-32, the 64-bit functions use instructions unavailable before the Pentium MMX.
//
// On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.
//
// On both ARM and x86-32, it is the caller's responsibility to arrange for 64-bit
// alignment of 64-bit words accessed atomically. The first word in a global
// variable or in an allocated struct or slice can be relied upon to be
// 64-bit aligned.

// SwapInt32 atomically stores new into *addr and returns the previous *addr value.
func SwapInt32(addr *int32, new int32) (old int32)

// SwapInt64 atomically stores new into *addr and returns the previous *addr value.
func SwapInt64(addr *int64, new int64) (old int64)

// SwapUint32 atomically stores new into *addr and returns the previous *addr value.
func SwapUint32(addr *uint32, new uint32) (old uint32)

// SwapUint64 atomically stores new into *addr and returns the previous *addr value.
func SwapUint64(addr *uint64, new uint64) (old uint64)

// SwapUintptr atomically stores new into *addr and returns the previous *addr value.
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)

// SwapPointer atomically stores new into *addr and returns the previous *addr value.
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)

// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)

// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)

// CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

// CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)

// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)

// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)

// AddInt32 atomically adds delta to *addr and returns the new value.
func AddInt32(addr *int32, delta int32) (new int32)

// AddUint32 atomically adds delta to *addr and returns the new value.
// To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)).
// In particular, to decrement x, do AddUint32(&x, ^uint32(0)).
func AddUint32(addr *uint32, delta uint32) (new uint32)

// AddInt64 atomically adds delta to *addr and returns the new value.
func AddInt64(addr *int64, delta int64) (new int64)

// AddUint64 atomically adds delta to *addr and returns the new value.
// To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)).
// In particular, to decrement x, do AddUint64(&x, ^uint64(0)).
func AddUint64(addr *uint64, delta uint64) (new uint64)

// AddUintptr atomically adds delta to *addr and returns the new value.
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)

// LoadInt64 atomically loads *addr.
func LoadInt64(addr *int64) (val int64)

// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)

// LoadUint64 atomically loads *addr.
func LoadUint64(addr *uint64) (val uint64)

// LoadUintptr atomically loads *addr.
func LoadUintptr(addr *uintptr) (val uintptr)

// LoadPointer atomically loads *addr.
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)

// StoreInt32 atomically stores val into *addr.
func StoreInt32(addr *int32, val int32)

// StoreInt64 atomically stores val into *addr.
func StoreInt64(addr *int64, val int64)

// StoreUint32 atomically stores val into *addr.
func StoreUint32(addr *uint32, val uint32)

// StoreUint64 atomically stores val into *addr.
func StoreUint64(addr *uint64, val uint64)

// StoreUintptr atomically stores val into *addr.
func StoreUintptr(addr *uintptr, val uintptr)

// StorePointer atomically stores val into *addr.
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)

// Helper for ARM.  Linker will discard on other systems
func panic64() {
	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
}
<|endoftext|>


<commit_before>/* This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>.

@author: UnHa Kim <unha.kim.ghts@gmail.com> */

package shared

import (
	"bytes"
	"fmt"
)

func init() {
	f메모()
}

func f메모() {
	버퍼 := new(bytes.Buffer)
	버퍼.WriteString("에러가 발생했는 데 원인도 모르겠고 막막하다면?\n")
	버퍼.WriteString("1. 문제를 잘게 쪼갠다.\n")
	버퍼.WriteString("2. 문제를 단순화 시킨다. 예:) 테스트 데이터를 1개로 한정.\n")
	버퍼.WriteString("3. 내부 실행과정을 추적한다.\n")
	버퍼.WriteString("디버깅에 이보다 달리 더 좋은 방법은 없다.\n\n")
	버퍼.WriteString("\n")

	버퍼.WriteString("테스트 실행 시 가끔씩 zmq소켓 초기화 에러 발생함.\n")
	버퍼.WriteString("해당 포트가 사용 중이라고 하는 데, 이것을 깨끗하게 정리할 방법은 없는가?\n")

	문자열 := 버퍼.String() + "\n\n"

	fmt.Println(문자열)
}
<commit_msg>tx OpenAPI 중계 호스트 구상 추가.<commit_after>/* This file is part of GHTS.

GHTS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

GHTS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GHTS.  If not, see <http://www.gnu.org/licenses/>.

@author: UnHa Kim <unha.kim.ghts@gmail.com> */

package shared

import (
	"bytes"
	"fmt"
)

func init() {
	f메모()
}

func f메모() {
	버퍼 := new(bytes.Buffer)
	버퍼.WriteString("에러가 발생했는 데 원인도 모르겠고 막막하다면?\n")
	버퍼.WriteString("1. 문제를 잘게 쪼갠다.\n")
	버퍼.WriteString("2. 문제를 단순화 시킨다. 예:) 테스트 데이터를 1개로 한정.\n")
	버퍼.WriteString("3. 내부 실행과정을 추적한다.\n")
	버퍼.WriteString("디버깅에 이보다 달리 더 좋은 방법은 없다.\n\n")
	버퍼.WriteString("\n")

	버퍼.WriteString("테스트 실행 시 가끔씩 zmq소켓 초기화 에러 발생함.\n")
	버퍼.WriteString("해당 포트가 사용 중이라고 하는 데, 이것을 깨끗하게 정리할 방법은 없는가?\n")
	버퍼.WriteString("\n")

	버퍼.WriteString("NH tx OpenAPI(혹은 WMCA SDK)는 Win32 dll 임.\n")
	버퍼.WriteString("64비트 윈도우에서 사용하기 위해서는 Win32 중계 프로그램이 필요함.\n")
	버퍼.WriteString("MsgPack, ZeroMQ를 사용하면 간단히 작성할 수 있을 듯 함.\n")
	버퍼.WriteString("wmcaConnect(), wmcaDisconnect(), wmcaQuery()등 대부분의 함수는 REQ-REP 소켓.\n")
	버퍼.WriteString("wmcaAttach()로 수신하는 실시간 데이터는 PUB-SUB 소켓으로 전달해 주면 됨.\n")
	버퍼.WriteString("문제는 내가 C++ 문외한이라는 것.\n")
	버퍼.WriteString("\n")

	문자열 := 버퍼.String() + "\n\n"

	fmt.Println(문자열)
}
<|endoftext|>


<commit_before>package protocol

import (
	"testing"
	"time"
)

var script = []TimedAction{
	{
		Action{
			Position: 5,
			Speed:    50,
		},
		time.Millisecond * 50,
	},
	{
		Action{
			Position: 50,
			Speed:    40,
		},
		time.Millisecond * 100,
	},
	{
		Action{
			Position: 90,
			Speed:    90,
		},
		time.Millisecond * 150,
	},
	{
		Action{
			Position: 30,
			Speed:    30,
		},
		time.Millisecond * 200,
	},
}

type timeTolerance time.Duration

func (p timeTolerance) roughlyEqual(a time.Duration, b time.Duration) bool {
	if a > b+time.Duration(p) {
		return false
	}
	if a < b-time.Duration(p) {
		return false
	}
	return true
}

var defaultTimeTolerance = timeTolerance(time.Millisecond * 10)

func TestPlay(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	var eventCount int
	starttime := time.Now()
	for a := range p.Play() {
		eventtime := time.Now().Sub(starttime)
		t.Logf("Action: %s: %d,%d", eventtime, a.Position, a.Speed)
		eventCount++
	}
	playTime := time.Now().Sub(starttime)

	if eventCount != len(script) {
		t.Errorf("not all actions were played, want %d, got %d",
			len(script), eventCount)
	}
	want := script[len(script)-1].Time
	if !defaultTimeTolerance.roughlyEqual(playTime, want) {
		t.Errorf("script was not played back at correct speed")
	}
}

func TestPauseResume(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	pauseTime := time.Millisecond * 100

	go func() {
		<-time.After(time.Millisecond * 75)
		if err := p.Pause(); err != nil {
			t.Error(err)
		}
		<-time.After(pauseTime)
		if err := p.Resume(); err != nil {
			t.Error(err)
		}
	}()

	var eventCount int
	starttime := time.Now()
	for range p.Play() {
		eventCount++
	}
	playTime := time.Now().Sub(starttime)

	if eventCount != len(script) {
		t.Errorf("not all actions were played, want %d, got %d",
			len(script), eventCount)
	}
	want := script[len(script)-1].Time + pauseTime
	if !defaultTimeTolerance.roughlyEqual(playTime, want) {
		t.Errorf("script was not played back at correct speed")
	}
}

func TestStop(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	stopTime := time.Millisecond * 75

	go func() {
		<-time.After(stopTime)
		if err := p.Stop(); err != nil {
			t.Error(err)
		}
	}()

	starttime := time.Now()
	for range p.Play() {
		// pass
	}
	playTime := time.Now().Sub(starttime)

	if !defaultTimeTolerance.roughlyEqual(playTime, stopTime) {
		t.Errorf("script was not stopped at the right time, want: %s, got: %s",
			stopTime, playTime)
	}
}

func TestSkip(t *testing.T) {
	cases := []struct {
		Name string
		At   time.Duration
		To   time.Duration
	}{
		{
			Name: "Forward",
			At:   time.Millisecond * 50,
			To:   time.Millisecond * 150,
		},
		{
			Name: "Back",
			At:   time.Millisecond * 50,
			To:   time.Millisecond * 150,
		},
		{
			Name: "Soon",
			At:   time.Millisecond * 0,
			To:   time.Millisecond * 150,
		},
	}

	for _, c := range cases {
		p := NewTimedActionsPlayer()
		p.Script = script

		go func() {
			<-time.After(c.At)
			if err := p.Skip(c.To); err != nil {
				t.Error(err)
			}
		}()

		starttime := time.Now()
		for range p.Play() {
			// pass
		}
		playTime := time.Now().Sub(starttime)
		want := script[len(script)-1].Time - (c.To - c.At)

		if !defaultTimeTolerance.roughlyEqual(playTime, want) {
			t.Errorf("%s: player did not skip correctly, want: %s, got: %s",
				c.Name, want, playTime)
		}
	}
}

func TestLimits(t *testing.T) {
	type TestCase struct {
		Low, High  int
		Slow, Fast int
	}

	cases := []TestCase{
		{0, 100, 0, 0},
		{10, 90, 0, 0},
		{30, 50, 0, 0},
		{50, 90, 0, 0},
		{60, 80, 0, 0},
		{0, 0, 20, 80},
		{0, 0, 30, 60},
		{0, 0, 50, 90},
		{0, 0, 10, 20},
		{0, 0, 0, 50},
		{0, 100, 20, 80},
		{10, 90, 30, 60},
		{30, 50, 50, 90},
		{50, 90, 10, 20},
		{60, 80, 0, 50},
	}
	for i, c := range cases {
		p := NewTimedActionsPlayer()
		p.Script = script
		if c.Low != 0 && c.High != 0 {
			p.LimitPosition(c.Low, c.High)
		}
		if c.Slow != 0 && c.Fast != 0 {
			p.LimitSpeed(c.Slow, c.Fast)
		}

		lowest, highest := c.Low, c.High
		slowest, fastest := c.Slow, c.Fast

		for a := range p.Play() {
			if a.Position < lowest {
				lowest = a.Position
			} else if a.Position > highest {
				highest = a.Position
			}
			if a.Position < slowest {
				slowest = a.Speed
			} else if a.Position > highest {
				fastest = a.Speed
			}
		}

		if c.Low != 0 && c.High != 0 {
			if lowest < c.Low {
				t.Errorf("case %d: went lower than allowed, %d < %d", i, lowest, c.Low)
			}
			if highest > c.High {
				t.Errorf("case %d: went higher than allowed, %d > %d", i, highest, c.High)
			}
		}

		if c.Slow != 0 && c.Fast != 0 {
			if slowest < c.Slow {
				t.Errorf("case %d: went slower than allowed, %d < %d", i, slowest, c.Slow)
			}
			if fastest > c.Fast {
				t.Errorf("case %d: went higher than allowed, %d > %d", i, fastest, c.Fast)
			}
		}

	}
}

func TestDump(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	actions, err := p.Dump()
	if err != nil {
		t.Error(err)
	}
	if len(script) != len(actions) {
		t.Errorf("dump did not return script actions: want %d, got %d",
			len(script), len(actions))
	}
}
<commit_msg>Increase the tolerance even more<commit_after>package protocol

import (
	"testing"
	"time"
)

var script = []TimedAction{
	{
		Action{
			Position: 5,
			Speed:    50,
		},
		time.Millisecond * 50,
	},
	{
		Action{
			Position: 50,
			Speed:    40,
		},
		time.Millisecond * 100,
	},
	{
		Action{
			Position: 90,
			Speed:    90,
		},
		time.Millisecond * 150,
	},
	{
		Action{
			Position: 30,
			Speed:    30,
		},
		time.Millisecond * 200,
	},
}

type timeTolerance time.Duration

func (p timeTolerance) roughlyEqual(a time.Duration, b time.Duration) bool {
	if a > b+time.Duration(p) {
		return false
	}
	if a < b-time.Duration(p) {
		return false
	}
	return true
}

var defaultTimeTolerance = timeTolerance(time.Millisecond * 30)

func TestPlay(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	var eventCount int
	starttime := time.Now()
	for a := range p.Play() {
		eventtime := time.Now().Sub(starttime)
		t.Logf("Action: %s: %d,%d", eventtime, a.Position, a.Speed)
		eventCount++
	}
	playTime := time.Now().Sub(starttime)

	if eventCount != len(script) {
		t.Errorf("not all actions were played, want %d, got %d",
			len(script), eventCount)
	}
	want := script[len(script)-1].Time
	if !defaultTimeTolerance.roughlyEqual(playTime, want) {
		t.Errorf("script was not played back at correct speed")
	}
}

func TestPauseResume(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	pauseTime := time.Millisecond * 100

	go func() {
		<-time.After(time.Millisecond * 75)
		if err := p.Pause(); err != nil {
			t.Error(err)
		}
		<-time.After(pauseTime)
		if err := p.Resume(); err != nil {
			t.Error(err)
		}
	}()

	var eventCount int
	starttime := time.Now()
	for range p.Play() {
		eventCount++
	}
	playTime := time.Now().Sub(starttime)

	if eventCount != len(script) {
		t.Errorf("not all actions were played, want %d, got %d",
			len(script), eventCount)
	}
	want := script[len(script)-1].Time + pauseTime
	if !defaultTimeTolerance.roughlyEqual(playTime, want) {
		t.Errorf("script was not played back at correct speed")
	}
}

func TestStop(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	stopTime := time.Millisecond * 75

	go func() {
		<-time.After(stopTime)
		if err := p.Stop(); err != nil {
			t.Error(err)
		}
	}()

	starttime := time.Now()
	for range p.Play() {
		// pass
	}
	playTime := time.Now().Sub(starttime)

	if !defaultTimeTolerance.roughlyEqual(playTime, stopTime) {
		t.Errorf("script was not stopped at the right time, want: %s, got: %s",
			stopTime, playTime)
	}
}

func TestSkip(t *testing.T) {
	cases := []struct {
		Name string
		At   time.Duration
		To   time.Duration
	}{
		{
			Name: "Forward",
			At:   time.Millisecond * 50,
			To:   time.Millisecond * 150,
		},
		{
			Name: "Back",
			At:   time.Millisecond * 50,
			To:   time.Millisecond * 150,
		},
		{
			Name: "Soon",
			At:   time.Millisecond * 0,
			To:   time.Millisecond * 150,
		},
	}

	for _, c := range cases {
		p := NewTimedActionsPlayer()
		p.Script = script

		go func() {
			<-time.After(c.At)
			if err := p.Skip(c.To); err != nil {
				t.Error(err)
			}
		}()

		starttime := time.Now()
		for range p.Play() {
			// pass
		}
		playTime := time.Now().Sub(starttime)
		want := script[len(script)-1].Time - (c.To - c.At)

		if !defaultTimeTolerance.roughlyEqual(playTime, want) {
			t.Errorf("%s: player did not skip correctly, want: %s, got: %s",
				c.Name, want, playTime)
		}
	}
}

func TestLimits(t *testing.T) {
	type TestCase struct {
		Low, High  int
		Slow, Fast int
	}

	cases := []TestCase{
		{0, 100, 0, 0},
		{10, 90, 0, 0},
		{30, 50, 0, 0},
		{50, 90, 0, 0},
		{60, 80, 0, 0},
		{0, 0, 20, 80},
		{0, 0, 30, 60},
		{0, 0, 50, 90},
		{0, 0, 10, 20},
		{0, 0, 0, 50},
		{0, 100, 20, 80},
		{10, 90, 30, 60},
		{30, 50, 50, 90},
		{50, 90, 10, 20},
		{60, 80, 0, 50},
	}
	for i, c := range cases {
		p := NewTimedActionsPlayer()
		p.Script = script
		if c.Low != 0 && c.High != 0 {
			p.LimitPosition(c.Low, c.High)
		}
		if c.Slow != 0 && c.Fast != 0 {
			p.LimitSpeed(c.Slow, c.Fast)
		}

		lowest, highest := c.Low, c.High
		slowest, fastest := c.Slow, c.Fast

		for a := range p.Play() {
			if a.Position < lowest {
				lowest = a.Position
			} else if a.Position > highest {
				highest = a.Position
			}
			if a.Position < slowest {
				slowest = a.Speed
			} else if a.Position > highest {
				fastest = a.Speed
			}
		}

		if c.Low != 0 && c.High != 0 {
			if lowest < c.Low {
				t.Errorf("case %d: went lower than allowed, %d < %d", i, lowest, c.Low)
			}
			if highest > c.High {
				t.Errorf("case %d: went higher than allowed, %d > %d", i, highest, c.High)
			}
		}

		if c.Slow != 0 && c.Fast != 0 {
			if slowest < c.Slow {
				t.Errorf("case %d: went slower than allowed, %d < %d", i, slowest, c.Slow)
			}
			if fastest > c.Fast {
				t.Errorf("case %d: went higher than allowed, %d > %d", i, fastest, c.Fast)
			}
		}

	}
}

func TestDump(t *testing.T) {
	p := NewTimedActionsPlayer()
	p.Script = script

	actions, err := p.Dump()
	if err != nil {
		t.Error(err)
	}
	if len(script) != len(actions) {
		t.Errorf("dump did not return script actions: want %d, got %d",
			len(script), len(actions))
	}
}
<|endoftext|>


<commit_before>package boober

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

const SPEC_ILLEGAL = -1
const MISSING_FILE_REFERENCE = -2
const MISSING_CONFIGURATION = -3
const ILLEGAL_JSON_CONFIGURATION = -4
const CONFIGURATION_FILE_IN_ROOT = -5
const ERROR_READING_FILE = -6
const BOOBER_ERROR = -7
const ILLEGAL_FILE = -8
const INTERNAL_ERROR = -9
const FOLDER_SETUP_NOT_SUPPORTED = -10
const OPERATION_OK = 0
const SPEC_IS_FILE = 1
const SPEC_IS_FOLDER = 2

// Struct to represent data to the Boober interface
type BooberInferface struct {
	Env         string                     `json:"env"`
	App         string                     `json:"app"`
	Affiliation string                     `json:"affiliation"`
	Files       map[string]json.RawMessage `json:"files"`
	Overrides   map[string]json.RawMessage `json:"overrides"`
}

// Struct to represent return data from the Boober interface
type BooberReturn struct {
	Sources          json.RawMessage `json:"sources"`
	Errors           []string        `json:"errors"`
	Valid            bool            `json:"valid"`
	Config           json.RawMessage `json:"config"`
	OpenshiftObjects json.RawMessage `json:"openshiftObjects"`
}

func ExecuteSetup(args []string, dryRun bool, showConfig bool, showObjects bool, verbose bool, localhost bool,
	overrideFiles []string) int {

	validateCode := validateCommand(args, overrideFiles)
	if validateCode < 0 {
		return validateCode
	}

	var absolutePath string

	absolutePath, _ = filepath.Abs(args[0])

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch validateCode {
	case SPEC_IS_FILE:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case SPEC_IS_FOLDER:
		folder = absolutePath
		envFile = ""
		fmt.Println("Setup on a folder is not yet supported")
		return FOLDER_SETUP_NOT_SUPPORTED
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		fmt.Println("Application configuration file cannot reside in root directory")
		return CONFIGURATION_FILE_IN_ROOT
	}

	// Initialize JSON

	var booberData BooberInferface
	booberData.App = strings.TrimSuffix(envFile, filepath.Ext(envFile)) //envFile
	booberData.Env = envFolder
	booberData.Affiliation = ""

	var returnMap = Folder2Map(folder, envFolder+"/")
	var returnMap2 = Folder2Map(parentFolder, "")

	booberData.Files = CombineMaps(returnMap, returnMap2)
	booberData.Overrides = overrides2map(args, overrideFiles)

	jsonByte, ok := json.Marshal(booberData)
	if !(ok == nil) {
		fmt.Println("Internal error in marshalling Boober data: " + ok.Error())
		return INTERNAL_ERROR
	}

	jsonStr := string(jsonByte)
	if dryRun {
		fmt.Println(string(PrettyPrintJson(jsonStr)))
	} else {
		validateCode = CallBoober(jsonStr, showConfig, showObjects, false, localhost, verbose)
		if validateCode < 0 {
			return validateCode
		}
	}
	return OPERATION_OK
}

func overrides2map(args []string, overrideFiles []string) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)
	for i := 0; i < len(overrideFiles); i++ {
		returnMap[overrideFiles[i]] = json.RawMessage(args[i+1])
	}
	return returnMap
}

func Folder2Map(folder string, prefix string) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)
	var allFilesOK bool = true

	files, _ := ioutil.ReadDir(folder)
	var filesProcessed = 0
	for _, f := range files {
		absolutePath := filepath.Join(folder, f.Name())
		if IsLegalFileFolder(absolutePath) == SPEC_IS_FILE { // Ignore folders
			matched, _ := filepath.Match("*.json", strings.ToLower(f.Name()))
			if matched {
				fileJson, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					fmt.Println("Error in reading file " + absolutePath)
					os.Exit(ERROR_READING_FILE)
				}
				if IsLegalJson(string(fileJson)) {
					filesProcessed++
					returnMap[prefix+f.Name()] = fileJson
				} else {
					fmt.Println("Illegal JSON in configuration file " + absolutePath)
					allFilesOK = false
				}
				filesProcessed++
			}
		}

	}
	if !allFilesOK {
		os.Exit(ILLEGAL_JSON_CONFIGURATION)
	}
	return returnMap
}

func CombineMaps(map1 map[string]json.RawMessage, map2 map[string]json.RawMessage) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)

	for k, v := range map1 {
		returnMap[k] = v
	}
	for k, v := range map2 {
		returnMap[k] = v
	}
	return returnMap
}

func validateCommand(args []string, overrideFiles []string) int {
	var errorString = ""
	var returnCode int

	if len(args) == 0 {
		returnCode = -1
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		returnCode = IsLegalFileFolder(args[0])
		if returnCode < 0 {
			errorString += "Illegal file / folder: " + args[0]
			returnCode = ILLEGAL_FILE
		}

		// We have at least one argument, now there should be a correlation between the number of args
		// and the number of override (-f) flags
		if len(overrideFiles) < (len(args) - 1) {
			returnCode = MISSING_FILE_REFERENCE
			errorString += "Configuration override specified without file reference flag "
		}
		if len(overrideFiles) > (len(args) - 1) {
			returnCode = MISSING_CONFIGURATION
			errorString += "Configuration overide file reference flag specified without configuration "
		}

		// Check for legal JSON argument for each overrideFiles flag
		for i := 1; i < len(args); i++ {
			if !IsLegalJson(args[i]) {
				errorString = "Illegal JSON configuration override: " + args[i] + " "
				returnCode = ILLEGAL_JSON_CONFIGURATION
			}
		}
	}

	if returnCode < 0 {
		fmt.Println(errorString)
	}
	return returnCode
}

func IsLegalFileFolder(filespec string) int {
	var err error
	var absolutePath string
	var fi os.FileInfo

	absolutePath, err = filepath.Abs(filespec)
	fi, err = os.Stat(absolutePath)
	if os.IsNotExist(err) {
		return SPEC_ILLEGAL
	} else {
		switch mode := fi.Mode(); {
		case mode.IsDir():
			return SPEC_IS_FOLDER
		case mode.IsRegular():
			return SPEC_IS_FILE
		}
	}
	return SPEC_ILLEGAL
}

func GetBooberAddress(clusterName string, localhost bool) string {
	var booberAddress string

	if localhost {
		booberAddress = "http://localhost:8080"
	} else {
		booberAddress = "http://boober-mfp-boober." + clusterName + ".paas.skead.no"
	}
	return booberAddress
}

func GetBooberSetupUrl(clusterName string, localhost bool) string {
	return GetBooberAddress(clusterName, localhost) + "/setup"
}

func CallBoober(combindedJson string, showConfig bool, showObjects bool, api bool, localhost bool, verbose bool) int {
	//var openshiftConfig *openshift.OpenshiftConfig
	var configLocation = viper.GetString("HOME") + "/.aoc.json"

	if localhost {
		CallBooberInstance(combindedJson, showConfig, showObjects, verbose,
			GetBooberSetupUrl("localhost", localhost))
	} else {
		openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
		if err != nil {
			fmt.Println("Error in loading OpenShift configuration")
			return INTERNAL_ERROR
		}

		for i := range openshiftConfig.Clusters {
			if openshiftConfig.Clusters[i].Reachable {
				if !api || openshiftConfig.Clusters[i].Name == openshiftConfig.APICluster {
					CallBooberInstance(combindedJson, showConfig, showObjects, verbose,
						GetBooberSetupUrl(openshiftConfig.Clusters[i].Name, localhost))
				}
			}
		}
	}
	return OPERATION_OK
}

func CallBooberInstance(combindedJson string, showConfig bool, showObjects bool, verbose bool, url string) int {

	if verbose {
		fmt.Println("Sending config to Boober at " + url)
	}

	var jsonStr = []byte(combindedJson)

	req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		fmt.Println("Internal error in NewRequest: ", err)
		return INTERNAL_ERROR
	}

	req.Header.Set("Authentication", "mydirtysecret")
	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error connecting to the Boober service on "+url+": ", err)
		return BOOBER_ERROR
	}

	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		fmt.Println("Error from the Boober service on " + url + ":")
		body, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(string(body))
		return BOOBER_ERROR
	}
	body, _ := ioutil.ReadAll(resp.Body)

	// Check return for error
	var booberReturn BooberReturn
	err = json.Unmarshal(body, &booberReturn)
	if err != nil {
		fmt.Println("Error unmashalling Boober return: " + err.Error())
		return BOOBER_ERROR
	}

	if !(booberReturn.Valid) {
		fmt.Println("Error in configuration: ")
		for _, message := range booberReturn.Errors {
			fmt.Println("  " + message)
		}
	}

	if showConfig {
		fmt.Println(PrettyPrintJson(string(booberReturn.Config)))
	}

	if showObjects {
		fmt.Println(PrettyPrintJson(string(booberReturn.OpenshiftObjects)))
	}

	return OPERATION_OK
}<commit_msg>Added Verbose flag to log progress<commit_after>package boober

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/skatteetaten/aoc/pkg/openshift"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	//"github.com/vbatts/gogololcat/lol"
)

const SPEC_ILLEGAL = -1
const MISSING_FILE_REFERENCE = -2
const MISSING_CONFIGURATION = -3
const ILLEGAL_JSON_CONFIGURATION = -4
const CONFIGURATION_FILE_IN_ROOT = -5
const ERROR_READING_FILE = -6
const BOOBER_ERROR = -7
const ILLEGAL_FILE = -8
const INTERNAL_ERROR = -9
const FOLDER_SETUP_NOT_SUPPORTED = -10
const OPERATION_OK = 0
const SPEC_IS_FILE = 1
const SPEC_IS_FOLDER = 2

// Struct to represent data to the Boober interface
type BooberInferface struct {
	Env         string                     `json:"env"`
	App         string                     `json:"app"`
	Affiliation string                     `json:"affiliation"`
	Files       map[string]json.RawMessage `json:"files"`
	Overrides   map[string]json.RawMessage `json:"overrides"`
}

// Struct to represent return data from the Boober interface
type BooberReturn struct {
	Sources          json.RawMessage `json:"sources"`
	Errors           []string        `json:"errors"`
	Valid            bool            `json:"valid"`
	Config           json.RawMessage `json:"config"`
	OpenshiftObjects json.RawMessage `json:"openshiftObjects"`
}

func ExecuteSetup(args []string, dryRun bool, showConfig bool, showObjects bool, verbose bool, localhost bool,
	overrideFiles []string) int {

	validateCode := validateCommand(args, overrideFiles)
	if validateCode < 0 {
		return validateCode
	}

	var absolutePath string

	absolutePath, _ = filepath.Abs(args[0])

	var envFile string      // Filename for app
	var envFolder string    // Short folder name (Env)
	var folder string       // Absolute path of folder
	var parentFolder string // Absolute path of parent

	switch validateCode {
	case SPEC_IS_FILE:
		folder = filepath.Dir(absolutePath)
		envFile = filepath.Base(absolutePath)
	case SPEC_IS_FOLDER:
		folder = absolutePath
		envFile = ""
		fmt.Println("Setup on a folder is not yet supported")
		return FOLDER_SETUP_NOT_SUPPORTED
	}

	parentFolder = filepath.Dir(folder)
	envFolder = filepath.Base(folder)

	if folder == parentFolder {
		fmt.Println("Application configuration file cannot reside in root directory")
		return CONFIGURATION_FILE_IN_ROOT
	}

	// Initialize JSON

	var booberData BooberInferface
	booberData.App = strings.TrimSuffix(envFile, filepath.Ext(envFile)) //envFile
	booberData.Env = envFolder
	booberData.Affiliation = ""

	var returnMap = Folder2Map(folder, envFolder+"/")
	var returnMap2 = Folder2Map(parentFolder, "")

	booberData.Files = CombineMaps(returnMap, returnMap2)
	booberData.Overrides = overrides2map(args, overrideFiles)

	jsonByte, ok := json.Marshal(booberData)
	if !(ok == nil) {
		fmt.Println("Internal error in marshalling Boober data: " + ok.Error())
		return INTERNAL_ERROR
	}

	jsonStr := string(jsonByte)
	if dryRun {
		//lol.Writer.Write(os.Stdout, []byte(PrettyPrintJson(jsonStr)))
		fmt.Println(string(PrettyPrintJson(jsonStr)))
	} else {
		validateCode = CallBoober(jsonStr, showConfig, showObjects, false, localhost, verbose)
		if validateCode < 0 {
			return validateCode
		}
	}
	return OPERATION_OK
}

func overrides2map(args []string, overrideFiles []string) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)
	for i := 0; i < len(overrideFiles); i++ {
		returnMap[overrideFiles[i]] = json.RawMessage(args[i+1])
	}
	return returnMap
}

func Folder2Map(folder string, prefix string) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)
	var allFilesOK bool = true

	files, _ := ioutil.ReadDir(folder)
	var filesProcessed = 0
	for _, f := range files {
		absolutePath := filepath.Join(folder, f.Name())
		if IsLegalFileFolder(absolutePath) == SPEC_IS_FILE { // Ignore folders
			matched, _ := filepath.Match("*.json", strings.ToLower(f.Name()))
			if matched {
				fileJson, err := ioutil.ReadFile(absolutePath)
				if err != nil {
					fmt.Println("Error in reading file " + absolutePath)
					os.Exit(ERROR_READING_FILE)
				}
				if IsLegalJson(string(fileJson)) {
					filesProcessed++
					returnMap[prefix+f.Name()] = fileJson
				} else {
					fmt.Println("Illegal JSON in configuration file " + absolutePath)
					allFilesOK = false
				}
				filesProcessed++
			}
		}

	}
	if !allFilesOK {
		os.Exit(ILLEGAL_JSON_CONFIGURATION)
	}
	return returnMap
}

func CombineMaps(map1 map[string]json.RawMessage, map2 map[string]json.RawMessage) map[string]json.RawMessage {
	var returnMap = make(map[string]json.RawMessage)

	for k, v := range map1 {
		returnMap[k] = v
	}
	for k, v := range map2 {
		returnMap[k] = v
	}
	return returnMap
}

func validateCommand(args []string, overrideFiles []string) int {
	var errorString = ""
	var returnCode int

	if len(args) == 0 {
		returnCode = -1
		errorString += "Missing file/folder "
	} else {
		// Chceck argument 0 for legal file / folder
		returnCode = IsLegalFileFolder(args[0])
		if returnCode < 0 {
			errorString += "Illegal file / folder: " + args[0]
			returnCode = ILLEGAL_FILE
		}

		// We have at least one argument, now there should be a correlation between the number of args
		// and the number of override (-f) flags
		if len(overrideFiles) < (len(args) - 1) {
			returnCode = MISSING_FILE_REFERENCE
			errorString += "Configuration override specified without file reference flag "
		}
		if len(overrideFiles) > (len(args) - 1) {
			returnCode = MISSING_CONFIGURATION
			errorString += "Configuration overide file reference flag specified without configuration "
		}

		// Check for legal JSON argument for each overrideFiles flag
		for i := 1; i < len(args); i++ {
			if !IsLegalJson(args[i]) {
				errorString = "Illegal JSON configuration override: " + args[i] + " "
				returnCode = ILLEGAL_JSON_CONFIGURATION
			}
		}
	}

	if returnCode < 0 {
		fmt.Println(errorString)
	}
	return returnCode
}

func IsLegalFileFolder(filespec string) int {
	var err error
	var absolutePath string
	var fi os.FileInfo

	absolutePath, err = filepath.Abs(filespec)
	fi, err = os.Stat(absolutePath)
	if os.IsNotExist(err) {
		return SPEC_ILLEGAL
	} else {
		switch mode := fi.Mode(); {
		case mode.IsDir():
			return SPEC_IS_FOLDER
		case mode.IsRegular():
			return SPEC_IS_FILE
		}
	}
	return SPEC_ILLEGAL
}

func GetBooberAddress(clusterName string, localhost bool) string {
	var booberAddress string

	if localhost {
		booberAddress = "http://localhost:8080"
	} else {
		booberAddress = "http://boober-mfp-boober." + clusterName + ".paas.skead.no"
	}
	return booberAddress
}

func GetBooberSetupUrl(clusterName string, localhost bool) string {
	return GetBooberAddress(clusterName, localhost) + "/setup"
}

func CallBoober(combindedJson string, showConfig bool, showObjects bool, api bool, localhost bool, verbose bool) int {
	//var openshiftConfig *openshift.OpenshiftConfig
	var configLocation = viper.GetString("HOME") + "/.aoc.json"

	if localhost {
		CallBooberInstance(combindedJson, showConfig, showObjects, verbose,
			GetBooberSetupUrl("localhost", localhost))
	} else {
		openshiftConfig, err := openshift.LoadOrInitiateConfigFile(configLocation)
		if err != nil {
			fmt.Println("Error in loading OpenShift configuration")
			return INTERNAL_ERROR
		}

		for i := range openshiftConfig.Clusters {
			if openshiftConfig.Clusters[i].Reachable {
				if !api || openshiftConfig.Clusters[i].Name == openshiftConfig.APICluster {
					CallBooberInstance(combindedJson, showConfig, showObjects, verbose,
						GetBooberSetupUrl(openshiftConfig.Clusters[i].Name, localhost))
				}
			}
		}
	}
	return OPERATION_OK
}

func CallBooberInstance(combindedJson string, showConfig bool, showObjects bool, verbose bool, url string) int {

	if verbose {
		fmt.Println("Sending config to Boober at " + url)
	}

	var jsonStr = []byte(combindedJson)

	req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		fmt.Println("Internal error in NewRequest: ", err)
		return INTERNAL_ERROR
	}

	req.Header.Set("Authentication", "mydirtysecret")
	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("Error connecting to the Boober service on "+url+": ", err)
		return BOOBER_ERROR
	}

	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		fmt.Println("Error from the Boober service on " + url + ":")
		body, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(string(body))
		return BOOBER_ERROR
	}
	body, _ := ioutil.ReadAll(resp.Body)

	// Check return for error
	var booberReturn BooberReturn
	err = json.Unmarshal(body, &booberReturn)
	if err != nil {
		fmt.Println("Error unmashalling Boober return: " + err.Error())
		return BOOBER_ERROR
	}

	if !(booberReturn.Valid) {
		fmt.Println("Error in configuration: ")
		for _, message := range booberReturn.Errors {
			fmt.Println("  " + message)
		}
	}

	if showConfig {
		fmt.Println(PrettyPrintJson(string(booberReturn.Config)))
	}

	if showObjects {
		fmt.Println(PrettyPrintJson(string(booberReturn.OpenshiftObjects)))
	}

	return OPERATION_OK
}<|endoftext|>