<commit_before>package main

import (
	"fmt"
	"github.com/keybase/go-libkb"
	"os"
	"strconv"
	"strings"
)

type UI struct {
	Terminal    *Terminal
	SecretEntry *SecretEntry
}

type BaseIdentifyUI struct {
	parent *UI
	them   *libkb.User
}

type IdentifySelfUI struct {
	BaseIdentifyUI
}

type IdentifyLubaUI struct {
	BaseIdentifyUI
}

type IdentifyUI struct {
	BaseIdentifyUI
}

func (u IdentifySelfUI) Start() {
	G.Log.Info("Verifying your key fingerprint....")
}
func (u IdentifyTrackUI) Start() {
	G.Log.Info("Generating tracking statement for " + ColorString("bold", u.them.GetName()))
}
func (u IdentifyLubaUI) Start() {
	G.Log.Info("LoadUserByAssertion: Verifying identify for " + ColorString("bold", u.them.GetName()))
}
func (u IdentifyUI) Start() {
	G.Log.Info("Identifying " + ColorString("bold", u.them.GetName()))
}

func (ui BaseIdentifyUI) baseFinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var warnings libkb.Warnings
	err, warnings = ires.GetErrorLax()
	if err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
	}
	return
}

func (ui IdentifyLubaUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	return ui.baseFinishAndPrompt(ires)
}
func (ui IdentifyUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	return ui.baseFinishAndPrompt(ires)
}

func (ui IdentifySelfUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var warnings libkb.Warnings
	err, warnings = ires.GetErrorLax()
	var prompt string
	if err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
		prompt = "Do you still accept these credentials to be your own?"
	} else if len(ires.ProofChecks) == 0 {
		prompt = "We found your account, but you have no hosted proofs. Check your fingerprint carefully. Is this you?"
	} else {
		prompt = "Is this you?"
	}

	err = ui.PromptForConfirmation(prompt)
	if err != nil {
		return
	}
	return
}

type IdentifyTrackUI struct {
	BaseIdentifyUI
	strict bool
}

func (ui IdentifyTrackUI) FinishAndPrompt(res *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var prompt string
	un := ui.them.GetName()
	var warnings libkb.Warnings

	if err, warnings = res.GetErrorAndWarnings(ui.strict); err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
		prompt = "Some proofs failed; still track " + un + "?"
	} else if len(res.ProofChecks) == 0 {
		prompt = "We found an account for " + un +
			", but they haven't proven their identity. Still track them?"
	} else {
		prompt = "Is this the " + un + "you wanted?"
	}

	if err = ui.PromptForConfirmation(prompt); err != nil {
		return
	}
	return
}

func (u BaseIdentifyUI) ReportHook(s string) {
	os.Stdout.Write([]byte(s + "\n"))
}

func (u BaseIdentifyUI) ShowWarnings(w libkb.Warnings) {
	w.Warn()
}

func (u BaseIdentifyUI) PromptForConfirmation(s string) error {
	return u.parent.PromptForConfirmation(s)
}

func (u BaseIdentifyUI) FinishSocialProofCheck(s *libkb.SocialProofChainLink, lcr libkb.LinkCheckResult) {
	var msg, lcrs string

	if diff := lcr.GetDiff(); diff != nil {
		lcrs = TrackDiffToColoredString(diff) + " "
	}

	if err := lcr.GetError(); err == nil {
		msg += (CHECK + " " + lcrs + `"` +
			ColorString("green", s.GetUsername()) + `" on ` + s.GetService() +
			": " + lcr.GetHint().GetHumanUrl())
	} else {
		msg += (BADX + " " + lcrs +
			ColorString("red", `"`+s.GetUsername()+`" on `+s.GetService()+" "+
				ColorString("bold", "failed")+": "+
				lcr.GetError().Error()))
	}
	if cached := lcr.GetCached(); cached != nil {
		msg += " " + ColorString("magenta", cached.ToDisplayString())
	}
	u.ReportHook(msg)
}

func TrackDiffToColoredString(t libkb.TrackDiff) string {
	s := t.ToDisplayString()
	var color string
	switch t.(type) {
	case libkb.TrackDiffError, libkb.TrackDiffClash, libkb.TrackDiffLost:
		color = "red"
	case libkb.TrackDiffUpgraded:
		color = "orange"
	case libkb.TrackDiffNew:
		color = "blue"
	case libkb.TrackDiffNone:
		color = "green"
	}
	if len(color) == 0 {
		s = ColorString(color, s)
	}
	return s
}

func (u BaseIdentifyUI) TrackDiffErrorToString(libkb.TrackDiffError) string {
	return ColorString("red", "<error>")
}
func (u BaseIdentifyUI) TrackDiffUpgradedToString(t libkb.TrackDiffUpgraded) string {
	return ColorString("orange", "<Upgraded from "+t.GetPrev()+" to "+t.GetCurr()+">")
}

func (u BaseIdentifyUI) FinishWebProofCheck(s *libkb.WebProofChainLink, lcr libkb.LinkCheckResult) {
	var msg, lcrs string

	if diff := lcr.GetDiff(); diff != nil {
		lcrs = TrackDiffToColoredString(diff) + " "
	}

	great_color := "green"
	ok_color := "yellow"

	if err := lcr.GetError(); err == nil {
		if s.GetProtocol() == "dns" {
			msg += (CHECK + " " + lcrs + "admin of " +
				ColorString(ok_color, "DNS") + " zone " +
				ColorString(ok_color, s.GetHostname()) +
				": found TXT entry " + lcr.GetHint().GetCheckText())
		} else {
			var color string
			if s.GetProtocol() == "https" {
				color = great_color
			} else {
				color = ok_color
			}
			msg += (CHECK + " " + lcrs + "admin of " +
				ColorString(color, s.GetHostname()) + " via " +
				ColorString(color, strings.ToUpper(s.GetProtocol())) +
				": " + lcr.GetHint().GetHumanUrl())
		}
	} else {
		msg = (BADX + " " + lcrs +
			ColorString("red", "Proof for "+s.ToDisplayString()+" "+
				ColorString("bold", "failed")+": "+
				lcr.GetError().Error()))
	}

	if cached := lcr.GetCached(); cached != nil {
		msg += " " + ColorString("magenta", cached.ToDisplayString())
	}
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) DisplayCryptocurrency(l *libkb.CryptocurrencyChainLink) {
	msg := (BTC + " bitcoin " + ColorString("green", l.GetAddress()))
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) DisplayKey(fp *libkb.PgpFingerprint, diff libkb.TrackDiff) {
	var ds string
	if diff != nil {
		ds = TrackDiffToColoredString(diff) + " "
	}
	msg := CHECK + " " + ds +
		ColorString("green", "public key fingerprint: "+fp.ToQuads())
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) ReportLastTrack(t *libkb.TrackLookup) {
	if t != nil {
		msg := ColorString("bold", fmt.Sprintf("You last tracked %s on %s",
			u.them.GetName(), libkb.FormatTime(t.GetCTime())))
		u.ReportHook(msg)
	}
}

func (u *UI) GetIdentifySelfUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifySelfUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetIdentifyTrackUI(them *libkb.User, strict bool) libkb.IdentifyUI {
	return IdentifyTrackUI{BaseIdentifyUI{u, them}, strict}
}

func (u *UI) GetIdentifyUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifyUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetIdentifyLubaUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifyLubaUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetSecret(args []libkb.SecretEntryArg) (*libkb.SecretEntryRes, error) {
	var term_arg *libkb.SecretEntryArg
	if len(args) > 1 {
		term_arg = &args[1]
	}
	return u.SecretEntry.Get(args[0], term_arg)
}

func (u *UI) Configure() error {
	u.Terminal = NewTerminal()
	u.SecretEntry = NewSecretEntry(u.Terminal)
	return nil
}

func (u *UI) Shutdown() error {
	var err error
	if u.Terminal != nil {
		err = u.Terminal.Shutdown()
	}
	return err
}

func (ui *UI) PromptForNewPassphrase(arg libkb.PromptArg) (text string, err error) {

	if arg.Checker == nil {
		arg.Checker = &libkb.CheckNewPassword
	}

	orig := arg
	var rm string

	for {
		text = ""
		var text2 string
		arg = orig
		if len(rm) > 0 {
			arg.RetryMessage = rm
			rm = ""
		}

		if text, err = ui.ppprompt(arg); err != nil {
			return
		}

		arg.TerminalPrompt = "confirm " + arg.TerminalPrompt
		arg.PinentryDesc = "Please reenter your passphase for confirmation"
		arg.RetryMessage = ""
		arg.Checker = nil

		if text2, err = ui.ppprompt(arg); err != nil {
			return
		}
		if text == text2 {
			break
		} else {
			rm = "Password mismatch"
		}
	}
	return
}

func (ui *UI) PromptForKeybasePassphrase(retry string) (text string, err error) {
	return ui.ppprompt(libkb.PromptArg{
		TerminalPrompt: "keybase passphrase",
		PinentryPrompt: "Your passphrase",
		PinentryDesc:   "Please enter your keybase passphrase (12+ characters)",
		Checker:        &libkb.CheckPasswordSimple,
		RetryMessage:   retry,
	})
}

func (ui *UI) ppprompt(arg libkb.PromptArg) (text string, err error) {

	first := true
	var res *libkb.SecretEntryRes

	for {

		tp := arg.TerminalPrompt
		var emp, emt string
		if !first {
			tp = tp + " (" + arg.Checker.Hint + ")"
			emp = sentencePunctuate(arg.Checker.Hint)
		} else if len(arg.RetryMessage) > 0 {
			emp = arg.RetryMessage
			emt = emp
		}

		tp = tp + ": "

		res, err = ui.GetSecret([]libkb.SecretEntryArg{{
			Error:  emp,
			Desc:   arg.PinentryDesc,
			Prompt: arg.PinentryPrompt,
		}, {
			Error:  emt,
			Prompt: tp,
		},
		})

		if err == nil && res.Canceled {
			err = InputCanceledError{}
		}
		if err != nil {
			break
		}
		if arg.Checker == nil || arg.Checker.F(res.Text) {
			text = res.Text
			break
		}
		first = false
	}

	return
}

func (ui *UI) Prompt(prompt string, password bool, checker libkb.Checker) (string, error) {
	var prompter func(string) (string, error)

	if ui.Terminal == nil {
		return "", NoTerminalError{}
	}

	if password {
		prompter = func(s string) (string, error) {
			return ui.Terminal.PromptPassword(s)
		}
	} else {
		prompter = func(s string) (string, error) {
			return ui.Terminal.Prompt(s)
		}
	}

	var res string
	var err error

	first := true
	for {
		p := prompt
		if !first && len(checker.Hint) > 0 {
			p = p + " (" + checker.Hint + ")"
		}
		p = p + ": "
		res, err = prompter(p)
		if err != nil || checker.F(res) {
			break
		}
		res = ""
		first = false
	}

	return res, err
}

func (ui *UI) PromptForConfirmation(prompt string) error {

	if ui.Terminal == nil {
		return NoTerminalError{}
	}

	res, err := ui.Terminal.Prompt(prompt + " (type 'YES' to confirm): ")
	if err != nil {
		return err
	}
	if res != "YES" {
		return NotConfirmedError{}
	}
	return nil

}

func sentencePunctuate(s string) string {
	return strings.ToUpper(s[0:1]) + s[1:] + "."
}

func (ui *UI) PromptYesNo(p string, def *bool) (ret bool, err error) {
	var ch string
	if def == nil {
		ch = "[y/n]"
	} else if *def {
		ch = "[Y/n]"
	} else {
		ch = "[y/N]"
	}
	prompt := p + " " + ch + " "
	done := false
	for !done && err == nil {
		var s string
		if s, err = ui.Terminal.Prompt(prompt); err != nil {
		} else if libkb.IsYes(s) {
			ret = true
			done = true
		} else if libkb.IsNo(s) {
			ret = false
			done = true
		} else if def != nil && libkb.IsEmpty(s) {
			ret = *def
			done = true
		}
	}
	return
}

func (ui *UI) PromptSelection(prompt string, low, hi int) (ret int, err error) {
	field := &Field{
		Name:   "selection",
		Prompt: prompt,
		Checker: &libkb.Checker{
			F: func(s string) bool {
				v, e := strconv.Atoi(s)
				return (e == nil && v >= low && v <= hi)
			},
			Hint: fmt.Sprintf("%d-%d", low, hi),
		},
	}
	err = NewPrompter([]*Field{field}).Run()
	if p := field.Value; p == nil {
		err = InputCanceledError{}
	} else {
		ret, err = strconv.Atoi(*p)
	}
	return
}

