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

package safehttp

import (
	"fmt"
	"log"
	"net/http"
)

// The HTTP request methods defined by RFC.
const (
	MethodConnect = "CONNECT" // RFC 7231, 4.3.6
	MethodDelete  = "DELETE"  // RFC 7231, 4.3.5
	MethodGet     = "GET"     // RFC 7231, 4.3.1
	MethodHead    = "HEAD"    // RFC 7231, 4.3.2
	MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
	MethodPatch   = "PATCH"   // RFC 5789
	MethodPost    = "POST"    // RFC 7231, 4.3.3
	MethodPut     = "PUT"     // RFC 7231, 4.3.4
	MethodTrace   = "TRACE"   // RFC 7231, 4.3.8
)

// ServeMux is an HTTP request multiplexer. It matches the URL of each incoming
// request against a list of registered patterns and calls the handler for
// the pattern that most closely matches the URL.
//
// Patterns names are fixed, rooted paths, like "/favicon.ico", or rooted
// subtrees like "/images/" (note the trailing slash). Longer patterns take
// precedence over shorter ones, so that if there are handlers registered for
// both "/images/" and "/images/thumbnails/", the latter handler will be called
// for paths beginning "/images/thumbnails/" and the former will receive
// requests for any other paths in the "/images/" subtree.
//
// Note that since a pattern ending in a slash names a rooted subtree, the
// pattern "/" matches all paths not matched by other registered patterns,
// not just the URL with Path == "/".
//
// If a subtree has been registered and a request is received naming the subtree
// root without its trailing slash, ServeMux redirects that request to
// the subtree root (adding the trailing slash). This behavior can be overridden
// with a separate registration for the path without the trailing slash. For
// example, registering "/images/" causes ServeMux to redirect a request for
// "/images" to "/images/", unless "/images" has been registered separately.
//
// Patterns may optionally begin with a host name, restricting matches to URLs
// on that host only.  Host-specific patterns take precedence over general
// patterns, so that a handler might register for the two patterns "/codesearch"
// and "codesearch.google.com/" without also taking over requests for
// "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path and the Host
// header, stripping the port number and redirecting any request containing . or
// .. elements or repeated slashes to an equivalent, cleaner URL.
//
// Multiple handlers can be registered for a single pattern, as long as they
// handle different HTTP methods.
type ServeMux struct {
	mux      *http.ServeMux
	handlers map[string]*registeredHandler

	dispatcher              Dispatcher
	interceptors            []Interceptor
	methodNotAllowedHandler handlerRegistration
}

// ServeHTTP dispatches the request to the handler whose method matches the
// incoming request and whose pattern most closely matches the request URL.
//
//  For each incoming request:
//  - [Before Phase] Interceptor.Before methods are called for every installed
//    interceptor, until an interceptor writes to a ResponseWriter (including
//    errors) or panics,
//  - the handler is called after a [Before Phase] if no writes or panics occured,
//  - the handler triggers the [Commit Phase] by writing to the ResponseWriter,
//  - [Commit Phase] Interceptor.Commit methods run for every interceptor whose
//    Before method was called,
//  - [Dispatcher Phase] after the [Commit Phase], the Dispatcher's appropriate
//    write method is called; the Dispatcher is responsible for determining whether
//    the response is indeed safe and writing it,
//  - if the handler attempts to write more than once, it is treated as an
//    unrecoverable error; the request processing ends abrubptly with a panic and
//    nothing else happens (note: this will change as soon as [After Phase] is
//    introduced)
//
// Interceptors should NOT rely on the order they're run.
func (m *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m.mux.ServeHTTP(w, r)
}

// Handle registers a handler for the given pattern and method. If a handler is
// registered twice for the same pattern and method, Build will panic.
//
// InterceptorConfigs can be passed in order to modify the behavior of the
// interceptors on a registered handler. Passing an InterceptorConfig whose
// corresponding Interceptor was not installed will produce no effect. If
// multiple configurations are passed for the same Interceptor, Mux will panic.
func (m *ServeMux) Handle(pattern string, method string, h Handler, cfgs ...InterceptorConfig) {
	methodNotAllowed := handlerConfig{
		Dispatcher:   m.dispatcher,
		Handler:      m.methodNotAllowedHandler.handler,
		Interceptors: configureInterceptors(m.interceptors, m.methodNotAllowedHandler.cfgs),
	}

	if m.handlers[pattern] == nil {
		m.handlers[pattern] = &registeredHandler{
			pattern:          pattern,
			methodNotAllowed: methodNotAllowed,
			methods:          make(map[string]handlerConfig),
		}
		m.mux.Handle(pattern, m.handlers[pattern])
	}
	m.handlers[pattern].handleMethod(method,
		handlerConfig{
			Dispatcher:   m.dispatcher,
			Handler:      h,
			Interceptors: configureInterceptors(m.interceptors, cfgs),
		})
}

// ServeMuxConfig is a builder for ServeMux.
type ServeMuxConfig struct {
	dispatcher              Dispatcher
	interceptors            []Interceptor
	methodNotAllowedHandler handlerRegistration
}

// NewServeMuxConfig crates a ServeMuxConfig with the provided Dispatcher. If
// the provided Dispatcher is nil, the DefaultDispatcher is used.
func NewServeMuxConfig(disp Dispatcher) *ServeMuxConfig {
	if disp == nil {
		disp = &DefaultDispatcher{}
	}
	return &ServeMuxConfig{
		dispatcher: disp,
		methodNotAllowedHandler: handlerRegistration{
			handler: HandlerFunc(defaultMethotNotAllowed),
		},
	}
}

type handlerRegistration struct {
	handler Handler
	cfgs    []InterceptorConfig
}

// HandleMethodNotAllowed registers a handler that runs when a given method is
// not allowed for a registered path.
func (s *ServeMuxConfig) HandleMethodNotAllowed(h Handler, cfgs ...InterceptorConfig) {
	s.methodNotAllowedHandler = handlerRegistration{
		handler: h,
		cfgs:    cfgs,
	}
}

func defaultMethotNotAllowed(w ResponseWriter, req *IncomingRequest) Result {
	return w.WriteError(StatusMethodNotAllowed)
}

// Intercept installs the given interceptors.
//
// Interceptors order is respected and interceptors are always run in the
// order they've been installed.
//
// Calling Intercept multiple times is valid. Interceptors that are added last
// will run last.
func (s *ServeMuxConfig) Intercept(is ...Interceptor) {
	s.interceptors = append(s.interceptors, is...)
}

// Mux returns the ServeMux with a copy of the current configuration.
func (s *ServeMuxConfig) Mux() *ServeMux {
	freezeLocalDev = true
	if IsLocalDev() {
		log.Println("Warning: creating safehttp.Mux in dev mode. This configuration is not valid for production use")
	}

	if s.dispatcher == nil {
		panic("Use NewServeMuxConfig instead of creating ServeMuxConfig using a composite literal.")
	}

	m := &ServeMux{
		mux:                     http.NewServeMux(),
		handlers:                make(map[string]*registeredHandler),
		dispatcher:              s.dispatcher,
		interceptors:            s.interceptors,
		methodNotAllowedHandler: s.methodNotAllowedHandler,
	}
	return m
}

// Clone creates a copy of the current config.
// This can be used to create several instances of Mux that share the same set of
// plugins and some common handlers.
func (s *ServeMuxConfig) Clone() *ServeMuxConfig {
	c := &ServeMuxConfig{
		dispatcher:              s.dispatcher,
		interceptors:            make([]Interceptor, len(s.interceptors)),
		methodNotAllowedHandler: s.methodNotAllowedHandler,
	}
	copy(c.interceptors, s.interceptors)
	return c
}

type registeredHandler struct {
	pattern          string
	methods          map[string]handlerConfig
	methodNotAllowed handlerConfig
}

func (rh *registeredHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	cfg, ok := rh.methods[r.Method]
	if !ok {
		cfg = rh.methodNotAllowed
	}
	processRequest(cfg, w, r)
}

func (rh *registeredHandler) handleMethod(method string, cfg handlerConfig) {
	if _, exists := rh.methods[method]; exists {
		panic(fmt.Sprintf("double registration of (pattern = %q, method = %q)", rh.pattern, method))
	}
	rh.methods[method] = cfg
}

func configureInterceptors(interceptors []Interceptor, cfgs []InterceptorConfig) []configuredInterceptor {
	var its []configuredInterceptor
	for _, it := range interceptors {
		var matches []InterceptorConfig
		for _, c := range cfgs {
			if it.Match(c) {
				matches = append(matches, c)
			}
		}

		if len(matches) > 1 {
			msg := fmt.Sprintf("multiple configurations specified for interceptor %T: ", it)
			for _, match := range matches {
				msg += fmt.Sprintf("%#v", match)
			}
			panic(msg)
		}

		var cfg InterceptorConfig
		if len(matches) == 1 {
			cfg = matches[0]
		}
		its = append(its, configuredInterceptor{interceptor: it, config: cfg})
	}
	return its
}
<commit_msg>Removed the handlerRegistration struct<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package safehttp

import (
	"fmt"
	"log"
	"net/http"
)

// The HTTP request methods defined by RFC.
const (
	MethodConnect = "CONNECT" // RFC 7231, 4.3.6
	MethodDelete  = "DELETE"  // RFC 7231, 4.3.5
	MethodGet     = "GET"     // RFC 7231, 4.3.1
	MethodHead    = "HEAD"    // RFC 7231, 4.3.2
	MethodOptions = "OPTIONS" // RFC 7231, 4.3.7
	MethodPatch   = "PATCH"   // RFC 5789
	MethodPost    = "POST"    // RFC 7231, 4.3.3
	MethodPut     = "PUT"     // RFC 7231, 4.3.4
	MethodTrace   = "TRACE"   // RFC 7231, 4.3.8
)

// ServeMux is an HTTP request multiplexer. It matches the URL of each incoming
// request against a list of registered patterns and calls the handler for
// the pattern that most closely matches the URL.
//
// Patterns names are fixed, rooted paths, like "/favicon.ico", or rooted
// subtrees like "/images/" (note the trailing slash). Longer patterns take
// precedence over shorter ones, so that if there are handlers registered for
// both "/images/" and "/images/thumbnails/", the latter handler will be called
// for paths beginning "/images/thumbnails/" and the former will receive
// requests for any other paths in the "/images/" subtree.
//
// Note that since a pattern ending in a slash names a rooted subtree, the
// pattern "/" matches all paths not matched by other registered patterns,
// not just the URL with Path == "/".
//
// If a subtree has been registered and a request is received naming the subtree
// root without its trailing slash, ServeMux redirects that request to
// the subtree root (adding the trailing slash). This behavior can be overridden
// with a separate registration for the path without the trailing slash. For
// example, registering "/images/" causes ServeMux to redirect a request for
// "/images" to "/images/", unless "/images" has been registered separately.
//
// Patterns may optionally begin with a host name, restricting matches to URLs
// on that host only.  Host-specific patterns take precedence over general
// patterns, so that a handler might register for the two patterns "/codesearch"
// and "codesearch.google.com/" without also taking over requests for
// "http://www.google.com/".
//
// ServeMux also takes care of sanitizing the URL request path and the Host
// header, stripping the port number and redirecting any request containing . or
// .. elements or repeated slashes to an equivalent, cleaner URL.
//
// Multiple handlers can be registered for a single pattern, as long as they
// handle different HTTP methods.
type ServeMux struct {
	mux      *http.ServeMux
	handlers map[string]*registeredHandler

	dispatcher       Dispatcher
	interceptors     []Interceptor
	methodNotAllowed handlerConfig
}

