<commit_before>// Force12.io is a package that monitors demand for resource in a system and then scales and repurposes
// containers, based on agreed "quality of service" contracts, to best handle that demand within the constraints of your existing VM
// or physical infrastructure (for v1).
//
// Force12 is defined to optimize the use of existing physical and VM resources instantly. VMs cannot be scaled in real time (it takes
// several minutes) and new physical machines take even longer. However, containers can be started or stopped at sub second speeds,
// allowing your infrastructure to adapt itself in real time to meet system demands.
//
// Force12 is aimed at effectively using the resources you have right now - your existing VMs or physical servers - by using them as
// optimally as possible.
//
// The Force12 approach is analogous to the way that a router dynamically optimises the use of a physical network. A router is limited
// by the capacity of the lines physically connected to it. Adding additional capacity is a physical process and takes time. Routers
// therefore make decisions in real time about which packets will be prioritized on a particular line based on the packet's priority
// (defined by a "quality of service" contract).
//
// For example, at times of high bandwidth usage a router might prioritize VOIP traffic over web browsing in real time.
//
// Containers allow Force12 to make similar "instant" judgements on service prioritisation within your existing infrastructure. Routers
// make very simplistic judgments because they have limited time and cpu and they act at a per packet level. Force12 has the capability
// of making far more sophisticated judgements, although even fairly simple ones will still provide a significant new service.
//
// This prototype is a bare bones implementation of Force12.io that recognises only 1 demand type:
// randomised demand for a priority 1 service. Resources are allocated to meet this demand for priority 1, and spare resource can
// be used for a priority 2 service.
//
// These demand type examples have been chosen purely for simplicity of demonstration. In the future more demand types
// will be offered
//
// V1 - Force12.io reacts to increased demand by starting/stopping containers on the slaves already in play.
//
// This version of Force12 starts and stops containers on a Mesos cluser using Marathon as the scheduler
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"bitbucket.org/force12io/force12-scheduler/compose"
	"bitbucket.org/force12io/force12-scheduler/consul"
	"bitbucket.org/force12io/force12-scheduler/demand"
	"bitbucket.org/force12io/force12-scheduler/marathon"
	"bitbucket.org/force12io/force12-scheduler/rng"
	"bitbucket.org/force12io/force12-scheduler/scheduler"
)

type sendStatePayload struct {
	CreatedAt          int64 `json:"createdAt"`
	Priority1Requested int   `json:"priority1Requested"`
	Priority1Running   int   `json:"priority1Running"`
	Priority2Running   int   `json:"priority2Running"`
}

const const_sleep = 100          //milliseconds
const const_sendstate_sleeps = 5 // number of sleeps before we send state on the API
const const_stopsleep = 250      //milliseconds pause between stopping and restarting containers
const const_p1demandstart int = 5
const const_p2demandstart int = 4
const const_maxcontainers int = 9

var p1TaskName string
var p2TaskName string
var p1FamilyName string
var p2FamilyName string

type Demand struct {
	sched scheduler.Scheduler
	input demand.Input

	p1demand    int // number of Priority 1 tasks demanded
	p2demand    int
	p1requested int // indicates how many P1 tasks we've tried to kick off.
	p2requested int
}

// set returns values that were there (p1, p2)
// if provided value is -1 don't update, demand will always be between 0 and const_maxcontainers
func (d *Demand) set(p1, p2 int) (int, int) {
	//d.mu.Lock()
	p1old := d.p1demand
	p2old := d.p2demand
	if p2 != -1 {
		d.p2demand = p2
	}
	if p1 != -1 {
		d.p1demand = p1
	}
	//d.mu.Unlock()
	return p1old, p2old
}

// get returns client, server AEC - Combine this with the set to reduce code
func (d *Demand) get() (int, int) {
	return d.p1demand, d.p2demand
}

// handle processes a change in demand
// Note that handle will make any judgment on what to do with a demand
// change, including potentially nothing.
func (d *Demand) handle() error {
	var err error
	err = d.sched.StopStartNTasks(p1TaskName, p1FamilyName, d.p1demand, d.p1requested)
	if err != nil {
		log.Printf("Failed to start Priority1 tasks. %v", err)
	}
	d.sched.StopStartNTasks(p2TaskName, p2FamilyName, d.p2demand, d.p2requested)
	if err != nil {
		log.Printf("Failed to start Priority2 tasks. %v", err)
	}

	return err
}

// update checks for changes in demand, returning true if demand changed
// Note that this function makes no judgement on whether a demand change is
// significant. handle() will determine that.
func (d *Demand) update() bool {
	//log.Println("demand update check.")
	var demandchange bool

	container_count, err := d.sched.GetContainerCount("priority1-demand")
	if err != nil {
		log.Printf("Failed to get container count. %v", err)
		return false
	}
	//log.Printf("container count %v\n", container_count)

	//Update our saved p1 demand
	oldP1, _ := d.set(container_count, const_maxcontainers-container_count)

	//Has the demand changed?
	demandchange = (container_count != oldP1)

	if demandchange {
		log.Println("demandchange from, to ", oldP1, container_count)
	}

	return demandchange
}

// sendStateToAPI checks the current state of cluster (or single node) and sends that
// state to the f12 API
func sendStateToAPI(currentdemand *Demand) error {
	count1, count2, err := currentdemand.sched.CountAllTasks()
	if err != nil {
		return fmt.Errorf("Failed to get state err %v", err)
	}

	// Submit a PUT request to the API
	// Note the magic hardcoded string is the user ID, we need to pass this in in some way. ENV VAR?
	url := getBaseF12APIUrl() + "/metrics/" + "5k5gk"
	log.Printf("API PUT: %s", url)

	payload := sendStatePayload{
		CreatedAt:          time.Now().Unix(),
		Priority1Requested: currentdemand.p1demand,
		Priority1Running:   count1,
		Priority2Running:   count2,
	}

	w := &bytes.Buffer{}
	encoder := json.NewEncoder(w)
	err = encoder.Encode(&payload)
	if err != nil {
		return fmt.Errorf("Failed to encode API json. %v", err)
	}

	req, err := http.NewRequest("PUT", url, w)

	if err != nil {
		return fmt.Errorf("Failed to build API PUT request err %v", err)
	}
	//req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	if err != nil {
		// handle error
		return fmt.Errorf("API state err %v", err)
	}

	if resp.StatusCode > 204 {
		return fmt.Errorf("error response from API. %s", resp.Status)
	}
	return err
}

func getBaseF12APIUrl() string {
	baseUrl := os.Getenv("API_ADDRESS")
	if baseUrl == "" {
		baseUrl = "https://force12-windtunnel.herokuapp.com"
	}
	return baseUrl
}

func getEnvOrDefault(name string, defaultValue string) string {
	v := os.Getenv(name)
	if v == "" {
		v = defaultValue
	}

	return v
}

// For the simple prototype, Force12.io sits in a loop checking for demand changes every X milliseconds
// In phase 2 we'll add a reactive mode where appropriate.
//
// Note - we don't route messages from demandcheckers to demandhandlers using channels because we want new values
// to override old values. Queued history is of no importance here.
//
// Also for simplicity this first release is concurrency free (single threaded)
func main() {
	var err error
	// TODO! Make it so you can send in settings on the command line
	var demandModelType string = getEnvOrDefault("F12_DEMAND_MODEL", "RNG")
	var schedulerType string = getEnvOrDefault("F12_SCHEDULER", "COMPOSE")
	var sendstate string = getEnvOrDefault("F12_SEND_STATE_TO_API", "true")
	p1TaskName = getEnvOrDefault("F12_PRIORITY1_TASK", "priority1-demand")
	p2TaskName = getEnvOrDefault("F12_PRIORITY2_TASK", "priority2-demand")
	// TODO!! FInd out what CLIENT/SERVER_FAMILY should default to
	p1FamilyName = os.Getenv("F12_PRIORITY1_FAMILY")
	p2FamilyName = os.Getenv("F12_PRIORITY2_FAMILY")

	var di demand.Input
	var s scheduler.Scheduler

	switch demandModelType {
	case "CONSUL":
		log.Println("Getting demand metric from Consul")
		di = consul.NewDemandModel()
	case "RNG":
		log.Println("Random demand generation")
		di = rng.NewDemandModel()
	default:
		log.Printf("Bad value for F12_DEMAND_MODEL: %s", demandModelType)
		return
	}

	switch schedulerType {
	case "MESOS":
		log.Println("Scheduling with Mesos / Marathon")
		s = marathon.NewScheduler()
	case "COMPOSE":
		log.Println("Scheduling with Docker compose")
		s = compose.NewScheduler()
	default:
		log.Printf("Bad value for F12_SCHEDULER: %s", schedulerType)
		return
	}

	currentdemand := Demand{
		input: di,
	}
	currentdemand.set(const_p1demandstart, const_p2demandstart)

	// Initialise container types
	err = currentdemand.sched.InitScheduler(p1TaskName)
	if err != nil {
		log.Printf("Failed to start P1 task. %v", err)
		return
	}

	err = currentdemand.sched.InitScheduler(p2TaskName)
	if err != nil {
		log.Printf("Failed to start P2 task. %v", err)
		return
	}

	var demandchangeflag bool
	demandchangeflag = currentdemand.update()
	demandchangeflag = true

	var sleepcount int = 0
	var sleep time.Duration
	sleep = const_sleep * time.Millisecond

	for {
		//Update currentdemand with latest client and server demand, if changed, set flag
		demandchangeflag = currentdemand.update()
		if demandchangeflag {
			// See how many tasks we should have already
			currentdemand.p1requested, currentdemand.p2requested, err = currentdemand.sched.CountAllTasks()
			if err != nil {
				log.Printf("Failed to count tasks. %v", err)
			}
			//make any changes dictated by the new demand level
			err = currentdemand.handle()
			if err != nil {
				log.Printf("Failed to handle demand change. %v", err)
			}
		}

		time.Sleep(sleep)
		sleepcount++
		if sleepcount == const_sendstate_sleeps {
			sleepcount = 0

			//Periodically send state to the API if required
			if sendstate == "true" {
				err = sendStateToAPI(&currentdemand)
				if err != nil {
					log.Printf("Failed to send state. %v", err)
				}
			}
		}

	}
}
<commit_msg>Get demand from the demand input not the scheduler. Also some variable names that I think are clearer<commit_after>// Force12.io is a package that monitors demand for resource in a system and then scales and repurposes
// containers, based on agreed "quality of service" contracts, to best handle that demand within the constraints of your existing VM
// or physical infrastructure (for v1).
//
// Force12 is defined to optimize the use of existing physical and VM resources instantly. VMs cannot be scaled in real time (it takes
// several minutes) and new physical machines take even longer. However, containers can be started or stopped at sub second speeds,
// allowing your infrastructure to adapt itself in real time to meet system demands.
//
// Force12 is aimed at effectively using the resources you have right now - your existing VMs or physical servers - by using them as
// optimally as possible.
//
// The Force12 approach is analogous to the way that a router dynamically optimises the use of a physical network. A router is limited
// by the capacity of the lines physically connected to it. Adding additional capacity is a physical process and takes time. Routers
// therefore make decisions in real time about which packets will be prioritized on a particular line based on the packet's priority
// (defined by a "quality of service" contract).
//
// For example, at times of high bandwidth usage a router might prioritize VOIP traffic over web browsing in real time.
//
// Containers allow Force12 to make similar "instant" judgements on service prioritisation within your existing infrastructure. Routers
// make very simplistic judgments because they have limited time and cpu and they act at a per packet level. Force12 has the capability
// of making far more sophisticated judgements, although even fairly simple ones will still provide a significant new service.
//
// This prototype is a bare bones implementation of Force12.io that recognises only 1 demand type:
// randomised demand for a priority 1 service. Resources are allocated to meet this demand for priority 1, and spare resource can
// be used for a priority 2 service.
//
// These demand type examples have been chosen purely for simplicity of demonstration. In the future more demand types
// will be offered
//
// V1 - Force12.io reacts to increased demand by starting/stopping containers on the slaves already in play.
//
// This version of Force12 starts and stops containers on a Mesos cluser using Marathon as the scheduler
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"bitbucket.org/force12io/force12-scheduler/compose"
	"bitbucket.org/force12io/force12-scheduler/consul"
	"bitbucket.org/force12io/force12-scheduler/demand"
	"bitbucket.org/force12io/force12-scheduler/marathon"
	"bitbucket.org/force12io/force12-scheduler/rng"
	"bitbucket.org/force12io/force12-scheduler/scheduler"
)

