<commit_before>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/gin-gonic/gin"
	"github.com/freeusd/solebtc/controllers/v1"
	"github.com/freeusd/solebtc/middlewares"
	"github.com/freeusd/solebtc/services/storage/mysql"
)

func init() {
	initConfig()
}

func main() {
	var (
		logWriter   io.Writer = os.Stdout
		panicWriter io.Writer = os.Stderr
	)

	// storage service
	storage, err := mysql.New(config.DB.DataSourceName)
	if err != nil {
		fmt.Fprintf(panicWriter, "Cannot create mysql storage: %v", err)
		return
	}

	gin.SetMode(ginEnvMode())
	router := gin.New()

	router.Use(gin.RecoveryWithWriter(panicWriter))
	router.Use(middlewares.LoggerWithWriter(logWriter))
	router.Use(middlewares.ErrorWriter())

	g1 := router.Group("/v1")
	g1.POST("/users", v1.Signup(storage.CreateUser))

	fmt.Fprintf(logWriter, "SoleBTC is running on %s", config.HTTP.Port)
	router.Run(config.HTTP.Port)
}
<commit_msg>Refine routes<commit_after>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/gin-gonic/gin"
	"github.com/freeusd/solebtc/controllers/v1"
	"github.com/freeusd/solebtc/middlewares"
	"github.com/freeusd/solebtc/services/storage/mysql"
)

func init() {
	initConfig()
}

func main() {
	var (
		logWriter   io.Writer = os.Stdout
		panicWriter io.Writer = os.Stderr
	)

	// storage service
	storage, err := mysql.New(config.DB.DataSourceName)
	if err != nil {
		fmt.Fprintf(panicWriter, "Cannot create mysql storage: %v", err)
		return
	}

	gin.SetMode(ginEnvMode())
	router := gin.New()

	router.Use(gin.RecoveryWithWriter(panicWriter))
	router.Use(middlewares.LoggerWithWriter(logWriter))
	router.Use(middlewares.ErrorWriter())

	v1Endpoints := router.Group("/v1")

	// user endpoints
	v1UserEndpoints := v1Endpoints.Group("/users")
	v1UserEndpoints.POST("", v1.Signup(storage.CreateUser))

	// auth token endpoints
	v1AuthTokenEndpoints := v1Endpoints.Group("/auth_tokens")
	v1AuthTokenEndpoints.POST("", v1.Login(storage.GetUserByEmail, storage.CreateAuthToken))

	fmt.Fprintf(logWriter, "SoleBTC is running on %s", config.HTTP.Port)
	router.Run(config.HTTP.Port)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"github.com/dimfeld/httptreemux"
	"github.com/sjug/am-go/server"
)

func main() {
	const port = ":8080"
	httpRouter := httptreemux.New()
	server.InitDetails(httpRouter)
	server.InitTier(httpRouter)

	log.Println("Listening on port", port)
	log.Fatal(http.ListenAndServe(port, httpRouter))
}
<commit_msg>Getting started on DB<commit_after>package main

import (
	"log"
	"net/http"

	"github.com/dimfeld/httptreemux"
	"github.com/sjug/am-go/database"
	"github.com/sjug/am-go/server"
)

func main() {
	const port = ":8080"
	httpRouter := httptreemux.New()
	server.InitDetails(httpRouter)
	server.InitTier(httpRouter)

	log.Println("Listening on port", port)
	log.Fatal(http.ListenAndServe(port, httpRouter))
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

type record struct {
	name    string
	index   int
	msg     string
	failed  int
	percent float32
}

type collector struct {
	w         io.Writer
	buf       *bytes.Buffer
	testName  string
	anyFailed bool
	records   map[string]record
	timesRan  map[string]int
	scanner   *bufio.Scanner
	curIndex  int
}

func newCollector(w io.Writer) *collector {
	return &collector{
		w:       w,
		buf:     new(bytes.Buffer),
		records: make(map[string]record, 0),
		timesRan: make(map[string]int, 0),
	}
}

func (c *collector) run(r io.Reader) {
	c.scanner = bufio.NewScanner(r)
	for c.scanner.Scan() {
		line := c.scanner.Text()
		c.parseLine(line)
	}
}

func extractTestName(line string) string {
	if fields := strings.Fields(line); len(fields) > 2 {
		return fields[2]
	}
	return "Unknown"
}

func (c *collector) parseLine(line string) {
	switch {
	case line == "FAIL" || line == "PASS":
	case strings.HasPrefix(line, "exit status"):
	case strings.HasPrefix(line, "=== RUN"):
		testName := extractTestName(line)
		if _, e := c.timesRan[testName]; e {
			c.timesRan[testName]++
		} else {
			c.timesRan[testName] = 1
		}
		c.finishRecord()
	case strings.HasPrefix(line, "?") || strings.HasPrefix(line, "ok"):
		// These report the overall progress, showing
		// what packages were ok or had no tests.
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "FAIL"):
		// Package failure. Show results.
		c.finishRecord()
		for _, r := range c.sortedRecords() {
			if r.percent > 0 {
				fmt.Fprintf(c.w, "--- FAIL: %s (%d times, %.2f%%)\n",
					r.name, r.failed, r.percent)
			} else {
				fmt.Fprintf(c.w, "--- FAIL: %s (%d times)\n",
					r.name, r.failed)
			}
			fmt.Fprint(c.w, r.msg)
		}
		c.records = make(map[string]record, 0)
		c.timesRan = make(map[string]int, 0)
		fmt.Fprintln(c.w, "FAIL")
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "--- FAIL"):
		// Single test failure.
		c.finishRecord()
		c.testName = extractTestName(line)
		fmt.Fprintln(c.buf, c.testName)
	case c.testName != "":
		// Part of the current test error output
		fmt.Fprintln(c.buf, line)
	}
}

func (c *collector) finishRecord() {
	if c.testName == "" {
		return
	}
	c.anyFailed = true
	s := c.buf.String()
	if r, e := c.records[s]; e {
		r.failed++
		c.records[s] = r
	} else {
		c.records[s] = record{
			name:   c.testName,
			failed: 1,
			index:  c.curIndex,
		}
		c.curIndex++
	}
	c.buf.Reset()
	c.testName = ""
}

type recordList []record

func (rl recordList) Len() int      { return len(rl) }
func (rl recordList) Swap(i, j int) { rl[i], rl[j] = rl[j], rl[i] }
func (rl recordList) Less(i, j int) bool {
	if rl[i].failed == rl[j].failed {
		return rl[i].index < rl[j].index
	}
	return rl[i].failed > rl[j].failed
}

func (c *collector) sortedRecords() []record {
	list := make(recordList, 0, len(c.records))
	for s, r := range c.records {
		if i := strings.Index(s, "\n"); i > 0 {
			s = s[i+1:]
		}
		r.msg = s
		ran := c.timesRan[r.name]
		if ran > 0 {
			r.percent = 100*(float32(r.failed)/float32(ran))
		}
		list = append(list, r)
	}
	sort.Sort(list)
	return list
}

func main() {
	c := newCollector(os.Stdout)
	c.run(os.Stdin)
	if c.anyFailed {
		os.Exit(1)
	}
}
<commit_msg>Separate results by test name<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
)

type testResults struct {
	name     string
	index    int
	timesRan int
	byMsg    map[string]int

	failed  int
	percent float32
}

type collector struct {
	scanner   *bufio.Scanner
	w         io.Writer
	buf       *bytes.Buffer
	testName  string
	anyFailed bool
	byName    map[string]testResults
	curIndex  int
}

func newCollector(w io.Writer) *collector {
	return &collector{
		w:       w,
		buf:     new(bytes.Buffer),
		byName: make(map[string]testResults, 0),
	}
}

func (c *collector) run(r io.Reader) {
	c.scanner = bufio.NewScanner(r)
	for c.scanner.Scan() {
		line := c.scanner.Text()
		c.parseLine(line)
	}
}

func extractTestName(line string) string {
	if fields := strings.Fields(line); len(fields) > 2 {
		return fields[2]
	}
	return "Unknown"
}

func (c *collector) parseLine(line string) {
	switch {
	case line == "FAIL" || line == "PASS":
	case strings.HasPrefix(line, "exit status"):
	case strings.HasPrefix(line, "=== RUN"):
		name := extractTestName(line)
		if _, e := c.byName[name]; !e {
			c.byName[name] = testResults{
				name: name,
				index: c.curIndex,
				byMsg: make(map[string]int, 0),
			}
			c.curIndex++
		}
		r := c.byName[name]
		r.timesRan++
		c.byName[name] = r
		c.finishRecord()
	case strings.HasPrefix(line, "?") || strings.HasPrefix(line, "ok"):
		// These report the overall progress, showing
		// what packages were ok or had no tests.
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "FAIL"):
		// Package failure. Show results.
		c.finishRecord()
		for _, r := range c.sortedResults() {
			if r.percent > 0 {
				fmt.Fprintf(c.w, "--- FAIL: %s (%d times, %.2f%%)\n",
					r.name, r.failed, r.percent)
			} else {
				fmt.Fprintf(c.w, "--- FAIL: %s (%d times)\n",
					r.name, r.failed)
			}
			for msg, count := range r.byMsg {
				if len(r.byMsg) > 1 {
					fmt.Fprintf(c.w, "-- Failed %d times:\n", count)
				}
				fmt.Fprint(c.w, msg)
			}
		}
		c.byName = make(map[string]testResults, 0)
		fmt.Fprintln(c.w, "FAIL")
		fmt.Fprintln(c.w, line)
	case strings.HasPrefix(line, "--- FAIL"):
		// Single test failure.
		c.finishRecord()
		c.testName = extractTestName(line)
	case c.testName != "":
		// Part of the current test error output
		fmt.Fprintln(c.buf, line)
	}
}

func (c *collector) finishRecord() {
	if c.testName == "" {
		return
	}
	c.anyFailed = true
	msg := c.buf.String()
	if _, e := c.byName[c.testName]; !e {
		c.byName[c.testName] = testResults{
			name: c.testName,
			index: c.curIndex,
			byMsg: make(map[string]int, 0),
		}
		c.curIndex++
	}
	r := c.byName[c.testName]
	r.failed++
	if _, e := r.byMsg[msg]; e {
		r.byMsg[msg]++
	} else {
		r.byMsg[msg] = 1
	}
	c.byName[c.testName] = r
	c.buf.Reset()
	c.testName = ""
}