// ServeHTTP dispatches the request to the handler whose method matches the
// incoming request and whose pattern most closely matches the request URL.
//
//  For each incoming request:
//  - [Before Phase] Interceptor.Before methods are called for every installed
//    interceptor, until an interceptor writes to a ResponseWriter (including
//    errors) or panics,
//  - the handler is called after a [Before Phase] if no writes or panics occured,
//  - the handler triggers the [Commit Phase] by writing to the ResponseWriter,
//  - [Commit Phase] Interceptor.Commit methods run for every interceptor whose
//    Before method was called,
//  - [Dispatcher Phase] after the [Commit Phase], the Dispatcher's appropriate
//    write method is called; the Dispatcher is responsible for determining whether
//    the response is indeed safe and writing it,
//  - if the handler attempts to write more than once, it is treated as an
//    unrecoverable error; the request processing ends abrubptly with a panic and
//    nothing else happens (note: this will change as soon as [After Phase] is
//    introduced)
//
// Interceptors should NOT rely on the order they're run.
func (m *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m.mux.ServeHTTP(w, r)
}

// Handle registers a handler for the given pattern and method. If a handler is
// registered twice for the same pattern and method, Build will panic.
//
// InterceptorConfigs can be passed in order to modify the behavior of the
// interceptors on a registered handler. Passing an InterceptorConfig whose
// corresponding Interceptor was not installed will produce no effect. If
// multiple configurations are passed for the same Interceptor, Mux will panic.
func (m *ServeMux) Handle(pattern string, method string, h Handler, cfgs ...InterceptorConfig) {
	if m.handlers[pattern] == nil {
		m.handlers[pattern] = &registeredHandler{
			pattern:          pattern,
			methodNotAllowed: m.methodNotAllowed,
			methods:          make(map[string]handlerConfig),
		}
		m.mux.Handle(pattern, m.handlers[pattern])
	}
	m.handlers[pattern].handleMethod(method,
		handlerConfig{
			Dispatcher:   m.dispatcher,
			Handler:      h,
			Interceptors: configureInterceptors(m.interceptors, cfgs),
		})
}

// ServeMuxConfig is a builder for ServeMux.
type ServeMuxConfig struct {
	dispatcher   Dispatcher
	interceptors []Interceptor

	methodNotAllowed     Handler
	methodNotAllowedCfgs []InterceptorConfig
}

// NewServeMuxConfig crates a ServeMuxConfig with the provided Dispatcher. If
// the provided Dispatcher is nil, the DefaultDispatcher is used.
func NewServeMuxConfig(disp Dispatcher) *ServeMuxConfig {
	if disp == nil {
		disp = &DefaultDispatcher{}
	}
	return &ServeMuxConfig{
		dispatcher:       disp,
		methodNotAllowed: HandlerFunc(defaultMethotNotAllowed),
	}
}

// HandleMethodNotAllowed registers a handler that runs when a given method is
// not allowed for a registered path.
func (s *ServeMuxConfig) HandleMethodNotAllowed(h Handler, cfgs ...InterceptorConfig) {
	s.methodNotAllowed = h
	s.methodNotAllowedCfgs = cfgs
}

var defaultMethotNotAllowed = HandlerFunc(func(w ResponseWriter, req *IncomingRequest) Result {
	return w.WriteError(StatusMethodNotAllowed)
})

// Intercept installs the given interceptors.
//
// Interceptors order is respected and interceptors are always run in the
// order they've been installed.
//
// Calling Intercept multiple times is valid. Interceptors that are added last
// will run last.
func (s *ServeMuxConfig) Intercept(is ...Interceptor) {
	s.interceptors = append(s.interceptors, is...)
}

// Mux returns the ServeMux with a copy of the current configuration.
func (s *ServeMuxConfig) Mux() *ServeMux {
	freezeLocalDev = true
	if IsLocalDev() {
		log.Println("Warning: creating safehttp.Mux in dev mode. This configuration is not valid for production use")
	}

	if s.dispatcher == nil {
		panic("Use NewServeMuxConfig instead of creating ServeMuxConfig using a composite literal.")
	}

	methodNotAllowed := handlerConfig{
		Dispatcher:   s.dispatcher,
		Handler:      s.methodNotAllowed,
		Interceptors: configureInterceptors(s.interceptors, s.methodNotAllowedCfgs),
	}

	m := &ServeMux{
		mux:              http.NewServeMux(),
		handlers:         make(map[string]*registeredHandler),
		dispatcher:       s.dispatcher,
		interceptors:     s.interceptors,
		methodNotAllowed: methodNotAllowed,
	}
	return m
}

// Clone creates a copy of the current config.
// This can be used to create several instances of Mux that share the same set of
// plugins and some common handlers.
func (s *ServeMuxConfig) Clone() *ServeMuxConfig {
	c := &ServeMuxConfig{
		dispatcher:       s.dispatcher,
		interceptors:     make([]Interceptor, len(s.interceptors)),
		methodNotAllowed: s.methodNotAllowed,
	}
	copy(c.interceptors, s.interceptors)
	copy(c.methodNotAllowedCfgs, s.methodNotAllowedCfgs)
	return c
}

type registeredHandler struct {
	pattern          string
	methods          map[string]handlerConfig
	methodNotAllowed handlerConfig
}

func (rh *registeredHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	cfg, ok := rh.methods[r.Method]
	if !ok {
		cfg = rh.methodNotAllowed
	}
	processRequest(cfg, w, r)
}

func (rh *registeredHandler) handleMethod(method string, cfg handlerConfig) {
	if _, exists := rh.methods[method]; exists {
		panic(fmt.Sprintf("double registration of (pattern = %q, method = %q)", rh.pattern, method))
	}
	rh.methods[method] = cfg
}

func configureInterceptors(interceptors []Interceptor, cfgs []InterceptorConfig) []configuredInterceptor {
	var its []configuredInterceptor
	for _, it := range interceptors {
		var matches []InterceptorConfig
		for _, c := range cfgs {
			if it.Match(c) {
				matches = append(matches, c)
			}
		}

		if len(matches) > 1 {
			msg := fmt.Sprintf("multiple configurations specified for interceptor %T: ", it)
			for _, match := range matches {
				msg += fmt.Sprintf("%#v", match)
			}
			panic(msg)
		}

		var cfg InterceptorConfig
		if len(matches) == 1 {
			cfg = matches[0]
		}
		its = append(its, configuredInterceptor{interceptor: it, config: cfg})
	}
	return its
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/davecheney/gpio"
	"github.com/paypal/gatt"
)

// These bytes are sent over BLE
const UNLOCKED byte = 0x01
const LOCKED byte = 0x02

// Car represents a car
type Car struct {
	Auth *Auth

	mu     sync.Mutex
	Status byte
	Pin    gpio.Pin
}

// NewCar creates a new instance of the Car type
func NewCar(pin gpio.Pin, auth *Auth) *Car {
	return &Car{
		Status: LOCKED,
		Pin:    pin,
		Auth:   auth,
	}
}

// HandleWrite will lock or unlock the car
func (c *Car) HandleWrite(r gatt.Request, data []byte) (status byte) {
	if !c.Auth.IsAuthenticated() {
		fmt.Println("You are not authenticated...")
		return gatt.StatusUnexpectedError
	}

	if len(data) < 1 {
		fmt.Println("Invalid data")
		return gatt.StatusUnexpectedError
	}

	// Pull the lever, Kronk!
	switch data[0] {
	case LOCKED:
		fmt.Println("--- Locking car")
		c.Lock()
		break
	case UNLOCKED:
		fmt.Println("+++ Unlocking car")
		c.Unlock()
		break
	}

	return gatt.StatusSuccess
}

// HandleRead reports the current status of the car
func (c *Car) HandleRead(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
	c.mu.Lock()
	status := c.Status
	c.mu.Unlock()

	resp.Write([]byte{status})
}

// HandleNotify sends the current  status of the car to the central every two
// seconds
func (c *Car) HandleNotify(r gatt.Request, n gatt.Notifier) {
	go func() {
		for !n.Done() {
			c.mu.Lock()
			status := c.Status
			c.mu.Unlock()

			n.Write([]byte{status})
			time.Sleep(2 * time.Second)
		}
	}()
}

// Unlock unlocks the car
func (c *Car) Unlock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.Status == LOCKED {
		if c.Pin != nil {
			c.Pin.Set()
		}
		c.Status = UNLOCKED
	}
}

// Lock locks the car
func (c *Car) Lock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.Status == UNLOCKED {
		if c.Pin != nil {
			c.Pin.Clear()
		}
		c.Status = LOCKED
	}
}
<commit_msg>Send notifications every 10 seconds<commit_after>package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/davecheney/gpio"
	"github.com/paypal/gatt"
)

// These bytes are sent over BLE
const UNLOCKED byte = 0x01
const LOCKED byte = 0x02

// Car represents a car
type Car struct {
	Auth *Auth

	mu     sync.Mutex
	Status byte
	Pin    gpio.Pin
}

// NewCar creates a new instance of the Car type
func NewCar(pin gpio.Pin, auth *Auth) *Car {
	return &Car{
		Status: LOCKED,
		Pin:    pin,
		Auth:   auth,
	}
}

// HandleWrite will lock or unlock the car
func (c *Car) HandleWrite(r gatt.Request, data []byte) (status byte) {
	if !c.Auth.IsAuthenticated() {
		fmt.Println("You are not authenticated...")
		return gatt.StatusUnexpectedError
	}

	if len(data) < 1 {
		fmt.Println("Invalid data")
		return gatt.StatusUnexpectedError
	}

	// Pull the lever, Kronk!
	switch data[0] {
	case LOCKED:
		fmt.Println("--- Locking car")
		c.Lock()
		break
	case UNLOCKED:
		fmt.Println("+++ Unlocking car")
		c.Unlock()
		break
	}

	return gatt.StatusSuccess
}

// HandleRead reports the current status of the car
func (c *Car) HandleRead(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
	c.mu.Lock()
	status := c.Status
	c.mu.Unlock()

	resp.Write([]byte{status})
}

// HandleNotify sends the current  status of the car to the central every two
// seconds
func (c *Car) HandleNotify(r gatt.Request, n gatt.Notifier) {
	go func() {
		for !n.Done() {
			c.mu.Lock()
			status := c.Status
			c.mu.Unlock()

			n.Write([]byte{status})
			time.Sleep(10 * time.Second)
		}
	}()
}

// Unlock unlocks the car
func (c *Car) Unlock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.Status == LOCKED {
		if c.Pin != nil {
			c.Pin.Set()
		}
		c.Status = UNLOCKED
	}
}

// Lock locks the car
func (c *Car) Lock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.Status == UNLOCKED {
		if c.Pin != nil {
			c.Pin.Clear()
		}
		c.Status = LOCKED
	}
}
<|endoftext|>


<commit_before>package main

type Thing interface {
	Id() identifier
	Name() string
	SetId(id identifier)
}