type sendStatePayload struct {
	CreatedAt          int64 `json:"createdAt"`
	Priority1Requested int   `json:"priority1Requested"`
	Priority1Running   int   `json:"priority1Running"`
	Priority2Running   int   `json:"priority2Running"`
}

const const_sleep = 100          //milliseconds
const const_sendstate_sleeps = 5 // number of sleeps before we send state on the API
const const_stopsleep = 250      //milliseconds pause between stopping and restarting containers
const const_p1demandstart int = 5
const const_p2demandstart int = 4
const const_maxcontainers int = 9

var p1TaskName string
var p2TaskName string
var p1FamilyName string
var p2FamilyName string

type Demand struct {
	sched scheduler.Scheduler
	input demand.Input

	p1demand    int // number of Priority 1 tasks demanded
	p2demand    int
	p1requested int // indicates how many P1 tasks we've tried to kick off.
	p2requested int
}

// set returns values that were there (p1, p2)
// if provided value is -1 don't update, demand will always be between 0 and const_maxcontainers
func (d *Demand) set(p1, p2 int) (int, int) {
	//d.mu.Lock()
	p1old := d.p1demand
	p2old := d.p2demand
	if p2 != -1 {
		d.p2demand = p2
	}
	if p1 != -1 {
		d.p1demand = p1
	}
	//d.mu.Unlock()
	return p1old, p2old
}

// get returns client, server AEC - Combine this with the set to reduce code
func (d *Demand) get() (int, int) {
	return d.p1demand, d.p2demand
}

// handle processes a change in demand
// Note that handle will make any judgment on what to do with a demand
// change, including potentially nothing.
func (d *Demand) handle() error {
	var err error
	err = d.sched.StopStartNTasks(p1TaskName, p1FamilyName, d.p1demand, d.p1requested)
	if err != nil {
		log.Printf("Failed to start Priority1 tasks. %v", err)
	}
	d.sched.StopStartNTasks(p2TaskName, p2FamilyName, d.p2demand, d.p2requested)
	if err != nil {
		log.Printf("Failed to start Priority2 tasks. %v", err)
	}

	return err
}

// update checks for changes in demand, returning true if demand changed
// Note that this function makes no judgement on whether a demand change is
// significant. handle() will determine that.
func (d *Demand) update() bool {
	//log.Println("demand update check.")
	var demandchange bool

	newP1Demand, err := d.input.GetDemand("priority1-demand")
	if err != nil {
		log.Printf("Failed to get new demand. %v", err)
		return false
	}
	//log.Printf("container count %v\n", container_count)
	newP2Demand := const_maxcontainers - newP1Demand

	//Update our saved demand
	oldP1Demand, oldP2Demand := d.set(newP1Demand, newP2Demand)

	//Has the demand changed?
	demandchange = (newP1Demand != oldP1Demand) || (newP2Demand != oldP2Demand)

	if demandchange {
		log.Printf("P1 demand changed from %d to %d", oldP1Demand, newP1Demand)
	}

	return demandchange
}

// sendStateToAPI checks the current state of cluster (or single node) and sends that
// state to the f12 API
func sendStateToAPI(currentdemand *Demand) error {
	count1, count2, err := currentdemand.sched.CountAllTasks()
	if err != nil {
		return fmt.Errorf("Failed to get state err %v", err)
	}

	// Submit a PUT request to the API
	// Note the magic hardcoded string is the user ID, we need to pass this in in some way. ENV VAR?
	url := getBaseF12APIUrl() + "/metrics/" + "5k5gk"
	log.Printf("API PUT: %s", url)

	payload := sendStatePayload{
		CreatedAt:          time.Now().Unix(),
		Priority1Requested: currentdemand.p1demand,
		Priority1Running:   count1,
		Priority2Running:   count2,
	}

	w := &bytes.Buffer{}
	encoder := json.NewEncoder(w)
	err = encoder.Encode(&payload)
	if err != nil {
		return fmt.Errorf("Failed to encode API json. %v", err)
	}

	req, err := http.NewRequest("PUT", url, w)

	if err != nil {
		return fmt.Errorf("Failed to build API PUT request err %v", err)
	}
	//req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	defer resp.Body.Close()

	if err != nil {
		// handle error
		return fmt.Errorf("API state err %v", err)
	}

	if resp.StatusCode > 204 {
		return fmt.Errorf("error response from API. %s", resp.Status)
	}
	return err
}

func getBaseF12APIUrl() string {
	baseUrl := os.Getenv("API_ADDRESS")
	if baseUrl == "" {
		baseUrl = "https://force12-windtunnel.herokuapp.com"
	}
	return baseUrl
}

func getEnvOrDefault(name string, defaultValue string) string {
	v := os.Getenv(name)
	if v == "" {
		v = defaultValue
	}

	return v
}

// For the simple prototype, Force12.io sits in a loop checking for demand changes every X milliseconds
// In phase 2 we'll add a reactive mode where appropriate.
//
// Note - we don't route messages from demandcheckers to demandhandlers using channels because we want new values
// to override old values. Queued history is of no importance here.
//
// Also for simplicity this first release is concurrency free (single threaded)
func main() {
	var err error
	// TODO! Make it so you can send in settings on the command line
	var demandModelType string = getEnvOrDefault("F12_DEMAND_MODEL", "RNG")
	var schedulerType string = getEnvOrDefault("F12_SCHEDULER", "COMPOSE")
	var sendstate string = getEnvOrDefault("F12_SEND_STATE_TO_API", "true")
	p1TaskName = getEnvOrDefault("F12_PRIORITY1_TASK", "priority1-demand")
	p2TaskName = getEnvOrDefault("F12_PRIORITY2_TASK", "priority2-demand")
	// TODO!! FInd out what CLIENT/SERVER_FAMILY should default to
	p1FamilyName = os.Getenv("F12_PRIORITY1_FAMILY")
	p2FamilyName = os.Getenv("F12_PRIORITY2_FAMILY")

	var di demand.Input
	var s scheduler.Scheduler

	switch demandModelType {
	case "CONSUL":
		log.Println("Getting demand metric from Consul")
		di = consul.NewDemandModel()
	case "RNG":
		log.Println("Random demand generation")
		di = rng.NewDemandModel()
	default:
		log.Printf("Bad value for F12_DEMAND_MODEL: %s", demandModelType)
		return
	}

	switch schedulerType {
	case "MESOS":
		log.Println("Scheduling with Mesos / Marathon")
		s = marathon.NewScheduler()
	case "COMPOSE":
		log.Println("Scheduling with Docker compose")
		s = compose.NewScheduler()
	default:
		log.Printf("Bad value for F12_SCHEDULER: %s", schedulerType)
		return
	}

	currentdemand := Demand{
		input: di,
	}
	currentdemand.set(const_p1demandstart, const_p2demandstart)

	// Initialise container types
	err = currentdemand.sched.InitScheduler(p1TaskName)
	if err != nil {
		log.Printf("Failed to start P1 task. %v", err)
		return
	}

	err = currentdemand.sched.InitScheduler(p2TaskName)
	if err != nil {
		log.Printf("Failed to start P2 task. %v", err)
		return
	}

	var demandchangeflag bool
	demandchangeflag = currentdemand.update()
	demandchangeflag = true

	var sleepcount int = 0
	var sleep time.Duration
	sleep = const_sleep * time.Millisecond

	for {
		//Update currentdemand with latest client and server demand, if changed, set flag
		demandchangeflag = currentdemand.update()
		if demandchangeflag {
			// See how many tasks we should have already
			currentdemand.p1requested, currentdemand.p2requested, err = currentdemand.sched.CountAllTasks()
			if err != nil {
				log.Printf("Failed to count tasks. %v", err)
			}
			//make any changes dictated by the new demand level
			err = currentdemand.handle()
			if err != nil {
				log.Printf("Failed to handle demand change. %v", err)
			}
		}

		time.Sleep(sleep)
		sleepcount++
		if sleepcount == const_sendstate_sleeps {
			sleepcount = 0

			//Periodically send state to the API if required
			if sendstate == "true" {
				err = sendStateToAPI(&currentdemand)
				if err != nil {
					log.Printf("Failed to send state. %v", err)
				}
			}
		}

	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

// Track is a program to track the time you spend on a project by storing
// the start and end times in a CSV file.
//
// The aim of track is to make it easy to manage your time.
package main

import (
	"os"
)

const which = map[string]func(string){
	"verify": verify,
	"status": status,
	"list":   list,
	"total":  total,
	"begin":  begin,
	"end":    end,
	"run":    run,
	"wait":   wait,
	"fork":   fork,
}

func main() {
	var path = "TIMES.csv"
	var command = status

	n := len(os.Args)
	if n > 1 {
		command = which[os.Args[1]]
		if command == nil || n > 3 {
			help()
			return
		}

		if n == 3 {
			path = os.Args[2]
		}
	}

	command(path)
}

func help() {}

func verify(path string) {}

func status(path string) {}

func list(path string) {}

func total(path string) {}

func begin(path string) {}

func end(path string) {}

func run(path string) {}

func wait(path string) {}

func fork(path string) {}
<commit_msg>WIP: 16. December 2013<commit_after>// Copyright (c) 2013, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

// Track is a program to track the time you spend on a project by storing
// the start and end times in a CSV file.
//
// The aim of track is to make it easy to manage your time.
package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/goulash/util"
)

const defaultTimesFile = "TIMES.csv"

var which = map[string]func(string){
	"verify": Verify,
	"status": Status,
	"list":   List,
	"total":  Total,
	"begin":  Begin,
	"end":    End,
	"run":    Run,
	"wait":   Wait,
	"fork":   Fork,
}

type FormatError struct {
	BadLines  []int
	LastIsBad bool
}

func (e *FormatError) JustIncomplete() bool {
	return len(e.BadLines) == 1 && e.LastIsBad
}

func (e *FormatError) Error() string {
	if e.JustIncomplete() {
		return "last entry is incomplete"
	} else {
		return fmt.Sprint("contains invalid entries on line(s)", e.BadLines...)
	}
}

func main() {
	var path = defaultTimesFile
	var command = Status

	n := len(os.Args)
	if n > 1 {
		command = which[os.Args[1]]
		if command == nil || n > 3 {
			Help()
			return
		}

		if n == 3 {
			path = os.Args[2]
		}
	}

	err := command(path)
	if err != nil {
		fmt.Fprintf("Error: %s\n", err)
		os.Exit(1)
	}
}

func Help() {
	fmt.Printf(`Usage: tracker [command [file]]

The default command is:
	tracker status %s

Commands available are:
    verify  verify the validity of the times
    status  show the current status of the times
    list    list all the times
    total   print the sum of all the times
    begin   begin a new time entry
    end     complete the begun time entry
	next	begin or end the entry depending on the contents
    run     begin a new time entry and complete upon termination
    wait    upon termination, complete the begun time entry
    fork    begin a new time entry and fork to terminate later
`, defaultTimesFile)
}

func Verify(path string) error {}

func Status(path string) error {}

func List(path string) error {}

func Total(path string) error {}

func Begin(path string) error {
	_, err := util.IsFileExists(path)
	if err != nil {
		return err
	}

	f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = verify(f); err != nil {
		return err
	}
	begin(f)
	return nil
}

func begin(f *File) {
	w := csv.NewWriter(f)
	w.Write([]string{currentTime()})
	w.Flush()
}

func Next(path string) error {
	_, err := util.IsFileExists(path)
	if err != nil {
		return err
	}

	f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = verify(f); err != nil {
		if ferr, ok := err.(*FormatError); ok {
			if ferr.JustIncomplete() {
				end(f) // then we complete it
				return nil
			}
		}
		return err
	}
	begin(f)
	return nil
}

func End(path string) error {}

func end(f *File) {
	// TODO
	w := csv.NewWriter(f)
}

func Run(path string) error {
	Begin(path)
	Wait(path)
}

func Wait(path string) error {}

func Fork(path string) error {}

// currentTime returns the current time as a string.
func currentTime() string {
	return time.Now().String()
}

// verify reads through all records from the Reader r, and returns a FormatError
// if any of the entries are invalid or incomplete.
func verify(r io.Reader) (count int, err error) {
	v := csv.NewReader(r)
	v.FieldsPerRecord = -1

	var formatErr FormatError
	for {
		r, err := v.Read()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}

		count++
		if len(r) == 2 {
			formatErr.LastIsBad = false
		} else {
			formatErr.LastIsBad = true
			if formatErr.BadLines == nil {
				formatErr.BadLines = make([]int, 0, 2)
			}
			append(formatErr.BadLines, count)
		}
	}

	if formatErr.BadLines != nil {
		return &formatErr
	}

	return nil
}
<|endoftext|>