func (ui *UI) Output(s string) error {
	_, err := os.Stdout.Write([]byte(s))
	return err
}
<commit_msg>working through more tracking stuff<commit_after>package main

import (
	"fmt"
	"github.com/keybase/go-libkb"
	"os"
	"strconv"
	"strings"
)

type UI struct {
	Terminal    *Terminal
	SecretEntry *SecretEntry
}

type BaseIdentifyUI struct {
	parent *UI
	them   *libkb.User
}

type IdentifySelfUI struct {
	BaseIdentifyUI
}

type IdentifyLubaUI struct {
	BaseIdentifyUI
}

type IdentifyUI struct {
	BaseIdentifyUI
}

func (u IdentifySelfUI) Start() {
	G.Log.Info("Verifying your key fingerprint....")
}
func (u IdentifyTrackUI) Start() {
	G.Log.Info("Generating tracking statement for " + ColorString("bold", u.them.GetName()))
}
func (u IdentifyLubaUI) Start() {
	G.Log.Info("LoadUserByAssertion: Verifying identify for " + ColorString("bold", u.them.GetName()))
}
func (u IdentifyUI) Start() {
	G.Log.Info("Identifying " + ColorString("bold", u.them.GetName()))
}

func (ui BaseIdentifyUI) baseFinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var warnings libkb.Warnings
	err, warnings = ires.GetErrorLax()
	if err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
	}
	return
}

func (ui IdentifyLubaUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	return ui.baseFinishAndPrompt(ires)
}
func (ui IdentifyUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	return ui.baseFinishAndPrompt(ires)
}

func (ui IdentifySelfUI) FinishAndPrompt(ires *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var warnings libkb.Warnings
	err, warnings = ires.GetErrorLax()
	var prompt string
	if err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
		prompt = "Do you still accept these credentials to be your own?"
	} else if len(ires.ProofChecks) == 0 {
		prompt = "We found your account, but you have no hosted proofs. Check your fingerprint carefully. Is this you?"
	} else {
		prompt = "Is this you?"
	}

	err = ui.PromptForConfirmation(prompt)
	if err != nil {
		return
	}
	return
}

type IdentifyTrackUI struct {
	BaseIdentifyUI
	strict bool
}

func (ui IdentifyTrackUI) FinishAndPrompt(res *libkb.IdentifyRes) (i libkb.TrackInstructions, err error) {
	var prompt string
	un := ui.them.GetName()
	var warnings libkb.Warnings

	if err, warnings = res.GetErrorAndWarnings(ui.strict); err != nil {
		return
	} else if !warnings.IsEmpty() {
		ui.ShowWarnings(warnings)
		prompt = "Some proofs failed; still track " + un + "?"
	} else if len(res.ProofChecks) == 0 {
		prompt = "We found an account for " + un +
			", but they haven't proven their identity. Still track them?"
	} else {
		prompt = "Is this the " + ColorString("bold", un) + " you wanted?"
	}

	if err = ui.PromptForConfirmation(prompt); err != nil {
		return
	}

	i.Local = true

	def := true
	prompt = "Publicly write tracking statement to server?"
	if i.Remote, err = ui.parent.PromptYesNo(prompt, &def); err != nil {
		return
	}

	return
}

func (u BaseIdentifyUI) ReportHook(s string) {
	os.Stdout.Write([]byte(s + "\n"))
}

func (u BaseIdentifyUI) ShowWarnings(w libkb.Warnings) {
	w.Warn()
}

func (u BaseIdentifyUI) PromptForConfirmation(s string) error {
	return u.parent.PromptForConfirmation(s)
}

func (u BaseIdentifyUI) FinishSocialProofCheck(s *libkb.SocialProofChainLink, lcr libkb.LinkCheckResult) {
	var msg, lcrs string

	if diff := lcr.GetDiff(); diff != nil {
		lcrs = TrackDiffToColoredString(diff) + " "
	}

	if err := lcr.GetError(); err == nil {
		msg += (CHECK + " " + lcrs + `"` +
			ColorString("green", s.GetUsername()) + `" on ` + s.GetService() +
			": " + lcr.GetHint().GetHumanUrl())
	} else {
		msg += (BADX + " " + lcrs +
			ColorString("red", `"`+s.GetUsername()+`" on `+s.GetService()+" "+
				ColorString("bold", "failed")+": "+
				lcr.GetError().Error()))
	}
	if cached := lcr.GetCached(); cached != nil {
		msg += " " + ColorString("magenta", cached.ToDisplayString())
	}
	u.ReportHook(msg)
}

func TrackDiffToColoredString(t libkb.TrackDiff) string {
	s := t.ToDisplayString()
	var color string
	switch t.(type) {
	case libkb.TrackDiffError, libkb.TrackDiffClash, libkb.TrackDiffLost:
		color = "red"
	case libkb.TrackDiffUpgraded:
		color = "orange"
	case libkb.TrackDiffNew:
		color = "blue"
	case libkb.TrackDiffNone:
		color = "green"
	}
	if len(color) > 0 {
		s = ColorString(color, s)
	}
	return s
}

func (u BaseIdentifyUI) TrackDiffErrorToString(libkb.TrackDiffError) string {
	return ColorString("red", "<error>")
}
func (u BaseIdentifyUI) TrackDiffUpgradedToString(t libkb.TrackDiffUpgraded) string {
	return ColorString("orange", "<Upgraded from "+t.GetPrev()+" to "+t.GetCurr()+">")
}

func (u BaseIdentifyUI) FinishWebProofCheck(s *libkb.WebProofChainLink, lcr libkb.LinkCheckResult) {
	var msg, lcrs string

	if diff := lcr.GetDiff(); diff != nil {
		lcrs = TrackDiffToColoredString(diff) + " "
	}

	great_color := "green"
	ok_color := "yellow"

	if err := lcr.GetError(); err == nil {
		if s.GetProtocol() == "dns" {
			msg += (CHECK + " " + lcrs + "admin of " +
				ColorString(ok_color, "DNS") + " zone " +
				ColorString(ok_color, s.GetHostname()) +
				": found TXT entry " + lcr.GetHint().GetCheckText())
		} else {
			var color string
			if s.GetProtocol() == "https" {
				color = great_color
			} else {
				color = ok_color
			}
			msg += (CHECK + " " + lcrs + "admin of " +
				ColorString(color, s.GetHostname()) + " via " +
				ColorString(color, strings.ToUpper(s.GetProtocol())) +
				": " + lcr.GetHint().GetHumanUrl())
		}
	} else {
		msg = (BADX + " " + lcrs +
			ColorString("red", "Proof for "+s.ToDisplayString()+" "+
				ColorString("bold", "failed")+": "+
				lcr.GetError().Error()))
	}

	if cached := lcr.GetCached(); cached != nil {
		msg += " " + ColorString("magenta", cached.ToDisplayString())
	}
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) DisplayCryptocurrency(l *libkb.CryptocurrencyChainLink) {
	msg := (BTC + " bitcoin " + ColorString("green", l.GetAddress()))
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) DisplayKey(fp *libkb.PgpFingerprint, diff libkb.TrackDiff) {
	var ds string
	if diff != nil {
		ds = TrackDiffToColoredString(diff) + " "
	}
	msg := CHECK + " " + ds +
		ColorString("green", "public key fingerprint: "+fp.ToQuads())
	u.ReportHook(msg)
}

func (u BaseIdentifyUI) ReportLastTrack(t *libkb.TrackLookup) {
	if t != nil {
		msg := ColorString("bold", fmt.Sprintf("You last tracked %s on %s",
			u.them.GetName(), libkb.FormatTime(t.GetCTime())))
		u.ReportHook(msg)
	}
}

func (u *UI) GetIdentifySelfUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifySelfUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetIdentifyTrackUI(them *libkb.User, strict bool) libkb.IdentifyUI {
	return IdentifyTrackUI{BaseIdentifyUI{u, them}, strict}
}

func (u *UI) GetIdentifyUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifyUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetIdentifyLubaUI(them *libkb.User) libkb.IdentifyUI {
	return IdentifyLubaUI{BaseIdentifyUI{u, them}}
}

func (u *UI) GetSecret(args []libkb.SecretEntryArg) (*libkb.SecretEntryRes, error) {
	var term_arg *libkb.SecretEntryArg
	if len(args) > 1 {
		term_arg = &args[1]
	}
	return u.SecretEntry.Get(args[0], term_arg)
}

func (u *UI) Configure() error {
	u.Terminal = NewTerminal()
	u.SecretEntry = NewSecretEntry(u.Terminal)
	return nil
}

func (u *UI) Shutdown() error {
	var err error
	if u.Terminal != nil {
		err = u.Terminal.Shutdown()
	}
	return err
}

func (ui *UI) PromptForNewPassphrase(arg libkb.PromptArg) (text string, err error) {

	if arg.Checker == nil {
		arg.Checker = &libkb.CheckNewPassword
	}

	orig := arg
	var rm string

	for {
		text = ""
		var text2 string
		arg = orig
		if len(rm) > 0 {
			arg.RetryMessage = rm
			rm = ""
		}

		if text, err = ui.ppprompt(arg); err != nil {
			return
		}

		arg.TerminalPrompt = "confirm " + arg.TerminalPrompt
		arg.PinentryDesc = "Please reenter your passphase for confirmation"
		arg.RetryMessage = ""
		arg.Checker = nil

		if text2, err = ui.ppprompt(arg); err != nil {
			return
		}
		if text == text2 {
			break
		} else {
			rm = "Password mismatch"
		}
	}
	return
}

func (ui *UI) PromptForKeybasePassphrase(retry string) (text string, err error) {
	return ui.ppprompt(libkb.PromptArg{
		TerminalPrompt: "keybase passphrase",
		PinentryPrompt: "Your passphrase",
		PinentryDesc:   "Please enter your keybase passphrase (12+ characters)",
		Checker:        &libkb.CheckPasswordSimple,
		RetryMessage:   retry,
	})
}

func (ui *UI) ppprompt(arg libkb.PromptArg) (text string, err error) {

	first := true
	var res *libkb.SecretEntryRes

	for {

		tp := arg.TerminalPrompt
		var emp, emt string
		if !first {
			tp = tp + " (" + arg.Checker.Hint + ")"
			emp = sentencePunctuate(arg.Checker.Hint)
		} else if len(arg.RetryMessage) > 0 {
			emp = arg.RetryMessage
			emt = emp
		}

		tp = tp + ": "

		res, err = ui.GetSecret([]libkb.SecretEntryArg{{
			Error:  emp,
			Desc:   arg.PinentryDesc,
			Prompt: arg.PinentryPrompt,
		}, {
			Error:  emt,
			Prompt: tp,
		},
		})

		if err == nil && res.Canceled {
			err = InputCanceledError{}
		}
		if err != nil {
			break
		}
		if arg.Checker == nil || arg.Checker.F(res.Text) {
			text = res.Text
			break
		}
		first = false
	}

	return
}

func (ui *UI) Prompt(prompt string, password bool, checker libkb.Checker) (string, error) {
	var prompter func(string) (string, error)

	if ui.Terminal == nil {
		return "", NoTerminalError{}
	}

	if password {
		prompter = func(s string) (string, error) {
			return ui.Terminal.PromptPassword(s)
		}
	} else {
		prompter = func(s string) (string, error) {
			return ui.Terminal.Prompt(s)
		}
	}

	var res string
	var err error

	first := true
	for {
		p := prompt
		if !first && len(checker.Hint) > 0 {
			p = p + " (" + checker.Hint + ")"
		}
		p = p + ": "
		res, err = prompter(p)
		if err != nil || checker.F(res) {
			break
		}
		res = ""
		first = false
	}

	return res, err
}

func (ui *UI) PromptForConfirmation(prompt string) error {

	if ui.Terminal == nil {
		return NoTerminalError{}
	}

	res, err := ui.Terminal.Prompt(prompt + " (type 'YES' to confirm): ")
	if err != nil {
		return err
	}
	if res != "YES" {
		return NotConfirmedError{}
	}
	return nil

}

func sentencePunctuate(s string) string {
	return strings.ToUpper(s[0:1]) + s[1:] + "."
}