type actualThing struct {
	id        identifier
	name      string
	brief     string
	long      string
	location  identifier
	presences map[identifier]bool
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) SetId(newId identifier) {
	t.id = newId
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}
func (t actualThing) Location() identifier {
	return t.location
}
func (t actualThing) SetLocation(l identifier) {
	t.location = l
}
func (t actualThing) Presences() map[identifier]bool {
	return t.presences
}
func (t actualThing) AddPresence(p identifier) {
	t.presences[p] = true
}
func (t actualThing) RemovePresence(p identifier) {
	delete(t.presences, p)
}

type ThingGetter chan Thing

func (g ThingGetter) Get() (Thing, bool) {
	thing, ok := <-g
	return thing, ok
}

type SetterMsg struct {
	it  Thing
	set chan Thing
}

type ThingSetter chan SetterMsg

func (s ThingSetter) Set(modify func(t *Thing)) (ok bool) {
	msg, ok := <-s
	if !ok {
		return false
	}
	modify(&msg.it)
	msg.set <- msg.it
	return true
}

type GetGetterMsg struct {
	id       identifier
	response chan ThingGetter
}

type GetSetterMsg struct {
	id       identifier
	response chan ThingSetter
}

type ThingAccessor struct {
	ThingGetter
	ThingSetter
}

type GetAccessorMsg struct {
	id       identifier
	response chan ThingAccessor
}

type ThingAdderMsg struct {
	thing    Thing
	response chan identifier
}

type ThingManager struct {
	getGetter   chan GetGetterMsg
	getSetter   chan GetSetterMsg
	getAccessor chan GetAccessorMsg
	add         chan ThingAdderMsg
	del         chan identifier
}

func (m ThingManager) GetThingAccessor(id identifier) ThingAccessor {
	response := make(chan ThingAccessor)
	m.getAccessor <- GetAccessorMsg{id, response}
	return <-response
}

func (m ThingManager) GetThingGetter(id identifier) ThingGetter {
	response := make(chan ThingGetter)
	m.getGetter <- GetGetterMsg{id, response}
	return <-response
}

func (m ThingManager) GetThingSetter(id identifier) ThingSetter {
	response := make(chan ThingSetter)
	m.getSetter <- GetSetterMsg{id, response}
	return <-response
}

func (m ThingManager) Add(t Thing) identifier {
	response := make(chan identifier)
	m.add <- ThingAdderMsg{t, response}
	return <-response
}

func (m ThingManager) Remove(id identifier) {
	m.del <- id
}

func NewThingManager() *ThingManager {
	manager := ThingManager{make(chan GetGetterMsg), make(chan GetSetterMsg), make(chan GetAccessorMsg), make(chan ThingAdderMsg), make(chan identifier)}
	nextId := identifier(0)
	go func() {
		type thingAccessors struct {
			getter chan Thing
			setter chan SetterMsg
			closer chan bool
		}

		Things := make(map[identifier]thingAccessors)
		for {
			select {
			case addThing := <-manager.add:
				addThing.thing.SetId(nextId)
				nextId++
				getter := make(chan Thing)
				setter := make(chan SetterMsg)
				closer := make(chan bool)

				thingFunc := func(thing Thing, setting func(thing Thing, thingChan chan Thing)) {
					thingChan := make(chan Thing)
					for {
						select {
						case setter <- SetterMsg{thing, thingChan}:
							go setting(thing, thingChan)
							return
						case getter <- thing:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}
				var settingFunc func(thing Thing, thingChan chan Thing)
				settingFunc = func(thing Thing, thingChan chan Thing) {
					for {
						select {
						case thing = <-thingChan:
							go thingFunc(thing, settingFunc)
						case getter <- thing:
						}
					}
				}
				go thingFunc(addThing.thing, settingFunc)
				Things[addThing.thing.Id()] = thingAccessors{getter, setter, closer}
				addThing.response <- addThing.thing.Id()
			case d := <-manager.del:
				Things[d].closer <- true
				delete(Things, d)
			case g := <-manager.getAccessor:
				g.response <- ThingAccessor{Things[g.id].getter, Things[g.id].setter}
			case g := <-manager.getGetter:
				g.response <- Things[g.id].getter
			case s := <-manager.getSetter:
				s.response <- Things[s.id].setter
			}
		}
	}()
	return &manager
}
<commit_msg>added data.go ThingManager.GetThingAccessorByName()<commit_after>package main

type Thing interface {
	Id() identifier
	Name() string
	SetId(id identifier)
}

type actualThing struct {
	id        identifier
	name      string
	brief     string
	long      string
	location  identifier
	presences map[identifier]bool
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) SetId(newId identifier) {
	t.id = newId
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}
func (t actualThing) Location() identifier {
	return t.location
}
func (t actualThing) SetLocation(l identifier) {
	t.location = l
}
func (t actualThing) Presences() map[identifier]bool {
	return t.presences
}
func (t actualThing) AddPresence(p identifier) {
	t.presences[p] = true
}
func (t actualThing) RemovePresence(p identifier) {
	delete(t.presences, p)
}

type ThingGetter chan Thing

func (g ThingGetter) Get() (Thing, bool) {
	thing, ok := <-g
	return thing, ok
}

type SetterMsg struct {
	it  Thing
	set chan Thing
}

type ThingSetter chan SetterMsg

func (s ThingSetter) Set(modify func(t *Thing)) (ok bool) {
	msg, ok := <-s
	if !ok {
		return false
	}
	modify(&msg.it)
	msg.set <- msg.it
	return true
}

type GetGetterMsg struct {
	id       identifier
	response chan ThingGetter
}

type GetSetterMsg struct {
	id       identifier
	response chan ThingSetter
}

type ThingAccessor struct {
	ThingGetter
	ThingSetter
}

type GetAccessorMsg struct {
	id       identifier
	response chan ThingAccessor
}

type GetAccessorByNameMsg struct {
	name     string
	response chan ThingAccessor
}

type ThingAdderMsg struct {
	thing    Thing
	response chan identifier
}

type ThingManager struct {
	getGetter         chan GetGetterMsg
	getSetter         chan GetSetterMsg
	getAccessor       chan GetAccessorMsg
	getAccessorByName chan GetAccessorByNameMsg
	add               chan ThingAdderMsg
	del               chan identifier
}

func (m ThingManager) GetThingAccessor(id identifier) ThingAccessor {
	response := make(chan ThingAccessor)
	m.getAccessor <- GetAccessorMsg{id, response}
	return <-response
}

func (m ThingManager) GetThingAccessorByName(name string) ThingAccessor {
	response := make(chan ThingAccessor)
	m.getAccessorByName <- GetAccessorByNameMsg{name, response}
	return <-response
}

func (m ThingManager) GetThingGetter(id identifier) ThingGetter {
	response := make(chan ThingGetter)
	m.getGetter <- GetGetterMsg{id, response}
	return <-response
}

func (m ThingManager) GetThingSetter(id identifier) ThingSetter {
	response := make(chan ThingSetter)
	m.getSetter <- GetSetterMsg{id, response}
	return <-response
}

func (m ThingManager) Add(t Thing) identifier {
	response := make(chan identifier)
	m.add <- ThingAdderMsg{t, response}
	return <-response
}

func (m ThingManager) Remove(id identifier) {
	m.del <- id
}

func NewThingManager() *ThingManager {
	manager := ThingManager{make(chan GetGetterMsg), make(chan GetSetterMsg), make(chan GetAccessorMsg), make(chan GetAccessorByNameMsg), make(chan ThingAdderMsg), make(chan identifier)}
	nextId := identifier(0)
	go func() {
		type thingAccessors struct {
			getter chan Thing
			setter chan SetterMsg
			closer chan bool
		}

		Things := make(map[identifier]thingAccessors)
		ThingsByName := make(map[string]thingAccessors)
		for {
			select {
			case addThing := <-manager.add:
				addThing.thing.SetId(nextId)
				nextId++
				getter := make(chan Thing)
				setter := make(chan SetterMsg)
				closer := make(chan bool)

				thingFunc := func(thing Thing, setting func(thing Thing, thingChan chan Thing)) {
					thingChan := make(chan Thing)
					for {
						select {
						case setter <- SetterMsg{thing, thingChan}:
							go setting(thing, thingChan)
							return
						case getter <- thing:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}
				var settingFunc func(thing Thing, thingChan chan Thing)
				settingFunc = func(thing Thing, thingChan chan Thing) {
					for {
						select {
						case thing = <-thingChan:
							go thingFunc(thing, settingFunc)
						case getter <- thing:
						}
					}
				}
				go thingFunc(addThing.thing, settingFunc)
				Things[addThing.thing.Id()] = thingAccessors{getter, setter, closer}
				addThing.response <- addThing.thing.Id()
			case d := <-manager.del:
				Things[d].closer <- true
				delete(Things, d)
			case g := <-manager.getAccessor:
				g.response <- ThingAccessor{Things[g.id].getter, Things[g.id].setter}
			case g := <-manager.getAccessorByName:
				g.response <- ThingAccessor{ThingsByName[g.name].getter, ThingsByName[g.name].setter}
			case g := <-manager.getGetter:
				g.response <- Things[g.id].getter
			case s := <-manager.getSetter:
				s.response <- Things[s.id].setter
			}
		}
	}()
	return &manager
}
<|endoftext|>


<commit_before>package torrent

import "io"

// Represents data storage for a Torrent.
type Data interface {
	io.ReaderAt
	io.WriterAt
	// Bro, do you even io.Closer?
	Close()
	// We believe the piece data will pass a hash check.
	PieceCompleted(index int) error
	// Returns true if the piece is complete.
	PieceComplete(index int) bool
}
<commit_msg>Improve doc comments on Data<commit_after>package torrent

import "io"

// Represents data storage for a Torrent.
type Data interface {
	// Should return io.EOF only at end of torrent. Short reads due to missing
	// data should return io.ErrUnexpectedEOF.
	io.ReaderAt
	io.WriterAt
	// Bro, do you even io.Closer?
	Close()
	// Called when the client believes the piece data will pass a hash check.
	// The storage can move or mark the piece data as read-only as it sees
	// fit.
	PieceCompleted(index int) error
	// Returns true if the piece is complete.
	PieceComplete(index int) bool
}
<|endoftext|>


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

package strconv

// FormatUint returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatUint(i uint64, base int) string {
	_, s := formatBits(nil, i, base, false, false)
	return s
}

// FormatInt returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatInt(i int64, base int) string {
	_, s := formatBits(nil, uint64(i), base, i < 0, false)
	return s
}

// Itoa is shorthand for FormatInt(i, 10).
func Itoa(i int) string {
	return FormatInt(int64(i), 10)
}

// AppendInt appends the string form of the integer i,
// as generated by FormatInt, to dst and returns the extended buffer.
func AppendInt(dst []byte, i int64, base int) []byte {
	dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
	return dst
}

// AppendUint appends the string form of the unsigned integer i,
// as generated by FormatUint, to dst and returns the extended buffer.
func AppendUint(dst []byte, i uint64, base int) []byte {
	dst, _ = formatBits(dst, i, base, false, true)
	return dst
}

const (
	digits   = "0123456789abcdefghijklmnopqrstuvwxyz"
	digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
	digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
)

var shifts = [len(digits) + 1]uint{
	1 << 1: 1,
	1 << 2: 2,
	1 << 3: 3,
	1 << 4: 4,
	1 << 5: 5,
}

// formatBits computes the string representation of u in the given base.
// If neg is set, u is treated as negative int64 value. If append_ is
// set, the string is appended to dst and the resulting byte slice is
// returned as the first result value; otherwise the string is returned
// as the second result value.
//
func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
	if base < 2 || base > len(digits) {
		panic("strconv: illegal AppendInt/FormatInt base")
	}
	// 2 <= base && base <= len(digits)

	var a [64 + 1]byte // +1 for sign of 64bit value in base 2
	i := len(a)

	if neg {
		u = -u
	}

	// convert bits
	if base == 10 {
		// common case: use constants for / and % because
		// the compiler can optimize it into a multiply+shift,
		// and unroll loop
		for u >= 100 {
			i -= 2
			q := u / 100
			j := uintptr(u - q*100)
			a[i+1] = digits01[j]
			a[i+0] = digits10[j]
			u = q
		}
		if u >= 10 {
			i--
			q := u / 10
			a[i] = digits[uintptr(u-q*10)]
			u = q
		}

	} else if s := shifts[base]; s > 0 {
		// base is power of 2: use shifts and masks instead of / and %
		b := uint64(base)
		m := uintptr(b) - 1 // == 1<<s - 1
		for u >= b {
			i--
			a[i] = digits[uintptr(u)&m]
			u >>= s
		}

	} else {
		// general case
		b := uint64(base)
		for u >= b {
			i--
			a[i] = digits[uintptr(u%b)]
			u /= b
		}
	}

	// u < base
	i--
	a[i] = digits[uintptr(u)]

	// add sign, if any
	if neg {
		i--
		a[i] = '-'
	}

	if append_ {
		d = append(dst, a[i:]...)
		return
	}
	s = string(a[i:])
	return
}
<commit_msg>strconv: optimize decimal to string conversion<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package strconv

// FormatUint returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatUint(i uint64, base int) string {
	_, s := formatBits(nil, i, base, false, false)
	return s
}

