<commit_before>// Copyright (c) 2012 The Gocov Authors.
//
// 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 gocov

import (
	"fmt"
	"testing"
)

func TestItoa(t *testing.T) {
	var values = [...]int{
		0, 1, -1, 10, -10, 100, -100, 1<<63 - 1, -1<<63 + 1,
		// (-1 << 63) will panic due to a known bug
	}
	for _, v := range values {
		expected := fmt.Sprint(v)
		actual := itoa(v)
		if actual != expected {
			t.Errorf("expected %s, received %s", expected, actual)
		}
	}

	// (-1 << 63) will panic due to a known bug
	panicked := false
	f := func() {
		defer func() {
			if err := recover(); err != nil {
				panicked = true
			}
		}()
		itoa(-1 << 63)
	}
	f()
	if !panicked {
		t.Error("Expected itoa(-1 << 63) to panic")
	}
}
<commit_msg>Improve coverage testing of gocov<commit_after>// Copyright (c) 2012 The Gocov Authors.
//
// 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 gocov

import (
	"bytes"
	"fmt"
	"runtime"
	"strings"
	"testing"
)

func checkPanic(f func()) (panicked bool) {
	defer func() {
		if err := recover(); err != nil {
			panicked = true
		}
	}()
	f()
	return panicked
}

func TestItoa(t *testing.T) {
	var values = [...]int{
		0, 1, -1, 10, -10, 100, -100, 1<<63 - 1, -1<<63 + 1,
		// (-1 << 63) will panic due to a known bug
	}
	for _, v := range values {
		expected := fmt.Sprint(v)
		actual := itoa(v)
		if actual != expected {
			t.Errorf("expected %s, received %s", expected, actual)
		}
	}

	// (-1 << 63) will panic due to a known bug
	if !checkPanic(func() { itoa(-1 << 63) }) {
		t.Error("Expected itoa(-1 << 63) to panic")
	}
}

func TestMallocs(t *testing.T) {
	ctx := &Context{}
	p := ctx.RegisterPackage("p1")
	f := p.RegisterFunction("f1", "file.go", 0, 1)
	s := f.RegisterStatement(0, 1)

	var ms runtime.MemStats
	runtime.ReadMemStats(&ms)
	m0 := ms.Mallocs

	f.Enter()
	s.At()
	f.Leave()

	runtime.ReadMemStats(&ms)
	mallocs := ms.Mallocs - m0
	if mallocs > 0 {
		t.Errorf("%d mallocs; want 0", mallocs)
	}
}

func TestTraceOutput(t *testing.T) {
	var buf bytes.Buffer
	ctx := &Context{Tracer: &buf}
	check := func(expected string) {
		actual := strings.TrimSpace(buf.String())
		if actual != expected {
			t.Errorf("Expected %q, found %q", expected, actual)
		}
	}

	p := ctx.RegisterPackage("p1")
	check(`RegisterPackage("p1"): gocovObject0`)
	buf.Reset()

	f := p.RegisterFunction("f1", "file.go", 0, 1)
	check(`gocovObject0.RegisterFunction("f1", "file.go", 0, 1): gocovObject1`)
	buf.Reset()

	s := f.RegisterStatement(0, 1)
	check(`gocovObject1.RegisterStatement(0, 1): gocovObject2`)
	buf.Reset()

	f.Enter()
	check(`gocovObject1.Enter()`)
	buf.Reset()

	s.At()
	check(`gocovObject2.At()`)
	buf.Reset()

	f.Leave()
	check(`gocovObject1.Leave()`)
	buf.Reset()
}

func TestTraceFlags(t *testing.T) {
	var buf bytes.Buffer
	ctx := &Context{Tracer: &buf}
	check := func(expected string) {
		actual := strings.TrimSpace(buf.String())
		if actual != expected {
			t.Errorf("Expected %q, found %q", expected, actual)
		}
	}

	p := ctx.RegisterPackage("p1")
	f := p.RegisterFunction("f1", "file.go", 0, 1)
	f.Enter()
	buf.Reset()

	// TraceAll is not set, second entry should be silent.
	f.Enter()
	check("")

	// TraceAll set now, so should get another log message.
	ctx.TraceFlags = TraceAll
	f.Enter()
	check(f.String() + ".Enter()")
	if f.Entered != 3 {
		t.Errorf("Expected f.Entered == 3, found %d", f.Entered)
	}
}

func TestAccumulatePackage(t *testing.T) {
	ctx := &Context{}
	p1_1 := ctx.RegisterPackage("p1")
	p1_2 := ctx.RegisterPackage("p1")
	p2 := ctx.RegisterPackage("p2")
	p3 := ctx.RegisterPackage("p1")
	p3.RegisterFunction("f", "file.go", 0, 1)
	p4 := ctx.RegisterPackage("p1")
	p4.RegisterFunction("f", "file.go", 1, 2)

	var tests = [...]struct {
		a, b       *Package
		expectPass bool
	}{
		// Should work: everything is the same.
		{p1_1, p1_2, true},
		// Should fail: name is different.
		{p1_1, p2, false},
		// Should fail: numbers of functions are different.
		{p1_1, p3, false},
		// Should fail: functions are different.
		{p3, p4, false},
	}

	for _, test := range tests {
		err := test.a.Accumulate(test.b)
		if test.expectPass {
			if err != nil {
				t.Error(err)
			}
		} else {
			if err == nil {
				t.Error("Expected an error")
			}
		}
	}
}

func TestAccumulateFunction(t *testing.T) {
	ctx := &Context{}
	p := ctx.RegisterPackage("p1")
	f1_1 := p.RegisterFunction("f1", "file.go", 0, 1)
	f1_2 := p.RegisterFunction("f1", "file.go", 0, 1)
	f2 := p.RegisterFunction("f2", "file.go", 0, 1)
	f3 := p.RegisterFunction("f1", "file2.go", 0, 1)
	f4 := p.RegisterFunction("f1", "file.go", 2, 3)
	f5 := p.RegisterFunction("f1", "file.go", 0, 1)
	f5.RegisterStatement(0, 1)
	f6 := p.RegisterFunction("f1", "file.go", 0, 1)
	f6.RegisterStatement(2, 3)

	var tests = [...]struct {
		a, b       *Function
		expectPass bool
	}{
		// Should work: everything is the same.
		{f1_1, f1_2, true},
		// Should fail: names are different.
		{f1_1, f2, false},
		// Should fail: files are different.
		{f1_1, f3, false},
		// Should fail: ranges are different.
		{f1_1, f4, false},
		// Should fail: numbers of statements are different.
		{f1_1, f5, false},
		// Should fail: all the same, except statement values.
		{f5, f6, false},
	}

	for _, test := range tests {
		err := test.a.Accumulate(test.b)
		if test.expectPass {
			if err != nil {
				t.Error(err)
			}
		} else {
			if err == nil {
				t.Error("Expected an error")
			}
		}
	}
}

func TestAccumulateStatement(t *testing.T) {
	ctx := &Context{}
	p := ctx.RegisterPackage("p1")
	f := p.RegisterFunction("f1", "file.go", 0, 1)
	s1_1 := f.RegisterStatement(0, 1)
	s1_2 := f.RegisterStatement(0, 1)
	s2 := f.RegisterStatement(2, 3)

	// Should work: ranges are the same.
	if err := s1_1.Accumulate(s1_2); err != nil {
		t.Error(err)
	}

	// Should fail: ranges are not the same.
	if err := s1_1.Accumulate(s2); err == nil {
		t.Errorf("Expected an error")
	}
}

func BenchmarkEnterLeave(b *testing.B) {
	ctx := &Context{}
	p := ctx.RegisterPackage("p1")
	f := p.RegisterFunction("f1", "file.go", 0, 1)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		f.Enter()
		f.Leave()
	}
}

func BenchmarkAt(b *testing.B) {
	ctx := &Context{}
	p := ctx.RegisterPackage("p1")
	f := p.RegisterFunction("f1", "file.go", 0, 1)
	s := f.RegisterStatement(0, 1)
	f.Enter()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		s.At()
	}
}
<|endoftext|>


<commit_before>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
/*
*  File: gonew_main.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat Jul  2 19:17:53 PDT 2011
*  Usage: gonew [options]
 */
import (
    "os"
    //"io"
    "log"
    "fmt"
    "flag"
    //"bufio"
    //"io/ioutil"
    //"path/filepath"
    //"github.com/hoisie/mustache.go"
    //"github.com/kr/pretty.go"
)

var (
    usage          = `
gonew [options] cmd NAME
gonew [options] pkg NAME
gonew [options] lib NAME PKG
`
    printUsageHead = func() { fmt.Fprint(os.Stderr, usage, "\n") }
    userepo        = true
    VERBOSE        = false
    DEBUG          = false
    DEBUG_LEVEL    = -1
    name           string
    ptype          string
    repo           string
    host           string
    user           string
    target         string
    license        string
    remote         string
    help           bool
)

func Debug(level int, msg string) {
    if DEBUG && DEBUG_LEVEL >= level {
        log.Print(msg)
    }
}

func Verbose(msg string) {
    if DEBUG || VERBOSE {
        fmt.Print(msg)
    }
}

func setupFlags() *flag.FlagSet {
    var fs = flag.NewFlagSet("gonew", flag.ExitOnError)
    fs.StringVar(&repo,
        "repo", "git", "Repository type (e.g. 'git').")
    fs.StringVar(&host,
        "host", "", "Repository host if any (e.g. 'github').")
    fs.StringVar(&user,
        "user", "", "Repo host username.")
    fs.StringVar(&remote,
        "remote", "", "Remote repository url to initialize and push to.")
    fs.StringVar(&target,
        "target", "", "Makefile target. Default based on NAME.")
    fs.StringVar(&license,
        "license", "", "Project license (e.g. 'newbsd').")
    fs.BoolVar(&(AppConfig.MakeTest),
        "test", AppConfig.MakeTest, "Produce test files with Go files.")
    fs.BoolVar(&(userepo), "userepo", true, "Create a local repository.")
    fs.BoolVar(&VERBOSE,
        "v", false, "Verbose output.")
    fs.IntVar(&DEBUG_LEVEL,
        "debug", -1, "Change the amout of debug output.")
    fs.BoolVar(&help,
        "help", false, "Show this message.")
    var usageTemp = fs.Usage
    fs.Usage = func() {
        printUsageHead()
        usageTemp()
    }
    return fs
}

type Request int

const (
    NilRequest Request = iota
    ProjectRequest
    LibraryRequest
)

var RequestedFile File
var RequestedProject Project

