<commit_before>package tools

// In /etc/hummingbird/andrewd-server.conf:
// [ring-monitor]
// initial_delay = 1      # seconds to wait between ring checks for the first pass
// pass_time_target = 60  # seconds to try to make subsequent passes take
// report_interval = 600  # seconds between progress reports

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/troubling/hummingbird/common/ring"
	"go.uber.org/zap"
)

type ringMonitor struct {
	aa *AutoAdmin
	// delay between each ring check; adjusted each pass to try to make passes last passTimeTarget
	delay          time.Duration
	passTimeTarget time.Duration
	reportInterval time.Duration
	prefix         string
	suffix         string
}

func newRingMonitor(aa *AutoAdmin) *ringMonitor {
	rm := &ringMonitor{
		aa:             aa,
		delay:          time.Duration(aa.serverconf.GetInt("ring-monitor", "initial_delay", 1)) * time.Second,
		passTimeTarget: time.Duration(aa.serverconf.GetInt("ring-monitor", "pass_time_target", 60)) * time.Second,
		reportInterval: time.Duration(aa.serverconf.GetInt("ring-monitor", "report_interval", 600)) * time.Second,
	}
	if rm.delay < 0 {
		rm.delay = time.Second
	}
	if rm.passTimeTarget < 0 {
		rm.passTimeTarget = time.Second
	}
	if rm.reportInterval < 0 {
		rm.reportInterval = time.Second
	}
	rm.prefix, rm.suffix = getAffixes()
	return rm
}

func (rm *ringMonitor) runForever() {
	for {
		sleepFor := rm.runOnce()
		if sleepFor < 0 {
			break
		}
		time.Sleep(sleepFor)
	}
}

