<commit_before>package vm

import (
	"fmt"
)

var (
	// UndefinedMethodErrorClass ...
	UndefinedMethodErrorClass *RClass
	// ArgumentErrorClass ...
	ArgumentErrorClass *RClass
	// TypeErrorClass ...
	TypeErrorClass *RClass
	// UnsupportedMethodClass
	UnsupportedMethodClass *RClass
	// NameErrorClass
	NameErrorClass     *RClass
	InternalErrorClass *RClass
)

const (
	// UndefinedMethodError describes the error type in string
	UndefinedMethodError = "UndefinedMethodError"
	// ArgumentError describes the error type in string
	ArgumentError = "ArgumentError"
	// TypeError describes the error type in string
	TypeError = "TypeError"
	// UnsupportedMethodError describes the error type in string
	UnsupportedMethodError = "UnsupportedMethodError"
	// NameError describes constant related errors
	NameError     = "NameError"
	InternalError = "InternalError"
)

func initErrorClasses() {
	bc := createBaseClass(UndefinedMethodError)
	UndefinedMethodErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(ArgumentError)
	ArgumentErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(TypeError)
	TypeErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(UnsupportedMethodError)
	UnsupportedMethodClass = &RClass{BaseClass: bc}
	bc = createBaseClass(NameError)
	NameErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(InternalError)
	InternalErrorClass = &RClass{BaseClass: bc}
}

// Error ...
type Error struct {
	Class   *RClass
	Message string
}

// toString ...
func (e *Error) toString() string {
	return "ERROR: " + e.Message
}

func (e *Error) toJSON() string {
	return e.toString()
}

func (e *Error) returnClass() Class {
	return e.Class
}

func initErrorObject(errorType *RClass, format string, args ...interface{}) *Error {
	return &Error{
		Class:   errorType,
		Message: fmt.Sprintf(errorType.Name+": "+format, args...),
	}
}
<commit_msg>Fix codeclimate's issues.<commit_after>package vm

import (
	"fmt"
)

// Nothing to describe here, just error classes
var (
	// UndefinedMethodErrorClass ...
	UndefinedMethodErrorClass *RClass
	// ArgumentErrorClass ...
	ArgumentErrorClass *RClass
	// TypeErrorClass ...
	TypeErrorClass *RClass
	// UnsupportedMethodClass ...
	UnsupportedMethodClass *RClass
	// NameErrorClass ...
	NameErrorClass *RClass
	// InternalErrorClass ...
	InternalErrorClass *RClass
)

const (
	// UndefinedMethodError describes the error type in string
	UndefinedMethodError = "UndefinedMethodError"
	// ArgumentError describes the error type in string
	ArgumentError = "ArgumentError"
	// TypeError describes the error type in string
	TypeError = "TypeError"
	// UnsupportedMethodError describes the error type in string
	UnsupportedMethodError = "UnsupportedMethodError"
	// NameError describes constant related errors
	NameError = "NameError"
	// InternalError is the default error type
	InternalError = "InternalError"
)

func initErrorClasses() {
	bc := createBaseClass(UndefinedMethodError)
	UndefinedMethodErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(ArgumentError)
	ArgumentErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(TypeError)
	TypeErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(UnsupportedMethodError)
	UnsupportedMethodClass = &RClass{BaseClass: bc}
	bc = createBaseClass(NameError)
	NameErrorClass = &RClass{BaseClass: bc}
	bc = createBaseClass(InternalError)
	InternalErrorClass = &RClass{BaseClass: bc}
}

// Error ...
type Error struct {
	Class   *RClass
	Message string
}

// toString ...
func (e *Error) toString() string {
	return "ERROR: " + e.Message
}

func (e *Error) toJSON() string {
	return e.toString()
}

func (e *Error) returnClass() Class {
	return e.Class
}

func initErrorObject(errorType *RClass, format string, args ...interface{}) *Error {
	return &Error{
		Class:   errorType,
		Message: fmt.Sprintf(errorType.Name+": "+format, args...),
	}
}
<|endoftext|>


<commit_before>package vm

import (
	"sync"
)

type stack struct {
	Data   []*Pointer
	thread *thread
	// Although every thread has its own stack, vm's main thread still can be accessed by other threads.
	// This is why we need a lock in stack
	// TODO: Find a way to fix this instead of put lock on every stack.
	*sync.RWMutex
}

func (s *stack) set(index int, pointer *Pointer) {
	s.Lock()

	defer s.Unlock()

	s.Data[index] = pointer
}

func (s *stack) push(v *Pointer) {
	s.Lock()
	defer s.Unlock()

	if len(s.Data) <= s.thread.sp {
		s.Data = append(s.Data, v)
	} else {
		s.Data[s.thread.sp] = v
	}

	s.thread.sp++
}

func (s *stack) pop() *Pointer {
	s.Lock()
	defer s.Unlock()

	if len(s.Data) < 1 {
		panic("Nothing to pop!")
	}

	if s.thread.sp < 0 {
		panic("SP is not normal!")
	}

	if s.thread.sp > 0 {
		s.thread.sp--
	}

	v := s.Data[s.thread.sp]
	s.Data[s.thread.sp] = nil
	return v
}

func (s *stack) top() *Pointer {
	s.RLock()
	defer s.RUnlock()

	if len(s.Data) == 0 {
		return nil
	}

	if s.thread.sp > 0 {
		return s.Data[s.thread.sp-1]
	}

	return s.Data[0]
}
<commit_msg>Remove defer usage from stack<commit_after>package vm

import (
	"sync"
)

type stack struct {
	Data   []*Pointer
	thread *thread
	// Although every thread has its own stack, vm's main thread still can be accessed by other threads.
	// This is why we need a lock in stack
	// TODO: Find a way to fix this instead of put lock on every stack.
	sync.RWMutex
}

func (s *stack) set(index int, pointer *Pointer) {
	s.Lock()

	s.Data[index] = pointer

	s.Unlock()
}

func (s *stack) push(v *Pointer) {
	s.Lock()

	if len(s.Data) <= s.thread.sp {
		s.Data = append(s.Data, v)
	} else {
		s.Data[s.thread.sp] = v
	}

	s.thread.sp++
	s.Unlock()
}

func (s *stack) pop() *Pointer {
	s.Lock()

	if len(s.Data) < 1 {
		panic("Nothing to pop!")
	}

	if s.thread.sp < 0 {
		panic("SP is not normal!")
	}

	if s.thread.sp > 0 {
		s.thread.sp--
	}

	v := s.Data[s.thread.sp]
	s.Data[s.thread.sp] = nil
	s.Unlock()
	return v
}

func (s *stack) top() *Pointer {
	var r *Pointer
	s.RLock()

	if len(s.Data) == 0 {
		r = nil
	} else if s.thread.sp > 0 {
		r = s.Data[s.thread.sp-1]
	} else {
		r = s.Data[0]
	}

	s.RUnlock()

	return r
}
<|endoftext|>


<commit_before>package web

import (
	"github.com/gorilla/mux"
	"github.com/jimmysawczuk/power-monitor/monitor"

	"bytes"
	"encoding/json"
	"html/template"
	"net/http"
	"path"
	"strconv"
	"time"
)

var activeMonitor *monitor.Monitor
var startTime time.Time
var indexTmpl *template.Template
var releaseMode = releaseModeDebug

const (
	releaseModeRelease = "release"
	releaseModeDebug   = "debug"
)

func init() {
	if releaseMode == releaseModeRelease {
		indexTmpl = template.Must(template.New("name").Parse(string(MustAsset("web/templates/index.html"))))
	}
}

func GetRouter(m *monitor.Monitor) *mux.Router {
	activeMonitor = m
	startTime = time.Now()

	r := mux.NewRouter()
	r.HandleFunc("/", getIndex)
	r.HandleFunc("/api/snapshots", getSnapshots)
	r.PathPrefix("/").HandlerFunc(getStaticFile)
	return r
}
func getStaticFile(w http.ResponseWriter, r *http.Request) {
	by, err := Asset("web/static" + r.URL.Path)
	if err != nil {
		w.WriteHeader(404)
		return
	}

	switch path.Ext(r.URL.Path) {
	case ".css":
		w.Header().Set("Content-Type", "text/css")
	case ".js":
		w.Header().Set("Content-Type", "application/javascript")
	}

	w.WriteHeader(200)
	w.Write(by)
}

func getIndex(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)

	tmpl := indexTmpl
	if tmpl == nil {
		tmpl = template.Must(template.New("name").Parse(string(MustAsset("web/templates/index.html"))))
	}

	var revision string
	if rev, err := Asset("web/static/REVISION.json"); err != nil {
		revision = "{}"
	} else {
		buf := &bytes.Buffer{}
		json.Compact(buf, rev)
		revision = buf.String()
	}

	tmpl.Execute(w, map[string]interface{}{
		"StartTime": startTime,
		"Interval":  int64(activeMonitor.Interval / 1e6),
		"Mode":      releaseMode,
		"Revision":  revision,
	})
}

