<commit_before>package logic

import (
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/cihub/seelog"
	"github.com/jonaz/astrotime"
	"github.com/jonaz/cron"
	"github.com/stampzilla/stampzilla-go/stampzilla-server/protocol"
)

type task struct {
	Name_    string       `json:"name"`
	Uuid_    string       `json:"uuid"`
	Actions  []RuleAction `json:"actions"`
	cronId   int
	CronWhen string `json:"when"`
	sync.RWMutex
	nodes *protocol.Nodes
	cron  *cron.Cron
}

type Task interface {
	cron.Job
	SetUuid(string)
	Uuid() string
	Name() string
	CronId() int
	AddAction(a RuleAction)
	Schedule(string)
}

func (t *task) SetUuid(uuid string) {
	t.Lock()
	t.Uuid_ = uuid
	t.Unlock()
}
func (r *task) Uuid() string {
	r.RLock()
	defer r.RUnlock()
	return r.Uuid_
}
func (r *task) Name() string {
	r.RLock()
	defer r.RUnlock()
	return r.Name_
}
func (r *task) CronId() int {
	r.RLock()
	defer r.RUnlock()
	return r.cronId
}

func (t *task) Run() {
	t.RLock()
	for _, action := range t.Actions {
		action.RunCommand()
	}
	t.RUnlock()

	if t.IsSunBased(t.CronWhen) != "" {
		t.reschedule()
	}
}

func (t *task) reschedule() {
	log.Debug("Rescheduling rule", t.CronWhen)
	t.cron.RemoveFunc(t.CronId())
	t.Schedule(t.CronWhen)
}

func (t *task) Schedule(when string) {
	var err error
	t.Lock()
	t.CronWhen = when

	when = t.CalculateSun(when)

	t.cronId, err = t.cron.AddJob(when, t)
	if err != nil {
		log.Error(err)
	}
	t.Unlock()
}

func (r *task) AddAction(a RuleAction) {
	if a, ok := a.(*ruleAction); ok {
		a.nodes = r.nodes
	}
	r.Lock()
	r.Actions = append(r.Actions, a)
	r.Unlock()
}

func (t *task) IsSunBased(when string) string {
	codes := []string{
		"sunset",
		"sunrise",
		"dusk",
		"dawn",
	}

	for _, v := range codes {
		if strings.Contains(when, v) {
			return v
		}
	}
	return ""
}

func (t *task) CalculateSun(when string) string {
	what := ""
	if what = t.IsSunBased(when); what == "" {
		return when
	}

	t1 := t.GetSunTime(what)
	when = strings.Replace(when, what+" "+what, strconv.Itoa(t1.Minute())+" "+strconv.Itoa(t1.Hour()), 1)
	return when
}
func (t *task) GetSunTime(what string) time.Time {

	var t1 time.Time
	switch what {
	case "sunset":
		t1 = astrotime.NextSunset(time.Now(), float64(56.878333), float64(14.809167))
	case "sunrise":
		t1 = astrotime.NextSunrise(time.Now(), float64(56.878333), float64(14.809167))
	case "dusk":
		t1 = astrotime.NextDusk(time.Now(), float64(56.878333), float64(14.809167), astrotime.CIVIL_DUSK)
	case "dawn":
		t1 = astrotime.NextDawn(time.Now(), float64(56.878333), float64(14.809167), astrotime.CIVIL_DAWN)
	}
	return t1
}
<commit_msg>fix for sun schedule at correct time<commit_after>package logic

import (
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/cihub/seelog"
	"github.com/jonaz/astrotime"
	"github.com/jonaz/cron"
	"github.com/stampzilla/stampzilla-go/stampzilla-server/protocol"
)

type task struct {
	Name_    string       `json:"name"`
	Uuid_    string       `json:"uuid"`
	Actions  []RuleAction `json:"actions"`
	cronId   int
	CronWhen string `json:"when"`
	sync.RWMutex
	nodes     *protocol.Nodes
	cron      *cron.Cron
	entryTime time.Time
}

type Task interface {
	cron.Job
	SetUuid(string)
	Uuid() string
	Name() string
	CronId() int
	AddAction(a RuleAction)
	Schedule(string)
}

func (t *task) SetUuid(uuid string) {
	t.Lock()
	t.Uuid_ = uuid
	t.Unlock()
}
func (r *task) Uuid() string {
	r.RLock()
	defer r.RUnlock()
	return r.Uuid_
}
func (r *task) Name() string {
	r.RLock()
	defer r.RUnlock()
	return r.Name_
}
func (r *task) CronId() int {
	r.RLock()
	defer r.RUnlock()
	return r.cronId
}

func (t *task) Run() {
	t.RLock()
	for _, action := range t.Actions {
		action.RunCommand()
	}
	t.RUnlock()

	if t.IsSunBased(t.CronWhen) != "" {
		t.reschedule()
	}
}

func (t *task) reschedule() {
	log.Debug("Rescheduling rule", t.CronWhen)

	for _, v := range t.cron.Entries() {
		if v.Id == t.CronId() {
			t.entryTime = v.Schedule.Next(time.Now().Local())
			break
		}
	}

	t.cron.RemoveFunc(t.CronId())
	t.Schedule(t.CronWhen)
}

func (t *task) Schedule(when string) {
	var err error
	t.Lock()
	t.CronWhen = when

	when = t.CalculateSun(when)

	t.cronId, err = t.cron.AddJob(when, t)
	if err != nil {
		log.Error(err)
	}
	t.Unlock()
}

func (r *task) AddAction(a RuleAction) {
	if a, ok := a.(*ruleAction); ok {
		a.nodes = r.nodes
	}
	r.Lock()
	r.Actions = append(r.Actions, a)
	r.Unlock()
}

func (t *task) IsSunBased(when string) string {
	codes := []string{
		"sunset",
		"sunrise",
		"dusk",
		"dawn",
	}

	for _, v := range codes {
		if strings.Contains(when, v) {
			return v
		}
	}
	return ""
}

func (t *task) CalculateSun(when string) string {
	what := ""
	if what = t.IsSunBased(when); what == "" {
		return when
	}

	t1 := t.GetSunTime(what)
	when = strings.Replace(when, what+" "+what, strconv.Itoa(t1.Minute())+" "+strconv.Itoa(t1.Hour()), 1)
	return when
}
func (t *task) GetSunTime(what string) time.Time {

	now := time.Now()
	if !t.entryTime.IsZero() {
		now = t.entryTime
	}

	var t1 time.Time
	switch what {
	case "sunset":
		t1 = astrotime.NextSunset(now, float64(56.878333), float64(14.809167))
	case "sunrise":
		t1 = astrotime.NextSunrise(now, float64(56.878333), float64(14.809167))
	case "dusk":
		t1 = astrotime.NextDusk(now, float64(56.878333), float64(14.809167), astrotime.CIVIL_DUSK)
	case "dawn":
		t1 = astrotime.NextDawn(now, float64(56.878333), float64(14.809167), astrotime.CIVIL_DAWN)
	}
	return t1
}
<|endoftext|>


<commit_before><commit_msg>Add a comment about cbMain.<commit_after><|endoftext|>


<commit_before><commit_msg>Add results from magic seaweed.<commit_after><|endoftext|>


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

package main

import (
	"fmt"
	_ "github.com/trivago/gollum/consumer"
	_ "github.com/trivago/gollum/contrib"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	_ "github.com/trivago/gollum/filter"
	_ "github.com/trivago/gollum/format"
	_ "github.com/trivago/gollum/producer"
	"github.com/trivago/gollum/shared"
	_ "github.com/trivago/gollum/stream"
	"io/ioutil"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
)

const (
	gollumMajorVer = 0
	gollumMinorVer = 4
	gollumPatchVer = 3
	gollumDevVer   = 5
)

func dumpMemoryProfile() {
	if file, err := os.Create(*flagMemProfile); err != nil {
		panic(err)
	} else {
		defer file.Close()
		pprof.WriteHeapProfile(file)
	}
}

func main() {
	parseFlags()
	Log.SetVerbosity(Log.Verbosity(*flagLoglevel))

	contribModules := shared.TypeRegistry.GetRegistered("contrib")
	modules := ""
	for _, typeName := range contribModules {
		modules += " + " + typeName[shared.IndexN(typeName, ".", 1)+1:] + "\n"
	}

	if *flagVersion {
		if gollumDevVer > 0 {
			fmt.Printf("Gollum v%d.%d.%d.%d dev\n%s", gollumMajorVer, gollumMinorVer, gollumPatchVer, gollumDevVer, modules)
		} else {
			fmt.Printf("Gollum v%d.%d.%d\n%s", gollumMajorVer, gollumMinorVer, gollumPatchVer, modules)
		}
		fmt.Println(runtime.Version())
		return // ### return, version only ###
	}

	configFile := flagConfigFile
	if *flagTestConfigFile != "" {
		configFile = flagTestConfigFile
	}

	if *flagHelp || *configFile == "" {
		printFlags()
		return // ### return, nothing to do ###
	}

	// Read config

	config, err := core.ReadConfig(*configFile)
	if err != nil {
		fmt.Printf("Config: %s\n", err.Error())
		return // ### return, config error ###
	} else if *flagTestConfigFile != "" {
		fmt.Printf("Config: %s parsed as ok.\n", *configFile)
		newMultiplexer(config, false)
		return // ### return, only test config ###
	}

	// Configure runtime

	if *flagPidFile != "" {
		ioutil.WriteFile(*flagPidFile, []byte(strconv.Itoa(os.Getpid())), 0644)
	}

	if *flagNumCPU == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		runtime.GOMAXPROCS(*flagNumCPU)
	}

	// Profiling flags

	if *flagCPUProfile != "" {
		if file, err := os.Create(*flagCPUProfile); err != nil {
			panic(err)
		} else {
			defer file.Close()
			pprof.StartCPUProfile(file)
			defer pprof.StopCPUProfile()
		}
	}

	if *flagMemProfile != "" {
		defer dumpMemoryProfile()
	}

	// Metrics server start

	if *flagMetricsPort != 0 {
		server := shared.NewMetricServer()
		go server.Start(*flagMetricsPort)
		defer server.Stop()
	}

	// Start the multiplexer

	plex := newMultiplexer(config, *flagProfile)
	plex.run()
}
<commit_msg>bumped dev version<commit_after>// Copyright 2015-2016 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	_ "github.com/trivago/gollum/consumer"
	_ "github.com/trivago/gollum/contrib"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	_ "github.com/trivago/gollum/filter"
	_ "github.com/trivago/gollum/format"
	_ "github.com/trivago/gollum/producer"
	"github.com/trivago/gollum/shared"
	_ "github.com/trivago/gollum/stream"
	"io/ioutil"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
)

const (
	gollumMajorVer = 0
	gollumMinorVer = 4
	gollumPatchVer = 3
	gollumDevVer   = 6
)

func dumpMemoryProfile() {
	if file, err := os.Create(*flagMemProfile); err != nil {
		panic(err)
	} else {
		defer file.Close()
		pprof.WriteHeapProfile(file)
	}
}

func main() {
	parseFlags()
	Log.SetVerbosity(Log.Verbosity(*flagLoglevel))

	contribModules := shared.TypeRegistry.GetRegistered("contrib")
	modules := ""
	for _, typeName := range contribModules {
		modules += " + " + typeName[shared.IndexN(typeName, ".", 1)+1:] + "\n"
	}

	if *flagVersion {
		if gollumDevVer > 0 {
			fmt.Printf("Gollum v%d.%d.%d.%d dev\n%s", gollumMajorVer, gollumMinorVer, gollumPatchVer, gollumDevVer, modules)
		} else {
			fmt.Printf("Gollum v%d.%d.%d\n%s", gollumMajorVer, gollumMinorVer, gollumPatchVer, modules)
		}
		fmt.Println(runtime.Version())
		return // ### return, version only ###
	}

	configFile := flagConfigFile
	if *flagTestConfigFile != "" {
		configFile = flagTestConfigFile
	}

	if *flagHelp || *configFile == "" {
		printFlags()
		return // ### return, nothing to do ###
	}

	// Read config

	config, err := core.ReadConfig(*configFile)
	if err != nil {
		fmt.Printf("Config: %s\n", err.Error())
		return // ### return, config error ###
	} else if *flagTestConfigFile != "" {
		fmt.Printf("Config: %s parsed as ok.\n", *configFile)
		newMultiplexer(config, false)
		return // ### return, only test config ###
	}

	// Configure runtime

	if *flagPidFile != "" {
		ioutil.WriteFile(*flagPidFile, []byte(strconv.Itoa(os.Getpid())), 0644)
	}

	if *flagNumCPU == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	} else {
		runtime.GOMAXPROCS(*flagNumCPU)
	}

	// Profiling flags

	if *flagCPUProfile != "" {
		if file, err := os.Create(*flagCPUProfile); err != nil {
			panic(err)
		} else {
			defer file.Close()
			pprof.StartCPUProfile(file)
			defer pprof.StopCPUProfile()
		}
	}

	if *flagMemProfile != "" {
		defer dumpMemoryProfile()
	}

	// Metrics server start

	if *flagMetricsPort != 0 {
		server := shared.NewMetricServer()
		go server.Start(*flagMetricsPort)
		defer server.Stop()
	}

	// Start the multiplexer

	plex := newMultiplexer(config, *flagProfile)
	plex.run()
}
<|endoftext|>