func (rm *ringMonitor) runOnce() time.Duration {
	start := time.Now()
	logger := rm.aa.logger.With(zap.String("process", "ring monitor"))
	logger.Debug("starting pass")
	if err := rm.aa.db.startProcessPass("ring monitor", "", 0); err != nil {
		logger.Error("startProcessPass", zap.Error(err))
	}
	var delays int64
	var errors int64
	var partitionCopiesChanged int64
	type ringTask struct {
		typ         string
		policy      int
		ring        ring.RingMD5
		previousMD5 string
	}
	var ringTasks []*ringTask
	ryng, err := ring.GetRingMD5("account", rm.prefix, rm.suffix, 0)
	if err != nil {
		errors++
		logger.Error("could not load ring", zap.String("type", "account"), zap.Int("policy", 0), zap.Error(err))
	} else {
		ringTasks = append(ringTasks, &ringTask{
			typ:  "account",
			ring: ryng,
		})
	}
	ryng, err = ring.GetRingMD5("container", rm.prefix, rm.suffix, 0)
	if err != nil {
		errors++
		logger.Error("could not load ring", zap.String("type", "container"), zap.Int("policy", 0), zap.Error(err))
	} else {
		ringTasks = append(ringTasks, &ringTask{
			typ:  "container",
			ring: ryng,
		})
	}
	for _, policy := range rm.aa.policies {
		if !policy.Deprecated {
			ryng, err = ring.GetRingMD5("object", rm.prefix, rm.suffix, policy.Index)
			if err != nil {
				errors++
				logger.Error("could not load ring", zap.String("type", "object"), zap.Int("policy", policy.Index), zap.Error(err))
				continue
			}
			ringTasks = append(ringTasks, &ringTask{
				typ:    "object",
				policy: policy.Index,
				ring:   ryng,
			})
		}
	}
	cancel := make(chan struct{})
	progressDone := make(chan struct{})
	go func() {
		for {
			select {
			case <-cancel:
				close(progressDone)
				return
			case <-time.After(rm.reportInterval):
				d := atomic.LoadInt64(&delays)
				e := atomic.LoadInt64(&errors)
				p := atomic.LoadInt64(&partitionCopiesChanged)
				eta := time.Duration(int64(time.Since(start)) / d * (int64(len(ringTasks)) - d))
				logger.Debug("progress", zap.Int64("rings so far", d), zap.Int("total rings", len(ringTasks)), zap.Int64("errors", e), zap.Int64("partition copies changed", p), zap.String("eta", eta.String()))
				if err := rm.aa.db.progressProcessPass("ring monitor", "", 0, fmt.Sprintf("%d of %d rings, %d errors, %d partition copies changed, eta %s", d, len(ringTasks), e, p, eta)); err != nil {
					logger.Error("progressProcessPass", zap.Error(err))
				}
			}
		}
	}()
	for _, ringTask := range ringTasks {
		taskLogger := logger.With(zap.String("type", ringTask.typ), zap.Int("policy", ringTask.policy), zap.String("previous md5", ringTask.previousMD5))
		if err := ringTask.ring.Reload(); err != nil {
			atomic.AddInt64(&errors, 1)
			taskLogger.Error("couldn't not reload", zap.Error(err))
			continue
		}
		if ringTask.previousMD5 == "" {
			ringTask.previousMD5, err = rm.aa.db.ringHash(ringTask.typ, ringTask.policy)
			if err != nil {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error("couldn't retreive previous hash", zap.Error(err))
				continue
			}
		}
		if ringTask.ring.MD5() != ringTask.previousMD5 {
			if ringTask.previousMD5 == "" {
				// First time seeing this ring
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			taskLogger.Debug("ring md5 changed", zap.String("current md5", ringTask.ring.MD5()))
			previousRing := ringTask.ring.RingMatching(ringTask.previousMD5)
			if previousRing == nil {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error("can't find previous ring; assuming nothing changed")
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			partitionCount := previousRing.PartitionCount()
			if partitionCount != ringTask.ring.PartitionCount() {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error(
					"cannot handle changing partition counts; assuming new ring as if no previous ring ever existed",
					zap.Uint64("previous partition count", previousRing.PartitionCount()),
					zap.Uint64("current partition count", ringTask.ring.PartitionCount()),
				)
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			replicaCount := previousRing.ReplicaCount()
			if replicaCount != ringTask.ring.ReplicaCount() {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error(
					"cannot handle changing replica counts; assuming new ring as if no previous ring ever existed",
					zap.Uint64("previous replica count", previousRing.ReplicaCount()),
					zap.Uint64("current replica count", ringTask.ring.ReplicaCount()),
				)
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			failed := false
			for partition := uint64(0); partition < partitionCount && !failed; partition++ {
				previousDev := previousRing.GetNodes(partition)
				currentDev := ringTask.ring.GetNodes(partition)
				for replica := uint64(0); replica < replicaCount; replica++ {
					if previousDev[replica].Id != currentDev[replica].Id {
						if err := rm.aa.db.queuePartitionReplication(
							ringTask.typ,
							ringTask.policy,
							partition,
							"ring change",
							previousDev[replica].Id,
							currentDev[replica].Id,
						); err != nil {
							atomic.AddInt64(&errors, 1)
							taskLogger.Error(
								"could not queue ring change; will try again next pass",
								zap.Uint64("partition", partition),
								zap.Uint64("replica", replica),
								zap.Int("previous id", previousDev[replica].Id),
								zap.Int("current id", currentDev[replica].Id),
								zap.Error(err),
							)
							failed = true
							break
						} else {
							atomic.AddInt64(&partitionCopiesChanged, 1)
						}
					}
				}
			}
			if !failed {
				if err = rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5()); err != nil {
					atomic.AddInt64(&errors, 1)
				}
			}
		}
		atomic.AddInt64(&delays, 1)
		time.Sleep(rm.delay)
	}
	close(cancel)
	<-progressDone
	rm.delay = rm.passTimeTarget / time.Duration(delays)
	sleepFor := time.Until(start.Add(rm.passTimeTarget))
	if sleepFor < 0 {
		sleepFor = 0
	}
	logger.Debug("pass complete", zap.Int("total rings", len(ringTasks)), zap.Int64("errors", errors), zap.Int64("partition copies changed", partitionCopiesChanged), zap.String("next delay", rm.delay.String()), zap.String("sleep for", sleepFor.String()))
	if err := rm.aa.db.progressProcessPass("ring monitor", "", 0, fmt.Sprintf("%d of %d urls, %d errors, %d partition copies changed", delays, len(ringTasks), errors, partitionCopiesChanged)); err != nil {
		logger.Error("progressProcessPass", zap.Error(err))
	}
	if err := rm.aa.db.completeProcessPass("ring monitor", "", 0); err != nil {
		logger.Error("completeProcessPass", zap.Error(err))
	}
	return sleepFor
}
<commit_msg>Fixed divide by zero bug<commit_after>package tools

// In /etc/hummingbird/andrewd-server.conf:
// [ring-monitor]
// initial_delay = 1      # seconds to wait between ring checks for the first pass
// pass_time_target = 60  # seconds to try to make subsequent passes take
// report_interval = 600  # seconds between progress reports

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/troubling/hummingbird/common/ring"
	"go.uber.org/zap"
)

type ringMonitor struct {
	aa *AutoAdmin
	// delay between each ring check; adjusted each pass to try to make passes last passTimeTarget
	delay          time.Duration
	passTimeTarget time.Duration
	reportInterval time.Duration
	prefix         string
	suffix         string
}

func newRingMonitor(aa *AutoAdmin) *ringMonitor {
	rm := &ringMonitor{
		aa:             aa,
		delay:          time.Duration(aa.serverconf.GetInt("ring-monitor", "initial_delay", 1)) * time.Second,
		passTimeTarget: time.Duration(aa.serverconf.GetInt("ring-monitor", "pass_time_target", 60)) * time.Second,
		reportInterval: time.Duration(aa.serverconf.GetInt("ring-monitor", "report_interval", 600)) * time.Second,
	}
	if rm.delay < 0 {
		rm.delay = time.Second
	}
	if rm.passTimeTarget < 0 {
		rm.passTimeTarget = time.Second
	}
	if rm.reportInterval < 0 {
		rm.reportInterval = time.Second
	}
	rm.prefix, rm.suffix = getAffixes()
	return rm
}

func (rm *ringMonitor) runForever() {
	for {
		sleepFor := rm.runOnce()
		if sleepFor < 0 {
			break
		}
		time.Sleep(sleepFor)
	}
}

func (rm *ringMonitor) runOnce() time.Duration {
	start := time.Now()
	logger := rm.aa.logger.With(zap.String("process", "ring monitor"))
	logger.Debug("starting pass")
	if err := rm.aa.db.startProcessPass("ring monitor", "", 0); err != nil {
		logger.Error("startProcessPass", zap.Error(err))
	}
	var delays int64
	var errors int64
	var partitionCopiesChanged int64
	type ringTask struct {
		typ         string
		policy      int
		ring        ring.RingMD5
		previousMD5 string
	}
	var ringTasks []*ringTask
	ryng, err := ring.GetRingMD5("account", rm.prefix, rm.suffix, 0)
	if err != nil {
		errors++
		logger.Error("could not load ring", zap.String("type", "account"), zap.Int("policy", 0), zap.Error(err))
	} else {
		ringTasks = append(ringTasks, &ringTask{
			typ:  "account",
			ring: ryng,
		})
	}
	ryng, err = ring.GetRingMD5("container", rm.prefix, rm.suffix, 0)
	if err != nil {
		errors++
		logger.Error("could not load ring", zap.String("type", "container"), zap.Int("policy", 0), zap.Error(err))
	} else {
		ringTasks = append(ringTasks, &ringTask{
			typ:  "container",
			ring: ryng,
		})
	}
	for _, policy := range rm.aa.policies {
		if !policy.Deprecated {
			ryng, err = ring.GetRingMD5("object", rm.prefix, rm.suffix, policy.Index)
			if err != nil {
				errors++
				logger.Error("could not load ring", zap.String("type", "object"), zap.Int("policy", policy.Index), zap.Error(err))
				continue
			}
			ringTasks = append(ringTasks, &ringTask{
				typ:    "object",
				policy: policy.Index,
				ring:   ryng,
			})
		}
	}
	cancel := make(chan struct{})
	progressDone := make(chan struct{})
	go func() {
		for {
			select {
			case <-cancel:
				close(progressDone)
				return
			case <-time.After(rm.reportInterval):
				d := atomic.LoadInt64(&delays)
				e := atomic.LoadInt64(&errors)
				p := atomic.LoadInt64(&partitionCopiesChanged)
				eta := time.Duration(int64(time.Since(start)) / d * (int64(len(ringTasks)) - d))
				logger.Debug("progress", zap.Int64("rings so far", d), zap.Int("total rings", len(ringTasks)), zap.Int64("errors", e), zap.Int64("partition copies changed", p), zap.String("eta", eta.String()))
				if err := rm.aa.db.progressProcessPass("ring monitor", "", 0, fmt.Sprintf("%d of %d rings, %d errors, %d partition copies changed, eta %s", d, len(ringTasks), e, p, eta)); err != nil {
					logger.Error("progressProcessPass", zap.Error(err))
				}
			}
		}
	}()
	for _, ringTask := range ringTasks {
		taskLogger := logger.With(zap.String("type", ringTask.typ), zap.Int("policy", ringTask.policy), zap.String("previous md5", ringTask.previousMD5))
		if err := ringTask.ring.Reload(); err != nil {
			atomic.AddInt64(&errors, 1)
			taskLogger.Error("couldn't not reload", zap.Error(err))
			continue
		}
		if ringTask.previousMD5 == "" {
			ringTask.previousMD5, err = rm.aa.db.ringHash(ringTask.typ, ringTask.policy)
			if err != nil {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error("couldn't retreive previous hash", zap.Error(err))
				continue
			}
		}
		if ringTask.ring.MD5() != ringTask.previousMD5 {
			if ringTask.previousMD5 == "" {
				// First time seeing this ring
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			taskLogger.Debug("ring md5 changed", zap.String("current md5", ringTask.ring.MD5()))
			previousRing := ringTask.ring.RingMatching(ringTask.previousMD5)
			if previousRing == nil {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error("can't find previous ring; assuming nothing changed")
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			partitionCount := previousRing.PartitionCount()
			if partitionCount != ringTask.ring.PartitionCount() {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error(
					"cannot handle changing partition counts; assuming new ring as if no previous ring ever existed",
					zap.Uint64("previous partition count", previousRing.PartitionCount()),
					zap.Uint64("current partition count", ringTask.ring.PartitionCount()),
				)
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			replicaCount := previousRing.ReplicaCount()
			if replicaCount != ringTask.ring.ReplicaCount() {
				atomic.AddInt64(&errors, 1)
				taskLogger.Error(
					"cannot handle changing replica counts; assuming new ring as if no previous ring ever existed",
					zap.Uint64("previous replica count", previousRing.ReplicaCount()),
					zap.Uint64("current replica count", ringTask.ring.ReplicaCount()),
				)
				rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5())
				continue
			}
			failed := false
			for partition := uint64(0); partition < partitionCount && !failed; partition++ {
				previousDev := previousRing.GetNodes(partition)
				currentDev := ringTask.ring.GetNodes(partition)
				for replica := uint64(0); replica < replicaCount; replica++ {
					if previousDev[replica].Id != currentDev[replica].Id {
						if err := rm.aa.db.queuePartitionReplication(
							ringTask.typ,
							ringTask.policy,
							partition,
							"ring change",
							previousDev[replica].Id,
							currentDev[replica].Id,
						); err != nil {
							atomic.AddInt64(&errors, 1)
							taskLogger.Error(
								"could not queue ring change; will try again next pass",
								zap.Uint64("partition", partition),
								zap.Uint64("replica", replica),
								zap.Int("previous id", previousDev[replica].Id),
								zap.Int("current id", currentDev[replica].Id),
								zap.Error(err),
							)
							failed = true
							break
						} else {
							atomic.AddInt64(&partitionCopiesChanged, 1)
						}
					}
				}
			}
			if !failed {
				if err = rm.aa.db.setRingHash(ringTask.typ, ringTask.policy, ringTask.ring.MD5()); err != nil {
					atomic.AddInt64(&errors, 1)
				}
			}
		}
		atomic.AddInt64(&delays, 1)
		time.Sleep(rm.delay)
	}
	close(cancel)
	<-progressDone
	if delays > 0 {
		rm.delay = rm.passTimeTarget / time.Duration(delays)
	}
	sleepFor := time.Until(start.Add(rm.passTimeTarget))
	if sleepFor < 0 {
		sleepFor = 0
	}
	logger.Debug("pass complete", zap.Int("total rings", len(ringTasks)), zap.Int64("errors", errors), zap.Int64("partition copies changed", partitionCopiesChanged), zap.String("next delay", rm.delay.String()), zap.String("sleep for", sleepFor.String()))
	if err := rm.aa.db.progressProcessPass("ring monitor", "", 0, fmt.Sprintf("%d of %d urls, %d errors, %d partition copies changed", delays, len(ringTasks), errors, partitionCopiesChanged)); err != nil {
		logger.Error("progressProcessPass", zap.Error(err))
	}
	if err := rm.aa.db.completeProcessPass("ring monitor", "", 0); err != nil {
		logger.Error("completeProcessPass", zap.Error(err))
	}
	return sleepFor
}
<|endoftext|>


<commit_before>package scamp

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
)

// Config represents scamp config
type Config struct {
	// string key for easy equals, byte return for easy nil
	values map[string][]byte
}

// TODO: Will I regret using such a common name as a global variable?
var defaultConfig *Config

var defaultAnnounceInterval = 5

// DefaultConfigPath is the path at which the library will, by default, look for its configuration.
var DefaultConfigPath = "/etc/SCAMP/soa.conf"

var (
	configLine   = regexp.MustCompile(`^\s*([\S^=]+)\s*=\s*([\S]+)`)
	globalConfig *Config
)

var (
	defaultGroupIP   = net.IPv4(239, 63, 248, 106)
	defaultGroupPort = 5555
)

func initConfig(configPath string) (err error) {
	defaultConfig = NewConfig()
	err = DefaultConfig().Load(configPath)
	if err != nil {
		err = fmt.Errorf("could not load config: %s", err)
		return
	}

	randomDebuggerString = scampDebuggerRandomString()

	return
}

// NewConfig creates a new configuration struct with default values initialized.
func NewConfig() (conf *Config) {
	conf = new(Config)
	conf.values = make(map[string][]byte)

	return
}

// SetDefaultConfig sets the global configuration manually if need be.
// In general, users should use Initialize instead.
func SetDefaultConfig(conf *Config) {
	initSCAMPLogger()
	defaultConfig = conf
}

// DefaultConfig fetches the global configuration struct for use.
// This function panics if the global configuration is not initialized (with `Initialize()`).
func DefaultConfig() (conf *Config) {
	if defaultConfig == nil {
		panic("Global configuration defaultConfig is not initialized! Call scamp.Initialize() before using package functionality.")
	}
	return defaultConfig
}

// Load loads configuration k/v pairs from the file at the given path.
func (conf *Config) Load(configPath string) (err error) {
	file, err := os.Open(configPath)
	if err != nil {
		err = fmt.Errorf("couldn't read config from `%s`: %v", configPath, err)
		return
	}
	scanner := bufio.NewScanner(file)
	conf.doLoad(scanner)

	return
}

func (conf *Config) doLoad(scanner *bufio.Scanner) (err error) {
	var read bool
	for {
		read = scanner.Scan()
		if !read {
			break
		}

		re := configLine.FindSubmatch(scanner.Bytes())
		if re != nil {
			conf.values[string(re[1])] = re[2]
		}
	}

	return
}

// ServiceKeyPath uses the configuration to generate a path at which the key for the given service name should be found.
func (conf *Config) ServiceKeyPath(serviceName string) (keyPath []byte) {
	path := conf.values[serviceName+".soa_key"]
	if path == nil {
		path = []byte(fmt.Sprintf("/etc/GT_private/services/%s.key", serviceName))
	}
	return path
}

// ServiceCertPath uses the configuration to generate a path at which the certificate for the given service name should be found.
func (conf *Config) ServiceCertPath(serviceName string) (certPath []byte) {
	path := conf.values[serviceName+".soa_cert"]
	if path == nil {
		path = []byte(fmt.Sprintf("/etc/GT_private/services/%s.crt", serviceName))
	}
	return path
}

// DiscoveryMulticastIP returns the configured discovery address, or the default one
// if there is no configured address (discovery.multicast_address)
func (conf *Config) DiscoveryMulticastIP() (ip net.IP) {
	rawAddr := conf.values["discovery.multicast_address"]
	if rawAddr != nil {
		return net.ParseIP(string(rawAddr))
	}

	return defaultGroupIP
}

// DiscoveryMulticastPort returns the configured discovery port, or the default one
// if there is no configured port (discovery.port)
func (conf *Config) DiscoveryMulticastPort() (port int) {
	portBytes := conf.values["discovery.port"]
	if portBytes != nil {
		port64, err := strconv.ParseInt(string(portBytes), 10, 0)
		if err != nil {
			Error.Printf("could not parse discovery.port `%s`. falling back to default", err)
			port = int(defaultGroupPort)
		} else {
			port = int(port64)
		}

		return
	}

	port = defaultGroupPort
	return
}

func (conf *Config) LocalDiscoveryMulticast() bool {
	_, ok := conf.values["discovery.local_multicast"]
	return ok
}

func (conf *Config) RunningServiceFileDirPath() (runningServiceFileDirPath []byte, err error) {
	runningServiceFileDirPath = conf.values["service.running_service_file_dir_path"]
	if runningServiceFileDirPath == nil {
		err = fmt.Errorf("Running service file dir path config value not found")
	}
	return
}

// Get returns the value of a given config option as a string, or false if it is not set.
func (conf *Config) Get(key string) (value string, ok bool) {
	valueBytes, ok := conf.values[key]
	value = string(valueBytes)
	return
}

// Set sets the given key to the given value in the configuration
func (conf *Config) Set(key string, value string) {
	valueBytes := []byte(value)
	conf.values[key] = valueBytes
}
<commit_msg>log.level config support<commit_after>package scamp

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"regexp"
	"strconv"
)

// Config represents scamp config
type Config struct {
	// string key for easy equals, byte return for easy nil
	values map[string][]byte
}

// TODO: Will I regret using such a common name as a global variable?
var defaultConfig *Config

var defaultAnnounceInterval = 5

// DefaultConfigPath is the path at which the library will, by default, look for its configuration.
var DefaultConfigPath = "/etc/SCAMP/soa.conf"

var (
	configLine   = regexp.MustCompile(`^\s*([\S^=]+)\s*=\s*([\S]+)`)
	globalConfig *Config
)

var (
	defaultGroupIP   = net.IPv4(239, 63, 248, 106)
	defaultGroupPort = 5555
)

func initConfig(configPath string) (err error) {
	defaultConfig = NewConfig()
	err = DefaultConfig().Load(configPath)
	if err != nil {
		err = fmt.Errorf("could not load config: %s", err)
		return
	}

	randomDebuggerString = scampDebuggerRandomString()

	return
}

// NewConfig creates a new configuration struct with default values initialized.
func NewConfig() (conf *Config) {
	conf = new(Config)
	conf.values = make(map[string][]byte)

	return
}

// SetDefaultConfig sets the global configuration manually if need be.
// In general, users should use Initialize instead.
func SetDefaultConfig(conf *Config) {
	initSCAMPLogger()
	defaultConfig = conf
}

// DefaultConfig fetches the global configuration struct for use.
// This function panics if the global configuration is not initialized (with `Initialize()`).
func DefaultConfig() (conf *Config) {
	if defaultConfig == nil {
		panic("Global configuration defaultConfig is not initialized! Call scamp.Initialize() before using package functionality.")
	}
	return defaultConfig
}

// Load loads configuration k/v pairs from the file at the given path.
func (conf *Config) Load(configPath string) (err error) {
	file, err := os.Open(configPath)
	if err != nil {
		err = fmt.Errorf("couldn't read config from `%s`: %v", configPath, err)
		return
	}
	scanner := bufio.NewScanner(file)
	conf.doLoad(scanner)

	return
}

func (conf *Config) doLoad(scanner *bufio.Scanner) (err error) {
	var read bool
	for {
		read = scanner.Scan()
		if !read {
			break
		}

		re := configLine.FindSubmatch(scanner.Bytes())
		if re != nil {
			conf.values[string(re[1])] = re[2]
		}
	}

	return
}

// ServiceKeyPath uses the configuration to generate a path at which the key for the given service name should be found.
func (conf *Config) ServiceKeyPath(serviceName string) (keyPath []byte) {
	path := conf.values[serviceName+".soa_key"]
	if path == nil {
		path = []byte(fmt.Sprintf("/etc/GT_private/services/%s.key", serviceName))
	}
	return path
}

// ServiceCertPath uses the configuration to generate a path at which the certificate for the given service name should be found.
func (conf *Config) ServiceCertPath(serviceName string) (certPath []byte) {
	path := conf.values[serviceName+".soa_cert"]
	if path == nil {
		path = []byte(fmt.Sprintf("/etc/GT_private/services/%s.crt", serviceName))
	}
	return path
}

// DiscoveryMulticastIP returns the configured discovery address, or the default one
// if there is no configured address (discovery.multicast_address)
func (conf *Config) DiscoveryMulticastIP() (ip net.IP) {
	rawAddr := conf.values["discovery.multicast_address"]
	if rawAddr != nil {
		return net.ParseIP(string(rawAddr))
	}

	return defaultGroupIP
}

// DiscoveryMulticastPort returns the configured discovery port, or the default one
// if there is no configured port (discovery.port)
func (conf *Config) DiscoveryMulticastPort() (port int) {
	portBytes := conf.values["discovery.port"]
	if portBytes != nil {
		port64, err := strconv.ParseInt(string(portBytes), 10, 0)
		if err != nil {
			Error.Printf("could not parse discovery.port `%s`. falling back to default", err)
			port = int(defaultGroupPort)
		} else {
			port = int(port64)
		}

		return
	}

	port = defaultGroupPort
	return
}

func (conf *Config) LocalDiscoveryMulticast() bool {
	_, ok := conf.values["discovery.local_multicast"]
	return ok
}

func (conf *Config) RunningServiceFileDirPath() (runningServiceFileDirPath []byte, err error) {
	runningServiceFileDirPath = conf.values["service.running_service_file_dir_path"]
	if runningServiceFileDirPath == nil {
		err = fmt.Errorf("Running service file dir path config value not found")
	}
	return
}

func (conf *Config) LogLevel() int {
	valueBytes, ok := conf.values["log.level"]
	if !ok {
		return 1
	}
	value, err := strconv.Atoi(string(valueBytes))
	if err != nil {
		Error.Printf("Could not parse log.level value `%s` as int: %s", string(valueBytes), err)
		return 1
	}

	return value
}

// Get returns the value of a given config option as a string, or false if it is not set.
func (conf *Config) Get(key string) (value string, ok bool) {
	valueBytes, ok := conf.values[key]
	value = string(valueBytes)
	return
}

// Set sets the given key to the given value in the configuration
func (conf *Config) Set(key string, value string) {
	valueBytes := []byte(value)
	conf.values[key] = valueBytes
}
<|endoftext|>


<commit_before>package models

import (
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/vivowares/octopus/Godeps/_workspace/src/gopkg.in/olivere/elastic.v3"
	. "github.com/vivowares/octopus/utils"
	"strconv"
	"strings"
	"time"
)

var SupportedDataTypes = []string{"float", "int", "boolean", "string"}

type Channel struct {
	Id              int         `sql:"type:integer" json:"-"`
	Name            string      `sql:"type:varchar(255);unique_index" json:"name"`
	Description     string      `sql:"type:text" json:"description"`
	Tags            StringSlice `sql:"type:text" json:"tags"`
	Fields          StringMap   `sql:"type:text" json:"fields"`
	MessageHandlers StringSlice `sql:"type:text" json:"message_handlers"`
	AccessTokens    StringSlice `sql:"type:text" json:"access_tokens"`
}

func (c *Channel) validate() error {
	if len(c.Name) == 0 {
		return errors.New("name is empty")
	}

	if len(c.Description) == 0 {
		return errors.New("description is empty")
	}

	if c.Tags == nil {
		c.Tags = StringSlice(make([]string, 0))
	}

	if c.Fields == nil {
		c.Fields = StringMap(make(map[string]string, 0))
	}

	if c.MessageHandlers == nil {
		c.MessageHandlers = StringSlice(make([]string, 0))
	}

	if c.AccessTokens == nil {
		c.AccessTokens = StringSlice(make([]string, 0))
	}

	// skip this validation for now
	// for _, h := range c.MessageHandlers {
	// 	if _, found := SupportedMessageHandlers[h]; !found {
	// 		return errors.New("unsupported message handler: " + h)
	// 	}
	// }

	if len(c.AccessTokens) == 0 {
		return errors.New("access_tokens are empty")
	}

	if len(c.Tags) > 64 {
		return errors.New("too many tags, at most 64 tags are supported")
	}

	tagMap := make(map[string]bool, 0)

	for _, tagName := range c.Tags {
		if !AlphaNumeric(tagName) {
			return errors.New("invalid tag name, only letters, numbers and underscores are allowed")
		}

		if _, found := tagMap[tagName]; found {
			return errors.New(fmt.Sprintf("duplicate tag name: %s", tagName))
		} else {
			tagMap[tagName] = true

			if _, found = c.Fields[tagName]; found {
				return errors.New(fmt.Sprintf("conflicting tag name: %s defined in fields", tagName))
			}
		}
	}

	if len(c.Fields) == 0 {
		return errors.New("fields are empty")
	}

	if len(c.Fields) > 128 {
		return errors.New("too many fields, at most 128 fields are supported")
	}

	for k, v := range c.Fields {
		if !AlphaNumeric(k) {
			return errors.New("invalid field name, only letters, numbers and underscores are allowed")
		}

		if !StringSliceContains(SupportedDataTypes, v) {
			return errors.New(fmt.Sprintf("unsupported datatype on %s: %s, supported datatypes are %s", k, v, strings.Join(SupportedDataTypes, ",")))
		}
	}

	return nil
}

func (c *Channel) BeforeCreate() error {
	return c.validate()
}

func (c *Channel) BeforeUpdate() error {
	ch := &Channel{}
	if found := ch.FindById(c.Id); !found {
		return errors.New("record not found")
	}

	//removing a tag is not allowed
	for _, t := range ch.Tags {
		if !StringSliceContains(c.Tags, t) {
			return errors.New("removing a tag is not allowed: " + t)
		}
	}

	// removing or modifying a field is not allowed
	for k, v := range ch.Fields {
		if fv, found := c.Fields[k]; !found {
			return errors.New("removing a field is not allowed: " + k)
		} else if v != fv {
			return errors.New("changing a field type is not allowed: " + k)
		}
	}

	return c.validate()
}

func (c *Channel) Create() error {
	return DB.Create(c).Error
}

func (c *Channel) Delete() error {
	return DB.Delete(c).Error
}

func (c *Channel) Update() error {
	return DB.Save(c).Error
}

func (c *Channel) FindById(id int) bool {
	DB.First(c, id)
	return !DB.NewRecord(c)
}

func (c *Channel) Base64Id() string {
	return base64.URLEncoding.EncodeToString([]byte(strconv.Itoa(c.Id)))
}

func (c *Channel) IndexStats() (*elastic.IndicesStatsResponse, error) {
	return IndexClient.IndexStats().Index(GlobIndexName(c)).Do()
}

func (c *Channel) Indices() []string {
	indices := []string{}
	stats, found := FetchCachedChannelIndexStatsById(c.Id)
	if found && stats.Indices != nil {
		for k, _ := range stats.Indices {
			indices = append(indices, k)
		}
	}
	return indices
}

func FetchCachedChannelById(id int) (*Channel, bool) {
	cacheKey := fmt.Sprintf("cache.channel:%d", id)
	ch, err := Cache.Fetch(cacheKey, 1*time.Minute, func() (interface{}, error) {
		c := &Channel{}
		found := c.FindById(id)
		if found {
			return c, nil
		} else {
			return nil, errors.New("channel not found")
		}
	})

	if err == nil {
		return ch.(*Channel), true
	} else {
		return nil, false
	}
}

func FetchCachedChannelIndexStatsById(id int) (*elastic.IndicesStatsResponse, bool) {
	cacheKey := fmt.Sprintf("cache.channel_stats:%d", id)
	resp, err := Cache.Fetch(cacheKey, 1*time.Minute, func() (interface{}, error) {
		c := &Channel{}
		found := c.FindById(id)
		if !found {
			return nil, errors.New("channel not found")
		} else {
			return c.IndexStats()
		}
	})

	if err == nil {
		return resp.(*elastic.IndicesStatsResponse), true
	} else {
		return nil, false
	}
}
<commit_msg>prevent channel id to be reused<commit_after>package models

import (
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/vivowares/octopus/Godeps/_workspace/src/gopkg.in/olivere/elastic.v3"
	. "github.com/vivowares/octopus/utils"
	"strconv"
	"strings"
	"time"
)

var SupportedDataTypes = []string{"float", "int", "boolean", "string"}

type Channel struct {
	Id              int         `sql:"type:integer primary key autoincrement" json:"-"`
	Name            string      `sql:"type:varchar(255);unique_index" json:"name"`
	Description     string      `sql:"type:text" json:"description"`
	Tags            StringSlice `sql:"type:text" json:"tags"`
	Fields          StringMap   `sql:"type:text" json:"fields"`
	MessageHandlers StringSlice `sql:"type:text" json:"message_handlers"`
	AccessTokens    StringSlice `sql:"type:text" json:"access_tokens"`
}

func (c *Channel) validate() error {
	if len(c.Name) == 0 {
		return errors.New("name is empty")
	}

	if len(c.Description) == 0 {
		return errors.New("description is empty")
	}

	if c.Tags == nil {
		c.Tags = StringSlice(make([]string, 0))
	}

	if c.Fields == nil {
		c.Fields = StringMap(make(map[string]string, 0))
	}

	if c.MessageHandlers == nil {
		c.MessageHandlers = StringSlice(make([]string, 0))
	}

	if c.AccessTokens == nil {
		c.AccessTokens = StringSlice(make([]string, 0))
	}

	// skip this validation for now
	// for _, h := range c.MessageHandlers {
	// 	if _, found := SupportedMessageHandlers[h]; !found {
	// 		return errors.New("unsupported message handler: " + h)
	// 	}
	// }

	if len(c.AccessTokens) == 0 {
		return errors.New("access_tokens are empty")
	}

	if len(c.Tags) > 64 {
		return errors.New("too many tags, at most 64 tags are supported")
	}

	tagMap := make(map[string]bool, 0)

	for _, tagName := range c.Tags {
		if !AlphaNumeric(tagName) {
			return errors.New("invalid tag name, only letters, numbers and underscores are allowed")
		}

		if _, found := tagMap[tagName]; found {
			return errors.New(fmt.Sprintf("duplicate tag name: %s", tagName))
		} else {
			tagMap[tagName] = true

			if _, found = c.Fields[tagName]; found {
				return errors.New(fmt.Sprintf("conflicting tag name: %s defined in fields", tagName))
			}
		}
	}

	if len(c.Fields) == 0 {
		return errors.New("fields are empty")
	}

	if len(c.Fields) > 128 {
		return errors.New("too many fields, at most 128 fields are supported")
	}

	for k, v := range c.Fields {
		if !AlphaNumeric(k) {
			return errors.New("invalid field name, only letters, numbers and underscores are allowed")
		}

		if !StringSliceContains(SupportedDataTypes, v) {
			return errors.New(fmt.Sprintf("unsupported datatype on %s: %s, supported datatypes are %s", k, v, strings.Join(SupportedDataTypes, ",")))
		}
	}

	return nil
}

func (c *Channel) BeforeCreate() error {
	return c.validate()
}

func (c *Channel) BeforeUpdate() error {
	ch := &Channel{}
	if found := ch.FindById(c.Id); !found {
		return errors.New("record not found")
	}

	//removing a tag is not allowed
	for _, t := range ch.Tags {
		if !StringSliceContains(c.Tags, t) {
			return errors.New("removing a tag is not allowed: " + t)
		}
	}

	// removing or modifying a field is not allowed
	for k, v := range ch.Fields {
		if fv, found := c.Fields[k]; !found {
			return errors.New("removing a field is not allowed: " + k)
		} else if v != fv {
			return errors.New("changing a field type is not allowed: " + k)
		}
	}

	return c.validate()
}

func (c *Channel) Create() error {
	return DB.Create(c).Error
}

func (c *Channel) Delete() error {
	return DB.Delete(c).Error
}

func (c *Channel) Update() error {
	return DB.Save(c).Error
}

func (c *Channel) FindById(id int) bool {
	DB.First(c, id)
	return !DB.NewRecord(c)
}

func (c *Channel) Base64Id() string {
	return base64.URLEncoding.EncodeToString([]byte(strconv.Itoa(c.Id)))
}

func (c *Channel) IndexStats() (*elastic.IndicesStatsResponse, error) {
	return IndexClient.IndexStats().Index(GlobIndexName(c)).Do()
}

func (c *Channel) Indices() []string {
	indices := []string{}
	stats, found := FetchCachedChannelIndexStatsById(c.Id)
	if found && stats.Indices != nil {
		for k, _ := range stats.Indices {
			indices = append(indices, k)
		}
	}
	return indices
}

func FetchCachedChannelById(id int) (*Channel, bool) {
	cacheKey := fmt.Sprintf("cache.channel:%d", id)
	ch, err := Cache.Fetch(cacheKey, 1*time.Minute, func() (interface{}, error) {
		c := &Channel{}
		found := c.FindById(id)
		if found {
			return c, nil
		} else {
			return nil, errors.New("channel not found")
		}
	})

	if err == nil {
		return ch.(*Channel), true
	} else {
		return nil, false
	}
}

func FetchCachedChannelIndexStatsById(id int) (*elastic.IndicesStatsResponse, bool) {
	cacheKey := fmt.Sprintf("cache.channel_stats:%d", id)
	resp, err := Cache.Fetch(cacheKey, 1*time.Minute, func() (interface{}, error) {
		c := &Channel{}
		found := c.FindById(id)
		if !found {
			return nil, errors.New("channel not found")
		} else {
			return c.IndexStats()
		}
	})

	if err == nil {
		return resp.(*elastic.IndicesStatsResponse), true
	} else {
		return nil, false
	}
}
<|endoftext|>


<commit_before>package schema

type Table struct {
	// Caller=you, SuppliesPK=are you supplying the PK or is
	// the database setting it for you? If true, then YOU
	// are responsible! Otherwise, the schema should involve
	// an auto-increment field, or a UUID sequence, or something.
	CallerSuppliesPK bool
	MultiKey         bool

	// TODO(rbastic): Document all these parameters.
	TableOpts string
	Primary   string
	Name      string
	// TODO(rbastic): document this
	AliasName string
	// dyndao supports one JSON bucket per table for now
	JSONCol string

	ForeignKeys      []string
	EssentialColumns []string
	// List of table names that this table is a 'child' of
	ParentTables []string

	Columns       map[string]*Column
	ColumnAliases map[string]string

	// List of table names that this table is a parent of
	Children map[string]*ChildTable

	// TODO: ChildrenInsertionOrder?
	// TODO: DeletionOrder?
}

// NewTable returns an empty table ready to be populated
func NewTable() *Table {
	fieldsMap := make(map[string]*Column)
	childrenMap := make(map[string]*ChildTable)
	emptyAliasesMap := make(map[string]string)

	tbl := &Table{
		Primary:          "",
		Columns:          fieldsMap,
		EssentialColumns: nil,
		Children:         childrenMap,
		ColumnAliases:    emptyAliasesMap,
	}
	return tbl
}

// GetTableName returns either ourDefault or the override string. It is assumed that you'll pass in the table key (schema.Tables[key]) and the table name (schema.Tables[key].Name), so that this wrapper function can decide.
func GetTableName(override string, ourDefault string) string {
	if override != "" {
		return override
	}
	return ourDefault
}

// GetColumnName returns the correct field name in a potentially aliased environment.
// This is useful in situations where you aren't sure what the 'real' key name may potentially be, but might want to perform manual transformations.
func (t *Table) GetColumnName(n string) string {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetColumn returns the correct field in a potentially aliased environment.
func (t *Table) GetColumn(name string) *Column {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[name]
		if !ok {
			// Perhaps it is not an alias
			return t.Columns[name]
		}
		return t.Columns[realName]
	}
	return t.Columns[name]
}

func (t *Table) Named(name string) *Table {
	t.Name = name
	return t
}
<commit_msg>elim TODOs<commit_after>package schema

type Table struct {
	// Caller=you, SuppliesPK=are you supplying the PK or is
	// the database setting it for you? If true, then YOU
	// are responsible! Otherwise, the schema should involve
	// an auto-increment field, or a UUID sequence, or something.
	CallerSuppliesPK bool
	MultiKey         bool

	TableOpts string
	Primary   string
	Name      string
	AliasName string
	// dyndao supports one JSON bucket per table for now
	JSONCol string

	ForeignKeys      []string
	EssentialColumns []string
	// List of table names that this table is a 'child' of
	ParentTables []string

	Columns       map[string]*Column
	ColumnAliases map[string]string

	// List of table names that this table is a parent of
	Children map[string]*ChildTable

}

// NewTable returns an empty table ready to be populated
func NewTable() *Table {
	fieldsMap := make(map[string]*Column)
	childrenMap := make(map[string]*ChildTable)
	emptyAliasesMap := make(map[string]string)

	tbl := &Table{
		Primary:          "",
		Columns:          fieldsMap,
		EssentialColumns: nil,
		Children:         childrenMap,
		ColumnAliases:    emptyAliasesMap,
	}
	return tbl
}

// GetTableName returns either ourDefault or the override string. It is assumed that you'll pass in the table key (schema.Tables[key]) and the table name (schema.Tables[key].Name), so that this wrapper function can decide.
func GetTableName(override string, ourDefault string) string {
	if override != "" {
		return override
	}
	return ourDefault
}

// GetColumnName returns the correct field name in a potentially aliased environment.
// This is useful in situations where you aren't sure what the 'real' key name may potentially be, but might want to perform manual transformations.
func (t *Table) GetColumnName(n string) string {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetColumn returns the correct field in a potentially aliased environment.
func (t *Table) GetColumn(name string) *Column {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[name]
		if !ok {
			// Perhaps it is not an alias
			return t.Columns[name]
		}
		return t.Columns[realName]
	}
	return t.Columns[name]
}

func (t *Table) Named(name string) *Table {
	t.Name = name
	return t
}
<|endoftext|>


<commit_before>package git

import (
	"JustGo/module/util"
	"os"
	"os/exec"
	"path/filepath"
)

func NewRepo(user, name string) {
	cmd := exec.Command("git", "init", "--bare", name+".git")
	os.Mkdir("./repo/"+user, 0777)
	cmd.Dir = filepath.Join(util.WorkingDir(), "repo", user)
	cmd.Run()
}
<commit_msg>import error<commit_after>package git

import (
	"os"
	"os/exec"
	"path/filepath"
)

func NewRepo(user, name string) {
	cmd := exec.Command("git", "init", "--bare", name+".git")
	os.Mkdir("./repo/"+user, 0777)
	cmd.Dir = filepath.Join(util.WorkingDir(), "repo", user)
	cmd.Run()
}
<|endoftext|>


<commit_before>package template

// Functions available to gondola templates

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gnd.la/app/serialize"
	"gnd.la/html"
	"gnd.la/template/assets"
	"gnd.la/util/types"
	"html/template"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func lt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() < v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() < v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() < v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func lte(arg1, arg2 interface{}) (bool, error) {
	lessThan, err := lt(arg1, arg2)
	if lessThan || err != nil {
		return lessThan, err
	}
	return eq(arg1, arg2), nil
}

func gt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() > v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() > v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() > v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func gte(arg1, arg2 interface{}) (bool, error) {
	greaterThan, err := gt(arg1, arg2)
	if greaterThan || err != nil {
		return greaterThan, err
	}
	return eq(arg1, arg2), nil
}

func jsons(arg interface{}) (string, error) {
	if jw, ok := arg.(serialize.JSONWriter); ok {
		var buf bytes.Buffer
		_, err := jw.WriteJSON(&buf)
		return buf.String(), err
	}
	b, err := json.Marshal(arg)
	return string(b), err
}

func _json(arg interface{}) (template.JS, error) {
	s, err := jsons(arg)
	return template.JS(s), err
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else if s, ok := v.(*string); ok {
				key = *s
			} else {
				return nil, fmt.Errorf("Invalid argument to map at index %d, %t instead of string", ii, v)
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

// this returns *[]interface{} so append works on
// slices declared in templates
func _slice(args ...interface{}) *[]interface{} {
	return &args
}

func _append(items interface{}, args ...interface{}) (string, error) {
	val := reflect.ValueOf(items)
	if !val.IsValid() || val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Slice {
		return "", fmt.Errorf("first argument to append must be pointer to slice, it's %T", items)
	}
	sl := val.Elem()
	for _, v := range args {
		vval := reflect.ValueOf(v)
		if !vval.Type().AssignableTo(sl.Type().Elem()) {
			return "", fmt.Errorf("can't append %s to %s", vval.Type(), sl.Type())
		}
		sl = reflect.Append(sl, vval)
	}
	val.Elem().Set(sl)
	return "", nil
}

func deref(arg interface{}) (interface{}, error) {
	v := reflect.ValueOf(arg)
	if v.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("argument to deref must be pointer, not %T", arg)
	}
	return v.Elem().Interface(), nil
}

func mult(args ...interface{}) (interface{}, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func add(args ...interface{}) (interface{}, error) {
	val := 0.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val += float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val += float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val += value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("error parsing string passed to add() at index %d: %s", ii, err)
			}
			val += v
		default:
			return 0, fmt.Errorf("invalid argument of type %T passed to add() at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func divisible(n interface{}, d interface{}) (bool, error) {
	ni, err := types.ToInt(n)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid number %v: %s", n, err)
	}
	di, err := types.ToInt(d)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid divisor %v: %s", d, err)
	}
	return ni%di == 0, nil
}

func even(arg interface{}) (bool, error) {
	return divisible(arg, 2)
}

func odd(arg interface{}) (bool, error) {
	res, err := divisible(arg, 2)
	if err != nil {
		return false, err
	}
	return !res, nil
}

func now() time.Time {
	return time.Now()
}

func toHtml(s string) template.HTML {
	return template.HTML(strings.Replace(html.Escape(s), "\n", "
", -1))
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":        eq,
	"neq":       neq,
	"lt":        lt,
	"lte":       lte,
	"gt":        gt,
	"gte":       gte,
	"json":      _json,
	"jsons":     jsons,
	"nz":        nz,
	"lower":     lower,
	"join":      join,
	"map":       _map,
	"slice":     _slice,
	"append":    _append,
	"deref":     deref,
	"mult":      mult,
	"divisible": divisible,
	"add":       add,
	"even":      even,
	"odd":       odd,
	"render":    assets.Render,
	"concat":    concat,
	"and":       and,
	"or":        or,
	"not":       not,
	"now":       now,
	"to_lower":  strings.ToLower,
	"to_title":  strings.ToTitle,
	"to_upper":  strings.ToUpper,
	"to_html":   toHtml,

	// Go builtins
	"call":     call,
	"html":     template.HTMLEscaper,
	"index":    index,
	"js":       template.JSEscaper,
	"len":      length,
	"print":    fmt.Sprint,
	"printf":   fmt.Sprintf,
	"println":  fmt.Sprintln,
	"urlquery": template.URLQueryEscaper,
}
<commit_msg>Fix error message<commit_after>package template

// Functions available to gondola templates

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gnd.la/app/serialize"
	"gnd.la/html"
	"gnd.la/template/assets"
	"gnd.la/util/types"
	"html/template"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
)

func eq(args ...interface{}) bool {
	if len(args) == 0 {
		return false
	}
	x := args[0]
	switch x := x.(type) {
	case string, int, int64, byte, float32, float64:
		for _, y := range args[1:] {
			if x == y {
				return true
			}
		}
		return false
	}

	for _, y := range args[1:] {
		if reflect.DeepEqual(x, y) {
			return true
		}
	}
	return false
}

func neq(args ...interface{}) bool {
	return !eq(args...)
}

func lt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() < v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() < v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() < v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func lte(arg1, arg2 interface{}) (bool, error) {
	lessThan, err := lt(arg1, arg2)
	if lessThan || err != nil {
		return lessThan, err
	}
	return eq(arg1, arg2), nil
}

func gt(arg1, arg2 interface{}) (bool, error) {
	v1 := reflect.ValueOf(arg1)
	v2 := reflect.ValueOf(arg2)
	t1 := v1.Type()
	t2 := v2.Type()
	switch {
	case types.IsInt(t1) && types.IsInt(t2):
		return v1.Int() > v2.Int(), nil
	case types.IsUint(t1) && types.IsUint(t2):
		return v1.Uint() > v2.Uint(), nil
	case types.IsFloat(t1) && types.IsFloat(t2):
		return v1.Float() > v2.Float(), nil
	}
	return false, fmt.Errorf("can't compare %T with %T", arg1, arg2)
}

func gte(arg1, arg2 interface{}) (bool, error) {
	greaterThan, err := gt(arg1, arg2)
	if greaterThan || err != nil {
		return greaterThan, err
	}
	return eq(arg1, arg2), nil
}

func jsons(arg interface{}) (string, error) {
	if jw, ok := arg.(serialize.JSONWriter); ok {
		var buf bytes.Buffer
		_, err := jw.WriteJSON(&buf)
		return buf.String(), err
	}
	b, err := json.Marshal(arg)
	return string(b), err
}

func _json(arg interface{}) (template.JS, error) {
	s, err := jsons(arg)
	return template.JS(s), err
}

func nz(x interface{}) bool {
	switch x := x.(type) {
	case int, uint, int64, uint64, byte, float32, float64:
		return x != 0
	case string:
		return len(x) > 0
	}
	return false
}

func lower(x string) string {
	return strings.ToLower(x)
}

func join(x []string, sep string) string {
	return strings.Join(x, sep)
}

func _map(args ...interface{}) (map[string]interface{}, error) {
	var key string
	m := make(map[string]interface{})
	for ii, v := range args {
		if ii%2 == 0 {
			if s, ok := v.(string); ok {
				key = s
			} else if s, ok := v.(*string); ok {
				key = *s
			} else {
				return nil, fmt.Errorf("invalid argument to map at index %d, %s instead of string", ii, reflect.TypeOf(v))
			}
		} else {
			m[key] = v
		}
	}
	return m, nil
}

// this returns *[]interface{} so append works on
// slices declared in templates
func _slice(args ...interface{}) *[]interface{} {
	return &args
}

func _append(items interface{}, args ...interface{}) (string, error) {
	val := reflect.ValueOf(items)
	if !val.IsValid() || val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Slice {
		return "", fmt.Errorf("first argument to append must be pointer to slice, it's %T", items)
	}
	sl := val.Elem()
	for _, v := range args {
		vval := reflect.ValueOf(v)
		if !vval.Type().AssignableTo(sl.Type().Elem()) {
			return "", fmt.Errorf("can't append %s to %s", vval.Type(), sl.Type())
		}
		sl = reflect.Append(sl, vval)
	}
	val.Elem().Set(sl)
	return "", nil
}

func deref(arg interface{}) (interface{}, error) {
	v := reflect.ValueOf(arg)
	if v.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("argument to deref must be pointer, not %T", arg)
	}
	return v.Elem().Interface(), nil
}

func mult(args ...interface{}) (interface{}, error) {
	val := 1.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val *= float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val *= float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val *= value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("Error parsing string passed to mult at index %d: %s", ii, err)
			}
			val *= v
		default:
			return 0, fmt.Errorf("Invalid argument of type %T passed to mult at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func add(args ...interface{}) (interface{}, error) {
	val := 0.0
	for ii, v := range args {
		value := reflect.ValueOf(v)
		switch value.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			val += float64(value.Int())
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			val += float64(value.Uint())
		case reflect.Float32, reflect.Float64:
			val += value.Float()
		case reflect.String:
			v, err := strconv.ParseFloat(value.String(), 64)
			if err != nil {
				return 0, fmt.Errorf("error parsing string passed to add() at index %d: %s", ii, err)
			}
			val += v
		default:
			return 0, fmt.Errorf("invalid argument of type %T passed to add() at index %d", v, ii)
		}
	}
	if math.Floor(val) == val {
		return int(val), nil
	}
	return val, nil

}

func concat(args ...interface{}) string {
	s := make([]string, len(args))
	for ii, v := range args {
		s[ii] = types.ToString(v)
	}
	return strings.Join(s, "")
}

func and(args ...interface{}) bool {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if !t {
			return false
		}
	}
	return true
}