func getSnapshots(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	now := time.Now()

	recent := activeMonitor.GetRecentSnapshots().Filter(func(s monitor.Snapshot) bool {

		switch {
		case isTimestampInLast(startTime, now, 3*time.Minute):
			return true

		case isTimestampInLast(startTime, now, 10*time.Minute):
			return isSignificantTimestamp(s.Timestamp, 10*time.Second)

		case isTimestampInLast(startTime, now, 1*time.Hour):
			return isSignificantTimestamp(s.Timestamp, 30*time.Second)

		case isTimestampInLast(startTime, now, 6*time.Hour):
			return isSignificantTimestamp(s.Timestamp, 5*time.Minute)

		case isTimestampInLast(startTime, now, 2*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, 30*time.Minute)

		case isTimestampInLast(startTime, now, 4*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, 1*time.Hour)

		case isTimestampInLast(s.Timestamp, now, 7*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, 3*time.Hour)

		default:
			return false
		}
	})

	limit_str := r.FormValue("limit")
	limit, _ := strconv.ParseInt(limit_str, 10, 64)
	if limit > 0 && limit < int64(len(recent)) {
		recent = recent[0:limit]
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	by, _ := json.Marshal(recent)
	w.Write(by)
}

func isTimestampInLast(s, now time.Time, dur time.Duration) bool {
	return now.Sub(s) < dur
}

func isSignificantTimestamp(s time.Time, frequency time.Duration) bool {
	return s.UnixNano()%int64(frequency) < int64(activeMonitor.Interval)
}
<commit_msg>Let's try this instead<commit_after>package web

import (
	"github.com/gorilla/mux"
	"github.com/jimmysawczuk/power-monitor/monitor"

	"bytes"
	"encoding/json"
	"html/template"
	"net/http"
	"path"
	"strconv"
	"time"
)

var activeMonitor *monitor.Monitor
var startTime time.Time
var indexTmpl *template.Template
var releaseMode = releaseModeDebug

const (
	releaseModeRelease = "release"
	releaseModeDebug   = "debug"
)

func init() {
	if releaseMode == releaseModeRelease {
		indexTmpl = template.Must(template.New("name").Parse(string(MustAsset("web/templates/index.html"))))
	}
}

func GetRouter(m *monitor.Monitor) *mux.Router {
	activeMonitor = m
	startTime = time.Now()

	r := mux.NewRouter()
	r.HandleFunc("/", getIndex)
	r.HandleFunc("/api/snapshots", getSnapshots)
	r.PathPrefix("/").HandlerFunc(getStaticFile)
	return r
}
func getStaticFile(w http.ResponseWriter, r *http.Request) {
	by, err := Asset("web/static" + r.URL.Path)
	if err != nil {
		w.WriteHeader(404)
		return
	}

	switch path.Ext(r.URL.Path) {
	case ".css":
		w.Header().Set("Content-Type", "text/css")
	case ".js":
		w.Header().Set("Content-Type", "application/javascript")
	}

	w.WriteHeader(200)
	w.Write(by)
}

func getIndex(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)

	tmpl := indexTmpl
	if tmpl == nil {
		tmpl = template.Must(template.New("name").Parse(string(MustAsset("web/templates/index.html"))))
	}

	var revision string
	if rev, err := Asset("web/static/REVISION.json"); err != nil {
		revision = "{}"
	} else {
		buf := &bytes.Buffer{}
		json.Compact(buf, rev)
		revision = buf.String()
	}

	tmpl.Execute(w, map[string]interface{}{
		"StartTime": startTime,
		"Interval":  int64(activeMonitor.Interval / 1e6),
		"Mode":      releaseMode,
		"Revision":  revision,
	})
}

func getSnapshots(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	now := time.Now()

	recent := activeMonitor.GetRecentSnapshots().Filter(func(s monitor.Snapshot) bool {

		switch {
		case isTimestampInLast(startTime, now, 3*time.Minute):
			return true

		case isTimestampInLast(startTime, now, 10*time.Minute):
			return isSignificantTimestamp(s.Timestamp, now, 10*time.Second)

		case isTimestampInLast(startTime, now, 1*time.Hour):
			return isSignificantTimestamp(s.Timestamp, now, 30*time.Second)

		case isTimestampInLast(startTime, now, 6*time.Hour):
			return isSignificantTimestamp(s.Timestamp, now, 5*time.Minute)

		case isTimestampInLast(startTime, now, 2*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, now, 30*time.Minute)

		case isTimestampInLast(startTime, now, 4*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, now, 1*time.Hour)

		case isTimestampInLast(s.Timestamp, now, 7*24*time.Hour):
			return isSignificantTimestamp(s.Timestamp, now, 3*time.Hour)

		default:
			return false
		}
	})

	limit_str := r.FormValue("limit")
	limit, _ := strconv.ParseInt(limit_str, 10, 64)
	if limit > 0 && limit < int64(len(recent)) {
		recent = recent[0:limit]
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	by, _ := json.Marshal(recent)
	w.Write(by)
}

func isTimestampInLast(s, now time.Time, dur time.Duration) bool {
	return now.Sub(s) < dur
}

func isSignificantTimestamp(s, now time.Time, frequency time.Duration) bool {
	return (now.UnixNano()-s.UnixNano())%int64(frequency) < int64(activeMonitor.Interval)
}
<|endoftext|>


<commit_before>package wmi

import (
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestQuery(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := Query(q, &dst)
	if err != nil {
		t.Fatal(err)
	}
}

func TestFieldMismatch(t *testing.T) {
	type s struct {
		Name        string
		HandleCount uint32
		Blah        uint32
	}
	var dst []s
	err := Query("SELECT Name, HandleCount FROM Win32_Process", &dst)
	if err == nil || err.Error() != `wmi: cannot load field "Blah" into a "uint32": no such struct field` {
		t.Error("Expected err field mismatch")
	}
}

func TestNamespace(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := QueryNamespace(q, &dst, `root\CIMV2`)
	if err != nil {
		t.Fatal(err)
	}
	dst = nil
	err = QueryNamespace(q, &dst, `broken\nothing`)
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestCreateQuery(t *testing.T) {
	type TestStruct struct {
		Name  string
		Count int
	}
	var dst []TestStruct
	output := "SELECT Name, Count FROM TestStruct WHERE Count > 2"
	tests := []interface{}{
		&dst,
		dst,
		TestStruct{},
		&TestStruct{},
	}
	for i, test := range tests {
		if o := CreateQuery(test, "WHERE Count > 2"); o != output {
			t.Error("bad output on", i, o)
		}
	}
	if CreateQuery(3, "") != "" {
		t.Error("expected empty string")
	}
}

func TestMany(t *testing.T) {
	runtime.GOMAXPROCS(2)
	limit := 500
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		for i := 0; i < limit; i++ {
			if i % 25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_PerfRawData_PerfDisk_LogicalDisk
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR disk", err)
			}
		}
		wg.Done()
	}()
	go func() {
		for i := 0; i > -limit; i-- {
			if i % 25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_OperatingSystem
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR OS", err)
			}
		}
		wg.Done()
	}()
	wg.Wait()
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfDisk_LogicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint32
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint32
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	FreeMegabytes                uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentFreeSpace             uint32
	PercentFreeSpace_Base        uint32
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}
<commit_msg>A bit more descriptive<commit_after>package wmi

import (
	"fmt"
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestQuery(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := Query(q, &dst)
	if err != nil {
		t.Fatal(err)
	}
}

func TestFieldMismatch(t *testing.T) {
	type s struct {
		Name        string
		HandleCount uint32
		Blah        uint32
	}
	var dst []s
	err := Query("SELECT Name, HandleCount FROM Win32_Process", &dst)
	if err == nil || err.Error() != `wmi: cannot load field "Blah" into a "uint32": no such struct field` {
		t.Error("Expected err field mismatch")
	}
}

func TestNamespace(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := QueryNamespace(q, &dst, `root\CIMV2`)
	if err != nil {
		t.Fatal(err)
	}
	dst = nil
	err = QueryNamespace(q, &dst, `broken\nothing`)
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestCreateQuery(t *testing.T) {
	type TestStruct struct {
		Name  string
		Count int
	}
	var dst []TestStruct
	output := "SELECT Name, Count FROM TestStruct WHERE Count > 2"
	tests := []interface{}{
		&dst,
		dst,
		TestStruct{},
		&TestStruct{},
	}
	for i, test := range tests {
		if o := CreateQuery(test, "WHERE Count > 2"); o != output {
			t.Error("bad output on", i, o)
		}
	}
	if CreateQuery(3, "") != "" {
		t.Error("expected empty string")
	}
}

func TestMany(t *testing.T) {
	limit := 5000
	fmt.Println("running until:", limit)
	fmt.Println("No panics mean it succeeded. Other errors are OK.")
	runtime.GOMAXPROCS(2)
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		for i := 0; i < limit; i++ {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_PerfRawData_PerfDisk_LogicalDisk
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR disk", err)
			}
		}
		wg.Done()
	}()
	go func() {
		for i := 0; i > -limit; i-- {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_OperatingSystem
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR OS", err)
			}
		}
		wg.Done()
	}()
	wg.Wait()
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfDisk_LogicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint32
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint32
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	FreeMegabytes                uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentFreeSpace             uint32
	PercentFreeSpace_Base        uint32
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}
<|endoftext|>


<commit_before>package jsonapi

import (
	"context"
	"io"

	"github.com/justwatchcom/gopass/store/root"
)

// API type holding store and context
type API struct {
	Store  *root.Store
	Reader io.Reader
	Writer io.Writer
}

// ReadAndRespond a single message via stdin/stdout
func (api *API) ReadAndRespond(ctx context.Context) error {
	message, err := readMessage(api.Reader)
	if message == nil || err != nil {
		return err
	}

	return api.respondMessage(ctx, message)
}

// RespondError sends err as JSON response via stdout
func (api *API) RespondError(err error) error {
	var response errorResponse
	response.Error = err.Error()

	return sendSerializedJSONMessage(response, api.Writer)
}
<commit_msg>Do not print status updates while writing messages (#582)<commit_after>package jsonapi

import (
	"context"
	"io"

	"github.com/justwatchcom/gopass/store/root"
	"github.com/justwatchcom/gopass/utils/out"
)

// API type holding store and context
type API struct {
	Store  *root.Store
	Reader io.Reader
	Writer io.Writer
}

// ReadAndRespond a single message via stdin/stdout
func (api *API) ReadAndRespond(ctx context.Context) error {
	silentCtx := out.WithHidden(ctx, true)
	message, err := readMessage(api.Reader)
	if message == nil || err != nil {
		return err
	}

	return api.respondMessage(silentCtx, message)
}

// RespondError sends err as JSON response via stdout
func (api *API) RespondError(err error) error {
	var response errorResponse
	response.Error = err.Error()

	return sendSerializedJSONMessage(response, api.Writer)
}
<|endoftext|>


<commit_before>// Package word2vec provides functionality for reading binary word2vec models
// and basic usage (see https://code.google.com/p/word2vec/).
package word2vec

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/ziutek/blas"
)