type resultsList []testResults

func (rl resultsList) Len() int      { return len(rl) }
func (rl resultsList) Swap(i, j int) { rl[i], rl[j] = rl[j], rl[i] }
func (rl resultsList) Less(i, j int) bool {
	if rl[i].failed == rl[j].failed {
		return rl[i].index < rl[j].index
	}
	return rl[i].failed > rl[j].failed
}

func (c *collector) sortedResults() []testResults {
	list := make(resultsList, 0, len(c.byName))
	for n, r := range c.byName {
		r.name = n
		if r.timesRan > 0 {
			r.percent = 100*(float32(r.failed)/float32(r.timesRan))
		}
		list = append(list, r)
	}
	sort.Sort(list)
	return list
}

func main() {
	c := newCollector(os.Stdout)
	c.run(os.Stdin)
	if c.anyFailed {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/genuinetools/weather/forecast"
	"github.com/genuinetools/weather/geocode"
	"github.com/genuinetools/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.genuinetools.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	server       string
	vrsn         bool
	client       bool
	geo          geocode.Geocode
)

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}

func init() {
	// parse flags
	flag.BoolVar(&vrsn, "version", false, "print version and exit")
	flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)")
	flag.StringVar(&location, "location", "", "Location to get the weather")
	flag.StringVar(&location, "l", "", "Location to get the weather (shorthand)")
	flag.BoolVar(&client, "client", false, "Get location for the ssh client")
	flag.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")
	flag.StringVar(&units, "units", "auto", "System of units")
	flag.StringVar(&units, "u", "auto", "System of units (shorthand)")
	flag.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	flag.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")
	flag.IntVar(&days, "days", 0, "No. of days to get forecast")
	flag.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")
	flag.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	flag.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	flag.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hours")

	flag.Usage = func() {
		flag.PrintDefaults()
	}

	flag.Parse()

	if server == "" {
		usageAndExit("Please enter a Weather API server uri or leave blank to use the default.", 0)
	}
}

//go:generate go run icons/generate.go

func main() {
	if vrsn {
		fmt.Printf("weather version %s, build %s", version.VERSION, version.GITCOMMIT)
		return
	}

	var err error
	if location == "" {
		sshConn := os.Getenv("SSH_CONNECTION")
		if client && len(sshConn) > 0 {
			// use their ssh connection to locate them
			ipports := strings.Split(sshConn, " ")
			geo, err = geocode.IPLocate(ipports[0])
			if err != nil {
				printError(err)
			}

		} else {
			// auto locate them
			geo, err = geocode.Autolocate()
			if err != nil {
				printError(err)
			}

			if geo.Latitude == 0 || geo.Longitude == 0 {
				printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
			}
		}
	} else {
		// get geolocation data for the given location
		geo, err = geocode.Locate(location, server)
		if err != nil {
			printError(err)
		}
	}

	if geo.Latitude == 0 || geo.Longitude == 0 {
		printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
	}

	data := forecast.Request{
		Latitude:  geo.Latitude,
		Longitude: geo.Longitude,
		Units:     units,
		Exclude:   []string{"minutely"},
	}
	if noForecast {
		data.Exclude = append(data.Exclude, "hourly")
	}

	fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
	if err != nil {
		printError(err)
	}

	if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
		printError(err)
	}

	if days > 0 {
		forecast.PrintDaily(fc, days)
	}
}

func usageAndExit(message string, exitCode int) {
	if message != "" {
		fmt.Fprintf(os.Stderr, message)
		fmt.Fprintf(os.Stderr, "\n\n")
	}
	flag.Usage()
	fmt.Fprintf(os.Stderr, "\n")
	os.Exit(exitCode)
}
<commit_msg>fix url<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/genuinetools/weather/forecast"
	"github.com/genuinetools/weather/geocode"
	"github.com/genuinetools/weather/version"
	"github.com/mitchellh/colorstring"
)

const (
	defaultServerURI string = "https://geocode.jessfraz.com"
)

var (
	location     string
	units        string
	days         int
	ignoreAlerts bool
	hideIcon     bool
	noForecast   bool
	server       string
	vrsn         bool
	client       bool
	geo          geocode.Geocode
)

func printError(err error) {
	fmt.Println(colorstring.Color("[red]" + err.Error()))
	os.Exit(1)
}

func init() {
	// parse flags
	flag.BoolVar(&vrsn, "version", false, "print version and exit")
	flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)")
	flag.StringVar(&location, "location", "", "Location to get the weather")
	flag.StringVar(&location, "l", "", "Location to get the weather (shorthand)")
	flag.BoolVar(&client, "client", false, "Get location for the ssh client")
	flag.BoolVar(&client, "c", false, "Get location for the ssh client (shorthand)")
	flag.StringVar(&units, "units", "auto", "System of units")
	flag.StringVar(&units, "u", "auto", "System of units (shorthand)")
	flag.StringVar(&server, "server", defaultServerURI, "Weather API server uri")
	flag.StringVar(&server, "s", defaultServerURI, "Weather API server uri (shorthand)")
	flag.IntVar(&days, "days", 0, "No. of days to get forecast")
	flag.IntVar(&days, "d", 0, "No. of days to get forecast (shorthand)")
	flag.BoolVar(&ignoreAlerts, "ignore-alerts", false, "Ignore alerts in weather output")
	flag.BoolVar(&hideIcon, "hide-icon", false, "Hide the weather icons from being output")
	flag.BoolVar(&noForecast, "no-forecast", false, "Hide the forecast for the next 16 hours")

	flag.Usage = func() {
		flag.PrintDefaults()
	}

	flag.Parse()

	if server == "" {
		usageAndExit("Please enter a Weather API server uri or leave blank to use the default.", 0)
	}
}

//go:generate go run icons/generate.go

func main() {
	if vrsn {
		fmt.Printf("weather version %s, build %s", version.VERSION, version.GITCOMMIT)
		return
	}

	var err error
	if location == "" {
		sshConn := os.Getenv("SSH_CONNECTION")
		if client && len(sshConn) > 0 {
			// use their ssh connection to locate them
			ipports := strings.Split(sshConn, " ")
			geo, err = geocode.IPLocate(ipports[0])
			if err != nil {
				printError(err)
			}

		} else {
			// auto locate them
			geo, err = geocode.Autolocate()
			if err != nil {
				printError(err)
			}

			if geo.Latitude == 0 || geo.Longitude == 0 {
				printError(errors.New("Latitude and Longitude could not be determined from your IP so the weather will not be accurate\nTry: weather -l <your_zipcode> OR weather -l \"your city, state\""))
			}
		}
	} else {
		// get geolocation data for the given location
		geo, err = geocode.Locate(location, server)
		if err != nil {
			printError(err)
		}
	}

	if geo.Latitude == 0 || geo.Longitude == 0 {
		printError(errors.New("Latitude and Longitude could not be determined so the weather will not be accurate"))
	}

	data := forecast.Request{
		Latitude:  geo.Latitude,
		Longitude: geo.Longitude,
		Units:     units,
		Exclude:   []string{"minutely"},
	}
	if noForecast {
		data.Exclude = append(data.Exclude, "hourly")
	}

	fc, err := forecast.Get(fmt.Sprintf("%s/forecast", server), data)
	if err != nil {
		printError(err)
	}

	if err := forecast.PrintCurrent(fc, geo, ignoreAlerts, hideIcon); err != nil {
		printError(err)
	}

	if days > 0 {
		forecast.PrintDaily(fc, days)
	}
}

func usageAndExit(message string, exitCode int) {
	if message != "" {
		fmt.Fprintf(os.Stderr, message)
		fmt.Fprintf(os.Stderr, "\n\n")
	}
	flag.Usage()
	fmt.Fprintf(os.Stderr, "\n")
	os.Exit(exitCode)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"log"
	"net/http"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "serve"
	app.Usage = "Simple HTTP Server"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "dir, d",
			Value: ".",
			Usage: "Directory to serve",
		},
		cli.StringFlag{
			Name:  "address, a",
			Value: ":8080",
			Usage: "Address to listen on",
		},
	}
	app.Action = func(c *cli.Context) {
		address := ":8080"
		dir := "."

		if c.String("dir") != "" {
			dir = c.String("dir")
		}
		if c.String("address") != "" {
			address = c.String("address")
		}
		log.Fatal(http.ListenAndServe(address, http.FileServer(http.Dir(dir))))
	}

	app.Run(os.Args)
}
<commit_msg>Adding GZIP compression<commit_after>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/codegangsta/cli"
	"github.com/gorilla/handlers"
)

func main() {
	app := cli.NewApp()
	app.Name = "serve"
	app.Usage = "Simple HTTP Server"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "dir, d",
			Value: ".",
			Usage: "Directory to serve",
		},
		cli.StringFlag{
			Name:  "address, a",
			Value: ":8080",
			Usage: "Address to listen on",
		},
	}
	app.Action = func(c *cli.Context) {
		address := ":8080"
		dir := "."

		if c.String("dir") != "" {
			dir = c.String("dir")
		}
		if c.String("address") != "" {
			address = c.String("address")
		}
		server := handlers.CompressHandler(http.FileServer(http.Dir(dir)))
		log.Fatal(http.ListenAndServe(address, server))
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"strings"
)

var (
	input_file = flag.String("input", "", "Input file with transactions")
	output_dir = flag.String("output", "", "A dir to store created clusters to")
)

type Cluster struct {
	id        int
	n         float64
	w         float64
	s         float64
	instances []string
	occ       map[string]int
}

type Transaction struct {
	cluster  *Cluster
	instance string
	items    []string
}

