<commit_before>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString = "Algernon 0.84"
	description   = "HTTP/2 Web Server"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
	fs              *FileStat
)

func main() {
	var err error

	// Will be default in Go 1.5
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// CPU profiling
	if profileCPU != "" {
		f, err := os.Create(profileCPU)
		if err != nil {
			log.Fatal(err)
		}
		go func() {
			log.Info("Profiling CPU usage")
			pprof.StartCPUProfile(f)
		}()
		atShutdown(func() {
			pprof.StopCPUProfile()
			log.Info("Done profiling CPU usage")
		})
	}

	// Memory profiling at server shutdown
	if profileMem != "" {
		atShutdown(func() {
			f, err := os.Create(profileMem)
			defer f.Close()
			if err != nil {
				log.Fatal(err)
			}
			log.Info("Saving heap profile to ", profileMem)
			pprof.WriteHeapProfile(f)
		})
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Create a new FileStat struct, with optional caching (for speed).
	// Clear the cache every 10 minutes.
	fs = NewFileStat(cacheFileStat, time.Minute*10)

	// Check if the given directory really is a directory
	if !fs.isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if fs.exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md", ".markdown":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if fs.isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if fs.exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// Connect to a database and retrieve a Permissions struct
	perm := mustAquirePermissions()

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	atShutdown(func() {
		luapool.Shutdown()
	})

	// TODO: save repl history + close luapool + close logs ++ at shutdown

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	// The final argument is for compressing with "fast" instead of "best".
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	if singleFileMode && filepath.Ext(serverDir) == ".lua" {
		luaServerFilename = serverDir
		serverDir = filepath.Dir(serverDir)
		singleFileMode = false
	}

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	if quietMode {
		os.Stdout.Close()
		os.Stderr.Close()
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if fs.exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool, cache, mux, false); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Run the standalone Lua server, if specified
	if luaServerFilename != "" {
		// Run the Lua server file and set up handlers
		if verboseMode {
			fmt.Println("Running Lua Server File")
		}
		if err := runConfiguration(luaServerFilename, perm, luapool, cache, mux, true); err != nil {
			log.Error("Error in Lua server script: " + luaServerFilename)
			fatalExit(err)
		}
	} else {
		// Register HTTP handler functions
		registerHandlers(mux, "/", serverDir, perm, luapool, cache, serverAddDomain)
	}

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()

	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		atShutdown(func() {
			// TODO This one is is special and should be closed after the other shutdown functions.
			//      Set up a "done" channel instead of sleeping.
			time.Sleep(100 * time.Millisecond)
			internalLogFile.Close()
		})
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	// For communicating to and from the REPL
	ready := make(chan bool) // for when the server is up and running
	done := make(chan bool)  // for when the user wish to quit the server

	// The Lua REPL
	if !serverMode {
		go REPL(perm, luapool, cache, ready, done)
	}

	conf := &algernonServerConfig{
		productionMode:      productionMode,
		serverHost:          serverHost,
		serverAddr:          serverAddr,
		serverCert:          serverCert,
		serverKey:           serverKey,
		serveJustHTTP:       serveJustHTTP,
		serveJustHTTP2:      serveJustHTTP2,
		shutdownTimeout:     10 * time.Second,
		internalLogFilename: internalLogFilename,
	}

	// Run the shutdown functions if graceful does not
	defer runShutdown()

	// Serve HTTP, HTTP/2 and/or HTTPS
	if err := serve(conf, mux, done, ready); err != nil {
		fatalExit(err)
	}
}
<commit_msg>Add a warning when serving index.lua or data.lua<commit_after>// HTTP/2 web server with built-in support for Lua, Markdown, GCSS, Amber and JSX.
package main

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	internallog "log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"

	"github.com/xyproto/unzip"
	"github.com/yuin/gopher-lua"
)

const (
	versionString = "Algernon 0.84"
	description   = "HTTP/2 Web Server"
)

var (
	// For convenience. Set in the main function.
	serverHost      string
	dbName          string
	refreshDuration time.Duration
	fs              *FileStat
)