func (ui *UI) PromptYesNo(p string, def *bool) (ret bool, err error) {
	var ch string
	if def == nil {
		ch = "[y/n]"
	} else if *def {
		ch = "[Y/n]"
	} else {
		ch = "[y/N]"
	}
	prompt := p + " " + ch + " "
	done := false
	for !done && err == nil {
		var s string
		if s, err = ui.Terminal.Prompt(prompt); err != nil {
		} else if libkb.IsYes(s) {
			ret = true
			done = true
		} else if libkb.IsNo(s) {
			ret = false
			done = true
		} else if def != nil && libkb.IsEmpty(s) {
			ret = *def
			done = true
		}
	}
	return
}

func (ui *UI) PromptSelection(prompt string, low, hi int) (ret int, err error) {
	field := &Field{
		Name:   "selection",
		Prompt: prompt,
		Checker: &libkb.Checker{
			F: func(s string) bool {
				v, e := strconv.Atoi(s)
				return (e == nil && v >= low && v <= hi)
			},
			Hint: fmt.Sprintf("%d-%d", low, hi),
		},
	}
	err = NewPrompter([]*Field{field}).Run()
	if p := field.Value; p == nil {
		err = InputCanceledError{}
	} else {
		ret, err = strconv.Atoi(*p)
	}
	return
}

func (ui *UI) Output(s string) error {
	_, err := os.Stdout.Write([]byte(s))
	return err
}
<|endoftext|>


<commit_before>package proxyproto

import (
	"bufio"
	"bytes"
	"net"
	"strconv"
	"strings"
)

const (
	CRLF      = "\r\n"
	SEPARATOR = " "
)

func initVersion1() *Header {
	header := new(Header)
	header.Version = 1
	// Command doesn't exist in v1
	header.Command = PROXY
	return header
}

func parseVersion1(reader *bufio.Reader) (*Header, error) {
	// Make sure we have a v1 header
	line, err := reader.ReadString('\n')
	if !strings.HasSuffix(line, CRLF) {
		return nil, ErrCantReadProtocolVersionAndCommand
	}
	tokens := strings.Split(line[:len(line)-2], SEPARATOR)
	if len(tokens) < 6 {
		return nil, ErrCantReadProtocolVersionAndCommand
	}

	header := initVersion1()

	// Read address family and protocol
	switch tokens[1] {
	case "TCP4":
		header.TransportProtocol = TCPv4
	case "TCP6":
		header.TransportProtocol = TCPv6
	default:
		header.TransportProtocol = UNSPEC
	}

	// Read addresses and ports
	header.SourceAddress, err = parseV1IPAddress(header.TransportProtocol, tokens[2])
	if err != nil {
		return nil, err
	}
	header.DestinationAddress, err = parseV1IPAddress(header.TransportProtocol, tokens[3])
	if err != nil {
		return nil, err
	}
	header.SourcePort, err = parseV1PortNumber(tokens[4])
	if err != nil {
		return nil, err
	}
	header.DestinationPort, err = parseV1PortNumber(tokens[5])
	if err != nil {
		return nil, err
	}
	return header, nil
}

func (header *Header) formatVersion1() ([]byte, error) {
	// As of version 1, only "TCP4" ( \x54 \x43 \x50 \x34 ) for TCP over IPv4,
	// and "TCP6" ( \x54 \x43 \x50 \x36 ) for TCP over IPv6 are allowed.
	var proto string
	if header.TransportProtocol == TCPv4 {
		proto = "TCP4"
	} else if header.TransportProtocol == TCPv6 {
		proto = "TCP6"
	} else {
		return []byte("PROXY UNKNOWN\r\n"), nil
	}

	var buf bytes.Buffer
	buf.Write(SIGV1)
	buf.WriteString(SEPARATOR)
	buf.WriteString(proto)
	buf.WriteString(SEPARATOR)
	buf.WriteString(header.SourceAddress.String())
	buf.WriteString(SEPARATOR)
	buf.WriteString(header.DestinationAddress.String())
	buf.WriteString(SEPARATOR)
	buf.WriteString(strconv.Itoa(int(header.SourcePort)))
	buf.WriteString(SEPARATOR)
	buf.WriteString(strconv.Itoa(int(header.DestinationPort)))
	buf.WriteString(CRLF)

	return buf.Bytes(), nil
}

func parseV1PortNumber(portStr string) (port uint16, err error) {
	_port, _err := strconv.Atoi(portStr)
	if _err == nil {
		if _port < 0 || _port > 65535 {
			err = ErrInvalidPortNumber
		} else {
			port = uint16(_port)
		}
	} else {
		err = ErrInvalidPortNumber
	}

	return
}

func parseV1IPAddress(protocol AddressFamilyAndProtocol, addrStr string) (addr net.IP, err error) {
	addr = net.ParseIP(addrStr)
	tryV4 := addr.To4()
	if (protocol == TCPv4 && tryV4 == nil) || (protocol == TCPv6 && tryV4 != nil) {
		err = ErrInvalidAddress
	}
	return
}
<commit_msg>v1: avoid buffer grown.<commit_after>package proxyproto

import (
	"bufio"
	"bytes"
	"net"
	"strconv"
	"strings"
)

const (
	CRLF      = "\r\n"
	SEPARATOR = " "
)

func initVersion1() *Header {
	header := new(Header)
	header.Version = 1
	// Command doesn't exist in v1
	header.Command = PROXY
	return header
}

func parseVersion1(reader *bufio.Reader) (*Header, error) {
	// Make sure we have a v1 header
	line, err := reader.ReadString('\n')
	if !strings.HasSuffix(line, CRLF) {
		return nil, ErrCantReadProtocolVersionAndCommand
	}
	tokens := strings.Split(line[:len(line)-2], SEPARATOR)
	if len(tokens) < 6 {
		return nil, ErrCantReadProtocolVersionAndCommand
	}

	header := initVersion1()

	// Read address family and protocol
	switch tokens[1] {
	case "TCP4":
		header.TransportProtocol = TCPv4
	case "TCP6":
		header.TransportProtocol = TCPv6
	default:
		header.TransportProtocol = UNSPEC
	}

	// Read addresses and ports
	header.SourceAddress, err = parseV1IPAddress(header.TransportProtocol, tokens[2])
	if err != nil {
		return nil, err
	}
	header.DestinationAddress, err = parseV1IPAddress(header.TransportProtocol, tokens[3])
	if err != nil {
		return nil, err
	}
	header.SourcePort, err = parseV1PortNumber(tokens[4])
	if err != nil {
		return nil, err
	}
	header.DestinationPort, err = parseV1PortNumber(tokens[5])
	if err != nil {
		return nil, err
	}
	return header, nil
}

func (header *Header) formatVersion1() ([]byte, error) {
	// As of version 1, only "TCP4" ( \x54 \x43 \x50 \x34 ) for TCP over IPv4,
	// and "TCP6" ( \x54 \x43 \x50 \x36 ) for TCP over IPv6 are allowed.
	var proto string
	if header.TransportProtocol == TCPv4 {
		proto = "TCP4"
	} else if header.TransportProtocol == TCPv6 {
		proto = "TCP6"
	} else {
		return []byte("PROXY UNKNOWN\r\n"), nil
	}

	buf := bytes.NewBuffer(make([]byte, 0, 108))
	buf.Write(SIGV1)
	buf.WriteString(SEPARATOR)
	buf.WriteString(proto)
	buf.WriteString(SEPARATOR)
	buf.WriteString(header.SourceAddress.String())
	buf.WriteString(SEPARATOR)
	buf.WriteString(header.DestinationAddress.String())
	buf.WriteString(SEPARATOR)
	buf.WriteString(strconv.Itoa(int(header.SourcePort)))
	buf.WriteString(SEPARATOR)
	buf.WriteString(strconv.Itoa(int(header.DestinationPort)))
	buf.WriteString(CRLF)

	return buf.Bytes(), nil
}

func parseV1PortNumber(portStr string) (port uint16, err error) {
	_port, _err := strconv.Atoi(portStr)
	if _err == nil {
		if _port < 0 || _port > 65535 {
			err = ErrInvalidPortNumber
		} else {
			port = uint16(_port)
		}
	} else {
		err = ErrInvalidPortNumber
	}

	return
}

func parseV1IPAddress(protocol AddressFamilyAndProtocol, addrStr string) (addr net.IP, err error) {
	addr = net.ParseIP(addrStr)
	tryV4 := addr.To4()
	if (protocol == TCPv4 && tryV4 == nil) || (protocol == TCPv6 && tryV4 != nil) {
		err = ErrInvalidAddress
	}
	return
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/containers/virtcontainers/pkg/oci"
	"github.com/urfave/cli"
)

var stateCLICommand = cli.Command{
	Name:  "state",
	Usage: "output the state of a container",
	ArgsUsage: `<container-id>

   <container-id> is your name for the instance of the container`,
	Description: `The state command outputs current state information for the
instance of a container.`,
	Action: func(context *cli.Context) error {
		args := context.Args()
		if len(args) != 1 {
			return fmt.Errorf("Expecting only one container ID, got %d: %v", len(args), []string(args))
		}

		return state(args.First())
	},
}

func state(containerID string) error {
	// Checks the MUST and MUST NOT from OCI runtime specification
	status, _, err := getExistingContainerInfo(containerID)
	if err != nil {
		return err
	}

	// Convert the status to the expected State structure
	state, err := oci.StatusToOCIState(status)
	if err != nil {
		return err
	}

	stateJSON, err := json.Marshal(state)
	if err != nil {
		return err
	}

	// Print stateJSON to stdout
	fmt.Fprintf(os.Stdout, "%s", stateJSON)

	return nil
}
<commit_msg>state: Apply indentation to json output from state cmd.<commit_after>// Copyright (c) 2014,2015,2016 Docker, Inc.
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/containers/virtcontainers/pkg/oci"
	"github.com/urfave/cli"
)

var stateCLICommand = cli.Command{
	Name:  "state",
	Usage: "output the state of a container",
	ArgsUsage: `<container-id>

   <container-id> is your name for the instance of the container`,
	Description: `The state command outputs current state information for the
instance of a container.`,
	Action: func(context *cli.Context) error {
		args := context.Args()
		if len(args) != 1 {
			return fmt.Errorf("Expecting only one container ID, got %d: %v", len(args), []string(args))
		}

		return state(args.First())
	},
}

func state(containerID string) error {
	// Checks the MUST and MUST NOT from OCI runtime specification
	status, _, err := getExistingContainerInfo(containerID)
	if err != nil {
		return err
	}

	// Convert the status to the expected State structure
	state, err := oci.StatusToOCIState(status)
	if err != nil {
		return err
	}

	stateJSON, err := json.MarshalIndent(state, "", "  ")
	if err != nil {
		return err
	}

	// Print stateJSON to stdout
	fmt.Fprintf(os.Stdout, "%s", stateJSON)

	return nil
}
<|endoftext|>


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

package main

import (
	"github.com/jacobsa/comeback/state"
	"log"
	"os"
	"sync"
)

var g_stateOnce sync.Once
var g_state state.State

func initState() {
	cfg := getConfig()
	var err error

	// Open the specified file.
	f, err := os.Open(cfg.StateFile)

	// Special case: if the error is that the file doesn't exist, initialize a
	// new one.
	if err != nil && os.IsNotExist(err) {
		log.Println("No state file found. Using fresh state.")
		g_state = state.State{
			ExistingScores:        nil,
			ExistingScoresVersion: 0,
		}
	} else {
		// Handle other Open errors.
		if err != nil {
			log.Fatalln("Opening state file:", err)
		}

		defer f.Close()

		// Load the state struct.
		log.Println("Loading from state file.")

		g_state, err = state.LoadState(f)
		if err != nil {
			log.Fatalln("LoadState:", err)
		}
	}

	// Throw out the existing scores set if it's out of date.
	reg := getRegistry()
	currentVersion, err := reg.GetCurrentScoreSetVersion()
	if err != nil {
		log.Fatalln("GetCurrentScoreSetVersion:", err)
	}

	if g_state.ExistingScoresVersion != currentVersion {
		log.Println("Scores in state file are stale. Throwing out.")
		g_state.ExistingScores = nil
		g_state.ExistingScoresVersion = currentVersion
	}

	// Throw out the existing score cache if requested.
	if *g_discardScoreCache {
		g_state.ScoresForFiles = state.NewScoreMap()
	}
}

func getState() *state.State {
	g_stateOnce.Do(initState)
	return &g_state
}