// Model is a type which represents a word2vec Model.
type Model struct {
	dim   int
	words map[string]Vector
}

// FromReader creates a Model using the binary model data provided by the io.Reader.
func FromReader(r io.Reader) (*Model, error) {
	br := bufio.NewReader(r)
	var size, dim int
	n, err := fmt.Fscanln(r, &size, &dim)
	if err != nil {
		return nil, err
	}
	if n != 2 {
		return nil, fmt.Errorf("could not extract size/dim from binary Data")
	}

	m := &Model{
		words: make(map[string]Vector, size),
		dim:   dim,
	}

	raw := make([]float32, size*dim)

	for i := 0; i < size; i++ {
		w, err := br.ReadString(' ')
		if err != nil {
			return nil, err
		}
		w = w[:len(w)-1]

		v := Vector(raw[dim*i : m.dim*(i+1)])
		err = binary.Read(br, binary.LittleEndian, v)
		if err != nil {
			return nil, err
		}

		v.Normalise()

		_, err = br.ReadByte()
		if err != nil {
			return nil, err
		}

		m.words[w] = v
	}
	return m, nil
}

// Vector is a type which represents a word vector.
type Vector []float32

// Normalise normalises the vector in-place.
func (v Vector) Normalise() {
	w := blas.Snrm2(len(v), v, 1)
	blas.Sscal(len(v), 1/w, v, 1)
}

// Add performs v += a * u (in-place).
func (v Vector) Add(a float32, u Vector) {
	blas.Saxpy(len(v), a, u, 1, v, 1)
}

// Dot computes the dot product with u.
func (v Vector) Dot(u Vector) float32 {
	return blas.Sdot(len(v), u, 1, v, 1)
}

// NotFoundError is an error returned from Model functions when an input
// word is not in the model.
type NotFoundError struct {
	Word string
}

func (e NotFoundError) Error() string {
	return fmt.Sprintf("word not found: %v", e.Word)
}

// Size returns the number of words in the model.
func (m *Model) Size() int {
	return len(m.words)
}

// Dim returns the dimention of the vectors in the model.
func (m *Model) Dim() int {
	return m.dim
}

// Similarity returns the similarity between the two words.
func (m *Model) Similarity(x, y string) (float32, error) {
	u, ok := m.words[x]
	if !ok {
		return 0.0, &NotFoundError{x}
	}
	v, ok := m.words[y]
	if !ok {
		return 0.0, &NotFoundError{y}
	}
	return u.Dot(v), nil
}

// Eval constructs a vector by adding and subtracting the vector values of
// lists of words.
func (m *Model) Eval(add []string, sub []string) (Vector, error) {
	v := Vector(make([]float32, m.dim))
	for _, w := range add {
		u, ok := m.words[w]
		if !ok {
			return nil, &NotFoundError{w}
		}
		v.Add(1, u)
	}
	for _, w := range sub {
		u, ok := m.words[w]
		if !ok {
			return nil, &NotFoundError{w}
		}
		v.Add(-1, u)
	}
	v.Normalise()
	return v, nil
}

// Pair is a type which represents a pairing of a word and score indicating
// the similarity of this word against a search word.
type Pair struct {
	Word  string
	Score float32
}

// MostSimilar is a method which returns a list of `n` most similar vectors
// to `v` in the model.
func (m *Model) MostSimilar(v Vector, n int) ([]Pair, error) {
	r := make([]Pair, n)
	for w, u := range m.words {
		score := v.Dot(u)
		p := Pair{w, score}
		// TODO(dhowden): MaxHeap would be better here if n is large.
		if r[n-1].Score > p.Score {
			continue
		}
		r[n-1] = p
		for j := n - 2; j >= 0; j-- {
			if r[j].Score > p.Score {
				break
			}
			r[j], r[j+1] = p, r[j]
		}
	}
	return r, nil
}
<commit_msg>Add Vectors method to Model to fetch vectors for a list of words.<commit_after>// Package word2vec provides functionality for reading binary word2vec models
// and basic usage (see https://code.google.com/p/word2vec/).
package word2vec

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/ziutek/blas"
)

// Model is a type which represents a word2vec Model.
type Model struct {
	dim   int
	words map[string]Vector
}

// FromReader creates a Model using the binary model data provided by the io.Reader.
func FromReader(r io.Reader) (*Model, error) {
	br := bufio.NewReader(r)
	var size, dim int
	n, err := fmt.Fscanln(r, &size, &dim)
	if err != nil {
		return nil, err
	}
	if n != 2 {
		return nil, fmt.Errorf("could not extract size/dim from binary Data")
	}

	m := &Model{
		words: make(map[string]Vector, size),
		dim:   dim,
	}

	raw := make([]float32, size*dim)

	for i := 0; i < size; i++ {
		w, err := br.ReadString(' ')
		if err != nil {
			return nil, err
		}
		w = w[:len(w)-1]

		v := Vector(raw[dim*i : m.dim*(i+1)])
		err = binary.Read(br, binary.LittleEndian, v)
		if err != nil {
			return nil, err
		}

		v.Normalise()

		_, err = br.ReadByte()
		if err != nil {
			return nil, err
		}

		m.words[w] = v
	}
	return m, nil
}

// Vector is a type which represents a word vector.
type Vector []float32

// Normalise normalises the vector in-place.
func (v Vector) Normalise() {
	w := blas.Snrm2(len(v), v, 1)
	blas.Sscal(len(v), 1/w, v, 1)
}

// Add performs v += a * u (in-place).
func (v Vector) Add(a float32, u Vector) {
	blas.Saxpy(len(v), a, u, 1, v, 1)
}

// Dot computes the dot product with u.
func (v Vector) Dot(u Vector) float32 {
	return blas.Sdot(len(v), u, 1, v, 1)
}

// NotFoundError is an error returned from Model functions when an input
// word is not in the model.
type NotFoundError struct {
	Word string
}

func (e NotFoundError) Error() string {
	return fmt.Sprintf("word not found: %v", e.Word)
}

// Size returns the number of words in the model.
func (m *Model) Size() int {
	return len(m.words)
}

// Dim returns the dimention of the vectors in the model.
func (m *Model) Dim() int {
	return m.dim
}

// Similarity returns the similarity between the two words.
func (m *Model) Similarity(x, y string) (float32, error) {
	u, ok := m.words[x]
	if !ok {
		return 0.0, &NotFoundError{x}
	}
	v, ok := m.words[y]
	if !ok {
		return 0.0, &NotFoundError{y}
	}
	return u.Dot(v), nil
}

// Vectors returns a mapping word -> Vector for each word in `w`,
// unknown words are ignored.
func (m *Model) Vectors(words []string) map[string]Vector {
	result := make(map[string]Vector)
	for _, w := range words {
		if v, ok := m.words[w]; ok {
			result[w] = v
		}
	}
	return result
}

// Eval constructs a vector by adding and subtracting the vector values of
// lists of words.
func (m *Model) Eval(add []string, sub []string) (Vector, error) {
	v := Vector(make([]float32, m.dim))
	for _, w := range add {
		u, ok := m.words[w]
		if !ok {
			return nil, &NotFoundError{w}
		}
		v.Add(1, u)
	}
	for _, w := range sub {
		u, ok := m.words[w]
		if !ok {
			return nil, &NotFoundError{w}
		}
		v.Add(-1, u)
	}
	v.Normalise()
	return v, nil
}

// Pair is a type which represents a pairing of a word and score indicating
// the similarity of this word against a search word.
type Pair struct {
	Word  string
	Score float32
}

// MostSimilar is a method which returns a list of `n` most similar vectors
// to `v` in the model.
func (m *Model) MostSimilar(v Vector, n int) ([]Pair, error) {
	r := make([]Pair, n)
	for w, u := range m.words {
		score := v.Dot(u)
		p := Pair{w, score}
		// TODO(dhowden): MaxHeap would be better here if n is large.
		if r[n-1].Score > p.Score {
			continue
		}
		r[n-1] = p
		for j := n - 2; j >= 0; j-- {
			if r[j].Score > p.Score {
				break
			}
			r[j], r[j+1] = p, r[j]
		}
	}
	return r, nil
}
<|endoftext|>


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