// FormatInt returns the string representation of i in the given base,
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
// for digit values >= 10.
func FormatInt(i int64, base int) string {
	_, s := formatBits(nil, uint64(i), base, i < 0, false)
	return s
}

// Itoa is shorthand for FormatInt(i, 10).
func Itoa(i int) string {
	return FormatInt(int64(i), 10)
}

// AppendInt appends the string form of the integer i,
// as generated by FormatInt, to dst and returns the extended buffer.
func AppendInt(dst []byte, i int64, base int) []byte {
	dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
	return dst
}

// AppendUint appends the string form of the unsigned integer i,
// as generated by FormatUint, to dst and returns the extended buffer.
func AppendUint(dst []byte, i uint64, base int) []byte {
	dst, _ = formatBits(dst, i, base, false, true)
	return dst
}

const (
	digits = "0123456789abcdefghijklmnopqrstuvwxyz"
)

var shifts = [len(digits) + 1]uint{
	1 << 1: 1,
	1 << 2: 2,
	1 << 3: 3,
	1 << 4: 4,
	1 << 5: 5,
}

// formatBits computes the string representation of u in the given base.
// If neg is set, u is treated as negative int64 value. If append_ is
// set, the string is appended to dst and the resulting byte slice is
// returned as the first result value; otherwise the string is returned
// as the second result value.
//
func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
	if base < 2 || base > len(digits) {
		panic("strconv: illegal AppendInt/FormatInt base")
	}
	// 2 <= base && base <= len(digits)

	var a [64 + 1]byte // +1 for sign of 64bit value in base 2
	i := len(a)

	if neg {
		u = -u
	}

	// convert bits
	if base == 10 {
		// common case: use constants for / because
		// the compiler can optimize it into a multiply+shift

		if ^uintptr(0)>>32 == 0 {
			for u > uint64(^uintptr(0)) {
				q := u / 1e9
				us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
				for j := 9; j > 0; j-- {
					i--
					qs := us / 10
					a[i] = byte(us - qs*10 + '0')
					us = qs
				}
				u = q
			}
		}

		// u guaranteed to fit into a uintptr
		us := uintptr(u)
		for us >= 10 {
			i--
			q := us / 10
			a[i] = byte(us - q*10 + '0')
			us = q
		}
		// u < 10
		i--
		a[i] = byte(us + '0')

	} else if s := shifts[base]; s > 0 {
		// base is power of 2: use shifts and masks instead of / and %
		b := uint64(base)
		m := uintptr(b) - 1 // == 1<<s - 1
		for u >= b {
			i--
			a[i] = digits[uintptr(u)&m]
			u >>= s
		}
		// u < base
		i--
		a[i] = digits[uintptr(u)]

	} else {
		// general case
		b := uint64(base)
		for u >= b {
			i--
			q := u / b
			a[i] = digits[uintptr(u-q*b)]
			u = q
		}
		// u < base
		i--
		a[i] = digits[uintptr(u)]
	}

	// add sign, if any
	if neg {
		i--
		a[i] = '-'
	}

	if append_ {
		d = append(dst, a[i:]...)
		return
	}
	s = string(a[i:])
	return
}
<|endoftext|>


<commit_before>package api

import (
	"net/http"

	"github.com/minchao/smsender/smsender"
)

func (s *Server) Hello(w http.ResponseWriter, r *http.Request) {
	render(w, 200, "Hello!")
}

func (s *Server) Routes(w http.ResponseWriter, r *http.Request) {
	render(w, 200, s.sender.GetRoutes())
}

type Message struct {
	To    []string `json:"to" validate:"required,dive,phone"`
	From  string   `json:"from"`
	Body  string   `json:"body" validate:"required"`
	Async bool     `json:"async,omitempty"`
}

func (s *Server) MessagesPost(w http.ResponseWriter, r *http.Request) {
	var msg Message
	var validate = newValidate()
	validate.RegisterValidation("phone", isPhoneNumber)
	err := getInput(r.Body, &msg, validate)
	if err != nil {
		render(w, http.StatusBadRequest, formErrorMessage(err))
		return
	}

	var (
		count         = len(msg.To)
		resultChans   = make([]<-chan smsender.Result, count)
		messageClones = []smsender.Message{}
		results       = []smsender.Result{}
	)

	if count > 100 {
		msg.Async = true
	}

	for i := 0; i < count; i++ {
		message := smsender.NewMessage(msg.To[i], msg.From, msg.Body, msg.Async)
		resultChans[i] = message.Result
		messageClones = append(messageClones, *message)

		s.out <- message
	}

	if msg.Async {
		for _, message := range messageClones {
			results = append(results, *smsender.NewAsyncResult(message))
		}
	} else {
		for _, c := range resultChans {
			select {
			case result := <-c:
				results = append(results, result)
			}
		}
	}

	render(w, 200, results)
}
<commit_msg>Recipients (to field) cannot be empty<commit_after>package api

import (
	"net/http"

	"github.com/minchao/smsender/smsender"
)

func (s *Server) Hello(w http.ResponseWriter, r *http.Request) {
	render(w, 200, "Hello!")
}

func (s *Server) Routes(w http.ResponseWriter, r *http.Request) {
	render(w, 200, s.sender.GetRoutes())
}

type Message struct {
	To    []string `json:"to" validate:"required,gt=0,dive,phone"`
	From  string   `json:"from"`
	Body  string   `json:"body" validate:"required"`
	Async bool     `json:"async,omitempty"`
}

func (s *Server) MessagesPost(w http.ResponseWriter, r *http.Request) {
	var msg Message
	var validate = newValidate()
	validate.RegisterValidation("phone", isPhoneNumber)
	err := getInput(r.Body, &msg, validate)
	if err != nil {
		render(w, http.StatusBadRequest, formErrorMessage(err))
		return
	}

	var (
		count         = len(msg.To)
		resultChans   = make([]<-chan smsender.Result, count)
		messageClones = []smsender.Message{}
		results       = []smsender.Result{}
	)

	if count > 100 {
		msg.Async = true
	}

	for i := 0; i < count; i++ {
		message := smsender.NewMessage(msg.To[i], msg.From, msg.Body, msg.Async)
		resultChans[i] = message.Result
		messageClones = append(messageClones, *message)

		s.out <- message
	}

	if msg.Async {
		for _, message := range messageClones {
			results = append(results, *smsender.NewAsyncResult(message))
		}
	} else {
		for _, c := range resultChans {
			select {
			case result := <-c:
				results = append(results, result)
			}
		}
	}

	render(w, 200, results)
}
<|endoftext|>


<commit_before>package dashboard

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/Cepave/fe/http/base"
	"github.com/Cepave/fe/model/dashboard"
)

type DashBoardController struct {
	base.BaseController
}

