<commit_before>package jwt_mdl

import (
	"errors"
	"github.com/dgrijalva/jwt-go"
	"net/http"
	"regexp"
)

type TokenExtractor func(r *http.Request) (string, error)
type StoreToken func(
	w http.ResponseWriter,
	r *http.Request,
	token *jwt.Token) error

type Options struct {
	// see: https://github.com/dgrijalva/jwt-go/blob/master/token.go
	// mandatory.
	// used to supply the private key for token hash validation
	KeyFunc jwt.Keyfunc

	// used to validate the jwt
	// default value is jwt.SigningMethodHS256
	SigningMethod jwt.SigningMethod

	// Function to extract the token from request.
	// The default implementation use the specification defined in:
	// https://jwt.io/introduction/
	Extractor TokenExtractor

	// store the token
	// this method is mandatory. use this to store the JWT object and/or
	// validate the JWT token value
	Store StoreToken
}

type JwtMiddleware struct {
	options Options
}

func New(options Options) *JwtMiddleware {
	if options.Store == nil {
		panic("Store is mandatory")
	}

	if options.KeyFunc == nil {
		panic("KeyFunc is mandatory")
	}

	if options.SigningMethod == nil {
		options.SigningMethod = jwt.SigningMethodHS256
	}

	// verify if a Extractor is defined
	// if don't define a extractor use the default implementation
	// "extractTokenFromHEADER"
	if options.Extractor == nil {
		options.Extractor = extractTokenFromHEADER
	}

	return &JwtMiddleware{options}
}

// middleware for negroni
func (middleware *JwtMiddleware) HandlerJWT(
	w http.ResponseWriter,
	r *http.Request,
	next http.HandlerFunc) {

	err := proccess(w, r, &middleware.options)

	// If there was an error or dont exist a next, do not call next function.
	if err == nil && next != nil {
		next(w, r)
	}
}

// proccess excute the logic flow to extract and store the JWT object
func proccess(w http.ResponseWriter, r *http.Request, options *Options) error {
	token, err := options.Extractor(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return err
	}

	// token is empty send a empty JWT token to Store method
	if token == "" {
		err = options.Store(w, r, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusUnauthorized)
		}
		return err
	}

	jwtToken, err := jwt.Parse(token, options.KeyFunc)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return err
	}

	// validate the JWT token
	if options.SigningMethod.Alg() != jwtToken.Header["alg"] || !jwtToken.Valid {
		http.Error(w, "invalid JWT token", http.StatusUnauthorized)
	}

	err = options.Store(w, r, jwtToken)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
	}

	return err
}

// extractTokenFromHEADER find the Authorization fild in HTTP HEADER.
// The Authorization example:
// Authorization: Bearer <token>
func extractTokenFromHEADER(r *http.Request) (string, error) {
	// get Authorization from HEADER
	auth := r.Header.Get("Authorization")

	// verify if is empty
	if auth == "" {
		return "", nil
	}

	// validate the Authorization HEAD format
	regex := regexp.MustCompile(`(?i)(bearer)( +)([\w-]+)`)
	if !regex.MatchString(auth) {
		msg := "Invalid Authorization header format. Authorization: Bearer <token>"
		return "", errors.New(msg)
	}

	return regex.FindStringSubmatch(auth)[3], nil
}
<commit_msg>[na] fix options method request<commit_after>package jwt_mdl

import (
	"errors"
	"github.com/dgrijalva/jwt-go"
	"net/http"
	"regexp"
	"strings"
)

type TokenExtractor func(r *http.Request) (string, error)
type StoreToken func(
	w http.ResponseWriter,
	r *http.Request,
	token *jwt.Token) error

type Options struct {
	// see: https://github.com/dgrijalva/jwt-go/blob/master/token.go
	// mandatory.
	// used to supply the private key for token hash validation
	KeyFunc jwt.Keyfunc

	// used to validate the jwt
	// default value is jwt.SigningMethodHS256
	SigningMethod jwt.SigningMethod

	// Function to extract the token from request.
	// The default implementation use the specification defined in:
	// https://jwt.io/introduction/
	Extractor TokenExtractor

	// store the token
	// this method is mandatory. use this to store the JWT object and/or
	// validate the JWT token value
	Store StoreToken
}

type JwtMiddleware struct {
	options Options
}

func New(options Options) *JwtMiddleware {
	if options.Store == nil {
		panic("Store is mandatory")
	}

	if options.KeyFunc == nil {
		panic("KeyFunc is mandatory")
	}

	if options.SigningMethod == nil {
		options.SigningMethod = jwt.SigningMethodHS256
	}

	// verify if a Extractor is defined
	// if don't define a extractor use the default implementation
	// "extractTokenFromHEADER"
	if options.Extractor == nil {
		options.Extractor = extractTokenFromHEADER
	}

	return &JwtMiddleware{options}
}

// middleware for negroni
func (middleware *JwtMiddleware) HandlerJWT(
	w http.ResponseWriter,
	r *http.Request,
	next http.HandlerFunc) {

	if strings.ToLower(r.Method) == "options" {
		w.WriteHeader(http.StatusOK)
	} else {
		err := proccess(w, r, &middleware.options)

		// If there was an error or dont exist a next, do not call next function.
		if err == nil && next != nil {
			next(w, r)
		}
	}
}

// proccess excute the logic flow to extract and store the JWT object
func proccess(w http.ResponseWriter, r *http.Request, options *Options) error {
	token, err := options.Extractor(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return err
	}

	// token is empty send a empty JWT token to Store method
	if token == "" {
		err = options.Store(w, r, nil)
		if err != nil {
			http.Error(w, err.Error(), http.StatusUnauthorized)
		}
		return err
	}

	jwtToken, err := jwt.Parse(token, options.KeyFunc)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return err
	}

	// validate the JWT token
	if options.SigningMethod.Alg() != jwtToken.Header["alg"] || !jwtToken.Valid {
		http.Error(w, "invalid JWT token", http.StatusUnauthorized)
	}

	err = options.Store(w, r, jwtToken)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
	}

	return err
}

// extractTokenFromHEADER find the Authorization fild in HTTP HEADER.
// The Authorization example:
// Authorization: Bearer <token>
func extractTokenFromHEADER(r *http.Request) (string, error) {
	// get Authorization from HEADER
	auth := r.Header.Get("Authorization")

	// verify if is empty
	if auth == "" {
		return "", nil
	}

	// validate the Authorization HEAD format
	regex := regexp.MustCompile(`(?i)(bearer)( +)([\w-]+)`)
	if !regex.MatchString(auth) {
		msg := "Invalid Authorization header format. Authorization: Bearer <token>"
		return "", errors.New(msg)
	}

	return regex.FindStringSubmatch(auth)[3], nil
}
<|endoftext|>


<commit_before>package main

/*
Minimal IRC bot in Go
*/

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"net"
	"net/http"
	"net/textproto"
	"net/url"
	"strings"
	"time"
)

const (
	VERSION = "0.1.1"
	USER = "USER"
	NICK = "NICK"
	JOIN = "JOIN"
	PING = "PING"
	PONG = "PONG"
	PRIVMSG = "PRIVMSG"
	ACTION = "\x01ACTION"
	SUFFIX = "\r\n"
	BEERTIME_WD = "Friday"
	BEERTIME_HR = 16
	BEERTIME_MIN = 30
	WIK_WORDS = 25
	JIRA = "https://webdrive.atlassian.net"
	GIPHY = "http://media.giphy.com"
	GIPHY_API = "http://api.giphy.com"
	GIPHY_KEY = "dc6zaTOxFJmzC"
	DDG_API = "http://api.duckduckgo.com"
)

/* structs */
type Privmsg struct {
	Source string
	Target string
	Message []string
}

type DuckDuckGo struct {
	AbstractText string
	AbstractURL string
}

type GIF struct {
	ID string
}

type Giphy struct {
	Data []GIF
}

/* simple message builders */
func msgUser(nick string) string {
	return USER + " " + nick + " 8 * :" + nick + SUFFIX
}

func msgNick(nick string) string {
	return NICK + " " + nick + SUFFIX
}

func msgJoin(channel string) string {
	return JOIN + " " + channel + SUFFIX
}

func msgPong(host string) string {
	return PONG + " :" + host + SUFFIX
}

func msgPrivmsg(receiver string, msg string) string {
	return PRIVMSG + " " + receiver + " :" + msg + SUFFIX
}

/* plugin helpers */
func searchGiphy(term string) (*Giphy, error) {
	var giphy *Giphy = &Giphy{}

	if term == "" {
		term = "cat"
	}
	encoded := url.QueryEscape(term)
	resource := fmt.Sprintf("%s/v1/gifs/search?api_key=%s&q=%s", GIPHY_API, GIPHY_KEY, encoded)

	resp, err := http.Get(resource)
	if err != nil {
		return giphy, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return giphy, err
	}
	if err = json.Unmarshal(body, giphy); err != nil {
		return giphy, err
	}
	return giphy, nil
}

func queryDuckDuckGo(term string) (*DuckDuckGo, error) {
	var ddg *DuckDuckGo = &DuckDuckGo{}

	encoded := url.QueryEscape(term)
	resource := fmt.Sprintf("%s?format=json&q=%s", DDG_API, encoded)

	resp, err := http.Get(resource)
	if err != nil {
		return ddg, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ddg, err
	}
	if err = json.Unmarshal(body, ddg); err != nil {
		return ddg, err
	}
	return ddg, nil
}

func timeDelta(weekday string, hour int, minute int) (string, error) {
	now := time.Now()
	wd := now.Weekday().String()
	if wd == weekday {
		y, m, d := now.Date()
		location := now.Location()

		beertime := time.Date(y, m, d, hour, minute, 0, 0, location)
		diff := beertime.Sub(now)

		if diff.Seconds() > 0 {
			return fmt.Sprintf("less than %d minute(s) to go...", int(math.Ceil(diff.Minutes()))), nil
		}
		return "it's beertime!", nil
	}
	return fmt.Sprintf("it's only %s...", strings.ToLower(wd)), nil
}

func slapAction(target string) (string, error) {
	actions := []string {
		"slaps", "kicks", "destroys", "annihilates", "punches",
		"roundhouse kicks", "rusty hooks", "pwns", "owns"}
	if strings.TrimSpace(target) != "" {
		selected_action := actions[rand.Intn(len(actions))]
		return fmt.Sprintf(ACTION + " " + selected_action + " " + target), nil
	} else {
		return fmt.Sprintf(ACTION + " zzzzz..."), nil
	}
}

/* plugins */
func replyVer(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, fmt.Sprintf("gerri version: %s", VERSION)), nil
}

func replyPing(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, ACTION + " meow"), nil
}

func replyGIF(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	giphy, err := searchGiphy(msg)
	if err != nil {
		return "", err
	}
	if len(giphy.Data) > 0 {
		m := fmt.Sprintf("%s/media/%s/giphy.gif", GIPHY, giphy.Data[rand.Intn(len(giphy.Data))].ID)
		return msgPrivmsg(pm.Target, m), nil
	}
	return msgPrivmsg(pm.Target, ACTION + " zzzzz..."), nil
}

func replyDay(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, strings.ToLower(time.Now().Weekday().String())), nil
}

func replyWik(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		ddg, err := queryDuckDuckGo(msg)
		if err != nil {
			return "", err
		}
		if ddg.AbstractText != "" && ddg.AbstractURL != "" {
			words := strings.Split(ddg.AbstractText, " ")
			var m string
			if len(words) > WIK_WORDS {
				m = fmt.Sprintf("%s... (source: %s)", strings.Join(words[:WIK_WORDS], " "), ddg.AbstractURL)
			} else {
				m = fmt.Sprintf("%s (source: %s)", ddg.AbstractText, ddg.AbstractURL)
			}
			return msgPrivmsg(pm.Target, m), nil
		}
		return msgPrivmsg(pm.Target, ACTION + " zzzzz..."), nil
	}
	return "", nil
}