func remove(array []string, item string) []string {
	var modifiedArray []string
	for i, arrayItem := range array {
		if arrayItem != item {
			modifiedArray = append(modifiedArray, arrayItem)
		} else {
			modifiedArray = append(modifiedArray, array[i+1:]...)
			break
		}
	}
	return modifiedArray
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, instances: make([]string, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
	c.s++
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
	c.s--
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	c.instances = append(c.instances, trans.instance)
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	log.Print(len(c.occ))
	c.n--
	c.instances = remove(c.instances, trans.instance)
	trans.cluster = nil
}

func clusterize(data []*Transaction, repulsion float64) []*Cluster {
	log.Print(data)
	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Print("Start moving")
	for {
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Printf("Finished %v", clusters)
	return clusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)
		log.Printf("Profit max %f", profitMax)
		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.items, repulsion)
			log.Printf("Cluster profit %f", clusterProfit)
			if clusterProfit >= profitMax {
				cluster.addTransaction(transaction)
				return clusters
			}
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}

func main() {
	flag.Parse()
	if *input_file == "" {
		log.Fatal("You must provide input file")
	}
	if *output_dir == "" {
		log.Fatal("You must provide output dir")
	}
	file, err := os.Open(*input_file)
	if err != nil {
		log.Fatalf("Cannot open transaction file at [%s]: [%s]\n", *input_file, err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var transactions []*Transaction
	for {
		line, err := r.ReadString('\n')

		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Fatalf("Error when reading file [%s]: [%s]\n", *input_file, err)
		}
		instance := strings.TrimSuffix(line, "\n")
		items := make([]string, 0)
		visited := make(map[string]bool)
		for _, item := range strings.Split(instance, " ") {
			if _, found := visited[item]; !found {
				items = append(items, item)
				visited[item] = true
			}
		}
		transactions = append(transactions, &Transaction{instance: instance, items: items})
	}
	for _, cluster := range clusterize(transactions, 4.0) {
		file, err := os.Create(fmt.Sprintf("%s/cluster_%d.txt", *output_dir, cluster.id))
		if err != nil {
			log.Fatalf("Cannot open cluster file at [%s]: [%s]\n", *input_file, err)
		}
		for _, instance := range cluster.instances {
			file.WriteString(fmt.Sprintf("%s\n", instance))
		}
		file.Close()
	}
}
<commit_msg>fixed clope algorythm to select best cluster until all transactions are in best clusters<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"strings"
)

var (
	input_file = flag.String("input", "", "Input file with transactions")
	output_dir = flag.String("output", "", "A dir to store created clusters to")
)

type Cluster struct {
	id        int
	n         float64
	w         float64
	s         float64
	instances []string
	occ       map[string]int
}

type Transaction struct {
	cluster  *Cluster
	instance string
	items    []string
}

func remove(array []string, item string) []string {
	var modifiedArray []string
	for i, arrayItem := range array {
		if arrayItem != item {
			modifiedArray = append(modifiedArray, arrayItem)
		} else {
			modifiedArray = append(modifiedArray, array[i+1:]...)
			break
		}
	}
	return modifiedArray
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, instances: make([]string, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
	c.s++
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
	c.s--
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	c.instances = append(c.instances, trans.instance)
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	c.n--
	c.instances = remove(c.instances, trans.instance)
	trans.cluster = nil
}

func clusterize(data []*Transaction, repulsion float64) []*Cluster {

	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	log.Print("Initializing")
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Print("Start moving")
	for {
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Printf("Finished %v", clusters)
	return clusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)

		var bestCluster *Cluster
		var bestProfit float64

		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.items, repulsion)
			if clusterProfit > bestProfit {
				bestCluster = cluster
				bestProfit = clusterProfit
			}
		}
		if bestProfit >= profitMax {
			bestCluster.addTransaction(transaction)
			return clusters
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}

func main() {
	flag.Parse()
	if *input_file == "" {
		log.Fatal("You must provide input file")
	}
	if *output_dir == "" {
		log.Fatal("You must provide output dir")
	}
	file, err := os.Open(*input_file)
	if err != nil {
		log.Fatalf("Cannot open transaction file at [%s]: [%s]\n", *input_file, err)
	}
	defer file.Close()
	r := bufio.NewReader(file)
	var transactions []*Transaction
	for {
		line, err := r.ReadString('\n')

		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Fatalf("Error when reading file [%s]: [%s]\n", *input_file, err)
		}
		instance := strings.TrimSuffix(line, "\n")
		items := make([]string, 0)
		visited := make(map[string]bool)
		for _, item := range strings.Split(instance, " ") {
			if _, found := visited[item]; !found {
				items = append(items, item)
				visited[item] = true
			}
		}
		transactions = append(transactions, &Transaction{instance: instance, items: items})
	}
	for _, cluster := range clusterize(transactions, 4.0) {
		file, err := os.Create(fmt.Sprintf("%s/cluster_%d.txt", *output_dir, cluster.id))
		if err != nil {
			log.Fatalf("Cannot open cluster file at [%s]: [%s]\n", *input_file, err)
		}
		for _, instance := range cluster.instances {
			file.WriteString(fmt.Sprintf("%s\n", instance))
		}
		file.Close()
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "net/http"
import "strings"
import "io/ioutil"
import "github.com/nlopes/slack"
import "os"

type SlackCommand struct {
	team    string
	domain  string
	channel string
	cname   string
	user    string
	uname   string
	command string
	text    string
}

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

	b, _ := ioutil.ReadAll(r.Body)
	data := string(b)
	sc := SlackCommand{}
	for _, v := range strings.Split(data, "&") {
		tokens := strings.Split(v, "=")
		field := tokens[0]
		if field == "team_id" {
			sc.team = tokens[1]
		} else if field == "team_domain" {
			sc.domain = tokens[1]
		} else if field == "channel_id" {
			sc.channel = tokens[1]
		} else if field == "channel_name" {
			sc.cname = tokens[1]
		} else if field == "user_id" {
			sc.user = tokens[1]
		} else if field == "user_name" {
			sc.uname = tokens[1]
		} else if field == "command" {
			sc.command = tokens[1]
		} else if field == "text" {
			sc.text = tokens[1]
		}
	}
	fmt.Println(sc)
	api := slack.New(os.Getenv("SLACK_PROPOSAL_BOT"))
	list, _ := api.GetUsers()
	for _, u := range list {
		if u.ID == sc.user {
			fmt.Println(u)
			fmt.Println(u.Profile)
			break
		}
	}

	/*

		team_id T035N23CL
		team_domain mooon
		channel_id D1KD59XH9
		channel_name directmessage
		user_id U035LF6C1
		user_name aa
		command %2Fpmbot
		text wefwef

			token=FRZTqnWNkEWVWS0YDWEA8LYV&team_id=T035N23CL&team_domain=mooon&channel_id=D1KD59XH9&channel_name=directmessage&user_id=U035LF6C1&user_name=aa&command=%2Fpmbot&text=wefwef&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT035N23CL%2F153490741014%2FX4k1pHZ79iQnX7E0apdW4Aes

			token=FRZTqnWNkEWVWS0YDWEA8LYV&team_id=T035N23CL&team_domain=mooon&channel_id=G3KGJUX7A&channel_name=privategroup&user_id=U035LF6C1&user_name=aa&command=%2Fpmbot&text=here&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT035N23CL%2F152849098884%2F6Wxo8D86YYSXRHdUx9yg2rQb

	*/
	fmt.Fprintf(w, "Hello astaxie!")
}

func main() {
	http.HandleFunc("/pmbot", process)
	err := http.ListenAndServe("0.0.0.0:8080", nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>email<commit_after>package main

import "fmt"
import "net/http"
import "strings"
import "io/ioutil"
import "github.com/nlopes/slack"
import "os"

type SlackCommand struct {
	team    string
	domain  string
	channel string
	cname   string
	user    string
	uname   string
	command string
	text    string
	suser   slack.User
}

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

	b, _ := ioutil.ReadAll(r.Body)
	data := string(b)
	sc := SlackCommand{}
	for _, v := range strings.Split(data, "&") {
		tokens := strings.Split(v, "=")
		field := tokens[0]
		if field == "team_id" {
			sc.team = tokens[1]
		} else if field == "team_domain" {
			sc.domain = tokens[1]
		} else if field == "channel_id" {
			sc.channel = tokens[1]
		} else if field == "channel_name" {
			sc.cname = tokens[1]
		} else if field == "user_id" {
			sc.user = tokens[1]
		} else if field == "user_name" {
			sc.uname = tokens[1]
		} else if field == "command" {
			sc.command = tokens[1]
		} else if field == "text" {
			sc.text = tokens[1]
		}
	}
	fmt.Println(sc)
	api := slack.New(os.Getenv("SLACK_PROPOSAL_BOT"))
	list, _ := api.GetUsers()
	for _, u := range list {
		if u.ID == sc.user {
			sc.suser = u
			break
		}
	}
	fmt.Println(sc.suser.Profile.Email)

	/*

		team_id T035N23CL
		team_domain mooon
		channel_id D1KD59XH9
		channel_name directmessage
		user_id U035LF6C1
		user_name aa
		command %2Fpmbot
		text wefwef

			token=FRZTqnWNkEWVWS0YDWEA8LYV&team_id=T035N23CL&team_domain=mooon&channel_id=D1KD59XH9&channel_name=directmessage&user_id=U035LF6C1&user_name=aa&command=%2Fpmbot&text=wefwef&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT035N23CL%2F153490741014%2FX4k1pHZ79iQnX7E0apdW4Aes

			token=FRZTqnWNkEWVWS0YDWEA8LYV&team_id=T035N23CL&team_domain=mooon&channel_id=G3KGJUX7A&channel_name=privategroup&user_id=U035LF6C1&user_name=aa&command=%2Fpmbot&text=here&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT035N23CL%2F152849098884%2F6Wxo8D86YYSXRHdUx9yg2rQb

	*/
	fmt.Fprintf(w, "Hello astaxie!")
}

func main() {
	http.HandleFunc("/pmbot", process)
	err := http.ListenAndServe("0.0.0.0:8080", nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strings"
	"time"

	"github.com/satori/go.uuid"
	"github.com/urfave/cli"
)

var (
	logger             = log.New(os.Stderr, "", log.LstdFlags)
	app       *cli.App = cli.NewApp()
	builddate string
)

var globalFlags = struct {
	Brokers  []string
	Topic    []string
	Offset   string
	Groupid  string
	Verbose  bool
	Port     string
	Lifetime time.Duration
}{}

func main() {
	app.Name = "kafkalogs"
	app.Usage = "kafkalogs is a tool to tail a kafka stream for json based log entries"
	app.Version = builddate

	id, _ := uuid.NewV4()

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "port",
			Usage:  "Port where the service listens for health check requests",
			EnvVar: "PORT",
			Value:  "8080",
		},
		cli.DurationFlag{
			Name:   "lifetime",
			Usage:  "Mark service unhealthty after this time",
			EnvVar: "LIFETIME",
			Value:  0,
		},
		cli.StringFlag{
			Name:   "brokers",
			Usage:  "The comma separated list of brokers in the Kafka cluster",
			EnvVar: "LOGTAIL_KAFKA_BROKERS",
		},
		cli.StringFlag{
			Name:   "topic",
			Usage:  "Kafka topic to listen",
			EnvVar: "LOGTAIL_KAFKA_TOPIC",
		},
		cli.StringFlag{
			Name:   "groupid",
			Usage:  "Consumer group identifier",
			EnvVar: "LOGTAIL_KAFKA_GROUPID",
			Value:  id.String(),
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "Use verbose logging",
			EnvVar: "VERBOSE",
		},
	}

	app.Before = func(c *cli.Context) error {

		globalFlags.Brokers = strings.Split(c.String("brokers"), ",")
		globalFlags.Topic = strings.Split(c.String("topic"), ",")
		globalFlags.Offset = c.String("offset")
		globalFlags.Groupid = c.String("groupid")
		globalFlags.Port = c.String("port")
		globalFlags.Lifetime = c.Duration("lifetime")
		globalFlags.Verbose = c.Bool("verbose")

		logger.Printf("Logtail starting with options %+v\n", globalFlags)

		return nil
	}

	app.Run(os.Args)
}
<commit_msg>Revert uuid logic to be whatever it was before<commit_after>package main

