<commit_before>package main

import "fmt"
import "encoding/json"
import "net/http"
import "os"
import "io/ioutil"
import "log"
import "strings"
import "math/rand"
import "time"
import "reflect"

type Configuration struct {
	Token   string
	RootDir string
}

var Conf Configuration = Configuration{}

func initConf() {
	// Development
	file, _ := os.Open("conf.json")

	// Production
	// file, _ := os.Open("/root/dogbot/prod.conf.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&Conf)
	if err != nil {
		fmt.Println("error:", err)
	}
}

func initBreeds(breeds map[string]string) {
	files, err := ioutil.ReadDir(Conf.RootDir + "static/")
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		spl := strings.Split(file.Name(), "-")
		breed := strings.ToLower(spl[1])
		breed = strings.Replace(breed, "_", " ", -1)
		breeds[breed] = file.Name()
	}
}

// Builds a url to a random image from the requested directory
func getRandomImageUrl(imgDir string) string {
	// Development
	// base := "http://localhost:8080/static/"
	// Production
	base := "http://dogbot.freddysplant.com/static/"
	files, err := ioutil.ReadDir(Conf.RootDir + "static/" + imgDir)
	if err != nil {
		log.Fatal(err)
	}
	idx := rand.Intn(len(files))
	file := files[idx]
	url := base + imgDir + "/" + file.Name()
	return url
}

// Levenshtein distance between two strings
func levenshtein(a string, b string) int {
	return 0
}

// Makes a guess at the requested category
func parseBreedQuery(query string, breeds []string) string {
	// TODO: Calculate levenshtein distance between this string and all other strings
	return query
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initConf()

	staticDir := Conf.RootDir + "static/"

	// Serve the images
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))
	// Development
	// go http.ListenAndServe(":5555", nil)

	// Production
	go http.ListenAndServe(":8080", nil)

	// Start an RTM session
	ws, id := slackConnect(Conf.Token)

	// build the map of human readable breed names to source directory
	var breeds map[string]string = make(map[string]string)
	initBreeds(breeds)
	keys := reflect.ValueOf(breeds).MapKeys()
	breedsAvailable := make([]string, len(keys))
	for i := 0; i < len(keys); i++ {
		breedsAvailable[i] = keys[i].String()
	}

	for {
		// read each incoming message
		m, err := getMessage(ws)
		if err != nil {
			log.Fatal(err)
		}

		// see if we're mentioned
		if m.Type == "message" && strings.HasPrefix(m.Text, "<@"+id+">") {
			fmt.Println(m)
			go func(m Message) {
				// Strip @ id
				breed := strings.Replace(m.Text, "<@"+id+"> ", "", -1)
				fmt.Println("Attempting to fetch photo for breed: " + breed)
				breed = parseBreedQuery(breed, breedsAvailable)
				if imgDir, ok := breeds[breed]; ok {
					msg := getRandomImageUrl(imgDir)
					m.Text = msg
				} else {
					m.Text = "Sorry, I don't know that dog."
				}
				postMessage(ws, m)
			}(m)
		}
	}
}
<commit_msg>More configuration extraction<commit_after>package main

import "fmt"
import "encoding/json"
import "net/http"
import "os"
import "io/ioutil"
import "log"
import "strings"
import "math/rand"
import "time"
import "reflect"

type Configuration struct {
	Token         string
	RootDir       string
	Port          string
	StaticBaseURL string
}

var Conf Configuration = Configuration{}

func initConf() {
	// Development
	// file, _ := os.Open("conf.json")

	// Production
	file, _ := os.Open("/root/dogbot/prod.conf.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&Conf)
	if err != nil {
		fmt.Println("error:", err)
	}
}

func initBreeds(breeds map[string]string) {
	files, err := ioutil.ReadDir(Conf.RootDir + "static/")
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		spl := strings.Split(file.Name(), "-")
		breed := strings.ToLower(spl[1])
		breed = strings.Replace(breed, "_", " ", -1)
		breeds[breed] = file.Name()
	}
}

// Builds a url to a random image from the requested directory
func getRandomImageUrl(imgDir string) string {
	files, err := ioutil.ReadDir(Conf.RootDir + "static/" + imgDir)
	if err != nil {
		log.Fatal(err)
	}
	idx := rand.Intn(len(files))
	file := files[idx]
	url := Conf.StaticBaseURL + imgDir + "/" + file.Name()
	return url
}

// Levenshtein distance between two strings
func levenshtein(a string, b string) int {
	return 0
}

// Makes a guess at the requested category
func parseBreedQuery(query string, breeds []string) string {
	// TODO: Calculate levenshtein distance between this string and all other strings
	return query
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initConf()

	staticDir := Conf.RootDir + "static/"

	// Serve the images
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))

	go http.ListenAndServe(Conf.Port, nil)

	// Start an RTM session
	ws, id := slackConnect(Conf.Token)

	// build the map of human readable breed names to source directory
	var breeds map[string]string = make(map[string]string)
	initBreeds(breeds)
	keys := reflect.ValueOf(breeds).MapKeys()
	breedsAvailable := make([]string, len(keys))
	for i := 0; i < len(keys); i++ {
		breedsAvailable[i] = keys[i].String()
	}

	for {
		// read each incoming message
		m, err := getMessage(ws)
		if err != nil {
			log.Fatal(err)
		}

		// see if we're mentioned
		if m.Type == "message" && strings.HasPrefix(m.Text, "<@"+id+">") {
			fmt.Println(m)
			go func(m Message) {
				// Strip @ id
				breed := strings.Replace(m.Text, "<@"+id+"> ", "", -1)
				fmt.Println("Attempting to fetch photo for breed: " + breed)
				breed = parseBreedQuery(breed, breedsAvailable)
				if imgDir, ok := breeds[breed]; ok {
					msg := getRandomImageUrl(imgDir)
					m.Text = msg
				} else {
					m.Text = "Sorry, I don't know that dog."
				}
				postMessage(ws, m)
			}(m)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/envy/lib"
	"github.com/codegangsta/gin/lib"

	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

var (
	startTime  = time.Now()
	logger     = log.New(os.Stdout, "[gin] ", 0)
	buildError error
)

func main() {
	app := cli.NewApp()
	app.Name = "gin"
	app.Usage = "A live reload utility for Go web applications."
	app.Action = MainAction
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "port for the proxy server",
		},
		cli.IntFlag{
			Name:  "appPort,a",
			Value: 3001,
			Usage: "port for the Go web server",
		},
		cli.StringFlag{
			Name:  "bin,b",
			Value: "gin-bin",
			Usage: "name of generated binary file",
		},
		cli.StringFlag{
			Name:  "path,t",
			Value: ".",
			Usage: "Path to watch files from",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "run",
			ShortName: "r",
			Usage:     "Run the gin proxy in the current working directory",
			Action:    MainAction,
		},
		{
			Name:      "env",
			ShortName: "e",
			Usage:     "Display environment variables set by the .env file",
			Action:    EnvAction,
		},
	}

	app.Run(os.Args)
}

func MainAction(c *cli.Context) {
	port := c.GlobalInt("port")
	appPort := strconv.Itoa(c.GlobalInt("appPort"))

	// Bootstrap the environment
	envy.Bootstrap()

	// Set the PORT env
	os.Setenv("PORT", appPort)

	wd, err := os.Getwd()
	if err != nil {
		logger.Fatal(err)
	}

	builder := gin.NewBuilder(c.GlobalString("path"), c.GlobalString("bin"))
	runner := gin.NewRunner(filepath.Join(wd, builder.Binary()), c.Args()...)
	runner.SetWriter(os.Stdout)
	proxy := gin.NewProxy(builder, runner)

	config := &gin.Config{
		Port:    port,
		ProxyTo: "http://localhost:" + appPort,
	}

	err = proxy.Run(config)
	if err != nil {
		logger.Fatal(err)
	}

	logger.Printf("listening on port %d\n", port)

	shutdown(runner)

	// build right now
	build(builder, logger)

	// scan for changes
	scanChanges(c.GlobalString("path"), func(path string) {
		runner.Kill()
		build(builder, logger)
	})
}

func EnvAction(c *cli.Context) {
	// Bootstrap the environment
	env, err := envy.Bootstrap()
	if err != nil {
		logger.Fatalln(err)
	}

	for k, v := range env {
		fmt.Printf("%s: %s\n", k, v)
	}

}

func build(builder gin.Builder, logger *log.Logger) {
	err := builder.Build()
	if err != nil {
		buildError = err
		logger.Println("ERROR! Build failed.")
		fmt.Println(builder.Errors())
	} else {
		// print success only if there were errors before
		if buildError != nil {
			logger.Println("Build Successful")
		}
		buildError = nil
	}

	time.Sleep(100 * time.Millisecond)
}

type scanCallback func(path string)

func scanChanges(watchPath string, cb scanCallback) {
	for {
		filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error {
			if path == ".git" {
				return filepath.SkipDir
			}

			// ignore hidden files
			if filepath.Base(path)[0] == '.' {
				return nil
			}

			if filepath.Ext(path) == ".go" && info.ModTime().After(startTime) {
				cb(path)
				startTime = time.Now()
				return errors.New("done")
			}

			return nil
		})
		time.Sleep(500 * time.Millisecond)
	}
}

func shutdown(runner gin.Runner) {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-c
		log.Println("Got signal: ", s)
		err := runner.Kill()
		if err != nil {
			log.Print("Error killing: ", err)
		}
		os.Exit(1)
	}()
}
<commit_msg>Should add HTML support<commit_after>package main

import (
	"errors"
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/envy/lib"
	"github.com/codegangsta/gin/lib"

	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"syscall"
	"time"
)

var (
	startTime  = time.Now()
	logger     = log.New(os.Stdout, "[gin] ", 0)
	buildError error
)

func main() {
	app := cli.NewApp()
	app.Name = "gin"
	app.Usage = "A live reload utility for Go web applications."
	app.Action = MainAction
	app.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "port for the proxy server",
		},
		cli.IntFlag{
			Name:  "appPort,a",
			Value: 3001,
			Usage: "port for the Go web server",
		},
		cli.StringFlag{
			Name:  "bin,b",
			Value: "gin-bin",
			Usage: "name of generated binary file",
		},
		cli.StringFlag{
			Name:  "path,t",
			Value: ".",
			Usage: "Path to watch files from",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "run",
			ShortName: "r",
			Usage:     "Run the gin proxy in the current working directory",
			Action:    MainAction,
		},
		{
			Name:      "env",
			ShortName: "e",
			Usage:     "Display environment variables set by the .env file",
			Action:    EnvAction,
		},
	}

	app.Run(os.Args)
}

func MainAction(c *cli.Context) {
	port := c.GlobalInt("port")
	appPort := strconv.Itoa(c.GlobalInt("appPort"))

	// Bootstrap the environment
	envy.Bootstrap()

	// Set the PORT env
	os.Setenv("PORT", appPort)

	wd, err := os.Getwd()
	if err != nil {
		logger.Fatal(err)
	}

	builder := gin.NewBuilder(c.GlobalString("path"), c.GlobalString("bin"))
	runner := gin.NewRunner(filepath.Join(wd, builder.Binary()), c.Args()...)
	runner.SetWriter(os.Stdout)
	proxy := gin.NewProxy(builder, runner)

	config := &gin.Config{
		Port:    port,
		ProxyTo: "http://localhost:" + appPort,
	}

	err = proxy.Run(config)
	if err != nil {
		logger.Fatal(err)
	}

	logger.Printf("listening on port %d\n", port)

	shutdown(runner)

	// build right now
	build(builder, logger)

	// scan for changes
	scanChanges(c.GlobalString("path"), func(path string) {
		runner.Kill()
		build(builder, logger)
	})
}

func EnvAction(c *cli.Context) {
	// Bootstrap the environment
	env, err := envy.Bootstrap()
	if err != nil {
		logger.Fatalln(err)
	}

	for k, v := range env {
		fmt.Printf("%s: %s\n", k, v)
	}

}

func build(builder gin.Builder, logger *log.Logger) {
	err := builder.Build()
	if err != nil {
		buildError = err
		logger.Println("ERROR! Build failed.")
		fmt.Println(builder.Errors())
	} else {
		// print success only if there were errors before
		if buildError != nil {
			logger.Println("Build Successful")
		}
		buildError = nil
	}

	time.Sleep(100 * time.Millisecond)
}

