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

package embed

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"strings"

	"github.com/coreos/etcd/discovery"
	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/pkg/cors"
	"github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/etcd/pkg/types"
	"github.com/ghodss/yaml"
)

const (
	ClusterStateFlagNew      = "new"
	ClusterStateFlagExisting = "existing"

	DefaultName                     = "default"
	DefaultInitialAdvertisePeerURLs = "http://localhost:2380"
	DefaultAdvertiseClientURLs      = "http://localhost:2379"
	DefaultListenPeerURLs           = "http://localhost:2380"
	DefaultListenClientURLs         = "http://localhost:2379"
	DefaultMaxSnapshots             = 5
	DefaultMaxWALs                  = 5

	// maxElectionMs specifies the maximum value of election timeout.
	// More details are listed in ../Documentation/tuning.md#time-parameters.
	maxElectionMs = 50000
)

var (
	ErrConflictBootstrapFlags = fmt.Errorf("multiple discovery or bootstrap flags are set. " +
		"Choose one of \"initial-cluster\", \"discovery\" or \"discovery-srv\"")
	ErrUnsetAdvertiseClientURLsFlag = fmt.Errorf("--advertise-client-urls is required when --listen-client-urls is set explicitly")
)

// Config holds the arguments for configuring an etcd server.
type Config struct {
	// member

	CorsInfo                *cors.CORSInfo
	LPUrls, LCUrls          []url.URL
	Dir                     string `json:"data-dir"`
	WalDir                  string `json:"wal-dir"`
	MaxSnapFiles            uint   `json:"max-snapshots"`
	MaxWalFiles             uint   `json:"max-wals"`
	Name                    string `json:"name"`
	SnapCount               uint64 `json:"snapshot-count"`
	AutoCompactionRetention int    `json:"auto-compaction-retention"`

	// TickMs is the number of milliseconds between heartbeat ticks.
	// TODO: decouple tickMs and heartbeat tick (current heartbeat tick = 1).
	// make ticks a cluster wide configuration.
	TickMs            uint  `json:"heartbeat-interval"`
	ElectionMs        uint  `json:"election-timeout"`
	QuotaBackendBytes int64 `json:"quota-backend-bytes"`

	// clustering

	APUrls, ACUrls      []url.URL
	ClusterState        string `json:"initial-cluster-state"`
	DNSCluster          string `json:"discovery-srv"`
	Dproxy              string `json:"discovery-proxy"`
	Durl                string `json:"discovery"`
	InitialCluster      string `json:"initial-cluster"`
	InitialClusterToken string `json:"initial-cluster-token"`
	StrictReconfigCheck bool   `json:"strict-reconfig-check"`

	// security

	ClientTLSInfo transport.TLSInfo
	ClientAutoTLS bool
	PeerTLSInfo   transport.TLSInfo
	PeerAutoTLS   bool

	// debug

	Debug        bool   `json:"debug"`
	LogPkgLevels string `json:"log-package-levels"`
	EnablePprof  bool

	// ForceNewCluster starts a new cluster even if previously started; unsafe.
	ForceNewCluster bool `json:"force-new-cluster"`
}

// configYAML holds the config suitable for yaml parsing
type configYAML struct {
	Config
	configJSON
}

// configJSON has file options that are translated into Config options
type configJSON struct {
	LPUrlsJSON         string         `json:"listen-peer-urls"`
	LCUrlsJSON         string         `json:"listen-client-urls"`
	CorsJSON           string         `json:"cors"`
	APUrlsJSON         string         `json:"initial-advertise-peer-urls"`
	ACUrlsJSON         string         `json:"advertise-client-urls"`
	ClientSecurityJSON securityConfig `json:"client-transport-security"`
	PeerSecurityJSON   securityConfig `json:"peer-transport-security"`
}

type securityConfig struct {
	CAFile        string `json:"ca-file"`
	CertFile      string `json:"cert-file"`
	KeyFile       string `json:"key-file"`
	CertAuth      bool   `json:"client-cert-auth"`
	TrustedCAFile string `json:"trusted-ca-file"`
	AutoTLS       bool   `json:"auto-tls"`
}

// NewConfig creates a new Config populated with default values.
func NewConfig() *Config {
	apurl, _ := url.Parse(DefaultInitialAdvertisePeerURLs)
	acurl, _ := url.Parse(DefaultAdvertiseClientURLs)
	cfg := &Config{
		CorsInfo:            &cors.CORSInfo{},
		MaxSnapFiles:        DefaultMaxSnapshots,
		MaxWalFiles:         DefaultMaxWALs,
		Name:                DefaultName,
		SnapCount:           etcdserver.DefaultSnapCount,
		TickMs:              100,
		ElectionMs:          1000,
		APUrls:              []url.URL{*apurl},
		ACUrls:              []url.URL{*acurl},
		ClusterState:        ClusterStateFlagNew,
		InitialClusterToken: "etcd-cluster",
	}
	cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
	return cfg
}

func ConfigFromFile(path string) (*Config, error) {
	cfg := &configYAML{}
	if err := cfg.configFromFile(path); err != nil {
		return nil, err
	}
	return &cfg.Config, nil
}

func (cfg *configYAML) configFromFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(b, cfg)
	if err != nil {
		return err
	}

	if cfg.LPUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.LPUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up listen-peer-urls: %v", err)
		}
		cfg.LPUrls = []url.URL(u)
	}

	if cfg.LCUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.LCUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up listen-client-urls: %v", err)
		}
		cfg.LCUrls = []url.URL(u)
	}

	if cfg.CorsJSON != "" {
		if err := cfg.CorsInfo.Set(cfg.CorsJSON); err != nil {
			plog.Panicf("unexpected error setting up cors: %v", err)
		}
	}

	if cfg.APUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.APUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up initial-advertise-peer-urls: %v", err)
		}
		cfg.APUrls = []url.URL(u)
	}

	if cfg.ACUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.ACUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up advertise-peer-urls: %v", err)
		}
		cfg.ACUrls = []url.URL(u)
	}

	if cfg.ClusterState == "" {
		cfg.ClusterState = ClusterStateFlagNew
	}

	copySecurityDetails := func(tls *transport.TLSInfo, ysc *securityConfig) {
		tls.CAFile = ysc.CAFile
		tls.CertFile = ysc.CertFile
		tls.KeyFile = ysc.KeyFile
		tls.ClientCertAuth = ysc.CertAuth
		tls.TrustedCAFile = ysc.TrustedCAFile
	}
	copySecurityDetails(&cfg.ClientTLSInfo, &cfg.ClientSecurityJSON)
	copySecurityDetails(&cfg.PeerTLSInfo, &cfg.PeerSecurityJSON)
	cfg.ClientAutoTLS = cfg.ClientSecurityJSON.AutoTLS
	cfg.PeerAutoTLS = cfg.PeerSecurityJSON.AutoTLS

	return cfg.Validate()
}

func (cfg *Config) Validate() error {
	// Check if conflicting flags are passed.
	nSet := 0
	for _, v := range []bool{cfg.Durl != "", cfg.InitialCluster != "", cfg.DNSCluster != ""} {
		if v {
			nSet++
		}
	}

	if cfg.ClusterState != ClusterStateFlagNew && cfg.ClusterState != ClusterStateFlagExisting {
		return fmt.Errorf("unexpected clusterState %q", cfg.ClusterState)
	}

	if nSet > 1 {
		return ErrConflictBootstrapFlags
	}

	if 5*cfg.TickMs > cfg.ElectionMs {
		return fmt.Errorf("--election-timeout[%vms] should be at least as 5 times as --heartbeat-interval[%vms]", cfg.ElectionMs, cfg.TickMs)
	}
	if cfg.ElectionMs > maxElectionMs {
		return fmt.Errorf("--election-timeout[%vms] is too long, and should be set less than %vms", cfg.ElectionMs, maxElectionMs)
	}

	// check this last since proxying in etcdmain may make this OK
	if cfg.LCUrls != nil && cfg.ACUrls == nil {
		return ErrUnsetAdvertiseClientURLsFlag
	}

	return nil
}

// PeerURLsMapAndToken sets up an initial peer URLsMap and cluster token for bootstrap or discovery.
func (cfg *Config) PeerURLsMapAndToken(which string) (urlsmap types.URLsMap, token string, err error) {
	switch {
	case cfg.Durl != "":
		urlsmap = types.URLsMap{}
		// If using discovery, generate a temporary cluster based on
		// self's advertised peer URLs
		urlsmap[cfg.Name] = cfg.APUrls
		token = cfg.Durl
	case cfg.DNSCluster != "":
		var clusterStr string
		clusterStr, token, err = discovery.SRVGetCluster(cfg.Name, cfg.DNSCluster, cfg.InitialClusterToken, cfg.APUrls)
		if err != nil {
			return nil, "", err
		}
		urlsmap, err = types.NewURLsMap(clusterStr)
		// only etcd member must belong to the discovered cluster.
		// proxy does not need to belong to the discovered cluster.
		if which == "etcd" {
			if _, ok := urlsmap[cfg.Name]; !ok {
				return nil, "", fmt.Errorf("cannot find local etcd member %q in SRV records", cfg.Name)
			}
		}
	default:
		// We're statically configured, and cluster has appropriately been set.
		urlsmap, err = types.NewURLsMap(cfg.InitialCluster)
		token = cfg.InitialClusterToken
	}
	return urlsmap, token, err
}

func (cfg Config) InitialClusterFromName(name string) (ret string) {
	if len(cfg.APUrls) == 0 {
		return ""
	}
	n := name
	if name == "" {
		n = DefaultName
	}
	for i := range cfg.APUrls {
		ret = ret + "," + n + "=" + cfg.APUrls[i].String()
	}
	return ret[1:]
}

func (cfg Config) IsNewCluster() bool { return cfg.ClusterState == ClusterStateFlagNew }
func (cfg Config) ElectionTicks() int { return int(cfg.ElectionMs / cfg.TickMs) }
<commit_msg>embed: add listen urls to default config<commit_after>// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package embed

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"strings"

	"github.com/coreos/etcd/discovery"
	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/pkg/cors"
	"github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/etcd/pkg/types"
	"github.com/ghodss/yaml"
)

const (
	ClusterStateFlagNew      = "new"
	ClusterStateFlagExisting = "existing"

	DefaultName                     = "default"
	DefaultInitialAdvertisePeerURLs = "http://localhost:2380"
	DefaultAdvertiseClientURLs      = "http://localhost:2379"
	DefaultListenPeerURLs           = "http://localhost:2380"
	DefaultListenClientURLs         = "http://localhost:2379"
	DefaultMaxSnapshots             = 5
	DefaultMaxWALs                  = 5

	// maxElectionMs specifies the maximum value of election timeout.
	// More details are listed in ../Documentation/tuning.md#time-parameters.
	maxElectionMs = 50000
)

var (
	ErrConflictBootstrapFlags = fmt.Errorf("multiple discovery or bootstrap flags are set. " +
		"Choose one of \"initial-cluster\", \"discovery\" or \"discovery-srv\"")
	ErrUnsetAdvertiseClientURLsFlag = fmt.Errorf("--advertise-client-urls is required when --listen-client-urls is set explicitly")
)

