<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"runtime/pprof"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/jessevdk/go-flags"
	"github.com/nsf/termbox-go"
)

// command line flags variable
var opts struct {
	// display ascii instead of kana's
	Ascii bool `short:"a" long:"ascii" description:"Use ascii/alphanumeric characters instead of japanese kana's."`

	// enable logging
	Logging bool `short:"l" long:"log" description:"Enable logging debug messages to ~/.gomatrix-log."`

	// enable profiling
	Profile string `short:"p" long:"profile" description:"Write profile to given file path"`

	// FPS
	FPS int `long:"fps" description:"required FPS, must be somewhere between 1 and 60" default:"25"`
}

// array with half width kanas as Go runes
// source: http://en.wikipedia.org/wiki/Half-width_kana
var halfWidthKana = []rune{
	'｡', '｢', '｣', '､', '･', 'ｦ', 'ｧ', 'ｨ', 'ｩ', 'ｪ', 'ｫ', 'ｬ', 'ｭ', 'ｮ', 'ｯ',
	'ｰ', 'ｱ', 'ｲ', 'ｳ', 'ｴ', 'ｵ', 'ｶ', 'ｷ', 'ｸ', 'ｹ', 'ｺ', 'ｻ', 'ｼ', 'ｽ', 'ｾ', 'ｿ',
	'ﾀ', 'ﾁ', 'ﾂ', 'ﾃ', 'ﾄ', 'ﾅ', 'ﾆ', 'ﾇ', 'ﾈ', 'ﾉ', 'ﾊ', 'ﾋ', 'ﾌ', 'ﾍ', 'ﾎ', 'ﾏ',
	'ﾐ', 'ﾑ', 'ﾒ', 'ﾓ', 'ﾔ', 'ﾕ', 'ﾖ', 'ﾗ', 'ﾘ', 'ﾙ', 'ﾚ', 'ﾛ', 'ﾜ', 'ﾝ', 'ﾞ', 'ﾟ',
}

// just basic alphanumeric characters
var alphaNumerics = []rune{
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
	'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
}

// characters to be used, is being set to alphaNumerics or halfWidthKana depending on flags
var characters []rune

// streamDisplays by column number
var streamDisplaysByColumn = make(map[int]*StreamDisplay)

// struct sizes contains terminal sizes (in amount of characters)
type sizes struct {
	width  int
	height int
}

var curSizes sizes                   // current sizes
var curStreamsPerStreamDisplay = 0   // curent amount of streams per display allowed
var sizesUpdateCh = make(chan sizes) //channel used to notify StreamDisplayManager

// set the sizes and notify StreamDisplayManager
func setSizes(width int, height int) {
	s := sizes{
		width:  width,
		height: height,
	}
	curSizes = s
	curStreamsPerStreamDisplay = 1 + height/10
	sizesUpdateCh <- s
}

func main() {
	// parse flags
	args, err := flags.Parse(&opts)
	if err != nil {
		flagError := err.(*flags.Error)
		if flagError.Type == flags.ErrHelp {
			return
		}
		if flagError.Type == flags.ErrUnknownFlag {
			fmt.Println("Use --help to view all available options.")
			return
		}
		fmt.Printf("Error parsing flags: %s\n", err)
		return
	}
	if len(args) > 0 {
		// we don't accept too much arguments..
		fmt.Printf("Unknown argument '%s'.\n", args[0])
		return
	}
	if opts.FPS < 1 || opts.FPS > 60 {
		fmt.Println("Error: option --fps not within range 1-60")
		os.Exit(1)
	}

	// Start profiling (if required)
	if len(opts.Profile) > 0 {
		f, err := os.Create(opts.Profile)
		if err != nil {
			fmt.Printf("Error opening profiling file: %s\n", err)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
	}

	// Juse a println for fun..
	fmt.Println("Opening connection to The Matrix.. Please stand by..")

	// setup logging with logfile /dev/null or ~/.gomatrix-log
	filename := os.DevNull
	if opts.Logging {
		filename = os.Getenv("HOME") + "/.gomatrix-log"
	}
	logfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("Could not open logfile. %s\n", err)
		os.Exit(1)
	}
	defer logfile.Close()
	log.SetOutput(logfile)
	log.Println("-------------")
	log.Println("Starting gomatrix. This logfile is for development/debug purposes.")

	characters = halfWidthKana
	if opts.Ascii {
		characters = alphaNumerics
	}

	// seed the rand package with time
	rand.Seed(time.Now().UnixNano())

	// initialize termbox
	err = termbox.Init()
	if err != nil {
		fmt.Println("Could not start termbox for gomatrix. View ~/.gomatrix-log for error messages.")
		log.Printf("Cannot start gomatrix, termbox.Init() gave an error:\n%s\n", err)
		os.Exit(1)
	}
	termbox.HideCursor()
	termbox.Clear(termbox.ColorBlack, termbox.ColorBlack)

	// StreamDisplay manager
	go func() {
		var lastWidth int

		for newSizes := range sizesUpdateCh {
			log.Printf("New width: %d\n", newSizes.width)
			diffWidth := newSizes.width - lastWidth

			if diffWidth == 0 {
				// same column size, wait for new information
				log.Println("Got resize over channel, but diffWidth = 0")
				continue
			}

			if diffWidth > 0 {
				log.Printf("Starting %d new SD's\n", diffWidth)
				for newColumn := lastWidth; newColumn < newSizes.width; newColumn++ {
					// create stream display
					sd := &StreamDisplay{
						column:    newColumn,
						stopCh:    make(chan bool, 1),
						streams:   make(map[*Stream]bool),
						newStream: make(chan bool, 1), // will only be filled at start and when a spawning stream has it's tail released
					}
					streamDisplaysByColumn[newColumn] = sd

					// start StreamDisplay in goroutine
					go sd.run()

					// create first new stream
					sd.newStream <- true
				}
				lastWidth = newSizes.width
			}

			if diffWidth < 0 {
				log.Printf("Closing %d SD's\n", diffWidth)
				for closeColumn := lastWidth - 1; closeColumn > newSizes.width; closeColumn-- {
					// get sd
					sd := streamDisplaysByColumn[closeColumn]

					// delete from map
					delete(streamDisplaysByColumn, closeColumn)

					// inform sd that it's being closed
					sd.stopCh <- true
				}
				lastWidth = newSizes.width
			}
		}
	}()

	// set initial sizes
	setSizes(termbox.Size())

	// flusher flushes the termbox every x miliseconds
	fpsSleepTime := time.Duration(1000000/opts.FPS) * time.Microsecond
	fmt.Println("fps sleep time: %s\n", fpsSleepTime.String())
	go func() {
		for {
			// <-time.After(40 * time.Millisecond) //++ TODO: find out wether .After() or .Sleep() is better performance-wise
			time.Sleep(fpsSleepTime)
			termbox.Flush()
		}
	}()

	// make chan for tembox events and run poller to send events on chan
	eventChan := make(chan termbox.Event)
	go func() {
		for {
			event := termbox.PollEvent()
			eventChan <- event
		}
	}()

	// register signals to channel
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, os.Interrupt)
	signal.Notify(sigChan, os.Kill)

	// handle termbox events and unix signals
	func() { //++ TODO: dont use function literal. use labels instead.
		for {
			// select for either event or signal
			select {
			case event := <-eventChan:
				log.Printf("Have event: \n%s", spew.Sdump(event))
				// switch on event type
				switch event.Type {
				case termbox.EventKey: // actions depend on key
					switch event.Key {
					case termbox.KeyCtrlZ, termbox.KeyCtrlC:
						return
						//++ TODO: add more fun keys (slowmo? freeze? rampage?)
					}

					switch event.Ch {
					case 'q':
						return

					case 'c':
						termbox.Clear(termbox.ColorBlack, termbox.ColorBlack)

					case 'a':
						characters = alphaNumerics

					case 'k':
						characters = halfWidthKana
					}

				case termbox.EventResize: // set sizes
					setSizes(event.Width, event.Height)

				case termbox.EventError: // quit
					log.Fatalf("Quitting because of termbox error: \n%s\n", event.Err)
				}
			case signal := <-sigChan:
				log.Printf("Have signal: \n%s", spew.Sdump(signal))
				return
			}
		}
	}()

	// close down
	termbox.Close()
	log.Println("stopping gomatrix")
	fmt.Println("Thank you for connecting with Morpheus' Matrix API v4.2. Have a nice day!")

	// stop profiling (if required)
	if len(opts.Profile) > 0 {
		pprof.StopCPUProfile()
	}
}
<commit_msg>Fix wrong fmt.Println call<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"runtime/pprof"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/jessevdk/go-flags"
	"github.com/nsf/termbox-go"
)

// command line flags variable
var opts struct {
	// display ascii instead of kana's
	Ascii bool `short:"a" long:"ascii" description:"Use ascii/alphanumeric characters instead of japanese kana's."`

	// enable logging
	Logging bool `short:"l" long:"log" description:"Enable logging debug messages to ~/.gomatrix-log."`

	// enable profiling
	Profile string `short:"p" long:"profile" description:"Write profile to given file path"`

	// FPS
	FPS int `long:"fps" description:"required FPS, must be somewhere between 1 and 60" default:"25"`
}

// array with half width kanas as Go runes
// source: http://en.wikipedia.org/wiki/Half-width_kana
var halfWidthKana = []rune{
	'｡', '｢', '｣', '､', '･', 'ｦ', 'ｧ', 'ｨ', 'ｩ', 'ｪ', 'ｫ', 'ｬ', 'ｭ', 'ｮ', 'ｯ',
	'ｰ', 'ｱ', 'ｲ', 'ｳ', 'ｴ', 'ｵ', 'ｶ', 'ｷ', 'ｸ', 'ｹ', 'ｺ', 'ｻ', 'ｼ', 'ｽ', 'ｾ', 'ｿ',
	'ﾀ', 'ﾁ', 'ﾂ', 'ﾃ', 'ﾄ', 'ﾅ', 'ﾆ', 'ﾇ', 'ﾈ', 'ﾉ', 'ﾊ', 'ﾋ', 'ﾌ', 'ﾍ', 'ﾎ', 'ﾏ',
	'ﾐ', 'ﾑ', 'ﾒ', 'ﾓ', 'ﾔ', 'ﾕ', 'ﾖ', 'ﾗ', 'ﾘ', 'ﾙ', 'ﾚ', 'ﾛ', 'ﾜ', 'ﾝ', 'ﾞ', 'ﾟ',
}