func or(args ...interface{}) interface{} {
	for _, v := range args {
		t, _ := types.IsTrue(v)
		if t {
			return v
		}
	}
	return nil
}

func not(arg interface{}) bool {
	t, _ := types.IsTrue(arg)
	return !t
}

func divisible(n interface{}, d interface{}) (bool, error) {
	ni, err := types.ToInt(n)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid number %v: %s", n, err)
	}
	di, err := types.ToInt(d)
	if err != nil {
		return false, fmt.Errorf("divisible() invalid divisor %v: %s", d, err)
	}
	return ni%di == 0, nil
}

func even(arg interface{}) (bool, error) {
	return divisible(arg, 2)
}

func odd(arg interface{}) (bool, error) {
	res, err := divisible(arg, 2)
	if err != nil {
		return false, err
	}
	return !res, nil
}

func now() time.Time {
	return time.Now()
}

func toHtml(s string) template.HTML {
	return template.HTML(strings.Replace(html.Escape(s), "\n", "
", -1))
}

var templateFuncs template.FuncMap = template.FuncMap{
	"eq":        eq,
	"neq":       neq,
	"lt":        lt,
	"lte":       lte,
	"gt":        gt,
	"gte":       gte,
	"json":      _json,
	"jsons":     jsons,
	"nz":        nz,
	"lower":     lower,
	"join":      join,
	"map":       _map,
	"slice":     _slice,
	"append":    _append,
	"deref":     deref,
	"mult":      mult,
	"divisible": divisible,
	"add":       add,
	"even":      even,
	"odd":       odd,
	"render":    assets.Render,
	"concat":    concat,
	"and":       and,
	"or":        or,
	"not":       not,
	"now":       now,
	"to_lower":  strings.ToLower,
	"to_title":  strings.ToTitle,
	"to_upper":  strings.ToUpper,
	"to_html":   toHtml,

	// Go builtins
	"call":     call,
	"html":     template.HTMLEscaper,
	"index":    index,
	"js":       template.JSEscaper,
	"len":      length,
	"print":    fmt.Sprint,
	"printf":   fmt.Sprintf,
	"println":  fmt.Sprintln,
	"urlquery": template.URLQueryEscaper,
}
<|endoftext|>


<commit_before>// +build darwin dragonfly freebsd linux netbsd openbsd

package disk

import (
	"syscall"
)

// Space returns total and free bytes available in a directory, e.g. `/`.
// Think of it as "df" UNIX command.
func Space(path string) (total, free int, err error) {
	s := syscall.Statfs_t{}
	err = syscall.Statfs(path, &s)
	if err != nil {
		return
	}
	total = int(s.Bsize) * int(s.Blocks)
	free = int(s.Bsize) * int(s.Bfree)
	return
}
<commit_msg>disk: free: blocks available to unprivileged users, cf. reserved blocks<commit_after>// +build darwin dragonfly freebsd linux netbsd openbsd

package disk

import (
	"syscall"
)

// Space returns total and free bytes available in a directory, e.g. `/`.
// Think of it as "df" UNIX command.
func Space(path string) (total, free int, err error) {
	s := syscall.Statfs_t{}
	err = syscall.Statfs(path, &s)
	if err != nil {
		return
	}
	total = int(s.Bsize) * int(s.Blocks)
	free = int(s.Bsize) * int(s.Bavail)
	return
}
<|endoftext|>


<commit_before>package moxxiConf

import (
	"encoding/json"
	"net/http"
	// "log"
	"strconv"
	"text/template"
)

// FormHandler - creates and returns a Handler for both Query and Form requests
func FormHandler(baseURL, confPath, confExt string, excludes []string,
	confTempl, resTempl template.Template, subdomainLen int) http.HandlerFunc {

	confWriter := confWrite(confPath, confExt, baseURL, subdomainLen, confTempl, excludes)

	return func(w http.ResponseWriter, r *http.Request) {

		err := r.ParseForm()
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		var tls bool

		if r.Form.Get("host") == "" {
			http.Error(w, "no provided hostname", http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if r.Form.Get("ip") == "" {
			http.Error(w, "no provided ip", http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if tls = parseCheckbox(r.Form.Get("tls")); err != nil {
			tls = DefaultBackendTLS
		}

		port, _ := strconv.Atoi(r.Form.Get("port"))
		config, err := confCheck(r.Form.Get("host"), r.Form.Get("ip"), tls, port,
			r.Form["header"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if config, err = confWriter(config); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some log line? or no?
			return
		}

		if err = resTempl.Execute(w, []siteParams{config}); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some long line? or no?
			return
		}
		return
	}
}

// JSONHandler - creates and returns a Handler for JSON body requests
func JSONHandler(config HandlerConfig) http.HandlerFunc {

	confWriter := confWrite(config)

	return func(w http.ResponseWriter, r *http.Request) {

// TODO move this stuff so it's declared once
		var v []struct {
			host           string
			ip             string
			port           int
			tls            bool
			blockedHeaders []string
		}

		decoder := json.NewDecoder(r.Body)
		// TODO this probably introduces a bug where only one json array is decoded
		err := decoder.Decode(&v)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}

		var responseConfig []siteParams

		for _, each := range v {
			confConfig, err := confCheck(each.host, each.ip, each.tls, each.port, each.blockedHeaders)
			if err != nil {
				http.Error(w, err.Error(), http.StatusPreconditionFailed)
				// TODO some log line?
				return
			}

			if confConfig, err = confWriter(confConfig); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				// TODO some log line? or no?
				return
			}

			responseConfig = append(responseConfig, confConfig)
		}

		if err = resTempl.Execute(w, responseConfig); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some long line? or no?
			return
		}
		return
	}
}

// StaticHandler - creates and returns a Handler to simply respond with a static response to every request
func StaticHandler(config HandlerConfig) http.HandlerFunc {
	res, err := ioutil.ReadFile(config.resFile)
	if err != nil {
		log.Printf("bad static response file %s - %v", config.resFile, err)
	}

	return func(w http.ResponseWriter, r *http.Request) {
		if _, err := w.Write(res); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
}
<commit_msg>rewrote handler.go making FormHandler now take a config instead<commit_after>package moxxiConf

import (
	"encoding/json"
	"net/http"
	// "log"
	"strconv"
	"text/template"
)

// FormHandler - creates and returns a Handler for both Query and Form requests
func FormHandler(config) http.HandlerFunc {
	confWriter := confWrite(config)

	return func(w http.ResponseWriter, r *http.Request) {

		err := r.ParseForm()
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		var tls bool

		if r.Form.Get("host") == "" {
			http.Error(w, "no provided hostname", http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if r.Form.Get("ip") == "" {
			http.Error(w, "no provided ip", http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if tls = parseCheckbox(r.Form.Get("tls")); err != nil {
			tls = DefaultBackendTLS
		}

		port, _ := strconv.Atoi(r.Form.Get("port"))
		siteConfig, err := confCheck(r.Form.Get("host"), r.Form.Get("ip"), tls, port,
			r.Form["header"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusPreconditionFailed)
			// TODO some log line?
			return
		}

		if siteConfig, err = confWriter(siteConfig); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some log line? or no?
			return
		}

		if err = resTempl.Execute(w, []siteParams{siteConfig}); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some long line? or no?
			return
		}
		return
	}
}

// JSONHandler - creates and returns a Handler for JSON body requests
func JSONHandler(config HandlerConfig) http.HandlerFunc {

	confWriter := confWrite(config)

	return func(w http.ResponseWriter, r *http.Request) {

// TODO move this stuff so it's declared once
		var v []struct {
			host           string
			ip             string
			port           int
			tls            bool
			blockedHeaders []string
		}

		decoder := json.NewDecoder(r.Body)
		// TODO this probably introduces a bug where only one json array is decoded
		err := decoder.Decode(&v)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
		}

		var responseConfig []siteParams

		for _, each := range v {
			confConfig, err := confCheck(each.host, each.ip, each.tls, each.port, each.blockedHeaders)
			if err != nil {
				http.Error(w, err.Error(), http.StatusPreconditionFailed)
				// TODO some log line?
				return
			}

			if confConfig, err = confWriter(confConfig); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				// TODO some log line? or no?
				return
			}

			responseConfig = append(responseConfig, confConfig)
		}

		if err = resTempl.Execute(w, responseConfig); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			// TODO some long line? or no?
			return
		}
		return
	}
}

// StaticHandler - creates and returns a Handler to simply respond with a static response to every request
func StaticHandler(config HandlerConfig) http.HandlerFunc {
	res, err := ioutil.ReadFile(config.resFile)
	if err != nil {
		log.Printf("bad static response file %s - %v", config.resFile, err)
	}

	return func(w http.ResponseWriter, r *http.Request) {
		if _, err := w.Write(res); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path"
	"strconv"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/pulse"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/pulseprofile"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

type PulseService struct {
	requestFactory
	Synchronous
}

// PublicPulseProfile get pulse profile by nickname
func (ps *PulseService) PublicPulseProfile(nickname string) (*pulseprofile.PulseProfile, error) {
	if (len(nickname)) == 0 {
		return nil, fmt.Errorf("nickname is required argument")
	}

	req := NewRequestWithMethod(path.Join("pulse", "profile", nickname), "GET")
	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pp, err := pulseprofile.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pp, nil
}

// PublicPulseHistory returns public pulse messages
func (ps *PulseService) PublicPulseHistory(limit, end int) ([]*pulse.Pulse, error) {
	req := NewRequestWithMethod(path.Join("pulse", "hist"), "GET")
	req.Params = make(url.Values)
	req.Params.Add("limit", strconv.Itoa(limit))
	req.Params.Add("end", strconv.Itoa(end))

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pph, err := pulse.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pph, nil
}

// AddPulse submits pulse messages
func (ps *PulseService) AddPulse(p *pulse.Pulse) (*pulse.Pulse, error) {
	tl := len(p.Title)
	if tl < 16 || tl > 120 {
		return nil, fmt.Errorf("Title length min 16 and max 120 characters. Got:%d", tl)
	}

	payload, err := json.Marshal(p)
	if err != nil {
		return nil, err
	}

	req, err := ps.requestFactory.NewAuthenticatedRequestWithBytes(bitfinex.PermissionWrite, path.Join("pulse", "add"), payload)
	if err != nil {
		return nil, err
	}

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pm, err := pulse.NewSingleFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pm, nil
}

// PulseHistory returns private pulse messages
func (ps *PulseService) PulseHistory(isPublic int) ([]*pulse.Pulse, error) {
	req, err := ps.NewAuthenticatedRequest(bitfinex.PermissionRead, path.Join("pulse", "hist"))
	if err != nil {
		return nil, err
	}

	req.Params = make(url.Values)
	req.Params.Add("isPublic", strconv.Itoa(isPublic))

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pph, err := pulse.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pph, nil
}

// DeletePulse removes pulse, returns 0 if no pulse was deleted and 1 if it was
func (ps *PulseService) DeletePulse(pid string) (int, error) {
	payload := map[string]interface{}{"pid": pid}

	req, err := ps.NewAuthenticatedRequestWithData(bitfinex.PermissionWrite, path.Join("pulse", "del"), payload)
	if err != nil {
		return 0, err
	}

	raw, err := ps.Request(req)
	if err != nil {
		return 0, err
	}

	return convert.ToInt(raw[0]), nil
}
<commit_msg>updating comments for better docs<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"net/url"
	"path"
	"strconv"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/pulse"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/pulseprofile"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

type PulseService struct {
	requestFactory
	Synchronous
}

// PublicPulseProfile returns details for a specific Pulse profile
// https://docs.bitfinex.com/reference#rest-public-pulse-profile
func (ps *PulseService) PublicPulseProfile(nickname string) (*pulseprofile.PulseProfile, error) {
	if (len(nickname)) == 0 {
		return nil, fmt.Errorf("nickname is required argument")
	}

	req := NewRequestWithMethod(path.Join("pulse", "profile", nickname), "GET")
	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pp, err := pulseprofile.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pp, nil
}

// PublicPulseHistory returns latest pulse messages. You can specify
// an end timestamp to view older messages.
// see https://docs.bitfinex.com/reference#rest-public-pulse-hist
func (ps *PulseService) PublicPulseHistory(limit, end int) ([]*pulse.Pulse, error) {
	req := NewRequestWithMethod(path.Join("pulse", "hist"), "GET")
	req.Params = make(url.Values)
	req.Params.Add("limit", strconv.Itoa(limit))
	req.Params.Add("end", strconv.Itoa(end))

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pph, err := pulse.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pph, nil
}

// AddPulse submits pulse message
// see https://docs.bitfinex.com/reference#rest-auth-pulse-add
func (ps *PulseService) AddPulse(p *pulse.Pulse) (*pulse.Pulse, error) {
	tl := len(p.Title)
	if tl < 16 || tl > 120 {
		return nil, fmt.Errorf("Title length min 16 and max 120 characters. Got:%d", tl)
	}

	payload, err := json.Marshal(p)
	if err != nil {
		return nil, err
	}

	req, err := ps.requestFactory.NewAuthenticatedRequestWithBytes(bitfinex.PermissionWrite, path.Join("pulse", "add"), payload)
	if err != nil {
		return nil, err
	}

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pm, err := pulse.NewSingleFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pm, nil
}

// PulseHistory allows you to retrieve your private pulse history or the public pulse history
// with an additional UID_LIKED field
// see https://docs.bitfinex.com/reference#rest-auth-pulse-hist
func (ps *PulseService) PulseHistory(isPublic int) ([]*pulse.Pulse, error) {
	req, err := ps.NewAuthenticatedRequest(bitfinex.PermissionRead, path.Join("pulse", "hist"))
	if err != nil {
		return nil, err
	}

	req.Params = make(url.Values)
	req.Params.Add("isPublic", strconv.Itoa(isPublic))

	raw, err := ps.Request(req)
	if err != nil {
		return nil, err
	}

	pph, err := pulse.NewFromRaw(raw)
	if err != nil {
		return nil, err
	}

	return pph, nil
}

// DeletePulse removes your pulse message. Returns 0 if no pulse was deleted and 1 if it was
// see https://docs.bitfinex.com/reference#rest-auth-pulse-del
func (ps *PulseService) DeletePulse(pid string) (int, error) {
	payload := map[string]interface{}{"pid": pid}

	req, err := ps.NewAuthenticatedRequestWithData(bitfinex.PermissionWrite, path.Join("pulse", "del"), payload)
	if err != nil {
		return 0, err
	}

	raw, err := ps.Request(req)
	if err != nil {
		return 0, err
	}

	return convert.ToInt(raw[0]), nil
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/coreos/ignition/v2/config"
	"github.com/coreos/ignition/v2/internal/version"
)

var (
	flagVersion bool
)

func init() {
	flag.BoolVar(&flagVersion, "version", false, "print the version of ignition-validate")
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), "Usage:\n  %s config.ign [flags]\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	runIgnValidate(os.Args[1:])
}

func stdout(format string, a ...interface{}) {
	fmt.Fprintf(os.Stdout, strings.TrimSpace(format)+"\n", a...)
}

func stderr(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, strings.TrimSpace(format)+"\n", a...)
}

func die(format string, a ...interface{}) {
	stderr(format, a...)
	os.Exit(1)
}

func runIgnValidate(args []string) {
	if flagVersion {
		stdout(version.String)
		return
	}

	if len(args) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	var blob []byte
	var err error
	if args[0] == "-" {
		blob, err = ioutil.ReadAll(os.Stdin)
	} else {
		blob, err = ioutil.ReadFile(args[0])
	}
	if err != nil {
		die("couldn't read config: %v", err)
	}
	_, rpt, err := config.Parse(blob)
	if len(rpt.Entries) > 0 {
		stdout(rpt.String())
	}
	if rpt.IsFatal() {
		os.Exit(1)
	}
	if err != nil {
		die("couldn't parse config: %v", err)
	}
}
<commit_msg>validate: fix flag handling<commit_after>// Copyright 2018 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/coreos/ignition/v2/config"
	"github.com/coreos/ignition/v2/internal/version"
)

var (
	flagVersion bool
)

func init() {
	flag.BoolVar(&flagVersion, "version", false, "print the version of ignition-validate")
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), "Usage:\n  %s config.ign [flags]\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	runIgnValidate(flag.Args())
}

func stdout(format string, a ...interface{}) {
	fmt.Fprintf(os.Stdout, strings.TrimSpace(format)+"\n", a...)
}

func stderr(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, strings.TrimSpace(format)+"\n", a...)
}