func parseArgs() Request {
    var fs = setupFlags()
    fs.Parse(os.Args[1:])
    if DEBUG_LEVEL >= 0 {
        DEBUG = true
    }
    if help {
        fs.Usage()
        os.Exit(0)
    }
    var narg = fs.NArg()
    if narg < 1 {
        fmt.Fprint(os.Stderr, "missing TYPE argument\n")
        os.Exit(1)
    }
    if narg < 2 {
        fmt.Fprint(os.Stderr, "missing NAME argument\n")
        os.Exit(1)
    }
    ptype = fs.Arg(0)
    name = fs.Arg(1)

    if target == "" {
        target = DefaultTarget(name)
    }
    var (
        file = File{
            Name: name, Pkg: "main",
            Repo: AppConfig.Repo, License: AppConfig.License,
            User: AppConfig.HostUser, Host: AppConfig.Host}
        project = Project{
            Name: name, Target: target,
            Type: NilProjectType, License: AppConfig.License, Remote: remote,
            Host: AppConfig.Host, User: AppConfig.HostUser,
            Repo: AppConfig.Repo}
        produceProject = true
        licObj         = NilLicenseType
        repoObj        = NilRepoType
        hostObj        = NilRepoHost
    )
    switch ptype {
    case "cmd":
        project.Type = CmdType
    case "pkg":
        project.Type = PkgType
    case "lib":
        produceProject = false
    default:
        fmt.Fprintf(os.Stderr, "Unknown TYPE %s\n", ptype)
        os.Exit(1)
    }
    switch license {
    case "":
        break
    case "newbsd":
        licObj = NewBSD
    default:
        fmt.Fprintf(os.Stderr, "Unknown TYPE %s\n", ptype)
        os.Exit(1)
    }
    switch repo {
    case "":
        break
    case "git":
        repoObj = GitType
    case "mercurial":
        repoObj = HgType
    default:
        fmt.Fprintf(os.Stderr, "Unknown REPO %s\n", repo)
        os.Exit(1)
    }
    switch host {
    case "":
        break
    case "github":
        hostObj = GitHubHost
        repoObj = GitType
    /*
       case "googlecode":
           hostObj = GoogleCodeType
           repoObj = HgType
    */
    default:
        fmt.Fprintf(os.Stderr, "Unknown HOST %s\n", host)
        os.Exit(1)
    }
    if produceProject {
        // TODO check target for improper characters.
        if user != "" {
            project.User = user
        }
        if licObj != NilLicenseType {
            project.License = licObj
        }
        if hostObj != NilRepoHost {
            project.Host = hostObj
        }
        if repoObj != NilRepoType {
            project.Repo = repoObj
        }
        RequestedProject = project
        return ProjectRequest
    } else {
        if narg < 3 {
            fmt.Fprint(os.Stderr, "missing PKG argument\n")
            os.Exit(1)
        }
        file.Pkg = fs.Arg(2)
        if user != "" {
            file.User = user
        }
        if licObj != NilLicenseType {
            file.License = licObj
        }
        if hostObj != NilRepoHost {
            file.Host = hostObj
        }
        if repoObj != NilRepoType {
            file.Repo = repoObj
        }
        RequestedFile = file
        return LibraryRequest
    }
    return NilRequest
}

func main() {
    var errTouch = TouchConfig()
    if errTouch != nil {
        fmt.Print(errTouch.String(), "\n")
        os.Exit(1)
    }
    if DEBUG || VERBOSE {
        fmt.Print("Parsing config file.\n")
    }
    ReadConfig()
    var request = parseArgs()
    switch request {
    case ProjectRequest:
        if DEBUG {
            fmt.Printf("Project requested %v\n", RequestedProject)
        } else if VERBOSE {
            fmt.Printf("Generating project %s\n", RequestedProject.Name)
        }
        var errCreate = RequestedProject.Create()
        if errCreate != nil {
            fmt.Fprint(os.Stderr, errCreate.String(), "\n")
            os.Exit(1)
        }
    case LibraryRequest:
        if DEBUG {
            fmt.Printf("Library requested %v\n", RequestedFile)
        } else if VERBOSE {
            fmt.Printf("Generating library %s (package %s)\n",
                RequestedFile.Name+".go", RequestedFile.Pkg)
        }
        var errCreate = RequestedFile.Create()
        if errCreate != nil {
            fmt.Fprint(os.Stderr, errCreate.String(), "\n")
            os.Exit(1)
        }
    }
}
<commit_msg>Clean up the main go file.<commit_after>// Copyright 2011, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
/*
*  File: gonew_main.go
*  Author: Bryan Matsuo [bmatsuo@soe.ucsc.edu]
*  Created: Sat Jul  2 19:17:53 PDT 2011
*  Usage: gonew [options]
 */
import (
    "os"
    //"io"
    "log"
    "fmt"
    "flag"
    //"bufio"
    //"io/ioutil"
    //"path/filepath"
    //"github.com/hoisie/mustache.go"
    //"github.com/kr/pretty.go"
)

var (
    usage          = `
gonew [options] cmd NAME
gonew [options] pkg NAME
gonew [options] lib NAME PKG
`
    printUsageHead = func() { fmt.Fprint(os.Stderr, usage, "\n") }
    userepo        = true
    VERBOSE        = false
    DEBUG          = false
    DEBUG_LEVEL    = -1
    name           string
    ptype          string
    repo           string
    host           string
    user           string
    target         string
    license        string
    remote         string
    help           bool
)

func Debug(level int, msg string) {
    if DEBUG && DEBUG_LEVEL >= level {
        log.Print(msg)
    }
}

func Verbose(msg string) {
    if DEBUG || VERBOSE {
        fmt.Print(msg)
    }
}

func setupFlags() *flag.FlagSet {
    var fs = flag.NewFlagSet("gonew", flag.ExitOnError)
    fs.StringVar(&repo,
        "repo", "git", "Repository type (e.g. 'git').")
    fs.StringVar(&host,
        "host", "", "Repository host if any (e.g. 'github').")
    fs.StringVar(&user,
        "user", "", "Repo host username.")
    fs.StringVar(&remote,
        "remote", "", "Remote repository url to initialize and push to.")
    fs.StringVar(&target,
        "target", "", "Makefile target. Default based on NAME.")
    fs.StringVar(&license,
        "license", "", "Project license (e.g. 'newbsd').")
    fs.BoolVar(&(AppConfig.MakeTest),
        "test", AppConfig.MakeTest, "Produce test files with Go files.")
    fs.BoolVar(&(userepo), "userepo", true, "Create a local repository.")
    fs.BoolVar(&VERBOSE,
        "v", false, "Verbose output.")
    fs.IntVar(&DEBUG_LEVEL,
        "debug", -1, "Change the amout of debug output.")
    fs.BoolVar(&help,
        "help", false, "Show this message.")
    var usageTemp = fs.Usage
    fs.Usage = func() {
        printUsageHead()
        usageTemp()
    }
    return fs
}

type Request int

const (
    NilRequest Request = iota
    ProjectRequest
    LibraryRequest
)

var RequestedFile File
var RequestedProject Project

func parseArgs() Request {
    var fs = setupFlags()
    fs.Parse(os.Args[1:])
    if DEBUG_LEVEL >= 0 {
        DEBUG = true
    }
    if help {
        fs.Usage()
        os.Exit(0)
    }
    var narg = fs.NArg()
    if narg < 1 {
        fmt.Fprint(os.Stderr, "missing TYPE argument\n")
        os.Exit(1)
    }
    if narg < 2 {
        fmt.Fprint(os.Stderr, "missing NAME argument\n")
        os.Exit(1)
    }
    ptype = fs.Arg(0)
    name = fs.Arg(1)

    if target == "" {
        target = DefaultTarget(name)
    }
    var (
        file = File{
            Name: name, Pkg: "main",
            Repo: AppConfig.Repo, License: AppConfig.License,
            User: AppConfig.HostUser, Host: AppConfig.Host}
        project = Project{
            Name: name, Target: target,
            Type: NilProjectType, License: AppConfig.License, Remote: remote,
            Host: AppConfig.Host, User: AppConfig.HostUser,
            Repo: AppConfig.Repo}
        produceProject = true
        licObj         = NilLicenseType
        repoObj        = NilRepoType
        hostObj        = NilRepoHost
    )
    switch ptype {
    case "cmd":
        project.Type = CmdType
    case "pkg":
        project.Type = PkgType
    case "lib":
        produceProject = false
    default:
        fmt.Fprintf(os.Stderr, "Unknown TYPE %s\n", ptype)
        os.Exit(1)
    }
    switch license {
    case "":
        break
    case "newbsd":
        licObj = NewBSD
    default:
        fmt.Fprintf(os.Stderr, "Unknown TYPE %s\n", ptype)
        os.Exit(1)
    }
    switch repo {
    case "":
        break
    case "git":
        repoObj = GitType
    case "mercurial":
        repoObj = HgType
    default:
        fmt.Fprintf(os.Stderr, "Unknown REPO %s\n", repo)
        os.Exit(1)
    }
    switch host {
    case "":
        break
    case "github":
        hostObj = GitHubHost
        repoObj = GitType
    /*
       case "googlecode":
           hostObj = GoogleCodeType
           repoObj = HgType
    */
    default:
        fmt.Fprintf(os.Stderr, "Unknown HOST %s\n", host)
        os.Exit(1)
    }
    if produceProject {
        // TODO check target for improper characters.
        if user != "" {
            project.User = user
        }
        if licObj != NilLicenseType {
            project.License = licObj
        }
        if hostObj != NilRepoHost {
            project.Host = hostObj
        }
        if repoObj != NilRepoType {
            project.Repo = repoObj
        }
        RequestedProject = project
        return ProjectRequest
    } else {
        if narg < 3 {
            fmt.Fprint(os.Stderr, "missing PKG argument\n")
            os.Exit(1)
        }
        file.Pkg = fs.Arg(2)
        if user != "" {
            file.User = user
        }
        if licObj != NilLicenseType {
            file.License = licObj
        }
        if hostObj != NilRepoHost {
            file.Host = hostObj
        }
        if repoObj != NilRepoType {
            file.Repo = repoObj
        }
        RequestedFile = file
        return LibraryRequest
    }
    return NilRequest
}

func main() {
    if err := TouchConfig(); err != nil {
        fmt.Fprint(os.Stderr, err.String(), "\n")
        os.Exit(1)
    }
    Verbose("Parsing config file.\n")
    ReadConfig()
    switch request := parseArgs(); request {
    case ProjectRequest:
        if DEBUG {
            fmt.Printf("Project requested %v\n", RequestedProject)
        } else if VERBOSE {
            fmt.Printf("Generating project %s\n", RequestedProject.Name)
        }
        if err := RequestedProject.Create(); err != nil {
            fmt.Fprint(os.Stderr, err.String(), "\n")
            os.Exit(1)
        }
    case LibraryRequest:
        if DEBUG {
            fmt.Printf("Library requested %v\n", RequestedFile)
        } else if VERBOSE {
            fmt.Printf("Generating library %s (package %s)\n",
                RequestedFile.Name+".go", RequestedFile.Pkg)
        }
        if err := RequestedFile.Create(); err != nil {
            fmt.Fprint(os.Stderr, err.String(), "\n")
            os.Exit(1)
        }
    }
}
<|endoftext|>


<commit_before>package gores

import (
  "encoding/json"
  "fmt"
  "os"
  "errors"
  "log"
  "strconv"
  _ "strings"
  "time"
  "github.com/garyburd/redigo/redis"
  "github.com/deckarep/golang-set"
  _ "gopkg.in/oleiade/reflections.v1"
)
// redis-cli -h host -p port -a password

// ResQ represents the main Gores object that stores all configurations and connection with Redis
type ResQ struct {
    pool *redis.Pool
    _watched_queues mapset.Set
    Host string
    config *Config
}

// NewResQ creates a new ResQ instance given the pointer to config object
func NewResQ(config *Config) *ResQ {
    var pool *redis.Pool
    var host string

    if len(config.REDISURL) != 0 && len(config.REDIS_PW) != 0 {
        pool = initPoolFromString(config.REDISURL, config.REDIS_PW)
        host = config.REDISURL
    } else {
        pool = initPool()
        host = os.Getenv("REDISURL")
    }
    if pool == nil {
        log.Printf("ERROR Initializing Redis Pool\n")
        return nil
    }
    return &ResQ{
              pool: pool,
              _watched_queues: mapset.NewSet(),
              Host: host,
              config: config,
            }
}

// NewResQ creates a new ResQ instance
// given the pointer to config object, Redis server address and password
func NewResQFromString(config *Config, server string, password string) *ResQ {
  pool := initPoolFromString(server, password)
  if pool == nil {
      log.Printf("initPool() Error\n")
      return nil
  }
  return &ResQ{
            pool: pool,
            _watched_queues: mapset.NewSet(),
            Host: os.Getenv("REDISURL"),
            config: config,
          }
}

// makeRedisPool creates new redis.Pool instance
// given Redis server address and password
func makeRedisPool(server string, password string) *redis.Pool {
    pool := &redis.Pool{
        MaxIdle: 5,
        IdleTimeout: 240 * time.Second,
        Dial: func () (redis.Conn, error) {
              c, err := redis.Dial("tcp", server)
              if err != nil {
                  return c, nil
              }
              c.Do("AUTH", password)

              /* the is needed only if "gores" is configured in Redis's configuration file redis.conf */
              //c.Do("SELECT", "gores")
              return c, nil
            },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
    }
    return pool
}