import (
	"log"
	"os"
	"strings"
	"time"

	"github.com/satori/go.uuid"
	"github.com/urfave/cli"
)

var (
	logger             = log.New(os.Stderr, "", log.LstdFlags)
	app       *cli.App = cli.NewApp()
	builddate string
)

var globalFlags = struct {
	Brokers  []string
	Topic    []string
	Offset   string
	Groupid  string
	Verbose  bool
	Port     string
	Lifetime time.Duration
}{}

func main() {
	app.Name = "kafkalogs"
	app.Usage = "kafkalogs is a tool to tail a kafka stream for json based log entries"
	app.Version = builddate

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "port",
			Usage:  "Port where the service listens for health check requests",
			EnvVar: "PORT",
			Value:  "8080",
		},
		cli.DurationFlag{
			Name:   "lifetime",
			Usage:  "Mark service unhealthty after this time",
			EnvVar: "LIFETIME",
			Value:  0,
		},
		cli.StringFlag{
			Name:   "brokers",
			Usage:  "The comma separated list of brokers in the Kafka cluster",
			EnvVar: "LOGTAIL_KAFKA_BROKERS",
		},
		cli.StringFlag{
			Name:   "topic",
			Usage:  "Kafka topic to listen",
			EnvVar: "LOGTAIL_KAFKA_TOPIC",
		},
		cli.StringFlag{
			Name:   "groupid",
			Usage:  "Consumer group identifier",
			EnvVar: "LOGTAIL_KAFKA_GROUPID",
			Value:  uuid.NewV4().String(),
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "Use verbose logging",
			EnvVar: "VERBOSE",
		},
	}

	app.Before = func(c *cli.Context) error {

		globalFlags.Brokers = strings.Split(c.String("brokers"), ",")
		globalFlags.Topic = strings.Split(c.String("topic"), ",")
		globalFlags.Offset = c.String("offset")
		globalFlags.Groupid = c.String("groupid")
		globalFlags.Port = c.String("port")
		globalFlags.Lifetime = c.Duration("lifetime")
		globalFlags.Verbose = c.Bool("verbose")

		logger.Printf("Logtail starting with options %+v\n", globalFlags)

		return nil
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "assets/paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/{clone}/{pasteId}", cloneHandler)
	router.HandleFunc("/{download}/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Correct template name<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/{clone}/{pasteId}", cloneHandler)
	router.HandleFunc("/{download}/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
)

const (
	protocolVersion = `0.1.3`
	cliVersion      = `0.1.5`
)

var (
	messageQueue  = make(chan *message, 10)
	devices       *deviceList
	installFlag   bool
	developerFlag bool
	versionFlag   bool
	devicesFlag   bool
)

type message struct {
	ID   string          `json:"id,omitempty"`
	Type messageType     `json:"type"`
	Data json.RawMessage `json:"data,omitempty"`
}

func writePump(ch <-chan *message) {
	var (
		enc = newEncoder(os.Stdout)
		err error
	)

	for msg := range ch {
		switch msg.Type {
		case typeDevices:
			out := &message{
				ID:   msg.ID,
				Type: typeDevices,
			}
			if out.Data, err = json.Marshal(devices.all()); err != nil {
				log(err)
				continue
			}
			if err = enc.Encode(out); err != nil {
				log(err)
				continue
			}
		case typeShare:
			share := &messageShare{}
			if err = json.Unmarshal(msg.Data, &share); err != nil {
				log(err)
				continue
			}
			if dev, ok := devices.get(share.Target); ok {
				if err = dev.share(share.URL); err != nil {
					log(err)
					continue
				}
			}
		case typeDeviceUpdate:
			if err = enc.Encode(msg); err != nil {
				log(err)
				continue
			}
		case typeVersion:
			out := &message{
				Type: typeVersion,
			}
			if out.Data, err = json.Marshal(protocolVersion); err != nil {
				log(err)
				continue
			}
			if err = enc.Encode(out); err != nil {
				log(err)
				continue
			}
		case typeError:
			log(fmt.Errorf("typeError: %+v", msg))
		default:
			log(fmt.Errorf("Unhandled message type: %+v", msg.Type))
		}
	}
}

func readPump(ch chan<- *message) {
	defer close(ch)
	dec := newDecoder(os.Stdin)
	for {
		msg := &message{}
		if err := dec.Decode(msg); err != nil {
			if err == io.EOF {
				return
			}
			log(err)
			continue
		}
		ch <- msg
	}
}

func log(err error) {
	if _, e := fmt.Fprintln(os.Stderr, err); e != nil {
		panic(e)
	}
}

func init() {
	var err error

	flag.BoolVar(&installFlag, `install`, false, `Perform installation`)
	flag.BoolVar(&developerFlag, `dev`, false, `Install as developer`)
	flag.BoolVar(&versionFlag, `version`, false, `Display version`)
	flag.BoolVar(&devicesFlag, `devices`, false, `Display visible devices`)
	flag.Parse()

	if devices, err = newDeviceList(); err != nil {
		panic(err)
	}
}

func main() {
	if versionFlag {
		fmt.Printf("kdeconnect-chrome-extension version %s, built with %s\n", cliVersion, runtime.Version())
		os.Exit(0)
	}

	if installFlag {
		if err := install(developerFlag); err != nil {
			panic(err)
		}
		os.Exit(0)
	}

	if err := devices.getDevices(); err != nil {
		log(err)
	}

	if devicesFlag {
		for _, dev := range devices.devices {
			fmt.Printf("- %s: %s (paired: %v; reachable: %v)\n", dev.Name, dev.ID, dev.IsTrusted, dev.IsReachable)
		}
		os.Exit(0)
	}

	go writePump(messageQueue)
	readPump(messageQueue)

	shutdown()
}

func shutdown() {
	if err := devices.Close(); err != nil {
		panic(err)
	}
}
<commit_msg>Add protocol version to version output<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
)

const (
	protocolVersion = `0.1.3`
	cliVersion      = `0.1.5`
)

var (
	messageQueue  = make(chan *message, 10)
	devices       *deviceList
	installFlag   bool
	developerFlag bool
	versionFlag   bool
	devicesFlag   bool
)

type message struct {
	ID   string          `json:"id,omitempty"`
	Type messageType     `json:"type"`
	Data json.RawMessage `json:"data,omitempty"`
}

func writePump(ch <-chan *message) {
	var (
		enc = newEncoder(os.Stdout)
		err error
	)

	for msg := range ch {
		switch msg.Type {
		case typeDevices:
			out := &message{
				ID:   msg.ID,
				Type: typeDevices,
			}
			if out.Data, err = json.Marshal(devices.all()); err != nil {
				log(err)
				continue
			}
			if err = enc.Encode(out); err != nil {
				log(err)
				continue
			}
		case typeShare:
			share := &messageShare{}
			if err = json.Unmarshal(msg.Data, &share); err != nil {
				log(err)
				continue
			}
			if dev, ok := devices.get(share.Target); ok {
				if err = dev.share(share.URL); err != nil {
					log(err)
					continue
				}
			}
		case typeDeviceUpdate:
			if err = enc.Encode(msg); err != nil {
				log(err)
				continue
			}
		case typeVersion:
			out := &message{
				Type: typeVersion,
			}
			if out.Data, err = json.Marshal(protocolVersion); err != nil {
				log(err)
				continue
			}
			if err = enc.Encode(out); err != nil {
				log(err)
				continue
			}
		case typeError:
			log(fmt.Errorf("typeError: %+v", msg))
		default:
			log(fmt.Errorf("Unhandled message type: %+v", msg.Type))
		}
	}
}

func readPump(ch chan<- *message) {
	defer close(ch)
	dec := newDecoder(os.Stdin)
	for {
		msg := &message{}
		if err := dec.Decode(msg); err != nil {
			if err == io.EOF {
				return
			}
			log(err)
			continue
		}
		ch <- msg
	}
}

func log(err error) {
	if _, e := fmt.Fprintln(os.Stderr, err); e != nil {
		panic(e)
	}
}