// just basic alphanumeric characters
var alphaNumerics = []rune{
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
	'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
}

// characters to be used, is being set to alphaNumerics or halfWidthKana depending on flags
var characters []rune

// streamDisplays by column number
var streamDisplaysByColumn = make(map[int]*StreamDisplay)

// struct sizes contains terminal sizes (in amount of characters)
type sizes struct {
	width  int
	height int
}

var curSizes sizes                   // current sizes
var curStreamsPerStreamDisplay = 0   // curent amount of streams per display allowed
var sizesUpdateCh = make(chan sizes) //channel used to notify StreamDisplayManager

// set the sizes and notify StreamDisplayManager
func setSizes(width int, height int) {
	s := sizes{
		width:  width,
		height: height,
	}
	curSizes = s
	curStreamsPerStreamDisplay = 1 + height/10
	sizesUpdateCh <- s
}

func main() {
	// parse flags
	args, err := flags.Parse(&opts)
	if err != nil {
		flagError := err.(*flags.Error)
		if flagError.Type == flags.ErrHelp {
			return
		}
		if flagError.Type == flags.ErrUnknownFlag {
			fmt.Println("Use --help to view all available options.")
			return
		}
		fmt.Printf("Error parsing flags: %s\n", err)
		return
	}
	if len(args) > 0 {
		// we don't accept too much arguments..
		fmt.Printf("Unknown argument '%s'.\n", args[0])
		return
	}
	if opts.FPS < 1 || opts.FPS > 60 {
		fmt.Println("Error: option --fps not within range 1-60")
		os.Exit(1)
	}

	// Start profiling (if required)
	if len(opts.Profile) > 0 {
		f, err := os.Create(opts.Profile)
		if err != nil {
			fmt.Printf("Error opening profiling file: %s\n", err)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
	}

	// Juse a println for fun..
	fmt.Println("Opening connection to The Matrix.. Please stand by..")

	// setup logging with logfile /dev/null or ~/.gomatrix-log
	filename := os.DevNull
	if opts.Logging {
		filename = os.Getenv("HOME") + "/.gomatrix-log"
	}
	logfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("Could not open logfile. %s\n", err)
		os.Exit(1)
	}
	defer logfile.Close()
	log.SetOutput(logfile)
	log.Println("-------------")
	log.Println("Starting gomatrix. This logfile is for development/debug purposes.")

	characters = halfWidthKana
	if opts.Ascii {
		characters = alphaNumerics
	}

	// seed the rand package with time
	rand.Seed(time.Now().UnixNano())

	// initialize termbox
	err = termbox.Init()
	if err != nil {
		fmt.Println("Could not start termbox for gomatrix. View ~/.gomatrix-log for error messages.")
		log.Printf("Cannot start gomatrix, termbox.Init() gave an error:\n%s\n", err)
		os.Exit(1)
	}
	termbox.HideCursor()
	termbox.Clear(termbox.ColorBlack, termbox.ColorBlack)

	// StreamDisplay manager
	go func() {
		var lastWidth int

		for newSizes := range sizesUpdateCh {
			log.Printf("New width: %d\n", newSizes.width)
			diffWidth := newSizes.width - lastWidth

			if diffWidth == 0 {
				// same column size, wait for new information
				log.Println("Got resize over channel, but diffWidth = 0")
				continue
			}

			if diffWidth > 0 {
				log.Printf("Starting %d new SD's\n", diffWidth)
				for newColumn := lastWidth; newColumn < newSizes.width; newColumn++ {
					// create stream display
					sd := &StreamDisplay{
						column:    newColumn,
						stopCh:    make(chan bool, 1),
						streams:   make(map[*Stream]bool),
						newStream: make(chan bool, 1), // will only be filled at start and when a spawning stream has it's tail released
					}
					streamDisplaysByColumn[newColumn] = sd

					// start StreamDisplay in goroutine
					go sd.run()

					// create first new stream
					sd.newStream <- true
				}
				lastWidth = newSizes.width
			}

			if diffWidth < 0 {
				log.Printf("Closing %d SD's\n", diffWidth)
				for closeColumn := lastWidth - 1; closeColumn > newSizes.width; closeColumn-- {
					// get sd
					sd := streamDisplaysByColumn[closeColumn]

					// delete from map
					delete(streamDisplaysByColumn, closeColumn)

					// inform sd that it's being closed
					sd.stopCh <- true
				}
				lastWidth = newSizes.width
			}
		}
	}()

	// set initial sizes
	setSizes(termbox.Size())

	// flusher flushes the termbox every x miliseconds
	fpsSleepTime := time.Duration(1000000/opts.FPS) * time.Microsecond
	fmt.Printf("fps sleep time: %s\n", fpsSleepTime.String())
	go func() {
		for {
			// <-time.After(40 * time.Millisecond) //++ TODO: find out wether .After() or .Sleep() is better performance-wise
			time.Sleep(fpsSleepTime)
			termbox.Flush()
		}
	}()

	// make chan for tembox events and run poller to send events on chan
	eventChan := make(chan termbox.Event)
	go func() {
		for {
			event := termbox.PollEvent()
			eventChan <- event
		}
	}()

	// register signals to channel
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, os.Interrupt)
	signal.Notify(sigChan, os.Kill)

	// handle termbox events and unix signals
	func() { //++ TODO: dont use function literal. use labels instead.
		for {
			// select for either event or signal
			select {
			case event := <-eventChan:
				log.Printf("Have event: \n%s", spew.Sdump(event))
				// switch on event type
				switch event.Type {
				case termbox.EventKey: // actions depend on key
					switch event.Key {
					case termbox.KeyCtrlZ, termbox.KeyCtrlC:
						return
						//++ TODO: add more fun keys (slowmo? freeze? rampage?)
					}

					switch event.Ch {
					case 'q':
						return

					case 'c':
						termbox.Clear(termbox.ColorBlack, termbox.ColorBlack)

					case 'a':
						characters = alphaNumerics

					case 'k':
						characters = halfWidthKana
					}

				case termbox.EventResize: // set sizes
					setSizes(event.Width, event.Height)

				case termbox.EventError: // quit
					log.Fatalf("Quitting because of termbox error: \n%s\n", event.Err)
				}
			case signal := <-sigChan:
				log.Printf("Have signal: \n%s", spew.Sdump(signal))
				return
			}
		}
	}()

	// close down
	termbox.Close()
	log.Println("stopping gomatrix")
	fmt.Println("Thank you for connecting with Morpheus' Matrix API v4.2. Have a nice day!")

	// stop profiling (if required)
	if len(opts.Profile) > 0 {
		pprof.StopCPUProfile()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	cliprocessor "github.com/wanelo/image-server/cli"
	"github.com/wanelo/image-server/core"
	fetcher "github.com/wanelo/image-server/fetcher/http"
	"github.com/wanelo/image-server/logger"
	"github.com/wanelo/image-server/logger/graphite"
	"github.com/wanelo/image-server/paths"
	processor "github.com/wanelo/image-server/processor/cli"
	"github.com/wanelo/image-server/server"
	"github.com/wanelo/image-server/uploader"
)

func main() {
	app := cli.NewApp()
	app.Name = "images"
	app.Version = "1.0.4"
	app.Usage = "Image server and CLI"
	app.Action = func(c *cli.Context) {
		println("boom! I say!")
	}

	app.Flags = globalFlags()

	app.Commands = []cli.Command{
		{
			Name:      "server",
			ShortName: "s",
			Usage:     "image server",
			Action: func(c *cli.Context) {
				sc, err := serverConfiguration(c)
				if err != nil {
					log.Panicln(err)
				}

				go initializeUploader(sc)

				port := c.GlobalString("port")
				server.InitializeRouter(sc, port)
			},
		},
		{
			Name:      "process",
			ShortName: "p",
			Usage:     "process image dimensions",
			Action: func(c *cli.Context) {
				sc, err := serverConfiguration(c)
				if err != nil {
					log.Panicln(err)
				}

				initializeUploader(sc)
				outputsStr := c.GlobalString("outputs")
				if outputsStr == "" {
					log.Println("Need to specify outputs: 'x300jpg,x300.webp'")
					return
				}

				// input := bufio.NewReader(os.Stdin)
				namespace := c.GlobalString("namespace")
				outputs := strings.Split(outputsStr, ",")
				err = cliprocessor.Process(sc, namespace, outputs, os.Stdin)
				if err != nil {
					log.Panic(err)
				}

			},
		},
	}

	app.Run(os.Args)
}

func globalFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "port", Value: "7000", Usage: "Specifies the server port."},
		cli.StringFlag{Name: "extensions", Value: "jpg,gif,webp", Usage: "Whitelisted extensions (separated by commas)"},
		cli.StringFlag{Name: "local_base_path", Value: "public", Usage: "Directory where the images will be saved"},
		cli.StringFlag{Name: "remote_base_url", Value: "http://us-east.manta.joyent.com/wanelo", Usage: "Source domain for images"},
		cli.StringFlag{Name: "remote_base_path", Value: "public/images/development", Usage: "base path for manta storage"},
		cli.StringFlag{Name: "graphite_host", Value: "127.0.0.1", Usage: "Graphite host"},
		cli.StringFlag{Name: "namespace", Value: "p", Usage: "Namespace"},
		cli.StringFlag{Name: "outputs", Value: "", Usage: "Output files with dimension and compression: 'x300.jpg,x300.webp'"},
		cli.IntFlag{Name: "graphite_port", Value: 8125, Usage: "Graphite port"},
		cli.IntFlag{Name: "maximum_width", Value: 1000, Usage: "Maximum image width"},
		cli.IntFlag{Name: "default_quality", Value: 75, Usage: "Default image compression quality"},
		cli.IntFlag{Name: "uploader_concurrency", Value: 10, Usage: "Uploader concurrency"},
	}
}

func initializeUploader(sc *core.ServerConfiguration) {
	uploader := uploader.Uploader{sc.RemoteBasePath}
	err := uploader.Initialize()
	if err != nil {
		log.Println("EXITING: Unable to initialize manta: ", err)
		os.Exit(2)
	}
}

func serverConfiguration(c *cli.Context) (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromContext(c)

	loggers := []core.Logger{
		graphite.New(sc.GraphiteHost, sc.GraphitePort),
	}

	adapters := &core.Adapters{
		Fetcher:   &fetcher.Fetcher{},
		Processor: &processor.Processor{},
		Paths:     &paths.Paths{sc.LocalBasePath, sc.RemoteBasePath, sc.RemoteBaseURL},
		Logger:    &logger.Logger{loggers},
	}
	sc.Adapters = adapters

	return sc, nil
}