// Config holds the arguments for configuring an etcd server.
type Config struct {
	// member

	CorsInfo                *cors.CORSInfo
	LPUrls, LCUrls          []url.URL
	Dir                     string `json:"data-dir"`
	WalDir                  string `json:"wal-dir"`
	MaxSnapFiles            uint   `json:"max-snapshots"`
	MaxWalFiles             uint   `json:"max-wals"`
	Name                    string `json:"name"`
	SnapCount               uint64 `json:"snapshot-count"`
	AutoCompactionRetention int    `json:"auto-compaction-retention"`

	// TickMs is the number of milliseconds between heartbeat ticks.
	// TODO: decouple tickMs and heartbeat tick (current heartbeat tick = 1).
	// make ticks a cluster wide configuration.
	TickMs            uint  `json:"heartbeat-interval"`
	ElectionMs        uint  `json:"election-timeout"`
	QuotaBackendBytes int64 `json:"quota-backend-bytes"`

	// clustering

	APUrls, ACUrls      []url.URL
	ClusterState        string `json:"initial-cluster-state"`
	DNSCluster          string `json:"discovery-srv"`
	Dproxy              string `json:"discovery-proxy"`
	Durl                string `json:"discovery"`
	InitialCluster      string `json:"initial-cluster"`
	InitialClusterToken string `json:"initial-cluster-token"`
	StrictReconfigCheck bool   `json:"strict-reconfig-check"`

	// security

	ClientTLSInfo transport.TLSInfo
	ClientAutoTLS bool
	PeerTLSInfo   transport.TLSInfo
	PeerAutoTLS   bool

	// debug

	Debug        bool   `json:"debug"`
	LogPkgLevels string `json:"log-package-levels"`
	EnablePprof  bool

	// ForceNewCluster starts a new cluster even if previously started; unsafe.
	ForceNewCluster bool `json:"force-new-cluster"`
}

// configYAML holds the config suitable for yaml parsing
type configYAML struct {
	Config
	configJSON
}

// configJSON has file options that are translated into Config options
type configJSON struct {
	LPUrlsJSON         string         `json:"listen-peer-urls"`
	LCUrlsJSON         string         `json:"listen-client-urls"`
	CorsJSON           string         `json:"cors"`
	APUrlsJSON         string         `json:"initial-advertise-peer-urls"`
	ACUrlsJSON         string         `json:"advertise-client-urls"`
	ClientSecurityJSON securityConfig `json:"client-transport-security"`
	PeerSecurityJSON   securityConfig `json:"peer-transport-security"`
}

type securityConfig struct {
	CAFile        string `json:"ca-file"`
	CertFile      string `json:"cert-file"`
	KeyFile       string `json:"key-file"`
	CertAuth      bool   `json:"client-cert-auth"`
	TrustedCAFile string `json:"trusted-ca-file"`
	AutoTLS       bool   `json:"auto-tls"`
}

// NewConfig creates a new Config populated with default values.
func NewConfig() *Config {
	lpurl, _ := url.Parse(DefaultListenPeerURLs)
	apurl, _ := url.Parse(DefaultInitialAdvertisePeerURLs)
	lcurl, _ := url.Parse(DefaultListenClientURLs)
	acurl, _ := url.Parse(DefaultAdvertiseClientURLs)
	cfg := &Config{
		CorsInfo:            &cors.CORSInfo{},
		MaxSnapFiles:        DefaultMaxSnapshots,
		MaxWalFiles:         DefaultMaxWALs,
		Name:                DefaultName,
		SnapCount:           etcdserver.DefaultSnapCount,
		TickMs:              100,
		ElectionMs:          1000,
		LPUrls:              []url.URL{*lpurl},
		LCUrls:              []url.URL{*lcurl},
		APUrls:              []url.URL{*apurl},
		ACUrls:              []url.URL{*acurl},
		ClusterState:        ClusterStateFlagNew,
		InitialClusterToken: "etcd-cluster",
	}
	cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
	return cfg
}

func ConfigFromFile(path string) (*Config, error) {
	cfg := &configYAML{}
	if err := cfg.configFromFile(path); err != nil {
		return nil, err
	}
	return &cfg.Config, nil
}

func (cfg *configYAML) configFromFile(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(b, cfg)
	if err != nil {
		return err
	}

	if cfg.LPUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.LPUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up listen-peer-urls: %v", err)
		}
		cfg.LPUrls = []url.URL(u)
	}

	if cfg.LCUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.LCUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up listen-client-urls: %v", err)
		}
		cfg.LCUrls = []url.URL(u)
	}

	if cfg.CorsJSON != "" {
		if err := cfg.CorsInfo.Set(cfg.CorsJSON); err != nil {
			plog.Panicf("unexpected error setting up cors: %v", err)
		}
	}

	if cfg.APUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.APUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up initial-advertise-peer-urls: %v", err)
		}
		cfg.APUrls = []url.URL(u)
	}

	if cfg.ACUrlsJSON != "" {
		u, err := types.NewURLs(strings.Split(cfg.ACUrlsJSON, ","))
		if err != nil {
			plog.Fatalf("unexpected error setting up advertise-peer-urls: %v", err)
		}
		cfg.ACUrls = []url.URL(u)
	}

	if cfg.ClusterState == "" {
		cfg.ClusterState = ClusterStateFlagNew
	}

	copySecurityDetails := func(tls *transport.TLSInfo, ysc *securityConfig) {
		tls.CAFile = ysc.CAFile
		tls.CertFile = ysc.CertFile
		tls.KeyFile = ysc.KeyFile
		tls.ClientCertAuth = ysc.CertAuth
		tls.TrustedCAFile = ysc.TrustedCAFile
	}
	copySecurityDetails(&cfg.ClientTLSInfo, &cfg.ClientSecurityJSON)
	copySecurityDetails(&cfg.PeerTLSInfo, &cfg.PeerSecurityJSON)
	cfg.ClientAutoTLS = cfg.ClientSecurityJSON.AutoTLS
	cfg.PeerAutoTLS = cfg.PeerSecurityJSON.AutoTLS

	return cfg.Validate()
}

func (cfg *Config) Validate() error {
	// Check if conflicting flags are passed.
	nSet := 0
	for _, v := range []bool{cfg.Durl != "", cfg.InitialCluster != "", cfg.DNSCluster != ""} {
		if v {
			nSet++
		}
	}

	if cfg.ClusterState != ClusterStateFlagNew && cfg.ClusterState != ClusterStateFlagExisting {
		return fmt.Errorf("unexpected clusterState %q", cfg.ClusterState)
	}

	if nSet > 1 {
		return ErrConflictBootstrapFlags
	}

	if 5*cfg.TickMs > cfg.ElectionMs {
		return fmt.Errorf("--election-timeout[%vms] should be at least as 5 times as --heartbeat-interval[%vms]", cfg.ElectionMs, cfg.TickMs)
	}
	if cfg.ElectionMs > maxElectionMs {
		return fmt.Errorf("--election-timeout[%vms] is too long, and should be set less than %vms", cfg.ElectionMs, maxElectionMs)
	}

	// check this last since proxying in etcdmain may make this OK
	if cfg.LCUrls != nil && cfg.ACUrls == nil {
		return ErrUnsetAdvertiseClientURLsFlag
	}

	return nil
}

// PeerURLsMapAndToken sets up an initial peer URLsMap and cluster token for bootstrap or discovery.
func (cfg *Config) PeerURLsMapAndToken(which string) (urlsmap types.URLsMap, token string, err error) {
	switch {
	case cfg.Durl != "":
		urlsmap = types.URLsMap{}
		// If using discovery, generate a temporary cluster based on
		// self's advertised peer URLs
		urlsmap[cfg.Name] = cfg.APUrls
		token = cfg.Durl
	case cfg.DNSCluster != "":
		var clusterStr string
		clusterStr, token, err = discovery.SRVGetCluster(cfg.Name, cfg.DNSCluster, cfg.InitialClusterToken, cfg.APUrls)
		if err != nil {
			return nil, "", err
		}
		urlsmap, err = types.NewURLsMap(clusterStr)
		// only etcd member must belong to the discovered cluster.
		// proxy does not need to belong to the discovered cluster.
		if which == "etcd" {
			if _, ok := urlsmap[cfg.Name]; !ok {
				return nil, "", fmt.Errorf("cannot find local etcd member %q in SRV records", cfg.Name)
			}
		}
	default:
		// We're statically configured, and cluster has appropriately been set.
		urlsmap, err = types.NewURLsMap(cfg.InitialCluster)
		token = cfg.InitialClusterToken
	}
	return urlsmap, token, err
}

func (cfg Config) InitialClusterFromName(name string) (ret string) {
	if len(cfg.APUrls) == 0 {
		return ""
	}
	n := name
	if name == "" {
		n = DefaultName
	}
	for i := range cfg.APUrls {
		ret = ret + "," + n + "=" + cfg.APUrls[i].String()
	}
	return ret[1:]
}

func (cfg Config) IsNewCluster() bool { return cfg.ClusterState == ClusterStateFlagNew }
func (cfg Config) ElectionTicks() int { return int(cfg.ElectionMs / cfg.TickMs) }
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	pubsub "google.golang.org/api/pubsub/v1"

	"github.com/urfave/cli"
)

type CliActions struct {
}

func (c *CliActions) configFlag() cli.StringFlag {
	return cli.StringFlag{
		Name:  "config, c",
		Usage: "`FILE` to load configuration",
	}
}

func (act *CliActions) MainFlags() []cli.Flag {
	return []cli.Flag{
		act.configFlag(),
	}
}

func (act *CliActions) Main(c *cli.Context) error {
	config := act.LoadAndSetupProcessConfig(c)
	p := act.newProcess(config)

	err := p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func (act *CliActions) CheckCommand() cli.Command {
	return cli.Command{
		Name:  "check",
		Usage: "Check config file is valid",
		Action: act.Check,
		Flags: []cli.Flag{
			act.configFlag(),
		},
	}
}

func (act *CliActions) Check(c *cli.Context) error {
	act.LoadAndSetupProcessConfig(c)
	fmt.Println("OK")
	return nil
}

func (act *CliActions) DownloadCommand() cli.Command {
	return cli.Command{
		Name:  "download",
		Usage: "Download the files from GCS to downloads directory",
		Action: act.Download,
		Flags: []cli.Flag{
			act.configFlag(),
			cli.StringFlag{
				Name:  "downloads_dir, d",
				Usage: "`PATH` to the directory which has bucket_name/path/to/file",
			},
			cli.IntFlag{
				Name:  "workers, n",
				Usage: "`NUMBER` of workers",
				Value: 5,
			},
			cli.IntFlag{
				Name:  "max_tries, m",
				Usage: "`NUMBER` of max tries",
				Value: 3,
			},
			cli.IntFlag{
				Name:  "wait, w",
				Usage: "`NUMBER` of seconds to wait",
				Value: 0,
			},
		},
	}
}

func (act *CliActions) Download(c *cli.Context) error {
	config_path := c.String("config")
	var config *ProcessConfig
	if config_path == "" {
		config = &ProcessConfig{}
		config.Log = &LogConfig{Level: "debug"}
	} else {
		var err error
		config, err = LoadProcessConfig(config_path)
		if err != nil {
			fmt.Printf("Failed to load config: %v because of %v\n", config_path, err)
			os.Exit(1)
		}
	}
	config.setup([]string{})
	config.Download.Workers = c.Int("workers")
	config.Download.MaxTries = c.Int("max_tries")
	config.Job.Sustainer = &JobSustainerConfig{
		Disabled: true,
	}
	p := act.newProcess(config)
	files := []interface{}{}
	for _, arg := range c.Args() {
		files = append(files, arg)
	}
	job := &Job{
		config:              config.Command,
		downloads_dir:       c.String("downloads_dir"),
		remoteDownloadFiles: files,
		storage:             p.storage,
		downloadConfig:      config.Download,
	}
	err := job.setupDownloadFiles()
	if err != nil {
		return err
	}
	err = job.downloadFiles()

	w := c.Int("wait")
	if w > 0 {
		time.Sleep(time.Duration(w) * time.Second)
	}

	return nil
}

func (act *CliActions) UploadCommand() cli.Command {
	return cli.Command{
		Name:  "upload",
		Usage: "Upload the files under uploads directory",
		Action: act.Upload,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "uploads_dir, d",
				Usage: "Path to the directory which has bucket_name/path/to/file",
			},
			cli.IntFlag{
				Name:  "uploaders, n",
				Usage: "Number of uploaders",
				Value: 6,
			},
		},
	}
}

