<commit_before>package main

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"

	"time"

	"strings"

	"github.com/claudetech/loggo"
	. "github.com/claudetech/loggo/default"
	flag "github.com/ogier/pflag"
	"golang.org/x/sys/unix"
)

func main() {
	// get the users home dir
	user, err := user.Current()
	if nil != err {
		panic(fmt.Sprintf("Could not read users homedir %v\n", err))
	}

	// parse the command line arguments
	argLogLevel := flag.IntP("verbosity", "v", 0, "Set the log level (0 = error, 1 = warn, 2 = info, 3 = debug, 4 = trace)")
	argConfigPath := flag.StringP("config", "c", filepath.Join(user.HomeDir, ".plexdrive"), "The path to the configuration directory")
	argTempPath := flag.StringP("temp", "t", os.TempDir(), "Path to a temporary directory to store temporary data")
	argChunkSize := flag.Int64("chunk-size", 5*1024*1024, "The size of each chunk that is downloaded (in byte)")
	argRefreshInterval := flag.Duration("refresh-interval", 5*time.Minute, "The time to wait till checking for changes")
	argClearInterval := flag.Duration("clear-chunk-interval", 1*time.Minute, "The time to wait till clearing the chunk directory")
	argClearChunkAge := flag.Duration("clear-chunk-age", 30*time.Minute, "The maximum age of a cached chunk file")
	argMountOptions := flag.StringP("fuse-options", "o", "", "Fuse mount options (e.g. -fuse-options allow_other,...)")
	argVersion := flag.Bool("version", false, "Displays program's version information")
	argUID := flag.Int64("uid", -1, "Set the mounts UID (-1 = default permissions)")
	argGID := flag.Int64("gid", -1, "Set the mounts GID (-1 = default permissions)")
	flag.Parse()

	// display version information
	if *argVersion {
		fmt.Println("2.0.0")
		return
	}

	// check if mountpoint is specified
	argMountPoint := flag.Arg(0)
	if "" == argMountPoint {
		flag.Usage()
		panic(fmt.Errorf("Mountpoint not specified"))
	}

	// calculate uid / gid
	uid := uint32(unix.Geteuid())
	gid := uint32(unix.Getegid())
	if *argUID > -1 {
		uid = uint32(*argUID)
	}
	if *argGID > -1 {
		gid = uint32(*argGID)
	}

	// parse the mount options
	var mountOptions []string
	if "" != *argMountOptions {
		mountOptions = strings.Split(*argMountOptions, ",")
	}

	// initialize the logger with the specific log level
	var logLevel loggo.Level
	switch *argLogLevel {
	case 0:
		logLevel = loggo.Error
	case 1:
		logLevel = loggo.Warning
	case 2:
		logLevel = loggo.Info
	case 3:
		logLevel = loggo.Debug
	case 4:
		logLevel = loggo.Trace
	default:
		logLevel = loggo.Warning
	}
	Log.SetLevel(logLevel)

	// debug all given parameters
	Log.Debugf("log-level            : %v", logLevel)
	Log.Debugf("config               : %v", *argConfigPath)
	Log.Debugf("temp                 : %v", *argTempPath)
	Log.Debugf("chunk-size           : %v", *argChunkSize)
	Log.Debugf("refresh-interval     : %v", *argRefreshInterval)
	Log.Debugf("clear-chunk-interval : %v", *argClearInterval)
	Log.Debugf("fuse-options         : %v", *argMountOptions)
	Log.Debugf("UID                  : %v", uid)
	Log.Debugf("GID                  : %v", gid)

	// create all directories
	if err := os.MkdirAll(*argConfigPath, 0766); nil != err {
		Log.Errorf("Could not create configuration directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}
	chunkPath := filepath.Join(*argTempPath, "chunks")
	if err := os.MkdirAll(chunkPath, 0777); nil != err {
		Log.Errorf("Could not create temp chunk directory")
		Log.Debugf("%v", err)
		os.Exit(2)
	}

	// set the global buffer configuration
	SetChunkPath(chunkPath)
	SetChunkSize(*argChunkSize)

	// read the configuration
	configPath := filepath.Join(*argConfigPath, "config.json")
	config, err := ReadConfig(configPath)
	if nil != err {
		config, err = CreateConfig(configPath)
		if nil != err {
			Log.Errorf("Could not read configuration")
			Log.Debugf("%v", err)
			os.Exit(3)
		}
	}

	cache, err := NewCache(*argConfigPath, *argLogLevel > 3)
	if nil != err {
		Log.Errorf("Could not initialize cache")
		Log.Debugf("%v", err)
		os.Exit(4)
	}
	defer cache.Close()

	drive, err := NewDriveClient(config, cache, *argRefreshInterval)
	if nil != err {
		Log.Errorf("Could not initialize Google Drive Client")
		Log.Debugf("%v", err)
		os.Exit(5)
	}

	go CleanChunkDir(chunkPath, *argClearInterval, *argClearChunkAge)
	if err := Mount(drive, argMountPoint, mountOptions, uid, gid); nil != err {
		Log.Debugf("%v", err)
		os.Exit(6)
	}
}
<commit_msg>fixed logging output<commit_after>package main

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"

	"time"

	"strings"

	"github.com/claudetech/loggo"
	. "github.com/claudetech/loggo/default"
	flag "github.com/ogier/pflag"
	"golang.org/x/sys/unix"
)

func main() {
	// get the users home dir
	user, err := user.Current()
	if nil != err {
		panic(fmt.Sprintf("Could not read users homedir %v\n", err))
	}

	// parse the command line arguments
	argLogLevel := flag.IntP("verbosity", "v", 0, "Set the log level (0 = error, 1 = warn, 2 = info, 3 = debug, 4 = trace)")
	argConfigPath := flag.StringP("config", "c", filepath.Join(user.HomeDir, ".plexdrive"), "The path to the configuration directory")
	argTempPath := flag.StringP("temp", "t", os.TempDir(), "Path to a temporary directory to store temporary data")
	argChunkSize := flag.Int64("chunk-size", 5*1024*1024, "The size of each chunk that is downloaded (in byte)")
	argRefreshInterval := flag.Duration("refresh-interval", 5*time.Minute, "The time to wait till checking for changes")
	argClearInterval := flag.Duration("clear-chunk-interval", 1*time.Minute, "The time to wait till clearing the chunk directory")
	argClearChunkAge := flag.Duration("clear-chunk-age", 30*time.Minute, "The maximum age of a cached chunk file")
	argMountOptions := flag.StringP("fuse-options", "o", "", "Fuse mount options (e.g. -fuse-options allow_other,...)")
	argVersion := flag.Bool("version", false, "Displays program's version information")
	argUID := flag.Int64("uid", -1, "Set the mounts UID (-1 = default permissions)")
	argGID := flag.Int64("gid", -1, "Set the mounts GID (-1 = default permissions)")
	flag.Parse()

	// display version information
	if *argVersion {
		fmt.Println("2.0.0")
		return
	}

	// check if mountpoint is specified
	argMountPoint := flag.Arg(0)
	if "" == argMountPoint {
		flag.Usage()
		panic(fmt.Errorf("Mountpoint not specified"))
	}

	// calculate uid / gid
	uid := uint32(unix.Geteuid())
	gid := uint32(unix.Getegid())
	if *argUID > -1 {
		uid = uint32(*argUID)
	}
	if *argGID > -1 {
		gid = uint32(*argGID)
	}

	// parse the mount options
	var mountOptions []string
	if "" != *argMountOptions {
		mountOptions = strings.Split(*argMountOptions, ",")
	}

	// initialize the logger with the specific log level
	var logLevel loggo.Level
	switch *argLogLevel {
	case 0:
		logLevel = loggo.Error
	case 1:
		logLevel = loggo.Warning
	case 2:
		logLevel = loggo.Info
	case 3:
		logLevel = loggo.Debug
	case 4:
		logLevel = loggo.Trace
	default:
		logLevel = loggo.Warning
	}
	Log.SetLevel(logLevel)

	// debug all given parameters
	Log.Debugf("verbosity            : %v", logLevel)
	Log.Debugf("config               : %v", *argConfigPath)
	Log.Debugf("temp                 : %v", *argTempPath)
	Log.Debugf("chunk-size           : %v", *argChunkSize)
	Log.Debugf("refresh-interval     : %v", *argRefreshInterval)
	Log.Debugf("clear-chunk-interval : %v", *argClearInterval)
	Log.Debugf("clear-chunk-age      : %v", *argClearChunkAge)
	Log.Debugf("fuse-options         : %v", *argMountOptions)
	Log.Debugf("UID                  : %v", uid)
	Log.Debugf("GID                  : %v", gid)
	// version missing here

	// create all directories
	if err := os.MkdirAll(*argConfigPath, 0766); nil != err {
		Log.Errorf("Could not create configuration directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}
	chunkPath := filepath.Join(*argTempPath, "chunks")
	if err := os.MkdirAll(chunkPath, 0777); nil != err {
		Log.Errorf("Could not create temp chunk directory")
		Log.Debugf("%v", err)
		os.Exit(2)
	}

	// set the global buffer configuration
	SetChunkPath(chunkPath)
	SetChunkSize(*argChunkSize)

	// read the configuration
	configPath := filepath.Join(*argConfigPath, "config.json")
	config, err := ReadConfig(configPath)
	if nil != err {
		config, err = CreateConfig(configPath)
		if nil != err {
			Log.Errorf("Could not read configuration")
			Log.Debugf("%v", err)
			os.Exit(3)
		}
	}

	cache, err := NewCache(*argConfigPath, *argLogLevel > 3)
	if nil != err {
		Log.Errorf("Could not initialize cache")
		Log.Debugf("%v", err)
		os.Exit(4)
	}
	defer cache.Close()

	drive, err := NewDriveClient(config, cache, *argRefreshInterval)
	if nil != err {
		Log.Errorf("Could not initialize Google Drive Client")
		Log.Debugf("%v", err)
		os.Exit(5)
	}

	go CleanChunkDir(chunkPath, *argClearInterval, *argClearChunkAge)
	if err := Mount(drive, argMountPoint, mountOptions, uid, gid); nil != err {
		Log.Debugf("%v", err)
		os.Exit(6)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/util"
)

const Version = "0.2.0.0"

func main() {
	var (
		hflag = flag.Bool("h", false, "help")
		sflag = flag.String("s", "localhost:8088", "address of api server")
		wflag = flag.String("w", "localhost:8089", "address of wallet api server")
		rpcUserflag     = flag.String("rpcuser", "", "Username for JSON-RPC connections")
		rpcPasswordflag = flag.String("rpcpassword", "", "Password for JSON-RPC connections")
	)
	flag.Parse()

	filename := util.ConfigFilename()
	cfg := util.ReadConfig(filename).Rpc
	if *rpcUserflag == "" {
		*rpcUserflag = cfg.RpcUser
	}
	if *rpcPasswordflag == "" {
		*rpcPasswordflag = cfg.RpcPass
	}
	if *rpcUserflag == "" || *rpcPasswordflag == "" {
		fmt.Println("Rpc user and password were not set. use both -rpcuser and -rpcpassword or config file")
	}

	args := flag.Args()

	if *hflag {
		args = []string{"help"}
	}
	factom.SetFactomdServer(*sflag)
	factom.SetWalletServer(*wflag)
	factom.SetRpcConfig(*rpcUserflag, *rpcPasswordflag)
	c := cli.New()
	c.Handle("help", help)
	c.Handle("ack", ack)
	c.Handle("addchain", addchain)
	c.Handle("addentry", addentry)
	c.Handle("backupwallet", backupwallet)
	c.Handle("balance", balance)
	c.Handle("ecrate", ecrate)
	c.Handle("exportaddresses", exportaddresses)
	c.Handle("get", get)
	c.Handle("importaddress", importaddresses)
	c.Handle("importwords", importwords)
	c.Handle("listaddresses", listaddresses)
	c.Handle("newecaddress", newecaddress)
	c.Handle("newfctaddress", newfctaddress)
	c.Handle("properties", properties)
	c.Handle("receipt", receipt)
	c.Handle("backupwallet", backupwallet)

	// transaction commands
	c.Handle("newtx", newtx)
	c.Handle("rmtx", rmtx)
	c.Handle("listtxs", listtxs)
	c.Handle("addtxinput", addtxinput)
	c.Handle("addtxoutput", addtxoutput)
	c.Handle("addtxecoutput", addtxecoutput)
	c.Handle("addtxfee", addtxfee)
	c.Handle("subtxfee", subtxfee)
	c.Handle("signtx", signtx)
	c.Handle("composetx", composetx)
	c.Handle("sendtx", sendtx)
	c.Handle("sendfct", sendfct)
	c.Handle("buyec", buyec)

	c.HandleDefault(help)
	c.Execute(args)
}

func errorln(a ...interface{}) (n int, err error) {
	return fmt.Fprintln(os.Stderr, a...)
}
<commit_msg>go fmt<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/util"
)

const Version = "0.2.0.0"

func main() {
	var (
		hflag           = flag.Bool("h", false, "help")
		sflag           = flag.String("s", "localhost:8088", "address of api server")
		wflag           = flag.String("w", "localhost:8089", "address of wallet api server")
		rpcUserflag     = flag.String("rpcuser", "", "Username for JSON-RPC connections")
		rpcPasswordflag = flag.String("rpcpassword", "", "Password for JSON-RPC connections")
	)
	flag.Parse()

	filename := util.ConfigFilename()
	cfg := util.ReadConfig(filename).Rpc
	if *rpcUserflag == "" {
		*rpcUserflag = cfg.RpcUser
	}
	if *rpcPasswordflag == "" {
		*rpcPasswordflag = cfg.RpcPass
	}
	if *rpcUserflag == "" || *rpcPasswordflag == "" {
		fmt.Println("Rpc user and password were not set. use both -rpcuser and -rpcpassword or config file")
	}

	args := flag.Args()

	if *hflag {
		args = []string{"help"}
	}
	factom.SetFactomdServer(*sflag)
	factom.SetWalletServer(*wflag)
	factom.SetRpcConfig(*rpcUserflag, *rpcPasswordflag)
	c := cli.New()
	c.Handle("help", help)
	c.Handle("ack", ack)
	c.Handle("addchain", addchain)
	c.Handle("addentry", addentry)
	c.Handle("backupwallet", backupwallet)
	c.Handle("balance", balance)
	c.Handle("ecrate", ecrate)
	c.Handle("exportaddresses", exportaddresses)
	c.Handle("get", get)
	c.Handle("importaddress", importaddresses)
	c.Handle("importwords", importwords)
	c.Handle("listaddresses", listaddresses)
	c.Handle("newecaddress", newecaddress)
	c.Handle("newfctaddress", newfctaddress)
	c.Handle("properties", properties)
	c.Handle("receipt", receipt)
	c.Handle("backupwallet", backupwallet)

	// transaction commands
	c.Handle("newtx", newtx)
	c.Handle("rmtx", rmtx)
	c.Handle("listtxs", listtxs)
	c.Handle("addtxinput", addtxinput)
	c.Handle("addtxoutput", addtxoutput)
	c.Handle("addtxecoutput", addtxecoutput)
	c.Handle("addtxfee", addtxfee)
	c.Handle("subtxfee", subtxfee)
	c.Handle("signtx", signtx)
	c.Handle("composetx", composetx)
	c.Handle("sendtx", sendtx)
	c.Handle("sendfct", sendfct)
	c.Handle("buyec", buyec)

	c.HandleDefault(help)
	c.Execute(args)
}

func errorln(a ...interface{}) (n int, err error) {
	return fmt.Fprintln(os.Stderr, a...)
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Aya Tokikaze
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	flags "github.com/jessevdk/go-flags"
)

const (
	cliName        = "oui"
	cliDescription = "search vender information for OUI(Organizationally Unique Identifier)"
	version        = "v0.2.1"
)

// MAC stract is MAC Address date format
type MAC struct {
	Registry   string
	Hex        string
	OrgName    string
	OrgAddress string
}

// Flags is list options
type Flags struct {
	Verbose bool `short:"v" long:"verbose" description:"print detailed information"`
	Input   bool `short:"i" long:"input" description:"use standard input"`
	Version bool `long:"version" description:"print oui version"`
}

func main() {

	var flag Flags
	var mac string
	var res MAC

	sc := bufio.NewScanner(os.Stdin)
	f := flags.NewParser(&flag, flags.Default)
	f.Name = "oui"
	f.Usage = "<ADDRESS> [OPTION]"

	args, _ := f.Parse()

	if flag.Version {
		fmt.Printf("%s version %s\n", cliName, version)
		os.Exit(0)
	}

	if len(args) == 0 {
		if os.Args[1] == "-h" {
			os.Exit(0)
		}
		if !flag.Input {
			f.WriteHelp(os.Stdout)
			os.Exit(1)
		}
	}

	data := InitMalData()

	if flag.Input && sc.Scan() {
		mac = sc.Text()
	} else {
		mac = args[0]
	}

	mac = strings.Replace(mac, ":", "", -1)
	mac = strings.Replace(mac, "-", "", -1)

	for i := range data {
		if data[i].Hex == strings.ToUpper(mac[0:6]) {
			res = data[i]
			break
		}
	}

	if flag.Verbose {
		split := []string{mac[0:2], mac[2:4], mac[4:6]}
		fmt.Printf("OUI/%s :      %s\nOrganization :  %s\nAddress :       %s\n", res.Registry, strings.Join(split, "-"), res.OrgName, res.OrgAddress)
	} else {
		fmt.Println(res.OrgName)
	}
}
<commit_msg>Clean code<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Aya Tokikaze
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	flags "github.com/jessevdk/go-flags"
)

const (
	cliName        = "oui"
	cliDescription = "search vender information for OUI(Organizationally Unique Identifier)"
	version        = "v0.3.0-dev"
)

// MAC stract is MAC Address date format
type MAC struct {
	Registry   string
	Hex        string
	OrgName    string
	OrgAddress string
}

// list options
type Options struct {
	Verbose bool `short:"v" long:"verbose" description:"print detailed information"`
	Input   bool `short:"i" long:"input" description:"use standard input"`
	Version bool `long:"version" description:"print oui version"`
	Org     bool `short:"o" long:"org" description:"search organization to OUI"`
}

func main() {

	var opt Options
	var mac string
	var res MAC

	sc := bufio.NewScanner(os.Stdin)
	f := flags.NewParser(&opt, flags.Default)
	f.Name = "oui"
	f.Usage = "<ADDRESS> [OPTION]"

	args, _ := f.Parse()

	if opt.Version {
		fmt.Printf("%s version %s\n", cliName, version)
		os.Exit(0)
	}

	if len(args) == 0 {
		if os.Args[1] == "-h" {
			os.Exit(0)
		}
		if !opt.Input {
			f.WriteHelp(os.Stdout)
			os.Exit(1)
		}
	}

	data := InitMalData()

	if opt.Input && sc.Scan() {
		mac = sc.Text()
	} else {
		mac = args[0]
	}

	mac = strings.Replace(mac, ":", "", -1)
	mac = strings.Replace(mac, "-", "", -1)

	for i := range data {
		if data[i].Hex == strings.ToUpper(mac[0:6]) {
			res = data[i]
			break
		}
	}

	if opt.Verbose {
		split := []string{mac[0:2], mac[2:4], mac[4:6]}
		fmt.Printf("OUI/%s :      %s\n", res.Registry, strings.Join(split, "-"))
		fmt.Printf("Organization :  %s\n", res.OrgName)
		fmt.Printf("Address :       %s\n", res.OrgAddress)
	} else {
		fmt.Println(res.OrgName)
	}
}
<|endoftext|>


<commit_before>package mpb

import (
	"context"
	"errors"
	"io"
	"log"
	"os"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/cwriter"
)

var logger = log.New(os.Stderr, "mpb: ", log.LstdFlags|log.Lshortfile)

// ErrCallAfterStop thrown by panic, if Progress methods like AddBar() are called
// after Stop() has been called
var ErrCallAfterStop = errors.New("method call on stopped Progress instance")

type (
	// BeforeRender is a func, which gets called before render process
	BeforeRender func([]*Bar)
	barOpType    uint

	operation struct {
		kind   barOpType
		bar    *Bar
		result chan bool
	}

	indexedBarBuffer struct {
		index int
		buf   []byte
	}

	indexedBar struct {
		index     int
		termWidth int
		bar       *Bar
	}
)

const (
	barAdd barOpType = iota
	barRemove
)

const (
	// default RefreshRate
	rr = 100
	// number of format runes for bar
	numFmtRunes = 5
)

// Progress represents the container that renders Progress bars
type Progress struct {
	// Context for canceling bars rendering
	ctx context.Context
	// WaitGroup for internal rendering sync
	wg *sync.WaitGroup

	out    io.Writer
	width  int
	format string

	operationCh    chan *operation
	rrChangeReqCh  chan time.Duration
	outChangeReqCh chan io.Writer
	barCountReqCh  chan chan int
	brCh           chan BeforeRender
	done           chan struct{}
}

// New creates new Progress instance, which will orchestrate bars rendering
// process. It acceepts context.Context, for cancellation.
// If you don't plan to cancel, it is safe to feed with nil
func New(ctx context.Context) *Progress {
	if ctx == nil {
		ctx = context.Background()
	}
	p := &Progress{
		width:          70,
		operationCh:    make(chan *operation),
		rrChangeReqCh:  make(chan time.Duration),
		outChangeReqCh: make(chan io.Writer),
		barCountReqCh:  make(chan chan int),
		brCh:           make(chan BeforeRender),
		done:           make(chan struct{}),
		wg:             new(sync.WaitGroup),
		ctx:            ctx,
	}
	go p.server(cwriter.New(os.Stdout), time.NewTicker(rr*time.Millisecond))
	return p
}

// SetWidth sets the width for all underlying bars
func (p *Progress) SetWidth(n int) *Progress {
	if n <= 0 {
		return p
	}
	p.width = n
	return p
}

// SetOut sets underlying writer of progress. Default is os.Stdout
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) SetOut(w io.Writer) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	if w == nil {
		return p
	}
	p.outChangeReqCh <- w
	return p
}

