<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
)

func (c *RawClass) getMethod(name string) Method {
	for _, m := range c.methods {
		n := c.constantPoolItems[m.nameIndex-1].(UTF8String).Contents
		if n == name {
			return m
		}
	}
	panic(fmt.Sprintf("Could not find method called %v", name))
}

func main() {
	var stack []byte
	flag.Parse()
	filename := flag.Arg(0)
	bytes, _ := ioutil.ReadFile(filename)
	class, _ := parse(bytes)
	method := class.getMethod("main")
	pc := 0
	for {
		instruction := method.code.code[pc]
		pc += 1
		if instruction == 18 {
			stack = append(stack, method.code.code[pc])
			pc += 1
		} else if instruction == 184 {
			var i uint16
			i = uint16(method.code.code[pc]) << 8
			pc += 1
			i |= uint16(method.code.code[pc])
			pc += 1
			m := class.constantPoolItems[i-1].(MethodRef)
			nt := class.constantPoolItems[m.NameAndTypeIndex-1].(NameAndType)
			n := class.constantPoolItems[nt.NameIndex-1].(UTF8String).Contents
			meth := class.getMethod(n)
			if (meth.accessFlags&Native) != 0 && n == "print" {
				index := class.constantPoolItems[stack[len(stack)-1]-1].(StringConstant).UTF8Index
				fmt.Print(class.constantPoolItems[index-1].(UTF8String).Contents)
			} else {
				panic(fmt.Sprintf("I don't know how to call method %v", n))
			}
		} else if instruction == 177 {
			break
		} else {
			panic(fmt.Sprintf("Unknow instruction: %v", instruction))
		}
	}
}
<commit_msg>clean up method execution<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
)

func (c *RawClass) getMethod(name string) Method {
	for _, m := range c.methods {
		n := c.constantPoolItems[m.nameIndex-1].(UTF8String).Contents
		if n == name {
			return m
		}
	}
	panic(fmt.Sprintf("Could not find method called %v", name))
}

func (class *RawClass) execute(methodName string, stack []byte) {
	method := class.getMethod(methodName)

	if (method.accessFlags&Native) != 0 && methodName == "print" {
		index := class.constantPoolItems[stack[len(stack)-1]-1].(StringConstant).UTF8Index
		fmt.Print(class.constantPoolItems[index-1].(UTF8String).Contents)
		return
	}

	pc := 0
	for {
		instruction := method.code.code[pc]
		pc += 1
		if instruction == 18 {
			stack = append(stack, method.code.code[pc])
			pc += 1
		} else if instruction == 184 {
			var i uint16
			i = uint16(method.code.code[pc]) << 8
			pc += 1
			i |= uint16(method.code.code[pc])
			pc += 1
			m := class.constantPoolItems[i-1].(MethodRef)
			nt := class.constantPoolItems[m.NameAndTypeIndex-1].(NameAndType)
			n := class.constantPoolItems[nt.NameIndex-1].(UTF8String).Contents
			class.execute(n, stack)
		} else if instruction == 177 {
			break
		} else {
			panic(fmt.Sprintf("Unknow instruction: %v", instruction))
		}
	}
}

func main() {
	flag.Parse()
	filename := flag.Arg(0)
	bytes, _ := ioutil.ReadFile(filename)
	class, _ := parse(bytes)
	var stack []byte
	class.execute("main", stack)
}
<|endoftext|>


<commit_before>package provision

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/docker/machine/drivers"
	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/provision/pkgaction"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/docker/machine/log"
	"github.com/docker/machine/utils"
)

const (
	// TODO: eventually the RPM install process will be integrated
	// into the get.docker.com install script; for now
	// we install via vendored RPMs
	dockerRPMPath = "https://docker-mcn.s3.amazonaws.com/public/redhat/rpms/docker-engine-1.6.1-0.0.20150511.171646.git1b47f9f.el7.centos.x86_64.rpm"
)

func init() {
	Register("RedHat", &RegisteredProvisioner{
		New: NewRedHatProvisioner,
	})
}

func NewRedHatProvisioner(d drivers.Driver) Provisioner {
	return &RedHatProvisioner{
		GenericProvisioner{
			DockerOptionsDir:  "/etc/docker",
			DaemonOptionsFile: "/lib/systemd/system/docker.service",
			OsReleaseId:       "rhel",
			Packages: []string{
				"curl",
			},
			Driver: d,
		},
	}
}

type RedHatProvisioner struct {
	GenericProvisioner
}

func (provisioner *RedHatProvisioner) Service(name string, action pkgaction.ServiceAction) error {
	reloadDaemon := false
	switch action {
	case pkgaction.Start, pkgaction.Restart:
		reloadDaemon = true
	}

	// systemd needs reloaded when config changes on disk; we cannot
	// be sure exactly when it changes from the provisioner so
	// we call a reload on every restart to be safe
	if reloadDaemon {
		if _, err := provisioner.SSHCommand("sudo systemctl daemon-reload"); err != nil {
			return err
		}
	}

	command := fmt.Sprintf("sudo systemctl %s %s", action.String(), name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) Package(name string, action pkgaction.PackageAction) error {
	var packageAction string

	switch action {
	case pkgaction.Install:
		packageAction = "install"
	case pkgaction.Remove:
		packageAction = "remove"
	case pkgaction.Upgrade:
		packageAction = "upgrade"
	}

	command := fmt.Sprintf("sudo -E yum %s -y %s", packageAction, name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) isAWS() bool {
	if _, err := provisioner.SSHCommand("curl -s http://169.254.169.254/latest/meta-data/ami-id"); err != nil {
		return false
	}

	return true
}

func (provisioner *RedHatProvisioner) configureRepos() error {
	log.Debug("configuring extra repo")
	repoCmd := "subscription-manager repos --enable=rhel-7-server-extras-rpms"
	if provisioner.isAWS() {
		repoCmd = "yum-config-manager --enable rhui-REGION-rhel-server-extras"
	}

	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo %s", repoCmd)); err != nil {
		return err
	}

	return nil
}

func installDocker(provisioner *RedHatProvisioner) error {
	if err := provisioner.installOfficialDocker(); err != nil {
		return err
	}

	if err := provisioner.Service("docker", pkgaction.Restart); err != nil {
		return err
	}

	if err := provisioner.Service("docker", pkgaction.Enable); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) installOfficialDocker() error {
	log.Debug("installing docker")

	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo yum install -y --nogpgcheck  %s", dockerRPMPath)); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) dockerDaemonResponding() bool {
	if _, err := provisioner.SSHCommand("sudo docker version"); err != nil {
		log.Warn("Error getting SSH command to check if the daemon is up: %s", err)
		return false
	}

	// The daemon is up if the command worked.  Carry on.
	return true
}

func (provisioner *RedHatProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
	provisioner.SwarmOptions = swarmOptions
	provisioner.AuthOptions = authOptions
	provisioner.EngineOptions = engineOptions

	// set default storage driver for redhat
	if provisioner.EngineOptions.StorageDriver == "" {
		provisioner.EngineOptions.StorageDriver = "devicemapper"
	}

	if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
		return err
	}

	// setup extras repo
	if err := provisioner.configureRepos(); err != nil {
		return err
	}

	for _, pkg := range provisioner.Packages {
		if err := provisioner.Package(pkg, pkgaction.Install); err != nil {
			return err
		}
	}

	// install docker
	if err := installDocker(provisioner); err != nil {
		return err
	}

	if err := utils.WaitFor(provisioner.dockerDaemonResponding); err != nil {
		return err
	}

	if err := makeDockerOptionsDir(provisioner); err != nil {
		return err
	}

	provisioner.AuthOptions = setRemoteAuthOptions(provisioner)

	if err := ConfigureAuth(provisioner); err != nil {
		return err
	}

	if err := configureSwarm(provisioner, swarmOptions); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
	var (
		engineCfg  bytes.Buffer
		configPath = provisioner.DaemonOptionsFile
	)

	// remove existing
	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo rm %s", configPath)); err != nil {
		return nil, err
	}

	driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
	provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)

	// systemd / redhat will not load options if they are on newlines
	// instead, it just continues with a different set of options; yeah...
	engineConfigTmpl := `[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target docker.socket
Required=docker.socket

[Service]
ExecStart=/usr/bin/docker -d -H tcp://0.0.0.0:{{.DockerPort}} -H unix:///var/run/docker.sock --storage-driver {{.EngineOptions.StorageDriver}} --tlsverify --tlscacert {{.AuthOptions.CaCertRemotePath}} --tlscert {{.AuthOptions.ServerCertRemotePath}} --tlskey {{.AuthOptions.ServerKeyRemotePath}} {{ range .EngineOptions.Labels }}--label {{.}} {{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}} {{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}} {{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}} {{ end }}
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
`
	t, err := template.New("engineConfig").Parse(engineConfigTmpl)
	if err != nil {
		return nil, err
	}

	engineConfigContext := EngineConfigContext{
		DockerPort:       dockerPort,
		AuthOptions:      provisioner.AuthOptions,
		EngineOptions:    provisioner.EngineOptions,
		DockerOptionsDir: provisioner.DockerOptionsDir,
	}

	t.Execute(&engineCfg, engineConfigContext)

	daemonOptsDir := configPath
	return &DockerOptions{
		EngineOptions:     engineCfg.String(),
		EngineOptionsPath: daemonOptsDir,
	}, nil
}
<commit_msg>redhat: remove configure repo as we use our own rpms now<commit_after>package provision

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/docker/machine/drivers"
	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/provision/pkgaction"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/docker/machine/log"
	"github.com/docker/machine/utils"
)

const (
	// TODO: eventually the RPM install process will be integrated
	// into the get.docker.com install script; for now
	// we install via vendored RPMs
	dockerRPMPath = "https://docker-mcn.s3.amazonaws.com/public/redhat/rpms/docker-engine-1.6.1-0.0.20150511.171646.git1b47f9f.el7.centos.x86_64.rpm"
)

func init() {
	Register("RedHat", &RegisteredProvisioner{
		New: NewRedHatProvisioner,
	})
}

func NewRedHatProvisioner(d drivers.Driver) Provisioner {
	return &RedHatProvisioner{
		GenericProvisioner{
			DockerOptionsDir:  "/etc/docker",
			DaemonOptionsFile: "/lib/systemd/system/docker.service",
			OsReleaseId:       "rhel",
			Packages: []string{
				"curl",
			},
			Driver: d,
		},
	}
}

type RedHatProvisioner struct {
	GenericProvisioner
}