type scanCallback func(path string)

func scanChanges(watchPath string, cb scanCallback) {
	for {
		filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error {
			if path == ".git" {
				return filepath.SkipDir
			}

			// ignore hidden files
			if filepath.Base(path)[0] == '.' {
				return nil
			}

			ext := filepath.Ext(path)
			if ext == ".go" || ext == ".html" && info.ModTime().After(startTime) {
				cb(path)
				startTime = time.Now()
				return errors.New("done")
			}

			return nil
		})
		time.Sleep(500 * time.Millisecond)
	}
}

func shutdown(runner gin.Runner) {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		s := <-c
		log.Println("Got signal: ", s)
		err := runner.Kill()
		if err != nil {
			log.Print("Error killing: ", err)
		}
		os.Exit(1)
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"github.com/fatih/color"
	_ "github.com/mattn/go-sqlite3"
	"io/ioutil"
	"log"
	"os/user"
)

type fUser struct {
	id       int64
	username string
}

type Conf struct {
	ConsumerKey    string `json:"consumerKey"`
	ConsumerSecret string `json:"consumerSecret"`
	AccessToken    string `json:"accessToken"`
	AccessSecret   string `json:"accessSecret"`
}

func main() {
	//User infos
	user, err := user.Current()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	//Config
	file, err := ioutil.ReadFile(fmt.Sprintf("%s/.goodbye.json", user.HomeDir))
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	var configuration Conf
	err = json.Unmarshal(file, &configuration)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	config := oauth1.NewConfig(configuration.ConsumerKey, configuration.ConsumerSecret)
	token := oauth1.NewToken(configuration.AccessToken, configuration.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	//Client
	client := twitter.NewClient(httpClient)
	//Cursor
	cursor := int64(-1)

	nick := flag.String("nick", "dlion92", "your nickname on twitter")
	url := flag.Bool("url", false, "true if you want to see the url in output")

	flag.Parse()

	db, err := sql.Open("sqlite3", fmt.Sprintf("%s/.goo.db", user.HomeDir))
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer db.Close()

	//Create a new db if not exists
	newDB := `
		CREATE TABLE IF NOT EXISTS users (id integer not null primary key, idUser integer, username text);
		CREATE TABLE IF NOT EXISTS usersTmp (id integer not null primary key, idUser integer, username text);
		`
	_, err = db.Exec(newDB)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	//Delete usersTmp table
	_, err = db.Exec(`DELETE FROM usersTmp`)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	//Count followers
	plus := 0
	//Begin
	tx, err := db.Begin()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	insertUsers, err := tx.Prepare("INSERT INTO usersTmp (idUser, username) VALUES(?, ?)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer insertUsers.Close()

	color.Set(color.FgYellow)
	fmt.Println("Getting followers, please wait...")
	color.Unset()
	// Get Followers
	for cursor != 0 {
		//dlion92 followers for now
		io := &twitter.FollowerListParams{ScreenName: *nick, Cursor: int(cursor), Count: 200}
		followers, resp, err := client.Followers.List(io)
		if err != nil || resp.StatusCode != 200 {
			color.Set(color.FgRed, color.BlinkSlow)
			if resp.StatusCode == 429 { //
				log.Fatal("Too much requests in a short period, try again after some minutes (15 minutes should be fine)")
			} else {
				log.Fatal(err)
			}
		}
		//Put usernames in the db
		for _, v := range followers.Users {
			_, err = insertUsers.Exec(v.ID, fmt.Sprintf("%s", v.ScreenName))
			if err != nil {
				color.Set(color.FgRed, color.BlinkSlow)
				log.Fatal(err)
			}
			plus++
		}
		//Next Follower
		cursor = followers.NextCursor
	}
	tx.Commit()

	//Check new followers
	var followers []fUser
	rows, err := db.Query("SELECT idUser, username FROM usersTmp WHERE idUser NOT IN (SELECT idUser FROM users)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var username string
		var id int64
		err = rows.Scan(&id, &username)
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
		u := fUser{
			id:       id,
			username: username,
		}
		followers = append(followers, u)
	}

	//Check new unfollowers
	var unfollowers []fUser
	rows, err = db.Query("SELECT idUser, username FROM users WHERE idUser NOT IN (SELECT idUser FROM usersTmp)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var username string
		var id int64
		err = rows.Scan(&id, &username)
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
		u := fUser{
			id:       id,
			username: username,
		}
		unfollowers = append(unfollowers, u)
	}

	//Delete all users to update the table
	_, err = db.Exec("DELETE FROM users")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	//Get all new followers
	rowsN, err := db.Query("SELECT idUser, username FROM usersTmp")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rowsN.Close()

	tx, err = db.Begin()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	insertUsers, err = tx.Prepare("INSERT INTO users (idUser, username) VALUES(?, ?)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	for rowsN.Next() {
		var username string
		var id int64
		err = rowsN.Scan(&id, &username)
		if err != nil {
			panic(err)
		}

		_, err = insertUsers.Exec(id, fmt.Sprintf("%s", username))
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
	}
	tx.Commit()

	db.Close()

	color.Set(color.FgHiBlue)
	fmt.Printf("%s has %d followers currently\n", *nick, plus)
	color.Unset()

	if len(followers) > 0 {
		color.Set(color.FgHiCyan)
		fmt.Printf("%s has %d new followers! :)\n", *nick, len(followers))
		color.Unset()
		color.Set(color.FgGreen)
		for i := range followers {
			if *url {
				fmt.Printf("https://twitter.com/")
			}

			fmt.Printf("%s welcome!\n", followers[i].username)
		}
		color.Unset()
	}

	if len(unfollowers) > 0 {
		color.Set(color.FgHiCyan)
		fmt.Printf("%s has %d new unfollowers! :(\n", *nick, len(unfollowers))
		color.Unset()
		color.Set(color.FgHiRed)
		for i := range unfollowers {
			if *url {
				fmt.Printf("https://twitter.com/")
			}
			fmt.Printf("%s goodbye!\n", unfollowers[i].username)
		}
		color.Unset()
	}

	if len(followers) == 0 && len(unfollowers) == 0 {
		color.Set(color.FgMagenta, color.Underline)
		fmt.Printf("%s has no new followers or unfollowers, bye!\n", *nick)
		color.Unset()
	}
}
<commit_msg>filepath instead sprintf; Close #2<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
	"github.com/fatih/color"
	_ "github.com/mattn/go-sqlite3"
	"io/ioutil"
	"log"
	"os/user"
	"path/filepath"
)

type fUser struct {
	id       int64
	username string
}

type Conf struct {
	ConsumerKey    string `json:"consumerKey"`
	ConsumerSecret string `json:"consumerSecret"`
	AccessToken    string `json:"accessToken"`
	AccessSecret   string `json:"accessSecret"`
}

func main() {
	//User infos
	user, err := user.Current()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	//Config
	file, err := ioutil.ReadFile(filepath.Join(user.HomeDir, ".goodbye.json"))
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	var configuration Conf
	err = json.Unmarshal(file, &configuration)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	config := oauth1.NewConfig(configuration.ConsumerKey, configuration.ConsumerSecret)
	token := oauth1.NewToken(configuration.AccessToken, configuration.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	//Client
	client := twitter.NewClient(httpClient)
	//Cursor
	cursor := int64(-1)

	nick := flag.String("nick", "dlion92", "your nickname on twitter")
	url := flag.Bool("url", false, "true if you want to see the url in output")

	flag.Parse()

	db, err := sql.Open("sqlite3", filepath.Join(user.HomeDir, ".goo.db"))
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer db.Close()

	//Create a new db if not exists
	newDB := `
		CREATE TABLE IF NOT EXISTS users (id integer not null primary key, idUser integer, username text);
		CREATE TABLE IF NOT EXISTS usersTmp (id integer not null primary key, idUser integer, username text);
		`
	_, err = db.Exec(newDB)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	//Delete usersTmp table
	_, err = db.Exec(`DELETE FROM usersTmp`)
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	//Count followers
	plus := 0
	//Begin
	tx, err := db.Begin()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	insertUsers, err := tx.Prepare("INSERT INTO usersTmp (idUser, username) VALUES(?, ?)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer insertUsers.Close()

	color.Set(color.FgYellow)
	fmt.Println("Getting followers, please wait...")
	color.Unset()
	// Get Followers
	for cursor != 0 {
		//dlion92 followers for now
		io := &twitter.FollowerListParams{ScreenName: *nick, Cursor: int(cursor), Count: 200}
		followers, resp, err := client.Followers.List(io)
		if err != nil || resp.StatusCode != 200 {
			color.Set(color.FgRed, color.BlinkSlow)
			if resp.StatusCode == 429 { //
				log.Fatal("Too much requests in a short period, try again after some minutes (15 minutes should be fine)")
			} else {
				log.Fatal(err)
			}
		}
		//Put usernames in the db
		for _, v := range followers.Users {
			_, err = insertUsers.Exec(v.ID, fmt.Sprintf("%s", v.ScreenName))
			if err != nil {
				color.Set(color.FgRed, color.BlinkSlow)
				log.Fatal(err)
			}
			plus++
		}
		//Next Follower
		cursor = followers.NextCursor
	}
	tx.Commit()

	//Check new followers
	var followers []fUser
	rows, err := db.Query("SELECT idUser, username FROM usersTmp WHERE idUser NOT IN (SELECT idUser FROM users)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var username string
		var id int64
		err = rows.Scan(&id, &username)
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
		u := fUser{
			id:       id,
			username: username,
		}
		followers = append(followers, u)
	}

	//Check new unfollowers
	var unfollowers []fUser
	rows, err = db.Query("SELECT idUser, username FROM users WHERE idUser NOT IN (SELECT idUser FROM usersTmp)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var username string
		var id int64
		err = rows.Scan(&id, &username)
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
		u := fUser{
			id:       id,
			username: username,
		}
		unfollowers = append(unfollowers, u)
	}

	//Delete all users to update the table
	_, err = db.Exec("DELETE FROM users")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	//Get all new followers
	rowsN, err := db.Query("SELECT idUser, username FROM usersTmp")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	defer rowsN.Close()

	tx, err = db.Begin()
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}
	insertUsers, err = tx.Prepare("INSERT INTO users (idUser, username) VALUES(?, ?)")
	if err != nil {
		color.Set(color.FgRed, color.BlinkSlow)
		log.Fatal(err)
	}

	for rowsN.Next() {
		var username string
		var id int64
		err = rowsN.Scan(&id, &username)
		if err != nil {
			panic(err)
		}

		_, err = insertUsers.Exec(id, fmt.Sprintf("%s", username))
		if err != nil {
			color.Set(color.FgRed, color.BlinkSlow)
			log.Fatal(err)
		}
	}
	tx.Commit()

	db.Close()

	color.Set(color.FgHiBlue)
	fmt.Printf("%s has %d followers currently\n", *nick, plus)
	color.Unset()

	if len(followers) > 0 {
		color.Set(color.FgHiCyan)
		fmt.Printf("%s has %d new followers! :)\n", *nick, len(followers))
		color.Unset()
		color.Set(color.FgGreen)
		for i := range followers {
			if *url {
				fmt.Printf("https://twitter.com/")
			}

			fmt.Printf("%s welcome!\n", followers[i].username)
		}
		color.Unset()
	}

	if len(unfollowers) > 0 {
		color.Set(color.FgHiCyan)
		fmt.Printf("%s has %d new unfollowers! :(\n", *nick, len(unfollowers))
		color.Unset()
		color.Set(color.FgHiRed)
		for i := range unfollowers {
			if *url {
				fmt.Printf("https://twitter.com/")
			}
			fmt.Printf("%s goodbye!\n", unfollowers[i].username)
		}
		color.Unset()
	}

	if len(followers) == 0 && len(unfollowers) == 0 {
		color.Set(color.FgMagenta, color.Underline)
		fmt.Printf("%s has no new followers or unfollowers, bye!\n", *nick)
		color.Unset()
	}
}
<|endoftext|>


<commit_before>package srcgraph

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

	"sourcegraph.com/sourcegraph/srcgraph/buildstore"
	"sourcegraph.com/sourcegraph/srcgraph/util2"

	"testing"

	"github.com/aybabtme/color/brush"
)

var mode = flag.String("test.mode", "test", "[test|keep|gen] 'test' runs test as normal; keep keeps around generated test files for inspection after tests complete; 'gen' generates new expected test data")
var repoMatch = flag.String("test.repo", "", "only test `srcgraph make` for repos that contain this string")

func TestMakeCmd(t *testing.T) {
	if testing.Short() {
		t.Skip("srcgraph make tests take a long time; skipping for -test.short")
	}

	// Since we exec `srcgraph`, make sure it's up-to-date.
	if out, err := exec.Command("make", "-C", "..", "srcgraph").CombinedOutput(); err != nil {
		t.Errorf("Failed to build srcgraph for `srcgraph make` tests: %s.\n\nOutput was:\n%s", err, out)
		return
	}

	cmd := exec.Command("git", "submodule", "update", "--init", "srcgraph/testdata/repos")
	cmd.Dir = ".."
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Errorf("Failed to update or init git submodules: %s.\n\nOutput was:\n%s", err, out)
		return
	}

	const testReposDir = "testdata/repos"
	fis, err := ioutil.ReadDir("testdata/repos")
	if err != nil {
		t.Fatal(err)
	}
	n := 0
	var wg sync.WaitGroup
	for _, fi := range fis {
		if repoDir := fi.Name(); strings.Contains(repoDir, *repoMatch) {
			fullRepoDir := filepath.Join(testReposDir, repoDir)
			wg.Add(1)
			go func() {
				defer wg.Done()
				testMakeCmd(t, fullRepoDir)
			}()
			n++
		}
	}
	wg.Wait()
	if n == 0 {
		t.Errorf("No TestMakeCmd cases were run. Did none match your constraint -test.match=%q?", *repoMatch)
	}
}

