<commit_before>package goriot

import (
	"fmt"
)

type playerStatsSummaryList struct {
	PlayerStatSummaries []PlayerStatsSummary `json:"playerStatSummaries"`
	SummonerID          int64                `json:"summonerId"`
}

//PlayerStatsSummary represents a summary of a League of Legends player's game stats
type PlayerStatsSummary struct {
	AggregatedStats       AggregatedStats `json:"aggregatedStats"`
	Losses                int             `json:"losses"`
	ModifyDate            int64           `json:"modifyDate"`
	PlayerStatSummaryType string          `json:"playerStatSummaryType"`
	Wins                  int             `json:"wins"`
}

//AggregatedStats contain all values for a player's game stat values
type AggregatedStats struct {
	AverageAssists              int `json:"averageAssists"`
	AverageChampionsKilled      int `json:"averageChampionsKilled"`
	AverageCombatPlayerScore    int `json:"averageCombatPlayerScore"`
	AverageNodeCapture          int `json:"averageNodeCapture"`
	AverageNodeCaptureAssist    int `json:"averageNodeCaptureAssist"`
	AverageNodeNeutralize       int `json:"averageNodeNeutralize"`
	AverageNodeNeutralizeAssist int `json:"averageNodeNeutralizeAssist"`
	AverageNumDeaths            int `json:"averageNumDeaths"`
	AverageObjectivePlayerScore int `json:"averageObjectivePlayerScore"`
	AverageTeamObjective        int `json:"averageTeamObjective"`
	AverageTotalPlayerScore     int `json:"averageTotalPlayerScore"`
	BotGamesPlayed              int `json:"botGamesPlayed"`
	KillingSpree                int `json:"killingSpree"`
	MaxAssists                  int `json:"maxAssists"`
	MaxChampionsKilled          int `json:"maxChampionsKilled"`
	MaxCombatPlayerScore        int `json:"maxCombatPlayerScore"`
	MaxLargestCriticalStrike    int `json:"maxLargestCriticalStrike"`
	MaxLargestKillingSpree      int `json:"maxLargestKillingSpree"`
	MaxNodeCapture              int `json:"maxNodeCapture"`
	MaxNodeCaptureAssist        int `json:"maxNodeCaptureAssist"`
	MaxNodeNeutralize           int `json:"maxNodeNeutralize"`
	MaxNodeNeutralizeAssist     int `json:"maxNodeNeutralizeAssist"`
	MaxObjectivePlayerScore     int `json:"maxObjectivePlayerScore"`
	MaxTeamObjective            int `json:"maxTeamObjective"`
	MaxTimePlayed               int `json:"maxTimePlayed"`
	MaxTimeSpentLiving          int `json:"maxTimeSpentLiving"`
	MaxTotalPlayerScore         int `json:"maxTotalPlayerScore"`
	MostChampionKillsPerSession int `json:"mostChampionKillsPerSession"`
	MostSpellsCast              int `json:"mostSpellsCast"`
	NormalGamesPlayed           int `json:"normalGamesPlayed"`
	RankedPremadeGamesPlayed    int `json:"rankedPremadeGamesPlayed"`
	RankedSoloGamesPlayed       int `json:"rankedSoloGamesPlayed"`
	TotalAssists                int `json:"totalAssists"`
	TotalChampionKills          int `json:"totalChampionKills"`
	TotalDamageDealt            int `json:"totalDamageDealt"`
	TotalDamageTaken            int `json:"totalDamageTaken"`
	TotalDoubleKills            int `json:"totalDoubleKills"`
	TotalFirstBlood             int `json:"totalFirstBlood"`
	TotalGoldEarned             int `json:"totalGoldEarned"`
	TotalHeal                   int `json:"totalHeal"`
	TotalMagicDamageDealt       int `json:"totalMagicDamageDealt"`
	TotalMinionKills            int `json:"totalMinionKills"`
	TotalNeutralMinionsKilled   int `json:"totalNeutralMinionsKilled"`
	TotalNodeCapture            int `json:"totalNodeCapture"`
	TotalNodeNeutralize         int `json:"totalNodeNeutralize"`
	TotalPentaKills             int `json:"totalPentaKills"`
	TotalPhysicalDamageDealt    int `json:"totalPhysicalDamageDealt"`
	TotalQuadraKills            int `json:"totalQuadraKills"`
	TotalSessionsLost           int `json:"totalSessionsLost"`
	TotalSessionsPlayed         int `json:"totalSessionsPlayed"`
	TotalSessionsWon            int `json:"totalSessionsWon"`
	TotalTripleKills            int `json:"totalTripleKills"`
	TotalTurretsKilled          int `json:"totalTurretsKilled"`
	TotalUnrealKills            int `json:"totalUnrealKills"`
}

//RankedStats represents a League of Legends player's statistics for ranked play
type RankedStats struct {
	Champions  []ChampionStats `json:"champions"`
	ModifyDate int64           `json:"modifyDate"`
	SummonerID int64           `json:"summonerId"`
}

//ChampionStats are the stats for a League of Legends player's champion in ranked
type ChampionStats struct {
	ID    int             `json:"id"`
	Name  string          `json:"name"`
	Stats AggregatedStats `json:"stats"`
}

//StatSummariesBySummoner retrieves the statistics of the supplied summonerID from Riot Games API.
//It returns an array of PlayerStatsSummary and any errors that occured from the server
//The global API key must be set before use
func StatSummariesBySummoner(region string, summonerID int64, season string) (stats []PlayerStatsSummary, err error) {
	var list playerStatsSummaryList
	if !IsKeySet() {
		return stats, ErrAPIKeyNotSet
	}
	var args string
	if season != "" {
		args = fmt.Sprintf("season=%s&", season)
	}
	args += "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.2/stats/by-summoner/%d/summary?%v", BaseURL, region, summonerID, args)

	err = requestAndUnmarshal(url, &list)
	if err != nil {
		return
	}
	return list.PlayerStatSummaries, err
}

//RankedStatsBySummoner retrieves the ranked statistics of the supplied summonerID from Riot Games API.
//It returns a RankedStats and any errors that occured from the server
//The global API key must be set before use
func RankedStatsBySummoner(region string, summonerID int64, season string) (stats RankedStats, err error) {
	if !IsKeySet() {
		return stats, ErrAPIKeyNotSet
	}
	var args string
	if season != "" {
		args = fmt.Sprintf("season=%s&", season)
	}
	args += "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.2/stats/by-summoner/%d/ranked?%v", BaseURL, region, summonerID, args)

	err = requestAndUnmarshal(url, &stats)
	if err != nil {
		return
	}
	return
}
<commit_msg>Added TotalDeathsPerSession.<commit_after>package goriot

import (
	"fmt"
)

type playerStatsSummaryList struct {
	PlayerStatSummaries []PlayerStatsSummary `json:"playerStatSummaries"`
	SummonerID          int64                `json:"summonerId"`
}

//PlayerStatsSummary represents a summary of a League of Legends player's game stats
type PlayerStatsSummary struct {
	AggregatedStats       AggregatedStats `json:"aggregatedStats"`
	Losses                int             `json:"losses"`
	ModifyDate            int64           `json:"modifyDate"`
	PlayerStatSummaryType string          `json:"playerStatSummaryType"`
	Wins                  int             `json:"wins"`
}

//AggregatedStats contain all values for a player's game stat values
type AggregatedStats struct {
	AverageAssists              int `json:"averageAssists"`
	AverageChampionsKilled      int `json:"averageChampionsKilled"`
	AverageCombatPlayerScore    int `json:"averageCombatPlayerScore"`
	AverageNodeCapture          int `json:"averageNodeCapture"`
	AverageNodeCaptureAssist    int `json:"averageNodeCaptureAssist"`
	AverageNodeNeutralize       int `json:"averageNodeNeutralize"`
	AverageNodeNeutralizeAssist int `json:"averageNodeNeutralizeAssist"`
	AverageNumDeaths            int `json:"averageNumDeaths"`
	AverageObjectivePlayerScore int `json:"averageObjectivePlayerScore"`
	AverageTeamObjective        int `json:"averageTeamObjective"`
	AverageTotalPlayerScore     int `json:"averageTotalPlayerScore"`
	BotGamesPlayed              int `json:"botGamesPlayed"`
	KillingSpree                int `json:"killingSpree"`
	MaxAssists                  int `json:"maxAssists"`
	MaxChampionsKilled          int `json:"maxChampionsKilled"`
	MaxCombatPlayerScore        int `json:"maxCombatPlayerScore"`
	MaxLargestCriticalStrike    int `json:"maxLargestCriticalStrike"`
	MaxLargestKillingSpree      int `json:"maxLargestKillingSpree"`
	MaxNodeCapture              int `json:"maxNodeCapture"`
	MaxNodeCaptureAssist        int `json:"maxNodeCaptureAssist"`
	MaxNodeNeutralize           int `json:"maxNodeNeutralize"`
	MaxNodeNeutralizeAssist     int `json:"maxNodeNeutralizeAssist"`
	MaxObjectivePlayerScore     int `json:"maxObjectivePlayerScore"`
	MaxTeamObjective            int `json:"maxTeamObjective"`
	MaxTimePlayed               int `json:"maxTimePlayed"`
	MaxTimeSpentLiving          int `json:"maxTimeSpentLiving"`
	MaxTotalPlayerScore         int `json:"maxTotalPlayerScore"`
	MostChampionKillsPerSession int `json:"mostChampionKillsPerSession"`
	MostSpellsCast              int `json:"mostSpellsCast"`
	NormalGamesPlayed           int `json:"normalGamesPlayed"`
	RankedPremadeGamesPlayed    int `json:"rankedPremadeGamesPlayed"`
	RankedSoloGamesPlayed       int `json:"rankedSoloGamesPlayed"`
	TotalAssists                int `json:"totalAssists"`
	TotalChampionKills          int `json:"totalChampionKills"`
	TotalDamageDealt            int `json:"totalDamageDealt"`
	TotalDamageTaken            int `json:"totalDamageTaken"`
	TotalDeathsPerSession		int `json:"totalDeathsPerSession"`
	TotalDoubleKills            int `json:"totalDoubleKills"`
	TotalFirstBlood             int `json:"totalFirstBlood"`
	TotalGoldEarned             int `json:"totalGoldEarned"`
	TotalHeal                   int `json:"totalHeal"`
	TotalMagicDamageDealt       int `json:"totalMagicDamageDealt"`
	TotalMinionKills            int `json:"totalMinionKills"`
	TotalNeutralMinionsKilled   int `json:"totalNeutralMinionsKilled"`
	TotalNodeCapture            int `json:"totalNodeCapture"`
	TotalNodeNeutralize         int `json:"totalNodeNeutralize"`
	TotalPentaKills             int `json:"totalPentaKills"`
	TotalPhysicalDamageDealt    int `json:"totalPhysicalDamageDealt"`
	TotalQuadraKills            int `json:"totalQuadraKills"`
	TotalSessionsLost           int `json:"totalSessionsLost"`
	TotalSessionsPlayed         int `json:"totalSessionsPlayed"`
	TotalSessionsWon            int `json:"totalSessionsWon"`
	TotalTripleKills            int `json:"totalTripleKills"`
	TotalTurretsKilled          int `json:"totalTurretsKilled"`
	TotalUnrealKills            int `json:"totalUnrealKills"`
}

//RankedStats represents a League of Legends player's statistics for ranked play
type RankedStats struct {
	Champions  []ChampionStats `json:"champions"`
	ModifyDate int64           `json:"modifyDate"`
	SummonerID int64           `json:"summonerId"`
}

//ChampionStats are the stats for a League of Legends player's champion in ranked
type ChampionStats struct {
	ID    int             `json:"id"`
	Name  string          `json:"name"`
	Stats AggregatedStats `json:"stats"`
}