func saveState() {
	var err error

	cfg := getConfig()
	stateStruct := getState()
	randSrc := getRandSrc()
	reg := getRegistry()

	// Assign a new random version for the existing scores.
	lastVersion := g_state.ExistingScoresVersion
	g_state.ExistingScoresVersion = randUint64(randSrc)

	// Update the registry.
	err = reg.UpdateScoreSetVersion(g_state.ExistingScoresVersion, lastVersion)
	if err != nil {
		log.Fatalln("UpdateScoreSetVersion:", err)
	}

	// Write out the state.
	f, err := os.Create(cfg.StateFile)
	if err != nil {
		log.Fatalln("Creating state file:", err)
	}

	defer f.Close()

	if err = state.SaveState(f, *stateStruct); err != nil {
		log.Fatalln("SaveState:", err)
	}
}
<commit_msg>Fixed a nil pointer dereference.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"github.com/jacobsa/comeback/state"
	"log"
	"os"
	"sync"
)

var g_stateOnce sync.Once
var g_state state.State

func initState() {
	cfg := getConfig()
	var err error

	// Open the specified file.
	f, err := os.Open(cfg.StateFile)

	// Special case: if the error is that the file doesn't exist, initialize a
	// new one.
	if err != nil && os.IsNotExist(err) {
		log.Println("No state file found. Using fresh state.")
		g_state = state.State{
			ExistingScores:        nil,
			ExistingScoresVersion: 0,
		}
	} else {
		// Handle other Open errors.
		if err != nil {
			log.Fatalln("Opening state file:", err)
		}

		defer f.Close()

		// Load the state struct.
		log.Println("Loading from state file.")

		g_state, err = state.LoadState(f)
		if err != nil {
			log.Fatalln("LoadState:", err)
		}
	}

	// Throw out the existing scores set if it's out of date.
	reg := getRegistry()
	currentVersion, err := reg.GetCurrentScoreSetVersion()
	if err != nil {
		log.Fatalln("GetCurrentScoreSetVersion:", err)
	}

	if g_state.ExistingScoresVersion != currentVersion {
		log.Println("Scores in state file are stale. Throwing out.")
		g_state.ExistingScores = nil
		g_state.ExistingScoresVersion = currentVersion
	}

	// Throw out the existing score cache if requested.
	if *g_discardScoreCache {
		g_state.ScoresForFiles = state.NewScoreMap()
	}

	// Make sure there are no nil interface values.
	if g_state.ScoresForFiles == nil {
		g_state.ScoresForFiles = state.NewScoreMap()
	}
}

func getState() *state.State {
	g_stateOnce.Do(initState)
	return &g_state
}

func saveState() {
	var err error

	cfg := getConfig()
	stateStruct := getState()
	randSrc := getRandSrc()
	reg := getRegistry()

	// Assign a new random version for the existing scores.
	lastVersion := g_state.ExistingScoresVersion
	g_state.ExistingScoresVersion = randUint64(randSrc)

	// Update the registry.
	err = reg.UpdateScoreSetVersion(g_state.ExistingScoresVersion, lastVersion)
	if err != nil {
		log.Fatalln("UpdateScoreSetVersion:", err)
	}

	// Write out the state.
	f, err := os.Create(cfg.StateFile)
	if err != nil {
		log.Fatalln("Creating state file:", err)
	}

	defer f.Close()

	if err = state.SaveState(f, *stateStruct); err != nil {
		log.Fatalln("SaveState:", err)
	}
}
<|endoftext|>


<commit_before>package workers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
)

type stats struct {
	Processed int         `json:"processed"`
	Failed    int         `json:"failed"`
	Jobs      interface{} `json:"jobs"`
}

func Stats(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	jobs := make(map[string][]*map[string]interface{})

	for _, m := range managers {
		queue := m.queueName()
		jobs[queue] = make([]*map[string]interface{}, 0)

		for _, worker := range m.workers {
			message := worker.currentMsg
			startedAt := worker.startedAt

			if message != nil && startedAt > 0 {
				jobs[queue] = append(jobs[queue], &map[string]interface{}{
					"message":    message,
					"started_at": startedAt,
				})
			}
		}
	}

	stats := stats{
		0,
		0,
		jobs,
	}

	conn := Config.Pool.Get()
	defer conn.Close()

	conn.Send("multi")
	conn.Send("get", Config.Namespace+"stat:processed")
	conn.Send("get", Config.Namespace+"stat:failed")
	r, err := conn.Do("exec")

	if err != nil {
		Logger.Println("couldn't retrieve stats:", err)
	}

	results := r.([]interface{})

	if len(results) == 2 {
		stats.Processed, _ = strconv.Atoi(string(results[0].([]byte)))
		stats.Failed, _ = strconv.Atoi(string(results[1].([]byte)))
	}

	body, _ := json.MarshalIndent(stats, "", "  ")
	fmt.Fprintln(w, string(body))
}
<commit_msg>Fix panic in Stats when there are nil failed or processed jobs<commit_after>package workers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
)

type stats struct {
	Processed int         `json:"processed"`
	Failed    int         `json:"failed"`
	Jobs      interface{} `json:"jobs"`
}

func Stats(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	jobs := make(map[string][]*map[string]interface{})

	for _, m := range managers {
		queue := m.queueName()
		jobs[queue] = make([]*map[string]interface{}, 0)

		for _, worker := range m.workers {
			message := worker.currentMsg
			startedAt := worker.startedAt

			if message != nil && startedAt > 0 {
				jobs[queue] = append(jobs[queue], &map[string]interface{}{
					"message":    message,
					"started_at": startedAt,
				})
			}
		}
	}

	stats := stats{
		0,
		0,
		jobs,
	}

	conn := Config.Pool.Get()
	defer conn.Close()

	conn.Send("multi")
	conn.Send("get", Config.Namespace+"stat:processed")
	conn.Send("get", Config.Namespace+"stat:failed")
	r, err := conn.Do("exec")

	if err != nil {
		Logger.Println("couldn't retrieve stats:", err)
	}

	results := r.([]interface{})

	if len(results) == 2 {
		if results[0] != nil {
			stats.Processed, _ = strconv.Atoi(string(results[0].([]byte)))
		}
		if results[1] != nil {
			stats.Failed, _ = strconv.Atoi(string(results[1].([]byte)))
		}
	}

	body, _ := json.MarshalIndent(stats, "", "  ")
	fmt.Fprintln(w, string(body))
}
<|endoftext|>


<commit_before>package core

import (
	"sync"
)

type StatCounter interface {
	Value() int64
	Set(int64) int64
	Add(int64) int64
}

type StatManager interface {
	Feature

	RegisterCounter(string) (StatCounter, error)
	GetCounter(string) StatCounter
}

type syncStatManager struct {
	sync.RWMutex
	StatManager
}

func (s *syncStatManager) Start() error {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}

	return s.StatManager.Start()
}

func (s *syncStatManager) Close() error {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}
	return s.StatManager.Close()
}

func (s *syncStatManager) RegisterCounter(name string) (StatCounter, error) {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil, newError("StatManager not set.")
	}
	return s.StatManager.RegisterCounter(name)
}

func (s *syncStatManager) GetCounter(name string) StatCounter {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}
	return s.StatManager.GetCounter(name)
}

func (s *syncStatManager) Set(m StatManager) {
	if m == nil {
		return
	}
	s.Lock()
	defer s.Unlock()

	s.StatManager.Close()
	s.StatManager = m
}
<commit_msg>add nil check<commit_after>package core

import (
	"sync"
)

type StatCounter interface {
	Value() int64
	Set(int64) int64
	Add(int64) int64
}

type StatManager interface {
	Feature

	RegisterCounter(string) (StatCounter, error)
	GetCounter(string) StatCounter
}

type syncStatManager struct {
	sync.RWMutex
	StatManager
}

func (s *syncStatManager) Start() error {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}

	return s.StatManager.Start()
}

func (s *syncStatManager) Close() error {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}
	return s.StatManager.Close()
}

func (s *syncStatManager) RegisterCounter(name string) (StatCounter, error) {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil, newError("StatManager not set.")
	}
	return s.StatManager.RegisterCounter(name)
}

func (s *syncStatManager) GetCounter(name string) StatCounter {
	s.RLock()
	defer s.RUnlock()

	if s.StatManager == nil {
		return nil
	}
	return s.StatManager.GetCounter(name)
}

func (s *syncStatManager) Set(m StatManager) {
	if m == nil {
		return
	}
	s.Lock()
	defer s.Unlock()

	if s.StatManager != nil {
		s.StatManager.Close()
	}
	s.StatManager = m
}
<|endoftext|>


<commit_before>// Package store is a dead simple configuration manager for Go applications.
package store

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/BurntSushi/toml"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
)

var applicationName string

// SetApplicationName defines a unique application handle for file system.
//
// By default, Store puts all your config data to $HOME/.config/<appname>
// on *nix systems and to %APPDATA%/<appname> on Windows.
//
// Warning: Store would panic on any sensitive calls if it's not set.
func SetApplicationName(handle string) {
	applicationName = handle
}

// Load reads a configuration from `path` and puts it into `v` pointer.
//
// Path is a full filename, with extension. Since Store currently support
// TOML and JSON only, passing others would result in a corresponding error.
//
// If `path` doesn't exist, Load will create one and emptify `v` pointer by
// replacing it with a newly created object, derived from type of `v`.
func Load(path string, v interface{}) error {
	if applicationName == "" {
		panic("store: application name not defined")
	}

	globalPath := buildPath(path)

	data, err := ioutil.ReadFile(globalPath)

	if err != nil {
		// There is a chance that file we are looking for
		// just doesn't exist. In this case we are supposed
		// to create an empty configuration file, based on v.
		empty := reflect.New(reflect.TypeOf(v))
		if innerErr := Save(path, &empty); innerErr != nil {
			// Must be smth with file system... returning error from read.
			return err
		}

		v = empty

		return nil
	}

	contents := string(data)
	if strings.HasSuffix(path, ".toml") {
		if _, err := toml.Decode(contents, v); err != nil {
			return err
		}
	} else if strings.HasSuffix(path, ".json") {
		if err := json.Unmarshal(data, v); err != nil {
			return err
		}
	} else {
		return &stringError{"unknown configuration format"}
	}

	return nil
}

// Save writes a configuration from `path` and puts it into `v` pointer.
//
// Path is a full filename, with extension. Since Store currently support
// TOML and JSON only, passing others would result in a corresponding error.
func Save(path string, v interface{}) error {
	if applicationName == "" {
		panic("store: application name not defined")
	}

	var data []byte

	if strings.HasSuffix(path, ".toml") {
		var b bytes.Buffer

		encoder := toml.NewEncoder(&b)
		if err := encoder.Encode(v); err != nil {
			return nil
		}

		data = b.Bytes()
	} else if strings.HasSuffix(path, ".json") {
		fileData, err := json.Marshal(v)

		if err != nil {
			return err
		}

		data = fileData
	} else {
		return &stringError{"unknown configuration format"}
	}

	globalPath := buildPath(path)
	if err := os.MkdirAll(filepath.Dir(globalPath), os.ModePerm); err != nil {
		return err
	}

	if err := ioutil.WriteFile(globalPath, data, os.ModePerm); err != nil {
		return err
	}

	return nil
}

// buildPlatformPath builds a platform-dependent path for relative path given.
func buildPath(path string) string {
	if runtime.GOOS == "windows" {
		return fmt.Sprintf("%s\\%s\\%s", os.Getenv("APPDATA"),
			applicationName,
			path)
	}

	return fmt.Sprintf("%s/.config/%s/%s", os.Getenv("HOME"),
		applicationName,
		path)
}
<commit_msg>Fixing annotation for Save<commit_after>// Package store is a dead simple configuration manager for Go applications.
package store

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/BurntSushi/toml"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
)

var applicationName string

// SetApplicationName defines a unique application handle for file system.
//
// By default, Store puts all your config data to $HOME/.config/<appname>
// on *nix systems and to %APPDATA%/<appname> on Windows.
//
// Warning: Store would panic on any sensitive calls if it's not set.
func SetApplicationName(handle string) {
	applicationName = handle
}