func testMakeCmd(t *testing.T, repoDir string) {
	repoName := filepath.Base(repoDir)

	// Directories for the actual ("got") and expected ("want") outputs.
	gotOutputDir := filepath.Join(repoDir, "../../repos-output/got", repoName)
	wantOutputDir := filepath.Join(repoDir, "../../repos-output/want", repoName)

	// Determine and wipe the desired output dir.
	var outputDir string
	if *mode == "gen" {
		outputDir = wantOutputDir
	} else {
		outputDir = gotOutputDir
	}
	outputDir, _ = filepath.Abs(outputDir)
	if err := os.RemoveAll(outputDir); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		t.Fatal(err)
	}

	// Symlink ${repoDir}/.sourcegraph-data/${commitID} to the desired output dir.
	origOutputDestDir := filepath.Join(repoDir, buildstore.BuildDataDirName, getHEADOrTipCommitID(t, repoDir))
	if err := os.Mkdir(filepath.Dir(origOutputDestDir), 0755); err != nil && !os.IsExist(err) {
		t.Fatal(err)
	}
	if err := os.Remove(origOutputDestDir); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	}
	if err := os.Symlink(outputDir, origOutputDestDir); err != nil {
		t.Error(err)
		return
	}
	defer func() {
		// Remove the symlink when we're done so the repo doesn't have
		// uncommitted changes.
		if err := os.Remove(origOutputDestDir); err != nil {
			t.Fatal(err)
		}
	}()

	// Run `srcgraph make`.
	var w io.Writer
	var buf bytes.Buffer
	if testing.Verbose() {
		w = io.MultiWriter(&buf, os.Stderr)
	} else {
		w = &buf
	}
	cmd := exec.Command("srcgraph", "-v", "make")
	cmd.Stderr, cmd.Stdout = w, w
	cmd.Dir = repoDir

	err := cmd.Run()
	if err != nil {
		t.Errorf("Command %v in %s failed: %s.\n\nOutput was:\n%s", cmd.Args, repoDir, err, buf.String())
		return
	}

	if *mode == "gen" {
		t.Errorf("Successfully generated expected output for %s in %s. (Triggering test error so you won't mistakenly interpret a 0 return code as a test success. Run without -test.mode=gen to run the test.)", repoName, wantOutputDir)
	} else {
		checkResults(t, buf, repoName, gotOutputDir, wantOutputDir)
	}
}

func checkResults(t *testing.T, output bytes.Buffer, repoName, gotOutputDir, wantOutputDir string) {
	out, err := exec.Command("diff", "-ur", wantOutputDir, gotOutputDir).CombinedOutput()
	if err != nil || len(out) > 0 {
		t.Logf(brush.Red(repoName + " FAIL").String())
		t.Errorf("Diff failed for %s: %s.", repoName, err)
		if len(out) > 0 {
			fmt.Println(brush.Red(repoName + "FAIL"))
			fmt.Println(output.String())
			fmt.Println(string(util2.ColorizeDiff(out)))
			t.Errorf("Output for %s differed from expected.", repoName)
		}
	} else {
		t.Logf(brush.Green(repoName + " PASS").String())
	}
}

func getHEADOrTipCommitID(t *testing.T, repoDir string) string {
	// TODO(sqs): assumes git
	cmd := exec.Command("git", "rev-parse", "HEAD")
	cmd.Dir = repoDir
	out, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	return string(bytes.TrimSpace(out))
}
<commit_msg>print repoMatch at beginning of make_test.go if set<commit_after>package srcgraph

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

	"sourcegraph.com/sourcegraph/srcgraph/buildstore"
	"sourcegraph.com/sourcegraph/srcgraph/util2"

	"testing"

	"github.com/aybabtme/color/brush"
)

var mode = flag.String("test.mode", "test", "[test|keep|gen] 'test' runs test as normal; keep keeps around generated test files for inspection after tests complete; 'gen' generates new expected test data")
var repoMatch = flag.String("test.repo", "", "only test `srcgraph make` for repos that contain this string")

func TestMakeCmd(t *testing.T) {
	if testing.Short() {
		t.Skip("srcgraph make tests take a long time; skipping for -test.short")
	}

	if *repoMatch != "" {
		t.Logf("Testing `srcgraph make` on repositories that contain \"%s\"", *repoMatch)
	}

	// Since we exec `srcgraph`, make sure it's up-to-date.
	if out, err := exec.Command("make", "-C", "..", "srcgraph").CombinedOutput(); err != nil {
		t.Errorf("Failed to build srcgraph for `srcgraph make` tests: %s.\n\nOutput was:\n%s", err, out)
		return
	}

	cmd := exec.Command("git", "submodule", "update", "--init", "srcgraph/testdata/repos")
	cmd.Dir = ".."
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Errorf("Failed to update or init git submodules: %s.\n\nOutput was:\n%s", err, out)
		return
	}

	const testReposDir = "testdata/repos"
	fis, err := ioutil.ReadDir("testdata/repos")
	if err != nil {
		t.Fatal(err)
	}
	n := 0
	var wg sync.WaitGroup
	for _, fi := range fis {
		if repoDir := fi.Name(); strings.Contains(repoDir, *repoMatch) {
			fullRepoDir := filepath.Join(testReposDir, repoDir)
			wg.Add(1)
			go func() {
				defer wg.Done()
				testMakeCmd(t, fullRepoDir)
			}()
			n++
		}
	}
	wg.Wait()
	if n == 0 {
		t.Errorf("No TestMakeCmd cases were run. Did none match your constraint -test.match=%q?", *repoMatch)
	}
}

func testMakeCmd(t *testing.T, repoDir string) {
	repoName := filepath.Base(repoDir)

	// Directories for the actual ("got") and expected ("want") outputs.
	gotOutputDir := filepath.Join(repoDir, "../../repos-output/got", repoName)
	wantOutputDir := filepath.Join(repoDir, "../../repos-output/want", repoName)

	// Determine and wipe the desired output dir.
	var outputDir string
	if *mode == "gen" {
		outputDir = wantOutputDir
	} else {
		outputDir = gotOutputDir
	}
	outputDir, _ = filepath.Abs(outputDir)
	if err := os.RemoveAll(outputDir); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		t.Fatal(err)
	}

	// Symlink ${repoDir}/.sourcegraph-data/${commitID} to the desired output dir.
	origOutputDestDir := filepath.Join(repoDir, buildstore.BuildDataDirName, getHEADOrTipCommitID(t, repoDir))
	if err := os.Mkdir(filepath.Dir(origOutputDestDir), 0755); err != nil && !os.IsExist(err) {
		t.Fatal(err)
	}
	if err := os.Remove(origOutputDestDir); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	}
	if err := os.Symlink(outputDir, origOutputDestDir); err != nil {
		t.Error(err)
		return
	}
	defer func() {
		// Remove the symlink when we're done so the repo doesn't have
		// uncommitted changes.
		if err := os.Remove(origOutputDestDir); err != nil {
			t.Fatal(err)
		}
	}()

	// Run `srcgraph make`.
	var w io.Writer
	var buf bytes.Buffer
	if testing.Verbose() {
		w = io.MultiWriter(&buf, os.Stderr)
	} else {
		w = &buf
	}
	cmd := exec.Command("srcgraph", "-v", "make")
	cmd.Stderr, cmd.Stdout = w, w
	cmd.Dir = repoDir

	err := cmd.Run()
	if err != nil {
		t.Errorf("Command %v in %s failed: %s.\n\nOutput was:\n%s", cmd.Args, repoDir, err, buf.String())
		return
	}

	if *mode == "gen" {
		t.Errorf("Successfully generated expected output for %s in %s. (Triggering test error so you won't mistakenly interpret a 0 return code as a test success. Run without -test.mode=gen to run the test.)", repoName, wantOutputDir)
	} else {
		checkResults(t, buf, repoName, gotOutputDir, wantOutputDir)
	}
}

func checkResults(t *testing.T, output bytes.Buffer, repoName, gotOutputDir, wantOutputDir string) {
	out, err := exec.Command("diff", "-ur", wantOutputDir, gotOutputDir).CombinedOutput()
	if err != nil || len(out) > 0 {
		t.Logf(brush.Red(repoName + " FAIL").String())
		t.Errorf("Diff failed for %s: %s.", repoName, err)
		if len(out) > 0 {
			fmt.Println(brush.Red(repoName + "FAIL"))
			fmt.Println(output.String())
			fmt.Println(string(util2.ColorizeDiff(out)))
			t.Errorf("Output for %s differed from expected.", repoName)
		}
	} else {
		t.Logf(brush.Green(repoName + " PASS").String())
	}
}

func getHEADOrTipCommitID(t *testing.T, repoDir string) string {
	// TODO(sqs): assumes git
	cmd := exec.Command("git", "rev-parse", "HEAD")
	cmd.Dir = repoDir
	out, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	return string(bytes.TrimSpace(out))
}
<|endoftext|>


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

package xormadapter

import (
	"log"
	"testing"

	"github.com/casbin/casbin"
	"github.com/casbin/casbin/util"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
)

func testGetPolicy(t *testing.T, e *casbin.Enforcer, res [][]string) {
	myRes := e.GetPolicy()
	log.Print("Policy: ", myRes)

	if !util.Array2DEquals(res, myRes) {
		t.Error("Policy: ", myRes, ", supposed to be ", res)
	}
}

func initPolicy(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Because the DB is empty at first,
	// so we need to load the policy from the file adapter (.CSV) first.
	e := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")

	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	// This is a trick to save the current policy to the DB.
	// We can't call e.SavePolicy() because the adapter in the enforcer is still the file adapter.
	// The current policy means the policy in the Casbin enforcer (aka in memory).
	err := a.SavePolicy(e.GetModel())
	if err != nil {
		panic(err)
	}

	// Clear the current policy.
	e.ClearPolicy()
	testGetPolicy(t, e, [][]string{})

	// Load the policy from DB.
	err = a.LoadPolicy(e.GetModel())
	if err != nil {
		panic(err)
	}
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
}

func testSaveLoad(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Initialize some policy in DB.
	initPolicy(t, driverName, dataSourceName, dbSpecified...)
	// Note: you don't need to look at the above code
	// if you already have a working DB with policy inside.

	// Now the DB has policy, so we can provide a normal use case.
	// Create an adapter and an enforcer.
	// NewEnforcer() will load the policy automatically.
	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	e := casbin.NewEnforcer("examples/rbac_model.conf", a)
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
}