func replyBeertime(pm Privmsg) (string, error) {
	td, err := timeDelta(BEERTIME_WD, BEERTIME_HR, BEERTIME_MIN)
	if err != nil {
		return "", err
	}
	return msgPrivmsg(pm.Target, td), nil
}

func replyJira(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		return msgPrivmsg(pm.Target, JIRA + "/browse/" + strings.ToUpper(msg)), nil
	}
	return msgPrivmsg(pm.Target, JIRA), nil
}

func replyAsk(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		rand.Seed(time.Now().UnixNano())
		return msgPrivmsg(pm.Target, [2]string{"yes!", "no..."}[rand.Intn(2)]), nil
	}
	return "", nil
}

func replySlap(pm Privmsg) (string, error) {
	slap, err := slapAction(strings.Join(pm.Message[1:], " "))
	if err != nil {
		return "", err
	}
	return msgPrivmsg(pm.Target, slap), nil
}

var repliers = map[string]func(Privmsg) (string, error) {
	":!ver": replyVer,
	":!version": replyVer,
	":!ping": replyPing,
	":!day": replyDay,
	":!gif": replyGIF,
	":!wik": replyWik,
	":!beertime": replyBeertime,
	":!jira": replyJira,
	":!ask": replyAsk,
	":!slap": replySlap,
}

func buildReply(conn net.Conn, pm Privmsg) {
	/* replies PRIVMSG message */
	fn, found := repliers[pm.Message[0]]
	if found {
		reply, err := fn(pm)
		if err != nil {
			log.Printf("error: %s", err)
		} else {
			if reply != "" {
				log.Printf("reply: %s", reply)
				conn.Write([]byte(reply))
			}
		}
	}
}

func connect(server string, port string) (net.Conn, error) {
	/* establishes irc connection  */
	log.Printf("connecting to %s:%s...", server, port)
	conn, err := net.Dial("tcp", server + ":" + port)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("connected")
	return conn, err
}

func send(ch chan<- string, conn net.Conn) {
	/* defines goroutine sending messages to channel */
	reader := textproto.NewReader(bufio.NewReader(conn))
	for {
		line, err := reader.ReadLine()
		if err != nil {
			log.Fatal(err)
			break
		}
		ch <- line
	}
}

func receive(ch <-chan string, conn net.Conn) {
	/* defines goroutine receiving messages from channel */
	for {
		line, ok := <-ch
		if !ok {
			log.Fatal("aborted: failed to receive from channel")
			break
		}
		log.Printf(line)

		tokens := strings.Split(line, " ")
		if tokens[0] == PING {
			// reply PING with PONG
			msg := msgPong(strings.Split(line, ":")[1])
			conn.Write([]byte(msg))
			log.Printf(msg)
		} else {
			// reply PRIVMSG
			if len(tokens) >= 4 && tokens[1] == PRIVMSG {
				pm := Privmsg{Source: tokens[0], Target: tokens[2], Message: tokens[3:]}
				go buildReply(conn, pm)  // reply asynchronously
			}
		}
	}
}

func main() {
	server, port := "chat.freenode.net", "8002"
	nick, channel := "gerri", "#microamp"

	// connect to irc
	conn, err := connect(server, port)
	if err != nil {
		log.Fatal(err)
	}

	// send messages: USER/NICK/JOIN
	conn.Write([]byte(msgUser(nick)))
	conn.Write([]byte(msgNick(nick)))
	conn.Write([]byte(msgJoin(channel)))

	defer conn.Close()

	// define goroutines communicating via channel
	ch := make(chan string)
	go send(ch, conn)
	go receive(ch, conn)

	var input string
	fmt.Scanln(&input)
}
<commit_msg>Version 0.2.1<commit_after>package main

/*
Minimal IRC bot in Go
*/

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"net"
	"net/http"
	"net/textproto"
	"net/url"
	"strings"
	"time"
)

const (
	VERSION = "0.2.1"
	USER = "USER"
	NICK = "NICK"
	JOIN = "JOIN"
	PING = "PING"
	PONG = "PONG"
	PRIVMSG = "PRIVMSG"
	ACTION = "\x01ACTION"
	SUFFIX = "\r\n"
	BEERTIME_WD = "Friday"
	BEERTIME_HR = 16
	BEERTIME_MIN = 30
	WIK_WORDS = 25
	JIRA = "https://webdrive.atlassian.net"
	GIPHY = "http://media.giphy.com"
	GIPHY_API = "http://api.giphy.com"
	GIPHY_KEY = "dc6zaTOxFJmzC"
	DDG_API = "http://api.duckduckgo.com"
)

/* structs */
type Privmsg struct {
	Source string
	Target string
	Message []string
}

type DuckDuckGo struct {
	AbstractText string
	AbstractURL string
}

type GIF struct {
	ID string
}

type Giphy struct {
	Data []GIF
}

/* simple message builders */
func msgUser(nick string) string {
	return USER + " " + nick + " 8 * :" + nick + SUFFIX
}

func msgNick(nick string) string {
	return NICK + " " + nick + SUFFIX
}

func msgJoin(channel string) string {
	return JOIN + " " + channel + SUFFIX
}

func msgPong(host string) string {
	return PONG + " :" + host + SUFFIX
}

func msgPrivmsg(receiver string, msg string) string {
	return PRIVMSG + " " + receiver + " :" + msg + SUFFIX
}

/* plugin helpers */
func searchGiphy(term string) (*Giphy, error) {
	var giphy *Giphy = &Giphy{}

	if term == "" {
		term = "cat"
	}
	encoded := url.QueryEscape(term)
	resource := fmt.Sprintf("%s/v1/gifs/search?api_key=%s&q=%s", GIPHY_API, GIPHY_KEY, encoded)

	resp, err := http.Get(resource)
	if err != nil {
		return giphy, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return giphy, err
	}
	if err = json.Unmarshal(body, giphy); err != nil {
		return giphy, err
	}
	return giphy, nil
}

func queryDuckDuckGo(term string) (*DuckDuckGo, error) {
	var ddg *DuckDuckGo = &DuckDuckGo{}

	encoded := url.QueryEscape(term)
	resource := fmt.Sprintf("%s?format=json&q=%s", DDG_API, encoded)

	resp, err := http.Get(resource)
	if err != nil {
		return ddg, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ddg, err
	}
	if err = json.Unmarshal(body, ddg); err != nil {
		return ddg, err
	}
	return ddg, nil
}

func timeDelta(weekday string, hour int, minute int) (string, error) {
	now := time.Now()
	wd := now.Weekday().String()
	if wd == weekday {
		y, m, d := now.Date()
		location := now.Location()

		beertime := time.Date(y, m, d, hour, minute, 0, 0, location)
		diff := beertime.Sub(now)

		if diff.Seconds() > 0 {
			return fmt.Sprintf("less than %d minute(s) to go...", int(math.Ceil(diff.Minutes()))), nil
		}
		return "it's beertime!", nil
	}
	return fmt.Sprintf("it's only %s...", strings.ToLower(wd)), nil
}

func slapAction(target string) (string, error) {
	actions := []string {
		"slaps", "kicks", "destroys", "annihilates", "punches",
		"roundhouse kicks", "rusty hooks", "pwns", "owns"}
	if strings.TrimSpace(target) != "" {
		selected_action := actions[rand.Intn(len(actions))]
		return fmt.Sprintf(ACTION + " " + selected_action + " " + target), nil
	} else {
		return fmt.Sprintf(ACTION + " zzzzz..."), nil
	}
}

/* plugins */
func replyVer(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, fmt.Sprintf("gerri version: %s", VERSION)), nil
}

func replyPing(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, ACTION + " meow"), nil
}

func replyGIF(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	giphy, err := searchGiphy(msg)
	if err != nil {
		return "", err
	}
	if len(giphy.Data) > 0 {
		m := fmt.Sprintf("%s/media/%s/giphy.gif", GIPHY, giphy.Data[rand.Intn(len(giphy.Data))].ID)
		return msgPrivmsg(pm.Target, m), nil
	}
	return msgPrivmsg(pm.Target, ACTION + " zzzzz..."), nil
}

func replyDay(pm Privmsg) (string, error) {
	return msgPrivmsg(pm.Target, strings.ToLower(time.Now().Weekday().String())), nil
}

func replyWik(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		ddg, err := queryDuckDuckGo(msg)
		if err != nil {
			return "", err
		}
		if ddg.AbstractText != "" && ddg.AbstractURL != "" {
			words := strings.Split(ddg.AbstractText, " ")
			var m string
			if len(words) > WIK_WORDS {
				m = fmt.Sprintf("%s... (source: %s)", strings.Join(words[:WIK_WORDS], " "), ddg.AbstractURL)
			} else {
				m = fmt.Sprintf("%s (source: %s)", ddg.AbstractText, ddg.AbstractURL)
			}
			return msgPrivmsg(pm.Target, m), nil
		}
		return msgPrivmsg(pm.Target, ACTION + " zzzzz..."), nil
	}
	return "", nil
}

func replyBeertime(pm Privmsg) (string, error) {
	td, err := timeDelta(BEERTIME_WD, BEERTIME_HR, BEERTIME_MIN)
	if err != nil {
		return "", err
	}
	return msgPrivmsg(pm.Target, td), nil
}

func replyJira(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		return msgPrivmsg(pm.Target, JIRA + "/browse/" + strings.ToUpper(msg)), nil
	}
	return msgPrivmsg(pm.Target, JIRA), nil
}

func replyAsk(pm Privmsg) (string, error) {
	msg := strings.Join(pm.Message[1:], " ")
	if strings.TrimSpace(msg) != "" {
		rand.Seed(time.Now().UnixNano())
		return msgPrivmsg(pm.Target, [2]string{"yes!", "no..."}[rand.Intn(2)]), nil
	}
	return "", nil
}

func replySlap(pm Privmsg) (string, error) {
	slap, err := slapAction(strings.Join(pm.Message[1:], " "))
	if err != nil {
		return "", err
	}
	return msgPrivmsg(pm.Target, slap), nil
}

var repliers = map[string]func(Privmsg) (string, error) {
	":!ver": replyVer,
	":!version": replyVer,
	":!ping": replyPing,
	":!day": replyDay,
	":!gif": replyGIF,
	":!wik": replyWik,
	":!beertime": replyBeertime,
	":!jira": replyJira,
	":!ask": replyAsk,
	":!slap": replySlap,
}

func buildReply(conn net.Conn, pm Privmsg) {
	/* replies PRIVMSG message */
	fn, found := repliers[pm.Message[0]]
	if found {
		reply, err := fn(pm)
		if err != nil {
			log.Printf("error: %s", err)
		} else {
			if reply != "" {
				log.Printf("reply: %s", reply)
				conn.Write([]byte(reply))
			}
		}
	}
}

func connect(server string, port string) (net.Conn, error) {
	/* establishes irc connection  */
	log.Printf("connecting to %s:%s...", server, port)
	conn, err := net.Dial("tcp", server + ":" + port)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("connected")
	return conn, err
}

func send(ch chan<- string, conn net.Conn) {
	/* defines goroutine sending messages to channel */
	reader := textproto.NewReader(bufio.NewReader(conn))
	for {
		line, err := reader.ReadLine()
		if err != nil {
			log.Fatal(err)
			break
		}
		ch <- line
	}
}