// RefreshRate overrides default (30ms) refreshRate value
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) RefreshRate(d time.Duration) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	p.rrChangeReqCh <- d
	return p
}

func (p *Progress) BeforeRenderFunc(f BeforeRender) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	p.brCh <- f
	return p
}

// AddBar creates a new progress bar and adds to the container
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) AddBar(total int64) *Bar {
	return p.AddBarWithID(0, total)
}

// AddBarWithID creates a new progress bar and adds to the container
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) AddBarWithID(id int, total int64) *Bar {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	result := make(chan bool)
	bar := newBar(p.ctx, p.wg, id, total, p.width, p.format)
	p.operationCh <- &operation{barAdd, bar, result}
	if <-result {
		p.wg.Add(1)
	}
	return bar
}

// RemoveBar removes bar at any time
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) RemoveBar(b *Bar) bool {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	result := make(chan bool)
	p.operationCh <- &operation{barRemove, b, result}
	return <-result
}

// BarCount returns bars count in the container.
// Pancis if called on stopped Progress instance, i.e after Stop()
func (p *Progress) BarCount() int {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	respCh := make(chan int)
	p.barCountReqCh <- respCh
	return <-respCh
}

// Format sets custom format for underlying bar(s).
// The default one is "[=>-]"
func (p *Progress) Format(format string) *Progress {
	if utf8.RuneCountInString(format) != numFmtRunes {
		return p
	}
	p.format = format
	return p
}