func (act *CliActions) Upload(c *cli.Context) error {
	fmt.Printf("Uploading files\n")
	config := &ProcessConfig{}
	config.Log = &LogConfig{Level: "debug"}
	config.setup([]string{})
	config.Upload.Workers = c.Int("uploaders")
	config.Job.Sustainer = &JobSustainerConfig{
		Disabled: true,
	}
	p := act.newProcess(config)
	p.setup()
	job := &Job{
		config:      config.Command,
		uploads_dir: c.String("uploads_dir"),
		storage:     p.storage,
	}
	fmt.Printf("Uploading files under %v\n", job.uploads_dir)
	err := job.uploadFiles()
	return err
}

func (act *CliActions) ExecCommand() cli.Command {
	return cli.Command{
		Name:  "exec",
		Usage: "Execute job without download nor upload",
		Action: act.Exec,
		Flags: []cli.Flag{
			act.configFlag(),
			cli.StringFlag{
				Name:  "message, m",
				Usage: "Path to the message json file which has attributes and data",
			},
			cli.StringFlag{
				Name:  "workspace, w",
				Usage: "Path to workspace directory which has downloads and uploads",
			},
		},
	}
}

func (act *CliActions) Exec(c *cli.Context) error {
	config := act.LoadAndSetupProcessConfig(c)

	msg_file := c.String("message")
	workspace := c.String("workspace")

	type Msg struct {
		Attributes  map[string]string `json:"attributes"`
		Data        string            `json:"data"`
		MessageId   string            `json:"messageId"`
		PublishTime string            `json:"publishTime"`
		AckId       string            `json:"ackId"`
	}
	var msg Msg

	data, err := ioutil.ReadFile(msg_file)
	if err != nil {
		fmt.Printf("Error to read file %v because of %v\n", msg_file, err)
		os.Exit(1)
	}

	err = json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Printf("Error to parse json file %v because of %v\n", msg_file, err)
		os.Exit(1)
	}

	job := &Job{
		workspace: workspace,
		config:    config.Command,
		message: &JobMessage{
			raw: &pubsub.ReceivedMessage{
				AckId: msg.AckId,
				Message: &pubsub.PubsubMessage{
					Attributes: msg.Attributes,
					Data:       msg.Data,
					MessageId:  msg.MessageId,
					// PublishTime: time.Now().Format(time.RFC3339),
					PublishTime: msg.PublishTime,
				},
			},
		},
	}
	fmt.Printf("Preparing job\n")
	err = job.prepare()
	if err != nil {
		return err
	}
	fmt.Printf("Executing job\n")
	err = job.execute()
	return err
}

func (act *CliActions) LoadAndSetupProcessConfig(c *cli.Context) *ProcessConfig {
	path := act.configPath(c)
	config, err := LoadProcessConfig(path)
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", path, err)
		os.Exit(1)
	}
	err = config.setup(c.Args())
	if err != nil {
		fmt.Printf("Error to setup %v cause of %v\n", path, err)
		os.Exit(1)
	}
	return config
}

func (act *CliActions) configPath(c *cli.Context) string {
	r := c.String("config")
	if r == "" {
		r = "./config.json"
	}
	return r
}

func (act *CliActions) newProcess(config *ProcessConfig) *Process {
	p := &Process{config: config}
	err := p.setup()
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}
	return p
}
<commit_msg>:recycle: Use cli.StringFlag#Value for default value<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	pubsub "google.golang.org/api/pubsub/v1"

	"github.com/urfave/cli"
)

type CliActions struct {
}

func (c *CliActions) configFlag() cli.StringFlag {
	return cli.StringFlag{
		Name:  "config, c",
		Usage: "`FILE` to load configuration",
		Value: "./config.json",
	}
}

func (act *CliActions) MainFlags() []cli.Flag {
	return []cli.Flag{
		act.configFlag(),
	}
}

func (act *CliActions) Main(c *cli.Context) error {
	config := act.LoadAndSetupProcessConfig(c)
	p := act.newProcess(config)

	err := p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func (act *CliActions) CheckCommand() cli.Command {
	return cli.Command{
		Name:  "check",
		Usage: "Check config file is valid",
		Action: act.Check,
		Flags: []cli.Flag{
			act.configFlag(),
		},
	}
}

func (act *CliActions) Check(c *cli.Context) error {
	act.LoadAndSetupProcessConfig(c)
	fmt.Println("OK")
	return nil
}

func (act *CliActions) DownloadCommand() cli.Command {
	return cli.Command{
		Name:  "download",
		Usage: "Download the files from GCS to downloads directory",
		Action: act.Download,
		Flags: []cli.Flag{
			act.configFlag(),
			cli.StringFlag{
				Name:  "downloads_dir, d",
				Usage: "`PATH` to the directory which has bucket_name/path/to/file",
			},
			cli.IntFlag{
				Name:  "workers, n",
				Usage: "`NUMBER` of workers",
				Value: 5,
			},
			cli.IntFlag{
				Name:  "max_tries, m",
				Usage: "`NUMBER` of max tries",
				Value: 3,
			},
			cli.IntFlag{
				Name:  "wait, w",
				Usage: "`NUMBER` of seconds to wait",
				Value: 0,
			},
		},
	}
}

func (act *CliActions) Download(c *cli.Context) error {
	config_path := c.String("config")
	var config *ProcessConfig
	if config_path == "" {
		config = &ProcessConfig{}
		config.Log = &LogConfig{Level: "debug"}
	} else {
		var err error
		config, err = LoadProcessConfig(config_path)
		if err != nil {
			fmt.Printf("Failed to load config: %v because of %v\n", config_path, err)
			os.Exit(1)
		}
	}
	config.setup([]string{})
	config.Download.Workers = c.Int("workers")
	config.Download.MaxTries = c.Int("max_tries")
	config.Job.Sustainer = &JobSustainerConfig{
		Disabled: true,
	}
	p := act.newProcess(config)
	files := []interface{}{}
	for _, arg := range c.Args() {
		files = append(files, arg)
	}
	job := &Job{
		config:              config.Command,
		downloads_dir:       c.String("downloads_dir"),
		remoteDownloadFiles: files,
		storage:             p.storage,
		downloadConfig:      config.Download,
	}
	err := job.setupDownloadFiles()
	if err != nil {
		return err
	}
	err = job.downloadFiles()

	w := c.Int("wait")
	if w > 0 {
		time.Sleep(time.Duration(w) * time.Second)
	}

	return nil
}

func (act *CliActions) UploadCommand() cli.Command {
	return cli.Command{
		Name:  "upload",
		Usage: "Upload the files under uploads directory",
		Action: act.Upload,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "uploads_dir, d",
				Usage: "Path to the directory which has bucket_name/path/to/file",
			},
			cli.IntFlag{
				Name:  "uploaders, n",
				Usage: "Number of uploaders",
				Value: 6,
			},
		},
	}
}

func (act *CliActions) Upload(c *cli.Context) error {
	fmt.Printf("Uploading files\n")
	config := &ProcessConfig{}
	config.Log = &LogConfig{Level: "debug"}
	config.setup([]string{})
	config.Upload.Workers = c.Int("uploaders")
	config.Job.Sustainer = &JobSustainerConfig{
		Disabled: true,
	}
	p := act.newProcess(config)
	p.setup()
	job := &Job{
		config:      config.Command,
		uploads_dir: c.String("uploads_dir"),
		storage:     p.storage,
	}
	fmt.Printf("Uploading files under %v\n", job.uploads_dir)
	err := job.uploadFiles()
	return err
}

func (act *CliActions) ExecCommand() cli.Command {
	return cli.Command{
		Name:  "exec",
		Usage: "Execute job without download nor upload",
		Action: act.Exec,
		Flags: []cli.Flag{
			act.configFlag(),
			cli.StringFlag{
				Name:  "message, m",
				Usage: "Path to the message json file which has attributes and data",
			},
			cli.StringFlag{
				Name:  "workspace, w",
				Usage: "Path to workspace directory which has downloads and uploads",
			},
		},
	}
}

func (act *CliActions) Exec(c *cli.Context) error {
	config := act.LoadAndSetupProcessConfig(c)

	msg_file := c.String("message")
	workspace := c.String("workspace")

	type Msg struct {
		Attributes  map[string]string `json:"attributes"`
		Data        string            `json:"data"`
		MessageId   string            `json:"messageId"`
		PublishTime string            `json:"publishTime"`
		AckId       string            `json:"ackId"`
	}
	var msg Msg

	data, err := ioutil.ReadFile(msg_file)
	if err != nil {
		fmt.Printf("Error to read file %v because of %v\n", msg_file, err)
		os.Exit(1)
	}

	err = json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Printf("Error to parse json file %v because of %v\n", msg_file, err)
		os.Exit(1)
	}

	job := &Job{
		workspace: workspace,
		config:    config.Command,
		message: &JobMessage{
			raw: &pubsub.ReceivedMessage{
				AckId: msg.AckId,
				Message: &pubsub.PubsubMessage{
					Attributes: msg.Attributes,
					Data:       msg.Data,
					MessageId:  msg.MessageId,
					// PublishTime: time.Now().Format(time.RFC3339),
					PublishTime: msg.PublishTime,
				},
			},
		},
	}
	fmt.Printf("Preparing job\n")
	err = job.prepare()
	if err != nil {
		return err
	}
	fmt.Printf("Executing job\n")
	err = job.execute()
	return err
}

func (act *CliActions) LoadAndSetupProcessConfig(c *cli.Context) *ProcessConfig {
	path := c.String("config")
	config, err := LoadProcessConfig(path)
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", path, err)
		os.Exit(1)
	}
	err = config.setup(c.Args())
	if err != nil {
		fmt.Printf("Error to setup %v cause of %v\n", path, err)
		os.Exit(1)
	}
	return config
}

func (act *CliActions) newProcess(config *ProcessConfig) *Process {
	p := &Process{config: config}
	err := p.setup()
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}
	return p
}
<|endoftext|>


<commit_before>package ip

import (
	"strings"

	"github.com/lxc/lxd/shared"
)

// Route represents arguments for route manipulation
type Route struct {
	DevName string
	Route   string
	Table   string
	Src     string
	Proto   string
	Family  string
}