func (provisioner *RedHatProvisioner) Service(name string, action pkgaction.ServiceAction) error {
	reloadDaemon := false
	switch action {
	case pkgaction.Start, pkgaction.Restart:
		reloadDaemon = true
	}

	// systemd needs reloaded when config changes on disk; we cannot
	// be sure exactly when it changes from the provisioner so
	// we call a reload on every restart to be safe
	if reloadDaemon {
		if _, err := provisioner.SSHCommand("sudo systemctl daemon-reload"); err != nil {
			return err
		}
	}

	command := fmt.Sprintf("sudo systemctl %s %s", action.String(), name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) Package(name string, action pkgaction.PackageAction) error {
	var packageAction string

	switch action {
	case pkgaction.Install:
		packageAction = "install"
	case pkgaction.Remove:
		packageAction = "remove"
	case pkgaction.Upgrade:
		packageAction = "upgrade"
	}

	command := fmt.Sprintf("sudo -E yum %s -y %s", packageAction, name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) isAWS() bool {
	if _, err := provisioner.SSHCommand("curl -s http://169.254.169.254/latest/meta-data/ami-id"); err != nil {
		return false
	}

	return true
}

func installDocker(provisioner *RedHatProvisioner) error {
	if err := provisioner.installOfficialDocker(); err != nil {
		return err
	}

	if err := provisioner.Service("docker", pkgaction.Restart); err != nil {
		return err
	}

	if err := provisioner.Service("docker", pkgaction.Enable); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) installOfficialDocker() error {
	log.Debug("installing docker")

	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo yum install -y --nogpgcheck  %s", dockerRPMPath)); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) dockerDaemonResponding() bool {
	if _, err := provisioner.SSHCommand("sudo docker version"); err != nil {
		log.Warn("Error getting SSH command to check if the daemon is up: %s", err)
		return false
	}

	// The daemon is up if the command worked.  Carry on.
	return true
}

func (provisioner *RedHatProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
	provisioner.SwarmOptions = swarmOptions
	provisioner.AuthOptions = authOptions
	provisioner.EngineOptions = engineOptions

	// set default storage driver for redhat
	if provisioner.EngineOptions.StorageDriver == "" {
		provisioner.EngineOptions.StorageDriver = "devicemapper"
	}

	if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
		return err
	}

	for _, pkg := range provisioner.Packages {
		if err := provisioner.Package(pkg, pkgaction.Install); err != nil {
			return err
		}
	}

	// install docker
	if err := installDocker(provisioner); err != nil {
		return err
	}

	if err := utils.WaitFor(provisioner.dockerDaemonResponding); err != nil {
		return err
	}

	if err := makeDockerOptionsDir(provisioner); err != nil {
		return err
	}

	provisioner.AuthOptions = setRemoteAuthOptions(provisioner)

	if err := ConfigureAuth(provisioner); err != nil {
		return err
	}

	if err := configureSwarm(provisioner, swarmOptions); err != nil {
		return err
	}

	return nil
}

func (provisioner *RedHatProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
	var (
		engineCfg  bytes.Buffer
		configPath = provisioner.DaemonOptionsFile
	)

	// remove existing
	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo rm %s", configPath)); err != nil {
		return nil, err
	}

	driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
	provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)

	// systemd / redhat will not load options if they are on newlines
	// instead, it just continues with a different set of options; yeah...
	engineConfigTmpl := `[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target docker.socket
Required=docker.socket

[Service]
ExecStart=/usr/bin/docker -d -H tcp://0.0.0.0:{{.DockerPort}} -H unix:///var/run/docker.sock --storage-driver {{.EngineOptions.StorageDriver}} --tlsverify --tlscacert {{.AuthOptions.CaCertRemotePath}} --tlscert {{.AuthOptions.ServerCertRemotePath}} --tlskey {{.AuthOptions.ServerKeyRemotePath}} {{ range .EngineOptions.Labels }}--label {{.}} {{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}} {{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}} {{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}} {{ end }}
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
`
	t, err := template.New("engineConfig").Parse(engineConfigTmpl)
	if err != nil {
		return nil, err
	}

	engineConfigContext := EngineConfigContext{
		DockerPort:       dockerPort,
		AuthOptions:      provisioner.AuthOptions,
		EngineOptions:    provisioner.EngineOptions,
		DockerOptionsDir: provisioner.DockerOptionsDir,
	}

	t.Execute(&engineCfg, engineConfigContext)

	daemonOptsDir := configPath
	return &DockerOptions{
		EngineOptions:     engineCfg.String(),
		EngineOptionsPath: daemonOptsDir,
	}, nil
}
<|endoftext|>


<commit_before>package uncrossed

func maxLines(arr1, arr2 []int) int {
	return 0
}
<commit_msg>solve 1035 use dp same approach as longest common sequences<commit_after>package uncrossed

import "github.com/catorpilor/LeetCode/utils"

func maxLines(arr1, arr2 []int) int {
	return useDP(arr1, arr2)
}

// useDP time complexity O(MN), space complexity O(MN)
func useDP(arr1, arr2 []int) int {
	m, n := len(arr1), len(arr2)
	if m < 1 || n < 1 {
		return 0
	}
	dp := make([][]int, m+1)
	for i := range dp {
		dp[i] = make([]int, n+1)
	}
	for i := 1; i < m+1; i++ {
		for j := 1; j < n+1; j++ {
			if arr1[i-1] == arr2[j-1] {
				dp[i][j] = dp[i-1][j-1] + 1
			} else {
				dp[i][j] = utils.Max(dp[i-1][j], dp[i][j-1])
			}
		}
	}
	return dp[m][n]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/everdev/mack"
	"github.com/robfig/cron"
)

var standardDate string = "Monday, January 02 2006" // 1-2-3-4-5-6 (01/02 03:04:05PM '06 -0700 = Mon Jan 2 15:04:05 MST 2006)

var wg sync.WaitGroup

func main() {
	wg.Add(1)

	c := cron.New()
	c.AddFunc("@daily", check)
	c.Start()

	wg.Wait()
}