func serverConfigurationFromContext(c *cli.Context) *core.ServerConfiguration {
	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(c.GlobalString("extensions"), ","),
		LocalBasePath:         c.GlobalString("local_base_path"),
		GraphitePort:          c.GlobalInt("graphite_port"),
		GraphiteHost:          c.GlobalString("graphite_host"),
		MaximumWidth:          c.GlobalInt("maximum_width"),
		RemoteBasePath:        c.GlobalString("remote_base_path"),
		RemoteBaseURL:         c.GlobalString("remote_base_url"),
		DefaultQuality:        uint(c.GlobalInt("default_quality")),
		UploaderConcurrency:   uint(c.GlobalInt("uploader_concurrency")),
	}
}
<commit_msg>pprof to help find memory leaks<commit_after>package main

import (
	"log"
	"os"
	"strings"

	"net/http"
	_ "net/http/pprof"

	"github.com/codegangsta/cli"
	cliprocessor "github.com/wanelo/image-server/cli"
	"github.com/wanelo/image-server/core"
	fetcher "github.com/wanelo/image-server/fetcher/http"
	"github.com/wanelo/image-server/logger"
	"github.com/wanelo/image-server/logger/graphite"
	"github.com/wanelo/image-server/paths"
	processor "github.com/wanelo/image-server/processor/cli"
	"github.com/wanelo/image-server/server"
	"github.com/wanelo/image-server/uploader"
)

func main() {
	go func() {
		// used for pprof
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	app := cli.NewApp()
	app.Name = "images"
	app.Version = "1.0.4"
	app.Usage = "Image server and CLI"
	app.Action = func(c *cli.Context) {
		println("boom! I say!")
	}

	app.Flags = globalFlags()

	app.Commands = []cli.Command{
		{
			Name:      "server",
			ShortName: "s",
			Usage:     "image server",
			Action: func(c *cli.Context) {
				sc, err := serverConfiguration(c)
				if err != nil {
					log.Panicln(err)
				}

				go initializeUploader(sc)

				port := c.GlobalString("port")
				server.InitializeRouter(sc, port)
			},
		},
		{
			Name:      "process",
			ShortName: "p",
			Usage:     "process image dimensions",
			Action: func(c *cli.Context) {
				sc, err := serverConfiguration(c)
				if err != nil {
					log.Panicln(err)
				}

				initializeUploader(sc)
				outputsStr := c.GlobalString("outputs")
				if outputsStr == "" {
					log.Println("Need to specify outputs: 'x300jpg,x300.webp'")
					return
				}

				// input := bufio.NewReader(os.Stdin)
				namespace := c.GlobalString("namespace")
				outputs := strings.Split(outputsStr, ",")
				err = cliprocessor.Process(sc, namespace, outputs, os.Stdin)
				if err != nil {
					log.Panic(err)
				}

			},
		},
	}

	app.Run(os.Args)
}

func globalFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "port", Value: "7000", Usage: "Specifies the server port."},
		cli.StringFlag{Name: "extensions", Value: "jpg,gif,webp", Usage: "Whitelisted extensions (separated by commas)"},
		cli.StringFlag{Name: "local_base_path", Value: "public", Usage: "Directory where the images will be saved"},
		cli.StringFlag{Name: "remote_base_url", Value: "http://us-east.manta.joyent.com/wanelo", Usage: "Source domain for images"},
		cli.StringFlag{Name: "remote_base_path", Value: "public/images/development", Usage: "base path for manta storage"},
		cli.StringFlag{Name: "graphite_host", Value: "127.0.0.1", Usage: "Graphite host"},
		cli.StringFlag{Name: "namespace", Value: "p", Usage: "Namespace"},
		cli.StringFlag{Name: "outputs", Value: "", Usage: "Output files with dimension and compression: 'x300.jpg,x300.webp'"},
		cli.IntFlag{Name: "graphite_port", Value: 8125, Usage: "Graphite port"},
		cli.IntFlag{Name: "maximum_width", Value: 1000, Usage: "Maximum image width"},
		cli.IntFlag{Name: "default_quality", Value: 75, Usage: "Default image compression quality"},
		cli.IntFlag{Name: "uploader_concurrency", Value: 10, Usage: "Uploader concurrency"},
	}
}

func initializeUploader(sc *core.ServerConfiguration) {
	uploader := uploader.Uploader{sc.RemoteBasePath}
	err := uploader.Initialize()
	if err != nil {
		log.Println("EXITING: Unable to initialize manta: ", err)
		os.Exit(2)
	}
}

func serverConfiguration(c *cli.Context) (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromContext(c)

	loggers := []core.Logger{
		graphite.New(sc.GraphiteHost, sc.GraphitePort),
	}

	adapters := &core.Adapters{
		Fetcher:   &fetcher.Fetcher{},
		Processor: &processor.Processor{},
		Paths:     &paths.Paths{sc.LocalBasePath, sc.RemoteBasePath, sc.RemoteBaseURL},
		Logger:    &logger.Logger{loggers},
	}
	sc.Adapters = adapters

	return sc, nil
}

func serverConfigurationFromContext(c *cli.Context) *core.ServerConfiguration {
	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(c.GlobalString("extensions"), ","),
		LocalBasePath:         c.GlobalString("local_base_path"),
		GraphitePort:          c.GlobalInt("graphite_port"),
		GraphiteHost:          c.GlobalString("graphite_host"),
		MaximumWidth:          c.GlobalInt("maximum_width"),
		RemoteBasePath:        c.GlobalString("remote_base_path"),
		RemoteBaseURL:         c.GlobalString("remote_base_url"),
		DefaultQuality:        uint(c.GlobalInt("default_quality")),
		UploaderConcurrency:   uint(c.GlobalInt("uploader_concurrency")),
	}
}
<|endoftext|>


<commit_before>// 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 main

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

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client
var PetDB *Pets

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	PetDB = NewPets()
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()

		//Add with new friend.
		if content != nil && content.IsOperation && content.ContentType == linebot.ContentTypeText {
			out := fmt.Sprintf("您好，感謝你加入成為好友一起幫助流浪動物找到新的家．輸入任何文字後，會隨機得到一個流浪動物，你可以不斷重複輸入文字然後查看目前所有的流浪動物．")
			_, err = bot.SendText([]string{content.From}, out)
			if err != nil {
				log.Println(err)
			}

			_, err = bot.SendText([]string{content.From}, out)
			if err != nil {
				log.Println(err)
			}
		}

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {

			pet := PetDB.GetNextPet()
			out := fmt.Sprintf("您好，目前的動物：名為%s, 所在地為:%s, 敘述: %s 電話為:%s", pet.Name, pet.Resettlement, pet.Note, pet.Phone)

			// text, err := content.TextContent()
			_, err = bot.SendText([]string{content.From}, out)
			if err != nil {
				log.Println(err)
			}

			_, err = bot.SendImage([]string{content.From}, pet.ImageName, pet.ImageName)
			if err != nil {
				log.Println(err)
			}

		}
	}
}
<commit_msg>fixed #2 Refine cue related code<commit_after>// 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 main

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

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client
var PetDB *Pets

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	PetDB = NewPets()
	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()

		//Add with new friend.
		if content != nil && content.IsOperation && content.ContentType == linebot.ContentTypeText {
			out := fmt.Sprintf("您好，感謝你加入成為好友一起幫助流浪動物找到新的家．輸入任何文字後，會隨機得到一個流浪動物，你可以不斷重複輸入文字然後查看目前所有的流浪動物．")
			_, err = bot.SendText([]string{content.From}, out)
			if err != nil {
				log.Println(err)
			}
			log.Println("New friend add, send cue to new friend.")
		}

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {

			pet := PetDB.GetNextPet()
			out := fmt.Sprintf("您好，目前的動物：名為%s, 所在地為:%s, 敘述: %s 電話為:%s", pet.Name, pet.Resettlement, pet.Note, pet.Phone)

			// text, err := content.TextContent()
			_, err = bot.SendText([]string{content.From}, out)
			if err != nil {
				log.Println(err)
			}

			_, err = bot.SendImage([]string{content.From}, pet.ImageName, pet.ImageName)
			if err != nil {
				log.Println(err)
			}

		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
	"github.com/alexcarol/bicing-api/station-state/repository"
	"github.com/alexcarol/bicing-api/station-state/collection"
)

func apiFakeDataProvider() []byte {
	return []byte(`<?xml version="1.0" encoding="UTF-8"?>
    <bicing_stations>
     <updatetime><![CDATA[1415996588]]></updatetime>
      <station>
        <id>1</id>
          <type>BIKE</type>
            <lat>41.397952</lat>
              <long>2.180042</long>
                <street><![CDATA[Gran Via Corts Catalanes]]></street>
                  <height>21</height>
                    <streetNumber>760</streetNumber>
                      <nearbyStationList>24, 369, 387, 426</nearbyStationList>
                        <status>OPN</status>
                          <slots>0</slots>
                            <bikes>24</bikes>
                             </station>
                             </bicing_stations>`)
}

func doAPIRequest() []byte {
	response, err := http.Get("http://wservice.viabicing.cat/v1/getstations.php?v=1")
	if err != nil {
		fmt.Printf("Error with the request %s", err)
		os.Exit(1)
	}

	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Printf("Error with the request %s", err)
		os.Exit(1)
	}

	return contents
}

func main() {
	ticker := time.NewTicker(2 * time.Second)
	quit := make(chan struct{})

	go func(s *repository.StationStateStorage) {
		for {
			select {
			case <-ticker.C:
				data := obtainAPIData()
				s.PersistCollection(data)
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}(repository.NewStorage())

	<-quit
}

func obtainAPIData() collection.StationStateCollection {
	startTime := time.Now()
	apiData := apiFakeDataProvider()
	requestEndTime := time.Now()

	var stationCollection collection.StationStateCollection

	err := xml.Unmarshal(apiData, &stationCollection)
	if err != nil {
		fmt.Printf("Unmarshal error: %v\n, structure :%s", err, apiData)
		return stationCollection
	}

	fmt.Printf("Data successfully received, request time: %v, unmarshalling time: %v\n", requestEndTime.Sub(startTime), time.Since(requestEndTime))
	return stationCollection
}

func persistCollection(s collection.StationStateCollection) {
	fmt.Println("Calling persistCollection", s.Updatetime)
}
<commit_msg>Removed unused method<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
	"github.com/alexcarol/bicing-api/station-state/repository"
	"github.com/alexcarol/bicing-api/station-state/collection"
)

func apiFakeDataProvider() []byte {
	return []byte(`<?xml version="1.0" encoding="UTF-8"?>
    <bicing_stations>
     <updatetime><![CDATA[1415996588]]></updatetime>
      <station>
        <id>1</id>
          <type>BIKE</type>
            <lat>41.397952</lat>
              <long>2.180042</long>
                <street><![CDATA[Gran Via Corts Catalanes]]></street>
                  <height>21</height>
                    <streetNumber>760</streetNumber>
                      <nearbyStationList>24, 369, 387, 426</nearbyStationList>
                        <status>OPN</status>
                          <slots>0</slots>
                            <bikes>24</bikes>
                             </station>
                             </bicing_stations>`)
}

func doAPIRequest() []byte {
	response, err := http.Get("http://wservice.viabicing.cat/v1/getstations.php?v=1")
	if err != nil {
		fmt.Printf("Error with the request %s", err)
		os.Exit(1)
	}

	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		fmt.Printf("Error with the request %s", err)
		os.Exit(1)
	}

	return contents
}