func main() {
	var err error

	// Will be default in Go 1.5
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Temporary directory that might be used for logging, databases or file extraction
	serverTempDir, err := ioutil.TempDir("", "algernon")
	if err != nil {
		log.Fatalln(err)
	}
	defer os.RemoveAll(serverTempDir)

	// Set several configuration variables, based on the given flags and arguments
	serverHost = handleFlags(serverTempDir)

	// Version
	if showVersion {
		if !quietMode {
			fmt.Println(versionString)
		}
		os.Exit(0)
	}

	// Console output
	if !quietMode {
		fmt.Println(banner())
	}

	// CPU profiling
	if profileCPU != "" {
		f, err := os.Create(profileCPU)
		if err != nil {
			log.Fatal(err)
		}
		go func() {
			log.Info("Profiling CPU usage")
			pprof.StartCPUProfile(f)
		}()
		atShutdown(func() {
			pprof.StopCPUProfile()
			log.Info("Done profiling CPU usage")
		})
	}

	// Memory profiling at server shutdown
	if profileMem != "" {
		atShutdown(func() {
			f, err := os.Create(profileMem)
			defer f.Close()
			if err != nil {
				log.Fatal(err)
			}
			log.Info("Saving heap profile to ", profileMem)
			pprof.WriteHeapProfile(f)
		})
	}

	// Dividing line between the banner and output from any of the configuration scripts
	if len(serverConfigurationFilenames) > 0 && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Request handlers
	mux := http.NewServeMux()

	// Read mime data from the system, if available
	initializeMime()

	// Create a new FileStat struct, with optional caching (for speed).
	// Clear the cache every 10 minutes.
	fs = NewFileStat(cacheFileStat, time.Minute*10)

	// Check if the given directory really is a directory
	if !fs.isDir(serverDir) {
		// Possibly a file
		filename := serverDir
		// Check if the file exists
		if fs.exists(filename) {
			// Switch based on the lowercase filename extension
			switch strings.ToLower(filepath.Ext(filename)) {
			case ".md", ".markdown":
				// Serve the given Markdown file as a static HTTP server
				serveStaticFile(filename, defaultWebColonPort)
				return
			case ".zip", ".alg":
				// Assume this to be a compressed Algernon application
				err := unzip.Extract(filename, serverTempDir)
				if err != nil {
					log.Fatalln(err)
				}
				// Use the directory where the file was extracted as the server directory
				serverDir = serverTempDir
				// If there is only one directory there, assume it's the
				// directory of the newly extracted ZIP file.
				if filenames := getFilenames(serverDir); len(filenames) == 1 {
					fullPath := filepath.Join(serverDir, filenames[0])
					if fs.isDir(fullPath) {
						// Use this as the server directory instead
						serverDir = fullPath
					}
				}
				// If there are server configuration files in the extracted
				// directory, register them.
				for _, filename := range serverConfigurationFilenames {
					configFilename := filepath.Join(serverDir, filename)
					if fs.exists(configFilename) {
						serverConfigurationFilenames = append(serverConfigurationFilenames, configFilename)
					}
				}
				// Disregard all configuration files from the current directory
				// (filenames without a path separator), since we are serving a
				// ZIP file.
				for i, filename := range serverConfigurationFilenames {
					if strings.Count(filepath.ToSlash(filename), "/") == 0 {
						// Remove the filename from the slice
						serverConfigurationFilenames = append(serverConfigurationFilenames[:i], serverConfigurationFilenames[i+1:]...)
					}
				}
			default:
				singleFileMode = true
			}
		} else {
			fatalExit(errors.New("File does not exist: " + filename))
		}
	}

	// Make a few changes to the defaults if we are serving a single file
	if singleFileMode {
		debugMode = true
		serveJustHTTP = true
	}

	// Connect to a database and retrieve a Permissions struct
	perm := mustAquirePermissions()

	// Lua LState pool
	luapool := &lStatePool{saved: make([]*lua.LState, 0, 4)}
	atShutdown(func() {
		luapool.Shutdown()
	})

	// TODO: save repl history + close luapool + close logs ++ at shutdown

	// Create a cache struct for reading files (contains functions that can
	// be used for reading files, also when caching is disabled).
	// The final argument is for compressing with "fast" instead of "best".
	cache := newFileCache(cacheSize, cacheCompression, cacheMaxEntitySize)

	if singleFileMode && filepath.Ext(serverDir) == ".lua" {
		luaServerFilename = serverDir
		if luaServerFilename == "index.lua" || luaServerFilename == "data.lua" {
			log.Warn("Using " + luaServerFilename + " as a standalone server!\nYou might wish to serve a directory instead.")
		}
		serverDir = filepath.Dir(serverDir)
		singleFileMode = false
	}

	// Log to a file as JSON, if a log file has been specified
	if serverLogFile != "" {
		f, err := os.OpenFile(serverLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, defaultPermissions)
		if err != nil {
			log.Error("Could not log to", serverLogFile)
			fatalExit(err)
		}
		log.SetFormatter(&log.JSONFormatter{})
		log.SetOutput(f)
	} else if quietMode {
		// If quiet mode is enabled and no log file has been specified, disable logging
		log.SetOutput(ioutil.Discard)
	}

	if quietMode {
		os.Stdout.Close()
		os.Stderr.Close()
	}

	// Read server configuration script, if present.
	// The scripts may change global variables.
	var ranConfigurationFilenames []string
	for _, filename := range serverConfigurationFilenames {
		if fs.exists(filename) {
			if verboseMode {
				fmt.Println("Running configuration file: " + filename)
			}
			if err := runConfiguration(filename, perm, luapool, cache, mux, false); err != nil {
				log.Error("Could not use configuration script: " + filename)
				fatalExit(err)
			}
			ranConfigurationFilenames = append(ranConfigurationFilenames, filename)
		}
	}
	// Only keep the active ones. Used when outputting server information.
	serverConfigurationFilenames = ranConfigurationFilenames

	// Run the standalone Lua server, if specified
	if luaServerFilename != "" {
		// Run the Lua server file and set up handlers
		if verboseMode {
			fmt.Println("Running Lua Server File")
		}
		if err := runConfiguration(luaServerFilename, perm, luapool, cache, mux, true); err != nil {
			log.Error("Error in Lua server script: " + luaServerFilename)
			fatalExit(err)
		}
	} else {
		// Register HTTP handler functions
		registerHandlers(mux, "/", serverDir, perm, luapool, cache, serverAddDomain)
	}

	// Set the values that has not been set by flags nor scripts
	// (and can be set by both)
	ranServerReadyFunction := finalConfiguration(serverHost)

	// If no configuration files were being ran succesfully,
	// output basic server information.
	if len(serverConfigurationFilenames) == 0 {
		if !quietMode {
			fmt.Println(serverInfo())
		}
		ranServerReadyFunction = true
	}

	// Dividing line between the banner and output from any of the
	// configuration scripts. Marks the end of the configuration output.
	if ranServerReadyFunction && !quietMode {
		fmt.Println("--------------------------------------- - - · ·")
	}

	// Direct internal logging elsewhere
	internalLogFile, err := os.Open(internalLogFilename)
	defer internalLogFile.Close()

	if err != nil {
		// Could not open the internalLogFilename filename, try using another filename
		internalLogFile, err = os.OpenFile("internal.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, defaultPermissions)
		atShutdown(func() {
			// TODO This one is is special and should be closed after the other shutdown functions.
			//      Set up a "done" channel instead of sleeping.
			time.Sleep(100 * time.Millisecond)
			internalLogFile.Close()
		})
		if err != nil {
			fatalExit(fmt.Errorf("Could not write to %s nor %s.", internalLogFilename, "internal.log"))
		}
	}
	internallog.SetOutput(internalLogFile)

	// Serve filesystem events in the background.
	// Used for reloading pages when the sources change.
	// Can also be used when serving a single file.
	if autoRefreshMode {
		refreshDuration, err = time.ParseDuration(eventRefresh)
		if err != nil {
			log.Warn(fmt.Sprintf("%s is an invalid duration. Using %s instead.", eventRefresh, defaultEventRefresh))
			// Ignore the error, since defaultEventRefresh is a constant and must be parseable
			refreshDuration, _ = time.ParseDuration(defaultEventRefresh)
		}
		if autoRefreshDir != "" {
			// Only watch the autoRefreshDir, recursively
			EventServer(eventAddr, defaultEventPath, autoRefreshDir, refreshDuration, "*")
		} else {
			// Watch everything in the server directory, recursively
			EventServer(eventAddr, defaultEventPath, serverDir, refreshDuration, "*")
		}
	}

	// For communicating to and from the REPL
	ready := make(chan bool) // for when the server is up and running
	done := make(chan bool)  // for when the user wish to quit the server

	// The Lua REPL
	if !serverMode {
		go REPL(perm, luapool, cache, ready, done)
	}

	conf := &algernonServerConfig{
		productionMode:      productionMode,
		serverHost:          serverHost,
		serverAddr:          serverAddr,
		serverCert:          serverCert,
		serverKey:           serverKey,
		serveJustHTTP:       serveJustHTTP,
		serveJustHTTP2:      serveJustHTTP2,
		shutdownTimeout:     10 * time.Second,
		internalLogFilename: internalLogFilename,
	}

	// Run the shutdown functions if graceful does not
	defer runShutdown()

	// Serve HTTP, HTTP/2 and/or HTTPS
	if err := serve(conf, mux, done, ready); err != nil {
		fatalExit(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/clinta/docker-vxlan-plugin/vxlan"
	"github.com/clinta/go-plugins-helpers/network"
	"github.com/codegangsta/cli"
)

const (
	version = "0.2.1"
)

func main() {

	var flagDebug = cli.BoolFlag{
		Name:  "debug, d",
		Usage: "enable debugging",
	}
	var flagScope = cli.StringFlag{
		Name:  "scope",
		Value: "local",
		Usage: "Scope of the network. local or global.",
	}
	var flagVtepDev = cli.StringFlag{
		Name:  "vtepdev",
		Value: "",
		Usage: "VTEP device.",
	}
	app := cli.NewApp()
	app.Name = "don"
	app.Usage = "Docker vxLan Networking"
	app.Version = version
	app.Flags = []cli.Flag{
		flagDebug,
		flagScope,
		flagVtepDev,
	}
	app.Action = Run
	app.Run(os.Args)
}

// Run initializes the driver
func Run(ctx *cli.Context) {
	if ctx.Bool("debug") {
		log.SetLevel(log.DebugLevel)
	}
	d, err := vxlan.NewDriver(ctx.String("scope"), ctx.String("vtepdev"))
	if err != nil {
		panic(err)
	}
	h := network.NewHandler(d)
	h.ServeUnix("root", "vxlan")
}
<commit_msg>version<commit_after>package main

import (
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/clinta/docker-vxlan-plugin/vxlan"
	"github.com/clinta/go-plugins-helpers/network"
	"github.com/codegangsta/cli"
)

const (
	version = "0.2.2"
)

func main() {

	var flagDebug = cli.BoolFlag{
		Name:  "debug, d",
		Usage: "enable debugging",
	}
	var flagScope = cli.StringFlag{
		Name:  "scope",
		Value: "local",
		Usage: "Scope of the network. local or global.",
	}
	var flagVtepDev = cli.StringFlag{
		Name:  "vtepdev",
		Value: "",
		Usage: "VTEP device.",
	}
	app := cli.NewApp()
	app.Name = "don"
	app.Usage = "Docker vxLan Networking"
	app.Version = version
	app.Flags = []cli.Flag{
		flagDebug,
		flagScope,
		flagVtepDev,
	}
	app.Action = Run
	app.Run(os.Args)
}

// Run initializes the driver
func Run(ctx *cli.Context) {
	if ctx.Bool("debug") {
		log.SetLevel(log.DebugLevel)
	}
	d, err := vxlan.NewDriver(ctx.String("scope"), ctx.String("vtepdev"))
	if err != nil {
		panic(err)
	}
	h := network.NewHandler(d)
	h.ServeUnix("root", "vxlan")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

var (
	apiURL                        = "https://api.github.com/search/"
	user, repo                    bool
	paging                        int
	searchString, language, login string
	line                          = "==============================================================================="
	linesmall                     = "-------------------------------------------------------------------------------"
	linebig                       = "###############################################################################"
)

func init() {
	flag.BoolVar(&user, "user", false, "search for a user.")
	flag.BoolVar(&user, "u", false, "shorthand for -user.")
	flag.BoolVar(&repo, "repo", false, "indicate the pattern you are looking for (don't combine with -user|-u).")
	flag.BoolVar(&repo, "r", false, "shorthand for -repo.")
	flag.StringVar(&searchString, "pattern", "", "indicate the pattern you are looking for.")
	flag.StringVar(&searchString, "p", "", "shorthand for -pattern.")
	flag.StringVar(&language, "lang", "", "indicate a language for search.")
	flag.StringVar(&language, "l", "", "shorthand for -lang.")
	flag.StringVar(&login, "login", "", "indicate username for a repo search.")
	flag.IntVar(&paging, "paging", 100, "set per page limit.")
}

func checkUsage() {
	fmt.Println("You must use an option like:")
	fmt.Println("./gitsearch -help")
	fmt.Println("./gitsearch -h")
	fmt.Println("./gitsearch -user -pattern pattern")
	fmt.Println("./gitsearch -repo -pattern pattern")
	fmt.Println("./gitsearch -u -p pattern")
	fmt.Println("./gitsearch -r -login username")
	fmt.Println("./gitsearch -r -p pattern")
	fmt.Println("./gitsearch -r -p pattern -l language -login username")
	fmt.Println("./gitsearch -r -p pattern -paging=10")
}

//Regexp function go get the url from Link in header
func Regexp(input string) string {
	var url string
	re1 := regexp.MustCompile("next")
	next := re1.FindString(input)
	if next != "" {
		re2 := regexp.MustCompile("[[:alnum:]]+[[:graph:]]+[[:alnum:]]")
		url = re2.FindString(input)
		return url
	}
	return url
}

func pager(input string) {
	pager := os.Getenv("PAGER")
	less := "/usr/bin/less"
	if pager == "" {
		if _, err := os.Stat(less); err == nil {
			pager = less
		} else {
			pager = "more"
		}
	}
	if pager == less || pager == "less" {
		cmd := exec.Command(pager, "-X")
		cmd.Stdin = strings.NewReader(input)
		cmd.Stdout = os.Stdout
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	} else {
		cmd := exec.Command(pager)
		cmd.Stdin = strings.NewReader(input)
		cmd.Stdout = os.Stdout
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	}
}

func main() {
	flag.Parse()
	perpage := strconv.Itoa(paging)
	if user && searchString != "" {
		RunSearchUser(searchString, perpage)
	} else if repo {
		switch {
		case searchString == "" && login == "":
			checkUsage()
		case searchString == "" && login != "":
			RunSearchRepo(searchString, perpage)
		case searchString != "":
			RunSearchRepo(searchString, perpage)
		}
	} else {
		checkUsage()
	}
}
<commit_msg>Added option quit-if-one-screen for 'less' pager.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

var (
	apiURL                        = "https://api.github.com/search/"
	user, repo                    bool
	paging                        int
	searchString, language, login string
	line                          = "==============================================================================="
	linesmall                     = "-------------------------------------------------------------------------------"
	linebig                       = "###############################################################################"
)

func init() {
	flag.BoolVar(&user, "user", false, "search for a user.")
	flag.BoolVar(&user, "u", false, "shorthand for -user.")
	flag.BoolVar(&repo, "repo", false, "indicate the pattern you are looking for (don't combine with -user|-u).")
	flag.BoolVar(&repo, "r", false, "shorthand for -repo.")
	flag.StringVar(&searchString, "pattern", "", "indicate the pattern you are looking for.")
	flag.StringVar(&searchString, "p", "", "shorthand for -pattern.")
	flag.StringVar(&language, "lang", "", "indicate a language for search.")
	flag.StringVar(&language, "l", "", "shorthand for -lang.")
	flag.StringVar(&login, "login", "", "indicate username for a repo search.")
	flag.IntVar(&paging, "paging", 100, "set per page limit.")
}

func checkUsage() {
	fmt.Println("You must use an option like:")
	fmt.Println("./gitsearch -help")
	fmt.Println("./gitsearch -h")
	fmt.Println("./gitsearch -user -pattern pattern")
	fmt.Println("./gitsearch -repo -pattern pattern")
	fmt.Println("./gitsearch -u -p pattern")
	fmt.Println("./gitsearch -r -login username")
	fmt.Println("./gitsearch -r -p pattern")
	fmt.Println("./gitsearch -r -p pattern -l language -login username")
	fmt.Println("./gitsearch -r -p pattern -paging=10")
}

//Regexp function go get the url from Link in header
func Regexp(input string) string {
	var url string
	re1 := regexp.MustCompile("next")
	next := re1.FindString(input)
	if next != "" {
		re2 := regexp.MustCompile("[[:alnum:]]+[[:graph:]]+[[:alnum:]]")
		url = re2.FindString(input)
		return url
	}
	return url
}

func pager(input string) {
	pager := os.Getenv("PAGER")
	less := "/usr/bin/less"
	if pager == "" {
		if _, err := os.Stat(less); err == nil {
			pager = less
		} else {
			pager = "more"
		}
	}
	if pager == less || pager == "less" {
		cmd := exec.Command(pager, "-X", "-F")
		cmd.Stdin = strings.NewReader(input)
		cmd.Stdout = os.Stdout
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	} else {
		cmd := exec.Command(pager)
		cmd.Stdin = strings.NewReader(input)
		cmd.Stdout = os.Stdout
		err := cmd.Run()
		if err != nil {
			log.Fatal(err)
		}
	}
}

func main() {
	flag.Parse()
	perpage := strconv.Itoa(paging)
	if user && searchString != "" {
		RunSearchUser(searchString, perpage)
	} else if repo {
		switch {
		case searchString == "" && login == "":
			checkUsage()
		case searchString == "" && login != "":
			RunSearchRepo(searchString, perpage)
		case searchString != "":
			RunSearchRepo(searchString, perpage)
		}
	} else {
		checkUsage()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/cego/zfs-cleaner/conf"
	"github.com/cego/zfs-cleaner/zfs"
	"github.com/spf13/cobra"
)

var (
	verbose    = false
	dryrun     = false
	concurrent = false
	plancheck  = false

	commandName      = "/sbin/zfs"
	commandArguments = []string{"list", "-t", "snapshot", "-o", "name,creation", "-s", "creation", "-r", "-H", "-p"}

	// This can be set to a specific time for testing.
	now = time.Now()

	// tasks can be added to this for testing.
	mainWaitGroup sync.WaitGroup

	// This can be changed to true when testing.
	panicBail = false

	rootCmd = &cobra.Command{
		Use:   "zfs-cleaner [config file]",
		Short: "Tool for destroying ZFS snapshots after predefined retention periods",
		RunE:  clean,
	}
)

func init() {
	rootCmd.PersistentFlags().BoolVarP(&dryrun, "dryrun", "n", false, "Do nothing destructive, only print")
	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Be more verbose")
	rootCmd.PersistentFlags().BoolVarP(&concurrent, "concurrent", "c", false, "Allow more than one zfs-cleaner to operate on the same configuration file simultaneously")
	rootCmd.PersistentFlags().BoolVarP(&plancheck, "plancheck", "p", false, "Print mounts that have no plan and exit")
}

func getList(name string) (zfs.SnapshotList, error) {
	// Output could be cached.
	output, err := exec.Command(commandName, commandArguments...).Output()

	if err != nil {
		return nil, err
	}

	return zfs.NewSnapshotListFromOutput(output, name)
}

func readConf(r *os.File) (*conf.Config, error) {
	conf := &conf.Config{}

	err := conf.Read(r)
	if err != nil {
		return nil, fmt.Errorf("failed to parse %s: %s", r.Name(), err.Error())
	}

	return conf, nil
}

func processAll(now time.Time, conf *conf.Config) ([]zfs.SnapshotList, error) {
	lists := []zfs.SnapshotList{}
	for _, plan := range conf.Plans {
		for _, path := range plan.Paths {
			list, err := getList(path)
			if err != nil {
				return nil, err
			}

			list.KeepLatest(plan.Latest)
			for _, period := range plan.Periods {
				start := now.Add(-period.Age)

				list.Sieve(start, period.Frequency)
			}

			lists = append(lists, list)
		}
	}

	return lists, nil
}

func planCheck(conf *conf.Config) error {
	args := []string{"list", "-t", "filesystem", "-o", "name", "-H"}
	output, err := exec.Command(commandName, args...).Output()
	if err != nil {
		return err
	}

	m := map[string]bool{}
	for _, plan := range conf.Plans {
		for _, path := range plan.Paths {
			m[path] = true
		}
	}

	for _, store := range strings.Fields(string(output)) {
		if !m[store] {
			fmt.Printf("No plan found for path: %s\n", store)
		}
	}

	return nil
}

func main() {
	err := rootCmd.Execute()
	if err != nil {
		if panicBail {
			panic(err.Error())
		}

		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}

func clean(cmd *cobra.Command, args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("%s /path/to/config.conf", cmd.Name())
	}

	confFile, err := os.Open(args[0])
	if err != nil {
		return fmt.Errorf("failed to open %s: %s", args[0], err.Error())
	}
	defer confFile.Close()

	conf, err := readConf(confFile)
	if err != nil {
		return err
	}

	if !concurrent {
		fd := int(confFile.Fd())
		err = syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB)
		if err != nil {
			return fmt.Errorf("Could not aquire lock on '%s'", confFile.Name())
		}

		// make sure to unlock :)
		defer syscall.Flock(fd, syscall.LOCK_UN)
	}

	if plancheck {
		return planCheck(conf)
	}

	lists, err := processAll(now, conf)
	if err != nil {
		return err
	}

	// Start by generating a list of stuff to do.
	todos := []todo{}

	for _, list := range lists {
		for _, snapshot := range list {
			if !snapshot.Keep {
				todos = append(todos, newDestroy(snapshot.Name))
			} else {
				todos = append(todos, newComment("Keep %s (Age %s)", snapshot.Name, now.Sub(snapshot.Creation)))
			}
		}
	}

	// And then do it! :-)
	for _, todo := range todos {
		err := todo.Do()
		if err != nil {
			return err
		}
	}

	mainWaitGroup.Wait()

	return nil
}
<commit_msg>output from -p now have the path in single qoutes<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/cego/zfs-cleaner/conf"
	"github.com/cego/zfs-cleaner/zfs"
	"github.com/spf13/cobra"
)

var (
	verbose    = false
	dryrun     = false
	concurrent = false
	plancheck  = false

	commandName      = "/sbin/zfs"
	commandArguments = []string{"list", "-t", "snapshot", "-o", "name,creation", "-s", "creation", "-r", "-H", "-p"}

	// This can be set to a specific time for testing.
	now = time.Now()

	// tasks can be added to this for testing.
	mainWaitGroup sync.WaitGroup

	// This can be changed to true when testing.
	panicBail = false

	rootCmd = &cobra.Command{
		Use:   "zfs-cleaner [config file]",
		Short: "Tool for destroying ZFS snapshots after predefined retention periods",
		RunE:  clean,
	}
)

func init() {
	rootCmd.PersistentFlags().BoolVarP(&dryrun, "dryrun", "n", false, "Do nothing destructive, only print")
	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Be more verbose")
	rootCmd.PersistentFlags().BoolVarP(&concurrent, "concurrent", "c", false, "Allow more than one zfs-cleaner to operate on the same configuration file simultaneously")
	rootCmd.PersistentFlags().BoolVarP(&plancheck, "plancheck", "p", false, "Print mounts that have no plan and exit")
}

func getList(name string) (zfs.SnapshotList, error) {
	// Output could be cached.
	output, err := exec.Command(commandName, commandArguments...).Output()

	if err != nil {
		return nil, err
	}

	return zfs.NewSnapshotListFromOutput(output, name)
}

func readConf(r *os.File) (*conf.Config, error) {
	conf := &conf.Config{}

	err := conf.Read(r)
	if err != nil {
		return nil, fmt.Errorf("failed to parse %s: %s", r.Name(), err.Error())
	}

	return conf, nil
}

func processAll(now time.Time, conf *conf.Config) ([]zfs.SnapshotList, error) {
	lists := []zfs.SnapshotList{}
	for _, plan := range conf.Plans {
		for _, path := range plan.Paths {
			list, err := getList(path)
			if err != nil {
				return nil, err
			}

			list.KeepLatest(plan.Latest)
			for _, period := range plan.Periods {
				start := now.Add(-period.Age)

				list.Sieve(start, period.Frequency)
			}

			lists = append(lists, list)
		}
	}

	return lists, nil
}

func planCheck(conf *conf.Config) error {
	args := []string{"list", "-t", "filesystem", "-o", "name", "-H"}
	output, err := exec.Command(commandName, args...).Output()
	if err != nil {
		return err
	}

	m := map[string]bool{}
	for _, plan := range conf.Plans {
		for _, path := range plan.Paths {
			m[path] = true
		}
	}

	for _, store := range strings.Fields(string(output)) {
		if !m[store] {
			fmt.Printf("No plan found for path: '%s'\n", store)
		}
	}

	return nil
}

func main() {
	err := rootCmd.Execute()
	if err != nil {
		if panicBail {
			panic(err.Error())
		}

		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}

func clean(cmd *cobra.Command, args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("%s /path/to/config.conf", cmd.Name())
	}

	confFile, err := os.Open(args[0])
	if err != nil {
		return fmt.Errorf("failed to open %s: %s", args[0], err.Error())
	}
	defer confFile.Close()

	conf, err := readConf(confFile)
	if err != nil {
		return err
	}

	if !concurrent {
		fd := int(confFile.Fd())
		err = syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB)
		if err != nil {
			return fmt.Errorf("Could not aquire lock on '%s'", confFile.Name())
		}

		// make sure to unlock :)
		defer syscall.Flock(fd, syscall.LOCK_UN)
	}

	if plancheck {
		return planCheck(conf)
	}

	lists, err := processAll(now, conf)
	if err != nil {
		return err
	}

	// Start by generating a list of stuff to do.
	todos := []todo{}

	for _, list := range lists {
		for _, snapshot := range list {
			if !snapshot.Keep {
				todos = append(todos, newDestroy(snapshot.Name))
			} else {
				todos = append(todos, newComment("Keep %s (Age %s)", snapshot.Name, now.Sub(snapshot.Creation)))
			}
		}
	}

	// And then do it! :-)
	for _, todo := range todos {
		err := todo.Do()
		if err != nil {
			return err
		}
	}

	mainWaitGroup.Wait()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/koding/klient/cmd/klientctl/util"
)

// sudoRequiredFor is the default list of commands that require sudo.
// The actual handling of this list is done in the SudoRequired func.
var sudoRequiredFor = []string{
	"install",
	"uninstall",
	"start",
	"stop",
	"restart",
	"update",
}

func main() {
	// Check if the command the user is giving requires sudo.
	if err := AdminRequired(os.Args, sudoRequiredFor, util.NewPermissions()); err != nil {
		// In the event of an error, simply print the error to the user
		// and exit.
		fmt.Println("Error: this command requires sudo.")
		os.Exit(10)
	}

	app := cli.NewApp()
	app.Name = Name
	app.Version = fmt.Sprintf("%d", Version)

	app.Commands = []cli.Command{
		cli.Command{
			Name:   "list",
			Usage:  "List the available machines.",
			Action: Exit(CheckUpdateFirst(ListCommand)),
			Subcommands: []cli.Command{
				cli.Command{
					Name:   "mounts",
					Usage:  "List the mounted machines.",
					Action: Exit(CheckUpdateFirst(MountsCommand)),
				},
			},
		},
		cli.Command{
			Name:        "mount",
			Usage:       "Mount a remote folder to a local folder.",
			Description: cmdDescriptions["mount"],
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "remotepath, r",
					Usage: "Full path of remote folder in machine to mount.",
				},
				cli.BoolFlag{
					Name:  "noignore, n",
					Usage: "Disable ignoring of default remote folders.",
				},
				// TODO: implement this in klient and then enable this
				// cli.StringFlag{
				//   Name:  "watch, w",
				//   Usage: "Enable watching for changes in remote machine.",
				// },
			},
			Action: Exit(CheckUpdateFirst(MountCommand)),
		},
		cli.Command{
			Name:        "unmount",
			Usage:       "Unmount previously mounted machine.",
			Description: cmdDescriptions["unmount"],
			Action:      Exit(CheckUpdateFirst(UnmountCommand)),
		},
		cli.Command{
			Name:        "ssh",
			Usage:       "SSH into the machine.",
			Description: cmdDescriptions["ssh"],
			Action:      Exit(CheckUpdateFirst(SSHCommandFactory)),
		},
		cli.Command{
			Name:        "install",
			Usage:       fmt.Sprintf("Install the %s.", KlientName),
			Description: cmdDescriptions["install"],
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "kontrol, k",
					Usage: "Specify an alternate Kontrol",
				},
			},
			//HideHelp: true,
			Action: Exit(InstallCommand),
		},
		cli.Command{
			Name:        "uninstall",
			Usage:       fmt.Sprintf("Uninstall the %s.", KlientName),
			Description: fmt.Sprintf("Uninstall the %s.", KlientName),
			Action:      Exit(UninstallCommand),
		},
		cli.Command{
			Name:        "status",
			Usage:       fmt.Sprintf("Status of the %s.", KlientName),
			Description: fmt.Sprintf("Status the %s.", KlientName),
			Action:      Exit(StatusCommand),
		},
		cli.Command{
			Name:        "start",
			Usage:       fmt.Sprintf("Start the %s.", KlientName),
			Description: fmt.Sprintf("Start the %s.", KlientName),
			Action:      Exit(StartCommand),
		},
		cli.Command{
			Name:        "stop",
			Usage:       fmt.Sprintf("Stop the %s.", KlientName),
			Description: fmt.Sprintf("Stop the %s.", KlientName),
			Action:      Exit(StopCommand),
		},
		cli.Command{
			Name:        "restart",
			Usage:       fmt.Sprintf("Restart the %s.", KlientName),
			Description: fmt.Sprintf("Restart the %s.", KlientName),
			Action:      Exit(RestartCommand),
		},
		cli.Command{
			Name:        "update",
			Usage:       "Update to latest version.",
			Description: "Update to latest version.",
			Action:      Exit(UpdateCommand),
		},
	}

	app.Run(os.Args)
}