<commit_before>package main

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

//custom type
type timeHandler struct {
	format string
}

// ServeHTTP for custom time which makes it a handler
func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(th.format)
	w.Write([]byte("The time is: " + tm))
}

//One off method handler
func timeHandlerOneOff(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(time.RFC1123)
	w.Write([]byte("The time is: " + tm))
}

//One off that we can pass things to!
func timeHandlerClosure(format string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is " + tm + " | CLOSURE!"))
	}
	return http.HandlerFunc(fn)
}

//different closure
func timeHandlerDifferentClosure(format string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is: " + tm))
	})
}

func main() {
	mux := http.NewServeMux()

	rh := http.RedirectHandler("http://example.org", 307)
	mux.Handle("/foo", rh)

	//time
	th1123 := &timeHandler{format: time.RFC1123}
	mux.Handle("/time/rfc1123", th1123)

	//reuse!
	th3339 := &timeHandler{format: time.RFC3339}
	mux.Handle("/time/rfc3339", th3339)

	//one off method
	thOneOff := http.HandlerFunc(timeHandlerOneOff)
	mux.Handle("/time/oneoff", thOneOff)

	//even simpler
	mux.HandleFunc("/time/simpler", timeHandlerOneOff)

	//passing through closure
	thClosure := timeHandlerClosure(time.RFC1123)
	mux.Handle("/time/closure", thClosure)

	thDifferent := timeHandlerDifferentClosure(time.RFC1123)
	mux.Handle("/time/different", thDifferent)

	log.Println("Listening...")
	http.ListenAndServe(":3000", mux)
}
<commit_msg>Yet another closure pattern<commit_after>package main

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

//custom type
type timeHandler struct {
	format string
}

// ServeHTTP for custom time which makes it a handler
func (th *timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(th.format)
	w.Write([]byte("The time is: " + tm))
}

//One off method handler
func timeHandlerOneOff(w http.ResponseWriter, r *http.Request) {
	tm := time.Now().Format(time.RFC1123)
	w.Write([]byte("The time is: " + tm))
}

//One off that we can pass things to!
func timeHandlerClosure(format string) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is " + tm + " | CLOSURE!"))
	}
	return http.HandlerFunc(fn)
}

//different closure
func timeHandlerDifferentClosure(format string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is: " + tm))
	})
}

//Third closure
func timeHandlerThirdClosure(format string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		tm := time.Now().Format(format)
		w.Write([]byte("The time is: " + tm))
	}
}