// helper function to create new redis.Pool instance
func initPool() *redis.Pool{
    return makeRedisPool(os.Getenv("REDISURL"), os.Getenv("REDIS_PW"))
}

// helper function to create new redis.Pool instance
// given Redis server address and password
func initPoolFromString(server string, password string) *redis.Pool {
    return makeRedisPool(server, password)
}

// Enqueue put new job item to Redis message queue
func (resq *ResQ) Enqueue(item map[string]interface{}) error {
    /*
      Enqueue a job into a specific queue. Make sure the map you are
      passing has keys
      **Name**, **Queue**, **Enqueue_timestamp**, **Args**
    */
    queue, ok1 := item["Queue"]
    _, ok2 := item["Args"]
    var err error
    if !ok1 || !ok2 {
        err = errors.New("Unable to enqueue Job map without keys: 'Queue' and 'Args'")
    } else  {
        err = resq.push(queue.(string), item)
    }
    return err
}

// Helper function to put job item to Redis message queue
func (resq *ResQ) push(queue string, item interface{}) error{
    conn := resq.pool.Get()

    if conn == nil {
        return errors.New("Redis pool's connection is nil")
    }

    _, err := conn.Do("RPUSH", fmt.Sprintf(QUEUE_PREFIX, queue), resq.Encode(item))
    if err != nil{
        err = errors.New("Invalid Redis RPUSH Response")
        return err
    }

    err = resq.watch_queue(queue)
    return err
}

// Pop calls "LPOP" command on Redis message queue
// "LPOP" does not block even there is no item found
func (resq *ResQ) Pop(queue string) map[string]interface{}{
    var decoded map[string]interface{}

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return decoded
    }

    reply, err := conn.Do("LPOP", fmt.Sprintf(QUEUE_PREFIX, queue))
    if err != nil || reply == nil {
        return decoded
    }

    data, err := redis.Bytes(reply, err)
    if err != nil{
        return decoded
    }
    decoded = resq.Decode(data)
    return decoded
}

// BlockPop calls "BLPOP" command on Redis message queue
// "BLPOP" blocks for a configured time until a new job item is found and popped
func (resq *ResQ) BlockPop(queues mapset.Set) (string, map[string]interface{}) {
    var decoded map[string]interface{}

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return "", decoded
    }

    queues_slice := make([]interface{}, queues.Cardinality())
    it := queues.Iterator()
    i := 0
    for elem := range it.C {
        queues_slice[i] = fmt.Sprintf(QUEUE_PREFIX, elem)
        i += 1
    }
    r_args := append(queues_slice, BLPOP_MAX_BLOCK_TIME)
    data, err := conn.Do("BLPOP", r_args...)

    if data == nil || err != nil {
        return "", decoded
    }

    // returned data contains [key, value], extract key at index 0, value at index 1
    queue_key := string(data.([]interface{})[0].([]byte))
    decoded = resq.Decode(data.([]interface{})[1].([]byte))
    return queue_key, decoded
}

// Decode unmarshals byte array returned from Redis to a map instance
func (resq *ResQ) Decode(data []byte) map[string]interface{}{
    var decoded map[string]interface{}
    if err := json.Unmarshal(data, &decoded); err != nil{
        return decoded
    }
    return decoded
}

// Encode marshalls map instance to ites string representation
func (resq *ResQ) Encode(item interface{}) string{
    b, err := json.Marshal(item)
    if err != nil{
        return ""
    }
    return string(b)
}

// Size returns the size of the given message queue "resq:queue:%s" on Redis
func (resq *ResQ) Size(queue string) int64 {
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    size, err:= conn.Do("LLEN", fmt.Sprintf(QUEUE_PREFIX, queue))
    if size == nil || err != nil {
        return 0
    }
    return size.(int64)
}

// SizeOfQueue return the size of any given queue on Redis
func (resq *ResQ) SizeOfQueue(key string) int64{
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    size, err := conn.Do("LLEN", key)
    if size == nil || err != nil {
        return 0
    }
    return size.(int64)
}

func (resq *ResQ) watch_queue(queue string) error{
    if resq._watched_queues.Contains(queue){
        return nil
    } else {
        conn := resq.pool.Get()
        if conn == nil {
            return errors.New("Redis pool's connection is nil")
        }

        _, err := conn.Do("SADD", WATCHED_QUEUES, queue)
        if err != nil{
            err = errors.New("watch_queue() SADD Error")
        }
        return err
    }
}

func (resq *ResQ) Enqueue_at(datetime int64, item interface{}) error {
    err := resq.delayedPush(datetime, item)
    if err != nil {
        return err
    }
    return nil
}

func (resq *ResQ) delayedPush(datetime int64, item interface{}) error {
    conn := resq.pool.Get()
    if conn == nil {
        return errors.New("Redis pool's connection is nil")
    }

    key := strconv.FormatInt(datetime, 10)
    _, err := conn.Do("RPUSH", fmt.Sprintf(DEPLAYED_QUEUE_PREFIX, key), resq.Encode(item))
    if err != nil {
        return errors.New("Invalid RPUSH response")
    }
    _, err = conn.Do("ZADD", WATCHED_DELAYED_QUEUE_SCHEDULE, datetime, datetime)
    if err != nil {
        err = errors.New("Invalid ZADD response")
    }
    return err
}

func (resq *ResQ) Queues() []string{
    queues := make([]string, 0)

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return queues
    }

    data, _ := conn.Do("SMEMBERS", WATCHED_QUEUES)
    for _, q := range data.([]interface{}){
        queues = append(queues, string(q.([]byte)))
    }
    return queues
}

func (resq *ResQ) Workers() []string {
    conn := resq.pool.Get()
    data, err := conn.Do("SMEMBERS", WATCHED_WORKERS)
    if data == nil || err != nil {
        return nil
    }

    workers := make([]string, len(data.([]interface{})))
    for i, w := range data.([]interface{}) {
        workers[i] = string(w.([]byte))
    }
    return workers
}

func (resq *ResQ) Info() map[string]interface{} {
    var pending int64 = 0
    for _, q := range resq.Queues() {
        pending += resq.Size(q)
    }

    info := make(map[string]interface{})
    info["pending"] = pending
    info["processed"] = NewStat("processed", resq).Get()
    info["queues"] = len(resq.Queues())
    info["workers"] = len(resq.Workers())
    info["failed"] = NewStat("falied", resq).Get()
    info["host"] = resq.Host
    return info
}

func (resq *ResQ) NextDelayedTimestamp() int64 {
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    key := resq.CurrentTime()
    data, err := conn.Do("ZRANGEBYSCORE", WATCHED_DELAYED_QUEUE_SCHEDULE, "-inf", key)
    if err != nil || data == nil {
        return 0
    }
    if len(data.([]interface{})) > 0 {
        bytes := make([]byte, len(data.([]interface{})[0].([]uint8)))
        for i, v := range data.([]interface{})[0].([]uint8) {
            bytes[i] = byte(v)
        }
        res, _ :=  strconv.Atoi(string(bytes))
        return int64(res)
    }
    return 0
}

func (resq *ResQ) NextItemForTimestamp(timestamp int64) map[string]interface{} {
    var res map[string]interface{}

    s_time := strconv.FormatInt(timestamp, 10)
    key := fmt.Sprintf(DEPLAYED_QUEUE_PREFIX, s_time)

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return res
    }

    reply, err := conn.Do("LPOP", key)
    if reply == nil || err != nil {
        return res
    }
    data, err := redis.Bytes(reply, err)
    if err != nil {
        return res
    }
    res = resq.Decode(data)
    llen, err := conn.Do("LLEN", key)
    if llen == nil || err != nil {
        return res
    }
    if llen.(int64) == 0 {
        conn.Do("DEL", key)
        conn.Do("ZREM", WATCHED_DELAYED_QUEUE_SCHEDULE, timestamp)
    }
    return res
}

func (resq *ResQ) CurrentTime() int64 {
    timestamp := time.Now().Unix()
    return timestamp
}

/* -------------------------------------------------------------------------- */
// Launch startups the gores Dispatcher and Worker to do background works
func Launch(config *Config, tasks *map[string]interface{}) error {
    resq := NewResQ(config)
    if resq == nil {
        return errors.New("ResQ is nil")
    }

    in_slice := make([]interface{}, len(config.Queues))
    for i, q := range config.Queues {
        in_slice[i] = q
    }
    queues_set := mapset.NewSetFromSlice(in_slice)

    dispatcher := NewDispatcher(resq, config, queues_set)
    if dispatcher == nil {
        return errors.New("Dispatcher is nil")
    }
    err := dispatcher.Run(tasks)
    return err
}
<commit_msg>refactor<commit_after>package gores

import (
  "encoding/json"
  "fmt"
  "os"
  "errors"
  "log"
  "strconv"
  _ "strings"
  "time"
  "github.com/garyburd/redigo/redis"
  "github.com/deckarep/golang-set"
  _ "gopkg.in/oleiade/reflections.v1"
)
// redis-cli -h host -p port -a password

// ResQ represents the main Gores object that stores all configurations and connection with Redis
type ResQ struct {
    pool *redis.Pool
    _watched_queues mapset.Set
    Host string
    config *Config
}

// NewResQ creates a new ResQ instance given the pointer to config object
func NewResQ(config *Config) *ResQ {
    var pool *redis.Pool
    var host string

    if len(config.REDISURL) != 0 && len(config.REDIS_PW) != 0 {
        pool = initPoolFromString(config.REDISURL, config.REDIS_PW)
        host = config.REDISURL
    } else {
        pool = initPool()
        host = os.Getenv("REDISURL")
    }
    if pool == nil {
        log.Printf("ERROR Initializing Redis Pool\n")
        return nil
    }
    return &ResQ{
              pool: pool,
              _watched_queues: mapset.NewSet(),
              Host: host,
              config: config,
            }
}

// NewResQ creates a new ResQ instance
// given the pointer to config object, Redis server address and password
func NewResQFromString(config *Config, server string, password string) *ResQ {
  pool := initPoolFromString(server, password)
  if pool == nil {
      log.Printf("initPool() Error\n")
      return nil
  }
  return &ResQ{
            pool: pool,
            _watched_queues: mapset.NewSet(),
            Host: os.Getenv("REDISURL"),
            config: config,
          }
}

// makeRedisPool creates new redis.Pool instance
// given Redis server address and password
func makeRedisPool(server string, password string) *redis.Pool {
    pool := &redis.Pool{
        MaxIdle: 5,
        IdleTimeout: 240 * time.Second,
        Dial: func () (redis.Conn, error) {
              c, err := redis.Dial("tcp", server)
              if err != nil {
                  return c, nil
              }
              c.Do("AUTH", password)

              /* the is needed only if "gores" is configured in Redis's configuration file redis.conf */
              //c.Do("SELECT", "gores")
              return c, nil
            },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
    }
    return pool
}

// helper function to create new redis.Pool instance
func initPool() *redis.Pool{
    return makeRedisPool(os.Getenv("REDISURL"), os.Getenv("REDIS_PW"))
}

// helper function to create new redis.Pool instance
// given Redis server address and password
func initPoolFromString(server string, password string) *redis.Pool {
    return makeRedisPool(server, password)
}

// Enqueue put new job item to Redis message queue
func (resq *ResQ) Enqueue(item map[string]interface{}) error {
    /*
      Enqueue a job into a specific queue. Make sure the map you are
      passing has keys
      **Name**, **Queue**, **Enqueue_timestamp**, **Args**
    */
    queue, ok1 := item["Queue"]
    _, ok2 := item["Args"]
    var err error
    if !ok1 || !ok2 {
        err = errors.New("Unable to enqueue Job map without keys: 'Queue' and 'Args'")
    } else  {
        err = resq.push(queue.(string), item)
    }
    return err
}