func testAutoSave(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Initialize some policy in DB.
	initPolicy(t, driverName, dataSourceName, dbSpecified...)
	// Note: you don't need to look at the above code
	// if you already have a working DB with policy inside.

	// Now the DB has policy, so we can provide a normal use case.
	// Create an adapter and an enforcer.
	// NewEnforcer() will load the policy automatically.
	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	e := casbin.NewEnforcer("examples/rbac_model.conf", a)

	// AutoSave is enabled by default.
	// Now we disable it.
	e.EnableAutoSave(false)

	// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
	// it doesn't affect the policy in the storage.
	e.AddPolicy("alice", "data1", "write")
	// Reload the policy from the storage to see the effect.
	e.LoadPolicy()
	// This is still the original policy.
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})

	// Now we enable the AutoSave.
	e.EnableAutoSave(true)

	// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
	// but also affects the policy in the storage.
	e.AddPolicy("alice", "data1", "write")
	// Reload the policy from the storage to see the effect.
	e.LoadPolicy()
	// The policy has a new rule: {"alice", "data1", "write"}.
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}, {"alice", "data1", "write"}})

	// Remove the added rule.
	e.RemovePolicy("alice", "data1", "write")
	e.LoadPolicy()
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})

	// Remove "data2_admin" related policy rules via a filter.
	// Two rules: {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"} are deleted.
	e.RemoveFilteredPolicy(0, "data2_admin")
	e.LoadPolicy()
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}})

}

func TestAdapters(t *testing.T) {
	// You can also use the following way to use an existing DB "abc":
	// testSaveLoad(t, "mysql", "root:@tcp(127.0.0.1:3306)/abc", true)

	testSaveLoad(t, "mysql", "root:@tcp(127.0.0.1:3306)/")
	testSaveLoad(t, "postgres", "user=postgres host=127.0.0.1 port=5432 sslmode=disable")

	testAutoSave(t, "mysql", "root:@tcp(127.0.0.1:3306)/")
	testAutoSave(t, "postgres", "user=postgres host=127.0.0.1 port=5432 sslmode=disable")
}
<commit_msg>Add t.Helper() to test.<commit_after>// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package xormadapter

import (
	"log"
	"testing"

	"github.com/casbin/casbin"
	"github.com/casbin/casbin/util"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
)

func testGetPolicy(t *testing.T, e *casbin.Enforcer, res [][]string) {
	t.Helper()
	myRes := e.GetPolicy()
	log.Print("Policy: ", myRes)

	if !util.Array2DEquals(res, myRes) {
		t.Error("Policy: ", myRes, ", supposed to be ", res)
	}
}

func initPolicy(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Because the DB is empty at first,
	// so we need to load the policy from the file adapter (.CSV) first.
	e := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")

	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	// This is a trick to save the current policy to the DB.
	// We can't call e.SavePolicy() because the adapter in the enforcer is still the file adapter.
	// The current policy means the policy in the Casbin enforcer (aka in memory).
	err := a.SavePolicy(e.GetModel())
	if err != nil {
		panic(err)
	}

	// Clear the current policy.
	e.ClearPolicy()
	testGetPolicy(t, e, [][]string{})

	// Load the policy from DB.
	err = a.LoadPolicy(e.GetModel())
	if err != nil {
		panic(err)
	}
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
}

func testSaveLoad(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Initialize some policy in DB.
	initPolicy(t, driverName, dataSourceName, dbSpecified...)
	// Note: you don't need to look at the above code
	// if you already have a working DB with policy inside.

	// Now the DB has policy, so we can provide a normal use case.
	// Create an adapter and an enforcer.
	// NewEnforcer() will load the policy automatically.
	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	e := casbin.NewEnforcer("examples/rbac_model.conf", a)
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
}

func testAutoSave(t *testing.T, driverName string, dataSourceName string, dbSpecified ...bool) {
	// Initialize some policy in DB.
	initPolicy(t, driverName, dataSourceName, dbSpecified...)
	// Note: you don't need to look at the above code
	// if you already have a working DB with policy inside.

	// Now the DB has policy, so we can provide a normal use case.
	// Create an adapter and an enforcer.
	// NewEnforcer() will load the policy automatically.
	a := NewAdapter(driverName, dataSourceName, dbSpecified...)
	e := casbin.NewEnforcer("examples/rbac_model.conf", a)

	// AutoSave is enabled by default.
	// Now we disable it.
	e.EnableAutoSave(false)

	// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
	// it doesn't affect the policy in the storage.
	e.AddPolicy("alice", "data1", "write")
	// Reload the policy from the storage to see the effect.
	e.LoadPolicy()
	// This is still the original policy.
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})

	// Now we enable the AutoSave.
	e.EnableAutoSave(true)

	// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
	// but also affects the policy in the storage.
	e.AddPolicy("alice", "data1", "write")
	// Reload the policy from the storage to see the effect.
	e.LoadPolicy()
	// The policy has a new rule: {"alice", "data1", "write"}.
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}, {"alice", "data1", "write"}})

	// Remove the added rule.
	e.RemovePolicy("alice", "data1", "write")
	e.LoadPolicy()
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})

	// Remove "data2_admin" related policy rules via a filter.
	// Two rules: {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"} are deleted.
	e.RemoveFilteredPolicy(0, "data2_admin")
	e.LoadPolicy()
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}})

}

func TestAdapters(t *testing.T) {
	// You can also use the following way to use an existing DB "abc":
	// testSaveLoad(t, "mysql", "root:@tcp(127.0.0.1:3306)/abc", true)

	testSaveLoad(t, "mysql", "root:@tcp(127.0.0.1:3306)/")
	testSaveLoad(t, "postgres", "user=postgres host=127.0.0.1 port=5432 sslmode=disable")

	testAutoSave(t, "mysql", "root:@tcp(127.0.0.1:3306)/")
	testAutoSave(t, "postgres", "user=postgres host=127.0.0.1 port=5432 sslmode=disable")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

func usage() {
	fmt.Println("Usage: go-renamer filepath")
}

func renameAll(f string) {
	if !strings.HasSuffix(f, "/") {
		f += "/"
	}
	files, err := ioutil.ReadDir(f)
	if err != nil {
		fmt.Println(err)
		return
	}
	oldfiles := make([]string, len(files))
	newfiles := make([]string, len(files))
	for i := 0; i < len(files); i++ {
		oldfiles[i] = files[i].Name()
	}

	setName(oldfiles, newfiles, 0)

	for {
		showChangeList(oldfiles, newfiles)
		fmt.Print("Really change files name or modify?(y/n/m): ")
		reader := bufio.NewReader(os.Stdin)
		c, err := reader.ReadByte()
		if err != nil {
			fmt.Println(err)
			return
		}
		if c == 'y' {
			for i := 0; i < len(newfiles); i++ {
				os.Rename(f+files[i].Name(), f+newfiles[i])
			}
			break
		} else if c == 'm' {
			modifyName(oldfiles, newfiles)
		} else {
			break
		}
	}
}

func modifyName(oldfiles, newfiles []string) {
	fmt.Print("Input modify number -->")
	reader := bufio.NewReader(os.Stdin)
	c, _, err := reader.ReadLine()
	if err != nil {
		fmt.Println(err)
		return
	}
	num, err := strconv.Atoi(string(c))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Print("Input new file name -->")
	c, _, err = reader.ReadLine()
	newfiles[num] = string(c)
}

func setName(oldfiles, newfiles []string, start int) {
	index := 0
	for i := start; i < len(oldfiles); i++ {
		if oldfiles[i][0] == '.' {
			newfiles[i] = oldfiles[i]
		} else if strings.Index(oldfiles[i], ".") == -1 {
			newfiles[i] = fmt.Sprintf("%03d", index)
			index++
		} else {
			tmp := strings.Split(oldfiles[i], ".")
			suffix := tmp[len(tmp)-1]
			newfiles[i] = fmt.Sprintf("%03d.%s", index, suffix)
			index++
		}
	}
}

func showChangeList(oldfiles, newfiles []string) {
	for i := 0; i < len(newfiles); i++ {
		fmt.Println(strconv.Itoa(i) + ": " + oldfiles[i] + " --> " + newfiles[i])
	}
}

func main() {
	if len(os.Args) < 2 {
		usage()
		os.Exit(1)
	}

	f, err := os.Stat(os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if f.IsDir() {
		renameAll(os.Args[1])
	} else {
		scanner := bufio.NewScanner(os.Stdin)
		fmt.Print(f.Name() + "--> ")
		for scanner.Scan() {
			nf := scanner.Text()
			if nf == "" {
				fmt.Print(f.Name() + "--> ")
				continue
			}
			os.Rename(os.Args[1], nf)
			break
		}
	}
}
<commit_msg>re-numbering filename after modified a name<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

type FileName struct {
	Oldname string
	Newname string
	Modify  bool
}

func usage() {
	fmt.Println("Usage: go-renamer filepath")
}

func renameAll(f string) {
	if !strings.HasSuffix(f, "/") {
		f += "/"
	}
	files, err := ioutil.ReadDir(f)
	if err != nil {
		fmt.Println(err)
		return
	}
	filename := make([]FileName, len(files))
	for i := 0; i < len(files); i++ {
		filename[i] = FileName{Oldname: files[i].Name(), Newname: "", Modify: false}
	}

	setName(filename, 0)

	for {
		showChangeList(filename)
		fmt.Print("Really change files name or modify?(y/n/m): ")
		reader := bufio.NewReader(os.Stdin)
		c, err := reader.ReadByte()
		if err != nil {
			fmt.Println(err)
			return
		}
		if c == 'y' {
			for i := 0; i < len(filename); i++ {
				os.Rename(f+filename[i].Oldname, f+filename[i].Newname)
			}
			break
		} else if c == 'm' {
			modifyName(filename)
			setName(filename, 0)
		} else {
			break
		}
	}
}

func modifyName(filename []FileName) {
	fmt.Print("Input modify number -->")
	reader := bufio.NewReader(os.Stdin)
	c, _, err := reader.ReadLine()
	if err != nil {
		fmt.Println(err)
		return
	}
	num, err := strconv.Atoi(string(c))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Print("Input new file name -->")
	c, _, err = reader.ReadLine()
	if checkName(filename, string(c)) {
		fmt.Println("Already exists the same name file")
		return
	}
	filename[num].Newname = string(c)
	filename[num].Modify = true
}

func checkName(filename []FileName, f string) bool {
	for _, fn := range filename {
		if fn.Newname == f {
			return true
		}
	}
	return false
}

func setName(filename []FileName, start int) {
	index := 0
	for i := start; i < len(filename); i++ {
		if filename[i].Modify {
			continue
		}
		if filename[i].Oldname[0] == '.' {
			filename[i].Newname = filename[i].Oldname
		} else if strings.Index(filename[i].Oldname, ".") == -1 {
			tmp := fmt.Sprintf("%03d", index)
			filename[i].Newname = tmp
			index++
		} else {
			tmp := strings.Split(filename[i].Oldname, ".")
			suffix := tmp[len(tmp)-1]
			fname := fmt.Sprintf("%03d.%s", index, suffix)
			filename[i].Newname = fname
			index++
		}
	}
}

func showChangeList(filename []FileName) {
	for i := 0; i < len(filename); i++ {
		fmt.Println(strconv.Itoa(i) + ": " + filename[i].Oldname + " --> " + filename[i].Newname)
	}
}

func main() {
	if len(os.Args) < 2 {
		usage()
		os.Exit(1)
	}

	f, err := os.Stat(os.Args[1])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if f.IsDir() {
		renameAll(os.Args[1])
	} else {
		scanner := bufio.NewScanner(os.Stdin)
		fmt.Print(f.Name() + "--> ")
		for scanner.Scan() {
			nf := scanner.Text()
			if nf == "" {
				fmt.Print(f.Name() + "--> ")
				continue
			}
			os.Rename(os.Args[1], nf)
			break
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"io"
	"log"
	"net"
	"os"
	"runtime"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/Luzifer/go-openssl"
)

const (
	// max open file should at least be
	_MaxOpenfile              = uint64(1024 * 1024 * 1024)
	_MaxBackendAddrCacheCount = 1024 * 1024
	_DefaultPort              = "4043"
	_MTU                      = 1500
)

var (
	_SecretPassphase string
	_OpenSSL         = openssl.New()
)

var (
	_BackendAddrCacheMutex sync.Mutex
	_BackendAddrCache      atomic.Value
	_BufioReaderPool       sync.Pool
)

type backendAddrMap map[string]string

func init() {
	_BackendAddrCache.Store(make(backendAddrMap))
}

func decryptBackendAddr(line []byte) (string, error) {
	// Try to check cache
	m1 := _BackendAddrCache.Load().(backendAddrMap)
	addr, ok := m1[string(line)]
	if ok {
		return addr, nil
	}
	// Try to decrypt it (AES)
	plaintext, err := _OpenSSL.DecryptString(_SecretPassphase, string(line))
	if err != nil {
		return "", err
	}
	addr = string(plaintext)
	cacheBackendAddr(string(line), addr)
	return addr, nil
}

func cacheBackendAddr(key, val string) {
	_BackendAddrCacheMutex.Lock()
	defer _BackendAddrCacheMutex.Unlock()

	m1 := _BackendAddrCache.Load().(backendAddrMap)
	// double check
	if _, ok := m1[key]; ok {
		return
	}

	m2 := make(backendAddrMap)
	// flush cache if there is way too many
	if len(m1) < _MaxBackendAddrCacheCount {
		// copy-on-write
		for k, v := range m1 {
			m2[k] = v // copy all data from the current object to the new one
		}
	}
	m2[key] = val
	_BackendAddrCache.Store(m2) // atomically replace the current object with the new one
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	os.Setenv("GOTRACEBACK", "crash")

	var lim syscall.Rlimit
	syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
	if lim.Cur < _MaxOpenfile || lim.Max < _MaxOpenfile {
		lim.Cur = _MaxOpenfile
		lim.Max = _MaxOpenfile
		syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim)
	}

	_SecretPassphase = os.Getenv("SECRET")

	ListenAndServe()
}

func ListenAndServe() {
	l, err := net.Listen("tcp", ":"+_DefaultPort)
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go handleConn(conn)
	}
}

func handleConn(c net.Conn) {
	defer func() {
		c.Close()
		if r := recover(); r != nil {
			log.Println("Recovered in", r, ":", string(debug.Stack()))
		}
	}()

	// TODO: get rid of bufio.Reader
	// TODO: use binary protocol if first byte is 0x00

	// Read first line
	rdr, ok := _BufioReaderPool.Get().(*bufio.Reader)
	if ok {
		rdr.Reset(c)
	} else {
		rdr = bufio.NewReader(c)
		defer _BufioReaderPool.Put(rdr)
	}
	line, isPrefix, err := rdr.ReadLine()
	if err != nil || isPrefix {
		log.Println(err)
		c.Write([]byte{0x04})
		return
	}

	// Try to check cache
	addr, err := decryptBackendAddr(line)
	if err != nil {
		c.Write([]byte{0x06})
		return
	}

	// TODO: check if addr is allowed

	// Build tunnel
	backend, err := net.Dial("tcp", addr)
	if err != nil {
		// handle error
		switch err := err.(type) {
		case net.Error:
			if err.Timeout() {
				c.Write([]byte{0x01})
				log.Println(err)
				return
			}
		}
		log.Println(err)
		c.Write([]byte{0x02})
		return
	}
	defer backend.Close()

	// Start transfering data
	go pipe(c, backend)
	pipe(backend, rdr)
}

// pipe upstream and downstream
func pipe(dst io.Writer, src io.Reader) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("Recovered in", r, ":", string(debug.Stack()))
		}
	}()

	_, err := io.Copy(dst, src)

	switch err {
	case io.EOF:
		err = nil
		return
	case nil:
		return
	}
	// log.Println("pipe:", n, err)
}
<commit_msg>Accept失败时重试，从net/http包里学来的<commit_after>package main