// Load reads a configuration from `path` and puts it into `v` pointer.
//
// Path is a full filename, with extension. Since Store currently support
// TOML and JSON only, passing others would result in a corresponding error.
//
// If `path` doesn't exist, Load will create one and emptify `v` pointer by
// replacing it with a newly created object, derived from type of `v`.
func Load(path string, v interface{}) error {
	if applicationName == "" {
		panic("store: application name not defined")
	}

	globalPath := buildPath(path)

	data, err := ioutil.ReadFile(globalPath)

	if err != nil {
		// There is a chance that file we are looking for
		// just doesn't exist. In this case we are supposed
		// to create an empty configuration file, based on v.
		empty := reflect.New(reflect.TypeOf(v))
		if innerErr := Save(path, &empty); innerErr != nil {
			// Must be smth with file system... returning error from read.
			return err
		}

		v = empty

		return nil
	}

	contents := string(data)
	if strings.HasSuffix(path, ".toml") {
		if _, err := toml.Decode(contents, v); err != nil {
			return err
		}
	} else if strings.HasSuffix(path, ".json") {
		if err := json.Unmarshal(data, v); err != nil {
			return err
		}
	} else {
		return &stringError{"unknown configuration format"}
	}

	return nil
}

// Save puts a configuration from `v` pointer into a file `path`.
//
// Path is a full filename, with extension. Since Store currently support
// TOML and JSON only, passing others would result in a corresponding error.
func Save(path string, v interface{}) error {
	if applicationName == "" {
		panic("store: application name not defined")
	}

	var data []byte

	if strings.HasSuffix(path, ".toml") {
		var b bytes.Buffer

		encoder := toml.NewEncoder(&b)
		if err := encoder.Encode(v); err != nil {
			return nil
		}

		data = b.Bytes()
	} else if strings.HasSuffix(path, ".json") {
		fileData, err := json.Marshal(v)

		if err != nil {
			return err
		}

		data = fileData
	} else {
		return &stringError{"unknown configuration format"}
	}

	globalPath := buildPath(path)
	if err := os.MkdirAll(filepath.Dir(globalPath), os.ModePerm); err != nil {
		return err
	}

	if err := ioutil.WriteFile(globalPath, data, os.ModePerm); err != nil {
		return err
	}

	return nil
}

// buildPlatformPath builds a platform-dependent path for relative path given.
func buildPath(path string) string {
	if runtime.GOOS == "windows" {
		return fmt.Sprintf("%s\\%s\\%s", os.Getenv("APPDATA"),
			applicationName,
			path)
	}

	return fmt.Sprintf("%s/.config/%s/%s", os.Getenv("HOME"),
		applicationName,
		path)
}
<|endoftext|>


<commit_before>package bolster

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/nochso/bolster/bytesort"
	"github.com/nochso/bolster/codec"
	"github.com/nochso/bolster/codec/json"
	"github.com/nochso/bolster/errlist"
)

const (
	tagBolster       = "bolster"
	tagID            = "id"
	tagAutoIncrement = "inc"
)

// Store can store and retrieve structs.
type Store struct {
	codec codec.Interface
	db    *bolt.DB
	types map[reflect.Type]structType
}

// Open creates and opens a Store.
func Open(path string, mode os.FileMode, options *bolt.Options) (*Store, error) {
	db, err := bolt.Open(path, mode, options)
	if err != nil {
		return nil, err
	}
	st := &Store{
		codec: json.Codec,
		db:    db,
		types: make(map[reflect.Type]structType),
	}
	return st, nil
}

// Bolt returns the bolt.DB instance.
func (s *Store) Bolt() *bolt.DB {
	return s.db
}

// Close releases all database resources.
// All transactions must be closed before closing the database.
func (s *Store) Close() error {
	return s.db.Close()
}

// Read executes a function within the context of a managed read-only transaction.
// Any error that is returned from the function is returned from the View() method.
func (s *Store) Read(fn func(*Tx) error) error {
	return s.db.View(func(btx *bolt.Tx) error {
		tx := &Tx{btx: btx, store: s, errs: errlist.New()}
		err := fn(tx)
		if err != nil {
			return err
		}
		return tx.errs.ErrorOrNil()
	})
}

// Write executes a function within the context of a read-write managed transaction.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Any error that is returned from the function or returned from the commit is
// returned from the Write() method.
func (s *Store) Write(fn func(*Tx) error) error {
	return s.db.Update(func(btx *bolt.Tx) error {
		tx := &Tx{btx: btx, store: s, errs: errlist.New()}
		err := fn(tx)
		if err != nil {
			return err
		}
		return tx.errs.ErrorOrNil()
	})
}

// Register validates struct types for later use.
// Structs that have not been registered can not be used.
func (s *Store) Register(v ...interface{}) error {
	errs := errlist.New()
	for _, vv := range v {
		errs.Append(s.register(vv))
	}
	return errs.ErrorOrNil()
}

func (s *Store) register(v interface{}) error {
	e := newErrorFactory(register)
	t := reflect.TypeOf(v)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if t.Kind() != reflect.Struct {
		return e.with(fmt.Errorf("expected struct, got %v", t.Kind()))
	}
	if st, exists := s.types[t]; exists {
		e.structType = st
		return e.with(errors.New("type is already registered"))
	}
	st, err := newStructType(t)
	e.structType = st
	if err != nil {
		return e.with(err)
	}
	s.types[st.Type] = st
	err = s.Write(func(tx *Tx) error {
		_, err = tx.btx.CreateBucketIfNotExists(st.FullName)
		return err
	})
	return e.with(err)
}

type structType struct {
	FullName []byte
	ID       idField
	Type     reflect.Type
}

func newStructType(t reflect.Type) (structType, error) {
	st := &structType{
		FullName: []byte(t.PkgPath() + "." + t.Name()),
		Type:     t,
	}
	var err error
	st.ID, err = newIDField(t)
	if err != nil {
		return *st, err
	}
	err = st.validateBytesort()
	return *st, err
}

func (st *structType) validateBytesort() error {
	zv := reflect.Zero(st.ID.Type)
	_, err := bytesort.Encode(zv.Interface())
	if err != nil {
		err = fmt.Errorf("ID field %q is not byte encodable: %s", st.ID.Name, err)
	}
	return err
}

func (st structType) String() string {
	return string(st.FullName)
}

type idField struct {
	StructPos     int
	AutoIncrement bool
	reflect.StructField
}

func (i idField) isInteger() bool {
	return i.Type.Kind() >= reflect.Int && i.Type.Kind() <= reflect.Uint64
}

func (i idField) encode(v interface{}) ([]byte, error) {
	f := reflect.ValueOf(v)
	// always encode integer IDs with 8 bytes length
	if i.isInteger() && f.Type().Size() < 8 {
		k := f.Type().Kind()
		if k >= reflect.Int && k <= reflect.Int64 {
			f = f.Convert(reflect.TypeOf(int64(0)))
		} else {
			f = f.Convert(reflect.TypeOf(uint64(0)))
		}
	}
	return bytesort.Encode(f.Interface())
}

func (i idField) encodeStruct(structRV reflect.Value) ([]byte, error) {
	return i.encode(structRV.Field(i.StructPos).Interface())
}

func newIDField(t reflect.Type) (idField, error) {
	id := idField{StructPos: -1}
	tags := newTagList(t)
	idKeys := tags.filter(tagID)
	if len(idKeys) > 1 {
		return id, fmt.Errorf("must not have multiple fields with tag %q", tagID)
	} else if len(idKeys) == 1 {
		id.StructPos = idKeys[0]
	} else if idField, ok := t.FieldByName("ID"); ok {
		id.StructPos = idField.Index[0]
	}
	if id.StructPos == -1 {
		return id, errors.New("unable to find ID field: field has to be named \"ID\" or tagged with `bolster:\"id\"`")
	}
	id.StructField = t.Field(id.StructPos)
	id.AutoIncrement = tags.contains(id.StructPos, tagAutoIncrement)
	if !id.isInteger() && id.AutoIncrement {
		return id, fmt.Errorf("autoincremented IDs must be integer, got %s", id.Type.Kind())
	}
	return id, nil
}

type tagList [][]string

// newTagList returns a list of bolster tags for each struct field.
func newTagList(rt reflect.Type) tagList {
	tl := make([][]string, 0, rt.NumField())
	for i := 0; i < rt.NumField(); i++ {
		ftags := strings.Split(rt.Field(i).Tag.Get(tagBolster), ",")
		tl = append(tl, ftags)
	}
	return tl
}

// filter returns the positions of fields containing a tag s.
func (tl tagList) filter(s string) []int {
	keys := []int{}
	for i := range tl {
		if tl.contains(i, s) {
			keys = append(keys, i)
		}
	}
	return keys
}

// contains returns true when i'th field contains tag s.
func (tl tagList) contains(i int, s string) bool {
	for _, w := range tl[i] {
		if w == s {
			return true
		}
	}
	return false
}
<commit_msg>Optimize size via adjacent bools in idField<commit_after>package bolster

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/boltdb/bolt"
	"github.com/nochso/bolster/bytesort"
	"github.com/nochso/bolster/codec"
	"github.com/nochso/bolster/codec/json"
	"github.com/nochso/bolster/errlist"
)

const (
	tagBolster       = "bolster"
	tagID            = "id"
	tagAutoIncrement = "inc"
)

// Store can store and retrieve structs.
type Store struct {
	codec codec.Interface
	db    *bolt.DB
	types map[reflect.Type]structType
}

// Open creates and opens a Store.
func Open(path string, mode os.FileMode, options *bolt.Options) (*Store, error) {
	db, err := bolt.Open(path, mode, options)
	if err != nil {
		return nil, err
	}
	st := &Store{
		codec: json.Codec,
		db:    db,
		types: make(map[reflect.Type]structType),
	}
	return st, nil
}

// Bolt returns the bolt.DB instance.
func (s *Store) Bolt() *bolt.DB {
	return s.db
}

// Close releases all database resources.
// All transactions must be closed before closing the database.
func (s *Store) Close() error {
	return s.db.Close()
}

// Read executes a function within the context of a managed read-only transaction.
// Any error that is returned from the function is returned from the View() method.
func (s *Store) Read(fn func(*Tx) error) error {
	return s.db.View(func(btx *bolt.Tx) error {
		tx := &Tx{btx: btx, store: s, errs: errlist.New()}
		err := fn(tx)
		if err != nil {
			return err
		}
		return tx.errs.ErrorOrNil()
	})
}

// Write executes a function within the context of a read-write managed transaction.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Any error that is returned from the function or returned from the commit is
// returned from the Write() method.
func (s *Store) Write(fn func(*Tx) error) error {
	return s.db.Update(func(btx *bolt.Tx) error {
		tx := &Tx{btx: btx, store: s, errs: errlist.New()}
		err := fn(tx)
		if err != nil {
			return err
		}
		return tx.errs.ErrorOrNil()
	})
}

// Register validates struct types for later use.
// Structs that have not been registered can not be used.
func (s *Store) Register(v ...interface{}) error {
	errs := errlist.New()
	for _, vv := range v {
		errs.Append(s.register(vv))
	}
	return errs.ErrorOrNil()
}

func (s *Store) register(v interface{}) error {
	e := newErrorFactory(register)
	t := reflect.TypeOf(v)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if t.Kind() != reflect.Struct {
		return e.with(fmt.Errorf("expected struct, got %v", t.Kind()))
	}
	if st, exists := s.types[t]; exists {
		e.structType = st
		return e.with(errors.New("type is already registered"))
	}
	st, err := newStructType(t)
	e.structType = st
	if err != nil {
		return e.with(err)
	}
	s.types[st.Type] = st
	err = s.Write(func(tx *Tx) error {
		_, err = tx.btx.CreateBucketIfNotExists(st.FullName)
		return err
	})
	return e.with(err)
}

type structType struct {
	FullName []byte
	ID       idField
	Type     reflect.Type
}

func newStructType(t reflect.Type) (structType, error) {
	st := &structType{
		FullName: []byte(t.PkgPath() + "." + t.Name()),
		Type:     t,
	}
	var err error
	st.ID, err = newIDField(t)
	if err != nil {
		return *st, err
	}
	err = st.validateBytesort()
	return *st, err
}

func (st *structType) validateBytesort() error {
	zv := reflect.Zero(st.ID.Type)
	_, err := bytesort.Encode(zv.Interface())
	if err != nil {
		err = fmt.Errorf("ID field %q is not byte encodable: %s", st.ID.Name, err)
	}
	return err
}

func (st structType) String() string {
	return string(st.FullName)
}

type idField struct {
	StructPos int
	reflect.StructField
	AutoIncrement bool
}