// Helper function to put job item to Redis message queue
func (resq *ResQ) push(queue string, item interface{}) error{
    conn := resq.pool.Get()

    if conn == nil {
        return errors.New("Redis pool's connection is nil")
    }

    itemString, err := resq.Encode(item)
    if err != nil {
        return err
    }

    _, err = conn.Do("RPUSH", fmt.Sprintf(QUEUE_PREFIX, queue), itemString)
    if err != nil{
        err = errors.New("Invalid Redis RPUSH Response")
        return err
    }

    return resq.watch_queue(queue)
}

// Pop calls "LPOP" command on Redis message queue
// "LPOP" does not block even there is no item found
func (resq *ResQ) Pop(queue string) map[string]interface{}{
    var decoded map[string]interface{}

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return decoded
    }

    reply, err := conn.Do("LPOP", fmt.Sprintf(QUEUE_PREFIX, queue))
    if err != nil || reply == nil {
        return decoded
    }

    data, err := redis.Bytes(reply, err)
    if err != nil{
        return decoded
    }
    item, _ := resq.Decode(data)
    return item
}

// BlockPop calls "BLPOP" command on Redis message queue
// "BLPOP" blocks for a configured time until a new job item is found and popped
func (resq *ResQ) BlockPop(queues mapset.Set) (string, map[string]interface{}) {
    var decoded map[string]interface{}

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return "", decoded
    }

    queues_slice := make([]interface{}, queues.Cardinality())
    it := queues.Iterator()
    i := 0
    for elem := range it.C {
        queues_slice[i] = fmt.Sprintf(QUEUE_PREFIX, elem)
        i += 1
    }
    r_args := append(queues_slice, BLPOP_MAX_BLOCK_TIME)
    data, err := conn.Do("BLPOP", r_args...)

    if data == nil || err != nil {
        return "", decoded
    }

    // returned data contains [key, value], extract key at index 0, value at index 1
    queue_key := string(data.([]interface{})[0].([]byte))
    decoded, _ = resq.Decode(data.([]interface{})[1].([]byte))
    return queue_key, decoded
}

// Decode unmarshals byte array returned from Redis to a map instance
func (resq *ResQ) Decode(data []byte) (map[string]interface{}, error) {
    var decoded map[string]interface{}
    if err := json.Unmarshal(data, &decoded); err != nil{
        return decoded, err
    }
    return decoded, nil
}

// Encode marshalls map instance to its string representation
func (resq *ResQ) Encode(item interface{}) (string, error) {
    b, err := json.Marshal(item)
    if err != nil{
        return "", err
    }
    return string(b), nil
}

// Size returns the size of the given message queue "resq:queue:%s" on Redis
func (resq *ResQ) Size(queue string) int64 {
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    size, err:= conn.Do("LLEN", fmt.Sprintf(QUEUE_PREFIX, queue))
    if size == nil || err != nil {
        return 0
    }
    return size.(int64)
}

// SizeOfQueue return the size of any given queue on Redis
func (resq *ResQ) SizeOfQueue(key string) int64{
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    size, err := conn.Do("LLEN", key)
    if size == nil || err != nil {
        return 0
    }
    return size.(int64)
}

func (resq *ResQ) watch_queue(queue string) error{
    if resq._watched_queues.Contains(queue){
        return nil
    } else {
        conn := resq.pool.Get()
        if conn == nil {
            return errors.New("Redis pool's connection is nil")
        }

        _, err := conn.Do("SADD", WATCHED_QUEUES, queue)
        if err != nil{
            err = errors.New("watch_queue() SADD Error")
        }
        return err
    }
}

func (resq *ResQ) Enqueue_at(datetime int64, item interface{}) error {
    err := resq.delayedPush(datetime, item)
    if err != nil {
        return err
    }
    return nil
}

func (resq *ResQ) delayedPush(datetime int64, item interface{}) error {
    conn := resq.pool.Get()
    if conn == nil {
        return errors.New("Redis pool's connection is nil")
    }

    key := strconv.FormatInt(datetime, 10)
    itemString, err := resq.Encode(item)
    if err != nil {
        return err
    }

    _, err = conn.Do("RPUSH", fmt.Sprintf(DEPLAYED_QUEUE_PREFIX, key), itemString)
    if err != nil {
        return errors.New("Invalid RPUSH response")
    }

    _, err = conn.Do("ZADD", WATCHED_DELAYED_QUEUE_SCHEDULE, datetime, datetime)
    if err != nil {
        err = errors.New("Invalid ZADD response")
    }
    return err
}

func (resq *ResQ) Queues() []string{
    queues := make([]string, 0)

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return queues
    }

    data, _ := conn.Do("SMEMBERS", WATCHED_QUEUES)
    for _, q := range data.([]interface{}){
        queues = append(queues, string(q.([]byte)))
    }
    return queues
}

func (resq *ResQ) Workers() []string {
    conn := resq.pool.Get()
    data, err := conn.Do("SMEMBERS", WATCHED_WORKERS)
    if data == nil || err != nil {
        return nil
    }

    workers := make([]string, len(data.([]interface{})))
    for i, w := range data.([]interface{}) {
        workers[i] = string(w.([]byte))
    }
    return workers
}

func (resq *ResQ) Info() map[string]interface{} {
    var pending int64 = 0
    for _, q := range resq.Queues() {
        pending += resq.Size(q)
    }

    info := make(map[string]interface{})
    info["pending"] = pending
    info["processed"] = NewStat("processed", resq).Get()
    info["queues"] = len(resq.Queues())
    info["workers"] = len(resq.Workers())
    info["failed"] = NewStat("falied", resq).Get()
    info["host"] = resq.Host
    return info
}

func (resq *ResQ) NextDelayedTimestamp() int64 {
    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return 0
    }

    key := resq.CurrentTime()
    data, err := conn.Do("ZRANGEBYSCORE", WATCHED_DELAYED_QUEUE_SCHEDULE, "-inf", key)
    if err != nil || data == nil {
        return 0
    }
    if len(data.([]interface{})) > 0 {
        bytes := make([]byte, len(data.([]interface{})[0].([]uint8)))
        for i, v := range data.([]interface{})[0].([]uint8) {
            bytes[i] = byte(v)
        }
        res, _ :=  strconv.Atoi(string(bytes))
        return int64(res)
    }
    return 0
}

func (resq *ResQ) NextItemForTimestamp(timestamp int64) map[string]interface{} {
    var res map[string]interface{}

    s_time := strconv.FormatInt(timestamp, 10)
    key := fmt.Sprintf(DEPLAYED_QUEUE_PREFIX, s_time)

    conn := resq.pool.Get()
    if conn == nil {
        log.Printf("Redis pool's connection is nil")
        return res
    }

    reply, err := conn.Do("LPOP", key)
    if reply == nil || err != nil {
        return res
    }
    data, err := redis.Bytes(reply, err)
    if err != nil {
        return res
    }
    res, _ = resq.Decode(data)
    llen, err := conn.Do("LLEN", key)
    if llen == nil || err != nil {
        return res
    }
    if llen.(int64) == 0 {
        conn.Do("DEL", key)
        conn.Do("ZREM", WATCHED_DELAYED_QUEUE_SCHEDULE, timestamp)
    }
    return res
}

func (resq *ResQ) CurrentTime() int64 {
    timestamp := time.Now().Unix()
    return timestamp
}

/* -------------------------------------------------------------------------- */
// Launch startups the gores Dispatcher and Worker to do background works
func Launch(config *Config, tasks *map[string]interface{}) error {
    resq := NewResQ(config)
    if resq == nil {
        return errors.New("ResQ is nil")
    }

    in_slice := make([]interface{}, len(config.Queues))
    for i, q := range config.Queues {
        in_slice[i] = q
    }
    queues_set := mapset.NewSetFromSlice(in_slice)

    dispatcher := NewDispatcher(resq, config, queues_set)
    if dispatcher == nil {
        return errors.New("Dispatcher is nil")
    }
    err := dispatcher.Run(tasks)
    return err
}
<|endoftext|>


<commit_before>package gormigrate

import (
	"errors"
	"fmt"

	"github.com/jinzhu/gorm"
)

const (
	initSchemaMigrationId = "SCHEMA_INIT"
)

// MigrateFunc is the func signature for migrating.
type MigrateFunc func(*gorm.DB) error

// RollbackFunc is the func signature for rollbacking.
type RollbackFunc func(*gorm.DB) error

// InitSchemaFunc is the func signature for initializing the schema.
type InitSchemaFunc func(*gorm.DB) error

// Options define options for all migrations.
type Options struct {
	// TableName is the migration table.
	TableName string
	// IDColumnName is the name of column where the migration id will be stored.
	IDColumnName string
	// IDColumnSize is the length of the migration id column
	IDColumnSize int
	// UseTransaction makes Gormigrate execute migrations inside a single transaction.
	// Keep in mind that not all databases support DDL commands inside transactions.
	UseTransaction bool
}

// Migration represents a database migration (a modification to be made on the database).
type Migration struct {
	// ID is the migration identifier. Usually a timestamp like "201601021504".
	ID string
	// Migrate is a function that will br executed while running this migration.
	Migrate MigrateFunc
	// Rollback will be executed on rollback. Can be nil.
	Rollback RollbackFunc
}

// Gormigrate represents a collection of all migrations of a database schema.
type Gormigrate struct {
	db         *gorm.DB
	tx         *gorm.DB
	options    *Options
	migrations []*Migration
	initSchema InitSchemaFunc
}

// ReservedIDError is returned when a migration is using a reserved ID
type ReservedIDError struct {
	ID string
}

func (e *ReservedIDError) Error() string {
	return fmt.Sprintf(`gormigrate: Reserved migration ID: "%s"`, e.ID)
}

// DuplicatedIDError is returned when more than one migration have the same ID
type DuplicatedIDError struct {
	ID string
}

func (e *DuplicatedIDError) Error() string {
	return fmt.Sprintf(`gormigrate: Duplicated migration ID: "%s"`, e.ID)
}

var (
	// DefaultOptions can be used if you don't want to think about options.
	DefaultOptions = &Options{
		TableName:      "migrations",
		IDColumnName:   "id",
		IDColumnSize:   255,
		UseTransaction: false,
	}

	// ErrRollbackImpossible is returned when trying to rollback a migration
	// that has no rollback function.
	ErrRollbackImpossible = errors.New("gormigrate: It's impossible to rollback this migration")

	// ErrNoMigrationDefined is returned when no migration is defined.
	ErrNoMigrationDefined = errors.New("gormigrate: No migration defined")

	// ErrMissingID is returned when the ID od migration is equal to ""
	ErrMissingID = errors.New("gormigrate: Missing ID in migration")

	// ErrNoRunMigration is returned when any run migration was found while
	// running RollbackLast
	ErrNoRunMigration = errors.New("gormigrate: Could not find last run migration")

	// ErrMigrationIDDoesNotExist is returned when migrating or rolling back to a migration ID that
	// does not exist in the list of migrations
	ErrMigrationIDDoesNotExist = errors.New("gormigrate: Tried to migrate to an ID that doesn't exist")
)

// New returns a new Gormigrate.
func New(db *gorm.DB, options *Options, migrations []*Migration) *Gormigrate {
	if options.TableName == "" {
		options.TableName = DefaultOptions.TableName
	}
	if options.IDColumnName == "" {
		options.IDColumnName = DefaultOptions.IDColumnName
	}
	if options.IDColumnSize == 0 {
		options.IDColumnSize = DefaultOptions.IDColumnSize
	}
	return &Gormigrate{
		db:         db,
		options:    options,
		migrations: migrations,
	}
}

// InitSchema sets a function that is run if no migration is found.
// The idea is preventing to run all migrations when a new clean database
// is being migrating. In this function you should create all tables and
// foreign key necessary to your application.
func (g *Gormigrate) InitSchema(initSchema InitSchemaFunc) {
	g.initSchema = initSchema
}