func check() {
	doc, err := goquery.NewDocument("http://www.ufc.com/schedule/event")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// My filtering of content is obviously very fragile and error prone
	// It'll likely need changing every time UFC change the structure of their page
	doc.Find("#event_content > div").Each(func(i int, s *goquery.Selection) {
		event := s.Find(".event-title").Text()

		if invalid(event) {
			return
		}

		// Stop after the first item
		// We could try using `.First()` but we have no way with CSS to determine valid item
		if i > 2 {
			return
		}

		extractedDate := strings.TrimSpace(
			s.Find(".event-info .date").Text(),
		)

		date := strings.Join(
			[]string{
				extractedDate,
				strconv.Itoa(
					time.Now().AddDate(verifyYear(extractedDate), 0, 0).Year(),
				),
			},
			" ",
		)

		// fmt.Printf("%s - %s\n", event, date)

		t, _ := time.Parse(standardDate, date)
		daysAway := daysDiff(t, time.Now())

		switch {
		case daysAway == 7:
			mack.Say(fmt.Sprintf("The UFC Event %s is coming up in a week", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		case daysAway == 3:
			mack.Say(fmt.Sprintf("The UFC Event %s is coming up in a few days", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		case daysAway == 0:
			mack.Say(fmt.Sprintf("The UFC Event %s is TODAY!", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		}
	})
}

func invalid(e string) bool {
	match, _ := regexp.MatchString("(?i)ufc\\s\\d{3}", e)

	if e == "" || match == false {
		return true
	}

	return false
}

func verifyYear(date string) int {
	t, _ := time.Parse("Monday, January 2", date)

	eventMonth := int(t.Month())

	if eventMonth < int(time.Now().Month()) {
		return 1 // if the event month is behind the current month, then we'll assume it is for next year
	}

	return 0
}

// Following functions borrowed from
// http://play.golang.org/p/nTcjGZQKAa
// https://groups.google.com/forum/#!topic/golang-nuts/O2NaRAH94GI

func lastDayOfYear(t time.Time) time.Time {
	return time.Date(t.Year(), 12, 31, 0, 0, 0, 0, t.Location())
}

func firstDayOfNextYear(t time.Time) time.Time {
	return time.Date(t.Year()+1, 1, 1, 0, 0, 0, 0, t.Location())
}

func daysDiff(a, b time.Time) (days int) {
	cur := b
	for cur.Year() < a.Year() {
		// add 1 to count the last day of the year too.
		days += lastDayOfYear(cur).YearDay() - cur.YearDay() + 1
		cur = firstDayOfNextYear(cur)
	}
	days += a.YearDay() - cur.YearDay()
	if b.AddDate(0, 0, days).After(a) {
		days -= 1
	}
	return days
}
<commit_msg>Tweaks to logic<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/everdev/mack"
	"github.com/robfig/cron"
)

var standardDate string = "Monday, January 02 2006" // 1-2-3-4-5-6 (01/02 03:04:05PM '06 -0700 = Mon Jan 2 15:04:05 MST 2006)

var wg sync.WaitGroup

func main() {
	wg.Add(1)

	c := cron.New()
	c.AddFunc("@every 8h30m", check)
	c.Start()

	wg.Wait()
}

func check() {
	doc, err := goquery.NewDocument("http://www.ufc.com/schedule/event")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// My filtering of content is obviously very fragile and error prone
	// It'll likely need changing every time UFC change the structure of their page
	doc.Find("#event_content > div").Each(func(i int, s *goquery.Selection) {
		event := s.Find(".event-title").Text()

		if invalid(event) {
			return
		}

		// Stop after the first item
		// We could try using `.First()` but we have no way with CSS to determine valid item
		if i > 2 {
			return
		}

		extractedDate := strings.TrimSpace(
			s.Find(".event-info .date").Text(),
		)

		date := strings.Join(
			[]string{
				extractedDate,
				strconv.Itoa(
					time.Now().AddDate(verifyYear(extractedDate), 0, 0).Year(),
				),
			},
			" ",
		)

		t, _ := time.Parse(standardDate, date)
		daysAway := daysDiff(t, time.Now())

		switch {
		case withinAWeek(daysAway):
			mack.Say(fmt.Sprintf("The UFC Event %s is coming up in a week", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		case withinAFewDays(daysAway):
			mack.Say(fmt.Sprintf("The UFC Event %s is coming up in a few days", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		case startsToday(daysAway):
			mack.Say(fmt.Sprintf("The UFC Event %s is TODAY!", event))
			mack.Notify(fmt.Sprintf("%s (%d days away)", date, daysAway), "UFC Event", event, "Ping")
		}
	})
}

func withinAWeek(daysAway int) bool {
	return daysAway <= 7 && daysAway > 3
}

func withinAFewDays(daysAway int) bool {
	return daysAway <= 3 && daysAway > 0
}

func startsToday(daysAway int) bool {
	return daysAway == 0
}

func invalid(e string) bool {
	match, _ := regexp.MatchString("(?i)ufc\\s\\d{3}", e)

	if e == "" || match == false {
		return true
	}

	return false
}

func verifyYear(date string) int {
	t, _ := time.Parse("Monday, January 2", date)

	eventMonth := int(t.Month())

	if eventMonth < int(time.Now().Month()) {
		return 1 // if the event month is behind the current month, then we'll assume it is for next year
	}

	return 0
}

// Following functions borrowed from
// http://play.golang.org/p/nTcjGZQKAa
// https://groups.google.com/forum/#!topic/golang-nuts/O2NaRAH94GI

func lastDayOfYear(t time.Time) time.Time {
	return time.Date(t.Year(), 12, 31, 0, 0, 0, 0, t.Location())
}

func firstDayOfNextYear(t time.Time) time.Time {
	return time.Date(t.Year()+1, 1, 1, 0, 0, 0, 0, t.Location())
}

func daysDiff(a, b time.Time) (days int) {
	cur := b
	for cur.Year() < a.Year() {
		// add 1 to count the last day of the year too.
		days += lastDayOfYear(cur).YearDay() - cur.YearDay() + 1
		cur = firstDayOfNextYear(cur)
	}
	days += a.YearDay() - cur.YearDay()
	if b.AddDate(0, 0, days).After(a) {
		days -= 1
	}
	return days
}
<|endoftext|>


<commit_before>package goproxy

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
)

// ReqCondition.HandleReq will decide whether or not to use the ReqHandler on an HTTP request
// before sending it to the remote server
type ReqCondition interface {
	RespCondition
	HandleReq(req *http.Request, ctx *ProxyCtx) bool
}

// ReqCondition.HandleReq will decide whether or not to use the RespHandler on an HTTP response
// before sending it to the proxy client
type RespCondition interface {
	HandleResp(resp *http.Response, ctx *ProxyCtx) bool
}

// ReqConditionFunc.HandleReq(req,ctx) <=> ReqConditionFunc(req,ctx)
type ReqConditionFunc func(req *http.Request, ctx *ProxyCtx) bool

// RespConditionFunc.HandleResp(resp,ctx) <=> RespConditionFunc(resp,ctx)
type RespConditionFunc func(resp *http.Response, ctx *ProxyCtx) bool

func (c ReqConditionFunc) HandleReq(req *http.Request, ctx *ProxyCtx) bool {
	return c(req, ctx)
}

// RespConditionFunc cannot test requests. It only satisfies ReqCondition interface so that
// RespCondition and ReqCondition will be of the same type.
func (c ReqConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool {
	return c(ctx.Req, ctx)
}

func (c RespConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool {
	return c(resp, ctx)
}

// UrlHasPrefix returns a ReqCondtion checking wether the destination URL the proxy client has requested
// has the given prefix, with or without the host.
// For example UrlHasPrefix("host/x") will match requests of the form 'GET host/x', and will match
// requests to url 'http://host/x'
func UrlHasPrefix(prefix string) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return strings.HasPrefix(req.URL.Path, prefix) ||
			strings.HasPrefix(req.URL.Host+"/"+req.URL.Path, prefix) ||
			strings.HasPrefix(req.URL.Scheme+req.URL.Host+req.URL.Path, prefix)
	}
}

// UrlIs returns a ReqCondition, testing whether or not the request URL is one of the given strings
// with or without the host prefix.
// UrlIs("google.com/","foo") will match requests 'GET /' to 'google.com', requests `'GET google.com/' to
// any host, and requests of the form 'GET foo'.
func UrlIs(urls ...string) ReqConditionFunc {
	urlSet := make(map[string]bool)
	for _, u := range urls {
		urlSet[u] = true
	}
	return func(req *http.Request, ctx *ProxyCtx) bool {
		_, pathOk := urlSet[req.URL.Path]
		_, hostAndOk := urlSet[req.URL.Host+req.URL.Path]
		return pathOk || hostAndOk
	}
}

// ReqHostMatches returns a ReqCondition, testing whether the host to which the request was directed to matches
// any of the given regular expressions.
func ReqHostMatches(regexps ...*regexp.Regexp) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		for _, re := range regexps {
			if re.MatchString(req.Host) {
				return true
			}
		}
		return false
	}
}

// ReqHostIs returns a ReqCondition, testing whether the host to which the request is directed to equal
// to one of the given strings
func ReqHostIs(hosts ...string) ReqConditionFunc {
	hostSet := make(map[string]bool)
	for _, h := range hosts {
		hostSet[h] = true
	}
	return func(req *http.Request, ctx *ProxyCtx) bool {
		_, ok := hostSet[req.URL.Host]
		return ok
	}
}

var localHostIpv4 = regexp.MustCompile(`127\.0\.0\.\d+`)

// IsLocalHost checks whether the destination host is explicitly local host
// (buggy, there can be IPv6 addresses it doesn't catch)
var IsLocalHost ReqConditionFunc = func(req *http.Request, ctx *ProxyCtx) bool {
	return req.URL.Host == "::1" ||
		req.URL.Host == "0:0:0:0:0:0:0:1" ||
		localHostIpv4.MatchString(req.URL.Host) ||
		req.URL.Host == "localhost"
}

// UrlMatches returns a ReqCondition testing whether the destination URL
// of the request matches the given regexp, with or without prefix
func UrlMatches(re *regexp.Regexp) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return re.MatchString(req.URL.Path) ||
			re.MatchString(req.URL.Host+req.URL.Path)
	}
}

// DstHostIs returns a ReqCondtion testing wether the host in the request url is the given string
func DstHostIs(host string) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return req.URL.Host == host
	}
}

// SrcIpIs returns a ReqCondtion testing wether the source IP of the request is the given string
func SrcIpIs(ip string) ReqCondition {
	return ReqConditionFunc(func(req *http.Request, ctx *ProxyCtx) bool {
		return strings.HasPrefix(req.RemoteAddr, ip+":")
	})
}

// Not returns a ReqCondtion negating the given ReqCondition
func Not(r ReqCondition) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return !r.HandleReq(req, ctx)
	}
}

// ContentTypeIs returns a RespCondition testing whether the HTTP response has Content-Type header equal
// to one of the given strings.
func ContentTypeIs(typ string, types ...string) RespCondition {
	types = append(types, typ)
	return RespConditionFunc(func(resp *http.Response, ctx *ProxyCtx) bool {
		contentType := resp.Header.Get("Content-Type")
		for _, typ := range types {
			if contentType == typ || strings.HasPrefix(contentType, typ+";") {
				return true
			}
		}
		return false
	})
}

// ProxyHttpServer.OnRequest Will return a temporary ReqProxyConds struct, aggregating the given condtions.
// You will use the ReqProxyConds struct to register a ReqHandler, that would filter
// the request, only if all the given ReqCondition matched.
// Typical usage:
//	proxy.OnRequest(UrlIs("example.com/foo"),UrlMatches(regexp.MustParse(`.*\.exampl.\com\./.*`)).Do(...)
func (proxy *ProxyHttpServer) OnRequest(conds ...ReqCondition) *ReqProxyConds {
	return &ReqProxyConds{proxy, conds}
}

// ReqProxyConds aggregate ReqConditions for a ProxyHttpServer. Upon calling Do, it will register a ReqHandler that would
// handle the request if all conditions on the HTTP request are met.
type ReqProxyConds struct {
	proxy    *ProxyHttpServer
	reqConds []ReqCondition
}

// DoFunc is equivalent to proxy.OnRequest().Do(FuncReqHandler(f))
func (pcond *ReqProxyConds) DoFunc(f func(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response)) {
	pcond.Do(FuncReqHandler(f))
}

// ReqProxyConds.Do will register the ReqHandler on the proxy,
// the ReqHandler will handle the HTTP request if all the conditions
// aggregated in the ReqProxyConds are met. Typical usage:
//	proxy.OnRequest().Do(handler) // will call handler.Handle(req,ctx) on every request to the proxy
//	proxy.OnRequest(cond1,cond2).Do(handler)
//	// given request to the proxy, will test if cond1.HandleReq(req,ctx) && cond2.HandleReq(req,ctx) are true
//	// if they are, will call handler.Handle(req,ctx)
func (pcond *ReqProxyConds) Do(h ReqHandler) {
	pcond.proxy.reqHandlers = append(pcond.proxy.reqHandlers,
		FuncReqHandler(func(r *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(r, ctx) {
					return r, nil
				}
			}
			return h.Handle(r, ctx)
		}))
}

// HandleConnect is used when proxy receives an HTTP CONNECT request,
// it'll then use the HttpsHandler to determine what should it
// do with this request. The handler returns a ConnectAction struct, the Action field in the ConnectAction
// struct returned will determine what to do with this request. ConnectAccept will simply accept the request
// forwarding all bytes from the client to the remote host, ConnectReject will close the connection with the
// client, and ConnectMitm, will assume the underlying connection is an HTTPS connection, and will use Man
// in the Middle attack to eavesdrop the connection. All regular handler will be active on this eavesdropped
// connection.
// The ConnectAction struct contains possible tlsConfig that will be used for eavesdropping. If nil, the proxy
// will use the default tls configuration.
//	proxy.OnRequest().HandleConnect(goproxy.AlwaysReject) // rejects all CONNECT requests
func (pcond *ReqProxyConds) HandleConnect(h HttpsHandler) {
	pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers,
		FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(ctx.Req, ctx) {
					return nil, ""
				}
			}
			return h.HandleConnect(host, ctx)
		}))
}

// HandleConnectFunc is equivalent to HandleConnect,
// for example, accepting CONNECT request if they contain a password in header
//	io.WriteString(h,password)
//	passHash := h.Sum(nil)
//	proxy.OnRequest().HandleConnectFunc(func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
//		c := sha1.New()
//		io.WriteString(c,ctx.Req.Header.Get("X-GoProxy-Auth"))
//		if c.Sum(nil) == passHash {
//			return OkConnect, host
//		}
//		return RejectConnect, host
//	})
func (pcond *ReqProxyConds) HandleConnectFunc(f func(host string, ctx *ProxyCtx) (*ConnectAction, string)) {
	pcond.HandleConnect(FuncHttpsHandler(f))
}

// ProxyConds is used to aggregate RespConditions for a ProxyHttpServer.
// Upon calling ProxyConds.Do, it will register a RespHandler that would
// handle the HTTP response from remote server if all conditions on the HTTP response are met.
type ProxyConds struct {
	proxy    *ProxyHttpServer
	reqConds []ReqCondition
	respCond []RespCondition
}

// ProxyConds.DoFunc is equivalent to proxy.OnResponse().Do(FuncRespHandler(f))
func (pcond *ProxyConds) DoFunc(f func(resp *http.Response, ctx *ProxyCtx) *http.Response) {
	pcond.Do(FuncRespHandler(f))
}

// ProxyConds.Do will register the RespHandler on the proxy, h.Handle(resp,ctx) will be called on every
// request that matches the conditions aggregated in pcond.
func (pcond *ProxyConds) Do(h RespHandler) {
	pcond.proxy.respHandlers = append(pcond.proxy.respHandlers,
		FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(ctx.Req, ctx) {
					return resp
				}
			}
			for _, cond := range pcond.respCond {
				if !cond.HandleResp(resp, ctx) {
					return resp
				}
			}
			return h.Handle(resp, ctx)
		}))
}