func init() {
	var err error

	flag.BoolVar(&installFlag, `install`, false, `Perform installation`)
	flag.BoolVar(&developerFlag, `dev`, false, `Install as developer`)
	flag.BoolVar(&versionFlag, `version`, false, `Display version`)
	flag.BoolVar(&devicesFlag, `devices`, false, `Display visible devices`)
	flag.Parse()

	if devices, err = newDeviceList(); err != nil {
		panic(err)
	}
}

func main() {
	if versionFlag {
		fmt.Printf("kdeconnect-chrome-extension version %s (protocol %s), built with %s\n", cliVersion, protocolVersion, runtime.Version())
		os.Exit(0)
	}

	if installFlag {
		if err := install(developerFlag); err != nil {
			panic(err)
		}
		os.Exit(0)
	}

	if err := devices.getDevices(); err != nil {
		log(err)
	}

	if devicesFlag {
		for _, dev := range devices.devices {
			fmt.Printf("- %s: %s (paired: %v; reachable: %v)\n", dev.Name, dev.ID, dev.IsTrusted, dev.IsReachable)
		}
		os.Exit(0)
	}

	go writePump(messageQueue)
	readPump(messageQueue)

	shutdown()
}

func shutdown() {
	if err := devices.Close(); err != nil {
		panic(err)
	}
}
<|endoftext|>


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

package main

import (
	"flag"

	"github.com/google/gxui"
	"github.com/google/gxui/drivers/gl"
	"github.com/google/gxui/math"
	"github.com/google/gxui/themes/dark"

	"image"
	"log"
	"os"

	"fmt"

	"github.com/kyokomi/gomajan/pai"
	"github.com/kyokomi/gomajan/player"
	"github.com/kyokomi/gomajan/taku"
)

type State int

const (
	InitState       State = 0
	PlayerTurnState State = 1
	CPUTurnState    State = 2
)

type MainWindow struct {
	gxui.Window
	theme  gxui.Theme
	driver gxui.Driver
}

func NewMainWindow(driver gxui.Driver) MainWindow {
	var mainWindow MainWindow
	theme := dark.CreateTheme(driver)
	window := theme.CreateWindow(1200, 800, "gxjan")

	mainWindow.Window = window
	mainWindow.theme = theme
	mainWindow.driver = driver

	return mainWindow
}

var _state State
var _taku *taku.Taku
var _yamaImage [4][2][17]*PaiImage

var _playerContainer [4]gxui.LinearLayout

func ChangeState(state State) {
	beforeState := _state
	_state = state

	if beforeState == PlayerTurnState && state == CPUTurnState {
		// playerTurn -> CPUTurn
		EventCPU(2)
		EventCPU(3)
		EventCPU(4)
		ChangeState(PlayerTurnState)
	}
}

func NowState() State {
	return _state
}

func EventCPU(playerID int) {
	// 1枚引いて
	mjPai := nextFunc(playerID)

	// 1枚捨てる
	p := Player(playerID)
	p.PaiInc(mjPai)
	_window.nextPaiImage(_playerContainer[playerID-1], playerID, mjPai)

	yakuCheck := p.NewYakuCheck(mjPai)
	if yakuCheck.Is和了() {
		fmt.Println("アガリ: ", yakuCheck.String())
		return
	}
	fmt.Println("チェック: ", yakuCheck.String())

	for _, noko := range yakuCheck.MentsuCheck().Nokori() {
		if noko.Pai.Type() == pai.NoneType || noko.Val == 0 {
			continue
		}

		fmt.Println("捨てた牌: ", noko.Pai)
		p.PaiDec(noko.Pai)

		for i := 0; i < _playerContainer[playerID-1].ChildCount(); i++ {
			paiImage := _playerContainer[playerID-1].ChildAt(i).(PaiImage)
			if paiImage.Pai == noko.Pai {
				_playerContainer[playerID-1].RemoveChildAt(i)
				_sutehaiLayers[playerID-1].AddChild(paiImage)
				break
			}
		}
		break
	}
}

var _window MainWindow
var _sutehaiLayers [4]gxui.LinearLayout

func appMain(driver gxui.Driver) {
	_window = NewMainWindow(driver)

	ChangeState(InitState)

	_taku = taku.NewTaku()

	// TODO: Splitterにしてみた
	rootLayer := _window.Theme().CreateSplitterLayout()
	//	rootLayer.SetOrientation(gxui.TopToBottom)
	//	rootLayer.SetVerticalAlignment(gxui.AlignTop)

	// 手牌
	{
		playLayer := _window.Theme().CreateSplitterLayout()
		playLayer.SetOrientation(gxui.Horizontal)

		tehaiLayer := _window.Theme().CreateLinearLayout()
		tehaiLayer.SetDirection(gxui.TopToBottom)
		tehaiLayer.SetVerticalAlignment(gxui.AlignTop)
		tehaiLayer.SetMargin(math.CreateSpacing(20))

		sutehaiLayer := _window.Theme().CreateLinearLayout()
		sutehaiLayer.SetDirection(gxui.TopToBottom)
		sutehaiLayer.SetVerticalAlignment(gxui.AlignTop)
		sutehaiLayer.SetMargin(math.CreateSpacing(20))

		for _, player := range _taku.Players {
			container := _window.Theme().CreateLinearLayout()
			container.SetDirection(gxui.LeftToRight)
			container.SetHorizontalAlignment(gxui.AlignCenter)

			for _, hai := range player.Tiles() {
				if hai.Pai.Type() == pai.NoneType || hai.Val <= 0 {
					continue
				}

				for i := 0; i < hai.Val; i++ {
					_window.nextPaiImage(container, player.PlayerID(), hai.Pai)
				}
			}
			container.SetMargin(math.CreateSpacing(10))
			tehaiLayer.AddChild(container)
			_playerContainer[player.PlayerID()-1] = container

			suteContainer := _window.Theme().CreateLinearLayout()
			suteContainer.SetDirection(gxui.LeftToRight)
			suteContainer.SetHorizontalAlignment(gxui.AlignCenter)
			suteContainer.SetMargin(math.CreateSpacing(10))

			_sutehaiLayers[player.PlayerID()-1] = suteContainer
			sutehaiLayer.AddChild(suteContainer)
		}
		playLayer.AddChild(tehaiLayer)
		playLayer.SetChildWeight(tehaiLayer, 0.5)

		playLayer.AddChild(sutehaiLayer)
		playLayer.SetChildWeight(sutehaiLayer, 0.5)

		rootLayer.AddChild(playLayer)
		rootLayer.SetChildWeight(playLayer, 0.4)
	}

	// 山
	{
		yamaLayer := _window.Theme().CreateLinearLayout()
		yamaLayer.SetDirection(gxui.TopToBottom)
		yamaLayer.SetVerticalAlignment(gxui.AlignTop)
		yamaLayer.SetMargin(math.CreateSpacing(20))

		for i, 山2 := range _taku.Yama {
			container := _window.Theme().CreateLinearLayout()
			container.SetDirection(gxui.TopToBottom)
			container.SetVerticalAlignment(gxui.AlignTop)
			for j, 山 := range 山2 {
				container2 := _window.Theme().CreateLinearLayout()
				container2.SetDirection(gxui.LeftToRight)
				container2.SetHorizontalAlignment(gxui.AlignCenter)
				for k, 牌 := range 山 {
					if 牌.Type() == pai.NoneType {
						continue
					}

					imagePai := _window.createPaiImage(牌)
					if _taku.YamaMask[i][j][k] != 0 {
						imagePai.SetVisible(false)
					}
					_yamaImage[i][j][k] = &imagePai
					container2.AddChild(imagePai)
				}
				container2.SetMargin(math.CreateSpacing(1))
				container.AddChild(container2)
			}
			container.SetMargin(math.CreateSpacing(4))
			yamaLayer.AddChild(container)
		}
		rootLayer.AddChild(yamaLayer)
		rootLayer.SetChildWeight(yamaLayer, 0.6)
	}

	//	label := window.Theme().CreateLabel()
	//	label.SetText("hogehogehoge")
	//	label.SetMargin(math.CreateSpacing(200))
	//	container.AddChild(label)
	_window.AddChild(rootLayer)
	_window.OnClose(driver.Terminate)

	ChangeState(PlayerTurnState)

	gxui.EventLoop(driver)
}

func (m MainWindow) Theme() gxui.Theme {
	return m.theme
}

type PaiImage struct {
	gxui.Image
	Pai pai.MJP
}

func (m MainWindow) createPaiImage(p pai.MJP) PaiImage {
	f, err := os.Open("data/pai-images/" + imageMappings[p])
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()
	im, _, err := image.Decode(f)
	if err != nil {
		log.Fatalln(err)
	}

	pict := m.theme.CreateImage()
	texture := m.driver.CreateTexture(im, 96)
	pict.SetTexture(texture)
	pict.SetExplicitSize(math.Size{32, 45})
	//	pict.SetMargin(math.CreateSpacing(4))

	return PaiImage{Image: pict, Pai: p}
}

var ueshita = 1 // ちょんちょん後の下段からなので1

func nextFunc(playerID int) pai.MJP {
	if ueshita == 2 {
		_taku.Add列And山越しFunc(1)
		ueshita = 0
	}

	p := _taku.Next(ueshita, playerID)

	// 引いた牌を非表示
	_yamaImage[_taku.PlayYamaIndex][ueshita][_taku.PlayRetuIndex].SetVisible(false)

	ueshita++
	return p
}

func Player(playerID int) *player.Player {
	for _, p := range _taku.Players {
		if p.PlayerID() == playerID {
			return &p
		}
	}
	return nil
}

func (m MainWindow) nextPaiImage(container gxui.LinearLayout, playerID int, mjPai pai.MJP) {
	paiImage := m.createPaiImage(mjPai)

	fmt.Println("nextPaiImage", playerID)
	// TODO: player1だけ操作可能にする
	if playerID == 1 {
		paiImage.OnClick(func(e gxui.MouseEvent) {
			ChangeState(CPUTurnState)

			fmt.Println("OnClick", playerID)

			Player(playerID).PaiDec(paiImage.Pai)
			container.RemoveChild(paiImage)

			_sutehaiLayers[playerID-1].AddChild(paiImage)

			nextPai := nextFunc(playerID)
			Player(playerID).PaiInc(nextPai)
			m.nextPaiImage(container, playerID, nextPai)
		})
	}

	for i := 0; i < container.ChildCount(); i++ {
		if container.ChildAt(i).(PaiImage).Pai > paiImage.Pai {
			container.AddChildAt(i, paiImage)
			return
		}
	}
	container.AddChild(paiImage)
}