func main() {
	mux := http.NewServeMux()

	rh := http.RedirectHandler("http://example.org", 307)
	mux.Handle("/foo", rh)

	//time
	th1123 := &timeHandler{format: time.RFC1123}
	mux.Handle("/time/rfc1123", th1123)

	//reuse!
	th3339 := &timeHandler{format: time.RFC3339}
	mux.Handle("/time/rfc3339", th3339)

	//one off method
	thOneOff := http.HandlerFunc(timeHandlerOneOff)
	mux.Handle("/time/oneoff", thOneOff)

	//even simpler
	mux.HandleFunc("/time/simpler", timeHandlerOneOff)

	//passing through closure
	thClosure := timeHandlerClosure(time.RFC1123)
	mux.Handle("/time/closure", thClosure)

	//second closure
	thDifferent := timeHandlerDifferentClosure(time.RFC1123)
	mux.Handle("/time/different", thDifferent)

	//third closure
	thThirdClosure := timeHandlerThirdClosure(time.RFC1123)
	mux.Handle("/time/third", thThirdClosure)

	log.Println("Listening...")
	http.ListenAndServe(":3000", mux)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type bufReader struct {
	r   *bufio.Reader
	buf []byte
	i   int
}

var reader = &bufReader{
	bufio.NewReader(os.Stdin),
	make([]byte, 0),
	0,
}

func (r *bufReader) readLine() {
	if r.i < len(r.buf) {
		return
	}
	r.buf = make([]byte, 0)
	r.i = 0
	for {
		line, isPrefix, err := r.r.ReadLine()
		if err != nil {
			panic(err)
		}
		r.buf = append(r.buf, line...)
		if !isPrefix {
			break
		}
	}
}

func (r *bufReader) next() string {
	r.readLine()
	from := r.i
	for ; r.i < len(r.buf); r.i++ {
		if r.buf[r.i] == ' ' {
			break
		}
	}
	s := string(r.buf[from:r.i])
	r.i++
	return s
}

func (r *bufReader) nextLine() string {
	r.readLine()
	s := string(r.buf[r.i:])
	r.i = len(r.buf)
	return s
}

var writer = bufio.NewWriter(os.Stdout)

func next() string {
	return reader.next()
}

func nextInt64() int64 {
	i, err := strconv.ParseInt(reader.next(), 10, 64)
	if err != nil {
		panic(err)
	}
	return i
}

func nextInt() int {
	return int(nextInt64())
}

func nextLine() string {
	return reader.nextLine()
}

func out(a ...interface{}) {
	fmt.Fprintln(writer, a...)
}

func max64(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

func min64(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func abs64(x int64) int64 {
	if x < 0 {
		return -x
	}
	return x
}

func max(x, y int) int {
	return int(max64(int64(x), int64(y)))
}

func min(x, y int) int {
	return int(min64(int64(x), int64(y)))
}

func abs(x int) int {
	return int(abs64(int64(x)))
}

func joinInt64s(a []int64, sep string) string {
	b := make([]string, len(a))
	for i, v := range a {
		b[i] = strconv.FormatInt(v, 10)
	}
	return strings.Join(b, sep)
}

func joinInts(a []int, sep string) string {
	b := make([]string, len(a))
	for i, v := range a {
		b[i] = strconv.Itoa(v)
	}
	return strings.Join(b, sep)
}

func divUp64(x, y int64) int64 {
	return (x + y - 1) / y
}

func divUp(x, y int) int {
	return int(divUp64(int64(x), int64(y)))
}

func main() {
	solve()
	writer.Flush()
}

func solve() {

}
<commit_msg>Add the `gcd` and `lcm` functions<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type bufReader struct {
	r   *bufio.Reader
	buf []byte
	i   int
}

var reader = &bufReader{
	bufio.NewReader(os.Stdin),
	make([]byte, 0),
	0,
}

func (r *bufReader) readLine() {
	if r.i < len(r.buf) {
		return
	}
	r.buf = make([]byte, 0)
	r.i = 0
	for {
		line, isPrefix, err := r.r.ReadLine()
		if err != nil {
			panic(err)
		}
		r.buf = append(r.buf, line...)
		if !isPrefix {
			break
		}
	}
}

func (r *bufReader) next() string {
	r.readLine()
	from := r.i
	for ; r.i < len(r.buf); r.i++ {
		if r.buf[r.i] == ' ' {
			break
		}
	}
	s := string(r.buf[from:r.i])
	r.i++
	return s
}

func (r *bufReader) nextLine() string {
	r.readLine()
	s := string(r.buf[r.i:])
	r.i = len(r.buf)
	return s
}

var writer = bufio.NewWriter(os.Stdout)

func next() string {
	return reader.next()
}

func nextInt64() int64 {
	i, err := strconv.ParseInt(reader.next(), 10, 64)
	if err != nil {
		panic(err)
	}
	return i
}

func nextInt() int {
	return int(nextInt64())
}

func nextLine() string {
	return reader.nextLine()
}

func out(a ...interface{}) {
	fmt.Fprintln(writer, a...)
}

func max64(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

func min64(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func abs64(x int64) int64 {
	if x < 0 {
		return -x
	}
	return x
}

func max(x, y int) int {
	return int(max64(int64(x), int64(y)))
}

func min(x, y int) int {
	return int(min64(int64(x), int64(y)))
}

func abs(x int) int {
	return int(abs64(int64(x)))
}

func joinInt64s(a []int64, sep string) string {
	b := make([]string, len(a))
	for i, v := range a {
		b[i] = strconv.FormatInt(v, 10)
	}
	return strings.Join(b, sep)
}

func joinInts(a []int, sep string) string {
	b := make([]string, len(a))
	for i, v := range a {
		b[i] = strconv.Itoa(v)
	}
	return strings.Join(b, sep)
}

func divUp64(x, y int64) int64 {
	return (x + y - 1) / y
}

func divUp(x, y int) int {
	return int(divUp64(int64(x), int64(y)))
}

func gcd64(x, y int64) int64 {
	if x < y {
		x, y = y, x
	}
	for y != 0 {
		x, y = y, x % y
	}
	return x
}

func gcd(x, y int) int {
	return int(gcd64(int64(x), int64(y)))
}

func lcm64(x, y int64) int64 {
	return x*y/gcd64(x, y)
}

func lcm(x, y int) int {
	return int(lcm64(int64(x), int64(y)))
}

func main() {
	solve()
	writer.Flush()
}

func solve() {

}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent <ulfr@mozilla.com>
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	// modules
	"github.com/mozilla-services/userplex/modules"
	_ "github.com/mozilla-services/userplex/modules/authorizedkeys"
	_ "github.com/mozilla-services/userplex/modules/aws"
	_ "github.com/mozilla-services/userplex/modules/datadog"

	"github.com/mozilla-services/mozldap"
	"gopkg.in/yaml.v2"
)

type conf struct {
	Ldap struct {
		Uri, Username, Password string
		Insecure, Starttls      bool
	}
	UidMap []struct {
		LdapUid string
		UsedUid string
	}

	Modules []modules.Configuration
}

func main() {
	var (
		err  error
		conf conf
	)
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s - Manage users in various SaaS based on a LDAP source\n"+
			"Usage: %s -c config.yaml\n",
			os.Args[0], os.Args[0])
		flag.PrintDefaults()
	}
	var config = flag.String("c", "config.yaml", "Load configuration from file")
	var dryrun = flag.Bool("dry", false, "Dry run, don't create/delete, just show stuff")
	flag.Parse()

	// load the local configuration file
	fd, err := ioutil.ReadFile(*config)
	if err != nil {
		log.Fatal(err)
	}
	err = yaml.Unmarshal(fd, &conf)
	if err != nil {
		log.Fatalf("error: %v", err)
	}

	// instanciate an ldap client
	cli, err := mozldap.NewClient(
		conf.Ldap.Uri,
		conf.Ldap.Username,
		conf.Ldap.Password,
		&tls.Config{InsecureSkipVerify: conf.Ldap.Insecure},
		conf.Ldap.Starttls)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("connected %s on %s:%d, tls:%v starttls:%v\n", cli.BaseDN, cli.Host, cli.Port, cli.UseTLS, cli.UseStartTLS)

	// store the value of dryrun and the ldap client
	// in the configuration of each module
	for i := range conf.Modules {
		conf.Modules[i].DryRun = *dryrun
		conf.Modules[i].LdapCli = cli
	}

	// run each module in the order it appears in the configuration
	for _, modconf := range conf.Modules {
		if _, ok := modules.Available[modconf.Name]; !ok {
			log.Printf("[warning] %s module not registered, skipping it", modconf.Name)
			continue
		}
		log.Println("[info] invoking module", modconf.Name)
		run := modules.Available[modconf.Name].NewRun(modconf)
		err = run.Run()
		if err != nil {
			log.Printf("[error] %s module failed with error: %v", modconf.Name, err)
		}
	}
}
<commit_msg>Support running a single module via "-module <name>"<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Julien Vehent <ulfr@mozilla.com>
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	// modules
	"github.com/mozilla-services/userplex/modules"
	_ "github.com/mozilla-services/userplex/modules/authorizedkeys"
	_ "github.com/mozilla-services/userplex/modules/aws"
	_ "github.com/mozilla-services/userplex/modules/datadog"

	"github.com/mozilla-services/mozldap"
	"gopkg.in/yaml.v2"
)

type conf struct {
	Ldap struct {
		Uri, Username, Password string
		Insecure, Starttls      bool
	}
	UidMap []struct {
		LdapUid string
		UsedUid string
	}

	Modules []modules.Configuration
}

func main() {
	var (
		err  error
		conf conf
	)
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s - Manage users in various SaaS based on a LDAP source\n"+
			"Usage: %s -c config.yaml\n",
			os.Args[0], os.Args[0])
		flag.PrintDefaults()
	}
	var config = flag.String("c", "config.yaml", "Load configuration from file")
	var dryrun = flag.Bool("dry", false, "Dry run, don't create/delete, just show stuff")
	var runmod = flag.String("module", "all", "Module to run. if 'all', run all available modules (default)")
	flag.Parse()

	// load the local configuration file
	fd, err := ioutil.ReadFile(*config)
	if err != nil {
		log.Fatal(err)
	}
	err = yaml.Unmarshal(fd, &conf)
	if err != nil {
		log.Fatalf("error: %v", err)
	}

	// instanciate an ldap client
	cli, err := mozldap.NewClient(
		conf.Ldap.Uri,
		conf.Ldap.Username,
		conf.Ldap.Password,
		&tls.Config{InsecureSkipVerify: conf.Ldap.Insecure},
		conf.Ldap.Starttls)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("connected %s on %s:%d, tls:%v starttls:%v\n", cli.BaseDN, cli.Host, cli.Port, cli.UseTLS, cli.UseStartTLS)

	// store the value of dryrun and the ldap client
	// in the configuration of each module
	for i := range conf.Modules {
		conf.Modules[i].DryRun = *dryrun
		conf.Modules[i].LdapCli = cli
	}

	// run each module in the order it appears in the configuration
	for _, modconf := range conf.Modules {
		if *runmod != "all" && *runmod != modconf.Name {
			continue
		}
		if _, ok := modules.Available[modconf.Name]; !ok {
			log.Printf("[warning] %s module not registered, skipping it", modconf.Name)
			continue
		}
		log.Println("[info] invoking module", modconf.Name)
		run := modules.Available[modconf.Name].NewRun(modconf)
		err = run.Run()
		if err != nil {
			log.Printf("[error] %s module failed with error: %v", modconf.Name, err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"fmt"
	"log"
	"math/big"
	"time"

	"github.com/y0ssar1an/slack-pushups/internal/slack"
)

const (
	minPushUps  = 10
	maxPushUps  = 30
	openingHour = 10
	openingMin  = 0
	openingSec  = 0
	closingHour = 6
)

func main() {
	// fail early if zoneinfo db not present on server
	loc, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		log.Fatal(err)
	}

	ch, err := slack.NewChannel("api-test")
	if err != nil {
		log.Fatal(err)
	}

	// start async routine that chooses users randomly for push-ups
	nextMemberID := make(chan string)
	go randomMember(ch, nextMemberID)

	SgtMittens := slack.Bot{"SgtMitt"}

	for {
		now := time.Now().In(loc)
		if closed, timeToOpen := isAfterHours(now, loc); closed {
			time.Sleep(timeToOpen)
			SgtMittens.PostMessage("RISE AND SHINE, CUPCAKES!", ch)
		}

		var user slack.User
		for user.Name == "" {
			user, err = slack.NewUser(<-nextMemberID)
			if err != nil {
				log.Println(err)
				time.Sleep(1 * time.Minute)
			}
		}

		pushUps := randInt(minPushUps, maxPushUps+1) // +1 because upper bound is non-inclusive
		msg := fmt.Sprintf(
			"@%s %d PUSH-UPS RIGHT MEOW!",
			user.Name,
			pushUps,
		)

		if !closingSoon(now) {
			msg += "\nNext lottery for push-ups in 20 minutes"
		}

		err = SgtMittens.PostMessage(msg, ch)
		if err != nil {
			log.Println(err)
			time.Sleep(1 * time.Minute)
			continue
		}
		time.Sleep(20 * time.Minute)
	}
}

func randomMember(ch slack.Channel, nextMemberID chan string) {
	var err error
	for {
		err = ch.UpdateMembers()
		if err != nil {
			log.Println(err)
		}

		i := randInt(0, len(ch.Members))
		nextMemberID <- ch.Members[i]
	}
}

func randInt(min, max int) int {
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	if err != nil {
		log.Println(err)
	}
	// return min if rand.Int() call fails
	return int(n.Int64()) + min
}

func isAfterHours(now time.Time, loc *time.Location) (bool, time.Duration) {
	var timeToOpen time.Duration

	if isWeekend(now) {
		days := daysToMonday(now.Weekday())
		mondayOpeningTime := time.Date(now.Year(), now.Month(), now.Day()+days, openingHour, 0, 0, 0, loc)
		timeToOpen = mondayOpeningTime.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() < openingHour {
		openToday := time.Date(now.Year(), now.Month(), now.Day(), openingHour, 0, 0, 0, loc)
		timeToOpen = openToday.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() >= closingHour {
		openTomorrow := time.Date(now.Year(), now.Month(), now.Day()+1, openingHour, 0, 0, 0, loc)
		timeToOpen = openTomorrow.Sub(now)
		return true, timeToOpen
	}

	return false, timeToOpen // 0 time
}

func isWeekend(t time.Time) bool {
	day := t.Weekday()
	return (day == time.Friday && t.Hour() >= closingHour) || day == time.Saturday || day == time.Sunday
}

func daysToMonday(day time.Weekday) int {
	const weekdays = 7
	return (weekdays - int(day-time.Monday)) % weekdays
}

// Return true if closing time is in less than 20 minutes.
func closingSoon(now time.Time) bool {
	closingTime := time.Date(now.Year(), now.Month(), now.Day(), closingHour, 0, 0, 0, loc)
	return closingTime.Sub(now) <= (20 * time.Minute)
}
<commit_msg>Fix missing loc arg in closingSoon()<commit_after>package main

import (
	"crypto/rand"
	"fmt"
	"log"
	"math/big"
	"time"

	"github.com/y0ssar1an/slack-pushups/internal/slack"
)

const (
	minPushUps  = 10
	maxPushUps  = 30
	openingHour = 10
	openingMin  = 0
	openingSec  = 0
	closingHour = 6
)

func main() {
	// fail early if zoneinfo db not present on server
	loc, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		log.Fatal(err)
	}

	ch, err := slack.NewChannel("api-test")
	if err != nil {
		log.Fatal(err)
	}

	// start async routine that chooses users randomly for push-ups
	nextMemberID := make(chan string)
	go randomMember(ch, nextMemberID)

	SgtMittens := slack.Bot{"SgtMitt"}

	for {
		now := time.Now().In(loc)
		if closed, timeToOpen := isAfterHours(now, loc); closed {
			time.Sleep(timeToOpen)
			SgtMittens.PostMessage("RISE AND SHINE, CUPCAKES!", ch)
		}

		var user slack.User
		for user.Name == "" {
			user, err = slack.NewUser(<-nextMemberID)
			if err != nil {
				log.Println(err)
				time.Sleep(1 * time.Minute)
			}
		}

		pushUps := randInt(minPushUps, maxPushUps+1) // +1 because upper bound is non-inclusive
		msg := fmt.Sprintf(
			"@%s %d PUSH-UPS RIGHT MEOW!",
			user.Name,
			pushUps,
		)

		if !closingSoon(now, loc) {
			msg += "\nNext lottery for push-ups in 20 minutes"
		}

		err = SgtMittens.PostMessage(msg, ch)
		if err != nil {
			log.Println(err)
			time.Sleep(1 * time.Minute)
			continue
		}
		time.Sleep(20 * time.Minute)
	}
}

func randomMember(ch slack.Channel, nextMemberID chan string) {
	var err error
	for {
		err = ch.UpdateMembers()
		if err != nil {
			log.Println(err)
		}

		i := randInt(0, len(ch.Members))
		nextMemberID <- ch.Members[i]
	}
}

func randInt(min, max int) int {
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	if err != nil {
		log.Println(err)
	}
	// return min if rand.Int() call fails
	return int(n.Int64()) + min
}

func isAfterHours(now time.Time, loc *time.Location) (bool, time.Duration) {
	var timeToOpen time.Duration

	if isWeekend(now) {
		days := daysToMonday(now.Weekday())
		mondayOpeningTime := time.Date(now.Year(), now.Month(), now.Day()+days, openingHour, 0, 0, 0, loc)
		timeToOpen = mondayOpeningTime.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() < openingHour {
		openToday := time.Date(now.Year(), now.Month(), now.Day(), openingHour, 0, 0, 0, loc)
		timeToOpen = openToday.Sub(now)
		return true, timeToOpen
	}

	if now.Hour() >= closingHour {
		openTomorrow := time.Date(now.Year(), now.Month(), now.Day()+1, openingHour, 0, 0, 0, loc)
		timeToOpen = openTomorrow.Sub(now)
		return true, timeToOpen
	}

	return false, timeToOpen // 0 time
}

func isWeekend(t time.Time) bool {
	day := t.Weekday()
	return (day == time.Friday && t.Hour() >= closingHour) || day == time.Saturday || day == time.Sunday
}

func daysToMonday(day time.Weekday) int {
	const weekdays = 7
	return (weekdays - int(day-time.Monday)) % weekdays
}

// Return true if closing time is in less than 20 minutes.
func closingSoon(now time.Time, loc *time.Location) bool {
	closingTime := time.Date(now.Year(), now.Month(), now.Day(), closingHour, 0, 0, 0, loc)
	return closingTime.Sub(now) <= (20 * time.Minute)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"unicode/utf16"
)

type File struct {
	StringPool  *ResStringPool
	ResourceMap []uint32
	Namespace   *ResXMLTreeNamespaceExt
}

const (
	RES_NULL_TYPE        = 0x0000
	RES_STRING_POOL_TYPE = 0x0001
	RES_TABLE_TYPE       = 0x0002
	RES_XML_TYPE         = 0x0003

	// Chunk types in RES_XML_TYPE
	RES_XML_FIRST_CHUNK_TYPE     = 0x0100
	RES_XML_START_NAMESPACE_TYPE = 0x0100
	RES_XML_END_NAMESPACE_TYPE   = 0x0101
	RES_XML_START_ELEMENT_TYPE   = 0x0102
	RES_XML_END_ELEMENT_TYPE     = 0x0103
	RES_XML_CDATA_TYPE           = 0x0104
	RES_XML_LAST_CHUNK_TYPE      = 0x017f

	// This contains a uint32_t array mapping strings in the string
	// pool back to resource identifiers.  It is optional.
	RES_XML_RESOURCE_MAP_TYPE = 0x0180

	// Chunk types in RES_TABLE_TYPE
	RES_TABLE_PACKAGE_TYPE   = 0x0200
	RES_TABLE_TYPE_TYPE      = 0x0201
	RES_TABLE_TYPE_SPEC_TYPE = 0x0202
)

type ResChunkHeader struct {
	Type       uint16
	HeaderSize uint16
	Size       uint32
}

const SORTED_FLAG = 1 << 0
const UTF8_FLAG = 1 << 8

type ResStringPoolRef uint32

const NilResStringPoolRef = ResStringPoolRef(0xFFFFFFFF)

type ResStringPoolHeader struct {
	Header      ResChunkHeader
	StringCount uint32
	StyleCount  uint32
	Flags       uint32
	StringStart uint32
	StylesStart uint32
}

type ResStringPool struct {
	Header  ResStringPoolHeader
	Strings []string
	Styles  []string
}

type ResXMLTreeNode struct {
	Header     ResChunkHeader
	LineNumber uint32
	Comment    ResStringPoolRef
}

type ResXMLTreeNamespaceExt struct {
	Prefix ResStringPoolRef
	Uri    ResStringPoolRef
}

type ResXMLTreeAttrExt struct {
	NS             ResStringPoolRef
	Name           ResStringPoolRef
	AttributeStart uint16
	AttributeSize  uint16
	AttributeCount uint16
	IdIndex        uint16
	ClassIndex     uint16
	StyleIndex     uint16
}

type ResXMLTreeAttribute struct {
	NS         ResStringPoolRef
	Name       ResStringPoolRef
	RawValue   ResStringPoolRef
	TypedValue ResValue
}

const (
	TYPE_NULL            = 0x00
	TYPE_REFERENCE       = 0x01
	TYPE_ATTRIBUTE       = 0x02
	TYPE_STRING          = 0x03
	TYPE_FLOAT           = 0x04
	TYPE_DIMENSION       = 0x05
	TYPE_FRACTION        = 0x06
	TYPE_FIRST_INT       = 0x10
	TYPE_INT_DEC         = 0x10
	TYPE_INT_HEX         = 0x11
	TYPE_INT_BOOLEAN     = 0x12
	TYPE_FIRST_COLOR_INT = 0x1c
	TYPE_INT_COLOR_ARGB8 = 0x1c
	TYPE_INT_COLOR_RGB8  = 0x1d
	TYPE_INT_COLOR_ARGB4 = 0x1e
	TYPE_INT_COLOR_RGB4  = 0x1f
	TYPE_LAST_COLOR_INT  = 0x1f
	TYPE_LAST_INT        = 0x1f
)

type ResValue struct {
	Size     uint16
	Res0     uint8
	DataType uint8
	Data     uint32
}

type ResXMLTreeEndElementExt struct {
	NS   ResStringPoolRef
	Name ResStringPoolRef
}

func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	offset := uint32(header.HeaderSize)

	for offset < header.Size {
		sr.Seek(int64(offset), os.SEEK_SET)
		chunkHeader := &ResChunkHeader{}
		binary.Read(sr, binary.LittleEndian, chunkHeader)

		var err error
		chunkReader := io.NewSectionReader(r, int64(offset), int64(chunkHeader.Size))
		switch chunkHeader.Type {
		case RES_STRING_POOL_TYPE:
			f.StringPool, err = ReadStringPool(chunkReader)
		case RES_XML_RESOURCE_MAP_TYPE:
			f.ResourceMap, err = ReadResourceMap(chunkReader)
		case RES_XML_START_NAMESPACE_TYPE:
			err = f.ReadStartNamespace(chunkReader)
		case RES_XML_START_ELEMENT_TYPE:
			err = f.ReadStartElement(chunkReader)
		case RES_XML_END_ELEMENT_TYPE:
			err = f.ReadEndElement(chunkReader)
		default:
			fmt.Println(chunkHeader.Type)
		}
		if err != nil {
			return nil, err
		}

		offset += chunkHeader.Size
	}
	return f, nil
}

func (f *File) GetString(ref ResStringPoolRef) string {
	if ref == NilResStringPoolRef {
		return ""
	}
	return f.StringPool.Strings[int(ref)]
}

func ReadStringPool(sr *io.SectionReader) (*ResStringPool, error) {
	sp := new(ResStringPool)
	binary.Read(sr, binary.LittleEndian, &sp.Header)

	stringStarts := make([]uint32, sp.Header.StringCount)
	binary.Read(sr, binary.LittleEndian, stringStarts)
	styleStarts := make([]uint32, sp.Header.StyleCount)
	binary.Read(sr, binary.LittleEndian, styleStarts)

	sp.Strings = make([]string, sp.Header.StringCount)
	for i, start := range stringStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StringStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StringStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Strings[i] = str
	}

	sp.Styles = make([]string, sp.Header.StyleCount)
	for i, start := range styleStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StylesStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StylesStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Styles[i] = str
	}

	return sp, nil
}