//StatSummariesBySummoner retrieves the statistics of the supplied summonerID from Riot Games API.
//It returns an array of PlayerStatsSummary and any errors that occured from the server
//The global API key must be set before use
func StatSummariesBySummoner(region string, summonerID int64, season string) (stats []PlayerStatsSummary, err error) {
	var list playerStatsSummaryList
	if !IsKeySet() {
		return stats, ErrAPIKeyNotSet
	}
	var args string
	if season != "" {
		args = fmt.Sprintf("season=%s&", season)
	}
	args += "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.2/stats/by-summoner/%d/summary?%v", BaseURL, region, summonerID, args)

	err = requestAndUnmarshal(url, &list)
	if err != nil {
		return
	}
	return list.PlayerStatSummaries, err
}

//RankedStatsBySummoner retrieves the ranked statistics of the supplied summonerID from Riot Games API.
//It returns a RankedStats and any errors that occured from the server
//The global API key must be set before use
func RankedStatsBySummoner(region string, summonerID int64, season string) (stats RankedStats, err error) {
	if !IsKeySet() {
		return stats, ErrAPIKeyNotSet
	}
	var args string
	if season != "" {
		args = fmt.Sprintf("season=%s&", season)
	}
	args += "api_key=" + apikey
	url := fmt.Sprintf("%v/lol/%v/v1.2/stats/by-summoner/%d/ranked?%v", BaseURL, region, summonerID, args)

	err = requestAndUnmarshal(url, &stats)
	if err != nil {
		return
	}
	return
}
<|endoftext|>


<commit_before>package sokudoku

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"time"

	"github.com/mattn/go-tty"
)

func Run(wait int) error {
	p, err := phraseInit()
	if err != nil {
		return err
	}
	defer p.Destroy()

	// Get a line from stdin.
	reader := bufio.NewScanner(os.Stdin)
	line := make(chan string, 1024)
	go func() {
		for reader.Scan() {
			line <- reader.Text()
		}
		close(line)
	}()

	// Parse a line.
	word := make(chan string, 1024)
	go func() {
		for {
			l, ok := <-line
			if !ok {
				break
			}
			res, err := p.Parse(l)
			if err != nil {
				break
			}
			for _, w := range res {
				word <- w
			}
		}
		close(word)
	}()

	// Output a word.
	oerr := outputWord(word, wait)
	if oerr != nil {
		return oerr
	}

	return reader.Err()
}

func outputWord(word <-chan string, wait int) error {
	if DEBUG {
		//-tags debug
		for {
			w, ok := <-word
			if !ok {
				break
			}
			fmt.Println("   ", w)
			time.Sleep(time.Duration(wait) * time.Millisecond)
		}
	} else {
		tty, err := tty.Open()
		if err != nil {
			return err
		}
		defer tty.Close()

		key_queue := make(chan rune)
		go func() {
			for {
				r, _ := tty.ReadRune()
				key_queue <- r
			}
		}()

	loop:
		for {
			select {
			case r := <-key_queue:
				switch r {
				case 3: // Ctrl-C
					break loop
				case 91: // [
					wait = int(math.Max(float64(wait)*0.9, 10))
				case 93: // ]
					wait = int(math.Min(float64(wait)*1.1, 2000))
				case 32: // Space
					// TODO puase
				}
			case w, ok := <-word:
				if !ok {
					break loop
				}
				fmt.Println("...", w)
				time.Sleep(time.Duration(wait) * time.Millisecond)
			}
		}
	}
	return nil
}
<commit_msg>exit and require press key<commit_after>package sokudoku

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"time"

	"github.com/mattn/go-tty"
)

func Run(wait int) error {
	p, err := phraseInit()
	if err != nil {
		return err
	}
	defer p.Destroy()

	// Get a line from stdin.
	reader := bufio.NewScanner(os.Stdin)
	line := make(chan string, 1024)
	go func() {
		for reader.Scan() {
			line <- reader.Text()
		}
		close(line)
	}()

	// Parse a line.
	word := make(chan string, 1024)
	go func() {
		for {
			l, ok := <-line
			if !ok {
				break
			}
			res, err := p.Parse(l)
			if err != nil {
				break
			}
			for _, w := range res {
				word <- w
			}
		}
		close(word)
	}()

	// Output a word.
	oerr := outputWord(word, wait)
	if oerr != nil {
		return oerr
	}

	return reader.Err()
}