import (
	"bufio"
	"io"
	"log"
	"net"
	"os"
	"runtime"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/Luzifer/go-openssl"
)

const (
	// max open file should at least be
	_MaxOpenfile              = uint64(1024 * 1024 * 1024)
	_MaxBackendAddrCacheCount = 1024 * 1024
	_DefaultPort              = "4043"
	_MTU                      = 1500
)

var (
	_SecretPassphase string
	_OpenSSL         = openssl.New()
)

var (
	_BackendAddrCacheMutex sync.Mutex
	_BackendAddrCache      atomic.Value
	_BufioReaderPool       sync.Pool
)

type backendAddrMap map[string]string

func init() {
	_BackendAddrCache.Store(make(backendAddrMap))
}

func decryptBackendAddr(line []byte) (string, error) {
	// Try to check cache
	m1 := _BackendAddrCache.Load().(backendAddrMap)
	addr, ok := m1[string(line)]
	if ok {
		return addr, nil
	}
	// Try to decrypt it (AES)
	plaintext, err := _OpenSSL.DecryptString(_SecretPassphase, string(line))
	if err != nil {
		return "", err
	}
	addr = string(plaintext)
	cacheBackendAddr(string(line), addr)
	return addr, nil
}

func cacheBackendAddr(key, val string) {
	_BackendAddrCacheMutex.Lock()
	defer _BackendAddrCacheMutex.Unlock()

	m1 := _BackendAddrCache.Load().(backendAddrMap)
	// double check
	if _, ok := m1[key]; ok {
		return
	}

	m2 := make(backendAddrMap)
	// flush cache if there is way too many
	if len(m1) < _MaxBackendAddrCacheCount {
		// copy-on-write
		for k, v := range m1 {
			m2[k] = v // copy all data from the current object to the new one
		}
	}
	m2[key] = val
	_BackendAddrCache.Store(m2) // atomically replace the current object with the new one
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	os.Setenv("GOTRACEBACK", "crash")

	var lim syscall.Rlimit
	syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
	if lim.Cur < _MaxOpenfile || lim.Max < _MaxOpenfile {
		lim.Cur = _MaxOpenfile
		lim.Max = _MaxOpenfile
		syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim)
	}

	_SecretPassphase = os.Getenv("SECRET")

	ListenAndServe()
}

func ListenAndServe() {
	l, err := net.Listen("tcp", ":"+_DefaultPort)
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	var tempDelay time.Duration
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				time.Sleep(tempDelay)
				continue
			}
			log.Fatal(err)
		}
		tempDelay = 0
		go handleConn(conn)
	}
}

func handleConn(c net.Conn) {
	defer func() {
		c.Close()
		if r := recover(); r != nil {
			log.Println("Recovered in", r, ":", string(debug.Stack()))
		}
	}()

	// TODO: get rid of bufio.Reader
	// TODO: use binary protocol if first byte is 0x00

	// Read first line
	rdr, ok := _BufioReaderPool.Get().(*bufio.Reader)
	if ok {
		rdr.Reset(c)
	} else {
		rdr = bufio.NewReader(c)
		defer _BufioReaderPool.Put(rdr)
	}
	line, isPrefix, err := rdr.ReadLine()
	if err != nil || isPrefix {
		log.Println(err)
		c.Write([]byte{0x04})
		return
	}

	// Try to check cache
	addr, err := decryptBackendAddr(line)
	if err != nil {
		c.Write([]byte{0x06})
		return
	}

	// TODO: check if addr is allowed

	// Build tunnel
	backend, err := net.Dial("tcp", addr)
	if err != nil {
		// handle error
		switch err := err.(type) {
		case net.Error:
			if err.Timeout() {
				c.Write([]byte{0x01})
				log.Println(err)
				return
			}
		}
		log.Println(err)
		c.Write([]byte{0x02})
		return
	}
	defer backend.Close()

	// Start transfering data
	go pipe(c, backend)
	pipe(backend, rdr)
}

// pipe upstream and downstream
func pipe(dst io.Writer, src io.Reader) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("Recovered in", r, ":", string(debug.Stack()))
		}
	}()

	_, err := io.Copy(dst, src)

	switch err {
	case io.EOF:
		err = nil
		return
	case nil:
		return
	}
	// log.Println("pipe:", n, err)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/rakyll/portmidi"
)

// Helpful links:
// portmidi lib docs: http://portmedia.sourceforge.net/portmidi/doxygen/
// MIDI general messages: https://www.midi.org/specifications/item/table-1-summary-of-midi-message
// MIDI Control Change messages: http://nickfever.com/music/midi-cc-list
// Concisely on pitch bends: https://www.midikits.net/midi_analyser/pitch_bend.htm
// Verbosely on pitch bends: http://www.infocellar.com/sound/midi/pitch-bends.htm

// Chroma is a musical note independent of octave.
type Chroma int

// Values are the same as the MIDI notes modulo 12
const (
	C  Chroma = iota // C natural
	Cs               // C sharp
	D                // ...
	Ds
	E
	F
	Fs
	G
	Gs
	A
	As
	B
)

func (chroma Chroma) String() string {
  switch chroma {
	case C:
		return "C"
	case Cs:
		return "C#"
	case D:
		return "D"
	case Ds:
		return "D#"
	case E:
		return "E"
	case F:
		return "F"
	case Fs:
		return "F#"
	case G:
		return "G"
	case Gs:
		return "G#"
	case A:
		return "A"
	case As:
		return "A#"
	case B:
		return "B"
	}
	return ""
}

// Convert user inputted character to its intended chroma.
func InputToChroma(bytes []byte) Chroma {
	switch instring := string(bytes); instring {
	case "c":
		return C
	case "C":
		return Cs
	case "d":
		return D
	case "D":
		return Ds
	case "e":
		return E
	case "f":
		return F
	case "F":
		return Fs
	case "g":
		return G
	case "G":
		return Gs
	case "a":
		return A
	case "A":
		return As
	case "b":
		return B
	default:
		// TODO: Return error code and have program continue
		log.Fatal("Unrecognized input: %s", bytes)
	}
	return C
}

// Lowest musical note eligible to play
const NOTE_LOWER = A + 0*12

// Highest musical note eligible to play
const NOTE_UPPER = C + 7*12

// Volume (ie how loud) as passed to portmidi.
//
// NB: a flag to the MIDI synthesizer also affects volume.
const VOLUME = 127

func execCmd(cmd *exec.Cmd) string {
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return string(out)
}

func main() {
	portmidi.Initialize()
	log.Printf(
		"portmidi CountDevices: %v DefaultInputDevice: %v DefaultOutputDevice: %v\n",
		portmidi.CountDevices(),
		portmidi.DefaultInputDeviceID(),
		portmidi.DefaultOutputDeviceID())
	for device := 0; device < portmidi.CountDevices(); device++ {
		log.Printf("portmidi DeviceID: %v %+v\n", device, portmidi.Info(portmidi.DeviceID(device)))
	}
	// TODO: Instead of hardcoded 2, search the portmidi.Info for the
	// first port which is not Midi Through Port-0 and
	// IsOutputAvailable.
	out, err := portmidi.NewOutputStream(
		2,
		1024,
		// Latency when opening midi output stream.
		//
		// Using 0 means MIDI events are sent right away, but timestamps
		// are not honored.
		//
		// Using 1 means 1ms delay before MIDI events are sent, but
		// timestamps are honored. Care is necessary to send all note
		// offs, pitch bend resets, etc, because fluidsynth will persist
		// those across MIDI stream sessions (but not across restarts of
		// fluidsynth).
		//
		// The portmidi Pm_OpenOutput doc on has more on this 'latency'
		// field.
		0)
	if err != nil {
		log.Fatal(err)
	}

	rand.Seed(time.Now().UnixNano())
	total_queries := 0
	correct_queries := 0
	for {
		note := int64(NOTE_LOWER) + int64(rand.Intn(int(NOTE_UPPER-NOTE_LOWER)+1))
		log.Printf("Playing note: %v%v\n", Chroma(note%12), note/12)
		out.WriteShort(0x90, note, VOLUME)
		time.Sleep(1 * time.Second)
		out.WriteShort(0x80, note, VOLUME)
		total_queries++
		correct_queries++
	}

	// Put tty into mode making single byte input on stdin promptly available.
	//
	// TODO: Maybe use github.com/pkg/term to do this?
	// TODO: Would like to change how input is shown. eg 'eF' -> 'E F#'
	ttyOrig := execCmd(exec.Command("stty", "-F", "/dev/tty", "-g"))
	log.Printf("Original tty: %s", ttyOrig)
	exec.Command("stty", "-F", "/dev/tty", "-icanon", "min", "1").Run()
	defer exec.Command("stty", "-F", "/dev/tty", strings.TrimSpace(ttyOrig)).Run()
	var b []byte = make([]byte, 1)
	fmt.Print("Enter text: ")
	os.Stdin.Read(b)
	fmt.Printf("\n")
	log.Printf("Inputted: %s or %v\n", b, InputToChroma(b))

	out.WriteShort(0xC0, 0, 0)
	out.WriteShort(0x90, 60, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x80, 60, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x90, 64, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x80, 64, VOLUME)

	// t0 := portmidi.Timestamp(portmidi.Time())
	// out.Write([]portmidi.Event{
	// 	// Set up for pitch bends
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x64,  // controller number for RPN LSB
	// 		Data2: 0x00,  // controller value (0x7F would reset)
	// 	},
	// 	// Set up for pitch bends
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x65,  // controller number for RPN MSB
	// 		Data2: 0x00,  // controller value (0x7F would reset)
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xC0,  // Program Change, channel 0
	// 		Data1: 4,
	// 		Data2: 0,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xC1,  // Program Change, channel 1
	// 		Data1: 59,  // Muted trumpet
	// 		Data2: 0,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0x90,  // Note on, channel 0
	// 		Data1: 60,  // C4
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1000),
	// 		Status: 0x91,  // Note on, channel 1
	// 		Data1: 64,  // E4
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1000),
	// 		Status: 0x90,  // Note on, channel 0
	// 		Data1: 67,  // G
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1100),
	// 		Status: 0x81,  // Note off
	// 		Data1: 64,  // E
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0x80,  // Note off
	// 		Data1: 60,  // C
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x06,  // controller number for Data Entry
	// 		Data2: 24,  // Pitch bend + or - 12 semitones
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0xE0,  // Pitch bend
	// 		Data1: 0x00,  // LSB
	// 		Data2: 0x00,  // MSB
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+3000),
	// 		Status: 0x80,  // Note off
	// 		Data1: 67,  // G
	// 		Data2: VOLUME,
	// 	},
	// })
	// time.Sleep(3 * time.Second)

	out.Close()

	portmidi.Terminate()
}
<commit_msg>Basic quizzing code.<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/rakyll/portmidi"
)