// Migrate executes all migrations that did not run yet.
func (g *Gormigrate) Migrate() error {
	if !g.hasMigrations() {
		return ErrNoMigrationDefined
	}
	var targetMigrationID string
	if len(g.migrations) > 0 {
		targetMigrationID = g.migrations[len(g.migrations)-1].ID
	}
	return g.migrate(targetMigrationID)
}

// MigrateTo executes all migrations that did not run yet up to the migration that matches `migrationID`.
func (g *Gormigrate) MigrateTo(migrationID string) error {
	if err := g.checkIDExist(migrationID); err != nil {
		return err
	}
	return g.migrate(migrationID)
}

func (g *Gormigrate) migrate(migrationID string) error {
	if !g.hasMigrations() {
		return ErrNoMigrationDefined
	}

	if err := g.checkReservedID(); err != nil {
		return err
	}

	if err := g.checkDuplicatedID(); err != nil {
		return err
	}

	g.begin()

	if err := g.createMigrationTableIfNotExists(); err != nil {
		return err
	}

	if g.initSchema != nil && g.canInitializeSchema() {
		if err := g.runInitSchema(); err != nil {
			g.rollback()
			return err
		}
		return g.commit()
	}

	for _, migration := range g.migrations {
		if err := g.runMigration(migration); err != nil {
			g.rollback()
			return err
		}
		if migrationID != "" && migration.ID == migrationID {
			break
		}
	}

	return g.commit()
}

// There are migrations to apply if either there's a defined
// initSchema function or if the list of migrations is not empty.
func (g *Gormigrate) hasMigrations() bool {
	return g.initSchema != nil || len(g.migrations) > 0
}

// Check whether any migration is using a reserved ID.
// For now there's only have one reserved ID, but there may be more in the future.
func (g *Gormigrate) checkReservedID() error {
	for _, m := range g.migrations {
		if m.ID == initSchemaMigrationId {
			return &ReservedIDError{ID: m.ID}
		}
	}
	return nil
}

func (g *Gormigrate) checkDuplicatedID() error {
	lookup := make(map[string]struct{}, len(g.migrations))
	for _, m := range g.migrations {
		if _, ok := lookup[m.ID]; ok {
			return &DuplicatedIDError{ID: m.ID}
		}
		lookup[m.ID] = struct{}{}
	}
	return nil
}

func (g *Gormigrate) checkIDExist(migrationID string) error {
	for _, migrate := range g.migrations {
		if migrate.ID == migrationID {
			return nil
		}
	}
	return ErrMigrationIDDoesNotExist
}

// RollbackLast undo the last migration
func (g *Gormigrate) RollbackLast() error {
	if len(g.migrations) == 0 {
		return ErrNoMigrationDefined
	}

	g.begin()
	lastRunMigration, err := g.getLastRunMigration()
	if err != nil {
		return err
	}
	g.rollback()

	if err := g.RollbackMigration(lastRunMigration); err != nil {
		return err
	}
	return nil
}

// RollbackTo undoes migrations up to the given migration that matches the `migrationID`.
// Migration with the matching `migrationID` is not rolled back.
func (g *Gormigrate) RollbackTo(migrationID string) error {
	if len(g.migrations) == 0 {
		return ErrNoMigrationDefined
	}

	if err := g.checkIDExist(migrationID); err != nil {
		return err
	}

	g.begin()

	for i := len(g.migrations) - 1; i >= 0; i-- {
		migration := g.migrations[i]
		if migration.ID == migrationID {
			break
		}
		if g.migrationDidRun(migration) {
			if err := g.rollbackMigration(migration); err != nil {
				g.rollback()
				return err
			}
		}
	}

	return g.commit()
}

func (g *Gormigrate) getLastRunMigration() (*Migration, error) {
	for i := len(g.migrations) - 1; i >= 0; i-- {
		migration := g.migrations[i]
		if g.migrationDidRun(migration) {
			return migration, nil
		}
	}
	return nil, ErrNoRunMigration
}

// RollbackMigration undo a migration.
func (g *Gormigrate) RollbackMigration(m *Migration) error {
	g.begin()
	if err := g.rollbackMigration(m); err != nil {
		g.rollback()
		return err
	}
	return g.commit()
}

func (g *Gormigrate) rollbackMigration(m *Migration) error {
	if m.Rollback == nil {
		return ErrRollbackImpossible
	}

	if err := m.Rollback(g.tx); err != nil {
		return err
	}

	sql := fmt.Sprintf("DELETE FROM %s WHERE %s = ?", g.options.TableName, g.options.IDColumnName)
	if err := g.tx.Exec(sql, m.ID).Error; err != nil {
		return err
	}
	return nil
}

func (g *Gormigrate) runInitSchema() error {
	if err := g.initSchema(g.tx); err != nil {
		return err
	}
	if err := g.insertMigration(initSchemaMigrationId); err != nil {
		return err
	}

	for _, migration := range g.migrations {
		if err := g.insertMigration(migration.ID); err != nil {
			return err
		}
	}

	return nil
}

func (g *Gormigrate) runMigration(migration *Migration) error {
	if len(migration.ID) == 0 {
		return ErrMissingID
	}

	if !g.migrationDidRun(migration) {
		if err := migration.Migrate(g.tx); err != nil {
			return err
		}

		if err := g.insertMigration(migration.ID); err != nil {
			return err
		}
	}
	return nil
}

func (g *Gormigrate) createMigrationTableIfNotExists() error {
	if g.tx.HasTable(g.options.TableName) {
		return nil
	}

	sql := fmt.Sprintf("CREATE TABLE %s (%s VARCHAR(%d) PRIMARY KEY)", g.options.TableName, g.options.IDColumnName, g.options.IDColumnSize)
	if err := g.tx.Exec(sql).Error; err != nil {
		return err
	}
	return nil
}

func (g *Gormigrate) migrationDidRun(m *Migration) bool {
	var count int
	g.tx.
		Table(g.options.TableName).
		Where(fmt.Sprintf("%s = ?", g.options.IDColumnName), m.ID).
		Count(&count)
	return count > 0
}

// The schema can be initialised only if it hasn't been initialised yet
// and no other migration has been applied already.
func (g *Gormigrate) canInitializeSchema() bool {
	if g.migrationDidRun(&Migration{ID: initSchemaMigrationId}) {
		return false
	}

	// If the ID doesn't exist, we also want the list of migrations to be empty
	var count int
	g.tx.
		Table(g.options.TableName).
		Count(&count)
	return count == 0
}

func (g *Gormigrate) insertMigration(id string) error {
	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?)", g.options.TableName, g.options.IDColumnName)
	return g.tx.Exec(sql, id).Error
}

func (g *Gormigrate) begin() {
	if g.options.UseTransaction {
		g.tx = g.db.Begin()
	} else {
		g.tx = g.db
	}
}

func (g *Gormigrate) commit() error {
	if g.options.UseTransaction {
		if err := g.tx.Commit().Error; err != nil {
			return err
		}
	}
	return nil
}

func (g *Gormigrate) rollback() {
	if g.options.UseTransaction {
		g.tx.Rollback()
	}
}
<commit_msg>Defer rollback in migrate<commit_after>package gormigrate

import (
	"errors"
	"fmt"

	"github.com/jinzhu/gorm"
)

const (
	initSchemaMigrationId = "SCHEMA_INIT"
)

// MigrateFunc is the func signature for migrating.
type MigrateFunc func(*gorm.DB) error

// RollbackFunc is the func signature for rollbacking.
type RollbackFunc func(*gorm.DB) error

// InitSchemaFunc is the func signature for initializing the schema.
type InitSchemaFunc func(*gorm.DB) error

// Options define options for all migrations.
type Options struct {
	// TableName is the migration table.
	TableName string
	// IDColumnName is the name of column where the migration id will be stored.
	IDColumnName string
	// IDColumnSize is the length of the migration id column
	IDColumnSize int
	// UseTransaction makes Gormigrate execute migrations inside a single transaction.
	// Keep in mind that not all databases support DDL commands inside transactions.
	UseTransaction bool
}

// Migration represents a database migration (a modification to be made on the database).
type Migration struct {
	// ID is the migration identifier. Usually a timestamp like "201601021504".
	ID string
	// Migrate is a function that will br executed while running this migration.
	Migrate MigrateFunc
	// Rollback will be executed on rollback. Can be nil.
	Rollback RollbackFunc
}

// Gormigrate represents a collection of all migrations of a database schema.
type Gormigrate struct {
	db         *gorm.DB
	tx         *gorm.DB
	options    *Options
	migrations []*Migration
	initSchema InitSchemaFunc
}

// ReservedIDError is returned when a migration is using a reserved ID
type ReservedIDError struct {
	ID string
}

func (e *ReservedIDError) Error() string {
	return fmt.Sprintf(`gormigrate: Reserved migration ID: "%s"`, e.ID)
}

// DuplicatedIDError is returned when more than one migration have the same ID
type DuplicatedIDError struct {
	ID string
}

func (e *DuplicatedIDError) Error() string {
	return fmt.Sprintf(`gormigrate: Duplicated migration ID: "%s"`, e.ID)
}

var (
	// DefaultOptions can be used if you don't want to think about options.
	DefaultOptions = &Options{
		TableName:      "migrations",
		IDColumnName:   "id",
		IDColumnSize:   255,
		UseTransaction: false,
	}

	// ErrRollbackImpossible is returned when trying to rollback a migration
	// that has no rollback function.
	ErrRollbackImpossible = errors.New("gormigrate: It's impossible to rollback this migration")

	// ErrNoMigrationDefined is returned when no migration is defined.
	ErrNoMigrationDefined = errors.New("gormigrate: No migration defined")

	// ErrMissingID is returned when the ID od migration is equal to ""
	ErrMissingID = errors.New("gormigrate: Missing ID in migration")

	// ErrNoRunMigration is returned when any run migration was found while
	// running RollbackLast
	ErrNoRunMigration = errors.New("gormigrate: Could not find last run migration")

	// ErrMigrationIDDoesNotExist is returned when migrating or rolling back to a migration ID that
	// does not exist in the list of migrations
	ErrMigrationIDDoesNotExist = errors.New("gormigrate: Tried to migrate to an ID that doesn't exist")
)

// New returns a new Gormigrate.
func New(db *gorm.DB, options *Options, migrations []*Migration) *Gormigrate {
	if options.TableName == "" {
		options.TableName = DefaultOptions.TableName
	}
	if options.IDColumnName == "" {
		options.IDColumnName = DefaultOptions.IDColumnName
	}
	if options.IDColumnSize == 0 {
		options.IDColumnSize = DefaultOptions.IDColumnSize
	}
	return &Gormigrate{
		db:         db,
		options:    options,
		migrations: migrations,
	}
}

// InitSchema sets a function that is run if no migration is found.
// The idea is preventing to run all migrations when a new clean database
// is being migrating. In this function you should create all tables and
// foreign key necessary to your application.
func (g *Gormigrate) InitSchema(initSchema InitSchemaFunc) {
	g.initSchema = initSchema
}

// Migrate executes all migrations that did not run yet.
func (g *Gormigrate) Migrate() error {
	if !g.hasMigrations() {
		return ErrNoMigrationDefined
	}
	var targetMigrationID string
	if len(g.migrations) > 0 {
		targetMigrationID = g.migrations[len(g.migrations)-1].ID
	}
	return g.migrate(targetMigrationID)
}

// MigrateTo executes all migrations that did not run yet up to the migration that matches `migrationID`.
func (g *Gormigrate) MigrateTo(migrationID string) error {
	if err := g.checkIDExist(migrationID); err != nil {
		return err
	}
	return g.migrate(migrationID)
}

