<commit_before>package catalog

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"

	"github.com/dnaeon/gru/graph"
	"github.com/dnaeon/gru/module"
	"github.com/dnaeon/gru/resource"
)

// ErrEmptyCatalog is returned when no resources were found from the
// loaded modules in the catalog
var ErrEmptyCatalog = errors.New("Catalog is empty")

type resourceMap map[string]resource.Resource

// Catalog type represents a collection of modules loaded from HCL or JSON
type Catalog struct {
	modules []*module.Module
}

// newCatalog creates a new empty catalog
func newCatalog() *Catalog {
	c := &Catalog{
		modules: make([]*module.Module, 0),
	}

	return c
}

// createResourceMap creates a map of the unique resource IDs and
// the actual resource instances
func (c *Catalog) createResourceMap() (resourceMap, error) {
	// A map containing the unique resource ID and the
	// module where the resource has been declared
	rModuleMap := make(map[string]string)

	rMap := make(resourceMap)
	for _, m := range c.modules {
		for _, r := range m.Resources {
			id := r.ID()
			if _, ok := rMap[id]; ok {
				return rMap, fmt.Errorf("Duplicate resource %s in %s, previous declaration was in %s", id, m.Name, rModuleMap[id])
			}
			rModuleMap[id] = m.Name
			rMap[id] = r
		}
	}

	if len(rMap) == 0 {
		return rMap, ErrEmptyCatalog
	}

	return rMap, nil
}

// resourceGraph creates a DAG graph for the resources in catalog
func (c *Catalog) resourceGraph() (*graph.Graph, error) {
	// Create a DAG graph of the resources in catalog
	// The generated graph can be topologically sorted in order to
	// determine the proper order of evaluating resources
	// If the graph cannot be sorted, it means we have a
	// circular dependency in our resources
	g := graph.NewGraph()

	resources, err := c.createResourceMap()
	if err != nil {
		return g, err
	}

	// A map containing the resource ids and their nodes in the graph
	// Create a graph nodes for each resource from the catalog
	nodes := make(map[string]*graph.Node)
	for name := range resources {
		node := graph.NewNode(name)
		nodes[name] = node
		g.AddNode(node)
	}

	// Connect the nodes in the graph
	for name, r := range resources {
		deps := r.Want()
		for _, dep := range deps {
			if _, ok := resources[dep]; !ok {
				e := fmt.Errorf("Resource %s wants %s, which is not in catalog", name, dep)
				return g, e
			}
			g.AddEdge(nodes[name], nodes[dep])
		}
	}

	return g, nil
}

// Run processes the catalog
func (c *Catalog) Run() error {
	rMap, err := c.createResourceMap()
	if err != nil {
		return err
	}

	// Perform topological sort of the resources graph
	g, err := c.resourceGraph()
	if err != nil {
		return err
	}

	sorted, err := g.Sort()
	if err != nil {
		return err
	}

	for _, node := range sorted {
		r := rMap[node.Name]
		id := r.ID()
		state, err := r.Evaluate()
		if err != nil {
			log.Printf("Failed to evaluate resource '%s': %s", id, err)
			continue
		}

		if state.Want == state.Current {
			continue
		}

		log.Printf("%s is %s, should be %s", id, state.Current, state.Want)
		switch {
		case state.Want == resource.ResourceStatePresent && state.Current == resource.ResourceStateAbsent:
			r.Create()
		case state.Want == resource.ResourceStateAbsent && state.Current != resource.ResourceStateAbsent:
			r.Delete()
		case state.Want == resource.ResourceStateUpdate && state.Current == resource.ResourceStatePresent:
			r.Update()
		default:
			log.Printf("Unknown state '%s' for resource '%s'", state.Want, id)
		}
	}

	return nil
}

// GenerateCatalogDOT generates a DOT file of the resources graph from catalog
func (c *Catalog) GenerateCatalogDOT(w io.Writer) error {
	g, err := c.resourceGraph()
	if err != nil {
		return err
	}
	g.GenerateDOT("resources", w)

	// Try a topological sort of the graph
	// In case of circular dependencies in the graph
	// generate a DOT file for the remaining nodes in the graph,
	// which would give us the resources causing circular dependencies
	if nodes, err := g.Sort(); err == graph.ErrCircularDependency {
		circularGraph := graph.NewGraph()
		circularGraph.AddNode(nodes...)
		circularGraph.GenerateDOT("resources_circular", w)
	}

	return nil
}

// Len returns the number of unique resources found in catalog
func (c *Catalog) Len() int {
	resources, err := c.createResourceMap()
	if err != nil {
		return 0
	}

	return len(resources)
}

// Load creates a catalog from the provided module name
func Load(main, path string) (*Catalog, error) {
	c := newCatalog()

	// Discover all modules from the provided module path
	registry, err := module.Discover(path)
	if _, ok := registry[main]; !ok {
		return c, fmt.Errorf("Module %s was not found in the module path", main)
	}

	// A map containing the module names and the actual loaded modules
	moduleNames := make(map[string]*module.Module)
	for n, p := range registry {
		m, err := module.Load(n, p)
		if err != nil {
			return c, err
		}
		moduleNames[n] = m
	}

	// A map containing the modules as graph nodes
	// The graph is used to determine if we have
	// circular module imports and also to provide the
	// proper ordering of loading modules after a
	// topological sort of the graph nodes
	nodes := make(map[string]*graph.Node)
	for n := range moduleNames {
		node := graph.NewNode(n)
		nodes[n] = node
	}

	// Recursively find all imports that the main module has and
	// resolve the dependency graph
	g := graph.NewGraph()
	var createModuleGraph func(m *module.Module) error
	createModuleGraph = func(m *module.Module) error {
		if !g.NodeExists(m.Name) {
			g.AddNode(nodes[m.Name])
		} else {
			return nil
		}

		for _, importName := range m.ModuleImport.Module {
			if _, ok := moduleNames[importName]; !ok {
				return fmt.Errorf("Module %s imports %s, which is not in the module path", m.Name, importName)
			}

			// Build the dependencies of imported modules as well
			createModuleGraph(moduleNames[importName])

			// Finally connect the nodes in the graph
			g.AddEdge(nodes[m.Name], nodes[importName])
		}

		return nil
	}

	//	Build the dependency graph of the module imports
	err = createModuleGraph(moduleNames[main])
	if err != nil {
		return c, err
	}

	// Topologically sort the graph
	// In case of an error it means we have a circular import
	sorted, err := g.Sort()
	if err != nil {
		return c, err
	}

	// Finally add the sorted modules to the catalog
	for _, node := range sorted {
		c.modules = append(c.modules, moduleNames[node.Name])
	}

	return c, nil
}

// MarshalJSON creates a stripped down version of the catalog in JSON,
// which contains all resources from the catalog and is suitable for
// clients to consume in order to create a single-module catalog from it.
func (c *Catalog) MarshalJSON() ([]byte, error) {
	rMap, err := c.createResourceMap()
	if err != nil {
		return nil, err
	}

	resources := make([]resourceMap, 0)
	for _, r := range rMap {
		rJson := resourceMap{
			r.Type(): r,
		}
		resources = append(resources, rJson)
	}

	return json.Marshal(map[string]interface{}{
		"resource": resources,
	})
}
<commit_msg>Comment update<commit_after>package catalog

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"

	"github.com/dnaeon/gru/graph"
	"github.com/dnaeon/gru/module"
	"github.com/dnaeon/gru/resource"
)

// ErrEmptyCatalog is returned when no resources were found from the
// loaded modules in the catalog
var ErrEmptyCatalog = errors.New("Catalog is empty")

type resourceMap map[string]resource.Resource

// Catalog type represents a collection of modules loaded from HCL or JSON
type Catalog struct {
	modules []*module.Module
}

// newCatalog creates a new empty catalog
func newCatalog() *Catalog {
	c := &Catalog{
		modules: make([]*module.Module, 0),
	}

	return c
}

// createResourceMap creates a map of the unique resource IDs and
// the actual resource instances
func (c *Catalog) createResourceMap() (resourceMap, error) {
	// A map containing the unique resource ID and the
	// module where the resource has been declared
	rModuleMap := make(map[string]string)

	rMap := make(resourceMap)
	for _, m := range c.modules {
		for _, r := range m.Resources {
			id := r.ID()
			if _, ok := rMap[id]; ok {
				return rMap, fmt.Errorf("Duplicate resource %s in %s, previous declaration was in %s", id, m.Name, rModuleMap[id])
			}
			rModuleMap[id] = m.Name
			rMap[id] = r
		}
	}

	if len(rMap) == 0 {
		return rMap, ErrEmptyCatalog
	}

	return rMap, nil
}

// resourceGraph creates a DAG graph for the resources in catalog
func (c *Catalog) resourceGraph() (*graph.Graph, error) {
	// Create a DAG graph of the resources in catalog
	// The generated graph can be topologically sorted in order to
	// determine the proper order of evaluating resources
	// If the graph cannot be sorted, it means we have a
	// circular dependency in our resources
	g := graph.NewGraph()

	resources, err := c.createResourceMap()
	if err != nil {
		return g, err
	}

	// A map containing the resource ids and their nodes in the graph
	// Create a graph nodes for each resource from the catalog
	nodes := make(map[string]*graph.Node)
	for name := range resources {
		node := graph.NewNode(name)
		nodes[name] = node
		g.AddNode(node)
	}

	// Connect the nodes in the graph
	for name, r := range resources {
		deps := r.Want()
		for _, dep := range deps {
			if _, ok := resources[dep]; !ok {
				e := fmt.Errorf("Resource %s wants %s, which is not in catalog", name, dep)
				return g, e
			}
			g.AddEdge(nodes[name], nodes[dep])
		}
	}

	return g, nil
}