func main() {
	ticker := time.NewTicker(2 * time.Second)
	quit := make(chan struct{})

	go func(s *repository.StationStateStorage) {
		for {
			select {
			case <-ticker.C:
				data := obtainAPIData()
				s.PersistCollection(data)
			case <-quit:
				ticker.Stop()
				return
			}
		}
	}(repository.NewStorage())

	<-quit
}

func obtainAPIData() collection.StationStateCollection {
	startTime := time.Now()
	apiData := apiFakeDataProvider()
	requestEndTime := time.Now()

	var stationCollection collection.StationStateCollection

	err := xml.Unmarshal(apiData, &stationCollection)
	if err != nil {
		fmt.Printf("Unmarshal error: %v\n, structure :%s", err, apiData)
		return stationCollection
	}

	fmt.Printf("Data successfully received, request time: %v, unmarshalling time: %v\n", requestEndTime.Sub(startTime), time.Since(requestEndTime))
	return stationCollection
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/mattn/go-sqlite3"
)

const (
	ADDRESS = "http://localhost:9900"
	LENGTH  = 6
	TEXT    = "$ <command> | curl -F 'p=<-' " + ADDRESS + "\n"
	PORT    = ":9900"
)

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

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("sqlite3", "./database.db")
	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 save(raw []byte) string {
	paste := raw[86 : len(raw)-46]

	s := generateName()
	db, err := sql.Open("sqlite3", "./database.db")
	check(err)
	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	_, err = stmt.Exec(s, html.EscapeString(string(paste)))
	check(err)
	db.Close()

	return s
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "POST":
		buf, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), 500)
		}
		name := save(buf)
		io.WriteString(w, ADDRESS+"/p/"+name+"\n")
	}

}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, TEXT)
}
func langHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste)
	highlight := pygments.Highlight(html.UnescapeString(s), lang, "html", "full, style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,", "utf-8")
	io.WriteString(w, highlight)

}

func getPaste(paste string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("sqlite3", "./database.db")
	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 {
		return html.UnescapeString(s)
	}

}
func pasteHandler(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().StrictSlash(true)
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", langHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save", saveHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Add json output<commit_after>package main

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

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
)

const (
	ADDRESS = "http://localhost:9900"
	LENGTH  = 6
	TEXT    = "$ <command> | curl -F 'p=<-' " + ADDRESS + "\n"
	PORT    = ":9900"
)

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

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

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("sqlite3", "./database.db")
	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 []byte) string {
	hasher := sha1.New()
	hasher.Write(paste)
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw []byte) []string {
	p := raw[86 : len(raw)-46]

	db, err := sql.Open("sqlite3", "./database.db")
	check(err)

	sha := hash(p)
	id := generateName()
	url := ADDRESS + "/p/" + id
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(string(p))

	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) {
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		buf, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), 500)
		}

		values := save(buf)

		switch output {
		case "json":
			b := &Response{
				ID:     values[0],
				HASH:   values[1],
				URL:    values[2],
				SIZE:   len(values[3]),
				DELKEY: values[4],
			}

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

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		default:
			io.WriteString(w, values[2]+"\n")
		}
	}

}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, TEXT)
}
func langHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste)
	highlight := pygments.Highlight(html.UnescapeString(s), lang, "html", "full, style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,", "utf-8")
	io.WriteString(w, highlight)

}

func getPaste(paste string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("sqlite3", "./database.db")
	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 {
		return html.UnescapeString(s)
	}

}
func pasteHandler(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().StrictSlash(true)
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", langHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// Webserver
package main

import (
	"fmt"
	"gopkg.in/gcfg.v1"
	"log"
	"net/http"
	"os"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome, %s!", r.URL.Path[1:])
}

type config struct {
	Main struct {
		Port string
	}
}

func getConfig() config {
	cfg := new(config)

	err := gcfg.ReadFileInto(cfg, "./config-example.conf")

	if err != nil {
		log.Fatalf("Failed to parse gcfg data: %s", err)
		os.Exit(1)
	}

	return *cfg
}

func main() {
	cfg := getConfig()
	port := cfg.Main.Port
	if port == "" {
		port = "8000"
	}

	fmt.Println(port)
	http.HandleFunc("/", handler)
	http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
}
<commit_msg>Read from a specified config file.<commit_after>// Webserver
package main

import (
	"flag"
	"fmt"
	"gopkg.in/gcfg.v1"
	"log"
	"net/http"
)

var configFile = flag.String("config", "/etc/bobbi.conf", "INI file for bobbi")

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome, %s!", r.URL.Path[1:])
}

type config struct {
	Main struct {
		Port string
	}
}

func getConfig(filename string) config {
	cfg := new(config)

	err := gcfg.ReadFileInto(cfg, filename)

	if err != nil {
		log.Fatalf("Failed reading config: %s", err)
	}

	return *cfg
}

func main() {
	flag.Parse()
	cfg := getConfig(*configFile)
	port := cfg.Main.Port
	if port == "" {
		port = "8000"
	}

	fmt.Println("Listening on port:", port)
	http.HandleFunc("/", handler)
	http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"

	"github.com/DHowett/go-plist"
)

type diskList struct {
	WholeDisks []string `plist:"WholeDisks"`
}

type diskInfo struct {
	BusProtocol string `plist:"BusProtocol"`
}

func errprint(msg string) {
	fmt.Fprintf(os.Stderr, "%s", msg)
}

func errexit(msg string) {
	errprint(msg)
	os.Exit(1)
}

func getDisks(diskType string) ([]string, error) {
	out, err := exec.Command("diskutil", "list", "-plist", "external", diskType).CombinedOutput()
	if err != nil {
		return nil, err
	}
	var disks diskList
	err = plist.NewDecoder(bytes.NewReader(out)).Decode(&disks)
	if err != nil {
		return nil, err
	}
	return disks.WholeDisks, nil
}

func isDiskImage(disk string) (bool, error) {
	out, err := exec.Command("diskutil", "info", "-plist", disk).CombinedOutput()
	if err != nil {
		return false, err
	}
	var info diskInfo
	err = plist.NewDecoder(bytes.NewReader(out)).Decode(&info)
	if err != nil {
		return false, err
	}
	return info.BusProtocol == "Disk Image", nil
}

func eject(disk string) {
	out, err := exec.Command("diskutil", "eject", disk).CombinedOutput()
	if err != nil {
		errexit(string(out))
	}
}

func ejectDiskImages() {
	disks, err := getDisks("virtual")
	if err != nil {
		errexit("get disks error")
	}
	for i := len(disks) - 1; i >= 0; i-- {
		disk := disks[i]
		isImage, err := isDiskImage(disk)
		if err != nil {
			errexit("check disk image error")
		}
		if isImage {
			eject(disk)
		}
	}
}

func ejectPhysicalDisks() {
	disks, err := getDisks("physical")
	if err != nil {
		errexit("get disks error")
	}
	for i := len(disks) - 1; i >= 0; i-- {
		eject(disks[i])
	}
}

func main() {
	ejectDiskImages()
	ejectPhysicalDisks()
}
<commit_msg>simplified algorithm, just eject disks in reverse order<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"

	"github.com/DHowett/go-plist"
)

type diskList struct {
	WholeDisks []string `plist:"WholeDisks"`
}

func errprint(msg string) {
	fmt.Fprintf(os.Stderr, "%s", msg)
}

func errexit(msg string) {
	errprint(msg)
	os.Exit(1)
}

func getDisks() ([]string, error) {
	out, err := exec.Command("diskutil", "list", "-plist", "external").CombinedOutput()
	if err != nil {
		return nil, err
	}
	var disks diskList
	err = plist.NewDecoder(bytes.NewReader(out)).Decode(&disks)
	if err != nil {
		return nil, err
	}
	return disks.WholeDisks, nil
}

func eject(disk string) {
	out, err := exec.Command("diskutil", "eject", disk).CombinedOutput()
	if err != nil {
		errexit(string(out))
	}
}

func main() {
	disks, err := getDisks()
	if err != nil {
		errexit("get disks error")
	}
	for i := len(disks) - 1; i >= 0; i-- {
		eject(disks[i])
	}
}
<|endoftext|>


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

package main

import (
	. "github.com/kahing/goofys/internal"

	"fmt"
	"os"
	"os/signal"
	"strings"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"

	"github.com/codegangsta/cli"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"

	"github.com/kardianos/osext"

	"github.com/Sirupsen/logrus"

	daemon "github.com/sevlyar/go-daemon"
)