// Add adds new route
func (r *Route) Add() error {
	cmd := []string{r.Family, "route", "add"}
	if r.Table != "" {
		cmd = append(cmd, "table", r.Table)
	}
	cmd = append(cmd, r.Route, "dev", r.DevName)
	if r.Src != "" {
		cmd = append(cmd, "src", r.Src)
	}
	if r.Proto != "" {
		cmd = append(cmd, "proto", r.Proto)
	}
	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Delete deletes routing table
func (r *Route) Delete() error {
	_, err := shared.RunCommand("ip", r.Family, "route", "delete", "table", r.Table, r.Route, "dev", r.DevName)
	if err != nil {
		return err
	}
	return nil
}

// Flush flushes routing tables
func (r *Route) Flush() error {
	cmd := []string{}
	if r.Family != "" {
		cmd = append(cmd, r.Family)
	}
	cmd = append(cmd, "route", "flush")
	if r.Route != "" {
		cmd = append(cmd, r.Route)
	}
	cmd = append(cmd, "dev", r.DevName)
	if r.Proto != "" {
		cmd = append(cmd, "proto", r.Proto)
	}

	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Replace changes or adds new route
func (r *Route) Replace(routes []string) error {
	cmd := []string{r.Family, "route", "replace", "dev", r.DevName, "proto", r.Proto}
	cmd = append(cmd, routes...)
	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Show lists routes
func (r *Route) Show() ([]string, error) {
	routes := []string{}
	out, err := shared.RunCommand("ip", r.Family, "route", "show", "dev", r.DevName, "proto", r.Proto)
	if err != nil {
		return routes, err
	}
	for _, line := range strings.Split(out, "\n") {
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			continue
		}
		route := strings.Replace(line, "linkdown", "", -1)
		routes = append(routes, route)
	}
	return routes, nil
}
<commit_msg>lxd/ip/route: Add support for 'via' when creating routes<commit_after>package ip

import (
	"strings"

	"github.com/lxc/lxd/shared"
)

// Route represents arguments for route manipulation
type Route struct {
	DevName string
	Route   string
	Table   string
	Src     string
	Proto   string
	Family  string
	Via     string
}

// Add adds new route
func (r *Route) Add() error {
	cmd := []string{r.Family, "route", "add"}
	if r.Table != "" {
		cmd = append(cmd, "table", r.Table)
	}
	if r.Via != "" {
		cmd = append(cmd, "via", r.Via)
	}
	cmd = append(cmd, r.Route, "dev", r.DevName)
	if r.Src != "" {
		cmd = append(cmd, "src", r.Src)
	}
	if r.Proto != "" {
		cmd = append(cmd, "proto", r.Proto)
	}
	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Delete deletes routing table
func (r *Route) Delete() error {
	_, err := shared.RunCommand("ip", r.Family, "route", "delete", "table", r.Table, r.Route, "dev", r.DevName)
	if err != nil {
		return err
	}
	return nil
}

// Flush flushes routing tables
func (r *Route) Flush() error {
	cmd := []string{}
	if r.Family != "" {
		cmd = append(cmd, r.Family)
	}
	cmd = append(cmd, "route", "flush")
	if r.Route != "" {
		cmd = append(cmd, r.Route)
	}
	if r.Via != "" {
		cmd = append(cmd, "via", r.Via)
	}
	cmd = append(cmd, "dev", r.DevName)
	if r.Proto != "" {
		cmd = append(cmd, "proto", r.Proto)
	}

	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Replace changes or adds new route
func (r *Route) Replace(routes []string) error {
	cmd := []string{r.Family, "route", "replace", "dev", r.DevName, "proto", r.Proto}
	cmd = append(cmd, routes...)
	_, err := shared.RunCommand("ip", cmd...)
	if err != nil {
		return err
	}
	return nil
}

// Show lists routes
func (r *Route) Show() ([]string, error) {
	routes := []string{}
	out, err := shared.RunCommand("ip", r.Family, "route", "show", "dev", r.DevName, "proto", r.Proto)
	if err != nil {
		return routes, err
	}
	for _, line := range strings.Split(out, "\n") {
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			continue
		}
		route := strings.Replace(line, "linkdown", "", -1)
		routes = append(routes, route)
	}
	return routes, nil
}
<|endoftext|>


<commit_before>// +build linux,cgo,!agent

package util

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	log "github.com/lxc/lxd/shared/log15"
	liblxc "gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared/idmap"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/osarch"
)

// GetArchitectures returns the list of supported architectures.
func GetArchitectures() ([]int, error) {
	architectures := []int{}

	architectureName, err := osarch.ArchitectureGetLocal()
	if err != nil {
		return nil, err
	}

	architecture, err := osarch.ArchitectureId(architectureName)
	if err != nil {
		return nil, err
	}
	architectures = append(architectures, architecture)

	personalities, err := osarch.ArchitecturePersonalities(architecture)
	if err != nil {
		return nil, err
	}
	for _, personality := range personalities {
		architectures = append(architectures, personality)
	}
	return architectures, nil
}

// GetIdmapSet reads the uid/gid allocation.
func GetIdmapSet() *idmap.IdmapSet {
	idmapSet, err := idmap.DefaultIdmapSet("", "")
	if err != nil {
		logger.Warn("Error reading default uid/gid map", log.Ctx{"err": err.Error()})
		logger.Warnf("Only privileged containers will be able to run")
		idmapSet = nil
	} else {
		kernelIdmapSet, err := idmap.CurrentIdmapSet()
		if err == nil {
			logger.Infof("Kernel uid/gid map:")
			for _, lxcmap := range kernelIdmapSet.ToLxcString() {
				logger.Infof(fmt.Sprintf(" - %s", lxcmap))
			}
		}

		if len(idmapSet.Idmap) == 0 {
			logger.Warnf("No available uid/gid map could be found")
			logger.Warnf("Only privileged containers will be able to run")
			idmapSet = nil
		} else {
			logger.Infof("Configured LXD uid/gid map:")
			for _, lxcmap := range idmapSet.Idmap {
				suffix := ""

				if lxcmap.Usable() != nil {
					suffix = " (unusable)"
				}

				for _, lxcEntry := range lxcmap.ToLxcString() {
					logger.Infof(" - %s%s", lxcEntry, suffix)
				}
			}

			err = idmapSet.Usable()
			if err != nil {
				logger.Warnf("One or more uid/gid map entry isn't usable (typically due to nesting)")
				logger.Warnf("Only privileged containers will be able to run")
				idmapSet = nil
			}
		}
	}
	return idmapSet
}

// RuntimeLiblxcVersionAtLeast checks if the system's liblxc matches the
// provided version requirement
func RuntimeLiblxcVersionAtLeast(major int, minor int, micro int) bool {
	version := liblxc.Version()
	version = strings.Replace(version, " (devel)", "-devel", 1)
	parts := strings.Split(version, ".")
	partsLen := len(parts)
	if partsLen == 0 {
		return false
	}

	develParts := strings.Split(parts[partsLen-1], "-")
	if len(develParts) == 2 && develParts[1] == "devel" {
		return true
	}

	maj := -1
	min := -1
	mic := -1

	for i, v := range parts {
		if i > 2 {
			break
		}

		num, err := strconv.Atoi(v)
		if err != nil {
			return false
		}

		switch i {
		case 0:
			maj = num
		case 1:
			min = num
		case 2:
			mic = num
		}
	}

	/* Major version is greater. */
	if maj > major {
		return true
	}

	if maj < major {
		return false
	}

	/* Minor number is greater.*/
	if min > minor {
		return true
	}

	if min < minor {
		return false
	}

	/* Patch number is greater. */
	if mic > micro {
		return true
	}

	if mic < micro {
		return false
	}

	return true
}

// GetExecPath returns the path to the current binary
func GetExecPath() string {
	execPath := os.Getenv("LXD_EXEC_PATH")
	if execPath != "" {
		return execPath
	}

	execPath, err := os.Readlink("/proc/self/exe")
	if err != nil {
		execPath = "bad-exec-path"
	}
	return execPath
}
<commit_msg>lxd/util/sys: Fixes GetExecPath when lxd binary has been removed/changed<commit_after>// +build linux,cgo,!agent

package util

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	log "github.com/lxc/lxd/shared/log15"
	liblxc "gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared/idmap"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/osarch"
)

// GetArchitectures returns the list of supported architectures.
func GetArchitectures() ([]int, error) {
	architectures := []int{}

	architectureName, err := osarch.ArchitectureGetLocal()
	if err != nil {
		return nil, err
	}

	architecture, err := osarch.ArchitectureId(architectureName)
	if err != nil {
		return nil, err
	}
	architectures = append(architectures, architecture)

	personalities, err := osarch.ArchitecturePersonalities(architecture)
	if err != nil {
		return nil, err
	}
	for _, personality := range personalities {
		architectures = append(architectures, personality)
	}
	return architectures, nil
}

// GetIdmapSet reads the uid/gid allocation.
func GetIdmapSet() *idmap.IdmapSet {
	idmapSet, err := idmap.DefaultIdmapSet("", "")
	if err != nil {
		logger.Warn("Error reading default uid/gid map", log.Ctx{"err": err.Error()})
		logger.Warnf("Only privileged containers will be able to run")
		idmapSet = nil
	} else {
		kernelIdmapSet, err := idmap.CurrentIdmapSet()
		if err == nil {
			logger.Infof("Kernel uid/gid map:")
			for _, lxcmap := range kernelIdmapSet.ToLxcString() {
				logger.Infof(fmt.Sprintf(" - %s", lxcmap))
			}
		}

		if len(idmapSet.Idmap) == 0 {
			logger.Warnf("No available uid/gid map could be found")
			logger.Warnf("Only privileged containers will be able to run")
			idmapSet = nil
		} else {
			logger.Infof("Configured LXD uid/gid map:")
			for _, lxcmap := range idmapSet.Idmap {
				suffix := ""

				if lxcmap.Usable() != nil {
					suffix = " (unusable)"
				}

				for _, lxcEntry := range lxcmap.ToLxcString() {
					logger.Infof(" - %s%s", lxcEntry, suffix)
				}
			}

			err = idmapSet.Usable()
			if err != nil {
				logger.Warnf("One or more uid/gid map entry isn't usable (typically due to nesting)")
				logger.Warnf("Only privileged containers will be able to run")
				idmapSet = nil
			}
		}
	}
	return idmapSet
}

// RuntimeLiblxcVersionAtLeast checks if the system's liblxc matches the
// provided version requirement
func RuntimeLiblxcVersionAtLeast(major int, minor int, micro int) bool {
	version := liblxc.Version()
	version = strings.Replace(version, " (devel)", "-devel", 1)
	parts := strings.Split(version, ".")
	partsLen := len(parts)
	if partsLen == 0 {
		return false
	}

	develParts := strings.Split(parts[partsLen-1], "-")
	if len(develParts) == 2 && develParts[1] == "devel" {
		return true
	}

	maj := -1
	min := -1
	mic := -1

	for i, v := range parts {
		if i > 2 {
			break
		}

		num, err := strconv.Atoi(v)
		if err != nil {
			return false
		}

		switch i {
		case 0:
			maj = num
		case 1:
			min = num
		case 2:
			mic = num
		}
	}

	/* Major version is greater. */
	if maj > major {
		return true
	}

	if maj < major {
		return false
	}

	/* Minor number is greater.*/
	if min > minor {
		return true
	}

	if min < minor {
		return false
	}

	/* Patch number is greater. */
	if mic > micro {
		return true
	}

	if mic < micro {
		return false
	}

	return true
}

// GetExecPath returns the path to the current binary
func GetExecPath() string {
	execPath := os.Getenv("LXD_EXEC_PATH")
	if execPath != "" {
		return execPath
	}

	execPath, err := os.Readlink("/proc/self/exe")
	if err != nil {
		execPath = "bad-exec-path"
	}

	// The execPath from /proc/self/exe can end with " (deleted)" if the lxd binary has been removed/changed
	// since the lxd process was started, strip this so that we only return a valid path.
	return strings.TrimSuffix(execPath, " (deleted)")
}
<|endoftext|>


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

package lzma

import (
	"errors"
	"io"

	"github.com/ulikunitz/xz/internal/xlog"
)

// Reader2 supports the reading of LZMA2 chunk sequences. Note that the
// first chunk should have a dictionary reset and the first compressed
// chunk a properties reset. The chunk sequence may not be terminated by
// an end-of-stream chunk.
type Reader2 struct {
	r   io.Reader
	err error

	dict        *decoderDict
	ur          *uncompressedReader
	decoder     *decoder
	chunkReader io.Reader

	cstate chunkState
	ctype  chunkType
}

// NewReader2 creates a reader for an LZMA2 chunk sequence with the given
// dictionary capacity.
func NewReader2(lzma2 io.Reader, dictCap int) (r *Reader2, err error) {
	return NewReader2Params(lzma2, &ReaderParams{DictCap: dictCap})
}

// NewReader2Params creates a new LZMA2 reader using the given
// parameters.
func NewReader2Params(lzma2 io.Reader, params *ReaderParams) (r *Reader2, err error) {
	params = fillReaderParams(params)
	if err = params.Verify(); err != nil {
		return nil, err
	}
	r = &Reader2{r: lzma2, cstate: start}
	r.dict, err = newDecoderDict(params.DictCap)
	if err != nil {
		return nil, err
	}
	if err = r.startChunk(); err != nil {
		return nil, err
	}
	return r, nil
}

// uncompressed tests whether the chunk type specifies an uncompressed
// chunk.
func uncompressed(ctype chunkType) bool {
	return ctype == cU || ctype == cUD
}

// startChunk parses a new chunk.
func (r *Reader2) startChunk() error {
	r.chunkReader = nil
	header, err := readChunkHeader(r.r)
	if err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		return err
	}
	xlog.Debugf("chunk header %v", header)
	if err = r.cstate.next(header.ctype); err != nil {
		return err
	}
	if r.cstate == stop {
		return io.EOF
	}
	if header.ctype == cUD || header.ctype == cLRND {
		r.dict.Reset()
	}
	size := int64(header.uncompressed) + 1
	if uncompressed(header.ctype) {
		if r.ur != nil {
			r.ur.Reopen(r.r, size)
		} else {
			r.ur = newUncompressedReader(r.r, r.dict, size)
		}
		r.chunkReader = r.ur
		return nil
	}
	br := ByteReader(io.LimitReader(r.r, int64(header.compressed)+1))
	if r.decoder == nil {
		state := newState(header.props)
		r.decoder, err = newDecoder(br, state, r.dict, size)
		if err != nil {
			return err
		}
		r.chunkReader = r.decoder
		return nil
	}
	switch header.ctype {
	case cLR:
		r.decoder.State.Reset()
	case cLRN, cLRND:
		r.decoder.State = newState(header.props)
	}
	err = r.decoder.Reopen(br, size)
	if err != nil {
		return err
	}
	r.chunkReader = r.decoder
	return nil
}