// Stop waits for bars to finish rendering and stops the rendering goroutine
func (p *Progress) Stop() {
	p.wg.Wait()
	if IsClosed(p.done) {
		return
	}
	close(p.operationCh)
}

// server monitors underlying channels and renders any progress bars
func (p *Progress) server(cw *cwriter.Writer, t *time.Ticker) {
	defer func() {
		t.Stop()
		close(p.done)
	}()
	const numDrawers = 3
	bars := make([]*Bar, 0, 4)
	var beforeRender BeforeRender
	var wg sync.WaitGroup
	recoverIfPanic := func() {
		if e := recover(); e != nil {
			logger.Printf("unexpected panic: %+v\n", e)
		}
		wg.Done()
	}
	for {
		select {
		case w := <-p.outChangeReqCh:
			cw.Flush()
			cw = cwriter.New(w)
		case op, ok := <-p.operationCh:
			if !ok {
				return
			}
			switch op.kind {
			case barAdd:
				bars = append(bars, op.bar)
				op.result <- true
			case barRemove:
				var ok bool
				for i, b := range bars {
					if b == op.bar {
						bars = append(bars[:i], bars[i+1:]...)
						ok = true
						b.remove()
						break
					}
				}
				op.result <- ok
			}
		case respCh := <-p.barCountReqCh:
			respCh <- len(bars)
		case beforeRender = <-p.brCh:
		case <-t.C:
			if beforeRender != nil {
				beforeRender(bars)
			}

			width, _, _ := cwriter.GetTermSize()
			ibars := iBarsGen(bars, width)
			c := make(chan indexedBarBuffer)
			wg.Add(numDrawers)
			for i := 0; i < numDrawers; i++ {
				go func() {
					defer recoverIfPanic()
					drawer(ibars, c)
				}()
			}
			go func() {
				wg.Wait()
				close(c)
			}()

			m := make(map[int][]byte, len(bars))
			for r := range c {
				m[r.index] = r.buf
			}
			for i := 0; i < len(bars); i++ {
				cw.Write(m[i])
			}

			cw.Flush()

			for _, b := range bars {
				b.flushed()
			}
		case d := <-p.rrChangeReqCh:
			t.Stop()
			t = time.NewTicker(d)
		case <-p.ctx.Done():
			return
		}
	}
}

func drawer(ibars <-chan indexedBar, c chan<- indexedBarBuffer) {
	for b := range ibars {
		buf := b.bar.bytes(b.termWidth)
		buf = append(buf, '\n')
		c <- indexedBarBuffer{b.index, buf}
	}
}

func iBarsGen(bars []*Bar, width int) <-chan indexedBar {
	ibars := make(chan indexedBar)
	go func() {
		defer close(ibars)
		for i, b := range bars {
			ibars <- indexedBar{i, width, b}
		}
	}()
	return ibars
}

// IsClosed check if ch closed
// caution see: http://www.tapirgames.com/blog/golang-channel-closing
func IsClosed(ch <-chan struct{}) bool {
	select {
	case <-ch:
		return true
	default:
		return false
	}
}
<commit_msg>doc comments update<commit_after>package mpb

import (
	"context"
	"errors"
	"io"
	"log"
	"os"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/vbauerster/mpb/cwriter"
)

var logger = log.New(os.Stderr, "mpb: ", log.LstdFlags|log.Lshortfile)

// ErrCallAfterStop thrown by panic, if Progress methods like AddBar() are called
// after Stop() has been called
var ErrCallAfterStop = errors.New("method call on stopped Progress instance")

type (
	// BeforeRender is a func, which gets called before render process
	BeforeRender func([]*Bar)
	barOpType    uint

	operation struct {
		kind   barOpType
		bar    *Bar
		result chan bool
	}

	indexedBarBuffer struct {
		index int
		buf   []byte
	}

	indexedBar struct {
		index     int
		termWidth int
		bar       *Bar
	}
)

const (
	barAdd barOpType = iota
	barRemove
)

const (
	// default RefreshRate
	rr = 100
	// number of format runes for bar
	numFmtRunes = 5
)

// Progress represents the container that renders Progress bars
type Progress struct {
	// Context for canceling bars rendering
	ctx context.Context
	// WaitGroup for internal rendering sync
	wg *sync.WaitGroup

	out    io.Writer
	width  int
	format string

	operationCh    chan *operation
	rrChangeReqCh  chan time.Duration
	outChangeReqCh chan io.Writer
	barCountReqCh  chan chan int
	brCh           chan BeforeRender
	done           chan struct{}
}

// New creates new Progress instance, which will orchestrate bars rendering
// process. It acceepts context.Context, for cancellation.
// If you don't plan to cancel, it is safe to feed with nil
func New(ctx context.Context) *Progress {
	if ctx == nil {
		ctx = context.Background()
	}
	p := &Progress{
		width:          70,
		operationCh:    make(chan *operation),
		rrChangeReqCh:  make(chan time.Duration),
		outChangeReqCh: make(chan io.Writer),
		barCountReqCh:  make(chan chan int),
		brCh:           make(chan BeforeRender),
		done:           make(chan struct{}),
		wg:             new(sync.WaitGroup),
		ctx:            ctx,
	}
	go p.server(cwriter.New(os.Stdout), time.NewTicker(rr*time.Millisecond))
	return p
}

// SetWidth overrides default (70) width of bar(s)
func (p *Progress) SetWidth(n int) *Progress {
	if n <= 0 {
		return p
	}
	p.width = n
	return p
}

// SetOut sets underlying writer of progress. Default is os.Stdout
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) SetOut(w io.Writer) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	if w == nil {
		return p
	}
	p.outChangeReqCh <- w
	return p
}

// RefreshRate overrides default (100ms) refresh rate value
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) RefreshRate(d time.Duration) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	p.rrChangeReqCh <- d
	return p
}

func (p *Progress) BeforeRenderFunc(f BeforeRender) *Progress {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	p.brCh <- f
	return p
}

// AddBar creates a new progress bar and adds to the container
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) AddBar(total int64) *Bar {
	return p.AddBarWithID(0, total)
}

// AddBarWithID creates a new progress bar and adds to the container
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) AddBarWithID(id int, total int64) *Bar {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	result := make(chan bool)
	bar := newBar(p.ctx, p.wg, id, total, p.width, p.format)
	p.operationCh <- &operation{barAdd, bar, result}
	if <-result {
		p.wg.Add(1)
	}
	return bar
}

// RemoveBar removes bar at any time
// pancis, if called on stopped Progress instance, i.e after Stop()
func (p *Progress) RemoveBar(b *Bar) bool {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	result := make(chan bool)
	p.operationCh <- &operation{barRemove, b, result}
	return <-result
}

// BarCount returns bars count in the container.
// Pancis if called on stopped Progress instance, i.e after Stop()
func (p *Progress) BarCount() int {
	if IsClosed(p.done) {
		panic(ErrCallAfterStop)
	}
	respCh := make(chan int)
	p.barCountReqCh <- respCh
	return <-respCh
}

// Format sets custom format for underlying bar(s).
// The default one is "[=>-]"
func (p *Progress) Format(format string) *Progress {
	if utf8.RuneCountInString(format) != numFmtRunes {
		return p
	}
	p.format = format
	return p
}

// Stop waits for bars to finish rendering and stops the rendering goroutine
func (p *Progress) Stop() {
	p.wg.Wait()
	if IsClosed(p.done) {
		return
	}
	close(p.operationCh)
}

// server monitors underlying channels and renders any progress bars
func (p *Progress) server(cw *cwriter.Writer, t *time.Ticker) {
	defer func() {
		t.Stop()
		close(p.done)
	}()
	const numDrawers = 3
	bars := make([]*Bar, 0, 4)
	var beforeRender BeforeRender
	var wg sync.WaitGroup
	recoverIfPanic := func() {
		if e := recover(); e != nil {
			logger.Printf("unexpected panic: %+v\n", e)
		}
		wg.Done()
	}
	for {
		select {
		case w := <-p.outChangeReqCh:
			cw.Flush()
			cw = cwriter.New(w)
		case op, ok := <-p.operationCh:
			if !ok {
				return
			}
			switch op.kind {
			case barAdd:
				bars = append(bars, op.bar)
				op.result <- true
			case barRemove:
				var ok bool
				for i, b := range bars {
					if b == op.bar {
						bars = append(bars[:i], bars[i+1:]...)
						ok = true
						b.remove()
						break
					}
				}
				op.result <- ok
			}
		case respCh := <-p.barCountReqCh:
			respCh <- len(bars)
		case beforeRender = <-p.brCh:
		case <-t.C:
			if beforeRender != nil {
				beforeRender(bars)
			}

			width, _, _ := cwriter.GetTermSize()
			ibars := iBarsGen(bars, width)
			c := make(chan indexedBarBuffer)
			wg.Add(numDrawers)
			for i := 0; i < numDrawers; i++ {
				go func() {
					defer recoverIfPanic()
					drawer(ibars, c)
				}()
			}
			go func() {
				wg.Wait()
				close(c)
			}()

			m := make(map[int][]byte, len(bars))
			for r := range c {
				m[r.index] = r.buf
			}
			for i := 0; i < len(bars); i++ {
				cw.Write(m[i])
			}

			cw.Flush()

			for _, b := range bars {
				b.flushed()
			}
		case d := <-p.rrChangeReqCh:
			t.Stop()
			t = time.NewTicker(d)
		case <-p.ctx.Done():
			return
		}
	}
}

func drawer(ibars <-chan indexedBar, c chan<- indexedBarBuffer) {
	for b := range ibars {
		buf := b.bar.bytes(b.termWidth)
		buf = append(buf, '\n')
		c <- indexedBarBuffer{b.index, buf}
	}
}

func iBarsGen(bars []*Bar, width int) <-chan indexedBar {
	ibars := make(chan indexedBar)
	go func() {
		defer close(ibars)
		for i, b := range bars {
			ibars <- indexedBar{i, width, b}
		}
	}()
	return ibars
}