func (g *Gormigrate) migrate(migrationID string) error {
	if !g.hasMigrations() {
		return ErrNoMigrationDefined
	}

	if err := g.checkReservedID(); err != nil {
		return err
	}

	if err := g.checkDuplicatedID(); err != nil {
		return err
	}

	g.begin()
	defer g.rollback()

	if err := g.createMigrationTableIfNotExists(); err != nil {
		return err
	}

	if g.initSchema != nil && g.canInitializeSchema() {
		if err := g.runInitSchema(); err != nil {
			return err
		}
		return g.commit()
	}

	for _, migration := range g.migrations {
		if err := g.runMigration(migration); err != nil {
			return err
		}
		if migrationID != "" && migration.ID == migrationID {
			break
		}
	}

	return g.commit()
}

// There are migrations to apply if either there's a defined
// initSchema function or if the list of migrations is not empty.
func (g *Gormigrate) hasMigrations() bool {
	return g.initSchema != nil || len(g.migrations) > 0
}

// Check whether any migration is using a reserved ID.
// For now there's only have one reserved ID, but there may be more in the future.
func (g *Gormigrate) checkReservedID() error {
	for _, m := range g.migrations {
		if m.ID == initSchemaMigrationId {
			return &ReservedIDError{ID: m.ID}
		}
	}
	return nil
}

func (g *Gormigrate) checkDuplicatedID() error {
	lookup := make(map[string]struct{}, len(g.migrations))
	for _, m := range g.migrations {
		if _, ok := lookup[m.ID]; ok {
			return &DuplicatedIDError{ID: m.ID}
		}
		lookup[m.ID] = struct{}{}
	}
	return nil
}

func (g *Gormigrate) checkIDExist(migrationID string) error {
	for _, migrate := range g.migrations {
		if migrate.ID == migrationID {
			return nil
		}
	}
	return ErrMigrationIDDoesNotExist
}

// RollbackLast undo the last migration
func (g *Gormigrate) RollbackLast() error {
	if len(g.migrations) == 0 {
		return ErrNoMigrationDefined
	}

	g.begin()
	lastRunMigration, err := g.getLastRunMigration()
	if err != nil {
		return err
	}
	g.rollback()

	if err := g.RollbackMigration(lastRunMigration); err != nil {
		return err
	}
	return nil
}

// RollbackTo undoes migrations up to the given migration that matches the `migrationID`.
// Migration with the matching `migrationID` is not rolled back.
func (g *Gormigrate) RollbackTo(migrationID string) error {
	if len(g.migrations) == 0 {
		return ErrNoMigrationDefined
	}

	if err := g.checkIDExist(migrationID); err != nil {
		return err
	}

	g.begin()

	for i := len(g.migrations) - 1; i >= 0; i-- {
		migration := g.migrations[i]
		if migration.ID == migrationID {
			break
		}
		if g.migrationDidRun(migration) {
			if err := g.rollbackMigration(migration); err != nil {
				g.rollback()
				return err
			}
		}
	}

	return g.commit()
}

func (g *Gormigrate) getLastRunMigration() (*Migration, error) {
	for i := len(g.migrations) - 1; i >= 0; i-- {
		migration := g.migrations[i]
		if g.migrationDidRun(migration) {
			return migration, nil
		}
	}
	return nil, ErrNoRunMigration
}

// RollbackMigration undo a migration.
func (g *Gormigrate) RollbackMigration(m *Migration) error {
	g.begin()
	if err := g.rollbackMigration(m); err != nil {
		g.rollback()
		return err
	}
	return g.commit()
}

func (g *Gormigrate) rollbackMigration(m *Migration) error {
	if m.Rollback == nil {
		return ErrRollbackImpossible
	}

	if err := m.Rollback(g.tx); err != nil {
		return err
	}

	sql := fmt.Sprintf("DELETE FROM %s WHERE %s = ?", g.options.TableName, g.options.IDColumnName)
	if err := g.tx.Exec(sql, m.ID).Error; err != nil {
		return err
	}
	return nil
}

func (g *Gormigrate) runInitSchema() error {
	if err := g.initSchema(g.tx); err != nil {
		return err
	}
	if err := g.insertMigration(initSchemaMigrationId); err != nil {
		return err
	}

	for _, migration := range g.migrations {
		if err := g.insertMigration(migration.ID); err != nil {
			return err
		}
	}

	return nil
}

func (g *Gormigrate) runMigration(migration *Migration) error {
	if len(migration.ID) == 0 {
		return ErrMissingID
	}

	if !g.migrationDidRun(migration) {
		if err := migration.Migrate(g.tx); err != nil {
			return err
		}

		if err := g.insertMigration(migration.ID); err != nil {
			return err
		}
	}
	return nil
}

func (g *Gormigrate) createMigrationTableIfNotExists() error {
	if g.tx.HasTable(g.options.TableName) {
		return nil
	}

	sql := fmt.Sprintf("CREATE TABLE %s (%s VARCHAR(%d) PRIMARY KEY)", g.options.TableName, g.options.IDColumnName, g.options.IDColumnSize)
	if err := g.tx.Exec(sql).Error; err != nil {
		return err
	}
	return nil
}

func (g *Gormigrate) migrationDidRun(m *Migration) bool {
	var count int
	g.tx.
		Table(g.options.TableName).
		Where(fmt.Sprintf("%s = ?", g.options.IDColumnName), m.ID).
		Count(&count)
	return count > 0
}

// The schema can be initialised only if it hasn't been initialised yet
// and no other migration has been applied already.
func (g *Gormigrate) canInitializeSchema() bool {
	if g.migrationDidRun(&Migration{ID: initSchemaMigrationId}) {
		return false
	}

	// If the ID doesn't exist, we also want the list of migrations to be empty
	var count int
	g.tx.
		Table(g.options.TableName).
		Count(&count)
	return count == 0
}

func (g *Gormigrate) insertMigration(id string) error {
	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?)", g.options.TableName, g.options.IDColumnName)
	return g.tx.Exec(sql, id).Error
}

func (g *Gormigrate) begin() {
	if g.options.UseTransaction {
		g.tx = g.db.Begin()
	} else {
		g.tx = g.db
	}
}

func (g *Gormigrate) commit() error {
	if g.options.UseTransaction {
		if err := g.tx.Commit().Error; err != nil {
			return err
		}
	}
	return nil
}

func (g *Gormigrate) rollback() {
	if g.options.UseTransaction {
		g.tx.Rollback()
	}
}
<|endoftext|>


<commit_before>package geohash

import "testing"

// TestCase objects are generated from independent code to verify we get the
// same results. See testcases_test.go.
type TestCase struct {
	hashInt  uint64
	hash     string
	lat, lng float64
}

// Test we get the same string geohashes.
func TestEncode(t *testing.T) {
	for _, c := range testcases {
		hash := Encode(c.lat, c.lng)
		if c.hash != hash {
			t.Errorf("incorrect encode string result for (%v,%v): %s != %s",
				c.lat, c.lng, c.hash, hash)
		}
	}
}

// Test we get the same integer geohashes.
func TestEncodeInt(t *testing.T) {
	for _, c := range testcases {
		hashInt := EncodeInt(c.lat, c.lng)
		if c.hashInt != hashInt {
			t.Errorf("incorrect encode integer result for (%v,%v): %016x != %016x xor %016x",
				c.lat, c.lng, c.hashInt, hashInt, c.hashInt^hashInt)
		}
	}
}

// Verify the prefix property.
func TestPrefixProperty(t *testing.T) {
	for _, c := range testcases {
		for chars := uint(1); chars <= 12; chars++ {
			hash := EncodeWithPrecision(c.lat, c.lng, chars)
			pre := c.hash[:chars]
			if pre != hash {
				t.Errorf("incorrect encode string result for (%v,%v) at precision %d: %s != %s",
					c.lat, c.lng, chars, pre, hash)
			}
		}
	}
}

// Test bounding boxes for string geohashes.
func TestBoundingBox(t *testing.T) {
	for _, c := range testcases {
		box := BoundingBox(c.hash)
		if !box.Contains(c.lat, c.lng) {
			t.Errorf("incorrect bounding box for %s", c.hash)
		}
	}
}

type DecodeTestCase struct {
	hash string
	box  Box
}

// Test decoding at various precisions.
func TestDecode(t *testing.T) {
	for _, c := range decodecases {
		lat, lng := Decode(c.hash)
		if !c.box.Contains(lat, lng) {
			t.Errorf("hash %s decoded to %f,%f should lie in %+v",
				c.hash, lat, lng, c.box)
		}
	}
}
<commit_msg>Test roundtrip decode then encode<commit_after>package geohash

import "testing"

// TestCase objects are generated from independent code to verify we get the
// same results. See testcases_test.go.
type TestCase struct {
	hashInt  uint64
	hash     string
	lat, lng float64
}

// Test we get the same string geohashes.
func TestEncode(t *testing.T) {
	for _, c := range testcases {
		hash := Encode(c.lat, c.lng)
		if c.hash != hash {
			t.Errorf("incorrect encode string result for (%v,%v): %s != %s",
				c.lat, c.lng, c.hash, hash)
		}
	}
}

// Test we get the same integer geohashes.
func TestEncodeInt(t *testing.T) {
	for _, c := range testcases {
		hashInt := EncodeInt(c.lat, c.lng)
		if c.hashInt != hashInt {
			t.Errorf("incorrect encode integer result for (%v,%v): %016x != %016x xor %016x",
				c.lat, c.lng, c.hashInt, hashInt, c.hashInt^hashInt)
		}
	}
}

// Verify the prefix property.
func TestPrefixProperty(t *testing.T) {
	for _, c := range testcases {
		for chars := uint(1); chars <= 12; chars++ {
			hash := EncodeWithPrecision(c.lat, c.lng, chars)
			pre := c.hash[:chars]
			if pre != hash {
				t.Errorf("incorrect encode string result for (%v,%v) at precision %d: %s != %s",
					c.lat, c.lng, chars, pre, hash)
			}
		}
	}
}

// Test bounding boxes for string geohashes.
func TestBoundingBox(t *testing.T) {
	for _, c := range testcases {
		box := BoundingBox(c.hash)
		if !box.Contains(c.lat, c.lng) {
			t.Errorf("incorrect bounding box for %s", c.hash)
		}
	}
}

type DecodeTestCase struct {
	hash string
	box  Box
}

// Test decoding at various precisions.
func TestDecode(t *testing.T) {
	for _, c := range decodecases {
		lat, lng := Decode(c.hash)
		if !c.box.Contains(lat, lng) {
			t.Errorf("hash %s decoded to %f,%f should lie in %+v",
				c.hash, lat, lng, c.box)
		}
	}
}