// Read reads data from the LZMA2 chunk sequence.
func (r *Reader2) Read(p []byte) (n int, err error) {
	if r.err != nil {
		return 0, r.err
	}
	for n < len(p) {
		var k int
		k, err = r.chunkReader.Read(p[n:])
		n += k
		if err == io.EOF {
			err = r.startChunk()
		}
		if err != nil {
			r.err = err
			return n, err
		}
		if k == 0 {
			r.err = errors.New("lzma: Reader2 doesn't get data")
			return n, r.err
		}
	}
	return n, nil
}

// EOS returns whether the LZMA2 stream has been terminated by an
// end-of-stream chunk.
func (r *Reader2) EOS() bool {
	return r.cstate == stop
}

// uncompressedReader is used to read uncompressed chunks.
type uncompressedReader struct {
	lr   io.LimitedReader
	Dict *decoderDict
	eof  bool
	err  error
}

// newUncompressedReader initializes a new uncompressedReader.
func newUncompressedReader(r io.Reader, dict *decoderDict, size int64) *uncompressedReader {
	ur := &uncompressedReader{
		lr:   io.LimitedReader{R: r, N: size},
		Dict: dict,
	}
	return ur
}

// Reopen reinitializes an uncompressed reader.
func (ur *uncompressedReader) Reopen(r io.Reader, size int64) {
	ur.err = nil
	ur.eof = false
	ur.lr = io.LimitedReader{R: r, N: size}
}

// fill reads uncompressed data into the dictionary.
func (ur *uncompressedReader) fill() error {
	if !ur.eof {
		n, err := io.CopyN(ur.Dict, &ur.lr, int64(ur.Dict.Available()))
		if err != io.EOF {
			return err
		}
		ur.eof = true
		if n > 0 {
			return nil
		}
	}
	if ur.lr.N != 0 {
		return io.ErrUnexpectedEOF
	}
	return io.EOF
}

// Read reads uncompressed data from the limited reader.
func (ur *uncompressedReader) Read(p []byte) (n int, err error) {
	if ur.err != nil {
		return 0, ur.err
	}
	for {
		var k int
		k, err = ur.Dict.Read(p[n:])
		n += k
		if n >= len(p) {
			return n, nil
		}
		if err != nil {
			break
		}
		err = ur.fill()
		if err != nil {
			break
		}
	}
	ur.err = err
	return n, err
}
<commit_msg>lzma: fixed bug in Read method of Reader2<commit_after>// Copyright 2014-2016 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lzma

import (
	"errors"
	"io"

	"github.com/ulikunitz/xz/internal/xlog"
)

// Reader2 supports the reading of LZMA2 chunk sequences. Note that the
// first chunk should have a dictionary reset and the first compressed
// chunk a properties reset. The chunk sequence may not be terminated by
// an end-of-stream chunk.
type Reader2 struct {
	r   io.Reader
	err error

	dict        *decoderDict
	ur          *uncompressedReader
	decoder     *decoder
	chunkReader io.Reader

	cstate chunkState
	ctype  chunkType
}

// NewReader2 creates a reader for an LZMA2 chunk sequence with the given
// dictionary capacity.
func NewReader2(lzma2 io.Reader, dictCap int) (r *Reader2, err error) {
	return NewReader2Params(lzma2, &ReaderParams{DictCap: dictCap})
}

// NewReader2Params creates a new LZMA2 reader using the given
// parameters.
func NewReader2Params(lzma2 io.Reader, params *ReaderParams) (r *Reader2, err error) {
	params = fillReaderParams(params)
	if err = params.Verify(); err != nil {
		return nil, err
	}
	r = &Reader2{r: lzma2, cstate: start}
	r.dict, err = newDecoderDict(params.DictCap)
	if err != nil {
		return nil, err
	}
	if err = r.startChunk(); err != nil {
		return nil, err
	}
	return r, nil
}

// uncompressed tests whether the chunk type specifies an uncompressed
// chunk.
func uncompressed(ctype chunkType) bool {
	return ctype == cU || ctype == cUD
}

// startChunk parses a new chunk.
func (r *Reader2) startChunk() error {
	r.chunkReader = nil
	header, err := readChunkHeader(r.r)
	if err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		return err
	}
	xlog.Debugf("chunk header %v", header)
	if err = r.cstate.next(header.ctype); err != nil {
		return err
	}
	if r.cstate == stop {
		return io.EOF
	}
	if header.ctype == cUD || header.ctype == cLRND {
		r.dict.Reset()
	}
	size := int64(header.uncompressed) + 1
	if uncompressed(header.ctype) {
		if r.ur != nil {
			r.ur.Reopen(r.r, size)
		} else {
			r.ur = newUncompressedReader(r.r, r.dict, size)
		}
		r.chunkReader = r.ur
		return nil
	}
	br := ByteReader(io.LimitReader(r.r, int64(header.compressed)+1))
	if r.decoder == nil {
		state := newState(header.props)
		r.decoder, err = newDecoder(br, state, r.dict, size)
		if err != nil {
			return err
		}
		r.chunkReader = r.decoder
		return nil
	}
	switch header.ctype {
	case cLR:
		r.decoder.State.Reset()
	case cLRN, cLRND:
		r.decoder.State = newState(header.props)
	}
	err = r.decoder.Reopen(br, size)
	if err != nil {
		return err
	}
	r.chunkReader = r.decoder
	return nil
}

// Read reads data from the LZMA2 chunk sequence.
func (r *Reader2) Read(p []byte) (n int, err error) {
	if r.err != nil {
		return 0, r.err
	}
	for n < len(p) {
		var k int
		k, err = r.chunkReader.Read(p[n:])
		n += k
		if err != nil {
			if err == io.EOF {
				err = r.startChunk()
				if err == nil {
					continue
				}
			}
			r.err = err
			return n, err
		}
		if k == 0 {
			r.err = errors.New("lzma: Reader2 doesn't get data")
			return n, r.err
		}
	}
	return n, nil
}

// EOS returns whether the LZMA2 stream has been terminated by an
// end-of-stream chunk.
func (r *Reader2) EOS() bool {
	return r.cstate == stop
}

// uncompressedReader is used to read uncompressed chunks.
type uncompressedReader struct {
	lr   io.LimitedReader
	Dict *decoderDict
	eof  bool
	err  error
}

// newUncompressedReader initializes a new uncompressedReader.
func newUncompressedReader(r io.Reader, dict *decoderDict, size int64) *uncompressedReader {
	ur := &uncompressedReader{
		lr:   io.LimitedReader{R: r, N: size},
		Dict: dict,
	}
	return ur
}

// Reopen reinitializes an uncompressed reader.
func (ur *uncompressedReader) Reopen(r io.Reader, size int64) {
	ur.err = nil
	ur.eof = false
	ur.lr = io.LimitedReader{R: r, N: size}
}

// fill reads uncompressed data into the dictionary.
func (ur *uncompressedReader) fill() error {
	if !ur.eof {
		n, err := io.CopyN(ur.Dict, &ur.lr, int64(ur.Dict.Available()))
		if err != io.EOF {
			return err
		}
		ur.eof = true
		if n > 0 {
			return nil
		}
	}
	if ur.lr.N != 0 {
		return io.ErrUnexpectedEOF
	}
	return io.EOF
}

// Read reads uncompressed data from the limited reader.
func (ur *uncompressedReader) Read(p []byte) (n int, err error) {
	if ur.err != nil {
		return 0, ur.err
	}
	for {
		var k int
		k, err = ur.Dict.Read(p[n:])
		n += k
		if n >= len(p) {
			return n, nil
		}
		if err != nil {
			break
		}
		err = ur.fill()
		if err != nil {
			break
		}
	}
	ur.err = err
	return n, err
}
<|endoftext|>


<commit_before>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"testing"

	"github.com/bmizerany/assert"
)

// dumbSound - Only for testing purpuses
type dumbSound struct {
	BeepCalled bool
}

func (s *dumbSound) Beep() {
	(*s).BeepCalled = true
}

// newCpuAt creates a new cpu and write the ins to the pc memory location
// Only for testing purpuse
func newCpuAt(ins uint16) cpu {
	s := &dumbSound{}
	c := newCpu(s)
	c.memory.WriteWord(uint16(c.pc), ins)

	return c
}