/*
	Package workpool implements a pool of go routines that are dedicated to processing work that is posted into the pool.

		Read the following blog post for more information:blogspot
		http://www.goinggo.net/2013/05/thread-pooling-in-go-programming.html

	New Parameters

	The following is a list of parameters for creating a TraceLog:

		numberOfRoutines: Sets the number of worker routines that are allowed to process work concurrently
		queueCapacity:    Sets the maximum number of pending work objects that can be in queue

	WorkPool Management

	Go routines are used to manage and process all the work. A single Queue routine provides the safe queuing of work.
	The Queue routine keeps track of the amount of work in the queue and reports an error if the queue is full.

	The concurrencyLevel parameter defines the number of work routines to create. These work routines will process work
	subbmitted to the queue. The work routines keep track of the number of active work routines for reporting.

	The PostWork method is used to post work into the ThreadPool. This call will block until the Queue routine reports back
	success or failure that the work is in queue.

	Example Use Of ThreadPool

	The following shows a simple test application

		package main

		import (
		    "github.com/goinggo/workpool"
		    "bufio"
		    "fmt"
		    "os"
		    "runtime"
		    "strconv"
		    "time"
		)

		type MyWork struct {
		    Name      string "The Name of a person"
		    BirthYear int    "The Yea the person was born"
		    WP        *workpool.WorkPool
		}

		func (this *MyWork) DoWork(workRoutine int) {
		    fmt.Printf("%s : %d\n", this.Name, this.BirthYear)
		    fmt.Printf("*******> WR: %d  QW: %d  AR: %d\n", workRoutine, this.WP.QueuedWork(), this.WP.ActiveRoutines())
		    time.Sleep(100 * time.Millisecond)

		    //panic("test")
		}

		func main() {

		    runtime.GOMAXPROCS(runtime.NumCPU())

		    workPool := workpool.New(runtime.NumCPU() * 3, 10)

		    shutdown := false // Just for testing, I Know

		    go func() {

				for i := 0; i < 1000; i++ {

					work := &MyWork{
						Name: "A" + strconv.Itoa(i),
						BirthYear: i,
						WP: workPool,
					}

					err := workPool.PostWork("name_routine", work)

					if err != nil {
						fmt.Printf("ERROR: %s\n", err)
						time.Sleep(100 * time.Millisecond)
					}

					if shutdown == true {
						return
					}
				}
			}()

		    fmt.Println("Hit any key to exit")

		    reader := bufio.NewReader(os.Stdin)
			reader.ReadString('\n')

			shutdown = true

			fmt.Println("Shutting Down\n")
			workPool.Shutdown("name_routine")
		}

	Example Output

	The following shows some sample output

		A336 : 336
		******> QW: 5  AR: 8
		A337 : 337
		*******> QW: 4  AR: 8
		ERROR: Thread Pool At Capacity
		A338 : 338
		*******> QW: 3  AR: 8
		A339 : 339
		*******> QW: 2  AR: 8

		CHANGE FOR ARTICLE
*/
package workpool

import (
	"fmt"
	"log"
	"runtime"
	"sync"
	"sync/atomic"
)

//** TYPES

type (
	// poolWork is passed into the queue for work to be performed
	poolWork struct {
		work          PoolWorker // The Work to be performed
		resultChannel chan error // Used to inform the queue operaion is complete
	}

	// WorkPool implements a work pool with the specified concurrency level and queue capacity
	WorkPool struct {
		shutdownQueueChannel chan string     // Channel used to shut down the queue routine
		shutdownWorkChannel  chan struct{}   // Channel used to shut down the work routines
		shutdownWaitGroup    sync.WaitGroup  // The WaitGroup for shutting down existing routines
		queueChannel         chan poolWork   // Channel used to sync access to the queue
		workChannel          chan PoolWorker // Channel used to process work
		queuedWork           int32           // The number of work items queued
		activeRoutines       int32           // The number of routines active
		queueCapacity        int32           // The max number of items we can store in the queue
	}
)

//** INTERFACES

// PoolWorker must be implemented by the object we will perform work on, now
type PoolWorker interface {
	DoWork(workRoutine int)
}

//** PUBLIC FUNCTIONS