// IsClosed check if ch closed
// caution see: http://www.tapirgames.com/blog/golang-channel-closing
func IsClosed(ch <-chan struct{}) bool {
	select {
	case <-ch:
		return true
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/tcnksm/go-gitconfig"
)

//go:generate go-bindata _templates/...

const (
	defaultVCS = "github.com"
	modelDir   = "models"
	outDir     = "controllers"
	targetFile = "main.go"
)

func usage() {
	fmt.Fprintf(os.Stderr, `Usage of %s:
	%s new <project name>
	%s gen`,
		os.Args[0], os.Args[0], os.Args[0])
	os.Exit(1)
}

func main() {

	if len(os.Args) < 2 {
		usage()
	}

	cmd := os.Args[1]

	switch cmd {
	case "gen":

		if !fileExists(targetFile) || !fileExists(modelDir) {
			fmt.Println("Error: Not found 'main.go'. Please move project root.")
			os.Exit(1)
		}
		cmdGen()

	case "new":
		var (
			vcs      string
			username string
		)

		flag := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

		flag.Usage = func() {
			fmt.Fprintf(os.Stderr, `Usage of %s:
	%s new <project name>

Options:
`, os.Args[0], os.Args[0])
			flag.PrintDefaults()
		}

		flag.StringVar(&vcs, "v", "", "VCS")
		flag.StringVar(&username, "u", "", "Username")

		if len(os.Args) < 3 {
			flag.Usage()
			os.Exit(1)
		}

		flag.Parse(os.Args[3:])

		if vcs == "" {
			vcs = defaultVCS
		}

		if username == "" {
			var err error
			username, err = gitconfig.GithubUser()

			if err != nil {
				username, err = gitconfig.Username()
				if err != nil {
					msg := "Cannot find `~/.gitconfig` file.\n" +
						"Please use -u option"
					fmt.Println(msg)
					os.Exit(1)
				}
			}
		}

		project := os.Args[2]

		detail := &Detail{VCS: vcs, User: username, Project: project}

		cmdNew(detail)

	default:
		usage()
	}

}

func cmdNew(detail *Detail) {
	gopath := os.Getenv("GOPATH")

	if gopath == "" {
		fmt.Println("Error: $GOPATH is not found")
		os.Exit(1)
	}

	outDir := filepath.Join(gopath, "src", detail.VCS, detail.User, detail.Project)

	if err := generateSkeleton(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func cmdGen() {
	if !fileExists(outDir) {
		if err := mkdir(outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

	files, err := ioutil.ReadDir(modelDir)

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	var models []*Model

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		if !strings.HasSuffix(file.Name(), ".go") {
			continue
		}

		modelPath := filepath.Join(modelDir, file.Name())
		ms, err := parseModel(modelPath)

		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		for _, model := range ms {
			models = append(models, model)
		}
	}

	paths, err := parseMain(targetFile)

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	importDir := formatImportDir(paths)

	if len(importDir) > 1 {
		fmt.Println("Error: Conflict import path. Please check 'main.go'.")
		os.Exit(1)
	}

	detail := &Detail{Models: models, ImportDir: importDir[0]}

	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	for _, model := range models {
		detail := &Detail{Model: model, ImportDir: importDir[0]}
		if err := generateController(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

	if err := generateREADME(models, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func formatImportDir(paths []string) []string {
	results := make([]string, 0, len(paths))
	flag := map[string]bool{}
	for i := 0; i < len(paths); i++ {
		dir := filepath.Dir(paths[i])
		if !flag[dir] {
			flag[dir] = true
			results = append(results, dir)
		}
	}
	return results
}
<commit_msg>Add error handling case<commit_after>package main

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

	"github.com/tcnksm/go-gitconfig"
)

//go:generate go-bindata _templates/...

const (
	defaultVCS = "github.com"
	modelDir   = "models"
	outDir     = "controllers"
	targetFile = "main.go"
)

func usage() {
	fmt.Fprintf(os.Stderr, `Usage of %s:
	%s new <project name>
	%s gen`,
		os.Args[0], os.Args[0], os.Args[0])
	os.Exit(1)
}

func main() {

	if len(os.Args) < 2 {
		usage()
	}

	cmd := os.Args[1]

	switch cmd {
	case "gen":

		if !fileExists(targetFile) || !fileExists(modelDir) {
			fmt.Println("Error: Not found 'main.go'. Please move project root.")
			os.Exit(1)
		}
		cmdGen()

	case "new":
		var (
			vcs      string
			username string
		)

		flag := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

		flag.Usage = func() {
			fmt.Fprintf(os.Stderr, `Usage of %s:
	%s new <project name>

Options:
`, os.Args[0], os.Args[0])
			flag.PrintDefaults()
		}

		flag.StringVar(&vcs, "v", "", "VCS")
		flag.StringVar(&username, "u", "", "Username")

		if len(os.Args) < 3 {
			flag.Usage()
			os.Exit(1)
		}

		flag.Parse(os.Args[3:])

		if vcs == "" {
			vcs = defaultVCS
		}

		if username == "" {
			var err error
			username, err = gitconfig.GithubUser()

			if err != nil {
				username, err = gitconfig.Username()
				if err != nil {
					msg := "Cannot find `~/.gitconfig` file.\n" +
						"Please use -u option"
					fmt.Println(msg)
					os.Exit(1)
				}
			}
		}

		project := os.Args[2]

		detail := &Detail{VCS: vcs, User: username, Project: project}

		cmdNew(detail)

	default:
		usage()
	}

}

func cmdNew(detail *Detail) {
	gopath := os.Getenv("GOPATH")

	if gopath == "" {
		fmt.Println("Error: $GOPATH is not found")
		os.Exit(1)
	}

	outDir := filepath.Join(gopath, "src", detail.VCS, detail.User, detail.Project)

	if err := generateSkeleton(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func cmdGen() {
	if !fileExists(outDir) {
		if err := mkdir(outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

	files, err := ioutil.ReadDir(modelDir)

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	var models []*Model

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		if !strings.HasSuffix(file.Name(), ".go") {
			continue
		}

		modelPath := filepath.Join(modelDir, file.Name())
		ms, err := parseModel(modelPath)

		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		for _, model := range ms {
			models = append(models, model)
		}
	}

	paths, err := parseMain(targetFile)

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	importDir := formatImportDir(paths)

	switch {
	case len(importDir) > 1:
		fmt.Println("Error: Conflict import path. Please check 'main.go'.")
		os.Exit(1)

	case len(importDir) == 0:
		fmt.Println("Error: Can't refer import path. Please check 'main.go'.")
		os.Exit(1)
	}

	detail := &Detail{Models: models, ImportDir: importDir[0]}

	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	for _, model := range models {
		detail := &Detail{Model: model, ImportDir: importDir[0]}
		if err := generateController(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

	if err := generateREADME(models, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func formatImportDir(paths []string) []string {
	results := make([]string, 0, len(paths))
	flag := map[string]bool{}
	for i := 0; i < len(paths); i++ {
		dir := filepath.Dir(paths[i])
		if !flag[dir] {
			flag[dir] = true
			results = append(results, dir)
		}
	}
	return results
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/NoahShen/gotunnelme/src/gotunnelme" // for tunneling
	"github.com/fatih/color"
	"github.com/gorilla/mux"
)

const (
	headerEvent     = "X-GitHub-Event"  // HTTP header where the webhook event is stored
	headerSignature = "X-Hub-Signature" // HTTP header where the sha1 signature of the payload is stored
)

var (
	config            = tomlConfig{} // the program config
	verbose           = false        // weither we should log the output of the command
	verboseTunnel     = false        // weither we should log the output of the tunneling
	configFile        = ""
	gitHubSecretToken = os.Getenv("GITHUB_HOOK_SECRET_TOKEN") // the webhook secret token, used to verify signature
)

// HookHandler receive hooks from GitHub.
func HookHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	// read the HTTP request body
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintln(os.Stderr, color.RedString("Error: "+err.Error()))
		BadRequestHandler(w, r)
		return
	}

	// validate signature
	if gitHubSecretToken != "" {
		sign := r.Header.Get(headerSignature)

		// to compute the HMAC in order to check for equality with what has been sent by GitHub
		mac := hmac.New(sha1.New, []byte(gitHubSecretToken))
		mac.Write(payload)
		expectedHash := hex.EncodeToString(mac.Sum(nil))
		receivedHash := sign[5:] // remove 'sha1='

		// signature mismatch, do not process
		if !hmac.Equal([]byte(receivedHash), []byte(expectedHash)) {
			color.Set(color.FgRed)
			fmt.Fprintf(os.Stderr, "Mismatch between expected (%s) and received (%s) hash.", expectedHash, receivedHash)
			color.Set(color.Faint)
			BadRequestHandler(w, r)
			return
		}
	}

	var eventPayload HookWithRepository
	json.Unmarshal(payload, &eventPayload)

	// verify that this is an event that we should process
	// event := r.Header.Get(headerEvent)
	event := eventPayload.EventName
	if event == "ping" {
		return // always respond 200 to pings
	}

	// check whether we're interested in that event
	if shouldHandleEvent(config.Events, event, eventPayload) {
		handleEvent(event, eventPayload, []byte(payload))
	} else {
		if verbose {
			color.Set(color.FgRed)
			fmt.Fprintf(os.Stderr, "Discarding %s on %s with ref %s.\n",
				color.CyanString(event), color.YellowString(eventPayload.Project.PathWithNamespace), color.YellowString(eventPayload.Ref))
			color.Set(color.Faint)
			BadRequestHandler(w, r)
			return // 400 Bad Request
		}
	}

}

func shouldHandleEvent(events map[string]event, event string, eventPayload HookWithRepository) bool {
	if _, ok := events[event+":"+eventPayload.Project.PathWithNamespace+":"+eventPayload.Ref]; ok {
		return true
	} else if _, ok := events[event+":"+eventPayload.Project.PathWithNamespace+":all"]; ok {
		return true
	}
	return false
}

// handleEvent handles any event.
func handleEvent(event string, hook HookWithRepository, payload []byte) {
	// show related commits if push event
	if event == "push" {
		var pushEvent HookPush
		json.Unmarshal(payload, &pushEvent)
		fmt.Println(event, "detected on", color.YellowString(hook.Project.PathWithNamespace),
			"with ref", color.YellowString(hook.Ref), "with the following commits:")
		for _, commit := range pushEvent.Commits {
			fmt.Printf("\t%s - %s by %s\n", commit.Timestamp, color.CyanString(commit.Message), color.BlueString(commit.Author.Name))
		}
	}

	// prepare the command
	eventKey := event + ":" + hook.Project.PathWithNamespace + ":" + hook.Ref
	if _, ok := config.Events[eventKey]; !ok {
		eventKey = event + ":" + hook.Project.PathWithNamespace + ":all"
	}
	cmd := exec.Command(config.Events[eventKey].Cmd,
		strings.Split(config.Events[eventKey].Args, " ")...)

	// in case of -verbose we log the output of the executed command
	if verbose {
		cmdReader, err := cmd.StdoutPipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err)
			return
		}
		scanner := bufio.NewScanner(cmdReader)
		go func() {
			for scanner.Scan() {
				color.White("> " + scanner.Text() + "\n")
			}
		}()
		cmdReader, err = cmd.StderrPipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error creating StderrPipe for Cmd", err)
			return
		}
		scanner = bufio.NewScanner(cmdReader)
		go func() {
			for scanner.Scan() {
				color.Yellow("> " + scanner.Text() + "\n")
			}
		}()
	}

	// launch it
	err := cmd.Start()
	if err != nil {
		color.Set(color.FgRed)
		fmt.Fprintln(os.Stderr, "Error starting Cmd", err)
		color.Set(color.Faint)
		return
	}
}

// BadRequestHandler handles bad requests. Status 400 and JSON error message.
func BadRequestHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Write([]byte(`{"message": "I don't know what you're talking about"}`))
}

// HeyHandler handles GET request on /.
func HeyHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(`Hey, what's up?`))
}

func main() {
	flag.BoolVar(&verbose, "v", false, "Whether we output stuff.")
	flag.BoolVar(&verboseTunnel, "vt", false, "Whether we output stuff regarding tunneling.")
	flag.StringVar(&configFile, "c", "", "config file to load other than ./config.toml")
	flag.Parse()

	// load the config.toml
	config = loadConfig()
	addr := config.Addr + ":" + strconv.Itoa(config.Port)
	color.White(`    __
   / /_  ____ __________  ____  ____  ____
  / __ \/ __ ` + "`" + `/ ___/ __ \/ __ \/ __ \/ __ \
 / / / / /_/ / /  / /_/ / /_/ / /_/ / / / /
/_/ /_/\__,_/_/  / .___/\____/\____/_/ /_/
                /_/                        ab
`)
	color.White("\tListening on " + addr)
	readyToListen := false

	if config.Tunnel {
		if verboseTunnel {
			gotunnelme.Debug = true
		}
		tunnel := gotunnelme.NewTunnel()
		url, err := tunnel.GetUrl(config.TunnelName)
		if err != nil {
			panic("Could not get localtunnel.me URL. " + err.Error())
		}
		go func() {
			for !readyToListen {
				time.Sleep(1 * time.Second)
			}
			color.Cyan("\tTunnel URL: " + url)
			err := tunnel.CreateTunnel(config.Port)
			if err != nil {
				panic("Could not create tunnel. " + err.Error())
			}
		}()
	}

	// router & server
	r := mux.NewRouter()
	r.HandleFunc("/", HookHandler).Methods("POST")
	r.HandleFunc("/", HeyHandler).Methods("GET")
	readyToListen = true
	http.ListenAndServe(addr, r)
}
<commit_msg>try to match all repos<commit_after>package main

import (
	"bufio"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/NoahShen/gotunnelme/src/gotunnelme" // for tunneling
	"github.com/fatih/color"
	"github.com/gorilla/mux"
)

const (
	headerEvent     = "X-GitHub-Event"  // HTTP header where the webhook event is stored
	headerSignature = "X-Hub-Signature" // HTTP header where the sha1 signature of the payload is stored
)

var (
	config            = tomlConfig{} // the program config
	verbose           = false        // weither we should log the output of the command
	verboseTunnel     = false        // weither we should log the output of the tunneling
	configFile        = ""
	gitHubSecretToken = os.Getenv("GITHUB_HOOK_SECRET_TOKEN") // the webhook secret token, used to verify signature
)

// HookHandler receive hooks from GitHub.
func HookHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	// read the HTTP request body
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintln(os.Stderr, color.RedString("Error: "+err.Error()))
		BadRequestHandler(w, r)
		return
	}

	// validate signature
	if gitHubSecretToken != "" {
		sign := r.Header.Get(headerSignature)

		// to compute the HMAC in order to check for equality with what has been sent by GitHub
		mac := hmac.New(sha1.New, []byte(gitHubSecretToken))
		mac.Write(payload)
		expectedHash := hex.EncodeToString(mac.Sum(nil))
		receivedHash := sign[5:] // remove 'sha1='

		// signature mismatch, do not process
		if !hmac.Equal([]byte(receivedHash), []byte(expectedHash)) {
			color.Set(color.FgRed)
			fmt.Fprintf(os.Stderr, "Mismatch between expected (%s) and received (%s) hash.", expectedHash, receivedHash)
			color.Set(color.Faint)
			BadRequestHandler(w, r)
			return
		}
	}

	var eventPayload HookWithRepository
	json.Unmarshal(payload, &eventPayload)

	// verify that this is an event that we should process
	// event := r.Header.Get(headerEvent)
	event := eventPayload.EventName
	if event == "ping" {
		return // always respond 200 to pings
	}

	// check whether we're interested in that event
	if shouldHandleEvent(config.Events, event, eventPayload) {
		handleEvent(event, eventPayload, []byte(payload))
	} else {
		if verbose {
			color.Set(color.FgRed)
			fmt.Fprintf(os.Stderr, "Discarding %s on %s with ref %s.\n",
				color.CyanString(event), color.YellowString(eventPayload.Project.PathWithNamespace), color.YellowString(eventPayload.Ref))
			color.Set(color.Faint)
			BadRequestHandler(w, r)
			return // 400 Bad Request
		}
	}

}

func shouldHandleEvent(events map[string]event, event string, eventPayload HookWithRepository) bool {
	if _, ok := events[event+":"+eventPayload.Project.PathWithNamespace+":"+eventPayload.Ref]; ok {
		return true
	} else if _, ok := events[event+":"+eventPayload.Project.PathWithNamespace+":all"]; ok {
		return true
	} else if _, ok := events[event+":all:all"]; ok {
		return true
	}
	return false
}

// handleEvent handles any event.
func handleEvent(event string, hook HookWithRepository, payload []byte) {
	// show related commits if push event
	if event == "push" {
		var pushEvent HookPush
		json.Unmarshal(payload, &pushEvent)
		fmt.Println(event, "detected on", color.YellowString(hook.Project.PathWithNamespace),
			"with ref", color.YellowString(hook.Ref), "with the following commits:")
		for _, commit := range pushEvent.Commits {
			fmt.Printf("\t%s - %s by %s\n", commit.Timestamp, color.CyanString(commit.Message), color.BlueString(commit.Author.Name))
		}
	}

	// prepare the command
	eventKey := event + ":" + hook.Project.PathWithNamespace + ":" + hook.Ref
	if _, ok := config.Events[eventKey]; !ok {
		eventKey = event + ":" + hook.Project.PathWithNamespace + ":all"
	}
	cmd := exec.Command(config.Events[eventKey].Cmd,
		strings.Split(config.Events[eventKey].Args, " ")...)

	// in case of -verbose we log the output of the executed command
	if verbose {
		cmdReader, err := cmd.StdoutPipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err)
			return
		}
		scanner := bufio.NewScanner(cmdReader)
		go func() {
			for scanner.Scan() {
				color.White("> " + scanner.Text() + "\n")
			}
		}()
		cmdReader, err = cmd.StderrPipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error creating StderrPipe for Cmd", err)
			return
		}
		scanner = bufio.NewScanner(cmdReader)
		go func() {
			for scanner.Scan() {
				color.Yellow("> " + scanner.Text() + "\n")
			}
		}()
	}

	// launch it
	err := cmd.Start()
	if err != nil {
		color.Set(color.FgRed)
		fmt.Fprintln(os.Stderr, "Error starting Cmd", err)
		color.Set(color.Faint)
		return
	}
}

// BadRequestHandler handles bad requests. Status 400 and JSON error message.
func BadRequestHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Write([]byte(`{"message": "I don't know what you're talking about"}`))
}

