<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"fmt"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

// TODO(jacobsa): Add a Destroy method here that calls ObjectProxy.Destroy, and
// make sure it's called when the inode is forgotten. Also, make sure package
// fuse has support for actually calling Forget.
type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id fuse.InodeID

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	ctx context.Context,
	bucket gcs.Bucket,
	id fuse.InodeID,
	o *storage.Object) (f *FileInode, err error) {
	// Set up the basic struct.
	f = &FileInode{
		bucket: bucket,
		id:     id,
	}

	// Set up the proxy.
	f.proxy, err = gcsproxy.NewObjectProxy(ctx, bucket, o)
	if err != nil {
		err = fmt.Errorf("NewObjectProxy: %v", err)
		return
	}

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	name := f.proxy.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) Name() string {
	return f.proxy.Name()
}

// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	// Stat the object.
	size, _, err := f.op.Stat(ctx)
	if err != nil {
		err = fmt.Errorf("Stat: %v", err)
		return
	}

	// Fill out the struct.
	//
	// TODO(jacobsa): Add a test for nlink == 0 when clobbered and update the
	// code here.
	attrs = fuse.InodeAttributes{
		Size:  uint64(size),
		Mode:  0700,
		Mtime: f.srcObject.Updated,
	}

	return
}

// Return the generation number from which this inode was branched. This is
// used as a precondition in object write requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation.
//
// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGeneration() int64 {
	return f.srcObject.Generation
}
<commit_msg>Fixed more build errors.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"fmt"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/gcsproxy"
	"golang.org/x/net/context"
	"google.golang.org/cloud/storage"
)

// TODO(jacobsa): Add a Destroy method here that calls ObjectProxy.Destroy, and
// make sure it's called when the inode is forgotten. Also, make sure package
// fuse has support for actually calling Forget.
type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id fuse.InodeID

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	ctx context.Context,
	bucket gcs.Bucket,
	id fuse.InodeID,
	o *storage.Object) (f *FileInode, err error) {
	// Set up the basic struct.
	f = &FileInode{
		bucket: bucket,
		id:     id,
	}

	// Set up the proxy.
	f.proxy, err = gcsproxy.NewObjectProxy(ctx, bucket, o)
	if err != nil {
		err = fmt.Errorf("NewObjectProxy: %v", err)
		return
	}

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	name := f.proxy.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) Name() string {
	return f.proxy.Name()
}

// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	// Stat the object.
	size, _, err := f.proxy.Stat(ctx)
	if err != nil {
		err = fmt.Errorf("Stat: %v", err)
		return
	}

	// Fill out the struct.
	//
	// TODO(jacobsa): Add a test for nlink == 0 when clobbered and update the
	// code here.
	//
	// TODO(jacobsa): Make ObjectProxy.Stat return a struct containing mtime as
	// well as size and clobbered. (Get mtime from the local file when around,
	// otherwise the source object.) Then include Mtime here. But first make sure
	// there is a failing test.
	attrs = fuse.InodeAttributes{
		Size: uint64(size),
		Mode: 0700,
	}

	return
}

// Return the generation number from which this inode was branched. This is
// used as a precondition in object write requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation.
//
// SHARED_LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGeneration() int64 {
	return f.srcObject.Generation
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    // s "strings"
    "os"
    "syscall"
)

type Config struct {
    // member  type        json element
    Colours map[string][]string `json:"colours"`
}

func main() {

    var config Config

    force := *(flag.Bool("f", false, "force map generation"))
    flag.Parse()

    if force {}

    source, err := ioutil.ReadFile("config.json")
    if err != nil {
	panic(err)
    }

    err = json.Unmarshal(source, &config)
    if err != nil {
	fmt.Fprintf(os.Stderr, "Unmarshal: ")
	panic(err)
    }

    //fmt.Println(config.Colours)

    syscall.Umask(022)
}

// vim:ai:sw=4:ts=8:
<commit_msg>successfully using package and updating a path element<commit_after>package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "regexp"
    "strconv"
    "os"
    "jfb/svgxml"
)

type Config struct {
    // member  type        json element
    Colours map[string]string `json:"colours"`
}

func main() {

    var config Config
    var colors map[int]string

    if len(os.Args) < 2 {
        fmt.Fprintf(os.Stderr, "Please specify at least one filename on the command line.\n")
        os.Exit(1)
    }

    jsoncfg, err := ioutil.ReadFile("config.json")
    if err != nil {
        panic(err)
    }

    mapsvg, err := ioutil.ReadFile(os.Args[1])
    if err != nil {
        panic(err)
    }

    err = json.Unmarshal(jsoncfg, &config)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Unmarshal: ")
        panic(err)
    }

    // convert string-based JSON to all-integer map
    colors = make(map[int]string)
    for k, v := range config.Colours {
        k_i, _ := strconv.ParseInt(k, 0, 64)
        colors[int(k_i)] = v
    }

    mapsvg_obj := svgxml.XML2SVG(mapsvg)
    if mapsvg_obj == nil {
        os.Exit(1)
    }

    re_fill, err := regexp.Compile(`(fill:#)......`)
    if err != nil {
        panic(err)
    }

    element := svgxml.FindPathById(mapsvg_obj, "HI")

    if element != nil {
        element.Style = string(re_fill.ReplaceAll([]byte(element.Style), []byte("${1}ffaaaa")))
    } else {
        fmt.Println("'HI' not found")
    }

    // fmt.Println(string(svgxml.SVG2XML(mapsvg_obj, true)))

}

// vim:ai:sw=4:ts=8:
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	DIGIT_ONLY             = regexp.MustCompile(`^\d+$`)
	COLON_SEPARATED_DIGITS = regexp.MustCompile(`^(\d+):(\d+)$`)
)

type Margin struct {
	left  int
	right int
}

func NewMargin(format string) (*Margin, error) {
	m := &Margin{}
	switch {
	case format == "":
		m.left, m.right = 1, 1
	case DIGIT_ONLY.MatchString(format):
		n, err := strconv.Atoi(format)
		if err != nil {
			return nil, err
		}
		m.left, m.right = n, n
	case COLON_SEPARATED_DIGITS.MatchString(format):
		a := COLON_SEPARATED_DIGITS.FindAllStringSubmatch(format, -1)[0]
		l, err := strconv.Atoi(a[1])
		if err != nil {
			return nil, err
		}
		r, err := strconv.Atoi(a[2])
		if err != nil {
			return nil, err
		}
		m.left, m.right = l, r
	default:
		return nil, fmt.Errorf("margin: invalid format: %s", format)
	}
	return m, nil
}

func NewMarginWithNumber(left, right int) *Margin {
	return &Margin{
		left:  left,
		right: right,
	}
}

func (m *Margin) Join(a []string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}

	l, r := m.left, m.right
	if r < 0 {
		r = 0
	}
	if l < 0 {
		l = 0
	}
	n := (l + r) * (len(a) / 2)
	if len(a)%2 == 0 {
		n -= r
	}
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}
	lm, rm := strings.Repeat(" ", l), strings.Repeat(" ", r)

	b := make([]byte, n)
	bp := copy(b, a[0])
	for i := 2; i <= len(a); i += 2 {
		bp += copy(b[bp:], lm)
		bp += copy(b[bp:], a[i-1])
		if i != len(a) {
			bp += copy(b[bp:], rm)
			bp += copy(b[bp:], a[i])
		}
	}
	return string(b)
}
<commit_msg>Refactoring Margin.Join<commit_after>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

var (
	DIGIT_ONLY             = regexp.MustCompile(`^\d+$`)
	COLON_SEPARATED_DIGITS = regexp.MustCompile(`^(\d+):(\d+)$`)
)

type Margin struct {
	left  int
	right int
}

func NewMargin(format string) (*Margin, error) {
	m := &Margin{}
	switch {
	case format == "":
		m.left, m.right = 1, 1
	case DIGIT_ONLY.MatchString(format):
		n, err := strconv.Atoi(format)
		if err != nil {
			return nil, err
		}
		m.left, m.right = n, n
	case COLON_SEPARATED_DIGITS.MatchString(format):
		a := COLON_SEPARATED_DIGITS.FindAllStringSubmatch(format, -1)[0]
		l, err := strconv.Atoi(a[1])
		if err != nil {
			return nil, err
		}
		r, err := strconv.Atoi(a[2])
		if err != nil {
			return nil, err
		}
		m.left, m.right = l, r
	default:
		return nil, fmt.Errorf("margin: invalid format: %s", format)
	}
	return m, nil
}

func NewMarginWithNumber(left, right int) *Margin {
	return &Margin{
		left:  left,
		right: right,
	}
}

func (m *Margin) Join(a []string) string {
	switch len(a) {
	case 0:
		return ""
	case 1:
		return a[0]
	}

	l, r := m.left, m.right
	if r < 0 {
		r = 0
	}
	if l < 0 {
		l = 0
	}

	buflen := (l + r) * (len(a) / 2)
	if len(a)%2 == 0 {
		buflen -= r
	}
	for i := 0; i < len(a); i++ {
		buflen += len(a[i])
	}
	lm, rm := strings.Repeat(" ", l), strings.Repeat(" ", r)

	b := make([]byte, buflen)
	bp := copy(b, a[0])
	for i := 2; i <= len(a); i += 2 {
		bp += copy(b[bp:], lm)
		bp += copy(b[bp:], a[i-1])
		if i != len(a) {
			bp += copy(b[bp:], rm)
			bp += copy(b[bp:], a[i])
		}
	}
	return string(b)
}
<|endoftext|>