func die(format string, a ...interface{}) {
	stderr(format, a...)
	os.Exit(1)
}

func runIgnValidate(args []string) {
	if flagVersion {
		stdout(version.String)
		return
	}

	if len(args) != 1 {
		flag.Usage()
		os.Exit(1)
	}
	var blob []byte
	var err error
	if args[0] == "-" {
		blob, err = ioutil.ReadAll(os.Stdin)
	} else {
		blob, err = ioutil.ReadFile(args[0])
	}
	if err != nil {
		die("couldn't read config: %v", err)
	}
	_, rpt, err := config.Parse(blob)
	if len(rpt.Entries) > 0 {
		stdout(rpt.String())
	}
	if rpt.IsFatal() {
		os.Exit(1)
	}
	if err != nil {
		die("couldn't parse config: %v", err)
	}
}
<|endoftext|>


<commit_before>// Package vector implements persistent vector.
package vector

import (
	"bytes"
	"encoding/json"
	"fmt"
)

const (
	chunkBits  = 5
	nodeSize   = 1 << chunkBits
	tailMaxLen = nodeSize
	chunkMask  = nodeSize - 1
)

// Vector is a persistent sequential container for arbitrary values. It supports
// O(1) lookup by index, modification by index, and insertion and removal
// operations at the end. Being a persistent variant of the data structure, it
// is immutable, and provides O(1) operations to create modified versions of the
// vector that shares the underlying data structure, making it suitable for
// concurrent access. The empty value is a valid empty vector.
type Vector interface {
	json.Marshaler
	// Len returns the length of the vector.
	Len() int
	// Nth returns the i-th element of the vector. It returns nil if the index
	// is smaller than 0 or greater than or equal to the length of the vector.
	Nth(i int) interface{}
	// AssocN returns an almost identical Vector, with the i-th element
	// replaced. If the index is smaller than 0 or greater than the length of
	// the vector, it returns nil. If the index is equal to the size of the
	// vector, it is equivalent to Cons.
	AssocN(i int, val interface{}) Vector
	// Cons returns an almost identical Vector, with an additional element
	// appended to the end.
	Cons(val interface{}) Vector
	// Pop returns an almost identical Vector, with the last element removed. It
	// returns nil if the vector is already empty.
	Pop() Vector
	// SubVector returns a subvector containing the elements from i up to but
	// not including j.
	SubVector(i, j int) Vector
	// Iterator returns an iterator over the vector.
	Iterator() Iterator
}