<commit_before><commit_msg>Improve a usage message for collectors flag<commit_after><|endoftext|>


<commit_before><commit_msg>for gocd set default logger to consolewriter without timestamp<commit_after><|endoftext|>


<commit_before><commit_msg>move api to query + add exec query<commit_after><|endoftext|>


<commit_before><commit_msg>Pass NotifyChannel to TrelloConfig<commit_after><|endoftext|>


<commit_before><commit_msg>remove commented regex pattern<commit_after><|endoftext|>


<commit_before><commit_msg>Split router initialization<commit_after><|endoftext|>


<commit_before><commit_msg>Inline use of cloudflare URL instead of using a variable<commit_after><|endoftext|>


<commit_before><commit_msg>Added some docs<commit_after><|endoftext|>


<commit_before><commit_msg>Stutus --> Status<commit_after><|endoftext|>


<commit_before><commit_msg>Restrict /bq redirect to admin only<commit_after><|endoftext|>


<commit_before><commit_msg>Added small correct<commit_after><|endoftext|>


<commit_before><commit_msg>fixing buffer issue<commit_after><|endoftext|>


<commit_before><commit_msg>Add default split charter<commit_after><|endoftext|>


<commit_before><commit_msg>Added  and  parameters for ibsearch. Added purge command<commit_after><|endoftext|>


<commit_before><commit_msg>Reactivate user-service for testing<commit_after><|endoftext|>


<commit_before><commit_msg>Adding insecureSkipVerify flag<commit_after><|endoftext|>


<commit_before><commit_msg>Check we actually got points back from the whisper file<commit_after><|endoftext|>


<commit_before><commit_msg>Added X-Forwarded-For header<commit_after><|endoftext|>


<commit_before>package main

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

	"github.com/gorilla/handlers"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"gopkg.in/mgo.v2"
)

type ErrorJson struct {
	Error string
}

var AddDeviceMissingDeviceIdError = ErrorJson{"POST to /device must be a JSON with a DeviceId property."}

func hello(context web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Herro, %s!", context.URLParams["name"])
}

func main() {
	err := SetupRoutes("SidewinderMain")
	if err == nil {
		goji.Serve()
	} else {
		fmt.Errorf("Error on launch:\n%v", err.Error())
		os.Exit(1)
	}
}

func SetupRoutes(mongoDB string) error {
	sidewinderDirector, err := NewSidewinderDirector(mongoDB)
	if err != nil {
		return err
	}

	goji.Get("/hello/:name", hello)
	goji.Get("/store/info", sidewinderDirector.DatastoreInfo)
	goji.Handle("/devices", handlers.MethodHandler{
		"POST": catchErr(sidewinderDirector.postDevice),
	})
	goji.Options("/devices/:id", func(context web.C, writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("Allow", "DELETE")
		writer.WriteHeader(200)
	})
	goji.Delete("/devices/:id", func(context web.C, writer http.ResponseWriter, request *http.Request) {
		deviceCollection := sidewinderDirector.Store().DB().C("devices")
		deviceId := context.URLParams["id"]

		var result DeviceDocument

		if err := deviceCollection.FindId(deviceId).One(&result); err != nil {
			writer.WriteHeader(500)
			fmt.Fprintln(writer, err.Error())
			return
		}

		if err := deviceCollection.RemoveId(deviceId); err != nil {
			writer.WriteHeader(500)
			fmt.Fprintln(writer, err.Error())
			return
		}

		writeJson(200, result, writer)
	})
	return nil
}

func NewSidewinderDirector(mongoDB string) (*SidewinderDirector, error) {
	session, err := mgo.Dial("mongo,localhost")
	if err != nil {
		return nil, err
	}

	return &SidewinderDirector{mongoDB, session}, nil
}

type Handler func(writer http.ResponseWriter, request *http.Request) error

func catchErr(handler Handler) http.Handler {
	return web.HandlerFunc(func(context web.C, writer http.ResponseWriter, request *http.Request) {
		if err := handler(writer, request); err != nil {
			writeJson(500, ErrorJson{err.Error()}, writer)
		}
	})
}

func (self *SidewinderDirector) postDevice(writer http.ResponseWriter, request *http.Request) error {
	if sentJSON := decodeDeviceDocument(request); sentJSON != nil {
		if recordWasCreated, err := self.Store().AddDevice(sentJSON.DeviceId); err != nil {
			return err
		} else if recordWasCreated {
			return writeJson(201, sentJSON, writer)
		} else {
			return writeJson(200, sentJSON, writer)
		}
	}
	return writeJson(400, AddDeviceMissingDeviceIdError, writer)
}

func decodeDeviceDocument(request *http.Request) *DeviceDocument {
	var sentJSON DeviceDocument
	if decodeErr := json.NewDecoder(request.Body).Decode(&sentJSON); decodeErr == nil && sentJSON.DeviceId != "" {
		return &sentJSON
	} else {
		return nil
	}
}

func writeJson(code int, value interface{}, writer http.ResponseWriter) error {
	writer.WriteHeader(code)
	writer.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(writer).Encode(value)
}
<commit_msg>Another minor refactor. Cleaner, cleaner... CLEANER!<commit_after>package main

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

	"github.com/gorilla/handlers"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"gopkg.in/mgo.v2"
)

type ErrorJson struct {
	Error string
}

var AddDeviceMissingDeviceIdError = ErrorJson{"POST to /device must be a JSON with a DeviceId property."}

func hello(context web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Herro, %s!", context.URLParams["name"])
}

func main() {
	err := SetupRoutes("SidewinderMain")
	if err == nil {
		goji.Serve()
	} else {
		fmt.Errorf("Error on launch:\n%v", err.Error())
		os.Exit(1)
	}
}

func SetupRoutes(mongoDB string) error {
	sidewinderDirector, err := NewSidewinderDirector(mongoDB)
	if err != nil {
		return err
	}

	goji.Get("/hello/:name", hello)
	goji.Get("/store/info", sidewinderDirector.DatastoreInfo)
	goji.Handle("/devices", handlers.MethodHandler{
		"POST": catchErr(sidewinderDirector.postDevice),
	})
	goji.Options("/devices/:id", func(context web.C, writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("Allow", "DELETE")
		writer.WriteHeader(200)
	})
	goji.Delete("/devices/:id", func(context web.C, writer http.ResponseWriter, request *http.Request) {
		deviceCollection := sidewinderDirector.Store().DB().C("devices")
		deviceId := context.URLParams["id"]

		var result DeviceDocument

		if err := deviceCollection.FindId(deviceId).One(&result); err != nil {
			writer.WriteHeader(500)
			fmt.Fprintln(writer, err.Error())
			return
		}

		if err := deviceCollection.RemoveId(deviceId); err != nil {
			writer.WriteHeader(500)
			fmt.Fprintln(writer, err.Error())
			return
		}

		writeJson(200, result, writer)
	})
	return nil
}

func NewSidewinderDirector(mongoDB string) (*SidewinderDirector, error) {
	session, err := mgo.Dial("mongo,localhost")
	if err != nil {
		return nil, err
	}

	return &SidewinderDirector{mongoDB, session}, nil
}

type Handler func(writer http.ResponseWriter, request *http.Request) error

func catchErr(handler Handler) http.Handler {
	return web.HandlerFunc(func(context web.C, writer http.ResponseWriter, request *http.Request) {
		if err := handler(writer, request); err != nil {
			writeJson(500, ErrorJson{err.Error()}, writer)
		}
	})
}

func (self *SidewinderDirector) postDevice(writer http.ResponseWriter, request *http.Request) error {
	sentJSON := decodeDeviceDocument(request)
	if sentJSON == nil {
		return writeJson(400, AddDeviceMissingDeviceIdError, writer)
	} else {
		recordWasCreated, err := self.Store().AddDevice(sentJSON.DeviceId)
		if err != nil {
			return err
		} else if recordWasCreated {
			return writeJson(201, sentJSON, writer)
		} else {
			return writeJson(200, sentJSON, writer)
		}
	}
}

func decodeDeviceDocument(request *http.Request) *DeviceDocument {
	var sentJSON DeviceDocument
	if decodeErr := json.NewDecoder(request.Body).Decode(&sentJSON); decodeErr == nil && sentJSON.DeviceId != "" {
		return &sentJSON
	} else {
		return nil
	}
}

func writeJson(code int, value interface{}, writer http.ResponseWriter) error {
	writer.WriteHeader(code)
	writer.Header().Set("Content-Type", "application/json")
	return json.NewEncoder(writer).Encode(value)
}
<|endoftext|>


<commit_before><commit_msg>Fix url variable location scope<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed bug where changes weren't displayed correctly.<commit_after><|endoftext|>


<commit_before><commit_msg>Switch from flag to kingpin<commit_after><|endoftext|>


<commit_before>package tnt

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestConnect(t *testing.T) {
	assert := assert.New(t)

	box, err := NewBox("", nil)
	assert.NoError(err)
	defer box.Close()

	conn, err := Connect(fmt.Sprintf("127.0.0.1:%d", box.Port), nil)
	if !assert.NoError(err) {
		return
	}
	defer conn.Close()

}
<commit_msg>Connect test fix<commit_after>package tnt

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestConnect(t *testing.T) {
	assert := assert.New(t)

	box, err := NewBox("", nil)
	assert.NoError(err)
	defer box.Close()

	conn, err := Connect(fmt.Sprintf("127.0.0.1:%d", box.Port), nil)
	if !assert.NoError(err) {
		return
	}
	defer conn.Close()

	assert.Contains(string(conn.Greeting.Version), "Tarantool")
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"github.com/go-sql-driver/mysql"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sort"
)

type Note struct {
	NoteId int64
	UserId int64
	Text string
	Link sql.NullString
	LinkType sql.NullString
	Date mysql.NullTime
	Edited bool
	Deleted bool
	GroupId int64
}

// interface for sorting strings by length
type ByLength []string
func (s ByLength) Len() int {
    return len(s)
}
func (s ByLength) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
    return len(s[i]) < len(s[j])
}

func parseNote(text string) (note *Note) {
	note = new(Note)
	note.Text = text

	// TODO: find @mentions
	// atrx := MustCompile("@([[:alnum:]]{1,16})@((?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z]))")
	// TODO: to be shortened, @mentions must be users that exist and are not blocking this user
	// TODO: defer that process so we can return to the user right away and return 202 Accepted

	// TODO: we will replace @mentions with @<number>
	// TODO: find the highest @<number> that doesn't collide with existing text
	// clients will substitute mentions for highest @<numbers> in reverse order

	// find all things that look like links
	linkrx := regexp.MustCompile("\\b(?i:https?|ftp)://\\S+")
	matches := linkrx.FindAllString(note.Text, -1)
	//fmt.Println(matches)

	if matches != nil {
		// find the longest link
		sort.Sort(ByLength(matches))
		note.Link.String = matches[len(matches) - 1]
		note.Link.Valid = true

		// ‡<number> indicates location to insert link
		dagIdx := 0
		// if for some strange reason someone actually typed that, we search for the highest non-colliding index
		dagrx := regexp.MustCompile("‡\\d+")
		daggers := dagrx.FindAllString(note.Text, 0)
		if daggers != nil {
			for _, dagger := range daggers {
				d2, _ := strconv.Atoi(dagger[1:])
				if d2 >= dagIdx {
					dagIdx = d2 + 1
				}
			}
		}

		// replace the link with our symbol
		// clients can later replace ‡<highest number> with the link
		dagger := fmt.Sprintf("‡%d", dagIdx)
		note.Text = strings.Replace(note.Text, note.Link.String, dagger, 1)
	}

	if len(note.Text) > 140 || len(note.Text) == 0 {
		// TODO: return error?
		return nil
	}
	return note
}