<commit_before>package main

// autotest github.com/a8n [paths...] [packages...] [testflags]
//  - new module for log colorization
//  - use StringArray (TestFlags, paths)

import (
	"fmt"
	"github.com/go-fsnotify/fsnotify"
	"go/build"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type watcher struct {
	// Finished is signaled when the watcher is closed.
	Finished chan bool

	// SettleTime indicates how long to wait after the last file system change before launching.
	SettleTime time.Duration

	// IgnoreDirs lists the names of directories that should not be watched for changes.
	IgnoreDirs map[string]bool

	// IgnoreFiles is a list of regular expression patterns for files that should be ignored.
	IgnoreFiles []*regexp.Regexp

	// TestFlags contains optional arguments for 'go test'.
	TestFlags []string

	debug       bool
	fs          *fsnotify.Watcher
	done        chan bool
	gosrc       string
	paths       []string
	timeSuccess time.Time
	timeFailure time.Time
	lastState   int
}

// Values for lastState
const (
	starting = iota
	working
	failing
)

// Go's time package does not provide a method such as:
//  func (d *Duration) Round(Duration)
// So we implement it here.
func round(duration, interval time.Duration) time.Duration {
	var t int64 = int64(duration) + int64(interval)/2
	return time.Duration(t - t%int64(interval))
}

func newWatcher() (*watcher, error) {
	fs, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	self := &watcher{
		Finished:   make(chan bool),
		SettleTime: 2 * time.Second,
		IgnoreDirs: map[string]bool{".git": true},
		IgnoreFiles: []*regexp.Regexp{
			regexp.MustCompile(`\..*\.swp$`),
		},
		TestFlags: make([]string, 0),
		debug:     false,
		fs:        fs,
		done:      make(chan bool),
		gosrc:     filepath.Join(os.Getenv("GOPATH"), "src"),
		paths:     make([]string, 0),
		lastState: starting,
	}
	return self, nil
}

func (self *watcher) Close() error {
	return self.fs.Close()
}

func (self *watcher) Start() {
	go self.monitorChanges()
}

func (self *watcher) Stop() {
	self.done <- true
}

func (self *watcher) Add(path string) error {
	// watch the file system path
	err := self.fs.Add(path)
	if err != nil {
		log.Fatal(err)
	}
	self.paths = append(self.paths, path)

	// is it a package dir (under $GOPATH/src?)
	if pkg := self.getPackageName(path); pkg != "" && self.debug {
		log.Println("package:", pkg, "in path:", path)
	}

	log.Println("watching for changes:", path)
	return err
}

func (self *watcher) Remove(path string) error {
	// find path in self.paths, remove the entry
	for i, val := range self.paths {
		if val == path {
			// delete entry at position i
			copy(self.paths[i:], self.paths[i+1:])
			self.paths = self.paths[0 : len(self.paths)-1]
			break
		}
	}
	return self.fs.Remove(path)
}

// AddRecursive walks a directory recursively, and watches all subdirectories.
func (self *watcher) AddRecursive(path string) error {
	return filepath.Walk(path, func(subpath string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if _, ignore := self.IgnoreDirs[info.Name()]; ignore {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return self.Add(subpath)
		}
		return nil
	})
}

// RunTests invokes the 'go test' tool for all monitored packages.
func (self *watcher) RunTests() {
	if err := self.handleModifications(); err != nil {
		msg := "error: " + err.Error()
		if self.lastState != failing {
			self.timeFailure = time.Now()
		}
		if self.lastState == working {
			msg += fmt.Sprintf(" (%s success)", round(time.Since(self.timeSuccess), time.Second))
		}
		self.lastState = failing
		log.Println("\u001b[31m" + msg + "\u001b[0m")
	} else {
		msg := ""
		if self.lastState != working {
			self.timeSuccess = time.Now()
		}
		if self.lastState == failing {
			msg = fmt.Sprintf("success after %s failures", round(time.Since(self.timeFailure), time.Second))
		}
		self.lastState = working
		if len(msg) != 0 {
			log.Println("\u001b[32m" + msg + "\u001b[0m")
		}
	}
}

// monitorChanges is the main processing loop for file system notifications.
func (self *watcher) monitorChanges() {
	modified := false
	for {
		select {
		case <-self.done:
			self.Finished <- true
			return

		case err := <-self.fs.Errors:
			log.Println("error:", err)

		case event := <-self.fs.Events:
			mod, err := self.handleEvent(event)
			if err != nil {
				log.Println("error:", err)
			} else if mod {
				modified = true
			}

		case <-time.After(self.SettleTime):
			if modified {
				self.RunTests()
				modified = false
			}
		}
	}
}

// handleEvent handles a file system change notification.
func (self *watcher) handleEvent(event fsnotify.Event) (bool, error) {
	filename := event.Name
	modified := false

	if event.Op&fsnotify.Create != 0 {
		info, err := os.Stat(filename)
		if err != nil {
			return false, err
		}
		if info.IsDir() {
			if err := self.Add(filename); err != nil {
				return false, err
			}
		} else {
			if self.debug {
				log.Println("created:", filename)
			}
			modified = true
		}
	}
	if event.Op&fsnotify.Remove != 0 {
		if err := self.Remove(filename); err != nil {
			// "can't remove non-existent inotify watch" is OK
			if !strings.HasPrefix(err.Error(), "can't remove non-existent inotify watch") {
				return false, err
			}
		}
		if self.debug {
			log.Println("removed:", filename)
		}
		modified = true
	}
	if event.Op&fsnotify.Write != 0 {
		// skip file if it matches any regexp in IgnoreFiles
		skip := false
		base := filepath.Base(filename)
		for _, re := range self.IgnoreFiles {
			if re.MatchString(base) {
				skip = true
				break
			}
		}
		if skip {
			if self.debug {
				log.Println("skipping:", filename)
			}
		} else {
			if self.debug {
				log.Println("modified:", filename)
			}
			modified = true
		}
	}
	return modified, nil
}

// handleModifications launches 'go test'.
func (self *watcher) handleModifications() error {
	args := make([]string, 1+len(self.TestFlags))
	args[0] = "test"
	copy(args[1:], self.TestFlags)
	npkg := 0
	for _, path := range self.paths {
		if pkg := self.getPackageName(path); pkg != "" {
			args = append(args, pkg)
			npkg++
		}
	}
	cmd := exec.Command("go", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("running go test with %d packages\n", npkg)
	return cmd.Run()
}

// getPackageName returns the go package name for a path, or "" if not a package dir.
func (self *watcher) getPackageName(path string) string {
	if pkg, err := filepath.Rel(self.gosrc, path); err == nil {
		return pkg
	}
	return ""
}

// --------------------------------------------------------------------------

func getCwd() string {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	return cwd
}

// findPackage looks for path in the current directory, and any go source dirs,
// and returns the resolved path or an empty string if not found.
func findPackage(path string) string {
	// check relative to current directory first
	if stat, err := os.Stat(path); err == nil && stat.IsDir() {
		if !filepath.IsAbs(path) {
			path = filepath.Join(getCwd(), path)
		}
		return path
	}

	// check GOROOT / GOPATH
	for _, srcDir := range build.Default.SrcDirs() {
		pkg, err := build.Default.Import(path, srcDir, build.FindOnly)
		if err == nil {
			return pkg.Dir
		}
	}

	log.Println("package not found:", path)
	return ""
}

func main() {
	for _, arg := range os.Args[1:] {
		if arg == "-h" || arg == "--help" {
			fmt.Printf(`Monitors the file system and automatically runs 'go test' on changes.

usage: %s [-h | --help] [testflags] [path...] [package...]

options:
  -h, --help   print this message
  testflags    flags supported by 'go test'; see 'go help testflag'
  path...      filesystem path, monitored recursively
  package...   go package name for which 'go test' will be issued
`, os.Args[0])
			os.Exit(0)
		}
	}
	if os.Getenv("GOPATH") == "" {
		log.Fatalln("GOPATH is not set")
	}

	w, err := newWatcher()
	if err != nil {
		log.Fatal(err)
	}
	w.SettleTime = 500 * time.Millisecond

	// signals used to stop
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		//signal := <-signals
		//log.Println("got signal:", signal)
		<-signals
		w.Stop()
	}()

	// monitor paths
	gotOne := false
	for _, arg := range os.Args[1:] {
		if arg[0] == '-' {
			w.TestFlags = append(w.TestFlags, arg)
		} else if path := findPackage(arg); path != "" {
			if err := w.AddRecursive(path); err != nil {
				log.Fatal(err)
			} else {
				gotOne = true
			}
		}
	}

	if !gotOne {
		log.Fatalln("no paths to watch")
	}

	w.Start()
	w.RunTests()
	<-w.Finished
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	log.Println("exiting")
}
<commit_msg>Avoid logging error for "no such file or directory" on change events (temp file)<commit_after>package main

// autotest github.com/a8n [paths...] [packages...] [testflags]
//  - new module for log colorization
//  - use StringArray (TestFlags, paths)

import (
	"fmt"
	"github.com/go-fsnotify/fsnotify"
	"go/build"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"
	"time"
)

type watcher struct {
	// Finished is signaled when the watcher is closed.
	Finished chan bool

	// SettleTime indicates how long to wait after the last file system change before launching.
	SettleTime time.Duration

	// IgnoreDirs lists the names of directories that should not be watched for changes.
	IgnoreDirs map[string]bool

	// IgnoreFiles is a list of regular expression patterns for files that should be ignored.
	IgnoreFiles []*regexp.Regexp

	// TestFlags contains optional arguments for 'go test'.
	TestFlags []string

	debug       bool
	fs          *fsnotify.Watcher
	done        chan bool
	gosrc       string
	paths       []string
	timeSuccess time.Time
	timeFailure time.Time
	lastState   int
}

// Values for lastState
const (
	starting = iota
	working
	failing
)

// Go's time package does not provide a method such as:
//  func (d *Duration) Round(Duration)
// So we implement it here.
func round(duration, interval time.Duration) time.Duration {
	var t int64 = int64(duration) + int64(interval)/2
	return time.Duration(t - t%int64(interval))
}

func newWatcher() (*watcher, error) {
	fs, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	self := &watcher{
		Finished:   make(chan bool),
		SettleTime: 2 * time.Second,
		IgnoreDirs: map[string]bool{".git": true},
		IgnoreFiles: []*regexp.Regexp{
			regexp.MustCompile(`\..*\.swp$`),
		},
		TestFlags: make([]string, 0),
		debug:     false,
		fs:        fs,
		done:      make(chan bool),
		gosrc:     filepath.Join(os.Getenv("GOPATH"), "src"),
		paths:     make([]string, 0),
		lastState: starting,
	}
	return self, nil
}

func (self *watcher) Close() error {
	return self.fs.Close()
}

func (self *watcher) Start() {
	go self.monitorChanges()
}

func (self *watcher) Stop() {
	self.done <- true
}

func (self *watcher) Add(path string) error {
	// watch the file system path
	err := self.fs.Add(path)
	if err != nil {
		log.Fatal(err)
	}
	self.paths = append(self.paths, path)

	// is it a package dir (under $GOPATH/src?)
	if pkg := self.getPackageName(path); pkg != "" && self.debug {
		log.Println("package:", pkg, "in path:", path)
	}

	log.Println("watching for changes:", path)
	return err
}

func (self *watcher) Remove(path string) error {
	// find path in self.paths, remove the entry
	for i, val := range self.paths {
		if val == path {
			// delete entry at position i
			copy(self.paths[i:], self.paths[i+1:])
			self.paths = self.paths[0 : len(self.paths)-1]
			break
		}
	}
	return self.fs.Remove(path)
}

// AddRecursive walks a directory recursively, and watches all subdirectories.
func (self *watcher) AddRecursive(path string) error {
	return filepath.Walk(path, func(subpath string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if _, ignore := self.IgnoreDirs[info.Name()]; ignore {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return self.Add(subpath)
		}
		return nil
	})
}

// RunTests invokes the 'go test' tool for all monitored packages.
func (self *watcher) RunTests() {
	if err := self.handleModifications(); err != nil {
		msg := "error: " + err.Error()
		if self.lastState != failing {
			self.timeFailure = time.Now()
		}
		if self.lastState == working {
			msg += fmt.Sprintf(" (%s success)", round(time.Since(self.timeSuccess), time.Second))
		}
		self.lastState = failing
		log.Println("\u001b[31m" + msg + "\u001b[0m")
	} else {
		msg := ""
		if self.lastState != working {
			self.timeSuccess = time.Now()
		}
		if self.lastState == failing {
			msg = fmt.Sprintf("success after %s failures", round(time.Since(self.timeFailure), time.Second))
		}
		self.lastState = working
		if len(msg) != 0 {
			log.Println("\u001b[32m" + msg + "\u001b[0m")
		}
	}
}

// monitorChanges is the main processing loop for file system notifications.
func (self *watcher) monitorChanges() {
	modified := false
	for {
		select {
		case <-self.done:
			self.Finished <- true
			return

		case err := <-self.fs.Errors:
			log.Println("error:", err)

		case event := <-self.fs.Events:
			mod, err := self.handleEvent(event)
			if err != nil {
				log.Println("error:", err)
			} else if mod {
				modified = true
			}

		case <-time.After(self.SettleTime):
			if modified {
				self.RunTests()
				modified = false
			}
		}
	}
}

// handleEvent handles a file system change notification.
func (self *watcher) handleEvent(event fsnotify.Event) (bool, error) {
	filename := event.Name
	modified := false

	if event.Op&fsnotify.Create != 0 {
		info, err := os.Stat(filename)
		if err != nil {
			// ENOENT can occur here for temp files (already deleted)
			if strings.HasSuffix(err.Error(), "no such file or directory") {
				return false, nil
			}
			return false, err
		}
		if info.IsDir() {
			if err := self.Add(filename); err != nil {
				return false, err
			}
		} else {
			if self.debug {
				log.Println("created:", filename)
			}
			modified = true
		}
	}
	if event.Op&fsnotify.Remove != 0 {
		if err := self.Remove(filename); err != nil {
			// "can't remove non-existent inotify watch" is OK
			if !strings.HasPrefix(err.Error(), "can't remove non-existent inotify watch") {
				return false, err
			}
		}
		if self.debug {
			log.Println("removed:", filename)
		}
		modified = true
	}
	if event.Op&fsnotify.Write != 0 {
		// skip file if it matches any regexp in IgnoreFiles
		skip := false
		base := filepath.Base(filename)
		for _, re := range self.IgnoreFiles {
			if re.MatchString(base) {
				skip = true
				break
			}
		}
		if skip {
			if self.debug {
				log.Println("skipping:", filename)
			}
		} else {
			if self.debug {
				log.Println("modified:", filename)
			}
			modified = true
		}
	}
	return modified, nil
}

// handleModifications launches 'go test'.
func (self *watcher) handleModifications() error {
	args := make([]string, 1+len(self.TestFlags))
	args[0] = "test"
	copy(args[1:], self.TestFlags)
	npkg := 0
	for _, path := range self.paths {
		if pkg := self.getPackageName(path); pkg != "" {
			args = append(args, pkg)
			npkg++
		}
	}
	cmd := exec.Command("go", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Printf("running go test with %d packages\n", npkg)
	return cmd.Run()
}

// getPackageName returns the go package name for a path, or "" if not a package dir.
func (self *watcher) getPackageName(path string) string {
	if pkg, err := filepath.Rel(self.gosrc, path); err == nil {
		return pkg
	}
	return ""
}

// --------------------------------------------------------------------------

func getCwd() string {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	return cwd
}

// findPackage looks for path in the current directory, and any go source dirs,
// and returns the resolved path or an empty string if not found.
func findPackage(path string) string {
	// check relative to current directory first
	if stat, err := os.Stat(path); err == nil && stat.IsDir() {
		if !filepath.IsAbs(path) {
			path = filepath.Join(getCwd(), path)
		}
		return path
	}

	// check GOROOT / GOPATH
	for _, srcDir := range build.Default.SrcDirs() {
		pkg, err := build.Default.Import(path, srcDir, build.FindOnly)
		if err == nil {
			return pkg.Dir
		}
	}

	log.Println("package not found:", path)
	return ""
}

func main() {
	for _, arg := range os.Args[1:] {
		if arg == "-h" || arg == "--help" {
			fmt.Printf(`Monitors the file system and automatically runs 'go test' on changes.

usage: %s [-h | --help] [testflags] [path...] [package...]

options:
  -h, --help   print this message
  testflags    flags supported by 'go test'; see 'go help testflag'
  path...      filesystem path, monitored recursively
  package...   go package name for which 'go test' will be issued
`, os.Args[0])
			os.Exit(0)
		}
	}
	if os.Getenv("GOPATH") == "" {
		log.Fatalln("GOPATH is not set")
	}

	w, err := newWatcher()
	if err != nil {
		log.Fatal(err)
	}
	w.SettleTime = 500 * time.Millisecond

	// signals used to stop
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		//signal := <-signals
		//log.Println("got signal:", signal)
		<-signals
		w.Stop()
	}()

	// monitor paths
	gotOne := false
	for _, arg := range os.Args[1:] {
		if arg[0] == '-' {
			w.TestFlags = append(w.TestFlags, arg)
		} else if path := findPackage(arg); path != "" {
			if err := w.AddRecursive(path); err != nil {
				log.Fatal(err)
			} else {
				gotOne = true
			}
		}
	}

	if !gotOne {
		log.Fatalln("no paths to watch")
	}

	w.Start()
	w.RunTests()
	<-w.Finished
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	log.Println("exiting")
}
<|endoftext|>


<commit_before><commit_msg>Added ${USER} environment variable to lambdas so that the pre- and post-traffic hooks don't fail with a bad identifier 'development-'.<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		client := newCharmstoreClient()
		return &charmstoreClient{client}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})
}