func (i idField) isInteger() bool {
	return i.Type.Kind() >= reflect.Int && i.Type.Kind() <= reflect.Uint64
}

func (i idField) encode(v interface{}) ([]byte, error) {
	f := reflect.ValueOf(v)
	// always encode integer IDs with 8 bytes length
	if i.isInteger() && f.Type().Size() < 8 {
		k := f.Type().Kind()
		if k >= reflect.Int && k <= reflect.Int64 {
			f = f.Convert(reflect.TypeOf(int64(0)))
		} else {
			f = f.Convert(reflect.TypeOf(uint64(0)))
		}
	}
	return bytesort.Encode(f.Interface())
}

func (i idField) encodeStruct(structRV reflect.Value) ([]byte, error) {
	return i.encode(structRV.Field(i.StructPos).Interface())
}

func newIDField(t reflect.Type) (idField, error) {
	id := idField{StructPos: -1}
	tags := newTagList(t)
	idKeys := tags.filter(tagID)
	if len(idKeys) > 1 {
		return id, fmt.Errorf("must not have multiple fields with tag %q", tagID)
	} else if len(idKeys) == 1 {
		id.StructPos = idKeys[0]
	} else if idField, ok := t.FieldByName("ID"); ok {
		id.StructPos = idField.Index[0]
	}
	if id.StructPos == -1 {
		return id, errors.New("unable to find ID field: field has to be named \"ID\" or tagged with `bolster:\"id\"`")
	}
	id.StructField = t.Field(id.StructPos)
	id.AutoIncrement = tags.contains(id.StructPos, tagAutoIncrement)
	if !id.isInteger() && id.AutoIncrement {
		return id, fmt.Errorf("autoincremented IDs must be integer, got %s", id.Type.Kind())
	}
	return id, nil
}

type tagList [][]string

// newTagList returns a list of bolster tags for each struct field.
func newTagList(rt reflect.Type) tagList {
	tl := make([][]string, 0, rt.NumField())
	for i := 0; i < rt.NumField(); i++ {
		ftags := strings.Split(rt.Field(i).Tag.Get(tagBolster), ",")
		tl = append(tl, ftags)
	}
	return tl
}

// filter returns the positions of fields containing a tag s.
func (tl tagList) filter(s string) []int {
	keys := []int{}
	for i := range tl {
		if tl.contains(i, s) {
			keys = append(keys, i)
		}
	}
	return keys
}