// Iterator is an iterator over vector elements. It can be used like this:
//
//     for it := v.Iterator(); it.HasElem(); it.Next() {
//         elem := it.Elem()
//         // do something with elem...
//     }
type Iterator interface {
	// Elem returns the element at the current position.
	Elem() interface{}
	// HasElem returns whether the iterator is pointing to an element.
	HasElem() bool
	// Next moves the iterator to the next position.
	Next()
}

type vector struct {
	count int
	// height of the tree structure, defined to be 0 when root is a leaf.
	height uint
	root   node
	tail   []interface{}
}

// Empty is an empty Vector.
var Empty Vector = &vector{}

// node is a node in the vector tree. It is always of the size nodeSize.
type node []interface{}

func newNode() node {
	return node(make([]interface{}, nodeSize))
}

func (n node) clone() node {
	m := newNode()
	copy(m, n)
	return m
}

// Count returns the number of elements in a Vector.
func (v *vector) Len() int {
	return v.count
}

// treeSize returns the number of elements stored in the tree (as opposed to the
// tail).
func (v *vector) treeSize() int {
	if v.count < tailMaxLen {
		return 0
	}
	return ((v.count - 1) >> chunkBits) << chunkBits
}

// sliceFor returns the slice where the i-th element is stored. The index must
// be in bound.
func (v *vector) sliceFor(i int) []interface{} {
	if i >= v.treeSize() {
		return v.tail
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n
}

func (v *vector) Nth(i int) interface{} {
	if i < 0 || i >= v.count {
		return nil
	}
	return v.sliceFor(i)[i&chunkMask]
}

func (v *vector) AssocN(i int, val interface{}) Vector {
	if i < 0 || i > v.count {
		return nil
	} else if i == v.count {
		return v.Cons(val)
	}
	if i >= v.treeSize() {
		newTail := append([]interface{}(nil), v.tail...)
		copy(newTail, v.tail)
		newTail[i&chunkMask] = val
		return &vector{v.count, v.height, v.root, newTail}
	}
	return &vector{v.count, v.height, doAssoc(v.height, v.root, i, val), v.tail}
}

// doAssoc returns an almost identical tree, with the i-th element replaced by
// val.
func doAssoc(height uint, n node, i int, val interface{}) node {
	m := n.clone()
	if height == 0 {
		m[i&chunkMask] = val
	} else {
		sub := (i >> (height * chunkBits)) & chunkMask
		m[sub] = doAssoc(height-1, m[sub].(node), i, val)
	}
	return m
}

func (v *vector) Cons(val interface{}) Vector {
	// Room in tail?
	if v.count-v.treeSize() < tailMaxLen {
		newTail := make([]interface{}, len(v.tail)+1)
		copy(newTail, v.tail)
		newTail[len(v.tail)] = val
		return &vector{v.count + 1, v.height, v.root, newTail}
	}
	// Full tail; push into tree.
	tailNode := node(v.tail)
	newHeight := v.height
	var newRoot node
	// Overflow root?
	if (v.count >> chunkBits) > (1 << (v.height * chunkBits)) {
		newRoot = newNode()
		newRoot[0] = v.root
		newRoot[1] = newPath(v.height, tailNode)
		newHeight++
	} else {
		newRoot = v.pushTail(v.height, v.root, tailNode)
	}
	return &vector{v.count + 1, newHeight, newRoot, []interface{}{val}}
}

// pushTail returns a tree with tail appended.
func (v *vector) pushTail(height uint, n node, tail node) node {
	if height == 0 {
		return tail
	}
	idx := ((v.count - 1) >> (height * chunkBits)) & chunkMask
	m := n.clone()
	child := n[idx]
	if child == nil {
		m[idx] = newPath(height-1, tail)
	} else {
		m[idx] = v.pushTail(height-1, child.(node), tail)
	}
	return m
}

// newPath creates a left-branching tree of specified height and leaf.
func newPath(height uint, leaf node) node {
	if height == 0 {
		return leaf
	}
	ret := newNode()
	ret[0] = newPath(height-1, leaf)
	return ret
}

func (v *vector) Pop() Vector {
	switch v.count {
	case 0:
		return nil
	case 1:
		return Empty
	}
	if v.count-v.treeSize() > 1 {
		newTail := make([]interface{}, len(v.tail)-1)
		copy(newTail, v.tail)
		return &vector{v.count - 1, v.height, v.root, newTail}
	}
	newTail := v.sliceFor(v.count - 2)
	newRoot := v.popTail(v.height, v.root)
	newHeight := v.height
	if v.height > 0 && newRoot[1] == nil {
		newRoot = newRoot[0].(node)
		newHeight--
	}
	return &vector{v.count - 1, newHeight, newRoot, newTail}
}

// popTail returns a new tree with the last leaf removed.
func (v *vector) popTail(level uint, n node) node {
	idx := ((v.count - 2) >> (level * chunkBits)) & chunkMask
	if level > 1 {
		newChild := v.popTail(level-1, n[idx].(node))
		if newChild == nil && idx == 0 {
			return nil
		}
		m := n.clone()
		if newChild == nil {
			// This is needed since `m[idx] = newChild` would store an
			// interface{} with a non-nil type part, which is non-nil
			m[idx] = nil
		} else {
			m[idx] = newChild
		}
		return m
	} else if idx == 0 {
		return nil
	} else {
		m := n.clone()
		m[idx] = nil
		return m
	}
}

func (v *vector) SubVector(begin, end int) Vector {
	if begin < 0 || begin > end || end > v.count {
		return nil
	}
	return &subVector{v, begin, end}
}

func (v *vector) Iterator() Iterator {
	return newIterator(v)
}

func (v *vector) MarshalJSON() ([]byte, error) {
	return marshalJSON(v.Iterator())
}

type subVector struct {
	v     *vector
	begin int
	end   int
}

func (s *subVector) Len() int {
	return s.end - s.begin
}

func (s *subVector) Nth(i int) interface{} {
	if i < 0 || s.begin+i >= s.end {
		return nil
	}
	return s.v.Nth(s.begin + i)
}

func (s *subVector) AssocN(i int, val interface{}) Vector {
	if i < 0 || s.begin+i > s.end {
		return nil
	} else if s.begin+i == s.end {
		return s.Cons(val)
	}
	return s.v.AssocN(s.begin+i, val).SubVector(s.begin, s.end)
}

func (s *subVector) Cons(val interface{}) Vector {
	return s.v.AssocN(s.end, val).SubVector(s.begin, s.end+1)
}

func (s *subVector) Pop() Vector {
	switch s.Len() {
	case 0:
		return nil
	case 1:
		return Empty
	default:
		return s.v.SubVector(s.begin, s.end-1)
	}
}

func (s *subVector) SubVector(i, j int) Vector {
	return s.v.SubVector(s.begin+i, s.begin+j)
}

func (s *subVector) Iterator() Iterator {
	return newIteratorWithRange(s.v, s.begin, s.end)
}

func (s *subVector) MarshalJSON() ([]byte, error) {
	return marshalJSON(s.Iterator())
}

type iterator struct {
	v        *vector
	treeSize int
	index    int
	end      int
	path     []pathEntry
}

type pathEntry struct {
	node  node
	index int
}

func (e pathEntry) current() interface{} {
	return e.node[e.index]
}

func newIterator(v *vector) *iterator {
	return newIteratorWithRange(v, 0, v.Len())
}

func newIteratorWithRange(v *vector, begin, end int) *iterator {
	it := &iterator{v, v.treeSize(), begin, end, nil}
	// Find the node for begin, remembering all nodes along the path.
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		idx := (begin >> shift) & chunkMask
		it.path = append(it.path, pathEntry{n, idx})
		n = n[idx].(node)
	}
	it.path = append(it.path, pathEntry{n, begin & chunkMask})
	return it
}