// Run processes the catalog
func (c *Catalog) Run() error {
	rMap, err := c.createResourceMap()
	if err != nil {
		return err
	}

	// Perform topological sort of the resources graph
	g, err := c.resourceGraph()
	if err != nil {
		return err
	}

	sorted, err := g.Sort()
	if err != nil {
		return err
	}

	for _, node := range sorted {
		r := rMap[node.Name]
		id := r.ID()
		state, err := r.Evaluate()
		if err != nil {
			log.Printf("Failed to evaluate resource '%s': %s", id, err)
			continue
		}

		if state.Want == state.Current {
			continue
		}

		log.Printf("%s is %s, should be %s", id, state.Current, state.Want)
		switch {
		case state.Want == resource.ResourceStatePresent && state.Current == resource.ResourceStateAbsent:
			r.Create()
		case state.Want == resource.ResourceStateAbsent && state.Current != resource.ResourceStateAbsent:
			r.Delete()
		case state.Want == resource.ResourceStateUpdate && state.Current == resource.ResourceStatePresent:
			r.Update()
		default:
			log.Printf("Unknown state '%s' for resource '%s'", state.Want, id)
		}
	}

	return nil
}

// GenerateCatalogDOT generates a DOT file for the resources in catalog
func (c *Catalog) GenerateCatalogDOT(w io.Writer) error {
	g, err := c.resourceGraph()
	if err != nil {
		return err
	}
	g.GenerateDOT("resources", w)

	// Try a topological sort of the graph
	// In case of circular dependencies in the graph
	// generate a DOT file for the remaining nodes in the graph,
	// which would give us the resources causing circular dependencies
	if nodes, err := g.Sort(); err == graph.ErrCircularDependency {
		circularGraph := graph.NewGraph()
		circularGraph.AddNode(nodes...)
		circularGraph.GenerateDOT("resources_circular", w)
	}

	return nil
}

// Len returns the number of unique resources found in catalog
func (c *Catalog) Len() int {
	resources, err := c.createResourceMap()
	if err != nil {
		return 0
	}

	return len(resources)
}

// Load creates a catalog from the provided module name
func Load(main, path string) (*Catalog, error) {
	c := newCatalog()

	// Discover all modules from the provided module path
	registry, err := module.Discover(path)
	if _, ok := registry[main]; !ok {
		return c, fmt.Errorf("Module %s was not found in the module path", main)
	}

	// A map containing the module names and the actual loaded modules
	moduleNames := make(map[string]*module.Module)
	for n, p := range registry {
		m, err := module.Load(n, p)
		if err != nil {
			return c, err
		}
		moduleNames[n] = m
	}

	// A map containing the modules as graph nodes
	// The graph is used to determine if we have
	// circular module imports and also to provide the
	// proper ordering of loading modules after a
	// topological sort of the graph nodes
	nodes := make(map[string]*graph.Node)
	for n := range moduleNames {
		node := graph.NewNode(n)
		nodes[n] = node
	}

	// Recursively find all imports that the main module has and
	// resolve the dependency graph
	g := graph.NewGraph()
	var createModuleGraph func(m *module.Module) error
	createModuleGraph = func(m *module.Module) error {
		if !g.NodeExists(m.Name) {
			g.AddNode(nodes[m.Name])
		} else {
			return nil
		}

		for _, importName := range m.ModuleImport.Module {
			if _, ok := moduleNames[importName]; !ok {
				return fmt.Errorf("Module %s imports %s, which is not in the module path", m.Name, importName)
			}

			// Build the dependencies of imported modules as well
			createModuleGraph(moduleNames[importName])

			// Finally connect the nodes in the graph
			g.AddEdge(nodes[m.Name], nodes[importName])
		}

		return nil
	}

	//	Build the dependency graph of the module imports
	err = createModuleGraph(moduleNames[main])
	if err != nil {
		return c, err
	}

	// Topologically sort the graph
	// In case of an error it means we have a circular import
	sorted, err := g.Sort()
	if err != nil {
		return c, err
	}

	// Finally add the sorted modules to the catalog
	for _, node := range sorted {
		c.modules = append(c.modules, moduleNames[node.Name])
	}

	return c, nil
}

// MarshalJSON creates a stripped down version of the catalog in JSON,
// which contains all resources from the catalog and is suitable for
// clients to consume in order to create a single-module catalog from it.
func (c *Catalog) MarshalJSON() ([]byte, error) {
	rMap, err := c.createResourceMap()
	if err != nil {
		return nil, err
	}

	resources := make([]resourceMap, 0)
	for _, r := range rMap {
		rJson := resourceMap{
			r.Type(): r,
		}
		resources = append(resources, rJson)
	}

	return json.Marshal(map[string]interface{}{
		"resource": resources,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"text/template"
	"time"

	"github.com/couchbaselabs/cbfs/config"
)

type StorageNode struct {
	Addr      string
	AddrRaw   string    `json:"addr_raw"`
	Started   time.Time `json:"starttime"`
	HBTime    time.Time `json:"hbtime"`
	BindAddr  string
	FrameBind string
	HBAgeStr  string `json:"hbage_str"`
	Used      int64
	Free      int64
	Size      int64
	UptimeStr string `json:"uptime_str"`
}

type Tasks map[string]interface{}

type Nodes map[string]StorageNode

var infoFlags = flag.NewFlagSet("info", flag.ExitOnError)
var infoTemplate = infoFlags.String("t", "", "Display template")

const defaultInfoTemplate = `nodes:
{{ range $name, $nodeinfo := .nodes }}  {{$name}} up {{$nodeinfo.HBAgeStr}}
{{ end }}
{{if .tasks}}tasks{{end}}{{ range $node, $tasks := .tasks }}
  {{$node}}
  {{ range $task, $info := $tasks }}    {{$task}} - {{$info.state}} - {{$info.ts}}
  {{end}}{{end}}
config:
{{ range $k, $v := .conf}}  {{$k}}: {{$v}}
{{end}}
`

func getJsonData(u string, into interface{}) error {
	res, err := http.Get(u)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP Error: %v", res.Status)
	}

	d := json.NewDecoder(res.Body)
	return d.Decode(into)
}

func infoCommand(base string, args []string) {
	infoFlags.Parse(args)

	tmplstr := *infoTemplate
	if tmplstr == "" {
		tmplstr = defaultInfoTemplate
	}

	tmpl, err := template.New("").Parse(tmplstr)
	if err != nil {
		log.Fatalf("Error parsing template: %v", err)
	}

	u, err := url.Parse(base)
	if err != nil {
		log.Fatalf("Error parsing URL: %v", err)
	}

	type namedThing struct {
		name  string
		thing interface{}
	}

	todo := map[string]namedThing{
		"/.cbfs/nodes/":  {"nodes", Nodes{}},
		"/.cbfs/tasks/":  {"tasks", Tasks{}},
		"/.cbfs/config/": {"conf", cbfsconfig.CBFSConfig{}},
	}

	results := map[string]interface{}{
		"STDOUT": os.Stdout,
	}

	for k, v := range todo {
		u.Path = k
		err = getJsonData(u.String(), &v.thing)
		if err != nil {
			log.Fatalf("Error getting node info: %v", err)
		}
		results[v.name] = v.thing
	}

	err = tmpl.Execute(os.Stdout, results)
	if err != nil {
		log.Fatalf("Error executing template: %v", err)
	}
}
<commit_msg>Fix up template handling.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"text/template"
	"time"

	"github.com/couchbaselabs/cbfs/config"
)

type StorageNode struct {
	Addr      string
	AddrRaw   string    `json:"addr_raw"`
	Started   time.Time `json:"starttime"`
	HBTime    time.Time `json:"hbtime"`
	BindAddr  string
	FrameBind string
	HBAgeStr  string `json:"hbage_str"`
	Used      int64
	Free      int64
	Size      int64
	UptimeStr string `json:"uptime_str"`
}

type Tasks map[string]interface{}

type Nodes map[string]StorageNode

var infoFlags = flag.NewFlagSet("info", flag.ExitOnError)
var infoTemplate = infoFlags.String("t", "", "Display template")

const defaultInfoTemplate = `nodes:
{{ range $name, $nodeinfo := .Nodes }}  {{$name}} up {{$nodeinfo.HBAgeStr}}
{{ end }}
{{if .Tasks}}tasks:{{end}}{{ range $node, $tasks := .Tasks }}
  {{$node}}
  {{ range $task, $info := $tasks }}    {{$task}} - {{$info.state}} - {{$info.ts}}
  {{end}}{{end}}
config:
{{ range $k, $v := .Conf.ToMap}}  {{$k}}: {{$v}}
{{end}}
`

func getJsonData(u string, into interface{}) error {
	res, err := http.Get(u)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		return fmt.Errorf("HTTP Error: %v", res.Status)
	}

	d := json.NewDecoder(res.Body)
	return d.Decode(into)
}