// init is called when the system is inited
func init() {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

// New creates a new WorkPool
//	numberOfRoutines: Sets the number of worker routines that are allowed to process work concurrently
//	queueCapacity:    Sets the maximum number of pending work objects that can be in queue
func New(numberOfRoutines int, queueCapacity int32) (workPool *WorkPool) {
	// Create the work pool and initialize it
	workPool = &WorkPool{
		shutdownQueueChannel: make(chan string),
		shutdownWorkChannel:  make(chan struct{}),
		queueChannel:         make(chan poolWork),
		workChannel:          make(chan PoolWorker, queueCapacity),
		queuedWork:           0,
		activeRoutines:       0,
		queueCapacity:        queueCapacity,
	}

	// Launch the work routines to process work
	for workRoutine := 0; workRoutine < numberOfRoutines; workRoutine++ {
		// Add the routine to the wait group
		workPool.shutdownWaitGroup.Add(1)

		// Start a work routine
		go workPool.workRoutine(workRoutine)
	}

	// Start the queue routine to capture and provide work
	go workPool.queueRoutine()

	return workPool
}

//** PUBLIC MEMBER FUNCTIONS

// Shutdown will release resources and shutdown all processing
func (this *WorkPool) Shutdown(goRoutine string) (err error) {
	defer catchPanic(&err, goRoutine, "Shutdown")

	writeStdout(goRoutine, "Shutdown", "Started")
	writeStdout(goRoutine, "Shutdown", "Queue Routine")

	this.shutdownQueueChannel <- "Down"
	<-this.shutdownQueueChannel

	close(this.queueChannel)
	close(this.shutdownQueueChannel)

	writeStdout(goRoutine, "Shutdown", "Shutting Down Work Routines")

	// Close the channel to shut things down
	close(this.shutdownWorkChannel)
	this.shutdownWaitGroup.Wait()

	close(this.workChannel)

	writeStdout(goRoutine, "Shutdown", "Completed")

	return err
}

// PostWork will post work into the WorkPool. This call will block until the Queue routine reports back
// success or failure that the work is in queue.
func (this *WorkPool) PostWork(goRoutine string, work PoolWorker) (err error) {
	defer catchPanic(&err, goRoutine, "PostWork")

	poolWork := poolWork{work, make(chan error)}

	defer close(poolWork.resultChannel)

	this.queueChannel <- poolWork
	err = <-poolWork.resultChannel

	return err
}

// QueuedWork will return the number of work items in queue
func (this *WorkPool) QueuedWork() int32 {
	return atomic.AddInt32(&this.queuedWork, 0)
}

// ActiveRoutines will return the number of routines performing work
func (this *WorkPool) ActiveRoutines() int32 {
	return atomic.AddInt32(&this.activeRoutines, 0)
}

//** PRIVATE FUNCTIONS

// CatchPanic is used to catch any Panic and log exceptions to Stdout. It will also write the stack trace
func catchPanic(err *error, goRoutine string, functionName string) {
	if r := recover(); r != nil {

		// Capture the stack trace
		buf := make([]byte, 10000)
		runtime.Stack(buf, false)

		writeStdoutf(goRoutine, functionName, "PANIC Defered [%v] : Stack Trace : %v", r, string(buf))

		if err != nil {
			*err = fmt.Errorf("%v", r)
		}
	}
}

// writeStdout is used to write a system message directly to stdout
func writeStdout(goRoutine string, functionName string, message string) {
	log.Printf("%s : %s : %s\n", goRoutine, functionName, message)
}

// writeStdoutf is used to write a formatted system message directly stdout
func writeStdoutf(goRoutine string, functionName string, format string, a ...interface{}) {
	writeStdout(goRoutine, functionName, fmt.Sprintf(format, a...))
}

//** PRIVATE MEMBER FUNCTIONS

// workRoutine performs the work required by the work pool
//  workRoutine: The id for the WorkRoutine
func (this *WorkPool) workRoutine(workRoutine int) {
	for {

		select {
		// Shutdown the WorkRoutine
		case <-this.shutdownWorkChannel:
			writeStdout(fmt.Sprintf("WorkRoutine %d", workRoutine), "workRoutine", "Going Down")
			this.shutdownWaitGroup.Done()
			return

		// There is work in the queue
		case poolWorker := <-this.workChannel:
			this.safelyDoWork(workRoutine, poolWorker)
			break
		}
	}
}

// safelyDoWork executes the user DoWork method
//  workRoutine: The internal id of the go routine making the call
//  poolWorker: The work to perform
func (this *WorkPool) safelyDoWork(workRoutine int, poolWorker PoolWorker) {
	defer catchPanic(nil, "WorkRoutine", "SafelyDoWork")
	defer func() {
		atomic.AddInt32(&this.activeRoutines, -1)
	}()

	// Update the counts
	atomic.AddInt32(&this.queuedWork, -1)
	atomic.AddInt32(&this.activeRoutines, 1)

	// Perform the work
	poolWorker.DoWork(workRoutine)
}

// queueRoutine captures and provides work
func (this *WorkPool) queueRoutine() {
	for {
		select {
		// Shutdown the QueueRoutine
		case <-this.shutdownQueueChannel:
			writeStdout("Queue", "queueRoutine", "Going Down")
			this.shutdownQueueChannel <- "Down"
			return

		// Post work to be processed
		case queueItem := <-this.queueChannel:
			// If the queue is at capacity don't add it
			if atomic.AddInt32(&this.queuedWork, 0) == this.queueCapacity {
				queueItem.resultChannel <- fmt.Errorf("Thread Pool At Capacity")
				continue
			}

			// Increment the queued work count
			atomic.AddInt32(&this.queuedWork, 1)

			// Queue the work for the WorkRoutine to process
			this.workChannel <- queueItem.work

			// Tell the caller the work is queued
			queueItem.resultChannel <- nil
			break
		}
	}
}
<commit_msg>Changed the receivers from "this" to more descriptive names<commit_after>// Copyright 2013 Ardan Studios. All rights reserved.
// Use of workPool source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package workpool implements a pool of go routines that are dedicated to processing work that is posted into the pool.

		Read the following blog post for more information:blogspot
		http://www.goinggo.net/2013/05/thread-pooling-in-go-programming.html

	New Parameters

	The following is a list of parameters for creating a TraceLog:

		numberOfRoutines: Sets the number of worker routines that are allowed to process work concurrently
		queueCapacity:    Sets the maximum number of pending work objects that can be in queue

	WorkPool Management

	Go routines are used to manage and process all the work. A single Queue routine provides the safe queuing of work.
	The Queue routine keeps track of the amount of work in the queue and reports an error if the queue is full.

	The concurrencyLevel parameter defines the number of work routines to create. These work routines will process work
	subbmitted to the queue. The work routines keep track of the number of active work routines for reporting.

	The PostWork method is used to post work into the ThreadPool. This call will block until the Queue routine reports back
	success or failure that the work is in queue.

	Example Use Of ThreadPool

	The following shows a simple test application

		package main

		import (
		    "github.com/goinggo/workpool"
		    "bufio"
		    "fmt"
		    "os"
		    "runtime"
		    "strconv"
		    "time"
		)

		type MyWork struct {
		    Name      string "The Name of a person"
		    BirthYear int    "The Yea the person was born"
		    WP        *workpool.WorkPool
		}

		func (workPool *MyWork) DoWork(workRoutine int) {
		    fmt.Printf("%s : %d\n", workPool.Name, workPool.BirthYear)
		    fmt.Printf("*******> WR: %d  QW: %d  AR: %d\n", workRoutine, workPool.WP.QueuedWork(), workPool.WP.ActiveRoutines())
		    time.Sleep(100 * time.Millisecond)

		    //panic("test")
		}

		func main() {

		    runtime.GOMAXPROCS(runtime.NumCPU())

		    workPool := workpool.New(runtime.NumCPU() * 3, 10)

		    shutdown := false // Just for testing, I Know

		    go func() {

				for i := 0; i < 1000; i++ {

					work := &MyWork{
						Name: "A" + strconv.Itoa(i),
						BirthYear: i,
						WP: workPool,
					}

					err := workPool.PostWork("name_routine", work)

					if err != nil {
						fmt.Printf("ERROR: %s\n", err)
						time.Sleep(100 * time.Millisecond)
					}

					if shutdown == true {
						return
					}
				}
			}()

		    fmt.Println("Hit any key to exit")

		    reader := bufio.NewReader(os.Stdin)
			reader.ReadString('\n')

			shutdown = true

			fmt.Println("Shutting Down\n")
			workPool.Shutdown("name_routine")
		}

	Example Output

	The following shows some sample output

		A336 : 336
		******> QW: 5  AR: 8
		A337 : 337
		*******> QW: 4  AR: 8
		ERROR: Thread Pool At Capacity
		A338 : 338
		*******> QW: 3  AR: 8
		A339 : 339
		*******> QW: 2  AR: 8

		CHANGE FOR ARTICLE
*/
package workpool

import (
	"fmt"
	"log"
	"runtime"
	"sync"
	"sync/atomic"
)

//** TYPES

type (
	// poolWork is passed into the queue for work to be performed
	poolWork struct {
		work          PoolWorker // The Work to be performed
		resultChannel chan error // Used to inform the queue operaion is complete
	}

	// WorkPool implements a work pool with the specified concurrency level and queue capacity
	WorkPool struct {
		shutdownQueueChannel chan string     // Channel used to shut down the queue routine
		shutdownWorkChannel  chan struct{}   // Channel used to shut down the work routines
		shutdownWaitGroup    sync.WaitGroup  // The WaitGroup for shutting down existing routines
		queueChannel         chan poolWork   // Channel used to sync access to the queue
		workChannel          chan PoolWorker // Channel used to process work
		queuedWork           int32           // The number of work items queued
		activeRoutines       int32           // The number of routines active
		queueCapacity        int32           // The max number of items we can store in the queue
	}
)

//** INTERFACES

// PoolWorker must be implemented by the object we will perform work on, now
type PoolWorker interface {
	DoWork(workRoutine int)
}

//** PUBLIC FUNCTIONS

// init is called when the system is inited
func init() {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

// New creates a new WorkPool
//	numberOfRoutines: Sets the number of worker routines that are allowed to process work concurrently
//	queueCapacity:    Sets the maximum number of pending work objects that can be in queue
func New(numberOfRoutines int, queueCapacity int32) (workPool *WorkPool) {
	// Create the work pool and initialize it
	workPool = &WorkPool{
		shutdownQueueChannel: make(chan string),
		shutdownWorkChannel:  make(chan struct{}),
		queueChannel:         make(chan poolWork),
		workChannel:          make(chan PoolWorker, queueCapacity),
		queuedWork:           0,
		activeRoutines:       0,
		queueCapacity:        queueCapacity,
	}

	// Launch the work routines to process work
	for workRoutine := 0; workRoutine < numberOfRoutines; workRoutine++ {
		// Add the routine to the wait group
		workPool.shutdownWaitGroup.Add(1)

		// Start a work routine
		go workPool.workRoutine(workRoutine)
	}

	// Start the queue routine to capture and provide work
	go workPool.queueRoutine()

	return workPool
}

//** PUBLIC MEMBER FUNCTIONS

// Shutdown will release resources and shutdown all processing
func (workPool *WorkPool) Shutdown(goRoutine string) (err error) {
	defer catchPanic(&err, goRoutine, "Shutdown")

	writeStdout(goRoutine, "Shutdown", "Started")
	writeStdout(goRoutine, "Shutdown", "Queue Routine")

	workPool.shutdownQueueChannel <- "Down"
	<-workPool.shutdownQueueChannel

	close(workPool.queueChannel)
	close(workPool.shutdownQueueChannel)

	writeStdout(goRoutine, "Shutdown", "Shutting Down Work Routines")

	// Close the channel to shut things down
	close(workPool.shutdownWorkChannel)
	workPool.shutdownWaitGroup.Wait()

	close(workPool.workChannel)

	writeStdout(goRoutine, "Shutdown", "Completed")

	return err
}

// PostWork will post work into the WorkPool. This call will block until the Queue routine reports back
// success or failure that the work is in queue.
func (workPool *WorkPool) PostWork(goRoutine string, work PoolWorker) (err error) {
	defer catchPanic(&err, goRoutine, "PostWork")

	poolWork := poolWork{work, make(chan error)}

	defer close(poolWork.resultChannel)

	workPool.queueChannel <- poolWork
	err = <-poolWork.resultChannel

	return err
}

// QueuedWork will return the number of work items in queue
func (workPool *WorkPool) QueuedWork() int32 {
	return atomic.AddInt32(&workPool.queuedWork, 0)
}

// ActiveRoutines will return the number of routines performing work
func (workPool *WorkPool) ActiveRoutines() int32 {
	return atomic.AddInt32(&workPool.activeRoutines, 0)
}

//** PRIVATE FUNCTIONS

// CatchPanic is used to catch any Panic and log exceptions to Stdout. It will also write the stack trace
func catchPanic(err *error, goRoutine string, functionName string) {
	if r := recover(); r != nil {

		// Capture the stack trace
		buf := make([]byte, 10000)
		runtime.Stack(buf, false)

		writeStdoutf(goRoutine, functionName, "PANIC Defered [%v] : Stack Trace : %v", r, string(buf))

		if err != nil {
			*err = fmt.Errorf("%v", r)
		}
	}
}

// writeStdout is used to write a system message directly to stdout
func writeStdout(goRoutine string, functionName string, message string) {
	log.Printf("%s : %s : %s\n", goRoutine, functionName, message)
}

// writeStdoutf is used to write a formatted system message directly stdout
func writeStdoutf(goRoutine string, functionName string, format string, a ...interface{}) {
	writeStdout(goRoutine, functionName, fmt.Sprintf(format, a...))
}

//** PRIVATE MEMBER FUNCTIONS

// workRoutine performs the work required by the work pool
//  workRoutine: The id for the WorkRoutine
func (workPool *WorkPool) workRoutine(workRoutine int) {
	for {

		select {
		// Shutdown the WorkRoutine
		case <-workPool.shutdownWorkChannel:
			writeStdout(fmt.Sprintf("WorkRoutine %d", workRoutine), "workRoutine", "Going Down")
			workPool.shutdownWaitGroup.Done()
			return

		// There is work in the queue
		case poolWorker := <-workPool.workChannel:
			workPool.safelyDoWork(workRoutine, poolWorker)
			break
		}
	}
}

// safelyDoWork executes the user DoWork method
//  workRoutine: The internal id of the go routine making the call
//  poolWorker: The work to perform
func (workPool *WorkPool) safelyDoWork(workRoutine int, poolWorker PoolWorker) {
	defer catchPanic(nil, "WorkRoutine", "SafelyDoWork")
	defer func() {
		atomic.AddInt32(&workPool.activeRoutines, -1)
	}()

	// Update the counts
	atomic.AddInt32(&workPool.queuedWork, -1)
	atomic.AddInt32(&workPool.activeRoutines, 1)

	// Perform the work
	poolWorker.DoWork(workRoutine)
}

// queueRoutine captures and provides work
func (workPool *WorkPool) queueRoutine() {
	for {
		select {
		// Shutdown the QueueRoutine
		case <-workPool.shutdownQueueChannel:
			writeStdout("Queue", "queueRoutine", "Going Down")
			workPool.shutdownQueueChannel <- "Down"
			return

		// Post work to be processed
		case queueItem := <-workPool.queueChannel:
			// If the queue is at capacity don't add it
			if atomic.AddInt32(&workPool.queuedWork, 0) == workPool.queueCapacity {
				queueItem.resultChannel <- fmt.Errorf("Thread Pool At Capacity")
				continue
			}

			// Increment the queued work count
			atomic.AddInt32(&workPool.queuedWork, 1)

			// Queue the work for the WorkRoutine to process
			workPool.workChannel <- queueItem.work

			// Tell the caller the work is queued
			queueItem.resultChannel <- nil
			break
		}
	}
}
<|endoftext|>


<commit_before>package arn

import (
	"errors"

	"github.com/aerogo/aero"
	"github.com/aerogo/api"
	"github.com/aerogo/markdown"
	"github.com/animenotifier/arn/autocorrect"
)

// Force interface implementations
var (
	_ Likeable       = (*Thread)(nil)
	_ api.Newable    = (*Thread)(nil)
	_ api.Editable   = (*Thread)(nil)
	_ api.Actionable = (*Thread)(nil)
)

// Actions
func init() {
	API.RegisterActions("Thread", []*api.Action{
		// Like thread
		LikeAction(),

		// Unlike thread
		UnlikeAction(),
	})
}

// Authorize returns an error if the given API POST request is not authorized.
func (thread *Thread) Authorize(ctx *aero.Context, action string) error {
	if !ctx.HasSession() {
		return errors.New("Neither logged in nor in session")
	}

	if action == "edit" {
		user := GetUserFromContext(ctx)

		if thread.AuthorID != user.ID {
			return errors.New("Can't edit the threads of other users")
		}
	}

	return nil
}

// Create sets the data for a new thread with data we received from the API request.
func (thread *Thread) Create(ctx *aero.Context) error {
	data, err := ctx.Request().Body().JSONObject()

	if err != nil {
		return err
	}

	userID, ok := ctx.Session().Get("userId").(string)

	if !ok || userID == "" {
		return errors.New("Not logged in")
	}

	user, err := GetUser(userID)

	if err != nil {
		return err
	}

	thread.ID = GenerateID("Thread")
	thread.Title, _ = data["title"].(string)
	thread.Text, _ = data["text"].(string)
	thread.AuthorID = user.ID
	thread.Sticky, _ = data["sticky"].(int)
	thread.Likes = []string{}
	thread.Posts = []string{}
	thread.Created = DateTimeUTC()
	thread.Edited = ""

	// Post-process text
	thread.Title = autocorrect.FixThreadTitle(thread.Title)
	thread.Text = autocorrect.FixPostText(thread.Text)

	// Tags
	tags, _ := data["tags"].([]interface{})
	thread.Tags = make([]string, len(tags))

	for i := range thread.Tags {
		thread.Tags[i] = tags[i].(string)
	}

	if len(tags) < 1 {
		return errors.New("Need to specify at least one tag")
	}

	if len(thread.Title) < 10 {
		return errors.New("Title too short: Should be at least 10 characters")
	}

	if len(thread.Text) < 10 {
		return errors.New("Text too short: Should be at least 10 characters")
	}

	return nil
}

// AfterEdit sets the edited date on the thread object.
func (thread *Thread) AfterEdit(ctx *aero.Context) error {
	thread.Edited = DateTimeUTC()
	thread.html = markdown.Render(thread.Text)
	return nil
}

// Save saves the thread object in the database.
func (thread *Thread) Save() {
	DB.Set("Thread", thread.ID, thread)
}
<commit_msg>✨ Added the thread deletion.<commit_after>package arn

import (
	"errors"

	"github.com/aerogo/aero"
	"github.com/aerogo/api"
	"github.com/aerogo/markdown"
	"github.com/animenotifier/arn/autocorrect"
)

// Force interface implementations
var (
	_ Likeable       = (*Thread)(nil)
	_ api.Newable    = (*Thread)(nil)
	_ api.Editable   = (*Thread)(nil)
	_ api.Actionable = (*Thread)(nil)
)

// Actions
func init() {
	API.RegisterActions("Thread", []*api.Action{
		// Like thread
		LikeAction(),

		// Unlike thread
		UnlikeAction(),
	})
}

// Authorize returns an error if the given API POST request is not authorized.
func (thread *Thread) Authorize(ctx *aero.Context, action string) error {
	if !ctx.HasSession() {
		return errors.New("Neither logged in nor in session")
	}

	if action == "edit" {
		user := GetUserFromContext(ctx)

		if thread.AuthorID != user.ID {
			return errors.New("Can't edit the threads of other users")
		}
	}

	return nil
}

// Create sets the data for a new thread with data we received from the API request.
func (thread *Thread) Create(ctx *aero.Context) error {
	data, err := ctx.Request().Body().JSONObject()

	if err != nil {
		return err
	}

	userID, ok := ctx.Session().Get("userId").(string)

	if !ok || userID == "" {
		return errors.New("Not logged in")
	}

	user, err := GetUser(userID)

	if err != nil {
		return err
	}

	thread.ID = GenerateID("Thread")
	thread.Title, _ = data["title"].(string)
	thread.Text, _ = data["text"].(string)
	thread.AuthorID = user.ID
	thread.Sticky, _ = data["sticky"].(int)
	thread.Likes = []string{}
	thread.Posts = []string{}
	thread.Created = DateTimeUTC()
	thread.Edited = ""

	// Post-process text
	thread.Title = autocorrect.FixThreadTitle(thread.Title)
	thread.Text = autocorrect.FixPostText(thread.Text)

	// Tags
	tags, _ := data["tags"].([]interface{})
	thread.Tags = make([]string, len(tags))

	for i := range thread.Tags {
		thread.Tags[i] = tags[i].(string)
	}

	if len(tags) < 1 {
		return errors.New("Need to specify at least one tag")
	}

	if len(thread.Title) < 10 {
		return errors.New("Title too short: Should be at least 10 characters")
	}

	if len(thread.Text) < 10 {
		return errors.New("Text too short: Should be at least 10 characters")
	}

	return nil
}

// AfterEdit sets the edited date on the thread object.
func (thread *Thread) AfterEdit(ctx *aero.Context) error {
	thread.Edited = DateTimeUTC()
	thread.html = markdown.Render(thread.Text)
	return nil
}

// Save saves the thread object in the database.
func (thread *Thread) Save() {
	DB.Set("Thread", thread.ID, thread)
}

// Delete deletes the thread and its posts from the database.
func (thread *Thread) Delete() error {
	// Delete all the posts contained in the thread
	for _, postID := range thread.Posts {
		// We don't use the Post.Delete function since it would
		// call unnecessary code for the thread deletion
		DB.Delete("Post", postID)
	}

	DB.Delete("Thread", thread.ID)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.246"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.213", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.247 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.247"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.214", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package xxhash

import (
	"encoding/binary"
	"encoding/hex"
	"hash"
)

var (
	xxhash64 *XXHash64
	_        hash.Hash64 = xxhash64
	_        hash.Hash   = xxhash64
)

// Constants
const (
	prime64_1 = 11400714785074694791
	prime64_2 = 14029467366897019727
	prime64_3 = 1609587929392839161
	prime64_4 = 9650029242287828579
	prime64_5 = 2870177450012600261
)

// XXHash64 implements the 64-bit variant of the xxHash algorithm.
type XXHash64 struct {
	seed           uint64
	v1, v2, v3, v4 uint64
	len            uint64
	mem            [32]byte
	memsize        uint32
}

// String returns the current value of the hash as a hexadecimal string
func (x *XXHash64) String() string {
	return hex.EncodeToString(x.Sum(nil))
}

// Uint64 returns the current value of the hash as an uint64
func (x *XXHash64) Uint64() uint64 {
	return binary.BigEndian.Uint64(x.Sum(nil))
}

/*
 * Implement hash.Hash64 interface
 */

// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying has state
func (x *XXHash64) Sum(b []byte) []byte {
	v := x.Sum64()
	return append(b, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32),
		byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}

// Reset resets the Hash to its initial state.
func (x *XXHash64) Reset() {
	x.v1 = x.seed + prime64_1 + prime64_2
	x.v2 = x.seed + prime64_2
	x.v3 = x.seed // + 0000
	x.v4 = x.seed - prime64_1
	x.len = 0
	x.memsize = 0
	for i := range x.mem {
		x.mem[i] = 0
	}
}

// Size returns the number of bytes Sum will return.
func (x *XXHash64) Size() int {
	return 8
}

// BlockSize returns the hash's underlying block size.
func (x *XXHash64) BlockSize() int {
	return 32
}

// Sum64 returns the current hash state
func (x *XXHash64) Sum64() uint64 {
	var h uint64

	if x.len >= 32 {
		v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4

		h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)

		v1 *= prime64_2
		v1 = rotl64_31(v1)
		v1 *= prime64_1
		h ^= v1
		h = h*prime64_1 + prime64_4

		v2 *= prime64_2
		v2 = rotl64_31(v2)
		v2 *= prime64_1
		h ^= v2
		h = h*prime64_1 + prime64_4

		v3 *= prime64_2
		v3 = rotl64_31(v3)
		v3 *= prime64_1
		h ^= v3
		h = h*prime64_1 + prime64_4

		v4 *= prime64_2
		v4 = rotl64_31(v4)
		v4 *= prime64_1
		h ^= v4
		h = h*prime64_1 + prime64_4
	} else {
		h = x.seed + prime64_5
	}

	h += x.len

	if x.memsize > 0 {
		in := x.mem[:x.memsize]
		for len(in) >= 8 {
			h ^= rotl64_31(bToU64(in[:8])*prime64_2) * prime64_1
			h = rotl64_27(h)*prime64_1 + prime64_4
			in = in[8:len(in):len(in)]
		}
		if len(in) >= 4 {
			h ^= uint64(bToU32(in[:4])) * prime64_1
			h = rotl64_23(h)*prime64_2 + prime64_3
			in = in[4:len(in):len(in)]
		}
		for i := 0; i < len(in); i++ {
			h ^= uint64(uint8(in[i])) * prime64_5
			h = rotl64_11(h) * prime64_1
		}
	}

	h ^= h >> 33
	h *= prime64_2
	h ^= h >> 29
	h *= prime64_3
	h ^= h >> 32

	return h
}

// Write adds more data to the running hash and updates the hash state
// It never returns an error
func (x *XXHash64) Write(input []byte) (int, error) {
	l := len(input)
	x.len += uint64(l)

	if x.memsize+uint32(l) < 32 {
		// new data fits into the buffer
		x.memsize += uint32(copy(x.mem[x.memsize:], input))
		return l, nil
	}

	if x.memsize > 0 {
		// new data does not fit into the buffer
		// and some data is still unprocessed from previous update
		n := 32 - x.memsize
		copy(x.mem[x.memsize:], input[:n:len(input)])

		x.v1 += bToU64(x.mem[:8:8]) * prime64_2
		x.v1 = rotl64_31(x.v1) * prime64_1

		x.v2 += bToU64(x.mem[8:16:16]) * prime64_2
		x.v2 = rotl64_31(x.v2) * prime64_1

		x.v3 += bToU64(x.mem[16:24:24]) * prime64_2
		x.v3 = rotl64_31(x.v3) * prime64_1

		x.v4 += bToU64(x.mem[24:32:32]) * prime64_2
		x.v4 = rotl64_31(x.v4) * prime64_1

		input = input[n:len(input):len(input)]
		x.memsize = 0
	}

	if len(input) >= 32 {
		for len(input) >= 32 {
			x.v1 += bToU64(input[:8:8]) * prime64_2
			x.v1 = rotl64_31(x.v1) * prime64_1

			x.v2 += bToU64(input[8:16:16]) * prime64_2
			x.v2 = rotl64_31(x.v2) * prime64_1

			x.v3 += bToU64(input[16:24:24]) * prime64_2
			x.v3 = rotl64_31(x.v3) * prime64_1

			x.v4 += bToU64(input[24:32:32]) * prime64_2
			x.v4 = rotl64_31(x.v4) * prime64_1

			input = input[32:len(input):len(input)]
		}
	}

	if len(input) > 0 {
		x.memsize += uint32(copy(x.mem[x.memsize:], input))
	}

	return l, nil
}

// NewSeedXXHash64 returns an instance of XXHash64 with the specified seed.
func NewSeedXXHash64(seed uint64) *XXHash64 {
	x := &XXHash64{
		seed: seed,
	}
	x.Reset()
	return x
}

// NewXXHash64 returns an instance of XXHash64 with seed set to 0.
func NewXXHash64() *XXHash64 {
	return NewSeedXXHash64(0)
}
<commit_msg>Improved performance.<commit_after>package xxhash

import (
	"encoding/binary"
	"encoding/hex"
	"hash"
)

var (
	xxhash64 *XXHash64
	_        hash.Hash64 = xxhash64
	_        hash.Hash   = xxhash64
)

// Constants
const (
	prime64_1 = 11400714785074694791
	prime64_2 = 14029467366897019727
	prime64_3 = 1609587929392839161
	prime64_4 = 9650029242287828579
	prime64_5 = 2870177450012600261
)

// XXHash64 implements the 64-bit variant of the xxHash algorithm.
type XXHash64 struct {
	seed           uint64
	v1, v2, v3, v4 uint64
	len            uint64
	mem            [32]byte
	memsize        uint32
}

// String returns the current value of the hash as a hexadecimal string
func (x *XXHash64) String() string {
	return hex.EncodeToString(x.Sum(nil))
}

// Uint64 returns the current value of the hash as an uint64
func (x *XXHash64) Uint64() uint64 {
	return binary.BigEndian.Uint64(x.Sum(nil))
}

/*
 * Implement hash.Hash64 interface
 */

// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying has state
func (x *XXHash64) Sum(b []byte) []byte {
	v := x.Sum64()
	return append(b, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32),
		byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}

// Reset resets the Hash to its initial state.
func (x *XXHash64) Reset() {
	x.v1 = x.seed + prime64_1 + prime64_2
	x.v2 = x.seed + prime64_2
	x.v3 = x.seed // + 0000
	x.v4 = x.seed - prime64_1
	x.len = 0
	x.memsize = 0
	for i := range x.mem {
		x.mem[i] = 0
	}
}

// Size returns the number of bytes Sum will return.
func (x *XXHash64) Size() int {
	return 8
}

// BlockSize returns the hash's underlying block size.
func (x *XXHash64) BlockSize() int {
	return 32
}

// Sum64 returns the current hash state
func (x *XXHash64) Sum64() uint64 {
	var h uint64

	if x.len >= 32 {
		v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4

		h = rotl64_1(v1) + rotl64_7(v2) + rotl64_12(v3) + rotl64_18(v4)

		v1 *= prime64_2
		v1 = rotl64_31(v1)
		v1 *= prime64_1
		h ^= v1
		h = h*prime64_1 + prime64_4

		v2 *= prime64_2
		v2 = rotl64_31(v2)
		v2 *= prime64_1
		h ^= v2
		h = h*prime64_1 + prime64_4

		v3 *= prime64_2
		v3 = rotl64_31(v3)
		v3 *= prime64_1
		h ^= v3
		h = h*prime64_1 + prime64_4

		v4 *= prime64_2
		v4 = rotl64_31(v4)
		v4 *= prime64_1
		h ^= v4
		h = h*prime64_1 + prime64_4
	} else {
		h = x.seed + prime64_5
	}

	h += x.len

	if x.memsize > 0 {
		in := x.mem[:x.memsize:x.memsize]
		for len(in) >= 8 {
			h ^= rotl64_31(bToU64(in[:8:8])*prime64_2) * prime64_1
			h = rotl64_27(h)*prime64_1 + prime64_4
			in = in[8:len(in):len(in)]
		}
		if len(in) >= 4 {
			h ^= uint64(bToU32(in[:4:4])) * prime64_1
			h = rotl64_23(h)*prime64_2 + prime64_3
			in = in[4:len(in):len(in)]
		}
		for i := 0; i < len(in); i++ {
			h ^= uint64(uint8(in[i])) * prime64_5
			h = rotl64_11(h) * prime64_1
		}
	}

	h ^= h >> 33
	h *= prime64_2
	h ^= h >> 29
	h *= prime64_3
	h ^= h >> 32

	return h
}

// Write adds more data to the running hash and updates the hash state
// It never returns an error
func (x *XXHash64) Write(input []byte) (int, error) {
	l := len(input)
	x.len += uint64(l)

	if x.memsize+uint32(l) < 32 {
		// new data fits into the buffer
		x.memsize += uint32(copy(x.mem[x.memsize:], input))
		return l, nil
	}

	if x.memsize > 0 {
		// new data does not fit into the buffer
		// and some data is still unprocessed from previous update
		n := 32 - x.memsize
		copy(x.mem[x.memsize:], input[:n:len(input)])

		x.v1 += bToU64(x.mem[:8:8]) * prime64_2
		x.v1 = rotl64_31(x.v1) * prime64_1

		x.v2 += bToU64(x.mem[8:16:16]) * prime64_2
		x.v2 = rotl64_31(x.v2) * prime64_1

		x.v3 += bToU64(x.mem[16:24:24]) * prime64_2
		x.v3 = rotl64_31(x.v3) * prime64_1

		x.v4 += bToU64(x.mem[24:32:32]) * prime64_2
		x.v4 = rotl64_31(x.v4) * prime64_1

		input = input[n:len(input):len(input)]
		x.memsize = 0
	}

	if len(input) >= 32 {
		for len(input) >= 32 {
			x.v1 += bToU64(input[:8:8]) * prime64_2
			x.v1 = rotl64_31(x.v1) * prime64_1

			x.v2 += bToU64(input[8:16:16]) * prime64_2
			x.v2 = rotl64_31(x.v2) * prime64_1

			x.v3 += bToU64(input[16:24:24]) * prime64_2
			x.v3 = rotl64_31(x.v3) * prime64_1

			x.v4 += bToU64(input[24:32:32]) * prime64_2
			x.v4 = rotl64_31(x.v4) * prime64_1

			input = input[32:len(input):len(input)]
		}
	}

	if len(input) > 0 {
		x.memsize += uint32(copy(x.mem[x.memsize:], input))
	}

	return l, nil
}

// NewSeedXXHash64 returns an instance of XXHash64 with the specified seed.
func NewSeedXXHash64(seed uint64) *XXHash64 {
	x := &XXHash64{
		seed: seed,
	}
	x.Reset()
	return x
}

// NewXXHash64 returns an instance of XXHash64 with seed set to 0.
func NewXXHash64() *XXHash64 {
	return NewSeedXXHash64(0)
}
<|endoftext|>


<commit_before>package font

import (
	"image"
	"image/draw"
	"io/ioutil"
	"log"

	"github.com/go-gl/gl/v4.1-core/gl"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
)

var fontList = map[string]*Font{}

// Font object
type Font struct {
	ttf *truetype.Font
}

// New returns a newly created Font object
func New(file string) (*Font, error) {

	if font, found := fontList[file]; found {
		return font, nil
	}
	s := &Font{}
	data, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatal(err)
	}
	s.ttf, err = truetype.Parse(data)
	if err != nil {
		log.Fatal(err)
	}

	fontList[file] = s
	return fontList[file], nil
}

// Draw will draw the font with text
func (font *Font) Draw(text string, size float64) {
	context := freetype.NewContext()
	context.SetFont(font.ttf)

	img := image.NewRGBA(image.Rect(0, 0, 800, 600))
	draw.Draw(img, img.Bounds(), image.Transparent, image.ZP, draw.Src)

	context.SetDst(img)
	context.SetClip(img.Bounds())
	context.SetSrc(image.Black)

	context.SetFontSize(size)
	context.SetDPI(300)

	var tex uint32
	gl.GenTextures(1, &tex)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, tex)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, tex)
	context.DrawString(text, freetype.Pt(0, 200))
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(img.Rect.Size().X),
		int32(img.Rect.Size().Y),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(img.Pix))

}
<commit_msg>change how we are going to draw fonts to creating textures<commit_after>package font