func (it *iterator) Elem() interface{} {
	if it.index >= it.treeSize {
		return it.v.tail[it.index-it.treeSize]
	}
	return it.path[len(it.path)-1].current()
}

func (it *iterator) HasElem() bool {
	return it.index < it.end
}

func (it *iterator) Next() {
	if it.index+1 >= it.treeSize {
		// Next element is in tail. Just increment the index.
		it.index++
		return
	}
	// Find the deepest level that can be advanced.
	var i int
	for i = len(it.path) - 1; i >= 0; i-- {
		e := it.path[i]
		if e.index+1 < len(e.node) && e.node[e.index+1] != nil {
			break
		}
	}
	if i == -1 {
		panic("cannot advance; vector iterator bug")
	}
	// Advance on this node, and re-populate all deeper levels.
	it.path[i].index++
	for i++; i < len(it.path); i++ {
		it.path[i] = pathEntry{it.path[i-1].current().(node), 0}
	}
	it.index++
}

type marshalError struct {
	index int
	cause error
}

func (err *marshalError) Error() string {
	return fmt.Sprintf("element %d: %s", err.index, err.cause)
}

func marshalJSON(it Iterator) ([]byte, error) {
	var buf bytes.Buffer
	buf.WriteByte('[')
	index := 0
	for ; it.HasElem(); it.Next() {
		if index > 0 {
			buf.WriteByte(',')
		}
		elemBytes, err := json.Marshal(it.Elem())
		if err != nil {
			return nil, &marshalError{index, err}
		}
		buf.Write(elemBytes)
		index++
	}
	buf.WriteByte(']')
	return buf.Bytes(), nil
}
<commit_msg>vector: Use an array pointer instead of slice for node.<commit_after>// Package vector implements persistent vector.
package vector