// Helpful links:
// portmidi lib docs: http://portmedia.sourceforge.net/portmidi/doxygen/
// MIDI general messages: https://www.midi.org/specifications/item/table-1-summary-of-midi-message
// MIDI Control Change messages: http://nickfever.com/music/midi-cc-list
// Concisely on pitch bends: https://www.midikits.net/midi_analyser/pitch_bend.htm
// Verbosely on pitch bends: http://www.infocellar.com/sound/midi/pitch-bends.htm

// Chroma is a musical note independent of octave.
type Chroma int

// Values are the same as the MIDI notes modulo 12
const (
	C  Chroma = iota // C natural
	Cs               // C sharp
	D                // ...
	Ds
	E
	F
	Fs
	G
	Gs
	A
	As
	B
)

func (chroma Chroma) String() string {
  switch chroma {
	case C:
		return "C"
	case Cs:
		return "C#"
	case D:
		return "D"
	case Ds:
		return "D#"
	case E:
		return "E"
	case F:
		return "F"
	case Fs:
		return "F#"
	case G:
		return "G"
	case Gs:
		return "G#"
	case A:
		return "A"
	case As:
		return "A#"
	case B:
		return "B"
	}
	return ""
}

// Convert user inputted character to its intended chroma.
func InputToChroma(bytes []byte) Chroma {
	switch instring := string(bytes); instring {
	case "c":
		return C
	case "C":
		return Cs
	case "d":
		return D
	case "D":
		return Ds
	case "e":
		return E
	case "f":
		return F
	case "F":
		return Fs
	case "g":
		return G
	case "G":
		return Gs
	case "a":
		return A
	case "A":
		return As
	case "b":
		return B
	default:
		// TODO: Return error code and have program continue
		log.Fatal("Unrecognized input: %s", bytes)
	}
	return C
}

// Lowest musical note eligible to play
const NOTE_LOWER = A + 0*12

// Highest musical note eligible to play
const NOTE_UPPER = C + 7*12

// Volume (ie how loud) as passed to portmidi.
//
// NB: a flag to the MIDI synthesizer also affects volume.
const VOLUME = 127

func execCmd(cmd *exec.Cmd) string {
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return string(out)
}

func main() {
	portmidi.Initialize()
	log.Printf(
		"portmidi CountDevices: %v DefaultInputDevice: %v DefaultOutputDevice: %v\n",
		portmidi.CountDevices(),
		portmidi.DefaultInputDeviceID(),
		portmidi.DefaultOutputDeviceID())
	for device := 0; device < portmidi.CountDevices(); device++ {
		log.Printf("portmidi DeviceID: %v %+v\n", device, portmidi.Info(portmidi.DeviceID(device)))
	}
	// TODO: Instead of hardcoded 2, search the portmidi.Info for the
	// first port which is not Midi Through Port-0 and
	// IsOutputAvailable.
	out, err := portmidi.NewOutputStream(
		2,
		1024,
		// Latency when opening midi output stream.
		//
		// Using 0 means MIDI events are sent right away, but timestamps
		// are not honored.
		//
		// Using 1 means 1ms delay before MIDI events are sent, but
		// timestamps are honored. Care is necessary to send all note
		// offs, pitch bend resets, etc, because fluidsynth will persist
		// those across MIDI stream sessions (but not across restarts of
		// fluidsynth).
		//
		// The portmidi Pm_OpenOutput doc on has more on this 'latency'
		// field.
		0)
	if err != nil {
		log.Fatal(err)
	}

	// Put tty into mode making single byte input on stdin promptly available.
	//
	// TODO: Maybe use github.com/pkg/term to do this?
	// TODO: Would like to change how input is shown. eg 'eF' -> 'E F#'
	ttyOrig := execCmd(exec.Command("stty", "-F", "/dev/tty", "-g"))
	log.Printf("Original tty: %s", ttyOrig)
	exec.Command("stty", "-F", "/dev/tty", "-icanon", "min", "1").Run()
	defer exec.Command("stty", "-F", "/dev/tty", strings.TrimSpace(ttyOrig)).Run()
	var b []byte = make([]byte, 1)

	rand.Seed(time.Now().UnixNano())
	correct_queries := 0
	total_queries := 0
	for {
		note := int64(NOTE_LOWER) + int64(rand.Intn(int(NOTE_UPPER-NOTE_LOWER)+1))
		out.WriteShort(0x90, note, VOLUME)
		os.Stdin.Read(b)
		out.WriteShort(0x80, note, VOLUME)
		fmt.Printf("\n")
		inputted_chroma := InputToChroma(b)
		actual_chroma := Chroma(note%12)
		if inputted_chroma == actual_chroma {
			correct_queries++
		}
		total_queries++
		log.Printf(
			"Inputted, actual are %v, %v%v. Correct/total is %v/%v\n",
			inputted_chroma, actual_chroma, note/12, correct_queries, total_queries)
	}

	out.WriteShort(0xC0, 0, 0)
	out.WriteShort(0x90, 60, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x80, 60, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x90, 64, VOLUME)
	time.Sleep(1 * time.Second)
	out.WriteShort(0x80, 64, VOLUME)

	// t0 := portmidi.Timestamp(portmidi.Time())
	// out.Write([]portmidi.Event{
	// 	// Set up for pitch bends
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x64,  // controller number for RPN LSB
	// 		Data2: 0x00,  // controller value (0x7F would reset)
	// 	},
	// 	// Set up for pitch bends
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x65,  // controller number for RPN MSB
	// 		Data2: 0x00,  // controller value (0x7F would reset)
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xC0,  // Program Change, channel 0
	// 		Data1: 4,
	// 		Data2: 0,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0xC1,  // Program Change, channel 1
	// 		Data1: 59,  // Muted trumpet
	// 		Data2: 0,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0),
	// 		Status: 0x90,  // Note on, channel 0
	// 		Data1: 60,  // C4
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1000),
	// 		Status: 0x91,  // Note on, channel 1
	// 		Data1: 64,  // E4
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1000),
	// 		Status: 0x90,  // Note on, channel 0
	// 		Data1: 67,  // G
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+1100),
	// 		Status: 0x81,  // Note off
	// 		Data1: 64,  // E
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0x80,  // Note off
	// 		Data1: 60,  // C
	// 		Data2: VOLUME,
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0xB0,  // Control Change
	// 		Data1: 0x06,  // controller number for Data Entry
	// 		Data2: 24,  // Pitch bend + or - 12 semitones
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+2000),
	// 		Status: 0xE0,  // Pitch bend
	// 		Data1: 0x00,  // LSB
	// 		Data2: 0x00,  // MSB
	// 	},
	// 	portmidi.Event {
	// 		Timestamp: portmidi.Timestamp(t0+3000),
	// 		Status: 0x80,  // Note off
	// 		Data1: 67,  // G
	// 		Data2: VOLUME,
	// 	},
	// })
	// time.Sleep(3 * time.Second)

	out.Close()

	portmidi.Terminate()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/guzzlerio/corcel/cmd"
	"github.com/guzzlerio/corcel/core"
	"github.com/guzzlerio/corcel/infrastructure/http"
	"github.com/guzzlerio/corcel/infrastructure/inproc"
	"github.com/guzzlerio/corcel/logger"
	"github.com/guzzlerio/corcel/serialisation/yaml"
)

var (
	//Version ...
	Version = "EMPTY"
	//BuildTime ...
	BuildTime = "EMPTY"
	//CommitHash ...
	CommitHash = "EMPTY"
)

func main() {

	logger.Initialise()

	//TODO: This is not as efficient as it could be for example:
	//Ideally we would only add the HTTP result processor IF an HTTP Action was used
	//Currently every result processor needs to be added.
	//TODO add a ScanForActions .ScanForAssertions .ScanForProcessors .ScanForExtractors .ScanForContexts
	registry := core.CreateRegistry().
		AddActionParser(inproc.YamlDummyActionParser{}).
		AddActionParser(http.YamlHTTPRequestParser{}).
		AddAssertionParser(yaml.ExactAssertionParser{}).
		AddAssertionParser(yaml.NotEqualAssertionParser{}).
		AddAssertionParser(yaml.EmptyAssertionParser{}).
		AddAssertionParser(yaml.NotEmptyAssertionParser{}).
		AddAssertionParser(yaml.GreaterThanAssertionParser{}).
		AddAssertionParser(yaml.GreaterThanOrEqualAssertionParser{}).
		AddAssertionParser(yaml.LessThanAssertionParser{}).
		AddAssertionParser(yaml.LessThanOrEqualAssertionParser{}).
		AddResultProcessor(http.NewExecutionResultProcessor()).
		AddResultProcessor(inproc.NewGeneralExecutionResultProcessor()).
		AddExtractorParser(yaml.RegexExtractorParser{}).
		AddExtractorParser(yaml.XPathExtractorParser{}).
		AddExtractorParser(yaml.JSONPathExtractorParser{})

	//kingpin.UsageTemplate(kingpin.CompactUsageTemplate)
	kingpin.CommandLine.Help = "An example implementation of curl."

	versionString := fmt.Sprintf("Version %s, Build Time: %s, Hash: %s", Version, BuildTime, CommitHash)

	app := kingpin.New("corcel", "").Version(versionString).Author("Andrew Rea").Author("James Allen")
	app.HelpFlag.Short('h')
	app.UsageTemplate(kingpin.LongHelpTemplate)

	cmd.NewRunCommand(app, &registry)
	cmd.NewServerCommand(app, &registry)

	kingpin.MustParse(app.Parse(os.Args[1:]))
}
<commit_msg>Supports compiling with profiling enabled.<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"runtime/pprof"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/guzzlerio/corcel/cmd"
	"github.com/guzzlerio/corcel/core"
	"github.com/guzzlerio/corcel/infrastructure/http"
	"github.com/guzzlerio/corcel/infrastructure/inproc"
	"github.com/guzzlerio/corcel/logger"
	"github.com/guzzlerio/corcel/serialisation/yaml"
)

var (
	//Version ...
	Version = "EMPTY"
	//BuildTime ...
	BuildTime = "EMPTY"
	//CommitHash ...
	CommitHash = "EMPTY"

	//profile
	profile = ""
)