type ExitingCommand func(*cli.Context) int

func Exit(f ExitingCommand) func(*cli.Context) {
	return func(c *cli.Context) { os.Exit(f(c)) }
}
<commit_msg>klientctl: add shortcuts for common commands<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/koding/klient/cmd/klientctl/util"
)

// sudoRequiredFor is the default list of commands that require sudo.
// The actual handling of this list is done in the SudoRequired func.
var sudoRequiredFor = []string{
	"install",
	"uninstall",
	"start",
	"stop",
	"restart",
	"update",
}

func main() {
	// Check if the command the user is giving requires sudo.
	if err := AdminRequired(os.Args, sudoRequiredFor, util.NewPermissions()); err != nil {
		// In the event of an error, simply print the error to the user
		// and exit.
		fmt.Println("Error: this command requires sudo.")
		os.Exit(10)
	}

	app := cli.NewApp()
	app.Name = Name
	app.Version = fmt.Sprintf("%d", Version)

	app.Commands = []cli.Command{
		cli.Command{
			Name:      "list",
			ShortName: "ls",
			Usage:     "List the available machines.",
			Action:    Exit(CheckUpdateFirst(ListCommand)),
			Subcommands: []cli.Command{
				cli.Command{
					Name:   "mounts",
					Usage:  "List the mounted machines.",
					Action: Exit(CheckUpdateFirst(MountsCommand)),
				},
			},
		},
		cli.Command{
			Name:        "mount",
			ShortName:   "m",
			Usage:       "Mount a remote folder to a local folder.",
			Description: cmdDescriptions["mount"],
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "remotepath, r",
					Usage: "Full path of remote folder in machine to mount.",
				},
				cli.BoolFlag{
					Name:  "noignore, n",
					Usage: "Disable ignoring of default remote folders.",
				},
				// TODO: implement this in klient and then enable this
				// cli.StringFlag{
				//   Name:  "watch, w",
				//   Usage: "Enable watching for changes in remote machine.",
				// },
			},
			Action: Exit(CheckUpdateFirst(MountCommand)),
		},
		cli.Command{
			Name:        "unmount",
			ShortName:   "u",
			Usage:       "Unmount previously mounted machine.",
			Description: cmdDescriptions["unmount"],
			Action:      Exit(CheckUpdateFirst(UnmountCommand)),
		},
		cli.Command{
			Name:        "ssh",
			ShortName:   "s",
			Usage:       "SSH into the machine.",
			Description: cmdDescriptions["ssh"],
			Action:      Exit(CheckUpdateFirst(SSHCommandFactory)),
		},
		cli.Command{
			Name:        "install",
			Usage:       fmt.Sprintf("Install the %s.", KlientName),
			Description: cmdDescriptions["install"],
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "kontrol, k",
					Usage: "Specify an alternate Kontrol",
				},
			},
			//HideHelp: true,
			Action: Exit(InstallCommand),
		},
		cli.Command{
			Name:        "uninstall",
			Usage:       fmt.Sprintf("Uninstall the %s.", KlientName),
			Description: fmt.Sprintf("Uninstall the %s.", KlientName),
			Action:      Exit(UninstallCommand),
		},
		cli.Command{
			Name:        "status",
			Usage:       fmt.Sprintf("Status of the %s.", KlientName),
			Description: fmt.Sprintf("Status the %s.", KlientName),
			Action:      Exit(StatusCommand),
		},
		cli.Command{
			Name:        "start",
			Usage:       fmt.Sprintf("Start the %s.", KlientName),
			Description: fmt.Sprintf("Start the %s.", KlientName),
			Action:      Exit(StartCommand),
		},
		cli.Command{
			Name:        "stop",
			Usage:       fmt.Sprintf("Stop the %s.", KlientName),
			Description: fmt.Sprintf("Stop the %s.", KlientName),
			Action:      Exit(StopCommand),
		},
		cli.Command{
			Name:        "restart",
			Usage:       fmt.Sprintf("Restart the %s.", KlientName),
			Description: fmt.Sprintf("Restart the %s.", KlientName),
			Action:      Exit(RestartCommand),
		},
		cli.Command{
			Name:        "update",
			Usage:       "Update to latest version.",
			Description: "Update to latest version.",
			Action:      Exit(UpdateCommand),
		},
	}

	app.Run(os.Args)
}