import (
	"bytes"
	"encoding/json"
	"fmt"
)

const (
	chunkBits  = 5
	nodeSize   = 1 << chunkBits
	tailMaxLen = nodeSize
	chunkMask  = nodeSize - 1
)

// Vector is a persistent sequential container for arbitrary values. It supports
// O(1) lookup by index, modification by index, and insertion and removal
// operations at the end. Being a persistent variant of the data structure, it
// is immutable, and provides O(1) operations to create modified versions of the
// vector that shares the underlying data structure, making it suitable for
// concurrent access. The empty value is a valid empty vector.
type Vector interface {
	json.Marshaler
	// Len returns the length of the vector.
	Len() int
	// Nth returns the i-th element of the vector. It returns nil if the index
	// is smaller than 0 or greater than or equal to the length of the vector.
	Nth(i int) interface{}
	// AssocN returns an almost identical Vector, with the i-th element
	// replaced. If the index is smaller than 0 or greater than the length of
	// the vector, it returns nil. If the index is equal to the size of the
	// vector, it is equivalent to Cons.
	AssocN(i int, val interface{}) Vector
	// Cons returns an almost identical Vector, with an additional element
	// appended to the end.
	Cons(val interface{}) Vector
	// Pop returns an almost identical Vector, with the last element removed. It
	// returns nil if the vector is already empty.
	Pop() Vector
	// SubVector returns a subvector containing the elements from i up to but
	// not including j.
	SubVector(i, j int) Vector
	// Iterator returns an iterator over the vector.
	Iterator() Iterator
}