// HeyHandler handles GET request on /.
func HeyHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write([]byte(`Hey, what's up?`))
}

func main() {
	flag.BoolVar(&verbose, "v", false, "Whether we output stuff.")
	flag.BoolVar(&verboseTunnel, "vt", false, "Whether we output stuff regarding tunneling.")
	flag.StringVar(&configFile, "c", "", "config file to load other than ./config.toml")
	flag.Parse()

	// load the config.toml
	config = loadConfig()
	addr := config.Addr + ":" + strconv.Itoa(config.Port)
	color.White(`    __
   / /_  ____ __________  ____  ____  ____
  / __ \/ __ ` + "`" + `/ ___/ __ \/ __ \/ __ \/ __ \
 / / / / /_/ / /  / /_/ / /_/ / /_/ / / / /
/_/ /_/\__,_/_/  / .___/\____/\____/_/ /_/
                /_/                        v2
`)
	color.White("\tListening on " + addr)
	readyToListen := false

	if config.Tunnel {
		if verboseTunnel {
			gotunnelme.Debug = true
		}
		tunnel := gotunnelme.NewTunnel()
		url, err := tunnel.GetUrl(config.TunnelName)
		if err != nil {
			panic("Could not get localtunnel.me URL. " + err.Error())
		}
		go func() {
			for !readyToListen {
				time.Sleep(1 * time.Second)
			}
			color.Cyan("\tTunnel URL: " + url)
			err := tunnel.CreateTunnel(config.Port)
			if err != nil {
				panic("Could not create tunnel. " + err.Error())
			}
		}()
	}

	// router & server
	r := mux.NewRouter()
	r.HandleFunc("/", HookHandler).Methods("POST")
	r.HandleFunc("/", HeyHandler).Methods("GET")
	readyToListen = true
	http.ListenAndServe(addr, r)
}
<|endoftext|>


<commit_before>// Package limitedstore implements a simple wrapper around existing
// datastores (tusd.DataStore) while limiting the used storage size.
// It will start terminating existing uploads if not enough space is left in
// order to create a new upload.
// This package's functionality is very limited and naive. It will terminate
// uploads whether they are finished yet or not and it won't terminate them
// intelligently (e.g. bigger uploads first). Only one datastore is allowed to
// access the underlying storage else the limited store will not function
// properly. Two tusd.FileStore instances using the same directory, for example.
// In addition the limited store will keep a list of the uploads' ids in memory
// which may create a growing memory leak.
package limitedstore

import (
	"github.com/tus/tusd"
	"sync"
  "sort"
)

type LimitedStore struct {
	StoreSize int64
	tusd.DataStore

	uploads  map[string]int64
	usedSize int64

	mutex *sync.Mutex
}

// pair structure to perform map-sorting
type pair struct {
  key string
  value int64
}

type pairlist []pair

func (p pairlist) Len() int           { return len(p) }
func (p pairlist) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
func (p pairlist) Less(i, j int) bool  { return p[i].value < p[j].value }

// Create a new limited store with the given size as the maximum storage size
func New(storeSize int64, dataStore tusd.DataStore) *LimitedStore {
	return &LimitedStore{
		StoreSize: storeSize,
		DataStore: dataStore,
		uploads:   make(map[string]int64),
		mutex:     new(sync.Mutex),
	}
}

func (store *LimitedStore) NewUpload(info tusd.FileInfo) (string, error) {
	store.mutex.Lock()
	defer store.mutex.Unlock()

	if err := store.ensureSpace(info.Size); err != nil {
		return "", err
	}

	id, err := store.DataStore.NewUpload(info)
	if err != nil {
		return "", err
	}

	store.usedSize += info.Size
	store.uploads[id] = info.Size

	return id, nil
}

func (store *LimitedStore) Terminate(id string) error {
	store.mutex.Lock()
	defer store.mutex.Unlock()

	return store.terminate(id)
}

func (store *LimitedStore) terminate(id string) error {
	err := store.DataStore.Terminate(id)
	if err != nil {
		return err
	}

	size := store.uploads[id]
	delete(store.uploads, id)
	store.usedSize -= size

	return nil
}