type ExitingCommand func(*cli.Context) int

func Exit(f ExitingCommand) func(*cli.Context) {
	return func(c *cli.Context) { os.Exit(f(c)) }
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path"

	bosherr "github.com/cloudfoundry/bosh-agent/errors"
	boshlog "github.com/cloudfoundry/bosh-agent/logger"
	boshlogfile "github.com/cloudfoundry/bosh-agent/logger/file"
	boshsys "github.com/cloudfoundry/bosh-agent/system"
	boshtime "github.com/cloudfoundry/bosh-agent/time"
	boshuuid "github.com/cloudfoundry/bosh-agent/uuid"

	bicmd "github.com/cloudfoundry/bosh-init/cmd"
	biconfig "github.com/cloudfoundry/bosh-init/config"

	biui "github.com/cloudfoundry/bosh-init/ui"
	biuifmt "github.com/cloudfoundry/bosh-init/ui/fmt"
)

const mainLogTag = "main"

func main() {
	logger := newLogger()
	defer logger.HandlePanic("Main")
	fileSystem := boshsys.NewOsFileSystem(logger)
	workspaceRootPath := path.Join(os.Getenv("HOME"), ".bosh_micro")
	workspaceRootPath := path.Join(os.Getenv("HOME"), ".bosh_init")
	ui := biui.NewConsoleUI(logger)
	config := biconfig.UserConfig{}

	uuidGenerator := boshuuid.NewGenerator()

	timeService := boshtime.NewConcreteService()

	cmdFactory := bicmd.NewFactory(
		config,
		fileSystem,
		ui,
		timeService,
		logger,
		uuidGenerator,
		workspaceRootPath,
	)

	cmdRunner := bicmd.NewRunner(cmdFactory)
	stage := biui.NewStage(ui, timeService, logger)
	err := cmdRunner.Run(stage, os.Args[1:]...)
	if err != nil {
		fail(err, ui, logger)
	}
}

func newLogger() boshlog.Logger {
	logLevelString := os.Getenv("BOSH_INIT_LOG_LEVEL")
	level := boshlog.LevelNone
	if logLevelString != "" {
		var err error
		level, err = boshlog.Levelify(logLevelString)
		if err != nil {
			err = bosherr.WrapError(err, "Invalid BOSH_INIT_LOG_LEVEL value")
			logger := boshlog.NewLogger(boshlog.LevelError)
			ui := biui.NewConsoleUI(logger)
			fail(err, ui, logger)
		}
	}

	logPath := os.Getenv("BOSH_INIT_LOG_PATH")
	if logPath != "" {
		return newFileLogger(logPath, level)
	}

	return boshlog.NewLogger(level)
}

func newFileLogger(logPath string, level boshlog.LogLevel) boshlog.Logger {
	// Log file logger errors to the STDERR logger
	logger := boshlog.NewLogger(boshlog.LevelError)
	fileSystem := boshsys.NewOsFileSystem(logger)

	// log file will be closed by process exit
	// log file readable by all
	logger, _, err := boshlogfile.New(level, logPath, boshlogfile.DefaultLogFileMode, fileSystem)
	if err != nil {
		logger := boshlog.NewLogger(boshlog.LevelError)
		ui := biui.NewConsoleUI(logger)
		fail(err, ui, logger)
	}
	return logger
}

func fail(err error, ui biui.UI, logger boshlog.Logger) {
	logger.Error(mainLogTag, err.Error())
	ui.ErrorLinef("")
	ui.ErrorLinef(biuifmt.MultilineError(err))
	os.Exit(1)
}
<commit_msg>Fix rebase issue<commit_after>package main

import (
	"os"
	"path"

	bosherr "github.com/cloudfoundry/bosh-agent/errors"
	boshlog "github.com/cloudfoundry/bosh-agent/logger"
	boshlogfile "github.com/cloudfoundry/bosh-agent/logger/file"
	boshsys "github.com/cloudfoundry/bosh-agent/system"
	boshtime "github.com/cloudfoundry/bosh-agent/time"
	boshuuid "github.com/cloudfoundry/bosh-agent/uuid"

	bicmd "github.com/cloudfoundry/bosh-init/cmd"
	biconfig "github.com/cloudfoundry/bosh-init/config"

	biui "github.com/cloudfoundry/bosh-init/ui"
	biuifmt "github.com/cloudfoundry/bosh-init/ui/fmt"
)

const mainLogTag = "main"

func main() {
	logger := newLogger()
	defer logger.HandlePanic("Main")
	fileSystem := boshsys.NewOsFileSystem(logger)
	workspaceRootPath := path.Join(os.Getenv("HOME"), ".bosh_init")
	ui := biui.NewConsoleUI(logger)
	config := biconfig.UserConfig{}

	uuidGenerator := boshuuid.NewGenerator()

	timeService := boshtime.NewConcreteService()

	cmdFactory := bicmd.NewFactory(
		config,
		fileSystem,
		ui,
		timeService,
		logger,
		uuidGenerator,
		workspaceRootPath,
	)

	cmdRunner := bicmd.NewRunner(cmdFactory)
	stage := biui.NewStage(ui, timeService, logger)
	err := cmdRunner.Run(stage, os.Args[1:]...)
	if err != nil {
		fail(err, ui, logger)
	}
}