func newCharmstoreClient() charmrepo.Interface {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	client := charmrepo.NewCharmStore(args)
	return client
}

// TODO(ericsnow) Get rid of charmstoreClient one charmrepo.Interface grows the methods.

type charmstoreClient struct {
	charmrepo.Interface
}

func (charmstoreClient) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	if len(charmURLs) != 1 || charmURLs[0].Name != "starsay" {
		res := make([][]charmresource.Resource, len(charmURLs))
		return res, nil
	}
	var fingerprint = []byte("123456789012345678901234567890123456789012345678")
	fp, err := charmresource.NewFingerprint(fingerprint)
	if err != nil {
		return nil, err
	}
	res := [][]charmresource.Resource{
		{
			{
				Meta: charmresource.Meta{
					Name:    "store-resource",
					Type:    charmresource.TypeFile,
					Path:    "filename.tgz",
					Comment: "One line that is useful when operators need to push it.",
				},
				Origin:      charmresource.OriginStore,
				Revision:    1,
				Fingerprint: fp,
				Size:        1,
			},
			{
				Meta: charmresource.Meta{
					Name:    "upload-resource",
					Type:    charmresource.TypeFile,
					Path:    "somename.xml",
					Comment: "Who uses xml anymore?",
				},
				Origin: charmresource.OriginUpload,
			},
		},
	}
	return res, nil
}