func main() {

	if profile != "" {
		f, err := os.Create("./corcel.prof")
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	logger.Initialise()

	//TODO: This is not as efficient as it could be for example:
	//Ideally we would only add the HTTP result processor IF an HTTP Action was used
	//Currently every result processor needs to be added.
	//TODO add a ScanForActions .ScanForAssertions .ScanForProcessors .ScanForExtractors .ScanForContexts
	registry := core.CreateRegistry().
		AddActionParser(inproc.YamlDummyActionParser{}).
		AddActionParser(http.YamlHTTPRequestParser{}).
		AddAssertionParser(yaml.ExactAssertionParser{}).
		AddAssertionParser(yaml.NotEqualAssertionParser{}).
		AddAssertionParser(yaml.EmptyAssertionParser{}).
		AddAssertionParser(yaml.NotEmptyAssertionParser{}).
		AddAssertionParser(yaml.GreaterThanAssertionParser{}).
		AddAssertionParser(yaml.GreaterThanOrEqualAssertionParser{}).
		AddAssertionParser(yaml.LessThanAssertionParser{}).
		AddAssertionParser(yaml.LessThanOrEqualAssertionParser{}).
		AddResultProcessor(http.NewExecutionResultProcessor()).
		AddResultProcessor(inproc.NewGeneralExecutionResultProcessor()).
		AddExtractorParser(yaml.RegexExtractorParser{}).
		AddExtractorParser(yaml.XPathExtractorParser{}).
		AddExtractorParser(yaml.JSONPathExtractorParser{})

	//kingpin.UsageTemplate(kingpin.CompactUsageTemplate)
	kingpin.CommandLine.Help = "An example implementation of curl."

	versionString := fmt.Sprintf("Version %s, Build Time: %s, Hash: %s", Version, BuildTime, CommitHash)

	app := kingpin.New("corcel", "").Version(versionString).Author("Andrew Rea").Author("James Allen")
	app.HelpFlag.Short('h')
	app.UsageTemplate(kingpin.LongHelpTemplate)

	cmd.NewRunCommand(app, &registry)
	cmd.NewServerCommand(app, &registry)

	kingpin.MustParse(app.Parse(os.Args[1:]))
}
<|endoftext|>


<commit_before>package sqlla

import (
	"fmt"
	"go/ast"
	"go/types"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"golang.org/x/tools/go/packages"
)

func Run(from, ext string) {
	fullpath, err := filepath.Abs(from)
	if err != nil {
		panic(err)
	}
	dir := filepath.Dir(fullpath)

	conf := &packages.Config{
		Mode: packages.NeedCompiledGoFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo,
	}
	pkgs, err := packages.Load(conf, dir)
	if err != nil {
		panic(err)
	}
	for _, pkg := range pkgs {
		files := pkg.Syntax
		for _, f := range files {
			for _, decl := range f.Decls {
				pos := pkg.Fset.Position(decl.Pos())
				if pos.Filename != fullpath {
					continue
				}
				genDecl, ok := decl.(*ast.GenDecl)
				if !ok {
					continue
				}
				if genDecl.Doc == nil {
					continue
				}
				var hasAnnotation bool
				var annotationComment string
				for _, comment := range genDecl.Doc.List {
					if trimmed := trimAnnotation(comment.Text); trimmed != comment.Text {
						hasAnnotation = true
						annotationComment = comment.Text
						break
					}
				}
				if !hasAnnotation {
					continue
				}
				table, err := toTable(pkg.Types, annotationComment, genDecl, pkg.TypesInfo)
				if err != nil {
					panic(err)
				}
				filename := filepath.Join(dir, table.Name+ext)
				f, err := os.Create(filename)
				if err != nil {
					panic(err)
				}
				if err := WriteCode(f, table); err != nil {
					panic(err)
				}
			}
		}
	}
}

var supportedNonPrimitiveTypes = map[string]struct{}{
	"time.Time":       {},
	"mysql.NullTime":  {},
	"sql.NullTime":    {},
	"sql.NullInt64":   {},
	"sql.NullString":  {},
	"sql.NullFloat64": {},
	"sql.NullBool":    {},
}

var altTypeNames = map[string]string{
	"[]byte":         "Bytes",
	"mysql.NullTime": "MysqlNullTime",
}

func toTable(tablePkg *types.Package, annotationComment string, gd *ast.GenDecl, ti *types.Info) (*Table, error) {
	table := new(Table)
	table.Package = tablePkg
	table.PackageName = tablePkg.Name()

	tableName := trimAnnotation(annotationComment)
	table.Name = tableName

	spec := gd.Specs[0]
	ts, ok := spec.(*ast.TypeSpec)
	if !ok {
		return nil, fmt.Errorf("toTable: not type spec: table=%s", tableName)
	}
	structType, ok := ts.Type.(*ast.StructType)
	if !ok {
		return nil, fmt.Errorf("toTable: not struct type: table=%s", tableName)
	}

	table.StructName = ts.Name.Name

	for _, field := range structType.Fields.List {
		tagText := field.Tag.Value[1 : len(field.Tag.Value)-1]
		tag := reflect.StructTag(tagText)
		columnInfo := tag.Get("db")
		columnMaps := strings.Split(columnInfo, ",")
		columnName := columnMaps[0]
		isPk := false
		for _, cm := range columnMaps {
			if cm == "primarykey" {
				isPk = true
				break
			}
		}
		t := ti.TypeOf(field.Type)
		var typeName, pkgName string
		baseTypeName := t.String()
		nt, ok := t.(*types.Named)
		if ok {
			pkgName = nt.Obj().Pkg().Path()
			if tablePkg.Path() != pkgName {
				typeName = strings.Join([]string{nt.Obj().Pkg().Name(), nt.Obj().Name()}, ".")
			} else {
				typeName = nt.Obj().Name()
			}
			baseTypeName = typeName
			if _, ok := supportedNonPrimitiveTypes[typeName]; !ok {
				bt := nt.Underlying()
				for _, ok := bt.Underlying().(*types.Named); ok; bt = bt.Underlying() {
				}
				baseTypeName = bt.String()
			}
		} else {
			typeName = t.String()
		}
		column := Column{
			Field:        field,
			Name:         columnName,
			IsPk:         isPk,
			TypeName:     typeName,
			BaseTypeName: baseTypeName,
			PkgName:      pkgName,
		}
		if alt, ok := altTypeNames[baseTypeName]; ok {
			column.AltTypeName = alt
		}
		table.AddColumn(column)
	}

	return table, nil
}

func trimAnnotation(comment string) string {
	prefixies := []string{"//+table: ", "// +table: ", "//sqlla:table "}
	for _, prefix := range prefixies {
		if trimmed := strings.TrimPrefix(comment, prefix); trimmed != comment {
			return trimmed
		}
	}
	return comment
}
<commit_msg>refactor: the plural form of prefix is prefixes<commit_after>package sqlla

import (
	"fmt"
	"go/ast"
	"go/types"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"golang.org/x/tools/go/packages"
)

func Run(from, ext string) {
	fullpath, err := filepath.Abs(from)
	if err != nil {
		panic(err)
	}
	dir := filepath.Dir(fullpath)

	conf := &packages.Config{
		Mode: packages.NeedCompiledGoFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo,
	}
	pkgs, err := packages.Load(conf, dir)
	if err != nil {
		panic(err)
	}
	for _, pkg := range pkgs {
		files := pkg.Syntax
		for _, f := range files {
			for _, decl := range f.Decls {
				pos := pkg.Fset.Position(decl.Pos())
				if pos.Filename != fullpath {
					continue
				}
				genDecl, ok := decl.(*ast.GenDecl)
				if !ok {
					continue
				}
				if genDecl.Doc == nil {
					continue
				}
				var hasAnnotation bool
				var annotationComment string
				for _, comment := range genDecl.Doc.List {
					if trimmed := trimAnnotation(comment.Text); trimmed != comment.Text {
						hasAnnotation = true
						annotationComment = comment.Text
						break
					}
				}
				if !hasAnnotation {
					continue
				}
				table, err := toTable(pkg.Types, annotationComment, genDecl, pkg.TypesInfo)
				if err != nil {
					panic(err)
				}
				filename := filepath.Join(dir, table.Name+ext)
				f, err := os.Create(filename)
				if err != nil {
					panic(err)
				}
				if err := WriteCode(f, table); err != nil {
					panic(err)
				}
			}
		}
	}
}

var supportedNonPrimitiveTypes = map[string]struct{}{
	"time.Time":       {},
	"mysql.NullTime":  {},
	"sql.NullTime":    {},
	"sql.NullInt64":   {},
	"sql.NullString":  {},
	"sql.NullFloat64": {},
	"sql.NullBool":    {},
}

var altTypeNames = map[string]string{
	"[]byte":         "Bytes",
	"mysql.NullTime": "MysqlNullTime",
}

func toTable(tablePkg *types.Package, annotationComment string, gd *ast.GenDecl, ti *types.Info) (*Table, error) {
	table := new(Table)
	table.Package = tablePkg
	table.PackageName = tablePkg.Name()

	tableName := trimAnnotation(annotationComment)
	table.Name = tableName

	spec := gd.Specs[0]
	ts, ok := spec.(*ast.TypeSpec)
	if !ok {
		return nil, fmt.Errorf("toTable: not type spec: table=%s", tableName)
	}
	structType, ok := ts.Type.(*ast.StructType)
	if !ok {
		return nil, fmt.Errorf("toTable: not struct type: table=%s", tableName)
	}

	table.StructName = ts.Name.Name

	for _, field := range structType.Fields.List {
		tagText := field.Tag.Value[1 : len(field.Tag.Value)-1]
		tag := reflect.StructTag(tagText)
		columnInfo := tag.Get("db")
		columnMaps := strings.Split(columnInfo, ",")
		columnName := columnMaps[0]
		isPk := false
		for _, cm := range columnMaps {
			if cm == "primarykey" {
				isPk = true
				break
			}
		}
		t := ti.TypeOf(field.Type)
		var typeName, pkgName string
		baseTypeName := t.String()
		nt, ok := t.(*types.Named)
		if ok {
			pkgName = nt.Obj().Pkg().Path()
			if tablePkg.Path() != pkgName {
				typeName = strings.Join([]string{nt.Obj().Pkg().Name(), nt.Obj().Name()}, ".")
			} else {
				typeName = nt.Obj().Name()
			}
			baseTypeName = typeName
			if _, ok := supportedNonPrimitiveTypes[typeName]; !ok {
				bt := nt.Underlying()
				for _, ok := bt.Underlying().(*types.Named); ok; bt = bt.Underlying() {
				}
				baseTypeName = bt.String()
			}
		} else {
			typeName = t.String()
		}
		column := Column{
			Field:        field,
			Name:         columnName,
			IsPk:         isPk,
			TypeName:     typeName,
			BaseTypeName: baseTypeName,
			PkgName:      pkgName,
		}
		if alt, ok := altTypeNames[baseTypeName]; ok {
			column.AltTypeName = alt
		}
		table.AddColumn(column)
	}

	return table, nil
}

func trimAnnotation(comment string) string {
	prefixes := []string{"//+table: ", "// +table: ", "//sqlla:table "}
	for _, prefix := range prefixes {
		if trimmed := strings.TrimPrefix(comment, prefix); trimmed != comment {
			return trimmed
		}
	}
	return comment
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/aerogo/aero"
	"github.com/aerogo/api"
	"github.com/aerogo/session-store-aerospike"
	"github.com/animenotifier/arn"
	"github.com/animenotifier/notify.moe/auth"
	"github.com/animenotifier/notify.moe/components/css"
	"github.com/animenotifier/notify.moe/layout"
	"github.com/animenotifier/notify.moe/middleware"
	"github.com/animenotifier/notify.moe/pages/admin"
	"github.com/animenotifier/notify.moe/pages/anime"
	"github.com/animenotifier/notify.moe/pages/animelist"
	"github.com/animenotifier/notify.moe/pages/animelistitem"
	"github.com/animenotifier/notify.moe/pages/apiview"
	"github.com/animenotifier/notify.moe/pages/best"
	"github.com/animenotifier/notify.moe/pages/character"
	"github.com/animenotifier/notify.moe/pages/dashboard"
	"github.com/animenotifier/notify.moe/pages/editanime"
	"github.com/animenotifier/notify.moe/pages/editor"
	"github.com/animenotifier/notify.moe/pages/embed"
	"github.com/animenotifier/notify.moe/pages/explore"
	"github.com/animenotifier/notify.moe/pages/forum"
	"github.com/animenotifier/notify.moe/pages/forums"
	"github.com/animenotifier/notify.moe/pages/listimport"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportanilist"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportkitsu"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportmyanimelist"
	"github.com/animenotifier/notify.moe/pages/login"
	"github.com/animenotifier/notify.moe/pages/music"
	"github.com/animenotifier/notify.moe/pages/newsoundtrack"
	"github.com/animenotifier/notify.moe/pages/newthread"
	"github.com/animenotifier/notify.moe/pages/posts"
	"github.com/animenotifier/notify.moe/pages/profile"
	"github.com/animenotifier/notify.moe/pages/search"
	"github.com/animenotifier/notify.moe/pages/settings"
	"github.com/animenotifier/notify.moe/pages/statistics"
	"github.com/animenotifier/notify.moe/pages/threads"
	"github.com/animenotifier/notify.moe/pages/tracks"
	"github.com/animenotifier/notify.moe/pages/user"
	"github.com/animenotifier/notify.moe/pages/users"
	"github.com/animenotifier/notify.moe/pages/webdev"
)

var app = aero.New()

func main() {
	// Configure and start
	configure(app).Run()
}

func configure(app *aero.Application) *aero.Application {
	// HTTPS
	app.Security.Load("security/fullchain.pem", "security/privkey.pem")

	// CSS
	app.SetStyle(css.Bundle())

	// Sessions
	app.Sessions.Duration = 3600 * 24 * 7
	app.Sessions.Store = aerospikestore.New(arn.DB, "Session", app.Sessions.Duration)

	// Layout
	app.Layout = layout.Render

	// Ajax routes
	app.Ajax("/", dashboard.Get)
	app.Ajax("/anime/:id", anime.Get)
	app.Ajax("/anime/:id/edit", editanime.Get)
	app.Ajax("/api", apiview.Get)
	app.Ajax("/best/anime", best.Get)
	app.Ajax("/explore", explore.Get)
	app.Ajax("/forum", forums.Get)
	app.Ajax("/forum/:tag", forum.Get)
	app.Ajax("/thread/:id", threads.Get)
	app.Ajax("/post/:id", posts.Get)
	app.Ajax("/track/:id", tracks.Get)
	app.Ajax("/character/:id", character.Get)
	app.Ajax("/new/thread", newthread.Get)
	app.Ajax("/new/soundtrack", newsoundtrack.Get)
	app.Ajax("/settings", settings.Get)
	app.Ajax("/music", music.Get)
	app.Ajax("/users", users.Get)
	app.Ajax("/login", login.Get)

	// User profiles
	app.Ajax("/user", user.Get)
	app.Ajax("/user/:nick", profile.Get)
	app.Ajax("/user/:nick/threads", profile.GetThreadsByUser)
	app.Ajax("/user/:nick/posts", profile.GetPostsByUser)
	app.Ajax("/user/:nick/tracks", profile.GetSoundTracksByUser)
	app.Ajax("/user/:nick/stats", profile.GetStatsByUser)
	app.Ajax("/user/:nick/animelist", animelist.Get)
	app.Ajax("/user/:nick/animelist/watching", animelist.FilterByStatus(arn.AnimeListStatusWatching))
	app.Ajax("/user/:nick/animelist/completed", animelist.FilterByStatus(arn.AnimeListStatusCompleted))
	app.Ajax("/user/:nick/animelist/planned", animelist.FilterByStatus(arn.AnimeListStatusPlanned))
	app.Ajax("/user/:nick/animelist/hold", animelist.FilterByStatus(arn.AnimeListStatusHold))
	app.Ajax("/user/:nick/animelist/dropped", animelist.FilterByStatus(arn.AnimeListStatusDropped))
	app.Ajax("/user/:nick/animelist/anime/:id", animelistitem.Get)

	// Search
	app.Ajax("/search", search.Get)
	app.Ajax("/search/:term", search.Get)

	// Admin
	app.Ajax("/admin", admin.Get)
	app.Ajax("/editor", editor.Get)
	app.Ajax("/statistics", statistics.Get)
	app.Ajax("/statistics/anime", statistics.Anime)
	app.Ajax("/webdev", webdev.Get)

	// Import
	app.Ajax("/import", listimport.Get)
	app.Ajax("/import/anilist/animelist", listimportanilist.Preview)
	app.Ajax("/import/anilist/animelist/finish", listimportanilist.Finish)
	app.Ajax("/import/myanimelist/animelist", listimportmyanimelist.Preview)
	app.Ajax("/import/myanimelist/animelist/finish", listimportmyanimelist.Finish)
	app.Ajax("/import/kitsu/animelist", listimportkitsu.Preview)
	app.Ajax("/import/kitsu/animelist/finish", listimportkitsu.Finish)

	// Genres
	// app.Ajax("/genres", genres.Get)
	// app.Ajax("/genres/:name", genre.Get)

	// Browser extension
	app.Ajax("/extension/embed", embed.Get)

	// Middleware
	app.Use(middleware.Log())
	app.Use(middleware.Session())
	app.Use(middleware.UserInfo())

	// API
	api := api.New("/api/", arn.DB)
	api.Install(app)

	// Domain
	if arn.IsDevelopment() {
		app.Config.Domain = "beta.notify.moe"
	} else {
		arn.DB.SetScanPriority("high")
	}

	// Authentication
	auth.Install(app)

	return app
}
<commit_msg>Increased session duration<commit_after>package main

import (
	"github.com/aerogo/aero"
	"github.com/aerogo/api"
	"github.com/aerogo/session-store-aerospike"
	"github.com/animenotifier/arn"
	"github.com/animenotifier/notify.moe/auth"
	"github.com/animenotifier/notify.moe/components/css"
	"github.com/animenotifier/notify.moe/layout"
	"github.com/animenotifier/notify.moe/middleware"
	"github.com/animenotifier/notify.moe/pages/admin"
	"github.com/animenotifier/notify.moe/pages/anime"
	"github.com/animenotifier/notify.moe/pages/animelist"
	"github.com/animenotifier/notify.moe/pages/animelistitem"
	"github.com/animenotifier/notify.moe/pages/apiview"
	"github.com/animenotifier/notify.moe/pages/best"
	"github.com/animenotifier/notify.moe/pages/character"
	"github.com/animenotifier/notify.moe/pages/dashboard"
	"github.com/animenotifier/notify.moe/pages/editanime"
	"github.com/animenotifier/notify.moe/pages/editor"
	"github.com/animenotifier/notify.moe/pages/embed"
	"github.com/animenotifier/notify.moe/pages/explore"
	"github.com/animenotifier/notify.moe/pages/forum"
	"github.com/animenotifier/notify.moe/pages/forums"
	"github.com/animenotifier/notify.moe/pages/listimport"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportanilist"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportkitsu"
	"github.com/animenotifier/notify.moe/pages/listimport/listimportmyanimelist"
	"github.com/animenotifier/notify.moe/pages/login"
	"github.com/animenotifier/notify.moe/pages/music"
	"github.com/animenotifier/notify.moe/pages/newsoundtrack"
	"github.com/animenotifier/notify.moe/pages/newthread"
	"github.com/animenotifier/notify.moe/pages/posts"
	"github.com/animenotifier/notify.moe/pages/profile"
	"github.com/animenotifier/notify.moe/pages/search"
	"github.com/animenotifier/notify.moe/pages/settings"
	"github.com/animenotifier/notify.moe/pages/statistics"
	"github.com/animenotifier/notify.moe/pages/threads"
	"github.com/animenotifier/notify.moe/pages/tracks"
	"github.com/animenotifier/notify.moe/pages/user"
	"github.com/animenotifier/notify.moe/pages/users"
	"github.com/animenotifier/notify.moe/pages/webdev"
)

var app = aero.New()

func main() {
	// Configure and start
	configure(app).Run()
}

func configure(app *aero.Application) *aero.Application {
	// HTTPS
	app.Security.Load("security/fullchain.pem", "security/privkey.pem")

	// CSS
	app.SetStyle(css.Bundle())

	// Sessions
	app.Sessions.Duration = 3600 * 24 * 30
	app.Sessions.Store = aerospikestore.New(arn.DB, "Session", app.Sessions.Duration)

	// Layout
	app.Layout = layout.Render

	// Ajax routes
	app.Ajax("/", dashboard.Get)
	app.Ajax("/anime/:id", anime.Get)
	app.Ajax("/anime/:id/edit", editanime.Get)
	app.Ajax("/api", apiview.Get)
	app.Ajax("/best/anime", best.Get)
	app.Ajax("/explore", explore.Get)
	app.Ajax("/forum", forums.Get)
	app.Ajax("/forum/:tag", forum.Get)
	app.Ajax("/thread/:id", threads.Get)
	app.Ajax("/post/:id", posts.Get)
	app.Ajax("/track/:id", tracks.Get)
	app.Ajax("/character/:id", character.Get)
	app.Ajax("/new/thread", newthread.Get)
	app.Ajax("/new/soundtrack", newsoundtrack.Get)
	app.Ajax("/settings", settings.Get)
	app.Ajax("/music", music.Get)
	app.Ajax("/users", users.Get)
	app.Ajax("/login", login.Get)

	// User profiles
	app.Ajax("/user", user.Get)
	app.Ajax("/user/:nick", profile.Get)
	app.Ajax("/user/:nick/threads", profile.GetThreadsByUser)
	app.Ajax("/user/:nick/posts", profile.GetPostsByUser)
	app.Ajax("/user/:nick/tracks", profile.GetSoundTracksByUser)
	app.Ajax("/user/:nick/stats", profile.GetStatsByUser)
	app.Ajax("/user/:nick/animelist", animelist.Get)
	app.Ajax("/user/:nick/animelist/watching", animelist.FilterByStatus(arn.AnimeListStatusWatching))
	app.Ajax("/user/:nick/animelist/completed", animelist.FilterByStatus(arn.AnimeListStatusCompleted))
	app.Ajax("/user/:nick/animelist/planned", animelist.FilterByStatus(arn.AnimeListStatusPlanned))
	app.Ajax("/user/:nick/animelist/hold", animelist.FilterByStatus(arn.AnimeListStatusHold))
	app.Ajax("/user/:nick/animelist/dropped", animelist.FilterByStatus(arn.AnimeListStatusDropped))
	app.Ajax("/user/:nick/animelist/anime/:id", animelistitem.Get)

	// Search
	app.Ajax("/search", search.Get)
	app.Ajax("/search/:term", search.Get)

	// Admin
	app.Ajax("/admin", admin.Get)
	app.Ajax("/editor", editor.Get)
	app.Ajax("/statistics", statistics.Get)
	app.Ajax("/statistics/anime", statistics.Anime)
	app.Ajax("/webdev", webdev.Get)

	// Import
	app.Ajax("/import", listimport.Get)
	app.Ajax("/import/anilist/animelist", listimportanilist.Preview)
	app.Ajax("/import/anilist/animelist/finish", listimportanilist.Finish)
	app.Ajax("/import/myanimelist/animelist", listimportmyanimelist.Preview)
	app.Ajax("/import/myanimelist/animelist/finish", listimportmyanimelist.Finish)
	app.Ajax("/import/kitsu/animelist", listimportkitsu.Preview)
	app.Ajax("/import/kitsu/animelist/finish", listimportkitsu.Finish)

	// Genres
	// app.Ajax("/genres", genres.Get)
	// app.Ajax("/genres/:name", genre.Get)

	// Browser extension
	app.Ajax("/extension/embed", embed.Get)

	// Middleware
	app.Use(middleware.Log())
	app.Use(middleware.Session())
	app.Use(middleware.UserInfo())

	// API
	api := api.New("/api/", arn.DB)
	api.Install(app)

	// Domain
	if arn.IsDevelopment() {
		app.Config.Domain = "beta.notify.moe"
	} else {
		arn.DB.SetScanPriority("high")
	}

	// Authentication
	auth.Install(app)

	return app
}
<|endoftext|>