// OnResponse is used when adding a response-filter to the HTTP proxy, usual pattern is
//	proxy.OnResponse(cond1,cond2).Do(handler) // handler.Handle(resp,ctx) will be used
//				// if cond1.HandleResp(resp) && cond2.HandleResp(resp)
func (proxy *ProxyHttpServer) OnResponse(conds ...RespCondition) *ProxyConds {
	return &ProxyConds{proxy, make([]ReqCondition, 0), conds}
}

// AlwaysMitm is a HttpsHandler that always eavesdrop https connections, for example to
// eavesdrop all https connections to www.google.com, we can use
//	proxy.OnRequest(goproxy.ReqHostIs("www.google.com")).HandleConnect(goproxy.AlwaysMitm)
var AlwaysMitm FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
	return MitmConnect, host
}

// AlwaysReject is a HttpsHandler that drops any CONNECT request, for example, this code will disallow
// connections to hosts on any other port than 443
//	proxy.OnRequest(goproxy.Not(goproxy.ReqHostMatches(regexp.MustCompile(":443$"))).
//		HandleConnect(goproxy.AlwaysReject)
var AlwaysReject FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
	return RejectConnect, host
}

// HandleBytes will return a RespHandler that read the entire body of the request
// to a byte array in memory, would run the user supplied f function on the byte arra,
// and will replace the body of the original response with the resulting byte array.
func HandleBytes(f func(b []byte, ctx *ProxyCtx) []byte) RespHandler {
	return FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response {
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			ctx.Warnf("Cannot read response %s", err)
			return resp
		}
		resp.Body.Close()

		resp.Body = ioutil.NopCloser(bytes.NewBuffer(f(b, ctx)))
		return resp
	})
}
<commit_msg>fixes #19, response might be nil, in case of error.<commit_after>package goproxy

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
)

// ReqCondition.HandleReq will decide whether or not to use the ReqHandler on an HTTP request
// before sending it to the remote server
type ReqCondition interface {
	RespCondition
	HandleReq(req *http.Request, ctx *ProxyCtx) bool
}

// RespCondition.HandleReq will decide whether or not to use the RespHandler on an HTTP response
// before sending it to the proxy client. Note that resp might be nil, in case there was an
// error sending the request.
type RespCondition interface {
	HandleResp(resp *http.Response, ctx *ProxyCtx) bool
}

// ReqConditionFunc.HandleReq(req,ctx) <=> ReqConditionFunc(req,ctx)
type ReqConditionFunc func(req *http.Request, ctx *ProxyCtx) bool

// RespConditionFunc.HandleResp(resp,ctx) <=> RespConditionFunc(resp,ctx)
type RespConditionFunc func(resp *http.Response, ctx *ProxyCtx) bool

func (c ReqConditionFunc) HandleReq(req *http.Request, ctx *ProxyCtx) bool {
	return c(req, ctx)
}

// ReqConditionFunc cannot test responses. It only satisfies RespCondition interface so that
// to be usable as RespCondition.
func (c ReqConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool {
	return c(ctx.Req, ctx)
}

func (c RespConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool {
	return c(resp, ctx)
}

// UrlHasPrefix returns a ReqCondtion checking wether the destination URL the proxy client has requested
// has the given prefix, with or without the host.
// For example UrlHasPrefix("host/x") will match requests of the form 'GET host/x', and will match
// requests to url 'http://host/x'
func UrlHasPrefix(prefix string) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return strings.HasPrefix(req.URL.Path, prefix) ||
			strings.HasPrefix(req.URL.Host+"/"+req.URL.Path, prefix) ||
			strings.HasPrefix(req.URL.Scheme+req.URL.Host+req.URL.Path, prefix)
	}
}

// UrlIs returns a ReqCondition, testing whether or not the request URL is one of the given strings
// with or without the host prefix.
// UrlIs("google.com/","foo") will match requests 'GET /' to 'google.com', requests `'GET google.com/' to
// any host, and requests of the form 'GET foo'.
func UrlIs(urls ...string) ReqConditionFunc {
	urlSet := make(map[string]bool)
	for _, u := range urls {
		urlSet[u] = true
	}
	return func(req *http.Request, ctx *ProxyCtx) bool {
		_, pathOk := urlSet[req.URL.Path]
		_, hostAndOk := urlSet[req.URL.Host+req.URL.Path]
		return pathOk || hostAndOk
	}
}

// ReqHostMatches returns a ReqCondition, testing whether the host to which the request was directed to matches
// any of the given regular expressions.
func ReqHostMatches(regexps ...*regexp.Regexp) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		for _, re := range regexps {
			if re.MatchString(req.Host) {
				return true
			}
		}
		return false
	}
}

// ReqHostIs returns a ReqCondition, testing whether the host to which the request is directed to equal
// to one of the given strings
func ReqHostIs(hosts ...string) ReqConditionFunc {
	hostSet := make(map[string]bool)
	for _, h := range hosts {
		hostSet[h] = true
	}
	return func(req *http.Request, ctx *ProxyCtx) bool {
		_, ok := hostSet[req.URL.Host]
		return ok
	}
}

var localHostIpv4 = regexp.MustCompile(`127\.0\.0\.\d+`)

// IsLocalHost checks whether the destination host is explicitly local host
// (buggy, there can be IPv6 addresses it doesn't catch)
var IsLocalHost ReqConditionFunc = func(req *http.Request, ctx *ProxyCtx) bool {
	return req.URL.Host == "::1" ||
		req.URL.Host == "0:0:0:0:0:0:0:1" ||
		localHostIpv4.MatchString(req.URL.Host) ||
		req.URL.Host == "localhost"
}

// UrlMatches returns a ReqCondition testing whether the destination URL
// of the request matches the given regexp, with or without prefix
func UrlMatches(re *regexp.Regexp) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return re.MatchString(req.URL.Path) ||
			re.MatchString(req.URL.Host+req.URL.Path)
	}
}

// DstHostIs returns a ReqCondtion testing wether the host in the request url is the given string
func DstHostIs(host string) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return req.URL.Host == host
	}
}

// SrcIpIs returns a ReqCondtion testing wether the source IP of the request is the given string
func SrcIpIs(ip string) ReqCondition {
	return ReqConditionFunc(func(req *http.Request, ctx *ProxyCtx) bool {
		return strings.HasPrefix(req.RemoteAddr, ip+":")
	})
}

// Not returns a ReqCondtion negating the given ReqCondition
func Not(r ReqCondition) ReqConditionFunc {
	return func(req *http.Request, ctx *ProxyCtx) bool {
		return !r.HandleReq(req, ctx)
	}
}

// ContentTypeIs returns a RespCondition testing whether the HTTP response has Content-Type header equal
// to one of the given strings.
func ContentTypeIs(typ string, types ...string) RespCondition {
	types = append(types, typ)
	return RespConditionFunc(func(resp *http.Response, ctx *ProxyCtx) bool {
		if resp == nil {
			return false
		}
		contentType := resp.Header.Get("Content-Type")
		for _, typ := range types {
			if contentType == typ || strings.HasPrefix(contentType, typ+";") {
				return true
			}
		}
		return false
	})
}

// ProxyHttpServer.OnRequest Will return a temporary ReqProxyConds struct, aggregating the given condtions.
// You will use the ReqProxyConds struct to register a ReqHandler, that would filter
// the request, only if all the given ReqCondition matched.
// Typical usage:
//	proxy.OnRequest(UrlIs("example.com/foo"),UrlMatches(regexp.MustParse(`.*\.exampl.\com\./.*`)).Do(...)
func (proxy *ProxyHttpServer) OnRequest(conds ...ReqCondition) *ReqProxyConds {
	return &ReqProxyConds{proxy, conds}
}

// ReqProxyConds aggregate ReqConditions for a ProxyHttpServer. Upon calling Do, it will register a ReqHandler that would
// handle the request if all conditions on the HTTP request are met.
type ReqProxyConds struct {
	proxy    *ProxyHttpServer
	reqConds []ReqCondition
}

// DoFunc is equivalent to proxy.OnRequest().Do(FuncReqHandler(f))
func (pcond *ReqProxyConds) DoFunc(f func(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response)) {
	pcond.Do(FuncReqHandler(f))
}

// ReqProxyConds.Do will register the ReqHandler on the proxy,
// the ReqHandler will handle the HTTP request if all the conditions
// aggregated in the ReqProxyConds are met. Typical usage:
//	proxy.OnRequest().Do(handler) // will call handler.Handle(req,ctx) on every request to the proxy
//	proxy.OnRequest(cond1,cond2).Do(handler)
//	// given request to the proxy, will test if cond1.HandleReq(req,ctx) && cond2.HandleReq(req,ctx) are true
//	// if they are, will call handler.Handle(req,ctx)
func (pcond *ReqProxyConds) Do(h ReqHandler) {
	pcond.proxy.reqHandlers = append(pcond.proxy.reqHandlers,
		FuncReqHandler(func(r *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(r, ctx) {
					return r, nil
				}
			}
			return h.Handle(r, ctx)
		}))
}

// HandleConnect is used when proxy receives an HTTP CONNECT request,
// it'll then use the HttpsHandler to determine what should it
// do with this request. The handler returns a ConnectAction struct, the Action field in the ConnectAction
// struct returned will determine what to do with this request. ConnectAccept will simply accept the request
// forwarding all bytes from the client to the remote host, ConnectReject will close the connection with the
// client, and ConnectMitm, will assume the underlying connection is an HTTPS connection, and will use Man
// in the Middle attack to eavesdrop the connection. All regular handler will be active on this eavesdropped
// connection.
// The ConnectAction struct contains possible tlsConfig that will be used for eavesdropping. If nil, the proxy
// will use the default tls configuration.
//	proxy.OnRequest().HandleConnect(goproxy.AlwaysReject) // rejects all CONNECT requests
func (pcond *ReqProxyConds) HandleConnect(h HttpsHandler) {
	pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers,
		FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(ctx.Req, ctx) {
					return nil, ""
				}
			}
			return h.HandleConnect(host, ctx)
		}))
}

// HandleConnectFunc is equivalent to HandleConnect,
// for example, accepting CONNECT request if they contain a password in header
//	io.WriteString(h,password)
//	passHash := h.Sum(nil)
//	proxy.OnRequest().HandleConnectFunc(func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
//		c := sha1.New()
//		io.WriteString(c,ctx.Req.Header.Get("X-GoProxy-Auth"))
//		if c.Sum(nil) == passHash {
//			return OkConnect, host
//		}
//		return RejectConnect, host
//	})
func (pcond *ReqProxyConds) HandleConnectFunc(f func(host string, ctx *ProxyCtx) (*ConnectAction, string)) {
	pcond.HandleConnect(FuncHttpsHandler(f))
}

// ProxyConds is used to aggregate RespConditions for a ProxyHttpServer.
// Upon calling ProxyConds.Do, it will register a RespHandler that would
// handle the HTTP response from remote server if all conditions on the HTTP response are met.
type ProxyConds struct {
	proxy    *ProxyHttpServer
	reqConds []ReqCondition
	respCond []RespCondition
}