func main() {
	flag.Parse()
	gl.StartDriver(appMain)
}
<commit_msg>上がり判定とゲーム終了実装<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"

	"github.com/google/gxui"
	"github.com/google/gxui/drivers/gl"
	"github.com/google/gxui/math"
	"github.com/google/gxui/themes/dark"

	"image"
	"log"
	"os"

	"fmt"

	"github.com/kyokomi/gomajan/pai"
	"github.com/kyokomi/gomajan/player"
	"github.com/kyokomi/gomajan/taku"
)

type State int

const (
	InitState       State = 0
	PlayerTurnState State = 1
	CPUTurnState    State = 2
	EndState        State = 3
)

type MainWindow struct {
	gxui.Window
	theme  gxui.Theme
	driver gxui.Driver
}

func NewMainWindow(driver gxui.Driver) MainWindow {
	var mainWindow MainWindow
	theme := dark.CreateTheme(driver)
	window := theme.CreateWindow(1200, 800, "gxjan")

	mainWindow.Window = window
	mainWindow.theme = theme
	mainWindow.driver = driver

	return mainWindow
}

var _state State
var _taku *taku.Taku
var _yamaImage [4][2][17]*PaiImage

var _playerContainer [4]gxui.LinearLayout

func ChangeState(state State) {
	beforeState := _state
	_state = state

	if beforeState == PlayerTurnState && state == CPUTurnState {
		// playerTurn -> CPUTurn
		EventCPU(2)
		EventCPU(3)
		EventCPU(4)
		ChangeState(PlayerTurnState)
	} else if state == EndState {
		fmt.Println("終了")
	}
}

func GameEnd() bool {
	return _state == EndState
}

func NowState() State {
	return _state
}

func EventCPU(playerID int) {
	// 1枚引いて
	mjPai := nextFunc(playerID)

	// 1枚捨てる
	p := Player(playerID)
	p.PaiInc(mjPai)
	_window.nextPaiImage(_playerContainer[playerID-1], playerID, mjPai)

	yakuCheck := p.NewYakuCheck(mjPai)
	if yakuCheck.Is和了() {
		fmt.Println("アガリ: ", yakuCheck.String())
		return
	}
	fmt.Println("チェック: ", yakuCheck.String())

	for _, noko := range yakuCheck.MentsuCheck().Nokori() {
		if noko.Pai.Type() == pai.NoneType || noko.Val == 0 {
			continue
		}

		fmt.Println("捨てた牌: ", noko.Pai)
		p.PaiDec(noko.Pai)

		for i := 0; i < _playerContainer[playerID-1].ChildCount(); i++ {
			paiImage := _playerContainer[playerID-1].ChildAt(i).(PaiImage)
			if paiImage.Pai == noko.Pai {
				_playerContainer[playerID-1].RemoveChildAt(i)
				_sutehaiLayers[playerID-1].AddChild(paiImage)
				break
			}
		}
		break
	}
}

var _window MainWindow
var _sutehaiLayers [4]gxui.LinearLayout

func appMain(driver gxui.Driver) {
	_window = NewMainWindow(driver)

	ChangeState(InitState)

	_taku = taku.NewTaku()

	// TODO: Splitterにしてみた
	rootLayer := _window.Theme().CreateSplitterLayout()
	//	rootLayer.SetOrientation(gxui.TopToBottom)
	//	rootLayer.SetVerticalAlignment(gxui.AlignTop)

	// 手牌
	{
		playLayer := _window.Theme().CreateSplitterLayout()
		playLayer.SetOrientation(gxui.Horizontal)

		tehaiLayer := _window.Theme().CreateLinearLayout()
		tehaiLayer.SetDirection(gxui.TopToBottom)
		tehaiLayer.SetVerticalAlignment(gxui.AlignTop)
		tehaiLayer.SetMargin(math.CreateSpacing(20))

		sutehaiLayer := _window.Theme().CreateLinearLayout()
		sutehaiLayer.SetDirection(gxui.TopToBottom)
		sutehaiLayer.SetVerticalAlignment(gxui.AlignTop)
		sutehaiLayer.SetMargin(math.CreateSpacing(20))

		for _, player := range _taku.Players {
			container := _window.Theme().CreateLinearLayout()
			container.SetDirection(gxui.LeftToRight)
			container.SetHorizontalAlignment(gxui.AlignCenter)

			for _, hai := range player.Tiles() {
				if hai.Pai.Type() == pai.NoneType || hai.Val <= 0 {
					continue
				}

				for i := 0; i < hai.Val; i++ {
					_window.nextPaiImage(container, player.PlayerID(), hai.Pai)
				}
			}
			container.SetMargin(math.CreateSpacing(10))
			tehaiLayer.AddChild(container)
			_playerContainer[player.PlayerID()-1] = container

			suteContainer := _window.Theme().CreateLinearLayout()
			suteContainer.SetDirection(gxui.LeftToRight)
			suteContainer.SetHorizontalAlignment(gxui.AlignCenter)
			suteContainer.SetMargin(math.CreateSpacing(10))

			_sutehaiLayers[player.PlayerID()-1] = suteContainer
			sutehaiLayer.AddChild(suteContainer)
		}
		playLayer.AddChild(tehaiLayer)
		playLayer.SetChildWeight(tehaiLayer, 0.5)

		playLayer.AddChild(sutehaiLayer)
		playLayer.SetChildWeight(sutehaiLayer, 0.5)

		rootLayer.AddChild(playLayer)
		rootLayer.SetChildWeight(playLayer, 0.4)
	}

	// 山
	{
		yamaLayer := _window.Theme().CreateLinearLayout()
		yamaLayer.SetDirection(gxui.TopToBottom)
		yamaLayer.SetVerticalAlignment(gxui.AlignTop)
		yamaLayer.SetMargin(math.CreateSpacing(20))

		for i, 山2 := range _taku.Yama {
			container := _window.Theme().CreateLinearLayout()
			container.SetDirection(gxui.TopToBottom)
			container.SetVerticalAlignment(gxui.AlignTop)
			for j, 山 := range 山2 {
				container2 := _window.Theme().CreateLinearLayout()
				container2.SetDirection(gxui.LeftToRight)
				container2.SetHorizontalAlignment(gxui.AlignCenter)
				for k, 牌 := range 山 {
					if 牌.Type() == pai.NoneType {
						continue
					}

					imagePai := _window.createPaiImage(牌)
					if _taku.YamaMask[i][j][k] != 0 {
						imagePai.SetVisible(false)
					}
					_yamaImage[i][j][k] = &imagePai
					container2.AddChild(imagePai)
				}
				container2.SetMargin(math.CreateSpacing(1))
				container.AddChild(container2)
			}
			container.SetMargin(math.CreateSpacing(4))
			yamaLayer.AddChild(container)
		}
		rootLayer.AddChild(yamaLayer)
		rootLayer.SetChildWeight(yamaLayer, 0.6)
	}

	//	label := window.Theme().CreateLabel()
	//	label.SetText("hogehogehoge")
	//	label.SetMargin(math.CreateSpacing(200))
	//	container.AddChild(label)
	_window.AddChild(rootLayer)
	_window.OnClose(driver.Terminate)

	ChangeState(PlayerTurnState)

	gxui.EventLoop(driver)
}

func (m MainWindow) Theme() gxui.Theme {
	return m.theme
}

type PaiImage struct {
	gxui.Image
	Pai pai.MJP
}

func (m MainWindow) createPaiImage(p pai.MJP) PaiImage {
	f, err := os.Open("data/pai-images/" + imageMappings[p])
	if err != nil {
		log.Fatalln(err)
	}
	defer f.Close()
	im, _, err := image.Decode(f)
	if err != nil {
		log.Fatalln(err)
	}

	pict := m.theme.CreateImage()
	texture := m.driver.CreateTexture(im, 96)
	pict.SetTexture(texture)
	pict.SetExplicitSize(math.Size{32, 45})
	//	pict.SetMargin(math.CreateSpacing(4))

	return PaiImage{Image: pict, Pai: p}
}

var ueshita = 1 // ちょんちょん後の下段からなので1

func nextFunc(playerID int) pai.MJP {
	if ueshita == 2 {
		_taku.Add列And山越しFunc(1)
		ueshita = 0
	}

	p := _taku.Next(ueshita, playerID)

	// 引いた牌を非表示
	_yamaImage[_taku.PlayYamaIndex][ueshita][_taku.PlayRetuIndex].SetVisible(false)

	ueshita++
	return p
}

func Player(playerID int) *player.Player {
	for _, p := range _taku.Players {
		if p.PlayerID() == playerID {
			return &p
		}
	}
	return nil
}

func (m MainWindow) nextPaiImage(container gxui.LinearLayout, playerID int, mjPai pai.MJP) {
	paiImage := m.createPaiImage(mjPai)

	fmt.Println("nextPaiImage", playerID)
	// TODO: player1だけ操作可能にする
	if playerID == 1 {
		paiImage.OnClick(func(e gxui.MouseEvent) {
			if GameEnd() {
				return
			}
			ChangeState(CPUTurnState)

			fmt.Println("OnClick", playerID, paiImage.Pai)

			Player(playerID).PaiDec(paiImage.Pai)
			container.RemoveChild(paiImage)

			_sutehaiLayers[playerID-1].AddChild(paiImage)

			nextPai := nextFunc(playerID)
			Player(playerID).PaiInc(nextPai)
			m.nextPaiImage(container, playerID, nextPai)
		})
	}

	for i := 0; i < container.ChildCount(); i++ {
		if container.ChildAt(i).(PaiImage).Pai > paiImage.Pai {
			container.AddChildAt(i, paiImage)
			return
		}
	}
	container.AddChild(paiImage)

	// TODO: 明かり判定
	if playerID == 1 {
		p := Player(playerID)
		yakuCheck := p.NewYakuCheck(mjPai)
		if yakuCheck.Is和了() {
			fmt.Println("!!! Player アガリ: ", yakuCheck.String())
			ChangeState(EndState)
			return
		}
		fmt.Println("!!! Player チェック: ", yakuCheck.String())
	}
}