var log = GetLogger("main")

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			log.Println("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Error("Failed to unmount in response to SIGINT: %v", err)
			} else {
				log.Printf("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *FlagStorage) (mfs *fuse.MountedFileSystem, err error) {

	awsConfig := &aws.Config{
		Region: aws.String("us-west-2"),
		Logger: GetLogger("s3"),
		//LogLevel: aws.LogLevel(aws.LogDebug),
	}
	if len(flags.Endpoint) > 0 {
		awsConfig.Endpoint = &flags.Endpoint
	}
	if flags.UsePathRequest {
		awsConfig.S3ForcePathStyle = aws.Bool(true)
	}

	goofys := NewGoofys(bucketName, awsConfig, flags)
	if goofys == nil {
		err = fmt.Errorf("Mount: initialization failed")
		return
	}
	server := fuseutil.NewFileSystemServer(goofys)

	fuseLog := GetLogger("fuse")

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:                  bucketName,
		Options:                 flags.MountOptions,
		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
		DisableWritebackCaching: true,
	}

	if flags.DebugFuse {
		fuseLog.Level = logrus.DebugLevel
		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}

func massagePath() {
	for _, e := range os.Environ() {
		if strings.HasPrefix(e, "PATH=") {
			return
		}
	}

	// mount -a seems to run goofys without PATH
	// usually fusermount is in /bin
	os.Setenv("PATH", "/bin")
}

func massageArg0() {
	var err error
	os.Args[0], err = osext.Executable()
	if err != nil {
		panic(fmt.Sprintf("Unable to discover current executable: %v", err))
	}
}

func main() {
	app := NewApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := PopulateFlags(c)

		InitLoggers(!flags.Foreground)

		massagePath()

		if !flags.Foreground {
			massageArg0()

			ctx := new(daemon.Context)
			child, err := ctx.Reborn()

			if err != nil {
				panic(fmt.Sprintf("unable to daemonize: %v", err))
			}

			if child != nil {
				return
			} else {
				defer ctx.Release()
			}

		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

	err := app.Run(MassageMountFlags(os.Args))
	if err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>terminate on SIGTERM<commit_after>// Copyright 2015 Ka-Hing Cheung
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	. "github.com/kahing/goofys/internal"

	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"golang.org/x/net/context"

	"github.com/aws/aws-sdk-go/aws"

	"github.com/codegangsta/cli"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"

	"github.com/kardianos/osext"

	"github.com/Sirupsen/logrus"

	daemon "github.com/sevlyar/go-daemon"
)

var log = GetLogger("main")

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			s := <-signalChan
			log.Infof("Received %v, attempting to unmount...", s)

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Errorf("Failed to unmount in response to %v: %v", s, err)
			} else {
				log.Printf("Successfully unmounted in response to %v", s)
				return
			}
		}
	}()
}

// Mount the file system based on the supplied arguments, returning a
// fuse.MountedFileSystem that can be joined to wait for unmounting.
func mount(
	ctx context.Context,
	bucketName string,
	mountPoint string,
	flags *FlagStorage) (mfs *fuse.MountedFileSystem, err error) {

	awsConfig := &aws.Config{
		Region: aws.String("us-west-2"),
		Logger: GetLogger("s3"),
		//LogLevel: aws.LogLevel(aws.LogDebug),
	}
	if len(flags.Endpoint) > 0 {
		awsConfig.Endpoint = &flags.Endpoint
	}
	if flags.UsePathRequest {
		awsConfig.S3ForcePathStyle = aws.Bool(true)
	}

	goofys := NewGoofys(bucketName, awsConfig, flags)
	if goofys == nil {
		err = fmt.Errorf("Mount: initialization failed")
		return
	}
	server := fuseutil.NewFileSystemServer(goofys)

	fuseLog := GetLogger("fuse")

	// Mount the file system.
	mountCfg := &fuse.MountConfig{
		FSName:                  bucketName,
		Options:                 flags.MountOptions,
		ErrorLogger:             GetStdLogger(NewLogger("fuse"), logrus.ErrorLevel),
		DisableWritebackCaching: true,
	}

	if flags.DebugFuse {
		fuseLog.Level = logrus.DebugLevel
		mountCfg.DebugLogger = GetStdLogger(fuseLog, logrus.DebugLevel)
	}

	mfs, err = fuse.Mount(mountPoint, server, mountCfg)
	if err != nil {
		err = fmt.Errorf("Mount: %v", err)
		return
	}

	return
}

func massagePath() {
	for _, e := range os.Environ() {
		if strings.HasPrefix(e, "PATH=") {
			return
		}
	}

	// mount -a seems to run goofys without PATH
	// usually fusermount is in /bin
	os.Setenv("PATH", "/bin")
}

func massageArg0() {
	var err error
	os.Args[0], err = osext.Executable()
	if err != nil {
		panic(fmt.Sprintf("Unable to discover current executable: %v", err))
	}
}

func main() {
	app := NewApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := PopulateFlags(c)

		InitLoggers(!flags.Foreground)

		massagePath()

		if !flags.Foreground {
			massageArg0()

			ctx := new(daemon.Context)
			child, err := ctx.Reborn()

			if err != nil {
				panic(fmt.Sprintf("unable to daemonize: %v", err))
			}

			if child != nil {
				return
			} else {
				defer ctx.Release()
			}

		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

	err := app.Run(MassageMountFlags(os.Args))
	if err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	//"net/http/pprof"
	"github.com/kardianos/osext"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
	//"github.com/sanderhahn/gozip"
	"github.com/vharitonsky/iniflags"
	"runtime/debug"
	"text/template"
	"time"
)

var (
	version      = "1.83"
	versionFloat = float32(1.83)
	addr         = flag.String("addr", ":8989", "http service address")
	addrSSL      = flag.String("addrSSL", ":8990", "https service address")
	//assets       = flag.String("assets", defaultAssetPath(), "path to assets")
	verbose = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	//homeTempl *template.Template
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")

	configIni = flag.String("configFile", "config.ini", "config file path")
	// regular expression to sort the serial port list
	// typically this wouldn't be provided, but if the user wants to clean
	// up their list with a regexp so it's cleaner inside their end-user interface
	// such as ChiliPeppr, this can make the massive list that Linux gives back
	// to you be a bit more manageable
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")

	// allow garbageCollection()
	//isGC = flag.Bool("gc", false, "Is garbage collection on? Off by default.")
	//isGC = flag.Bool("gc", true, "Is garbage collection on? Off by default.")
	gcType = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")

	// whether to do buffer flow debugging
	bufFlowDebugType = flag.String("bufflowdebug", "off", "off = (default) We do not send back any debug JSON, on = We will send back a JSON response with debug info based on the configuration of the buffer flow that the user picked")

	// hostname. allow user to override, otherwise we look it up
	hostname = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")

	updateUrl = flag.String("updateUrl", "", "")
	appName   = flag.String("appName", "", "")
)

var globalConfigMap map[string]interface{}

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

func defaultAssetPath() string {
	//p, err := build.Default.Import("gary.burd.info/go-websocket-chat", "", build.FindOnly)
	p, err := build.Default.Import("github.com/johnlauer/serial-port-json-server", "", build.FindOnly)
	if err != nil {
		return "."
	}
	return p.Dir
}

func homeHandler(c http.ResponseWriter, req *http.Request) {
	homeTemplate.Execute(c, req.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 5 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 5 secs. Now launching...")
}

func main() {

	go func() {

		// autoextract self
		src, _ := osext.Executable()
		dest := filepath.Dir(src)

		// save the config.ini (if it exists)
		if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
			fmt.Println("First run, unzipping self")
			err := Unzip(src, dest)
			fmt.Println("Self extraction, err:", err)
		}

		if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
			flag.Parse()
			fmt.Println("No config.ini at", *configIni)
		} else {
			flag.Set("config", dest+"/"+*configIni)
			iniflags.Parse()
		}

		// setup logging
		log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

		// see if we are supposed to wait 5 seconds
		if *isLaunchSelf {
			launchSelfLater()
		}

		var updater = &Updater{
			CurrentVersion: version,
			ApiURL:         *updateUrl,
			BinURL:         *updateUrl,
			DiffURL:        "",
			Dir:            "update/",
			CmdName:        *appName,
		}

		if updater != nil {
			go updater.BackgroundRun()
		}

		// data, err := Asset("arduino.zip")
		// if err != nil {
		// 	log.Println("arduino tools not found")
		// }

		createGlobalConfigMap(&globalConfigMap)

		//getList()
		f := flag.Lookup("addr")
		log.Println("Version:" + version)

		// hostname
		hn, _ := os.Hostname()
		if *hostname == "unknown-hostname" {
			*hostname = hn
		}
		log.Println("Hostname:", *hostname)

		// turn off garbage collection
		// this is dangerous, as u could overflow memory
		//if *isGC {
		if *gcType == "std" {
			log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
		} else if *gcType == "max" {
			log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
		} else {
			log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
			debug.SetGCPercent(-1)
		}

		ip, err := externalIP()
		if err != nil {
			log.Println(err)
		}

		log.Print("Starting server and websocket on " + ip + "" + f.Value.String())
		//homeTempl = template.Must(template.ParseFiles(filepath.Join(*assets, "home.html")))

		log.Println("The Serial Port JSON Server is now running.")
		log.Println("If you are using ChiliPeppr, you may go back to it and connect to this server.")
		// launch the hub routine which is the singleton for the websocket server
		go h.run()
		// launch our serial port routine
		go sh.run()
		// launch our dummy data routine
		//go d.run()

		http.HandleFunc("/", homeHandler)
		http.HandleFunc("/ws", wsHandler)

		go func() {
			if err := http.ListenAndServeTLS(*addrSSL, "cert.pem", "key.pem", nil); err != nil {
				fmt.Printf("Error trying to bind to port: %v, so exiting...", err)
				log.Fatal("Error ListenAndServe:", err)
			}
		}()

		if err := http.ListenAndServe(*addr, nil); err != nil {
			fmt.Printf("Error trying to bind to port: %v, so exiting...", err)
			log.Fatal("Error ListenAndServe:", err)
		}

		// see if they provided a regex filter
		if len(*regExpFilter) > 0 {
			log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
		}

		// list serial ports
		portList, _ := GetList(false)
		/*if errSys != nil {
			log.Printf("Got system error trying to retrieve serial port list. Err:%v\n", errSys)
			log.Fatal("Exiting")
		}*/
		log.Println("Your serial ports:")
		if len(portList) == 0 {
			log.Println("\tThere are no serial ports to list.")
		}
		for _, element := range portList {
			log.Printf("\t%v\n", element)

		}

		if !*verbose {
			log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
			log.SetOutput(new(NullWriter)) //route all logging to nullwriter
		}

		// launch the hub routine which is the singleton for the websocket server
		go h.run()
		// launch our serial port routine
		go sh.run()
		// launch our dummy data routine
		//go d.run()

		go func() {
			http.HandleFunc("/", homeHandler)
			http.HandleFunc("/ws", wsHandler)
			http.HandleFunc("/upload", uploadHandler)
			if err := http.ListenAndServe(*addr, nil); err != nil {
				fmt.Printf("Error trying to bind to port: %v, so exiting...", err)
				log.Fatal("Error ListenAndServe:", err)
			}
		}()
	}()
	setupSysTray()
}