func outputWord(word <-chan string, wait int) error {
	if DEBUG {
		//-tags debug
		for {
			w, ok := <-word
			if !ok {
				break
			}
			fmt.Println("   ", w)
			time.Sleep(time.Duration(wait) * time.Millisecond)
		}
	} else {
		tty, err := tty.Open()
		if err != nil {
			return err
		}
		defer func() {
			for {
				fmt.Println("Please ENTER.")
				r, _ := tty.ReadRune()
				if r == 13 {
					break
				}
			}
			tty.Close()
		}()

		key_queue := make(chan rune)
		go func() {
			for {
				r, _ := tty.ReadRune()
				key_queue <- r
			}
		}()

	loop:
		for {
			select {
			case r := <-key_queue:
				switch r {
				case 3: // Ctrl-C
					break loop
				case 91: // [
					wait = int(math.Max(float64(wait)*0.9, 10))
				case 93: // ]
					wait = int(math.Min(float64(wait)*1.1, 2000))
				case 32: // Space
					// TODO puase
				}
			case w, ok := <-word:
				if !ok {
					break loop
				}
				fmt.Println("...", w)
				time.Sleep(time.Duration(wait) * time.Millisecond)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "web"
    "strings"
    "godis"
    "fmt"
    "os"
    "url"
    "flag"
    "strconv"
    "time"
    "json"
    "http"
)

const(
    // special key in redis, that is our global counter
    COUNTER = "__counter__"
    HTTP = "http"
    ROLL = "https://www.youtube.com/watch?v=jRHmvy5eaG4"
)

var (
    redis *godis.Client
    config *Config
)

type KurzUrl struct{
    Key string
    ShortUrl string
    LongUrl string
    CreationDate int64
    Clicks int64
}

// Converts the KurzUrl to JSON.
func (k KurzUrl) Json()[]byte{
    b, _ := json.Marshal(k)
    return b
}

// Creates a new KurzUrl instance. The Given key, shorturl and longurl will
// be used. Clicks will be set to 0 and CreationDate to time.Nanoseconds()
func NewKurzUrl(key, shorturl, longurl string) *KurzUrl{
    kurl := new(KurzUrl)
    kurl.CreationDate = time.Nanoseconds()
    kurl.Key = key
    kurl.LongUrl = longurl
    kurl.ShortUrl = shorturl
    kurl.Clicks = 0
    return kurl
}

// function to display the info about a KurzUrl given by it's Key
func info(ctx *web.Context, short string) {

    if strings.HasSuffix(short, "+"){
        short = strings.Replace(short, "+", "", 1)
    }
    kurl, err :=  load(short)
    if err == nil{
        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    } else{
        ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

// function to resolve a shorturl and redirect
func resolve(ctx *web.Context, short string) {
    kurl, err :=  load(short)
    if err == nil {
        go redis.Hincrby(kurl.Key, "Clicks", 1)
        ctx.Redirect(http.StatusMovedPermanently,
             kurl.LongUrl)
    } else {
        ctx.Redirect(http.StatusMovedPermanently,
            ROLL)
    }
}

func index(ctx *web.Context){
    redirect := config.GetStringDefault("index", ROLL)
    ctx.Redirect(http.StatusMovedPermanently, redirect)
}

// Determines if the string rawurl is a valid URL to be stored.
func isValidUrl(rawurl string) (u *url.URL, err os.Error){
    if len(rawurl) == 0{
        return nil, os.NewError("empty url")
    }
    // XXX this needs some love...
    if !strings.HasPrefix(rawurl, HTTP){
        rawurl = fmt.Sprintf("%s://%s", HTTP, rawurl)
    }
    return url.Parse(rawurl)
}

// stores a new KurzUrl for the given key, shorturl and longurl. Existing
// ones with the same url will be overwritten
func store(key, shorturl, longurl string)*KurzUrl{
    kurl := NewKurzUrl(key, shorturl, longurl)
    go redis.Hset(kurl.Key, "LongUrl", kurl.LongUrl)
    go redis.Hset(kurl.Key, "ShortUrl", kurl.ShortUrl)
    go redis.Hset(kurl.Key, "CreationDate", kurl.CreationDate)
    go redis.Hset(kurl.Key, "Clicks", kurl.Clicks)
    return kurl
}

// loads a KurzUrl instance for the given key. If the key is
// not found, os.Error is returned.
func load(key string) (kurl *KurzUrl, err os.Error){
    if ok, _ := redis.Hexists(key, "ShortUrl"); ok{
        kurl := new(KurzUrl)
        kurl.Key = key
        reply, _ := redis.Hmget(key, "LongUrl", "ShortUrl", "CreationDate", "Clicks")
        kurl.LongUrl, kurl.ShortUrl, kurl.CreationDate, kurl.Clicks =
            reply.Elems[0].Elem.String(), reply.Elems[1].Elem.String(),
            reply.Elems[2].Elem.Int64(), reply.Elems[3].Elem.Int64()
        return kurl, nil
    }
    return nil, os.NewError("unknown key: " + key )
}

// function to shorten and store a url
func shorten(ctx *web.Context, data string){
    host := config.GetStringDefault("hostname", "localhost")
    r, _ := ctx.Request.Params["url"]
    theUrl, err := isValidUrl(string(r))
    if err == nil{
        ctr, _ := redis.Incr(COUNTER)
        encoded := Encode(ctr)
        location := fmt.Sprintf("%s://%s/%s", HTTP, host, encoded)

        kurl := store(encoded, location, theUrl.Raw)

        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.SetHeader("Location", location, true)
        ctx.StartResponse(http.StatusCreated)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    }else{
       ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

func latest(ctx *web.Context, data string){
    howmany, err := strconv.Atoi64(data)
    if err != nil {
        howmany = 10
    }
    c, _ := redis.Get(COUNTER)

    last := c.Int64()
    upTo := (last - howmany)

    ctx.SetHeader("Content-Type", "application/json", true)
    ctx.WriteString("{ \"urls\" : [")
    for i := last; i > upTo && i > 0; i -= 1{
        kurl, err := load(Encode(i))
        if err == nil{
            ctx.Write(kurl.Json())
            if i != upTo + 1 {
                ctx.WriteString(",")
            }
        }
    }
    ctx.WriteString("] }")
    ctx.WriteString("\n")
}

// bootstraps the server
func bootstrap(path string) os.Error {
    config = NewConfig(path)
    config.Parse()

    host := config.GetStringDefault("redis.address", "tcp:localhost:6379")
    db := config.GetIntDefault("redis.database", 0)
    passwd := config.GetStringDefault("redis.password", "")

    redis = godis.New(host, db, passwd)

    web.Config.StaticDir = config.GetStringDefault("static-directory", "")

    web.Post("/shorten/(.*)", shorten)
    // support for Get makes it easier to implement a bookmarklet
    web.Get("/shorten/(.*)", shorten)

    web.Get("/", index)
    web.Get("/([a-zA-Z0-9]*)", resolve)
    web.Get("/([a-zA-Z0-9]*)\\+", info)
    web.Get("/latest/([0-9]*)", latest)
    web.Get("/info/([a-zA-Z0-9]*)", info)

    return nil
}

// main function that starts everything
func main() {
    flag.Parse()
    cfgFile := flag.Arg(0)
    err := bootstrap(cfgFile)
    if err == nil {
        listen := config.GetStringDefault("listen", "0.0.0.0")
        port := config.GetStringDefault("port", "9999")
        web.Run(fmt.Sprintf("%s:%s", listen, port))
    }
}

<commit_msg>redirect to the info 'page' after creation, wich removes duplicate code<commit_after>package main

import (
    "web"
    "strings"
    "godis"
    "fmt"
    "os"
    "url"
    "flag"
    "strconv"
    "time"
    "json"
    "http"
)

const(
    // special key in redis, that is our global counter
    COUNTER = "__counter__"
    HTTP = "http"
    ROLL = "https://www.youtube.com/watch?v=jRHmvy5eaG4"
)

var (
    redis *godis.Client
    config *Config
)

type KurzUrl struct{
    Key string
    ShortUrl string
    LongUrl string
    CreationDate int64
    Clicks int64
}

// Converts the KurzUrl to JSON.
func (k KurzUrl) Json() [] byte{
    b, _ := json.Marshal(k)
    return b
}

// Creates a new KurzUrl instance. The Given key, shorturl and longurl will
// be used. Clicks will be set to 0 and CreationDate to time.Nanoseconds()
func NewKurzUrl(key, shorturl, longurl string) *KurzUrl{
    kurl := new(KurzUrl)
    kurl.CreationDate = time.Nanoseconds()
    kurl.Key = key
    kurl.LongUrl = longurl
    kurl.ShortUrl = shorturl
    kurl.Clicks = 0
    return kurl
}

// stores a new KurzUrl for the given key, shorturl and longurl. Existing
// ones with the same url will be overwritten
func store(key, shorturl, longurl string) *KurzUrl{
    kurl := NewKurzUrl(key, shorturl, longurl)
    go redis.Hset(kurl.Key, "LongUrl", kurl.LongUrl)
    go redis.Hset(kurl.Key, "ShortUrl", kurl.ShortUrl)
    go redis.Hset(kurl.Key, "CreationDate", kurl.CreationDate)
    go redis.Hset(kurl.Key, "Clicks", kurl.Clicks)
    return kurl
}

// loads a KurzUrl instance for the given key. If the key is
// not found, os.Error is returned.
func load(key string) (*KurzUrl, os.Error){
    if ok, _ := redis.Hexists(key, "ShortUrl"); ok{
        kurl := new(KurzUrl)
        kurl.Key = key
        reply, _ := redis.Hmget(key, "LongUrl", "ShortUrl", "CreationDate", "Clicks")
        kurl.LongUrl, kurl.ShortUrl, kurl.CreationDate, kurl.Clicks =
            reply.Elems[0].Elem.String(), reply.Elems[1].Elem.String(),
            reply.Elems[2].Elem.Int64(), reply.Elems[3].Elem.Int64()
        return kurl, nil
    }
    return nil, os.NewError("unknown key: " + key )
}

// function to display the info about a KurzUrl given by it's Key
func info(ctx *web.Context, short string) {

    if strings.HasSuffix(short, "+"){
        short = strings.Replace(short, "+", "", 1)
    }
    kurl, err :=  load(short)
    if err == nil{
        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    } else{
        ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

// function to resolve a shorturl and redirect
func resolve(ctx *web.Context, short string) {
    kurl, err :=  load(short)
    if err == nil {
        go redis.Hincrby(kurl.Key, "Clicks", 1)
        ctx.Redirect(http.StatusMovedPermanently,
             kurl.LongUrl)
    } else {
        ctx.Redirect(http.StatusMovedPermanently,
            ROLL)
    }
}

func index(ctx *web.Context){
    redirect := config.GetStringDefault("index", ROLL)
    ctx.Redirect(http.StatusMovedPermanently, redirect)
}

// Determines if the string rawurl is a valid URL to be stored.
func isValidUrl(rawurl string) (u *url.URL, err os.Error){
    if len(rawurl) == 0{
        return nil, os.NewError("empty url")
    }
    // XXX this needs some love...
    if !strings.HasPrefix(rawurl, HTTP){
        rawurl = fmt.Sprintf("%s://%s", HTTP, rawurl)
    }
    return url.Parse(rawurl)
}

// function to shorten and store a url
func shorten(ctx *web.Context, data string){
    host := config.GetStringDefault("hostname", "localhost")
    r, _ := ctx.Request.Params["url"]
    theUrl, err := isValidUrl(string(r))
    if err == nil{
        ctr, _ := redis.Incr(COUNTER)
        encoded := Encode(ctr)
        location := fmt.Sprintf("%s://%s/%s", HTTP, host, encoded)
        store(encoded, location, theUrl.Raw)
        // redirect to the info page
       ctx.Redirect(http.StatusMovedPermanently, location + "+")
    }else{
       ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

func latest(ctx *web.Context, data string){
    howmany, err := strconv.Atoi64(data)
    if err != nil {
        howmany = 10
    }
    c, _ := redis.Get(COUNTER)

    last := c.Int64()
    upTo := (last - howmany)

    ctx.SetHeader("Content-Type", "application/json", true)
    ctx.WriteString("{ \"urls\" : [")
    for i := last; i > upTo && i > 0; i -= 1{
        kurl, err := load(Encode(i))
        if err == nil{
            ctx.Write(kurl.Json())
            if i != upTo + 1 {
                ctx.WriteString(",")
            }
        }
    }
    ctx.WriteString("] }")
    ctx.WriteString("\n")
}

// bootstraps the server
func bootstrap(path string) os.Error {
    config = NewConfig(path)
    config.Parse()

    host := config.GetStringDefault("redis.address", "tcp:localhost:6379")
    db := config.GetIntDefault("redis.database", 0)
    passwd := config.GetStringDefault("redis.password", "")

    redis = godis.New(host, db, passwd)

    web.Config.StaticDir = config.GetStringDefault("static-directory", "")

    web.Post("/shorten/(.*)", shorten)
    // support for Get makes it easier to implement a bookmarklet
    web.Get("/shorten/(.*)", shorten)

    web.Get("/", index)
    web.Get("/([a-zA-Z0-9]*)", resolve)
    web.Get("/([a-zA-Z0-9]*)\\+", info)
    web.Get("/latest/([0-9]*)", latest)
    web.Get("/info/([a-zA-Z0-9]*)", info)

    return nil
}

// main function that starts everything
func main() {
    flag.Parse()
    cfgFile := flag.Arg(0)
    err := bootstrap(cfgFile)
    if err == nil {
        listen := config.GetStringDefault("listen", "0.0.0.0")
        port := config.GetStringDefault("port", "9999")
        web.Run(fmt.Sprintf("%s:%s", listen, port))
    }
}

<|endoftext|>


<commit_before>package dns

import (
	"errors"
	"fmt"
	"math/rand"
	"net"
	"strconv"
	"time"

	"github.com/miekg/dns"
)

// DefaultNameServer - Google
const DefaultNameServer = "8.8.8.8:53"

// -
var (
	Timeout     = 20 * time.Second
	StepTimeout = 2 * time.Second
	RetryWait   = 2 * time.Second

	ErrEmptyIPS = errors.New("No IP's for a given host")
)

// Pool - for caching DNS records and easy retrieval
type Pool struct {
	NameServer string
	records    map[string]*net.TCPAddr
}

// New - returns new dns records pool
func New() *Pool {
	return &Pool{
		NameServer: DefaultNameServer,
		records:    make(map[string]*net.TCPAddr),
	}
}

// Get - retuns random IP from map for a given host
func (p *Pool) Get(hostport string) (*net.TCPAddr, error) {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return nil, err
	}
	if value, ok := p.records[hostport]; ok {
		return value, nil
	}
	ips, _, err := ResolveName(host, p.NameServer)
	if err != nil {
		return nil, err
	}
	if len(ips) == 0 {
		return nil, ErrEmptyIPS
	}
	po, _ := strconv.Atoi(port)
	p.records[hostport] = &net.TCPAddr{IP: ips[rand.Intn(len(ips))], Port: po}
	return p.Get(hostport)
}

// ResolveName - resolves name for given host and returns array of IP's
func ResolveName(name, nameserver string) (addrs []net.IP, dur time.Duration, err error) {
	dnsClient := &dns.Client{
		Net:          "tcp",
		ReadTimeout:  StepTimeout,
		WriteTimeout: StepTimeout,
	}
	dnsMessage := new(dns.Msg)
	dnsMessage.MsgHdr.RecursionDesired = true
	dnsMessage.SetQuestion(dns.Fqdn(name), dns.TypeA)
	addrs = make([]net.IP, 0)
	retryWait := RetryWait

Redo:
	var reply *dns.Msg
	var rtt time.Duration
	reply, rtt, err = dnsClient.Exchange(dnsMessage, nameserver)
	dur += rtt
	if err != nil {
		if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
			if dur+retryWait < Timeout {
				time.Sleep(retryWait)
				retryWait *= 2
				goto Redo
			}
		}
		return nil, dur, err
	}
	if reply.Rcode != dns.RcodeSuccess {
		err = fmt.Errorf(`ResolveName(%s, %s): %s`, name, nameserver, dns.RcodeToString[reply.Rcode])
		return nil, dur, err
	}
	for _, a := range reply.Answer {
		if rra, ok := a.(*dns.A); ok {
			addrs = append(addrs, rra.A)
		}
		if rra6, ok := a.(*dns.AAAA); ok {
			addrs = append(addrs, rra6.AAAA)
		}
	}
	if reply.MsgHdr.Truncated {
		goto Redo
	}
	return
}
<commit_msg>Extract dns into standalone package<commit_after><|endoftext|>


<commit_before>// main.go
package main

import (
	"database/sql"
	"flag"
	"log"
	"os/exec"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

const (
	SLEEP_TIME          = 3 * time.Second // time between processing xinput output
	KEYBOARD_BUFER_SIZE = 10000
	DATABASE_NAME       = "file:gokeystat.db?cache=shared&mode=rwc"
	CAPTURE_TIME        = 5 // time in seconds between capturing keyboard to db
)

// StatForTime stotres pressed keys and beginning time
type StatForTime struct {
	time int64
	keys map[uint8]int
}

func (stat *StatForTime) Init() {
	stat.time = time.Now().Unix()
	stat.keys = make(map[uint8]int)
}

// GetKeymap returns map from key numbers to key names like "F1", "Tab", "d"
func GetKeymap() map[uint8]string {
	return GetKeymapFromOutput(GetKeymapOutput())
}

// GetKeymapOutput returns output of utility that prints system keymap
func GetKeymapOutput() []byte {
	cmd := exec.Command("xmodmap", "-pke")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return out
}

// GetKeymapFromOutput returns map with keymap from text
func GetKeymapFromOutput(buf []byte) map[uint8]string {
	const KEY_NUM_STRING_RE = "\\d+[ ]*=[ ]*\\S+"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyMap := make(map[uint8]string)
	for _, line := range resByte {
		lineSpitted := strings.Split(string(line), " ")
		if key, err := strconv.Atoi(lineSpitted[0]); err == nil {
			keyMap[uint8(key)] = lineSpitted[2]
		}
	}
	return keyMap
}

// GetKeyNumsFromOutput extract pressed keys from bufer buf
// It returns slice with key numbers in the same order
func GetKeyNumsFromOutput(buf []byte) []uint8 {
	const KEY_NUM_STRING_RE = "press[ ]+(\\d+)"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyNums := make([]uint8, len(resByte))
	re = regexp.MustCompile("\\d+")
	for i, line := range resByte {
		numByte := re.Find(line)
		if num, err := strconv.Atoi(string(numByte)); err == nil {
			keyNums[i] = uint8(num)
		} else {
			log.Fatal(err)
		}
	}
	return keyNums
}

func GetKeyNumsFromKeyMap(keyMap map[uint8]string) []int {
	res := make([]int, 0, len(keyMap))
	for keyNum := range keyMap {
		res = append(res, int(keyNum))
	}
	sort.Ints(res)
	return res
}

// InitDb creates tables, inserts keymap to db
func InitDb(db *sql.DB, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	sqlInit := `CREATE TABLE IF NOT EXISTS keylog (
        time INTEGER primary key`

	for keyNum := range keyNums {
		sqlInit += ",\n" + "KEY" + strconv.Itoa(keyNum) + " INTEGER"
	}
	sqlInit += "\n);"

	// Inserting keymap to table
	sqlInit += ` CREATE TABLE IF NOT EXISTS keymap (
        num INTEGER primary key,
		value STRING
	);`

	_, err := db.Exec(sqlInit)
	if err != nil {
		log.Fatalf("%q: %s\n", err, sqlInit)
	}

	rows, err := db.Query("SELECT COUNT(*) FROM keymap")
	if err != nil {
		log.Fatal(err)
	}

	var rowsCount int
	rows.Next()
	rows.Scan(&rowsCount)
	if rowsCount > 0 {
		// already inserted keymap
		return
	}
	rows.Close()

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("INSERT INTO keymap(num, value) VALUES(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	for keyNum, keyName := range keyMap {
		_, err = stmt.Exec(keyNum, keyName)
		if err != nil {
			log.Fatal(err)
		}
	}
	tx.Commit()
}

func AddStatTimeToDb(db *sql.DB, statTime StatForTime, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)
	sqlStmt := "insert into keylog(time"
	for keyNum := range keyNums {
		sqlStmt += ",\n" + "KEY" + strconv.Itoa(keyNum)
	}
	sqlStmt += ") values "
	sqlStmt += "(" + strconv.FormatInt(statTime.time, 10)
	for keyNum := range keyNums {
		keyNumber, _ := statTime.keys[uint8(keyNum)]
		sqlStmt += ",\n" + strconv.Itoa(keyNumber)
	}
	sqlStmt += ")"
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	_, err = tx.Exec(sqlStmt)
	if err != nil {
		log.Printf("%q: %s\n", err, sqlStmt)
	}

	tx.Commit()
}

// GetStatTimesFromDb returns slice with StatForTime objects that
func GetStatTimesFromDb(db *sql.DB, fromTime int64, keyMap map[uint8]string) []StatForTime {
	sqlStmt := "select * from keylog where time > " + strconv.FormatInt(fromTime, 10)
	rows, err := db.Query(sqlStmt)
	if err != nil {
		log.Fatalln("Error with query", sqlStmt, " is ", err)
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		log.Fatalln("Failed to get columns", err)
	}

	rawResult := make([][]byte, len(cols))
	result := make([]int64, len(cols))

	dest := make([]interface{}, len(cols)) // A temporary interface{} slice
	for i := range rawResult {
		dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
	}

	// keyNums[i] stores i-th keynum
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	// result
	res := make([]StatForTime, 0)
	for rows.Next() {
		err = rows.Scan(dest...)
		if err != nil {
			log.Fatalln("Failed to scan row", err)
		}

		for i, raw := range rawResult {
			if raw == nil {
				result[i] = 0
			} else {
				// Only numbers in db: converting it to int64
				result[i], err = strconv.ParseInt(string(raw), 10, 64)
				if err != nil {
					log.Fatalln("Error when parsing ", raw, " from db:", err)
				}
			}
		}

		var resStatTime StatForTime
		resStatTime.time = result[0]
		resStatTime.keys = make(map[uint8]int)
		for index, val := range result[1:] {
			if val == 0 {
				continue
			}
			resStatTime.keys[uint8(keyNums[index])] = int(val)
		}
		res = append(res, resStatTime)
	}
	if err = rows.Err(); err != nil {
		log.Fatalln("Error when iterating over rows", err)
	}

	return res
}

func GetFileType(path string) string {

}

func main() {

	keyboardID := flag.Int("id", -1, "Your keyboard id")
	outputPath := flag.String("o", "", "Path to export file")
	fullExport := flag.Bool("full", false, "Export full stats")
	flag.Parse()

	log.Println("keyboardID =", *keyboardID, "outputPath =", *outputPath)

	// Opening database
	db, err := sql.Open("sqlite3", DATABASE_NAME)
	if err != nil {
		log.Fatal(err)
	}
	db.SetMaxIdleConns(5)
	db.SetMaxOpenConns(5)
	defer db.Close()

	keyMap := GetKeymap()

	InitDb(db, keyMap)

	switch {
	case *keyboardID == -1 && *outputPath == "":
		flag.PrintDefaults()
		return
	case *keyboardID != -1:

		cmd := exec.Command("xinput", "test", strconv.Itoa(*keyboardID))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// output of xinput command
		buf := make([]byte, KEYBOARD_BUFER_SIZE)

		var curStat StatForTime
		curStat.Init()

		for {
			n, err := stdout.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			// processing buf here
			for _, keyNum := range GetKeyNumsFromOutput(buf[:n]) {
				oldKeyCount, _ := curStat.keys[keyNum]
				curStat.keys[keyNum] = oldKeyCount + 1
			}

			// Every CAPTURE_TIME seconds save to BD
			if time.Now().Unix()-curStat.time > CAPTURE_TIME {
				AddStatTimeToDb(db, curStat, keyMap)
				curStat.Init()
			}

			time.Sleep(SLEEP_TIME)
		}
	case *outputPath != "":
		exportingData := GetStatTimesFromDb(db, 0, keyMap)
		filetype := GetFileType(*outputPath)
		log.Println(filetype)
		switch filetype {
		case ".csv":
			SaveToCsvFile(exportingData, keyMap, *outputPath, *fullExport)
		case ".json":
			SaveToJSONFile(exportingData, keyMap, *outputPath, *fullExport)
		case ".jsl":
			SaveToJSLFile(exportingData, keyMap, *outputPath, *fullExport)

		case ".csv.gz":
			SaveToCsvGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case ".json.gz":
			SaveToJSONGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case ".jsl.gz":
			SaveToJSLGzFile(exportingData, keyMap, *outputPath, *fullExport)
		default:
			log.Fatal("Incorrect file type")
		}
	}
}
<commit_msg>Implement GetFileType<commit_after>// main.go
package main

import (
	"database/sql"
	"flag"
	"log"
	"os/exec"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

const (
	SLEEP_TIME          = 3 * time.Second // time between processing xinput output
	KEYBOARD_BUFER_SIZE = 10000
	DATABASE_NAME       = "file:gokeystat.db?cache=shared&mode=rwc"
	CAPTURE_TIME        = 5 // time in seconds between capturing keyboard to db
)

// StatForTime stotres pressed keys and beginning time
type StatForTime struct {
	time int64
	keys map[uint8]int
}

func (stat *StatForTime) Init() {
	stat.time = time.Now().Unix()
	stat.keys = make(map[uint8]int)
}

// GetKeymap returns map from key numbers to key names like "F1", "Tab", "d"
func GetKeymap() map[uint8]string {
	return GetKeymapFromOutput(GetKeymapOutput())
}

// GetKeymapOutput returns output of utility that prints system keymap
func GetKeymapOutput() []byte {
	cmd := exec.Command("xmodmap", "-pke")
	out, err := cmd.Output()
	if err != nil {
		log.Fatal(err)
	}
	return out
}

// GetKeymapFromOutput returns map with keymap from text
func GetKeymapFromOutput(buf []byte) map[uint8]string {
	const KEY_NUM_STRING_RE = "\\d+[ ]*=[ ]*\\S+"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyMap := make(map[uint8]string)
	for _, line := range resByte {
		lineSpitted := strings.Split(string(line), " ")
		if key, err := strconv.Atoi(lineSpitted[0]); err == nil {
			keyMap[uint8(key)] = lineSpitted[2]
		}
	}
	return keyMap
}

// GetKeyNumsFromOutput extract pressed keys from bufer buf
// It returns slice with key numbers in the same order
func GetKeyNumsFromOutput(buf []byte) []uint8 {
	const KEY_NUM_STRING_RE = "press[ ]+(\\d+)"
	re := regexp.MustCompile(KEY_NUM_STRING_RE)
	resByte := re.FindAll(buf, -1)
	keyNums := make([]uint8, len(resByte))
	re = regexp.MustCompile("\\d+")
	for i, line := range resByte {
		numByte := re.Find(line)
		if num, err := strconv.Atoi(string(numByte)); err == nil {
			keyNums[i] = uint8(num)
		} else {
			log.Fatal(err)
		}
	}
	return keyNums
}

func GetKeyNumsFromKeyMap(keyMap map[uint8]string) []int {
	res := make([]int, 0, len(keyMap))
	for keyNum := range keyMap {
		res = append(res, int(keyNum))
	}
	sort.Ints(res)
	return res
}

// InitDb creates tables, inserts keymap to db
func InitDb(db *sql.DB, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	sqlInit := `CREATE TABLE IF NOT EXISTS keylog (
        time INTEGER primary key`

	for keyNum := range keyNums {
		sqlInit += ",\n" + "KEY" + strconv.Itoa(keyNum) + " INTEGER"
	}
	sqlInit += "\n);"

	// Inserting keymap to table
	sqlInit += ` CREATE TABLE IF NOT EXISTS keymap (
        num INTEGER primary key,
		value STRING
	);`

	_, err := db.Exec(sqlInit)
	if err != nil {
		log.Fatalf("%q: %s\n", err, sqlInit)
	}

	rows, err := db.Query("SELECT COUNT(*) FROM keymap")
	if err != nil {
		log.Fatal(err)
	}

	var rowsCount int
	rows.Next()
	rows.Scan(&rowsCount)
	if rowsCount > 0 {
		// already inserted keymap
		return
	}
	rows.Close()

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("INSERT INTO keymap(num, value) VALUES(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	for keyNum, keyName := range keyMap {
		_, err = stmt.Exec(keyNum, keyName)
		if err != nil {
			log.Fatal(err)
		}
	}
	tx.Commit()
}

func AddStatTimeToDb(db *sql.DB, statTime StatForTime, keyMap map[uint8]string) {
	keyNums := GetKeyNumsFromKeyMap(keyMap)
	sqlStmt := "insert into keylog(time"
	for keyNum := range keyNums {
		sqlStmt += ",\n" + "KEY" + strconv.Itoa(keyNum)
	}
	sqlStmt += ") values "
	sqlStmt += "(" + strconv.FormatInt(statTime.time, 10)
	for keyNum := range keyNums {
		keyNumber, _ := statTime.keys[uint8(keyNum)]
		sqlStmt += ",\n" + strconv.Itoa(keyNumber)
	}
	sqlStmt += ")"
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	_, err = tx.Exec(sqlStmt)
	if err != nil {
		log.Printf("%q: %s\n", err, sqlStmt)
	}

	tx.Commit()
}

// GetStatTimesFromDb returns slice with StatForTime objects that
func GetStatTimesFromDb(db *sql.DB, fromTime int64, keyMap map[uint8]string) []StatForTime {
	sqlStmt := "select * from keylog where time > " + strconv.FormatInt(fromTime, 10)
	rows, err := db.Query(sqlStmt)
	if err != nil {
		log.Fatalln("Error with query", sqlStmt, " is ", err)
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		log.Fatalln("Failed to get columns", err)
	}

	rawResult := make([][]byte, len(cols))
	result := make([]int64, len(cols))

	dest := make([]interface{}, len(cols)) // A temporary interface{} slice
	for i := range rawResult {
		dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
	}

	// keyNums[i] stores i-th keynum
	keyNums := GetKeyNumsFromKeyMap(keyMap)

	// result
	res := make([]StatForTime, 0)
	for rows.Next() {
		err = rows.Scan(dest...)
		if err != nil {
			log.Fatalln("Failed to scan row", err)
		}

		for i, raw := range rawResult {
			if raw == nil {
				result[i] = 0
			} else {
				// Only numbers in db: converting it to int64
				result[i], err = strconv.ParseInt(string(raw), 10, 64)
				if err != nil {
					log.Fatalln("Error when parsing ", raw, " from db:", err)
				}
			}
		}

		var resStatTime StatForTime
		resStatTime.time = result[0]
		resStatTime.keys = make(map[uint8]int)
		for index, val := range result[1:] {
			if val == 0 {
				continue
			}
			resStatTime.keys[uint8(keyNums[index])] = int(val)
		}
		res = append(res, resStatTime)
	}
	if err = rows.Err(); err != nil {
		log.Fatalln("Error when iterating over rows", err)
	}

	return res
}

func GetFileType(path string) string {
	path = strings.ToLower(path)
	if path[len(path)-3:] == ".gz" {
		return GetFileType(path[:len(path)-3]) + ".gz"
	}

	i := len(path) - 1
	for path[i] != '.' {
		i--
	}

	return path[i+1:]
}

func main() {

	keyboardID := flag.Int("id", -1, "Your keyboard id")
	outputPath := flag.String("o", "", "Path to export file")
	fullExport := flag.Bool("full", false, "Export full stats")
	flag.Parse()

	log.Println("keyboardID =", *keyboardID, "outputPath =", *outputPath)

	// Opening database
	db, err := sql.Open("sqlite3", DATABASE_NAME)
	if err != nil {
		log.Fatal(err)
	}
	db.SetMaxIdleConns(5)
	db.SetMaxOpenConns(5)
	defer db.Close()

	keyMap := GetKeymap()

	InitDb(db, keyMap)

	switch {
	case *keyboardID == -1 && *outputPath == "":
		flag.PrintDefaults()
		return
	case *keyboardID != -1:

		cmd := exec.Command("xinput", "test", strconv.Itoa(*keyboardID))

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := cmd.Start(); err != nil {
			log.Fatal(err)
		}

		// output of xinput command
		buf := make([]byte, KEYBOARD_BUFER_SIZE)

		var curStat StatForTime
		curStat.Init()

		for {
			n, err := stdout.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			// processing buf here
			for _, keyNum := range GetKeyNumsFromOutput(buf[:n]) {
				oldKeyCount, _ := curStat.keys[keyNum]
				curStat.keys[keyNum] = oldKeyCount + 1
			}

			// Every CAPTURE_TIME seconds save to BD
			if time.Now().Unix()-curStat.time > CAPTURE_TIME {
				AddStatTimeToDb(db, curStat, keyMap)
				curStat.Init()
			}

			time.Sleep(SLEEP_TIME)
		}
	case *outputPath != "":
		exportingData := GetStatTimesFromDb(db, 0, keyMap)
		filetype := GetFileType(*outputPath)
		log.Println(filetype)
		switch filetype {
		case "csv":
			SaveToCsvFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json":
			SaveToJSONFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl":
			SaveToJSLFile(exportingData, keyMap, *outputPath, *fullExport)

		case "csv.gz":
			SaveToCsvGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "json.gz":
			SaveToJSONGzFile(exportingData, keyMap, *outputPath, *fullExport)
		case "jsl.gz":
			SaveToJSLGzFile(exportingData, keyMap, *outputPath, *fullExport)
		default:
			log.Fatal("Incorrect file type")
		}
	}
}
<|endoftext|>


<commit_before>package modules

import (
	"strings"

	"github.com/pajlada/pajbot2/bot"
	"github.com/pajlada/pajbot2/common"
)

// Quit xD
type Quit struct {
}

// Ensure the module implements the interface properly
var _ Module = (*Quit)(nil)

// Check xD
func (module *Quit) Check(b *bot.Bot, msg *common.Msg, action *bot.Action) error {
	m := strings.Split(msg.Text, " ")
	trigger := strings.ToLower(m[0])

	// TODO: Make sure the User level is the right level
	if (trigger == "!quit" || trigger == "!exit") && (msg.User.Name == "nuuls" || msg.User.Name == "pajlada") {
		b.Quit <- "ayy lmao something bad happened xD"
	}
	return nil
}
<commit_msg>made !quit/!exit message better<commit_after>package modules

import (
	"strings"

	"github.com/pajlada/pajbot2/bot"
	"github.com/pajlada/pajbot2/common"
)

// Quit xD
type Quit struct {
}

// Ensure the module implements the interface properly
var _ Module = (*Quit)(nil)

// Check xD
func (module *Quit) Check(b *bot.Bot, msg *common.Msg, action *bot.Action) error {
	m := strings.Split(msg.Text, " ")
	trigger := strings.ToLower(m[0])

	// TODO: Make sure the User level is the right level
	if (trigger == "!quit" || trigger == "!exit") && (msg.User.Name == "nuuls" || msg.User.Name == "pajlada") {
		b.Quit <- "quit from command by " + msg.User.Name
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 Buf Technologies, Inc.
//
// 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 appprotoexec

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strconv"
	"strings"

	"github.com/bufbuild/buf/internal/pkg/app"
	"github.com/bufbuild/buf/internal/pkg/app/appproto"
	"github.com/bufbuild/buf/internal/pkg/instrument"
	"github.com/bufbuild/buf/internal/pkg/ioutilextended"
	"github.com/bufbuild/buf/internal/pkg/protoencoding"
	"github.com/bufbuild/buf/internal/pkg/storage"
	"github.com/bufbuild/buf/internal/pkg/storage/storageos"
	"github.com/bufbuild/buf/internal/pkg/tmp"
	"go.uber.org/multierr"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/descriptorpb"
	"google.golang.org/protobuf/types/pluginpb"
)

type protocProxyHandler struct {
	logger     *zap.Logger
	protocPath string
	pluginName string
}

func newProtocProxyHandler(
	logger *zap.Logger,
	protocPath string,
	pluginName string,
) *protocProxyHandler {
	return &protocProxyHandler{
		logger:     logger.Named("appprotoexec"),
		protocPath: protocPath,
		pluginName: pluginName,
	}
}

func (h *protocProxyHandler) Handle(
	ctx context.Context,
	container app.EnvStderrContainer,
	responseWriter appproto.ResponseWriter,
	request *pluginpb.CodeGeneratorRequest,
) (retErr error) {
	defer instrument.Start(h.logger, "protoc_proxy", zap.String("plugin", h.pluginName)).End()
	if app.DevStdinFilePath == "" {
		return errors.New("app.DevStdinFilePath is empty for this platform")
	}
	featureProto3Optional, err := h.getFeatureProto3Optional(ctx, container)
	if err != nil {
		return err
	}
	fileDescriptorSet := &descriptorpb.FileDescriptorSet{
		File: request.ProtoFile,
	}
	fileDescriptorSetData, err := protoencoding.NewWireMarshaler().Marshal(fileDescriptorSet)
	if err != nil {
		return err
	}
	tmpDir, err := tmp.NewDir("")
	if err != nil {
		return err
	}
	defer func() {
		retErr = multierr.Append(retErr, tmpDir.Close())
	}()
	args := []string{
		fmt.Sprintf("--descriptor_set_in=%s", app.DevStdinFilePath),
		fmt.Sprintf("--%s_out=%s", h.pluginName, tmpDir.AbsPath()),
	}
	if parameter := request.GetParameter(); parameter != "" {
		args = append(
			args,
			fmt.Sprintf("%s_opt=%s", h.pluginName, parameter),
		)
	}
	args = append(
		args,
		request.FileToGenerate...,
	)
	cmd := exec.CommandContext(ctx, h.protocPath, args...)
	cmd.Env = app.Environ(container)
	cmd.Stdin = bytes.NewReader(fileDescriptorSetData)
	cmd.Stdout = ioutil.Discard
	cmd.Stderr = container.Stderr()
	if err := cmd.Run(); err != nil {
		// TODO: strip binary path as well?
		return err
	}
	if featureProto3Optional {
		responseWriter.SetFeatureProto3Optional()
	}
	readWriteBucket, err := storageos.NewReadWriteBucket(tmpDir.AbsPath())
	if err != nil {
		return err
	}
	return storage.WalkReadObjects(
		ctx,
		readWriteBucket,
		"",
		func(readObject storage.ReadObject) error {
			data, err := ioutil.ReadAll(readObject)
			if err != nil {
				return err
			}
			return responseWriter.Add(
				&pluginpb.CodeGeneratorResponse_File{
					Name:    proto.String(readObject.Path()),
					Content: proto.String(string(data)),
				},
			)
		},
	)
}

func (h *protocProxyHandler) getFeatureProto3Optional(
	ctx context.Context,
	container app.EnvContainer,
) (bool, error) {
	stdoutBuffer := bytes.NewBuffer(nil)
	stderrBuffer := bytes.NewBuffer(nil)
	cmd := exec.CommandContext(ctx, h.protocPath, "--version")
	cmd.Env = app.Environ(container)
	cmd.Stdin = ioutilextended.DiscardReader
	// do we want to do this?
	cmd.Stdout = stdoutBuffer
	cmd.Stderr = stderrBuffer
	if err := cmd.Run(); err != nil {
		// TODO: strip binary path as well?
		return false, fmt.Errorf("%v\n%v", err, stderrBuffer.String())
	}
	return getFeatureProto3OptionalForVersionString(strings.TrimSpace(stdoutBuffer.String())), nil
}

func getFeatureProto3OptionalForVersionString(value string) bool {
	// This is buf's protoc, which supports proto3 optional
	if strings.HasSuffix(value, "-buf") {
		return true
	}
	// Otherwise, we parse what we expect from protoc
	if !strings.HasPrefix(value, "libprotoc ") {
		return false
	}
	value = strings.TrimPrefix(value, "libprotoc ")
	split := strings.Split(value, ".")
	if len(split) != 3 {
		return false
	}
	major, err := strconv.Atoi(split[0])
	if err != nil {
		return false
	}
	minor, err := strconv.Atoi(split[1])
	if err != nil {
		return false
	}
	_, err = strconv.Atoi(split[2])
	if err != nil {
		return false
	}
	if major != 3 {
		return false
	}
	return minor > 11
}
<commit_msg>Add missing `--` to protoc proxy handler opt flag (#116)<commit_after>// Copyright 2020 Buf Technologies, Inc.
//
// 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 appprotoexec

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strconv"
	"strings"

	"github.com/bufbuild/buf/internal/pkg/app"
	"github.com/bufbuild/buf/internal/pkg/app/appproto"
	"github.com/bufbuild/buf/internal/pkg/instrument"
	"github.com/bufbuild/buf/internal/pkg/ioutilextended"
	"github.com/bufbuild/buf/internal/pkg/protoencoding"
	"github.com/bufbuild/buf/internal/pkg/storage"
	"github.com/bufbuild/buf/internal/pkg/storage/storageos"
	"github.com/bufbuild/buf/internal/pkg/tmp"
	"go.uber.org/multierr"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/descriptorpb"
	"google.golang.org/protobuf/types/pluginpb"
)

type protocProxyHandler struct {
	logger     *zap.Logger
	protocPath string
	pluginName string
}

func newProtocProxyHandler(
	logger *zap.Logger,
	protocPath string,
	pluginName string,
) *protocProxyHandler {
	return &protocProxyHandler{
		logger:     logger.Named("appprotoexec"),
		protocPath: protocPath,
		pluginName: pluginName,
	}
}

func (h *protocProxyHandler) Handle(
	ctx context.Context,
	container app.EnvStderrContainer,
	responseWriter appproto.ResponseWriter,
	request *pluginpb.CodeGeneratorRequest,
) (retErr error) {
	defer instrument.Start(h.logger, "protoc_proxy", zap.String("plugin", h.pluginName)).End()
	if app.DevStdinFilePath == "" {
		return errors.New("app.DevStdinFilePath is empty for this platform")
	}
	featureProto3Optional, err := h.getFeatureProto3Optional(ctx, container)
	if err != nil {
		return err
	}
	fileDescriptorSet := &descriptorpb.FileDescriptorSet{
		File: request.ProtoFile,
	}
	fileDescriptorSetData, err := protoencoding.NewWireMarshaler().Marshal(fileDescriptorSet)
	if err != nil {
		return err
	}
	tmpDir, err := tmp.NewDir("")
	if err != nil {
		return err
	}
	defer func() {
		retErr = multierr.Append(retErr, tmpDir.Close())
	}()
	args := []string{
		fmt.Sprintf("--descriptor_set_in=%s", app.DevStdinFilePath),
		fmt.Sprintf("--%s_out=%s", h.pluginName, tmpDir.AbsPath()),
	}
	if parameter := request.GetParameter(); parameter != "" {
		args = append(
			args,
			fmt.Sprintf("--%s_opt=%s", h.pluginName, parameter),
		)
	}
	args = append(
		args,
		request.FileToGenerate...,
	)
	cmd := exec.CommandContext(ctx, h.protocPath, args...)
	cmd.Env = app.Environ(container)
	cmd.Stdin = bytes.NewReader(fileDescriptorSetData)
	cmd.Stdout = ioutil.Discard
	cmd.Stderr = container.Stderr()
	if err := cmd.Run(); err != nil {
		// TODO: strip binary path as well?
		return err
	}
	if featureProto3Optional {
		responseWriter.SetFeatureProto3Optional()
	}
	readWriteBucket, err := storageos.NewReadWriteBucket(tmpDir.AbsPath())
	if err != nil {
		return err
	}
	return storage.WalkReadObjects(
		ctx,
		readWriteBucket,
		"",
		func(readObject storage.ReadObject) error {
			data, err := ioutil.ReadAll(readObject)
			if err != nil {
				return err
			}
			return responseWriter.Add(
				&pluginpb.CodeGeneratorResponse_File{
					Name:    proto.String(readObject.Path()),
					Content: proto.String(string(data)),
				},
			)
		},
	)
}

func (h *protocProxyHandler) getFeatureProto3Optional(
	ctx context.Context,
	container app.EnvContainer,
) (bool, error) {
	stdoutBuffer := bytes.NewBuffer(nil)
	stderrBuffer := bytes.NewBuffer(nil)
	cmd := exec.CommandContext(ctx, h.protocPath, "--version")
	cmd.Env = app.Environ(container)
	cmd.Stdin = ioutilextended.DiscardReader
	// do we want to do this?
	cmd.Stdout = stdoutBuffer
	cmd.Stderr = stderrBuffer
	if err := cmd.Run(); err != nil {
		// TODO: strip binary path as well?
		return false, fmt.Errorf("%v\n%v", err, stderrBuffer.String())
	}
	return getFeatureProto3OptionalForVersionString(strings.TrimSpace(stdoutBuffer.String())), nil
}

func getFeatureProto3OptionalForVersionString(value string) bool {
	// This is buf's protoc, which supports proto3 optional
	if strings.HasSuffix(value, "-buf") {
		return true
	}
	// Otherwise, we parse what we expect from protoc
	if !strings.HasPrefix(value, "libprotoc ") {
		return false
	}
	value = strings.TrimPrefix(value, "libprotoc ")
	split := strings.Split(value, ".")
	if len(split) != 3 {
		return false
	}
	major, err := strconv.Atoi(split[0])
	if err != nil {
		return false
	}
	minor, err := strconv.Atoi(split[1])
	if err != nil {
		return false
	}
	_, err = strconv.Atoi(split[2])
	if err != nil {
		return false
	}
	if major != 3 {
		return false
	}
	return minor > 11
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/juju/names"
	jc "github.com/juju/testing/checkers"
	jujutxn "github.com/juju/txn"
	txntesting "github.com/juju/txn/testing"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"
	"gopkg.in/juju/charm.v5"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/mongo"
	"github.com/juju/juju/network"
	"github.com/juju/juju/testcharms"
)

const (
	InstanceDataC      = instanceDataC
	MachinesC          = machinesC
	NetworkInterfacesC = networkInterfacesC
	ServicesC          = servicesC
	SettingsC          = settingsC
	UnitsC             = unitsC
	UsersC             = usersC
	BlockDevicesC      = blockDevicesC
	StorageInstancesC  = storageInstancesC
	StatusesHistoryC   = statusesHistoryC
)

var (
	ToolstorageNewStorage  = &toolstorageNewStorage
	ImageStorageNewStorage = &imageStorageNewStorage
	MachineIdLessThan      = machineIdLessThan
	StateServerAvailable   = &stateServerAvailable
	GetOrCreatePorts       = getOrCreatePorts
	GetPorts               = getPorts
	PortsGlobalKey         = portsGlobalKey
	CurrentUpgradeId       = currentUpgradeId
	NowToTheSecond         = nowToTheSecond
	PickAddress            = &pickAddress
	AddVolumeOp            = (*State).addVolumeOp
	CombineMeterStatus     = combineMeterStatus
	NewStatusNotFound      = newStatusNotFound
)

type (
	CharmDoc        charmDoc
	MachineDoc      machineDoc
	RelationDoc     relationDoc
	ServiceDoc      serviceDoc
	UnitDoc         unitDoc
	BlockDevicesDoc blockDevicesDoc
)

func SetTestHooks(c *gc.C, st *State, hooks ...jujutxn.TestHook) txntesting.TransactionChecker {
	return txntesting.SetTestHooks(c, newRunnerForHooks(st), hooks...)
}

func SetBeforeHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
	return txntesting.SetBeforeHooks(c, newRunnerForHooks(st), fs...)
}

func SetAfterHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
	return txntesting.SetAfterHooks(c, newRunnerForHooks(st), fs...)
}

func SetRetryHooks(c *gc.C, st *State, block, check func()) txntesting.TransactionChecker {
	return txntesting.SetRetryHooks(c, newRunnerForHooks(st), block, check)
}

func newRunnerForHooks(st *State) jujutxn.Runner {
	db := st.database.(*database)
	runner := jujutxn.NewRunner(jujutxn.RunnerParams{Database: db.raw})
	db.runner = runner
	return runner
}

// SetPolicy updates the State's policy field to the
// given Policy, and returns the old value.
func SetPolicy(st *State, p Policy) Policy {
	old := st.policy
	st.policy = p
	return old
}

func (doc *MachineDoc) String() string {
	m := &Machine{doc: machineDoc(*doc)}
	return m.String()
}

func ServiceSettingsRefCount(st *State, serviceName string, curl *charm.URL) (int, error) {
	settingsRefsCollection, closer := st.getCollection(settingsrefsC)
	defer closer()

	key := serviceSettingsKey(serviceName, curl)
	var doc settingsRefsDoc
	if err := settingsRefsCollection.FindId(key).One(&doc); err == nil {
		return doc.RefCount, nil
	}
	return 0, mgo.ErrNotFound
}

func AddTestingCharm(c *gc.C, st *State, name string) *Charm {
	return addCharm(c, st, "quantal", testcharms.Repo.CharmDir(name))
}

func AddTestingService(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag) *Service {
	return addTestingService(c, st, name, ch, owner, nil, nil)
}

func AddTestingServiceWithNetworks(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, networks []string) *Service {
	return addTestingService(c, st, name, ch, owner, networks, nil)
}

func AddTestingServiceWithStorage(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, storage map[string]StorageConstraints) *Service {
	return addTestingService(c, st, name, ch, owner, nil, storage)
}

func addTestingService(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, networks []string, storage map[string]StorageConstraints) *Service {
	c.Assert(ch, gc.NotNil)
	service, err := st.AddService(name, owner.String(), ch, networks, storage)
	c.Assert(err, jc.ErrorIsNil)
	return service
}

func AddCustomCharm(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm {
	path := testcharms.Repo.ClonedDirPath(c.MkDir(), name)
	if filename != "" {
		config := filepath.Join(path, filename)
		err := ioutil.WriteFile(config, []byte(content), 0644)
		c.Assert(err, jc.ErrorIsNil)
	}
	ch, err := charm.ReadCharmDir(path)
	c.Assert(err, jc.ErrorIsNil)
	if revision != -1 {
		ch.SetRevision(revision)
	}
	return addCharm(c, st, series, ch)
}

func addCharm(c *gc.C, st *State, series string, ch charm.Charm) *Charm {
	ident := fmt.Sprintf("%s-%s-%d", series, ch.Meta().Name, ch.Revision())
	curl := charm.MustParseURL("local:" + series + "/" + ident)
	sch, err := st.AddCharm(ch, curl, "dummy-path", ident+"-sha256")
	c.Assert(err, jc.ErrorIsNil)
	return sch
}

// SetCharmBundleURL sets the deprecated bundleurl field in the
// charm document for the charm with the specified URL.
func SetCharmBundleURL(c *gc.C, st *State, curl *charm.URL, bundleURL string) {
	ops := []txn.Op{{
		C:      charmsC,
		Id:     st.docID(curl.String()),
		Assert: txn.DocExists,
		Update: bson.D{{"$set", bson.D{{"bundleurl", bundleURL}}}},
	}}
	err := st.runTransaction(ops)
	c.Assert(err, jc.ErrorIsNil)
}

// SCHEMACHANGE
// This method is used to reset the ownertag attribute
func SetServiceOwnerTag(s *Service, ownerTag string) {
	s.doc.OwnerTag = ownerTag
}

// SCHEMACHANGE
// Get the owner directly
func GetServiceOwnerTag(s *Service) string {
	return s.doc.OwnerTag
}

func SetPasswordHash(e Authenticator, passwordHash string) error {
	type hasSetPasswordHash interface {
		setPasswordHash(string) error
	}
	return e.(hasSetPasswordHash).setPasswordHash(passwordHash)
}

// Return the underlying PasswordHash stored in the database. Used by the test
// suite to check that the PasswordHash gets properly updated to new values
// when compatibility mode is detected.
func GetPasswordHash(e Authenticator) string {
	type hasGetPasswordHash interface {
		getPasswordHash() string
	}
	return e.(hasGetPasswordHash).getPasswordHash()
}

func init() {
	txnLogSize = txnLogSizeTests
}

// TxnRevno returns the txn-revno field of the document
// associated with the given Id in the given collection.
func TxnRevno(st *State, collName string, id interface{}) (int64, error) {
	var doc struct {
		TxnRevno int64 `bson:"txn-revno"`
	}
	coll, closer := st.getCollection(collName)
	defer closer()
	err := coll.FindId(id).One(&doc)
	if err != nil {
		return 0, err
	}
	return doc.TxnRevno, nil
}

// MinUnitsRevno returns the Revno of the minUnits document
// associated with the given service name.
func MinUnitsRevno(st *State, serviceName string) (int, error) {
	minUnitsCollection, closer := st.getCollection(minUnitsC)
	defer closer()
	var doc minUnitsDoc
	if err := minUnitsCollection.FindId(serviceName).One(&doc); err != nil {
		return 0, err
	}
	return doc.Revno, nil
}

func ConvertTagToCollectionNameAndId(st *State, tag names.Tag) (string, interface{}, error) {
	return st.tagToCollectionAndId(tag)
}

func RunTransaction(st *State, ops []txn.Op) error {
	return st.runTransaction(ops)
}

// Return the PasswordSalt that goes along with the PasswordHash
func GetUserPasswordSaltAndHash(u *User) (string, string) {
	return u.doc.PasswordSalt, u.doc.PasswordHash
}

func CheckUserExists(st *State, name string) (bool, error) {
	return st.checkUserExists(name)
}

func WatcherMergeIds(st *State, changeset *[]string, updates map[interface{}]bool) error {
	return mergeIds(st, changeset, updates)
}

func WatcherEnsureSuffixFn(marker string) func(string) string {
	return ensureSuffixFn(marker)
}

func WatcherMakeIdFilter(st *State, marker string, receivers ...ActionReceiver) func(interface{}) bool {
	return makeIdFilter(st, marker, receivers...)
}

func NewActionStatusWatcher(st *State, receivers []ActionReceiver, statuses ...ActionStatus) StringsWatcher {
	return newActionStatusWatcher(st, receivers, statuses...)
}

func GetAllUpgradeInfos(st *State) ([]*UpgradeInfo, error) {
	upgradeInfos, closer := st.getCollection(upgradeInfoC)
	defer closer()

	var out []*UpgradeInfo
	var doc upgradeInfoDoc
	iter := upgradeInfos.Find(nil).Iter()
	defer iter.Close()
	for iter.Next(&doc) {
		out = append(out, &UpgradeInfo{st: st, doc: doc})
	}
	if err := iter.Err(); err != nil {
		return nil, err
	}
	return out, nil
}

func UserEnvNameIndex(username, envName string) string {
	return userEnvNameIndex(username, envName)
}

func DocID(st *State, id string) string {
	return st.docID(id)
}

func LocalID(st *State, id string) string {
	return st.localID(id)
}

func StrictLocalID(st *State, id string) (string, error) {
	return st.strictLocalID(id)
}

func GetUnitEnvUUID(unit *Unit) string {
	return unit.doc.EnvUUID
}

func GetCollection(st *State, name string) (mongo.Collection, func()) {
	return st.getCollection(name)
}

func GetRawCollection(st *State, name string) (*mgo.Collection, func()) {
	return st.getRawCollection(name)
}

func NewMultiEnvRunnerForTesting(envUUID string, baseRunner jujutxn.Runner) jujutxn.Runner {
	collections := set.NewStrings()
	for name, info := range allCollections {
		if !info.global {
			collections.Add(name)
		}
	}
	return &multiEnvRunner{
		rawRunner:   baseRunner,
		envUUID:     envUUID,
		collections: collections,
	}
}

func Sequence(st *State, name string) (int, error) {
	return st.sequence(name)
}

// This is a naive environment destruction function, used to test environment
// watching after the client calls DestroyEnvironment and the environ doc is removed.
// It is also used to test annotations.
func RemoveEnvironment(st *State, uuid string) error {
	ops := []txn.Op{{
		C:      environmentsC,
		Id:     uuid,
		Assert: txn.DocExists,
		Remove: true,
	}}
	return st.runTransaction(ops)
}

type MockGlobalEntity struct {
}

func (m MockGlobalEntity) globalKey() string {
	return "globalKey"
}
func (m MockGlobalEntity) Tag() names.Tag {
	return names.NewMachineTag("42")
}

var (
	_                    GlobalEntity = (*MockGlobalEntity)(nil)
	TagToCollectionAndId              = (*State).tagToCollectionAndId
)

func AssertAddressConversion(c *gc.C, netAddr network.Address) {
	addr := fromNetworkAddress(netAddr)
	newNetAddr := addr.networkAddress()
	c.Assert(netAddr, gc.DeepEquals, newNetAddr)

	size := 5
	netAddrs := make([]network.Address, size)
	for i := 0; i < size; i++ {
		netAddrs[i] = netAddr
	}
	addrs := fromNetworkAddresses(netAddrs)
	newNetAddrs := networkAddresses(addrs)
	c.Assert(netAddrs, gc.DeepEquals, newNetAddrs)
}

func AssertHostPortConversion(c *gc.C, netHostPort network.HostPort) {
	hostPort := fromNetworkHostPort(netHostPort)
	newNetHostPort := hostPort.networkHostPort()
	c.Assert(netHostPort, gc.DeepEquals, newNetHostPort)

	size := 5
	netHostsPorts := make([][]network.HostPort, size)
	for i := 0; i < size; i++ {
		netHostsPorts[i] = make([]network.HostPort, size)
		for j := 0; j < size; j++ {
			netHostsPorts[i][j] = netHostPort
		}
	}
	hostsPorts := fromNetworkHostsPorts(netHostsPorts)
	newNetHostsPorts := networkHostsPorts(hostsPorts)
	c.Assert(netHostsPorts, gc.DeepEquals, newNetHostsPorts)
}

type StatusDoc statusDoc

func NewStatusDoc(s StatusDoc) statusDoc {
	return statusDoc(s)
}

func NewHistoricalStatusDoc(s StatusDoc, key string) *historicalStatusDoc {
	sdoc := statusDoc(s)
	return newHistoricalStatusDoc(sdoc, key)
}

var StatusHistory = statusHistory
var UpdateStatusHistory = updateStatusHistory

func EraseUnitHistory(u *Unit) error {
	return u.eraseHistory()
}

func UnitGlobalKey(u *Unit) string {
	return u.globalKey()
}

func UnitAgentGlobalKey(u *UnitAgent) string {
	return u.globalKey()
}
<commit_msg>set txnLogSizeTests inside allCollections<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/juju/names"
	jc "github.com/juju/testing/checkers"
	jujutxn "github.com/juju/txn"
	txntesting "github.com/juju/txn/testing"
	"github.com/juju/utils/set"
	gc "gopkg.in/check.v1"
	"gopkg.in/juju/charm.v5"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/mongo"
	"github.com/juju/juju/network"
	"github.com/juju/juju/testcharms"
)

const (
	InstanceDataC      = instanceDataC
	MachinesC          = machinesC
	NetworkInterfacesC = networkInterfacesC
	ServicesC          = servicesC
	SettingsC          = settingsC
	UnitsC             = unitsC
	UsersC             = usersC
	BlockDevicesC      = blockDevicesC
	StorageInstancesC  = storageInstancesC
	StatusesHistoryC   = statusesHistoryC
)

var (
	ToolstorageNewStorage  = &toolstorageNewStorage
	ImageStorageNewStorage = &imageStorageNewStorage
	MachineIdLessThan      = machineIdLessThan
	StateServerAvailable   = &stateServerAvailable
	GetOrCreatePorts       = getOrCreatePorts
	GetPorts               = getPorts
	PortsGlobalKey         = portsGlobalKey
	CurrentUpgradeId       = currentUpgradeId
	NowToTheSecond         = nowToTheSecond
	PickAddress            = &pickAddress
	AddVolumeOp            = (*State).addVolumeOp
	CombineMeterStatus     = combineMeterStatus
	NewStatusNotFound      = newStatusNotFound
)

type (
	CharmDoc        charmDoc
	MachineDoc      machineDoc
	RelationDoc     relationDoc
	ServiceDoc      serviceDoc
	UnitDoc         unitDoc
	BlockDevicesDoc blockDevicesDoc
)

func SetTestHooks(c *gc.C, st *State, hooks ...jujutxn.TestHook) txntesting.TransactionChecker {
	return txntesting.SetTestHooks(c, newRunnerForHooks(st), hooks...)
}

func SetBeforeHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
	return txntesting.SetBeforeHooks(c, newRunnerForHooks(st), fs...)
}

func SetAfterHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
	return txntesting.SetAfterHooks(c, newRunnerForHooks(st), fs...)
}

func SetRetryHooks(c *gc.C, st *State, block, check func()) txntesting.TransactionChecker {
	return txntesting.SetRetryHooks(c, newRunnerForHooks(st), block, check)
}

func newRunnerForHooks(st *State) jujutxn.Runner {
	db := st.database.(*database)
	runner := jujutxn.NewRunner(jujutxn.RunnerParams{Database: db.raw})
	db.runner = runner
	return runner
}

// SetPolicy updates the State's policy field to the
// given Policy, and returns the old value.
func SetPolicy(st *State, p Policy) Policy {
	old := st.policy
	st.policy = p
	return old
}

func (doc *MachineDoc) String() string {
	m := &Machine{doc: machineDoc(*doc)}
	return m.String()
}

func ServiceSettingsRefCount(st *State, serviceName string, curl *charm.URL) (int, error) {
	settingsRefsCollection, closer := st.getCollection(settingsrefsC)
	defer closer()

	key := serviceSettingsKey(serviceName, curl)
	var doc settingsRefsDoc
	if err := settingsRefsCollection.FindId(key).One(&doc); err == nil {
		return doc.RefCount, nil
	}
	return 0, mgo.ErrNotFound
}

func AddTestingCharm(c *gc.C, st *State, name string) *Charm {
	return addCharm(c, st, "quantal", testcharms.Repo.CharmDir(name))
}

func AddTestingService(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag) *Service {
	return addTestingService(c, st, name, ch, owner, nil, nil)
}

func AddTestingServiceWithNetworks(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, networks []string) *Service {
	return addTestingService(c, st, name, ch, owner, networks, nil)
}

func AddTestingServiceWithStorage(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, storage map[string]StorageConstraints) *Service {
	return addTestingService(c, st, name, ch, owner, nil, storage)
}

func addTestingService(c *gc.C, st *State, name string, ch *Charm, owner names.UserTag, networks []string, storage map[string]StorageConstraints) *Service {
	c.Assert(ch, gc.NotNil)
	service, err := st.AddService(name, owner.String(), ch, networks, storage)
	c.Assert(err, jc.ErrorIsNil)
	return service
}

func AddCustomCharm(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm {
	path := testcharms.Repo.ClonedDirPath(c.MkDir(), name)
	if filename != "" {
		config := filepath.Join(path, filename)
		err := ioutil.WriteFile(config, []byte(content), 0644)
		c.Assert(err, jc.ErrorIsNil)
	}
	ch, err := charm.ReadCharmDir(path)
	c.Assert(err, jc.ErrorIsNil)
	if revision != -1 {
		ch.SetRevision(revision)
	}
	return addCharm(c, st, series, ch)
}

func addCharm(c *gc.C, st *State, series string, ch charm.Charm) *Charm {
	ident := fmt.Sprintf("%s-%s-%d", series, ch.Meta().Name, ch.Revision())
	curl := charm.MustParseURL("local:" + series + "/" + ident)
	sch, err := st.AddCharm(ch, curl, "dummy-path", ident+"-sha256")
	c.Assert(err, jc.ErrorIsNil)
	return sch
}

// SetCharmBundleURL sets the deprecated bundleurl field in the
// charm document for the charm with the specified URL.
func SetCharmBundleURL(c *gc.C, st *State, curl *charm.URL, bundleURL string) {
	ops := []txn.Op{{
		C:      charmsC,
		Id:     st.docID(curl.String()),
		Assert: txn.DocExists,
		Update: bson.D{{"$set", bson.D{{"bundleurl", bundleURL}}}},
	}}
	err := st.runTransaction(ops)
	c.Assert(err, jc.ErrorIsNil)
}

// SCHEMACHANGE
// This method is used to reset the ownertag attribute
func SetServiceOwnerTag(s *Service, ownerTag string) {
	s.doc.OwnerTag = ownerTag
}

// SCHEMACHANGE
// Get the owner directly
func GetServiceOwnerTag(s *Service) string {
	return s.doc.OwnerTag
}

func SetPasswordHash(e Authenticator, passwordHash string) error {
	type hasSetPasswordHash interface {
		setPasswordHash(string) error
	}
	return e.(hasSetPasswordHash).setPasswordHash(passwordHash)
}

// Return the underlying PasswordHash stored in the database. Used by the test
// suite to check that the PasswordHash gets properly updated to new values
// when compatibility mode is detected.
func GetPasswordHash(e Authenticator) string {
	type hasGetPasswordHash interface {
		getPasswordHash() string
	}
	return e.(hasGetPasswordHash).getPasswordHash()
}

func init() {
	allCollections[txnLogC].explicitCreate.MaxBytes = txnLogSizeTests
}

// TxnRevno returns the txn-revno field of the document
// associated with the given Id in the given collection.
func TxnRevno(st *State, collName string, id interface{}) (int64, error) {
	var doc struct {
		TxnRevno int64 `bson:"txn-revno"`
	}
	coll, closer := st.getCollection(collName)
	defer closer()
	err := coll.FindId(id).One(&doc)
	if err != nil {
		return 0, err
	}
	return doc.TxnRevno, nil
}

// MinUnitsRevno returns the Revno of the minUnits document
// associated with the given service name.
func MinUnitsRevno(st *State, serviceName string) (int, error) {
	minUnitsCollection, closer := st.getCollection(minUnitsC)
	defer closer()
	var doc minUnitsDoc
	if err := minUnitsCollection.FindId(serviceName).One(&doc); err != nil {
		return 0, err
	}
	return doc.Revno, nil
}

func ConvertTagToCollectionNameAndId(st *State, tag names.Tag) (string, interface{}, error) {
	return st.tagToCollectionAndId(tag)
}

func RunTransaction(st *State, ops []txn.Op) error {
	return st.runTransaction(ops)
}

// Return the PasswordSalt that goes along with the PasswordHash
func GetUserPasswordSaltAndHash(u *User) (string, string) {
	return u.doc.PasswordSalt, u.doc.PasswordHash
}

func CheckUserExists(st *State, name string) (bool, error) {
	return st.checkUserExists(name)
}

func WatcherMergeIds(st *State, changeset *[]string, updates map[interface{}]bool) error {
	return mergeIds(st, changeset, updates)
}

func WatcherEnsureSuffixFn(marker string) func(string) string {
	return ensureSuffixFn(marker)
}

func WatcherMakeIdFilter(st *State, marker string, receivers ...ActionReceiver) func(interface{}) bool {
	return makeIdFilter(st, marker, receivers...)
}

func NewActionStatusWatcher(st *State, receivers []ActionReceiver, statuses ...ActionStatus) StringsWatcher {
	return newActionStatusWatcher(st, receivers, statuses...)
}

func GetAllUpgradeInfos(st *State) ([]*UpgradeInfo, error) {
	upgradeInfos, closer := st.getCollection(upgradeInfoC)
	defer closer()

	var out []*UpgradeInfo
	var doc upgradeInfoDoc
	iter := upgradeInfos.Find(nil).Iter()
	defer iter.Close()
	for iter.Next(&doc) {
		out = append(out, &UpgradeInfo{st: st, doc: doc})
	}
	if err := iter.Err(); err != nil {
		return nil, err
	}
	return out, nil
}

func UserEnvNameIndex(username, envName string) string {
	return userEnvNameIndex(username, envName)
}

func DocID(st *State, id string) string {
	return st.docID(id)
}

func LocalID(st *State, id string) string {
	return st.localID(id)
}

func StrictLocalID(st *State, id string) (string, error) {
	return st.strictLocalID(id)
}

func GetUnitEnvUUID(unit *Unit) string {
	return unit.doc.EnvUUID
}

func GetCollection(st *State, name string) (mongo.Collection, func()) {
	return st.getCollection(name)
}

func GetRawCollection(st *State, name string) (*mgo.Collection, func()) {
	return st.getRawCollection(name)
}

func NewMultiEnvRunnerForTesting(envUUID string, baseRunner jujutxn.Runner) jujutxn.Runner {
	collections := set.NewStrings()
	for name, info := range allCollections {
		if !info.global {
			collections.Add(name)
		}
	}
	return &multiEnvRunner{
		rawRunner:   baseRunner,
		envUUID:     envUUID,
		collections: collections,
	}
}

func Sequence(st *State, name string) (int, error) {
	return st.sequence(name)
}

// This is a naive environment destruction function, used to test environment
// watching after the client calls DestroyEnvironment and the environ doc is removed.
// It is also used to test annotations.
func RemoveEnvironment(st *State, uuid string) error {
	ops := []txn.Op{{
		C:      environmentsC,
		Id:     uuid,
		Assert: txn.DocExists,
		Remove: true,
	}}
	return st.runTransaction(ops)
}

type MockGlobalEntity struct {
}

func (m MockGlobalEntity) globalKey() string {
	return "globalKey"
}
func (m MockGlobalEntity) Tag() names.Tag {
	return names.NewMachineTag("42")
}

var (
	_                    GlobalEntity = (*MockGlobalEntity)(nil)
	TagToCollectionAndId              = (*State).tagToCollectionAndId
)

func AssertAddressConversion(c *gc.C, netAddr network.Address) {
	addr := fromNetworkAddress(netAddr)
	newNetAddr := addr.networkAddress()
	c.Assert(netAddr, gc.DeepEquals, newNetAddr)

	size := 5
	netAddrs := make([]network.Address, size)
	for i := 0; i < size; i++ {
		netAddrs[i] = netAddr
	}
	addrs := fromNetworkAddresses(netAddrs)
	newNetAddrs := networkAddresses(addrs)
	c.Assert(netAddrs, gc.DeepEquals, newNetAddrs)
}

func AssertHostPortConversion(c *gc.C, netHostPort network.HostPort) {
	hostPort := fromNetworkHostPort(netHostPort)
	newNetHostPort := hostPort.networkHostPort()
	c.Assert(netHostPort, gc.DeepEquals, newNetHostPort)

	size := 5
	netHostsPorts := make([][]network.HostPort, size)
	for i := 0; i < size; i++ {
		netHostsPorts[i] = make([]network.HostPort, size)
		for j := 0; j < size; j++ {
			netHostsPorts[i][j] = netHostPort
		}
	}
	hostsPorts := fromNetworkHostsPorts(netHostsPorts)
	newNetHostsPorts := networkHostsPorts(hostsPorts)
	c.Assert(netHostsPorts, gc.DeepEquals, newNetHostsPorts)
}

type StatusDoc statusDoc

func NewStatusDoc(s StatusDoc) statusDoc {
	return statusDoc(s)
}

func NewHistoricalStatusDoc(s StatusDoc, key string) *historicalStatusDoc {
	sdoc := statusDoc(s)
	return newHistoricalStatusDoc(sdoc, key)
}

var StatusHistory = statusHistory
var UpdateStatusHistory = updateStatusHistory

func EraseUnitHistory(u *Unit) error {
	return u.eraseHistory()
}

func UnitGlobalKey(u *Unit) string {
	return u.globalKey()
}

func UnitAgentGlobalKey(u *UnitAgent) string {
	return u.globalKey()
}
<|endoftext|>


<commit_before>package movingmedian

import "container/heap"

type item struct {
	f         float64
	heapIndex int
}

type itemHeap []*item

func (h itemHeap) Len() int { return len(h) }
func (h itemHeap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].heapIndex = i
	h[j].heapIndex = j
}

func (h *itemHeap) Push(x interface{}) {
	e := x.(*item)
	e.heapIndex = len(*h)
	*h = append(*h, e)
}

func (h *itemHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minItemHeap struct {
	itemHeap
}

func (h minItemHeap) Less(i, j int) bool { return h.itemHeap[i].f < h.itemHeap[j].f }

type maxItemHeap struct {
	itemHeap
}

func (h maxItemHeap) Less(i, j int) bool { return h.itemHeap[i].f > h.itemHeap[j].f }

// MovingMedian computes the moving median of a windowed stream of numbers.
type MovingMedian struct {
	queueIndex int
	nitems     int
	queue      []item
	maxHeap    maxItemHeap
	minHeap    minItemHeap
}

// NewMovingMedian returns a MovingMedian with the given window size.
func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]item, size),
		maxHeap: maxItemHeap{},
		minHeap: minItemHeap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

// Push adds an element to the stream, removing old data which has expired from the window.
func (m *MovingMedian) Push(v float64) {
	if len(m.queue) == 1 {
		m.queue[0].f = v
		return
	}

	itemPtr := &m.queue[m.queueIndex]
	m.queueIndex++
	if m.queueIndex >= len(m.queue) {
		m.queueIndex = 0
	}

	if m.nitems == len(m.queue) {
		minAbove := m.minHeap.itemHeap[0].f
		maxBelow := m.maxHeap.itemHeap[0].f
		itemPtr.f = v
		if itemPtr.heapIndex < m.minHeap.Len() && itemPtr == m.minHeap.itemHeap[itemPtr.heapIndex] {
			if v >= maxBelow {
				heap.Fix(&m.minHeap, itemPtr.heapIndex)
				return
			}

			rotate(&m.maxHeap, &m.minHeap, m.maxHeap.itemHeap, m.minHeap.itemHeap, itemPtr)
			return
		}

		if v <= minAbove {
			heap.Fix(&m.maxHeap, itemPtr.heapIndex)
			return
		}

		rotate(&m.minHeap, &m.maxHeap, m.minHeap.itemHeap, m.maxHeap.itemHeap, itemPtr)
		return
	}

	m.nitems++
	itemPtr.f = v
	if m.minHeap.Len() == 0 || v > m.minHeap.itemHeap[0].f {
		heap.Push(&m.minHeap, itemPtr)
		rebalance(&m.minHeap, &m.maxHeap)
	} else {
		heap.Push(&m.maxHeap, itemPtr)
		rebalance(&m.maxHeap, &m.minHeap)
	}
}

func rebalance(heapA, heapB heap.Interface) {
	if heapA.Len() == (heapB.Len() + 2) {
		moveItem := heap.Pop(heapA)
		heap.Push(heapB, moveItem)
	}
}

func rotate(heapA, heapB heap.Interface, itemHeapA, itemHeapB itemHeap, itemPtr *item) {
	moveItem := itemHeapA[0]
	moveItem.heapIndex = itemPtr.heapIndex
	itemHeapB[itemPtr.heapIndex] = moveItem
	itemHeapA[0] = itemPtr
	heap.Fix(heapB, itemPtr.heapIndex)
	itemPtr.heapIndex = 0
	heap.Fix(heapA, 0)
}

// Median returns the current value of the median from the window.
func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 1 {
		return m.queue[0].f
	}

	if m.maxHeap.Len() == m.minHeap.Len() {
		return (m.maxHeap.itemHeap[0].f + m.minHeap.itemHeap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.itemHeap[0].f
	}

	return m.minHeap.itemHeap[0].f
}
<commit_msg>more docs<commit_after>// Package movingmedian computes the median of a windowed stream of data.
package movingmedian

import "container/heap"

type item struct {
	f         float64
	heapIndex int
}

type itemHeap []*item

func (h itemHeap) Len() int { return len(h) }
func (h itemHeap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].heapIndex = i
	h[j].heapIndex = j
}

func (h *itemHeap) Push(x interface{}) {
	e := x.(*item)
	e.heapIndex = len(*h)
	*h = append(*h, e)
}

func (h *itemHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minItemHeap struct {
	itemHeap
}

func (h minItemHeap) Less(i, j int) bool { return h.itemHeap[i].f < h.itemHeap[j].f }

type maxItemHeap struct {
	itemHeap
}

func (h maxItemHeap) Less(i, j int) bool { return h.itemHeap[i].f > h.itemHeap[j].f }

// MovingMedian computes the moving median of a windowed stream of numbers.
type MovingMedian struct {
	queueIndex int
	nitems     int
	queue      []item
	maxHeap    maxItemHeap
	minHeap    minItemHeap
}

// NewMovingMedian returns a MovingMedian with the given window size.
func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]item, size),
		maxHeap: maxItemHeap{},
		minHeap: minItemHeap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

// Push adds an element to the stream, removing old data which has expired from the window.  It runs in O(log windowSize).
func (m *MovingMedian) Push(v float64) {
	if len(m.queue) == 1 {
		m.queue[0].f = v
		return
	}

	itemPtr := &m.queue[m.queueIndex]
	m.queueIndex++
	if m.queueIndex >= len(m.queue) {
		m.queueIndex = 0
	}

	if m.nitems == len(m.queue) {
		minAbove := m.minHeap.itemHeap[0].f
		maxBelow := m.maxHeap.itemHeap[0].f
		itemPtr.f = v
		if itemPtr.heapIndex < m.minHeap.Len() && itemPtr == m.minHeap.itemHeap[itemPtr.heapIndex] {
			if v >= maxBelow {
				heap.Fix(&m.minHeap, itemPtr.heapIndex)
				return
			}

			rotate(&m.maxHeap, &m.minHeap, m.maxHeap.itemHeap, m.minHeap.itemHeap, itemPtr)
			return
		}

		if v <= minAbove {
			heap.Fix(&m.maxHeap, itemPtr.heapIndex)
			return
		}

		rotate(&m.minHeap, &m.maxHeap, m.minHeap.itemHeap, m.maxHeap.itemHeap, itemPtr)
		return
	}

	m.nitems++
	itemPtr.f = v
	if m.minHeap.Len() == 0 || v > m.minHeap.itemHeap[0].f {
		heap.Push(&m.minHeap, itemPtr)
		rebalance(&m.minHeap, &m.maxHeap)
	} else {
		heap.Push(&m.maxHeap, itemPtr)
		rebalance(&m.maxHeap, &m.minHeap)
	}
}

func rebalance(heapA, heapB heap.Interface) {
	if heapA.Len() == (heapB.Len() + 2) {
		moveItem := heap.Pop(heapA)
		heap.Push(heapB, moveItem)
	}
}

func rotate(heapA, heapB heap.Interface, itemHeapA, itemHeapB itemHeap, itemPtr *item) {
	moveItem := itemHeapA[0]
	moveItem.heapIndex = itemPtr.heapIndex
	itemHeapB[itemPtr.heapIndex] = moveItem
	itemHeapA[0] = itemPtr
	heap.Fix(heapB, itemPtr.heapIndex)
	itemPtr.heapIndex = 0
	heap.Fix(heapA, 0)
}

// Median returns the current value of the median from the window.
func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 1 {
		return m.queue[0].f
	}

	if m.maxHeap.Len() == m.minHeap.Len() {
		return (m.maxHeap.itemHeap[0].f + m.minHeap.itemHeap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.itemHeap[0].f
	}

	return m.minHeap.itemHeap[0].f
}
<|endoftext|>