// Ensure enough space is available to store an upload of the specified size.
// It will terminate uploads until enough space is freed.
func (store *LimitedStore) ensureSpace(size int64) error {
	if (store.usedSize + size) <= store.StoreSize {
		// Enough space is available to store the new upload
		return nil
	}
  sorted_uploads := make(pairlist, len(store.uploads))
  i := 0
  for u,h := range store.uploads {
    sorted_uploads[i] = pair{u, h}
    i++
  }
  sort.Sort(sort.Reverse(sorted_uploads))

  // Forward traversal through the
  // uploads in terms of size, biggest upload first
  for _,k := range sorted_uploads {
    id := k.key
		if err := store.terminate(id); err != nil {
			return err
		}

		if (store.usedSize + size) <= store.StoreSize {
			// Enough space has been freed to store the new upload
			return nil
		}
	}

	return nil
}
<commit_msg>Add documentation for order of termination<commit_after>// Package limitedstore implements a simple wrapper around existing
// datastores (tusd.DataStore) while limiting the used storage size.
// It will start terminating existing uploads if not enough space is left in
// order to create a new upload.
// The order in which the uploads will be terminated is defined by their size,
// whereas the biggest ones are deleted first.
// This package's functionality is very limited and naive. It will terminate
// uploads whether they are finished yet or not. Only one datastore is allowed to
// access the underlying storage else the limited store will not function
// properly. Two tusd.FileStore instances using the same directory, for example.
// In addition the limited store will keep a list of the uploads' IDs in memory
// which may create a growing memory leak.
package limitedstore

import (
	"github.com/tus/tusd"
	"sync"
  "sort"
)

type LimitedStore struct {
	StoreSize int64
	tusd.DataStore

	uploads  map[string]int64
	usedSize int64

	mutex *sync.Mutex
}

// pair structure to perform map-sorting
type pair struct {
  key string
  value int64
}

type pairlist []pair

func (p pairlist) Len() int           { return len(p) }
func (p pairlist) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
func (p pairlist) Less(i, j int) bool  { return p[i].value < p[j].value }

// Create a new limited store with the given size as the maximum storage size
func New(storeSize int64, dataStore tusd.DataStore) *LimitedStore {
	return &LimitedStore{
		StoreSize: storeSize,
		DataStore: dataStore,
		uploads:   make(map[string]int64),
		mutex:     new(sync.Mutex),
	}
}

func (store *LimitedStore) NewUpload(info tusd.FileInfo) (string, error) {
	store.mutex.Lock()
	defer store.mutex.Unlock()

	if err := store.ensureSpace(info.Size); err != nil {
		return "", err
	}

	id, err := store.DataStore.NewUpload(info)
	if err != nil {
		return "", err
	}

	store.usedSize += info.Size
	store.uploads[id] = info.Size

	return id, nil
}

func (store *LimitedStore) Terminate(id string) error {
	store.mutex.Lock()
	defer store.mutex.Unlock()

	return store.terminate(id)
}

func (store *LimitedStore) terminate(id string) error {
	err := store.DataStore.Terminate(id)
	if err != nil {
		return err
	}

	size := store.uploads[id]
	delete(store.uploads, id)
	store.usedSize -= size

	return nil
}