func newLogger() boshlog.Logger {
	logLevelString := os.Getenv("BOSH_INIT_LOG_LEVEL")
	level := boshlog.LevelNone
	if logLevelString != "" {
		var err error
		level, err = boshlog.Levelify(logLevelString)
		if err != nil {
			err = bosherr.WrapError(err, "Invalid BOSH_INIT_LOG_LEVEL value")
			logger := boshlog.NewLogger(boshlog.LevelError)
			ui := biui.NewConsoleUI(logger)
			fail(err, ui, logger)
		}
	}

	logPath := os.Getenv("BOSH_INIT_LOG_PATH")
	if logPath != "" {
		return newFileLogger(logPath, level)
	}

	return boshlog.NewLogger(level)
}

func newFileLogger(logPath string, level boshlog.LogLevel) boshlog.Logger {
	// Log file logger errors to the STDERR logger
	logger := boshlog.NewLogger(boshlog.LevelError)
	fileSystem := boshsys.NewOsFileSystem(logger)

	// log file will be closed by process exit
	// log file readable by all
	logger, _, err := boshlogfile.New(level, logPath, boshlogfile.DefaultLogFileMode, fileSystem)
	if err != nil {
		logger := boshlog.NewLogger(boshlog.LevelError)
		ui := biui.NewConsoleUI(logger)
		fail(err, ui, logger)
	}
	return logger
}

func fail(err error, ui biui.UI, logger boshlog.Logger) {
	logger.Error(mainLogTag, err.Error())
	ui.ErrorLinef("")
	ui.ErrorLinef(biuifmt.MultilineError(err))
	os.Exit(1)
}
<|endoftext|>


<commit_before>// Copyright 2014 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 implements cloudsql-import, a program resilient to
// restarts that replays a mysql dump to a MySQL server. The resilience
// is gained by saving the current state after each query.
package main

// TODO: save the /*!... */ queries and replay them when restarting from a checkpoint.
// TODO: speed up the replay by issuing queries concurrently.

import (
	"bufio"
	"bytes"
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/go-sql-driver/mysql"
)

var (
	dump = flag.String("dump", "", "MySQL dump file")
	dsn  = flag.String("dsn", "root:root@tcp(0.0.0.0:3306)/", "MySQL Data Source Name")
)

type logLine struct {
	Position int64
}

// recover recovers the last checkpoint offset.
func recover(filename string) (int64, error) {
	f, err := os.Open(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return 0, nil
		}
		return 0, err
	}
	defer f.Close()
	s := bufio.NewScanner(f)
	last := int64(0)
	for s.Scan() {
		ll := &logLine{}
		err = json.Unmarshal(s.Bytes(), ll)
		if err != nil {
			return 0, err
		}
		last = ll.Position
	}
	if err := s.Err(); err != nil {
		return 0, err
	}
	return last, nil
}

func save(f *os.File, pos int64) error {
	b, err := json.Marshal(logLine{Position: pos})
	if err != nil {
		return err
	}
	_, err = f.Write(append(b, '\n'))
	if err != nil {
		return err
	}
	return f.Sync()
}

// replay replays a MySQL line. Returns false if more data is needed.
func replay(db *sql.DB, line []byte, pos int64, size int64) bool {
	// A comment line starts either with "#" or a "-- ". A "--" is
	// also a valid comment line. A regular line ends with a ";",
	//
	// Reference: http://dev.mysql.com/doc/refman/5.5/en/comments.html
	if len(line) == 0 ||
		bytes.Equal(line, []byte("--")) ||
		bytes.HasPrefix(line, []byte("-- ")) ||
		bytes.HasPrefix(line, []byte("#")) {
		return true
	}

	if line[len(line)-1] != ';' {
		return false
	}

	s := string(line)
	start := time.Now()
	_, err := db.Exec(s)
	since := time.Since(start)
	if len(s) > 80 {
		s = s[:60] + "[...]" + s[len(s)-10:]
	}
	log.Printf("%.2f %7dms %7d %q", float64(pos)/float64(size), since/time.Millisecond, len(line), s)

	if err != nil {
		if merr, ok := err.(*mysql.MySQLError); ok && merr.Number == 1062 {
			log.Printf(`ignoring "duplicate entry" error`)
		} else {
			log.Fatal(err)
		}
	}

	return true
}

func main() {
	flag.Parse()

	if *dump == "" {
		log.Fatalf("no -dump file specified")
	}

	db, err := sql.Open("mysql", *dsn)
	if err != nil {
		log.Fatalln("sql.Open:", err)
	}
	defer db.Close()

	f, err := os.Open(*dump)
	if err != nil {
		log.Fatalf("os.Open: %v", err)
	}
	defer f.Close()
	dumpInfo, err := f.Stat()
	if err != nil {
		log.Fatalf("Stat: %v", err)
	}
	size := dumpInfo.Size()

	logFilename := fmt.Sprintf("%s.log", dumpInfo.Name())
	pos, err := recover(logFilename)
	if err != nil {
		log.Fatalf("recover from log: %v", err)
	}
	if pos != 0 {
		log.Printf("seeking to %d in %q", pos, f.Name())
		if _, err = f.Seek(pos, os.SEEK_SET); err != nil {
			log.Fatalf("Seek: %v", err)
		}
	}

	logFile, err := os.OpenFile(logFilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("os.OpenFile: %v", err)
	}
	defer logFile.Close()

	// buf[i:j] are the bytes that have been read from f but not
	// yet replayed. k indicates up to where we read in a
	// multi-line query.
	buf := make([]byte, 1024*1024)
	i, j, k, readErr := 0, 0, 0, error(nil)
	for {
		if p := bytes.IndexByte(buf[k:j], '\n'); p >= 0 {
			k += p + 1 // The +1 is for the trailing '\n'.
			pos += int64(p + 1)
			if replay(db, buf[i:k-1], pos, size) {
				i = k
				err = save(logFile, pos)
				if err != nil {
					log.Fatalf("Error saving to log: %v", err)
				}
			}
			continue
		}

		if readErr != nil {
			if readErr == io.EOF {
				if i != j {
					log.Println(i, j)
					log.Fatalf(`The contents of %q do not end with a "\n"`, *dump)
				}
				return
			}
			log.Fatal(readErr)
		}

		// First, make sure at least half of the buffer is empty. If we can do
		// that by moving the contents of buf[i:j] to the start of the existing
		// buffer, that's great. Otherwise, allocate a bigger buffer.
		newBuf := buf
		if j-i > len(buf)/2 {
			newBuf = make([]byte, len(buf)*2)
		}
		i, j, k = 0, copy(newBuf, buf[i:j]), k-i
		buf = newBuf
		// Read some more bytes.
		var n int
		n, readErr = f.Read(buf[j:])
		j += n
	}
}
<commit_msg>Adding SSL support to Cloud SQL.<commit_after>// Copyright 2014 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 implements cloudsql-import, a program resilient to
// restarts that replays a mysql dump to a MySQL server. The resilience
// is gained by saving the current state after each query.
package main

// TODO: save the /*!... */ queries and replay them when restarting from a checkpoint.
// TODO: speed up the replay by issuing queries concurrently.

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/go-sql-driver/mysql"
)

var (
	dump       = flag.String("dump", "", "MySQL dump file")
	dsn        = flag.String("dsn", "root:root@tcp(0.0.0.0:3306)/", "MySQL Data Source Name")
	enableSsl  = flag.Bool("enable_ssl", false, "Connect to MySQL with SSL")
	sslCa      = flag.String("ssl_ca", "server-ca.pem", "MySQL Server certificate")
	sslCert    = flag.String("ssl_cert", "client-cert.pem", "MySQL Client PEM cert file")
	sslKey     = flag.String("ssl_key", "client-key.pem", "MySQL Client PEM key file")
	serverName = flag.String("server_name", "project:instance", "Cloud SQL project and instance name")
)

type logLine struct {
	Position int64
}

// recover recovers the last checkpoint offset.
func recover(filename string) (int64, error) {
	f, err := os.Open(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return 0, nil
		}
		return 0, err
	}
	defer f.Close()
	s := bufio.NewScanner(f)
	last := int64(0)
	for s.Scan() {
		ll := &logLine{}
		err = json.Unmarshal(s.Bytes(), ll)
		if err != nil {
			return 0, err
		}
		last = ll.Position
	}
	if err := s.Err(); err != nil {
		return 0, err
	}
	return last, nil
}

func save(f *os.File, pos int64) error {
	b, err := json.Marshal(logLine{Position: pos})
	if err != nil {
		return err
	}
	_, err = f.Write(append(b, '\n'))
	if err != nil {
		return err
	}
	return f.Sync()
}

// replay replays a MySQL line. Returns false if more data is needed.
func replay(db *sql.DB, line []byte, pos int64, size int64) bool {
	// A comment line starts either with "#" or a "-- ". A "--" is
	// also a valid comment line. A regular line ends with a ";",
	//
	// Reference: http://dev.mysql.com/doc/refman/5.5/en/comments.html
	if len(line) == 0 ||
		bytes.Equal(line, []byte("--")) ||
		bytes.HasPrefix(line, []byte("-- ")) ||
		bytes.HasPrefix(line, []byte("#")) {
		return true
	}

	if line[len(line)-1] != ';' {
		return false
	}

	s := string(line)
	start := time.Now()
	_, err := db.Exec(s)
	since := time.Since(start)
	if len(s) > 80 {
		s = s[:60] + "[...]" + s[len(s)-10:]
	}
	log.Printf("%.2f %7dms %7d %q", float64(pos)/float64(size), since/time.Millisecond, len(line), s)

	if err != nil {
		if merr, ok := err.(*mysql.MySQLError); ok && merr.Number == 1062 {
			log.Printf(`ignoring "duplicate entry" error`)
		} else {
			log.Fatal(err)
		}
	}

	return true
}

func main() {
	flag.Parse()

	if *dump == "" {
		log.Fatalf("no -dump file specified")
	}

	if *enableSsl {
		rootCertPool := x509.NewCertPool()
		pem, err := ioutil.ReadFile(*sslCa)
		if err != nil {
			log.Fatalln("ioutil.Readline:", err)
		}
		if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
			log.Fatal("Failed to append CA certificate PEM.")
		}
		clientCert := []tls.Certificate{}
		certs, err := tls.LoadX509KeyPair(*sslCert, *sslKey)
		if err != nil {
			log.Fatalln("tls.LoadX509KeyPair:", err)
		}
		clientCert = append(clientCert, certs)
		mysql.RegisterTLSConfig("custom", &tls.Config{
			RootCAs:      rootCertPool,
			Certificates: clientCert,
			ServerName:   *serverName,
		})
	}
	db, err := sql.Open("mysql", *dsn)
	if err != nil {
		log.Fatalln("sql.Open:", err)
	}
	defer db.Close()

	f, err := os.Open(*dump)
	if err != nil {
		log.Fatalf("os.Open: %v", err)
	}
	defer f.Close()
	dumpInfo, err := f.Stat()
	if err != nil {
		log.Fatalf("Stat: %v", err)
	}
	size := dumpInfo.Size()

	logFilename := fmt.Sprintf("%s.log", dumpInfo.Name())
	pos, err := recover(logFilename)
	if err != nil {
		log.Fatalf("recover from log: %v", err)
	}
	if pos != 0 {
		log.Printf("seeking to %d in %q", pos, f.Name())
		if _, err = f.Seek(pos, os.SEEK_SET); err != nil {
			log.Fatalf("Seek: %v", err)
		}
	}

	logFile, err := os.OpenFile(logFilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("os.OpenFile: %v", err)
	}
	defer logFile.Close()

	// buf[i:j] are the bytes that have been read from f but not
	// yet replayed. k indicates up to where we read in a
	// multi-line query.
	buf := make([]byte, 1024*1024)
	i, j, k, readErr := 0, 0, 0, error(nil)
	for {
		if p := bytes.IndexByte(buf[k:j], '\n'); p >= 0 {
			k += p + 1 // The +1 is for the trailing '\n'.
			pos += int64(p + 1)
			if replay(db, buf[i:k-1], pos, size) {
				i = k
				err = save(logFile, pos)
				if err != nil {
					log.Fatalf("Error saving to log: %v", err)
				}
			}
			continue
		}

		if readErr != nil {
			if readErr == io.EOF {
				if i != j {
					log.Println(i, j)
					log.Fatalf(`The contents of %q do not end with a "\n"`, *dump)
				}
				return
			}
			log.Fatal(readErr)
		}

		// First, make sure at least half of the buffer is empty. If we can do
		// that by moving the contents of buf[i:j] to the start of the existing
		// buffer, that's great. Otherwise, allocate a bigger buffer.
		newBuf := buf
		if j-i > len(buf)/2 {
			newBuf = make([]byte, len(buf)*2)
		}
		i, j, k = 0, copy(newBuf, buf[i:j]), k-i
		buf = newBuf
		// Read some more bytes.
		var n int
		n, readErr = f.Read(buf[j:])
		j += n
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"time"

	"github.com/yaacov/mohawk/backends"
	"github.com/yaacov/mohawk/router"
)