func receive(ch <-chan string, conn net.Conn) {
	/* defines goroutine receiving messages from channel */
	for {
		line, ok := <-ch
		if !ok {
			log.Fatal("aborted: failed to receive from channel")
			break
		}
		log.Printf(line)

		tokens := strings.Split(line, " ")
		if tokens[0] == PING {
			// reply PING with PONG
			msg := msgPong(strings.Split(line, ":")[1])
			conn.Write([]byte(msg))
			log.Printf(msg)
		} else {
			// reply PRIVMSG
			if len(tokens) >= 4 && tokens[1] == PRIVMSG {
				pm := Privmsg{Source: tokens[0], Target: tokens[2], Message: tokens[3:]}
				go buildReply(conn, pm)  // reply asynchronously
			}
		}
	}
}

func main() {
	server, port := "chat.freenode.net", "8002"
	nick, channel := "gerri", "#microamp"

	// connect to irc
	conn, err := connect(server, port)
	if err != nil {
		log.Fatal(err)
	}

	// send messages: USER/NICK/JOIN
	conn.Write([]byte(msgUser(nick)))
	conn.Write([]byte(msgNick(nick)))
	conn.Write([]byte(msgJoin(channel)))

	defer conn.Close()

	// define goroutines communicating via channel
	ch := make(chan string)
	go send(ch, conn)
	go receive(ch, conn)

	var input string
	fmt.Scanln(&input)
}
<|endoftext|>


<commit_before>package uno

import (
	"errors"
	"strings"

	"github.com/Unknwon/com"
	"github.com/belak/go-seabird"
	"github.com/belak/go-seabird/plugins"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("uno", newUnoPlugin)
}

type unoPlugin struct {
	games   map[string]*Game
	tracker *plugins.ChannelTracker

	BlacklistedChannels []string
	BlacklistedMessage  string
}

func newUnoPlugin(b *seabird.Bot, cm *seabird.CommandMux, tracker *plugins.ChannelTracker) error {
	p := &unoPlugin{
		games:   make(map[string]*Game),
		tracker: tracker,

		BlacklistedMessage: "Uno is blacklisted in this channel.",
	}

	err := b.Config("uno", p)
	if err != nil {
		return err
	}

	// TODO: Track channel parts

	cm.Channel("uno", p.unoCallback, &seabird.HelpInfo{
		Usage:       "[create|join|start|stop]",
		Description: "Flow control and stuff",
	})

	cm.Channel("hand", p.handCallback, &seabird.HelpInfo{
		Usage:       "hand",
		Description: "Messages you your hand in an UNO game",
	})

	cm.Channel("play", p.playCallback, &seabird.HelpInfo{
		Usage:       "play <hand_index>",
		Description: "Plays card from your hand at <hand_index> and ends your turn",
	})

	cm.Channel("draw", p.drawCallback, &seabird.HelpInfo{
		Usage:       "draw",
		Description: "Draws a card and possibly ends your turn",
	})

	cm.Channel("draw_play", p.drawPlayCallback, &seabird.HelpInfo{
		Usage:       "draw_play [yes|no]",
		Description: "Used after a call to <prefix>draw to possibly play a card",
	})

	cm.Channel("color", p.colorCallback, &seabird.HelpInfo{
		Usage:       "color red|yellow|green|blue",
		Description: "Selects next color to play",
	})

	cm.Channel("uno_state", p.stateCallback, &seabird.HelpInfo{
		Usage:       "uno_state",
		Description: "Return the top card and current player.",
	})

	return nil
}

func (p *unoPlugin) lookupDataRaw(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game) {
	user := p.tracker.LookupUser(m.Prefix.Name)
	game := p.games[m.Params[0]]

	return user, game
}

func (p *unoPlugin) lookupData(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game, error) {
	user, game := p.lookupDataRaw(b, m)

	if user == nil {
		return user, game, errors.New("Couldn't find user")
	}

	if game == nil {
		return user, game, errors.New("No game in this channel")
	}

	return user, game, nil
}

// sendMessages is an abstraction around sending the uno Message
// type. This simplifies the translation between that and IRC.
func (p *unoPlugin) sendMessages(b *seabird.Bot, m *irc.Message, uMsgs []*Message) {
	for _, uMsg := range uMsgs {
		if uMsg.Target == nil {
			b.Reply(m, "%s", uMsg.Message)
		} else if uMsg.Private {
			b.Send(&irc.Message{
				Command: "NOTICE",
				Params: []string{
					uMsg.Target.Nick,
					uMsg.Message,
				},
			})
		} else {
			b.Reply(m, "%s: %s", uMsg.Target.Nick, uMsg.Message)
		}
	}
}

func (p *unoPlugin) stateCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game == nil {
		b.MentionReply(m, "There's no game in this channel")
		return
	}

	// TODO: This should pull from some State struct or similar from
	// the Game
	if game.state == stateNew {
		b.MentionReply(m, "Game hasn't been started yet")
		return
	}
	b.MentionReply(m, "Current Player: %s", game.currentPlayer().User.Nick)
	b.MentionReply(m, "Top Card: %s", game.lastPlayed())
}

func (p *unoPlugin) unoCallback(b *seabird.Bot, m *irc.Message) {
	trailing := strings.TrimSpace(m.Trailing())

	if len(trailing) == 0 {
		p.rawUnoCallback(b, m)
		return
	}

	switch trailing {
	case "create":
		p.createCallback(b, m)
	case "join":
		p.joinCallback(b, m)
	case "start":
		p.startCallback(b, m)
	case "stop":
		p.stopCallback(b, m)
	default:
		b.MentionReply(m, "Usage: <prefix>uno [create|join|start|stop]")
	}
}

func (p *unoPlugin) rawUnoCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SayUno(user))
}

func (p *unoPlugin) createCallback(b *seabird.Bot, m *irc.Message) {
	// If the current channel is in the blacklist.
	if com.IsSliceContainsStr(p.BlacklistedChannels, m.Params[0]) {
		b.MentionReply(m, "%s", p.BlacklistedMessage)
		return
	}

	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game != nil {
		b.MentionReply(m, "There's already a game in this channel")
		return
	}

	// Create a new game, add the current user and store it.
	game, messages := NewGame(user)
	p.sendMessages(b, m, messages)
	p.games[m.Params[0]] = game
}

func (p *unoPlugin) joinCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.AddPlayer(user))
}

func (p *unoPlugin) startCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Start(user))
}

func (p *unoPlugin) stopCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, ok := game.Stop(user)

	p.sendMessages(b, m, messages)

	if ok {
		delete(p.games, m.Params[0])
	}
}

func (p *unoPlugin) handCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.GetHand(user))
}

func (p *unoPlugin) playCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, done := game.Play(user, m.Trailing())
	if done {
		delete(p.games, m.Params[0])
	}

	p.sendMessages(b, m, messages)
}

func (p *unoPlugin) drawCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Draw(user))
}

func (p *unoPlugin) drawPlayCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.DrawPlay(user, m.Trailing()))
}

func (p *unoPlugin) colorCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SetColor(user, m.Trailing()))
}
<commit_msg>Fix help text for uno commands<commit_after>package uno

import (
	"errors"
	"strings"

	"github.com/Unknwon/com"
	"github.com/belak/go-seabird"
	"github.com/belak/go-seabird/plugins"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("uno", newUnoPlugin)
}

type unoPlugin struct {
	games   map[string]*Game
	tracker *plugins.ChannelTracker

	BlacklistedChannels []string
	BlacklistedMessage  string
}

func newUnoPlugin(b *seabird.Bot, cm *seabird.CommandMux, tracker *plugins.ChannelTracker) error {
	p := &unoPlugin{
		games:   make(map[string]*Game),
		tracker: tracker,

		BlacklistedMessage: "Uno is blacklisted in this channel.",
	}

	err := b.Config("uno", p)
	if err != nil {
		return err
	}

	// TODO: Track channel parts

	cm.Channel("uno", p.unoCallback, &seabird.HelpInfo{
		Usage:       "[create|join|start|stop]",
		Description: "Flow control and stuff",
	})

	cm.Channel("hand", p.handCallback, &seabird.HelpInfo{
		Usage:       "",
		Description: "Messages you your hand in an UNO game",
	})

	cm.Channel("play", p.playCallback, &seabird.HelpInfo{
		Usage:       "<hand_index>",
		Description: "Plays card from your hand at <hand_index> and ends your turn",
	})

	cm.Channel("draw", p.drawCallback, &seabird.HelpInfo{
		Usage:       "",
		Description: "Draws a card and possibly ends your turn",
	})

	cm.Channel("draw_play", p.drawPlayCallback, &seabird.HelpInfo{
		Usage:       "[yes|no]",
		Description: "Used after a call to <prefix>draw to possibly play a card",
	})

	cm.Channel("color", p.colorCallback, &seabird.HelpInfo{
		Usage:       "red|yellow|green|blue",
		Description: "Selects next color to play",
	})

	cm.Channel("uno_state", p.stateCallback, &seabird.HelpInfo{
		Usage:       "",
		Description: "Return the top card and current player.",
	})

	return nil
}

func (p *unoPlugin) lookupDataRaw(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game) {
	user := p.tracker.LookupUser(m.Prefix.Name)
	game := p.games[m.Params[0]]

	return user, game
}

func (p *unoPlugin) lookupData(b *seabird.Bot, m *irc.Message) (*plugins.User, *Game, error) {
	user, game := p.lookupDataRaw(b, m)

	if user == nil {
		return user, game, errors.New("Couldn't find user")
	}

	if game == nil {
		return user, game, errors.New("No game in this channel")
	}

	return user, game, nil
}

// sendMessages is an abstraction around sending the uno Message
// type. This simplifies the translation between that and IRC.
func (p *unoPlugin) sendMessages(b *seabird.Bot, m *irc.Message, uMsgs []*Message) {
	for _, uMsg := range uMsgs {
		if uMsg.Target == nil {
			b.Reply(m, "%s", uMsg.Message)
		} else if uMsg.Private {
			b.Send(&irc.Message{
				Command: "NOTICE",
				Params: []string{
					uMsg.Target.Nick,
					uMsg.Message,
				},
			})
		} else {
			b.Reply(m, "%s: %s", uMsg.Target.Nick, uMsg.Message)
		}
	}
}

func (p *unoPlugin) stateCallback(b *seabird.Bot, m *irc.Message) {
	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game == nil {
		b.MentionReply(m, "There's no game in this channel")
		return
	}

	// TODO: This should pull from some State struct or similar from
	// the Game
	if game.state == stateNew {
		b.MentionReply(m, "Game hasn't been started yet")
		return
	}
	b.MentionReply(m, "Current Player: %s", game.currentPlayer().User.Nick)
	b.MentionReply(m, "Top Card: %s", game.lastPlayed())
}

func (p *unoPlugin) unoCallback(b *seabird.Bot, m *irc.Message) {
	trailing := strings.TrimSpace(m.Trailing())

	if len(trailing) == 0 {
		p.rawUnoCallback(b, m)
		return
	}

	switch trailing {
	case "create":
		p.createCallback(b, m)
	case "join":
		p.joinCallback(b, m)
	case "start":
		p.startCallback(b, m)
	case "stop":
		p.stopCallback(b, m)
	default:
		b.MentionReply(m, "Usage: <prefix>uno [create|join|start|stop]")
	}
}

func (p *unoPlugin) rawUnoCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SayUno(user))
}

func (p *unoPlugin) createCallback(b *seabird.Bot, m *irc.Message) {
	// If the current channel is in the blacklist.
	if com.IsSliceContainsStr(p.BlacklistedChannels, m.Params[0]) {
		b.MentionReply(m, "%s", p.BlacklistedMessage)
		return
	}

	user, game := p.lookupDataRaw(b, m)
	if user == nil {
		b.MentionReply(m, "Couldn't find user")
		return
	}

	if game != nil {
		b.MentionReply(m, "There's already a game in this channel")
		return
	}

	// Create a new game, add the current user and store it.
	game, messages := NewGame(user)
	p.sendMessages(b, m, messages)
	p.games[m.Params[0]] = game
}