func ReadUTF16(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint16, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(utf16.Decode(buf)), nil
}

func ReadUTF8(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint8, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

func ReadResourceMap(sr *io.SectionReader) ([]uint32, error) {
	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	count := (header.Size - uint32(header.HeaderSize)) / 4
	fmt.Println(header.Size, header.HeaderSize, count)
	resourceMap := make([]uint32, count)
	if err := binary.Read(sr, binary.LittleEndian, resourceMap); err != nil {
		return nil, err
	}
	return resourceMap, nil
}

func (f *File) ReadStartNamespace(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	namespace := new(ResXMLTreeNamespaceExt)
	binary.Read(sr, binary.LittleEndian, namespace)
	f.Namespace = namespace
	return nil
}

func (f *File) ReadStartElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	attrExt := new(ResXMLTreeAttrExt)
	binary.Read(sr, binary.LittleEndian, attrExt)

	fmt.Println(f.GetString(attrExt.Name))

	offset := int64(attrExt.AttributeStart + header.Header.HeaderSize)
	for i := 0; i < int(attrExt.AttributeCount); i++ {
		sr.Seek(offset, os.SEEK_SET)
		attr := new(ResXMLTreeAttribute)
		binary.Read(sr, binary.LittleEndian, attr)
		fmt.Println(f.GetString(attr.Name), f.GetString(attr.RawValue))
		offset += int64(attrExt.AttributeSize)
	}
	return nil
}

func (f *File) ReadEndElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
		return err
	}
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	ext := new(ResXMLTreeEndElementExt)
	if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
		return err
	}
	if ext.NS != NilResStringPoolRef {
		fmt.Printf("</%s:%s>\n", f.GetString(ext.NS), f.GetString(ext.Name))
	} else {
		fmt.Printf("</%s>\n", f.GetString(ext.Name))
	}
	return nil
}

func main() {
	f, _ := os.Open("AndroidManifest.xml")
	fmt.Println(NewFile(f))
}
<commit_msg>未知のタイプは無視<commit_after>package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"unicode/utf16"
)

type File struct {
	StringPool  *ResStringPool
	ResourceMap []uint32
	Namespace   *ResXMLTreeNamespaceExt
}

const (
	RES_NULL_TYPE        = 0x0000
	RES_STRING_POOL_TYPE = 0x0001
	RES_TABLE_TYPE       = 0x0002
	RES_XML_TYPE         = 0x0003

	// Chunk types in RES_XML_TYPE
	RES_XML_FIRST_CHUNK_TYPE     = 0x0100
	RES_XML_START_NAMESPACE_TYPE = 0x0100
	RES_XML_END_NAMESPACE_TYPE   = 0x0101
	RES_XML_START_ELEMENT_TYPE   = 0x0102
	RES_XML_END_ELEMENT_TYPE     = 0x0103
	RES_XML_CDATA_TYPE           = 0x0104
	RES_XML_LAST_CHUNK_TYPE      = 0x017f

	// This contains a uint32_t array mapping strings in the string
	// pool back to resource identifiers.  It is optional.
	RES_XML_RESOURCE_MAP_TYPE = 0x0180

	// Chunk types in RES_TABLE_TYPE
	RES_TABLE_PACKAGE_TYPE   = 0x0200
	RES_TABLE_TYPE_TYPE      = 0x0201
	RES_TABLE_TYPE_SPEC_TYPE = 0x0202
)

type ResChunkHeader struct {
	Type       uint16
	HeaderSize uint16
	Size       uint32
}

const SORTED_FLAG = 1 << 0
const UTF8_FLAG = 1 << 8

type ResStringPoolRef uint32

const NilResStringPoolRef = ResStringPoolRef(0xFFFFFFFF)