func TestTimers(t *testing.T) {
	s := &dumbSound{}
	c := newCpu(s)

	// With Beep
	c.memory.WriteWord(uint16(c.pc), 0x0E0)

	c.dt = 1
	c.st = 1

	assert.Equal(t, s.BeepCalled, false)

	c.Step()

	assert.Equal(t, c.dt, byte(0))
	assert.Equal(t, c.st, byte(0))
	assert.Equal(t, s.BeepCalled, true)

	// No Beep
	c.memory.WriteWord(uint16(c.pc), 0x0E0)
	s.BeepCalled = false

	c.st = 2
	c.Step()

	assert.Equal(t, s.BeepCalled, false)
	assert.Equal(t, c.st, byte(1))
}

// 00E0 - CLS
func Test00E0(t *testing.T) {

	c := newCpuAt(0x00E0)
	c.gfx.SetPixel(0, 0)
	c.Step()

	for i := 0; i < 64; i++ {
		for j := 0; j < 32; j++ {
			assert.Equal(t, byte(COLOR_BLACK), byte(c.gfx.GetPixel(i, j)))
		}
	}
}

// 00EE - RET
func Test00EE(t *testing.T) {
	c := newCpuAt(0x00EE)

	c.stack.Push(pc(1))
	c.Step()

	assert.Equal(t, pc(1), c.pc)
}

// 1nnn - JP addr
func Test1000(t *testing.T) {
	c := newCpuAt(0x1FFF)
	c.Step()

	assert.Equal(t, pc(0x0FFF), c.pc)
}

// 2nnn - CALL addr
func Test2000(t *testing.T) {
	c := newCpuAt(0x2FFF)
	oldPC := c.pc + 2 // The increment happen before the Step

	c.Step()

	assert.Equal(t, oldPC, c.stack.Pop())
	assert.Equal(t, pc(0x0FFF), c.pc)
}