func ListNotesHandler(rw http.ResponseWriter, r *http.Request) {
}

func PostNoteHandler(rw http.ResponseWriter, r *http.Request) {
	// TODO: we should make an auth middleware, once I can wrap my head around that
	token, err := FetchToken(db, r)
	if err != nil {
		fmt.Println(err)
		sendError(rw, http.StatusInternalServerError, err.Error())
		return
	}
	if token == nil {
		fmt.Println(err)
		sendError(rw, http.StatusUnauthorized, "Unauthorized")
		return
	}

	r.ParseForm()

	noteText := r.PostFormValue("note")
	note := parseNote(noteText)

	if note == nil {
		sendError(rw, http.StatusBadRequest, "Bad Request")
		return
	}

	// TODO: group
	// TODO: defer processing mentions
	// TODO: save to db

	sendData(rw, http.StatusCreated, note)
}

func GetNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

func PutNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

func DeleteNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

<commit_msg>save notes to the db<commit_after>package main

import (
	"database/sql"
	"fmt"
	"github.com/go-sql-driver/mysql"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sort"
)

type Note struct {
	NoteId int64
	UserId int64
	Text string
	Link sql.NullString
	LinkType sql.NullString
	Date mysql.NullTime
	Edited bool
	Deleted bool
	GroupId int64
}

// interface for sorting strings by length
type ByLength []string
func (s ByLength) Len() int {
    return len(s)
}
func (s ByLength) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
    return len(s[i]) < len(s[j])
}

func parseNote(text string) (note *Note) {
	note = new(Note)
	note.Text = text

	// TODO: find @mentions
	// atrx := MustCompile("@([[:alnum:]]{1,16})@((?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z]))")
	// TODO: to be shortened, @mentions must be users that exist and are not blocking this user
	// TODO: defer that process so we can return to the user right away and return 202 Accepted

	// TODO: we will replace @mentions with @<number>
	// TODO: find the highest @<number> that doesn't collide with existing text
	// clients will substitute mentions for highest @<numbers> in reverse order

	// find all things that look like links
	linkrx := regexp.MustCompile("\\b(?i:https?|ftp)://\\S+")
	matches := linkrx.FindAllString(note.Text, -1)
	//fmt.Println(matches)

	if matches != nil {
		// find the longest link
		sort.Sort(ByLength(matches))
		note.Link.String = matches[len(matches) - 1]
		note.Link.Valid = true

		// ‡<number> indicates location to insert link
		dagIdx := 0
		// if for some strange reason someone actually typed that, we search for the highest non-colliding index
		dagrx := regexp.MustCompile("‡\\d+")
		daggers := dagrx.FindAllString(note.Text, 0)
		if daggers != nil {
			for _, dagger := range daggers {
				d2, _ := strconv.Atoi(dagger[1:])
				if d2 >= dagIdx {
					dagIdx = d2 + 1
				}
			}
		}

		// replace the link with our symbol
		// clients can later replace ‡<highest number> with the link
		dagger := fmt.Sprintf("‡%d", dagIdx)
		note.Text = strings.Replace(note.Text, note.Link.String, dagger, 1)
	}

	if len(note.Text) > 140 || len(note.Text) == 0 {
		// TODO: return error?
		return nil
	}
	return note
}

func ListNotesHandler(rw http.ResponseWriter, r *http.Request) {
}

func PostNoteHandler(rw http.ResponseWriter, r *http.Request) {
	// TODO: we should make an auth middleware, once I can wrap my head around that
	token, err := FetchToken(db, r)
	if err != nil {
		fmt.Println(err)
		sendError(rw, http.StatusInternalServerError, err.Error())
		return
	}
	if token == nil {
		fmt.Println(err)
		sendError(rw, http.StatusUnauthorized, "Unauthorized")
		return
	}

	r.ParseForm()

	noteText := r.PostFormValue("note")
	note := parseNote(noteText)

	if note == nil {
		sendError(rw, http.StatusBadRequest, "Bad Request")
		return
	}

	// TODO: groups
	group := r.PostFormValue("group")
	if len(group) > 0 {
		groupId, _ := strconv.Atoi(group)
		note.GroupId = int64(groupId)
	}

	// TODO: defer processing mentions

	note.UserId = token.UserId
	result, err := db.NamedExec("INSERT INTO `Note` (`UserId`, `Text`, `Link`, `LinkType`, `GroupId`) " +
			"VALUES (:UserId, :Text, :Link, :LinkType, :GroupId)", note)
	if err != nil {
		fmt.Println(err)
		sendError(rw, http.StatusInternalServerError, err.Error())
		return
	}
	note.NoteId, err = result.LastInsertId()
	if err != nil {
		fmt.Println(err)
	}

	sendData(rw, http.StatusCreated, note)
}

func GetNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

func PutNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

func DeleteNoteHandler(rw http.ResponseWriter, r *http.Request) {
}

<|endoftext|>


<commit_before>package godate

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

// NullDate represents a date that may be null.
type NullDate struct {
	Date  Date
	Valid bool // Valid is true if Int64 is not NULL
}

// Scan implements the Scanner interface.
func (nd *NullDate) Scan(value interface{}) error {
	var err error
	switch x := value.(type) {
	case time.Time:
		nd.Date = Date{x}
	case nil:
		nd.Valid = false
		return nil
	default:
		err = fmt.Errorf("godate: cannot scan type %T into godate.NullDate: %v", value, value)
	}
	nd.Valid = err == nil
	return err
}

// Value implements the driver Valuer interface.
func (nd NullDate) Value() (driver.Value, error) {
	if !nd.Valid {
		return nil, nil
	}
	return nd.Date, nil
}

// NewNullDate creates a new Date.
func NewNullDate(d Date, valid bool) NullDate {
	return NullDate{
		Date:  d,
		Valid: valid,
	}
}

// NullDateFrom creates a new Time that will always be valid.
func NullDateFrom(d Date) NullDate {
	return NewNullDate(d, true)
}

// NullDateFromPtr creates a new Date that will be null if t is nil.
func NullDateFromPtr(d *Date) NullDate {
	if d == nil {
		return NewNullDate(Date{}, false)
	}
	return NewNullDate(*d, true)
}

// MarshalJSON implements json.Marshaler.
// It will encode null if this date is null.
func (nd NullDate) MarshalJSON() ([]byte, error) {
	if !nd.Valid {
		return []byte("null"), nil
	}
	return nd.Date.MarshalJSON()
}

// UnmarshalJSON implements json.Unmarshaler.
func (nd *NullDate) UnmarshalJSON(data []byte) error {
	var err error
	var v interface{}
	if err = json.Unmarshal(data, &v); err != nil {
		return err
	}
	switch v.(type) {
	case string:
		err = nd.Date.UnmarshalJSON(data)
	case nil:
		nd.Valid = false
		return nil
	default:
		err = fmt.Errorf("godate: cannot unmarshal %v into Go value of type godate.NullDate", reflect.TypeOf(v).Name())
	}
	nd.Valid = err == nil
	return err
}

// SetValid changes this Date's value and sets it to be non-null.
func (nd *NullDate) SetValid(v Date) {
	nd.Date = v
	nd.Valid = true
}

// Ptr returns a pointer to this Date's value, or a nil pointer if this Date is null.
func (nd NullDate) Ptr() *Date {
	if !nd.Valid {
		return nil
	}
	return &nd.Date
}
<commit_msg>Fix return value of Scan method of NullDate<commit_after>package godate

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

// NullDate represents a date that may be null.
type NullDate struct {
	Date  Date
	Valid bool // Valid is true if Int64 is not NULL
}

// Scan implements the Scanner interface.
func (nd *NullDate) Scan(value interface{}) error {
	var err error
	switch x := value.(type) {
	case time.Time:
		nd.Date = Date{x}
	case nil:
		nd.Valid = false
		return nil
	default:
		err = fmt.Errorf("godate: cannot scan type %T into godate.NullDate: %v", value, value)
	}
	nd.Valid = err == nil
	return err
}

// Value implements the driver Valuer interface.
func (nd NullDate) Value() (driver.Value, error) {
	if !nd.Valid {
		return nil, nil
	}
	return nd.Date.String(), nil
}

// NewNullDate creates a new Date.
func NewNullDate(d Date, valid bool) NullDate {
	return NullDate{
		Date:  d,
		Valid: valid,
	}
}

// NullDateFrom creates a new Time that will always be valid.
func NullDateFrom(d Date) NullDate {
	return NewNullDate(d, true)
}

// NullDateFromPtr creates a new Date that will be null if t is nil.
func NullDateFromPtr(d *Date) NullDate {
	if d == nil {
		return NewNullDate(Date{}, false)
	}
	return NewNullDate(*d, true)
}

// MarshalJSON implements json.Marshaler.
// It will encode null if this date is null.
func (nd NullDate) MarshalJSON() ([]byte, error) {
	if !nd.Valid {
		return []byte("null"), nil
	}
	return nd.Date.MarshalJSON()
}

// UnmarshalJSON implements json.Unmarshaler.
func (nd *NullDate) UnmarshalJSON(data []byte) error {
	var err error
	var v interface{}
	if err = json.Unmarshal(data, &v); err != nil {
		return err
	}
	switch v.(type) {
	case string:
		err = nd.Date.UnmarshalJSON(data)
	case nil:
		nd.Valid = false
		return nil
	default:
		err = fmt.Errorf("godate: cannot unmarshal %v into Go value of type godate.NullDate", reflect.TypeOf(v).Name())
	}
	nd.Valid = err == nil
	return err
}

// SetValid changes this Date's value and sets it to be non-null.
func (nd *NullDate) SetValid(v Date) {
	nd.Date = v
	nd.Valid = true
}

// Ptr returns a pointer to this Date's value, or a nil pointer if this Date is null.
func (nd NullDate) Ptr() *Date {
	if !nd.Valid {
		return nil
	}
	return &nd.Date
}
<|endoftext|>


<commit_before>package genericsite