func main() {
	flag.Parse()
	gl.StartDriver(appMain)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"text/template"
	"time"

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

var quitProgram = false

func renderTemplate(filename string, tmplFile string, data interface{}) (err error) {
	tmpl, err := template.ParseFiles(tmplFile)
	if err != nil {
		return
	}
	fd, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer fd.Close()
	err = tmpl.Execute(fd, data)
	return
}

func renderWithDefault(tmplFile string, defaultTmpl []byte, data interface{}) (out string, err error) {
	buf := &bytes.Buffer{}
	if !fileExists(tmplFile) {
		ioutil.WriteFile(tmplFile, defaultTmpl, 0644)
	}
	tmpl, err := template.ParseFiles(tmplFile)
	if err != nil {
		return
	}
	err = tmpl.Execute(buf, data)
	return string(buf.Bytes()), err
}

func renderFileWithDefault(filename string, tmplFile string, defaultTmpl []byte, data interface{}) (err error) {
	if !fileExists(tmplFile) {
		ioutil.WriteFile(tmplFile, defaultTmpl, 0644)
	}
	return renderTemplate(filename, tmplFile, data)
}

func dumpFile(filename string, data interface{}) (err error) {
	out, err := goyaml.Marshal(data)
	if err != nil {
		return
	}
	return ioutil.WriteFile(filename, out, 0644)
}

func loadFile(filename string, data interface{}) (err error) {
	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	return goyaml.Unmarshal(raw, data)
}

func ignore(info os.FileInfo) bool {
	if info.IsDir() {
		if info.Name() != "." && info.Name() != ".." &&
			strings.HasPrefix(info.Name(), ".") { // ignore hidden dir
			return true
		}
	} else {
		return strings.HasPrefix(info.Name(), ".")
	}
	return false
}

func pathWalk(path string, depth int) (files []string, err error) {
	files = make([]string, 0)
	baseNumSeps := strings.Count(path, string(os.PathSeparator))
	err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			pathDepth := strings.Count(path, string(os.PathSeparator)) - baseNumSeps
			// FIXME: there is bug here
			if pathDepth > depth {
				return filepath.SkipDir
			}
			if ignore(info) {
				return filepath.SkipDir
			}
		} else if info.Mode().IsRegular() && !ignore(info) {
			if matched, _ := regexp.Match(mycnf.Include, []byte(info.Name())); matched {
				files = append(files, path)
			}
		}
		return nil
	})
	return
}

type GlobalConfig struct {
	Replacer string `yaml:"-"` //short:"i" description:"replacer"`
	Command  string `short:"c" description:"specify how to process each file"`
	Include  string `short:"I" long:"include-regex" description:"regex set which file can be included"`
	Path     string `short:"p" long:"path" description:"path for search"`
	Depth    int    `short:"d" long:"depth" description:"depth to travel directory tree"`
	Verbose  bool   `short:"v" long:"verbose" description:"show verbose output"`
	Result   string `yaml:"report-html" short:"H" long:"out-html" description:"output result as html"`
	Timeout  string `short:"t" long:"timeout" description:"timeout for each exec"`
	Reload   bool   `short:"r" long:"reload" description:"reload all failed cmd, run again:"`
	Exclude  string `yaml:"-"`

	Version  bool     `yaml:"-"`
	InitYaml bool     `yaml:"-" long:"init" description:"create a sample .trival.yml and exit"`
	Notify   []string `yaml:"notify" long:"notify" description:"notify people when task finish"`
}

var mycnf = &GlobalConfig{
	Depth:    0,
	Path:     "./",
	Replacer: "{}",
	Version:  false,
	Result:   "test.html",
	Timeout:  "30m",
	Command:  "./{}",
	Include:  ".*",
	Verbose:  false,
}

func init() {
	if fileExists(".travel.yml") {
		loadFile(".travel.yml", mycnf)
	}
	args, err := flags.Parse(mycnf)
	_, _ = args, err
	if err != nil {
		if er, ok := err.(*flags.Error); ok && er.Type == flags.ErrHelp {
			os.Exit(0)
		}
		log.Fatal(err)
	}
	if mycnf.InitYaml {
		dumpFile(".travel.yml", mycnf)
		os.Exit(0)
	}
	if mycnf.Version {
		fmt.Println(VERSION)
		os.Exit(0)
	}
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type TaskConfig struct {
	Replacer string
	Command  string
	Timeout  time.Duration
	Files    []string
}

type TaskResult struct {
	StartTime string
	TimeCost  time.Duration
	Command   string
	Filename  string
	Output    string // console out
	Source    string // source code
	Error     error
}

func Go(f func() error) chan error {
	ch := make(chan error)
	go func() {
		err := f()
		ch <- err
	}()
	return ch
}

func groupKill(cmd *exec.Cmd) (err error) {
	var pid, pgid int
	if cmd.Process != nil {
		pid = cmd.Process.Pid
		c := exec.Command("/bin/ps", "-o", "pgid", "-p", strconv.Itoa(pid), "--no-header")
		var out []byte
		out, err = c.Output()
		if err != nil {
			return
		}
		_, err = fmt.Sscanf(string(out), "%d", &pgid)
		if err != nil {
			return
		}
		err = exec.Command("/bin/kill", "-TERM", "-"+strconv.Itoa(pgid)).Run()
	}
	return
}

func work(cfg *TaskConfig) (results []TaskResult) {
	var err error
	results = []TaskResult{}
	for i, file := range cfg.Files {
		start := time.Now()
		r := TaskResult{
			StartTime: start.Format("15:04:05"),
			Filename:  file,
		}
		c := strings.Replace(cfg.Command, cfg.Replacer, file, -1)
		r.Command = c
		if quitProgram {
			r.Error = errors.New("not started, skiped for SIGINT interrupt")
			results = append(results, r)
			break
		}

		prefix := fmt.Sprintf("\r\033[36m>>>\033[0m %-5d", i)
		format := fmt.Sprintf(prefix+"%%-14v %-24s\n", c) //file) //file)
		// show current exec file
		fmt.Printf(prefix+"exec %s ...", strconv.Quote(file))
		if mycnf.Verbose {
			fmt.Printf("\n")
		}

		output := bytes.NewBuffer(nil)
		cmd := exec.Command("/bin/bash", "-c", c)
		if mycnf.Verbose {
			cmd.Stdout = io.MultiWriter(os.Stdout, output)
			cmd.Stderr = io.MultiWriter(os.Stderr, output)
		} else {
			cmd.Stdout = output
			cmd.Stderr = output
		}
		cmd.SysProcAttr = &syscall.SysProcAttr{}
		cmd.SysProcAttr.Setpgid = true

		// handle timeout
		if err = cmd.Start(); err == nil {
			select {
			case <-sigC:
				quitProgram = true
				groupKill(cmd)
				err = errors.New("signal: interrupt")
			case <-time.After(cfg.Timeout):
				//cmd.Process.Kill()
				groupKill(cmd)
				err = errors.New("signal: terminated")
			case err = <-Go(cmd.Wait):
			}
		}

		if err != nil {
			r.Error = err
			fmt.Printf(format, fmt.Sprintf("\033[33m"+"err: %s"+"\033[0m", err))
		} else {
			fmt.Printf(format, "\033[32m"+"success"+"\033[0m")
		}
		r.TimeCost = time.Now().Sub(start)
		r.Output = string(output.Bytes())
		r.Source = "unfinished(todo)"
		results = append(results, r)
	}
	return
}

func fileExists(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.Mode().IsRegular()
}

func selfPath() string {
	return filepath.Dir(os.Args[0])
}

const STATE_FILE = ".saved-state.yml"

func main() {
	var err error
	var taskcfg = &TaskConfig{}
	var startTime = time.Now()
	if mycnf.Reload && fileExists(STATE_FILE) {
		err = loadFile(STATE_FILE, taskcfg)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		files, err := pathWalk(mycnf.Path, mycnf.Depth)
		if err != nil {
			log.Fatal(err)
		}
		taskcfg.Command = mycnf.Command
		taskcfg.Replacer = mycnf.Replacer
		timeout, err := time.ParseDuration(mycnf.Timeout)
		if err != nil {
			log.Fatal(err)
		}
		taskcfg.Timeout = timeout
		taskcfg.Files = files
	}

	results := work(taskcfg)
	errfiles := []string{}
	errCnt, totCnt := 0, 0
	for _, r := range results {
		if r.Error != nil {
			errCnt++
			errfiles = append(errfiles, r.Filename)
		}
		totCnt++
	}
	defer func() {
		if errCnt != 0 {
			os.Exit(13) // 13 is a lucky number
		}
	}()

	// reder html
	data := map[string]interface{}{}
	data["StartTime"] = startTime.Format("2006-01-02 15:04:05")
	endTime := time.Now()
	data["TimeCost"] = endTime.Sub(startTime)
	data["Tasks"] = results
	hostname, _ := os.Hostname()
	data["Host"] = hostname
	data["Total"] = len(taskcfg.Files)
	data["FailCount"] = errCnt

	htmlTmplPath := filepath.Join(selfPath(), ".html.tmpl")
	err = renderFileWithDefault(mycnf.Result, htmlTmplPath, defaultTemplate, data)
	if err != nil {
		log.Fatal(err)
	}
	htmlData, _ := ioutil.ReadFile(mycnf.Result)

	// save to restart again
	taskcfg.Files = errfiles
	err = dumpFile(STATE_FILE, taskcfg)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("summary: (total: %d fail: %d)\n", totCnt, errCnt)
	smsTmplPath := filepath.Join(selfPath(), ".sms.tmpl")
	if !quitProgram && len(mycnf.Notify) != 0 {
		msg, err := renderWithDefault(smsTmplPath, defaultSMSTemplate, data)
		if err != nil {
			log.Fatal(err)
		}
		err = sendNotify(msg, htmlData, mycnf.Notify...)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>fix depth bug<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"text/template"
	"time"

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

var quitProgram = false

func renderTemplate(filename string, tmplFile string, data interface{}) (err error) {
	tmpl, err := template.ParseFiles(tmplFile)
	if err != nil {
		return
	}
	fd, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer fd.Close()
	err = tmpl.Execute(fd, data)
	return
}

func renderWithDefault(tmplFile string, defaultTmpl []byte, data interface{}) (out string, err error) {
	buf := &bytes.Buffer{}
	if !fileExists(tmplFile) {
		ioutil.WriteFile(tmplFile, defaultTmpl, 0644)
	}
	tmpl, err := template.ParseFiles(tmplFile)
	if err != nil {
		return
	}
	err = tmpl.Execute(buf, data)
	return string(buf.Bytes()), err
}

func renderFileWithDefault(filename string, tmplFile string, defaultTmpl []byte, data interface{}) (err error) {
	if !fileExists(tmplFile) {
		ioutil.WriteFile(tmplFile, defaultTmpl, 0644)
	}
	return renderTemplate(filename, tmplFile, data)
}

func dumpFile(filename string, data interface{}) (err error) {
	out, err := goyaml.Marshal(data)
	if err != nil {
		return
	}
	return ioutil.WriteFile(filename, out, 0644)
}

func loadFile(filename string, data interface{}) (err error) {
	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	return goyaml.Unmarshal(raw, data)
}

func ignore(info os.FileInfo) bool {
	if info.IsDir() {
		if info.Name() != "." && info.Name() != ".." &&
			strings.HasPrefix(info.Name(), ".") { // ignore hidden dir
			return true
		}
	} else {
		return strings.HasPrefix(info.Name(), ".")
	}
	return false
}

func pathWalk(path string, depth int) (files []string, err error) {
	files = make([]string, 0)
	path = filepath.Clean(path) // remove extra /
	baseNumSeps := strings.Count(path, string(os.PathSeparator))
	err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			pathDepth := strings.Count(path, string(os.PathSeparator)) - baseNumSeps
			if pathDepth > depth {
				return filepath.SkipDir
			}
			if ignore(info) {
				return filepath.SkipDir
			}
		} else if info.Mode().IsRegular() && !ignore(info) {
			if matched, _ := regexp.Match(mycnf.Include, []byte(info.Name())); matched {
				files = append(files, path)
			}
		}
		return nil
	})
	return
}