func externalIP() (string, error) {
	//log.Println("Getting external IP")
	ifaces, err := net.Interfaces()
	if err != nil {
		log.Println("Got err getting external IP addr")
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			//log.Println("Iface down")
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			//log.Println("Loopback")
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			log.Println("Got err on iface.Addrs()")
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				//log.Println("Ip was nil or loopback")
				continue
			}
			ip = ip.To4()
			if ip == nil {
				//log.Println("Was not ipv4 addr")
				continue // not an ipv4 address
			}
			//log.Println("IP is ", ip.String())
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
</form>

`
<commit_msg>Remove duplicate code<commit_after>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"errors"
	"flag"
	"fmt"
	"go/build"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	//"net/http/pprof"
	"github.com/kardianos/osext"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
	//"github.com/sanderhahn/gozip"
	"github.com/vharitonsky/iniflags"
	"runtime/debug"
	"text/template"
	"time"
)

var (
	version      = "1.83"
	versionFloat = float32(1.83)
	addr         = flag.String("addr", ":8989", "http service address")
	addrSSL      = flag.String("addrSSL", ":8990", "https service address")
	//assets       = flag.String("assets", defaultAssetPath(), "path to assets")
	verbose = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	//homeTempl *template.Template
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")

	configIni = flag.String("configFile", "config.ini", "config file path")
	// regular expression to sort the serial port list
	// typically this wouldn't be provided, but if the user wants to clean
	// up their list with a regexp so it's cleaner inside their end-user interface
	// such as ChiliPeppr, this can make the massive list that Linux gives back
	// to you be a bit more manageable
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")

	// allow garbageCollection()
	//isGC = flag.Bool("gc", false, "Is garbage collection on? Off by default.")
	//isGC = flag.Bool("gc", true, "Is garbage collection on? Off by default.")
	gcType = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")

	// whether to do buffer flow debugging
	bufFlowDebugType = flag.String("bufflowdebug", "off", "off = (default) We do not send back any debug JSON, on = We will send back a JSON response with debug info based on the configuration of the buffer flow that the user picked")

	// hostname. allow user to override, otherwise we look it up
	hostname = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")

	updateUrl = flag.String("updateUrl", "", "")
	appName   = flag.String("appName", "", "")
)

var globalConfigMap map[string]interface{}

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

func defaultAssetPath() string {
	//p, err := build.Default.Import("gary.burd.info/go-websocket-chat", "", build.FindOnly)
	p, err := build.Default.Import("github.com/johnlauer/serial-port-json-server", "", build.FindOnly)
	if err != nil {
		return "."
	}
	return p.Dir
}

func homeHandler(c http.ResponseWriter, req *http.Request) {
	homeTemplate.Execute(c, req.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 5 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 5 secs. Now launching...")
}

func main() {

	go func() {

		// autoextract self
		src, _ := osext.Executable()
		dest := filepath.Dir(src)

		// save the config.ini (if it exists)
		if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
			fmt.Println("First run, unzipping self")
			err := Unzip(src, dest)
			fmt.Println("Self extraction, err:", err)
		}

		if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
			flag.Parse()
			fmt.Println("No config.ini at", *configIni)
		} else {
			flag.Set("config", dest+"/"+*configIni)
			iniflags.Parse()
		}

		// setup logging
		log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

		// see if we are supposed to wait 5 seconds
		if *isLaunchSelf {
			launchSelfLater()
		}

		var updater = &Updater{
			CurrentVersion: version,
			ApiURL:         *updateUrl,
			BinURL:         *updateUrl,
			DiffURL:        "",
			Dir:            "update/",
			CmdName:        *appName,
		}

		if updater != nil {
			go updater.BackgroundRun()
		}

		// data, err := Asset("arduino.zip")
		// if err != nil {
		// 	log.Println("arduino tools not found")
		// }

		createGlobalConfigMap(&globalConfigMap)

		//getList()
		f := flag.Lookup("addr")
		log.Println("Version:" + version)

		// hostname
		hn, _ := os.Hostname()
		if *hostname == "unknown-hostname" {
			*hostname = hn
		}
		log.Println("Hostname:", *hostname)

		// turn off garbage collection
		// this is dangerous, as u could overflow memory
		//if *isGC {
		if *gcType == "std" {
			log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
		} else if *gcType == "max" {
			log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
		} else {
			log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
			debug.SetGCPercent(-1)
		}

		ip, err := externalIP()
		if err != nil {
			log.Println(err)
		}

		log.Print("Starting server and websocket on " + ip + "" + f.Value.String())
		//homeTempl = template.Must(template.ParseFiles(filepath.Join(*assets, "home.html")))

		log.Println("The Serial Port JSON Server is now running.")
		log.Println("If you are using ChiliPeppr, you may go back to it and connect to this server.")

		// see if they provided a regex filter
		if len(*regExpFilter) > 0 {
			log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
		}

		// list serial ports
		portList, _ := GetList(false)
		/*if errSys != nil {
			log.Printf("Got system error trying to retrieve serial port list. Err:%v\n", errSys)
			log.Fatal("Exiting")
		}*/
		log.Println("Your serial ports:")
		if len(portList) == 0 {
			log.Println("\tThere are no serial ports to list.")
		}
		for _, element := range portList {
			log.Printf("\t%v\n", element)

		}

		if !*verbose {
			log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
			log.SetOutput(new(NullWriter)) //route all logging to nullwriter
		}

		// launch the hub routine which is the singleton for the websocket server
		go h.run()
		// launch our serial port routine
		go sh.run()
		// launch our dummy data routine
		//go d.run()

		go func() {
			http.HandleFunc("/", homeHandler)
			http.HandleFunc("/ws", wsHandler)
			http.HandleFunc("/upload", uploadHandler)

			if err := http.ListenAndServeTLS(*addrSSL, "cert.pem", "key.pem", nil); err != nil {
				fmt.Printf("Error trying to bind to port: %v, so exiting...", err)
				log.Fatal("Error ListenAndServe:", err)
			}
		}()

		if err := http.ListenAndServe(*addr, nil); err != nil {
			fmt.Printf("Error trying to bind to port: %v, so exiting...", err)
			log.Fatal("Error ListenAndServe:", err)
		}
	}()
	setupSysTray()
}

func externalIP() (string, error) {
	//log.Println("Getting external IP")
	ifaces, err := net.Interfaces()
	if err != nil {
		log.Println("Got err getting external IP addr")
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			//log.Println("Iface down")
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			//log.Println("Loopback")
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			log.Println("Got err on iface.Addrs()")
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				//log.Println("Ip was nil or loopback")
				continue
			}
			ip = ip.To4()
			if ip == nil {
				//log.Println("Was not ipv4 addr")
				continue // not an ipv4 address
			}
			//log.Println("IP is ", ip.String())
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
</form>

`
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"regexp"
)

var (
	verbose = flag.Bool("v", false, "print the names of packages as they are checked")
)

func init() {
	if err := typesInit(); err != nil {
		errExit(err)
	}
}

func main() {
	flag.Parse()
	if err := checkPaths(flag.Args(), os.Stdout); err != nil {
		errExit(err)
	}
}

func errExit(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}

func typesMatch(wanted, got []types.Type) bool {
	if len(wanted) != len(got) {
		return false
	}
	for i, w := range wanted {
		g := got[i]
		if !types.ConvertibleTo(g, w) {
			return false
		}
	}
	return true
}

func resultsMatch(wanted, got []types.Type) bool {
	if len(got) == 0 {
		return true
	}
	return typesMatch(wanted, got)
}

func usedMatch(t types.Type, usedAs []types.Type) bool {
	if len(usedAs) < 1 {
		return true
	}
	for _, u := range usedAs {
		if !types.ConvertibleTo(t, u) {
			return false
		}
	}
	return true
}

func interfaceMatching(calls map[string]funcSign, usedAs []types.Type) string {
	matchesIface := func(iface ifaceSign) bool {
		if len(calls) > len(iface.funcs) {
			return false
		}
		if !usedMatch(iface.t, usedAs) {
			return false
		}
		for name, f := range iface.funcs {
			c, e := calls[name]
			if !e {
				return false
			}
			if !typesMatch(f.params, c.params) {
				return false
			}
			if !resultsMatch(f.results, c.results) {
				return false
			}
		}
		return true
	}
	for name, iface := range parsed {
		if matchesIface(iface) {
			return name
		}
	}
	return ""
}

var skipDir = regexp.MustCompile(`^(testdata|vendor|_.*)$`)

func getDirs(d string, recursive bool) ([]string, error) {
	var dirs []string
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if skipDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			dirs = append(dirs, path)
			if !recursive {
				return filepath.SkipDir
			}
		}
		return nil
	}
	if err := filepath.Walk(d, walkFn); err != nil {
		return nil, err
	}
	return dirs, nil
}

func getPkgs(p string) ([]*build.Package, []string, error) {
	recursive := filepath.Base(p) == "..."
	if !recursive {
		info, err := os.Stat(p)
		if err != nil {
			return nil, nil, err
		}
		if !info.IsDir() {
			pkg := &build.Package{
				Name:    "stdin",
				GoFiles: []string{p},
			}
			return []*build.Package{pkg}, []string{"."}, nil
		}
	}
	d := p
	if recursive {
		d = p[:len(p)-4]
	}
	dirs, err := getDirs(d, recursive)
	if err != nil {
		return nil, nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	var pkgs []*build.Package
	var basedirs []string
	for _, d := range dirs {
		pkg, err := build.Import("./"+d, wd, 0)
		if _, ok := err.(*build.NoGoError); ok {
			continue
		}
		if err != nil {
			return nil, nil, err
		}
		pkgs = append(pkgs, pkg)
		basedirs = append(basedirs, d)
	}
	return pkgs, basedirs, nil
}

func checkPaths(paths []string, w io.Writer) error {
	conf := &types.Config{Importer: importer.Default()}
	for _, p := range paths {
		pkgs, basedirs, err := getPkgs(p)
		if err != nil {
			return err
		}
		for i, pkg := range pkgs {
			basedir := basedirs[i]
			if err := checkPkg(conf, pkg, basedir, w); err != nil {
				return err
			}
		}
	}
	return nil
}

func checkPkg(conf *types.Config, pkg *build.Package, basedir string, w io.Writer) error {
	if *verbose {
		importPath := pkg.ImportPath
		if importPath == "" {
			importPath = "command-line-arguments"
		}
		fmt.Fprintln(w, importPath)
	}
	gp := &goPkg{
		Package: pkg,
		fset:    token.NewFileSet(),
	}
	for _, p := range pkg.GoFiles {
		fp := filepath.Join(basedir, p)
		if err := gp.parsePath(fp); err != nil {
			return err
		}
	}
	if err := gp.check(conf, w); err != nil {
		return err
	}
	return nil
}

type goPkg struct {
	*build.Package

	fset  *token.FileSet
	files []*ast.File
}

func (gp *goPkg) parsePath(fp string) error {
	f, err := os.Open(fp)
	if err != nil {
		return err
	}
	defer f.Close()
	if err := gp.parseReader(fp, f); err != nil {
		return err
	}
	return nil
}

func (gp *goPkg) parseReader(name string, r io.Reader) error {
	f, err := parser.ParseFile(gp.fset, name, r, 0)
	if err != nil {
		return err
	}
	gp.files = append(gp.files, f)
	return nil
}

func (gp *goPkg) check(conf *types.Config, w io.Writer) error {
	info := &types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
		Uses:  make(map[*ast.Ident]types.Object),
	}
	_, err := conf.Check(gp.Name, gp.fset, gp.files, info)
	if err != nil {
		return err
	}
	v := &Visitor{
		Info: info,
		w:    w,
		fset: gp.fset,
	}
	for _, f := range gp.files {
		ast.Walk(v, f)
	}
	return nil
}