import (
	"time"

	"github.com/drbawb/mustache"
	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type ContentPage struct {
	GeneratedCSSurl          string
	ExtraCSSurls             []string
	JqueryJSurl              string
	Faviconurl               string
	BgImageURL               string
	StretchBackground        bool
	Title                    string
	Subtitle                 string
	ContentTitle             string
	ContentHTML              string
	HeaderJS                 string
	ContentJS                string
	SearchButtonText         string
	SearchURL                string
	FooterText               string
	BackgroundTextureURL     string
	DarkBackgroundTextureURL string
	FooterTextColor          string
	FooterColor              string
	UserState                *UserState
	RoundedLook              bool
	Url                      string
	ColorScheme              *ColorScheme
}

// Content page generator
type CPgen (func(userState *UserState) *ContentPage)

// A collection of ContentPages
type PageCollection []ContentPage

// Every input from the user must be intitially stored in a UserInput variable, not in a string!
// This is just to be aware of which data one should be careful with, and to keep it clean.
type UserInput string

type ColorScheme struct {
	Darkgray           string
	Nicecolor          string
	Menu_link          string
	Menu_hover         string
	Menu_active        string
	Default_background string
	TitleText          string
}

type BaseCP func(state *UserState) *ContentPage

type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator

// The default settings
// Do not publish this page directly, but use it as a basis for the other pages
func DefaultCP(userState *UserState) *ContentPage {
	var cp ContentPage
	cp.GeneratedCSSurl = "/css/style.css"
	cp.ExtraCSSurls = []string{"/css/menu.css"}
	// TODO: fallback to local jquery.min.js, google how
	cp.JqueryJSurl = "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" // "/js/jquery-1.9.1.js"
	cp.Faviconurl = "/img/favicon.ico"
	cp.ContentTitle = "NOP"
	cp.ContentHTML = "NOP NOP NOP"
	cp.ContentJS = ""
	cp.HeaderJS = ""
	cp.SearchButtonText = "Search"
	cp.SearchURL = "/search"

	// http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2010/04/gray-texture.jpg
	// TODO: Draw these two backgroundimages with a canvas instead
	cp.BackgroundTextureURL = "" // "/img/gray.jpg"
	// http://turbo.designwoop.com/uploads/2012/03/16_free_subtle_textures_subtle_dark_vertical.jpg
	cp.DarkBackgroundTextureURL = "/img/darkgray.jpg"

	cp.FooterColor = "black"
	cp.FooterTextColor = "#303040"

	cp.FooterText = "NOP"

	cp.UserState = userState
	cp.RoundedLook = false

	cp.Url = "/" // To be filled in when published

	// The default color scheme
	var cs ColorScheme
	cs.Darkgray = "#202020"
	cs.Nicecolor = "#5080D0"   // nice blue
	cs.Menu_link = "#c0c0c0"   // light gray
	cs.Menu_hover = "#efefe0"  // light gray, somewhat yellow
	cs.Menu_active = "#ffffff" // white
	cs.Default_background = "#000030"
	cs.TitleText = "#303030"

	cp.ColorScheme = &cs

	return &cp
}

func genericPageBuilder(cp *ContentPage) *Page {
	// TODO: Record the time from one step out, because content may be generated and inserted into this generated conten
	startTime := time.Now()

	page := NewHTML5Page(cp.Title + " " + cp.Subtitle)

	page.LinkToCSS(cp.GeneratedCSSurl)
	for _, cssurl := range cp.ExtraCSSurls {
		page.LinkToCSS(cssurl)
	}
	page.LinkToJS(cp.JqueryJSurl)
	page.LinkToFavicon(cp.Faviconurl)

	AddHeader(page, cp.HeaderJS)
	AddGoogleFonts(page, []string{"Armata"})
	AddBodyStyle(page, cp.BgImageURL, cp.StretchBackground)
	AddTopBox(page, cp.Title, cp.Subtitle, cp.SearchURL, cp.SearchButtonText, cp.BackgroundTextureURL, cp.RoundedLook, cp.ColorScheme)

	// TODO: Move the menubox into the TopBox

	AddMenuBox(page, cp.DarkBackgroundTextureURL)

	AddContent(page, cp.ContentTitle, cp.ContentHTML+DocumentReadyJS(cp.ContentJS))

	elapsed := time.Since(startTime)
	AddFooter(page, cp.FooterText, cp.FooterTextColor, cp.FooterColor, elapsed)

	return page
}

// Publish a list of ContentPaages, a colorscheme and template content
func PublishCPs(userState *UserState, pc PageCollection, cs *ColorScheme, tvgf TemplateValueGeneratorFactory, cssurl string) {
	// For each content page in the page collection
	for _, cp := range pc {
		// TODO: different css urls for all of these?
		cp.Pub(userState, cp.Url, cssurl, cs, tvgf(userState))
	}
}

// Some Engines like Admin must be served separately
// JQuery is at 1.9.1 at the time of writing
func ServeSite(basecp BaseCP, userState *UserState, cps PageCollection, tvgf TemplateValueGeneratorFactory, jqueryversion string) {
	cs := basecp(userState).ColorScheme
	PublishCPs(userState, cps, cs, tvgf, "/css/menu.css")

	// TODO: Add fallback to this local version
	Publish("/js/jquery-"+jqueryversion+".js", "static/js/jquery-"+jqueryversion+".js", true)

	// TODO: Generate these
	Publish("/robots.txt", "static/various/robots.txt", false)
	Publish("/sitemap_index.xml", "static/various/sitemap_index.xml", false)
}

// CSS for the menu, and a bit more
func GenerateMenuCSS(state *UserState, stretchBackground bool, cs *ColorScheme) SimpleContextHandle {
	return func(ctx *web.Context) string {
		ctx.ContentType("css")
		// one of the extra css files that are loaded after the main style
		retval := `
a {
  text-decoration: none;
  color: #303030;
  font-weight: regular;
}
a:link {color:` + cs.Menu_link + `;}
a:visited {color:` + cs.Menu_link + `;}
a:hover {color:` + cs.Menu_hover + `;}
a:active {color:` + cs.Menu_active + `;}
.menuEntry {
	display: inline;
}
.menuList {
	list-style-type: none;
	float: left;
	margin: 0;
}
.separator {
	display: inline;
	color: #a0a0a0;
}
`
		// The load order of background-color, background-size and background-image
		// is actually significant in some browsers! Do not reorder lightly.
		if stretchBackground {
			retval = "body {\nbackground-color: " + cs.Default_background + ";\nbackground-size: cover;\n}\n" + retval
		} else {
			retval = "body {\nbackground-color: " + cs.Default_background + ";\n}\n" + retval
		}
		retval += ".titletext { display: inline; }"
		return retval
	}
}

// Make an html and css page available
func (cp *ContentPage) Pub(userState *UserState, url, cssurl string, cs *ColorScheme, tvg TemplateValueGenerator) {
	genericpage := genericPageBuilder(cp)
	web.Get(url, GenerateHTMLwithTemplate(genericpage, tvg))
	web.Get(cp.GeneratedCSSurl, GenerateCSS(genericpage))
	web.Get(cssurl, GenerateMenuCSS(userState, cp.StretchBackground, cs))
}

// TODO: Write a function for rendering a CowboyTag inside a Page by the use of template {{{placeholders}}

// Render a page by inserting data at the {{{placeholders}}} for both html and css
func RenderPage(page *Page, templateContents map[string]string) (string, string) {
	// Note that the whitespace formatting of the generated html matter for the menu layout!
	return mustache.Render(page.String(), templateContents), mustache.Render(page.GetCSS(), templateContents)
}

// Wrap a lonely string in an entire webpage
func (cp *ContentPage) Surround(s string, templateContents map[string]string) (string, string) {
	cp.ContentHTML = s
	archpage := genericPageBuilder(cp)
	return RenderPage(archpage, templateContents)
}

// Uses a given WebHandle as the contents for the the ContentPage contents
func (cp *ContentPage) WrapWebHandle(wh WebHandle, tvg TemplateValueGenerator) WebHandle {
	return func(ctx *web.Context, val string) string {
		html, css := cp.Surround(wh(ctx, val), tvg(ctx))
		web.Get(cp.GeneratedCSSurl, css)
		return html
	}
}

// Uses a given SimpleContextHandle as the contents for the the ContentPage contents
func (cp *ContentPage) WrapSimpleContextHandle(sch SimpleContextHandle, tvg TemplateValueGenerator) SimpleContextHandle {
	return func(ctx *web.Context) string {
		html, css := cp.Surround(sch(ctx), tvg(ctx))
		web.Get(cp.GeneratedCSSurl, css)
		return html
	}
}
<commit_msg>Changed the backup jquery url<commit_after>package genericsite

import (
	"time"

	"github.com/drbawb/mustache"
	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type ContentPage struct {
	GeneratedCSSurl          string
	ExtraCSSurls             []string
	JqueryJSurl              string
	Faviconurl               string
	BgImageURL               string
	StretchBackground        bool
	Title                    string
	Subtitle                 string
	ContentTitle             string
	ContentHTML              string
	HeaderJS                 string
	ContentJS                string
	SearchButtonText         string
	SearchURL                string
	FooterText               string
	BackgroundTextureURL     string
	DarkBackgroundTextureURL string
	FooterTextColor          string
	FooterColor              string
	UserState                *UserState
	RoundedLook              bool
	Url                      string
	ColorScheme              *ColorScheme
}

// Content page generator
type CPgen (func(userState *UserState) *ContentPage)

// A collection of ContentPages
type PageCollection []ContentPage

// Every input from the user must be intitially stored in a UserInput variable, not in a string!
// This is just to be aware of which data one should be careful with, and to keep it clean.
type UserInput string

type ColorScheme struct {
	Darkgray           string
	Nicecolor          string
	Menu_link          string
	Menu_hover         string
	Menu_active        string
	Default_background string
	TitleText          string
}

type BaseCP func(state *UserState) *ContentPage

type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator

// The default settings
// Do not publish this page directly, but use it as a basis for the other pages
func DefaultCP(userState *UserState) *ContentPage {
	var cp ContentPage
	cp.GeneratedCSSurl = "/css/style.css"
	cp.ExtraCSSurls = []string{"/css/menu.css"}
	// TODO: fallback to local jquery.min.js, google how
	cp.JqueryJSurl = "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js" // "/js/jquery-2.0.0.js"
	cp.Faviconurl = "/img/favicon.ico"
	cp.ContentTitle = "NOP"
	cp.ContentHTML = "NOP NOP NOP"
	cp.ContentJS = ""
	cp.HeaderJS = ""
	cp.SearchButtonText = "Search"
	cp.SearchURL = "/search"

	// http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2010/04/gray-texture.jpg
	// TODO: Draw these two backgroundimages with a canvas instead
	cp.BackgroundTextureURL = "" // "/img/gray.jpg"
	// http://turbo.designwoop.com/uploads/2012/03/16_free_subtle_textures_subtle_dark_vertical.jpg
	cp.DarkBackgroundTextureURL = "/img/darkgray.jpg"

	cp.FooterColor = "black"
	cp.FooterTextColor = "#303040"

	cp.FooterText = "NOP"

	cp.UserState = userState
	cp.RoundedLook = false

	cp.Url = "/" // To be filled in when published

	// The default color scheme
	var cs ColorScheme
	cs.Darkgray = "#202020"
	cs.Nicecolor = "#5080D0"   // nice blue
	cs.Menu_link = "#c0c0c0"   // light gray
	cs.Menu_hover = "#efefe0"  // light gray, somewhat yellow
	cs.Menu_active = "#ffffff" // white
	cs.Default_background = "#000030"
	cs.TitleText = "#303030"

	cp.ColorScheme = &cs

	return &cp
}

func genericPageBuilder(cp *ContentPage) *Page {
	// TODO: Record the time from one step out, because content may be generated and inserted into this generated conten
	startTime := time.Now()

	page := NewHTML5Page(cp.Title + " " + cp.Subtitle)

	page.LinkToCSS(cp.GeneratedCSSurl)
	for _, cssurl := range cp.ExtraCSSurls {
		page.LinkToCSS(cssurl)
	}
	page.LinkToJS(cp.JqueryJSurl)
	page.LinkToFavicon(cp.Faviconurl)

	AddHeader(page, cp.HeaderJS)
	AddGoogleFonts(page, []string{"Armata"})
	AddBodyStyle(page, cp.BgImageURL, cp.StretchBackground)
	AddTopBox(page, cp.Title, cp.Subtitle, cp.SearchURL, cp.SearchButtonText, cp.BackgroundTextureURL, cp.RoundedLook, cp.ColorScheme)

	// TODO: Move the menubox into the TopBox

	AddMenuBox(page, cp.DarkBackgroundTextureURL)

	AddContent(page, cp.ContentTitle, cp.ContentHTML+DocumentReadyJS(cp.ContentJS))

	elapsed := time.Since(startTime)
	AddFooter(page, cp.FooterText, cp.FooterTextColor, cp.FooterColor, elapsed)

	return page
}

// Publish a list of ContentPaages, a colorscheme and template content
func PublishCPs(userState *UserState, pc PageCollection, cs *ColorScheme, tvgf TemplateValueGeneratorFactory, cssurl string) {
	// For each content page in the page collection
	for _, cp := range pc {
		// TODO: different css urls for all of these?
		cp.Pub(userState, cp.Url, cssurl, cs, tvgf(userState))
	}
}

// Some Engines like Admin must be served separately
// jquerypath is ie "/js/jquery.2.0.0.js", will then serve the file at static/js/jquery.2.0.0.js
func ServeSite(basecp BaseCP, userState *UserState, cps PageCollection, tvgf TemplateValueGeneratorFactory, jquerypath string) {
	cs := basecp(userState).ColorScheme
	PublishCPs(userState, cps, cs, tvgf, "/css/menu.css")

	// TODO: Add fallback to this local version
	Publish(jquerypath, "static"+jquerypath, true)

	// TODO: Generate these
	Publish("/robots.txt", "static/various/robots.txt", false)
	Publish("/sitemap_index.xml", "static/various/sitemap_index.xml", false)
}

// CSS for the menu, and a bit more
func GenerateMenuCSS(state *UserState, stretchBackground bool, cs *ColorScheme) SimpleContextHandle {
	return func(ctx *web.Context) string {
		ctx.ContentType("css")
		// one of the extra css files that are loaded after the main style
		retval := `
a {
  text-decoration: none;
  color: #303030;
  font-weight: regular;
}
a:link {color:` + cs.Menu_link + `;}
a:visited {color:` + cs.Menu_link + `;}
a:hover {color:` + cs.Menu_hover + `;}
a:active {color:` + cs.Menu_active + `;}
.menuEntry {
	display: inline;
}
.menuList {
	list-style-type: none;
	float: left;
	margin: 0;
}
.separator {
	display: inline;
	color: #a0a0a0;
}
`
		// The load order of background-color, background-size and background-image
		// is actually significant in some browsers! Do not reorder lightly.
		if stretchBackground {
			retval = "body {\nbackground-color: " + cs.Default_background + ";\nbackground-size: cover;\n}\n" + retval
		} else {
			retval = "body {\nbackground-color: " + cs.Default_background + ";\n}\n" + retval
		}
		retval += ".titletext { display: inline; }"
		return retval
	}
}

// Make an html and css page available
func (cp *ContentPage) Pub(userState *UserState, url, cssurl string, cs *ColorScheme, tvg TemplateValueGenerator) {
	genericpage := genericPageBuilder(cp)
	web.Get(url, GenerateHTMLwithTemplate(genericpage, tvg))
	web.Get(cp.GeneratedCSSurl, GenerateCSS(genericpage))
	web.Get(cssurl, GenerateMenuCSS(userState, cp.StretchBackground, cs))
}

// TODO: Write a function for rendering a CowboyTag inside a Page by the use of template {{{placeholders}}

// Render a page by inserting data at the {{{placeholders}}} for both html and css
func RenderPage(page *Page, templateContents map[string]string) (string, string) {
	// Note that the whitespace formatting of the generated html matter for the menu layout!
	return mustache.Render(page.String(), templateContents), mustache.Render(page.GetCSS(), templateContents)
}

// Wrap a lonely string in an entire webpage
func (cp *ContentPage) Surround(s string, templateContents map[string]string) (string, string) {
	cp.ContentHTML = s
	archpage := genericPageBuilder(cp)
	return RenderPage(archpage, templateContents)
}

// Uses a given WebHandle as the contents for the the ContentPage contents
func (cp *ContentPage) WrapWebHandle(wh WebHandle, tvg TemplateValueGenerator) WebHandle {
	return func(ctx *web.Context, val string) string {
		html, css := cp.Surround(wh(ctx, val), tvg(ctx))
		web.Get(cp.GeneratedCSSurl, css)
		return html
	}
}

// Uses a given SimpleContextHandle as the contents for the the ContentPage contents
func (cp *ContentPage) WrapSimpleContextHandle(sch SimpleContextHandle, tvg TemplateValueGenerator) SimpleContextHandle {
	return func(ctx *web.Context) string {
		html, css := cp.Surround(sch(ctx), tvg(ctx))
		web.Get(cp.GeneratedCSSurl, css)
		return html
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
	"unicode/utf16"
	"unsafe"

	"golang.org/x/sys/windows/registry"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mackerelio/go-check-plugins/check-event-log/internal/eventlog"
)

type logOpts struct {
	Log            string `long:"log" description:"Event Names (comma separated)"`
	ID             string `long:"id" description:"Event IDs (comma separated)"`
	Type           string `long:"type" description:"Event Types (comma separated)"`
	SourcePattern  string `long:"source-pattern" description:"Event Source (regexp pattern)"`
	MessagePattern string `long:"message-pattern" description:"Message Pattern (regexp pattern)"`
	ReturnContent  bool   `short:"r" long:"return" description:"Return matched line"`
	StateDir       string `short:"s" long:"state-dir" default:"/var/mackerel-cache/check-event-log" value-name:"DIR" description:"Dir to keep state files under"`
	NoState        bool   `long:"no-state" description:"Don't use state file and read whole logs"`
	FailFirst      bool   `long:"fail-first" description:"Count errors on first seek"`
	Verbose        bool   `long:"verbose" description:"Verbose output"`

	logList        []string
	idList         []int64
	typeList       []string
	sourcePattern  *regexp.Regexp
	messagePattern *regexp.Regexp
}

func stringList(s string) []string {
	l := strings.Split(s, ",")
	if len(l) == 0 || l[0] == "" {
		return []string{}
	}
	return l
}

func (opts *logOpts) prepare() error {
	opts.logList = stringList(opts.Log)
	if len(opts.logList) == 0 || opts.logList[0] == "" {
		opts.logList = []string{"Application"}
	}
	for _, id := range stringList(opts.ID) {
		negate := int64(1)
		if id != "" && id[0] == '!' {
			negate = -1
			id = id[1:]
		}
		i, err := strconv.Atoi(id)
		if err != nil {
			return err
		}
		opts.idList = append(opts.idList, int64(i)*negate)
	}
	opts.typeList = stringList(opts.Type)

	var err error
	opts.sourcePattern, err = regexp.Compile(opts.SourcePattern)
	if err != nil {
		return err
	}
	opts.messagePattern, err = regexp.Compile(opts.MessagePattern)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Event Log"
	ckr.Exit()
}

func parseArgs(args []string) (*logOpts, error) {
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	checkSt := checkers.OK
	warnNum := int64(0)
	critNum := int64(0)
	errorOverall := ""

	for _, f := range opts.logList {
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}
	msg := fmt.Sprintf("%d warnings, %d criticals.", warnNum, critNum)
	return checkers.NewChecker(checkSt, msg)
}

func bytesToString(b []byte) (string, uint32) {
	var i int
	s := make([]uint16, len(b)/2)
	for i = range s {
		s[i] = uint16(b[i*2]) + uint16(b[(i*2)+1])<<8
		if s[i] == 0 {
			s = s[0:i]
			break
		}
	}
	return string(utf16.Decode(s)), uint32(i * 2)
}

func getResourceMessage(providerName, sourceName string, eventID uint32, argsptr uintptr) (string, error) {
	regkey := fmt.Sprintf(
		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
		providerName, sourceName)
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer key.Close()

	val, _, err := key.GetStringValue("EventMessageFile")
	if err != nil {
		return "", err
	}
	val, err = registry.ExpandString(val)
	if err != nil {
		return "", err
	}

	handle, err := eventlog.LoadLibraryEx(syscall.StringToUTF16Ptr(val), 0,
		eventlog.DONT_RESOLVE_DLL_REFERENCES|eventlog.LOAD_LIBRARY_AS_DATAFILE)
	if err != nil {
		return "", err
	}
	defer syscall.CloseHandle(handle)

	msgbuf := make([]byte, 1<<16)
	numChars, err := eventlog.FormatMessage(
		syscall.FORMAT_MESSAGE_FROM_SYSTEM|
			syscall.FORMAT_MESSAGE_FROM_HMODULE|
			syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY,
		handle,
		eventID,
		0,
		&msgbuf[0],
		uint32(len(msgbuf)),
		argsptr)
	if err != nil {
		return "", err
	}
	message, _ := bytesToString(msgbuf[:numChars*2])
	message = strings.Replace(message, "\r", "", -1)
	message = strings.TrimSuffix(message, "\n")
	return message, nil
}

func (opts *logOpts) searchLog(eventName string) (warnNum, critNum int64, errLines string, err error) {
	stateFile := getStateFile(opts.StateDir, eventName)
	recordNumber := int64(0)
	if !opts.NoState {
		s, err := getLastOffset(stateFile)
		if err != nil {
			return 0, 0, "", err
		}
		recordNumber = s
	}

	ptr := syscall.StringToUTF16Ptr(eventName)
	h, err := eventlog.OpenEventLog(nil, ptr)
	if err != nil {
		log.Fatal(err)
	}
	defer eventlog.CloseEventLog(h)

	var num, oldnum uint32

	eventlog.GetNumberOfEventLogRecords(h, &num)
	if err != nil {
		log.Fatal(err)
	}
	eventlog.GetOldestEventLogRecord(h, &oldnum)
	if err != nil {
		log.Fatal(err)
	}

	flags := eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEEK_READ

	if recordNumber > 0 && oldnum <= uint32(recordNumber) {
		if uint32(recordNumber)+1 == oldnum+num {
			return 0, 0, "", nil
		}
		recordNumber += 1
	} else {
		recordNumber = 1
	}

	size := uint32(1)
	buf := []byte{0}

	var readBytes uint32
	var nextSize uint32
	var lastNumber uint32
	for i := uint32(recordNumber); i < oldnum+num; i++ {
		err = eventlog.ReadEventLog(
			h,
			flags,
			i,
			&buf[0],
			size,
			&readBytes,
			&nextSize)
		if err != nil {
			if err != syscall.ERROR_INSUFFICIENT_BUFFER {
				break
			}
			buf = make([]byte, nextSize)
			size = nextSize
			err = eventlog.ReadEventLog(
				h,
				eventlog.EVENTLOG_FORWARDS_READ|eventlog.EVENTLOG_SEQUENTIAL_READ,
				i,
				&buf[0],
				size,
				&readBytes,
				&nextSize)
			if err != nil {
				log.Printf("eventlog.ReadEventLog: %v", err)
				break
			}
		}

		r := *(*eventlog.EVENTLOGRECORD)(unsafe.Pointer(&buf[0]))
		if opts.Verbose {
			log.Printf("RecordNumber=%v", r.RecordNumber)
			log.Printf("TimeGenerated=%v", time.Unix(int64(r.TimeGenerated), 0).String())
			log.Printf("TimeWritten=%v", time.Unix(int64(r.TimeWritten), 0).String())
			log.Printf("EventID=%v", r.EventID)
		}
		lastNumber = i

		if len(opts.idList) > 0 {
			found := false
			for _, id := range opts.idList {
				if id > 0 && uint32(id) == r.EventID {
					found = true
					break
				} else if id <= 0 && uint32(-id) != r.EventID {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		tn := eventlog.EventType(r.EventType).String()
		if opts.Verbose {
			log.Printf("EventType=%v", tn)
		}
		tn = strings.ToLower(tn)
		if len(opts.typeList) > 0 {
			found := false
			for _, typ := range opts.typeList {
				if typ == tn {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		sourceName, sourceNameOff := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{}):])
		computerName, _ := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{})+uintptr(sourceNameOff+2):])
		if opts.Verbose {
			log.Printf("SourceName=%v", sourceName)
			log.Println("ComputerName=%v", computerName)
		}

		if opts.sourcePattern != nil {
			if !opts.sourcePattern.MatchString(sourceName) {
				continue
			}
		}

		off := uint32(0)
		args := make([]*byte, uintptr(r.NumStrings)*unsafe.Sizeof((*uint16)(nil)))
		for n := 0; n < int(r.NumStrings); n++ {
			args[n] = &buf[r.StringOffset+off]
			_, boff := bytesToString(buf[r.StringOffset+off:])
			off += boff + 2
		}

		var argsptr uintptr
		if r.NumStrings > 0 {
			argsptr = uintptr(unsafe.Pointer(&args[0]))
		}
		message, err := getResourceMessage(eventName, sourceName, r.EventID, argsptr)
		if err == nil {
			if opts.Verbose {
				log.Printf("Message=%v", message)
			}
			if opts.messagePattern != nil {
				if !opts.messagePattern.MatchString(message) {
					continue
				}
			}
		}
		if opts.ReturnContent {
			errLines += sourceName + ":" + strings.Replace(message, "\n", "", -1) + "\n"
		}
		switch tn {
		case "error":
			critNum++
		case "audit failure":
			critNum++
		case "warning":
			warnNum++
		}
	}

	if !opts.NoState {
		err = writeLastOffset(stateFile, int64(lastNumber))
		if err != nil {
			log.Printf("writeLastOffset failed: %s\n", err.Error())
		}
	}

	if recordNumber == 1 && !opts.FailFirst {
		if strings.Contains(errLines, "テストエラー") {
			println("================================================")
		}
		return 0, 0, "", nil
	}
	return warnNum, critNum, errLines, nil
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string) string {
	return filepath.ToSlash(filepath.Join(stateDir, stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator))))
}

func getLastOffset(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, nil
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func writeLastOffset(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(f, []byte(fmt.Sprintf("%d", num)), 0644)
}
<commit_msg>fix call fmt.Printf<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"syscall"
	"time"
	"unicode/utf16"
	"unsafe"

	"golang.org/x/sys/windows/registry"

	"github.com/jessevdk/go-flags"
	"github.com/mackerelio/checkers"
	"github.com/mackerelio/go-check-plugins/check-event-log/internal/eventlog"
)

type logOpts struct {
	Log            string `long:"log" description:"Event Names (comma separated)"`
	ID             string `long:"id" description:"Event IDs (comma separated)"`
	Type           string `long:"type" description:"Event Types (comma separated)"`
	SourcePattern  string `long:"source-pattern" description:"Event Source (regexp pattern)"`
	MessagePattern string `long:"message-pattern" description:"Message Pattern (regexp pattern)"`
	ReturnContent  bool   `short:"r" long:"return" description:"Return matched line"`
	StateDir       string `short:"s" long:"state-dir" default:"/var/mackerel-cache/check-event-log" value-name:"DIR" description:"Dir to keep state files under"`
	NoState        bool   `long:"no-state" description:"Don't use state file and read whole logs"`
	FailFirst      bool   `long:"fail-first" description:"Count errors on first seek"`
	Verbose        bool   `long:"verbose" description:"Verbose output"`

	logList        []string
	idList         []int64
	typeList       []string
	sourcePattern  *regexp.Regexp
	messagePattern *regexp.Regexp
}

func stringList(s string) []string {
	l := strings.Split(s, ",")
	if len(l) == 0 || l[0] == "" {
		return []string{}
	}
	return l
}

func (opts *logOpts) prepare() error {
	opts.logList = stringList(opts.Log)
	if len(opts.logList) == 0 || opts.logList[0] == "" {
		opts.logList = []string{"Application"}
	}
	for _, id := range stringList(opts.ID) {
		negate := int64(1)
		if id != "" && id[0] == '!' {
			negate = -1
			id = id[1:]
		}
		i, err := strconv.Atoi(id)
		if err != nil {
			return err
		}
		opts.idList = append(opts.idList, int64(i)*negate)
	}
	opts.typeList = stringList(opts.Type)

	var err error
	opts.sourcePattern, err = regexp.Compile(opts.SourcePattern)
	if err != nil {
		return err
	}
	opts.messagePattern, err = regexp.Compile(opts.MessagePattern)
	if err != nil {
		return err
	}
	return nil
}

func main() {
	ckr := run(os.Args[1:])
	ckr.Name = "Event Log"
	ckr.Exit()
}

func parseArgs(args []string) (*logOpts, error) {
	opts := &logOpts{}
	_, err := flags.ParseArgs(opts, args)
	return opts, err
}

func run(args []string) *checkers.Checker {
	opts, err := parseArgs(args)
	if err != nil {
		os.Exit(1)
	}

	err = opts.prepare()
	if err != nil {
		return checkers.Unknown(err.Error())
	}

	checkSt := checkers.OK
	warnNum := int64(0)
	critNum := int64(0)
	errorOverall := ""

	for _, f := range opts.logList {
		w, c, errLines, err := opts.searchLog(f)
		if err != nil {
			return checkers.Unknown(err.Error())
		}
		warnNum += w
		critNum += c
		if opts.ReturnContent {
			errorOverall += errLines
		}
	}
	msg := fmt.Sprintf("%d warnings, %d criticals.", warnNum, critNum)
	return checkers.NewChecker(checkSt, msg)
}

func bytesToString(b []byte) (string, uint32) {
	var i int
	s := make([]uint16, len(b)/2)
	for i = range s {
		s[i] = uint16(b[i*2]) + uint16(b[(i*2)+1])<<8
		if s[i] == 0 {
			s = s[0:i]
			break
		}
	}
	return string(utf16.Decode(s)), uint32(i * 2)
}

func getResourceMessage(providerName, sourceName string, eventID uint32, argsptr uintptr) (string, error) {
	regkey := fmt.Sprintf(
		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
		providerName, sourceName)
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer key.Close()

	val, _, err := key.GetStringValue("EventMessageFile")
	if err != nil {
		return "", err
	}
	val, err = registry.ExpandString(val)
	if err != nil {
		return "", err
	}

	handle, err := eventlog.LoadLibraryEx(syscall.StringToUTF16Ptr(val), 0,
		eventlog.DONT_RESOLVE_DLL_REFERENCES|eventlog.LOAD_LIBRARY_AS_DATAFILE)
	if err != nil {
		return "", err
	}
	defer syscall.CloseHandle(handle)

	msgbuf := make([]byte, 1<<16)
	numChars, err := eventlog.FormatMessage(
		syscall.FORMAT_MESSAGE_FROM_SYSTEM|
			syscall.FORMAT_MESSAGE_FROM_HMODULE|
			syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY,
		handle,
		eventID,
		0,
		&msgbuf[0],
		uint32(len(msgbuf)),
		argsptr)
	if err != nil {
		return "", err
	}
	message, _ := bytesToString(msgbuf[:numChars*2])
	message = strings.Replace(message, "\r", "", -1)
	message = strings.TrimSuffix(message, "\n")
	return message, nil
}

func (opts *logOpts) searchLog(eventName string) (warnNum, critNum int64, errLines string, err error) {
	stateFile := getStateFile(opts.StateDir, eventName)
	recordNumber := int64(0)
	if !opts.NoState {
		s, err := getLastOffset(stateFile)
		if err != nil {
			return 0, 0, "", err
		}
		recordNumber = s
	}

	ptr := syscall.StringToUTF16Ptr(eventName)
	h, err := eventlog.OpenEventLog(nil, ptr)
	if err != nil {
		log.Fatal(err)
	}
	defer eventlog.CloseEventLog(h)

	var num, oldnum uint32

	eventlog.GetNumberOfEventLogRecords(h, &num)
	if err != nil {
		log.Fatal(err)
	}
	eventlog.GetOldestEventLogRecord(h, &oldnum)
	if err != nil {
		log.Fatal(err)
	}

	flags := eventlog.EVENTLOG_FORWARDS_READ | eventlog.EVENTLOG_SEEK_READ

	if recordNumber > 0 && oldnum <= uint32(recordNumber) {
		if uint32(recordNumber)+1 == oldnum+num {
			return 0, 0, "", nil
		}
		recordNumber += 1
	} else {
		recordNumber = 1
	}

	size := uint32(1)
	buf := []byte{0}

	var readBytes uint32
	var nextSize uint32
	var lastNumber uint32
	for i := uint32(recordNumber); i < oldnum+num; i++ {
		err = eventlog.ReadEventLog(
			h,
			flags,
			i,
			&buf[0],
			size,
			&readBytes,
			&nextSize)
		if err != nil {
			if err != syscall.ERROR_INSUFFICIENT_BUFFER {
				break
			}
			buf = make([]byte, nextSize)
			size = nextSize
			err = eventlog.ReadEventLog(
				h,
				eventlog.EVENTLOG_FORWARDS_READ|eventlog.EVENTLOG_SEQUENTIAL_READ,
				i,
				&buf[0],
				size,
				&readBytes,
				&nextSize)
			if err != nil {
				log.Printf("eventlog.ReadEventLog: %v", err)
				break
			}
		}

		r := *(*eventlog.EVENTLOGRECORD)(unsafe.Pointer(&buf[0]))
		if opts.Verbose {
			log.Printf("RecordNumber=%v", r.RecordNumber)
			log.Printf("TimeGenerated=%v", time.Unix(int64(r.TimeGenerated), 0).String())
			log.Printf("TimeWritten=%v", time.Unix(int64(r.TimeWritten), 0).String())
			log.Printf("EventID=%v", r.EventID)
		}
		lastNumber = i

		if len(opts.idList) > 0 {
			found := false
			for _, id := range opts.idList {
				if id > 0 && uint32(id) == r.EventID {
					found = true
					break
				} else if id <= 0 && uint32(-id) != r.EventID {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		tn := eventlog.EventType(r.EventType).String()
		if opts.Verbose {
			log.Printf("EventType=%v", tn)
		}
		tn = strings.ToLower(tn)
		if len(opts.typeList) > 0 {
			found := false
			for _, typ := range opts.typeList {
				if typ == tn {
					found = true
					break
				}
			}
			if !found {
				continue
			}
		}

		sourceName, sourceNameOff := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{}):])
		computerName, _ := bytesToString(buf[unsafe.Sizeof(eventlog.EVENTLOGRECORD{})+uintptr(sourceNameOff+2):])
		if opts.Verbose {
			log.Printf("SourceName=%v", sourceName)
			log.Printf("ComputerName=%v", computerName)
		}

		if opts.sourcePattern != nil {
			if !opts.sourcePattern.MatchString(sourceName) {
				continue
			}
		}

		off := uint32(0)
		args := make([]*byte, uintptr(r.NumStrings)*unsafe.Sizeof((*uint16)(nil)))
		for n := 0; n < int(r.NumStrings); n++ {
			args[n] = &buf[r.StringOffset+off]
			_, boff := bytesToString(buf[r.StringOffset+off:])
			off += boff + 2
		}

		var argsptr uintptr
		if r.NumStrings > 0 {
			argsptr = uintptr(unsafe.Pointer(&args[0]))
		}
		message, err := getResourceMessage(eventName, sourceName, r.EventID, argsptr)
		if err == nil {
			if opts.Verbose {
				log.Printf("Message=%v", message)
			}
			if opts.messagePattern != nil {
				if !opts.messagePattern.MatchString(message) {
					continue
				}
			}
		}
		if opts.ReturnContent {
			errLines += sourceName + ":" + strings.Replace(message, "\n", "", -1) + "\n"
		}
		switch tn {
		case "error":
			critNum++
		case "audit failure":
			critNum++
		case "warning":
			warnNum++
		}
	}

	if !opts.NoState {
		err = writeLastOffset(stateFile, int64(lastNumber))
		if err != nil {
			log.Printf("writeLastOffset failed: %s\n", err.Error())
		}
	}

	if recordNumber == 1 && !opts.FailFirst {
		if strings.Contains(errLines, "テストエラー") {
			println("================================================")
		}
		return 0, 0, "", nil
	}
	return warnNum, critNum, errLines, nil
}

var stateRe = regexp.MustCompile(`^([A-Z]):[/\\]`)

func getStateFile(stateDir, f string) string {
	return filepath.ToSlash(filepath.Join(stateDir, stateRe.ReplaceAllString(f, `$1`+string(filepath.Separator))))
}

func getLastOffset(f string) (int64, error) {
	_, err := os.Stat(f)
	if err != nil {
		return 0, nil
	}
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, err
	}
	i, err := strconv.ParseInt(strings.Trim(string(b), " \r\n"), 10, 64)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func writeLastOffset(f string, num int64) error {
	err := os.MkdirAll(filepath.Dir(f), 0755)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(f, []byte(fmt.Sprintf("%d", num)), 0644)
}
<|endoftext|>


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

package http

import (
	"io"
	"net/textproto"
	"sort"
	"strings"
)

// A Header represents the key-value pairs in an HTTP header.
type Header map[string][]string

// Add adds the key, value pair to the header.
// It appends to any existing values associated with key.
func (h Header) Add(key, value string) {
	textproto.MIMEHeader(h).Add(key, value)
}

// Set sets the header entries associated with key to
// the single element value.  It replaces any existing
// values associated with key.
func (h Header) Set(key, value string) {
	textproto.MIMEHeader(h).Set(key, value)
}

// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns "".
// To access multiple values of a key, access the map directly
// with CanonicalHeaderKey.
func (h Header) Get(key string) string {
	return textproto.MIMEHeader(h).Get(key)
}

// get is like Get, but key must already be in CanonicalHeaderKey form.
func (h Header) get(key string) string {
	if v := h[key]; len(v) > 0 {
		return v[0]
	}
	return ""
}

// Del deletes the values associated with key.
func (h Header) Del(key string) {
	textproto.MIMEHeader(h).Del(key)
}

// Write writes a header in wire format.
func (h Header) Write(w io.Writer) error {
	return h.WriteSubset(w, nil)
}

var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")

// WriteSubset writes a header in wire format.
// If exclude is not nil, keys where exclude[key] == true are not written.
func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
	keys := make([]string, 0, len(h))
	for k := range h {
		if !exclude[k] {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	for _, k := range keys {
		for _, v := range h[k] {
			v = headerNewlineToSpace.Replace(v)
			v = strings.TrimSpace(v)
			for _, s := range []string{k, ": ", v, "\r\n"} {
				if _, err := io.WriteString(w, s); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// CanonicalHeaderKey returns the canonical format of the
// header key s.  The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
// the rest are converted to lowercase.  For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }

// hasToken returns whether token appears with v, ASCII
// case-insensitive, with space or comma boundaries.
// token must be all lowercase.
// v may contain mixed cased.
func hasToken(v, token string) bool {
	if len(token) > len(v) || token == "" {
		return false
	}
	if v == token {
		return true
	}
	for sp := 0; sp <= len(v)-len(token); sp++ {
		// Check that first character is good.
		if b := v[sp]; b != token[0] && b|0x20 != token[0] {
			continue
		}
		// Check that start pos is on a valid token boundary.
		if sp > 0 && !isTokenBoundary(v[sp-1]) {
			continue
		}
		// Check that end pos is on a valid token boundary.
		if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
			continue
		}
		if strings.EqualFold(v[sp:sp+len(token)], token) {
			return true
		}
	}
	return false
}

func isTokenBoundary(b byte) bool {
	return b == ' ' || b == ',' || b == '\t'
}
<commit_msg>net/http: better comment in hasToken<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

import (
	"io"
	"net/textproto"
	"sort"
	"strings"
)

// A Header represents the key-value pairs in an HTTP header.
type Header map[string][]string

// Add adds the key, value pair to the header.
// It appends to any existing values associated with key.
func (h Header) Add(key, value string) {
	textproto.MIMEHeader(h).Add(key, value)
}

// Set sets the header entries associated with key to
// the single element value.  It replaces any existing
// values associated with key.
func (h Header) Set(key, value string) {
	textproto.MIMEHeader(h).Set(key, value)
}

// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns "".
// To access multiple values of a key, access the map directly
// with CanonicalHeaderKey.
func (h Header) Get(key string) string {
	return textproto.MIMEHeader(h).Get(key)
}

// get is like Get, but key must already be in CanonicalHeaderKey form.
func (h Header) get(key string) string {
	if v := h[key]; len(v) > 0 {
		return v[0]
	}
	return ""
}

// Del deletes the values associated with key.
func (h Header) Del(key string) {
	textproto.MIMEHeader(h).Del(key)
}

// Write writes a header in wire format.
func (h Header) Write(w io.Writer) error {
	return h.WriteSubset(w, nil)
}

var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")

// WriteSubset writes a header in wire format.
// If exclude is not nil, keys where exclude[key] == true are not written.
func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
	keys := make([]string, 0, len(h))
	for k := range h {
		if !exclude[k] {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	for _, k := range keys {
		for _, v := range h[k] {
			v = headerNewlineToSpace.Replace(v)
			v = strings.TrimSpace(v)
			for _, s := range []string{k, ": ", v, "\r\n"} {
				if _, err := io.WriteString(w, s); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// CanonicalHeaderKey returns the canonical format of the
// header key s.  The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
// the rest are converted to lowercase.  For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }

// hasToken returns whether token appears with v, ASCII
// case-insensitive, with space or comma boundaries.
// token must be all lowercase.
// v may contain mixed cased.
func hasToken(v, token string) bool {
	if len(token) > len(v) || token == "" {
		return false
	}
	if v == token {
		return true
	}
	for sp := 0; sp <= len(v)-len(token); sp++ {
		// Check that first character is good.
		// The token is ASCII, so checking only a single byte
		// is sufficient.  We skip this potential starting
		// position if both the first byte and its potential
		// ASCII uppercase equivalent (b|0x20) don't match.
		// False positives ('^' => '~') are caught by EqualFold.
		if b := v[sp]; b != token[0] && b|0x20 != token[0] {
			continue
		}
		// Check that start pos is on a valid token boundary.
		if sp > 0 && !isTokenBoundary(v[sp-1]) {
			continue
		}
		// Check that end pos is on a valid token boundary.
		if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
			continue
		}
		if strings.EqualFold(v[sp:sp+len(token)], token) {
			return true
		}
	}
	return false
}

func isTokenBoundary(b byte) bool {
	return b == ' ' || b == ',' || b == '\t'
}
<|endoftext|>


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

package os

const (
	PathSeparator     = '\\' // OS-specific path separator
	PathListSeparator = ':'  // OS-specific path list separator
)

// IsPathSeparator returns true if c is a directory separator character.
func IsPathSeparator(c uint8) bool {
	// NOTE: Windows accept / as path separator.
	return c == '\\' || c == '/'
}
<commit_msg>os: fixed PathListSeparator to ';' for windows. Fixed issue 1992<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

const (
	PathSeparator     = '\\' // OS-specific path separator
	PathListSeparator = ';'  // OS-specific path list separator
)

// IsPathSeparator returns true if c is a directory separator character.
func IsPathSeparator(c uint8) bool {
	// NOTE: Windows accept / as path separator.
	return c == '\\' || c == '/'
}
<|endoftext|>


<commit_before><commit_msg>added godoc<commit_after><|endoftext|>


<commit_before>// Package pop3 provides simple POP3 client.
package pop3

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
)

var (
	EOF = errors.New("skip the all mail remaining")
)

// MessageInfo has Number, Size, and Uid fields,
// and used as a return value of ListAll and UidlAll.
// When used as the return value of the method ListAll,
// MessageInfo contain only the Number and Size values.
// When used as the return value of the method UidlAll,
// MessageInfo contain only the Number and Uid values.
type MessageInfo struct {
	Number int
	Size   uint64
	Uid    string
}

// A Client represents a client connection to an POP server.
type Client struct {
	// Text is the pop3.Conn used by the Client.
	Text *Conn
	// keep a reference to the connection so it can be used to create a TLS
	// connection later
	conn net.Conn
}

// Dial returns a new Client connected to an POP server at addr.
// The addr must include a port number.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)

	if err != nil {
		return nil, err
	}

	return NewClient(conn)
}

// NewClient returns a new Client using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	text := NewConn(conn)

	_, err := text.ReadResponse()

	if err != nil {
		return nil, err
	}

	return &Client{Text: text, conn: conn}, nil
}

// User issues a USER command to the server using the provided user name.
func (c *Client) User(user string) error {
	return c.cmdSimple("USER %s", user)
}

// Pass issues a PASS command to the server using the provided password.
func (c *Client) Pass(pass string) error {
	return c.cmdSimple("PASS %s", pass)
}

// Stat issues a STAT command to the server
// and returns mail count and total size.
func (c *Client) Stat() (int, uint64, error) {
	return c.cmdStatOrList("STAT", "STAT")
}

// Retr issues a RETR command to the server using the provided mail number
// and returns mail data.
func (c *Client) Retr(number int) (string, error) {
	var err error

	err = c.Text.WriteLine("RETR %d", number)

	if err != nil {
		return "", err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return "", err
	}

	return c.Text.ReadToPeriod()
}

// List issues a LIST command to the server using the provided mail number
// and returns mail number and size.
func (c *Client) List(number int) (int, uint64, error) {
	return c.cmdStatOrList("LIST", "LIST %d", number)
}

// List issues a LIST command to the server
// and returns array of MessageInfo.
func (c *Client) ListAll() ([]MessageInfo, error) {
	list := make([]MessageInfo, 0)

	err := c.cmdReadLines("LIST", func(line string) error {
		number, size, err := c.convertNumberAndSize(line)

		if err != nil {
			return err
		}

		list = append(list, MessageInfo{Number: number, Size: size})

		return nil
	})

	if err != nil {
		return nil, err
	}

	return list, nil
}

// Uidl issues a UIDL command to the server using the provided mail number
// and returns mail number and unique id.
func (c *Client) Uidl(number int) (int, string, error) {
	var err error

	err = c.Text.WriteLine("UIDL %d", number)

	if err != nil {
		return 0, "", err
	}

	var msg string

	msg, err = c.Text.ReadResponse()

	if err != nil {
		return 0, "", err
	}

	var val int
	var uid string

	val, uid, err = c.convertNumberAndUid(msg)

	if err != nil {
		return 0, "", err
	}

	return val, uid, nil
}

// Uidl issues a UIDL command to the server
// and returns array of MessageInfo.
func (c *Client) UidlAll() ([]MessageInfo, error) {
	list := make([]MessageInfo, 0)

	err := c.cmdReadLines("UIDL", func(line string) error {
		number, uid, err := c.convertNumberAndUid(line)

		if err != nil {
			return err
		}

		list = append(list, MessageInfo{Number: number, Uid: uid})

		return nil
	})

	if err != nil {
		return nil, err
	}

	return list, nil
}

// Dele issues a DELE command to the server using the provided mail number.
func (c *Client) Dele(number int) error {
	return c.cmdSimple("DELE %d", number)
}

// Noop issues a NOOP command to the server.
func (c *Client) Noop() error {
	return c.cmdSimple("NOOP")
}

// Rset issues a RSET command to the server.
func (c *Client) Rset() error {
	return c.cmdSimple("RSET")
}

// Quit issues a QUIT command to the server.
func (c *Client) Quit() error {
	return c.cmdSimple("QUIT")
}

// ReceiveMail connects to the server at addr,
// and authenticates with user and pass,
// and calling receiveFn for each mail.
func ReceiveMail(addr, user, pass string, receiveFn ReceiveMailFunc) error {
	c, err := Dial(addr)

	if err != nil {
		return err
	}

	defer func() {
		if err != nil && err != EOF {
			c.Rset()
		}

		c.Quit()
		c.Close()
	}()

	if err = c.User(user); err != nil {
		return err
	}

	if err = c.Pass(pass); err != nil {
		return err
	}

	var mis []MessageInfo

	if mis, err = c.UidlAll(); err != nil {
		return err
	}

	for _, mi := range mis {
		var data string

		data, err = c.Retr(mi.Number)

		del, err := receiveFn(mi.Number, mi.Uid, data, err)

		if err != nil && err != EOF {
			return err
		}

		if del {
			if err = c.Dele(mi.Number); err != nil {
				return err
			}
		}

		if err == EOF {
			break
		}
	}

	return nil
}

// ReceiveMailFunc is the type of the function called for each mail.
// Its arguments are mail's number, uid, data, and mail receiving error.
// if this function returns false value, the mail will be deleted,
// if its returns EOF, skip the all mail of remaining.
// (after deleting mail, if necessary)
type ReceiveMailFunc func(number int, uid, data string, err error) (bool, error)

func (c *Client) cmdSimple(format string, args ...interface{}) error {
	var err error

	err = c.Text.WriteLine(format, args...)

	if err != nil {
		return err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return err
	}

	return nil
}

func (c *Client) cmdStatOrList(name, format string, args ...interface{}) (int, uint64, error) {
	var err error

	err = c.Text.WriteLine(format, args...)

	if err != nil {
		return 0, 0, err
	}

	var msg string

	msg, err = c.Text.ReadResponse()

	if err != nil {
		return 0, 0, err
	}

	s := strings.Split(msg, " ")

	if len(s) < 2 {
		return 0, 0, ResponseError(fmt.Sprintf("invalid response format: %s", msg))
	}

	var val int
	var size uint64

	val, size, err = c.convertNumberAndSize(msg)

	if err != nil {
		return 0, 0, err
	}

	return val, size, nil
}

func (c *Client) cmdReadLines(cmnd string, lineFn lineFunc) error {
	var err error

	err = c.Text.WriteLine(cmnd)

	if err != nil {
		return err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return err
	}

	var lines []string

	lines, err = c.Text.ReadLines()

	if err != nil {
		return err
	}

	for _, line := range lines {
		err = lineFn(line)

		if err != nil {
			return err
		}
	}

	return nil
}

type lineFunc func(line string) error

func (c *Client) Close() error {
	return c.Text.Close()
}

func (c *Client) convertNumberAndSize(line string) (int, uint64, error) {
	var err error

	s := strings.Split(line, " ")

	if len(s) < 2 {
		return 0, 0, errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
	}

	var val int
	var size uint64

	if val, err = strconv.Atoi(s[0]); err != nil {
		return 0, 0, errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
	}

	if size, err = strconv.ParseUint(s[1], 10, 64); err != nil {
		return 0, 0, errors.New(fmt.Sprintf("can not convert element[1] to uint64 type: %s", line))
	}

	return val, size, nil
}

func (c *Client) convertNumberAndUid(line string) (int, string, error) {
	var err error

	s := strings.Split(line, " ")

	if len(s) < 2 {
		return 0, "", errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
	}

	var val int

	if val, err = strconv.Atoi(s[0]); err != nil {
		return 0, "", errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
	}

	return val, s[1], nil
}
<commit_msg>add support for Top command, scan without retrieving<commit_after>// Package pop3 provides simple POP3 client.
package pop3

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
)

var (
	EOF = errors.New("skip the all mail remaining")
)

// MessageInfo has Number, Size, and Uid fields,
// and used as a return value of ListAll and UidlAll.
// When used as the return value of the method ListAll,
// MessageInfo contain only the Number and Size values.
// When used as the return value of the method UidlAll,
// MessageInfo contain only the Number and Uid values.
type MessageInfo struct {
	Number int
	Size   uint64
	Uid    string
}

// A Client represents a client connection to an POP server.
type Client struct {
	// Text is the pop3.Conn used by the Client.
	Text *Conn
	// keep a reference to the connection so it can be used to create a TLS
	// connection later
	conn net.Conn
}

// Dial returns a new Client connected to an POP server at addr.
// The addr must include a port number.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)

	if err != nil {
		return nil, err
	}

	return NewClient(conn)
}

// NewClient returns a new Client using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	text := NewConn(conn)

	_, err := text.ReadResponse()

	if err != nil {
		return nil, err
	}

	return &Client{Text: text, conn: conn}, nil
}

// User issues a USER command to the server using the provided user name.
func (c *Client) User(user string) error {
	return c.cmdSimple("USER %s", user)
}

// Pass issues a PASS command to the server using the provided password.
func (c *Client) Pass(pass string) error {
	return c.cmdSimple("PASS %s", pass)
}

// Stat issues a STAT command to the server
// and returns mail count and total size.
func (c *Client) Stat() (int, uint64, error) {
	return c.cmdStatOrList("STAT", "STAT")
}

// Retr issues a RETR command to the server using the provided mail number
// and returns mail data.
func (c *Client) Retr(number int) (string, error) {
	var err error

	err = c.Text.WriteLine("RETR %d", number)

	if err != nil {
		return "", err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return "", err
	}

	return c.Text.ReadToPeriod()
}

// Top issues a TOP command to the server using the provided mail number and number of lines
// and returns mail headers with the specified number of body lines.
func (c *Client) Top(number, body_lines int) (string, error) {
	var err error

	err = c.Text.WriteLine("TOP %d %d", number, body_lines)

	if err != nil {
		return "", err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return "", err
	}

	return c.Text.ReadToPeriod()
}

// List issues a LIST command to the server using the provided mail number
// and returns mail number and size.
func (c *Client) List(number int) (int, uint64, error) {
	return c.cmdStatOrList("LIST", "LIST %d", number)
}

// List issues a LIST command to the server
// and returns array of MessageInfo.
func (c *Client) ListAll() ([]MessageInfo, error) {
	list := make([]MessageInfo, 0)

	err := c.cmdReadLines("LIST", func(line string) error {
		number, size, err := c.convertNumberAndSize(line)

		if err != nil {
			return err
		}

		list = append(list, MessageInfo{Number: number, Size: size})

		return nil
	})

	if err != nil {
		return nil, err
	}

	return list, nil
}

// Uidl issues a UIDL command to the server using the provided mail number
// and returns mail number and unique id.
func (c *Client) Uidl(number int) (int, string, error) {
	var err error

	err = c.Text.WriteLine("UIDL %d", number)

	if err != nil {
		return 0, "", err
	}

	var msg string

	msg, err = c.Text.ReadResponse()

	if err != nil {
		return 0, "", err
	}

	var val int
	var uid string

	val, uid, err = c.convertNumberAndUid(msg)

	if err != nil {
		return 0, "", err
	}

	return val, uid, nil
}

// Uidl issues a UIDL command to the server
// and returns array of MessageInfo.
func (c *Client) UidlAll() ([]MessageInfo, error) {
	list := make([]MessageInfo, 0)

	err := c.cmdReadLines("UIDL", func(line string) error {
		number, uid, err := c.convertNumberAndUid(line)

		if err != nil {
			return err
		}

		list = append(list, MessageInfo{Number: number, Uid: uid})

		return nil
	})

	if err != nil {
		return nil, err
	}

	return list, nil
}

// Dele issues a DELE command to the server using the provided mail number.
func (c *Client) Dele(number int) error {
	return c.cmdSimple("DELE %d", number)
}

// Noop issues a NOOP command to the server.
func (c *Client) Noop() error {
	return c.cmdSimple("NOOP")
}

// Rset issues a RSET command to the server.
func (c *Client) Rset() error {
	return c.cmdSimple("RSET")
}

// Quit issues a QUIT command to the server.
func (c *Client) Quit() error {
	return c.cmdSimple("QUIT")
}

// ScanMail connects to the server at addr,
// and authenticates with user and pass,
// and calling messageFn for each mail.
func ScanMail(addr, user, pass string, messageFn ScanMailFunc) error {
	c, err := Dial(addr)

	if err != nil {
		return err
	}

	defer func() {
		if err != nil && err != EOF {
			c.Rset()
		}

		c.Quit()
		c.Close()
	}()

	if err = c.User(user); err != nil {
		return err
	}

	if err = c.Pass(pass); err != nil {
		return err
	}

	var mis []MessageInfo

	if mis, err = c.UidlAll(); err != nil {
		return err
	}

	for _, mi := range mis {
		err := messageFn(c, mi.Number, mi.Uid)

		if err == EOF {
			break
		}
		if err != nil {
			return err
		}
	}

	return nil
}

// ScanMailFunc is the type of the function called for each mail.
// Its arguments are mail's number and uid.
// If it returns EOF, skip the all mail of remaining.
type ScanMailFunc func(c *Client, number int, uid string) (error)

// ReceiveMail connects to the server at addr,
// and authenticates with user and pass,
// and calling receiveFn for each mail.
func ReceiveMail(addr, user, pass string, receiveFn ReceiveMailFunc) error {
	c, err := Dial(addr)

	if err != nil {
		return err
	}

	defer func() {
		if err != nil && err != EOF {
			c.Rset()
		}

		c.Quit()
		c.Close()
	}()

	if err = c.User(user); err != nil {
		return err
	}

	if err = c.Pass(pass); err != nil {
		return err
	}

	var mis []MessageInfo

	if mis, err = c.UidlAll(); err != nil {
		return err
	}

	for _, mi := range mis {
		var data string

		data, err = c.Retr(mi.Number)

		del, err := receiveFn(mi.Number, mi.Uid, data, err)

		if err != nil && err != EOF {
			return err
		}

		if del {
			if err = c.Dele(mi.Number); err != nil {
				return err
			}
		}

		if err == EOF {
			break
		}
	}

	return nil
}

// ReceiveMailFunc is the type of the function called for each mail.
// Its arguments are mail's number, uid, data, and mail receiving error.
// if this function returns false value, the mail will be deleted,
// if its returns EOF, skip the all mail of remaining.
// (after deleting mail, if necessary)
type ReceiveMailFunc func(number int, uid, data string, err error) (bool, error)

func (c *Client) cmdSimple(format string, args ...interface{}) error {
	var err error

	err = c.Text.WriteLine(format, args...)

	if err != nil {
		return err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return err
	}

	return nil
}

func (c *Client) cmdStatOrList(name, format string, args ...interface{}) (int, uint64, error) {
	var err error

	err = c.Text.WriteLine(format, args...)

	if err != nil {
		return 0, 0, err
	}

	var msg string

	msg, err = c.Text.ReadResponse()

	if err != nil {
		return 0, 0, err
	}

	s := strings.Split(msg, " ")

	if len(s) < 2 {
		return 0, 0, ResponseError(fmt.Sprintf("invalid response format: %s", msg))
	}

	var val int
	var size uint64

	val, size, err = c.convertNumberAndSize(msg)

	if err != nil {
		return 0, 0, err
	}

	return val, size, nil
}

func (c *Client) cmdReadLines(cmnd string, lineFn lineFunc) error {
	var err error

	err = c.Text.WriteLine(cmnd)

	if err != nil {
		return err
	}

	_, err = c.Text.ReadResponse()

	if err != nil {
		return err
	}

	var lines []string

	lines, err = c.Text.ReadLines()

	if err != nil {
		return err
	}

	for _, line := range lines {
		err = lineFn(line)

		if err != nil {
			return err
		}
	}

	return nil
}

type lineFunc func(line string) error

func (c *Client) Close() error {
	return c.Text.Close()
}

func (c *Client) convertNumberAndSize(line string) (int, uint64, error) {
	var err error

	s := strings.Split(line, " ")

	if len(s) < 2 {
		return 0, 0, errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
	}

	var val int
	var size uint64

	if val, err = strconv.Atoi(s[0]); err != nil {
		return 0, 0, errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
	}

	if size, err = strconv.ParseUint(s[1], 10, 64); err != nil {
		return 0, 0, errors.New(fmt.Sprintf("can not convert element[1] to uint64 type: %s", line))
	}

	return val, size, nil
}

func (c *Client) convertNumberAndUid(line string) (int, string, error) {
	var err error

	s := strings.Split(line, " ")

	if len(s) < 2 {
		return 0, "", errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
	}

	var val int

	if val, err = strconv.Atoi(s[0]); err != nil {
		return 0, "", errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
	}

	return val, s[1], nil
}
<|endoftext|>


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

package testing

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"time"
)

type InternalExample struct {
	Name   string
	F      func()
	Output string
}

func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
	ok = true

	var eg InternalExample

	stdout := os.Stdout

	for _, eg = range examples {
		matched, err := matchString(*match, eg.Name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
			os.Exit(1)
		}
		if !matched {
			continue
		}
		if *chatty {
			fmt.Printf("=== RUN: %s\n", eg.Name)
		}

		// capture stdout
		r, w, err := os.Pipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		os.Stdout = w
		outC := make(chan string)
		go func() {
			buf := new(bytes.Buffer)
			_, err := io.Copy(buf, r)
			if err != nil {
				fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
				os.Exit(1)
			}
			outC <- buf.String()
		}()

		// run example
		t0 := time.Now()
		eg.F()
		dt := time.Now().Sub(t0)

		// close pipe, restore stdout, get output
		w.Close()
		os.Stdout = stdout
		out := <-outC

		// report any errors
		tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
		if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
			fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
				eg.Name, tstr, g, e)
			ok = false
		} else if *chatty {
			fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
		}
	}

	return
}
<commit_msg>testing: fix example test fd leak<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"time"
)

type InternalExample struct {
	Name   string
	F      func()
	Output string
}

func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
	ok = true

	var eg InternalExample

	stdout := os.Stdout

	for _, eg = range examples {
		matched, err := matchString(*match, eg.Name)
		if err != nil {
			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
			os.Exit(1)
		}
		if !matched {
			continue
		}
		if *chatty {
			fmt.Printf("=== RUN: %s\n", eg.Name)
		}

		// capture stdout
		r, w, err := os.Pipe()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		os.Stdout = w
		outC := make(chan string)
		go func() {
			buf := new(bytes.Buffer)
			_, err := io.Copy(buf, r)
			r.Close()
			if err != nil {
				fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
				os.Exit(1)
			}
			outC <- buf.String()
		}()

		// run example
		t0 := time.Now()
		eg.F()
		dt := time.Now().Sub(t0)

		// close pipe, restore stdout, get output
		w.Close()
		os.Stdout = stdout
		out := <-outC

		// report any errors
		tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
		if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
			fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
				eg.Name, tstr, g, e)
			ok = false
		} else if *chatty {
			fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
		}
	}

	return
}
<|endoftext|>