type ResStringPoolHeader struct {
	Header      ResChunkHeader
	StringCount uint32
	StyleCount  uint32
	Flags       uint32
	StringStart uint32
	StylesStart uint32
}

type ResStringPool struct {
	Header  ResStringPoolHeader
	Strings []string
	Styles  []string
}

type ResXMLTreeNode struct {
	Header     ResChunkHeader
	LineNumber uint32
	Comment    ResStringPoolRef
}

type ResXMLTreeNamespaceExt struct {
	Prefix ResStringPoolRef
	Uri    ResStringPoolRef
}

type ResXMLTreeAttrExt struct {
	NS             ResStringPoolRef
	Name           ResStringPoolRef
	AttributeStart uint16
	AttributeSize  uint16
	AttributeCount uint16
	IdIndex        uint16
	ClassIndex     uint16
	StyleIndex     uint16
}

type ResXMLTreeAttribute struct {
	NS         ResStringPoolRef
	Name       ResStringPoolRef
	RawValue   ResStringPoolRef
	TypedValue ResValue
}

const (
	TYPE_NULL            = 0x00
	TYPE_REFERENCE       = 0x01
	TYPE_ATTRIBUTE       = 0x02
	TYPE_STRING          = 0x03
	TYPE_FLOAT           = 0x04
	TYPE_DIMENSION       = 0x05
	TYPE_FRACTION        = 0x06
	TYPE_FIRST_INT       = 0x10
	TYPE_INT_DEC         = 0x10
	TYPE_INT_HEX         = 0x11
	TYPE_INT_BOOLEAN     = 0x12
	TYPE_FIRST_COLOR_INT = 0x1c
	TYPE_INT_COLOR_ARGB8 = 0x1c
	TYPE_INT_COLOR_RGB8  = 0x1d
	TYPE_INT_COLOR_ARGB4 = 0x1e
	TYPE_INT_COLOR_RGB4  = 0x1f
	TYPE_LAST_COLOR_INT  = 0x1f
	TYPE_LAST_INT        = 0x1f
)

type ResValue struct {
	Size     uint16
	Res0     uint8
	DataType uint8
	Data     uint32
}

type ResXMLTreeEndElementExt struct {
	NS   ResStringPoolRef
	Name ResStringPoolRef
}

func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	offset := uint32(header.HeaderSize)

	for offset < header.Size {
		sr.Seek(int64(offset), os.SEEK_SET)
		chunkHeader := &ResChunkHeader{}
		binary.Read(sr, binary.LittleEndian, chunkHeader)

		var err error
		chunkReader := io.NewSectionReader(r, int64(offset), int64(chunkHeader.Size))
		switch chunkHeader.Type {
		case RES_STRING_POOL_TYPE:
			f.StringPool, err = ReadStringPool(chunkReader)
		case RES_XML_RESOURCE_MAP_TYPE:
			f.ResourceMap, err = ReadResourceMap(chunkReader)
		case RES_XML_START_NAMESPACE_TYPE:
			err = f.ReadStartNamespace(chunkReader)
		case RES_XML_START_ELEMENT_TYPE:
			err = f.ReadStartElement(chunkReader)
		case RES_XML_END_ELEMENT_TYPE:
			err = f.ReadEndElement(chunkReader)
		}
		if err != nil {
			return nil, err
		}

		offset += chunkHeader.Size
	}
	return f, nil
}

func (f *File) GetString(ref ResStringPoolRef) string {
	if ref == NilResStringPoolRef {
		return ""
	}
	return f.StringPool.Strings[int(ref)]
}

func ReadStringPool(sr *io.SectionReader) (*ResStringPool, error) {
	sp := new(ResStringPool)
	binary.Read(sr, binary.LittleEndian, &sp.Header)

	stringStarts := make([]uint32, sp.Header.StringCount)
	binary.Read(sr, binary.LittleEndian, stringStarts)
	styleStarts := make([]uint32, sp.Header.StyleCount)
	binary.Read(sr, binary.LittleEndian, styleStarts)

	sp.Strings = make([]string, sp.Header.StringCount)
	for i, start := range stringStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StringStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StringStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Strings[i] = str
	}

	sp.Styles = make([]string, sp.Header.StyleCount)
	for i, start := range styleStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StylesStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StylesStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Styles[i] = str
	}

	return sp, nil
}

func ReadUTF16(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint16, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(utf16.Decode(buf)), nil
}

func ReadUTF8(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint8, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

func ReadResourceMap(sr *io.SectionReader) ([]uint32, error) {
	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	count := (header.Size - uint32(header.HeaderSize)) / 4
	fmt.Println(header.Size, header.HeaderSize, count)
	resourceMap := make([]uint32, count)
	if err := binary.Read(sr, binary.LittleEndian, resourceMap); err != nil {
		return nil, err
	}
	return resourceMap, nil
}

func (f *File) ReadStartNamespace(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	namespace := new(ResXMLTreeNamespaceExt)
	binary.Read(sr, binary.LittleEndian, namespace)
	f.Namespace = namespace
	return nil
}

func (f *File) ReadStartElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	attrExt := new(ResXMLTreeAttrExt)
	binary.Read(sr, binary.LittleEndian, attrExt)

	fmt.Println(f.GetString(attrExt.Name))

	offset := int64(attrExt.AttributeStart + header.Header.HeaderSize)
	for i := 0; i < int(attrExt.AttributeCount); i++ {
		sr.Seek(offset, os.SEEK_SET)
		attr := new(ResXMLTreeAttribute)
		binary.Read(sr, binary.LittleEndian, attr)
		fmt.Println(f.GetString(attr.Name), f.GetString(attr.RawValue))
		offset += int64(attrExt.AttributeSize)
	}
	return nil
}

func (f *File) ReadEndElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
		return err
	}
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	ext := new(ResXMLTreeEndElementExt)
	if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
		return err
	}
	if ext.NS != NilResStringPoolRef {
		fmt.Printf("</%s:%s>\n", f.GetString(ext.NS), f.GetString(ext.Name))
	} else {
		fmt.Printf("</%s>\n", f.GetString(ext.Name))
	}
	return nil
}

func main() {
	f, _ := os.Open("AndroidManifest.xml")
	fmt.Println(NewFile(f))
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"flag"
	"fmt"
	"os"
)