func (charmstoreClient) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)

	return client.NewClient(caller, apiCaller), nil
}
<commit_msg>add todo<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		client := newCharmstoreClient()
		return &charmstoreClient{client}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})
}

func newCharmstoreClient() charmrepo.Interface {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	client := charmrepo.NewCharmStore(args)
	return client
}

// TODO(ericsnow) Get rid of charmstoreClient one charmrepo.Interface grows the methods.

type charmstoreClient struct {
	charmrepo.Interface
}

func (charmstoreClient) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	// TODO(natefinch): this is all demo stuff and should go away afterward.
	if len(charmURLs) != 1 || charmURLs[0].Name != "starsay" {
		res := make([][]charmresource.Resource, len(charmURLs))
		return res, nil
	}
	var fingerprint = []byte("123456789012345678901234567890123456789012345678")
	fp, err := charmresource.NewFingerprint(fingerprint)
	if err != nil {
		return nil, err
	}
	res := [][]charmresource.Resource{
		{
			{
				Meta: charmresource.Meta{
					Name:    "store-resource",
					Type:    charmresource.TypeFile,
					Path:    "filename.tgz",
					Comment: "One line that is useful when operators need to push it.",
				},
				Origin:      charmresource.OriginStore,
				Revision:    1,
				Fingerprint: fp,
				Size:        1,
			},
			{
				Meta: charmresource.Meta{
					Name:    "upload-resource",
					Type:    charmresource.TypeFile,
					Path:    "somename.xml",
					Comment: "Who uses xml anymore?",
				},
				Origin: charmresource.OriginUpload,
			},
		},
	}
	return res, nil
}

func (charmstoreClient) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)

	return client.NewClient(caller, apiCaller), nil
}
<|endoftext|>


<commit_before>package zmq3_test

import (
	zmq "github.com/pebbe/zmq3"

	"errors"
	"fmt"
	"runtime"
)

func Example_test_version() {
	major, _, _ := zmq.Version()
	fmt.Println("Version:", major)
	// Output:
	// Version: 3
}

func Example_test_connect_delay() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_connect_resolve() {

	/*
		copied from zmq4
	*/

	sock, err := zmq.NewSocket(zmq.PUB)
	if checkErr(err) {
		return
	}

	err = sock.Connect("tcp://localhost:1234")
	checkErr(err)

	err = sock.Connect("tcp://localhost:invalid")
	fmt.Println(err)

	err = sock.Connect("tcp://in val id:1234")
	fmt.Println(err)

	err = sock.Connect("invalid://localhost:1234")
	fmt.Println(err)

	err = sock.Close()
	checkErr(err)

	fmt.Println("Done")
	// Output:
	// invalid argument
	// invalid argument
	// protocol not supported
	// Done
}

func Example_test_disconnect_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_hwm() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_invalid_rep() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_last_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_monitor() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_msg_flags() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_device() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_router_mandatory() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_shutdown_stress() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_sub_forward() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_term_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_timeo() {

	fmt.Println("Done")
	// Output:
	// Done
}

func bounce(server, client *zmq.Socket) {

	content := "12345678ABCDEFGH12345678abcdefgh"

	//  Send message from client to server
	rc, err := client.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = client.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at server side
	msg, err := server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err := server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at server side
	msg, err = server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

	// The same, from server back to client

	//  Send message from server to client
	rc, err = server.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = server.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

}

func checkErr(err error) bool {
	if err != nil {
		_, filename, lineno, ok := runtime.Caller(1)
		if ok {
			fmt.Printf("%v:%v: %v\n", filename, lineno, err)
		} else {
			fmt.Println(err)
		}
		return true
	}
	return false
}
<commit_msg>Using generic error message in tests, because error messages are not the same for all platforms<commit_after>package zmq3_test

import (
	zmq "github.com/pebbe/zmq3"

	"errors"
	"fmt"
	"runtime"
)

var (
	errerr = errors.New("error")
)

func Example_test_version() {
	major, _, _ := zmq.Version()
	fmt.Println("Version:", major)
	// Output:
	// Version: 3
}

func Example_test_connect_delay() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_connect_resolve() {

	/*
		copied from zmq4
	*/

	sock, err := zmq.NewSocket(zmq.PUB)
	if checkErr(err) {
		return
	}

	err = sock.Connect("tcp://localhost:1234")
	checkErr(err)

	err = sock.Connect("tcp://localhost:invalid")
	fmt.Println(e(err, true))

	err = sock.Connect("tcp://in val id:1234")
	fmt.Println(e(err, true))

	err = sock.Connect("invalid://localhost:1234")
	fmt.Println(e(err, true))

	err = sock.Close()
	checkErr(err)

	fmt.Println("Done")
	// Output:
	// error
	// error
	// error
	// Done
}

func Example_test_disconnect_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_hwm() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_invalid_rep() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_last_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_monitor() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_msg_flags() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_device() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_router_mandatory() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_shutdown_stress() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_sub_forward() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_term_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_timeo() {

	fmt.Println("Done")
	// Output:
	// Done
}

func bounce(server, client *zmq.Socket) {

	content := "12345678ABCDEFGH12345678abcdefgh"

	//  Send message from client to server
	rc, err := client.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = client.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at server side
	msg, err := server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err := server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at server side
	msg, err = server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

	// The same, from server back to client

	//  Send message from server to client
	rc, err = server.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = server.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

}

func checkErr(err error) bool {
	if err != nil {
		_, filename, lineno, ok := runtime.Caller(1)
		if ok {
			fmt.Printf("%v:%v: %v\n", filename, lineno, err)
		} else {
			fmt.Println(err)
		}
		return true
	}
	return false
}

func e(err error, willfail bool) error {
	if err == nil || willfail == false {
		return err
	}
	return errerr
}
<|endoftext|>


<commit_before>package bio

// Copyright ©2011 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

import (
	"bytes"
	"fmt"
	"runtime"
	"strings"
)

// Trace depth
var TraceDepth = 10

// Base Error handling for bio packages.
type Error struct {
	*runtime.Func
	pc      []uintptr
	message string
	Item    interface{}
}

// Create a new Error with message, storing information about the caller stack frame skip levels above the caller and any item that may be needed for handling the error.
func NewError(message string, skip int, item interface{}) (err *Error) {
	err = &Error{
		pc:      make([]uintptr, TraceDepth),
		message: message,
		Item:    item,
	}

	var n int
	if n = runtime.Callers(skip+2, err.pc); n > 0 {
		err.Func = runtime.FuncForPC(err.pc[0])
	}
	err.pc = err.pc[:n]

	return
}

// Return the file name and line number of caller stored at creation of the Error.
func (self *Error) FileLine() (file string, line int) {

	return self.Func.FileLine(self.pc[0])
}

// Return a slice contining the stack trace stored at creation of the Error.
func (self *Error) Trace() (stack []*runtime.Func) {
	stack = make([]*runtime.Func, len(self.pc))
	for i, pc := range self.pc {
		stack[i] = runtime.FuncForPC(pc)
	}

	return
}

// Return the package name of the stored caller.
func (self *Error) Package() string {
	caller := strings.Split(self.Func.Name(), ".")
	return strings.Join(caller[0:len(caller)-1], ".")
}

// Return the function name of the stored caller.
func (self *Error) Function() string {
	caller := strings.Split(self.Func.Name(), ".")
	return caller[len(caller)-1]
}

// A formatted stack trace of the error extending depth frames into the stack, 0 indicates no limit.
func (self *Error) Tracef(depth int) string {
	var last, name string
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "Trace: %s:\n", self.message)
	for i, frame := range self.Trace() {
		if depth > 0 && i >= depth {
			break
		}
		file, line := frame.FileLine(self.pc[i])
		if name = frame.Name(); name != last {
			fmt.Fprintf(b, "\n %s:\n", frame.Name())
		}
		last = name
		fmt.Fprintf(b, "\t%s#L=%d\n", file, line)
	}

	return string(b.Bytes())
}