func main() {
	db := backend.Random{}
	db.Open()

	h := Handler{
		backend: db,
		version: "0.21.0",
	}
	r := router.Router{
		Prefix:           "/hawkular/metrics/",
		HandleBadRequest: h.BadRequest,
	}

	r.Add("GET", "status", h.GetStatus)
	r.Add("GET", "metrics", h.GetMetrics)
	r.Add("GET", "gauges/:id/raw", h.GetData)

	srv := &http.Server{
		Addr:           ":8443",
		Handler:        r,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(srv.ListenAndServeTLS("server.pem", "server.key"))
}
<commit_msg>add counters<commit_after>package main

import (
	"log"
	"net/http"
	"time"

	"github.com/yaacov/mohawk/backends"
	"github.com/yaacov/mohawk/router"
)

func main() {
	db := backend.Random{}
	db.Open()

	h := Handler{
		backend: db,
		version: "0.21.0",
	}
	r := router.Router{
		Prefix:           "/hawkular/metrics/",
		HandleBadRequest: h.BadRequest,
	}

	r.Add("GET", "status", h.GetStatus)
	r.Add("GET", "metrics", h.GetMetrics)
	r.Add("GET", "gauges/:id/raw", h.GetData)
	r.Add("GET", "counters/:id/raw", h.GetData)

	srv := &http.Server{
		Addr:           ":8443",
		Handler:        r,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	log.Fatal(srv.ListenAndServeTLS("server.pem", "server.key"))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

func main() {
	a := time.Now()
	fmt.Println(a)
}
<commit_msg>tests tags<commit_after>package main

import (
	"fmt"
	"time"
)

func main() {
	a := time.Now()

	fmt.Println(a)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"image/color"
	"image/gif"
	"log"
	"math"
	"math/rand"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
	"unicode/utf8"

	"github.com/nsf/termbox-go"
)

const HelpBanner = `
╔═╗╦╔═╗╔╦╗╔═╗╦═╗
║ ╦║╠╣  ║ ║╣ ╠╦╝
╚═╝╩╚   ╩ ╚═╝╩╚═
Run gif files in terminal.

Supported Commands:

`

var (
	wg         sync.WaitGroup
	gifImg     *GifImg
	terminal   *Terminal
	termWidth  = Window.Width
	termHeight = Window.Height
	ratio      = Window.Ratio

	// Flags
	out   string
	cell  string
	rb    bool
	delay int
	count uint64

	fs flag.FlagSet
)

func init() {
	// Flags
	fs = *flag.NewFlagSet("Commands", flag.ExitOnError)
	fs.BoolVar(&rb, "rb", false, "Remove background color")
	fs.StringVar(&out, "out", "output.gif", "Create a new GIF file with the dominant (background) color removed")
	fs.StringVar(&cell, "cell", "▄", "Used unicode character as cell block")
	fs.IntVar(&delay, "delay", 120, "Animation speed (delay between frame rates)")
	fs.Uint64Var(&count, "loop", math.MaxUint64, "Loop count")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, HelpBanner)
		fs.PrintDefaults()
	}

	if len(os.Args) <= 1 || os.Args[1] == "--help" || os.Args[1] == "-h" {
		fmt.Fprintf(os.Stderr, HelpBanner)
		fs.PrintDefaults()

		fmt.Println("\nPlease provide a GIF file, or type --help for the supported flags.\n")
		fmt.Println("Exit the animation by pressing <ESC> or 'q'.\n")
		os.Exit(1)
	}

	fs.Parse(os.Args[2:])
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	signalChan := make(chan os.Signal, 2)
	signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

	if delay <= 0 {
		delay = 1
	}

	terminal = &Terminal{}

	img := loadGif(os.Args[1])
	gifImg = &GifImg{}

	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	err := termbox.Init()
	if err != nil {
		log.Fatalf("Unable to initialize termbox: %v", err)
	}
	defer termbox.Close()
	termbox.SetOutputMode(termbox.Output256)

	if rb {
		dominantColor := gifImg.GetDominantColor(img)
		for idx := 0; idx < len(img.Image); idx++ {
			for x := 0; x < img.Config.Width; x++ {
				for y := 0; y < img.Config.Height; y++ {
					gf := img.Image[idx]
					r, g, b, a := gf.At(x, y).RGBA()
					rd, gd, bd, _ := dominantColor.RGBA()
					// remove background color
					if rd == r && gd == g && bd == b {
						r, g, b = 0x00, 0x00, 0x00
					}
					gf.Set(x, y, color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)})
				}
			}
		}
		file, err := os.Create(out)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		defer file.Close()

		// Write out the data into the new GIF file
		err = gif.EncodeAll(file, img)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		img = loadGif(out)
	}
	// Render the gif image
	draw(img)
}

func loadGif(fileName string) *gif.GIF {
	img, err := gifImg.Load(fileName)
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	}
	return img
}

// Render gif on terminal window
func draw(img *gif.GIF) {
	var startX, startY, endX, endY int
	var loopCount uint64

	ticker := time.Tick(time.Millisecond * time.Duration(delay))
	imgWidth, imgHeight := img.Config.Width, img.Config.Height
	scaleX, scaleY := gifImg.Scale(imgWidth, imgHeight, termWidth, termHeight, ratio)
	dominantColor := gifImg.GetDominantColor(img)

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	// This where the magic happens
loop:
	for {
		if loopCount >= count {
			os.Remove(out)
			break loop
		}
		for idx := 0; idx < len(img.Image); idx++ {
			select {
			case ev := <-eventQueue:
				switch ev.Type {
				case termbox.EventKey:
					if ev.Ch == 'q' || ev.Key == termbox.KeyEsc || ev.Key == termbox.KeyCtrlC || ev.Key == termbox.KeyCtrlD {
						os.Remove(out)
						break loop
					}
				case termbox.EventResize:
					//break loop
				}
			default:
				wg.Add(1)
				<-ticker
				go func(idx int) {
					defer wg.Done()
					for x := 0; x < img.Config.Width; x++ {
						for y := 0; y < img.Config.Height; y++ {
							if img.Config.Width <= img.Config.Height {
								startX, startY, endX, endY = gifImg.CellSize(x, y, scaleX, scaleY*ratio, ratio)
							} else {
								startX, startY, endX, endY = gifImg.CellSize(x, y, scaleX, scaleY, ratio)
							}
							col := gifImg.CellAvgRGB(img, dominantColor, startX, startY, endX, (startY+endY)/2, idx)
							colorUp := termbox.Attribute(col)

							col = gifImg.CellAvgRGB(img, dominantColor, startX, (startY+endY)/2, endX, endY, idx)
							colorDown := termbox.Attribute(col)

							r, _ := utf8.DecodeRuneInString(cell)
							termbox.SetCell(x, y, r, colorDown, colorUp)
						}
					}
					termbox.Flush()
				}(idx)
			}
			wg.Wait()
			time.Sleep(10 * time.Millisecond)
		}
		loopCount++
	}
}
<commit_msg>Modify helper banner<commit_after>package main

import (
	"flag"
	"fmt"
	"image/color"
	"image/gif"
	"log"
	"math"
	"math/rand"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
	"unicode/utf8"

	"github.com/nsf/termbox-go"
)

const HelpBanner = `

██████╗ ██╗███████╗████████╗███████╗██████╗
██╔════╝ ██║██╔════╝╚══██╔══╝██╔════╝██╔══██╗
██║  ███╗██║█████╗     ██║   █████╗  ██████╔╝
██║   ██║██║██╔══╝     ██║   ██╔══╝  ██╔══██╗
╚██████╔╝██║██║        ██║   ███████╗██║  ██║
 ╚═════╝ ╚═╝╚═╝        ╚═╝   ╚══════╝╚═╝  ╚═╝

Run gif files in terminal.

Supported Commands:

`

var (
	wg         sync.WaitGroup
	gifImg     *GifImg
	terminal   *Terminal
	termWidth  = Window.Width
	termHeight = Window.Height
	ratio      = Window.Ratio

	// Flags
	out   string
	cell  string
	rb    bool
	delay int
	count uint64

	fs flag.FlagSet
)

func init() {
	// Flags
	fs = *flag.NewFlagSet("Commands", flag.ExitOnError)
	fs.BoolVar(&rb, "rb", false, "Remove background color")
	fs.StringVar(&out, "out", "output.gif", "Create a new GIF file with the dominant (background) color removed")
	fs.StringVar(&cell, "cell", "▄", "Used unicode character as cell block")
	fs.IntVar(&delay, "delay", 120, "Animation speed (delay between frame rates)")
	fs.Uint64Var(&count, "loop", math.MaxUint64, "Loop count")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, HelpBanner)
		fs.PrintDefaults()
	}

	if len(os.Args) <= 1 || os.Args[1] == "--help" || os.Args[1] == "-h" {
		fmt.Fprintf(os.Stderr, HelpBanner)
		fs.PrintDefaults()

		fmt.Println("\nPlease provide a GIF file, or type --help for the supported flags.\n")
		fmt.Println("Exit the animation by pressing <ESC> or 'q'.\n")
		os.Exit(1)
	}

	fs.Parse(os.Args[2:])
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	signalChan := make(chan os.Signal, 2)
	signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

	if delay <= 0 {
		delay = 1
	}

	terminal = &Terminal{}

	img := loadGif(os.Args[1])
	gifImg = &GifImg{}

	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	err := termbox.Init()
	if err != nil {
		log.Fatalf("Unable to initialize termbox: %v", err)
	}
	defer termbox.Close()
	termbox.SetOutputMode(termbox.Output256)

	if rb {
		dominantColor := gifImg.GetDominantColor(img)
		for idx := 0; idx < len(img.Image); idx++ {
			for x := 0; x < img.Config.Width; x++ {
				for y := 0; y < img.Config.Height; y++ {
					gf := img.Image[idx]
					r, g, b, a := gf.At(x, y).RGBA()
					rd, gd, bd, _ := dominantColor.RGBA()
					// remove background color
					if rd == r && gd == g && bd == b {
						r, g, b = 0x00, 0x00, 0x00
					}
					gf.Set(x, y, color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)})
				}
			}
		}
		file, err := os.Create(out)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		defer file.Close()

		// Write out the data into the new GIF file
		err = gif.EncodeAll(file, img)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		img = loadGif(out)
	}
	// Render the gif image
	draw(img)
}