type Visitor struct {
	*types.Info

	w    io.Writer
	fset *token.FileSet

	nodes []ast.Node

	params map[string]types.Type
	called map[string]map[string]funcSign

	inBlock bool
	usedAs  map[string][]types.Type
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	stype := params.At(params.Len() - 1).Type().(*types.Slice)
	return stype.Elem()
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	var top ast.Node
	if len(v.nodes) > 0 {
		top = v.nodes[len(v.nodes)-1]
	}
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.Defs[x.Name].(*types.Func)
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.called = make(map[string]map[string]funcSign)
		v.usedAs = make(map[string][]types.Type)
	case *ast.BlockStmt:
		v.inBlock = true
	case *ast.AssignStmt:
		if !v.inBlock {
			break
		}
		for i, e := range x.Rhs {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			lid, ok := x.Lhs[i].(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			vtype := v.Types[lid].Type
			if vtype == nil {
				continue
			}
			v.usedAs[name] = append(v.usedAs[name], vtype)
		}
	case *ast.CallExpr:
		if !v.inBlock {
			break
		}
		if v.usedAs == nil {
			break
		}
		sign := funcSignature(v.Types[x.Fun].Type)
		if sign == nil {
			break
		}
		for i, e := range x.Args {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			ptype := paramType(sign, i)
			if ptype == nil {
				continue
			}
			v.usedAs[name] = append(v.usedAs[name], ptype)
		}
		v.onCall(x)
	case nil:
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); ok {
			v.funcEnded(top.Pos())
			v.params = nil
			v.called = nil
			v.usedAs = nil
			v.inBlock = false
		}
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *Visitor) onCall(ce *ast.CallExpr) {
	if v.called == nil {
		return
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vname := left.Name
	if _, e := v.params[vname]; !e {
		return
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	c := funcSign{}
	results := sign.Results()
	for i := 0; i < results.Len(); i++ {
		v := results.At(i)
		c.results = append(c.results, v.Type())
	}
	for _, a := range ce.Args {
		c.params = append(c.params, v.Types[a].Type)
	}
	if _, e := v.called[vname]; !e {
		v.called[vname] = make(map[string]funcSign)
	}
	fname := sel.Sel.Name
	v.called[vname][fname] = c
	return
}

func (v *Visitor) funcEnded(pos token.Pos) {
	for name, methods := range v.called {
		usedAs := v.usedAs[name]
		iface := interfaceMatching(methods, usedAs)
		if iface == "" {
			continue
		}
		param, e := v.params[name]
		if !e {
			continue
		}
		if iface == param.String() {
			continue
		}
		pos := v.fset.Position(pos)
		fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
			pos.Filename, pos.Line, name, iface)
	}
}
<commit_msg>Remove unused code<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"os"
	"path/filepath"
	"regexp"
)

var (
	verbose = flag.Bool("v", false, "print the names of packages as they are checked")
)

func init() {
	if err := typesInit(); err != nil {
		errExit(err)
	}
}

func main() {
	flag.Parse()
	if err := checkPaths(flag.Args(), os.Stdout); err != nil {
		errExit(err)
	}
}

func errExit(err error) {
	fmt.Fprintf(os.Stderr, "%v\n", err)
	os.Exit(1)
}

func typesMatch(wanted, got []types.Type) bool {
	if len(wanted) != len(got) {
		return false
	}
	for i, w := range wanted {
		g := got[i]
		if !types.ConvertibleTo(g, w) {
			return false
		}
	}
	return true
}

func resultsMatch(wanted, got []types.Type) bool {
	if len(got) == 0 {
		return true
	}
	return typesMatch(wanted, got)
}

func usedMatch(t types.Type, usedAs []types.Type) bool {
	if len(usedAs) < 1 {
		return true
	}
	for _, u := range usedAs {
		if !types.ConvertibleTo(t, u) {
			return false
		}
	}
	return true
}

func interfaceMatching(calls map[string]funcSign, usedAs []types.Type) string {
	matchesIface := func(iface ifaceSign) bool {
		if len(calls) > len(iface.funcs) {
			return false
		}
		if !usedMatch(iface.t, usedAs) {
			return false
		}
		for name, f := range iface.funcs {
			c, e := calls[name]
			if !e {
				return false
			}
			if !typesMatch(f.params, c.params) {
				return false
			}
			if !resultsMatch(f.results, c.results) {
				return false
			}
		}
		return true
	}
	for name, iface := range parsed {
		if matchesIface(iface) {
			return name
		}
	}
	return ""
}

var skipDir = regexp.MustCompile(`^(testdata|vendor|_.*)$`)

func getDirs(d string, recursive bool) ([]string, error) {
	var dirs []string
	walkFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if skipDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			dirs = append(dirs, path)
			if !recursive {
				return filepath.SkipDir
			}
		}
		return nil
	}
	if err := filepath.Walk(d, walkFn); err != nil {
		return nil, err
	}
	return dirs, nil
}

func getPkgs(p string) ([]*build.Package, []string, error) {
	recursive := filepath.Base(p) == "..."
	if !recursive {
		info, err := os.Stat(p)
		if err != nil {
			return nil, nil, err
		}
		if !info.IsDir() {
			pkg := &build.Package{
				Name:    "stdin",
				GoFiles: []string{p},
			}
			return []*build.Package{pkg}, []string{"."}, nil
		}
	}
	d := p
	if recursive {
		d = p[:len(p)-4]
	}
	dirs, err := getDirs(d, recursive)
	if err != nil {
		return nil, nil, err
	}
	wd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	var pkgs []*build.Package
	var basedirs []string
	for _, d := range dirs {
		pkg, err := build.Import("./"+d, wd, 0)
		if _, ok := err.(*build.NoGoError); ok {
			continue
		}
		if err != nil {
			return nil, nil, err
		}
		pkgs = append(pkgs, pkg)
		basedirs = append(basedirs, d)
	}
	return pkgs, basedirs, nil
}

func checkPaths(paths []string, w io.Writer) error {
	conf := &types.Config{Importer: importer.Default()}
	for _, p := range paths {
		pkgs, basedirs, err := getPkgs(p)
		if err != nil {
			return err
		}
		for i, pkg := range pkgs {
			basedir := basedirs[i]
			if err := checkPkg(conf, pkg, basedir, w); err != nil {
				return err
			}
		}
	}
	return nil
}

func checkPkg(conf *types.Config, pkg *build.Package, basedir string, w io.Writer) error {
	if *verbose {
		importPath := pkg.ImportPath
		if importPath == "" {
			importPath = "command-line-arguments"
		}
		fmt.Fprintln(w, importPath)
	}
	gp := &goPkg{
		Package: pkg,
		fset:    token.NewFileSet(),
	}
	for _, p := range pkg.GoFiles {
		fp := filepath.Join(basedir, p)
		if err := gp.parsePath(fp); err != nil {
			return err
		}
	}
	if err := gp.check(conf, w); err != nil {
		return err
	}
	return nil
}

type goPkg struct {
	*build.Package

	fset  *token.FileSet
	files []*ast.File
}

func (gp *goPkg) parsePath(fp string) error {
	f, err := os.Open(fp)
	if err != nil {
		return err
	}
	defer f.Close()
	if err := gp.parseReader(fp, f); err != nil {
		return err
	}
	return nil
}

func (gp *goPkg) parseReader(name string, r io.Reader) error {
	f, err := parser.ParseFile(gp.fset, name, r, 0)
	if err != nil {
		return err
	}
	gp.files = append(gp.files, f)
	return nil
}

func (gp *goPkg) check(conf *types.Config, w io.Writer) error {
	info := &types.Info{
		Types: make(map[ast.Expr]types.TypeAndValue),
		Defs:  make(map[*ast.Ident]types.Object),
		Uses:  make(map[*ast.Ident]types.Object),
	}
	_, err := conf.Check(gp.Name, gp.fset, gp.files, info)
	if err != nil {
		return err
	}
	v := &Visitor{
		Info: info,
		w:    w,
		fset: gp.fset,
	}
	for _, f := range gp.files {
		ast.Walk(v, f)
	}
	return nil
}