// ProxyConds.DoFunc is equivalent to proxy.OnResponse().Do(FuncRespHandler(f))
func (pcond *ProxyConds) DoFunc(f func(resp *http.Response, ctx *ProxyCtx) *http.Response) {
	pcond.Do(FuncRespHandler(f))
}

// ProxyConds.Do will register the RespHandler on the proxy, h.Handle(resp,ctx) will be called on every
// request that matches the conditions aggregated in pcond.
func (pcond *ProxyConds) Do(h RespHandler) {
	pcond.proxy.respHandlers = append(pcond.proxy.respHandlers,
		FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response {
			for _, cond := range pcond.reqConds {
				if !cond.HandleReq(ctx.Req, ctx) {
					return resp
				}
			}
			for _, cond := range pcond.respCond {
				if !cond.HandleResp(resp, ctx) {
					return resp
				}
			}
			return h.Handle(resp, ctx)
		}))
}

// OnResponse is used when adding a response-filter to the HTTP proxy, usual pattern is
//	proxy.OnResponse(cond1,cond2).Do(handler) // handler.Handle(resp,ctx) will be used
//				// if cond1.HandleResp(resp) && cond2.HandleResp(resp)
func (proxy *ProxyHttpServer) OnResponse(conds ...RespCondition) *ProxyConds {
	return &ProxyConds{proxy, make([]ReqCondition, 0), conds}
}

// AlwaysMitm is a HttpsHandler that always eavesdrop https connections, for example to
// eavesdrop all https connections to www.google.com, we can use
//	proxy.OnRequest(goproxy.ReqHostIs("www.google.com")).HandleConnect(goproxy.AlwaysMitm)
var AlwaysMitm FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
	return MitmConnect, host
}

// AlwaysReject is a HttpsHandler that drops any CONNECT request, for example, this code will disallow
// connections to hosts on any other port than 443
//	proxy.OnRequest(goproxy.Not(goproxy.ReqHostMatches(regexp.MustCompile(":443$"))).
//		HandleConnect(goproxy.AlwaysReject)
var AlwaysReject FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) {
	return RejectConnect, host
}

// HandleBytes will return a RespHandler that read the entire body of the request
// to a byte array in memory, would run the user supplied f function on the byte arra,
// and will replace the body of the original response with the resulting byte array.
func HandleBytes(f func(b []byte, ctx *ProxyCtx) []byte) RespHandler {
	return FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response {
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			ctx.Warnf("Cannot read response %s", err)
			return resp
		}
		resp.Body.Close()

		resp.Body = ioutil.NopCloser(bytes.NewBuffer(f(b, ctx)))
		return resp
	})
}
<|endoftext|>


<commit_before>// Copyright ${YEAR} Home24 AG. All rights reserved.
// Proprietary license.
package main

import (
	"net/http"
	"github.com/urakozz/transpoint.io/middleware"
	"html/template"
	"time"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/sessions"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/goods/httpbuf"
	"github.com/satori/go.uuid"
	"github.com/OneOfOne/xxhash/native"

	"encoding/json"
	"strings"
	"log"
	"strconv"
)

const (
	TokenLength int = 32
	TtlDuration time.Duration = 20 * time.Minute
)

type WebContext struct {
	Session *sessions.Session
	User    *User
	CSRF    string
}

type WebAction func(w http.ResponseWriter, r *http.Request, ctx *WebContext) (error)

func (a WebAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	buf := new(httpbuf.Buffer)
	ctx := &WebContext{
		Session: context.Get(r, "session").(*sessions.Session),
		User: context.Get(r, "user").(*User),
		CSRF: context.Get(r, "csrf").(string),
	}
	err := a(buf, r, ctx)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	buf.Apply(w)
}

type User struct {
	Id    string      `json:"id"`
	Email string      `json:"email"`
	Token string      `json:"token"`
	Pass  string      `json:"pass"`
	Keys  []string    `json:"keys"`
}

func (u *User) IsLogin() bool {
	return u.Id != ""
}

type TemplateMap map[string]*template.Template
var Templates TemplateMap

func webInit() {
	parseFiles := func(name string) (*template.Template) {
		base := "templates/"
		partials := base + "partials/"
		mainTpl := base + name + ".html"
		return template.Must(template.ParseFiles(mainTpl, partials+"header.html", partials + "footer.html"))
	}
	Templates = make(TemplateMap)
	Templates["login"] = parseFiles("login")
	Templates["register"] = parseFiles("register")
	Templates["panel-index"] = parseFiles("panel-index")
}

func WebRouter() http.Handler {
	webInit()
	r := mux.NewRouter()

	r.Handle("/webapp", WebAction(WebIndex)).Methods("GET")
	r.Handle("/webapp/login", WebAction(WebLogin)).Methods("POST")
	r.Handle("/webapp/register", WebAction(WebRegisterGet)).Methods("GET")
	r.Handle("/webapp/register", WebAction(WebRegister)).Methods("POST")
	r.Handle("/webapp/logout", WebAction(WebLogout))
	r.Handle("/webapp/panel", WebAction(WebPanelIndex)).Methods("GET")
	r.Handle("/webapp/panel/keys", WebAction(WebPanelKeysPost)).Methods("POST")

	app := negroni.New()
	app.Use(middleware.NewSession(cookieStore))
	app.Use(middleware.NewCsrfMiddleware("csrf"))
	app.Use(middleware.NewUserMiddleware(&middleware.UserMiddlewareConfig{
		Authenticator:func(userId string) (interface{}, error) {
			userObj := &User{}
			str, err := driver.Client.HGet("user", userId).Result()
			if err != nil {
				return nil, err
			}
			json.Unmarshal([]byte(str), &userObj)
			return userObj, nil
		},
	}))
	app.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		if iface := context.Get(r, "user"); iface == nil {
			user := new(User)
			context.Set(r, "user", user)
		}
		next(w, r)
	})
	app.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		if 0 == strings.Index(r.URL.Path, "/webapp/panel") && !context.Get(r, "user").(*User).IsLogin() {
			http.Redirect(w, r, "/webapp", http.StatusFound)
			return
		}
		if r.URL.Path == "/webapp" && context.Get(r, "user").(*User).IsLogin() {
			http.Redirect(w, r, "/webapp/panel", http.StatusFound)
			return
		}
		next(w, r)
	})
	app.UseHandler(r)
	return app
}

func WebIndex(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	Templates["login"].Execute(w, map[string]string{"Title":"Login", "token":ctx.CSRF})

	return
}

func WebLogin(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	session := ctx.Session

	r.ParseForm()
	username := r.Form.Get("username")
	pass := r.Form.Get("pass")

	res, err := driver.Client.HGet("user", username).Result()
	if res != "" && err == nil {
		user := &User{}
		err = json.Unmarshal([]byte(res), user)
		if nil == err && user.Pass == pass {
			session.Values["user"] = username
		}
	}

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)

	return
}

func WebRegister(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	r.ParseForm()
	username := r.Form.Get("username")
	pass := r.Form.Get("pass")

	res, err := driver.Client.HGet("user", username).Result()
	log.Println(res, err, "reg")
	if res == "" {
		user := &User{Id:username, Pass:pass}
		bytes, _ := json.Marshal(user)
		driver.Client.HSet("user", username, string(bytes))
		res, err = driver.Client.HGet("user", username).Result()
		ctx.Session.Values["user"] = username
		log.Println(res)
	}

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)

	return
}

func WebRegisterGet(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	Templates["register"].Execute(w, map[string]string{"Title":"Register", "token":ctx.CSRF})

	return
}

func WebLogout(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	delete(ctx.Session.Values, "user")

	http.Redirect(w, r, "/webapp", http.StatusFound)

	return
}

func WebPanelIndex(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	keys, _ := driver.Client.HMGet("keys", ctx.User.Keys...).Result()
	keyMap := make(map[string]string, len(ctx.User.Keys))
	for i, key := range ctx.User.Keys {
		keyMap[key] = keys[i].(string)
	}

	Templates["panel-index"].Execute(w, map[string]interface{}{"Title":"Panel", "token":ctx.CSRF, "keys":keyMap, "user":ctx.User})

	return
}

func WebPanelKeysPost(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	uid := uuid.NewV4().String()
	uHash := xxhash.Checksum64([]byte(ctx.User.Id))
	var keyBytes []byte
	keyBytes = strconv.AppendUint(keyBytes, uHash, 10)
	keyBytes = append(keyBytes, '.')
	keyBytes = append(keyBytes, []byte(uid)[:8]...)

	var secretBytes []byte
	sHash := xxhash.Checksum64([]byte(uid))
	secretBytes = append(secretBytes, []byte(uid)[9:13]...)
	secretBytes = append(secretBytes, '.')
	secretBytes = strconv.AppendUint(secretBytes, sHash, 10)
	secretBytes = append(secretBytes, '.')
	secretBytes = append(secretBytes, []byte(uid)[24:]...)

	key := string(keyBytes)
	secret := string(secretBytes)
	ctx.User.Keys = append(ctx.User.Keys, key)
	bytes, _ := json.Marshal(ctx.User)
	driver.Client.HSet("user", ctx.User.Id, string(bytes))
	driver.Client.HSet("keys", key, secret)

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)
	return
}

// UserMiddleware checks for the User in the session and adds them to the request context if they exist.
//func UserMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
//	s := GetSession(r)
//	if id, ok := s.Values[sessionUser]; ok {
//		if user, err := dbmap.Get(User{}, id.(int64)); err == nil {
//			SetContextUser(user.(*User), r)
//		}
//	}
//	next(w, r)
//}
//
//// LoginRequiredMiddleware ensures a User is logged in, otherwise redirects them to the login page.
//func LoginRequiredMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
//	if !IsLoggedIn(r) {
//		http.Redirect(w, r, "/", http.StatusFound)
//		return
//	}
//	next(w, r)
//}<commit_msg>pass hash<commit_after>// Copyright ${YEAR} Home24 AG. All rights reserved.
// Proprietary license.
package main

import (
	"net/http"
	"github.com/urakozz/transpoint.io/middleware"
	"html/template"
	"time"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/sessions"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	"github.com/goods/httpbuf"
	"github.com/satori/go.uuid"
	"github.com/OneOfOne/xxhash/native"

	"encoding/json"
	"strings"
	"log"
	"strconv"
)

const (
	TokenLength int = 32
	TtlDuration time.Duration = 20 * time.Minute
)

type WebContext struct {
	Session *sessions.Session
	User    *User
	CSRF    string
}

type WebAction func(w http.ResponseWriter, r *http.Request, ctx *WebContext) (error)

func (a WebAction) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	buf := new(httpbuf.Buffer)
	ctx := &WebContext{
		Session: context.Get(r, "session").(*sessions.Session),
		User: context.Get(r, "user").(*User),
		CSRF: context.Get(r, "csrf").(string),
	}
	err := a(buf, r, ctx)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	buf.Apply(w)
}