import (
	"image"
	"image/draw"
	"io/ioutil"
	"log"

	"github.com/go-gl/gl/v4.1-core/gl"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
)

var fontList = map[string]*Font{}

// Font object
type Font struct {
	ttf *truetype.Font
}

// New returns a newly created Font object
func New(file string) (*Font, error) {

	if font, found := fontList[file]; found {
		return font, nil
	}
	s := &Font{}
	data, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatal(err)
	}
	s.ttf, err = truetype.Parse(data)
	if err != nil {
		log.Fatal(err)
	}

	fontList[file] = s
	return fontList[file], nil
}

// CreateTexture will create a texture for given text
func (font *Font) CreateTexture(text string, width int, height int, size float64, dpi float64) uint32 {
	context := freetype.NewContext()
	context.SetFont(font.ttf)

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	draw.Draw(img, img.Bounds(), image.Transparent, image.ZP, draw.Src)

	context.SetDst(img)
	context.SetClip(img.Bounds())
	context.SetSrc(image.Black)

	context.SetFontSize(size)
	context.SetDPI(dpi)

	var tex uint32
	gl.GenTextures(1, &tex)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, tex)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, tex)
	context.DrawString(text, freetype.Pt(0, height/2))
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(img.Rect.Size().X),
		int32(img.Rect.Size().Y),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(img.Pix))

	return tex
}
<|endoftext|>


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