// Test roundtrip decoding then encoding again.
func TestDecodeThenEncode(t *testing.T) {
	for _, c := range decodecases {
		precision := uint(len(c.hash))
		lat, lng := Decode(c.hash)
		rehashed := EncodeWithPrecision(lat, lng, precision)
		if c.hash != rehashed {
			t.Errorf("hash %s decoded and re-encoded to %s", c.hash, rehashed)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2020 Institute of the Czech National Corpus,
//                Faculty of Arts, Charles University
//
// 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 mapka

import (
	"time"
)

const poolSize = 1000

// PrevReqPool is a cyclic list containing recently processed
// requests. It is used for searching very similar requests as
// in case of the app 'Mapka', the initialization actually triggers
// two requests we want to count as a single one.
type PrevReqPool struct {
	requests       [poolSize]*OutputRecord
	lastIdx        int
	maxTimeDistSec int
}

// AddItem adds a new record to the pool
func (prp *PrevReqPool) AddItem(rec *OutputRecord) {
	prp.lastIdx = (prp.lastIdx + 1) % poolSize
	prp.requests[prp.lastIdx] = rec
}

// ContainsSimilar tests whethere there is a similar request already
// present. The similarity is tested using:
// 1) IP address
// 2) user agent
// 3) server action
func (prp *PrevReqPool) ContainsSimilar(rec *OutputRecord) bool {
	for i := 0; i < poolSize; i++ {
		item := prp.requests[(i+prp.lastIdx+1)%poolSize]
		if item == nil {
			continue
		}
		if item.UserAgent == rec.UserAgent && item.IPAddress == rec.IPAddress &&
			item.Action == rec.Action &&
			rec.GetTime().Sub(item.GetTime()) <= time.Duration(prp.maxTimeDistSec)*time.Second {
			return true
		}
	}
	return false
}

// NewPrevReqPool is a recommended factory for PrevReqPool
func NewPrevReqPool(maxTimeDistSec int) *PrevReqPool {
	return &PrevReqPool{
		lastIdx:        -1,
		maxTimeDistSec: maxTimeDistSec,
	}
}
<commit_msg>Decrease pool size<commit_after>// Copyright 2020 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2020 Institute of the Czech National Corpus,
//                Faculty of Arts, Charles University
//
// 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 mapka

import (
	"time"
)

const poolSize = 200

// PrevReqPool is a cyclic list containing recently processed
// requests. It is used for searching very similar requests as
// in case of the app 'Mapka', the initialization actually triggers
// two requests we want to count as a single one.
type PrevReqPool struct {
	requests       [poolSize]*OutputRecord
	lastIdx        int
	maxTimeDistSec int
}

// AddItem adds a new record to the pool
func (prp *PrevReqPool) AddItem(rec *OutputRecord) {
	prp.lastIdx = (prp.lastIdx + 1) % poolSize
	prp.requests[prp.lastIdx] = rec
}

// ContainsSimilar tests whethere there is a similar request already
// present. The similarity is tested using:
// 1) IP address
// 2) user agent
// 3) server action
func (prp *PrevReqPool) ContainsSimilar(rec *OutputRecord) bool {
	for i := 0; i < poolSize; i++ {
		item := prp.requests[(i+prp.lastIdx+1)%poolSize]
		if item == nil {
			continue
		}
		if item.UserAgent == rec.UserAgent && item.IPAddress == rec.IPAddress &&
			item.Action == rec.Action &&
			rec.GetTime().Sub(item.GetTime()) <= time.Duration(prp.maxTimeDistSec)*time.Second {
			return true
		}
	}
	return false
}

// NewPrevReqPool is a recommended factory for PrevReqPool
func NewPrevReqPool(maxTimeDistSec int) *PrevReqPool {
	return &PrevReqPool{
		lastIdx:        -1,
		maxTimeDistSec: maxTimeDistSec,
	}
}
<|endoftext|>


<commit_before>package gui

import (
	"github.com/felixangell/nate/gfx"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/sdl_ttf"
	"github.com/vinzmay/go-rope"
	"unicode/utf8"
)

const (
	TAB_SIZE int32 = 4
)

type Cursor struct {
	x, y   int
	rx, ry int
}

func (c *Cursor) move(x, y int) {
	c.move_render(x, y, x, y)
}

// moves the cursors position, and the
// rendered coordinates by the given amount
func (c *Cursor) move_render(x, y, rx, ry int) {
	c.x += x
	c.y += y

	c.rx += rx
	c.ry += ry
}

const (
	cursor_flash_ms uint32 = 400
	reset_delay_ms  uint32 = 400
)

var (
	should_draw  bool   = false
	should_flash bool   = true
	timer        uint32 = 0
	reset_timer  uint32 = 0
)

type Buffer struct {
	ComponentLocation
	font          *ttf.Font
	contents      []*rope.Rope
	curs          *Cursor
	input_handler *InputHandler
}

func NewBuffer() *Buffer {
	font, err := ttf.OpenFont("./res/firacode.ttf", 24)
	if err != nil {
		panic(err)
	}

	buff := &Buffer{
		contents: []*rope.Rope{},
		font:     font,
		curs:     &Cursor{},
	}
	buff.appendLine("This is a test.")
	return buff
}

func (b *Buffer) Init() {}

func (b *Buffer) GetComponents() []Component {
	return []Component{}
}

func (b *Buffer) AddComponent(c Component) {}

func (b *Buffer) SetInputHandler(i *InputHandler) {
	b.input_handler = i
}

func (b *Buffer) GetInputHandler() *InputHandler {
	return b.input_handler
}

func (b *Buffer) appendLine(val string) {
	b.contents = append(b.contents, rope.New(val))
	b.curs.move(len(val), 0)
}

func (b *Buffer) processTextInput(t *sdl.TextInputEvent) {
	// TODO: how the fuck do decode this properly?
	raw_val, size := utf8.DecodeLastRune(t.Text[:1])
	if raw_val == utf8.RuneError || size == 0 {
		return
	}

	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(raw_val))
	b.curs.move(1, 0)
}

func (b *Buffer) processActionKey(t *sdl.KeyDownEvent) {
	switch t.Keysym.Scancode {
	case sdl.SCANCODE_RETURN:
		initial_x := b.curs.x
		prev_line_len := b.contents[b.curs.y].Len()

		var new_rope *rope.Rope
		if initial_x < prev_line_len && initial_x > 0 {
			left, right := b.contents[b.curs.y].Split(initial_x)
			new_rope = right
			b.contents[b.curs.y] = left
		} else if initial_x == 0 {
			b.contents = append(b.contents, new(rope.Rope))      // grow
			copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:]) // shift
			b.contents[b.curs.y] = new(rope.Rope)                // set
			b.curs.move(0, 1)
			return
		} else {
			new_rope = rope.New(" ")
		}

		b.curs.move(0, 1)
		for x := 0; x < initial_x; x++ {
			b.curs.move(-1, 0)
		}
		b.contents = append(b.contents, new_rope)
	case sdl.SCANCODE_BACKSPACE:
		if b.curs.x > 0 {
			b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
			b.curs.move(-1, 0)
		} else if b.curs.x == 0 && b.curs.y > 0 {
			// start of line, wrap to previous
			// two cases here:

			// the line_len is zero, in which case
			// we delete the line and go to the end
			// of the previous line
			if b.contents[b.curs.y].Len() == 0 {
				b.curs.move(b.contents[b.curs.y-1].Len(), -1)
				// FIXME, delete from the curs.y dont pop!
				b.contents = b.contents[:len(b.contents)-1]
				return
			}

			// or, the line has characters, so we join
			// that line with the previous line
			prev_line_len := b.contents[b.curs.y-1].Len()
			b.contents[b.curs.y-1] = b.contents[b.curs.y-1].Concat(b.contents[b.curs.y])
			b.curs.move(prev_line_len, -1)

			// FIXME delete from curs.y, not pop!
			b.contents = b.contents[:len(b.contents)-1]
		}
	case sdl.SCANCODE_RIGHT:
		curr_line_length := b.contents[b.curs.y].Len()
		if b.curs.x >= curr_line_length && b.curs.y < len(b.contents)-1 {
			// we're at the end of the line and we have
			// some lines after, let's wrap around
			b.curs.move(0, 1)
			b.curs.move(-curr_line_length, 0)
		} else if b.curs.x < b.contents[b.curs.y].Len() {
			// we have characters to the right, let's move along
			b.curs.move(1, 0)
		}
	case sdl.SCANCODE_LEFT:
		if b.curs.x == 0 && b.curs.y > 0 {
			b.curs.move(b.contents[b.curs.y-1].Len(), -1)

		} else if b.curs.x > 0 {
			b.curs.move(-1, 0)
		}
	case sdl.SCANCODE_TAB:
		// TODO
	}
}

func renderString(font *ttf.Font, val string, col sdl.Color, smooth bool) *sdl.Surface {
	if smooth {
		text, err := font.RenderUTF8_Blended(val, col)
		if err != nil {
			panic(err)
		}
		return text
	} else {
		text, err := font.RenderUTF8_Solid(val, col)
		if err != nil {
			panic(err)
		}
		return text
	}
	return nil
}

func (b *Buffer) Translate(x, y int32) {
	b.x += x
	b.y += y
}

func (b *Buffer) Update() {
	prev_x := b.curs.x
	prev_y := b.curs.y

	if b.input_handler == nil {
		panic("fuck")
	}

	if b.input_handler.Event != nil {
		switch t := b.input_handler.Event.(type) {
		case *sdl.TextInputEvent:
			b.processTextInput(t)
		case *sdl.KeyDownEvent:
			b.processActionKey(t)
		}
	}

	if b.curs.x != prev_x || b.curs.y != prev_y {
		should_draw = true
		should_flash = false
		reset_timer = sdl.GetTicks()
	}

	if !should_flash && sdl.GetTicks()-reset_timer > reset_delay_ms {
		should_flash = true
	}

	if sdl.GetTicks()-timer > cursor_flash_ms && should_flash {
		timer = sdl.GetTicks()
		should_draw = !should_draw
	}
}

var last_w, last_h int32

func (b *Buffer) Render(ctx *sdl.Renderer) {

	// render the ol' cursor
	if should_draw {
		gfx.SetDrawColorHex(ctx, 0x657B83)
		ctx.FillRect(&sdl.Rect{
			b.x + (int32(b.curs.rx)+1)*last_w,
			b.y + int32(b.curs.ry)*last_h,
			last_w,
			last_h,
		})
	}

	var y_col int32
	for _, rope := range b.contents {
		// this is because if we had the following
		// text input:
		//
		// Foo
		// _			<-- underscore is a space!
		// Blah
		// and we delete that underscore... it causes
		// a panic because there are no characters in
		// the empty string!
		if rope.Len() == 0 {
			y_col += 1
			continue
		}

		var x_col int32
		for _, char := range rope.String() {
			switch char {
			case '\n':
				x_col = 0
				y_col += 1
				continue
			case '\t':
				x_col += TAB_SIZE
				continue
			}

			x_col += 1

			text := renderString(b.font, string(char), gfx.HexColor(0x7a7a7a), true)
			defer text.Free()

			last_w = text.W
			last_h = text.H

			// FIXME very slow
			texture, _ := ctx.CreateTextureFromSurface(text)
			defer texture.Destroy()

			ctx.Copy(texture, nil, &sdl.Rect{
				b.x + (x_col * text.W),
				b.y + (y_col * text.H),
				text.W,
				text.H,
			})
		}

		y_col += 1
	}
}
<commit_msg>be mindful of your language feliks<commit_after>package gui

import (
	"github.com/felixangell/nate/gfx"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/sdl_ttf"
	"github.com/vinzmay/go-rope"
	"unicode/utf8"
)

const (
	TAB_SIZE int32 = 4
)

type Cursor struct {
	x, y   int
	rx, ry int
}

func (c *Cursor) move(x, y int) {
	c.move_render(x, y, x, y)
}

// moves the cursors position, and the
// rendered coordinates by the given amount
func (c *Cursor) move_render(x, y, rx, ry int) {
	c.x += x
	c.y += y

	c.rx += rx
	c.ry += ry
}

const (
	cursor_flash_ms uint32 = 400
	reset_delay_ms  uint32 = 400
)

var (
	should_draw  bool   = false
	should_flash bool   = true
	timer        uint32 = 0
	reset_timer  uint32 = 0
)

type Buffer struct {
	ComponentLocation
	font          *ttf.Font
	contents      []*rope.Rope
	curs          *Cursor
	input_handler *InputHandler
}

func NewBuffer() *Buffer {
	font, err := ttf.OpenFont("./res/firacode.ttf", 24)
	if err != nil {
		panic(err)
	}

	buff := &Buffer{
		contents: []*rope.Rope{},
		font:     font,
		curs:     &Cursor{},
	}
	buff.appendLine("This is a test.")
	return buff
}

func (b *Buffer) Init() {}

func (b *Buffer) GetComponents() []Component {
	return []Component{}
}

func (b *Buffer) AddComponent(c Component) {}

func (b *Buffer) SetInputHandler(i *InputHandler) {
	b.input_handler = i
}

func (b *Buffer) GetInputHandler() *InputHandler {
	return b.input_handler
}

func (b *Buffer) appendLine(val string) {
	b.contents = append(b.contents, rope.New(val))
	b.curs.move(len(val), 0)
}

func (b *Buffer) processTextInput(t *sdl.TextInputEvent) {
	// TODO: how the fuck do decode this properly?
	raw_val, size := utf8.DecodeLastRune(t.Text[:1])
	if raw_val == utf8.RuneError || size == 0 {
		return
	}

	b.contents[b.curs.y] = b.contents[b.curs.y].Insert(b.curs.x, string(raw_val))
	b.curs.move(1, 0)
}