func loadGif(fileName string) *gif.GIF {
	img, err := gifImg.Load(fileName)
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(1)
	}
	return img
}

// Render gif on terminal window
func draw(img *gif.GIF) {
	var startX, startY, endX, endY int
	var loopCount uint64

	ticker := time.Tick(time.Millisecond * time.Duration(delay))
	imgWidth, imgHeight := img.Config.Width, img.Config.Height
	scaleX, scaleY := gifImg.Scale(imgWidth, imgHeight, termWidth, termHeight, ratio)
	dominantColor := gifImg.GetDominantColor(img)

	eventQueue := make(chan termbox.Event)
	go func() {
		for {
			eventQueue <- termbox.PollEvent()
		}
	}()

	// This where the magic happens
loop:
	for {
		if loopCount >= count {
			os.Remove(out)
			break loop
		}
		for idx := 0; idx < len(img.Image); idx++ {
			select {
			case ev := <-eventQueue:
				switch ev.Type {
				case termbox.EventKey:
					if ev.Ch == 'q' || ev.Key == termbox.KeyEsc || ev.Key == termbox.KeyCtrlC || ev.Key == termbox.KeyCtrlD {
						os.Remove(out)
						break loop
					}
				case termbox.EventResize:
					//break loop
				}
			default:
				wg.Add(1)
				<-ticker
				go func(idx int) {
					defer wg.Done()
					for x := 0; x < img.Config.Width; x++ {
						for y := 0; y < img.Config.Height; y++ {
							if img.Config.Width <= img.Config.Height {
								startX, startY, endX, endY = gifImg.CellSize(x, y, scaleX, scaleY*ratio, ratio)
							} else {
								startX, startY, endX, endY = gifImg.CellSize(x, y, scaleX, scaleY, ratio)
							}
							col := gifImg.CellAvgRGB(img, dominantColor, startX, startY, endX, (startY+endY)/2, idx)
							colorUp := termbox.Attribute(col)

							col = gifImg.CellAvgRGB(img, dominantColor, startX, (startY+endY)/2, endX, endY, idx)
							colorDown := termbox.Attribute(col)

							r, _ := utf8.DecodeRuneInString(cell)
							termbox.SetCell(x, y, r, colorDown, colorUp)
						}
					}
					termbox.Flush()
				}(idx)
			}
			wg.Wait()
			time.Sleep(10 * time.Millisecond)
		}
		loopCount++
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"ponydownloader/settings"
	"strconv"

	"github.com/vaughan0/go-ini"
)

//	default variables
var (
	QDEPTH     int64       = 20    //Depth of the queue buffer - how many images are enqueued
	IMGDIR     string      = "img" //Default download directory
	TAG        string      = ""    //Default tag string is empty, it should be extracted from command line and only command line
	STARTPAGE  int         = 1     //Default start page, derpiboo.ru 1-indexed
	STOPPAGE   int         = 0     //Default stop page, would stop parsing json when stop page is reached or site reaches the end of search
	elog       *log.Logger         //The logger for errors
	SCRFILTER  int                 //So we can ignore things with limited
	FILTERFLAG bool        = false //Gah, not sure how to make it better.
)

type Image struct {
	imgid    int
	url      string
	filename string
	score    int
	//	hash     string
}

func main() {

	fmt.Println("Derpiboo.ru Downloader version 0.2.0")

	elog, logfile := settings.SetLog() //setting up logging of errors

	defer logfile.Close() //Almost forgot. Always close the file in the end.

	config, err := ini.LoadFile("config.ini") // Loading default config file and checking for various errors.

	if os.IsNotExist(err) {
		elog.Fatalln("Config.ini does not exist, create it") //We can not live without config. We could, in theory, but writing default config if none exist can wait
	}

	if err != nil {
		elog.Panicln(err) //Oh, something is broken beyond my understanding. Sorry.
	}

	//Getting stuff from config, overwriting hardwired defaults when needed

	key, ok := config.Get("main", "key")

	if !ok || key == "" {
		elog.Println("'key' variable missing from 'main' section. It is vital for server-side filtering") //Empty key or key does not exist. Derpibooru works with this, but default image filter filters too much. Use key to set your own!
	}

	Q_temp, _ := config.Get("main", "workers")

	if Q_temp != "" {
		QDEPTH, err = strconv.ParseInt(Q_temp, 10, 0)

		if err != nil {
			elog.Fatalln("Wrong configuration: Depth of the buffer queue is not a number")

		}
	}

	ID_temp, _ := config.Get("main", "downdir")

	if ID_temp != "" {
		IMGDIR = ID_temp
	}

	//Here we are parsing all the flags. Command line argument hold priority to config. Except for 'key'. API-key is config-only

	flag.StringVar(&TAG, "t", TAG, "Tags to download")
	flag.IntVar(&STARTPAGE, "p", STARTPAGE, "Starting page for search")
	flag.IntVar(&STOPPAGE, "np", STOPPAGE, "Stopping page for search, 0 - parse all all search pages")
	flag.IntVar(&SCRFILTER, "scr", SCRFILTER, "Minimal score of image for it to be downloaded")
	flag.BoolVar(&FILTERFLAG, "filter", FILTERFLAG, "If set to true, enables client-side filtration of downloaded images")

	flag.Parse()

	if flag.NArg() == 0 && TAG == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
		log.SetPrefix("Done at ") //We can not do this with elog!
		log.Println("Nothing to download, bye!")
		os.Exit(0)
	}

	//Creating directory for downloads if it does not yet exist
	if err := os.MkdirAll(IMGDIR, 0644); err != nil { //Execute? No need to execute any image. Also, all those other users can not do anything beyond enjoying our images.
		elog.Fatalln(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(chan Image, QDEPTH) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal perfomance on my system
	done := make(chan bool)

	if TAG == "" { //Because we can put imgid with flags. Why not?

		//	Checking argument for being a number and then getting image data

		imgid := flag.Arg(0) //0-indexed, unlike os.Args. os.Args[0] is path to program. It needs to be used later, when we are searching for what directory we are writing in
		_, err = strconv.Atoi(imgid)

		if err != nil {
			elog.Fatalln("Wrong input: can not parse", imgid, "as a number")
		}

		log.Println("Processing image No", imgid)

		go ParseImg(imgdat, imgid, key) // Sending imgid to parser. Here validity is our problem

	} else {

		//	and here we send tags to getter/parser. Validity is server problem, mostly

		log.Println("Processing tags", TAG)
		go ParseTag(imgdat, TAG, key)
	}

	log.Println("Starting worker") //It would be funny if worker goroutine does not start

	filtimgdat := make(chan Image, QDEPTH)
	go FilterChannel(imgdat, filtimgdat)
	go DlImg(filtimgdat, done)

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finised")
	//And we are done here! Hooray!
	return
}

func ParseImg(imgchan chan<- Image, imgid string, key string) {

	source := "http://derpiboo.ru/images/" + imgid + ".json?nofav=&nocomments="
	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Getting image info at:", source)

	resp, err := http.Get(source) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
	if err != nil {
		elog.Println(err)
		return
	}

	defer resp.Body.Close() //and not forgetting to close it when it's done

	var dat map[string]interface{}

	body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
	if err != nil {
		elog.Println(err)
		return
	}

	if err := json.Unmarshal(body, &dat); //transforming json into native map

	err != nil {
		elog.Println(err)
		return
	}

	InfoToChannel(dat, imgchan)

	close(imgchan) //closing channel, we are done here

	return
}

func DlImg(imgchan <-chan Image, done chan bool) {

	fmt.Println("Worker started; reading channel") //nice notification that we are not forgotten

	for {

		imgdata, more := <-imgchan

		if more { //checking that there is an image in channel

			if imgdata.filename == "" {
				elog.Println("Empty filename. Oops?") //something somewhere had gone wrong, going to the next image
			} else {

				fmt.Println("Saving as", imgdata.filename)

				func() { // to not hold all the files open when there is no need

					output, err := os.Create(IMGDIR + string(os.PathSeparator) + imgdata.filename) //And now, THE FILE!
					if err != err {
						elog.Println("Error when creating file for image" + strconv.Itoa(imgdata.imgid))
						elog.Println(err)
						return
					}
					defer output.Close() //Not forgetting to deal with it after completing download

					response, err := http.Get(imgdata.url)
					if err != nil {
						elog.Println("Error when getting image", imgdata.imgid)
						elog.Println(err)
						return
					}
					defer response.Body.Close() //Same, we shall not listen to the void when we finished getting image

					io.Copy(output, response.Body) //	Writing things we got from Derpibooru into the file and into hasher

				}()
			}

			//fmt.Println("\n", hex.EncodeToString(hash.Sum(nil)), "\n", imgdata.hash )

		} else {
			done <- true //well, there is no images in channel, it means we got them all, so synchronization is kicking in and ending the process
			break        //Just in case, so it would not stupidly die when program finishes - it will die smartly

		}
	}
}

func ParseTag(imgchan chan<- Image, tag string, key string) {

	source := "http://derpiboo.ru/search.json?nofav=&nocomments=" //yay hardwiring url strings!

	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Searching as", source+"&q="+tag)
	var working bool = true
	i := STARTPAGE
	for working {
		func() {
			fmt.Println("Searching page", i)
			resp, err := http.Get(source + "&q=" + tag + "&page=" + strconv.Itoa(i)) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
			defer resp.Body.Close()                                                  //and not forgetting to close it when it's done. And before we panic and die horribly.
			if err != nil {
				elog.Println("Error while getting search page", i)
				elog.Println(err)
				return
			}

			var dats []map[string]interface{} //Because we got array incoming instead of single object, we using an slive of maps!

			//fmt.Println(resp)

			body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
			if err != nil {
				elog.Println("Error while reading search page", i)
				elog.Println(err)
				return
			}

			//fmt.Println(body)

			if err := json.Unmarshal(body, &dats); //transforming json into native slice of maps

			err != nil {
				elog.Println("Error while parsing search page", i)
				elog.Println(err)
				return

			}

			if len(dats) == 0 {
				fmt.Println("Pages are over")
				working = false
				return
			} //exit due to finishing all pages

			for _, dat := range dats {
				InfoToChannel(dat, imgchan)
			}
			if i == STOPPAGE {
				working = false
				return
			}
			i++

		}()
	}

	close(imgchan)
}

func InfoToChannel(dat map[string]interface{}, imgchan chan<- Image) {

	var imgdata Image

	imgdata.url = "http:" + dat["image"].(string)
	//	imgdata.hash = dat["sha512_hash"].(string)
	imgdata.filename = (strconv.FormatFloat(dat["id_number"].(float64), 'f', -1, 64) + "." + dat["file_name"].(string) + "." + dat["original_format"].(string))
	imgdata.imgid = int(dat["id_number"].(float64))
	imgdata.score = int(dat["score"].(float64))

	//	for troubleshooting - possibly debug flag?
	//	fmt.Println(dat)
	//	fmt.Println(imgdata.url)
	//	fmt.Println(imgdata.hash)
	//	fmt.Println(imgdata.filename)

	imgchan <- imgdata
}

func FilterChannel(inchan <-chan Image, outchan chan<- Image) {

	for {

		imgdata, more := <-inchan

		if !more {
			close(outchan)
			return //Why make a bunch of layers of ifs if one can just end it all?
		}

		if !FILTERFLAG || (FILTERFLAG && imgdata.score >= SCRFILTER) {
			outchan <- imgdata
		} else {
			fmt.Println("Filtering " + imgdata.filename)
		}
	}
}
<commit_msg>One level of braces from major function is gone. Now it's ought to be more readable and whatever<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"ponydownloader/settings"
	"strconv"

	"github.com/vaughan0/go-ini"
)

//	default variables
var (
	QDEPTH     int64       = 20    //Depth of the queue buffer - how many images are enqueued
	IMGDIR     string      = "img" //Default download directory
	TAG        string      = ""    //Default tag string is empty, it should be extracted from command line and only command line
	STARTPAGE  int         = 1     //Default start page, derpiboo.ru 1-indexed
	STOPPAGE   int         = 0     //Default stop page, would stop parsing json when stop page is reached or site reaches the end of search
	elog       *log.Logger         //The logger for errors
	SCRFILTER  int                 //So we can ignore things with limited
	FILTERFLAG bool        = false //Gah, not sure how to make it better.
)

type Image struct {
	imgid    int
	url      string
	filename string
	score    int
	//	hash     string
}

func main() {

	fmt.Println("Derpiboo.ru Downloader version 0.2.0")

	elog, logfile := settings.SetLog() //setting up logging of errors

	defer logfile.Close() //Almost forgot. Always close the file in the end.

	config, err := ini.LoadFile("config.ini") // Loading default config file and checking for various errors.

	if os.IsNotExist(err) {
		elog.Fatalln("Config.ini does not exist, create it") //We can not live without config. We could, in theory, but writing default config if none exist can wait
	}

	if err != nil {
		elog.Panicln(err) //Oh, something is broken beyond my understanding. Sorry.
	}

	//Getting stuff from config, overwriting hardwired defaults when needed

	key, ok := config.Get("main", "key")

	if !ok || key == "" {
		elog.Println("'key' variable missing from 'main' section. It is vital for server-side filtering") //Empty key or key does not exist. Derpibooru works with this, but default image filter filters too much. Use key to set your own!
	}

	Q_temp, _ := config.Get("main", "workers")

	if Q_temp != "" {
		QDEPTH, err = strconv.ParseInt(Q_temp, 10, 0)

		if err != nil {
			elog.Fatalln("Wrong configuration: Depth of the buffer queue is not a number")

		}
	}

	ID_temp, _ := config.Get("main", "downdir")

	if ID_temp != "" {
		IMGDIR = ID_temp
	}

	//Here we are parsing all the flags. Command line argument hold priority to config. Except for 'key'. API-key is config-only

	flag.StringVar(&TAG, "t", TAG, "Tags to download")
	flag.IntVar(&STARTPAGE, "p", STARTPAGE, "Starting page for search")
	flag.IntVar(&STOPPAGE, "np", STOPPAGE, "Stopping page for search, 0 - parse all all search pages")
	flag.IntVar(&SCRFILTER, "scr", SCRFILTER, "Minimal score of image for it to be downloaded")
	flag.BoolVar(&FILTERFLAG, "filter", FILTERFLAG, "If set to true, enables client-side filtration of downloaded images")

	flag.Parse()

	if flag.NArg() == 0 && TAG == "" { //If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
		log.SetPrefix("Done at ") //We can not do this with elog!
		log.Println("Nothing to download, bye!")
		os.Exit(0)
	}

	//Creating directory for downloads if it does not yet exist
	if err := os.MkdirAll(IMGDIR, 0644); err != nil { //Execute? No need to execute any image. Also, all those other users can not do anything beyond enjoying our images.
		elog.Fatalln(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(chan Image, QDEPTH) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal perfomance on my system
	done := make(chan bool)

	if TAG == "" { //Because we can put imgid with flags. Why not?

		//	Checking argument for being a number and then getting image data

		imgid := flag.Arg(0) //0-indexed, unlike os.Args. os.Args[0] is path to program. It needs to be used later, when we are searching for what directory we are writing in
		_, err = strconv.Atoi(imgid)

		if err != nil {
			elog.Fatalln("Wrong input: can not parse", imgid, "as a number")
		}

		log.Println("Processing image No", imgid)

		go ParseImg(imgdat, imgid, key) // Sending imgid to parser. Here validity is our problem

	} else {

		//	and here we send tags to getter/parser. Validity is server problem, mostly

		log.Println("Processing tags", TAG)
		go ParseTag(imgdat, TAG, key)
	}

	log.Println("Starting worker") //It would be funny if worker goroutine does not start

	filtimgdat := make(chan Image, QDEPTH)
	go FilterChannel(imgdat, filtimgdat)
	go DlImg(filtimgdat, done)

	<-done
	log.SetPrefix("Done at ")
	log.Println("Finised")
	//And we are done here! Hooray!
	return
}

func ParseImg(imgchan chan<- Image, imgid string, key string) {

	source := "http://derpiboo.ru/images/" + imgid + ".json?nofav=&nocomments="
	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Getting image info at:", source)

	resp, err := http.Get(source) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
	if err != nil {
		elog.Println(err)
		return
	}

	defer resp.Body.Close() //and not forgetting to close it when it's done

	var dat map[string]interface{}

	body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
	if err != nil {
		elog.Println(err)
		return
	}

	if err := json.Unmarshal(body, &dat); //transforming json into native map

	err != nil {
		elog.Println(err)
		return
	}

	InfoToChannel(dat, imgchan)

	close(imgchan) //closing channel, we are done here

	return
}

func DlImg(imgchan <-chan Image, done chan bool) {

	fmt.Println("Worker started; reading channel") //nice notification that we are not forgotten

	for {

		imgdata, more := <-imgchan

		if !more { //checking that there is an image in channel
			done <- true //well, there is no images in channel, it means we got them all, so synchronization is kicking in and ending the process
			break        //Just in case, so it would not stupidly die when program finishes - it will die smartly
		}

		if imgdata.filename == "" {
			elog.Println("Empty filename. Oops?") //something somewhere had gone wrong, not a cause to die, going to the next image
		} else {

			fmt.Println("Saving as", imgdata.filename)

			func() { // To not hold all the files open when there is no need. All pointers to files are in the scope of this function.

				output, err := os.Create(IMGDIR + string(os.PathSeparator) + imgdata.filename) //And now, THE FILE!
				if err != err {
					elog.Println("Error when creating file for image" + strconv.Itoa(imgdata.imgid))
					elog.Println(err) //Either we got no permisson or no space, end of line
					return
				}
				defer output.Close() //Not forgetting to deal with it after completing download

				response, err := http.Get(imgdata.url)
				if err != nil {
					elog.Println("Error when getting image", imgdata.imgid)
					elog.Println(err)
					return
				}
				defer response.Body.Close() //Same, we shall not listen to the void when we finished getting image

				io.Copy(output, response.Body) //	Writing things we got from Derpibooru into the file and into hasher

			}()
		}

		//fmt.Println("\n", hex.EncodeToString(hash.Sum(nil)), "\n", imgdata.hash )

	}
}

func ParseTag(imgchan chan<- Image, tag string, key string) {

	source := "http://derpiboo.ru/search.json?nofav=&nocomments=" //yay hardwiring url strings!

	if key != "" {
		source = source + "&key=" + key
	}

	fmt.Println("Searching as", source+"&q="+tag)
	var working bool = true
	i := STARTPAGE
	for working {
		func() { //I suspect that all those returns could be dealt with in some way. But lazy.
			fmt.Println("Searching page", i)
			resp, err := http.Get(source + "&q=" + tag + "&page=" + strconv.Itoa(i)) //Getting our nice http response. Needs checking for 404 and other responses that are... less expected
			defer resp.Body.Close()                                                  //and not forgetting to close it when it's done. And before we panic and die horribly.
			if err != nil {
				elog.Println("Error while getting search page", i)
				elog.Println(err)
				return
			}

			var dats []map[string]interface{} //Because we got array incoming instead of single object, we using an slive of maps!

			//fmt.Println(resp)

			body, err := ioutil.ReadAll(resp.Body) //stolen from official documentation
			if err != nil {
				elog.Println("Error while reading search page", i)
				elog.Println(err)
				return
			}

			//fmt.Println(body)

			if err := json.Unmarshal(body, &dats); //transforming json into native slice of maps

			err != nil {
				elog.Println("Error while parsing search page", i)
				elog.Println(err)
				return

			}

			if len(dats) == 0 {
				fmt.Println("Pages are over") //Does not mean that process is over.
				working = false
				return
			} //exit due to finishing all pages

			for _, dat := range dats {
				InfoToChannel(dat, imgchan)
			}
			if i == STOPPAGE {
				working = false
				return
			}
			i++

		}()
	}

	close(imgchan)
}

func InfoToChannel(dat map[string]interface{}, imgchan chan<- Image) {

	var imgdata Image

	imgdata.url = "http:" + dat["image"].(string)
	//	imgdata.hash = dat["sha512_hash"].(string)
	imgdata.filename = (strconv.FormatFloat(dat["id_number"].(float64), 'f', -1, 64) + "." + dat["file_name"].(string) + "." + dat["original_format"].(string))
	imgdata.imgid = int(dat["id_number"].(float64))
	imgdata.score = int(dat["score"].(float64))

	//	for troubleshooting - possibly debug flag?
	//	fmt.Println(dat)
	//	fmt.Println(imgdata.url)
	//	fmt.Println(imgdata.hash)
	//	fmt.Println(imgdata.filename)

	imgchan <- imgdata
}

func FilterChannel(inchan <-chan Image, outchan chan<- Image) {

	for {

		imgdata, more := <-inchan

		if !more {
			close(outchan)
			return //Why make a bunch of layers of ifs if one can just end it all?
		}

		if !FILTERFLAG || (FILTERFLAG && imgdata.score >= SCRFILTER) {
			outchan <- imgdata
		} else {
			fmt.Println("Filtering " + imgdata.filename)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Hello world!")
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe("localhost:8000", nil)
}
<commit_msg>Add http mux and error handling.<commit_after>package main

import (
	"io"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Hello world!")
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", hello)

	if err := http.ListenAndServe("localhost:8000", mux); err != nil {
		panic(err)
	}
}
<|endoftext|>