func (this *DashBoardController) EndpRegxqury() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	queryStr := this.GetString("queryStr", "")
	if queryStr == "" {
		this.ResposeError(baseResp, "query string is empty, please it")
		return
	}
	limitNum, _ := this.GetInt("limit", 0)
	enp, err := dashboard.QueryEndpintByNameRegx(queryStr, limitNum)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(enp) > 0 {
		baseResp.Data["endpoints"] = enp
	} else {
		baseResp.Data["endpoints"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

//counter query by endpoints
func (this *DashBoardController) CounterQuery() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	endpoints := this.GetString("endpoints", "")
	endpointcheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if endpoints == "" || endpointcheck.MatchString(endpoints) {
		this.ResposeError(baseResp, "query string is empty, please it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	endpointsArr := strings.Split(rexstr.ReplaceAllString(endpoints, ""), ",")
	limitNum, _ := this.GetInt("limit", 0)
	counters, err := dashboard.QueryCounterByEndpoints(endpointsArr, limitNum)
	switch {
	case err != nil:
		this.ResposeError(baseResp, err.Error())
		return
	case len(counters) == 0:
		baseResp.Data["counters"] = []string{}
	default:
		baseResp.Data["counters"] = counters
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) HostGroupQuery() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	queryStr := this.GetString("queryStr", "")
	if queryStr == "" {
		this.ResposeError(baseResp, "query string is empty, please it")
		return
	}
	limitNum, _ := this.GetInt("limit", 0)
	hostgroupList, err := dashboard.QueryHostGroupByNameRegx(queryStr, limitNum)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(hostgroupList) > 0 {
		baseResp.Data["hostgroups"] = hostgroupList
	} else {
		baseResp.Data["hostgroups"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) HostsQueryByHostGroups() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}

	hostgroups := this.GetString("hostgroups", "")
	hostgroupscheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if hostgroups == "" || hostgroupscheck.MatchString(hostgroups) {
		this.ResposeError(baseResp, "query string is empty, please it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	hostgroupsArr := strings.Split(rexstr.ReplaceAllString(hostgroups, ""), ",")
	hosts_resp, err := dashboard.GetHostsByHostGroupName(hostgroupsArr)

	if len(hosts_resp) > 0 {
		baseResp.Data["hosts"] = hosts_resp
	} else {
		baseResp.Data["hosts"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) CounterQueryByHostGroup() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}

	hostgroups := this.GetString("hostgroups", "")
	hostgroupscheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if hostgroups == "" || hostgroupscheck.MatchString(hostgroups) {
		this.ResposeError(baseResp, "query string is empty, please it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	hostgroupsArr := strings.Split(rexstr.ReplaceAllString(hostgroups, ""), ",")

	hosts, err := dashboard.GetHostsByHostGroupName(hostgroupsArr)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(hosts) > 0 {
		var endpoints []string
		for _, v := range hosts {
			endpoints = append(endpoints, fmt.Sprintf("\"%v\"", v.Hostname))
		}
		limitNum, _ := this.GetInt("limit", 0)
		counters, err := dashboard.QueryCounterByEndpoints(endpoints, limitNum)
		if err != nil {
			this.ResposeError(baseResp, err.Error())
			return
		} else if len(counters) > 0 {
			baseResp.Data["counters"] = counters
		} else {
			baseResp.Data["counters"] = []string{}
		}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) CountNumOfHostGroup() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()

	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	} else {
		numberOfteam, err := dashboard.CountNumOfHostGroup()
		if err != nil {
			this.ResposeError(baseResp, err.Error())
			return
		}
		baseResp.Data["count"] = numberOfteam
	}
	this.ServeApiJson(baseResp)
	return
}
<commit_msg>fixed missing text of response message<commit_after>package dashboard

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/Cepave/fe/http/base"
	"github.com/Cepave/fe/model/dashboard"
)

type DashBoardController struct {
	base.BaseController
}

func (this *DashBoardController) EndpRegxqury() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	queryStr := this.GetString("queryStr", "")
	if queryStr == "" {
		this.ResposeError(baseResp, "query string is empty, please check it")
		return
	}
	limitNum, _ := this.GetInt("limit", 0)
	enp, err := dashboard.QueryEndpintByNameRegx(queryStr, limitNum)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(enp) > 0 {
		baseResp.Data["endpoints"] = enp
	} else {
		baseResp.Data["endpoints"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

//counter query by endpoints
func (this *DashBoardController) CounterQuery() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	endpoints := this.GetString("endpoints", "")
	endpointcheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if endpoints == "" || endpointcheck.MatchString(endpoints) {
		this.ResposeError(baseResp, "query string is empty, please check it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	endpointsArr := strings.Split(rexstr.ReplaceAllString(endpoints, ""), ",")
	limitNum, _ := this.GetInt("limit", 0)
	counters, err := dashboard.QueryCounterByEndpoints(endpointsArr, limitNum)
	switch {
	case err != nil:
		this.ResposeError(baseResp, err.Error())
		return
	case len(counters) == 0:
		baseResp.Data["counters"] = []string{}
	default:
		baseResp.Data["counters"] = counters
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) HostGroupQuery() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	queryStr := this.GetString("queryStr", "")
	if queryStr == "" {
		this.ResposeError(baseResp, "query string is empty, please check it")
		return
	}
	limitNum, _ := this.GetInt("limit", 0)
	hostgroupList, err := dashboard.QueryHostGroupByNameRegx(queryStr, limitNum)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(hostgroupList) > 0 {
		baseResp.Data["hostgroups"] = hostgroupList
	} else {
		baseResp.Data["hostgroups"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) HostsQueryByHostGroups() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}

	hostgroups := this.GetString("hostgroups", "")
	hostgroupscheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if hostgroups == "" || hostgroupscheck.MatchString(hostgroups) {
		this.ResposeError(baseResp, "query string is empty, please check it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	hostgroupsArr := strings.Split(rexstr.ReplaceAllString(hostgroups, ""), ",")
	hosts_resp, err := dashboard.GetHostsByHostGroupName(hostgroupsArr)

	if len(hosts_resp) > 0 {
		baseResp.Data["hosts"] = hosts_resp
	} else {
		baseResp.Data["hosts"] = []string{}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) CounterQueryByHostGroup() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}

	hostgroups := this.GetString("hostgroups", "")
	hostgroupscheck, _ := regexp.Compile("^\\s*\\[\\s*\\]\\s*$")
	if hostgroups == "" || hostgroupscheck.MatchString(hostgroups) {
		this.ResposeError(baseResp, "query string is empty, please check it")
		return
	}
	rexstr, _ := regexp.Compile("^\\s*\\[\\s*|\\s*\\]\\s*$")
	hostgroupsArr := strings.Split(rexstr.ReplaceAllString(hostgroups, ""), ",")

	hosts, err := dashboard.GetHostsByHostGroupName(hostgroupsArr)
	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	}
	if len(hosts) > 0 {
		var endpoints []string
		for _, v := range hosts {
			endpoints = append(endpoints, fmt.Sprintf("\"%v\"", v.Hostname))
		}
		limitNum, _ := this.GetInt("limit", 0)
		counters, err := dashboard.QueryCounterByEndpoints(endpoints, limitNum)
		if err != nil {
			this.ResposeError(baseResp, err.Error())
			return
		} else if len(counters) > 0 {
			baseResp.Data["counters"] = counters
		} else {
			baseResp.Data["counters"] = []string{}
		}
	}
	this.ServeApiJson(baseResp)
	return
}

func (this *DashBoardController) CountNumOfHostGroup() {
	baseResp := this.BasicRespGen()
	_, err := this.SessionCheck()

	if err != nil {
		this.ResposeError(baseResp, err.Error())
		return
	} else {
		numberOfteam, err := dashboard.CountNumOfHostGroup()
		if err != nil {
			this.ResposeError(baseResp, err.Error())
			return
		}
		baseResp.Data["count"] = numberOfteam
	}
	this.ServeApiJson(baseResp)
	return
}
<|endoftext|>


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

package display

import (
	"fmt"
	"testing"

	"golang.org/x/text/internal/testtext"
)

func TestLinking(t *testing.T) {
	base := getSize(t, `display.Tags(language.English).Name(language.English)`)
	compact := getSize(t, `display.English.Languages().Name(language.English)`)

	if d := base - compact; d < 1.5*1024*1024 {
		t.Errorf("size(base)-size(compact) was %d; want > 1.5MB", base, compact)
	}
}

func getSize(t *testing.T, main string) int {
	size, err := testtext.CodeSize(fmt.Sprintf(body, main))
	if err != nil {
		t.Fatal(err)
	}
	return size
}

const body = `package main
import (
	"golang.org/x/text/display"
	"golang.org/x/text/language"
)
func main() {
	%s
}
`
<commit_msg>display: skip link test if go binary not found<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package display

import (
	"fmt"
	"testing"

	"golang.org/x/text/internal/testtext"
)

func TestLinking(t *testing.T) {
	base := getSize(t, `display.Tags(language.English).Name(language.English)`)
	compact := getSize(t, `display.English.Languages().Name(language.English)`)

	if d := base - compact; d < 1.5*1024*1024 {
		t.Errorf("size(base)-size(compact) was %d; want > 1.5MB", base, compact)
	}
}

func getSize(t *testing.T, main string) int {
	size, err := testtext.CodeSize(fmt.Sprintf(body, main))
	if err != nil {
		t.Skipf("skipping link size test; binary size could not be determined: %v", err)
	}
	return size
}

const body = `package main
import (
	"golang.org/x/text/display"
	"golang.org/x/text/language"
)
func main() {
	%s
}
`
<|endoftext|>


<commit_before>package err

import (
	"fmt"
)

type exitErr struct {
	data	string	//interface{}
	code	int
}

type ExitCoder interface {
	error
	ExitCode()	int
}

func ExitError(exitCode int, info error) ExitCoder {
	return &exitErr{
		code: exitCode,
		data: info.Error(),
	}
}

func ExitErrorV(exitCode int, msg ...interface{}) ExitCoder {
	return &exitErr{
		code: exitCode,
		data: fmt.Sprint(msg...),
	}
}

func ExitErrorf(exitCode int, format string, msg ...interface{}) ExitCoder {
	return &exitErr{
		code: exitCode,
		data: fmt.Sprintf(format,msg...),
	}
}

// Error returns the string message, fulfilling the interface required by
// `error`
func (ee *exitErr) Error() string {
	return ee.data		// fmt.Sprintf("%v", ee.data)
}

// ExitCode returns the exit code, fulfilling the interface required by
// `ExitCoder`
func (ee *exitErr) ExitCode() int {
	return ee.code
}
<commit_msg>Removed older "errors" package<commit_after><|endoftext|>


<commit_before>package engine

import (
	"encoding/json"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/funkygao/dbus"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

type APIHandler func(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error)

func (this *Engine) launchHttpServ() {
	this.httpRouter = mux.NewRouter()
	this.httpServer = &http.Server{
		Addr:    this.String("apisvr_addr", "127.0.0.1:9876"),
		Handler: this.httpRouter,
	}

	this.setupAPIRoutings()

	var err error
	if this.httpListener, err = net.Listen("tcp", this.httpServer.Addr); err != nil {
		panic(err)
	}

	go this.httpServer.Serve(this.httpListener)
	log.Info("API server ready on http://%s", this.httpServer.Addr)
}

func (this *Engine) stopHttpServ() {
	if this.httpListener != nil {
		this.httpListener.Close()
		log.Info("API server stopped")
	}
}

func (this *Engine) setupAPIRoutings() {
	this.RegisterAPI("/stat", this.httpStat).Methods("GET")
	this.RegisterAPI("/plugins", this.httpPlugins).Methods("GET")
}

func (this *Engine) httpPlugins(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error) {
	names := make([]string, 0, 20)
	for _, pr := range this.InputRunners {
		names = append(names, pr.Name())
	}
	for _, pr := range this.FilterRunners {
		names = append(names, pr.Name())
	}
	for _, pr := range this.OutputRunners {
		names = append(names, pr.Name())
	}

	return names, nil
}

func (this *Engine) httpStat(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error) {
	var output = make(map[string]interface{})
	output["ver"] = dbus.Version
	output["started"] = Globals().StartedAt
	output["elapsed"] = time.Since(Globals().StartedAt).String()
	output["pid"] = this.pid
	output["hostname"] = this.hostname
	output["build"] = dbus.BuildID
	return output, nil
}

func (this *Engine) RegisterAPI(path string, handlerFunc APIHandler) *mux.Route {
	wrappedFunc := func(w http.ResponseWriter, req *http.Request) {
		var (
			ret interface{}
			t1  = time.Now()
		)

		params, err := this.decodeHttpParams(w, req)
		if err == nil {
			ret, err = handlerFunc(w, req, params)
		}

		if err != nil {
			ret = map[string]interface{}{"error": err.Error()}
		}

		w.Header().Set("Server", "dbus")
		w.Header().Set("Content-Type", "application/json")
		var status int
		if err == nil {
			status = http.StatusOK
		} else {
			status = http.StatusInternalServerError
		}
		w.WriteHeader(status)

		// access log
		log.Trace("%s \"%s %s %s\" %d %s",
			req.RemoteAddr,
			req.Method,
			req.RequestURI,
			req.Proto,
			status,
			time.Since(t1))
		if status != http.StatusOK {
			log.Error("ERROR %v", err)
		}

		if ret != nil {
			// pretty write json result
			pretty, _ := json.MarshalIndent(ret, "", "    ")
			w.Write(pretty)
			w.Write([]byte("\n"))
		}
	}

	// path can't be duplicated
	for _, p := range this.httpPaths {
		if p == path {
			panic(path + " already registered")
		}
	}

	this.httpPaths = append(this.httpPaths, path)
	return this.httpRouter.HandleFunc(path, wrappedFunc)
}

func (this *Engine) decodeHttpParams(w http.ResponseWriter, req *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})
	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&params)
	if err != nil && err != io.EOF {
		return nil, err
	}

	return params, nil
}
<commit_msg>tweak of the plugins API<commit_after>package engine

import (
	"encoding/json"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/funkygao/dbus"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

type APIHandler func(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error)

func (this *Engine) launchHttpServ() {
	this.httpRouter = mux.NewRouter()
	this.httpServer = &http.Server{
		Addr:    this.String("apisvr_addr", "127.0.0.1:9876"),
		Handler: this.httpRouter,
	}

	this.setupAPIRoutings()

	var err error
	if this.httpListener, err = net.Listen("tcp", this.httpServer.Addr); err != nil {
		panic(err)
	}

	go this.httpServer.Serve(this.httpListener)
	log.Info("API server ready on http://%s", this.httpServer.Addr)
}

func (this *Engine) stopHttpServ() {
	if this.httpListener != nil {
		this.httpListener.Close()
		log.Info("API server stopped")
	}
}

func (this *Engine) setupAPIRoutings() {
	this.RegisterAPI("/stat", this.httpStat).Methods("GET")
	this.RegisterAPI("/plugins", this.httpPlugins).Methods("GET")
	this.RegisterAPI("/metris", this.httpMetrics).Methods("GET")
}

func (this *Engine) httpMetrics(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error) {
	return nil, nil
}

func (this *Engine) httpPlugins(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error) {
	plugins := make(map[string][]string)
	for _, r := range this.InputRunners {
		if _, present := plugins[r.Class()]; !present {
			plugins[r.Class()] = []string{r.Name()}
		} else {
			plugins[r.Class()] = append(plugins[r.Class()], r.Name())
		}
	}
	for _, r := range this.FilterRunners {
		if _, present := plugins[r.Class()]; !present {
			plugins[r.Class()] = []string{r.Name()}
		} else {
			plugins[r.Class()] = append(plugins[r.Class()], r.Name())
		}
	}
	for _, r := range this.OutputRunners {
		if _, present := plugins[r.Class()]; !present {
			plugins[r.Class()] = []string{r.Name()}
		} else {
			plugins[r.Class()] = append(plugins[r.Class()], r.Name())
		}
	}

	return plugins, nil
}

func (this *Engine) httpStat(w http.ResponseWriter, req *http.Request, params map[string]interface{}) (interface{}, error) {
	var output = make(map[string]interface{})
	output["ver"] = dbus.Version
	output["started"] = Globals().StartedAt
	output["elapsed"] = time.Since(Globals().StartedAt).String()
	output["pid"] = this.pid
	output["hostname"] = this.hostname
	output["build"] = dbus.BuildID
	return output, nil
}

func (this *Engine) RegisterAPI(path string, handlerFunc APIHandler) *mux.Route {
	wrappedFunc := func(w http.ResponseWriter, req *http.Request) {
		var (
			ret interface{}
			t1  = time.Now()
		)

		params, err := this.decodeHttpParams(w, req)
		if err == nil {
			ret, err = handlerFunc(w, req, params)
		}

		if err != nil {
			ret = map[string]interface{}{"error": err.Error()}
		}

		w.Header().Set("Server", "dbus")
		w.Header().Set("Content-Type", "application/json")
		var status int
		if err == nil {
			status = http.StatusOK
		} else {
			status = http.StatusInternalServerError
		}
		w.WriteHeader(status)

		// access log
		log.Trace("%s \"%s %s %s\" %d %s",
			req.RemoteAddr,
			req.Method,
			req.RequestURI,
			req.Proto,
			status,
			time.Since(t1))
		if status != http.StatusOK {
			log.Error("ERROR %v", err)
		}

		if ret != nil {
			// pretty write json result
			pretty, _ := json.MarshalIndent(ret, "", "    ")
			w.Write(pretty)
			w.Write([]byte("\n"))
		}
	}

	// path can't be duplicated
	for _, p := range this.httpPaths {
		if p == path {
			panic(path + " already registered")
		}
	}

	this.httpPaths = append(this.httpPaths, path)
	return this.httpRouter.HandleFunc(path, wrappedFunc)
}

func (this *Engine) decodeHttpParams(w http.ResponseWriter, req *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})
	decoder := json.NewDecoder(req.Body)
	err := decoder.Decode(&params)
	if err != nil && err != io.EOF {
		return nil, err
	}

	return params, nil
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"net/http"

	"github.com/labstack/echo"
	log "github.com/sirupsen/logrus"
	"github.com/ubccr/goipa"
	"github.com/ubccr/mokey/model"
)

func (h *Handler) ApiKey(c echo.Context) error {
	if len(h.apiClients) == 0 {
		log.Info("No api key clients configured")
		return echo.NewHTTPError(http.StatusNotFound, "No api key clients configured")
	}

	user := c.Get(ContextKeyUser).(*ipa.UserRecord)

	vars := map[string]interface{}{
		"user": user,
		"csrf": c.Get("csrf").(string),
	}

	if c.Request().Method == "POST" {
		action := c.FormValue("action")
		clientID := c.FormValue("client_id")

		if clientID != "" && action == "remove" {
			err := h.removeApiKey(string(user.Uid), clientID)

			if err == nil {
				vars["message"] = "Api Key Deleted"
			} else {
				vars["message"] = err.Error()
			}
		} else if clientID != "" && action == "enable" {
			secret, client, err := h.enableApiKey(string(user.Uid), clientID)

			if err == nil {
				vars := map[string]interface{}{
					"client": client,
					"secret": secret,
					"user":   user}

				return c.Render(http.StatusOK, "apikey-show.html", vars)
			}

			vars["message"] = err.Error()
		}
	}

	keys, err := h.db.FetchApiKeys(string(user.Uid))
	if err != nil && err != model.ErrNotFound {
		log.WithFields(log.Fields{
			"uid":   string(user.Uid),
			"error": err,
		}).Error("Failed to fetch api keys")
		return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch api keys")
	}

	keyMap := make(map[string]*model.ApiKey)
	for _, k := range keys {
		keyMap[k.ClientID] = k
	}

	vars["apiClients"] = h.apiClients
	vars["keys"] = keyMap

	return c.Render(http.StatusOK, "apikey.html", vars)
}

func (h *Handler) removeApiKey(user, clientID string) error {
	err := h.db.DestroyApiKey(user, clientID)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":   user,
			"error": err,
		}).Error("Failed to remove api key")
		return errors.New("Failed to remove api key")
	}

	return nil
}

func (h *Handler) enableApiKey(user, clientID string) (string, *model.ApiKeyClient, error) {
	client, ok := h.apiClients[clientID]
	if !ok {
		log.WithFields(log.Fields{
			"uid":      user,
			"clientID": client.ClientID,
		}).Error("Invalid client ID")
		return "", nil, errors.New("Invalid client id")
	}

	_, secret, err := h.db.CreateApiKey(user, client.ClientID, client.Scopes)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":      user,
			"clientID": client.ClientID,
			"error":    err,
		}).Error("Failed to create new api key")
		return "", nil, errors.New("Fatal system error. Please contact your administrator")
	}

	return secret, client, nil
}
<commit_msg>When user removes apikey, revoke login/consent sessions with Hydra<commit_after>package server