func (b *Buffer) processActionKey(t *sdl.KeyDownEvent) {
	switch t.Keysym.Scancode {
	case sdl.SCANCODE_RETURN:
		initial_x := b.curs.x
		prev_line_len := b.contents[b.curs.y].Len()

		var new_rope *rope.Rope
		if initial_x < prev_line_len && initial_x > 0 {
			left, right := b.contents[b.curs.y].Split(initial_x)
			new_rope = right
			b.contents[b.curs.y] = left
		} else if initial_x == 0 {
			b.contents = append(b.contents, new(rope.Rope))      // grow
			copy(b.contents[b.curs.y+1:], b.contents[b.curs.y:]) // shift
			b.contents[b.curs.y] = new(rope.Rope)                // set
			b.curs.move(0, 1)
			return
		} else {
			new_rope = rope.New(" ")
		}

		b.curs.move(0, 1)
		for x := 0; x < initial_x; x++ {
			b.curs.move(-1, 0)
		}
		b.contents = append(b.contents, new_rope)
	case sdl.SCANCODE_BACKSPACE:
		if b.curs.x > 0 {
			b.contents[b.curs.y] = b.contents[b.curs.y].Delete(b.curs.x, 1)
			b.curs.move(-1, 0)
		} else if b.curs.x == 0 && b.curs.y > 0 {
			// start of line, wrap to previous
			// two cases here:

			// the line_len is zero, in which case
			// we delete the line and go to the end
			// of the previous line
			if b.contents[b.curs.y].Len() == 0 {
				b.curs.move(b.contents[b.curs.y-1].Len(), -1)
				// FIXME, delete from the curs.y dont pop!
				b.contents = b.contents[:len(b.contents)-1]
				return
			}

			// or, the line has characters, so we join
			// that line with the previous line
			prev_line_len := b.contents[b.curs.y-1].Len()
			b.contents[b.curs.y-1] = b.contents[b.curs.y-1].Concat(b.contents[b.curs.y])
			b.curs.move(prev_line_len, -1)

			// FIXME delete from curs.y, not pop!
			b.contents = b.contents[:len(b.contents)-1]
		}
	case sdl.SCANCODE_RIGHT:
		curr_line_length := b.contents[b.curs.y].Len()
		if b.curs.x >= curr_line_length && b.curs.y < len(b.contents)-1 {
			// we're at the end of the line and we have
			// some lines after, let's wrap around
			b.curs.move(0, 1)
			b.curs.move(-curr_line_length, 0)
		} else if b.curs.x < b.contents[b.curs.y].Len() {
			// we have characters to the right, let's move along
			b.curs.move(1, 0)
		}
	case sdl.SCANCODE_LEFT:
		if b.curs.x == 0 && b.curs.y > 0 {
			b.curs.move(b.contents[b.curs.y-1].Len(), -1)

		} else if b.curs.x > 0 {
			b.curs.move(-1, 0)
		}
	case sdl.SCANCODE_TAB:
		// TODO
	}
}

func renderString(font *ttf.Font, val string, col sdl.Color, smooth bool) *sdl.Surface {
	if smooth {
		text, err := font.RenderUTF8_Blended(val, col)
		if err != nil {
			panic(err)
		}
		return text
	} else {
		text, err := font.RenderUTF8_Solid(val, col)
		if err != nil {
			panic(err)
		}
		return text
	}
	return nil
}

func (b *Buffer) Translate(x, y int32) {
	b.x += x
	b.y += y
}

func (b *Buffer) Update() {
	prev_x := b.curs.x
	prev_y := b.curs.y

	if b.input_handler == nil {
		panic("help")
	}

	if b.input_handler.Event != nil {
		switch t := b.input_handler.Event.(type) {
		case *sdl.TextInputEvent:
			b.processTextInput(t)
		case *sdl.KeyDownEvent:
			b.processActionKey(t)
		}
	}

	if b.curs.x != prev_x || b.curs.y != prev_y {
		should_draw = true
		should_flash = false
		reset_timer = sdl.GetTicks()
	}

	if !should_flash && sdl.GetTicks()-reset_timer > reset_delay_ms {
		should_flash = true
	}

	if sdl.GetTicks()-timer > cursor_flash_ms && should_flash {
		timer = sdl.GetTicks()
		should_draw = !should_draw
	}
}

var last_w, last_h int32

func (b *Buffer) Render(ctx *sdl.Renderer) {

	// render the ol' cursor
	if should_draw {
		gfx.SetDrawColorHex(ctx, 0x657B83)
		ctx.FillRect(&sdl.Rect{
			b.x + (int32(b.curs.rx)+1)*last_w,
			b.y + int32(b.curs.ry)*last_h,
			last_w,
			last_h,
		})
	}

	var y_col int32
	for _, rope := range b.contents {
		// this is because if we had the following
		// text input:
		//
		// Foo
		// _			<-- underscore is a space!
		// Blah
		// and we delete that underscore... it causes
		// a panic because there are no characters in
		// the empty string!
		if rope.Len() == 0 {
			y_col += 1
			continue
		}

		var x_col int32
		for _, char := range rope.String() {
			switch char {
			case '\n':
				x_col = 0
				y_col += 1
				continue
			case '\t':
				x_col += TAB_SIZE
				continue
			}

			x_col += 1

			text := renderString(b.font, string(char), gfx.HexColor(0x7a7a7a), true)
			defer text.Free()

			last_w = text.W
			last_h = text.H

			// FIXME very slow
			texture, _ := ctx.CreateTextureFromSurface(text)
			defer texture.Destroy()

			ctx.Copy(texture, nil, &sdl.Rect{
				b.x + (x_col * text.W),
				b.y + (y_col * text.H),
				text.W,
				text.H,
			})
		}

		y_col += 1
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

const (
	addrFailedToParse   = "400 Failed to parse address"
	addrNoInfo          = "404 No information for this address"
	localPlaceholder    = "LOCAL REP"
	senatePlaceholder   = "US SENATE"
	housePlaceholder    = "US HOUSE"
	governorPlaceholder = "GOVERNOR"
)

type handler struct {
	repFinder   RepFinder
	issueLister IssueLister
}

func (h *handler) GetIssues(w http.ResponseWriter, r *http.Request) {
	var localReps *LocalReps
	var normalizedAddress *Address
	var err error

	var civicLocationParam string
	zip := mux.Vars(r)["zip"]
	address := r.URL.Query().Get("address") // could be geolocation too

	if len(zip) != 0 && len(zip) == 5 {
		civicLocationParam = zip
	}
	if len(address) != 0 {
		civicLocationParam = address
	}

	issueResponse := IssueResponse{}
	if len(civicLocationParam) != 0 {
		log.Println("getting local reps for", civicLocationParam)

		localReps, normalizedAddress, err = h.repFinder.GetReps(civicLocationParam)
		if err != nil {
			log.Println("Unable to find local reps for", zip, err)
			invalidAddress := err.Error() == addrFailedToParse || err.Error() == addrNoInfo
			if invalidAddress {
				issueResponse.InvalidAddress = true
			}
		}
	} else {
		log.Println("no address or zip")
	}

	if localReps != nil && localReps.HouseRep == nil {
		issueResponse.SplitDistrict = true
	}

	if normalizedAddress != nil {
		issueResponse.NormalizedLocation = normalizedAddress.City
	}

	// add local reps where necessary
	all, err := h.issueLister.AllIssues()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for _, issue := range all {
		newContacts := []Contact{}
		for _, contact := range issue.Contacts {
			if contact.Name == localPlaceholder {
				if localReps != nil {
					if localReps.HouseRep != nil {
						c := *localReps.HouseRep
						c.Reason = "This is your local representative in the house"
						newContacts = append(newContacts, c)
					}
					for _, s := range localReps.Senators {
						c := *s
						c.Reason = "This is one of your two senators"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == senatePlaceholder {
				if localReps != nil {
					for _, s := range localReps.Senators {
						c := *s
						c.Reason = "This is one of your two senators"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == housePlaceholder {
				if localReps != nil {
					if localReps.HouseRep != nil {
						c := *localReps.HouseRep
						c.Reason = "This is your local representative in the house"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == governorPlaceholder {
				if localReps != nil {
					if localReps.Governor != nil {
						c := *localReps.Governor
						c.Reason = "This is your state governor"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Phone == "" {
				// filter anyone without a phone
			} else {
				// Set sane default contact reason here.
				if contact.Reason == "" {
					contact.Reason = "This organization is driving legislation related to the issue."
				}
				newContacts = append(newContacts, contact)
			}
		}
		issue.Contacts = newContacts
		issueResponse.Issues = append(issueResponse.Issues, issue)
	}
	writeJSON(w, issueResponse)
}
<commit_msg>proper capitalization.<commit_after>package main

import (
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

const (
	addrFailedToParse   = "400 Failed to parse address"
	addrNoInfo          = "404 No information for this address"
	localPlaceholder    = "LOCAL REP"
	senatePlaceholder   = "US SENATE"
	housePlaceholder    = "US HOUSE"
	governorPlaceholder = "GOVERNOR"
)

type handler struct {
	repFinder   RepFinder
	issueLister IssueLister
}

func (h *handler) GetIssues(w http.ResponseWriter, r *http.Request) {
	var localReps *LocalReps
	var normalizedAddress *Address
	var err error

	var civicLocationParam string
	zip := mux.Vars(r)["zip"]
	address := r.URL.Query().Get("address") // could be geolocation too

	if len(zip) != 0 && len(zip) == 5 {
		civicLocationParam = zip
	}
	if len(address) != 0 {
		civicLocationParam = address
	}

	issueResponse := IssueResponse{}
	if len(civicLocationParam) != 0 {
		log.Println("getting local reps for", civicLocationParam)

		localReps, normalizedAddress, err = h.repFinder.GetReps(civicLocationParam)
		if err != nil {
			log.Println("Unable to find local reps for", zip, err)
			invalidAddress := err.Error() == addrFailedToParse || err.Error() == addrNoInfo
			if invalidAddress {
				issueResponse.InvalidAddress = true
			}
		}
	} else {
		log.Println("no address or zip")
	}

	if localReps != nil && localReps.HouseRep == nil {
		issueResponse.SplitDistrict = true
	}

	if normalizedAddress != nil {
		issueResponse.NormalizedLocation = normalizedAddress.City
	}

	// add local reps where necessary
	all, err := h.issueLister.AllIssues()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for _, issue := range all {
		newContacts := []Contact{}
		for _, contact := range issue.Contacts {
			if contact.Name == localPlaceholder {
				if localReps != nil {
					if localReps.HouseRep != nil {
						c := *localReps.HouseRep
						c.Reason = "This is your local representative in the House"
						newContacts = append(newContacts, c)
					}
					for _, s := range localReps.Senators {
						c := *s
						c.Reason = "This is one of your two Senators"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == senatePlaceholder {
				if localReps != nil {
					for _, s := range localReps.Senators {
						c := *s
						c.Reason = "This is one of your two Senators"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == housePlaceholder {
				if localReps != nil {
					if localReps.HouseRep != nil {
						c := *localReps.HouseRep
						c.Reason = "This is your local representative in the House"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Name == governorPlaceholder {
				if localReps != nil {
					if localReps.Governor != nil {
						c := *localReps.Governor
						c.Reason = "This is your state Governor"
						newContacts = append(newContacts, c)
					}
				}
			} else if contact.Phone == "" {
				// filter anyone without a phone
			} else {
				// Set sane default contact reason here.
				if contact.Reason == "" {
					contact.Reason = "This organization is driving legislation related to the issue."
				}
				newContacts = append(newContacts, contact)
			}
		}
		issue.Contacts = newContacts
		issueResponse.Issues = append(issueResponse.Issues, issue)
	}
	writeJSON(w, issueResponse)
}
<|endoftext|>