// Ensure enough space is available to store an upload of the specified size.
// It will terminate uploads until enough space is freed.
func (store *LimitedStore) ensureSpace(size int64) error {
	if (store.usedSize + size) <= store.StoreSize {
		// Enough space is available to store the new upload
		return nil
	}
  sorted_uploads := make(pairlist, len(store.uploads))
  i := 0
  for u,h := range store.uploads {
    sorted_uploads[i] = pair{u, h}
    i++
  }
  sort.Sort(sort.Reverse(sorted_uploads))

  // Forward traversal through the
  // uploads in terms of size, biggest upload first
  for _,k := range sorted_uploads {
    id := k.key
		if err := store.terminate(id); err != nil {
			return err
		}

		if (store.usedSize + size) <= store.StoreSize {
			// Enough space has been freed to store the new upload
			return nil
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package bild

import "image"

// Add returns an image with the added color values of two images
func Add(a image.Image, b image.Image) *image.RGBA {
	// Currently only equal size images are supported
	if a.Bounds() != b.Bounds() {
		panic("only equal size images are supported")
	}

	bounds := a.Bounds()
	srcA := CloneAsRGBA(a)
	srcB := CloneAsRGBA(b)

	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y

	parallelize(h, func(start, end int) {
		for x := 0; x < w; x++ {
			for y := start; y < end; y++ {
				pos := y*dst.Stride + x*4

				r0 := float64(srcA.Pix[pos+0])
				g0 := float64(srcA.Pix[pos+1])
				b0 := float64(srcA.Pix[pos+2])
				a0 := float64(srcA.Pix[pos+3])

				r1 := float64(srcB.Pix[pos+0])
				g1 := float64(srcB.Pix[pos+1])
				b1 := float64(srcB.Pix[pos+2])
				a1 := float64(srcB.Pix[pos+3])

				dst.Pix[pos+0] = uint8(clampFloat64(r0+r1, 0, 255))
				dst.Pix[pos+1] = uint8(clampFloat64(g0+g1, 0, 255))
				dst.Pix[pos+2] = uint8(clampFloat64(b0+b1, 0, 255))
				dst.Pix[pos+3] = uint8(clampFloat64(a0+a1, 0, 255))
			}
		}
	})

	return dst
}

// Multiply returns an image with the normalized color values of two images multiplied
func Multiply(a image.Image, b image.Image) *image.RGBA {
	// Currently only equal size images are supported
	if a.Bounds() != b.Bounds() {
		panic("only equal size images are supported")
	}

	bounds := a.Bounds()
	srcA := CloneAsRGBA(a)
	srcB := CloneAsRGBA(b)

	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y

	parallelize(h, func(start, end int) {
		for x := 0; x < w; x++ {
			for y := start; y < end; y++ {
				pos := y*dst.Stride + x*4

				r0 := float64(srcA.Pix[pos+0]) / 255
				g0 := float64(srcA.Pix[pos+1]) / 255
				b0 := float64(srcA.Pix[pos+2]) / 255
				a0 := float64(srcA.Pix[pos+3]) / 255

				r1 := float64(srcB.Pix[pos+0]) / 255
				g1 := float64(srcB.Pix[pos+1]) / 255
				b1 := float64(srcB.Pix[pos+2]) / 255
				a1 := float64(srcB.Pix[pos+3]) / 255

				dst.Pix[pos+0] = uint8(r0 * r1 * 255)
				dst.Pix[pos+1] = uint8(g0 * g1 * 255)
				dst.Pix[pos+2] = uint8(b0 * b1 * 255)
				dst.Pix[pos+3] = uint8(a0 * a1 * 255)
			}
		}
	})

	return dst
}

// Overlay returns an image that combines Multiply and Screen blend modes
func Overlay(a image.Image, b image.Image) *image.RGBA {
	// Currently only equal size images are supported
	if a.Bounds() != b.Bounds() {
		panic("only equal size images are supported")
	}

	bounds := a.Bounds()
	srcA := CloneAsRGBA(a)
	srcB := CloneAsRGBA(b)

	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y

	parallelize(h, func(start, end int) {
		for x := 0; x < w; x++ {
			for y := start; y < end; y++ {
				pos := y*dst.Stride + x*4

				r0 := float64(srcA.Pix[pos+0]) / 255
				g0 := float64(srcA.Pix[pos+1]) / 255
				b0 := float64(srcA.Pix[pos+2]) / 255
				a0 := float64(srcA.Pix[pos+3]) / 255

				r1 := float64(srcB.Pix[pos+0]) / 255
				g1 := float64(srcB.Pix[pos+1]) / 255
				b1 := float64(srcB.Pix[pos+2]) / 255
				a1 := float64(srcB.Pix[pos+3]) / 255

				if 0.3*r0+0.6*g0+0.1*b0 < 0.5 {
					dst.Pix[pos+0] = uint8(clampFloat64(r0*r1*2*255, 0, 255))
					dst.Pix[pos+1] = uint8(clampFloat64(g0*g1*2*255, 0, 255))
					dst.Pix[pos+2] = uint8(clampFloat64(b0*b1*2*255, 0, 255))
					dst.Pix[pos+3] = uint8(clampFloat64(a0*a1*2*255, 0, 255))
				} else {
					dst.Pix[pos+0] = uint8(clampFloat64((1-(2*(1-r0)*(1-r1)))*255, 0, 255))
					dst.Pix[pos+1] = uint8(clampFloat64((1-(2*(1-g0)*(1-g1)))*255, 0, 255))
					dst.Pix[pos+2] = uint8(clampFloat64((1-(2*(1-b0)*(1-b1)))*255, 0, 255))
					dst.Pix[pos+3] = uint8(clampFloat64((1-(2*(1-a0)*(1-a1)))*255, 0, 255))
				}
			}
		}
	})

	return dst
}
<commit_msg>refactored blend function<commit_after>package bild

import (
	"image"
	"image/color"
)

type normColor struct {
	r, g, b, a float64
}

// Add returns an image with the added color values of two images
func Add(a image.Image, b image.Image) *image.RGBA {
	dst := blendOperation(a, b, func(c0 color.RGBA, c1 color.RGBA) color.RGBA {

		r0 := float64(c0.R)
		g0 := float64(c0.G)
		b0 := float64(c0.B)
		a0 := float64(c0.A)

		r1 := float64(c1.R)
		g1 := float64(c1.G)
		b1 := float64(c1.B)
		a1 := float64(c1.A)

		r2 := uint8(clampFloat64(r0+r1, 0, 255))
		g2 := uint8(clampFloat64(g0+g1, 0, 255))
		b2 := uint8(clampFloat64(b0+b1, 0, 255))
		a2 := uint8(clampFloat64(a0+a1, 0, 255))

		return color.RGBA{r2, g2, b2, a2}
	})

	return dst
}

// Multiply returns an image with the normalized color values of two images multiplied
func Multiply(a image.Image, b image.Image) *image.RGBA {
	dst := blendOperation(a, b, func(c0 color.RGBA, c1 color.RGBA) color.RGBA {

		r0 := float64(c0.R) / 255
		g0 := float64(c0.G) / 255
		b0 := float64(c0.B) / 255
		a0 := float64(c0.A) / 255

		r1 := float64(c1.R) / 255
		g1 := float64(c1.G) / 255
		b1 := float64(c1.B) / 255
		a1 := float64(c1.A) / 255

		r2 := uint8(r0 * r1 * 255)
		g2 := uint8(g0 * g1 * 255)
		b2 := uint8(b0 * b1 * 255)
		a2 := uint8(a0 * a1 * 255)

		return color.RGBA{r2, g2, b2, a2}
	})

	return dst
}

// Overlay returns an image that combines Multiply and Screen blend modes
func Overlay(a image.Image, b image.Image) *image.RGBA {
	dst := blendOperation(a, b, func(c0 color.RGBA, c1 color.RGBA) color.RGBA {

		r0 := float64(c0.R) / 255
		g0 := float64(c0.G) / 255
		b0 := float64(c0.B) / 255
		a0 := float64(c0.A) / 255

		r1 := float64(c1.R) / 255
		g1 := float64(c1.G) / 255
		b1 := float64(c1.B) / 255
		a1 := float64(c1.A) / 255

		var r2, g2, b2, a2 uint8
		if 0.3*r0+0.6*g0+0.1*b0 < 0.5 {
			r2 = uint8(clampFloat64(r0*r1*2*255, 0, 255))
			g2 = uint8(clampFloat64(g0*g1*2*255, 0, 255))
			b2 = uint8(clampFloat64(b0*b1*2*255, 0, 255))
			a2 = uint8(clampFloat64(a0*a1*2*255, 0, 255))
		} else {
			r2 = uint8(clampFloat64((1-(2*(1-r0)*(1-r1)))*255, 0, 255))
			g2 = uint8(clampFloat64((1-(2*(1-g0)*(1-g1)))*255, 0, 255))
			b2 = uint8(clampFloat64((1-(2*(1-b0)*(1-b1)))*255, 0, 255))
			a2 = uint8(clampFloat64((1-(2*(1-a0)*(1-a1)))*255, 0, 255))
		}

		return color.RGBA{r2, g2, b2, a2}
	})

	return dst
}

func blendOperation(a image.Image, b image.Image, fn func(color.RGBA, color.RGBA) color.RGBA) *image.RGBA {
	// Currently only equal size images are supported
	if a.Bounds() != b.Bounds() {
		panic("blend operation: only equal size images are supported")
	}

	bounds := a.Bounds()
	srcA := CloneAsRGBA(a)
	srcB := CloneAsRGBA(b)

	dst := image.NewRGBA(bounds)

	w, h := bounds.Max.X, bounds.Max.Y

	parallelize(h, func(start, end int) {
		for x := 0; x < w; x++ {
			for y := start; y < end; y++ {
				pos := y*dst.Stride + x*4
				result := fn(color.RGBA{srcA.Pix[pos+0], srcA.Pix[pos+1], srcA.Pix[pos+2], srcA.Pix[pos+3]},
					color.RGBA{srcB.Pix[pos+0], srcB.Pix[pos+1], srcB.Pix[pos+2], srcB.Pix[pos+3]})

				dst.Pix[pos+0] = result.R
				dst.Pix[pos+1] = result.G
				dst.Pix[pos+2] = result.B
				dst.Pix[pos+3] = result.A
			}

		}
	})

	return dst
}
<|endoftext|>


<commit_before>/*
Copyright 2014 go-trello authors. 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 trello

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type Board struct {
	client         *Client
	Id             string   `json:"id"`
	Name           string   `json:"name"`
	Desc           string   `json:"desc"`
	DescData       string   `json:"descData"`
	Closed         bool     `json:"closed"`
	IdOrganization string   `json:"idOrganization"`
	Pinned         []string `json:"pinned"`
	Url            string   `json:"url"`
	ShortUrl       string   `json:"shortUrl`
	Prefs          struct {
		PermissionLevel       string `json:"permissionLevel"`
		Voting                string `json:"voting"`
		Comments              string `json:"comments"`
		Invitations           string `json:"invitations"`
		SelfJoin              bool   `json:"selfjoin"`
		CardCovers            bool   `json:"cardCovers"`
		CardAging             string `json:"cardAging"`
		CalendarFeedEnabled   bool   `json:"calendarFeedEnabled"`
		Background            string `json:"background"`
		BackgroundColor       string `json:"backgroundColor"`
		BackgroundImage       string `json:"backgroundImage"`
		BackgroundImageScaled string `json:"backgroundImageScaled"`
		BackgroundTile        bool   `json:"backgroundTile"`
		BackgroundBrightness  string `json:"backgroundBrightness"`
		CanBePublic           bool   `json:"canBePublic"`
		CanBeOrg              bool   `json:"canBeOrg"`
		CanBePrivate          bool   `json:"canBePrivate"`
		CanInvite             bool   `json:"canInvite"`
	} `json:"prefs"`
	LabelNames struct {
		Red    string `json:"red"`
		Orange string `json:"orange"`
		Yellow string `json:"yellow"`
		Green  string `json:"green"`
		Blue   string `json:"blue"`
		Purple string `json:"purple"`
	} `json:"labelNames"`
}

func (c *Client) Board(boardId string) (board *Board, err error) {
	req, err := http.NewRequest("GET", c.endpoint+"/boards/"+boardId, nil)
	if err != nil {
		return
	}

	resp, err := c.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &board)
	board.client = c
	return
}

func (b *Board) Lists() (lists []List, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/lists", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &lists)
	for i, _ := range lists {
		lists[i].client = b.client
	}
	return
}

func (b *Board) Members() (members []Member, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/members", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &members)
	return
}

func (b *Board) Cards() (cards []Card, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/cards", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &cards)
	for i, _ := range cards {
		cards[i].client = b.client
	}
	return
}
<commit_msg>Add Board.Card() method<commit_after>/*
Copyright 2014 go-trello authors. 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 trello

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type Board struct {
	client         *Client
	Id             string   `json:"id"`
	Name           string   `json:"name"`
	Desc           string   `json:"desc"`
	DescData       string   `json:"descData"`
	Closed         bool     `json:"closed"`
	IdOrganization string   `json:"idOrganization"`
	Pinned         []string `json:"pinned"`
	Url            string   `json:"url"`
	ShortUrl       string   `json:"shortUrl`
	Prefs          struct {
		PermissionLevel       string `json:"permissionLevel"`
		Voting                string `json:"voting"`
		Comments              string `json:"comments"`
		Invitations           string `json:"invitations"`
		SelfJoin              bool   `json:"selfjoin"`
		CardCovers            bool   `json:"cardCovers"`
		CardAging             string `json:"cardAging"`
		CalendarFeedEnabled   bool   `json:"calendarFeedEnabled"`
		Background            string `json:"background"`
		BackgroundColor       string `json:"backgroundColor"`
		BackgroundImage       string `json:"backgroundImage"`
		BackgroundImageScaled string `json:"backgroundImageScaled"`
		BackgroundTile        bool   `json:"backgroundTile"`
		BackgroundBrightness  string `json:"backgroundBrightness"`
		CanBePublic           bool   `json:"canBePublic"`
		CanBeOrg              bool   `json:"canBeOrg"`
		CanBePrivate          bool   `json:"canBePrivate"`
		CanInvite             bool   `json:"canInvite"`
	} `json:"prefs"`
	LabelNames struct {
		Red    string `json:"red"`
		Orange string `json:"orange"`
		Yellow string `json:"yellow"`
		Green  string `json:"green"`
		Blue   string `json:"blue"`
		Purple string `json:"purple"`
	} `json:"labelNames"`
}

func (c *Client) Board(boardId string) (board *Board, err error) {
	req, err := http.NewRequest("GET", c.endpoint+"/boards/"+boardId, nil)
	if err != nil {
		return
	}

	resp, err := c.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &board)
	board.client = c
	return
}

func (b *Board) Lists() (lists []List, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/lists", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &lists)
	for i, _ := range lists {
		lists[i].client = b.client
	}
	return
}

func (b *Board) Members() (members []Member, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/members", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &members)
	return
}

func (b *Board) Cards() (cards []Card, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/cards", nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &cards)
	for i, _ := range cards {
		cards[i].client = b.client
	}
	return
}

func (b *Board) Card(IdCard string) (card *Card, err error) {
	req, err := http.NewRequest("GET", b.client.endpoint+"/boards/"+b.Id+"/cards/"+IdCard, nil)
	if err != nil {
		return
	}

	resp, err := b.client.client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	} else if resp.StatusCode != 200 {
		err = fmt.Errorf("Received unexpected status %d while trying to retrieve the server data", resp.StatusCode)
		return
	}

	err = json.Unmarshal(body, &card)
	card.client = b.client
	return
}
<|endoftext|>


<commit_before>package gogo

import (
	"errors"
	"fmt"
	"runtime/debug"
	"strconv"
	"strings"

	"github.com/xlvector/hector/lr"
)

const (
	PATTERN_SIZE = 15
)

type Board struct {
	size         int
	w            []Point
	komi         float64
	ko           Point
	takeBlack    int
	takeWhite    int
	model        *lr.LogisticRegression
	step         int
	info         *BoardInfo
	pdm          *PointDistanceMap
	pointHash    []int64
	patternHash  [][]int64
	lastMoveHash []int64
}

func NewBoard(size int) *Board {
	b := &Board{}
	b.Clear(size)
	return b
}

func (b *Board) GetPatternHash(p int) []int64 {
	if p < 0 || p >= len(b.patternHash) {
		fmt.Println("GetPatternHash", p, len(b.patternHash))
		return nil
	}
	ret := make([]int64, PATTERN_SIZE)
	h := int64(0)
	for i, ph := range b.patternHash[p] {
		h ^= ph
		ret[i] = h
	}
	return ret
}

func (b *Board) SetPointDistanceMap(pdm *PointDistanceMap) {
	b.pdm = pdm
	b.InitPatternHash(pdm)
}

func (b *Board) Clear(size int) {
	b.size = size
	b.w = make([]Point, size*size)
	b.pointHash = make([]int64, size*size)
	b.patternHash = make([][]int64, size*size)
	b.lastMoveHash = make([]int64, 0, 20)
	b.ko = InvalidPoint()
	i := 0
	for y := 0; y < size; y++ {
		for x := 0; x < size; x++ {
			b.w[i] = Point{x, y, GRAY}
			b.patternHash[i] = make([]int64, PATTERN_SIZE)
			i += 1
		}
	}

	for i, p := range b.w {
		b.pointHash[i] = b.PointHash(p)
	}
}

func (b *Board) W() []Point {
	return b.w
}

func (b *Board) Model() *lr.LogisticRegression {
	return b.model
}

func (b *Board) Copy() *Board {
	ret := &Board{
		size:      b.size,
		w:         make([]Point, 0, 1+len(b.w)),
		komi:      b.komi,
		takeBlack: b.takeBlack,
		takeWhite: b.takeWhite,
		ko:        b.ko,
		model:     b.model,
		step:      b.step,
		pdm:       b.pdm,
	}
	ret.pointHash = make([]int64, b.size*b.size)
	ret.patternHash = make([][]int64, b.size*b.size)
	ret.lastMoveHash = make([]int64, 0, 20)

	for _, v := range b.pointHash {
		ret.pointHash = append(ret.pointHash, v)
	}
	for _, v := range b.lastMoveHash {
		ret.lastMoveHash = append(ret.lastMoveHash, v)
	}

	for _, ph := range b.patternHash {
		tmp := []int64{}
		for _, v := range ph {
			tmp = append(tmp, v)
		}
		ret.patternHash = append(ret.patternHash, tmp)
	}
	for _, p := range b.w {
		ret.w = append(ret.w, p)
	}
	return ret
}

func (b *Board) XMirror(p Point) Point {
	return b.Get(b.size-p.x, p.y)
}

func (b *Board) YMirror(p Point) Point {
	return b.Get(p.x, b.size-p.y)
}

func (b *Board) DMirror(p Point) Point {
	return b.Get(b.size-p.x, b.size-p.y)
}

func (b *Board) index(x, y int) int {
	return y*b.size + x
}

func (b *Board) Index(p Point) int {
	return b.index(p.x, p.y)
}

func (b *Board) pos(p int) (int, int) {
	return p % b.size, p / b.size
}

func (b *Board) PutLabel(buf string) error {
	c := buf[0:1]
	x := strings.Index(LX, strings.ToUpper(buf[1:2]))
	y, _ := strconv.Atoi(buf[2:])
	y -= 1
	if c == "B" {
		return b.Put(x, y, BLACK)
	} else if c == "W" {
		return b.Put(x, y, WHITE)
	} else {
		return errors.New("invalid input: " + buf)
	}
}

func (b *Board) Put(x, y int, stone Color) error {
	if !b.valid(stone, x, y) {
		return errors.New("invalid position")
	}
	if b.ko.x == x && b.ko.y == y {
		return errors.New("ko position")
	}
	b.ko = InvalidPoint()
	i := b.index(x, y)
	b.lastMoveHash = b.PointSimpleFeature(b.w[i], stone)
	prevWi := b.w[i]
	b.w[i] = Point{x, y, stone}
	b.UpdateHash(x, y, stone, b.pdm)
	tworms := b.GetTakeWorms(stone, x, y)
	if len(tworms) == 0 {
		pworm := b.WormContainsPoint(i)
		if pworm.Dead() {
			b.w[i] = prevWi
			return errors.New("sucide position")
		}
	} else {
		b.ko = b.koPositionOfDeadWorms(b.w[i], tworms)
		b.TakeWorms(tworms)
	}
	b.step += 1
	return nil
}

func (b *Board) Size() int {
	return b.size
}

func (b *Board) Get(x, y int) Point {
	if x < 0 || y < 0 || x >= b.size || y >= b.size {
		return InvalidPoint()
	}
	return b.w[b.index(x, y)]
}

func (b *Board) SingleEye(x, y int, stone Color) bool {
	if b.Get(x, y).color != GRAY {
		return false
	}
	n4 := b.Neighbor4(x, y)
	for _, p := range n4 {
		if p.color != stone {
			return false
		}
	}
	return true
}

func (b *Board) Neighbor4(x, y int) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x, y+1); p.Valid() {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) Neighbor4Color(x, y int, color Color) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x, y-1); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x, y+1); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) NeighDiamond(x, y int) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y+1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x-1, y+1); p.Valid() {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) Valid(p Point) bool {
	return b.valid(p.color, p.x, p.y)
}

func (b *Board) valid(stone Color, x, y int) bool {
	if x < 0 || y < 0 || x >= b.size || y >= b.size {
		return false
	}

	p := b.Get(x, y)
	if p.color != GRAY {
		return false
	}
	return true
}

func (b *Board) Stone(x, y int, ls Point) string {
	i := b.index(x, y)
	if b.w[i].color == GRAY {
		return "."
	} else if b.w[i].color == BLACK {
		if ls.x == x && ls.y == y {
			return "#"
		} else {
			return "X"
		}
	} else if b.w[i].color == WHITE {
		if ls.x == x && ls.y == y {
			return "@"
		} else {
			return "O"
		}
	} else {
		return "?"
	}
}

func (b *Board) String(lastStep Point) string {
	defer func() {
		if r := recover(); r != nil {
			debug.PrintStack()
		}
	}()
	ret := ""
	if b == nil || b.size == 0 {
		return ret
	}
	for y := b.size; y >= 0; y-- {
		ret += fmt.Sprintf("    ")
		for x := 0; x <= b.size; x++ {
			if y == 0 {
				if x == 0 {
					ret += fmt.Sprintf("   ")
				} else {
					ret += fmt.Sprintf(string(LX[x-1]))
					ret += fmt.Sprintf(" ")
				}
			} else {
				if x == 0 {
					if y < 10 {
						ret += fmt.Sprintf(" %d", y)
					} else {
						ret += fmt.Sprintf("%d", y)
					}
					ret += fmt.Sprintf(" ")
				} else {
					ret += fmt.Sprintf(b.Stone(x-1, y-1, lastStep))
					ret += fmt.Sprintf(" ")
				}
			}
		}
		ret += fmt.Sprintf("\n")
	}
	ret += fmt.Sprintf("\n")
	return ret
}
<commit_msg>lr model: mcts, copy<commit_after>package gogo

import (
	"errors"
	"fmt"
	"runtime/debug"
	"strconv"
	"strings"

	"github.com/xlvector/hector/lr"
)

const (
	PATTERN_SIZE = 15
)

type Board struct {
	size         int
	w            []Point
	komi         float64
	ko           Point
	takeBlack    int
	takeWhite    int
	model        *lr.LogisticRegression
	step         int
	info         *BoardInfo
	pdm          *PointDistanceMap
	pointHash    []int64
	patternHash  [][]int64
	lastMoveHash []int64
}

func NewBoard(size int) *Board {
	b := &Board{}
	b.Clear(size)
	return b
}

func (b *Board) GetPatternHash(p int) []int64 {
	if p < 0 || p >= len(b.patternHash) {
		fmt.Println("GetPatternHash", p, len(b.patternHash))
		return nil
	}
	ret := make([]int64, PATTERN_SIZE)
	h := int64(0)
	for i, ph := range b.patternHash[p] {
		h ^= ph
		ret[i] = h
	}
	return ret
}

func (b *Board) SetPointDistanceMap(pdm *PointDistanceMap) {
	b.pdm = pdm
	b.InitPatternHash(pdm)
}

func (b *Board) Clear(size int) {
	b.size = size
	b.w = make([]Point, size*size)
	b.pointHash = make([]int64, size*size)
	b.patternHash = make([][]int64, size*size)
	b.lastMoveHash = make([]int64, 0, 20)
	b.ko = InvalidPoint()
	i := 0
	for y := 0; y < size; y++ {
		for x := 0; x < size; x++ {
			b.w[i] = Point{x, y, GRAY}
			b.patternHash[i] = make([]int64, PATTERN_SIZE)
			i += 1
		}
	}

	for i, p := range b.w {
		b.pointHash[i] = b.PointHash(p)
	}
}

func (b *Board) W() []Point {
	return b.w
}

func (b *Board) Model() *lr.LogisticRegression {
	return b.model
}

func (b *Board) Copy() *Board {
	ret := &Board{
		size:      b.size,
		w:         make([]Point, 0, 1+len(b.w)),
		komi:      b.komi,
		takeBlack: b.takeBlack,
		takeWhite: b.takeWhite,
		ko:        b.ko,
		model:     b.model,
		step:      b.step,
		pdm:       b.pdm,
	}
	ret.pointHash = make([]int64, b.size*b.size)
	ret.patternHash = make([][]int64, b.size*b.size)
	ret.lastMoveHash = make([]int64, 0, 20)

	for i, v := range b.pointHash {
		ret.pointHash[i] = v
	}
	for _, v := range b.lastMoveHash {
		ret.lastMoveHash = append(ret.lastMoveHash, v)
	}

	for i, ph := range b.patternHash {
		tmp := []int64{}
		for _, v := range ph {
			tmp = append(tmp, v)
		}
		ret.patternHash[i] = tmp
	}
	for _, p := range b.w {
		ret.w = append(ret.w, p)
	}
	return ret
}

func (b *Board) XMirror(p Point) Point {
	return b.Get(b.size-p.x, p.y)
}

func (b *Board) YMirror(p Point) Point {
	return b.Get(p.x, b.size-p.y)
}

func (b *Board) DMirror(p Point) Point {
	return b.Get(b.size-p.x, b.size-p.y)
}

func (b *Board) index(x, y int) int {
	return y*b.size + x
}

func (b *Board) Index(p Point) int {
	return b.index(p.x, p.y)
}

func (b *Board) pos(p int) (int, int) {
	return p % b.size, p / b.size
}

func (b *Board) PutLabel(buf string) error {
	c := buf[0:1]
	x := strings.Index(LX, strings.ToUpper(buf[1:2]))
	y, _ := strconv.Atoi(buf[2:])
	y -= 1
	if c == "B" {
		return b.Put(x, y, BLACK)
	} else if c == "W" {
		return b.Put(x, y, WHITE)
	} else {
		return errors.New("invalid input: " + buf)
	}
}

func (b *Board) Put(x, y int, stone Color) error {
	if !b.valid(stone, x, y) {
		return errors.New("invalid position")
	}
	if b.ko.x == x && b.ko.y == y {
		return errors.New("ko position")
	}
	b.ko = InvalidPoint()
	i := b.index(x, y)
	b.lastMoveHash = b.PointSimpleFeature(b.w[i], stone)
	prevWi := b.w[i]
	b.w[i] = Point{x, y, stone}
	b.UpdateHash(x, y, stone, b.pdm)
	tworms := b.GetTakeWorms(stone, x, y)
	if len(tworms) == 0 {
		pworm := b.WormContainsPoint(i)
		if pworm.Dead() {
			b.w[i] = prevWi
			return errors.New("sucide position")
		}
	} else {
		b.ko = b.koPositionOfDeadWorms(b.w[i], tworms)
		b.TakeWorms(tworms)
	}
	b.step += 1
	return nil
}

func (b *Board) Size() int {
	return b.size
}

func (b *Board) Get(x, y int) Point {
	if x < 0 || y < 0 || x >= b.size || y >= b.size {
		return InvalidPoint()
	}
	return b.w[b.index(x, y)]
}

func (b *Board) SingleEye(x, y int, stone Color) bool {
	if b.Get(x, y).color != GRAY {
		return false
	}
	n4 := b.Neighbor4(x, y)
	for _, p := range n4 {
		if p.color != stone {
			return false
		}
	}
	return true
}

func (b *Board) Neighbor4(x, y int) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x, y+1); p.Valid() {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) Neighbor4Color(x, y int, color Color) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x, y-1); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	if p := b.Get(x, y+1); p.Valid() && p.color == color {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) NeighDiamond(x, y int) []Point {
	ret := make([]Point, 0, 4)
	if p := b.Get(x-1, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y+1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x+1, y-1); p.Valid() {
		ret = append(ret, p)
	}
	if p := b.Get(x-1, y+1); p.Valid() {
		ret = append(ret, p)
	}
	return ret
}

func (b *Board) Valid(p Point) bool {
	return b.valid(p.color, p.x, p.y)
}

func (b *Board) valid(stone Color, x, y int) bool {
	if x < 0 || y < 0 || x >= b.size || y >= b.size {
		return false
	}

	p := b.Get(x, y)
	if p.color != GRAY {
		return false
	}
	return true
}

func (b *Board) Stone(x, y int, ls Point) string {
	i := b.index(x, y)
	if b.w[i].color == GRAY {
		return "."
	} else if b.w[i].color == BLACK {
		if ls.x == x && ls.y == y {
			return "#"
		} else {
			return "X"
		}
	} else if b.w[i].color == WHITE {
		if ls.x == x && ls.y == y {
			return "@"
		} else {
			return "O"
		}
	} else {
		return "?"
	}
}

func (b *Board) String(lastStep Point) string {
	defer func() {
		if r := recover(); r != nil {
			debug.PrintStack()
		}
	}()
	ret := ""
	if b == nil || b.size == 0 {
		return ret
	}
	for y := b.size; y >= 0; y-- {
		ret += fmt.Sprintf("    ")
		for x := 0; x <= b.size; x++ {
			if y == 0 {
				if x == 0 {
					ret += fmt.Sprintf("   ")
				} else {
					ret += fmt.Sprintf(string(LX[x-1]))
					ret += fmt.Sprintf(" ")
				}
			} else {
				if x == 0 {
					if y < 10 {
						ret += fmt.Sprintf(" %d", y)
					} else {
						ret += fmt.Sprintf("%d", y)
					}
					ret += fmt.Sprintf(" ")
				} else {
					ret += fmt.Sprintf(b.Stone(x-1, y-1, lastStep))
					ret += fmt.Sprintf(" ")
				}
			}
		}
		ret += fmt.Sprintf("\n")
	}
	ret += fmt.Sprintf("\n")
	return ret
}
<|endoftext|>