import (
	"errors"
	"net/http"

	"github.com/labstack/echo"
	log "github.com/sirupsen/logrus"
	"github.com/ubccr/goipa"
	"github.com/ubccr/mokey/model"
)

func (h *Handler) ApiKey(c echo.Context) error {
	if len(h.apiClients) == 0 {
		log.Info("No api key clients configured")
		return echo.NewHTTPError(http.StatusNotFound, "No api key clients configured")
	}

	user := c.Get(ContextKeyUser).(*ipa.UserRecord)

	vars := map[string]interface{}{
		"user": user,
		"csrf": c.Get("csrf").(string),
	}

	if c.Request().Method == "POST" {
		action := c.FormValue("action")
		clientID := c.FormValue("client_id")

		if clientID != "" && action == "remove" {
			err := h.removeApiKey(string(user.Uid), clientID)

			if err == nil {
				vars["message"] = "Api Key Deleted"
			} else {
				vars["message"] = err.Error()
			}
		} else if clientID != "" && action == "enable" {
			secret, client, err := h.enableApiKey(string(user.Uid), clientID)

			if err == nil {
				vars := map[string]interface{}{
					"client": client,
					"secret": secret,
					"user":   user}

				return c.Render(http.StatusOK, "apikey-show.html", vars)
			}

			vars["message"] = err.Error()
		}
	}

	keys, err := h.db.FetchApiKeys(string(user.Uid))
	if err != nil && err != model.ErrNotFound {
		log.WithFields(log.Fields{
			"uid":   string(user.Uid),
			"error": err,
		}).Error("Failed to fetch api keys")
		return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch api keys")
	}

	keyMap := make(map[string]*model.ApiKey)
	for _, k := range keys {
		keyMap[k.ClientID] = k
	}

	vars["apiClients"] = h.apiClients
	vars["keys"] = keyMap

	return c.Render(http.StatusOK, "apikey.html", vars)
}

func (h *Handler) removeApiKey(user, clientID string) error {
	err := h.db.DestroyApiKey(user, clientID)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":   user,
			"error": err,
		}).Error("Failed to remove api key")
		return errors.New("Failed to remove api key")
	}

	response, err := h.hydraClient.RevokeAuthenticationSession(user)
	if err != nil {
		log.WithFields(log.Fields{
			"error":    err,
			"user":     user,
			"clientID": clientID,
		}).Error("Failed to revoke hydra authentication session")
	} else if response.StatusCode != http.StatusOK {
		log.WithFields(log.Fields{
			"statusCode": response.StatusCode,
			"user":       user,
			"clientID":   clientID,
		}).Error("HTTP Response not OK. Failed to revoke hydra authentication session")
	}

	response, err = h.hydraClient.RevokeUserClientConsentSessions(user, clientID)
	if err != nil {
		log.WithFields(log.Fields{
			"error":    err,
			"user":     user,
			"clientID": clientID,
		}).Error("Failed to revoke hydra consent session")
	} else if response.StatusCode != http.StatusOK {
		log.WithFields(log.Fields{
			"statusCode": response.StatusCode,
			"user":       user,
			"clientID":   clientID,
		}).Error("HTTP Response not OK. Failed to revoke hydra consent session")
	}

	return nil
}

func (h *Handler) enableApiKey(user, clientID string) (string, *model.ApiKeyClient, error) {
	client, ok := h.apiClients[clientID]
	if !ok {
		log.WithFields(log.Fields{
			"uid":      user,
			"clientID": client.ClientID,
		}).Error("Invalid client ID")
		return "", nil, errors.New("Invalid client id")
	}

	_, secret, err := h.db.CreateApiKey(user, client.ClientID, client.Scopes)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":      user,
			"clientID": client.ClientID,
			"error":    err,
		}).Error("Failed to create new api key")
		return "", nil, errors.New("Fatal system error. Please contact your administrator")
	}

	return secret, client, nil
}
<|endoftext|>


<commit_before>package daveloc

import (
	"fmt"
	"net/http"
	// "encoding/json"
	"time"
	// "log"
)

type DaveCoord struct {
	lat float32
	lon float32
}

type DaveLoc struct {
	coord   DaveCoord
	heading int16
}

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	loc := getDaveLoc()
	fmt.Fprintf(w, "{\"lat\": %f, \"lon\" : %f,\"heading\": %d}", loc.coord.lat, loc.coord.lon, loc.heading)
}