type GlobalConfig struct {
	Replacer string `yaml:"-"` //short:"i" description:"replacer"`
	Command  string `short:"c" description:"specify how to process each file"`
	Include  string `short:"I" long:"include-regex" description:"regex set which file can be included"`
	Path     string `short:"p" long:"path" description:"path for search"`
	Depth    int    `short:"d" long:"depth" description:"depth to travel directory tree"`
	Verbose  bool   `short:"v" long:"verbose" description:"show verbose output"`
	Result   string `yaml:"report-html" short:"H" long:"out-html" description:"output result as html"`
	Timeout  string `short:"t" long:"timeout" description:"timeout for each exec"`
	Reload   bool   `short:"r" long:"reload" description:"reload all failed cmd, run again:"`
	Exclude  string `yaml:"-"`

	Version  bool     `yaml:"-"`
	InitYaml bool     `yaml:"-" long:"init" description:"create a sample .trival.yml and exit"`
	Notify   []string `yaml:"notify" long:"notify" description:"notify people when task finish"`
}

var mycnf = &GlobalConfig{
	Depth:    0,
	Path:     "./",
	Replacer: "{}",
	Version:  false,
	Result:   "test.html",
	Timeout:  "30m",
	Command:  "./{}",
	Include:  ".*",
	Verbose:  false,
}

func init() {
	if fileExists(".travel.yml") {
		loadFile(".travel.yml", mycnf)
	}
	args, err := flags.Parse(mycnf)
	_, _ = args, err
	if err != nil {
		if er, ok := err.(*flags.Error); ok && er.Type == flags.ErrHelp {
			os.Exit(0)
		}
		log.Fatal(err)
	}
	if mycnf.InitYaml {
		dumpFile(".travel.yml", mycnf)
		os.Exit(0)
	}
	if mycnf.Version {
		fmt.Println(VERSION)
		os.Exit(0)
	}
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type TaskConfig struct {
	Replacer string
	Command  string
	Timeout  time.Duration
	Files    []string
}

type TaskResult struct {
	StartTime string
	TimeCost  time.Duration
	Command   string
	Filename  string
	Output    string // console out
	Source    string // source code
	Error     error
}

func Go(f func() error) chan error {
	ch := make(chan error)
	go func() {
		err := f()
		ch <- err
	}()
	return ch
}

func groupKill(cmd *exec.Cmd) (err error) {
	var pid, pgid int
	if cmd.Process != nil {
		pid = cmd.Process.Pid
		c := exec.Command("/bin/ps", "-o", "pgid", "-p", strconv.Itoa(pid), "--no-header")
		var out []byte
		out, err = c.Output()
		if err != nil {
			return
		}
		_, err = fmt.Sscanf(string(out), "%d", &pgid)
		if err != nil {
			return
		}
		err = exec.Command("/bin/kill", "-TERM", "-"+strconv.Itoa(pgid)).Run()
	}
	return
}

func work(cfg *TaskConfig) (results []TaskResult) {
	var err error
	results = []TaskResult{}
	for i, file := range cfg.Files {
		start := time.Now()
		r := TaskResult{
			StartTime: start.Format("15:04:05"),
			Filename:  file,
		}
		c := strings.Replace(cfg.Command, cfg.Replacer, file, -1)
		r.Command = c
		if quitProgram {
			r.Error = errors.New("not started, skiped for SIGINT interrupt")
			results = append(results, r)
			break
		}

		prefix := fmt.Sprintf("\r\033[36m>>>\033[0m %-5d", i)
		format := fmt.Sprintf(prefix+"%%-14v %-24s\n", c) //file) //file)
		// show current exec file
		fmt.Printf(prefix+"exec %s ...", strconv.Quote(file))
		if mycnf.Verbose {
			fmt.Printf("\n")
		}

		output := bytes.NewBuffer(nil)
		cmd := exec.Command("/bin/bash", "-c", c)
		if mycnf.Verbose {
			cmd.Stdout = io.MultiWriter(os.Stdout, output)
			cmd.Stderr = io.MultiWriter(os.Stderr, output)
		} else {
			cmd.Stdout = output
			cmd.Stderr = output
		}
		cmd.SysProcAttr = &syscall.SysProcAttr{}
		cmd.SysProcAttr.Setpgid = true

		// handle timeout
		if err = cmd.Start(); err == nil {
			select {
			case <-sigC:
				quitProgram = true
				groupKill(cmd)
				err = errors.New("signal: interrupt")
			case <-time.After(cfg.Timeout):
				//cmd.Process.Kill()
				groupKill(cmd)
				err = errors.New("signal: terminated")
			case err = <-Go(cmd.Wait):
			}
		}

		if err != nil {
			r.Error = err
			fmt.Printf(format, fmt.Sprintf("\033[33m"+"err: %s"+"\033[0m", err))
		} else {
			fmt.Printf(format, "\033[32m"+"success"+"\033[0m")
		}
		r.TimeCost = time.Now().Sub(start)
		r.Output = string(output.Bytes())
		r.Source = "unfinished(todo)"
		results = append(results, r)
	}
	return
}

func fileExists(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.Mode().IsRegular()
}

func selfPath() string {
	return filepath.Dir(os.Args[0])
}

const STATE_FILE = ".saved-state.yml"

func main() {
	var err error
	var taskcfg = &TaskConfig{}
	var startTime = time.Now()
	if mycnf.Reload && fileExists(STATE_FILE) {
		err = loadFile(STATE_FILE, taskcfg)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		files, err := pathWalk(mycnf.Path, mycnf.Depth)
		if err != nil {
			log.Fatal(err)
		}
		taskcfg.Command = mycnf.Command
		taskcfg.Replacer = mycnf.Replacer
		timeout, err := time.ParseDuration(mycnf.Timeout)
		if err != nil {
			log.Fatal(err)
		}
		taskcfg.Timeout = timeout
		taskcfg.Files = files
	}

	results := work(taskcfg)
	errfiles := []string{}
	errCnt, totCnt := 0, 0
	for _, r := range results {
		if r.Error != nil {
			errCnt++
			errfiles = append(errfiles, r.Filename)
		}
		totCnt++
	}
	defer func() {
		if errCnt != 0 {
			os.Exit(13) // 13 is a lucky number
		}
	}()

	// reder html
	data := map[string]interface{}{}
	data["StartTime"] = startTime.Format("2006-01-02 15:04:05")
	endTime := time.Now()
	data["TimeCost"] = endTime.Sub(startTime)
	data["Tasks"] = results
	hostname, _ := os.Hostname()
	data["Host"] = hostname
	data["Total"] = len(taskcfg.Files)
	data["FailCount"] = errCnt

	htmlTmplPath := filepath.Join(selfPath(), ".html.tmpl")
	err = renderFileWithDefault(mycnf.Result, htmlTmplPath, defaultTemplate, data)
	if err != nil {
		log.Fatal(err)
	}
	htmlData, _ := ioutil.ReadFile(mycnf.Result)

	// save to restart again
	taskcfg.Files = errfiles
	err = dumpFile(STATE_FILE, taskcfg)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("summary: (total: %d fail: %d)\n", totCnt, errCnt)
	smsTmplPath := filepath.Join(selfPath(), ".sms.tmpl")
	if !quitProgram && len(mycnf.Notify) != 0 {
		msg, err := renderWithDefault(smsTmplPath, defaultSMSTemplate, data)
		if err != nil {
			log.Fatal(err)
		}
		err = sendNotify(msg, htmlData, mycnf.Notify...)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import "urlfetch"

func main() {
    urlfetch.Server("8000")
}
<commit_msg>Add support for options<commit_after>package main

import "urlfetch"
import "flag"

func main() {
    var port string
    flag.StringVar(&port, "port", "8000", "URL fetch server port number")
    flag.Parse()
    urlfetch.Server(port)
}
<|endoftext|>