<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"math"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

func ParseLine(line string) (*Example, error) {
	tokens := strings.Split(line, "\t")
	var url string
	if len(tokens) == 1 {
		url = tokens[0]
		return NewExample(url, UNLABELED), nil
	} else if len(tokens) == 2 {
		url = tokens[0]
		label, _ := strconv.ParseInt(tokens[1], 10, 0)
		switch LabelType(label) {
		case POSITIVE, NEGATIVE, UNLABELED:
			return NewExample(url, LabelType(label)), nil
		default:
			return nil, errors.New(fmt.Sprintf("Invalid Label type %d in %s", label, line))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("Invalid line: %s", line))
	}
}

func ReadExamples(filename string) ([]*Example, error) {
	fp, err := os.Open(filename)
	defer fp.Close()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(fp)
	var examples Examples
	for scanner.Scan() {
		line := scanner.Text()
		e, err := ParseLine(line)
		if err != nil {
			return nil, err
		}
		examples = append(examples, e)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return examples, nil
}

func WriteExamples(examples Examples, filename string) error {
	fp, err := os.Create(filename)
	defer fp.Close()
	if err != nil {
		return err
	}

	writer := bufio.NewWriter(fp)
	for _, e := range examples {
		if e.IsNew && e.IsLabeled() {
			url := e.FinalUrl
			if url == "" {
				url = e.Url
			}
			_, err := writer.WriteString(url + "\t" + strconv.Itoa(int(e.Label)) + "\n")
			if err != nil {
				return err
			}
		}
	}

	writer.Flush()
	return nil
}

func FilterLabeledExamples(examples Examples) Examples {
	var result Examples
	for _, e := range examples {
		if e.IsLabeled() {
			result = append(result, e)
		}
	}
	return result
}

func FilterUnlabeledExamples(examples Examples) Examples {
	result := Examples{}

	alreadyLabeledByURL := make(map[string]bool)
	alreadyLabeledByTitle := make(map[string]bool)
	for _, e := range FilterLabeledExamples(examples) {
		alreadyLabeledByURL[e.Url] = true
		alreadyLabeledByURL[e.FinalUrl] = true
		alreadyLabeledByTitle[e.Title] = true
	}

	for _, e := range examples {
		if _, ok := alreadyLabeledByURL[e.Url]; ok {
			continue
		}
		if _, ok := alreadyLabeledByTitle[e.Title]; ok {
			continue
		}
		if !e.IsLabeled() {
			alreadyLabeledByURL[e.Url] = true
			alreadyLabeledByURL[e.FinalUrl] = true
			alreadyLabeledByTitle[e.Title] = true
			result = append(result, e)
		}
	}
	return result
}

func removeDuplicate(args []string) []string {
	results := make([]string, 0)
	encountered := map[string]bool{}
	for i := 0; i < len(args); i++ {
		if !encountered[args[i]] {
			encountered[args[i]] = true
			results = append(results, args[i])
		}
	}
	return results
}

func attachMetaData(cache *Cache, examples Examples) {
	oldStdout := os.Stdout
	readFile, writeFile, _ := os.Pipe()
	os.Stdout = writeFile

	defer func() {
		writeFile.Close()
		readFile.Close()
		os.Stdout = oldStdout
	}()

	shuffle(examples)

	wg := &sync.WaitGroup{}
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	sem := make(chan struct{}, 20)
	for idx, e := range examples {
		wg.Add(1)
		sem <- struct{}{}
		go func(e *Example, idx int) {
			defer wg.Done()
			if example, ok := cache.Get(*e); ok {
				e.Title = example.Title
				e.FinalUrl = example.FinalUrl
				e.Description = example.Description
				e.Body = example.Body
				e.StatusCode = example.StatusCode
				e.Fv = example.Fv
			} else {
				fmt.Fprintln(os.Stderr, "Fetching("+strconv.Itoa(idx)+"): "+e.Url)
				article := GetArticle(e.Url)
				e.Title = article.Title
				e.FinalUrl = article.Url
				e.Description = article.Description
				e.Body = article.Body
				e.StatusCode = article.StatusCode
				e.Fv = removeDuplicate(ExtractFeatures(*e))
				e.Description = ""
				e.Body = ""
				cache.Add(*e)
			}
			<-sem
		}(e, idx)
	}
	wg.Wait()
}

func AttachMetaData(cache *Cache, examples Examples) {
	batchSize := 1000
	examplesList := make([]Examples, 0)
	n := len(examples)

	for i := 0; i < n; i += batchSize {
		max := int(math.Min(float64(i+batchSize), float64(n)))
		examplesList = append(examplesList, examples[i:max])
	}
	for _, l := range examplesList {
		attachMetaData(cache, l)
		cache.Save(CacheFilename)
	}
}

func FilterStatusCodeOkExamples(examples Examples) Examples {
	result := Examples{}

	for _, e := range examples {
		if e.StatusCode == 200 {
			result = append(result, e)
		}
	}

	return result
}

func NewOutputFilename() string {
	t := time.Now()
	return fmt.Sprintf("%d-%02d-%02d-%02d-%02d.txt", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
}

func splitTrainAndDev(examples Examples) (train Examples, dev Examples) {
	shuffle(examples)
	n := int(0.8 * float64(len(examples)))
	return examples[0:n], examples[n:]
}
<commit_msg>同時に取ってくる数を減らす<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"math"
	"os"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
)

func ParseLine(line string) (*Example, error) {
	tokens := strings.Split(line, "\t")
	var url string
	if len(tokens) == 1 {
		url = tokens[0]
		return NewExample(url, UNLABELED), nil
	} else if len(tokens) == 2 {
		url = tokens[0]
		label, _ := strconv.ParseInt(tokens[1], 10, 0)
		switch LabelType(label) {
		case POSITIVE, NEGATIVE, UNLABELED:
			return NewExample(url, LabelType(label)), nil
		default:
			return nil, errors.New(fmt.Sprintf("Invalid Label type %d in %s", label, line))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("Invalid line: %s", line))
	}
}

func ReadExamples(filename string) ([]*Example, error) {
	fp, err := os.Open(filename)
	defer fp.Close()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(fp)
	var examples Examples
	for scanner.Scan() {
		line := scanner.Text()
		e, err := ParseLine(line)
		if err != nil {
			return nil, err
		}
		examples = append(examples, e)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return examples, nil
}

func WriteExamples(examples Examples, filename string) error {
	fp, err := os.Create(filename)
	defer fp.Close()
	if err != nil {
		return err
	}

	writer := bufio.NewWriter(fp)
	for _, e := range examples {
		if e.IsNew && e.IsLabeled() {
			url := e.FinalUrl
			if url == "" {
				url = e.Url
			}
			_, err := writer.WriteString(url + "\t" + strconv.Itoa(int(e.Label)) + "\n")
			if err != nil {
				return err
			}
		}
	}

	writer.Flush()
	return nil
}

func FilterLabeledExamples(examples Examples) Examples {
	var result Examples
	for _, e := range examples {
		if e.IsLabeled() {
			result = append(result, e)
		}
	}
	return result
}

func FilterUnlabeledExamples(examples Examples) Examples {
	result := Examples{}

	alreadyLabeledByURL := make(map[string]bool)
	alreadyLabeledByTitle := make(map[string]bool)
	for _, e := range FilterLabeledExamples(examples) {
		alreadyLabeledByURL[e.Url] = true
		alreadyLabeledByURL[e.FinalUrl] = true
		alreadyLabeledByTitle[e.Title] = true
	}

	for _, e := range examples {
		if _, ok := alreadyLabeledByURL[e.Url]; ok {
			continue
		}
		if _, ok := alreadyLabeledByTitle[e.Title]; ok {
			continue
		}
		if !e.IsLabeled() {
			alreadyLabeledByURL[e.Url] = true
			alreadyLabeledByURL[e.FinalUrl] = true
			alreadyLabeledByTitle[e.Title] = true
			result = append(result, e)
		}
	}
	return result
}

func removeDuplicate(args []string) []string {
	results := make([]string, 0)
	encountered := map[string]bool{}
	for i := 0; i < len(args); i++ {
		if !encountered[args[i]] {
			encountered[args[i]] = true
			results = append(results, args[i])
		}
	}
	return results
}

func attachMetaData(cache *Cache, examples Examples) {
	oldStdout := os.Stdout
	readFile, writeFile, _ := os.Pipe()
	os.Stdout = writeFile

	defer func() {
		writeFile.Close()
		readFile.Close()
		os.Stdout = oldStdout
	}()

	shuffle(examples)

	wg := &sync.WaitGroup{}
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	sem := make(chan struct{}, 4)
	for idx, e := range examples {
		wg.Add(1)
		sem <- struct{}{}
		go func(e *Example, idx int) {
			defer wg.Done()
			if example, ok := cache.Get(*e); ok {
				e.Title = example.Title
				e.FinalUrl = example.FinalUrl
				e.Description = example.Description
				e.Body = example.Body
				e.StatusCode = example.StatusCode
				e.Fv = example.Fv
			} else {
				fmt.Fprintln(os.Stderr, "Fetching("+strconv.Itoa(idx)+"): "+e.Url)
				article := GetArticle(e.Url)
				e.Title = article.Title
				e.FinalUrl = article.Url
				e.Description = article.Description
				e.Body = article.Body
				e.StatusCode = article.StatusCode
				e.Fv = removeDuplicate(ExtractFeatures(*e))
				e.Description = ""
				e.Body = ""
				cache.Add(*e)
			}
			<-sem
		}(e, idx)
	}
	wg.Wait()
}

func AttachMetaData(cache *Cache, examples Examples) {
	batchSize := 1000
	examplesList := make([]Examples, 0)
	n := len(examples)

	for i := 0; i < n; i += batchSize {
		max := int(math.Min(float64(i+batchSize), float64(n)))
		examplesList = append(examplesList, examples[i:max])
	}
	for _, l := range examplesList {
		attachMetaData(cache, l)
		cache.Save(CacheFilename)
	}
}

func FilterStatusCodeOkExamples(examples Examples) Examples {
	result := Examples{}

	for _, e := range examples {
		if e.StatusCode == 200 {
			result = append(result, e)
		}
	}

	return result
}

func NewOutputFilename() string {
	t := time.Now()
	return fmt.Sprintf("%d-%02d-%02d-%02d-%02d.txt", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
}

func splitTrainAndDev(examples Examples) (train Examples, dev Examples) {
	shuffle(examples)
	n := int(0.8 * float64(len(examples)))
	return examples[0:n], examples[n:]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/bgentry/go-netrc/netrc"
	"github.com/mgutz/ansi"
)

var nrc *netrc.Netrc

// user.Current() requires cgo and thus doesn't work with cross-compiling.
// The following is an alternative that matches how the Heroku Toolbelt
// works, though per @fdr it may not be correct for all cases (when users have
// modified their home dir).
//
// homePath() is defined in the platform-specific source files unix.go and
// windows.go.
//
// http://stackoverflow.com/questions/7922270/obtain-users-home-directory
func hkHome() string {
	return filepath.Join(homePath(), ".hk")
}

func netrcPath() string {
	if s := os.Getenv("NETRC_PATH"); s != "" {
		return s
	}

	return filepath.Join(homePath(), netrcFilename)
}

func loadNetrc() {
	if nrc == nil {
		var err error
		if nrc, err = netrc.ParseFile(netrcPath()); err != nil {
			if os.IsNotExist(err) {
				return
			}
			printError("loading netrc: " + err.Error())
		}
	}
}

func getCreds(u string) (user, pass string) {
	loadNetrc()
	if nrc == nil {
		return "", ""
	}

	apiURL, err := url.Parse(u)
	if err != nil {
		printError("invalid API URL: %s", err)
	}
	if apiURL.Host == "" {
		printError("missing API host: %s", u)
	}
	if apiURL.User != nil {
		pw, _ := apiURL.User.Password()
		return apiURL.User.Username(), pw
	}

	m := nrc.FindMachine(apiURL.Host)
	if m == nil {
		return "", ""
	}
	return m.Login, m.Password
}

func saveCreds(host, user, pass string) error {
	loadNetrc()
	m := nrc.FindMachine(host)
	if m == nil || m.IsDefault() {
		m = nrc.NewMachine(host, user, pass, "")
	}
	m.UpdateLogin(user)
	m.UpdatePassword(pass)

	body, err := nrc.MarshalText()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(netrcPath(), body, 0600)
}

func removeCreds(host string) error {
	loadNetrc()
	nrc.RemoveMachine(host)

	body, err := nrc.MarshalText()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(netrcPath(), body, 0600)
}

// exists returns whether the given file or directory exists or not
func fileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func must(err error) {
	if err != nil {
		printError(err.Error())
	}
}

func printError(message string, args ...interface{}) {
	log.Fatal(colorizeMessage("red", "error:", message, args...))
}

func printWarning(message string, args ...interface{}) {
	log.Fatal(colorizeMessage("yellow", "warning:", message, args...))
}

func colorizeMessage(color, prefix, message string, args ...interface{}) string {
	prefResult := ""
	if prefix != "" {
		prefResult = ansi.Color(prefix, color+"+b") + " " + ansi.ColorCode("reset")
	}
	return prefResult + ansi.Color(fmt.Sprintf(message, args...), color) + ansi.ColorCode("reset")
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}

type prettyTime struct {
	time.Time
}

func (s prettyTime) String() string {
	if time.Now().Sub(s.Time) < 12*30*24*time.Hour {
		return s.Local().Format("Jan _2 15:04")
	}
	return s.Local().Format("Jan _2  2006")
}

type prettyDuration struct {
	time.Duration
}

func (a prettyDuration) String() string {
	switch d := a.Duration; {
	case d > 2*24*time.Hour:
		return a.Unit(24*time.Hour, "d")
	case d > 2*time.Hour:
		return a.Unit(time.Hour, "h")
	case d > 2*time.Minute:
		return a.Unit(time.Minute, "m")
	}
	return a.Unit(time.Second, "s")
}

func (a prettyDuration) Unit(u time.Duration, s string) string {
	return fmt.Sprintf("%2d", roundDur(a.Duration, u)) + s
}

func roundDur(d, k time.Duration) int {
	return int((d + k/2 - 1) / k)
}

func abbrev(s string, n int) string {
	if len(s) > n {
		return s[:n-1] + "…"
	}
	return s
}

func ensurePrefix(val, prefix string) string {
	if !strings.HasPrefix(val, prefix) {
		return prefix + val
	}
	return val
}

func openURL(url string) error {
	var command string
	var args []string
	switch runtime.GOOS {
	case "darwin":
		command = "open"
		args = []string{command, url}
	case "windows":
		command = "cmd"
		args = []string{"/c", "start " + strings.Replace(url, "&", "^&", -1)}
	default:
		if _, err := exec.LookPath("xdg-open"); err != nil {
			log.Println("xdg-open is required to open web pages on " + runtime.GOOS)
			os.Exit(2)
		}
		command = "xdg-open"
		args = []string{command, url}
	}
	return runCommand(command, args, os.Environ())
}

func runCommand(command string, args, env []string) error {
	if runtime.GOOS != "windows" {
		p, err := exec.LookPath(command)
		if err != nil {
			log.Printf("Error finding path to %q: %s\n", command, err)
			os.Exit(2)
		}
		command = p
	}
	return sysExec(command, args, env)
}
<commit_msg>print login message on unauthorized errors<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/bgentry/go-netrc/netrc"
	"github.com/bgentry/heroku-go"
	"github.com/mgutz/ansi"
)

var nrc *netrc.Netrc

// user.Current() requires cgo and thus doesn't work with cross-compiling.
// The following is an alternative that matches how the Heroku Toolbelt
// works, though per @fdr it may not be correct for all cases (when users have
// modified their home dir).
//
// homePath() is defined in the platform-specific source files unix.go and
// windows.go.
//
// http://stackoverflow.com/questions/7922270/obtain-users-home-directory
func hkHome() string {
	return filepath.Join(homePath(), ".hk")
}

func netrcPath() string {
	if s := os.Getenv("NETRC_PATH"); s != "" {
		return s
	}

	return filepath.Join(homePath(), netrcFilename)
}

func loadNetrc() {
	if nrc == nil {
		var err error
		if nrc, err = netrc.ParseFile(netrcPath()); err != nil {
			if os.IsNotExist(err) {
				return
			}
			printError("loading netrc: " + err.Error())
		}
	}
}

func getCreds(u string) (user, pass string) {
	loadNetrc()
	if nrc == nil {
		return "", ""
	}

	apiURL, err := url.Parse(u)
	if err != nil {
		printError("invalid API URL: %s", err)
	}
	if apiURL.Host == "" {
		printError("missing API host: %s", u)
	}
	if apiURL.User != nil {
		pw, _ := apiURL.User.Password()
		return apiURL.User.Username(), pw
	}

	m := nrc.FindMachine(apiURL.Host)
	if m == nil {
		return "", ""
	}
	return m.Login, m.Password
}

func saveCreds(host, user, pass string) error {
	loadNetrc()
	m := nrc.FindMachine(host)
	if m == nil || m.IsDefault() {
		m = nrc.NewMachine(host, user, pass, "")
	}
	m.UpdateLogin(user)
	m.UpdatePassword(pass)

	body, err := nrc.MarshalText()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(netrcPath(), body, 0600)
}

func removeCreds(host string) error {
	loadNetrc()
	nrc.RemoveMachine(host)

	body, err := nrc.MarshalText()
	if err != nil {
		return err
	}
	return ioutil.WriteFile(netrcPath(), body, 0600)
}

// exists returns whether the given file or directory exists or not
func fileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func must(err error) {
	if err != nil {
		if herror, ok := err.(heroku.Error); ok {
			if herror.Id == "unauthorized" {
				printError(err.Error() + " Log in with `hk login`.")
			}
		}
		printError(err.Error())
	}
}

func printError(message string, args ...interface{}) {
	log.Fatal(colorizeMessage("red", "error:", message, args...))
}

func printWarning(message string, args ...interface{}) {
	log.Fatal(colorizeMessage("yellow", "warning:", message, args...))
}

func colorizeMessage(color, prefix, message string, args ...interface{}) string {
	prefResult := ""
	if prefix != "" {
		prefResult = ansi.Color(prefix, color+"+b") + " " + ansi.ColorCode("reset")
	}
	return prefResult + ansi.Color(fmt.Sprintf(message, args...), color) + ansi.ColorCode("reset")
}

func listRec(w io.Writer, a ...interface{}) {
	for i, x := range a {
		fmt.Fprint(w, x)
		if i+1 < len(a) {
			w.Write([]byte{'\t'})
		} else {
			w.Write([]byte{'\n'})
		}
	}
}

type prettyTime struct {
	time.Time
}

func (s prettyTime) String() string {
	if time.Now().Sub(s.Time) < 12*30*24*time.Hour {
		return s.Local().Format("Jan _2 15:04")
	}
	return s.Local().Format("Jan _2  2006")
}

type prettyDuration struct {
	time.Duration
}

func (a prettyDuration) String() string {
	switch d := a.Duration; {
	case d > 2*24*time.Hour:
		return a.Unit(24*time.Hour, "d")
	case d > 2*time.Hour:
		return a.Unit(time.Hour, "h")
	case d > 2*time.Minute:
		return a.Unit(time.Minute, "m")
	}
	return a.Unit(time.Second, "s")
}

func (a prettyDuration) Unit(u time.Duration, s string) string {
	return fmt.Sprintf("%2d", roundDur(a.Duration, u)) + s
}

func roundDur(d, k time.Duration) int {
	return int((d + k/2 - 1) / k)
}

func abbrev(s string, n int) string {
	if len(s) > n {
		return s[:n-1] + "…"
	}
	return s
}

func ensurePrefix(val, prefix string) string {
	if !strings.HasPrefix(val, prefix) {
		return prefix + val
	}
	return val
}

func openURL(url string) error {
	var command string
	var args []string
	switch runtime.GOOS {
	case "darwin":
		command = "open"
		args = []string{command, url}
	case "windows":
		command = "cmd"
		args = []string{"/c", "start " + strings.Replace(url, "&", "^&", -1)}
	default:
		if _, err := exec.LookPath("xdg-open"); err != nil {
			log.Println("xdg-open is required to open web pages on " + runtime.GOOS)
			os.Exit(2)
		}
		command = "xdg-open"
		args = []string{command, url}
	}
	return runCommand(command, args, os.Environ())
}

func runCommand(command string, args, env []string) error {
	if runtime.GOOS != "windows" {
		p, err := exec.LookPath(command)
		if err != nil {
			log.Printf("Error finding path to %q: %s\n", command, err)
			os.Exit(2)
		}
		command = p
	}
	return sysExec(command, args, env)
}
<|endoftext|>


<commit_before>package gom

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

func IsEmpty(v interface{}) bool {
	times := time.Time{}
	if times == v {
		return true
	}
	if v == "" {
		return true
	}
	if v == 0 {
		return true
	}
	if v == 0.0 {
		return true
	}
	if v == nil {
		return true
	}
	return false
}
func getType(v interface{}) (reflect.Type, bool, bool) {
	tt := reflect.TypeOf(v)
	isPtr := false
	islice := false
	if tt.Kind() == reflect.Ptr {
		tt = tt.Elem()
		isPtr = true
	}
	if tt.Kind() == reflect.Slice || tt.Kind() == reflect.Array {
		tt = tt.Elem()
		islice = true
	}
	if debug {
		fmt.Println("Test getType, result:", tt, isPtr, islice)
	}
	return tt, isPtr, islice
}
func getTableModels(vs ...interface{}) []TableModel {
	tablemodels := []TableModel{}
	for _, v := range vs {
		tablemodels = append(tablemodels, getTableModel(v))
	}
	return tablemodels
}
func GetTableModel(v interface{}, names ...string) TableModel {
	tm := getTableModel(v)
	var cc []Column
	for _, ct := range tm.Columns {
		for _, name := range names {
			if ct.ColumnName == name {
				cc = append(cc, ct)
			}
		}
	}
	tm.Columns = cc
	return tm

}
func CreateSingleValueTableModel(v interface{}, table string, field string) TableModel {
	tt, _, _ := getType(v)
	vals := reflect.New(tt).Elem()
	columns := []Column{{ColumnName: field, ColumnType: tt, IsPrimary: false, Auto: false}}
	return TableModel{Columns: columns, TableName: table, ModelType: tt, ModelValue: vals}
}
func getTableModel(v interface{}) TableModel {
	if v != nil && reflect.TypeOf(v).Kind() != reflect.Interface {
		tt, isPtr, isSlice := getType(v)
		vals := reflect.ValueOf(v)
		if isPtr {
			vals = vals.Elem()
		}
		if isSlice {
			vals = reflect.New(tt)
		}
		if tt.NumField() > 0 && tt.NumMethod() > 0 {
			nameMethod := vals.MethodByName("TableName")
			if debug {
				fmt.Println(nameMethod)
			}
			tableName := nameMethod.Call(nil)[0].String()
			columns, primary := getColumns(vals)
			ccs := []Column{primary}
			ccs = append(ccs, columns...)
			return TableModel{ModelType: tt, ModelValue: vals, Columns: ccs, TableName: tableName, Primary: primary}
		} else {
			return TableModel{}
		}
	} else {
		return TableModel{}
	}
}
func getColumns(v reflect.Value) ([]Column, Column) {
	var columns []Column
	var primary Column
	results := reflect.Indirect(reflect.ValueOf(&columns))
	oo := v.Type()
	i := 0
	for ; i < oo.NumField(); i++ {
		field := oo.Field(i)
		col, tps := getColumnFromField(field)
		if tps != -1 {
			if tps == 1 || tps == 2 {
				primary = col
			} else {
				n := reflect.Indirect(reflect.ValueOf(&col))
				if results.Kind() == reflect.Ptr {
					results.Set(reflect.Append(results, n.Addr()))
				} else {
					results.Set(reflect.Append(results, n))
				}
			}

		}
	}
	if debug {
		fmt.Println("columns is:", columns)
	}
	return columns, primary
}
func getColumnFromField(filed reflect.StructField) (Column, int) {
	tag, tps := getTagFromField(filed)
	if debug {
		fmt.Println("Tag is:", tag, "type is:", tps)
	}
	if tps != -1 {
		return Column{ColumnType: filed.Type, ColumnName: tag, FieldName: filed.Name, Auto: tps == 2, IsPrimary: tps == 1 || tps == 2}, tps
	} else {
		return Column{}, -1
	}

}
func getTagFromField(field reflect.StructField) (string, int) {
	tag, hasTag := field.Tag.Lookup("gom")
	if hasTag {
		if strings.EqualFold(tag, "-") || len(tag) == 0 {
			return "", -1
		} else if len(tag) == 1 {
			tps := 0
			if strings.EqualFold(tag, "@") {
				tps = 2
			}
			if strings.EqualFold(tag, "!") {
				tps = 1
			}
			return strings.ToLower(field.Name), tps
		} else {
			if strings.Contains(tag, ",") {
				tags := strings.Split(tag, ",")
				if len(tags) == 2 {
					if strings.EqualFold(tags[0], "!") || strings.EqualFold(tags[0], "primary") {
						return tags[1], 1
					} else if strings.EqualFold(tags[0], "@") || strings.EqualFold(tags[0], "auto") {
						return tags[1], 2
					} else if strings.EqualFold(tags[0], "#") || strings.EqualFold(tags[0], "column") {
						return tags[1], 0
					} else {
						return "", -1
					}
				} else {
					return "", -1
				}
			} else {
				return tag, 0
			}
		}
	} else {
		return "", -1
	}
}
func getValueOfTableRow(model TableModel, row RowChooser) reflect.Value {
	maps := getBytesMap(model, row)
	ccs := model.Columns
	vv := reflect.New(model.ModelType)
	isStruct := model.ModelType.Kind() == reflect.Struct && model.ModelType != reflect.TypeOf(time.Time{})
	for _, c := range ccs {
		var dds interface{}
		dbytes := maps[c.ColumnName]
		data := string(dbytes)
		switch c.ColumnType.Kind() {
		case reflect.Uint:
			dds, _ = UIntfromString(data)
		case reflect.Uint16:
			dds, _ = UInt16fromString(data)
		case reflect.Uint32:
			dds, _ = UInt32fromString(data)
		case reflect.Uint64:
			dds, _ = UInt64fromString(data)
		case reflect.Int:
			dds, _ = IntfromString(data)
		case reflect.Int8:
			dds, _ = Int8fromString(data)
		case reflect.Int16:
			dds, _ = Int16fromString(data)
		case reflect.Int32:
			dds, _ = Int32fromString(data)
		case reflect.Int64:
			dds, _ = Int64fromString(data)
		case reflect.Float32:
			dds, _ = Float32fromString(data)
		case reflect.Float64:
			dds, _ = Float64fromString(data)
		case reflect.String:
			dds = data
		case reflect.TypeOf([]byte{}).Kind():
			dds = dbytes
		case reflect.TypeOf(time.Time{}).Kind():
			dds, _ = TimeFromString(data)
		default:
			dds = data
		}
		if isStruct {
			vv.Elem().FieldByName(c.FieldName).Set(reflect.ValueOf(dds))
		} else {
			vv.Elem().Set(reflect.ValueOf(dds))
		}
	}
	return vv
}
func getBytesMap(model TableModel, row RowChooser) map[string][]byte {

	data := make([][]byte, len(model.Columns))
	dest := make([]interface{}, len(model.Columns)) // A temporary interface{} slice
	for i, _ := range data {
		dest[i] = &data[i] // Put pointers to each string in the interface slice
	}
	err := row.Scan(dest...)
	if err != nil {
		return map[string][]byte{}
	}
	result := make(map[string][]byte, len(model.Columns))
	ccs := model.Columns
	for i, dd := range ccs {
		result[dd.ColumnName] = data[i]
	}
	return result

}
<commit_msg>优化项目结构<commit_after>package gom

import (
	"fmt"
	"reflect"
	"strings"
	"time"
)

func IsEmpty(v interface{}) bool {
	times := time.Time{}
	if times == v {
		return true
	}
	if v == "" {
		return true
	}
	if v == 0 {
		return true
	}
	if v == 0.0 {
		return true
	}
	if v == nil {
		return true
	}
	return false
}
func getType(v interface{}) (reflect.Type, bool, bool) {
	tt := reflect.TypeOf(v)
	isPtr := false
	islice := false
	if tt.Kind() == reflect.Ptr {
		tt = tt.Elem()
		isPtr = true
	}
	if tt.Kind() == reflect.Slice || tt.Kind() == reflect.Array {
		tt = tt.Elem()
		islice = true
	}
	if debug {
		fmt.Println("Test getType, result:", tt, isPtr, islice)
	}
	return tt, isPtr, islice
}
func getTableModels(vs ...interface{}) []TableModel {
	tablemodels := []TableModel{}
	for _, v := range vs {
		tablemodels = append(tablemodels, getTableModel(v))
	}
	return tablemodels
}
func GetTableModel(v interface{}, names ...string) TableModel {
	tm := getTableModel(v)
	var cc []Column
	for _, ct := range tm.Columns {
		for _, name := range names {
			if ct.ColumnName == name {
				cc = append(cc, ct)
			}
		}
	}
	tm.Columns = cc
	return tm

}
func CreateSingleValueTableModel(v interface{}, table string, field string) TableModel {
	tt, _, _ := getType(v)
	vals := reflect.New(tt).Elem()
	columns := []Column{{ColumnName: field, ColumnType: tt, IsPrimary: false, Auto: false}}
	return TableModel{Columns: columns, TableName: table, ModelType: tt, ModelValue: vals}
}
func getTableModel(v interface{}) TableModel {
	if v != nil && reflect.TypeOf(v).Kind() != reflect.Interface {
		tt, isPtr, isSlice := getType(v)
		vals := reflect.ValueOf(v)
		if isPtr {
			vals = vals.Elem()
		}
		if isSlice {
			vals = reflect.New(tt).Elem()
		}
		if tt.NumField() > 0 && tt.NumMethod() > 0 {
			nameMethod := vals.MethodByName("TableName")
			if debug {
				fmt.Println(nameMethod)
			}
			tableName := nameMethod.Call(nil)[0].String()
			columns, primary := getColumns(vals)
			ccs := []Column{primary}
			ccs = append(ccs, columns...)
			return TableModel{ModelType: tt, ModelValue: vals, Columns: ccs, TableName: tableName, Primary: primary}
		} else {
			return TableModel{}
		}
	} else {
		return TableModel{}
	}
}
func getColumns(v reflect.Value) ([]Column, Column) {
	var columns []Column
	var primary Column
	results := reflect.Indirect(reflect.ValueOf(&columns))
	oo := v.Type()
	i := 0
	for ; i < oo.NumField(); i++ {
		field := oo.Field(i)
		col, tps := getColumnFromField(field)
		if tps != -1 {
			if tps == 1 || tps == 2 {
				primary = col
			} else {
				n := reflect.Indirect(reflect.ValueOf(&col))
				if results.Kind() == reflect.Ptr {
					results.Set(reflect.Append(results, n.Addr()))
				} else {
					results.Set(reflect.Append(results, n))
				}
			}

		}
	}
	if debug {
		fmt.Println("columns is:", columns)
	}
	return columns, primary
}
func getColumnFromField(filed reflect.StructField) (Column, int) {
	tag, tps := getTagFromField(filed)
	if debug {
		fmt.Println("Tag is:", tag, "type is:", tps)
	}
	if tps != -1 {
		return Column{ColumnType: filed.Type, ColumnName: tag, FieldName: filed.Name, Auto: tps == 2, IsPrimary: tps == 1 || tps == 2}, tps
	} else {
		return Column{}, -1
	}

}
func getTagFromField(field reflect.StructField) (string, int) {
	tag, hasTag := field.Tag.Lookup("gom")
	if hasTag {
		if strings.EqualFold(tag, "-") || len(tag) == 0 {
			return "", -1
		} else if len(tag) == 1 {
			tps := 0
			if strings.EqualFold(tag, "@") {
				tps = 2
			}
			if strings.EqualFold(tag, "!") {
				tps = 1
			}
			return strings.ToLower(field.Name), tps
		} else {
			if strings.Contains(tag, ",") {
				tags := strings.Split(tag, ",")
				if len(tags) == 2 {
					if strings.EqualFold(tags[0], "!") || strings.EqualFold(tags[0], "primary") {
						return tags[1], 1
					} else if strings.EqualFold(tags[0], "@") || strings.EqualFold(tags[0], "auto") {
						return tags[1], 2
					} else if strings.EqualFold(tags[0], "#") || strings.EqualFold(tags[0], "column") {
						return tags[1], 0
					} else {
						return "", -1
					}
				} else {
					return "", -1
				}
			} else {
				return tag, 0
			}
		}
	} else {
		return "", -1
	}
}
func getValueOfTableRow(model TableModel, row RowChooser) reflect.Value {
	maps := getBytesMap(model, row)
	ccs := model.Columns
	vv := reflect.New(model.ModelType)
	isStruct := model.ModelType.Kind() == reflect.Struct && model.ModelType != reflect.TypeOf(time.Time{})
	for _, c := range ccs {
		var dds interface{}
		dbytes := maps[c.ColumnName]
		data := string(dbytes)
		switch c.ColumnType.Kind() {
		case reflect.Uint:
			dds, _ = UIntfromString(data)
		case reflect.Uint16:
			dds, _ = UInt16fromString(data)
		case reflect.Uint32:
			dds, _ = UInt32fromString(data)
		case reflect.Uint64:
			dds, _ = UInt64fromString(data)
		case reflect.Int:
			dds, _ = IntfromString(data)
		case reflect.Int8:
			dds, _ = Int8fromString(data)
		case reflect.Int16:
			dds, _ = Int16fromString(data)
		case reflect.Int32:
			dds, _ = Int32fromString(data)
		case reflect.Int64:
			dds, _ = Int64fromString(data)
		case reflect.Float32:
			dds, _ = Float32fromString(data)
		case reflect.Float64:
			dds, _ = Float64fromString(data)
		case reflect.String:
			dds = data
		case reflect.TypeOf([]byte{}).Kind():
			dds = dbytes
		case reflect.TypeOf(time.Time{}).Kind():
			dds, _ = TimeFromString(data)
		default:
			dds = data
		}
		if isStruct {
			vv.Elem().FieldByName(c.FieldName).Set(reflect.ValueOf(dds))
		} else {
			vv.Elem().Set(reflect.ValueOf(dds))
		}
	}
	return vv
}
func getBytesMap(model TableModel, row RowChooser) map[string][]byte {

	data := make([][]byte, len(model.Columns))
	dest := make([]interface{}, len(model.Columns)) // A temporary interface{} slice
	for i, _ := range data {
		dest[i] = &data[i] // Put pointers to each string in the interface slice
	}
	err := row.Scan(dest...)
	if err != nil {
		return map[string][]byte{}
	}
	result := make(map[string][]byte, len(model.Columns))
	ccs := model.Columns
	for i, dd := range ccs {
		result[dd.ColumnName] = data[i]
	}
	return result

}
<|endoftext|>


<commit_before>package main

import (
	"koding/artifact"
	"koding/kites/common"
	"koding/kites/terraformer"

	"github.com/koding/kite"
	kiteconfig "github.com/koding/kite/config"
	"github.com/koding/metrics"
	"github.com/koding/multiconfig"
)

var (
	Name    = "terraformer"
	Version = "0.0.1"
)

func main() {
	conf := &terraformer.Config{}

	// Load the config, it's reads environment variables or from flags
	multiconfig.New().MustLoad(conf)

	k := newKite(conf)

	if conf.Debug {
		k.Log.Info("Debug mode enabled")
	}

	registerURL := k.RegisterURL(true)

	if err := k.RegisterForever(registerURL); err != nil {
		k.Log.Fatal(err.Error())
	}

	k.Run()
}

func newKite(conf *terraformer.Config) *kite.Kite {
	k := kite.New(Name, Version)
	k.Config = kiteconfig.MustGet()
	k.Config.Port = conf.Port

	if conf.Region != "" {
		k.Config.Region = conf.Region
	}

	if conf.Environment != "" {
		k.Config.Environment = conf.Environment
	}

	stats := common.MustInitMetrics(Name)

	t := terraformer.New()
	t.Metrics = stats
	t.Log = common.NewLogger(Name, conf.Debug)

	// track every kind of call
	k.PreHandleFunc(createTracker(stats))

	// Terraformer handling methods
	k.HandleFunc("apply", t.Apply)
	k.HandleFunc("destroy", t.Destroy)
	k.HandleFunc("plan", t.Plan)

	k.HandleHTTPFunc("/healthCheck", artifact.HealthCheckHandler(Name))
	k.HandleHTTPFunc("/version", artifact.VersionHandler())

	return k
}

func createTracker(metrics *metrics.DogStatsD) kite.HandlerFunc {
	return func(r *kite.Request) (interface{}, error) {
		metrics.Count(
			"functionCallCount", // metric name
			1,                   // count
			[]string{"funcName:" + r.Method}, // tags for metric call
			1.0, // rate
		)

		return true, nil
	}
}
<commit_msg>Terraformer: fix doc and assign debug parameter<commit_after>package main

import (
	"koding/artifact"
	"koding/kites/common"
	"koding/kites/terraformer"

	"github.com/koding/kite"
	kiteconfig "github.com/koding/kite/config"
	"github.com/koding/metrics"
	"github.com/koding/multiconfig"
)

var (
	Name    = "terraformer"
	Version = "0.0.1"
)

func main() {
	conf := &terraformer.Config{}

	// Load the config, reads environment variables or from flags
	multiconfig.New().MustLoad(conf)

	k := newKite(conf)

	if conf.Debug {
		k.Log.Info("Debug mode enabled")
	}

	registerURL := k.RegisterURL(true)

	if err := k.RegisterForever(registerURL); err != nil {
		k.Log.Fatal(err.Error())
	}

	k.Run()
}

func newKite(conf *terraformer.Config) *kite.Kite {
	k := kite.New(Name, Version)
	k.Config = kiteconfig.MustGet()
	k.Config.Port = conf.Port

	if conf.Region != "" {
		k.Config.Region = conf.Region
	}

	if conf.Environment != "" {
		k.Config.Environment = conf.Environment
	}

	stats := common.MustInitMetrics(Name)

	t := terraformer.New()
	t.Metrics = stats
	t.Log = common.NewLogger(Name, conf.Debug)
	t.Debug = conf.Debug

	// track every kind of call
	k.PreHandleFunc(createTracker(stats))

	// Terraformer handling methods
	k.HandleFunc("apply", t.Apply)
	k.HandleFunc("destroy", t.Destroy)
	k.HandleFunc("plan", t.Plan)

	k.HandleHTTPFunc("/healthCheck", artifact.HealthCheckHandler(Name))
	k.HandleHTTPFunc("/version", artifact.VersionHandler())

	return k
}

func createTracker(metrics *metrics.DogStatsD) kite.HandlerFunc {
	return func(r *kite.Request) (interface{}, error) {
		metrics.Count(
			"functionCallCount", // metric name
			1,                   // count
			[]string{"funcName:" + r.Method}, // tags for metric call
			1.0, // rate
		)

		return true, nil
	}
}
<|endoftext|>


<commit_before>package yiigo

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// X is a convenient alias for a map[string]interface{} map
type X map[string]interface{}

/**
 * ReturnSuccess API返回成功
 * @param data ...interface{} 返回的数据
 */
func ReturnSuccess(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"code": 0,
		"msg":  "success",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

/**
 * ReturnFailed API返回失败
 * @param data ...interface{} 返回的数据
 */
func ReturnFailed(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"code": -1,
		"msg":  "failed",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

/**
 * ReturnJson API返回JSON数据
 * @param c *gin.Context
 * @param code int 返回的 Code
 * @param msg string 返回的 Message
 * @param data ...interface{} 返回的数据
 */
func ReturnJson(c *gin.Context, code int, msg string, data ...interface{}) {
	obj := gin.H{
		"code": code,
		"msg":  msg,
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}
<commit_msg>update<commit_after>package yiigo

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// X is a convenient alias for a map[string]interface{} map
type X map[string]interface{}

// IsXhr 判断是否为Ajax请求
func IsXhr(c *gin.Context) bool {
	x := c.Request.Header.Get("X-Requested-With")

	if x == "XMLHttpRequest" {
		return true
	}

	return false
}

// ReturnSuccess API返回成功
func ReturnSuccess(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"code": 0,
		"msg":  "success",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

// ReturnFailed API返回失败
func ReturnFailed(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"code": -1,
		"msg":  "failed",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

// ReturnJSON API返回JSON数据
func ReturnJSON(c *gin.Context, code int, msg string, data ...interface{}) {
	obj := gin.H{
		"code": code,
		"msg":  msg,
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}
<|endoftext|>


<commit_before>package yiigo

import (
	"crypto/md5"
	"fmt"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// X is a convenient alias for a map[string]interface{}.
type X map[string]interface{}

// MD5 calculate the md5 hash of a string.
func MD5(s string) string {
	h := md5.New()
	h.Write([]byte(s))

	return fmt.Sprintf("%x", h.Sum(nil))
}

// Date format a local time/date and
// returns a string formatted according to the given format string using the given timestamp of int64.
// The default format is: 2006-01-02 15:04:05.
func Date(timestamp int64, format ...string) string {
	layout := "2006-01-02 15:04:05"

	if len(format) > 0 {
		layout = format[0]
	}

	date := time.Unix(timestamp, 0).Format(layout)

	return date
}

// IsXhr checks if a request is xml-http-request (ajax).
func IsXhr(c *gin.Context) bool {
	x := c.Request.Header.Get("X-Requested-With")

	if strings.ToLower(x) == "xmlhttprequest" {
		return true
	}

	return false
}

// RemoteIP returns the IP of remote client，eg: 127.0.0.1.
func RemoteIP(c *gin.Context) string {
	if remoteAddr := c.Request.Header.Get("X-Forwarded-For"); remoteAddr != "" {
		ips := strings.Split(remoteAddr, ",")

		for _, v := range ips {
			if ip := strings.TrimSpace(v); ip != "unknown" {
				return ip
			}
		}
	}

	if remoteAddr := c.Request.Header.Get("X-Real-IP"); remoteAddr != "" {
		ip := strings.TrimSpace(remoteAddr)

		return ip
	}

	if remoteAddr := c.Request.Header.Get("Http-Client-IP"); remoteAddr != "" {
		ip := strings.TrimSpace(remoteAddr)

		return ip
	}

	ip, _, err := net.SplitHostPort(c.Request.RemoteAddr)

	if err != nil {
		return "unknown"
	}

	if ip == "::1" {
		ip = "127.0.0.1"
	}

	return ip
}

// IP2long converts a string containing an (IPv4) Internet Protocol dotted address into a long integer
func IP2long(ip string) int64 {
	ipv4 := net.ParseIP(ip).To4()

	if ipv4 == nil {
		return 0
	}

	ret := big.NewInt(0)
	ret.SetBytes(ipv4)

	return ret.Int64()
}

// Long2IP converts an long integer address into a string in (IPv4) Internet standard dotted format
func Long2IP(ip int64) string {
	ipv4 := fmt.Sprintf("%d.%d.%d.%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))

	return ipv4
}

// OK returns success of an API.
func OK(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"success": true,
		"code":    0,
		"msg":     "success",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

// Error returns error of an API.
func Error(c *gin.Context, code int, msg ...string) {
	obj := gin.H{
		"success": false,
		"code":    code,
		"msg":     "something wrong",
	}

	if len(msg) > 0 {
		obj["msg"] = msg[0]
	}

	c.JSON(http.StatusOK, obj)
}
<commit_msg>update<commit_after>package yiigo

import (
	"crypto/md5"
	"fmt"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// X is a convenient alias for a map[string]interface{}.
type X map[string]interface{}

// MD5 calculate the md5 hash of a string.
func MD5(s string) string {
	h := md5.New()
	h.Write([]byte(s))

	return fmt.Sprintf("%x", h.Sum(nil))
}

// Date format a local time/date and
// returns a string formatted according to the given format string using the given timestamp of int64.
// The default format is: 2006-01-02 15:04:05.
func Date(timestamp int64, format ...string) string {
	layout := "2006-01-02 15:04:05"

	if len(format) > 0 {
		layout = format[0]
	}

	date := time.Unix(timestamp, 0).Format(layout)

	return date
}

// IsXhr checks if a request is xml-http-request (ajax).
func IsXhr(c *gin.Context) bool {
	x := c.Request.Header.Get("X-Requested-With")

	if strings.ToLower(x) == "xmlhttprequest" {
		return true
	}

	return false
}

// IP2long converts a string containing an (IPv4) Internet Protocol dotted address into a long integer
func IP2long(ip string) int64 {
	ipv4 := net.ParseIP(ip).To4()

	if ipv4 == nil {
		return 0
	}

	ret := big.NewInt(0)
	ret.SetBytes(ipv4)

	return ret.Int64()
}

// Long2IP converts an long integer address into a string in (IPv4) Internet standard dotted format
func Long2IP(ip int64) string {
	ipv4 := fmt.Sprintf("%d.%d.%d.%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))

	return ipv4
}

// OK returns success of an API.
func OK(c *gin.Context, data ...interface{}) {
	obj := gin.H{
		"success": true,
		"code":    0,
		"msg":     "success",
	}

	if len(data) > 0 {
		obj["data"] = data[0]
	}

	c.JSON(http.StatusOK, obj)
}

// Err returns error of an API.
func Err(c *gin.Context, code int, msg ...string) {
	obj := gin.H{
		"success": false,
		"code":    code,
		"msg":     "something wrong",
	}

	if len(msg) > 0 {
		obj["msg"] = msg[0]
	}

	c.JSON(http.StatusOK, obj)
}
<|endoftext|>


<commit_before>package web

import (
	"log"
	"mime"
	"net/http"
	"os"
	"strings"
)

// newContext return a web.Context
func newContext(w http.ResponseWriter, r *http.Request, params *Params) *Context {

	ctx := &Context{
		ResponseWriter: w,
		Request:        r,
		params:         params,
	}

	return ctx
}

func contentType(val string) string {
	var ctype string

	if strings.ContainsRune(val, '/') {
		ctype = val
	} else {
		if !strings.HasPrefix(val, ".") {
			val = "." + val
		}
		ctype = mime.TypeByExtension(val)
	}

	return ctype
}

func logf(format string, v ...interface{}) {
	log.Printf(format, v...)
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)
	if err != nil {
		return false
	}

	return !info.IsDir()
}
<commit_msg>removed fileExists<commit_after>package web

import (
	"log"
	"mime"
	"net/http"
	"strings"
)

// newContext return a web.Context
func newContext(w http.ResponseWriter, r *http.Request, params *Params) *Context {

	ctx := &Context{
		ResponseWriter: w,
		Request:        r,
		params:         params,
	}

	return ctx
}

func contentType(val string) string {
	var ctype string

	if strings.ContainsRune(val, '/') {
		ctype = val
	} else {
		if !strings.HasPrefix(val, ".") {
			val = "." + val
		}
		ctype = mime.TypeByExtension(val)
	}

	return ctype
}

func logf(format string, v ...interface{}) {
	log.Printf(format, v...)
}
<|endoftext|>


<commit_before>package api_v1

import (
	"errors"
	"fmt"
	"math/rand"
	"scal/settings"
	. "scal/user_lib"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	. "github.com/ilius/ripo"
	"golang.org/x/crypto/bcrypt"
)

const TOKEN_CONTEXT = "user"

const PASSWORD_HASH_COST = 14

var (
	errTokenNotFound       = errors.New("JWT Authorization token not found")
	errTokenBadFormat      = errors.New("JWT Authorization header format must be 'Bearer {token}'")
	errTokenInvalid        = errors.New("JWT token is invalid")
	errClaimsNotFound      = errors.New("JWT claims not found")
	errClaimsEmailNotFound = errors.New("Email not found in JWT claims")
)

func TokenFromHeader(authHeader string) (*jwt.Token, error) {
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
		return nil, errTokenBadFormat
	}
	tokenStr := authHeaderParts[1]
	if tokenStr == "" {
		return nil, errTokenNotFound
	}

	token, err := jwt.Parse(
		tokenStr,
		func(token *jwt.Token) (interface{}, error) {
			return []byte(settings.JWT_TOKEN_SECRET), nil
		},
	)
	if err != nil {
		return nil, fmt.Errorf("Error parsing token: %v", err)
	}

	expectedAlg := settings.JWT_ALG
	tokenAlg := token.Header["alg"]
	if expectedAlg != tokenAlg {
		return nil, fmt.Errorf(
			"Expected %s signing method but token specified %s",
			expectedAlg,
			tokenAlg,
		)
	}

	if !token.Valid {
		return nil, errTokenInvalid
	}

	return token, nil
}

func randomSleep(maxSeconds int) {
	maxMS := 1000 * maxSeconds
	minMS := maxMS / 2
	time.Sleep(time.Duration(minMS+rand.Intn(maxMS-minMS)) * time.Millisecond)
}

func AuthError(err error) RPCError {
	randomSleep(4)
	return NewError(Unauthenticated, "", err)
}

func ForbiddenError(publicMsg string, err error) RPCError {
	randomSleep(4)
	return NewError(PermissionDenied, publicMsg, err)
}

func CheckAuth(req Request) (*UserModel, error) {
	authHeader := req.Header("Authorization")
	if authHeader == "" {
		return nil, AuthError(errTokenNotFound)
	}
	token, err := TokenFromHeader(authHeader)
	if err != nil {
		return nil, AuthError(err)
	}
	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return nil, NewError(Internal, "", errClaimsNotFound)
	}
	emailI, ok := claims["email"]
	if !ok {
		return nil, AuthError(fmt.Errorf("Error parsing token: Missing 'email'"))
	}
	email, ok := emailI.(string)
	if !ok {
		return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'email'"))
	}
	if email == "" {
		return nil, AuthError(fmt.Errorf("Error parsing token: Empty 'email'"))
	}
	userModel := UserModelByEmail(email, globalDb)
	if userModel == nil {
		//SetHttpErrorUserNotFound(w, email) // FIXME
		return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'email'"))
	}
	if userModel.Locked {
		return nil, ForbiddenError("user is locked", nil)
	}
	if userModel.LastLogoutTime != nil {
		issuedAtI, ok := claims["iat"]
		if !ok {
			return nil, AuthError(fmt.Errorf("Error parsing token: Missing 'iat'"))
		}
		issuedAt, err := time.Parse(time.RFC3339, issuedAtI.(string))
		if err != nil {
			return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'iat'"))
		}
		if userModel.LastLogoutTime.After(issuedAt) {
			return nil, AuthError(fmt.Errorf("Error parsing token: Token is expired"))
		}
	}
	return userModel, nil
}

/*
NEW:
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email

OLD:
	userModel := CheckAuthGetUserModel(w, r)
	if userModel == nil {
		return
	}
	email := userModel.Email

VERY OLD:
	ok, email := CheckAuthGetEmail(w, r)
	if !ok {
		return
	}
*/

func EmailIsAdmin(email string) bool {
	for _, adminEmail := range settings.ADMIN_EMAILS {
		if email == adminEmail {
			return true
		}
	}
	return false
}

func AdminCheckAuth(req Request) (*UserModel, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	if !EmailIsAdmin(userModel.Email) {
		return nil, NewError(PermissionDenied, "you are not admin", nil)
	}
	if !userModel.EmailConfirmed {
		return nil, NewError(PermissionDenied, "email is not confirmed", nil)
	}
	return userModel, nil
}

func GetPasswordHash(email string, password string) (string, error) {
	pwHash, err := bcrypt.GenerateFromPassword(
		[]byte(
			fmt.Sprintf(
				"%s:%s:%s",
				email,
				settings.PASSWORD_SALT,
				password,
			),
		),
		PASSWORD_HASH_COST,
	)
	return string(pwHash), err
}

func CheckPasswordHash(email string, password string, pwHash string) bool {
	err := bcrypt.CompareHashAndPassword(
		[]byte(pwHash),
		[]byte(
			fmt.Sprintf(
				"%s:%s:%s",
				email,
				settings.PASSWORD_SALT,
				password,
			),
		),
	)
	return err == nil
}

func NewSignedToken(userModel *UserModel) string {
	now := time.Now()
	exp := now.Add(settings.JWT_TOKEN_EXP_SECONDS * time.Second)
	token := jwt.NewWithClaims(
		jwt.GetSigningMethod(settings.JWT_ALG),
		jwt.MapClaims{
			"email": userModel.Email,
			"iat":   now.Unix(),
			"exp":   exp.Unix(),
		},
		// jwt.StandardClaims {
		// 	//ExpiresAt: exp.Unix(),
		// 	Issuer:	settings.HOST, // add ":port" too? FIXME
		// },
	)

	// Signs the token with a secret.
	signedToken, _ := token.SignedString([]byte(
		settings.JWT_TOKEN_SECRET,
	))
	return signedToken
}
<commit_msg>fix panic in CheckAuth after logout (when LastLogoutTime is set)<commit_after>package api_v1

import (
	"errors"
	"fmt"
	"math/rand"
	"scal/settings"
	. "scal/user_lib"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	. "github.com/ilius/ripo"
	"golang.org/x/crypto/bcrypt"
)

const TOKEN_CONTEXT = "user"

const PASSWORD_HASH_COST = 14

var (
	errTokenNotFound       = errors.New("JWT Authorization token not found")
	errTokenBadFormat      = errors.New("JWT Authorization header format must be 'Bearer {token}'")
	errTokenInvalid        = errors.New("JWT token is invalid")
	errClaimsNotFound      = errors.New("JWT claims not found")
	errClaimsEmailNotFound = errors.New("Email not found in JWT claims")
)

func TokenFromHeader(authHeader string) (*jwt.Token, error) {
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
		return nil, errTokenBadFormat
	}
	tokenStr := authHeaderParts[1]
	if tokenStr == "" {
		return nil, errTokenNotFound
	}

	token, err := jwt.Parse(
		tokenStr,
		func(token *jwt.Token) (interface{}, error) {
			return []byte(settings.JWT_TOKEN_SECRET), nil
		},
	)
	if err != nil {
		return nil, fmt.Errorf("Error parsing token: %v", err)
	}

	expectedAlg := settings.JWT_ALG
	tokenAlg := token.Header["alg"]
	if expectedAlg != tokenAlg {
		return nil, fmt.Errorf(
			"Expected %s signing method but token specified %s",
			expectedAlg,
			tokenAlg,
		)
	}

	if !token.Valid {
		return nil, errTokenInvalid
	}

	return token, nil
}

func randomSleep(maxSeconds int) {
	maxMS := 1000 * maxSeconds
	minMS := maxMS / 2
	time.Sleep(time.Duration(minMS+rand.Intn(maxMS-minMS)) * time.Millisecond)
}

func AuthError(err error) RPCError {
	randomSleep(4)
	return NewError(Unauthenticated, "", err)
}

func ForbiddenError(publicMsg string, err error) RPCError {
	randomSleep(4)
	return NewError(PermissionDenied, publicMsg, err)
}

func CheckAuth(req Request) (*UserModel, error) {
	authHeader := req.Header("Authorization")
	if authHeader == "" {
		return nil, AuthError(errTokenNotFound)
	}
	token, err := TokenFromHeader(authHeader)
	if err != nil {
		return nil, AuthError(err)
	}
	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return nil, NewError(Internal, "", errClaimsNotFound)
	}
	emailI, ok := claims["email"]
	if !ok {
		return nil, AuthError(fmt.Errorf("Error parsing token: Missing 'email'"))
	}
	email, ok := emailI.(string)
	if !ok {
		return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'email'"))
	}
	if email == "" {
		return nil, AuthError(fmt.Errorf("Error parsing token: Empty 'email'"))
	}
	userModel := UserModelByEmail(email, globalDb)
	if userModel == nil {
		//SetHttpErrorUserNotFound(w, email) // FIXME
		return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'email'"))
	}
	if userModel.Locked {
		return nil, ForbiddenError("user is locked", nil)
	}
	if userModel.LastLogoutTime != nil {
		issuedAtI, ok := claims["iat"]
		if !ok {
			return nil, AuthError(fmt.Errorf("Error parsing token: Missing 'iat'"))
		}
		issuedAtFloat, ok := issuedAtI.(float64)
		if !ok {
			return nil, AuthError(fmt.Errorf("Error parsing token: Bad 'iat'"))
		}
		issuedAt := time.Unix(int64(issuedAtFloat), 0)
		if userModel.LastLogoutTime.After(issuedAt) {
			return nil, AuthError(fmt.Errorf("Error parsing token: Token is expired"))
		}
	}
	return userModel, nil
}

/*
NEW:
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	email := userModel.Email

OLD:
	userModel := CheckAuthGetUserModel(w, r)
	if userModel == nil {
		return
	}
	email := userModel.Email

VERY OLD:
	ok, email := CheckAuthGetEmail(w, r)
	if !ok {
		return
	}
*/

func EmailIsAdmin(email string) bool {
	for _, adminEmail := range settings.ADMIN_EMAILS {
		if email == adminEmail {
			return true
		}
	}
	return false
}

func AdminCheckAuth(req Request) (*UserModel, error) {
	userModel, err := CheckAuth(req)
	if err != nil {
		return nil, err
	}
	if !EmailIsAdmin(userModel.Email) {
		return nil, NewError(PermissionDenied, "you are not admin", nil)
	}
	if !userModel.EmailConfirmed {
		return nil, NewError(PermissionDenied, "email is not confirmed", nil)
	}
	return userModel, nil
}

func GetPasswordHash(email string, password string) (string, error) {
	pwHash, err := bcrypt.GenerateFromPassword(
		[]byte(
			fmt.Sprintf(
				"%s:%s:%s",
				email,
				settings.PASSWORD_SALT,
				password,
			),
		),
		PASSWORD_HASH_COST,
	)
	return string(pwHash), err
}

func CheckPasswordHash(email string, password string, pwHash string) bool {
	err := bcrypt.CompareHashAndPassword(
		[]byte(pwHash),
		[]byte(
			fmt.Sprintf(
				"%s:%s:%s",
				email,
				settings.PASSWORD_SALT,
				password,
			),
		),
	)
	return err == nil
}

func NewSignedToken(userModel *UserModel) string {
	now := time.Now()
	exp := now.Add(settings.JWT_TOKEN_EXP_SECONDS * time.Second)
	token := jwt.NewWithClaims(
		jwt.GetSigningMethod(settings.JWT_ALG),
		jwt.MapClaims{
			"email": userModel.Email,
			"iat":   now.Unix(),
			"exp":   exp.Unix(),
		},
		// jwt.StandardClaims {
		// 	//ExpiresAt: exp.Unix(),
		// 	Issuer:	settings.HOST, // add ":port" too? FIXME
		// },
	)

	// Signs the token with a secret.
	signedToken, _ := token.SignedString([]byte(
		settings.JWT_TOKEN_SECRET,
	))
	return signedToken
}
<|endoftext|>


<commit_before>package main

import (
	"./db"
	"fmt"
	"math/rand"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	_FOLLOW     = iota
	_UNFOLLOW   = iota
	_FAVORITE   = iota
	_UNFAVORITE = iota
	_TWEET      = iota
	_REPLY      = iota
)

type Action struct {
	name   int
	weight int
}

func performDailyAction() {
	actions := make([]Action, 0, 5)

	actions = append(actions, Action{name: _FOLLOW, weight: ACTION_FOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFOLLOW, weight: ACTION_UNFOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _FAVORITE, weight: ACTION_FAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFAVORITE, weight: ACTION_UNFAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _TWEET, weight: ACTION_TWEET_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _REPLY, weight: ACTION_REPLY_WEIGHT * rand.Intn(100)})

	selectAndPerformAction(actions)
}

func performNightlyAction() {
	actions := make([]Action, 0, 5)

	actions = append(actions, Action{name: _FOLLOW, weight: ACTION_NIGHTLY_FOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFOLLOW, weight: ACTION_NIGHTLY_UNFOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _FAVORITE, weight: ACTION_NIGHTLY_FAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFAVORITE, weight: ACTION_NIGHTLY_UNFAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _TWEET, weight: ACTION_NIGHTLY_TWEET_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _REPLY, weight: ACTION_NIGHTLY_REPLY_WEIGHT * rand.Intn(100)})

	selectAndPerformAction(actions)
}

func selectAndPerformAction(actions []Action) {
	selectedAction := Action{name: -1, weight: -1}

	for _, action := range actions {
		if action.weight > selectedAction.weight {
			selectedAction = action
		}
	}

	switch selectedAction.name {
	case _FOLLOW:
		actionFollow()
		break
	case _UNFOLLOW:
		actionUnfollow()
		break
	case _FAVORITE:
		actionFavorite()
		break
	case _UNFAVORITE:
		actionUnfavorite()
		break
	case _TWEET:
		actionTweet()
		break
	case _REPLY:
		actionReply()
		break
	}
}

func actionFollow() {
	fmt.Println("Action follow")

	search, v := generateAPISearchValues(KEYWORDS[rand.Intn(len(KEYWORDS))])

	searchResult, err := api.GetSearch(search, v)
	if err != nil {
		fmt.Println("Error while querying twitter API", err)
		return
	}

	for _, tweet := range searchResult.Statuses {

		if !isUserAcceptable(tweet) {
			fmt.Println("Ignoring user for follow : @" + tweet.User.ScreenName)
			continue
		}

		if isMentionOrRT(tweet) {
			fmt.Println("Ignoring tweet for follow, mention or RT")
			continue
		}

		if isMe(tweet) {
			fmt.Println("Ignoring my own tweet for follow")
			continue
		}

		follow, err := db.AlreadyFollow(tweet.User.Id)
		if err == nil && !follow {

			err := db.Follow{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, Status: tweet.Text, FollowDate: time.Now()}.Persist()
			if err != nil {
				fmt.Println("Error while persisting follow", err)
				return
			}

			_, err = api.FollowUser(tweet.User.ScreenName)
			if err != nil {
				fmt.Println("Error while following user "+tweet.User.ScreenName+" : ", err)
			}

			fmt.Println("Now follow ", tweet.User.ScreenName)
			return
		}

	}
}

func actionUnfollow() {
	fmt.Println("Action unfollow")

	date := time.Now()
	duration, err := time.ParseDuration("-72h") // -3 days
	date = date.Add(duration)

	follows, err := db.GetNotUnfollowed(date, UNFOLLOW_LIMIT_IN_A_ROW)
	if err != nil {
		fmt.Println("Error while querying db to find people to unfollow", err)
		return
	}

	for _, follow := range follows {
		follow.LastAction = time.Now()

		isFollowing, err := isUserFollowing(follow.UserName)
		if err != nil {
			fmt.Println("Error while querying API for friendships", err)
			return
		}

		if isFollowing {
			err = follow.Persist()
			if err != nil {
				fmt.Println("Error while persisting follow", err)
				return
			}

			continue
		}

		follow.UnfollowDate = time.Now()

		err = follow.Persist()
		if err != nil {
			fmt.Println("Error while persisting follow", err)
			return
		}

		_, err = api.UnfollowUser(follow.UserName)
		if err != nil {
			fmt.Println("Error while querying API to unfollow @"+follow.UserName, err)
			return
		}

		fmt.Println("Unfollowed @" + follow.UserName)
	}
}

func actionFavorite() {
	fmt.Println("Action fav")

	search, v := generateAPISearchValues(KEYWORDS[rand.Intn(len(KEYWORDS))])

	searchResult, err := api.GetSearch(search, v)
	if err != nil {
		fmt.Println("Error while querying twitter API", err)
		return
	}

	i := 0
	for _, tweet := range searchResult.Statuses {
		if i >= FAV_LIMIT_IN_A_ROW {
			return
		}

		if !isUserAcceptable(tweet) {
			fmt.Println("Ignoring user for favorite : @" + tweet.User.ScreenName)
			continue
		}

		if isMentionOrRT(tweet) {
			fmt.Println("Ignoring tweet for favorite, mention or RT")
			continue
		}

		if isMe(tweet) {
			fmt.Println("Ignoring my own tweet for favorite")
			continue
		}

		follow, err := db.AlreadyFollow(tweet.User.Id)
		if err == nil && follow {
			fmt.Println("Ignoring tweet for favorite, already follow @" + tweet.User.ScreenName)
			continue
		}

		alreadyFav, err := db.HasAlreadyFav(tweet.Id)
		if err != nil {
			fmt.Println("Error while checking already fav", err)
			return
		}

		if alreadyFav {
			fmt.Println("Ignoring tweet for favorite, already fav tweet from @" + tweet.User.ScreenName)
			continue
		}

		err = db.Favorite{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, TweetId: tweet.Id, Status: tweet.Text, FavDate: time.Now()}.Persist()
		if err != nil {
			fmt.Println("Error while persisting fav", err)
			return
		}

		_, err = api.Favorite(tweet.Id)
		if err != nil {
			if strings.Contains(err.Error(), "139") { // Case of an already favorited tweet
				continue
			}

			fmt.Println("Error while favoriting tweet", err)
		} else {
			fmt.Println("Just favorited tweet : ", tweet.Text)
		}

		i++
	}
}

func actionUnfavorite() {
	fmt.Println("Action unfavorite")

	date := time.Now()
	duration, err := time.ParseDuration("-72h") // -3 days
	date = date.Add(duration)

	favs, err := db.GetNotUnfavorite(date, UNFAVORITE_LIMIT_IN_A_ROW)
	if err != nil {
		fmt.Println("Error while querying db to find tweet to unfav", err)
		return
	}

	for _, fav := range favs {
		fav.LastAction = time.Now()

		isFollowing, err := isUserFollowing(fav.UserName)
		if err != nil {
			fmt.Println("Error while querying API for friendships", err)
			return
		}

		if isFollowing {
			err = fav.Persist()
			if err != nil {
				fmt.Println("Error while persisting fav", err)
				return
			}

			continue
		}

		fav.UnfavDate = time.Now()

		err = fav.Persist()
		if err != nil {
			fmt.Println("Error while persisting fav", err)
			return
		}

		_, err = api.Unfavorite(fav.TweetId)
		if err != nil {
			fmt.Println("Error while querying API to unfav : "+fav.Status, err)
			return
		}

		fmt.Println("Unfaved @" + fav.Status)
	}
}

func actionTweet() {
	fmt.Println("Action tweet")

	hasReachLimit, err := hasReachDailyTweetLimit()
	if err != nil {
		fmt.Println("Error while getting daily limit reached", err)
		return
	}

	if hasReachLimit {
		fmt.Println("Day tweet limit reached, abording")
		return
	}

	content, err := generateTweetContent()
	if err != nil {
		fmt.Println("Error while getting tweet content : ", err)
		return
	}

	tweetText := content.text + " " + content.url + content.hashtags

	err = db.Tweet{Content: tweetText, Date: time.Now()}.Persist()
	if err != nil {
		fmt.Println("Error while persisting tweet", err)
		return
	}

	tweet, err := api.PostTweet(tweetText, nil)
	if err != nil {
		fmt.Println("Error while posting tweet", err)
		return
	}

	fmt.Println("Tweet posted : ", tweet.Text)
}

func actionReply() {
	fmt.Println("Action reply")

	tweets, err := api.GetMentionsTimeline(nil)
	if err != nil {
		fmt.Println("Error while querying twitter mention API", err)
		return
	}

	for _, tweet := range tweets {

		replied, err := db.HasAlreadyReplied(tweet.Id)
		if err == nil && !replied {
			fmt.Println("Building reply for tweet : " + tweet.Text)

			response, err := buildReply(tweet)
			if err != nil {
				fmt.Println("Error while building reply", err)
				return
			}

			err = db.Reply{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, TweetId: tweet.Id, Status: tweet.Text, Answer: response, ReplyDate: time.Now()}.Persist()
			if err != nil {
				fmt.Println("Error while persisting reply", err)
				return
			}

			if response != "" {
				v := url.Values{}
				v.Add("in_reply_to_status_id", strconv.FormatInt(tweet.Id, 10))

				respTweet, err := api.PostTweet(response, v)
				if err != nil {
					fmt.Println("Error while posting reply", err)
					return
				}

				fmt.Println("Reply posted : ", respTweet.Text)
			} else {
				fmt.Println("No response found for tweet : " + tweet.Text)
			}

			return
		}
	}

	fmt.Println("Nothing to reply found :(")
}
<commit_msg>Optim<commit_after>package main

import (
	"./db"
	"fmt"
	"math/rand"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	_FOLLOW     = iota
	_UNFOLLOW   = iota
	_FAVORITE   = iota
	_UNFAVORITE = iota
	_TWEET      = iota
	_REPLY      = iota
)

type Action struct {
	name   int
	weight int
}

func performDailyAction() {
	actions := make([]Action, 0, 6)

	actions = append(actions, Action{name: _FOLLOW, weight: ACTION_FOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFOLLOW, weight: ACTION_UNFOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _FAVORITE, weight: ACTION_FAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFAVORITE, weight: ACTION_UNFAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _TWEET, weight: ACTION_TWEET_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _REPLY, weight: ACTION_REPLY_WEIGHT * rand.Intn(100)})

	selectAndPerformAction(actions)
}

func performNightlyAction() {
	actions := make([]Action, 0, 6)

	actions = append(actions, Action{name: _FOLLOW, weight: ACTION_NIGHTLY_FOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFOLLOW, weight: ACTION_NIGHTLY_UNFOLLOW_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _FAVORITE, weight: ACTION_NIGHTLY_FAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _UNFAVORITE, weight: ACTION_NIGHTLY_UNFAVORITE_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _TWEET, weight: ACTION_NIGHTLY_TWEET_WEIGHT * rand.Intn(100)})
	actions = append(actions, Action{name: _REPLY, weight: ACTION_NIGHTLY_REPLY_WEIGHT * rand.Intn(100)})

	selectAndPerformAction(actions)
}

func selectAndPerformAction(actions []Action) {
	selectedAction := Action{name: -1, weight: -1}

	for _, action := range actions {
		if action.weight > selectedAction.weight {
			selectedAction = action
		}
	}

	switch selectedAction.name {
	case _FOLLOW:
		actionFollow()
		break
	case _UNFOLLOW:
		actionUnfollow()
		break
	case _FAVORITE:
		actionFavorite()
		break
	case _UNFAVORITE:
		actionUnfavorite()
		break
	case _TWEET:
		actionTweet()
		break
	case _REPLY:
		actionReply()
		break
	}
}

func actionFollow() {
	fmt.Println("Action follow")

	search, v := generateAPISearchValues(KEYWORDS[rand.Intn(len(KEYWORDS))])

	searchResult, err := api.GetSearch(search, v)
	if err != nil {
		fmt.Println("Error while querying twitter API", err)
		return
	}

	for _, tweet := range searchResult.Statuses {

		if !isUserAcceptable(tweet) {
			fmt.Println("Ignoring user for follow : @" + tweet.User.ScreenName)
			continue
		}

		if isMentionOrRT(tweet) {
			fmt.Println("Ignoring tweet for follow, mention or RT")
			continue
		}

		if isMe(tweet) {
			fmt.Println("Ignoring my own tweet for follow")
			continue
		}

		follow, err := db.AlreadyFollow(tweet.User.Id)
		if err == nil && !follow {

			err := db.Follow{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, Status: tweet.Text, FollowDate: time.Now()}.Persist()
			if err != nil {
				fmt.Println("Error while persisting follow", err)
				return
			}

			_, err = api.FollowUser(tweet.User.ScreenName)
			if err != nil {
				fmt.Println("Error while following user "+tweet.User.ScreenName+" : ", err)
			}

			fmt.Println("Now follow ", tweet.User.ScreenName)
			return
		}

	}
}

func actionUnfollow() {
	fmt.Println("Action unfollow")

	date := time.Now()
	duration, err := time.ParseDuration("-72h") // -3 days
	date = date.Add(duration)

	follows, err := db.GetNotUnfollowed(date, UNFOLLOW_LIMIT_IN_A_ROW)
	if err != nil {
		fmt.Println("Error while querying db to find people to unfollow", err)
		return
	}

	for _, follow := range follows {
		follow.LastAction = time.Now()

		isFollowing, err := isUserFollowing(follow.UserName)
		if err != nil {
			fmt.Println("Error while querying API for friendships", err)
			return
		}

		if isFollowing {
			err = follow.Persist()
			if err != nil {
				fmt.Println("Error while persisting follow", err)
				return
			}

			continue
		}

		follow.UnfollowDate = time.Now()

		err = follow.Persist()
		if err != nil {
			fmt.Println("Error while persisting follow", err)
			return
		}

		_, err = api.UnfollowUser(follow.UserName)
		if err != nil {
			fmt.Println("Error while querying API to unfollow @"+follow.UserName, err)
			return
		}

		fmt.Println("Unfollowed @" + follow.UserName)
	}
}

func actionFavorite() {
	fmt.Println("Action fav")

	search, v := generateAPISearchValues(KEYWORDS[rand.Intn(len(KEYWORDS))])

	searchResult, err := api.GetSearch(search, v)
	if err != nil {
		fmt.Println("Error while querying twitter API", err)
		return
	}

	i := 0
	for _, tweet := range searchResult.Statuses {
		if i >= FAV_LIMIT_IN_A_ROW {
			return
		}

		if !isUserAcceptable(tweet) {
			fmt.Println("Ignoring user for favorite : @" + tweet.User.ScreenName)
			continue
		}

		if isMentionOrRT(tweet) {
			fmt.Println("Ignoring tweet for favorite, mention or RT")
			continue
		}

		if isMe(tweet) {
			fmt.Println("Ignoring my own tweet for favorite")
			continue
		}

		follow, err := db.AlreadyFollow(tweet.User.Id)
		if err == nil && follow {
			fmt.Println("Ignoring tweet for favorite, already follow @" + tweet.User.ScreenName)
			continue
		}

		alreadyFav, err := db.HasAlreadyFav(tweet.Id)
		if err != nil {
			fmt.Println("Error while checking already fav", err)
			return
		}

		if alreadyFav {
			fmt.Println("Ignoring tweet for favorite, already fav tweet from @" + tweet.User.ScreenName)
			continue
		}

		err = db.Favorite{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, TweetId: tweet.Id, Status: tweet.Text, FavDate: time.Now()}.Persist()
		if err != nil {
			fmt.Println("Error while persisting fav", err)
			return
		}

		_, err = api.Favorite(tweet.Id)
		if err != nil {
			if strings.Contains(err.Error(), "139") { // Case of an already favorited tweet
				continue
			}

			fmt.Println("Error while favoriting tweet", err)
		} else {
			fmt.Println("Just favorited tweet : ", tweet.Text)
		}

		i++
	}
}

func actionUnfavorite() {
	fmt.Println("Action unfavorite")

	date := time.Now()
	duration, err := time.ParseDuration("-72h") // -3 days
	date = date.Add(duration)

	favs, err := db.GetNotUnfavorite(date, UNFAVORITE_LIMIT_IN_A_ROW)
	if err != nil {
		fmt.Println("Error while querying db to find tweet to unfav", err)
		return
	}

	for _, fav := range favs {
		fav.LastAction = time.Now()

		isFollowing, err := isUserFollowing(fav.UserName)
		if err != nil {
			fmt.Println("Error while querying API for friendships", err)
			return
		}

		if isFollowing {
			err = fav.Persist()
			if err != nil {
				fmt.Println("Error while persisting fav", err)
				return
			}

			continue
		}

		fav.UnfavDate = time.Now()

		err = fav.Persist()
		if err != nil {
			fmt.Println("Error while persisting fav", err)
			return
		}

		_, err = api.Unfavorite(fav.TweetId)
		if err != nil {
			fmt.Println("Error while querying API to unfav : "+fav.Status, err)
			return
		}

		fmt.Println("Unfaved @" + fav.Status)
	}
}

func actionTweet() {
	fmt.Println("Action tweet")

	hasReachLimit, err := hasReachDailyTweetLimit()
	if err != nil {
		fmt.Println("Error while getting daily limit reached", err)
		return
	}

	if hasReachLimit {
		fmt.Println("Day tweet limit reached, abording")
		return
	}

	content, err := generateTweetContent()
	if err != nil {
		fmt.Println("Error while getting tweet content : ", err)
		return
	}

	tweetText := content.text + " " + content.url + content.hashtags

	err = db.Tweet{Content: tweetText, Date: time.Now()}.Persist()
	if err != nil {
		fmt.Println("Error while persisting tweet", err)
		return
	}

	tweet, err := api.PostTweet(tweetText, nil)
	if err != nil {
		fmt.Println("Error while posting tweet", err)
		return
	}

	fmt.Println("Tweet posted : ", tweet.Text)
}

func actionReply() {
	fmt.Println("Action reply")

	tweets, err := api.GetMentionsTimeline(nil)
	if err != nil {
		fmt.Println("Error while querying twitter mention API", err)
		return
	}

	for _, tweet := range tweets {

		replied, err := db.HasAlreadyReplied(tweet.Id)
		if err == nil && !replied {
			fmt.Println("Building reply for tweet : " + tweet.Text)

			response, err := buildReply(tweet)
			if err != nil {
				fmt.Println("Error while building reply", err)
				return
			}

			err = db.Reply{UserId: tweet.User.Id, UserName: tweet.User.ScreenName, TweetId: tweet.Id, Status: tweet.Text, Answer: response, ReplyDate: time.Now()}.Persist()
			if err != nil {
				fmt.Println("Error while persisting reply", err)
				return
			}

			if response != "" {
				v := url.Values{}
				v.Add("in_reply_to_status_id", strconv.FormatInt(tweet.Id, 10))

				respTweet, err := api.PostTweet(response, v)
				if err != nil {
					fmt.Println("Error while posting reply", err)
					return
				}

				fmt.Println("Reply posted : ", respTweet.Text)
			} else {
				fmt.Println("No response found for tweet : " + tweet.Text)
			}

			return
		}
	}

	fmt.Println("Nothing to reply found :(")
}
<|endoftext|>


<commit_before>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/mail"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string
var netRcPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
	netRcPath = filepath.Join(os.Getenv("HOME"), ".netrc")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI                 string
	Branch              string
	PrivateKey          string
	Username            string
	Password            string
	File                string
	GitUser             string
	Depth               string
	CommitMessage       string
	SkipSSLVerification bool
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return semver.Version{}, err
	}

	err = driver.setUserInfo()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for i := 1; i <= maxRetries; i++ {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}
	if err != nil {
		return semver.Version{}, err
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpAuth()
	if err != nil {
		return err
	}

	err = driver.setUserInfo()
	if err != nil {
		return err
	}

	err = driver.skipSSLVerificationIfNeeded()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	err = driver.skipSSLVerificationIfNeeded()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GTE(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch)
		if len(driver.Depth) > 0 {
			gitClone.Args = append(gitClone.Args, "--depth", driver.Depth)
		}
		gitClone.Args = append(gitClone.Args, "--single-branch", gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) skipSSLVerificationIfNeeded() error {
	if driver.SkipSSLVerification {
		gitSkipSSLVerification := exec.Command("git", "config", "http.sslVerify", "'false'")
		gitSkipSSLVerification.Stdout = os.Stderr
		gitSkipSSLVerification.Stderr = os.Stderr
		if err := gitSkipSSLVerification.Run(); err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpAuth() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		err := os.Remove(netRcPath)
		if err != nil {
			return err
		}
	}

	if len(driver.PrivateKey) > 0 {
		err := driver.setUpKey()
		if err != nil {
			return err
		}
	}

	if len(driver.Username) > 0 && len(driver.Password) > 0 {
		err := driver.setUpUsernamePassword()
		if err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	if isPrivateKeyEncrypted(privateKeyPath) {
		return ErrEncryptedKey
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no -i "+privateKeyPath)
}

func isPrivateKeyEncrypted(path string) bool {
	passphrase := ``
	cmd := exec.Command(`ssh-keygen`, `-y`, `-f`, path, `-P`, passphrase)
	err := cmd.Run()

	return err != nil
}

func (driver *GitDriver) setUpUsernamePassword() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if os.IsNotExist(err) {
			content := fmt.Sprintf("default login %s password %s", driver.Username, driver.Password)
			err := ioutil.WriteFile(netRcPath, []byte(content), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUserInfo() error {
	if len(driver.GitUser) == 0 {
		return nil
	}

	e, err := mail.ParseAddress(driver.GitUser)
	if err != nil {
		return err
	}

	if len(e.Name) > 0 {
		gitName := exec.Command("git", "config", "--global", "user.name", e.Name)
		gitName.Stdout = os.Stderr
		gitName.Stderr = os.Stderr
		if err := gitName.Run(); err != nil {
			return err
		}
	}

	gitEmail := exec.Command("git", "config", "--global", "user.email", e.Address)
	gitEmail.Stdout = os.Stderr
	gitEmail.Stderr = os.Stderr
	if err := gitEmail.Run(); err != nil {
		return err
	}
	return nil
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}
	var commitMessage string
	if driver.CommitMessage == "" {
		commitMessage = "bump to " + newVersion.String()
	} else {
		commitMessage = strings.Replace(driver.CommitMessage, "%version%", newVersion.String(), -1)
		commitMessage = strings.Replace(commitMessage, "%file%", driver.File, -1)
	}

	gitCommit := exec.Command("git", "commit", "-m", commitMessage)
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRejectedString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<commit_msg>retry for 3 times<commit_after>package driver

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/mail"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/blang/semver"
	"github.com/concourse/semver-resource/version"
)

var gitRepoDir string
var privateKeyPath string
var netRcPath string

var ErrEncryptedKey = errors.New("private keys with passphrases are not supported")
var RetriesOnErrorWriteVersion = 3

func init() {
	gitRepoDir = filepath.Join(os.TempDir(), "semver-git-repo")
	privateKeyPath = filepath.Join(os.TempDir(), "private-key")
	netRcPath = filepath.Join(os.Getenv("HOME"), ".netrc")
}

type GitDriver struct {
	InitialVersion semver.Version

	URI                 string
	Branch              string
	PrivateKey          string
	Username            string
	Password            string
	File                string
	GitUser             string
	Depth               string
	CommitMessage       string
	SkipSSLVerification bool
}

func (driver *GitDriver) Bump(bump version.Bump) (semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return semver.Version{}, err
	}

	err = driver.setUserInfo()
	if err != nil {
		return semver.Version{}, err
	}

	var newVersion semver.Version

	for i := 1; i <= RetriesOnErrorWriteVersion; i++ {
		err = driver.setUpRepo()
		if err != nil {
			return semver.Version{}, err
		}

		currentVersion, exists, err := driver.readVersion()
		if err != nil {
			return semver.Version{}, err
		}

		if !exists {
			currentVersion = driver.InitialVersion
		}

		newVersion = bump.Apply(currentVersion)

		wrote, err := driver.writeVersion(newVersion)
		if wrote {
			break
		}
	}
	if err != nil {
		return semver.Version{}, err
	}

	return newVersion, nil
}

func (driver *GitDriver) Set(newVersion semver.Version) error {
	err := driver.setUpAuth()
	if err != nil {
		return err
	}

	err = driver.setUserInfo()
	if err != nil {
		return err
	}

	err = driver.skipSSLVerificationIfNeeded()
	if err != nil {
		return err
	}

	for {
		err = driver.setUpRepo()
		if err != nil {
			return err
		}

		wrote, err := driver.writeVersion(newVersion)
		if err != nil {
			return err
		}

		if wrote {
			break
		}
	}

	return nil
}

func (driver *GitDriver) Check(cursor *semver.Version) ([]semver.Version, error) {
	err := driver.setUpAuth()
	if err != nil {
		return nil, err
	}

	err = driver.setUpRepo()
	if err != nil {
		return nil, err
	}

	err = driver.skipSSLVerificationIfNeeded()
	if err != nil {
		return nil, err
	}

	currentVersion, exists, err := driver.readVersion()
	if err != nil {
		return nil, err
	}

	if !exists {
		return []semver.Version{driver.InitialVersion}, nil
	}

	if cursor == nil || currentVersion.GTE(*cursor) {
		return []semver.Version{currentVersion}, nil
	}

	return []semver.Version{}, nil
}

func (driver *GitDriver) setUpRepo() error {
	_, err := os.Stat(gitRepoDir)
	if err != nil {
		gitClone := exec.Command("git", "clone", driver.URI, "--branch", driver.Branch)
		if len(driver.Depth) > 0 {
			gitClone.Args = append(gitClone.Args, "--depth", driver.Depth)
		}
		gitClone.Args = append(gitClone.Args, "--single-branch", gitRepoDir)
		gitClone.Stdout = os.Stderr
		gitClone.Stderr = os.Stderr
		if err := gitClone.Run(); err != nil {
			return err
		}
	} else {
		gitFetch := exec.Command("git", "fetch", "origin", driver.Branch)
		gitFetch.Dir = gitRepoDir
		gitFetch.Stdout = os.Stderr
		gitFetch.Stderr = os.Stderr
		if err := gitFetch.Run(); err != nil {
			return err
		}
	}

	gitCheckout := exec.Command("git", "reset", "--hard", "origin/"+driver.Branch)
	gitCheckout.Dir = gitRepoDir
	gitCheckout.Stdout = os.Stderr
	gitCheckout.Stderr = os.Stderr
	if err := gitCheckout.Run(); err != nil {
		return err
	}

	return nil
}

func (driver *GitDriver) skipSSLVerificationIfNeeded() error {
	if driver.SkipSSLVerification {
		gitSkipSSLVerification := exec.Command("git", "config", "http.sslVerify", "'false'")
		gitSkipSSLVerification.Stdout = os.Stderr
		gitSkipSSLVerification.Stderr = os.Stderr
		if err := gitSkipSSLVerification.Run(); err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpAuth() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		err := os.Remove(netRcPath)
		if err != nil {
			return err
		}
	}

	if len(driver.PrivateKey) > 0 {
		err := driver.setUpKey()
		if err != nil {
			return err
		}
	}

	if len(driver.Username) > 0 && len(driver.Password) > 0 {
		err := driver.setUpUsernamePassword()
		if err != nil {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUpKey() error {
	_, err := os.Stat(privateKeyPath)
	if err != nil {
		if os.IsNotExist(err) {
			err := ioutil.WriteFile(privateKeyPath, []byte(driver.PrivateKey), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	if isPrivateKeyEncrypted(privateKeyPath) {
		return ErrEncryptedKey
	}

	return os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no -i "+privateKeyPath)
}

func isPrivateKeyEncrypted(path string) bool {
	passphrase := ``
	cmd := exec.Command(`ssh-keygen`, `-y`, `-f`, path, `-P`, passphrase)
	err := cmd.Run()

	return err != nil
}

func (driver *GitDriver) setUpUsernamePassword() error {
	_, err := os.Stat(netRcPath)
	if err != nil {
		if os.IsNotExist(err) {
			content := fmt.Sprintf("default login %s password %s", driver.Username, driver.Password)
			err := ioutil.WriteFile(netRcPath, []byte(content), 0600)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	return nil
}

func (driver *GitDriver) setUserInfo() error {
	if len(driver.GitUser) == 0 {
		return nil
	}

	e, err := mail.ParseAddress(driver.GitUser)
	if err != nil {
		return err
	}

	if len(e.Name) > 0 {
		gitName := exec.Command("git", "config", "--global", "user.name", e.Name)
		gitName.Stdout = os.Stderr
		gitName.Stderr = os.Stderr
		if err := gitName.Run(); err != nil {
			return err
		}
	}

	gitEmail := exec.Command("git", "config", "--global", "user.email", e.Address)
	gitEmail.Stdout = os.Stderr
	gitEmail.Stderr = os.Stderr
	if err := gitEmail.Run(); err != nil {
		return err
	}
	return nil
}

func (driver *GitDriver) readVersion() (semver.Version, bool, error) {
	var currentVersionStr string
	versionFile, err := os.Open(filepath.Join(gitRepoDir, driver.File))
	if err != nil {
		if os.IsNotExist(err) {
			return semver.Version{}, false, nil
		}

		return semver.Version{}, false, err
	}

	defer versionFile.Close()

	_, err = fmt.Fscanf(versionFile, "%s", &currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	currentVersion, err := semver.Parse(currentVersionStr)
	if err != nil {
		return semver.Version{}, false, err
	}

	return currentVersion, true, nil
}

const nothingToCommitString = "nothing to commit"
const falsePushString = "Everything up-to-date"
const pushRejectedString = "[rejected]"
const pushRemoteRejectedString = "[remote rejected]"

func (driver *GitDriver) writeVersion(newVersion semver.Version) (bool, error) {
	err := ioutil.WriteFile(filepath.Join(gitRepoDir, driver.File), []byte(newVersion.String()+"\n"), 0644)
	if err != nil {
		return false, err
	}

	gitAdd := exec.Command("git", "add", driver.File)
	gitAdd.Dir = gitRepoDir
	gitAdd.Stdout = os.Stderr
	gitAdd.Stderr = os.Stderr
	if err := gitAdd.Run(); err != nil {
		return false, err
	}
	var commitMessage string
	if driver.CommitMessage == "" {
		commitMessage = "bump to " + newVersion.String()
	} else {
		commitMessage = strings.Replace(driver.CommitMessage, "%version%", newVersion.String(), -1)
		commitMessage = strings.Replace(commitMessage, "%file%", driver.File, -1)
	}

	gitCommit := exec.Command("git", "commit", "-m", commitMessage)
	gitCommit.Dir = gitRepoDir

	commitOutput, err := gitCommit.CombinedOutput()

	if strings.Contains(string(commitOutput), nothingToCommitString) {
		return true, nil
	}

	if err != nil {
		os.Stderr.Write(commitOutput)
		return false, err
	}

	gitPush := exec.Command("git", "push", "origin", "HEAD:"+driver.Branch)
	gitPush.Dir = gitRepoDir

	pushOutput, err := gitPush.CombinedOutput()

	if strings.Contains(string(pushOutput), falsePushString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRejectedString) {
		return false, nil
	}

	if strings.Contains(string(pushOutput), pushRemoteRejectedString) {
		return false, nil
	}

	if err != nil {
		os.Stderr.Write(pushOutput)
		return false, err
	}

	return true, nil
}
<|endoftext|>


<commit_before>// Copyright 2019 The Oto Authors
//
// 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.

// +build darwin,ios
// +build !js

package oto

// #cgo LDFLAGS: -framework Foundation -framework AVFoundation
//
// #import <AudioToolbox/AudioToolbox.h>
import "C"

import (
	"fmt"
)

func componentSubType() C.OSType {
	return C.kAudioUnitSubType_RemoteIO
}
<commit_msg>ios: Bug fix: Build error<commit_after>// Copyright 2019 The Oto Authors
//
// 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.

// +build darwin,ios
// +build !js

package oto

// #cgo LDFLAGS: -framework Foundation -framework AVFoundation
//
// #import <AudioToolbox/AudioToolbox.h>
import "C"

func componentSubType() C.OSType {
	return C.kAudioUnitSubType_RemoteIO
}
<|endoftext|>


<commit_before>package testutils

import (
	"bytes"
	"errors"
	"io"
	"sync"
	"testing"
)

type WriteVerifier interface {
	io.Writer
	CheckDone()
}

type parallelWriteVerifier struct {
	name           string
	expectedWrites []string
	writeMatch     []bool
	t              *testing.T
	lock           *sync.RWMutex
}

func NewParallelWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
	return &parallelWriteVerifier{
		name:           name,
		expectedWrites: expectedWrites,
		writeMatch:     make([]bool, len(expectedWrites)),
		t:              t,
		lock:           &sync.RWMutex{},
	}
}

func (v *parallelWriteVerifier) CheckDone() {
	done := true
	for _, m := range v.writeMatch {
		if m == false {
			done = false
		}
	}
	if !done {
		v.t.Errorf("%s writer did not receive all expected writes.\n%#v\n%#v", v.name, v.expectedWrites, v.writeMatch)
	}
}

func (v *parallelWriteVerifier) Write(p []byte) (int, error) {
	v.lock.Lock()
	defer v.lock.Unlock()

	for i, e := range v.expectedWrites {
		if e == string(p) && v.writeMatch[i] == false {
			v.writeMatch[i] = true

			if string(p) == "Fail this write" {
				return -1, errors.New("I was told to fail this!")
			}
			return len(p), nil
		}
	}
	v.t.Errorf("%s writer received unexpected write: \"%s\"\n%#v\n%#v", v.name, p, v.expectedWrites, v.writeMatch)
	return len(p), nil
}

type sequentialWriteVerifier struct {
	name           string
	expectedWrites []string
	currentIndex   int
	t              *testing.T
}

func NewSequentialWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
	return &sequentialWriteVerifier{
		name:           name,
		expectedWrites: expectedWrites,
		currentIndex:   0,
		t:              t,
	}
}

func (s *sequentialWriteVerifier) CheckDone() {
	if s.currentIndex != len(s.expectedWrites) {
		s.t.Errorf("%s writer did not receive all expected writes.", s.name)
	}
}

func (s *sequentialWriteVerifier) Write(p []byte) (int, error) {
	if s.currentIndex >= len(s.expectedWrites) {
		s.t.Errorf("%s writer was not expecting a write but received \"%s\"", s.name, p)
		return len(p), nil
	}
	if !bytes.Equal(p, []byte(s.expectedWrites[s.currentIndex])) {
		s.t.Errorf("%s writer at index %d expected \"%s\" but received \"%s\"", s.name, s.currentIndex, s.expectedWrites[s.currentIndex], p)
	}
	s.currentIndex++
	if string(p) == "Fail this write" {
		return -1, errors.New("I was told to fail this!")
	}
	return len(p), nil
}
<commit_msg>Better documentation + FailWrite string<commit_after>package testutils

import (
	"bytes"
	"errors"
	"sync"
	"testing"
)

const (
	// FailWrite is the string that should be sent to a WriteVerfier to test
	// Write failures. This string will cause Write calls to return -1,
	// errors.New("I was told to fail this!")
	FailWrite = "Fail this write!"
)

// WriteVerifier functions as an io.Writer allowing users to test code that should
// write to an io.Writer interface. It calls it's testing.T instance's Error
// on unexpected writes and then the user can call CheckDone to verify all expected
// writes did indeed take place
type WriteVerifier interface {
	// Write emulates the Write method of io.Writers but instead compares it
	// against an internal set of expected writes. If the write does not match an
	// expected write that has yet to take place it will call testing.T.Error
	Write(p []byte) (n int, err error)

	// CheckDone should be called after all writes to the write should have
	// completed. The object then validates that all expected writes were received,
	// calling the Error method in the testing.T instance if any were missed.
	CheckDone()
}

type parallelWriteVerifier struct {
	name           string
	expectedWrites []string
	writeMatch     []bool
	t              *testing.T
	lock           *sync.RWMutex
}

// NewParallelWV creates a concurrency enabled WriteVerifier for testing code that
// concurrently writes to io.Writers
func NewParallelWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
	return &parallelWriteVerifier{
		name:           name,
		expectedWrites: expectedWrites,
		writeMatch:     make([]bool, len(expectedWrites)),
		t:              t,
		lock:           &sync.RWMutex{},
	}
}

// CheckDone should be called after all writes to the write should have
// completed. The object then validates that all expected writes were received,
// calling the Error method in the testing.T instance if any were missed.
func (v *parallelWriteVerifier) CheckDone() {
	done := true
	for _, m := range v.writeMatch {
		if m == false {
			done = false
		}
	}
	if !done {
		v.t.Errorf("%s writer did not receive all expected writes.\n%#v\n%#v", v.name, v.expectedWrites, v.writeMatch)
	}
}

// Write emulates the Write method of io.Writers but instead compares it
// against an internal set of expected writes. If the write does not match an
// expected write that has yet to take place it will call testing.T.Error
func (v *parallelWriteVerifier) Write(p []byte) (int, error) {
	v.lock.Lock()
	defer v.lock.Unlock()

	for i, e := range v.expectedWrites {
		if e == string(p) && v.writeMatch[i] == false {
			v.writeMatch[i] = true

			if bytes.Equal(p, []byte(FailWrite)) {
				return -1, errors.New("I was told to fail this!")
			}
			return len(p), nil
		}
	}
	v.t.Errorf("%s writer received unexpected write: \"%s\"\n%#v\n%#v", v.name, p, v.expectedWrites, v.writeMatch)
	return len(p), nil
}

type sequentialWriteVerifier struct {
	name           string
	expectedWrites []string
	currentIndex   int
	t              *testing.T
}

// NewSequentialWV creates a sequential WriteVerifier which can be used to test
// code writing to an io.Writer interface non-concurrently
func NewSequentialWV(name string, expectedWrites []string, t *testing.T) WriteVerifier {
	return &sequentialWriteVerifier{
		name:           name,
		expectedWrites: expectedWrites,
		currentIndex:   0,
		t:              t,
	}
}

// CheckDone should be called after all writes to the write should have
// completed. The object then validates that all expected writes were received,
// calling the Error method in the testing.T instance if any were missed.
func (s *sequentialWriteVerifier) CheckDone() {
	if s.currentIndex != len(s.expectedWrites) {
		s.t.Errorf("%s writer did not receive all expected writes.", s.name)
	}
}

// Write emulates the Write method of io.Writers but instead compares it
// against an internal set of expected writes. If the write does not match an
// expected write that has yet to take place it will call testing.T.Error
func (s *sequentialWriteVerifier) Write(p []byte) (int, error) {
	if s.currentIndex >= len(s.expectedWrites) {
		s.t.Errorf("%s writer was not expecting a write but received \"%s\"", s.name, p)
		return len(p), nil
	}
	if !bytes.Equal(p, []byte(s.expectedWrites[s.currentIndex])) {
		s.t.Errorf("%s writer at index %d expected \"%s\" but received \"%s\"", s.name, s.currentIndex, s.expectedWrites[s.currentIndex], p)
	}
	s.currentIndex++
	if bytes.Equal(p, []byte(FailWrite)) {
		return -1, errors.New("I was told to fail this!")
	}
	return len(p), nil
}
<|endoftext|>