func getCurrentCoord(start DaveCoord, finish DaveCoord, percent float32) DaveCoord {
	lat := ((finish.lat - start.lat) * percent) + start.lat
	lon := ((finish.lon - start.lon) * percent) + start.lon
	return DaveCoord{lat, lon}
}

func getDaveLoc() *DaveLoc {
	topRight := DaveCoord{47.631568, -122.132382}
	topLeft := DaveCoord{47.631503, -122.143143}
	bottomLeft := DaveCoord{47.627852, -122.143068}
	bottomRight := DaveCoord{47.627801, -122.132479}

	currentTime := time.Now()
	currentSec := currentTime.Second()
	currentPos := currentSec / 15
	percentComplete := float32(currentSec) / 60.0
	var returnCoord DaveCoord
	var heading int16

	switch currentPos {
	case 0:
		returnCoord = getCurrentCoord(topRight, topLeft, percentComplete)
		heading = 270
	case 1:
		returnCoord = getCurrentCoord(topLeft, bottomLeft, percentComplete)
		heading = 180
	case 2:
		returnCoord = getCurrentCoord(bottomLeft, bottomRight, percentComplete)
		heading = 90
	case 3:
		returnCoord = getCurrentCoord(bottomRight, topRight, percentComplete)
		heading = 0
	}
	return &DaveLoc{returnCoord, heading}
}
<commit_msg>added ID Tag to sample JSON<commit_after>package daveloc

import (
	"fmt"
	"net/http"
	// "encoding/json"
	"time"
	// "log"
)

type DaveCoord struct {
	lat float32
	lon float32
}

type DaveLoc struct {
	coord   DaveCoord
	heading int16
}

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	loc := getDaveLoc()
	fmt.Fprintf(w, "{\"lat\": %f, \"lon\" : %f,\"heading\": %d, \"id\" : 5}", loc.coord.lat, loc.coord.lon, loc.heading)
}

func getCurrentCoord(start DaveCoord, finish DaveCoord, percent float32) DaveCoord {
	lat := ((finish.lat - start.lat) * percent) + start.lat
	lon := ((finish.lon - start.lon) * percent) + start.lon
	return DaveCoord{lat, lon}
}

func getDaveLoc() *DaveLoc {
	topRight := DaveCoord{47.631568, -122.132382}
	topLeft := DaveCoord{47.631503, -122.143143}
	bottomLeft := DaveCoord{47.627852, -122.143068}
	bottomRight := DaveCoord{47.627801, -122.132479}

	currentTime := time.Now()
	currentSec := currentTime.Second()
	currentPos := currentSec / 15
	percentComplete := float32(currentSec) / 60.0
	var returnCoord DaveCoord
	var heading int16

	switch currentPos {
	case 0:
		returnCoord = getCurrentCoord(topRight, topLeft, percentComplete)
		heading = 270
	case 1:
		returnCoord = getCurrentCoord(topLeft, bottomLeft, percentComplete)
		heading = 180
	case 2:
		returnCoord = getCurrentCoord(bottomLeft, bottomRight, percentComplete)
		heading = 90
	case 3:
		returnCoord = getCurrentCoord(bottomRight, topRight, percentComplete)
		heading = 0
	}
	return &DaveLoc{returnCoord, heading}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package alitasks

import (
	"fmt"
	"strings"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ram"

	"k8s.io/klog"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
	"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
)

//go:generate fitask -type=RAMRole

type RAMRole struct {
	Lifecycle                *fi.Lifecycle
	Name                     *string
	AssumeRolePolicyDocument *string
	RAMRoleId                *string
}

var _ fi.CompareWithID = &RAMRole{}

func (r *RAMRole) CompareWithID() *string {
	return r.Name
}

func compactPolicy(s string) string {
	removedStrings := []string{"\n", "
", " ", "\r\n"}
	for _, each := range removedStrings {
		s = strings.Replace(s, each, "", -1)
	}
	return s
}

func (r *RAMRole) Find(c *fi.Context) (*RAMRole, error) {
	cloud := c.Cloud.(aliup.ALICloud)

	request := ram.RoleQueryRequest{
		RoleName: fi.StringValue(r.Name),
	}

	roleResp, err := cloud.RamClient().GetRole(request)
	if err != nil {
		if e, ok := err.(*common.Error); ok && e.StatusCode == 404 {
			klog.V(2).Infof("no RamRole with name: %q", *r.Name)
			return nil, nil
		}
		return nil, fmt.Errorf("error get RamRole %q: %v", *r.Name, err)
	}

	role := roleResp.Role
	if role.RoleId == "" {
		klog.V(2).Infof("no RamRole with name: %q", *r.Name)
		return nil, nil
	}

	klog.V(2).Infof("found matching RamRole with name: %q", *r.Name)
	actual := &RAMRole{
		Name:                     fi.String(role.RoleName),
		RAMRoleId:                fi.String(role.RoleId),
		AssumeRolePolicyDocument: fi.String(compactPolicy(role.AssumeRolePolicyDocument)),
	}

	// Ignore "system" fields
	actual.Lifecycle = r.Lifecycle
	r.RAMRoleId = actual.RAMRoleId

	return actual, nil
}

func (r *RAMRole) Run(c *fi.Context) error {
	return fi.DefaultDeltaRunMethod(r, c)
}

func (_ *RAMRole) CheckChanges(a, e, changes *RAMRole) error {
	if a == nil {
		if e.AssumeRolePolicyDocument == nil {
			return fi.RequiredField("AssumeRolePolicyDocument")
		}
		if e.Name == nil {
			return fi.RequiredField("Name")
		}
	}
	return nil
}

func (_ *RAMRole) RenderALI(t *aliup.ALIAPITarget, a, e, changes *RAMRole) error {
	if a == nil {
		klog.V(2).Infof("Creating RAMRole with Name:%q", fi.StringValue(e.Name))

		roleRequest := ram.RoleRequest{
			RoleName:                 fi.StringValue(e.Name),
			AssumeRolePolicyDocument: fi.StringValue(e.AssumeRolePolicyDocument),
		}

		roleResponse, err := t.Cloud.RamClient().CreateRole(roleRequest)
		if err != nil {
			return fmt.Errorf("error creating RAMRole: %v", err)
		}

		e.RAMRoleId = fi.String(roleResponse.Role.RoleId)
	}

	return nil
}

type terraformRAMRole struct {
	Name     *string `json:"name,omitempty"`
	Document *string `json:"document,omitempty"`
}

func (_ *RAMRole) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *RAMRole) error {
	tf := &terraformRAMRole{
		Name:     e.Name,
		Document: e.AssumeRolePolicyDocument,
	}
	return t.RenderResource("alicloud_ram_role", *e.Name, tf)
}

func (s *RAMRole) TerraformLink() *terraform.Literal {
	return terraform.LiteralProperty("alicloud_ram_role", *s.Name, "name")
}
<commit_msg>Alicloud: rename RAMRoleId to ID in RAMRole<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package alitasks

import (
	"fmt"
	"strings"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ram"

	"k8s.io/klog"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
	"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
)

//go:generate fitask -type=RAMRole

type RAMRole struct {
	ID                       *string
	Lifecycle                *fi.Lifecycle
	Name                     *string
	AssumeRolePolicyDocument *string
}

var _ fi.CompareWithID = &RAMRole{}

func (r *RAMRole) CompareWithID() *string {
	return r.Name
}

func compactPolicy(s string) string {
	removedStrings := []string{"\n", "
", " ", "\r\n"}
	for _, each := range removedStrings {
		s = strings.Replace(s, each, "", -1)
	}
	return s
}

func (r *RAMRole) Find(c *fi.Context) (*RAMRole, error) {
	cloud := c.Cloud.(aliup.ALICloud)

	request := ram.RoleQueryRequest{
		RoleName: fi.StringValue(r.Name),
	}

	roleResp, err := cloud.RamClient().GetRole(request)
	if err != nil {
		if e, ok := err.(*common.Error); ok && e.StatusCode == 404 {
			klog.V(2).Infof("no RamRole with name: %q", *r.Name)
			return nil, nil
		}
		return nil, fmt.Errorf("error get RamRole %q: %v", *r.Name, err)
	}

	role := roleResp.Role
	if role.RoleId == "" {
		klog.V(2).Infof("no RamRole with name: %q", *r.Name)
		return nil, nil
	}

	klog.V(2).Infof("found matching RamRole with name: %q", *r.Name)
	actual := &RAMRole{
		Name:                     fi.String(role.RoleName),
		ID:                       fi.String(role.RoleId),
		AssumeRolePolicyDocument: fi.String(compactPolicy(role.AssumeRolePolicyDocument)),
	}

	// Ignore "system" fields
	actual.Lifecycle = r.Lifecycle
	r.ID = actual.ID

	return actual, nil
}

func (r *RAMRole) Run(c *fi.Context) error {
	return fi.DefaultDeltaRunMethod(r, c)
}

func (_ *RAMRole) CheckChanges(a, e, changes *RAMRole) error {
	if a == nil {
		if e.AssumeRolePolicyDocument == nil {
			return fi.RequiredField("AssumeRolePolicyDocument")
		}
		if e.Name == nil {
			return fi.RequiredField("Name")
		}
	}
	return nil
}

func (_ *RAMRole) RenderALI(t *aliup.ALIAPITarget, a, e, changes *RAMRole) error {
	if a == nil {
		klog.V(2).Infof("Creating RAMRole with Name:%q", fi.StringValue(e.Name))

		roleRequest := ram.RoleRequest{
			RoleName:                 fi.StringValue(e.Name),
			AssumeRolePolicyDocument: fi.StringValue(e.AssumeRolePolicyDocument),
		}

		roleResponse, err := t.Cloud.RamClient().CreateRole(roleRequest)
		if err != nil {
			return fmt.Errorf("error creating RAMRole: %v", err)
		}

		e.ID = fi.String(roleResponse.Role.RoleId)
	}

	return nil
}

type terraformRAMRole struct {
	Name     *string `json:"name,omitempty"`
	Document *string `json:"document,omitempty"`
}

func (_ *RAMRole) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *RAMRole) error {
	tf := &terraformRAMRole{
		Name:     e.Name,
		Document: e.AssumeRolePolicyDocument,
	}
	return t.RenderResource("alicloud_ram_role", *e.Name, tf)
}

func (s *RAMRole) TerraformLink() *terraform.Literal {
	return terraform.LiteralProperty("alicloud_ram_role", *s.Name, "name")
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"time"

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

var settings struct {
	DailyTarget int
	Database    string
}

func init() {
	flag.IntVar(&settings.DailyTarget, "target", 900, "The number of words to write daily")
	flag.StringVar(&settings.Database, "db", "diary.db", "The name of the database file")
}

func main() {
	flag.Parse()

	db, err := sql.Open("sqlite3", settings.Database)
	if err != nil {
		panic(err)
	}

	_, err = db.Exec("CREATE TABLE IF NOT EXISTS entries (date TEXT PRIMARY KEY, text TEXT, words INTEGER)")
	if err != nil {
		panic(err)
	}

	if flag.NArg() >= 1 {
		cmd := flag.Arg(0)
		if cmd == "import" {
			importEntry(db)
			return
		}
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		now := time.Now()
		days := daysOfMonth(now)
		annotatedDays, err := annotateDays(db, days)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}

		text := ""
		words := 0
		rows, err := db.Query("SELECT text, words FROM entries WHERE date = ?", now.Format("2006-01-02"))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
		defer rows.Close()

		if rows.Next() {
			err = rows.Scan(&text, &words)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			}
		}

		err = indexTmpl.Execute(w, map[string]interface{}{
			"Title": fmt.Sprintf("%d words", settings.DailyTarget),

			"Now":  now,
			"Days": annotatedDays,

			"Text":  text,
			"Words": words,
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.HandleFunc("/save", func(w http.ResponseWriter, req *http.Request) {
		var entry map[string]string
		dec := json.NewDecoder(req.Body)
		err := dec.Decode(&entry)
		if err != nil {
			respondWithError(w, http.StatusBadRequest, err)
			return
		}

		text, ok := entry["text"]
		if !ok {
			respondWithError(w, http.StatusBadRequest, fmt.Errorf("Missing field 'text'"))
			return
		}

		now := time.Now()
		err = saveEntry(db, now, text)
		if err != nil {
			respondWithError(w, http.StatusInternalServerError, fmt.Errorf("%s", http.StatusText(http.StatusInternalServerError)))
			return
		}

		enc := json.NewEncoder(w)
		err = enc.Encode(map[string]string{"message": "saved post", "time": now.Format(time.RFC3339)})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.ListenAndServe("localhost:12345", nil)
}

func respondWithError(w http.ResponseWriter, status int, err error) {
	res := map[string]string{"error": err.Error()}
	out, err := json.Marshal(res)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "{\"error\": %q}", http.StatusText(http.StatusInternalServerError))
		return
	}
	w.WriteHeader(status)
	w.Write(out)
}

func saveEntry(db *sql.DB, date time.Time, text string) error {
	_, err := db.Exec("INSERT OR REPLACE INTO entries VALUES (?, ?, ?)", date.Format("2006-01-02"), text, countWords(text))
	return err
}

func importEntry(db *sql.DB) {
	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s import <date>\n", os.Args[0])
		os.Exit(1)
	}

	rawDate := flag.Arg(1)
	date, err := time.Parse("2006-01-02", rawDate)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid date '%s': %s\n", rawDate, err)
		os.Exit(1)
	}

	f := os.Stdin
	if flag.NArg() >= 3 {
		f, err = os.Open(flag.Arg(2))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			os.Exit(1)
		}
	}
	defer f.Close()

	text, err := ioutil.ReadAll(f)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: reading %s: %s\n", f.Name(), err)
		os.Exit(1)
	}

	err = saveEntry(db, date, string(text))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: saving entry: %s\n", err)
		os.Exit(1)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`<!doctype html>

		<meta charset="utf-8" />
		<title>{{ .Title }}</title>

{{ .Title }}

{{ .Now.Format "January 2006" }}

			{{ $now := .Now }}
			{{ range $day := .Days -}}

{{ $day.Date.Day }}

			{{ end }}

{{ .Now.Format "Monday, January 2, 2006" }}

				<textarea id="editor">{{ .Text }}</textarea>

					0 words

				Made with <3 by strange adventures.  —  /about

`))