type User struct {
	Id    string      `json:"id"`
	Email string      `json:"email"`
	Token string      `json:"token"`
	Pass  string      `json:"pass"`
	Keys  []string    `json:"keys"`
}

func (u *User) IsLogin() bool {
	return u.Id != ""
}

type TemplateMap map[string]*template.Template
var Templates TemplateMap

func webInit() {
	parseFiles := func(name string) (*template.Template) {
		base := "templates/"
		partials := base + "partials/"
		mainTpl := base + name + ".html"
		return template.Must(template.ParseFiles(mainTpl, partials+"header.html", partials + "footer.html"))
	}
	Templates = make(TemplateMap)
	Templates["login"] = parseFiles("login")
	Templates["register"] = parseFiles("register")
	Templates["panel-index"] = parseFiles("panel-index")
}

func WebRouter() http.Handler {
	webInit()
	r := mux.NewRouter()

	r.Handle("/webapp", WebAction(WebIndex)).Methods("GET")
	r.Handle("/webapp/login", WebAction(WebLogin)).Methods("POST")
	r.Handle("/webapp/register", WebAction(WebRegisterGet)).Methods("GET")
	r.Handle("/webapp/register", WebAction(WebRegister)).Methods("POST")
	r.Handle("/webapp/logout", WebAction(WebLogout))
	r.Handle("/webapp/panel", WebAction(WebPanelIndex)).Methods("GET")
	r.Handle("/webapp/panel/keys", WebAction(WebPanelKeysPost)).Methods("POST")

	app := negroni.New()
	app.Use(middleware.NewSession(cookieStore))
	app.Use(middleware.NewCsrfMiddleware("csrf"))
	app.Use(middleware.NewUserMiddleware(&middleware.UserMiddlewareConfig{
		Authenticator:func(userId string) (interface{}, error) {
			userObj := &User{}
			str, err := driver.Client.HGet("user", userId).Result()
			if err != nil {
				return nil, err
			}
			json.Unmarshal([]byte(str), &userObj)
			return userObj, nil
		},
	}))
	app.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		if iface := context.Get(r, "user"); iface == nil {
			user := new(User)
			context.Set(r, "user", user)
		}
		next(w, r)
	})
	app.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
		if 0 == strings.Index(r.URL.Path, "/webapp/panel") && !context.Get(r, "user").(*User).IsLogin() {
			http.Redirect(w, r, "/webapp", http.StatusFound)
			return
		}
		if r.URL.Path == "/webapp" && context.Get(r, "user").(*User).IsLogin() {
			http.Redirect(w, r, "/webapp/panel", http.StatusFound)
			return
		}
		next(w, r)
	})
	app.UseHandler(r)
	return app
}

func WebIndex(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	Templates["login"].Execute(w, map[string]string{"Title":"Login", "token":ctx.CSRF})

	return
}

func WebLogin(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	session := ctx.Session

	r.ParseForm()
	username := r.Form.Get("username")
	pass := r.Form.Get("pass")

	res, err := driver.Client.HGet("user", username).Result()
	if res != "" && err == nil {
		user := &User{}
		err = json.Unmarshal([]byte(res), user)

		pHash := xxhash.Checksum64([]byte(pass))
		var passBytes []byte
		passBytes = strconv.AppendUint(passBytes, pHash, 10)
		if nil == err && user.Pass == string(passBytes) {
			session.Values["user"] = username
		}
	}

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)

	return
}

func WebRegister(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	r.ParseForm()
	username := r.Form.Get("username")
	pass := r.Form.Get("pass")

	res, err := driver.Client.HGet("user", username).Result()
	log.Println(res, err, "reg")
	if res == "" {
		pHash := xxhash.Checksum64([]byte(pass))
		var passBytes []byte
		passBytes = strconv.AppendUint(passBytes, pHash, 10)
		user := &User{Id:username, Pass:string(passBytes)}
		bytes, _ := json.Marshal(user)
		driver.Client.HSet("user", username, string(bytes))
		res, err = driver.Client.HGet("user", username).Result()
		ctx.Session.Values["user"] = username
		log.Println(res)
	}

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)

	return
}

func WebRegisterGet(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	Templates["register"].Execute(w, map[string]string{"Title":"Register", "token":ctx.CSRF})

	return
}

func WebLogout(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	delete(ctx.Session.Values, "user")

	http.Redirect(w, r, "/webapp", http.StatusFound)

	return
}

func WebPanelIndex(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {

	keys, _ := driver.Client.HMGet("keys", ctx.User.Keys...).Result()
	keyMap := make(map[string]string, len(ctx.User.Keys))
	for i, key := range ctx.User.Keys {
		keyMap[key] = keys[i].(string)
	}

	Templates["panel-index"].Execute(w, map[string]interface{}{"Title":"Panel", "token":ctx.CSRF, "keys":keyMap, "user":ctx.User})

	return
}

func WebPanelKeysPost(w http.ResponseWriter, r *http.Request, ctx *WebContext) (err error) {
	uid := uuid.NewV4().String()
	uHash := xxhash.Checksum64([]byte(ctx.User.Id))
	var keyBytes []byte
	keyBytes = strconv.AppendUint(keyBytes, uHash, 10)
	keyBytes = append(keyBytes, '.')
	keyBytes = append(keyBytes, []byte(uid)[:8]...)

	var secretBytes []byte
	sHash := xxhash.Checksum64([]byte(uid))
	secretBytes = append(secretBytes, []byte(uid)[9:13]...)
	secretBytes = append(secretBytes, '.')
	secretBytes = strconv.AppendUint(secretBytes, sHash, 10)
	secretBytes = append(secretBytes, '.')
	secretBytes = append(secretBytes, []byte(uid)[24:]...)

	key := string(keyBytes)
	secret := string(secretBytes)
	ctx.User.Keys = append(ctx.User.Keys, key)
	bytes, _ := json.Marshal(ctx.User)
	driver.Client.HSet("user", ctx.User.Id, string(bytes))
	driver.Client.HSet("keys", key, secret)

	http.Redirect(w, r, "/webapp/panel", http.StatusFound)
	return
}

// UserMiddleware checks for the User in the session and adds them to the request context if they exist.
//func UserMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
//	s := GetSession(r)
//	if id, ok := s.Values[sessionUser]; ok {
//		if user, err := dbmap.Get(User{}, id.(int64)); err == nil {
//			SetContextUser(user.(*User), r)
//		}
//	}
//	next(w, r)
//}
//
//// LoginRequiredMiddleware ensures a User is logged in, otherwise redirects them to the login page.
//func LoginRequiredMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
//	if !IsLoggedIn(r) {
//		http.Redirect(w, r, "/", http.StatusFound)
//		return
//	}
//	next(w, r)
//}<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	std "github.com/balzaczyy/golucene/analysis/standard"
	_ "github.com/balzaczyy/golucene/core/codec/lucene49"
	"github.com/balzaczyy/golucene/core/index"
	"github.com/balzaczyy/golucene/core/search"
	"github.com/balzaczyy/golucene/core/store"
	"github.com/balzaczyy/golucene/core/util"
	qp "github.com/balzaczyy/golucene/queryparser/classic"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
)

func main() {

	util.SetDefaultInfoStream(util.NewPrintStreamInfoStream(os.Stdout))
	index.DefaultSimilarity = func() index.Similarity {
		return search.NewDefaultSimilarity()
	}
	directory, err := store.OpenFSDirectory("index")
	if err != nil {
		log.Panicf("Failed to open directory: %v", err)
	}
	defer directory.Close()
	reader, err := index.OpenDirectoryReader(directory)
	if err != nil {
		log.Panicf("Failed to open writer: %v", err)
	}
	defer reader.Close()
	analyzer := std.NewStandardAnalyzer()
	qParser := qp.NewQueryParser(util.VERSION_49, "text", analyzer)
	ss := search.NewIndexSearcher(reader)

	port := os.Getenv("VCAP_APP_PORT")
	if port == "" {
		port = "8080"
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		file := r.URL.Path
		if path.Ext(file) == "" {
			file = path.Join(file, "index.html")
		}
		if strings.HasPrefix(file, "/") {
			file = file[1:]
		}
		log.Printf("Serving %v", file)
		http.ServeFile(w, r, file)
	})
	http.HandleFunc("/api/search", func(w http.ResponseWriter, r *http.Request) {
		queryStr := r.URL.Query().Get("q")
		log.Printf("Query: %v", queryStr)
		query, err := qParser.Parse(queryStr)
		if err != nil {
			log.Printf("Parse failed: %v", err)
			w.WriteHeader(500)
			return
		}

		hits, err := ss.SearchTop(query, 100)
		if err != nil {
			log.Printf("Search failed: %v", err)
			w.WriteHeader(500)
			return
		}

		var lines []string
		for _, hit := range hits.ScoreDocs {
			doc, err := reader.Document(hit.Doc)
			if err != nil {
				log.Printf("Fetch doc %v failed: %v", hit.Doc, err)
				continue
			}
			lines = append(lines, doc.Get("text"))
		}

		data, err := json.Marshal(lines)
		if err != nil {
			log.Printf("IO error: %v", err)
			w.WriteHeader(500)
			return
		}

		w.WriteHeader(200)
		w.Write(data)
	})
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<commit_msg>use go-logging<commit_after>package main

import (
	"encoding/json"
	std "github.com/balzaczyy/golucene/analysis/standard"
	_ "github.com/balzaczyy/golucene/core/codec/lucene49"
	"github.com/balzaczyy/golucene/core/index"
	"github.com/balzaczyy/golucene/core/search"
	"github.com/balzaczyy/golucene/core/store"
	"github.com/balzaczyy/golucene/core/util"
	qp "github.com/balzaczyy/golucene/queryparser/classic"
	"github.com/op/go-logging"
	"net/http"
	"os"
	"path"
	"strings"
)

var log = logging.MustGetLogger("hamlet")

func init() {
	format := logging.MustStringFormatter(
		"%{color}%{time:15:04:05.000000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}")
	backend := logging.NewLogBackend(os.Stdout, "", 0)
	logging.SetBackend(logging.NewBackendFormatter(backend, format))
	log.Info("Logger is configured.")
}