// Satisfy the error interface.
func (self *Error) Error() string {
	return self.message
}
<commit_msg>Change Item to variadic Items.<commit_after>package bio

// Copyright ©2011 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

import (
	"bytes"
	"fmt"
	"runtime"
	"strings"
)

// Trace depth
var TraceDepth = 10

// Base Error handling for bio packages.
type Error struct {
	*runtime.Func
	pc      []uintptr
	message string
	Items   []interface{}
}

// Create a new Error with message, storing information about the caller stack frame skip levels above the caller and any item that may be needed for handling the error.
func NewError(message string, skip int, items ...interface{}) (err *Error) {
	err = &Error{
		pc:      make([]uintptr, TraceDepth),
		message: message,
		Items:   items,
	}

	var n int
	if n = runtime.Callers(skip+2, err.pc); n > 0 {
		err.Func = runtime.FuncForPC(err.pc[0])
	}
	err.pc = err.pc[:n]

	return
}

// Return the file name and line number of caller stored at creation of the Error.
func (self *Error) FileLine() (file string, line int) {

	return self.Func.FileLine(self.pc[0])
}

// Return a slice contining the stack trace stored at creation of the Error.
func (self *Error) Trace() (stack []*runtime.Func) {
	stack = make([]*runtime.Func, len(self.pc))
	for i, pc := range self.pc {
		stack[i] = runtime.FuncForPC(pc)
	}

	return
}

// Return the package name of the stored caller.
func (self *Error) Package() string {
	caller := strings.Split(self.Func.Name(), ".")
	return strings.Join(caller[0:len(caller)-1], ".")
}

// Return the function name of the stored caller.
func (self *Error) Function() string {
	caller := strings.Split(self.Func.Name(), ".")
	return caller[len(caller)-1]
}

// A formatted stack trace of the error extending depth frames into the stack, 0 indicates no limit.
func (self *Error) Tracef(depth int) string {
	var last, name string
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "Trace: %s:\n", self.message)
	for i, frame := range self.Trace() {
		if depth > 0 && i >= depth {
			break
		}
		file, line := frame.FileLine(self.pc[i])
		if name = frame.Name(); name != last {
			fmt.Fprintf(b, "\n %s:\n", frame.Name())
		}
		last = name
		fmt.Fprintf(b, "\t%s#L=%d\n", file, line)
	}

	return string(b.Bytes())
}

// Satisfy the error interface.
func (self *Error) Error() string {
	return self.message
}
<|endoftext|>


<commit_before>package slack

import (
	"encoding/json"

	"github.com/pkg/errors"
)

type sumtype struct {
	TypeVal string `json:"type"`
}

// MarshalJSON implements the Marshaller interface for Blocks so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b Blocks) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(b.BlockSet)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for Blocks, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *Blocks) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	var blocks Blocks
	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var blockType string
		if s.TypeVal != "" {
			blockType = s.TypeVal
		}

		var block Block
		switch blockType {
		case "actions":
			block = &ActionBlock{}
		case "context":
			block = &ContextBlock{}
		case "divider":
			block = &DividerBlock{}
		case "image":
			block = &ImageBlock{}
		case "input":
			block = &InputBlock{}
		case "section":
			block = &SectionBlock{}
		case "rich_text":
			// for now ignore the (complex) content of rich_text blocks until we can fully support it
			continue
		default:
			return errors.New("unsupported block type")
		}

		err = json.Unmarshal(r, block)
		if err != nil {
			return err
		}

		blocks.BlockSet = append(blocks.BlockSet, block)
	}

	*b = blocks
	return nil
}

// UnmarshalJSON implements the Unmarshaller interface for InputBlock, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *InputBlock) UnmarshalJSON(data []byte) error {
	type alias InputBlock
	a := struct {
		Element json.RawMessage `json:"element"`
		*alias
	}{
		alias: (*alias)(b),
	}

	if err := json.Unmarshal(data, &a); err != nil {
		return err
	}

	s := sumtype{}
	if err := json.Unmarshal(a.Element, &s); err != nil {
		return nil
	}

	var e BlockElement
	switch s.TypeVal {
	case "datepicker":
		e = &DatePickerBlockElement{}
	case "plain_text_input":
		e = &PlainTextInputBlockElement{}
	case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
		e = &SelectBlockElement{}
	default:
		return errors.New("unsupported block element type")
	}

	if err := json.Unmarshal(a.Element, e); err != nil {
		return err
	}
	b.Element = e

	return nil
}

// MarshalJSON implements the Marshaller interface for BlockElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b *BlockElements) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(b.ElementSet)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for BlockElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *BlockElements) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	var blockElements BlockElements
	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var blockElementType string
		if s.TypeVal != "" {
			blockElementType = s.TypeVal
		}

		var blockElement BlockElement
		switch blockElementType {
		case "image":
			blockElement = &ImageBlockElement{}
		case "button":
			blockElement = &ButtonBlockElement{}
		case "overflow":
			blockElement = &OverflowBlockElement{}
		case "datepicker":
			blockElement = &DatePickerBlockElement{}
		case "plain_text_input":
			blockElement = &PlainTextInputBlockElement{}
		case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
			blockElement = &SelectBlockElement{}
		default:
			return errors.New("unsupported block element type")
		}

		err = json.Unmarshal(r, blockElement)
		if err != nil {
			return err
		}

		blockElements.ElementSet = append(blockElements.ElementSet, blockElement)
	}

	*b = blockElements
	return nil
}

// MarshalJSON implements the Marshaller interface for Accessory so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (a *Accessory) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(toBlockElement(a))
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for Accessory, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (a *Accessory) UnmarshalJSON(data []byte) error {
	var r json.RawMessage

	if string(data) == "{\"accessory\":null}" {
		return nil
	}

	err := json.Unmarshal(data, &r)
	if err != nil {
		return err
	}

	s := sumtype{}
	err = json.Unmarshal(r, &s)
	if err != nil {
		return err
	}

	var blockElementType string
	if s.TypeVal != "" {
		blockElementType = s.TypeVal
	}

	switch blockElementType {
	case "image":
		element, err := unmarshalBlockElement(r, &ImageBlockElement{})
		if err != nil {
			return err
		}
		a.ImageElement = element.(*ImageBlockElement)
	case "button":
		element, err := unmarshalBlockElement(r, &ButtonBlockElement{})
		if err != nil {
			return err
		}
		a.ButtonElement = element.(*ButtonBlockElement)
	case "overflow":
		element, err := unmarshalBlockElement(r, &OverflowBlockElement{})
		if err != nil {
			return err
		}
		a.OverflowElement = element.(*OverflowBlockElement)
	case "datepicker":
		element, err := unmarshalBlockElement(r, &DatePickerBlockElement{})
		if err != nil {
			return err
		}
		a.DatePickerElement = element.(*DatePickerBlockElement)
	case "static_select":
		element, err := unmarshalBlockElement(r, &SelectBlockElement{})
		if err != nil {
			return err
		}
		a.SelectElement = element.(*SelectBlockElement)
	}

	return nil
}

func unmarshalBlockElement(r json.RawMessage, element BlockElement) (BlockElement, error) {
	err := json.Unmarshal(r, element)
	if err != nil {
		return nil, err
	}
	return element, nil
}

func toBlockElement(element *Accessory) BlockElement {
	if element.ImageElement != nil {
		return element.ImageElement
	}
	if element.ButtonElement != nil {
		return element.ButtonElement
	}
	if element.OverflowElement != nil {
		return element.OverflowElement
	}
	if element.DatePickerElement != nil {
		return element.DatePickerElement
	}
	if element.SelectElement != nil {
		return element.SelectElement
	}

	return nil
}

// MarshalJSON implements the Marshaller interface for ContextElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (e *ContextElements) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(e.Elements)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for ContextElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (e *ContextElements) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{\"elements\":null}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var contextElementType string
		if s.TypeVal != "" {
			contextElementType = s.TypeVal
		}

		switch contextElementType {
		case PlainTextType, MarkdownType:
			elem, err := unmarshalBlockObject(r, &TextBlockObject{})
			if err != nil {
				return err
			}

			e.Elements = append(e.Elements, elem.(*TextBlockObject))
		case "image":
			elem, err := unmarshalBlockElement(r, &ImageBlockElement{})
			if err != nil {
				return err
			}

			e.Elements = append(e.Elements, elem.(*ImageBlockElement))
		default:
			return errors.New("unsupported context element type")
		}
	}

	return nil
}
<commit_msg> fix unsupported block type Error by 'file' type block<commit_after>package slack

import (
	"encoding/json"

	"github.com/pkg/errors"
)

type sumtype struct {
	TypeVal string `json:"type"`
}

// MarshalJSON implements the Marshaller interface for Blocks so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b Blocks) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(b.BlockSet)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for Blocks, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *Blocks) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	var blocks Blocks
	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var blockType string
		if s.TypeVal != "" {
			blockType = s.TypeVal
		}

		var block Block
		switch blockType {
		case "actions":
			block = &ActionBlock{}
		case "context":
			block = &ContextBlock{}
		case "divider":
			block = &DividerBlock{}
		case "image":
			block = &ImageBlock{}
		case "input":
			block = &InputBlock{}
		case "section":
			block = &SectionBlock{}
		case "rich_text":
			// for now ignore the (complex) content of rich_text blocks until we can fully support it
			continue
		case "file":
			// for now ignore the file blocks until we can fully support it
			continue
		default:
			return errors.New("unsupported block type")
		}

		err = json.Unmarshal(r, block)
		if err != nil {
			return err
		}

		blocks.BlockSet = append(blocks.BlockSet, block)
	}

	*b = blocks
	return nil
}