var wordSeperator = regexp.MustCompile(`\s+`)

func countWords(text string) int {
	ws := wordSeperator.Split(text, -1)
	c := 0
	for _, w := range ws {
		if w != "" {
			c += 1
		}
	}
	return c
}

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}

type Day struct {
	Date  time.Time
	Words int
}

func (d Day) Classes(now time.Time) string {
	var classes string
	if d.Date.Before(now) {
		classes = "past"
	} else {
		classes = "future"
	}

	if d.Words >= 1 {
		classes += " written"
	}

	if d.Words >= settings.DailyTarget {
		classes += " yay"
	}

	return classes
}

func annotateDays(db *sql.DB, days []time.Time) ([]Day, error) {
	rows, err := db.Query("SELECT date, words FROM entries WHERE date >= ? AND date <= ?", days[0].Format("2006-01-02"), days[len(days)-1].Format("2006-01-02"))
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var day string
	var words int
	if rows.Next() {
		err = rows.Scan(&day, &words)
		if err != nil {
			return nil, err
		}
	}

	annotatedDays := make([]Day, len(days))
	for i, t := range days {
		d := Day{Date: t, Words: 0}

		if t.Format("2006-01-02") == day {
			d.Words = words

			if rows.Next() {
				err = rows.Scan(&day, &words)
				if err != nil {
					return nil, err
				}
			}
		}

		annotatedDays[i] = d
	}

	return annotatedDays, nil
}
<commit_msg>Make past days viewable<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

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

var settings struct {
	DailyTarget int
	Database    string
}

func init() {
	flag.IntVar(&settings.DailyTarget, "target", 900, "The number of words to write daily")
	flag.StringVar(&settings.Database, "db", "diary.db", "The name of the database file")
}

func main() {
	flag.Parse()

	db, err := sql.Open("sqlite3", settings.Database)
	if err != nil {
		panic(err)
	}

	_, err = db.Exec("CREATE TABLE IF NOT EXISTS entries (date TEXT PRIMARY KEY, text TEXT, words INTEGER)")
	if err != nil {
		panic(err)
	}

	if flag.NArg() >= 1 {
		cmd := flag.Arg(0)
		if cmd == "import" {
			importEntry(db)
			return
		}
	}

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		renderEntry(w, req, db, time.Now())
	})

	http.HandleFunc("/day/", func(w http.ResponseWriter, req *http.Request) {
		parts := strings.SplitN(req.URL.Path, "/", 3)
		if len(parts) != 3 {
			w.WriteHeader(http.StatusNotFound)
			w.Write([]byte(http.StatusText(http.StatusNotFound)))
			return
		}

		date, err := time.Parse("2006-01-02", parts[2])
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintf(w, "No such day: %q\n", parts[2])
			fmt.Fprintf(os.Stderr, "Invalid date: %q: %s\n", date, err)
			return
		}

		renderEntry(w, req, db, date)
	})

	http.HandleFunc("/save", func(w http.ResponseWriter, req *http.Request) {
		var entry map[string]string
		dec := json.NewDecoder(req.Body)
		err := dec.Decode(&entry)
		if err != nil {
			respondWithError(w, http.StatusBadRequest, err)
			return
		}

		text, ok := entry["text"]
		if !ok {
			respondWithError(w, http.StatusBadRequest, fmt.Errorf("Missing field 'text'"))
			return
		}

		now := time.Now()
		err = saveEntry(db, now, text)
		if err != nil {
			respondWithError(w, http.StatusInternalServerError, fmt.Errorf("%s", http.StatusText(http.StatusInternalServerError)))
			return
		}

		enc := json.NewEncoder(w)
		err = enc.Encode(map[string]string{"message": "saved post", "time": now.Format(time.RFC3339)})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})

	http.ListenAndServe("localhost:12345", nil)
}

func respondWithError(w http.ResponseWriter, status int, err error) {
	res := map[string]string{"error": err.Error()}
	out, err := json.Marshal(res)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "{\"error\": %q}", http.StatusText(http.StatusInternalServerError))
		return
	}
	w.WriteHeader(status)
	w.Write(out)
}

func renderEntry(w http.ResponseWriter, req *http.Request, db *sql.DB, date time.Time) {
	now := time.Now()
	isSameDay := date.Format("2006-01-02") == now.Format("2006-01-02")

	if isSameDay && req.URL.Path != "/" {
		w.Header().Set("Location", "/")
		w.WriteHeader(http.StatusTemporaryRedirect)
		return
	}

	days := daysOfMonth(date)
	annotatedDays, err := annotateDays(db, days)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
	}

	text := ""
	words := 0
	rows, err := db.Query("SELECT text, words FROM entries WHERE date = ?", date.Format("2006-01-02"))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
	}
	defer rows.Close()

	if rows.Next() {
		err = rows.Scan(&text, &words)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	}

	err = indexTmpl.Execute(w, map[string]interface{}{
		"Title": fmt.Sprintf("%d words", settings.DailyTarget),

		"Now":  now,
		"Day":  date,
		"Days": annotatedDays,

		"Text":  text,
		"Words": words,

		"Editable": isSameDay,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
	}
}

func saveEntry(db *sql.DB, date time.Time, text string) error {
	_, err := db.Exec("INSERT OR REPLACE INTO entries VALUES (?, ?, ?)", date.Format("2006-01-02"), text, countWords(text))
	return err
}

func importEntry(db *sql.DB) {
	if flag.NArg() < 2 {
		fmt.Fprintf(os.Stderr, "Usage: %s import <date>\n", os.Args[0])
		os.Exit(1)
	}

	rawDate := flag.Arg(1)
	date, err := time.Parse("2006-01-02", rawDate)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: invalid date '%s': %s\n", rawDate, err)
		os.Exit(1)
	}

	f := os.Stdin
	if flag.NArg() >= 3 {
		f, err = os.Open(flag.Arg(2))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
			os.Exit(1)
		}
	}
	defer f.Close()

	text, err := ioutil.ReadAll(f)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: reading %s: %s\n", f.Name(), err)
		os.Exit(1)
	}

	err = saveEntry(db, date, string(text))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: saving entry: %s\n", err)
		os.Exit(1)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`<!doctype html>

		<meta charset="utf-8" />
		<title>{{ .Title }}</title>

{{ .Title }}

{{ .Day.Format "January 2006" }}

			{{ $now := .Now }}
			{{ range $day := .Days -}}

{{ $day.Date.Day }}

			{{ end }}

{{ .Day.Format "Monday, January 2, 2006" }}

				{{ if not .Editable }}
This day is over, so you can't change what you wrote anymore.  Try again today.
{{ end }}
				<textarea id="editor" {{ if not .Editable }}disabled{{ end }}>{{ .Text }}</textarea>

					0 words

				Made with <3 by strange adventures.  —  /about

`))

var wordSeperator = regexp.MustCompile(`\s+`)

func countWords(text string) int {
	ws := wordSeperator.Split(text, -1)
	c := 0
	for _, w := range ws {
		if w != "" {
			c += 1
		}
	}
	return c
}

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}

type Day struct {
	Date  time.Time
	Words int
}

func (d Day) Classes(now time.Time) string {
	var classes string
	if d.Date.Before(now) {
		classes = "past"
	} else {
		classes = "future"
	}

	if d.Words >= 1 {
		classes += " written"
	}

	if d.Words >= settings.DailyTarget {
		classes += " yay"
	}

	return classes
}

func annotateDays(db *sql.DB, days []time.Time) ([]Day, error) {
	rows, err := db.Query("SELECT date, words FROM entries WHERE date >= ? AND date <= ?", days[0].Format("2006-01-02"), days[len(days)-1].Format("2006-01-02"))
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var day string
	var words int
	if rows.Next() {
		err = rows.Scan(&day, &words)
		if err != nil {
			return nil, err
		}
	}

	annotatedDays := make([]Day, len(days))
	for i, t := range days {
		d := Day{Date: t, Words: 0}

		if t.Format("2006-01-02") == day {
			d.Words = words

			if rows.Next() {
				err = rows.Scan(&day, &words)
				if err != nil {
					return nil, err
				}
			}
		}

		annotatedDays[i] = d
	}

	return annotatedDays, nil
}
<|endoftext|>