func (p *unoPlugin) joinCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.AddPlayer(user))
}

func (p *unoPlugin) startCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Start(user))
}

func (p *unoPlugin) stopCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, ok := game.Stop(user)

	p.sendMessages(b, m, messages)

	if ok {
		delete(p.games, m.Params[0])
	}
}

func (p *unoPlugin) handCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.GetHand(user))
}

func (p *unoPlugin) playCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	messages, done := game.Play(user, m.Trailing())
	if done {
		delete(p.games, m.Params[0])
	}

	p.sendMessages(b, m, messages)
}

func (p *unoPlugin) drawCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.Draw(user))
}

func (p *unoPlugin) drawPlayCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.DrawPlay(user, m.Trailing()))
}

func (p *unoPlugin) colorCallback(b *seabird.Bot, m *irc.Message) {
	user, game, err := p.lookupData(b, m)
	if err != nil {
		b.MentionReply(m, "%s", err.Error())
		return
	}

	p.sendMessages(b, m, game.SetColor(user, m.Trailing()))
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
)

type Tree struct {
  left *Tree
  value int
  right *Tree
}

/*

  INVARIANTS:
    - Greatest value stays at top of tree.

  OPERATIONS
    - Insert
    - Remove
    - Balance(?)

*/

func main() {

  fmt.Printf("Hello\n")

}
<commit_msg>adds imperfect insert to heap.go<commit_after>package main

import (
  "fmt"
)

type Heap struct {
  left *Heap
  value int
  right *Heap
}

/*

  INVARIANTS:
    - Greatest value stays at top of heap.

  OPERATIONS
    - Insert
    - Remove
    - Balance(?)

*/

/* TODO: shouldn't only build up on the left hand side */
func insert(heap *Heap, val int) *Heap {
  if heap == nil {
    heap = &Heap{ nil, val, nil }
  } else if val > heap.value {
    heap.left = insert(heap.left, val)
  } else if val < heap.value {
    heap.left = insert(heap.left, heap.value)
    heap.value = val
  }
  return heap
}

func print_heap(heap *Heap) {
  if heap == nil {
    return
  }
  print_heap(heap.left)
  fmt.Printf("%d \n", heap.value)
  print_heap(heap.right)
}

func main() {

  var heap *Heap

  /* TODO: get values from somewhere more interesting (array?) */
  heap = insert(heap, 1);
  heap = insert(heap, 3);
  heap = insert(heap, 2);
  print_heap(heap);

}
<|endoftext|>


<commit_before>package glope

import (
	"log"
	"math"
)

type Cluster struct {
	id           int
	n            float64
	w            float64
	s            float64
	occ          map[string]int
	Transactions []*Transaction
}

type Transaction struct {
	cluster         *Cluster
	clusterPosition int
	Instance        interface{}
	Items           []string
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, Transactions: make([]*Transaction, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
	c.s++
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
	c.s--
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.Items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	trans.clusterPosition = len(c.Transactions)
	c.Transactions = append(c.Transactions, trans)
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.Items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	c.n--
	trans.cluster = nil
	c.Transactions[trans.clusterPosition] = nil
}

func (c *Cluster) clearNilTransactions(){
	nonNilTransactions := make([]*Transaction, 0)
	for _, transaction := range(c.Transactions){
		if transaction != nil{
			nonNilTransactions = append(nonNilTransactions, transaction)
		}
	}
	c.Transactions = nonNilTransactions
}

func Clusterize(data []*Transaction, repulsion float64) []*Cluster {
	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	log.Print("Initializing clusters")
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Printf("Init finished, created %d clusters", len(clusters))
	log.Print("Moving transactions to best clusters")
	for {
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Print("Finished, cleaning empty clusters")
	notEmptyClusters := make([]*Cluster, 0)
	for _, cluster := range clusters{
		if cluster.n > 0{
			cluster.clearNilTransactions()
			notEmptyClusters = append(notEmptyClusters, cluster)
		}
	}
	log.Printf("Cleaning finished, returning %d clusters", len(notEmptyClusters))
	return notEmptyClusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.Items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)

		var bestCluster *Cluster
		var bestProfit float64

		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.Items, repulsion)
			if clusterProfit > bestProfit {
				bestCluster = cluster
				bestProfit = clusterProfit
			}
		}
		if bestProfit >= profitMax {
			bestCluster.addTransaction(transaction)
			return clusters
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}
<commit_msg>added move debug logging, added move optimization<commit_after>package glope

import (
	"log"
	"math"
)

type Cluster struct {
	id           int
	n            float64 //Number of transactions
	w            float64 //Number of unique items
	s            float64 //Total number of items
	occ          map[string]int //Item to item count map
	Transactions []*Transaction
}

type Transaction struct {
	cluster         *Cluster
	clusterPosition int //Position of transaction inside cluster
	Instance        interface{}
	Items           []string
}

func getProfit(s, w, r float64) float64 {
	return s / math.Pow(w, r)
}

func newCluster(id int) *Cluster {
	return &Cluster{id: id, n: 0, w: 0, s: 0, Transactions: make([]*Transaction, 0), occ: make(map[string]int, 0)}
}

func (c *Cluster) getProfit(items []string, r float64) float64 {
	sNew := c.s + float64(len(items))
	wNew := c.w
	for _, item := range items {
		if _, found := c.occ[item]; !found {
			wNew++
		}
	}
	if c.n == 0 {
		return getProfit(sNew, wNew, r)
	} else {
		profit := getProfit(c.s*c.n, c.w, r)
		profitNew := getProfit(sNew*(c.n+1), wNew, r)
		return profitNew - profit
	}
}

func (c *Cluster) addItem(item string) {
	val, found := c.occ[item]
	if !found {
		c.occ[item] = 1
	} else {
		c.occ[item] = val + 1
	}
	c.s++
}

func (c *Cluster) removeItem(item string) {
	val, found := c.occ[item]
	if !found {
		return
	}
	if val == 1 {
		delete(c.occ, item)
	}
	c.occ[item] -= 1
	c.s--
}

func (c *Cluster) addTransaction(trans *Transaction) {
	for _, item := range trans.Items {
		c.addItem(item)
	}
	c.w = float64(len(c.occ))
	c.n++
	trans.clusterPosition = len(c.Transactions)
	c.Transactions = append(c.Transactions, trans)
	trans.cluster = c
}

func (c *Cluster) removeTransaction(trans *Transaction) {
	for _, item := range trans.Items {
		c.removeItem(item)
	}
	c.w = float64(len(c.occ))
	c.n--
	trans.cluster = nil
	c.Transactions[trans.clusterPosition] = nil
}

func (c *Cluster) clearNilTransactions(){
	nonNilTransactions := make([]*Transaction, 0)
	for _, transaction := range(c.Transactions){
		if transaction != nil{
			nonNilTransactions = append(nonNilTransactions, transaction)
		}
	}
	c.Transactions = nonNilTransactions
}

func Clusterize(data []*Transaction, repulsion float64) []*Cluster {
	if repulsion == 0 {
		repulsion = 4.0 // default value
	}
	var clusters []*Cluster
	log.Print("Initializing clusters")
	for _, transaction := range data {
		clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
	}
	log.Printf("Init finished, created %d clusters", len(clusters))
	log.Print("Moving transactions to best clusters")
	for i:=1;;i++{
		log.Printf("move %d",i)
		moved := false
		for _, transaction := range data {
			originalClusterId := transaction.cluster.id
			transaction.cluster.removeTransaction(transaction)
			clusters = addTransactionToBestCluster(clusters, transaction, repulsion)
			if transaction.cluster.id != originalClusterId {
				moved = true
			}
		}
		if !moved {
			break
		}
	}
	log.Print("Finished, cleaning empty clusters")
	notEmptyClusters := make([]*Cluster, 0)
	for _, cluster := range clusters{
		if cluster.n > 0{
			cluster.clearNilTransactions()
			notEmptyClusters = append(notEmptyClusters, cluster)
		}
	}
	log.Printf("Cleaning finished, returning %d clusters", len(notEmptyClusters))
	return notEmptyClusters
}

func addTransactionToBestCluster(clusters []*Cluster, transaction *Transaction, repulsion float64) []*Cluster {
	if len(clusters) > 0 {
		tempS := float64(len(transaction.Items))
		tempW := tempS
		profitMax := getProfit(tempS, tempW, repulsion)

		var bestCluster *Cluster
		var bestProfit float64

		for _, cluster := range clusters {
			clusterProfit := cluster.getProfit(transaction.Items, repulsion)
			if clusterProfit > bestProfit {
				bestCluster = cluster
				bestProfit = clusterProfit
			}
			if clusterProfit > profitMax{
				cluster.addTransaction(transaction)
				return clusters
			}
		}
		if bestProfit >= profitMax {
			bestCluster.addTransaction(transaction)
			return clusters
		}
	}

	cluster := newCluster(len(clusters))
	cluster.addTransaction(transaction)
	return append(clusters, cluster)
}
<|endoftext|>


<commit_before>/*Package gobcy implements a wrapper for the http://www.blockcypher.com API.
You can use it to interact with addresses, transactions, and blocks from
various blockchains, including Bitcoin's main and test3 chains,
and the BlockCypher test chain.

Please note: we assume you use are using a 64-bit architecture for deployment,
which automatically makes `int` types 64-bit. Without 64-bit ints, some values
might overflow on certain calls, depending on the blockchain you are querying.
If you are using a 32-bit system, you can change all `int` types to `int64` to
explicitly work around this issue..*/

package gobcy

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/url"
)

const baseURL = "https://api.blockcypher.com/v1/"

//API stores your BlockCypher Token, and the coin/chain
//you're querying. Coins can be "btc","bcy","ltc", and "doge".
//Chains can be "main", "test3", or "test", depending on the Coin.
//Check http://dev.blockcypher.com/ for more information.
//All your credentials are stored within an API struct, as are
//many of the API methods.
//You can allocate an API struct like so:
//	bc = gobcy.API{"your-api-token","btc","main"}
//Then query as you like:
//	chain = bc.GetChain()
type API struct {
	Token, Coin, Chain string
}