// UnmarshalJSON implements the Unmarshaller interface for InputBlock, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *InputBlock) UnmarshalJSON(data []byte) error {
	type alias InputBlock
	a := struct {
		Element json.RawMessage `json:"element"`
		*alias
	}{
		alias: (*alias)(b),
	}

	if err := json.Unmarshal(data, &a); err != nil {
		return err
	}

	s := sumtype{}
	if err := json.Unmarshal(a.Element, &s); err != nil {
		return nil
	}

	var e BlockElement
	switch s.TypeVal {
	case "datepicker":
		e = &DatePickerBlockElement{}
	case "plain_text_input":
		e = &PlainTextInputBlockElement{}
	case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
		e = &SelectBlockElement{}
	default:
		return errors.New("unsupported block element type")
	}

	if err := json.Unmarshal(a.Element, e); err != nil {
		return err
	}
	b.Element = e

	return nil
}

// MarshalJSON implements the Marshaller interface for BlockElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (b *BlockElements) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(b.ElementSet)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for BlockElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (b *BlockElements) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	var blockElements BlockElements
	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var blockElementType string
		if s.TypeVal != "" {
			blockElementType = s.TypeVal
		}

		var blockElement BlockElement
		switch blockElementType {
		case "image":
			blockElement = &ImageBlockElement{}
		case "button":
			blockElement = &ButtonBlockElement{}
		case "overflow":
			blockElement = &OverflowBlockElement{}
		case "datepicker":
			blockElement = &DatePickerBlockElement{}
		case "plain_text_input":
			blockElement = &PlainTextInputBlockElement{}
		case "static_select", "external_select", "users_select", "conversations_select", "channels_select":
			blockElement = &SelectBlockElement{}
		default:
			return errors.New("unsupported block element type")
		}

		err = json.Unmarshal(r, blockElement)
		if err != nil {
			return err
		}

		blockElements.ElementSet = append(blockElements.ElementSet, blockElement)
	}

	*b = blockElements
	return nil
}

// MarshalJSON implements the Marshaller interface for Accessory so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (a *Accessory) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(toBlockElement(a))
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for Accessory, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (a *Accessory) UnmarshalJSON(data []byte) error {
	var r json.RawMessage

	if string(data) == "{\"accessory\":null}" {
		return nil
	}

	err := json.Unmarshal(data, &r)
	if err != nil {
		return err
	}

	s := sumtype{}
	err = json.Unmarshal(r, &s)
	if err != nil {
		return err
	}

	var blockElementType string
	if s.TypeVal != "" {
		blockElementType = s.TypeVal
	}

	switch blockElementType {
	case "image":
		element, err := unmarshalBlockElement(r, &ImageBlockElement{})
		if err != nil {
			return err
		}
		a.ImageElement = element.(*ImageBlockElement)
	case "button":
		element, err := unmarshalBlockElement(r, &ButtonBlockElement{})
		if err != nil {
			return err
		}
		a.ButtonElement = element.(*ButtonBlockElement)
	case "overflow":
		element, err := unmarshalBlockElement(r, &OverflowBlockElement{})
		if err != nil {
			return err
		}
		a.OverflowElement = element.(*OverflowBlockElement)
	case "datepicker":
		element, err := unmarshalBlockElement(r, &DatePickerBlockElement{})
		if err != nil {
			return err
		}
		a.DatePickerElement = element.(*DatePickerBlockElement)
	case "static_select":
		element, err := unmarshalBlockElement(r, &SelectBlockElement{})
		if err != nil {
			return err
		}
		a.SelectElement = element.(*SelectBlockElement)
	}

	return nil
}

func unmarshalBlockElement(r json.RawMessage, element BlockElement) (BlockElement, error) {
	err := json.Unmarshal(r, element)
	if err != nil {
		return nil, err
	}
	return element, nil
}

func toBlockElement(element *Accessory) BlockElement {
	if element.ImageElement != nil {
		return element.ImageElement
	}
	if element.ButtonElement != nil {
		return element.ButtonElement
	}
	if element.OverflowElement != nil {
		return element.OverflowElement
	}
	if element.DatePickerElement != nil {
		return element.DatePickerElement
	}
	if element.SelectElement != nil {
		return element.SelectElement
	}

	return nil
}

// MarshalJSON implements the Marshaller interface for ContextElements so that any JSON
// marshalling is delegated and proper type determination can be made before marshal
func (e *ContextElements) MarshalJSON() ([]byte, error) {
	bytes, err := json.Marshal(e.Elements)
	if err != nil {
		return nil, err
	}

	return bytes, nil
}