func main() {

	util.SetDefaultInfoStream(util.NewPrintStreamInfoStream(os.Stdout))
	index.DefaultSimilarity = func() index.Similarity {
		return search.NewDefaultSimilarity()
	}
	directory, err := store.OpenFSDirectory("index")
	if err != nil {
		log.Critical("Failed to open directory: %v", err)
		return
	}
	defer directory.Close()
	reader, err := index.OpenDirectoryReader(directory)
	if err != nil {
		log.Critical("Failed to open writer: %v", err)
		return
	}
	defer reader.Close()
	analyzer := std.NewStandardAnalyzer()
	qParser := qp.NewQueryParser(util.VERSION_49, "text", analyzer)
	ss := search.NewIndexSearcher(reader)

	port := os.Getenv("VCAP_APP_PORT")
	if port == "" {
		port = "8080"
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		file := r.URL.Path
		if path.Ext(file) == "" {
			file = path.Join(file, "index.html")
		}
		if strings.HasPrefix(file, "/") {
			file = file[1:]
		}
		log.Debug("Serving %v", file)
		http.ServeFile(w, r, file)
	})
	http.HandleFunc("/api/search", func(w http.ResponseWriter, r *http.Request) {
		queryStr := r.URL.Query().Get("q")
		log.Debug("Query: %v", queryStr)
		query, err := qParser.Parse(queryStr)
		if err != nil {
			log.Error("Parse failed: %v", err)
			w.WriteHeader(500)
			return
		}

		hits, err := ss.SearchTop(query, 100)
		if err != nil {
			log.Error("Search failed: %v", err)
			w.WriteHeader(500)
			return
		}

		var lines []string
		for _, hit := range hits.ScoreDocs {
			doc, err := reader.Document(hit.Doc)
			if err != nil {
				log.Warning("Fetch doc %v failed: %v", hit.Doc, err)
				continue
			}
			lines = append(lines, doc.Get("text"))
		}

		data, err := json.Marshal(lines)
		if err != nil {
			log.Error("IO error: %v", err)
			w.WriteHeader(500)
			return
		}

		w.WriteHeader(200)
		w.Write(data)
	})
	log.Critical("%v", http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"text/template"
	"time"

	"github.com/gbl08ma/disturbancesmlx/dataobjects"

	"encoding/json"

	"github.com/gorilla/mux"
	"github.com/rickb777/date"
)

var webtemplate *template.Template

// WebServer starts the web server
func WebServer() {
	router := mux.NewRouter().StrictSlash(true)

	webLog.Println("Starting Web server...")

	router.HandleFunc("/", HomePage)
	router.HandleFunc("/lookingglass", LookingGlass)
	router.HandleFunc("/lookingglass/heatmap", Heatmap)
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))

	WebReloadTemplate()

	server := http.Server{
		Addr:    ":8089",
		Handler: router,
	}

	err := server.ListenAndServe()
	if err != nil {
		webLog.Println(err)
	}
	webLog.Println("Web server terminated")
}