/*
Represents dates from Jan 1 1970 - Jun 6 2149 as days since the Unix epoch.
This format requires 2 bytes (it's a uint16), in contrast to the 16 or 20 byte
representations (on 32 or 64-bit systems, respectively) used by the standard
time package.

Timezone is accounted for when applicable; when converting from standard time
format into a Date, the date relative to the time value's zone is retained.
Times at any point during a given day (relative to timezone) are normalized to
the same date.

Conversely, conversions back to standard time format may be done using the
Local, UTC, and In methods (semantically corresponding to the same-named Time
methods), but with the result normalized to midnight (the beginning of the day)
relative to that timezone.

All functions and methods with the same names as those found in the stdlib time
package have identical semantics in epochdate, with the exception that
epochdate truncates time-of-day information.
*/
package epochdate

import (
	"errors"
	"time"
)

const (
	day     = 60 * 60 * 24
	maxUnix = (1<<16)*day - 1
)

const (
	RFC3339        = "2006-01-02"
	AmericanShort  = "1-2-06"
	AmericanCommon = "01-02-06"
)

var ErrOutOfRange = errors.New("The given date is out of range")

type Date uint16

func Today() Date {
	date, err := NewFromTime(time.Now())
	if err != nil {
		panic(err)
	}
	return date
}