// UnmarshalJSON implements the Unmarshaller interface for ContextElements, so that any JSON
// unmarshalling is delegated and proper type determination can be made before unmarshal
func (e *ContextElements) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage

	if string(data) == "{\"elements\":null}" {
		return nil
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	for _, r := range raw {
		s := sumtype{}
		err := json.Unmarshal(r, &s)
		if err != nil {
			return err
		}

		var contextElementType string
		if s.TypeVal != "" {
			contextElementType = s.TypeVal
		}

		switch contextElementType {
		case PlainTextType, MarkdownType:
			elem, err := unmarshalBlockObject(r, &TextBlockObject{})
			if err != nil {
				return err
			}

			e.Elements = append(e.Elements, elem.(*TextBlockObject))
		case "image":
			elem, err := unmarshalBlockElement(r, &ImageBlockElement{})
			if err != nil {
				return err
			}

			e.Elements = append(e.Elements, elem.(*ImageBlockElement))
		default:
			return errors.New("unsupported context element type")
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package lib

import (
	"encoding/json"
	"net/url"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/gravitational/roundtrip"
	"github.com/gravitational/trace"
)

// GrafanaClient is Grafana HTTP API client
type GrafanaClient struct {
	*roundtrip.Client
}

// NewGrafanaClient returns a Grafana HTTP API client
func NewGrafanaClient() (*GrafanaClient, error) {
	username := os.Getenv(GrafanaUsernameEnv)
	if username == "" {
		return nil, trace.BadParameter("%s environment variable is not set", GrafanaUsernameEnv)
	}

	password := os.Getenv(GrafanaPasswordEnv)
	if password == "" {
		return nil, trace.BadParameter("%s environment variable is not set", GrafanaPasswordEnv)
	}

	client, err := roundtrip.NewClient(GrafanaAPIAddress, "", roundtrip.BasicAuth(username, password))
	if err != nil {
		return nil, trace.Wrap(err)
	}

	return &GrafanaClient{Client: client}, nil
}

// Health checks the status of Grafana HTTP API
func (c *GrafanaClient) Health() error {
	// use "home dashboard" API as a health check
	_, err := c.Get(c.Endpoint("api", "dashboards", "home"), url.Values{})
	if err != nil {
		return trace.Wrap(err)
	}
	return nil
}

// CreateDashboard creates a new dashboard from the provided dashboard data
func (c *GrafanaClient) CreateDashboard(data string) error {
	// dashboard data should be a valid JSON
	var dashboardJSON map[string]interface{}
	if err := json.Unmarshal([]byte(data), &dashboardJSON); err != nil {
		return trace.Wrap(err)
	}

	response, err := c.PostJSON(c.Endpoint("api", "dashboards", "db"), CreateDashboardRequest{
		Dashboard: dashboardJSON,
		overwrite: true,
	})
	if err != nil {
		return trace.Wrap(err)
	}

	log.Infof("%v", response)
	return nil
}

// CreateDashboardRequest is request to create a new dashboard
type CreateDashboardRequest struct {
	// Dashboard is the dashboard data
	Dashboard map[string]interface{} `json:"dashboard"`
	// Overwrite is whether to overwrite existing dashboard with newer version or with same dashboard title
	Overwrite bool `json:"overwrite"`
}
<commit_msg>Fixed typo<commit_after>package lib

import (
	"encoding/json"
	"net/url"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/gravitational/roundtrip"
	"github.com/gravitational/trace"
)

// GrafanaClient is Grafana HTTP API client
type GrafanaClient struct {
	*roundtrip.Client
}

// NewGrafanaClient returns a Grafana HTTP API client
func NewGrafanaClient() (*GrafanaClient, error) {
	username := os.Getenv(GrafanaUsernameEnv)
	if username == "" {
		return nil, trace.BadParameter("%s environment variable is not set", GrafanaUsernameEnv)
	}

	password := os.Getenv(GrafanaPasswordEnv)
	if password == "" {
		return nil, trace.BadParameter("%s environment variable is not set", GrafanaPasswordEnv)
	}

	client, err := roundtrip.NewClient(GrafanaAPIAddress, "", roundtrip.BasicAuth(username, password))
	if err != nil {
		return nil, trace.Wrap(err)
	}

	return &GrafanaClient{Client: client}, nil
}

// Health checks the status of Grafana HTTP API
func (c *GrafanaClient) Health() error {
	// use "home dashboard" API as a health check
	_, err := c.Get(c.Endpoint("api", "dashboards", "home"), url.Values{})
	if err != nil {
		return trace.Wrap(err)
	}
	return nil
}

// CreateDashboard creates a new dashboard from the provided dashboard data
func (c *GrafanaClient) CreateDashboard(data string) error {
	// dashboard data should be a valid JSON
	var dashboardJSON map[string]interface{}
	if err := json.Unmarshal([]byte(data), &dashboardJSON); err != nil {
		return trace.Wrap(err)
	}

	response, err := c.PostJSON(c.Endpoint("api", "dashboards", "db"), CreateDashboardRequest{
		Dashboard: dashboardJSON,
		Overwrite: true,
	})
	if err != nil {
		return trace.Wrap(err)
	}

	log.Infof("%v", response)
	return nil
}

// CreateDashboardRequest is request to create a new dashboard
type CreateDashboardRequest struct {
	// Dashboard is the dashboard data
	Dashboard map[string]interface{} `json:"dashboard"`
	// Overwrite is whether to overwrite existing dashboard with newer version or with same dashboard title
	Overwrite bool `json:"overwrite"`
}
<|endoftext|>


<commit_before>package web

import (
	"testing"
)

// To tell you the truth, I'm not actually sure how many of these cases are
// needed. Presumably someone with more patience than I could comb through
// http://golang.org/s/go11func and figure out what all the different cases I
// ought to test are, but I think this test includes all the cases I care about
// and is at least reasonably thorough.

func a() string {
	return "A"
}
func b() string {
	return "B"
}
func mkFn(s string) func() string {
	return func() string {
		return s
	}
}

var c = mkFn("C")
var d = mkFn("D")
var e = a
var f = c
var g = mkFn("D")

type Type string

func (t *Type) String() string {
	return string(*t)
}

var t1 = Type("hi")
var t2 = Type("bye")
var t1f = t1.String
var t2f = t2.String

var funcEqualTests = []struct {
	a, b   func() string
	result bool
}{
	{a, a, true},
	{a, b, false},
	{b, b, true},
	{a, c, false},
	{c, c, true},
	{c, d, false},
	{a, e, true},
	{a, f, false},
	{c, f, true},
	{e, f, false},
	{d, g, false},
	{t1f, t1f, true},
	{t1f, t2f, false},
}

func TestFuncEqual(t *testing.T) {
	t.Parallel()

	for _, test := range funcEqualTests {
		r := funcEqual(test.a, test.b)
		if r != test.result {
			t.Errorf("funcEqual(%v, %v) should have been %v",
				test.a, test.b, test.result)
		}
	}
	h := mkFn("H")
	i := h
	j := mkFn("H")
	k := a
	if !funcEqual(h, i) {
		t.Errorf("h and i should have been equal")
	}
	if funcEqual(h, j) {
		t.Errorf("h and j should not have been equal")
	}
	if !funcEqual(a, k) {
		t.Errorf("a and k should not have been equal")
	}
}
<commit_msg>Fix typo in a test error message<commit_after>package web

import (
	"testing"
)

// To tell you the truth, I'm not actually sure how many of these cases are
// needed. Presumably someone with more patience than I could comb through
// http://golang.org/s/go11func and figure out what all the different cases I
// ought to test are, but I think this test includes all the cases I care about
// and is at least reasonably thorough.

func a() string {
	return "A"
}
func b() string {
	return "B"
}
func mkFn(s string) func() string {
	return func() string {
		return s
	}
}

var c = mkFn("C")
var d = mkFn("D")
var e = a
var f = c
var g = mkFn("D")

type Type string

func (t *Type) String() string {
	return string(*t)
}

var t1 = Type("hi")
var t2 = Type("bye")
var t1f = t1.String
var t2f = t2.String

var funcEqualTests = []struct {
	a, b   func() string
	result bool
}{
	{a, a, true},
	{a, b, false},
	{b, b, true},
	{a, c, false},
	{c, c, true},
	{c, d, false},
	{a, e, true},
	{a, f, false},
	{c, f, true},
	{e, f, false},
	{d, g, false},
	{t1f, t1f, true},
	{t1f, t2f, false},
}

func TestFuncEqual(t *testing.T) {
	t.Parallel()

	for _, test := range funcEqualTests {
		r := funcEqual(test.a, test.b)
		if r != test.result {
			t.Errorf("funcEqual(%v, %v) should have been %v",
				test.a, test.b, test.result)
		}
	}
	h := mkFn("H")
	i := h
	j := mkFn("H")
	k := a
	if !funcEqual(h, i) {
		t.Errorf("h and i should have been equal")
	}
	if funcEqual(h, j) {
		t.Errorf("h and j should not have been equal")
	}
	if !funcEqual(a, k) {
		t.Errorf("a and k should have been equal")
	}
}
<|endoftext|>


<commit_before>// A Naive Bayesian Classifier
// Jake Brukhman <jbrukh@gmail.com>

//
// BAYESIAN CLASSIFICATION REFRESHER: suppose you have a set
// of classes (e.g. categories) C := {C_1, ..., C_n}, and a
// document D consisting of words D := {W_1, ..., W_k}.
// We wish to ascertain the probability that the document
// belongs to some class C_j given some set of training data
// associating documents and classes.
//
// By Bayes Theorem, we have that
//
//    P(C_j|D) = P(D|C_j)*P(C_j)/P(D).
//
// The LHS is the probability that the document belongs to class
// C_j given the document itself (by which is meant, in practice,
// the word frequencies occurring in this document), and our program
// will calculate this probability for each j and spit out the
// most likely class for this document.
//
// P(C_j) is referred to as the "prior" probability, or the
// probability that a document belongs to C_j in general, without
// seeing the document first. P(D|C_j) is the probability of seeing
// such a document, given that it belongs to C_j. Here, by assuming
// that words appear independently in documents (this being the
// "naive" assumption), we can estimate
//
//    P(D|C_j) ~= P(W_1|C_j)*...*P(W_k|C_j)
//
// where P(W_i|C_j) is the probability of seeing the given word
// in a document of the given class. Finally, P(D) can be seen as
// merely a scaling factor and is not strictly relevant to
// classificiation, unless you want to normalize the resulting
// scores and actually see probabilities. In this case, note that
//
//    P(D) = SUM_j(P(D|C_j)*P(C_j))
//
// One practical issue with performing these calculations is the
// possibility of float64 underflow when calculating P(D|C_j), as
// individual word probabilities can be arbitrarily small, and
// a document can have an arbitrarily large number of them. A
// typical method for dealing with this case is to transform the
// probability to the log domain and perform additions instead
// of multiplications:
//
//   log P(C_j|D) ~ log(P(C_j)) + SUM_i(log P(W_i|C_j))
//
// where i = 1, ..., k. Note that by doing this, we are discarding
// the scaling factor P(D) and our scores are no longer
// probabilities.
//
package bayesian

import "math"

// defaultProb is the tiny non-zero probability that a word
// we have not seen before appears in the class.
const defaultProb = 0.001

// This type defines a set of classes that the classifier will
// filter: C = {C_1, ..., C_n}. You should define your classes
// as a set of constants, for example as follows:
//
//    const (
//        Good Class = "Good"
//        Bad Class = "Bad
//    )
//
type Class string

// Classifier implements the Naive Bayesian Classifier.
type Classifier struct {
    Classes []Class
    datas map[Class]*classData
}

// classData holds the frequency data for words in a
// particular class. In the future, we may replace this
// structure with a trie-like structure for more
// efficient storage.
type classData struct {
    freqs map[string]int
    total int
}

// newClassData creates a new empty class data node.
func newClassData() *classData {
    return &classData{
        freqs: make(map[string]int),
    }
}

// P(W|Cj) -- the probability of seeing a particular word
// in a document of this class.
func (this *classData) getWordProb(word string) float64 {
    value, ok := this.freqs[word]
    if !ok {
        return defaultProb
    }
    return float64(value)/float64(this.total)
}

// P(D|C_j) -- the probability of seeing this set of words
// in a document of this class.
//
// Note that words should not be empty, and this method of
// calulation is prone to underflow if there are many words
// and their individual probabilties are small.
func (this *classData) getWordsProb(words []string) (prob float64) {
    prob = 1
    for _, word := range words {
        prob *= this.getWordProb(word)
    }
    return
}

// New creates a new Classifier.
func NewClassifier(classes ...Class) (inst *Classifier) {
    if len(classes) < 2 {
        panic("provide at least two classes")
    }
    inst = &Classifier{
            classes,
            make(map[Class]*classData),
    }
    for _, class := range classes {
        inst.datas[class] = newClassData()
    }
    return
}

// getPriors returns the prior probabilities for the
// classes provided -- P(C_i). There is a way to
// smooth priors, currently not implemented here.
func (this *Classifier) getPriors() (priors []float64) {
    n := len(this.Classes)
    priors = make([]float64, n, n)
    sum := 0
    for index, class := range this.Classes {
        total := this.datas[class].total;
        priors[index] = float64(total)
        sum += total
    }
    if sum != 0 {
        for i := 0; i < n; i++ {
            priors[i] /= float64(sum)
        }
    }
    return
}

// Learn will train the classifier on the provided data.
func (this *Classifier) Learn(words []string, which Class) {
    data := this.datas[which]
    for _, word := range words {
        data.freqs[word]++
        data.total++
    }
}

// Score will produce an array of scores that correspond
// to its opinion on the document in question, and whether it
// belongs to the given class. The order of the scores
// in the return values follows the order of the inital array
// of Class objects parameterized to the NewClassifier() function.
// If no training data has been provided, this will return
// a 0 array.
//
// The value of the score is proportional to the likelihood,
// even if the score is negative, so that the score with the
// greatest value corresponds to the most likely class.
//
// Additionally, this function will return the index of the
// maximum probability. The value of this number is given by
// scores[inx]. The class of that corresponds to this number
// is classifier.Classes[inx]. If more than one of the
// returned probabilities has the maximum values, then
// strict is false.
func (this *Classifier) Score(words []string) (scores []float64, inx int, strict bool) {
    n := len(this.Classes)
    scores = make([]float64, n, n)
    priors := this.getPriors()

    // calculate the score for each class
    for index, class := range this.Classes {
        data := this.datas[class]
        // this is the sum of the logarithms
        // as outlined in the refresher
        score := math.Log(priors[index])
        for _, word := range words {
            score += math.Log(data.getWordProb(word))
        }
        scores[index] = score
    }
    inx, strict = findMax(scores)
    return scores, inx, strict
}

// Probabilities works the same as Score, but delivers
// actual probabilities as discussed above. Note that float64
// underflow is possible if the word list contains too
// many words that have probabilities very close to 0.
func (this *Classifier) Probabilities(words []string) (scores []float64, inx int, strict bool) {
    n := len(this.Classes)
    scores = make([]float64, n, n)
    priors := this.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range this.Classes {
        data := this.datas[class]
        // this is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        for _, word := range words {
            score *= data.getWordProb(word)
        }
        scores[index] = score
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    return scores, inx, strict
}

func findMax(scores []float64) (inx int, strict bool) {
    inx = 0
    strict = true
    for i := 1; i < len(scores); i++ {
        if scores[inx] < scores[i] {
            inx = i
            strict = true
        } else if scores[inx] == scores[i] {
            strict = false
        }
    }
    return
}
<commit_msg>Added comment to findMax.<commit_after>// A Naive Bayesian Classifier
// Jake Brukhman <jbrukh@gmail.com>

//
// BAYESIAN CLASSIFICATION REFRESHER: suppose you have a set
// of classes (e.g. categories) C := {C_1, ..., C_n}, and a
// document D consisting of words D := {W_1, ..., W_k}.
// We wish to ascertain the probability that the document
// belongs to some class C_j given some set of training data
// associating documents and classes.
//
// By Bayes Theorem, we have that
//
//    P(C_j|D) = P(D|C_j)*P(C_j)/P(D).
//
// The LHS is the probability that the document belongs to class
// C_j given the document itself (by which is meant, in practice,
// the word frequencies occurring in this document), and our program
// will calculate this probability for each j and spit out the
// most likely class for this document.
//
// P(C_j) is referred to as the "prior" probability, or the
// probability that a document belongs to C_j in general, without
// seeing the document first. P(D|C_j) is the probability of seeing
// such a document, given that it belongs to C_j. Here, by assuming
// that words appear independently in documents (this being the
// "naive" assumption), we can estimate
//
//    P(D|C_j) ~= P(W_1|C_j)*...*P(W_k|C_j)
//
// where P(W_i|C_j) is the probability of seeing the given word
// in a document of the given class. Finally, P(D) can be seen as
// merely a scaling factor and is not strictly relevant to
// classificiation, unless you want to normalize the resulting
// scores and actually see probabilities. In this case, note that
//
//    P(D) = SUM_j(P(D|C_j)*P(C_j))
//
// One practical issue with performing these calculations is the
// possibility of float64 underflow when calculating P(D|C_j), as
// individual word probabilities can be arbitrarily small, and
// a document can have an arbitrarily large number of them. A
// typical method for dealing with this case is to transform the
// probability to the log domain and perform additions instead
// of multiplications:
//
//   log P(C_j|D) ~ log(P(C_j)) + SUM_i(log P(W_i|C_j))
//
// where i = 1, ..., k. Note that by doing this, we are discarding
// the scaling factor P(D) and our scores are no longer
// probabilities.
//
package bayesian

import "math"

// defaultProb is the tiny non-zero probability that a word
// we have not seen before appears in the class.
const defaultProb = 0.001

// This type defines a set of classes that the classifier will
// filter: C = {C_1, ..., C_n}. You should define your classes
// as a set of constants, for example as follows:
//
//    const (
//        Good Class = "Good"
//        Bad Class = "Bad
//    )
//
type Class string

// Classifier implements the Naive Bayesian Classifier.
type Classifier struct {
    Classes []Class
    datas map[Class]*classData
}

// classData holds the frequency data for words in a
// particular class. In the future, we may replace this
// structure with a trie-like structure for more
// efficient storage.
type classData struct {
    freqs map[string]int
    total int
}

// newClassData creates a new empty class data node.
func newClassData() *classData {
    return &classData{
        freqs: make(map[string]int),
    }
}

// P(W|Cj) -- the probability of seeing a particular word
// in a document of this class.
func (this *classData) getWordProb(word string) float64 {
    value, ok := this.freqs[word]
    if !ok {
        return defaultProb
    }
    return float64(value)/float64(this.total)
}

// P(D|C_j) -- the probability of seeing this set of words
// in a document of this class.
//
// Note that words should not be empty, and this method of
// calulation is prone to underflow if there are many words
// and their individual probabilties are small.
func (this *classData) getWordsProb(words []string) (prob float64) {
    prob = 1
    for _, word := range words {
        prob *= this.getWordProb(word)
    }
    return
}

// New creates a new Classifier.
func NewClassifier(classes ...Class) (inst *Classifier) {
    if len(classes) < 2 {
        panic("provide at least two classes")
    }
    inst = &Classifier{
            classes,
            make(map[Class]*classData),
    }
    for _, class := range classes {
        inst.datas[class] = newClassData()
    }
    return
}

// getPriors returns the prior probabilities for the
// classes provided -- P(C_i). There is a way to
// smooth priors, currently not implemented here.
func (this *Classifier) getPriors() (priors []float64) {
    n := len(this.Classes)
    priors = make([]float64, n, n)
    sum := 0
    for index, class := range this.Classes {
        total := this.datas[class].total;
        priors[index] = float64(total)
        sum += total
    }
    if sum != 0 {
        for i := 0; i < n; i++ {
            priors[i] /= float64(sum)
        }
    }
    return
}

// Learn will train the classifier on the provided data.
func (this *Classifier) Learn(words []string, which Class) {
    data := this.datas[which]
    for _, word := range words {
        data.freqs[word]++
        data.total++
    }
}

// Score will produce an array of scores that correspond
// to its opinion on the document in question, and whether it
// belongs to the given class. The order of the scores
// in the return values follows the order of the inital array
// of Class objects parameterized to the NewClassifier() function.
// If no training data has been provided, this will return
// a 0 array.
//
// The value of the score is proportional to the likelihood,
// even if the score is negative, so that the score with the
// greatest value corresponds to the most likely class.
//
// Additionally, this function will return the index of the
// maximum probability. The value of this number is given by
// scores[inx]. The class of that corresponds to this number
// is classifier.Classes[inx]. If more than one of the
// returned probabilities has the maximum values, then
// strict is false.
func (this *Classifier) Score(words []string) (scores []float64, inx int, strict bool) {
    n := len(this.Classes)
    scores = make([]float64, n, n)
    priors := this.getPriors()

    // calculate the score for each class
    for index, class := range this.Classes {
        data := this.datas[class]
        // this is the sum of the logarithms
        // as outlined in the refresher
        score := math.Log(priors[index])
        for _, word := range words {
            score += math.Log(data.getWordProb(word))
        }
        scores[index] = score
    }
    inx, strict = findMax(scores)
    return scores, inx, strict
}

// Probabilities works the same as Score, but delivers
// actual probabilities as discussed above. Note that float64
// underflow is possible if the word list contains too
// many words that have probabilities very close to 0.
func (this *Classifier) Probabilities(words []string) (scores []float64, inx int, strict bool) {
    n := len(this.Classes)
    scores = make([]float64, n, n)
    priors := this.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range this.Classes {
        data := this.datas[class]
        // this is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        for _, word := range words {
            score *= data.getWordProb(word)
        }
        scores[index] = score
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    return scores, inx, strict
}

// findMax finds the maximum of a set of scores; if the
// maximum is strict -- that is, it is the single unique
// maximum from the set -- then strict has return value
// true. Otherwise it is false.
func findMax(scores []float64) (inx int, strict bool) {
    inx = 0
    strict = true
    for i := 1; i < len(scores); i++ {
        if scores[inx] < scores[i] {
            inx = i
            strict = true
        } else if scores[inx] == scores[i] {
            strict = false
        }
    }
    return
}
<|endoftext|>