// contains returns true when i'th field contains tag s.
func (tl tagList) contains(i int, s string) bool {
	for _, w := range tl[i] {
		if w == s {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	var n = 600851475143
	s := make([]int, 1)
	for i := 2; i <= n; i++ {
		for n%i == 0 {
			s[0] = i
			n = n / i
		}
	}
	fmt.Printf("largest prime factor %d", s[0])
}
<commit_msg>Add problem 3 question<commit_after>/*
The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?
*/

package main

import "fmt"

func main() {
	var n = 600851475143
	s := make([]int, 1)
	for i := 2; i <= n; i++ {
		for n%i == 0 {
			s[0] = i
			n = n / i
		}
	}
	fmt.Printf("largest prime factor %d", s[0])
}
<|endoftext|>


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

package sutil

import (
	"io"
	"math/rand"
	"hash/fnv"
	"io/ioutil"
	"fmt"
	"strings"
	"strconv"
	"bytes"
	"os"
	"encoding/json"
	"unicode/utf8"
	"crypto/md5"
	//"crypto/sha1"

	"sync"
	"code.google.com/p/go-uuid/uuid"
)

func HashV(addrs []string, key string) string {
	if len(addrs) == 0 {
		return ""
	}
    h := fnv.New32a()
    h.Write([]byte(key))
    hv := h.Sum32()

	return addrs[hv % uint32(len(addrs))]

}

func IsJSON(s []byte) bool {
    //var js map[string]interface{}
    var js interface{}
    return json.Unmarshal(s, &js) == nil
}

func JsonBigInt64Decode(s []byte, v interface{}) (err error) {
    d := json.NewDecoder(bytes.NewReader(s))
    d.UseNumber()
    return d.Decode(&v)
}

func ComputeFileMd5(filePath string) (string, error) {
  file, err := os.Open(filePath)
  if err != nil {
    return "", err
  }
  defer file.Close()

  hash := md5.New()
  if _, err := io.Copy(hash, file); err != nil {
    return "", err
  }

  var result []byte
  h := hash.Sum(result)

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

// 截取获取合法 num 个unicode字符 的utf8字符串
// num 为0，全部截取
// 返回截取的unicode字符个数，以及字符串
func GetInvalidUtf8String(s string, num int) (string, int) {
	rv := ""
	count := 0
	for i := 0; len(s)>0; i++ {
		ru, size := utf8.DecodeRuneInString(s)
		if ru != utf8.RuneError {
			rv += s[:size]
			count++

			if num > 0 && count >= num {
				break
			}
		}
		s = s[size:]
	}

	return rv, count
}

func GetUtf8Chars(s string, num int) string {
	rv := ""
	for i := 0; len(s)>0 && i < num; i++ {
		_, size := utf8.DecodeRuneInString(s)
		rv += s[:size]
		s = s[size:]
	}

	return rv
}

func GetUtf8Chars_old(s string, num int) string {
	b := []byte(s)
	rv := ""
	for i := 0; len(b)>0 && i < num; i++ {
		_, size := utf8.DecodeRune(b)
		rv += string(b[:size])
		b = b[size:]
	}

	return rv
}

var uuidMu sync.Mutex
func GetUUID() string {
	uuidMu.Lock()
	defer uuidMu.Unlock()

	uuidgen := uuid.NewUUID()
	return uuidgen.String()
}

func GetUniqueMd5() string {
	u := GetUUID()
	h := md5.Sum([]byte(u))
	return fmt.Sprintf("%x", h)
}

// 文件输出，目录不存在自动创建
func WriteFile(path string, data []byte, perm os.FileMode) error {

	idx := strings.LastIndex(path, "/")
	if idx != -1 {
		logdir := path[:idx]
		err := os.MkdirAll(logdir, 0777)
		if err != nil {
			return err
		}
	}

	return ioutil.WriteFile(path, data, perm)
}

// 四舍五入
func Round(val float64, deci int) float64 {
	format := fmt.Sprintf("%%0.%df", deci)
	sval := fmt.Sprintf(format, val)

	nv, _ := strconv.ParseFloat(sval, 64)

	return nv
}

const letterDigit = "0123456789"

const letterAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func randString(n int, ctype int) string {

    randset := letterAlpha
    if ctype == 1 {
        randset = letterDigit

    } else if ctype == 2 {
        randset = letterAlpha
    }

    b := make([]byte, n)
    for i := range b {
        b[i] = randset[rand.Intn(len(randset))]
    }
    return string(b)
}

func RandString(n int) string {
	return randString(n, 2)
}

func RandDigit(n int) string {
	return randString(n, 1)
}

type VersionCmp struct {
	ver string
}

func NewVersionCmp(ver string) *VersionCmp {
	v := &VersionCmp{
	}

	v.ver = v.fmtver(ver)
	return v
}

func (m *VersionCmp) fmtver(ver string) string {
	pvs := strings.Split(ver, ".")

	rv := ""
	for _, pv := range(pvs) {
		rv += fmt.Sprintf("%020s", pv)
	}

	return rv

}

func (m *VersionCmp) Min() string {
	return m.fmtver("0")
}

func (m *VersionCmp) Max() string {
	return m.fmtver("99999999999999999999")
}

func (m *VersionCmp) Lt(ver string) bool {
	return m.ver < m.fmtver(ver)
}

func (m *VersionCmp) Lte(ver string) bool {
	return m.ver <= m.fmtver(ver)
}

func (m *VersionCmp) Gt(ver string) bool {
	return m.ver > m.fmtver(ver)
}

func (m *VersionCmp) Gte(ver string) bool {
	return m.ver >= m.fmtver(ver)
}

func (m *VersionCmp) Eq(ver string) bool {
	return m.ver == m.fmtver(ver)
}

func (m *VersionCmp) Ne(ver string) bool {
	return m.ver != m.fmtver(ver)
}

<commit_msg>add emoji check<commit_after>// Copyright 2014 The sutil Author. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sutil

import (
	"io"
	"math/rand"
	"hash/fnv"
	"io/ioutil"
	"fmt"
	"strings"
	"strconv"
	"bytes"
	"os"
	"encoding/json"
	"unicode/utf8"
	"crypto/md5"
	//"crypto/sha1"

	"sync"
	"code.google.com/p/go-uuid/uuid"

	"github.com/kaneshin/go-pkg/unicode"
)

func HashV(addrs []string, key string) string {
	if len(addrs) == 0 {
		return ""
	}
    h := fnv.New32a()
    h.Write([]byte(key))
    hv := h.Sum32()

	return addrs[hv % uint32(len(addrs))]

}

func IsJSON(s []byte) bool {
    //var js map[string]interface{}
    var js interface{}
    return json.Unmarshal(s, &js) == nil
}

func JsonBigInt64Decode(s []byte, v interface{}) (err error) {
    d := json.NewDecoder(bytes.NewReader(s))
    d.UseNumber()
    return d.Decode(&v)
}

func ComputeFileMd5(filePath string) (string, error) {
  file, err := os.Open(filePath)
  if err != nil {
    return "", err
  }
  defer file.Close()

  hash := md5.New()
  if _, err := io.Copy(hash, file); err != nil {
    return "", err
  }

  var result []byte
  h := hash.Sum(result)

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

func IsHaveEmoji(s string) bool {
    rs := []rune(s)
    for _, r := range rs {
        if unicode.IsEmoji(r) {
            return true
        }
    }

    return false
}

func ReplaceEmoji(s string, ns string) string {
    var rv []rune
    rs := []rune(s)
    for _, r := range rs {
        if unicode.IsEmoji(r) {
            rv = append(rv, []rune(ns)...)
        } else {
            rv = append(rv, r)
        }
    }

    return string(rv)
}

// 截取获取合法 num 个unicode字符 的utf8字符串
// num 为0，全部截取
// 返回截取的unicode字符个数，以及字符串
func GetInvalidUtf8String(s string, num int) (string, int) {
	rv := ""
	count := 0
	for i := 0; len(s)>0; i++ {
		ru, size := utf8.DecodeRuneInString(s)
		if ru != utf8.RuneError {
			rv += s[:size]
			count++

			if num > 0 && count >= num {
				break
			}
		}
		s = s[size:]
	}

	return rv, count
}

func GetUtf8Chars(s string, num int) string {
	rv := ""
	for i := 0; len(s)>0 && i < num; i++ {
		_, size := utf8.DecodeRuneInString(s)
		rv += s[:size]
		s = s[size:]
	}

	return rv
}

func GetUtf8Chars_old(s string, num int) string {
	b := []byte(s)
	rv := ""
	for i := 0; len(b)>0 && i < num; i++ {
		_, size := utf8.DecodeRune(b)
		rv += string(b[:size])
		b = b[size:]
	}

	return rv
}

var uuidMu sync.Mutex
func GetUUID() string {
	uuidMu.Lock()
	defer uuidMu.Unlock()

	uuidgen := uuid.NewUUID()
	return uuidgen.String()
}

func GetUniqueMd5() string {
	u := GetUUID()
	h := md5.Sum([]byte(u))
	return fmt.Sprintf("%x", h)
}

// 文件输出，目录不存在自动创建
func WriteFile(path string, data []byte, perm os.FileMode) error {

	idx := strings.LastIndex(path, "/")
	if idx != -1 {
		logdir := path[:idx]
		err := os.MkdirAll(logdir, 0777)
		if err != nil {
			return err
		}
	}

	return ioutil.WriteFile(path, data, perm)
}

// 四舍五入
func Round(val float64, deci int) float64 {
	format := fmt.Sprintf("%%0.%df", deci)
	sval := fmt.Sprintf(format, val)

	nv, _ := strconv.ParseFloat(sval, 64)

	return nv
}

const letterDigit = "0123456789"

const letterAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func randString(n int, ctype int) string {

    randset := letterAlpha
    if ctype == 1 {
        randset = letterDigit

    } else if ctype == 2 {
        randset = letterAlpha
    }

    b := make([]byte, n)
    for i := range b {
        b[i] = randset[rand.Intn(len(randset))]
    }
    return string(b)
}

func RandString(n int) string {
	return randString(n, 2)
}

func RandDigit(n int) string {
	return randString(n, 1)
}

type VersionCmp struct {
	ver string
}

func NewVersionCmp(ver string) *VersionCmp {
	v := &VersionCmp{
	}

	v.ver = v.fmtver(ver)
	return v
}

func (m *VersionCmp) fmtver(ver string) string {
	pvs := strings.Split(ver, ".")

	rv := ""
	for _, pv := range(pvs) {
		rv += fmt.Sprintf("%020s", pv)
	}

	return rv

}

func (m *VersionCmp) Min() string {
	return m.fmtver("0")
}

func (m *VersionCmp) Max() string {
	return m.fmtver("99999999999999999999")
}

func (m *VersionCmp) Lt(ver string) bool {
	return m.ver < m.fmtver(ver)
}

func (m *VersionCmp) Lte(ver string) bool {
	return m.ver <= m.fmtver(ver)
}

func (m *VersionCmp) Gt(ver string) bool {
	return m.ver > m.fmtver(ver)
}

func (m *VersionCmp) Gte(ver string) bool {
	return m.ver >= m.fmtver(ver)
}

func (m *VersionCmp) Eq(ver string) bool {
	return m.ver == m.fmtver(ver)
}

func (m *VersionCmp) Ne(ver string) bool {
	return m.ver != m.fmtver(ver)
}

func (m *VersionCmp) GetFormatVersion() string{
	return m.ver
}
<|endoftext|>


<commit_before>package h2spec

import (
	"bytes"
	"github.com/bradfitz/http2"
	"github.com/bradfitz/http2/hpack"
	"time"
)

func TestData(ctx *Context) {
	PrintHeader("6.1. DATA", 0)

	func(ctx *Context) {
		desc := "Sends a DATA frame with 0x0 stream identifier"
		msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR."
		result := false

		http2Conn := CreateHttp2Conn(ctx, true)
		defer http2Conn.conn.Close()

		http2Conn.fr.WriteData(0, true, []byte("test"))
		timeCh := time.After(3 * time.Second)

	loop:
		for {
			select {
			case f := <-http2Conn.dataCh:
				gf, ok := f.(*http2.GoAwayFrame)
				if ok {
					if gf.ErrCode == http2.ErrCodeProtocol {
						result = true
					}
				}
			case <-http2Conn.errCh:
				break loop
			case <-timeCh:
				break loop
			}
		}

		PrintResult(result, desc, msg, 0)
	}(ctx)

	func(ctx *Context) {
		desc := "Sends a DATA frame on the stream that is not opend"
		msg := "The endpoint MUST respond with a stream error of type STREAM_CLOSED."
		result := false

		http2Conn := CreateHttp2Conn(ctx, true)
		defer http2Conn.conn.Close()

		var buf bytes.Buffer
		hdrs := []hpack.HeaderField{
			pair(":method", "GET"),
			pair(":scheme", "http"),
			pair(":path", "/"),
			pair(":authority", ctx.Authority()),
		}
		enc := hpack.NewEncoder(&buf)
		for _, hf := range hdrs {
			_ = enc.WriteField(hf)
		}

		var hp http2.HeadersFrameParam
		hp.StreamID = 1
		hp.EndStream = true
		hp.EndHeaders = true
		hp.BlockFragment = buf.Bytes()
		http2Conn.fr.WriteHeaders(hp)
		http2Conn.fr.WriteData(1, true, []byte("test"))

		timeCh := time.After(3 * time.Second)

	loop:
		for {
			select {
			case f := <-http2Conn.dataCh:
				gf, ok := f.(*http2.RSTStreamFrame)
				if ok {
					if gf.ErrCode == http2.ErrCodeStreamClosed {
						result = true
					}
				}
			case <-http2Conn.errCh:
				break loop
			case <-timeCh:
				break loop
			}
		}

		PrintResult(result, desc, msg, 0)
	}(ctx)

	// bradfitz/http2 does not support padding of DATA frame.
	/*
		func(ctx *Context) {
			desc := "Sends a DATA frame with invalid pad length"
			msg := "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR."
			result := false

			http2Conn := CreateHttp2Conn(ctx, true)
			defer http2Conn.conn.Close()

			var buf bytes.Buffer
			hdrs := []hpack.HeaderField{
				pair(":method", "GET"),
				pair(":scheme", "http"),
				pair(":path", "/"),
				pair(":authority", ctx.Authority()),
			}
			enc := hpack.NewEncoder(&buf)
			for _, hf := range hdrs {
				_ = enc.WriteField(hf)
			}

			var hp http2.HeadersFrameParam
			hp.StreamID = 1
			hp.EndStream = true
			hp.EndHeaders = true
			hp.BlockFragment = buf.Bytes()
			http2Conn.fr.WriteHeaders(hp)

			http2Conn.fr.WriteData(1, true, []byte("test"))

			timeCh := time.After(3 * time.Second)

		loop:
			for {
				select {
				case f := <-http2Conn.dataCh:
					gf, ok := f.(*http2.GoAwayFrame)
					if ok {
						if gf.ErrCode == http2.ErrCodeProtocol {
							result = true
						}
					}
				case <-http2Conn.errCh:
					break loop
				case <-timeCh:
					break loop
				}
			}

			PrintResult(result, desc, msg, 0)
		}(ctx)
	*/

	PrintFooter()
}
<commit_msg>should check if is either of GOAWAY or RST_STREAM<commit_after>package h2spec

import (
	"bytes"
	"github.com/bradfitz/http2"
	"github.com/bradfitz/http2/hpack"
	"time"
)

func TestData(ctx *Context) {
	PrintHeader("6.1. DATA", 0)

	func(ctx *Context) {
		desc := "Sends a DATA frame with 0x0 stream identifier"
		msg := "The endpoint MUST respond with a connection error of type PROTOCOL_ERROR."
		result := false

		http2Conn := CreateHttp2Conn(ctx, true)
		defer http2Conn.conn.Close()

		http2Conn.fr.WriteData(0, true, []byte("test"))
		timeCh := time.After(3 * time.Second)

	loop:
		for {
			select {
			case f := <-http2Conn.dataCh:
				gf, ok := f.(*http2.GoAwayFrame)
				if ok {
					if gf.ErrCode == http2.ErrCodeProtocol {
						result = true
					}
				}
			case <-http2Conn.errCh:
				break loop
			case <-timeCh:
				break loop
			}
		}

		PrintResult(result, desc, msg, 0)
	}(ctx)

	func(ctx *Context) {
		desc := "Sends a DATA frame on the stream that is not opend"
		msg := "The endpoint MUST respond with a stream error of type STREAM_CLOSED."
		result := false

		http2Conn := CreateHttp2Conn(ctx, true)
		defer http2Conn.conn.Close()

		var buf bytes.Buffer
		hdrs := []hpack.HeaderField{
			pair(":method", "GET"),
			pair(":scheme", "http"),
			pair(":path", "/"),
			pair(":authority", ctx.Authority()),
		}
		enc := hpack.NewEncoder(&buf)
		for _, hf := range hdrs {
			_ = enc.WriteField(hf)
		}

		var hp http2.HeadersFrameParam
		hp.StreamID = 1
		hp.EndStream = true
		hp.EndHeaders = true
		hp.BlockFragment = buf.Bytes()
		http2Conn.fr.WriteHeaders(hp)
		http2Conn.fr.WriteData(1, true, []byte("test"))

		timeCh := time.After(3 * time.Second)

	loop:
		for {
			select {
			case f := <-http2Conn.dataCh:
				switch f := f.(type) {
				case *http2.RSTStreamFrame:
					if f.ErrCode == http2.ErrCodeStreamClosed {
						result = true
					}
				case *http2.GoAwayFrame:
					if f.ErrCode == http2.ErrCodeStreamClosed {
						result = true
					}
				}
			case <-http2Conn.errCh:
				break loop
			case <-timeCh:
				break loop
			}
		}

		PrintResult(result, desc, msg, 0)
	}(ctx)

	// bradfitz/http2 does not support padding of DATA frame.
	/*
		func(ctx *Context) {
			desc := "Sends a DATA frame with invalid pad length"
			msg := "The endpoint MUST treat this as a connection error of type PROTOCOL_ERROR."
			result := false

			http2Conn := CreateHttp2Conn(ctx, true)
			defer http2Conn.conn.Close()

			var buf bytes.Buffer
			hdrs := []hpack.HeaderField{
				pair(":method", "GET"),
				pair(":scheme", "http"),
				pair(":path", "/"),
				pair(":authority", ctx.Authority()),
			}
			enc := hpack.NewEncoder(&buf)
			for _, hf := range hdrs {
				_ = enc.WriteField(hf)
			}

			var hp http2.HeadersFrameParam
			hp.StreamID = 1
			hp.EndStream = true
			hp.EndHeaders = true
			hp.BlockFragment = buf.Bytes()
			http2Conn.fr.WriteHeaders(hp)

			http2Conn.fr.WriteData(1, true, []byte("test"))

			timeCh := time.After(3 * time.Second)

		loop:
			for {
				select {
				case f := <-http2Conn.dataCh:
					gf, ok := f.(*http2.GoAwayFrame)
					if ok {
						if gf.ErrCode == http2.ErrCodeProtocol {
							result = true
						}
					}
				case <-http2Conn.errCh:
					break loop
				case <-timeCh:
					break loop
				}
			}

			PrintResult(result, desc, msg, 0)
		}(ctx)
	*/

	PrintFooter()
}
<|endoftext|>


<commit_before>package schema

import (
	"database/sql"
	"fmt"
	"strings"

	"github.com/juju/errors"
)

// Connection to the DB.
type Connection struct {
	db *sql.DB
}

// NewConnection stores a connection to a DB to apply schema changes to it.
func NewConnection(db *sql.DB) *Connection {
	return &Connection{db: db}
}

// Column it's the common interface between all type of columns.
type Column interface {

	// SQL generates the SQL needed to create the column.
	SQL() string
}

// CreateTable creates a new table.
func (conn *Connection) CreateTable(name string, columns []Column) error {
	lines := make([]string, len(columns))
	for i, col := range columns {
		lines[i] = col.SQL()
	}

	stmt := fmt.Sprintf("CREATE TABLE `%s` (%s) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin", name, strings.Join(lines, ","))
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropTable drops a table.
func (conn *Connection) DropTable(name string) error {
	stmt := fmt.Sprintf("DROP TABLE `%s`", name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// TableExists checks if the table already exists in the DB.
func (conn *Connection) TableExists(name string) (bool, error) {
	var n string
	err := conn.db.QueryRow(fmt.Sprintf("SHOW TABLES LIKE '%s';", name)).Scan(&n)
	switch {
	case err == sql.ErrNoRows:
		return false, nil

	case err != nil:
		return false, errors.Trace(err)

	default:
		return true, nil
	}
}

// CreateTableIfNotExists creates the table if it is not already present.
func (conn *Connection) CreateTableIfNotExists(name string, columns []Column) error {
	exists, err := conn.TableExists(name)
	switch {
	case err != nil:
		return errors.Trace(err)

	case !exists:
		return errors.Trace(conn.CreateTable(name, columns))
	}

	return nil
}

// RenameColumn changes the name of a column. It needs the current type of the column.
// It is not recommended to change the type manually with that string (though it's possible).
func (conn *Connection) RenameColumn(tableName, oldColumnName, columnName, columnType string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` CHANGE `%s` `%s` %s", tableName, oldColumnName, columnName, columnType)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddColumn creates a new column in a table that already exists.
func (conn *Connection) AddColumn(tableName string, col Column) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD %s", tableName, col.SQL())
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropColumn removes a column from a table.
func (conn *Connection) DropColumn(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropPrimaryKey removes the primary key from a table (not the column, only the index).
func (conn *Connection) DropPrimaryKey(name string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP PRIMARY KEY", name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AssignPrimaryKey sets the new primary key of the table. It should have been dropped
// before, or not exist previously.
func (conn *Connection) AssignPrimaryKey(tableName string, columnName []string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD PRIMARY KEY (`%s`)", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddUnique adds a new unique index to a column.
func (conn *Connection) AddUnique(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD UNIQUE INDEX (`%s`)", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropUnique removes the unique index of a column.
func (conn *Connection) DropUnique(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP INDEX `%s`", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// RenameTable changes the name of the table to a new one.
func (conn *Connection) RenameTable(oldName, name string) error {
	stmt := fmt.Sprintf("RENAME TABLE `%s` TO `%s`", oldName, name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}
<commit_msg>Allow test memory-only tables.<commit_after>package schema

import (
	"database/sql"
	"fmt"
	"strings"

	"github.com/juju/errors"
)

// Connection to the DB.
type Connection struct {
	db           *sql.DB
	tablesEngine string
}

// NewConnection stores a connection to a DB to apply schema changes to it.
func NewConnection(db *sql.DB) *Connection {
	return &Connection{
		db:           db,
		tablesEngine: "InnoDB",
	}
}

// NewTestConnection stores a connection to a DB to apply schema changes to it. All
// tables created with this connection will reside in memory for tests.
func NewTestConnection(db *sql.DB) *Connection {
	return &Connection{
		db:           db,
		tablesEngine: "MEMORY",
	}
}

// Column it's the common interface between all type of columns.
type Column interface {

	// SQL generates the SQL needed to create the column.
	SQL() string
}

// CreateTable creates a new table.
func (conn *Connection) CreateTable(name string, columns []Column) error {
	lines := make([]string, len(columns))
	for i, col := range columns {
		lines[i] = col.SQL()
	}

	stmt := fmt.Sprintf("CREATE TABLE `%s` (%s) ENGINE=%s DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin", name, strings.Join(lines, ","), conn.tablesEngine)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropTable drops a table.
func (conn *Connection) DropTable(name string) error {
	stmt := fmt.Sprintf("DROP TABLE `%s`", name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// TableExists checks if the table already exists in the DB.
func (conn *Connection) TableExists(name string) (bool, error) {
	var n string
	err := conn.db.QueryRow(fmt.Sprintf("SHOW TABLES LIKE '%s';", name)).Scan(&n)
	switch {
	case err == sql.ErrNoRows:
		return false, nil

	case err != nil:
		return false, errors.Trace(err)

	default:
		return true, nil
	}
}

// CreateTableIfNotExists creates the table if it is not already present.
func (conn *Connection) CreateTableIfNotExists(name string, columns []Column) error {
	exists, err := conn.TableExists(name)
	switch {
	case err != nil:
		return errors.Trace(err)

	case !exists:
		return errors.Trace(conn.CreateTable(name, columns))
	}

	return nil
}

// RenameColumn changes the name of a column. It needs the current type of the column.
// It is not recommended to change the type manually with that string (though it's possible).
func (conn *Connection) RenameColumn(tableName, oldColumnName, columnName, columnType string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` CHANGE `%s` `%s` %s", tableName, oldColumnName, columnName, columnType)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddColumn creates a new column in a table that already exists.
func (conn *Connection) AddColumn(tableName string, col Column) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD %s", tableName, col.SQL())
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropColumn removes a column from a table.
func (conn *Connection) DropColumn(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP COLUMN %s", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropPrimaryKey removes the primary key from a table (not the column, only the index).
func (conn *Connection) DropPrimaryKey(name string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP PRIMARY KEY", name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AssignPrimaryKey sets the new primary key of the table. It should have been dropped
// before, or not exist previously.
func (conn *Connection) AssignPrimaryKey(tableName string, columnName []string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD PRIMARY KEY (`%s`)", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddUnique adds a new unique index to a column.
func (conn *Connection) AddUnique(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` ADD UNIQUE INDEX (`%s`)", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// DropUnique removes the unique index of a column.
func (conn *Connection) DropUnique(tableName, columnName string) error {
	stmt := fmt.Sprintf("ALTER TABLE `%s` DROP INDEX `%s`", tableName, columnName)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// RenameTable changes the name of the table to a new one.
func (conn *Connection) RenameTable(oldName, name string) error {
	stmt := fmt.Sprintf("RENAME TABLE `%s` TO `%s`", oldName, name)
	if _, err := conn.db.Exec(stmt); err != nil {
		return errors.Trace(err)
	}

	return nil
}
<|endoftext|>


<commit_before>package qb

import (
	"fmt"
	"strings"
)

// NewTable generates a new table pointer given table name, column and table constraints
func NewTable(name string, columns []Column, constraints []Constraint) *Table {
	return &Table{
		name:        name,
		columns:     columns,
		constraints: constraints,
		builder:     NewBuilder(),
		primaryCols: []string{},
		refs:        []ref{},
	}
}

// Table is the base abstraction for any sql table
type Table struct {
	name        string
	columns     []Column
	constraints []Constraint
	builder     *Builder
	primaryCols []string
	refs        []ref
}

// SQL generates create table syntax of table
func (t *Table) SQL() string {

	cols := []string{}
	for _, v := range t.columns {
		cols = append(cols, v.SQL())
	}

	constraints := []string{}

	// build primary key constraints using primaryCols
	if len(t.primaryCols) > 0 {
		constraints = append(constraints, fmt.Sprintf("PRIMARY KEY(%s)", strings.Join(t.primaryCols, ", ")))
	}

	// build foreign key constraints using refCols
	for _, ref := range t.refs {
		constraints = append(constraints, fmt.Sprintf("FOREIGN KEY(%s) REFERENCES %s(%s)", strings.Join(ref.cols, ", "), ref.refTable, strings.Join(ref.refCols, ", ")))
	}

	for _, v := range t.constraints {
		constraints = append(constraints, v.Name)
	}

	sql, _, _ := t.builder.CreateTable(t.name, cols, constraints).Build()
	return sql
}

// AddColumn appends a new column to current table
func (t *Table) AddColumn(column Column) {
	t.columns = append(t.columns, column)
}

// AddConstraint appends a new constraint to current table
func (t *Table) AddConstraint(c Constraint) {
	t.constraints = append(t.constraints, c)
}

// AddPrimaryCol appends a primary column that will be lazily built as a constraint
func (t *Table) AddPrimary(col string) {
	t.primaryCols = append(t.primaryCols, col)
}

// AddRef appends a new reference struct that will be lazily built as a constraint
func (t *Table) AddRef(col string, refTable string, refCol string) {

	if len(t.refs) > 0 {
		for k, ref := range t.refs {
			if refTable == ref.refTable {
				t.refs[k].cols = append(t.refs[k].cols, fmt.Sprintf("`%s`", col))
				t.refs[k].refCols = append(t.refs[k].refCols, fmt.Sprintf("`%s`", refCol))
				return
			}
		}
	}

	r := ref{[]string{}, refTable, []string{}}
	r.cols = append(r.cols, col)
	r.refCols = append(r.refCols, refCol)
	t.refs = append(t.refs, r)
}

// Constraints returns the constraint slice of current table
func (t *Table) Constraints() []Constraint {
	return t.constraints
}

type ref struct {
	cols     []string
	refTable string
	refCols  []string
}
<commit_msg>fix lint errors on table<commit_after>package qb

import (
	"fmt"
	"strings"
)

// NewTable generates a new table pointer given table name, column and table constraints
func NewTable(name string, columns []Column, constraints []Constraint) *Table {
	return &Table{
		name:        name,
		columns:     columns,
		constraints: constraints,
		builder:     NewBuilder(),
		primaryCols: []string{},
		refs:        []ref{},
	}
}

// Table is the base abstraction for any sql table
type Table struct {
	name        string
	columns     []Column
	constraints []Constraint
	builder     *Builder
	primaryCols []string
	refs        []ref
}

// SQL generates create table syntax of table
func (t *Table) SQL() string {

	cols := []string{}
	for _, v := range t.columns {
		cols = append(cols, v.SQL())
	}

	constraints := []string{}

	// build primary key constraints using primaryCols
	if len(t.primaryCols) > 0 {
		constraints = append(constraints, fmt.Sprintf("PRIMARY KEY(%s)", strings.Join(t.primaryCols, ", ")))
	}

	// build foreign key constraints using refCols
	for _, ref := range t.refs {
		constraints = append(constraints, fmt.Sprintf("FOREIGN KEY(%s) REFERENCES %s(%s)", strings.Join(ref.cols, ", "), ref.refTable, strings.Join(ref.refCols, ", ")))
	}

	for _, v := range t.constraints {
		constraints = append(constraints, v.Name)
	}

	sql, _, _ := t.builder.CreateTable(t.name, cols, constraints).Build()
	return sql
}

// AddColumn appends a new column to current table
func (t *Table) AddColumn(column Column) {
	t.columns = append(t.columns, column)
}

// AddConstraint appends a new constraint to current table
func (t *Table) AddConstraint(c Constraint) {
	t.constraints = append(t.constraints, c)
}

// AddPrimary appends a primary column that will be lazily built as a primary key constraint
func (t *Table) AddPrimary(col string) {
	t.primaryCols = append(t.primaryCols, col)
}

// AddRef appends a new reference struct that will be lazily built as a foreign key constraint
func (t *Table) AddRef(col string, refTable string, refCol string) {

	if len(t.refs) > 0 {
		for k, ref := range t.refs {
			if refTable == ref.refTable {
				t.refs[k].cols = append(t.refs[k].cols, fmt.Sprintf("`%s`", col))
				t.refs[k].refCols = append(t.refs[k].refCols, fmt.Sprintf("`%s`", refCol))
				return
			}
		}
	}

	r := ref{[]string{}, refTable, []string{}}
	r.cols = append(r.cols, col)
	r.refCols = append(r.refCols, refCol)
	t.refs = append(t.refs, r)
}

// Constraints returns the constraint slice of current table
func (t *Table) Constraints() []Constraint {
	return t.constraints
}

type ref struct {
	cols     []string
	refTable string
	refCols  []string
}
<|endoftext|>


<commit_before>package gocropy

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

type Lloc struct {
	Codepoint  rune
	Adjustment float64
}

func (lloc Lloc) String() string {
	return fmt.Sprintf("%c\t%f", lloc.Codepoint, lloc.Adjustment)
}

// This implementation is weird. fmt.ScanState seems to skip leading
// whitespace on a line.
func (lloc *Lloc) Scan(state fmt.ScanState, verb rune) error {
	token, err := state.Token(false, func(r rune) bool {
		return r != '\n'
	})
	if err != nil {
		return err
	}
	//fmt.Printf("token: `%v`\n", token)
	if strings.ContainsRune(string(token), '\t') {
		_, err = fmt.Sscanf(
			string(token),
			"%c\t%f",
			&lloc.Codepoint,
			&lloc.Adjustment,
		)
	} else {
		lloc.Codepoint = ' '
		_, err = fmt.Sscanf(
			string(token),
			"%f",
			&lloc.Adjustment,
		)
	}
	return err
}

func ReadLlocs(file string) ([]Lloc, error) {
	in, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer in.Close()
	var llocs []Lloc
	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		var lloc Lloc
		_, err := fmt.Sscanf(scanner.Text(), "%v", &lloc)
		if err != nil {
			return nil, err
		}
		llocs = append(llocs, lloc)
	}
	return llocs, nil
}

func MustReadLlocs(file string) []Lloc {
	llocs, err := ReadLlocs(file)
	if err != nil {
		panic(err)
	}
	return llocs
}
<commit_msg>improve parsing of llocs<commit_after>package gocropy

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	//	"strings"
	//	"unicode/utf8"
)

type Lloc struct {
	Codepoint  rune
	Adjustment float64
}

func (lloc Lloc) String() string {
	return fmt.Sprintf("%c\t%f", lloc.Codepoint, lloc.Adjustment)
}

var splitRe = regexp.MustCompile("\\s+")

func isOkLlocLine(splits []string) bool {
	return len(splits) == 2 && len(splits[1]) > 0
}

func llocFromString(line string) (Lloc, error) {
	var lloc Lloc
	splits := splitRe.Split(line, 2)

	if !isOkLlocLine(splits) {
		return lloc, fmt.Errorf("invalid llocs line `%s`", line)
	}
	if len(splits[0]) == 0 {
		lloc.Codepoint = ' '
	} else {
		_, err := fmt.Sscanf(splits[0], "%c", &lloc.Codepoint)
		if err != nil {
			return lloc, err
		}
	}
	_, err := fmt.Sscanf(splits[1], "%f", &lloc.Adjustment)
	return lloc, err
}

func ReadLlocs(file string) ([]Lloc, error) {
	in, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer in.Close()
	var llocs []Lloc
	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		lloc, err := llocFromString(scanner.Text())
		if err != nil {
			return nil, err
		}
		llocs = append(llocs, lloc)
	}
	return llocs, nil
}

func MustReadLlocs(file string) []Lloc {
	llocs, err := ReadLlocs(file)
	if err != nil {
		panic(err)
	}
	return llocs
}
<|endoftext|>