// 3xkk - SE Vx, byte
func Test3000Equal(t *testing.T) {
	c := newCpuAt(0x31FF)
	c.regs[1] = 0xFF

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 3xkk - SE Vx, byte
func Test3000NotEqual(t *testing.T) {
	c := newCpuAt(0x31FF)
	c.regs[1] = 0xAA

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 4xkk - SNE Vx, byte
func Test4000Equal(t *testing.T) {
	c := newCpuAt(0x41FF)
	c.regs[1] = 0xFF

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 4xkk - SNE Vx, byte
func Test4000NotEqual(t *testing.T) {
	c := newCpuAt(0x41FF)
	c.regs[1] = 0xAA

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 5xy0 - SE Vx, Vy
func Test5000Equal(t *testing.T) {
	c := newCpuAt(0x512F)
	c.regs[1] = 0xFF
	c.regs[2] = 0xFF

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 5xy0 - SE Vx, Vy
func Test5000NotEqual(t *testing.T) {
	c := newCpuAt(0x512F)
	c.regs[1] = 0xFF
	c.regs[2] = 0xAA

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 6xkk - LD Vx, byte
func Test6000(t *testing.T) {
	c := newCpuAt(0x61FF)
	c.Step()
	assert.Equal(t, c.regs[1], byte(0xFF))
}

// 7xkk - ADD Vx, byte
func Test7000(t *testing.T) {
	c := newCpuAt(0x7101)
	c.regs[1] = 1
	c.Step()
	assert.Equal(t, c.regs[1], byte(2))
}

// 8xy0 - LD Vx, Vy
func Test8xy0(t *testing.T) {
	c := newCpuAt(0x8120)
	c.regs[1] = 1
	c.regs[2] = 0
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(0))
	c.Step()
	assert.Equal(t, c.regs[1], byte(0))
	assert.Equal(t, c.regs[2], byte(0))
}

// 8xy1 - OR Vx, Vy
func Test8xy1(t *testing.T) {
	c := newCpuAt(0x8121)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1|2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy2 - OR Vx, Vy
func Test8xy2(t *testing.T) {
	c := newCpuAt(0x8122)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1&2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy3 - OR Vx, Vy
func Test8xy3(t *testing.T) {
	c := newCpuAt(0x8123)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1^2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy4 - ADD Vx, Vy
func Test8xy4Overflow(t *testing.T) {
	c := newCpuAt(0x8124)
	c.regs[1] = 0xFF
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy4 - ADD Vx, Vy
func Test8xy4ONotverflow(t *testing.T) {
	c := newCpuAt(0x8124)
	c.regs[1] = 0xF0
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xF0+1))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xy5 - SUB Vx, Vy
func Test8xy5Greater(t *testing.T) {
	c := newCpuAt(0x8125)
	c.regs[1] = 2
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy5 - SUB Vx, Vy
func Test8xy5NotGreater(t *testing.T) {
	c := newCpuAt(0x8125)
	c.regs[1] = 1
	c.regs[2] = 2

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xFF))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xy6 - SHR Vx {, Vy}
func Test8xy6(t *testing.T) {
	c := newCpuAt(0x8126)
	c.regs[1] = 1

	c.Step()

	assert.Equal(t, c.regs[0xF], byte(1&0x0001))
	assert.Equal(t, c.regs[1], byte(1/2))
}

// 8xy7 - SUBN Vx, Vy
func Test8xy7Greater(t *testing.T) {
	c := newCpuAt(0x8127)
	c.regs[1] = 1
	c.regs[2] = 2

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy7 - SUBN Vx, Vy
func Test8xy7NotGreater(t *testing.T) {
	c := newCpuAt(0x8127)
	c.regs[1] = 2
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xFF))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xyE - SHL Vx {, Vy}
func Test8xyE(t *testing.T) {
	c := newCpuAt(0x812E)
	c.regs[1] = 1

	c.Step()

	assert.Equal(t, c.regs[0xF], byte(1&0x0001))
	assert.Equal(t, c.regs[1], byte(1*2))
}

// 9xy0 - SNE Vx, Vy
func Test9xy0NotEqual(t *testing.T) {
	c := newCpuAt(0x9120)
	c.regs[1] = 1
	c.regs[2] = 2

	oldPC := c.pc

	c.Step()

	assert.Equal(t, c.pc, oldPC+4)
}

// 9xy0 - SNE Vx, Vy
func Test9xy0Equal(t *testing.T) {
	c := newCpuAt(0x9120)
	c.regs[1] = 1
	c.regs[2] = 1

	oldPC := c.pc

	c.Step()

	assert.Equal(t, c.pc, oldPC+2)
}
<commit_msg>Added test for 0xA000<commit_after>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"testing"

	"github.com/bmizerany/assert"
)

// dumbSound - Only for testing purpuses
type dumbSound struct {
	BeepCalled bool
}

func (s *dumbSound) Beep() {
	(*s).BeepCalled = true
}

// newCpuAt creates a new cpu and write the ins to the pc memory location
// Only for testing purpuse
func newCpuAt(ins uint16) cpu {
	s := &dumbSound{}
	c := newCpu(s)
	c.memory.WriteWord(uint16(c.pc), ins)

	return c
}

func TestTimers(t *testing.T) {
	s := &dumbSound{}
	c := newCpu(s)

	// With Beep
	c.memory.WriteWord(uint16(c.pc), 0x0E0)

	c.dt = 1
	c.st = 1

	assert.Equal(t, s.BeepCalled, false)

	c.Step()

	assert.Equal(t, c.dt, byte(0))
	assert.Equal(t, c.st, byte(0))
	assert.Equal(t, s.BeepCalled, true)

	// No Beep
	c.memory.WriteWord(uint16(c.pc), 0x0E0)
	s.BeepCalled = false

	c.st = 2
	c.Step()

	assert.Equal(t, s.BeepCalled, false)
	assert.Equal(t, c.st, byte(1))
}

// 00E0 - CLS
func Test00E0(t *testing.T) {

	c := newCpuAt(0x00E0)
	c.gfx.SetPixel(0, 0)
	c.Step()

	for i := 0; i < 64; i++ {
		for j := 0; j < 32; j++ {
			assert.Equal(t, byte(COLOR_BLACK), byte(c.gfx.GetPixel(i, j)))
		}
	}
}

// 00EE - RET
func Test00EE(t *testing.T) {
	c := newCpuAt(0x00EE)

	c.stack.Push(pc(1))
	c.Step()

	assert.Equal(t, pc(1), c.pc)
}

// 1nnn - JP addr
func Test1000(t *testing.T) {
	c := newCpuAt(0x1FFF)
	c.Step()

	assert.Equal(t, pc(0x0FFF), c.pc)
}

// 2nnn - CALL addr
func Test2000(t *testing.T) {
	c := newCpuAt(0x2FFF)
	oldPC := c.pc + 2 // The increment happen before the Step

	c.Step()

	assert.Equal(t, oldPC, c.stack.Pop())
	assert.Equal(t, pc(0x0FFF), c.pc)
}

// 3xkk - SE Vx, byte
func Test3000Equal(t *testing.T) {
	c := newCpuAt(0x31FF)
	c.regs[1] = 0xFF

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 3xkk - SE Vx, byte
func Test3000NotEqual(t *testing.T) {
	c := newCpuAt(0x31FF)
	c.regs[1] = 0xAA

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 4xkk - SNE Vx, byte
func Test4000Equal(t *testing.T) {
	c := newCpuAt(0x41FF)
	c.regs[1] = 0xFF

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 4xkk - SNE Vx, byte
func Test4000NotEqual(t *testing.T) {
	c := newCpuAt(0x41FF)
	c.regs[1] = 0xAA

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 5xy0 - SE Vx, Vy
func Test5000Equal(t *testing.T) {
	c := newCpuAt(0x512F)
	c.regs[1] = 0xFF
	c.regs[2] = 0xFF

	oldPC := c.pc + 4
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 5xy0 - SE Vx, Vy
func Test5000NotEqual(t *testing.T) {
	c := newCpuAt(0x512F)
	c.regs[1] = 0xFF
	c.regs[2] = 0xAA

	oldPC := c.pc + 2
	c.Step()

	assert.Equal(t, oldPC, c.pc)
}

// 6xkk - LD Vx, byte
func Test6000(t *testing.T) {
	c := newCpuAt(0x61FF)
	c.Step()
	assert.Equal(t, c.regs[1], byte(0xFF))
}

// 7xkk - ADD Vx, byte
func Test7000(t *testing.T) {
	c := newCpuAt(0x7101)
	c.regs[1] = 1
	c.Step()
	assert.Equal(t, c.regs[1], byte(2))
}

// 8xy0 - LD Vx, Vy
func Test8xy0(t *testing.T) {
	c := newCpuAt(0x8120)
	c.regs[1] = 1
	c.regs[2] = 0
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(0))
	c.Step()
	assert.Equal(t, c.regs[1], byte(0))
	assert.Equal(t, c.regs[2], byte(0))
}

// 8xy1 - OR Vx, Vy
func Test8xy1(t *testing.T) {
	c := newCpuAt(0x8121)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1|2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy2 - OR Vx, Vy
func Test8xy2(t *testing.T) {
	c := newCpuAt(0x8122)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1&2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy3 - OR Vx, Vy
func Test8xy3(t *testing.T) {
	c := newCpuAt(0x8123)
	c.regs[1] = 1
	c.regs[2] = 2
	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[2], byte(2))
	c.Step()
	assert.Equal(t, c.regs[1], byte(1^2))
	assert.Equal(t, c.regs[2], byte(2))
}

// 8xy4 - ADD Vx, Vy
func Test8xy4Overflow(t *testing.T) {
	c := newCpuAt(0x8124)
	c.regs[1] = 0xFF
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy4 - ADD Vx, Vy
func Test8xy4ONotverflow(t *testing.T) {
	c := newCpuAt(0x8124)
	c.regs[1] = 0xF0
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xF0+1))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xy5 - SUB Vx, Vy
func Test8xy5Greater(t *testing.T) {
	c := newCpuAt(0x8125)
	c.regs[1] = 2
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy5 - SUB Vx, Vy
func Test8xy5NotGreater(t *testing.T) {
	c := newCpuAt(0x8125)
	c.regs[1] = 1
	c.regs[2] = 2

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xFF))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xy6 - SHR Vx {, Vy}
func Test8xy6(t *testing.T) {
	c := newCpuAt(0x8126)
	c.regs[1] = 1

	c.Step()

	assert.Equal(t, c.regs[0xF], byte(1&0x0001))
	assert.Equal(t, c.regs[1], byte(1/2))
}

// 8xy7 - SUBN Vx, Vy
func Test8xy7Greater(t *testing.T) {
	c := newCpuAt(0x8127)
	c.regs[1] = 1
	c.regs[2] = 2

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(1))
	assert.Equal(t, c.regs[0xF], byte(1))
}

// 8xy7 - SUBN Vx, Vy
func Test8xy7NotGreater(t *testing.T) {
	c := newCpuAt(0x8127)
	c.regs[1] = 2
	c.regs[2] = 1

	assert.Equal(t, c.regs[0xF], byte(0))

	c.Step()

	assert.Equal(t, c.regs[1], byte(0xFF))
	assert.Equal(t, c.regs[0xF], byte(0))
}

// 8xyE - SHL Vx {, Vy}
func Test8xyE(t *testing.T) {
	c := newCpuAt(0x812E)
	c.regs[1] = 1

	c.Step()

	assert.Equal(t, c.regs[0xF], byte(1&0x0001))
	assert.Equal(t, c.regs[1], byte(1*2))
}

// 9xy0 - SNE Vx, Vy
func Test9xy0NotEqual(t *testing.T) {
	c := newCpuAt(0x9120)
	c.regs[1] = 1
	c.regs[2] = 2

	oldPC := c.pc

	c.Step()

	assert.Equal(t, c.pc, oldPC+4)
}

// 9xy0 - SNE Vx, Vy
func Test9xy0Equal(t *testing.T) {
	c := newCpuAt(0x9120)
	c.regs[1] = 1
	c.regs[2] = 1

	oldPC := c.pc

	c.Step()

	assert.Equal(t, c.pc, oldPC+2)
}

// Annn - LD I, addr
func TestA000(t *testing.T) {
	c := newCpuAt(0xAFFF)

	c.Step()

	assert.Equal(t, c.i, uint16(0xFFF))
}
<|endoftext|>


<commit_before>package css // import "github.com/tdewolff/parse/css"

import (
	"bytes"
	"io"
)

////////////////////////////////////////////////////////////////

// Node is an interface that all nodes implement.
type Node interface {
	WriteTo(io.Writer) (int64, error)
}

////////////////////////////////////////////////////////////////

// TokenNode is a leaf node of a single token.
type TokenNode struct {
	TokenType
	Data []byte
}

// NewToken returns a new TokenNode.
func NewToken(tt TokenType, data []byte) *TokenNode {
	return &TokenNode{
		tt,
		data,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (token TokenNode) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(token.Data)
	return int64(n), err
}

////////////////////////////////////////////////////////////////

// StylesheetNode is the apex node of the whole stylesheet.
// Nodes contains TokenNode, AtRuleNode, DeclarationNode and RulesetNode nodes.
type StylesheetNode struct {
	Nodes []Node
}

// NewStylesheet returns a new StylesheetNode.
func NewStylesheet() *StylesheetNode {
	return &StylesheetNode{
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (stylesheet StylesheetNode) WriteTo(w io.Writer) (size int64, err error) {
	var m int64
	for _, node := range stylesheet.Nodes {
		m, err = node.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// AtRuleNode contains several nodes and/or a block node.
type AtRuleNode struct {
	At    *TokenNode
	Nodes []Node
	Rules []Node
}

// NewAtRule returns a new AtRuleNode.
func NewAtRule(at *TokenNode) *AtRuleNode {
	return &AtRuleNode{
		at,
		nil,
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (atrule AtRuleNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = atrule.At.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	for i, node := range atrule.Nodes {
		if i != 0 {
			var t *TokenNode
			if k, ok := atrule.Nodes[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := atrule.Nodes[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || t.Data[0] != ',' {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		} else {
			n, err = w.Write([]byte(" "))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = node.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	if len(atrule.Rules) > 0 {
		n, err = w.Write([]byte("{"))
		if err != nil {
			return
		}
		size += int64(n)
		for _, rule := range atrule.Rules {
			m, err = rule.WriteTo(w)
			if err != nil {
				return
			}
			size += m
		}
		n, err = w.Write([]byte("}"))
		if err != nil {
			return
		}
		size += int64(n)
	} else {
		n, err = w.Write([]byte(";"))
		if err != nil {
			return
		}
		size += int64(n)
	}
	return
}

////////////////////////////////////////////////////////////////

// RulesetNode consists of selector groups (separated by commas) and a declaration list.
type RulesetNode struct {
	Selectors []*SelectorNode
	Decls     []*DeclarationNode
}

// NewRuleset returns a new RulesetNode.
func NewRuleset() *RulesetNode {
	return &RulesetNode{
		nil,
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (ruleset RulesetNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	for i, sel := range ruleset.Selectors {
		if i != 0 {
			n, err = w.Write([]byte(","))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = sel.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte("{"))
	if err != nil {
		return
	}
	size += int64(n)
	for _, decl := range ruleset.Decls {
		m, err = decl.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte("}"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// SelectorNode contains the tokens of a single selector, either TokenNode or AttributeSelectorNode.
type SelectorNode struct {
	Elems []*TokenNode
}

// NewSelector returns a new SelectorNode.
func NewSelector() *SelectorNode {
	return &SelectorNode{
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (sel SelectorNode) WriteTo(w io.Writer) (size int64, err error) {
	var m int64
	for _, elem := range sel.Elems {
		m, err = elem.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// DeclarationNode represents a property declaration.
// Vals contains FunctionNode and TokenNode nodes.
type DeclarationNode struct {
	Prop      *TokenNode
	Vals      []Node
	Important bool
}

// NewDeclaration returns a new DeclarationNode.
func NewDeclaration(prop *TokenNode) *DeclarationNode {
	prop.Data = bytes.ToLower(prop.Data)
	return &DeclarationNode{
		prop,
		nil,
		false,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (decl DeclarationNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = decl.Prop.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	n, err = w.Write([]byte(":"))
	if err != nil {
		return
	}
	size += int64(n)
	for i, val := range decl.Vals {
		if i != 0 {
			var t *TokenNode
			if k, ok := decl.Vals[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := decl.Vals[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || (t.Data[0] != ',' && t.Data[0] != '/' && t.Data[0] != ':' && t.Data[0] != '.') {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		}
		m, err = val.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	if decl.Important {
		n, err = w.Write([]byte(" !important"))
		if err != nil {
			return
		}
		size += int64(n)
	}
	n, err = w.Write([]byte(";"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// FunctionNode represents a function and its arguments (separated by commas).
type FunctionNode struct {
	Func *TokenNode
	Args []*ArgumentNode
}

// NewFunction returns a new FunctionNode.
func NewFunction(fun *TokenNode) *FunctionNode {
	fun.Data = fun.Data[:len(fun.Data)-1]
	return &FunctionNode{
		fun,
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (fun FunctionNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = fun.Func.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	n, err = w.Write([]byte("("))
	if err != nil {
		return
	}
	size += int64(n)
	for i, arg := range fun.Args {
		if i != 0 {
			n, err = w.Write([]byte(","))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = arg.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte(")"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// ArgumentNode represents the key and parts of an argument separated by spaces.
type ArgumentNode struct {
	Vals []Node
}

// NewArgument returns a new ArgumentNode.
func NewArgument() *ArgumentNode {
	return &ArgumentNode{
		[]Node{},
	}
}

// WriteTo writes the string representation of the node to the writer.
func (arg ArgumentNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	for i, val := range arg.Vals {
		if i != 0 {
			var t *TokenNode
			if k, ok := arg.Vals[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := arg.Vals[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || (t.Data[0] != '=' && t.Data[0] != '*' && t.Data[0] != '/') {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		}
		m, err = val.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// BlockNode contains the contents of a block (brace, bracket or parenthesis blocks).
// Nodes contains AtRuleNode, DeclarationNode, RulesetNode and BlockNode nodes.
type BlockNode struct {
	Open  *TokenNode
	Nodes []Node
	Close *TokenNode
}

// NewBlock returns a new BlockNode.
func NewBlock(open *TokenNode) *BlockNode {
	return &BlockNode{
		open,
		nil,
		nil,
	}
}

// WriteTo writes the string representation of the node to the writer.
func (block BlockNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	if block.Open != nil && block.Close != nil && len(block.Nodes) > 0 {
		m, err = block.Open.WriteTo(w)
		if err != nil {
			return
		}
		size += m
		for i, node := range block.Nodes {
			if i != 0 {
				var t *TokenNode
				if k, ok := block.Nodes[i-1].(*TokenNode); ok && len(k.Data) == 1 {
					t = k
				} else if k, ok := block.Nodes[i].(*TokenNode); ok && len(k.Data) == 1 {
					t = k
				}
				if t == nil || t.Data[0] != ':' {
					n, err = w.Write([]byte(" "))
					if err != nil {
						return
					}
					size += int64(n)
				}
			}
			m, err = node.WriteTo(w)
			if err != nil {
				return
			}
			size += m
		}
		m, err = block.Close.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}
<commit_msg>Remove New functions and a few renames<commit_after>package css // import "github.com/tdewolff/parse/css"

import (
	"io"
)

// Node is an interface that all nodes implement.
type Node interface {
	WriteTo(io.Writer) (int64, error)
}

////////////////////////////////////////////////////////////////

// TokenNode is a leaf node of a single token.
type TokenNode struct {
	TokenType
	Data []byte
}

// WriteTo writes the string representation of the node to the writer.
func (token TokenNode) WriteTo(w io.Writer) (int64, error) {
	n, err := w.Write(token.Data)
	return int64(n), err
}

////////////////////////////////////////////////////////////////

// StylesheetNode is the apex node of the whole stylesheet.
// Nodes contains TokenNode, AtRuleNode, DeclarationNode and RulesetNode nodes.
type StylesheetNode struct {
	Nodes []Node
}

// WriteTo writes the string representation of the node to the writer.
func (stylesheet StylesheetNode) WriteTo(w io.Writer) (size int64, err error) {
	var m int64
	for _, node := range stylesheet.Nodes {
		m, err = node.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// AtRuleNode contains several nodes and/or a block node.
type AtRuleNode struct {
	Name  *TokenNode
	Nodes []Node
	Rules []Node
}

// WriteTo writes the string representation of the node to the writer.
func (atrule AtRuleNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = atrule.Name.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	for i, node := range atrule.Nodes {
		if i != 0 {
			var t *TokenNode
			if k, ok := atrule.Nodes[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := atrule.Nodes[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || t.Data[0] != ',' {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		} else {
			n, err = w.Write([]byte(" "))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = node.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	if len(atrule.Rules) > 0 {
		n, err = w.Write([]byte("{"))
		if err != nil {
			return
		}
		size += int64(n)
		for _, rule := range atrule.Rules {
			m, err = rule.WriteTo(w)
			if err != nil {
				return
			}
			size += m
		}
		n, err = w.Write([]byte("}"))
		if err != nil {
			return
		}
		size += int64(n)
	} else {
		n, err = w.Write([]byte(";"))
		if err != nil {
			return
		}
		size += int64(n)
	}
	return
}

////////////////////////////////////////////////////////////////

// RulesetNode consists of selector groups (separated by commas) and a declaration list.
type RulesetNode struct {
	Selectors []*SelectorNode
	Decls     []*DeclarationNode
}

// WriteTo writes the string representation of the node to the writer.
func (ruleset RulesetNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	for i, sel := range ruleset.Selectors {
		if i != 0 {
			n, err = w.Write([]byte(","))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = sel.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte("{"))
	if err != nil {
		return
	}
	size += int64(n)
	for _, decl := range ruleset.Decls {
		m, err = decl.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte("}"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// SelectorNode contains the tokens of a single selector, either TokenNode or AttributeSelectorNode.
type SelectorNode struct {
	Elems []*TokenNode
}

// WriteTo writes the string representation of the node to the writer.
func (sel SelectorNode) WriteTo(w io.Writer) (size int64, err error) {
	var m int64
	for _, elem := range sel.Elems {
		m, err = elem.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// DeclarationNode represents a property declaration.
// Vals contains FunctionNode and TokenNode nodes.
type DeclarationNode struct {
	Prop      *TokenNode
	Vals      []Node
	Important bool
}

// WriteTo writes the string representation of the node to the writer.
func (decl DeclarationNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = decl.Prop.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	n, err = w.Write([]byte(":"))
	if err != nil {
		return
	}
	size += int64(n)
	for i, val := range decl.Vals {
		if i != 0 {
			var t *TokenNode
			if k, ok := decl.Vals[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := decl.Vals[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || (t.Data[0] != ',' && t.Data[0] != '/' && t.Data[0] != ':' && t.Data[0] != '.') {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		}
		m, err = val.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	if decl.Important {
		n, err = w.Write([]byte(" !important"))
		if err != nil {
			return
		}
		size += int64(n)
	}
	n, err = w.Write([]byte(";"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// FunctionNode represents a function and its arguments (separated by commas).
type FunctionNode struct {
	Name *TokenNode
	Args []*ArgumentNode
}

// WriteTo writes the string representation of the node to the writer.
func (fun FunctionNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	m, err = fun.Name.WriteTo(w)
	if err != nil {
		return
	}
	size += m
	n, err = w.Write([]byte("("))
	if err != nil {
		return
	}
	size += int64(n)
	for i, arg := range fun.Args {
		if i != 0 {
			n, err = w.Write([]byte(","))
			if err != nil {
				return
			}
			size += int64(n)
		}
		m, err = arg.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	n, err = w.Write([]byte(")"))
	if err != nil {
		return
	}
	size += int64(n)
	return
}

////////////////////////////////////////////////////////////////

// ArgumentNode represents the key and parts of an argument separated by spaces.
type ArgumentNode struct {
	Vals []Node
}

// WriteTo writes the string representation of the node to the writer.
func (arg ArgumentNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	for i, val := range arg.Vals {
		if i != 0 {
			var t *TokenNode
			if k, ok := arg.Vals[i-1].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			} else if k, ok := arg.Vals[i].(*TokenNode); ok && len(k.Data) == 1 {
				t = k
			}
			if t == nil || (t.Data[0] != '=' && t.Data[0] != '*' && t.Data[0] != '/') {
				n, err = w.Write([]byte(" "))
				if err != nil {
					return
				}
				size += int64(n)
			}
		}
		m, err = val.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}

////////////////////////////////////////////////////////////////

// BlockNode contains the contents of a block (brace, bracket or parenthesis blocks).
// Nodes contains AtRuleNode, DeclarationNode, RulesetNode and BlockNode nodes.
type BlockNode struct {
	Open  *TokenNode
	Nodes []Node
	Close *TokenNode
}

// WriteTo writes the string representation of the node to the writer.
func (block BlockNode) WriteTo(w io.Writer) (size int64, err error) {
	var n int
	var m int64
	if block.Open != nil && block.Close != nil && len(block.Nodes) > 0 {
		m, err = block.Open.WriteTo(w)
		if err != nil {
			return
		}
		size += m
		for i, node := range block.Nodes {
			if i != 0 {
				var t *TokenNode
				if k, ok := block.Nodes[i-1].(*TokenNode); ok && len(k.Data) == 1 {
					t = k
				} else if k, ok := block.Nodes[i].(*TokenNode); ok && len(k.Data) == 1 {
					t = k
				}
				if t == nil || t.Data[0] != ':' {
					n, err = w.Write([]byte(" "))
					if err != nil {
						return
					}
					size += int64(n)
				}
			}
			m, err = node.WriteTo(w)
			if err != nil {
				return
			}
			size += m
		}
		m, err = block.Close.WriteTo(w)
		if err != nil {
			return
		}
		size += m
	}
	return
}
<|endoftext|>


<commit_before>package ctxerr

import (
	"fmt"

	"github.com/fatih/color"
)

func init() {
	color.NoColor = true
}

func ExamplePoint() {
	fmt.Println(New("00100", Point(1, 3)))
	// Output:
	// 1:3:
	// 1 | 00100
	//   |   ^
}

func ExampleRange() {
	fmt.Println(New("01110", Range(1, 2, 1, 4)))
	// Output:
	// 1:2-4:
	// 1 | 01110
	//   |  ^^^
}

func ExampleRange_multiline() {
	fmt.Println(New("00001\n11110", Range(1, 5, 2, 4)))
	// Output:
	// 1:5-2:4:
	// 1 | 00001
	//   |     ^
	// 2 | 11110
	//   | ^^^^
}

func ExampleCtx_WithHint() {
	ctx := New("010101102110", Point(1, 9)).WithHint("don't worry, bender")
	fmt.Println(ctx)
	// Output:
	// 1:9:
	// 1 | 010101102110
	//   |         ^ don't worry, bender
}

func ExampleCtx_WithContext_limited() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12)).WithContext(1)
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
}

func ExampleCtx_WithContext_all() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12)).WithContext(-1)
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 1 | 1st
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
	// 5 | 5th
}
<commit_msg>Test WithContext with multiline region<commit_after>package ctxerr

import (
	"fmt"

	"github.com/fatih/color"
)

func init() {
	color.NoColor = true
}

func ExamplePoint() {
	fmt.Println(New("00100", Point(1, 3)))
	// Output:
	// 1:3:
	// 1 | 00100
	//   |   ^
}

func ExampleRange() {
	fmt.Println(New("01110", Range(1, 2, 1, 4)))
	// Output:
	// 1:2-4:
	// 1 | 01110
	//   |  ^^^
}

func ExampleRange_multiline() {
	fmt.Println(New("00001\n11110", Range(1, 5, 2, 4)))
	// Output:
	// 1:5-2:4:
	// 1 | 00001
	//   |     ^
	// 2 | 11110
	//   | ^^^^
}

func ExampleCtx_WithHint() {
	ctx := New("010101102110", Point(1, 9)).WithHint("don't worry, bender")
	fmt.Println(ctx)
	// Output:
	// 1:9:
	// 1 | 010101102110
	//   |         ^ don't worry, bender
}

func ExampleCtx_WithContext_limited() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12)).WithContext(1)
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
}

func ExampleCtx_WithContext_limitedMultiline() {
	in := `1st
2nd
3rd has an error
4th still has an error
5th`
	ctx := New(in, Range(3, 1, 4, 22)).WithContext(1)
	fmt.Println(ctx)
	// Output:
	// 3:1-4:22:
	// 2 | 2nd
	// 3 | 3rd has an error
	//   | ^^^^^^^^^^^^^^^^
	// 4 | 4th still has an error
	//   | ^^^^^^^^^^^^^^^^^^^^^^
	// 5 | 5th
}

func ExampleCtx_WithContext_all() {
	in := `1st
2nd
3rd has an error
4th
5th`
	ctx := New(in, Point(3, 12)).WithContext(-1)
	fmt.Println(ctx)
	// Output:
	// 3:12:
	// 1 | 1st
	// 2 | 2nd
	// 3 | 3rd has an error
	//   |            ^
	// 4 | 4th
	// 5 | 5th
}
<|endoftext|>


<commit_before>package poloniex

type Currency struct {
	Name               string  `json:"name"`
	MaxDailyWithdrawal float64 `json:"maxDailyWithdrawal,string"`
	TxFee              float64 `json:"txFee,string"`
	MinConf            int     `json:"minConf"`
	Disabled           int     `json:"disabled"`
	Frozen             int     `json:"frozen"`
	Delisted           int     `json:"delisted"`
}

type Currencies struct {
	Pair map[string]Currency
}
<commit_msg>maxDailyWithdrawal now returns string "DEPRECATED"<commit_after>package poloniex

type Currency struct {
	Name               string  `json:"name"`
	MaxDailyWithdrawal string  `json:"maxDailyWithdrawal"`
	TxFee              float64 `json:"txFee,string"`
	MinConf            int     `json:"minConf"`
	Disabled           int     `json:"disabled"`
	Frozen             int     `json:"frozen"`
	Delisted           int     `json:"delisted"`
}

type Currencies struct {
	Pair map[string]Currency
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"regexp"
)

type karmas map[string]int

var regex = regexp.MustCompile("[^ ]+\\+\\+")

func main() {
	k := karmas(make(map[string]int))
	http.Handle("/", k)

	http.ListenAndServe(":8080", nil)
}

func (k karmas) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	text := r.Form.Get("text")
	matches := regex.FindAllString(text, -1)
	if matches == nil {
		return
	}
	for _, match := range matches {
		k[match]++
	}
}
<commit_msg>IT'S ALIVE<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"regexp"
)

type karmas struct {
	karmaMap *map[string]int
}

var regex = regexp.MustCompile("([^ ]+)\\+\\+")
var getkarma = regexp.MustCompile("^!karma +([^ ]+)")

func main() {
	k := newKarmas()
	http.Handle("/", k)

	http.ListenAndServe(":8080", nil)
}

func newKarmas() karmas {
	m := make(map[string]int)
	return karmas{&m}
}

func (k karmas) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	text := r.Form.Get("text")
	matches := regex.FindAllStringSubmatch(text, -1)
	karma := getkarma.FindStringSubmatch(text)
	if matches != nil {
		for _, match := range matches {
			key := match[1]
			if key != "" {
				(*k.karmaMap)[key]++
			}
		}
		fmt.Println(*k.karmaMap)
	} else if karma != nil {
		name := karma[1]
		fmt.Println("asking for", name)
		res := make(map[string]string)
		res["text"] = fmt.Sprintf("%v: %v", r.Form.Get("user_name"), (*k.karmaMap)[name])
		res["parse"] = "full"
		resp, _ := json.Marshal(res)
		fmt.Println(string(resp))
		w.WriteHeader(200)
		w.Write(resp)
	}
}
<|endoftext|>