func infoCommand(base string, args []string) {
	infoFlags.Parse(args)

	tmplstr := *infoTemplate
	if tmplstr == "" {
		tmplstr = defaultInfoTemplate
	}

	tmpl, err := template.New("").Parse(tmplstr)
	if err != nil {
		log.Fatalf("Error parsing template: %v", err)
	}

	u, err := url.Parse(base)
	if err != nil {
		log.Fatalf("Error parsing URL: %v", err)
	}

	result := struct {
		Nodes Nodes
		Tasks Tasks
		Conf  cbfsconfig.CBFSConfig
	}{}

	todo := map[string]interface{}{
		"/.cbfs/nodes/":  &result.Nodes,
		"/.cbfs/tasks/":  &result.Tasks,
		"/.cbfs/config/": &result.Conf,
	}

	for k, v := range todo {
		u.Path = k
		err = getJsonData(u.String(), v)
		if err != nil {
			log.Fatalf("Error getting node info: %v", err)
		}
	}

	err = tmpl.Execute(os.Stdout, result)
	if err != nil {
		log.Fatalf("Error executing template: %v", err)
	}
}
<|endoftext|>


<commit_before>package piece

import "point"

type Piece struct {
	movable      []point.Point
	firstMovable []point.Point
	enemyMovable []point.Point
	white        byte
	black        byte
}

func NewPiece(movable, firstMovable, enemyMovable []point.Point, white, black byte) *Piece {
	piece := new(Piece)
	piece.movable = movable
	piece.firstMovable = firstMovable
	piece.enemyMovable = enemyMovable
	piece.white = white
	piece.black = black
	return piece
}

func (piece Piece) CanMove(diff point.Point, first, enemy bool) bool {
	for _, i := range piece.movable {
		if diff.Y == i.Y && diff.X == i.X && (Pawn.IsSymbol(piece.white) == false || enemy == false) {
			return true
		}
	}
	for _, i := range piece.firstMovable {
		if diff.Y == i.Y && diff.X == i.X && first {
			return true
		}
	}
	for _, i := range piece.enemyMovable {
		if diff.Y == i.Y && diff.X == i.X && enemy {
			return true
		}
	}
	return false
}

func (piece Piece) IsSymbol(symbol byte) bool {
	return symbol == piece.white || symbol == piece.black
}

func WhichPiece(symbol byte) Piece {
	switch symbol {
	case 'B', 'b':
		return Bishop
	case 'K', 'k':
		return King
	case 'N', 'n':
		return Knight
	case 'P', 'p':
		return Pawn
	case 'Q', 'q':
		return Queen
	case 'R', 'r':
		return Rook
	default:
		return Empty
	}
}
<commit_msg>Pawns can't move 2 to forward if there is an enemy<commit_after>package piece

import "point"

type Piece struct {
	movable      []point.Point
	firstMovable []point.Point
	enemyMovable []point.Point
	white        byte
	black        byte
}

func NewPiece(movable, firstMovable, enemyMovable []point.Point, white, black byte) *Piece {
	piece := new(Piece)
	piece.movable = movable
	piece.firstMovable = firstMovable
	piece.enemyMovable = enemyMovable
	piece.white = white
	piece.black = black
	return piece
}

func (piece Piece) CanMove(diff point.Point, first, enemy bool) bool {
	for _, i := range piece.movable {
		if diff.Y == i.Y && diff.X == i.X && (Pawn.IsSymbol(piece.white) == false || enemy == false) {
			return true
		}
	}
	for _, i := range piece.firstMovable {
		if diff.Y == i.Y && diff.X == i.X && first && (Pawn.IsSymbol(piece.white) == false || enemy == false) {
			return true
		}
	}
	for _, i := range piece.enemyMovable {
		if diff.Y == i.Y && diff.X == i.X && enemy {
			return true
		}
	}
	return false
}

func (piece Piece) IsSymbol(symbol byte) bool {
	return symbol == piece.white || symbol == piece.black
}