// HomePage serves the home page
func HomePage(w http.ResponseWriter, r *http.Request) {
	if DEBUG {
		WebReloadTemplate()
	}
	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	loc, _ := time.LoadLocation("Europe/Lisbon")
	p := struct {
		Hours int
		Days  int
		Lines []struct {
			*dataobjects.Line
			Down            bool
			Minutes         int
			DayCounts       []int
			HourCounts      []int
			LastDisturbance *dataobjects.Disturbance
			Availability    string
			AvgDuration     string
		}
		DayNames          []string
		LastChangeAgoMin  int
		LastChangeAgoHour int
		LastUpdateAgoMin  int
		LastUpdateAgoHour int
	}{
		LastChangeAgoMin:  int(time.Now().Sub(lastChange).Minutes()) % 60,
		LastChangeAgoHour: int(time.Now().Sub(lastChange).Hours()),
		LastUpdateAgoMin:  int(time.Now().Sub(mlxscr.LastUpdate()).Minutes()) % 60,
		LastUpdateAgoHour: int(time.Now().Sub(mlxscr.LastUpdate()).Hours()),
	}

	t := time.Now().In(loc).AddDate(0, 0, -6)
	for i := 0; i < 7; i++ {
		weekDay := ""
		switch t.Weekday() {
		case time.Sunday:
			weekDay = "dom"
		case time.Monday:
			weekDay = "seg"
		case time.Tuesday:
			weekDay = "ter"
		case time.Wednesday:
			weekDay = "qua"
		case time.Thursday:
			weekDay = "qui"
		case time.Friday:
			weekDay = "sex"
		case time.Saturday:
			weekDay = "sáb"
		}
		name := fmt.Sprintf("%s, %d", weekDay, t.Day())
		p.DayNames = append(p.DayNames, name)
		t = t.AddDate(0, 0, 1)
	}

	lastDisturbanceTime, err := MLlastDisturbanceTime(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	p.Days = int(date.NewAt(time.Now().In(loc)).Sub(date.NewAt(lastDisturbanceTime.In(loc))))
	p.Hours = int(time.Since(lastDisturbanceTime).Hours())

	n, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	lines, err := n.Lines(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	p.Lines = make([]struct {
		*dataobjects.Line
		Down            bool
		Minutes         int
		DayCounts       []int
		HourCounts      []int
		LastDisturbance *dataobjects.Disturbance
		Availability    string
		AvgDuration     string
	}, len(lines))

	for i := range lines {
		p.Lines[i].Line = lines[i]
		d, err := lines[i].LastOngoingDisturbance(tx)
		p.Lines[i].Down = err == nil
		if err == nil {
			p.Lines[i].Minutes = int(time.Now().Sub(d.StartTime).Minutes())
		}

		p.Lines[i].LastDisturbance, err = lines[i].LastDisturbance(tx)
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		p.Lines[i].DayCounts, err = lines[i].CountDisturbancesByDay(tx, time.Now().In(loc).AddDate(0, 0, -6), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		hourCounts, err := lines[i].CountDisturbancesByHourOfDay(tx, time.Now().In(loc).AddDate(0, 0, -6), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// Metro de Lisboa starts operating at 06:30 AM and stops at 01:00 AM
		for j := 6; j < 24; j++ {
			p.Lines[i].HourCounts = append(p.Lines[i].HourCounts, hourCounts[j])
		}
		p.Lines[i].HourCounts = append(p.Lines[i].HourCounts, hourCounts[0])

		availability, avgd, err := MLlineAvailability(tx, lines[i], time.Now().In(loc).Add(-24*7*time.Hour), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		p.Lines[i].Availability = fmt.Sprintf("%.03f%%", availability*100)
		p.Lines[i].AvgDuration = fmt.Sprintf("%.01f", avgd.Minutes())
	}

	err = webtemplate.ExecuteTemplate(w, "index.html", p)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// LookingGlass serves the looking glass page
func LookingGlass(w http.ResponseWriter, r *http.Request) {
	if DEBUG {
		WebReloadTemplate()
	}
	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	p := struct {
		Lines []struct {
			*dataobjects.Line
			Down    bool
			Minutes int
		}
		LastChangeAgoMin  int
		LastChangeAgoHour int
		LastUpdateAgoMin  int
		LastUpdateAgoHour int
	}{
		LastChangeAgoMin:  int(time.Now().Sub(lastChange).Minutes()) % 60,
		LastChangeAgoHour: int(time.Now().Sub(lastChange).Hours()),
		LastUpdateAgoMin:  int(time.Now().Sub(mlxscr.LastUpdate()).Minutes()) % 60,
		LastUpdateAgoHour: int(time.Now().Sub(mlxscr.LastUpdate()).Hours()),
	}

	n, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	lines, err := n.Lines(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	p.Lines = make([]struct {
		*dataobjects.Line
		Down    bool
		Minutes int
	}, len(lines))

	for i := range lines {
		p.Lines[i].Line = lines[i]
		d, err := lines[i].LastOngoingDisturbance(tx)
		p.Lines[i].Down = err == nil
		if err == nil {
			p.Lines[i].Minutes = int(time.Now().Sub(d.StartTime).Minutes())
		}
	}

	err = webtemplate.ExecuteTemplate(w, "lg.html", p)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// Heatmap serves data for the disturbance heatmap
func Heatmap(w http.ResponseWriter, r *http.Request) {
	startTime, err := time.Parse(time.RFC3339Nano, r.URL.Query().Get("start"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	endTime, err := time.Parse(time.RFC3339Nano, r.URL.Query().Get("stop"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	network, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}

	dayCounts, err := network.CountDisturbancesByHour(tx, startTime, endTime)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}

	data := make(map[int64]int)

	for _, count := range dayCounts {
		data[startTime.Unix()] = count
		startTime = startTime.Add(1 * time.Hour)
	}

	json, err := json.Marshal(data)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}
	w.Write(json)
}

// WebReloadTemplate reloads the templates for the website
func WebReloadTemplate() {
	funcMap := template.FuncMap{
		"minus": func(a, b int) int {
			return a - b
		},
		"plus": func(a, b int) int {
			return a + b
		},
		"minus64": func(a, b int64) int64 {
			return a - b
		},
		"plus64": func(a, b int64) int64 {
			return a + b
		},
		"formatDisturbanceTime": func(t time.Time) string {
			loc, _ := time.LoadLocation("Europe/Lisbon")
			return t.In(loc).Format("02 Jan 2006 15:04")
		},
	}

	webtemplate, _ = template.New("index.html").Funcs(funcMap).ParseGlob("web/*.html")
}
<commit_msg>Fix disturbance status order on web page<commit_after>package main

import (
	"fmt"
	"net/http"
	"text/template"
	"time"

	"github.com/gbl08ma/disturbancesmlx/dataobjects"

	"encoding/json"

	"sort"

	"github.com/gorilla/mux"
	"github.com/rickb777/date"
)

var webtemplate *template.Template

// WebServer starts the web server
func WebServer() {
	router := mux.NewRouter().StrictSlash(true)

	webLog.Println("Starting Web server...")

	router.HandleFunc("/", HomePage)
	router.HandleFunc("/lookingglass", LookingGlass)
	router.HandleFunc("/lookingglass/heatmap", Heatmap)
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))

	WebReloadTemplate()

	server := http.Server{
		Addr:    ":8089",
		Handler: router,
	}

	err := server.ListenAndServe()
	if err != nil {
		webLog.Println(err)
	}
	webLog.Println("Web server terminated")
}

// HomePage serves the home page
func HomePage(w http.ResponseWriter, r *http.Request) {
	if DEBUG {
		WebReloadTemplate()
	}
	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	loc, _ := time.LoadLocation("Europe/Lisbon")
	p := struct {
		Hours int
		Days  int
		Lines []struct {
			*dataobjects.Line
			Down            bool
			Minutes         int
			DayCounts       []int
			HourCounts      []int
			LastDisturbance *dataobjects.Disturbance
			Availability    string
			AvgDuration     string
		}
		DayNames          []string
		LastChangeAgoMin  int
		LastChangeAgoHour int
		LastUpdateAgoMin  int
		LastUpdateAgoHour int
	}{
		LastChangeAgoMin:  int(time.Now().Sub(lastChange).Minutes()) % 60,
		LastChangeAgoHour: int(time.Now().Sub(lastChange).Hours()),
		LastUpdateAgoMin:  int(time.Now().Sub(mlxscr.LastUpdate()).Minutes()) % 60,
		LastUpdateAgoHour: int(time.Now().Sub(mlxscr.LastUpdate()).Hours()),
	}

	t := time.Now().In(loc).AddDate(0, 0, -6)
	for i := 0; i < 7; i++ {
		weekDay := ""
		switch t.Weekday() {
		case time.Sunday:
			weekDay = "dom"
		case time.Monday:
			weekDay = "seg"
		case time.Tuesday:
			weekDay = "ter"
		case time.Wednesday:
			weekDay = "qua"
		case time.Thursday:
			weekDay = "qui"
		case time.Friday:
			weekDay = "sex"
		case time.Saturday:
			weekDay = "sáb"
		}
		name := fmt.Sprintf("%s, %d", weekDay, t.Day())
		p.DayNames = append(p.DayNames, name)
		t = t.AddDate(0, 0, 1)
	}

	lastDisturbanceTime, err := MLlastDisturbanceTime(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	p.Days = int(date.NewAt(time.Now().In(loc)).Sub(date.NewAt(lastDisturbanceTime.In(loc))))
	p.Hours = int(time.Since(lastDisturbanceTime).Hours())

	n, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	lines, err := n.Lines(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	p.Lines = make([]struct {
		*dataobjects.Line
		Down            bool
		Minutes         int
		DayCounts       []int
		HourCounts      []int
		LastDisturbance *dataobjects.Disturbance
		Availability    string
		AvgDuration     string
	}, len(lines))

	for i := range lines {
		p.Lines[i].Line = lines[i]
		d, err := lines[i].LastOngoingDisturbance(tx)
		p.Lines[i].Down = err == nil
		if err == nil {
			p.Lines[i].Minutes = int(time.Now().Sub(d.StartTime).Minutes())
		}

		p.Lines[i].LastDisturbance, err = lines[i].LastDisturbance(tx)
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		sort.Slice(p.Lines[i].LastDisturbance.Statuses, func(j, k int) bool {
			return p.Lines[i].LastDisturbance.Statuses[j].Time.Before(p.Lines[i].LastDisturbance.Statuses[k].Time)
		})

		p.Lines[i].DayCounts, err = lines[i].CountDisturbancesByDay(tx, time.Now().In(loc).AddDate(0, 0, -6), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		hourCounts, err := lines[i].CountDisturbancesByHourOfDay(tx, time.Now().In(loc).AddDate(0, 0, -6), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// Metro de Lisboa starts operating at 06:30 AM and stops at 01:00 AM
		for j := 6; j < 24; j++ {
			p.Lines[i].HourCounts = append(p.Lines[i].HourCounts, hourCounts[j])
		}
		p.Lines[i].HourCounts = append(p.Lines[i].HourCounts, hourCounts[0])

		availability, avgd, err := MLlineAvailability(tx, lines[i], time.Now().In(loc).Add(-24*7*time.Hour), time.Now().In(loc))
		if err != nil {
			webLog.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		p.Lines[i].Availability = fmt.Sprintf("%.03f%%", availability*100)
		p.Lines[i].AvgDuration = fmt.Sprintf("%.01f", avgd.Minutes())
	}

	err = webtemplate.ExecuteTemplate(w, "index.html", p)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// LookingGlass serves the looking glass page
func LookingGlass(w http.ResponseWriter, r *http.Request) {
	if DEBUG {
		WebReloadTemplate()
	}
	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	p := struct {
		Lines []struct {
			*dataobjects.Line
			Down    bool
			Minutes int
		}
		LastChangeAgoMin  int
		LastChangeAgoHour int
		LastUpdateAgoMin  int
		LastUpdateAgoHour int
	}{
		LastChangeAgoMin:  int(time.Now().Sub(lastChange).Minutes()) % 60,
		LastChangeAgoHour: int(time.Now().Sub(lastChange).Hours()),
		LastUpdateAgoMin:  int(time.Now().Sub(mlxscr.LastUpdate()).Minutes()) % 60,
		LastUpdateAgoHour: int(time.Now().Sub(mlxscr.LastUpdate()).Hours()),
	}

	n, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	lines, err := n.Lines(tx)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	p.Lines = make([]struct {
		*dataobjects.Line
		Down    bool
		Minutes int
	}, len(lines))

	for i := range lines {
		p.Lines[i].Line = lines[i]
		d, err := lines[i].LastOngoingDisturbance(tx)
		p.Lines[i].Down = err == nil
		if err == nil {
			p.Lines[i].Minutes = int(time.Now().Sub(d.StartTime).Minutes())
		}
	}

	err = webtemplate.ExecuteTemplate(w, "lg.html", p)
	if err != nil {
		webLog.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
	}
}

// Heatmap serves data for the disturbance heatmap
func Heatmap(w http.ResponseWriter, r *http.Request) {
	startTime, err := time.Parse(time.RFC3339Nano, r.URL.Query().Get("start"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	endTime, err := time.Parse(time.RFC3339Nano, r.URL.Query().Get("stop"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	tx, err := rootSqalxNode.Beginx()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
		return
	}
	defer tx.Commit()

	network, err := dataobjects.GetNetwork(tx, MLnetworkID)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}

	dayCounts, err := network.CountDisturbancesByHour(tx, startTime, endTime)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}

	data := make(map[int64]int)

	for _, count := range dayCounts {
		data[startTime.Unix()] = count
		startTime = startTime.Add(1 * time.Hour)
	}

	json, err := json.Marshal(data)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		webLog.Println(err)
	}
	w.Write(json)
}

// WebReloadTemplate reloads the templates for the website
func WebReloadTemplate() {
	funcMap := template.FuncMap{
		"minus": func(a, b int) int {
			return a - b
		},
		"plus": func(a, b int) int {
			return a + b
		},
		"minus64": func(a, b int64) int64 {
			return a - b
		},
		"plus64": func(a, b int64) int64 {
			return a + b
		},
		"formatDisturbanceTime": func(t time.Time) string {
			loc, _ := time.LoadLocation("Europe/Lisbon")
			return t.In(loc).Format("02 Jan 2006 15:04")
		},
	}

	webtemplate, _ = template.New("index.html").Funcs(funcMap).ParseGlob("web/*.html")
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"time"
)

func Who(char string, lvl int) {
	date := time.Now()
	db, err := sql.Open("sqlite3", "toril.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// check if character exists in DB
	stmt, err := db.Prepare("SELECT account_name, char_name FROM chars WHERE LOWER(char_name) = LOWER(?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	var acc string
	var name string
	err = stmt.QueryRow(char).Scan(&acc, &name)
	if err != nil {
		// if char doesn't exist, 'who char'
		fmt.Printf("who %s\n", char)
		return
	} else {
		// if char does exist, tell the DB the time they were spotted and
		// update their level
		// todo: also check class change for necro->lich
		// todo: also check for account name change
		tx, err := db.Begin()
		if err != nil {
			log.Fatal(err)
		}
		stmt, err := tx.Prepare("UPDATE chars SET char_level = ?, last_seen = ? WHERE account_name = ? AND char_name = ?")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		_, err = stmt.Exec(lvl, date, acc, name)
		if err != nil {
			log.Fatal(err)
		}
		tx.Commit()
	}
}

func WhoChar(char string, lvl int, class string, race string, acct string) {
	date := time.Now()
	db, err := sql.Open("sqlite3", "toril.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// check if character exists in DB
	stmt, err := db.Prepare("SELECT account_name, char_name FROM chars WHERE LOWER(char_name) = LOWER(?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	var acc string
	var name string
	err = stmt.QueryRow(char).Scan(&acc, &name)
	if err != nil {
		// if no char, check if account exists in DB, create char
		stmt, err = db.Prepare("SELECT account_name FROM accounts WHERE LOWER(account_name) = LOWER(?)")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		err = stmt.QueryRow(char).Scan(&acc)
		if err != nil { // if no acct, create acccount
			tx, err := db.Begin()
			if err != nil {
				log.Fatal(err)
			}

			stmt, err := tx.Prepare("INSERT INTO accounts (account_name) VALUES(?)")
			if err != nil {
				log.Fatal(err)
			}
			defer stmt.Close()

			_, err = stmt.Exec(acct)
			if err != nil {
				log.Fatal(err)
			}
			tx.Commit()
		}
		// create character
		tx, err := db.Begin()
		if err != nil {
			log.Fatal(err)
		}

		stmt, err := tx.Prepare("INSERT INTO chars VALUES(%s, %s, %s, %s, %s, %s, 't')")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		_, err = stmt.Exec(acct, char, class, race, lvl, date)
		if err != nil {
			log.Fatal(err)
		}
		tx.Commit()
	}
}
<commit_msg>Debugging time always being in UTC<commit_after>package main

import (
	"database/sql"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"time"
)

func Who(char string, lvl int) {
	loc, err := time.LoadLocation("America/New_York")
	if err != nil {
		log.Fatal(err)
	}
	date := time.Now().In(loc)
	// debugging
	fmt.Printf("Time: %v\n", date)
	db, err := sql.Open("sqlite3", "toril.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// check if character exists in DB
	stmt, err := db.Prepare("SELECT account_name, char_name FROM chars WHERE LOWER(char_name) = LOWER(?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	var acc string
	var name string
	err = stmt.QueryRow(char).Scan(&acc, &name)
	if err != nil {
		// if char doesn't exist, 'who char'
		fmt.Printf("who %s\n", char)
		return
	} else {
		// if char does exist, tell the DB the time they were spotted and
		// update their level
		// todo: also check class change for necro->lich
		// todo: also check for account name change
		tx, err := db.Begin()
		if err != nil {
			log.Fatal(err)
		}
		stmt, err := tx.Prepare("UPDATE chars SET char_level = ?, last_seen = ? WHERE account_name = ? AND char_name = ?")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		_, err = stmt.Exec(lvl, date, acc, name)
		if err != nil {
			log.Fatal(err)
		}
		tx.Commit()
	}
}

func WhoChar(char string, lvl int, class string, race string, acct string) {
	date := time.Now()
	db, err := sql.Open("sqlite3", "toril.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// check if character exists in DB
	stmt, err := db.Prepare("SELECT account_name, char_name FROM chars WHERE LOWER(char_name) = LOWER(?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	var acc string
	var name string
	err = stmt.QueryRow(char).Scan(&acc, &name)
	if err != nil {
		// if no char, check if account exists in DB, create char
		stmt, err = db.Prepare("SELECT account_name FROM accounts WHERE LOWER(account_name) = LOWER(?)")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		err = stmt.QueryRow(char).Scan(&acc)
		if err != nil { // if no acct, create acccount
			tx, err := db.Begin()
			if err != nil {
				log.Fatal(err)
			}

			stmt, err := tx.Prepare("INSERT INTO accounts (account_name) VALUES(?)")
			if err != nil {
				log.Fatal(err)
			}
			defer stmt.Close()

			_, err = stmt.Exec(acct)
			if err != nil {
				log.Fatal(err)
			}
			tx.Commit()
		}
		// create character
		tx, err := db.Begin()
		if err != nil {
			log.Fatal(err)
		}

		stmt, err := tx.Prepare("INSERT INTO chars VALUES(%s, %s, %s, %s, %s, %s, 't')")
		if err != nil {
			log.Fatal(err)
		}
		defer stmt.Close()

		_, err = stmt.Exec(acct, char, class, race, lvl, date)
		if err != nil {
			log.Fatal(err)
		}
		tx.Commit()
	}
}
<|endoftext|>