//getResponse is a boilerplate for HTTP GET responses.
func getResponse(target *url.URL) (resp *http.Response, err error) {
	resp, err = http.Get(target.String())
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//postResponse is a boilerplate for HTTP POST responses.
func postResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	resp, err = http.Post(target.String(), "application/json", data)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//putResponse is a boilerplate for HTTP PUT responses.
func putResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("PUT", target.String(), data)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//deleteResponse is a boilerplate for HTTP DELETE responses.
func deleteResponse(target *url.URL) (resp *http.Response, err error) {
	req, err := http.NewRequest("DELETE", target.String(), nil)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//constructs BlockCypher URLs for requests
func (api *API) buildURL(u string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	//add token to url, if present
	if api.Token != "" {
		values := target.Query()
		values.Set("token", api.Token)
		target.RawQuery = values.Encode()
	}
	return
}

//constructs BlockCypher URLs with parameters for requests
func (api *API) buildURLParams(u string, params map[string]string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	values := target.Query()
	//Set parameters
	for k, v := range params {
		values.Set(k, v)
	}
	//add token to url, if present
	if api.Token != "" {
		values.Set("token", api.Token)
	}
	target.RawQuery = values.Encode()
	return
}
<commit_msg>fix godoc comment<commit_after>/*Package gobcy implements a wrapper for the http://www.blockcypher.com API.
You can use it to interact with addresses, transactions, and blocks from
various blockchains, including Bitcoin's main and test3 chains,
and the BlockCypher test chain.

Please note: we assume you use are using a 64-bit architecture for deployment,
which automatically makes `int` types 64-bit. Without 64-bit ints, some values
might overflow on certain calls, depending on the blockchain you are querying.
If you are using a 32-bit system, you can change all `int` types to `int64` to
explicitly work around this issue.*/
package gobcy

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/url"
)

const baseURL = "https://api.blockcypher.com/v1/"

//API stores your BlockCypher Token, and the coin/chain
//you're querying. Coins can be "btc","bcy","ltc", and "doge".
//Chains can be "main", "test3", or "test", depending on the Coin.
//Check http://dev.blockcypher.com/ for more information.
//All your credentials are stored within an API struct, as are
//many of the API methods.
//You can allocate an API struct like so:
//	bc = gobcy.API{"your-api-token","btc","main"}
//Then query as you like:
//	chain = bc.GetChain()
type API struct {
	Token, Coin, Chain string
}

//getResponse is a boilerplate for HTTP GET responses.
func getResponse(target *url.URL) (resp *http.Response, err error) {
	resp, err = http.Get(target.String())
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//postResponse is a boilerplate for HTTP POST responses.
func postResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	resp, err = http.Post(target.String(), "application/json", data)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//putResponse is a boilerplate for HTTP PUT responses.
func putResponse(target *url.URL, data io.Reader) (resp *http.Response, err error) {
	req, err := http.NewRequest("PUT", target.String(), data)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//deleteResponse is a boilerplate for HTTP DELETE responses.
func deleteResponse(target *url.URL) (resp *http.Response, err error) {
	req, err := http.NewRequest("DELETE", target.String(), nil)
	if err != nil {
		return
	}
	resp, err = http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
		msg := make(map[string]string)
		dec := json.NewDecoder(resp.Body)
		dec.Decode(&msg)
		resp.Body.Close()
		err = errors.New(resp.Status + ", Message: " + msg["error"])
	}
	return
}

//constructs BlockCypher URLs for requests
func (api *API) buildURL(u string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	//add token to url, if present
	if api.Token != "" {
		values := target.Query()
		values.Set("token", api.Token)
		target.RawQuery = values.Encode()
	}
	return
}

//constructs BlockCypher URLs with parameters for requests
func (api *API) buildURLParams(u string, params map[string]string) (target *url.URL, err error) {
	target, err = url.Parse(baseURL + api.Coin + "/" + api.Chain + u)
	if err != nil {
		return
	}
	values := target.Query()
	//Set parameters
	for k, v := range params {
		values.Set(k, v)
	}
	//add token to url, if present
	if api.Token != "" {
		values.Set("token", api.Token)
	}
	target.RawQuery = values.Encode()
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"time"
)

var Char struct {
	class, name, race, acct string
	lvl                     int
	seen                    time.Time
}

func ChkErr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	f, err := os.OpenFile("logs/bot.log", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0640)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	// for who.go WhoChar(char string, lvl int,
	// class string, race string, acct string)
	var char = flag.String("char", "",
		"Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0,
		"Character level for update or import. Ex: 50")
	var class = flag.String("class", "",
		"Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "",
		"Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "",
		"Character account for initial import. Ex: Krimic")
	// for who.go WhoBatch(ppl string)
	var who = flag.String("who", "",
		"Batched who output. "+
			"Ex: \"[10 Ctr] Rarac  (Orc)|[ 2 War] Xatus  (Troll)\"")
	// for identify.go Identify(filename string)
	var file = flag.String("import", "",
		"Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup string)
	var time = flag.String("time", "",
		"Parse uptime for boot tracking. Ex: 58:10:26")
	// for tell.go ReplyTo(char string, tell string)
	var tell = flag.String("tell", "",
		"Tell with command and maybe operant. Ex: \"stat a longsword\"")
	// run database backup, restore, and parsing
	var backup = flag.Bool("bak", false,
		"Backup the toril.db database.")
	var restore = flag.String("res", "",
		"Restore the toril.db database from backup file. Ex: toril.db.gz")
	var short_stats = flag.Bool("s", false,
		"Run ShortStats() creation for item DB.")
	var long_stats = flag.Bool("l", false,
		"Run LongStats() creation for item DB.")

	flag.Parse()

	// only run one command at a time
	switch {
	case *time != "":
		Uptime(*time)
	case *who != "":
		WhoBatch(*who)
	case *char != "" && *tell != "":
		ReplyTo(*char, *tell)
	case *char != "" && 50 >= *lvl && *lvl > 0 &&
		*class != "" && *race != "" && *acct != "":
		WhoChar(*char, *lvl, *class, *race, *acct)
	case *short_stats:
		ShortStats()
	case *long_stats:
		LongStats()
	case *file != "":
		Identify(*file)
	case *backup:
		cmd := exec.Command("sh", "-c",
			"echo '.dump' | sqlite3 toril.db | "+
				"gzip -c >toril.db.`date +\"%Y-%m-%d\"`.gz")
		err := cmd.Run()
		ChkErr(err)
	case *restore != "": // this doesn't work on Mac OS X
		cmd := exec.Command("sh", "-c", "zcat "+*restore+" | sqlite3 toril.db")
		err := cmd.Run()
		ChkErr(err)
	}
}
<commit_msg>Change from Long/Short to FormatStats()<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"time"
)

var Char struct {
	class, name, race, acct string
	lvl                     int
	seen                    time.Time
}

func ChkErr(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	f, err := os.OpenFile("logs/bot.log", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0640)
	defer f.Close()
	ChkErr(err)
	log.SetOutput(f)

	// for who.go WhoChar(char string, lvl int,
	// class string, race string, acct string)
	var char = flag.String("char", "",
		"Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0,
		"Character level for update or import. Ex: 50")
	var class = flag.String("class", "",
		"Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "",
		"Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "",
		"Character account for initial import. Ex: Krimic")
	// for who.go WhoBatch(ppl string)
	var who = flag.String("who", "",
		"Batched who output. "+
			"Ex: \"[10 Ctr] Rarac  (Orc)|[ 2 War] Xatus  (Troll)\"")
	// for identify.go Identify(filename string)
	var file = flag.String("import", "",
		"Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup string)
	var time = flag.String("time", "",
		"Parse uptime for boot tracking. Ex: 58:10:26")
	// for tell.go ReplyTo(char string, tell string)
	var tell = flag.String("tell", "",
		"Tell with command and maybe operant. Ex: \"stat a longsword\"")
	// run database backup, restore, and parsing
	var backup = flag.Bool("bak", false,
		"Backup the toril.db database.")
	var restore = flag.String("res", "",
		"Restore the toril.db database from backup file. Ex: toril.db.gz")
	var stats = flag.Bool("s", false,
		"Run FormatStats() creation for item DB.")

	flag.Parse()

	// only run one command at a time
	switch {
	case *time != "":
		Uptime(*time)
	case *who != "":
		WhoBatch(*who)
	case *char != "" && *tell != "":
		ReplyTo(*char, *tell)
	case *char != "" && 50 >= *lvl && *lvl > 0 &&
		*class != "" && *race != "" && *acct != "":
		WhoChar(*char, *lvl, *class, *race, *acct)
	case *stats:
		FormatStats()
	case *file != "":
		Identify(*file)
	case *backup:
		cmd := exec.Command("sh", "-c",
			"echo '.dump' | sqlite3 toril.db | "+
				"gzip -c >toril.db.`date +\"%Y-%m-%d\"`.gz")
		err := cmd.Run()
		ChkErr(err)
	case *restore != "": // this doesn't work on Mac OS X
		cmd := exec.Command("sh", "-c", "zcat "+*restore+" | sqlite3 toril.db")
		err := cmd.Run()
		ChkErr(err)
	}
}
<|endoftext|>


<commit_before>package gocli

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"
)

type Command struct {
	UsageLine string
	Short     string
	Long      string

	Flags flag.FlagSet
	Args  []string

	parent  *Command
	subcmds []*Command
}

func (cmd *Command) Name() string {
	name := cmd.UsageLine
	if i := strings.Index(name, " "); i >= 0 {
		name = name[:i]
	}
	return name
}

func (cmd *Command) Usage(msg ...string) {
	// Print message if supplied
	if len(msg) == 1 {
		fmt.Fprintf(os.Stderr, "%s\n\n", msg[0])
	}

	// Print usage line
	var usage = cmd.UsageLine
	for p := cmd.parent; p != nil; p = p.parent {
		usage = p.UsageLine + " " + usage
	}
	fmt.Fprintf(os.Stderr, "Usage: %s\n\n", usage)

	// Print long
	fmt.Fprintln(os.Stderr, strings.TrimSpace(cmd.Long))

	// Print options
	var opts bytes.Buffer
	cmd.Flags.SetOutput(&opts)
	cmd.Flags.PrintDefaults()
	if len(opts.String()) != 0 {
		fmt.Fprintln(os.Stderr, "Options:")
		fmt.Fprintln(os.Stderr, opts)
	}

	// Print options for the supercommands as well
	for p := cmd.parent; p != nil; p = p.parent {
		fmt.Fprintf(os.Stderr, "Options (supercommand '%s'):", p.Name())
		p.Flags.PrintDefaults()
	}

	// Print subcommands
	if cmd.subcmds != nil {
		fmt.Fprintf(os.Stderr, "\nSubcommands:\n")
		for _, subcmd := range cmd.subcmds {
			fmt.Fprintf(os.Stderr, "  %s \t %s\n", subcmd.Name(), subcmd.Short)
		}
	}
}

func (cmd *Command) Invoke() {

}

func (cmd *Command) ParseAndInvoke(args []string) {
	err := cmd.Flags.Parse(args)
	if err != nil {
		cmd.Usage(err.Error())
	}

	fArgs := cmd.Flags.Args()

	if cmd.Args != nil {
		if len(cmd.Args) != len(fArgs) {
			cmd.Usage("Invalid number of arguments")
		}
		for i := range cmd.Args {
			cmd.Args[i] = fArgs[i]
		}

		cmd.Invoke()
		return
	}

	if len(fArgs) == 0 {
		cmd.Invoke()
		return
	}

	if cmd.subcmds == nil {
		cmd.Usage("No subcommand defined: " + fArgs[0])
	}

	name := fArgs[0]
	for _, subcmd := range cmd.subcmds {
		if subcmd.Name() == name {
			subcmd.parent = cmd
			subcmd.ParseAndInvoke(fArgs[1:])
			return
		}
	}

	cmd.Usage("No subcommand defined: " + fArgs[0])
}

func (cmd *Command) MustRegisterSubcommand(subcmd *Command) {
	if cmd.subcmds == nil {
		cmd.subcmds = []*Command{subcmd}
		return
	}

	for _, c := range cmd.subcmds {
		if c.Name() == subcmd.Name() {
			panic(fmt.Sprintf("Subcommand %s already defined", subcmd.Name()))
		}
	}

	cmd.subcmds = append(cmd.subcmds, subcmd)
}
<commit_msg>Add license into gocli.go<commit_after>/*
    The MIT License (MIT)

    Copyright (c) 2013 Ondřej Kupka

    Permission is hereby granted, free of charge, to any person obtaining a copy of
    this software and associated documentation files (the "Software"), to deal in
    the Software without restriction, including without limitation the rights to
    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
    the Software, and to permit persons to whom the Software is furnished to do so,
    subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package gocli

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"strings"
)

type Command struct {
	UsageLine string
	Short     string
	Long      string

	Flags flag.FlagSet
	Args  []string

	parent  *Command
	subcmds []*Command
}

func (cmd *Command) Name() string {
	name := cmd.UsageLine
	if i := strings.Index(name, " "); i >= 0 {
		name = name[:i]
	}
	return name
}

func (cmd *Command) Usage(msg ...string) {
	// Print message if supplied
	if len(msg) == 1 {
		fmt.Fprintf(os.Stderr, "%s\n\n", msg[0])
	}

	// Print usage line
	var usage = cmd.UsageLine
	for p := cmd.parent; p != nil; p = p.parent {
		usage = p.UsageLine + " " + usage
	}
	fmt.Fprintf(os.Stderr, "Usage: %s\n\n", usage)

	// Print long
	fmt.Fprintln(os.Stderr, strings.TrimSpace(cmd.Long))

	// Print options
	var opts bytes.Buffer
	cmd.Flags.SetOutput(&opts)
	cmd.Flags.PrintDefaults()
	if len(opts.String()) != 0 {
		fmt.Fprintln(os.Stderr, "Options:")
		fmt.Fprintln(os.Stderr, opts)
	}

	// Print options for the supercommands as well
	for p := cmd.parent; p != nil; p = p.parent {
		fmt.Fprintf(os.Stderr, "Options (supercommand '%s'):", p.Name())
		p.Flags.PrintDefaults()
	}

	// Print subcommands
	if cmd.subcmds != nil {
		fmt.Fprintf(os.Stderr, "\nSubcommands:\n")
		for _, subcmd := range cmd.subcmds {
			fmt.Fprintf(os.Stderr, "  %s \t %s\n", subcmd.Name(), subcmd.Short)
		}
	}
}

func (cmd *Command) Invoke() {

}

func (cmd *Command) ParseAndInvoke(args []string) {
	err := cmd.Flags.Parse(args)
	if err != nil {
		cmd.Usage(err.Error())
	}

	fArgs := cmd.Flags.Args()

	if cmd.Args != nil {
		if len(cmd.Args) != len(fArgs) {
			cmd.Usage("Invalid number of arguments")
		}
		for i := range cmd.Args {
			cmd.Args[i] = fArgs[i]
		}

		cmd.Invoke()
		return
	}

	if len(fArgs) == 0 {
		cmd.Invoke()
		return
	}

	if cmd.subcmds == nil {
		cmd.Usage("No subcommand defined: " + fArgs[0])
	}

	name := fArgs[0]
	for _, subcmd := range cmd.subcmds {
		if subcmd.Name() == name {
			subcmd.parent = cmd
			subcmd.ParseAndInvoke(fArgs[1:])
			return
		}
	}

	cmd.Usage("No subcommand defined: " + fArgs[0])
}

func (cmd *Command) MustRegisterSubcommand(subcmd *Command) {
	if cmd.subcmds == nil {
		cmd.subcmds = []*Command{subcmd}
		return
	}

	for _, c := range cmd.subcmds {
		if c.Name() == subcmd.Name() {
			panic(fmt.Sprintf("Subcommand %s already defined", subcmd.Name()))
		}
	}

	cmd.subcmds = append(cmd.subcmds, subcmd)
}
<|endoftext|>


<commit_before>package gohll

//**
// HLL++ Implemintation by Micha Gorelick
// paper -- http://im.micha.gd/1dc0z0S
//**

import (
	"errors"
	"github.com/reusee/mmh3"
	"math"
)

const (
	SPARSE byte = iota
	NORMAL
)

var (
	InvalidPError        = errors.New("Invalid value of P, must be 4<=p<=25")
	SamePError           = errors.New("Both HLL instances must have the same value of P")
	ErrorRateOutOfBounds = errors.New("Error rate must be 0.26>=errorRate>=0.00025390625")
)

// The default hasher uses murmurhash and return a uint64
func MMH3Hash(value string) uint64 {
	hashBytes := mmh3.Hash128([]byte(value))
	var hash uint64
	for i, value := range hashBytes {
		hash |= uint64(value) << uint(i*8)
	}
	return hash
}

type HLL struct {
	P uint8

	Hasher func(string) uint64

	m1 uint
	m2 uint

	alpha  float64
	format byte

	tempSet    *tempSet
	sparseList *sparseList

	registers []uint8
}

// NewHLLByError creates a new HLL object with error rate given by `errorRate`.
// The error must be between 26% and 0.0253%
func NewHLLByError(errorRate float64) (*HLL, error) {
	if errorRate < 0.00025390625 || errorRate > 0.26 {
		return nil, ErrorRateOutOfBounds
	}
	p := uint8(math.Ceil(math.Log2(math.Pow(1.04/errorRate, 2))))
	return NewHLL(p)
}

// NewHLL creates a new HLL object given a normal mode precision between 4 and
// 25
func NewHLL(p uint8) (*HLL, error) {
	if p < 4 || p > 25 {
		return nil, InvalidPError
	}

	m1 := uint(1 << p)
	m2 := uint(1 << 25)

	var alpha float64
	switch m1 {
	case 16:
		alpha = 0.673
	case 32:
		alpha = 0.697
	case 64:
		alpha = 0.709
	default:
		alpha = 0.7213 / (1 + 1.079/float64(m1))
	}

	format := SPARSE

	// Since HLL.registers is a uint8 slice and the SparseList is a uint32
	// slice, we switch from sparse to normal with the sparse list is |m1/4| in
	// size (ie: the same size as the registers would be.
	sparseList := newSparseList(p, int(m1/4))
	tempSet := make(tempSet, 0, int(m1/8))

	return &HLL{
		P:          p,
		Hasher:     MMH3Hash,
		m1:         m1,
		m2:         m2,
		alpha:      alpha,
		format:     format,
		tempSet:    &tempSet,
		sparseList: sparseList,
	}, nil
}

// Add will add the given string value to the HLL using the currently set
// Hasher function
func (h *HLL) Add(value string) {
	hash := h.Hasher(value)
	switch h.format {
	case NORMAL:
		h.addNormal(hash)
	case SPARSE:
		h.addSparse(hash)
	}
}

func (h *HLL) addNormal(hash uint64) {
	index := sliceUint64(hash, 63, 64-h.P)
	w := sliceUint64(hash, 63-h.P, 0) << h.P
	rho := leadingBitUint64(w) + 1
	if h.registers[index] < rho {
		h.registers[index] = rho
	}
}

func (h *HLL) addSparse(hash uint64) {
	k := encodeHash(hash, h.P)
	h.tempSet = h.tempSet.Append(k)
	if h.tempSet.Full() {
		h.mergeSparse()
		h.checkModeChange()
	}
}

func (h *HLL) mergeSparse() {
	h.sparseList.Merge(h.tempSet)
	h.tempSet.Clear()
}

func (h *HLL) checkModeChange() {
	if h.sparseList.Full() {
		h.ToNormal()
	}
}

// ToNormal will convert the current HLL to normal mode, maintaining any data
// already inserted into the structure, if it is in sparse mode
func (h *HLL) ToNormal() {
	if h.format != SPARSE {
		return
	}
	h.format = NORMAL
	h.registers = make([]uint8, h.m1)
	for _, value := range h.sparseList.Data {
		index, rho := decodeHash(value, h.P)
		if h.registers[index] < rho {
			h.registers[index] = rho
		}
	}
	for _, value := range *(h.tempSet) {
		index, rho := decodeHash(value, h.P)
		if h.registers[index] < rho {
			h.registers[index] = rho
		}
	}
	h.tempSet.Clear()
	h.sparseList.Clear()
}

// Cardinality returns the estimated cardinality of the current HLL object
func (h *HLL) Cardinality() float64 {
	var cardinality float64
	switch h.format {
	case NORMAL:
		cardinality = h.cardinalityNormal()
	case SPARSE:
		cardinality = h.cardinalitySparse()
	}
	return cardinality
}

func (h *HLL) cardinalityNormal() float64 {
	var V int
	Ebottom := 0.0
	for _, value := range h.registers {
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}

	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityNormalCorrected(Ebottom float64, V int) float64 {
	E := h.alpha * float64(h.m1*h.m1) / Ebottom
	var Eprime float64
	if E < 5*float64(h.m1) {
		Eprime = E - estimateBias(E, h.P)
	} else {
		Eprime = E
	}

	var H float64
	if V != 0 {
		H = linearCounting(h.m1, V)
	} else {
		H = Eprime
	}

	if H <= threshold(h.P) {
		return H
	}
	return Eprime
}

func (h *HLL) cardinalitySparse() float64 {
	h.mergeSparse()
	return linearCounting(h.m2, int(h.m2)-h.sparseList.Len())
}

// Union will merge all data in another HLL object into this one.
func (h *HLL) Union(other *HLL) error {
	if h.P != other.P {
		return SamePError
	}
	if other.format == NORMAL {
		if h.format == SPARSE {
			h.ToNormal()
		}
		for i := uint(0); i < h.m1; i++ {
			if other.registers[i] > h.registers[i] {
				h.registers[i] = other.registers[i]
			}
		}
	} else if h.format == NORMAL && other.format == SPARSE {
		other.mergeSparse()
		for _, value := range other.sparseList.Data {
			index, rho := decodeHash(value, h.P)
			if h.registers[index] < rho {
				h.registers[index] = rho
			}
		}
	} else if h.format == SPARSE && other.format == SPARSE {
		h.mergeSparse()
		other.mergeSparse()
		h.sparseList.Merge(other.sparseList)
		h.checkModeChange()
	}
	return nil
}

// CardinalityIntersection returns the estimated cardinality of the
// intersection between this HLL object and another one.  That is, it returns
// an estimate of the number of unique items that occur in both this and the
// other HLL object.  This is done with the Inclusion–exclusion principle and
// does not satisfy the error guarantee.
func (h *HLL) CardinalityIntersection(other *HLL) (float64, error) {
	if h.P != other.P {
		return 0.0, SamePError
	}
	A := h.Cardinality()
	B := other.Cardinality()
	AuB, _ := h.CardinalityUnion(other)
	return A + B - AuB, nil
}

// CardinalityUnion returns the estimated cardinality of the union between this
// and another HLL object.  This result would be the same as first taking the
// union between this and the other object and then calling Cardinality.
// However, by calling this function we are not making any changes to the HLL
// object.
func (h *HLL) CardinalityUnion(other *HLL) (float64, error) {
	if h.P != other.P {
		return 0.0, SamePError
	}
	cardinality := 0.0
	if h.format == NORMAL && other.format == NORMAL {
		cardinality = h.cardinalityUnionNN(other)
	} else if h.format == NORMAL && other.format == SPARSE {
		cardinality = h.cardinalityUnionNS(other)
	} else if h.format == SPARSE && other.format == NORMAL {
		cardinality, _ = other.CardinalityUnion(h)
	} else if h.format == SPARSE && other.format == SPARSE {
		cardinality = h.cardinalityUnionSS(other)
	}
	return cardinality, nil
}

func (h *HLL) cardinalityUnionNN(other *HLL) float64 {
	var V int
	Ebottom := 0.0
	for i, value := range h.registers {
		if other.registers[i] > value {
			value = other.registers[i]
		}
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}
	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityUnionNS(other *HLL) float64 {
	var V int
	other.mergeSparse()
	registerOther := make([]uint8, h.m1)
	for _, value := range other.sparseList.Data {
		index, rho := decodeHash(value, other.P)
		if registerOther[index] < rho {
			registerOther[index] = rho
		}
	}
	Ebottom := 0.0
	for i, value := range h.registers {
		if registerOther[i] > value {
			value = registerOther[i]
		}
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}
	registerOther = registerOther[:0]
	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityUnionSS(other *HLL) float64 {
	h.mergeSparse()
	other.mergeSparse()
	if h.sparseList.Len() == 0 {
		return other.Cardinality()
	} else if other.sparseList.Len() == 0 {
		return h.Cardinality()
	}
	var i, j, V int
	var idxH, idxOther uint32
	for i < h.sparseList.Len()-1 || j < other.sparseList.Len()-1 {
		if i < h.sparseList.Len() {
			idxH = getIndexSparse(h.sparseList.Get(i))
		}
		if j < other.sparseList.Len() {
			idxOther = getIndexSparse(other.sparseList.Get(j))
		}
		V += 1
		if idxH < idxOther {
			i += 1
		} else if idxH > idxOther {
			j += 1
		} else {
			i += 1
			j += 1
		}
	}
	return linearCounting(h.m2, int(h.m2)-V)
}
<commit_msg>go-lint fixes<commit_after>package gohll

//**
// HLL++ Implemintation by Micha Gorelick
// paper -- http://im.micha.gd/1dc0z0S
//**

import (
	"errors"
	"github.com/reusee/mmh3"
	"math"
)

const (
	SPARSE byte = iota
	NORMAL
)

var (
	ErrInvalidP             = errors.New("invalid value of P, must be 4<=p<=25")
	ErrSameP                = errors.New("both HLL instances must have the same value of P")
	ErrErrorRateOutOfBounds = errors.New("error rate must be 0.26>=errorRate>=0.00025390625")
)

// MMH3Hash is the default hasher and uses murmurhash to return a uint64
func MMH3Hash(value string) uint64 {
	hashBytes := mmh3.Hash128([]byte(value))
	var hash uint64
	for i, value := range hashBytes {
		hash |= uint64(value) << uint(i*8)
	}
	return hash
}

type HLL struct {
	P uint8

	Hasher func(string) uint64

	m1 uint
	m2 uint

	alpha  float64
	format byte

	tempSet    *tempSet
	sparseList *sparseList

	registers []uint8
}

// NewHLLByError creates a new HLL object with error rate given by `errorRate`.
// The error must be between 26% and 0.0253%
func NewHLLByError(errorRate float64) (*HLL, error) {
	if errorRate < 0.00025390625 || errorRate > 0.26 {
		return nil, ErrErrorRateOutOfBounds
	}
	p := uint8(math.Ceil(math.Log2(math.Pow(1.04/errorRate, 2))))
	return NewHLL(p)
}

// NewHLL creates a new HLL object given a normal mode precision between 4 and
// 25
func NewHLL(p uint8) (*HLL, error) {
	if p < 4 || p > 25 {
		return nil, ErrInvalidP
	}

	m1 := uint(1 << p)
	m2 := uint(1 << 25)

	var alpha float64
	switch m1 {
	case 16:
		alpha = 0.673
	case 32:
		alpha = 0.697
	case 64:
		alpha = 0.709
	default:
		alpha = 0.7213 / (1 + 1.079/float64(m1))
	}

	format := SPARSE

	// Since HLL.registers is a uint8 slice and the SparseList is a uint32
	// slice, we switch from sparse to normal with the sparse list is |m1/4| in
	// size (ie: the same size as the registers would be.
	sparseList := newSparseList(p, int(m1/4))
	tempSet := make(tempSet, 0, int(m1/8))

	return &HLL{
		P:          p,
		Hasher:     MMH3Hash,
		m1:         m1,
		m2:         m2,
		alpha:      alpha,
		format:     format,
		tempSet:    &tempSet,
		sparseList: sparseList,
	}, nil
}

// Add will add the given string value to the HLL using the currently set
// Hasher function
func (h *HLL) Add(value string) {
	hash := h.Hasher(value)
	switch h.format {
	case NORMAL:
		h.addNormal(hash)
	case SPARSE:
		h.addSparse(hash)
	}
}

func (h *HLL) addNormal(hash uint64) {
	index := sliceUint64(hash, 63, 64-h.P)
	w := sliceUint64(hash, 63-h.P, 0) << h.P
	rho := leadingBitUint64(w) + 1
	if h.registers[index] < rho {
		h.registers[index] = rho
	}
}

func (h *HLL) addSparse(hash uint64) {
	k := encodeHash(hash, h.P)
	h.tempSet = h.tempSet.Append(k)
	if h.tempSet.Full() {
		h.mergeSparse()
		h.checkModeChange()
	}
}

func (h *HLL) mergeSparse() {
	h.sparseList.Merge(h.tempSet)
	h.tempSet.Clear()
}

func (h *HLL) checkModeChange() {
	if h.sparseList.Full() {
		h.ToNormal()
	}
}

// ToNormal will convert the current HLL to normal mode, maintaining any data
// already inserted into the structure, if it is in sparse mode
func (h *HLL) ToNormal() {
	if h.format != SPARSE {
		return
	}
	h.format = NORMAL
	h.registers = make([]uint8, h.m1)
	for _, value := range h.sparseList.Data {
		index, rho := decodeHash(value, h.P)
		if h.registers[index] < rho {
			h.registers[index] = rho
		}
	}
	for _, value := range *(h.tempSet) {
		index, rho := decodeHash(value, h.P)
		if h.registers[index] < rho {
			h.registers[index] = rho
		}
	}
	h.tempSet.Clear()
	h.sparseList.Clear()
}

// Cardinality returns the estimated cardinality of the current HLL object
func (h *HLL) Cardinality() float64 {
	var cardinality float64
	switch h.format {
	case NORMAL:
		cardinality = h.cardinalityNormal()
	case SPARSE:
		cardinality = h.cardinalitySparse()
	}
	return cardinality
}

func (h *HLL) cardinalityNormal() float64 {
	var V int
	Ebottom := 0.0
	for _, value := range h.registers {
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}

	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityNormalCorrected(Ebottom float64, V int) float64 {
	E := h.alpha * float64(h.m1*h.m1) / Ebottom
	var Eprime float64
	if E < 5*float64(h.m1) {
		Eprime = E - estimateBias(E, h.P)
	} else {
		Eprime = E
	}

	var H float64
	if V != 0 {
		H = linearCounting(h.m1, V)
	} else {
		H = Eprime
	}

	if H <= threshold(h.P) {
		return H
	}
	return Eprime
}

func (h *HLL) cardinalitySparse() float64 {
	h.mergeSparse()
	return linearCounting(h.m2, int(h.m2)-h.sparseList.Len())
}

// Union will merge all data in another HLL object into this one.
func (h *HLL) Union(other *HLL) error {
	if h.P != other.P {
		return ErrSameP
	}
	if other.format == NORMAL {
		if h.format == SPARSE {
			h.ToNormal()
		}
		for i := uint(0); i < h.m1; i++ {
			if other.registers[i] > h.registers[i] {
				h.registers[i] = other.registers[i]
			}
		}
	} else if h.format == NORMAL && other.format == SPARSE {
		other.mergeSparse()
		for _, value := range other.sparseList.Data {
			index, rho := decodeHash(value, h.P)
			if h.registers[index] < rho {
				h.registers[index] = rho
			}
		}
	} else if h.format == SPARSE && other.format == SPARSE {
		h.mergeSparse()
		other.mergeSparse()
		h.sparseList.Merge(other.sparseList)
		h.checkModeChange()
	}
	return nil
}

// CardinalityIntersection returns the estimated cardinality of the
// intersection between this HLL object and another one.  That is, it returns
// an estimate of the number of unique items that occur in both this and the
// other HLL object.  This is done with the Inclusion–exclusion principle and
// does not satisfy the error guarantee.
func (h *HLL) CardinalityIntersection(other *HLL) (float64, error) {
	if h.P != other.P {
		return 0.0, ErrSameP
	}
	A := h.Cardinality()
	B := other.Cardinality()
	AuB, _ := h.CardinalityUnion(other)
	return A + B - AuB, nil
}

// CardinalityUnion returns the estimated cardinality of the union between this
// and another HLL object.  This result would be the same as first taking the
// union between this and the other object and then calling Cardinality.
// However, by calling this function we are not making any changes to the HLL
// object.
func (h *HLL) CardinalityUnion(other *HLL) (float64, error) {
	if h.P != other.P {
		return 0.0, ErrSameP
	}
	cardinality := 0.0
	if h.format == NORMAL && other.format == NORMAL {
		cardinality = h.cardinalityUnionNN(other)
	} else if h.format == NORMAL && other.format == SPARSE {
		cardinality = h.cardinalityUnionNS(other)
	} else if h.format == SPARSE && other.format == NORMAL {
		cardinality, _ = other.CardinalityUnion(h)
	} else if h.format == SPARSE && other.format == SPARSE {
		cardinality = h.cardinalityUnionSS(other)
	}
	return cardinality, nil
}

func (h *HLL) cardinalityUnionNN(other *HLL) float64 {
	var V int
	Ebottom := 0.0
	for i, value := range h.registers {
		if other.registers[i] > value {
			value = other.registers[i]
		}
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}
	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityUnionNS(other *HLL) float64 {
	var V int
	other.mergeSparse()
	registerOther := make([]uint8, h.m1)
	for _, value := range other.sparseList.Data {
		index, rho := decodeHash(value, other.P)
		if registerOther[index] < rho {
			registerOther[index] = rho
		}
	}
	Ebottom := 0.0
	for i, value := range h.registers {
		if registerOther[i] > value {
			value = registerOther[i]
		}
		Ebottom += math.Pow(2, -1.0*float64(value))
		if value == 0 {
			V += 1
		}
	}
	registerOther = registerOther[:0]
	return h.cardinalityNormalCorrected(Ebottom, V)
}

func (h *HLL) cardinalityUnionSS(other *HLL) float64 {
	h.mergeSparse()
	other.mergeSparse()
	if h.sparseList.Len() == 0 {
		return other.Cardinality()
	} else if other.sparseList.Len() == 0 {
		return h.Cardinality()
	}
	var i, j, V int
	var idxH, idxOther uint32
	for i < h.sparseList.Len()-1 || j < other.sparseList.Len()-1 {
		if i < h.sparseList.Len() {
			idxH = getIndexSparse(h.sparseList.Get(i))
		}
		if j < other.sparseList.Len() {
			idxOther = getIndexSparse(other.sparseList.Get(j))
		}
		V += 1
		if idxH < idxOther {
			i += 1
		} else if idxH > idxOther {
			j += 1
		} else {
			i += 1
			j += 1
		}
	}
	return linearCounting(h.m2, int(h.m2)-V)
}
<|endoftext|>


<commit_before>package flag

import (
	"bytes"
	"fmt"
	"strings"
)

const (
	minInfoLen = 12
	maxInfoLen = 24
)

type writer struct {
	buf           *bytes.Buffer
	isTop         bool
	inheritIndent string
	forceVerbose  bool
	maxInfoLen    int
}

func (w *writer) maxFlagInfoLen(f *FlagSet) int {
	var maxLen int
	for i := range f.flags {
		l := len(f.flags[i].Names)
		if f.flags[i].Arglist != "" {
			l += 1 + len(f.flags[i].Arglist)
		}
		if maxLen < l {
			maxLen = l
		}
	}
	if maxLen < minInfoLen {
		maxLen = minInfoLen
	}
	if maxLen > maxInfoLen {
		maxLen = maxInfoLen
	}
	return maxLen
}

func (w *writer) maxSubsetInfoLen(f *FlagSet, needArglist bool) int {
	var maxLen int
	for i := range f.subsets {
		l := len(f.subsets[i].self.Names)
		if needArglist {
			args := w.arglist(&f.subsets[i])
			if args != "" {
				l += 1 + len(args)
			}
		}
		if maxLen < l {
			maxLen = l
		}
	}
	if maxLen < minInfoLen {
		maxLen = minInfoLen
	}
	if maxLen > maxInfoLen {
		maxLen = maxInfoLen
	}
	return maxLen
}

func (w *writer) arglist(f *FlagSet) string {
	if f.self.Arglist == "-" {
		return ""
	}
	if f.self.Arglist != "" {
		return f.self.Arglist
	}
	var (
		arglist             string
		flagCount, setCount = len(f.flags), len(f.subsets)
	)
	if flagCount != 0 {
		if setCount != 0 {
			arglist = "[FLAG|SET]..."
		} else {
			arglist = "[FLAG]..."
		}
	} else {
		if setCount != 0 {
			arglist = "[SET]..."
		}
	}
	return arglist
}

func (w *writer) write(elem ...string) {
	for _, s := range elem {
		w.buf.WriteString(s)
	}
}

func (w *writer) nextIndent(curr string) string {
	const indent = "\t"
	return curr + indent
}

func (w *writer) writeln(elem ...string) {
	w.write(elem...)
	w.buf.WriteByte('\n')
}

func (w *writer) writeWithPads(names string, maxLen int) {
	w.write(names)
	if padlen := maxLen - len(names); padlen > 0 {
		w.write(strings.Repeat(" ", padlen))
	}
}

func (w *writer) writeLines(indent string, lines []string) {
	for _, line := range lines {
		w.writeln(indent, line)
	}
}

func (w *writer) parseFlagInfo(flag *Flag, args string) string {
	info := flag.Names
	if args != "" {
		info += " " + args
	}
	return info
}

func (w *writer) writeFlagInfo(currIndent string, flag *Flag, isTop bool, args string, maxInfoLen int) {
	w.write(currIndent)
	if isTop {
		if flag.Usage != "" {
			w.writeln(currIndent, flag.Usage)
			w.writeln()
		}
		w.writeln(currIndent, "Usage:")
		w.write(w.nextIndent(currIndent))
	}
	flagInfo := w.parseFlagInfo(flag, args)
	w.writeWithPads(flagInfo, maxInfoLen)
	if !isTop && flag.Usage != "" {
		w.write(" ", flag.Usage)
	}
}

func (w *writer) writeFlagValueInfo(flag *Flag) {
	w.write(" (")
	w.write("type: ", typeName(flag.Ptr))
	if flag.Env != "" || flag.Default != nil || flag.Selects != nil {
		if flag.Env != "" {
			w.write("; env: ", flag.Env)
			if isSlicePtr(flag.Ptr) {
				w.write(", splitted by ", fmt.Sprintf("'%s'", flag.ValSep))
			}
		}
		if flag.Default != nil {
			w.write("; default: ", fmt.Sprintf("%v", flag.Default))
		}
		if flag.Selects != nil {
			w.write("; selects: ", fmt.Sprintf("%v", flag.Selects))
		}
	}
	w.write(")")
}

func (w *writer) writeFlagSet(f *FlagSet) {
	var (
		currIndent       = w.inheritIndent
		flagIndent       = w.nextIndent(currIndent)
		outline          = !w.forceVerbose
		flagCount        = len(f.flags)
		subsetCount      = len(f.subsets)
		versionLineCount = len(f.self.versionLines)
		descLineCount    = len(f.self.descLines)
	)

	var arglist string
	if w.isTop {
		arglist = w.arglist(f)
	}
	w.writeFlagInfo(currIndent, &f.self, w.isTop, arglist, w.maxInfoLen)
	w.writeln()

	if outline && !w.isTop {
		return
	}
	if versionLineCount > 0 {
		if w.isTop {
			w.writeln()
			w.writeln(currIndent, "Version:")
			w.writeLines(flagIndent, f.self.versionLines)
		}
	}

	if descLineCount > 0 {
		if w.isTop {
			w.writeln()
			w.writeln(currIndent, "Description:")
			w.writeLines(flagIndent, f.self.descLines)
		}
	}

	if flagCount > 0 {
		if versionLineCount > 0 || descLineCount > 0 || w.isTop {
			w.writeln()
		}
		if w.isTop {
			w.writeln(currIndent, "Flags:")
		}
		var (
			maxFlagInfoLen = w.maxFlagInfoLen(f)
			nextFlagIndent = w.nextIndent(flagIndent)
		)
		for i := range f.flags {
			flag := &f.flags[i]

			w.writeFlagInfo(flagIndent, flag, false, flag.Arglist, maxFlagInfoLen)
			w.writeFlagValueInfo(flag)
			w.writeln()
			w.writeLines(nextFlagIndent, flag.descLines)
		}
	}

	if subsetCount > 0 {
		if w.isTop || descLineCount > 0 || flagCount > 0 {
			w.writeln()
		}
		if w.isTop {
			w.writeln(currIndent, "Commands:")
		}
		var (
			maxSubsetLen = w.maxSubsetInfoLen(f, !outline)
			subsetIndent = flagIndent
		)
		for i := range f.subsets {
			set := &f.subsets[i]

			nw := writer{
				buf:           w.buf,
				inheritIndent: subsetIndent,
				forceVerbose:  w.forceVerbose,
				maxInfoLen:    maxSubsetLen,
			}
			nw.writeFlagSet(set)
		}
	}
}
<commit_msg>update help message<commit_after>package flag

import (
	"bytes"
	"fmt"
	"strings"
)

const (
	minInfoLen = 12
	maxInfoLen = 24
)

type writer struct {
	buf           *bytes.Buffer
	isTop         bool
	inheritIndent string
	forceVerbose  bool
	maxInfoLen    int
}

func (w *writer) maxFlagInfoLen(f *FlagSet) int {
	var maxLen int
	for i := range f.flags {
		l := len(f.flags[i].Names)
		if f.flags[i].Arglist != "" {
			l += 1 + len(f.flags[i].Arglist)
		}
		if maxLen < l {
			maxLen = l
		}
	}
	if maxLen < minInfoLen {
		maxLen = minInfoLen
	}
	if maxLen > maxInfoLen {
		maxLen = maxInfoLen
	}
	return maxLen
}

func (w *writer) maxSubsetInfoLen(f *FlagSet, needArglist bool) int {
	var maxLen int
	for i := range f.subsets {
		l := len(f.subsets[i].self.Names)
		if needArglist {
			args := w.arglist(&f.subsets[i])
			if args != "" {
				l += 1 + len(args)
			}
		}
		if maxLen < l {
			maxLen = l
		}
	}
	if maxLen < minInfoLen {
		maxLen = minInfoLen
	}
	if maxLen > maxInfoLen {
		maxLen = maxInfoLen
	}
	return maxLen
}

func (w *writer) arglist(f *FlagSet) string {
	if f.self.Arglist == "-" {
		return ""
	}
	if f.self.Arglist != "" {
		return f.self.Arglist
	}
	var (
		arglist             string
		flagCount, setCount = len(f.flags), len(f.subsets)
	)
	if flagCount != 0 {
		if setCount != 0 {
			arglist = "[FLAG|COMMAND]..."
		} else {
			arglist = "[FLAG]..."
		}
	} else {
		if setCount != 0 {
			arglist = "[COMMAND]..."
		}
	}
	return arglist
}

func (w *writer) write(elem ...string) {
	for _, s := range elem {
		w.buf.WriteString(s)
	}
}

func (w *writer) nextIndent(curr string) string {
	const indent = "\t"
	return curr + indent
}

func (w *writer) writeln(elem ...string) {
	w.write(elem...)
	w.buf.WriteByte('\n')
}

func (w *writer) writeWithPads(names string, maxLen int) {
	w.write(names)
	if padlen := maxLen - len(names); padlen > 0 {
		w.write(strings.Repeat(" ", padlen))
	}
}

func (w *writer) writeLines(indent string, lines []string) {
	for _, line := range lines {
		w.writeln(indent, line)
	}
}

func (w *writer) parseFlagInfo(flag *Flag, args string) string {
	info := flag.Names
	if args != "" {
		info += " " + args
	}
	return info
}

func (w *writer) writeFlagInfo(currIndent string, flag *Flag, isTop bool, args string, maxInfoLen int) {
	w.write(currIndent)
	if isTop {
		if flag.Usage != "" {
			w.writeln(currIndent, flag.Usage)
			w.writeln()
		}
		w.writeln(currIndent, "Usage:")
		w.write(w.nextIndent(currIndent))
	}
	flagInfo := w.parseFlagInfo(flag, args)
	w.writeWithPads(flagInfo, maxInfoLen)
	if !isTop && flag.Usage != "" {
		w.write(" ", flag.Usage)
	}
}

func (w *writer) writeFlagValueInfo(flag *Flag) {
	w.write(" (")
	w.write("type: ", typeName(flag.Ptr))
	if flag.Env != "" || flag.Default != nil || flag.Selects != nil {
		if flag.Env != "" {
			w.write("; env: ", flag.Env)
			if isSlicePtr(flag.Ptr) {
				w.write(", splitted by ", fmt.Sprintf("'%s'", flag.ValSep))
			}
		}
		if flag.Default != nil {
			w.write("; default: ", fmt.Sprintf("%v", flag.Default))
		}
		if flag.Selects != nil {
			w.write("; selects: ", fmt.Sprintf("%v", flag.Selects))
		}
	}
	w.write(")")
}

func (w *writer) writeFlagSet(f *FlagSet) {
	var (
		currIndent       = w.inheritIndent
		flagIndent       = w.nextIndent(currIndent)
		outline          = !w.forceVerbose
		flagCount        = len(f.flags)
		subsetCount      = len(f.subsets)
		versionLineCount = len(f.self.versionLines)
		descLineCount    = len(f.self.descLines)
	)

	var arglist string
	if w.isTop {
		arglist = w.arglist(f)
	}
	w.writeFlagInfo(currIndent, &f.self, w.isTop, arglist, w.maxInfoLen)
	w.writeln()

	if outline && !w.isTop {
		return
	}
	if versionLineCount > 0 {
		if w.isTop {
			w.writeln()
			w.writeln(currIndent, "Version:")
			w.writeLines(flagIndent, f.self.versionLines)
		}
	}

	if descLineCount > 0 {
		if w.isTop {
			w.writeln()
			w.writeln(currIndent, "Description:")
			w.writeLines(flagIndent, f.self.descLines)
		}
	}

	if flagCount > 0 {
		if versionLineCount > 0 || descLineCount > 0 || w.isTop {
			w.writeln()
		}
		if w.isTop {
			w.writeln(currIndent, "Flags:")
		}
		var (
			maxFlagInfoLen = w.maxFlagInfoLen(f)
			nextFlagIndent = w.nextIndent(flagIndent)
		)
		for i := range f.flags {
			flag := &f.flags[i]

			w.writeFlagInfo(flagIndent, flag, false, flag.Arglist, maxFlagInfoLen)
			w.writeFlagValueInfo(flag)
			w.writeln()
			w.writeLines(nextFlagIndent, flag.descLines)
		}
	}

	if subsetCount > 0 {
		if w.isTop || descLineCount > 0 || flagCount > 0 {
			w.writeln()
		}
		if w.isTop {
			w.writeln(currIndent, "Commands:")
		}
		var (
			maxSubsetLen = w.maxSubsetInfoLen(f, !outline)
			subsetIndent = flagIndent
		)
		for i := range f.subsets {
			set := &f.subsets[i]

			nw := writer{
				buf:           w.buf,
				inheritIndent: subsetIndent,
				forceVerbose:  w.forceVerbose,
				maxInfoLen:    maxSubsetLen,
			}
			nw.writeFlagSet(set)
		}
	}
}
<|endoftext|>


<commit_before>package golib

import (
    _ "bitbucket.org/mikespook/golib/cache"
    _ "bitbucket.org/mikespook/golib/log"
    _ "bitbucket.org/mikespook/golib/util"
)
<commit_msg>fixed the import path<commit_after>package golib

import (
    _ "bitbucket.org/mikespook/golib/cache"
    _ "bitbucket.org/mikespook/golib/log"
    _ "bitbucket.org/mikespook/golib/pid"
    _ "bitbucket.org/mikespook/golib/prof"
    _ "bitbucket.org/mikespook/golib/signal"
)
<|endoftext|>