func WhichPiece(symbol byte) Piece {
	switch symbol {
	case 'B', 'b':
		return Bishop
	case 'K', 'k':
		return King
	case 'N', 'n':
		return Knight
	case 'P', 'p':
		return Pawn
	case 'Q', 'q':
		return Queen
	case 'R', 'r':
		return Rook
	default:
		return Empty
	}
}
<|endoftext|>


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

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%x" with 4 digits default
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power
			of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	The width and precision control formatting and are in units of Unicode
	code points.  (This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For numeric values, width sets the width of the field and precision
	sets the number of places after the decimal, if appropriate.  For
	example, the format %6.2f prints 123.45.

	For strings, width is the minimum number of characters to output,
	padding with spaces if necessary, and precision is the maximum
	number of characters to output, truncating if necessary.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<commit_msg>fmt: document %%<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value
		%%	a literal percent sign; consumes no value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%x" with 4 digits default
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power
			of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	The width and precision control formatting and are in units of Unicode
	code points.  (This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For numeric values, width sets the width of the field and precision
	sets the number of places after the decimal, if appropriate.  For
	example, the format %6.2f prints 123.45.

	For strings, width is the minimum number of characters to output,
	padding with spaces if necessary, and precision is the maximum
	number of characters to output, truncating if necessary.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"compress/flate"
	gzip "compress/gzip"
	"io"
	"io/ioutil"
	"fmt"
	"os"
	"runtime"
	"testing"

	bgzf "github.com/biogo/hts/bgzf"
	pgzip "github.com/klauspost/pgzip"
	lz4 "github.com/pierrec/lz4"
)

type Compressor struct {
	r  *os.File
	w  *os.File
	sr int64
	sw int64
}

func (c *Compressor) Close() error {
	var err error

	fi, _ := c.w.Stat()
	c.sw = fi.Size()
	if err = c.w.Close(); err != nil {
		return err
	}

	fi, _ = c.r.Stat()
	c.sr = fi.Size()
	if err = c.r.Close(); err != nil {
		return err
	}

	return nil
}

func NewCompressor(src, dst string) (*Compressor, error) {
	r, err := os.Open(src)
	if err != nil {
		return nil, err
	}

	w, err := os.Create(dst)
	if err != nil {
		r.Close()
		return nil, err
	}

	c := &Compressor{r: r, w: w}
	return c, nil
}

func main() {

        runtime.GOMAXPROCS(runtime.NumCPU())

	var resw testing.BenchmarkResult
	var resr testing.BenchmarkResult

	c, err := NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkGZIPWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkGZIPReader)
	c.Close()
	fmt.Printf("gzip:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkBGZFWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkBGZFReader)
	c.Close()
	fmt.Printf("bgzf:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkPGZIPWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkPGZIPReader)
	c.Close()
	fmt.Printf("pgzip:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkLZ4Writer)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkLZ4Reader)
	c.Close()
	fmt.Printf("lz4:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

}

func (c *Compressor) BenchmarkGZIPWriter(b *testing.B) {
	cw, _ := gzip.NewWriterLevel(c.w, flate.BestSpeed)
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkGZIPReader(b *testing.B) {
	cr, _ := gzip.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkBGZFWriter(b *testing.B) {
	cw, _ := bgzf.NewWriterLevel(c.w, flate.BestSpeed, runtime.NumCPU())
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	c.w.Sync()
}

func (c *Compressor) BenchmarkBGZFReader(b *testing.B) {
	cr, _ := bgzf.NewReader(c.w, 0)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkPGZIPWriter(b *testing.B) {
	cw, _ := pgzip.NewWriterLevel(c.w, flate.BestSpeed)
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkPGZIPReader(b *testing.B) {
	cr, _ := pgzip.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkLZ4Writer(b *testing.B) {
	cw := lz4.NewWriter(c.w)
//	cw.Header.HighCompression = true
	cw.Header.NoChecksum = true
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkLZ4Reader(b *testing.B) {
	cr := lz4.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}
<commit_msg>Remove redundant aliases<commit_after>// +build ignore

package main

import (
	"compress/flate"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"testing"

	"github.com/biogo/hts/bgzf"
	"github.com/klauspost/pgzip"
	"github.com/pierrec/lz4"
)

type Compressor struct {
	r  *os.File
	w  *os.File
	sr int64
	sw int64
}

func (c *Compressor) Close() error {
	var err error

	fi, _ := c.w.Stat()
	c.sw = fi.Size()
	if err = c.w.Close(); err != nil {
		return err
	}

	fi, _ = c.r.Stat()
	c.sr = fi.Size()
	if err = c.r.Close(); err != nil {
		return err
	}

	return nil
}

func NewCompressor(src, dst string) (*Compressor, error) {
	r, err := os.Open(src)
	if err != nil {
		return nil, err
	}

	w, err := os.Create(dst)
	if err != nil {
		r.Close()
		return nil, err
	}

	c := &Compressor{r: r, w: w}
	return c, nil
}

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	var resw testing.BenchmarkResult
	var resr testing.BenchmarkResult

	c, err := NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkGZIPWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkGZIPReader)
	c.Close()
	fmt.Printf("gzip:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkBGZFWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkBGZFReader)
	c.Close()
	fmt.Printf("bgzf:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkPGZIPWriter)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkPGZIPReader)
	c.Close()
	fmt.Printf("pgzip:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

	c, err = NewCompressor("/tmp/image.r", "/tmp/image.w")
	if err != nil {
		panic(err)
	}
	resw = testing.Benchmark(c.BenchmarkLZ4Writer)
	c.w.Seek(0, 0)
	resr = testing.Benchmark(c.BenchmarkLZ4Reader)
	c.Close()
	fmt.Printf("lz4:\twriter %s\treader %s\tsize %d\n", resw.T.String(), resr.T.String(), c.sw)

}

func (c *Compressor) BenchmarkGZIPWriter(b *testing.B) {
	cw, _ := gzip.NewWriterLevel(c.w, flate.BestSpeed)
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkGZIPReader(b *testing.B) {
	cr, _ := gzip.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkBGZFWriter(b *testing.B) {
	cw, _ := bgzf.NewWriterLevel(c.w, flate.BestSpeed, runtime.NumCPU())
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	c.w.Sync()
}

func (c *Compressor) BenchmarkBGZFReader(b *testing.B) {
	cr, _ := bgzf.NewReader(c.w, 0)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkPGZIPWriter(b *testing.B) {
	cw, _ := pgzip.NewWriterLevel(c.w, flate.BestSpeed)
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkPGZIPReader(b *testing.B) {
	cr, _ := pgzip.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}

func (c *Compressor) BenchmarkLZ4Writer(b *testing.B) {
	cw := lz4.NewWriter(c.w)
	//	cw.Header.HighCompression = true
	cw.Header.NoChecksum = true
	b.ResetTimer()

	_, err := io.Copy(cw, c.r)
	if err != nil {
		b.Fatal(err)
	}
	cw.Close()
	c.w.Sync()
}

func (c *Compressor) BenchmarkLZ4Reader(b *testing.B) {
	cr := lz4.NewReader(c.w)
	b.ResetTimer()

	_, err := io.Copy(ioutil.Discard, cr)
	if err != nil {
		b.Fatal(err)
	}
}
<|endoftext|>


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

package main

import (
    "fmt"
    "log"
    "path/filepath"
    "strings"
)

func (d *Dogo) Monitor() {
    watcher, err := NewWatcher()
    if err != nil {
        log.Fatalf("[dogo] NewWatcher Error: %s\n", err.Error())
    }

    mask := IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE | IN_MOVED_TO | IN_MOVE_SELF | IN_ISDIR

    for _, dir := range d.sourceDir {
        err = watcher.AddWatch(dir, mask)
        if err != nil {
            log.Fatalf("[dogo] AddWatch Error: %s\n", err.Error())
        }
    }

    var decreasing uint8

    for {
        select {
        case ev := <-watcher.Event:
            fmt.Printf("[dogo] Changed files: %v\n", ev)

            masks := getMask(ev)

            _, isCreate := masks[IN_CREATE]
            _, isDelete := masks[IN_DELETE]
            if !isDelete {
                _, isDelete = masks[IN_DELETE_SELF]
            }
            _, isModify := masks[IN_MODIFY]
            _, isMove := masks[IN_MOVE]
            if !isMove {
                _, isMove = masks[IN_MOVED_TO]
            }
            if !isMove {
                _, isMove = masks[IN_MOVE_SELF]
            }
            _, isDir := masks[IN_ISDIR]

            if isDir && isCreate {
                err = watcher.AddWatch(ev.Name, mask)
                if err != nil {
                    log.Fatalf("[dogo] AddWatch Error: %s\n", err.Error())
                }
            }

            if isDir && isDelete {
                err = watcher.RemoveWatch(ev.Name)
                if err != nil {
                    log.Fatalf("[dogo] RemoveWatch Error: %s\n", err.Error())
                }
            }

            if !isDir && (isDelete || isModify || isMove) {
                ext := strings.ToLower(filepath.Ext(ev.Name))
                for _, v := range d.SourceExt {
                    if ext == strings.ToLower(v) {
                        // d.BuildAndRun()
                        if decreasing > 0 {
                            decreasing--
                            fmt.Printf("[dogo] Decreasing %d: %v\n", decreasing, ev.Name)
                        } else {
                            d.isModified = true
                            fmt.Printf("[dogo] Changed files: %v\n", ev.Name)
                            d.BuildAndRun()
                            decreasing = d.Decreasing
                            // time.Sleep(time.Duration(1 * time.Second))
                        }

                        break
                    }
                }
            }
        case err := <-watcher.Error:
            fmt.Printf("[dogo] Error: %s\n", err.Error())
        }
    }
}

func getMask(ev *Event) map[uint32]string {
    masks := map[uint32]string{}
    m := ev.Mask
    for _, b := range eventBits {
        if m&b.Value == b.Value {
            m &^= b.Value
            masks[b.Value] = b.Name
        }
    }

    return masks
}
<commit_msg>clean message format<commit_after>// Copyright 2014 The dogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
    "fmt"
    "log"
    "path/filepath"
    "strings"
    "time"
)

func (d *Dogo) Monitor() {
    watcher, err := NewWatcher()
    if err != nil {
        log.Fatalf("[dogo] NewWatcher Error: %s\n", err.Error())
    }

    mask := IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE | IN_MOVED_TO | IN_MOVE_SELF | IN_ISDIR

    for _, dir := range d.sourceDir {
        err = watcher.AddWatch(dir, mask)
        if err != nil {
            log.Fatalf("[dogo] AddWatch Error: %s\n", err.Error())
        }
    }

    var decreasing uint8

    for {
        select {
        case ev := <-watcher.Event:
            fmt.Printf("[dogo] Changed files: %v\n", ev.Name)

            masks := getMask(ev)

            _, isCreate := masks[IN_CREATE]
            _, isDelete := masks[IN_DELETE]
            if !isDelete {
                _, isDelete = masks[IN_DELETE_SELF]
            }
            _, isModify := masks[IN_MODIFY]
            _, isMove := masks[IN_MOVE]
            if !isMove {
                _, isMove = masks[IN_MOVED_TO]
            }
            if !isMove {
                _, isMove = masks[IN_MOVE_SELF]
            }
            _, isDir := masks[IN_ISDIR]

            if isDir && isCreate {
                err = watcher.AddWatch(ev.Name, mask)
                if err != nil {
                    log.Fatalf("[dogo] AddWatch Error: %s\n", err.Error())
                }
            }

            if isDir && isDelete {
                err = watcher.RemoveWatch(ev.Name)
                if err != nil {
                    log.Fatalf("[dogo] RemoveWatch Error: %s\n", err.Error())
                }
            }

            if !isDir && (isDelete || isModify || isMove) {
                ext := strings.ToLower(filepath.Ext(ev.Name))
                for _, v := range d.SourceExt {
                    if ext == strings.ToLower(v) {
                        if decreasing > 0 {
                            decreasing--
                            fmt.Printf("[dogo] Decreasing %d: %v\n", decreasing, ev.Name)
                        } else {
                            d.isModified = true
                            d.BuildAndRun()
                            decreasing = d.Decreasing
                            time.Sleep(time.Duration(1 * time.Second))
                        }

                        break
                    }
                }
            }
        case err := <-watcher.Error:
            fmt.Printf("[dogo] Error: %s\n", err.Error())
        }
    }
}

func getMask(ev *Event) map[uint32]string {
    masks := map[uint32]string{}
    m := ev.Mask
    for _, b := range eventBits {
        if m&b.Value == b.Value {
            m &^= b.Value
            masks[b.Value] = b.Name
        }
    }

    return masks
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"net/http"
	"net/http/httputil"
	"net/url"
	// "io"
	"io/ioutil"
	"flag"
	"time"
)

func get(hostname string, port int, path string, verbose bool, timeout int) (rv bool, err error) {

	// defer func() {
	// 	if err := recover(); err != nil {
	// 		return
	// 	}
	// }()

	rv = true

	if verbose {
		fmt.Fprintf(os.Stderr, "fetching:url:%s:\n", hostname)
	}

	client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
	// res, err := client.Head(url)

	// req, err := http.NewRequest("HEAD", url, nil)

	// if err != nil {
	// 	rv = false
	// 	return
	// }

	// had to allocate this or the SetBasicAuth below causes a panic
    headers := make(map[string][]string)
    hostPort := fmt.Sprintf("%s:%d", hostname, port)
    fmt.Fprintf(os.Stderr, "adding hostPort:%s:%d:path:%s:\n", hostname, port, path)
	req := &http.Request{
		Method: "HEAD",
		// Host:  hostPort,
		URL: &url.URL{
			Host:   hostPort,
			Scheme: "http",
			Opaque: path,
		},
		Header: headers,
	}

	req.SetBasicAuth("guest", "guest")

    dump, err := httputil.DumpRequestOut(req, true)
    fmt.Fprintf(os.Stderr, "%s", dump)

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err.Error())
		rv = false
		return
	}

	defer res.Body.Close()
	_, err = ioutil.ReadAll(res.Body)

	// res, err := http.Head(url)
	// if err != nil {
	// 	fmt.Println(err.Error())
	// 	rv = false
	// 	return
	// }

	fmt.Println(res.Status)
	for k, v := range res.Header {
		fmt.Println(k+":", v)
	}

	if res.StatusCode != http.StatusOK {
		rv = false
	}

	return
}

func main() {

	status := "OK"
	rv := 0
	name := "Bulk HTTP"
	bad := 0
	total := 0

	verbose := flag.Bool("v", false, "verbose output")
	warn := flag.Int("w", 10, "warning level - number of non-200s or percentage of non-200s (default is numeric not percentage)")
	crit := flag.Int("c", 20, "critical level - number of non-200s or percentage of non-200s (default is numeric not percentage)")
	timeout := flag.Int("t", 2, "timeout in seconds - don't wait.  Do Head requests and don't wait.")
	// pct := flag.Bool("pct", false, "interpret warming and critical levels are percentages")
	path := flag.String("path", "", "optional path to append to the stdin lines - these will not be urlencoded. This is ignored is the urls option is given (not implemented yet).")
	file := flag.String("file", "", "optional path to read data from a file instead of stdin.  If its a dash then read from stdin - these will not be urlencoded")
	port := flag.Int("port", 80, "optional port for the http request")
	// bare := flag.Bool("urls", false, "Assume the input data is full urls - its normally a list of hostnames")

	flag.Usage = func() {

        fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
        fmt.Fprintf(os.Stderr, `
	Read hostnames from a file or STDIN and do a single nagios check over
	them all.  Just check for 200s.  Warning and Critical are either
	percentages of the total, or a regular numeric thresholds.

	The output contains the hostname of any non-200 reporting hosts.

	Skip input lines that are commented out with shell style comments
	like /^#/.

	Do Head requests since we don't care about the content.  Make this
	optional some day.

	Also make this read from a file of urls with a -f option.

	Make the auth configurable from the cli

    	`)

        flag.PrintDefaults()
	}

	flag.Parse()

	if len(flag.Args()) > 0 {

		flag.Usage()
		os.Exit(3)

	}

	// defer func() {
	// 	if err := recover(); err != nil {
	// 		fmt.Println(name+" Unknown: ", err)
	// 		os.Exit(3)
	// 	}
	// }()

	if file == nil || *file == "" {
		flag.Usage()
		os.Exit(3)
	}

	// inputSource := &io.Reader
	inputSource := os.Stdin

	if (*file)[0] != "-"[0] {

		var err error

		inputSource, err = os.Open(*file)

		if err != nil {

			fmt.Printf("Couldn't open the specified input file:%s:error:%v:\n\n", name, err)
			flag.Usage()
			os.Exit(3)

		}

	}

	scanner := bufio.NewScanner(inputSource)
	for scanner.Scan() {

		total++

		hostname := scanner.Text()

		if hostname[0] == "#"[0] {

			if *verbose {

				fmt.Printf("skipping:%s:\n", hostname)

			}

			continue
		}

		// url := hostname + *path

		if *verbose {

			fmt.Printf("working on:%s:\n", hostname)

		}

		goodCheck, err := get(hostname, *port, *path, *verbose, *timeout)
		if err != nil {

			fmt.Printf("%s Unknown: %T %s %#v\n", name, err, err, err)

			// os.Exit(3)
			continue

		}

		if !goodCheck {
			bad++
		}

	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}

	if bad >= *crit {
		status = "Critical"
		rv = 1
	} else if bad >= *warn {
		status = "Warning"
		rv = 2
	}

	fmt.Printf("%s %s: %d\n", name, status, bad)
	os.Exit(rv)
}
<commit_msg>add auth flag and move some output into verbose<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"net/http"
	"net/http/httputil"
	"net/url"
	// "io"
	"io/ioutil"
	"flag"
	"time"
	"strings"
)

func get(hostname string, port int, path string, auth string, verbose bool, timeout int) (rv bool, err error) {

	// defer func() {
	// 	if err := recover(); err != nil {
	// 		return
	// 	}
	// }()

	rv = true

	if verbose {
		fmt.Fprintf(os.Stderr, "fetching:hostname:%s:\n", hostname)
	}

	client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
	// res, err := client.Head(url)

	// req, err := http.NewRequest("HEAD", url, nil)

	// if err != nil {
	// 	rv = false
	// 	return
	// }

	// had to allocate this or the SetBasicAuth below causes a panic
    headers := make(map[string][]string)
    hostPort := fmt.Sprintf("%s:%d", hostname, port)
    fmt.Fprintf(os.Stderr, "adding hostPort:%s:%d:path:%s:\n", hostname, port, path)
	req := &http.Request{
		Method: "HEAD",
		// Host:  hostPort,
		URL: &url.URL{
			Host:   hostPort,
			Scheme: "http",
			Opaque: path,
		},
		Header: headers,
	}

    if auth != "" {

    	up := strings.SplitN(auth, ":", 2)
	    fmt.Fprintf(os.Stderr, "Doing auth with:username:%s:password:%s:", up[0], up[1])
		req.SetBasicAuth(up[0], up[1])

    }

    if verbose {

	    dump, _ := httputil.DumpRequestOut(req, true)
	    fmt.Fprintf(os.Stderr, "%s", dump)

    }

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err.Error())
		rv = false
		return
	}

	defer res.Body.Close()
	_, err = ioutil.ReadAll(res.Body)

	// res, err := http.Head(url)
	// if err != nil {
	// 	fmt.Println(err.Error())
	// 	rv = false
	// 	return
	// }

	if verbose {

		fmt.Println(res.Status)
		for k, v := range res.Header {
			fmt.Println(k+":", v)
		}

	}

	if res.StatusCode != http.StatusOK {
		rv = false
	}

	return
}

func main() {

	status := "OK"
	rv := 0
	name := "Bulk HTTP"
	bad := 0
	total := 0

	verbose := flag.Bool("v", false, "verbose output")
	warn := flag.Int("w", 10, "warning level - number of non-200s or percentage of non-200s (default is numeric not percentage)")
	crit := flag.Int("c", 20, "critical level - number of non-200s or percentage of non-200s (default is numeric not percentage)")
	timeout := flag.Int("t", 2, "timeout in seconds - don't wait.  Do Head requests and don't wait.")
	// pct := flag.Bool("pct", false, "interpret warming and critical levels are percentages")
	path := flag.String("path", "", "optional path to append to the stdin lines - these will not be urlencoded. This is ignored is the urls option is given (not implemented yet).")
	file := flag.String("file", "", "optional path to read data from a file instead of stdin.  If its a dash then read from stdin - these will not be urlencoded")
	port := flag.Int("port", 80, "optional port for the http request")
	// bare := flag.Bool("urls", false, "Assume the input data is full urls - its normally a list of hostnames")
	auth := flag.String("auth", "", "Do basic auth with this username:passwd - make this use .netrc instead")

	flag.Usage = func() {

        fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
        fmt.Fprintf(os.Stderr, `
	Read hostnames from a file or STDIN and do a single nagios check over
	them all.  Just check for 200s.  Warning and Critical are either
	percentages of the total, or a regular numeric thresholds.

	The output contains the hostname of any non-200 reporting hosts.

	Skip input lines that are commented out with shell style comments
	like /^#/.

	Do Head requests since we don't care about the content.  Make this
	optional some day.

	Also make this read from a file of urls with a -f option.

	Make the auth configurable from the cli

    	`)

        flag.PrintDefaults()
	}

	flag.Parse()

	if len(flag.Args()) > 0 {

		flag.Usage()
		os.Exit(3)

	}

	// defer func() {
	// 	if err := recover(); err != nil {
	// 		fmt.Println(name+" Unknown: ", err)
	// 		os.Exit(3)
	// 	}
	// }()

	if file == nil || *file == "" {
		flag.Usage()
		os.Exit(3)
	}

	// inputSource := &io.Reader
	inputSource := os.Stdin

	if (*file)[0] != "-"[0] {

		var err error

		inputSource, err = os.Open(*file)

		if err != nil {

			fmt.Printf("Couldn't open the specified input file:%s:error:%v:\n\n", name, err)
			flag.Usage()
			os.Exit(3)

		}

	}

	scanner := bufio.NewScanner(inputSource)
	for scanner.Scan() {

		total++

		hostname := scanner.Text()

		if hostname[0] == "#"[0] {

			if *verbose {

				fmt.Printf("skipping:%s:\n", hostname)

			}

			continue
		}

		// url := hostname + *path

		if *verbose {

			fmt.Printf("working on:%s:\n", hostname)

		}

		goodCheck, err := get(hostname, *port, *path, *auth, *verbose, *timeout)
		if err != nil {

			fmt.Printf("%s get error: %T %s %#v\n", name, err, err, err)

			// os.Exit(3)
			continue

		}

		if !goodCheck {
			bad++
		}

	}
	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}

	if bad >= *crit {
		status = "Critical"
		rv = 1
	} else if bad >= *warn {
		status = "Warning"
		rv = 2
	}

	fmt.Printf("%s %s: %d\n", name, status, bad)
	os.Exit(rv)
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 gochimp

import (
	"fmt"
)

const (
	get_content_endpoint     string = "/campaigns/content.%s"
	campaign_create_endpoint string = "/campaigns/create.json"
	campaign_send_endpoint   string = "/campaigns/send.json"
)

func (a *ChimpAPI) getContent(apiKey string, cid string, options map[string]interface{}, contentFormat string) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["apikey"] = apiKey
	params["cid"] = cid
	params["options"] = options
	err := parseChimpJson(a, fmt.Sprintf(get_content_endpoint, contentFormat), params, &response)
	return response, err
}

func (a *ChimpAPI) CampaignCreate(req CampaignCreate) (CampaignCreateResponse, error) {
	req.ApiKey = a.Key
	var response CampaignCreateResponse
	err := parseChimpJson(a, campaign_create_endpoint, req, &response)
	return response, err
}

func (a *ChimpAPI) CampaignSend(cid string) (CampaignSendResponse, error) {
	req := campaignSend{
		ApiKey:     a.Key,
		CampaignId: cid,
	}
	var response CampaignSendResponse
	err := parseChimpJson(a, campaign_send_endpoint, req, &response)
	return response, err
}

type campaignSend struct {
	ApiKey     string `json:"apikey"`
	CampaignId string `json:"cid"`
}

type CampaignSendResponse struct {
	Complete bool `json:"complete"`
}

type CampaignCreate struct {
	ApiKey  string                `json:"apikey"`
	Type    string                `json:"type"`
	Options CampaignCreateOptions `json:"options"`
	Content CampaignCreateContent `json:"content"`
}

type CampaignCreateOptions struct {
	// ListID is the list to send this campaign to
	ListID string `json:"list_id"`

	// Subject is the subject line for your campaign message
	Subject string `json:"subject"`

	// FromEmail is the From: email address for your campaign message
	FromEmail string `json:"from_email"`

	// FromName is the From: name for your campaign message (not an email address)
	FromName string `json:"from_name"`

	// ToName is the To: name recipients will see (not email address)
	ToName string `json:"to_name"`
}

type CampaignCreateContent struct {
	// HTML is the raw/pasted HTML content for the campaign
	HTML string `json:"html"`

	// When using a template instead of raw HTML, each key
	// in the map should be the unique mc:edit area name from
	// the template.
	Sections map[string]string `json:"sections,omitempty"`

	// Text is the plain-text version of the body
	Text string `json:"text"`

	// MailChimp will pull in content from this URL. Note,
	// this will override any other content options - for lists
	// with Email Format options, you'll need to turn on
	// generate_text as well
	URL string `json:"url,omitempty"`

	// A Base64 encoded archive file for MailChimp to import all
	// media from. Note, this will override any other content
	// options - for lists with Email Format options, you'll
	// need to turn on generate_text as well
	Archive string `json:"archive,omitempty"`

	// ArchiveType only applies to the Archive field. Supported
	// formats are: zip, tar.gz, tar.bz2, tar, tgz, tbz.
	// If not included, we will default to zip
	ArchiveType string `json:"archive_options,omitempty"`
}

type CampaignCreateResponse struct {
	Id                 string           `json:"id"`
	WebId              int              `json:"web_id"`
	ListId             string           `json:"list_id"`
	FolderId           int              `json:"folder_id"`
	TemplateId         int              `json:"template_id"`
	ContentType        string           `json:"content_type"`
	ContentEditedBy    string           `json:"content_edited_by"`
	Title              string           `json:"title"`
	Type               string           `json:"type"`
	CreateTime         string           `json:"create_time"`
	SendTime           string           `json:"send_time"`
	ContentUpdatedTime string           `json:"content_updated_time"`
	Status             string           `json:"status"`
	FromName           string           `json:"from_name"`
	FromEmail          string           `json:"from_email"`
	Subject            string           `json:"subject"`
	ToName             string           `json:"to_name"`
	ArchiveURL         string           `json:"archive_url"`
	ArchiveURLLong     string           `json:"archive_url_long"`
	EmailsSent         int              `json:"emails_sent"`
	Analytics          string           `json:"analytics"`
	AnalyticsTag       string           `json:"analytics_tag"`
	InlineCSS          bool             `json:"inline_css"`
	Authenticate       bool             `json:authenticate"`
	Ecommm360          bool             `json:"ecomm360"`
	AutoTweet          bool             `json:"auto_tweet"`
	AutoFacebookPort   string           `json:"auto_fb_post"`
	AutoFooter         bool             `json:"auto_footer"`
	Timewarp           bool             `json:"timewarp"`
	TimewarpSchedule   string           `json:"timewarp_schedule,omitempty"`
	Tracking           CampaignTracking `json:"tracking"`
	ParentId           string           `json:"parent_id"`
	IsChild            bool             `json:"is_child"`
	TestsSent          int              `json:"tests_sent"`
	TestsRemaining     int              `json:"tests_remain"`
	SegmentText        string           `json:"segment_text"`
}

type CampaignTracking struct {
	HTMLClicks bool `json:"html_clicks"`
	TextClicks bool `json:"text_clicks"`
	Opens      bool `json:"opens"`
}
<commit_msg>Add CampaignList<commit_after>// Copyright 2013 Matthew Baird
// 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 gochimp

import (
	"fmt"
)

const (
	get_content_endpoint     string = "/campaigns/content.%s"
	campaign_create_endpoint string = "/campaigns/create.json"
	campaign_send_endpoint   string = "/campaigns/send.json"
	campaign_list_endpoint   string = "/campaigns/list.json"
)

func (a *ChimpAPI) getContent(apiKey string, cid string, options map[string]interface{}, contentFormat string) ([]SendResponse, error) {
	var response []SendResponse
	var params map[string]interface{} = make(map[string]interface{})
	params["apikey"] = apiKey
	params["cid"] = cid
	params["options"] = options
	err := parseChimpJson(a, fmt.Sprintf(get_content_endpoint, contentFormat), params, &response)
	return response, err
}

func (a *ChimpAPI) CampaignCreate(req CampaignCreate) (CampaignCreateResponse, error) {
	req.ApiKey = a.Key
	var response CampaignCreateResponse
	err := parseChimpJson(a, campaign_create_endpoint, req, &response)
	return response, err
}

func (a *ChimpAPI) CampaignSend(cid string) (CampaignSendResponse, error) {
	req := campaignSend{
		ApiKey:     a.Key,
		CampaignId: cid,
	}
	var response CampaignSendResponse
	err := parseChimpJson(a, campaign_send_endpoint, req, &response)
	return response, err
}

func (a *ChimpAPI) CampaignList(req CampaignList) (CampaignListResponse, error) {
	req.ApiKey = a.Key
	var response CampaignListResponse
	err := parseChimpJson(a, campaign_list_endpoint, req, &response)
	return response, err
}

type CampaignListResponse struct {
}

type CampaignList struct {
	// A valid API Key for your user account. Get by visiting your API dashboard
	ApiKey string `json:"apikey"`

	// Filters to apply to this query - all are optional:
	Filter CampaignListFilter `json:"filters,omitempty"`

	// Control paging of campaigns, start results at this campaign #,
	// defaults to 1st page of data (page 0)
	Start int `json:"start,omitempty"`

	// Control paging of campaigns, number of campaigns to return with each call, defaults to 25 (max=1000)
	Limit int `json:"limit,omitempty"`

	// One of "create_time", "send_time", "title", "subject". Invalid values
	// will fall back on "create_time" - case insensitive.
	SortField string `json:"sort_field,omitempty"`

	// "DESC" for descending (default), "ASC" for Ascending. Invalid values
	// will fall back on "DESC" - case insensitive.
	OrderOrder string `json:"sort_dir,omitempty"`
}

type CampaignListFilter struct {
	// Return the campaign using a know campaign_id. Accepts
	// multiples separated by commas when not using exact matching.
	CampaignID string `json:"campaign_id,omitempty"`

	// Return the child campaigns using a known parent campaign_id.
	// Accepts multiples separated by commas when not using exact matching.
	ParentID string `json:"parent_id,omitempty"`

	// The list to send this campaign to - Get lists using ListList.
	// Accepts multiples separated by commas when not using exact matching.
	ListID string `json:"list_id,omitempty"`

	// Only show campaigns from this folder id - get folders using FoldersList.
	// Accepts multiples separated by commas when not using exact matching.
	FolderID int `json:"folder_id,omitempty"`

	// Only show campaigns using this template id - get templates using TemplatesList.
	// Accepts multiples separated by commas when not using exact matching.
	TemplateID int `json:"template_id,omitempty"`

	// Return campaigns of a specific status - one of "sent", "save", "paused", "schedule", "sending".
	// Accepts multiples separated by commas when not using exact matching.
	Status string `json:"status,omitempty"`

	// Return campaigns of a specific type - one of "regular", "plaintext", "absplit", "rss", "auto".
	// Accepts multiples separated by commas when not using exact matching.
	Type string `json:"type,omitempty"`

	// Only show campaigns that have this "From Name"
	FromName string `json:"from_name,omitempty"`

	// Only show campaigns that have this "Reply-to Email"
	FromEmail string `json:"from_email,omitempty"`

	// Only show campaigns that have this title
	Title string `json:"title"`

	// Only show campaigns that have this subject
	Subject string `json:"subject"`

	// Only show campaigns that have been sent since this date/time (in GMT) - -
	// 24 hour format in GMT, eg "2013-12-30 20:30:00" - if this is invalid the whole call fails
	SendTimeStart string `json:"sendtime_start,omitempty"`

	// Only show campaigns that have been sent before this date/time (in GMT) - -
	// 24 hour format in GMT, eg "2013-12-30 20:30:00" - if this is invalid the whole call fails
	SendTimeEnd string `json:"sendtime_end,omitempty"`

	// Whether to return just campaigns with or without segments
	UsesSegment bool `json:"uses_segment,omitempty"`

	// Flag for whether to filter on exact values when filtering, or search within content for
	// filter values - defaults to true. Using this disables the use of any filters that accept multiples.
	Exact bool `json:"exact,omitempty"`
}

type campaignSend struct {
	ApiKey     string `json:"apikey"`
	CampaignId string `json:"cid"`
}

type CampaignSendResponse struct {
	Complete bool `json:"complete"`
}

type CampaignCreate struct {
	ApiKey  string                `json:"apikey"`
	Type    string                `json:"type"`
	Options CampaignCreateOptions `json:"options"`
	Content CampaignCreateContent `json:"content"`
}

type CampaignCreateOptions struct {
	// ListID is the list to send this campaign to
	ListID string `json:"list_id"`

	// Subject is the subject line for your campaign message
	Subject string `json:"subject"`

	// FromEmail is the From: email address for your campaign message
	FromEmail string `json:"from_email"`

	// FromName is the From: name for your campaign message (not an email address)
	FromName string `json:"from_name"`

	// ToName is the To: name recipients will see (not email address)
	ToName string `json:"to_name"`
}

type CampaignCreateContent struct {
	// HTML is the raw/pasted HTML content for the campaign
	HTML string `json:"html"`

	// When using a template instead of raw HTML, each key
	// in the map should be the unique mc:edit area name from
	// the template.
	Sections map[string]string `json:"sections,omitempty"`

	// Text is the plain-text version of the body
	Text string `json:"text"`

	// MailChimp will pull in content from this URL. Note,
	// this will override any other content options - for lists
	// with Email Format options, you'll need to turn on
	// generate_text as well
	URL string `json:"url,omitempty"`

	// A Base64 encoded archive file for MailChimp to import all
	// media from. Note, this will override any other content
	// options - for lists with Email Format options, you'll
	// need to turn on generate_text as well
	Archive string `json:"archive,omitempty"`

	// ArchiveType only applies to the Archive field. Supported
	// formats are: zip, tar.gz, tar.bz2, tar, tgz, tbz.
	// If not included, we will default to zip
	ArchiveType string `json:"archive_options,omitempty"`
}

type CampaignCreateResponse struct {
	Id                 string           `json:"id"`
	WebId              int              `json:"web_id"`
	ListId             string           `json:"list_id"`
	FolderId           int              `json:"folder_id"`
	TemplateId         int              `json:"template_id"`
	ContentType        string           `json:"content_type"`
	ContentEditedBy    string           `json:"content_edited_by"`
	Title              string           `json:"title"`
	Type               string           `json:"type"`
	CreateTime         string           `json:"create_time"`
	SendTime           string           `json:"send_time"`
	ContentUpdatedTime string           `json:"content_updated_time"`
	Status             string           `json:"status"`
	FromName           string           `json:"from_name"`
	FromEmail          string           `json:"from_email"`
	Subject            string           `json:"subject"`
	ToName             string           `json:"to_name"`
	ArchiveURL         string           `json:"archive_url"`
	ArchiveURLLong     string           `json:"archive_url_long"`
	EmailsSent         int              `json:"emails_sent"`
	Analytics          string           `json:"analytics"`
	AnalyticsTag       string           `json:"analytics_tag"`
	InlineCSS          bool             `json:"inline_css"`
	Authenticate       bool             `json:authenticate"`
	Ecommm360          bool             `json:"ecomm360"`
	AutoTweet          bool             `json:"auto_tweet"`
	AutoFacebookPort   string           `json:"auto_fb_post"`
	AutoFooter         bool             `json:"auto_footer"`
	Timewarp           bool             `json:"timewarp"`
	TimewarpSchedule   string           `json:"timewarp_schedule,omitempty"`
	Tracking           CampaignTracking `json:"tracking"`
	ParentId           string           `json:"parent_id"`
	IsChild            bool             `json:"is_child"`
	TestsSent          int              `json:"tests_sent"`
	TestsRemaining     int              `json:"tests_remain"`
	SegmentText        string           `json:"segment_text"`
}

type CampaignTracking struct {
	HTMLClicks bool `json:"html_clicks"`
	TextClicks bool `json:"text_clicks"`
	Opens      bool `json:"opens"`
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Vitess 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 collations

import (
	"fmt"
	"strings"
	"sync"
)

type colldefaults struct {
	Default Collation
	Binary  Collation
}

// Environment is a collation environment for a MySQL version, which contains
// a database of collations and defaults for that specific version.
type Environment struct {
	version     collver
	byName      map[string]Collation
	byID        map[ID]Collation
	byCharset   map[string]*colldefaults
	unsupported map[string]ID
}

// LookupByName returns the collation with the given name. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByName(name string) Collation {
	if coll, ok := env.byName[name]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupByID returns the collation with the given numerical identifier. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByID(id ID) Collation {
	if coll, ok := env.byID[id]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupID returns the collation ID for the given name, and whether
// the collation is supported by this package.
func (env *Environment) LookupID(name string) (ID, bool) {
	if supported, ok := env.byName[name]; ok {
		return supported.ID(), true
	}
	if unsupported, ok := env.unsupported[name]; ok {
		return unsupported, false
	}
	return Unknown, false
}

// DefaultCollationForCharset returns the default collation for a charset
func (env *Environment) DefaultCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Default != nil {
			defaults.Default.Init()
			return defaults.Default
		}
	}
	return nil
}

// BinaryCollationForCharset returns the default binary collation for a charset
func (env *Environment) BinaryCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Binary != nil {
			defaults.Binary.Init()
			return defaults.Binary
		}
	}
	return nil
}

// AllCollations returns a slice with all known collations in Vitess. This is an expensive call because
// it will initialize the internal state of all the collations before returning them.
// Used for testing/debugging.
func (env *Environment) AllCollations() (all []Collation) {
	all = make([]Collation, 0, len(env.byID))
	for _, col := range env.byID {
		col.Init()
		all = append(all, col)
	}
	return
}

// NewEnvironment creates a collation Environment for the given MySQL Version
func NewEnvironment(serverVersion string) (*Environment, error) {
	var version collver
	switch {
	case strings.Contains(serverVersion, "MariaDB"):
		switch {
		case strings.HasPrefix(serverVersion, "10.0."):
			version = collverMariaDB100
		case strings.HasPrefix(serverVersion, "10.1."):
			version = collverMariaDB101
		case strings.HasPrefix(serverVersion, "10.2."):
			version = collverMariaDB102
		case strings.HasPrefix(serverVersion, "10.3."):
			version = collverMariaDB103
		}
	case strings.HasPrefix(serverVersion, "5.6."):
		version = collverMySQL56
	case strings.HasPrefix(serverVersion, "5.7."):
		version = collverMySQL57
	case strings.HasPrefix(serverVersion, "8.0."):
		version = collverMySQL80
	}
	if version == collverInvalid {
		return nil, fmt.Errorf("unknown ServerVersion value: %q", serverVersion)
	}
	return makeEnv(version), nil
}

func makeEnv(version collver) *Environment {
	env := &Environment{
		version:     version,
		byName:      make(map[string]Collation),
		byID:        make(map[ID]Collation),
		byCharset:   make(map[string]*colldefaults),
		unsupported: make(map[string]ID),
	}

	for collid, vi := range globalVersionInfo {
		var ourname string
		for mask, name := range vi.alias {
			if mask&version != 0 {
				ourname = name
				break
			}
		}
		if ourname == "" {
			continue
		}

		collation, ok := globalAllCollations[collid]
		if !ok {
			env.unsupported[ourname] = collid
			continue
		}

		env.byName[ourname] = collation
		env.byID[collid] = collation

		csname := collation.Charset().Name()
		if _, ok := env.byCharset[csname]; !ok {
			env.byCharset[csname] = &colldefaults{}
		}
		defaults := env.byCharset[csname]
		if vi.isdefault&version != 0 {
			defaults.Default = collation
		}
		if collation.IsBinary() {
			if defaults.Binary != nil && defaults.Binary.ID() > collation.ID() {
				// If there's more than one binary collation, the one with the
				// highest ID (i.e. the newest one) takes precedence. This applies
				// to utf8mb4_bin vs utf8mb4_0900_bin
				continue
			}
			defaults.Binary = collation
		}
	}
	return env
}

var globalDefault *Environment
var globalDefaultInit sync.Once

// Default is the default collation Environment for Vitess. This is set to
// the collation set and defaults available in MySQL 8.0
func Default() *Environment {
	globalDefaultInit.Do(func() {
		globalDefault = makeEnv(collverMySQL80)
	})
	return globalDefault
}
<commit_msg>collations: clarify comment<commit_after>/*
Copyright 2021 The Vitess 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 collations

import (
	"fmt"
	"strings"
	"sync"
)

type colldefaults struct {
	Default Collation
	Binary  Collation
}

// Environment is a collation environment for a MySQL version, which contains
// a database of collations and defaults for that specific version.
type Environment struct {
	version     collver
	byName      map[string]Collation
	byID        map[ID]Collation
	byCharset   map[string]*colldefaults
	unsupported map[string]ID
}

// LookupByName returns the collation with the given name. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByName(name string) Collation {
	if coll, ok := env.byName[name]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupByID returns the collation with the given numerical identifier. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByID(id ID) Collation {
	if coll, ok := env.byID[id]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupID returns the collation ID for the given name, and whether
// the collation is supported by this package.
func (env *Environment) LookupID(name string) (ID, bool) {
	if supported, ok := env.byName[name]; ok {
		return supported.ID(), true
	}
	if unsupported, ok := env.unsupported[name]; ok {
		return unsupported, false
	}
	return Unknown, false
}

// DefaultCollationForCharset returns the default collation for a charset
func (env *Environment) DefaultCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Default != nil {
			defaults.Default.Init()
			return defaults.Default
		}
	}
	return nil
}

// BinaryCollationForCharset returns the default binary collation for a charset
func (env *Environment) BinaryCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Binary != nil {
			defaults.Binary.Init()
			return defaults.Binary
		}
	}
	return nil
}

// AllCollations returns a slice with all known collations in Vitess. This is an expensive call because
// it will initialize the internal state of all the collations before returning them.
// Used for testing/debugging.
func (env *Environment) AllCollations() (all []Collation) {
	all = make([]Collation, 0, len(env.byID))
	for _, col := range env.byID {
		col.Init()
		all = append(all, col)
	}
	return
}

// NewEnvironment creates a collation Environment for the given MySQL version string.
// The version string must be in the format that is sent by the server as the version packet
// when opening a new MySQL connection
func NewEnvironment(serverVersion string) (*Environment, error) {
	var version collver
	switch {
	case strings.Contains(serverVersion, "MariaDB"):
		switch {
		case strings.HasPrefix(serverVersion, "10.0."):
			version = collverMariaDB100
		case strings.HasPrefix(serverVersion, "10.1."):
			version = collverMariaDB101
		case strings.HasPrefix(serverVersion, "10.2."):
			version = collverMariaDB102
		case strings.HasPrefix(serverVersion, "10.3."):
			version = collverMariaDB103
		}
	case strings.HasPrefix(serverVersion, "5.6."):
		version = collverMySQL56
	case strings.HasPrefix(serverVersion, "5.7."):
		version = collverMySQL57
	case strings.HasPrefix(serverVersion, "8.0."):
		version = collverMySQL80
	}
	if version == collverInvalid {
		return nil, fmt.Errorf("unknown ServerVersion value: %q", serverVersion)
	}
	return makeEnv(version), nil
}

func makeEnv(version collver) *Environment {
	env := &Environment{
		version:     version,
		byName:      make(map[string]Collation),
		byID:        make(map[ID]Collation),
		byCharset:   make(map[string]*colldefaults),
		unsupported: make(map[string]ID),
	}

	for collid, vi := range globalVersionInfo {
		var ourname string
		for mask, name := range vi.alias {
			if mask&version != 0 {
				ourname = name
				break
			}
		}
		if ourname == "" {
			continue
		}

		collation, ok := globalAllCollations[collid]
		if !ok {
			env.unsupported[ourname] = collid
			continue
		}

		env.byName[ourname] = collation
		env.byID[collid] = collation

		csname := collation.Charset().Name()
		if _, ok := env.byCharset[csname]; !ok {
			env.byCharset[csname] = &colldefaults{}
		}
		defaults := env.byCharset[csname]
		if vi.isdefault&version != 0 {
			defaults.Default = collation
		}
		if collation.IsBinary() {
			if defaults.Binary != nil && defaults.Binary.ID() > collation.ID() {
				// If there's more than one binary collation, the one with the
				// highest ID (i.e. the newest one) takes precedence. This applies
				// to utf8mb4_bin vs utf8mb4_0900_bin
				continue
			}
			defaults.Binary = collation
		}
	}
	return env
}

var globalDefault *Environment
var globalDefaultInit sync.Once

// Default is the default collation Environment for Vitess. This is set to
// the collation set and defaults available in MySQL 8.0
func Default() *Environment {
	globalDefaultInit.Do(func() {
		globalDefault = makeEnv(collverMySQL80)
	})
	return globalDefault
}
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"fmt"
	"log"
	"reflect"
	"regexp"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func deleteSpannerBackups(d *schema.ResourceData, config *Config, res map[string]interface{}, userAgent string, billingProject string) error {
	var v interface{}
	var ok bool

	v, ok = res["backups"]
	if !ok || v == nil {
		return nil
	}

	// Iterate over the list and delete each backup.
	for _, itemRaw := range v.([]interface{}) {
		if itemRaw == nil {
			continue
		}
		item := itemRaw.(map[string]interface{})

		backupName := item["name"].(string)

		log.Printf("[DEBUG] Found backups for resource %q: %#v)", d.Id(), item)

		path := "{{SpannerBasePath}}" + backupName

		url, err := replaceVars(d, config, path)
		if err != nil {
			return err
		}

		_, err = sendRequest(config, "DELETE", billingProject, url, userAgent, nil)
		if err != nil {
			return err
		}
	}
	return nil
}

func GetSpannerInstanceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//spanner.googleapis.com/projects/{{project}}/instances/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetSpannerInstanceApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "spanner.googleapis.com/Instance",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/spanner/v1/rest",
				DiscoveryName:        "Instance",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetSpannerInstanceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	nameProp, err := expandSpannerInstanceName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	configProp, err := expandSpannerInstanceConfig(d.Get("config"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(configProp)) && (ok || !reflect.DeepEqual(v, configProp)) {
		obj["config"] = configProp
	}
	displayNameProp, err := expandSpannerInstanceDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	nodeCountProp, err := expandSpannerInstanceNumNodes(d.Get("num_nodes"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("num_nodes"); !isEmptyValue(reflect.ValueOf(nodeCountProp)) && (ok || !reflect.DeepEqual(v, nodeCountProp)) {
		obj["nodeCount"] = nodeCountProp
	}
	labelsProp, err := expandSpannerInstanceLabels(d.Get("labels"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
		obj["labels"] = labelsProp
	}

	return resourceSpannerInstanceEncoder(d, config, obj)
}

func resourceSpannerInstanceEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	newObj := make(map[string]interface{})
	newObj["instance"] = obj
	if obj["name"] == nil {
		if err := d.Set("name", resource.PrefixedUniqueId("tfgen-spanid-")[:30]); err != nil {
			return nil, fmt.Errorf("Error setting name: %s", err)
		}
		newObj["instanceId"] = d.Get("name").(string)
	} else {
		newObj["instanceId"] = obj["name"]
	}
	delete(obj, "name")
	return newObj, nil
}

func expandSpannerInstanceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	r := regexp.MustCompile("projects/(.+)/instanceConfigs/(.+)")
	if r.MatchString(v.(string)) {
		return v.(string), nil
	}

	project, err := getProject(d, config)
	if err != nil {
		return nil, err
	}

	return fmt.Sprintf("projects/%s/instanceConfigs/%s", project, v.(string)), nil
}

func expandSpannerInstanceDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceNumNodes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
	if v == nil {
		return map[string]string{}, nil
	}
	m := make(map[string]string)
	for k, val := range v.(map[string]interface{}) {
		m[k] = val.(string)
	}
	return m, nil
}
<commit_msg>Add support for `processing_units` to `google_spanner_instance` (#4993) (#756)<commit_after>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"fmt"
	"log"
	"reflect"
	"regexp"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func deleteSpannerBackups(d *schema.ResourceData, config *Config, res map[string]interface{}, userAgent string, billingProject string) error {
	var v interface{}
	var ok bool

	v, ok = res["backups"]
	if !ok || v == nil {
		return nil
	}

	// Iterate over the list and delete each backup.
	for _, itemRaw := range v.([]interface{}) {
		if itemRaw == nil {
			continue
		}
		item := itemRaw.(map[string]interface{})

		backupName := item["name"].(string)

		log.Printf("[DEBUG] Found backups for resource %q: %#v)", d.Id(), item)

		path := "{{SpannerBasePath}}" + backupName

		url, err := replaceVars(d, config, path)
		if err != nil {
			return err
		}

		_, err = sendRequest(config, "DELETE", billingProject, url, userAgent, nil)
		if err != nil {
			return err
		}
	}
	return nil
}

func GetSpannerInstanceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//spanner.googleapis.com/projects/{{project}}/instances/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetSpannerInstanceApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "spanner.googleapis.com/Instance",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/spanner/v1/rest",
				DiscoveryName:        "Instance",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetSpannerInstanceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	nameProp, err := expandSpannerInstanceName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	configProp, err := expandSpannerInstanceConfig(d.Get("config"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(configProp)) && (ok || !reflect.DeepEqual(v, configProp)) {
		obj["config"] = configProp
	}
	displayNameProp, err := expandSpannerInstanceDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	nodeCountProp, err := expandSpannerInstanceNumNodes(d.Get("num_nodes"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("num_nodes"); !isEmptyValue(reflect.ValueOf(nodeCountProp)) && (ok || !reflect.DeepEqual(v, nodeCountProp)) {
		obj["nodeCount"] = nodeCountProp
	}
	processingUnitsProp, err := expandSpannerInstanceProcessingUnits(d.Get("processing_units"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("processing_units"); !isEmptyValue(reflect.ValueOf(processingUnitsProp)) && (ok || !reflect.DeepEqual(v, processingUnitsProp)) {
		obj["processingUnits"] = processingUnitsProp
	}
	labelsProp, err := expandSpannerInstanceLabels(d.Get("labels"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
		obj["labels"] = labelsProp
	}

	return resourceSpannerInstanceEncoder(d, config, obj)
}

func resourceSpannerInstanceEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	// Temp Logic to accomodate processing_units and num_nodes
	if obj["processingUnits"] == nil && obj["nodeCount"] == nil {
		obj["nodeCount"] = 1
	}
	newObj := make(map[string]interface{})
	newObj["instance"] = obj
	if obj["name"] == nil {
		if err := d.Set("name", resource.PrefixedUniqueId("tfgen-spanid-")[:30]); err != nil {
			return nil, fmt.Errorf("Error setting name: %s", err)
		}
		newObj["instanceId"] = d.Get("name").(string)
	} else {
		newObj["instanceId"] = obj["name"]
	}
	delete(obj, "name")
	return newObj, nil
}

func expandSpannerInstanceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	r := regexp.MustCompile("projects/(.+)/instanceConfigs/(.+)")
	if r.MatchString(v.(string)) {
		return v.(string), nil
	}

	project, err := getProject(d, config)
	if err != nil {
		return nil, err
	}

	return fmt.Sprintf("projects/%s/instanceConfigs/%s", project, v.(string)), nil
}

func expandSpannerInstanceDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceNumNodes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceProcessingUnits(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
	if v == nil {
		return map[string]string{}, nil
	}
	m := make(map[string]string)
	for k, val := range v.(map[string]interface{}) {
		m[k] = val.(string)
	}
	return m, nil
}
<|endoftext|>