func Parse(layout, value string) (d Date, err error) {
	t, err := time.Parse(layout, value)
	if err == nil {
		d, err = NewFromTime(t)
	}
	return
}

func NewFromTime(t time.Time) (Date, error) {
	s := t.Unix()
	_, offset := t.Zone()
	return NewFromUnix(s + int64(offset))
}

func NewFromDate(year int, month time.Month, day int) (Date, error) {
	return NewFromUnix(time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Unix())
}

// NewFromUnix creates a Date from a Unix timestamp, relative to any location
// Specifically, if you pass in t.Unix(), where t is a time.Time value with a
// non-UTC zone, you may receive an unexpected Date. Unless this behavior is
// specifically desired (returning the date in one location at the given time
// instant in another location), it's best to use epochdate.NewFromTime(t),
// which normalizes the resulting Date value by adjusting for zone offsets.
func NewFromUnix(seconds int64) (d Date, err error) {
	if UnixInRange(seconds) {
		d = Date(seconds / day)
	} else {
		err = ErrOutOfRange
	}
	return
}

// UnixInRange is true if the provided Unix timestamp is in Date's
// representable range. The timestamp is interpreted according to the semantics
// used by NewFromUnix. You probably won't need to use this, since this will
// only return false if NewFromUnix returns an error of ErrOutOfRange.
func UnixInRange(seconds int64) bool {
	return seconds >= 0 && seconds <= maxUnix
}

// Returns an RFC3339/ISO-8601 date string, of the form "2006-01-02".
func (d Date) String() string {
	return d.Format(RFC3339)
}

// Identical to time.Time.Format, except that any time-of-day format specifiers
// will be equivalent to "00:00:00Z".
func (d Date) Format(layout string) string {
	return d.UTC().Format(layout)
}

func (d Date) Date() (year int, month time.Month, day int) {
	return d.UTC().Date()
}

// UTC returns a UTC Time object set to 00:00:00 on the given date
func (d Date) UTC() time.Time {
	return time.Unix(int64(d)*day, 0).UTC()
}

// Local returns a local Time object set to 00:00:00 on the given date
func (d Date) Local() time.Time {
	return d.In(time.Local)
}

// In returns a location-relative Time object set to 00:00:00 on the given date
func (d Date) In(loc *time.Location) time.Time {
	t := time.Unix(int64(d)*day, 0).In(loc)
	_, offset := t.Zone()
	return t.Add(time.Duration(-offset) * time.Second)
}

func (d Date) MarshalJSON() ([]byte, error) {
	return []byte(d.Format(`"` + RFC3339 + `"`)), nil
}

func (d *Date) UnmarshalJSON(data []byte) (err error) {
	*d, err = Parse(`"`+RFC3339+`"`, string(data))
	return
}
<commit_msg>Improved documentation.<commit_after>// Copyright 2012 Kevin Gillette. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Represents dates from Jan 1 1970 - Jun 6 2149 as days since the Unix epoch.
This format requires 2 bytes (it's a uint16), in contrast to the 16 or 20 byte
representations (on 32 or 64-bit systems, respectively) used by the standard
time package.

Timezone is accounted for when applicable; when converting from standard time
format into a Date, the date relative to the time value's zone is retained.
Times at any point during a given day (relative to timezone) are normalized to
the same date.

Conversely, conversions back to standard time format may be done using the
Local, UTC, and In methods (semantically corresponding to the same-named Time
methods), but with the result normalized to midnight (the beginning of the day)
relative to that timezone.

All functions and methods with the same names as those found in the stdlib time
package have identical semantics in epochdate, with the exception that
epochdate truncates time-of-day information.
*/
package epochdate

import (
	"errors"
	"time"
)

const (
	day     = 60 * 60 * 24
	maxUnix = (1<<16)*day - 1
)

const (
	RFC3339        = "2006-01-02"
	AmericanShort  = "1-2-06"
	AmericanCommon = "01-02-06"
)

var ErrOutOfRange = errors.New("The given date is out of range")

type Date uint16

// Today returns the current date, relative to the current timezone.
func Today() Date {
	date, err := NewFromTime(time.Now())
	if err != nil {
		panic(err)
	}
	return date
}

// Parse follows the same semantics as time.Parse, but ignores time-of-day
// information and returns a Date value.
func Parse(layout, value string) (d Date, err error) {
	t, err := time.Parse(layout, value)
	if err == nil {
		d, err = NewFromTime(t)
	}
	return
}

// NewFromTime returns a Date equivalent to NewFromDate(t.Date()),
// where t is a time.Time object.
func NewFromTime(t time.Time) (Date, error) {
	s := t.Unix()
	_, offset := t.Zone()
	return NewFromUnix(s + int64(offset))
}

// NewFromDate returns a Date value corresponding to the supplied
// year, month, and day.
func NewFromDate(year int, month time.Month, day int) (Date, error) {
	return NewFromUnix(time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Unix())
}

// NewFromUnix creates a Date from a Unix timestamp, relative to any location
// Specifically, if you pass in t.Unix(), where t is a time.Time value with a
// non-UTC zone, you may receive an unexpected Date. Unless this behavior is
// specifically desired (returning the date in one location at the given time
// instant in another location), it's best to use epochdate.NewFromTime(t),
// which normalizes the resulting Date value by adjusting for zone offsets.
func NewFromUnix(seconds int64) (d Date, err error) {
	if UnixInRange(seconds) {
		d = Date(seconds / day)
	} else {
		err = ErrOutOfRange
	}
	return
}

// UnixInRange is true if the provided Unix timestamp is in Date's
// representable range. The timestamp is interpreted according to the semantics
// used by NewFromUnix. You probably won't need to use this, since this will
// only return false if NewFromUnix returns an error of ErrOutOfRange.
func UnixInRange(seconds int64) bool {
	return seconds >= 0 && seconds <= maxUnix
}

// Returns an RFC3339/ISO-8601 date string, of the form "2006-01-02".
func (d Date) String() string {
	return d.Format(RFC3339)
}

// Identical to time.Time.Format, except that any time-of-day format specifiers
// that are used will be equivalent to "00:00:00Z".
func (d Date) Format(layout string) string {
	return d.UTC().Format(layout)
}

// Date is semantically identical to the behavior of t.Date(), where t is a
// time.Time value.
func (d Date) Date() (year int, month time.Month, day int) {
	return d.UTC().Date()
}

// UTC returns a UTC Time object set to 00:00:00 on the given date.
func (d Date) UTC() time.Time {
	return time.Unix(int64(d)*day, 0).UTC()
}

// Local returns a local Time object set to 00:00:00 on the given date.
func (d Date) Local() time.Time {
	return d.In(time.Local)
}

// In returns a location-relative Time object set to 00:00:00 on the given date.
func (d Date) In(loc *time.Location) time.Time {
	t := time.Unix(int64(d)*day, 0).In(loc)
	_, offset := t.Zone()
	return t.Add(time.Duration(-offset) * time.Second)
}

func (d Date) MarshalJSON() ([]byte, error) {
	return []byte(d.Format(`"` + RFC3339 + `"`)), nil
}

func (d *Date) UnmarshalJSON(data []byte) (err error) {
	*d, err = Parse(`"`+RFC3339+`"`, string(data))
	return
}
<|endoftext|>