var (
	matchStr = flag.String("match", "", "regexp to match the output")
	shellStr = flag.String("run", "", "shell command to test reductions")
	verbose  = flag.Bool("v", false, "log applied changes to stderr")

	shellStrBuild = `go build -ldflags "-w -s"`
	shellStrRun   = `go build -ldflags "-w -s" -o out && ./out`
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Usage: goreduce -match=re [-run=cmd] dir\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
If -run=cmd is omitted, the default for non-main packages is:

  `+shellStrBuild+`

And for main packages:

  `+shellStrRun+`

The shell code is run in a Bash-compatible shell interpreter. The
package being reduced will be in its current directory.

To catch a run-time error/crash entering main:

  goreduce -match 'index out of range' .

To catch a build error/crash with custom build flags:

  goreduce -match 'internal compiler error' . 'go build -gcflags "-c=2"'

Note that you may also call a script or any other program.
`)
	}
	flag.Parse()
}

func main() {
	args := flag.Args()
	if len(args) < 1 || *matchStr == "" {
		flag.Usage()
		os.Exit(2)
	}
	if err := reduce(args[0], *matchStr, os.Stderr, *shellStr); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>fix 'go test' on Go 1.13 and later<commit_after>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"flag"
	"fmt"
	"os"
)

var (
	matchStr = flag.String("match", "", "regexp to match the output")
	shellStr = flag.String("run", "", "shell command to test reductions")
	verbose  = flag.Bool("v", false, "log applied changes to stderr")

	shellStrBuild = `go build -ldflags "-w -s"`
	shellStrRun   = `go build -ldflags "-w -s" -o out && ./out`
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Usage: goreduce -match=re [-run=cmd] dir\n")
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, `
If -run=cmd is omitted, the default for non-main packages is:

  `+shellStrBuild+`

And for main packages:

  `+shellStrRun+`

The shell code is run in a Bash-compatible shell interpreter. The
package being reduced will be in its current directory.

To catch a run-time error/crash entering main:

  goreduce -match 'index out of range' .

To catch a build error/crash with custom build flags:

  goreduce -match 'internal compiler error' . 'go build -gcflags "-c=2"'

Note that you may also call a script or any other program.
`)
	}
}

func main() {
	flag.Parse()
	args := flag.Args()
	if len(args) < 1 || *matchStr == "" {
		flag.Usage()
		os.Exit(2)
	}
	if err := reduce(args[0], *matchStr, os.Stderr, *shellStr); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

const (
	myName           = "gjfy"
	defaultHostname  = "localhost"
	listenDefault    = ":9154"
	uApiGet          = "/api/v1/get/"
	uApiNew          = "/api/v1/new"
	uGet             = "/g"
	uInfo            = "/i"
	uClientShell     = "/gjfy-post"
	uFav             = "/favicon.ico"
	uLogoSmall       = "/gjfy-logo-small.png"
	uCss             = "/custom.css"
	uLogo            = "/logo.png"
	maxData          = 1048576 // 1MB
	defaultValidity  = 7       // days
	expiryCheck      = 30      // minutes
	defaultMaxClicks = 1
	crtFile          = myName + ".crt"
	keyFile          = myName + ".key"
	TLSDefault       = false
	notifyDefault    = false
)

var (
	auth            TokenDB
	css             []byte
	logo            []byte
	updated         = time.Time{}
	fListen         string
	fURLBase        string
	fTLS            bool
	fNotify         bool
	scheme          = "http://"
	configDir       = "/etc/" + myName
	userMessageView string
)

type viewInfoEntry struct {
	StoreEntryInfo
	UserMessageView string
}

func getRealIP(r *http.Request) string {
	xFF := r.Header.Get("X-Forwarded-For")
	xRI := r.Header.Get("X-Real-IP")
	if xFF != "" {
		return xFF
	} else if xRI != "" {
		return xRI
	}
	return "none"
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		realRemoteAddr := getRealIP(r)
		log.Printf("%s (%s) \"%s %s %s\" \"%s\"", r.RemoteAddr, realRemoteAddr, r.Method, r.URL.Path, r.Proto, r.Header.Get("User-Agent"))
		handler.ServeHTTP(w, r)
	})
}

func updateFiles() {
	auth = makeTokenDB(tryReadFile(authFileName))
	if auth == nil {
		log.Println("auth db could not be loaded, please fix and reload")
	}
	css = tryReadFile(cssFileName)
	logo = tryReadFile(logoFileName)
	userMessageView = fileOrConst(userMessageViewFilename, userMessageViewDefaultText)
	updated = time.Now()
}

func getURLBase() string {
	if fURLBase != "" {
		return fURLBase
	}
	sl := strings.Split(fListen, ":")
	port := sl[len(sl)-1]
	return fmt.Sprintf("%s%s:%s", scheme, defaultHostname, port)
}

func main() {
	flag.StringVar(&fListen, "listen", listenDefault, "listen on IP:port")
	flag.StringVar(&fURLBase, "urlbase", "", "base URL (will be generated by default)")
	flag.BoolVar(&fTLS, "tls", TLSDefault, "use TLS connection")
	flag.BoolVar(&fNotify, "notify", notifyDefault, "send email notification when one time link is used")
	flag.Parse()

	log.Printf("gjfy version %s\n", version)

	store := make(secretStore)
	store.NewEntry("secret", 100, 0, "test@example.org", "test")
	go store.Expiry(time.Minute * expiryCheck)

	updateFiles()

	sighup := make(chan os.Signal, 1)
	signal.Notify(sighup, syscall.SIGHUP)
	go func() {
		for {
			<-sighup
			log.Println("reloading configuration...")
			updateFiles()
		}
	}()

	tIndex := template.New("index")
	tIndex.Parse(htmlMaster)
	tIndex.Parse(htmlIndex)
	tView := template.New("view")
	tView.Parse(htmlMaster)
	tView.Parse(htmlView)
	tViewErr := template.New("viewErr")
	tViewErr.Parse(htmlMaster)
	tViewErr.Parse(htmlViewErr)
	tViewInfo := template.New("viewInfo")
	tViewInfo.Parse(htmlMaster)
	tViewInfo.Parse(htmlViewInfo)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		tIndex.ExecuteTemplate(w, "master", nil)
	})

	http.HandleFunc(uApiGet, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Path[len(uApiGet):]
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(w, "{}")
		} else {
			store.Click(id, r)
			w.WriteHeader(http.StatusOK)
			if err := json.NewEncoder(w).Encode(entry); err != nil {
				panic(err)
			}
		}
	})

	http.HandleFunc(uApiNew, func(w http.ResponseWriter, r *http.Request) {
		var entry StoreEntry
		body, err := ioutil.ReadAll(io.LimitReader(r.Body, maxData))
		if err != nil {
			panic(err)
		}
		if err := r.Body.Close(); err != nil {
			panic(err)
		}
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		if err := json.Unmarshal(body, &entry); err != nil {
			w.WriteHeader(422) // unprocessable entity
			if err := json.NewEncoder(w).Encode(err); err != nil {
				panic(err)
			}
		}
		if !auth.isAuthorized(&entry) {
			w.WriteHeader(http.StatusUnauthorized)
			fmt.Fprintln(w, `{"error":"unauthorized"}`)
		} else {
			id := store.AddEntry(entry, "")
			newEntry, _ := store.GetEntryInfoHidden(id)
			log.Println("New ID:", id)
			w.WriteHeader(http.StatusCreated)
			if err := json.NewEncoder(w).Encode(newEntry); err != nil {
				panic(err)
			}
		}
	})

	http.HandleFunc(uGet, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			tViewErr.ExecuteTemplate(w, "master", nil)
		} else {
			store.Click(id, r)
			w.WriteHeader(http.StatusOK)
			viewEntry := viewInfoEntry{entry, userMessageView}
			tView.ExecuteTemplate(w, "master", viewEntry)
		}
	})

	http.HandleFunc(uInfo, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			tViewErr.ExecuteTemplate(w, "master", nil)
		} else {
			w.WriteHeader(http.StatusOK)
			tViewInfo.ExecuteTemplate(w, "master", entry)
		}
	})

	http.HandleFunc(uFav, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "image/x-icon")
		w.WriteHeader(http.StatusOK)
		w.Write(favicon)
	})

	http.HandleFunc(uLogoSmall, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "image/png")
		w.WriteHeader(http.StatusOK)
		w.Write(gjfyLogoSmall)
	})

	http.HandleFunc(uCss, func(w http.ResponseWriter, r *http.Request) {
		http.ServeContent(w, r, cssFileName, updated, bytes.NewReader(css))
	})

	http.HandleFunc(uLogo, func(w http.ResponseWriter, r *http.Request) {
		http.ServeContent(w, r, logoFileName, updated, bytes.NewReader(logo))
	})

	http.HandleFunc(uClientShell, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-sh")
		w.WriteHeader(http.StatusOK)
		ClientShellScript(w, getURLBase()+uApiNew)
	})

	if fNotify {
		log.Println("email notifications enabled")
	}

	if fTLS {
		scheme = "https://"
		cf := tryFile(crtFile)
		if cf == "" {
			log.Fatalf("unable to open %s\n", crtFile)
		}
		kf := tryFile(keyFile)
		if kf == "" {
			log.Fatalf("unable to open %s\n", keyFile)
		}
		log.Printf("using '%s' as URL base\n", getURLBase())
		log.Println("listening on", fListen, "with TLS")
		log.Fatal(http.ListenAndServeTLS(fListen, cf, kf, Log(http.DefaultServeMux)))
	} else {
		log.Printf("using '%s' as URL base\n", getURLBase())
		log.Println("listening on", fListen, "without TLS")
		log.Fatal(http.ListenAndServe(fListen, Log(http.DefaultServeMux)))
	}
}
<commit_msg>fix if/else clause<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

const (
	myName           = "gjfy"
	defaultHostname  = "localhost"
	listenDefault    = ":9154"
	uApiGet          = "/api/v1/get/"
	uApiNew          = "/api/v1/new"
	uGet             = "/g"
	uInfo            = "/i"
	uClientShell     = "/gjfy-post"
	uFav             = "/favicon.ico"
	uLogoSmall       = "/gjfy-logo-small.png"
	uCss             = "/custom.css"
	uLogo            = "/logo.png"
	maxData          = 1048576 // 1MB
	defaultValidity  = 7       // days
	expiryCheck      = 30      // minutes
	defaultMaxClicks = 1
	crtFile          = myName + ".crt"
	keyFile          = myName + ".key"
	TLSDefault       = false
	notifyDefault    = false
)

var (
	auth            TokenDB
	css             []byte
	logo            []byte
	updated         = time.Time{}
	fListen         string
	fURLBase        string
	fTLS            bool
	fNotify         bool
	scheme          = "http://"
	configDir       = "/etc/" + myName
	userMessageView string
)

type viewInfoEntry struct {
	StoreEntryInfo
	UserMessageView string
}

func getRealIP(r *http.Request) string {
	xFF := r.Header.Get("X-Forwarded-For")
	xRI := r.Header.Get("X-Real-IP")
	if xFF != "" {
		return xFF
	} else if xRI != "" {
		return xRI
	}
	return "none"
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		realRemoteAddr := getRealIP(r)
		log.Printf("%s (%s) \"%s %s %s\" \"%s\"", r.RemoteAddr, realRemoteAddr, r.Method, r.URL.Path, r.Proto, r.Header.Get("User-Agent"))
		handler.ServeHTTP(w, r)
	})
}

func updateFiles() {
	auth = makeTokenDB(tryReadFile(authFileName))
	if auth == nil {
		log.Println("auth db could not be loaded, please fix and reload")
	}
	css = tryReadFile(cssFileName)
	logo = tryReadFile(logoFileName)
	userMessageView = fileOrConst(userMessageViewFilename, userMessageViewDefaultText)
	updated = time.Now()
}

func getURLBase() string {
	if fURLBase != "" {
		return fURLBase
	}
	sl := strings.Split(fListen, ":")
	port := sl[len(sl)-1]
	return fmt.Sprintf("%s%s:%s", scheme, defaultHostname, port)
}

func main() {
	flag.StringVar(&fListen, "listen", listenDefault, "listen on IP:port")
	flag.StringVar(&fURLBase, "urlbase", "", "base URL (will be generated by default)")
	flag.BoolVar(&fTLS, "tls", TLSDefault, "use TLS connection")
	flag.BoolVar(&fNotify, "notify", notifyDefault, "send email notification when one time link is used")
	flag.Parse()

	log.Printf("gjfy version %s\n", version)

	store := make(secretStore)
	store.NewEntry("secret", 100, 0, "test@example.org", "test")
	go store.Expiry(time.Minute * expiryCheck)

	updateFiles()

	sighup := make(chan os.Signal, 1)
	signal.Notify(sighup, syscall.SIGHUP)
	go func() {
		for {
			<-sighup
			log.Println("reloading configuration...")
			updateFiles()
		}
	}()

	tIndex := template.New("index")
	tIndex.Parse(htmlMaster)
	tIndex.Parse(htmlIndex)
	tView := template.New("view")
	tView.Parse(htmlMaster)
	tView.Parse(htmlView)
	tViewErr := template.New("viewErr")
	tViewErr.Parse(htmlMaster)
	tViewErr.Parse(htmlViewErr)
	tViewInfo := template.New("viewInfo")
	tViewInfo.Parse(htmlMaster)
	tViewInfo.Parse(htmlViewInfo)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		tIndex.ExecuteTemplate(w, "master", nil)
	})

	http.HandleFunc(uApiGet, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Path[len(uApiGet):]
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(w, "{}")
		} else {
			store.Click(id, r)
			w.WriteHeader(http.StatusOK)
			if err := json.NewEncoder(w).Encode(entry); err != nil {
				panic(err)
			}
		}
	})

	http.HandleFunc(uApiNew, func(w http.ResponseWriter, r *http.Request) {
		var entry StoreEntry
		body, err := ioutil.ReadAll(io.LimitReader(r.Body, maxData))
		if err != nil {
			panic(err)
		}
		if err := r.Body.Close(); err != nil {
			panic(err)
		}
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		if err := json.Unmarshal(body, &entry); err != nil {
			w.WriteHeader(422) // unprocessable entity
			if err := json.NewEncoder(w).Encode(err); err != nil {
				panic(err)
			}
		} else if !auth.isAuthorized(&entry) {
			w.WriteHeader(http.StatusUnauthorized)
			fmt.Fprintln(w, `{"error":"unauthorized"}`)
		} else {
			id := store.AddEntry(entry, "")
			newEntry, _ := store.GetEntryInfoHidden(id)
			log.Println("New ID:", id)
			w.WriteHeader(http.StatusCreated)
			if err := json.NewEncoder(w).Encode(newEntry); err != nil {
				panic(err)
			}
		}
	})

	http.HandleFunc(uGet, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			tViewErr.ExecuteTemplate(w, "master", nil)
		} else {
			store.Click(id, r)
			w.WriteHeader(http.StatusOK)
			viewEntry := viewInfoEntry{entry, userMessageView}
			tView.ExecuteTemplate(w, "master", viewEntry)
		}
	})

	http.HandleFunc(uInfo, func(w http.ResponseWriter, r *http.Request) {
		id := r.URL.Query().Get("id")
		if entry, ok := store.GetEntryInfo(id); !ok {
			w.WriteHeader(http.StatusNotFound)
			tViewErr.ExecuteTemplate(w, "master", nil)
		} else {
			w.WriteHeader(http.StatusOK)
			tViewInfo.ExecuteTemplate(w, "master", entry)
		}
	})

	http.HandleFunc(uFav, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "image/x-icon")
		w.WriteHeader(http.StatusOK)
		w.Write(favicon)
	})

	http.HandleFunc(uLogoSmall, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "image/png")
		w.WriteHeader(http.StatusOK)
		w.Write(gjfyLogoSmall)
	})

	http.HandleFunc(uCss, func(w http.ResponseWriter, r *http.Request) {
		http.ServeContent(w, r, cssFileName, updated, bytes.NewReader(css))
	})

	http.HandleFunc(uLogo, func(w http.ResponseWriter, r *http.Request) {
		http.ServeContent(w, r, logoFileName, updated, bytes.NewReader(logo))
	})

	http.HandleFunc(uClientShell, func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-sh")
		w.WriteHeader(http.StatusOK)
		ClientShellScript(w, getURLBase()+uApiNew)
	})

	if fNotify {
		log.Println("email notifications enabled")
	}

	if fTLS {
		scheme = "https://"
		cf := tryFile(crtFile)
		if cf == "" {
			log.Fatalf("unable to open %s\n", crtFile)
		}
		kf := tryFile(keyFile)
		if kf == "" {
			log.Fatalf("unable to open %s\n", keyFile)
		}
		log.Printf("using '%s' as URL base\n", getURLBase())
		log.Println("listening on", fListen, "with TLS")
		log.Fatal(http.ListenAndServeTLS(fListen, cf, kf, Log(http.DefaultServeMux)))
	} else {
		log.Printf("using '%s' as URL base\n", getURLBase())
		log.Println("listening on", fListen, "without TLS")
		log.Fatal(http.ListenAndServe(fListen, Log(http.DefaultServeMux)))
	}
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type method struct {
	args []interface{}
}

var parsed map[string]map[string]method

var suggested = [...]string{
	"io.ByteReader",
	"io.ByteScanner",
	"io.ByteWriter",
	"io.Closer",
	"io.ReadCloser",
	"io.ReadSeeker",
	"io.ReadWriteCloser",
	"io.ReadWriteSeeker",
	"io.ReadWriter",
	"io.Reader",
	"io.ReaderAt",
	"io.ReaderFrom",
	"io.RuneReader",
	"io.RuneScanner",
	"io.Seeker",
	"io.WriteCloser",
	"io.WriteSeeker",
	"io.Writer",
	"io.WriterAt",
	"io.WriterTo",
}

func typeList(t *types.Tuple) []interface{} {
	var l []interface{}
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		l = append(l, v.Type())
	}
	return l
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]method, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		if _, e := parsed[ifname]; e {
			log.Fatalf("%s is duplicated", ifname)
		}
		parsed[ifname] = make(map[string]method, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			parsed[ifname][fname] = method{
				args: typeList(sign.Params()),
			}
		}
	}
}

func init() {
	typesInit()
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	case nil:
		switch t1.(type) {
		case *types.Slice:
			return true
		case *types.Map:
			return true
		default:
			return false
		}
	default:
		return false
	}
}

func argsMatch(args1, args2 []interface{}) bool {
	if len(args1) != len(args2) {
		return false
	}
	for i, a1 := range args1 {
		a2 := args2[i]
		t1 := a1.(types.Type)
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(methods map[string]method) string {
	matchesIface := func(decls map[string]method) bool {
		if len(methods) > len(decls) {
			return false
		}
		for n, d := range decls {
			m, e := methods[n]
			if !e {
				return false
			}
			if !argsMatch(d.args, m.args) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	args map[string]types.Type
	used map[string]map[string]method
}

func scopeName(e ast.Expr) string {
	switch x := e.(type) {
	case *ast.Ident:
		return x.Name
	case *ast.StarExpr:
		return scopeName(x.X)
	default:
		return ""
	}
}

func (v *Visitor) getFuncType(fd *ast.FuncDecl) *types.Func {
	name := fd.Name.Name
	scope := v.scopes[len(v.scopes)-1]
	if fd.Recv == nil {
		return scope.Lookup(name).(*types.Func)
	}
	if len(fd.Recv.List) > 1 {
		return nil
	}
	tname := scopeName(fd.Recv.List[0].Type)
	st := scope.Lookup(tname).(*types.TypeName)
	named := st.Type().(*types.Named)
	for i := 0; i < named.NumMethods(); i++ {
		f := named.Method(i)
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.getFuncType(x)
		if f == nil {
			return nil
		}
		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		v.args = typeMap(sign.Params())
		v.used = make(map[string]map[string]method, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.args[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.args = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := method{}
	for _, a := range c.Args {
		m.args = append(m.args, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]method)
	}
	v.used[vname][fname] = m
}
<commit_msg>Rename args to params<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type method struct {
	params []interface{}
}

var parsed map[string]map[string]method

var suggested = [...]string{
	"io.ByteReader",
	"io.ByteScanner",
	"io.ByteWriter",
	"io.Closer",
	"io.ReadCloser",
	"io.ReadSeeker",
	"io.ReadWriteCloser",
	"io.ReadWriteSeeker",
	"io.ReadWriter",
	"io.Reader",
	"io.ReaderAt",
	"io.ReaderFrom",
	"io.RuneReader",
	"io.RuneScanner",
	"io.Seeker",
	"io.WriteCloser",
	"io.WriteSeeker",
	"io.Writer",
	"io.WriterAt",
	"io.WriterTo",
}

func typeList(t *types.Tuple) []interface{} {
	var l []interface{}
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		l = append(l, v.Type())
	}
	return l
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]method, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		if _, e := parsed[ifname]; e {
			log.Fatalf("%s is duplicated", ifname)
		}
		parsed[ifname] = make(map[string]method, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			parsed[ifname][fname] = method{
				params: typeList(sign.Params()),
			}
		}
	}
}

func init() {
	typesInit()
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	case nil:
		switch t1.(type) {
		case *types.Slice:
			return true
		case *types.Map:
			return true
		default:
			return false
		}
	default:
		return false
	}
}

func typesMatch(args1, args2 []interface{}) bool {
	if len(args1) != len(args2) {
		return false
	}
	for i, a1 := range args1 {
		a2 := args2[i]
		t1 := a1.(types.Type)
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(methods map[string]method) string {
	matchesIface := func(decls map[string]method) bool {
		if len(methods) > len(decls) {
			return false
		}
		for n, d := range decls {
			m, e := methods[n]
			if !e {
				return false
			}
			if !typesMatch(d.params, m.params) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	params map[string]types.Type
	used   map[string]map[string]method
}

func scopeName(e ast.Expr) string {
	switch x := e.(type) {
	case *ast.Ident:
		return x.Name
	case *ast.StarExpr:
		return scopeName(x.X)
	default:
		return ""
	}
}

func (v *Visitor) getFuncType(fd *ast.FuncDecl) *types.Func {
	name := fd.Name.Name
	scope := v.scopes[len(v.scopes)-1]
	if fd.Recv == nil {
		return scope.Lookup(name).(*types.Func)
	}
	if len(fd.Recv.List) > 1 {
		return nil
	}
	tname := scopeName(fd.Recv.List[0].Type)
	st := scope.Lookup(tname).(*types.TypeName)
	named := st.Type().(*types.Named)
	for i := 0; i < named.NumMethods(); i++ {
		f := named.Method(i)
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		f := v.getFuncType(x)
		if f == nil {
			return nil
		}
		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		v.params = typeMap(sign.Params())
		v.used = make(map[string]map[string]method, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.params[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.params = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := method{}
	for _, a := range c.Args {
		m.params = append(m.params, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]method)
	}
	v.used[vname][fname] = m
}
<|endoftext|>


<commit_before>// Package prob provides functions for working with probability distributions.
package prob

// Sampler represents a probability distribution capable of sampling.
type Sampler interface {
	Sample() float64
}

// CDFer represents a probability distribution capable of evaluating its CDF.
type CDFer interface {
	CDF(float64) float64
}

// InvCDFer represents a probability distribution capable of evaluating the
// inverse of its CDF.
type InvCDFer interface {
	InvCDF(float64) float64
}

// Sample draws samples from the given distribution.
func Sample(dist Sampler, count uint32) []float64 {
	result := make([]float64, count)

	for i := range result {
		result[i] = dist.Sample()
	}

	return result
}

// CDF evalues the CDF of the given distribution.
func CDF(dist CDFer, x[]float64) []float64 {
	result := make([]float64, len(x))

	for i := range result {
		result[i] = dist.CDF(x[i])
	}

	return result
}

// InvCDF evalues the inverse of the CDF of the given distribution.
func InvCDF(dist InvCDFer, x[]float64) []float64 {
	result := make([]float64, len(x))

	for i := range result {
		result[i] = dist.InvCDF(x[i])
	}

	return result
}
<commit_msg>Renamed the interfaces in prob; added Distribution<commit_after>// Package prob provides functions for working with probability distributions.
package prob

// Sampler represents a probability distribution capable of sampling.
type Sampler interface {
	Sample() float64
}

// Cumulator represents a probability distribution capable of evaluating its
// cumulative distribution function.
type Cumulator interface {
	CDF(float64) float64
}

// Inverter represents a probability distribution capable of evaluating the
// inverse of its cumulative distribution function.
type Inverter interface {
	InvCDF(float64) float64
}

// Distribution represents a probability distribution.
type Distribution interface {
	Cumulator
	Inverter
	Sampler
}

// Sample draws samples from the given distribution.
func Sample(dist Sampler, count uint32) []float64 {
	result := make([]float64, count)

	for i := range result {
		result[i] = dist.Sample()
	}

	return result
}

// CDF evaluates the cumulative distribution function of the given
// distribution.
func CDF(dist Cumulator, x[]float64) []float64 {
	result := make([]float64, len(x))

	for i := range result {
		result[i] = dist.CDF(x[i])
	}

	return result
}

// InvCDF evaluates the inverse of the cumulative distribution function of the
// given distribution.
func InvCDF(dist Inverter, x[]float64) []float64 {
	result := make([]float64, len(x))

	for i := range result {
		result[i] = dist.InvCDF(x[i])
	}

	return result
}
<|endoftext|>


<commit_before>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

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.
*/

/*
pzsvc-gdaldem provides an endpoint for accepting PDAL requests.

Examples

  $ curl -v -X POST -H "Content-Type: application/json" \
    -d '{"source":{"bucket":"venicegeo-sample-data","key":"pointcloud/samp11-utm.laz"},"function":"info"}' http://hostIP:8080/pdal
*/
package main

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

	"github.com/julienschmidt/httprouter"
)

func main() {
	router := httprouter.New()

	router.GET("/", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
		fmt.Fprintf(w, "Hi!")
	})

	// Setup the PDAL service.
	// router.POST("/gdaldem", handlers.GdalDemHandler)

	var defaultPort = os.Getenv("PORT")
	log.Println("PORT is ", defaultPort)
	if defaultPort == "" {
		defaultPort = "8080"
	}

	log.Println("Starting on ", defaultPort)
	if err := http.ListenAndServe(":"+defaultPort, router); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Re-enable the gdal handler<commit_after>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

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.
*/

/*
pzsvc-gdaldem provides an endpoint for accepting PDAL requests.

Examples

  $ curl -v -X POST -H "Content-Type: application/json" \
    -d '{"source":{"bucket":"venicegeo-sample-data","key":"pointcloud/samp11-utm.laz"},"function":"info"}' http://hostIP:8080/pdal
*/
package main

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

	"github.com/julienschmidt/httprouter"
	"github.com/venicegeo/pzsvc-gdaldem/handlers"
)

func main() {
	router := httprouter.New()

	router.GET("/", func(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
		fmt.Fprintf(w, "Hi!")
	})

	// Setup the PDAL service.
	router.POST("/gdaldem", handlers.GdalDemHandler)

	var defaultPort = os.Getenv("PORT")
	if defaultPort == "" {
		defaultPort = "8080"
	}

	log.Println("Starting on ", defaultPort)
	if err := http.ListenAndServe(":"+defaultPort, router); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>