// Iterator is an iterator over vector elements. It can be used like this:
//
//     for it := v.Iterator(); it.HasElem(); it.Next() {
//         elem := it.Elem()
//         // do something with elem...
//     }
type Iterator interface {
	// Elem returns the element at the current position.
	Elem() interface{}
	// HasElem returns whether the iterator is pointing to an element.
	HasElem() bool
	// Next moves the iterator to the next position.
	Next()
}

type vector struct {
	count int
	// height of the tree structure, defined to be 0 when root is a leaf.
	height uint
	root   node
	tail   []interface{}
}

// Empty is an empty Vector.
var Empty Vector = &vector{}

// node is a node in the vector tree. It is always of the size nodeSize.
type node *[nodeSize]interface{}

func newNode() node {
	return node(&[nodeSize]interface{}{})
}

func clone(n node) node {
	a := *n
	return node(&a)
}

func nodeFromSlice(s []interface{}) node {
	var n [nodeSize]interface{}
	copy(n[:], s)
	return &n
}

// Count returns the number of elements in a Vector.
func (v *vector) Len() int {
	return v.count
}

// treeSize returns the number of elements stored in the tree (as opposed to the
// tail).
func (v *vector) treeSize() int {
	if v.count < tailMaxLen {
		return 0
	}
	return ((v.count - 1) >> chunkBits) << chunkBits
}

// sliceFor returns the slice where the i-th element is stored. The index must
// be in bound.
func (v *vector) sliceFor(i int) []interface{} {
	if i >= v.treeSize() {
		return v.tail
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n[:]
}

func (v *vector) Nth(i int) interface{} {
	if i < 0 || i >= v.count {
		return nil
	}
	return v.sliceFor(i)[i&chunkMask]
}

func (v *vector) AssocN(i int, val interface{}) Vector {
	if i < 0 || i > v.count {
		return nil
	} else if i == v.count {
		return v.Cons(val)
	}
	if i >= v.treeSize() {
		newTail := append([]interface{}(nil), v.tail...)
		copy(newTail, v.tail)
		newTail[i&chunkMask] = val
		return &vector{v.count, v.height, v.root, newTail}
	}
	return &vector{v.count, v.height, doAssoc(v.height, v.root, i, val), v.tail}
}

// doAssoc returns an almost identical tree, with the i-th element replaced by
// val.
func doAssoc(height uint, n node, i int, val interface{}) node {
	m := clone(n)
	if height == 0 {
		m[i&chunkMask] = val
	} else {
		sub := (i >> (height * chunkBits)) & chunkMask
		m[sub] = doAssoc(height-1, m[sub].(node), i, val)
	}
	return m
}

func (v *vector) Cons(val interface{}) Vector {
	// Room in tail?
	if v.count-v.treeSize() < tailMaxLen {
		newTail := make([]interface{}, len(v.tail)+1)
		copy(newTail, v.tail)
		newTail[len(v.tail)] = val
		return &vector{v.count + 1, v.height, v.root, newTail}
	}
	// Full tail; push into tree.
	tailNode := nodeFromSlice(v.tail)
	newHeight := v.height
	var newRoot node
	// Overflow root?
	if (v.count >> chunkBits) > (1 << (v.height * chunkBits)) {
		newRoot = newNode()
		newRoot[0] = v.root
		newRoot[1] = newPath(v.height, tailNode)
		newHeight++
	} else {
		newRoot = v.pushTail(v.height, v.root, tailNode)
	}
	return &vector{v.count + 1, newHeight, newRoot, []interface{}{val}}
}

// pushTail returns a tree with tail appended.
func (v *vector) pushTail(height uint, n node, tail node) node {
	if height == 0 {
		return tail
	}
	idx := ((v.count - 1) >> (height * chunkBits)) & chunkMask
	m := clone(n)
	child := n[idx]
	if child == nil {
		m[idx] = newPath(height-1, tail)
	} else {
		m[idx] = v.pushTail(height-1, child.(node), tail)
	}
	return m
}

// newPath creates a left-branching tree of specified height and leaf.
func newPath(height uint, leaf node) node {
	if height == 0 {
		return leaf
	}
	ret := newNode()
	ret[0] = newPath(height-1, leaf)
	return ret
}

func (v *vector) Pop() Vector {
	switch v.count {
	case 0:
		return nil
	case 1:
		return Empty
	}
	if v.count-v.treeSize() > 1 {
		newTail := make([]interface{}, len(v.tail)-1)
		copy(newTail, v.tail)
		return &vector{v.count - 1, v.height, v.root, newTail}
	}
	newTail := v.sliceFor(v.count - 2)
	newRoot := v.popTail(v.height, v.root)
	newHeight := v.height
	if v.height > 0 && newRoot[1] == nil {
		newRoot = newRoot[0].(node)
		newHeight--
	}
	return &vector{v.count - 1, newHeight, newRoot, newTail}
}

// popTail returns a new tree with the last leaf removed.
func (v *vector) popTail(level uint, n node) node {
	idx := ((v.count - 2) >> (level * chunkBits)) & chunkMask
	if level > 1 {
		newChild := v.popTail(level-1, n[idx].(node))
		if newChild == nil && idx == 0 {
			return nil
		}
		m := clone(n)
		if newChild == nil {
			// This is needed since `m[idx] = newChild` would store an
			// interface{} with a non-nil type part, which is non-nil
			m[idx] = nil
		} else {
			m[idx] = newChild
		}
		return m
	} else if idx == 0 {
		return nil
	} else {
		m := clone(n)
		m[idx] = nil
		return m
	}
}

func (v *vector) SubVector(begin, end int) Vector {
	if begin < 0 || begin > end || end > v.count {
		return nil
	}
	return &subVector{v, begin, end}
}

func (v *vector) Iterator() Iterator {
	return newIterator(v)
}

func (v *vector) MarshalJSON() ([]byte, error) {
	return marshalJSON(v.Iterator())
}

type subVector struct {
	v     *vector
	begin int
	end   int
}

func (s *subVector) Len() int {
	return s.end - s.begin
}

func (s *subVector) Nth(i int) interface{} {
	if i < 0 || s.begin+i >= s.end {
		return nil
	}
	return s.v.Nth(s.begin + i)
}

func (s *subVector) AssocN(i int, val interface{}) Vector {
	if i < 0 || s.begin+i > s.end {
		return nil
	} else if s.begin+i == s.end {
		return s.Cons(val)
	}
	return s.v.AssocN(s.begin+i, val).SubVector(s.begin, s.end)
}

func (s *subVector) Cons(val interface{}) Vector {
	return s.v.AssocN(s.end, val).SubVector(s.begin, s.end+1)
}

func (s *subVector) Pop() Vector {
	switch s.Len() {
	case 0:
		return nil
	case 1:
		return Empty
	default:
		return s.v.SubVector(s.begin, s.end-1)
	}
}

func (s *subVector) SubVector(i, j int) Vector {
	return s.v.SubVector(s.begin+i, s.begin+j)
}

func (s *subVector) Iterator() Iterator {
	return newIteratorWithRange(s.v, s.begin, s.end)
}

func (s *subVector) MarshalJSON() ([]byte, error) {
	return marshalJSON(s.Iterator())
}

type iterator struct {
	v        *vector
	treeSize int
	index    int
	end      int
	path     []pathEntry
}

type pathEntry struct {
	node  node
	index int
}

func (e pathEntry) current() interface{} {
	return e.node[e.index]
}

func newIterator(v *vector) *iterator {
	return newIteratorWithRange(v, 0, v.Len())
}

func newIteratorWithRange(v *vector, begin, end int) *iterator {
	it := &iterator{v, v.treeSize(), begin, end, nil}
	// Find the node for begin, remembering all nodes along the path.
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		idx := (begin >> shift) & chunkMask
		it.path = append(it.path, pathEntry{n, idx})
		n = n[idx].(node)
	}
	it.path = append(it.path, pathEntry{n, begin & chunkMask})
	return it
}

func (it *iterator) Elem() interface{} {
	if it.index >= it.treeSize {
		return it.v.tail[it.index-it.treeSize]
	}
	return it.path[len(it.path)-1].current()
}

func (it *iterator) HasElem() bool {
	return it.index < it.end
}

func (it *iterator) Next() {
	if it.index+1 >= it.treeSize {
		// Next element is in tail. Just increment the index.
		it.index++
		return
	}
	// Find the deepest level that can be advanced.
	var i int
	for i = len(it.path) - 1; i >= 0; i-- {
		e := it.path[i]
		if e.index+1 < len(e.node) && e.node[e.index+1] != nil {
			break
		}
	}
	if i == -1 {
		panic("cannot advance; vector iterator bug")
	}
	// Advance on this node, and re-populate all deeper levels.
	it.path[i].index++
	for i++; i < len(it.path); i++ {
		it.path[i] = pathEntry{it.path[i-1].current().(node), 0}
	}
	it.index++
}

type marshalError struct {
	index int
	cause error
}

func (err *marshalError) Error() string {
	return fmt.Sprintf("element %d: %s", err.index, err.cause)
}

func marshalJSON(it Iterator) ([]byte, error) {
	var buf bytes.Buffer
	buf.WriteByte('[')
	index := 0
	for ; it.HasElem(); it.Next() {
		if index > 0 {
			buf.WriteByte(',')
		}
		elemBytes, err := json.Marshal(it.Elem())
		if err != nil {
			return nil, &marshalError{index, err}
		}
		buf.Write(elemBytes)
		index++
	}
	buf.WriteByte(']')
	return buf.Bytes(), nil
}
<|endoftext|>