type Visitor struct {
	*types.Info

	w    io.Writer
	fset *token.FileSet

	nodes []ast.Node

	params map[string]types.Type
	called map[string]map[string]funcSign

	inBlock bool
	usedAs  map[string][]types.Type
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	stype := params.At(params.Len() - 1).Type().(*types.Slice)
	return stype.Elem()
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	var top ast.Node
	if len(v.nodes) > 0 {
		top = v.nodes[len(v.nodes)-1]
	}
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.Defs[x.Name].(*types.Func)
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.called = make(map[string]map[string]funcSign)
		v.usedAs = make(map[string][]types.Type)
	case *ast.BlockStmt:
		v.inBlock = true
	case *ast.AssignStmt:
		if !v.inBlock {
			return nil
		}
		for i, e := range x.Rhs {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			lid, ok := x.Lhs[i].(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			vtype := v.Types[lid].Type
			if vtype == nil {
				continue
			}
			v.usedAs[name] = append(v.usedAs[name], vtype)
		}
	case *ast.CallExpr:
		if !v.inBlock {
			return nil
		}
		if v.usedAs == nil {
			break
		}
		sign := funcSignature(v.Types[x.Fun].Type)
		if sign == nil {
			break
		}
		for i, e := range x.Args {
			id, ok := e.(*ast.Ident)
			if !ok {
				continue
			}
			name := id.Name
			if _, e := v.params[name]; !e {
				continue
			}
			ptype := paramType(sign, i)
			if ptype == nil {
				continue
			}
			v.usedAs[name] = append(v.usedAs[name], ptype)
		}
		v.onCall(x)
	case nil:
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); ok {
			v.funcEnded(top.Pos())
			v.params = nil
			v.called = nil
			v.usedAs = nil
			v.inBlock = false
		}
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *Visitor) onCall(ce *ast.CallExpr) {
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vname := left.Name
	if _, e := v.params[vname]; !e {
		return
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	c := funcSign{}
	results := sign.Results()
	for i := 0; i < results.Len(); i++ {
		v := results.At(i)
		c.results = append(c.results, v.Type())
	}
	for _, a := range ce.Args {
		c.params = append(c.params, v.Types[a].Type)
	}
	if _, e := v.called[vname]; !e {
		v.called[vname] = make(map[string]funcSign)
	}
	fname := sel.Sel.Name
	v.called[vname][fname] = c
	return
}

func (v *Visitor) funcEnded(pos token.Pos) {
	for name, methods := range v.called {
		usedAs := v.usedAs[name]
		iface := interfaceMatching(methods, usedAs)
		if iface == "" {
			continue
		}
		param, e := v.params[name]
		if !e {
			continue
		}
		if iface == param.String() {
			continue
		}
		pos := v.fset.Position(pos)
		fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
			pos.Filename, pos.Line, name, iface)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/skelterjohn/go.wde"
	_ "github.com/skelterjohn/go.wde/xgb"
	t "github.com/tincann/go-path-tracer/tracer"
)

func main() {
	go start()
	wde.Run()
}

func start() {
	w, _ := wde.NewWindow(500, 500)
	acc := t.NewAccumulator(w.Screen().Bounds())

	scene := t.TriangleScene()

	eye := t.NewVector(0, -3, 0)
	direction := t.NewVector(0, 1, 0)
	camera := t.NewCamera(
		eye,
		direction,
		t.NewVector(0, 0, 1),
		1.5, //distance to image plane
		3,   //image plane width
		3,   //image plane height
		0.5, //move speed
	)

	tracer := t.NewTracer(camera, 1, 4)

	go handleEvents(w, w.Screen(), acc, tracer)

	screen := w.Screen()
	bounds := screen.Bounds()

	w.FlushImage(w.Screen().Bounds())
	w.Show()

	for {
		tracer.TraceRegion(bounds, bounds, acc, scene, 10)
		acc.DrawContents(screen)
		w.FlushImage(acc.Bounds)
	}
}

func handleEvents(w wde.Window, screen wde.Image, acc *t.Accumulator, tracer *t.Tracer) {
	for {
		e := <-w.EventChan()

		moveVector := t.NewVector(0, 0, 0)
		theta, phi := 0.0, 0.0
		switch e.(type) {

		case wde.KeyDownEvent:
			event := e.(wde.KeyDownEvent)
			switch event.Key {

			case wde.KeyEscape:
				wde.Stop()

			//camera movement
			case wde.KeyW:
				moveVector.Y++
			case wde.KeyS:
				moveVector.Y--
			case wde.KeyA:
				moveVector.X--
			case wde.KeyD:
				moveVector.X++
			case wde.KeySpace:
				moveVector.Z++
			case wde.KeyLeftShift:
				moveVector.Z--
			case wde.KeyLeftArrow:
				theta--
			case wde.KeyRightArrow:
				theta++

			case wde.KeyTab:
				acc.Reset()

			}
		}

		if moveVector.X != 0 || moveVector.Y != 0 || moveVector.Z != 0 {
			tracer.Camera.Move(moveVector)
			acc.Reset()
		}

		if theta != 0 || phi != 0 {
			tracer.Camera.Rotate(phi, theta)
			acc.Reset()
		}
	}
}
<commit_msg>Refactor main<commit_after>package main

import (
	"github.com/skelterjohn/go.wde"
	_ "github.com/skelterjohn/go.wde/xgb"
	t "github.com/tincann/go-path-tracer/tracer"
)

func main() {
	go start()
	wde.Run()
}

func start() {
	w, _ := wde.NewWindow(500, 500)
	screen := w.Screen()
	bounds := screen.Bounds()

	camera := t.NewCamera(
		t.NewVector(0, -3, 0), //eye
		t.NewVector(0, 1, 0),  //direction
		t.NewVector(0, 0, 1),  //up
		1.5,                   //distance to image plane
		3,                     //image plane width
		3,                     //image plane height
		0.5,                   //move speed
	)

	tracer := t.NewTracer(camera, 1, 4)

	acc := t.NewAccumulator(bounds)

	go handleEvents(w, screen, acc, tracer)

	w.FlushImage(bounds)
	w.Show()

	scene := t.TriangleScene()
	for {
		tracer.TraceRegion(bounds, bounds, acc, scene, 10)
		acc.DrawContents(screen)
		w.FlushImage(acc.Bounds)
	}
}

func handleEvents(w wde.Window, screen wde.Image, acc *t.Accumulator, tracer *t.Tracer) {
	for {
		e := <-w.EventChan()

		moveVector := t.NewVector(0, 0, 0)
		theta, phi := 0.0, 0.0
		switch e.(type) {

		case wde.KeyDownEvent:
			event := e.(wde.KeyDownEvent)
			switch event.Key {

			case wde.KeyEscape:
				wde.Stop()

			//camera movement
			case wde.KeyW:
				moveVector.Y++
			case wde.KeyS:
				moveVector.Y--
			case wde.KeyA:
				moveVector.X--
			case wde.KeyD:
				moveVector.X++
			case wde.KeySpace:
				moveVector.Z++
			case wde.KeyLeftShift:
				moveVector.Z--
			case wde.KeyLeftArrow:
				theta--
			case wde.KeyRightArrow:
				theta++

			case wde.KeyTab:
				acc.Reset()

			}
		}

		if moveVector.X != 0 || moveVector.Y != 0 || moveVector.Z != 0 {
			tracer.Camera.Move(moveVector)
			acc.Reset()
		}

		if theta != 0 || phi != 0 {
			tracer.Camera.Rotate(phi, theta)
			acc.Reset()
		}
	}
}
<|endoftext|>


<commit_before>// MIT License

// Copyright (c) 2017 FLYING

// 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 (
	"fmt"
	"net/http"
	"os"

	"github.com/yang-f/beauty/controllers"

	"github.com/yang-f/beauty/router"
	"github.com/yang-f/beauty/settings"
	"github.com/yang-f/beauty/utils"
	"github.com/yang-f/beauty/utils/log"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	app      = kingpin.New("beauty", "A command-line tools of beauty.")
	demo     = app.Command("demo", "Demo of web server.")
	generate = app.Command("generate", "Generate a new app.")
	name     = generate.Arg("name", "AppName for app.").Required().String()
)

func main() {
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case generate.FullCommand():
		GOPATH := os.Getenv("GOPATH")
		appPath := fmt.Sprintf("%s/src/%s", GOPATH, *name)
		origin := fmt.Sprintf("%s/src/github.com/yang-f/beauty/etc/demo.zip", GOPATH)
		dst := fmt.Sprintf("%s.zip", appPath)
		_, err := utils.CopyFile(dst, origin)
		if err != nil {
			fmt.Println(err.Error())
		}
		utils.Unzip(dst, appPath)
		os.RemoveAll(dst)
		helper := utils.ReplaceHelper{
			Root:    appPath,
			OldText: "{appName}",
			NewText: *name,
		}
		helper.DoWrok()
		log.Printf("Generate %s success.", *name)
	case demo.FullCommand():
		log.Printf("Start server on port %s", settings.Listen)
		r := router.New()
		r.GET("/", controllers.Config().ContentJSON())
		r.GET("/demo1", controllers.Config().ContentJSON().Auth())
		r.GET("/demo2", controllers.Config().ContentJSON().Verify())
		r.GET("/demo3", controllers.Config().ContentJSON().Auth().Verify())
		log.Fatal(http.ListenAndServe(settings.Listen, r))
	}
}
<commit_msg>should be fatal if 'copy' failed when 'generate', and support if multiple-gopath.<commit_after>// MIT License

// Copyright (c) 2017 FLYING

// 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 (
	"fmt"
	"net/http"
	"os"
	"strings"

	"github.com/yang-f/beauty/controllers"

	"github.com/yang-f/beauty/router"
	"github.com/yang-f/beauty/settings"
	"github.com/yang-f/beauty/utils"
	"github.com/yang-f/beauty/utils/log"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	app      = kingpin.New("beauty", "A command-line tools of beauty.")
	demo     = app.Command("demo", "Demo of web server.")
	generate = app.Command("generate", "Generate a new app.")
	name     = generate.Arg("name", "AppName for app.").Required().String()
)

func main() {
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case generate.FullCommand():
		GOPATH := os.Getenv("GOPATH")
		gopathLst := strings.Split(GOPATH, ":")
		GOPATH_r := ""
		origin := ""
		origin_p := "github.com/yang-f/beauty/etc/demo.zip"
		for _, gopathLstItem := range gopathLst {
			origin_t := fmt.Sprintf("%s/src/"+origin_p, gopathLstItem)
			_, err := os.Stat(origin_t)
			if err == nil {
				GOPATH_r = gopathLstItem
				origin = origin_t
				break
			}
		}
		if origin == "" {
			log.Fatal("Err_Fatal: " + "can not find " + origin_p + " in your gopath.")
		}
		appPath := fmt.Sprintf("%s/src/%s", GOPATH_r, *name)
		dst := fmt.Sprintf("%s.zip", appPath)
		_, err := utils.CopyFile(dst, origin)
		if err != nil {
			log.Fatal("Err_Fatal: " + err.Error())
		}
		utils.Unzip(dst, appPath)
		os.RemoveAll(dst)
		helper := utils.ReplaceHelper{
			Root:    appPath,
			OldText: "{appName}",
			NewText: *name,
		}
		helper.DoWrok()
		log.Printf("Generate %s success.", *name)
	case demo.FullCommand():
		log.Printf("Start server on port %s", settings.Listen)
		r := router.New()
		r.GET("/", controllers.Config().ContentJSON())
		r.GET("/demo1", controllers.Config().ContentJSON().Auth())
		r.GET("/demo2", controllers.Config().ContentJSON().Verify())
		r.GET("/demo3", controllers.Config().ContentJSON().Auth().Verify())
		log.Fatal(http.ListenAndServe(settings.Listen, r))
	}
}
<|endoftext|>