<commit_before>package tesla

import (
	"encoding/json"
	"strconv"
	"log"
)

// Contains the current charge states that exist within the vehicle
type ChargeState struct {
	ChargingState               string      `json:"charging_state"`
	ChargeLimitSoc              int         `json:"charge_limit_soc"`
	ChargeLimitSocStd           int         `json:"charge_limit_soc_std"`
	ChargeLimitSocMin           int         `json:"charge_limit_soc_min"`
	ChargeLimitSocMax           int         `json:"charge_limit_soc_max"`
	ChargeToMaxRange            bool        `json:"charge_to_max_range"`
	BatteryHeaterOn             bool        `json:"battery_heater_on"`
	NotEnoughPowerToHeat        bool        `json:"not_enough_power_to_heat"`
	MaxRangeChargeCounter       int         `json:"max_range_charge_counter"`
	FastChargerPresent          bool        `json:"fast_charger_present"`
	FastChargerType             string      `json:"fast_charger_type"`
	BatteryRange                float64     `json:"battery_range"`
	EstBatteryRange             float64     `json:"est_battery_range"`
	IdealBatteryRange           float64     `json:"ideal_battery_range"`
	BatteryLevel                int         `json:"battery_level"`
	UsableBatteryLevel          int         `json:"usable_battery_level"`
	BatteryCurrent              interface{} `json:"battery_current"`
	ChargeEnergyAdded           float64     `json:"charge_energy_added"`
	ChargeMilesAddedRated       float64     `json:"charge_miles_added_rated"`
	ChargeMilesAddedIdeal       float64     `json:"charge_miles_added_ideal"`
	ChargerVoltage              interface{} `json:"charger_voltage"`
	ChargerPilotCurrent         interface{} `json:"charger_pilot_current"`
	ChargerActualCurrent        interface{} `json:"charger_actual_current"`
	ChargerPower                interface{} `json:"charger_power"`
	TimeToFullCharge            float64     `json:"time_to_full_charge"`
	TripCharging                interface{} `json:"trip_charging"`
	ChargeRate                  float64     `json:"charge_rate"`
	ChargePortDoorOpen          bool        `json:"charge_port_door_open"`
	MotorizedChargePort         bool        `json:"motorized_charge_port"`
	ScheduledChargingStartTime  interface{} `json:"scheduled_charging_start_time"`
	ScheduledChargingPending    bool        `json:"scheduled_charging_pending"`
	UserChargeEnableRequest     interface{} `json:"user_charge_enable_request"`
	ChargeEnableRequest         bool        `json:"charge_enable_request"`
	EuVehicle                   bool        `json:"eu_vehicle"`
	ChargerPhases               interface{} `json:"charger_phases"`
	ChargePortLatch             string      `json:"charge_port_latch"`
	ChargeCurrentRequest        int         `json:"charge_current_request"`
	ChargeCurrentRequestMax     int         `json:"charge_current_request_max"`
	ManagedChargingActive       bool        `json:"managed_charging_active"`
	ManagedChargingUserCanceled bool        `json:"managed_charging_user_canceled"`
	ManagedChargingStartTime    interface{} `json:"managed_charging_start_time"`
}

// Contains the current climate states availale from the vehicle
type ClimateState struct {
	InsideTemp              float64     `json:"inside_temp"`
	OutsideTemp             float64     `json:"outside_temp"`
	DriverTempSetting       float64     `json:"driver_temp_setting"`
	PassengerTempSetting    float64     `json:"passenger_temp_setting"`
	LeftTempDirection       float64     `json:"left_temp_direction"`
	RightTempDirection      float64     `json:"right_temp_direction"`
	IsAutoConditioningOn    bool        `json:"is_auto_conditioning_on"`
	IsFrontDefrosterOn      bool         `json:"is_front_defroster_on"`
	IsRearDefrosterOn       bool        `json:"is_rear_defroster_on"`
	FanStatus               interface{} `json:"fan_status"`
	IsClimateOn             bool        `json:"is_climate_on"`
	MinAvailTemp            float64     `json:"min_avail_temp"`
	MaxAvailTemp            float64     `json:"max_avail_temp"`
	SeatHeaterLeft          int         `json:"seat_heater_left"`
	SeatHeaterRight         int         `json:"seat_heater_right"`
	SeatHeaterRearLeft      int         `json:"seat_heater_rear_left"`
	SeatHeaterRearRight     int         `json:"seat_heater_rear_right"`
	SeatHeaterRearCenter    int         `json:"seat_heater_rear_center"`
	SeatHeaterRearRightBack int         `json:"seat_heater_rear_right_back"`
	SeatHeaterRearLeftBack  int         `json:"seat_heater_rear_left_back"`
	SmartPreconditioning    bool        `json:"smart_preconditioning"`
}

// Contains the current drive state of the vehicle
type DriveState struct {
	ShiftState interface{} `json:"shift_state"`
	Speed      float64     `json:"speed"`
	Latitude   float64     `json:"latitude"`
	Longitude  float64     `json:"longitude"`
	Heading    int         `json:"heading"`
	GpsAsOf    int64       `json:"gps_as_of"`
}

// Contains the current GUI settings of the vehicle
type GuiSettings struct {
	GuiDistanceUnits    string `json:"gui_distance_units"`
	GuiTemperatureUnits string `json:"gui_temperature_units"`
	GuiChargeRateUnits  string `json:"gui_charge_rate_units"`
	Gui24HourTime       bool   `json:"gui_24_hour_time"`
	GuiRangeDisplay     string `json:"gui_range_display"`
}

// Contains the current state of the vehicle
type VehicleState struct {
	APIVersion              int     `json:"api_version"`
	AutoParkState           string  `json:"autopark_state"`
	AutoParkStateV2         string  `json:"autopark_state_v2"`
	CalendarSupported       bool    `json:"calendar_supported"`
	CarType                 string  `json:"car_type"`
	CarVersion              string  `json:"car_version"`
	CenterDisplayState      int     `json:"center_display_state"`
	DarkRims                bool    `json:"dark_rims"`
	Df                      int     `json:"df"`
	Dr                      int     `json:"dr"`
	ExteriorColor           string  `json:"exterior_color"`
	Ft                      int     `json:"ft"`
	HasSpoiler              bool    `json:"has_spoiler"`
	Locked                  bool    `json:"locked"`
	NotificationsSupported  bool    `json:"notifications_supported"`
	Odometer                float64 `json:"odometer"`
	ParsedCalendarSupported bool    `json:"parsed_calendar_supported"`
	PerfConfig              string  `json:"perf_config"`
	Pf                      int     `json:"pf"`
	Pr                      int     `json:"pr"`
	RearSeatHeaters         int     `json:"rear_seat_heaters"`
	RemoteStart             bool    `json:"remote_start"`
	RemoteStartSupported    bool    `json:"remote_start_supported"`
	Rhd                     bool    `json:"rhd"`
	RoofColor               string  `json:"roof_color"`
	Rt                      int     `json:"rt"`
	SeatType                int     `json:"seat_type"`
	SpoilerType             string  `json:"spoiler_type"`
	SunRoofInstalled        int     `json:"sun_roof_installed"`
	SunRoofPercentOpen      int     `json:"sun_roof_percent_open"`
	SunRoofState            string  `json:"sun_roof_state"`
	ThirdRowSeats           string  `json:"third_row_seats"`
	ValetMode               bool    `json:"valet_mode"`
	VehicleName             string  `json:"vehicle_name"`
	WheelType               string  `json:"wheel_type"`
}

// Represents the request to get the states of the vehicle
type StateRequest struct {
	Response struct {
		*ChargeState
		*ClimateState
		*DriveState
		*GuiSettings
		*VehicleState
	} `json:"response"`
}

// The response when a state is requested
type Response struct {
	Bool bool `json:"response"`
}

// Returns if the vehicle is mobile enabled for Tesla API control
func (v *Vehicle) MobileEnabled() (bool, error) {
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/mobile_enabled")
	if err != nil {
		return false, err
	}
	response := &Response{}
	err = json.Unmarshal(body, response)
	if err != nil {
		return false, err
	}
	return response.Bool, nil
}

// Returns the charge state of the vehicle
func (v *Vehicle) ChargeState() (*ChargeState, error) {
	stateRequest, err := fetchState("/charge_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.ChargeState, nil
}

// Returns the climate state of the vehicle
func (v Vehicle) ClimateState() (*ClimateState, error) {
	stateRequest, err := fetchState("/climate_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.ClimateState, nil
}

func (v Vehicle) DriveState() (*DriveState, error) {
	stateRequest, err := fetchState("/drive_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.DriveState, nil
}

// Returns the GUI settings of the vehicle
func (v Vehicle) GuiSettings() (*GuiSettings, error) {
	stateRequest, err := fetchState("/gui_settings", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.GuiSettings, nil
}

func (v Vehicle) VehicleState() (*VehicleState, error) {
	stateRequest, err := fetchState("/vehicle_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.VehicleState, nil
}

// A utility function to fetch the appropriate state of the vehicle
func fetchState(resource string, id int64) (*StateRequest, error) {
	stateRequest := &StateRequest{}
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(id, 10) + "/data_request" + resource)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(body, stateRequest)
	if err != nil {
		return nil, err
	}
	return stateRequest, nil
}

// Data : Get data of the vehicle (calling this will not permit the car to sleep)
func (v Vehicle) Data(vid int64) (*StateRequest, error) {

	log.Println("Retreiving vehicle data")
	stateRequest := &StateRequest{}

	/*log.Println(BaseURL + "/vehicles/" + strconv.FormatInt(vid, 10) + "/vehicle_data")
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(vid, 10) + "/vehicle_data")
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(body, stateRequest)
	if err != nil {
		return nil, err
	}*/

	// charge_state
	stateRequestCharge, err := fetchState("/charge_state", v.ID)
	if err != nil {
		log.Println("Error getting charge_state")
		return nil, err
	}
	stateRequest.Response.ChargeState = stateRequestCharge.Response.ChargeState

	// climate_state
	stateRequestClimate, err := fetchState("/climate_state", v.ID)
	if err != nil {
		log.Println("Error getting climate_state")
		return nil, err
	}
	stateRequest.Response.ClimateState = stateRequestClimate.Response.ClimateState

	// drive_state
	stateRequestGui, err := fetchState("/drive_state", v.ID)
	if err != nil {
		log.Println("Error getting drive_state")
		return nil, err
	}
	stateRequest.Response.DriveState = stateRequestGui.Response.DriveState

	// gui_settings
	stateRequestSettings, err := fetchState("/gui_settings", v.ID)
	if err != nil {
		log.Println("Error getting gui_settings")
		return nil, err
	}
	stateRequest.Response.GuiSettings = stateRequestSettings.Response.GuiSettings

	// vehicle_state
	stateRequestVehicle, err := fetchState("/vehicle_state", v.ID)
	if err != nil {
		log.Println("Error getting vehicle_state")
		return nil, err
	}
	stateRequest.Response.VehicleState = stateRequestVehicle.Response.VehicleState

	return stateRequest, nil
}
<commit_msg>Error messages<commit_after>package tesla

import (
	"encoding/json"
	"strconv"
	"log"
)

// Contains the current charge states that exist within the vehicle
type ChargeState struct {
	ChargingState               string      `json:"charging_state"`
	ChargeLimitSoc              int         `json:"charge_limit_soc"`
	ChargeLimitSocStd           int         `json:"charge_limit_soc_std"`
	ChargeLimitSocMin           int         `json:"charge_limit_soc_min"`
	ChargeLimitSocMax           int         `json:"charge_limit_soc_max"`
	ChargeToMaxRange            bool        `json:"charge_to_max_range"`
	BatteryHeaterOn             bool        `json:"battery_heater_on"`
	NotEnoughPowerToHeat        bool        `json:"not_enough_power_to_heat"`
	MaxRangeChargeCounter       int         `json:"max_range_charge_counter"`
	FastChargerPresent          bool        `json:"fast_charger_present"`
	FastChargerType             string      `json:"fast_charger_type"`
	BatteryRange                float64     `json:"battery_range"`
	EstBatteryRange             float64     `json:"est_battery_range"`
	IdealBatteryRange           float64     `json:"ideal_battery_range"`
	BatteryLevel                int         `json:"battery_level"`
	UsableBatteryLevel          int         `json:"usable_battery_level"`
	BatteryCurrent              interface{} `json:"battery_current"`
	ChargeEnergyAdded           float64     `json:"charge_energy_added"`
	ChargeMilesAddedRated       float64     `json:"charge_miles_added_rated"`
	ChargeMilesAddedIdeal       float64     `json:"charge_miles_added_ideal"`
	ChargerVoltage              interface{} `json:"charger_voltage"`
	ChargerPilotCurrent         interface{} `json:"charger_pilot_current"`
	ChargerActualCurrent        interface{} `json:"charger_actual_current"`
	ChargerPower                interface{} `json:"charger_power"`
	TimeToFullCharge            float64     `json:"time_to_full_charge"`
	TripCharging                interface{} `json:"trip_charging"`
	ChargeRate                  float64     `json:"charge_rate"`
	ChargePortDoorOpen          bool        `json:"charge_port_door_open"`
	MotorizedChargePort         bool        `json:"motorized_charge_port"`
	ScheduledChargingStartTime  interface{} `json:"scheduled_charging_start_time"`
	ScheduledChargingPending    bool        `json:"scheduled_charging_pending"`
	UserChargeEnableRequest     interface{} `json:"user_charge_enable_request"`
	ChargeEnableRequest         bool        `json:"charge_enable_request"`
	EuVehicle                   bool        `json:"eu_vehicle"`
	ChargerPhases               interface{} `json:"charger_phases"`
	ChargePortLatch             string      `json:"charge_port_latch"`
	ChargeCurrentRequest        int         `json:"charge_current_request"`
	ChargeCurrentRequestMax     int         `json:"charge_current_request_max"`
	ManagedChargingActive       bool        `json:"managed_charging_active"`
	ManagedChargingUserCanceled bool        `json:"managed_charging_user_canceled"`
	ManagedChargingStartTime    interface{} `json:"managed_charging_start_time"`
}

// Contains the current climate states availale from the vehicle
type ClimateState struct {
	InsideTemp              float64     `json:"inside_temp"`
	OutsideTemp             float64     `json:"outside_temp"`
	DriverTempSetting       float64     `json:"driver_temp_setting"`
	PassengerTempSetting    float64     `json:"passenger_temp_setting"`
	LeftTempDirection       float64     `json:"left_temp_direction"`
	RightTempDirection      float64     `json:"right_temp_direction"`
	IsAutoConditioningOn    bool        `json:"is_auto_conditioning_on"`
	IsFrontDefrosterOn      bool         `json:"is_front_defroster_on"`
	IsRearDefrosterOn       bool        `json:"is_rear_defroster_on"`
	FanStatus               interface{} `json:"fan_status"`
	IsClimateOn             bool        `json:"is_climate_on"`
	MinAvailTemp            float64     `json:"min_avail_temp"`
	MaxAvailTemp            float64     `json:"max_avail_temp"`
	SeatHeaterLeft          int         `json:"seat_heater_left"`
	SeatHeaterRight         int         `json:"seat_heater_right"`
	SeatHeaterRearLeft      int         `json:"seat_heater_rear_left"`
	SeatHeaterRearRight     int         `json:"seat_heater_rear_right"`
	SeatHeaterRearCenter    int         `json:"seat_heater_rear_center"`
	SeatHeaterRearRightBack int         `json:"seat_heater_rear_right_back"`
	SeatHeaterRearLeftBack  int         `json:"seat_heater_rear_left_back"`
	SmartPreconditioning    bool        `json:"smart_preconditioning"`
}

// Contains the current drive state of the vehicle
type DriveState struct {
	ShiftState interface{} `json:"shift_state"`
	Speed      float64     `json:"speed"`
	Latitude   float64     `json:"latitude"`
	Longitude  float64     `json:"longitude"`
	Heading    int         `json:"heading"`
	GpsAsOf    int64       `json:"gps_as_of"`
}

// Contains the current GUI settings of the vehicle
type GuiSettings struct {
	GuiDistanceUnits    string `json:"gui_distance_units"`
	GuiTemperatureUnits string `json:"gui_temperature_units"`
	GuiChargeRateUnits  string `json:"gui_charge_rate_units"`
	Gui24HourTime       bool   `json:"gui_24_hour_time"`
	GuiRangeDisplay     string `json:"gui_range_display"`
}

// Contains the current state of the vehicle
type VehicleState struct {
	APIVersion              int     `json:"api_version"`
	AutoParkState           string  `json:"autopark_state"`
	AutoParkStateV2         string  `json:"autopark_state_v2"`
	CalendarSupported       bool    `json:"calendar_supported"`
	CarType                 string  `json:"car_type"`
	CarVersion              string  `json:"car_version"`
	CenterDisplayState      int     `json:"center_display_state"`
	DarkRims                bool    `json:"dark_rims"`
	Df                      int     `json:"df"`
	Dr                      int     `json:"dr"`
	ExteriorColor           string  `json:"exterior_color"`
	Ft                      int     `json:"ft"`
	HasSpoiler              bool    `json:"has_spoiler"`
	Locked                  bool    `json:"locked"`
	NotificationsSupported  bool    `json:"notifications_supported"`
	Odometer                float64 `json:"odometer"`
	ParsedCalendarSupported bool    `json:"parsed_calendar_supported"`
	PerfConfig              string  `json:"perf_config"`
	Pf                      int     `json:"pf"`
	Pr                      int     `json:"pr"`
	RearSeatHeaters         int     `json:"rear_seat_heaters"`
	RemoteStart             bool    `json:"remote_start"`
	RemoteStartSupported    bool    `json:"remote_start_supported"`
	Rhd                     bool    `json:"rhd"`
	RoofColor               string  `json:"roof_color"`
	Rt                      int     `json:"rt"`
	SeatType                int     `json:"seat_type"`
	SpoilerType             string  `json:"spoiler_type"`
	SunRoofInstalled        int     `json:"sun_roof_installed"`
	SunRoofPercentOpen      int     `json:"sun_roof_percent_open"`
	SunRoofState            string  `json:"sun_roof_state"`
	ThirdRowSeats           string  `json:"third_row_seats"`
	ValetMode               bool    `json:"valet_mode"`
	VehicleName             string  `json:"vehicle_name"`
	WheelType               string  `json:"wheel_type"`
}

// Represents the request to get the states of the vehicle
type StateRequest struct {
	Response struct {
		*ChargeState
		*ClimateState
		*DriveState
		*GuiSettings
		*VehicleState
	} `json:"response"`
}

// The response when a state is requested
type Response struct {
	Bool bool `json:"response"`
}

// Returns if the vehicle is mobile enabled for Tesla API control
func (v *Vehicle) MobileEnabled() (bool, error) {
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(v.ID, 10) + "/mobile_enabled")
	if err != nil {
		return false, err
	}
	response := &Response{}
	err = json.Unmarshal(body, response)
	if err != nil {
		return false, err
	}
	return response.Bool, nil
}

// Returns the charge state of the vehicle
func (v *Vehicle) ChargeState() (*ChargeState, error) {
	stateRequest, err := fetchState("/charge_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.ChargeState, nil
}

// Returns the climate state of the vehicle
func (v Vehicle) ClimateState() (*ClimateState, error) {
	stateRequest, err := fetchState("/climate_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.ClimateState, nil
}

func (v Vehicle) DriveState() (*DriveState, error) {
	stateRequest, err := fetchState("/drive_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.DriveState, nil
}

// Returns the GUI settings of the vehicle
func (v Vehicle) GuiSettings() (*GuiSettings, error) {
	stateRequest, err := fetchState("/gui_settings", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.GuiSettings, nil
}

func (v Vehicle) VehicleState() (*VehicleState, error) {
	stateRequest, err := fetchState("/vehicle_state", v.ID)
	if err != nil {
		return nil, err
	}
	return stateRequest.Response.VehicleState, nil
}

// A utility function to fetch the appropriate state of the vehicle
func fetchState(resource string, id int64) (*StateRequest, error) {
	stateRequest := &StateRequest{}
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(id, 10) + "/data_request" + resource)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(body, stateRequest)
	if err != nil {
		return nil, err
	}
	return stateRequest, nil
}

// Data : Get data of the vehicle (calling this will not permit the car to sleep)
func (v Vehicle) Data(vid int64) (*StateRequest, error) {

	log.Println("Retreiving vehicle data")
	stateRequest := &StateRequest{}

	/*log.Println(BaseURL + "/vehicles/" + strconv.FormatInt(vid, 10) + "/vehicle_data")
	body, err := ActiveClient.get(BaseURL + "/vehicles/" + strconv.FormatInt(vid, 10) + "/vehicle_data")
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(body, stateRequest)
	if err != nil {
		return nil, err
	}*/

	// climate_state
	stateRequestClimate, err := fetchState("/climate_state", v.ID)
	if err != nil {
		log.Println("Error getting climate_state")
		return nil, err
	}
	stateRequest.Response.ClimateState = stateRequestClimate.Response.ClimateState

	// drive_state
	stateRequestGui, err := fetchState("/drive_state", v.ID)
	if err != nil {
		log.Println("Error getting drive_state")
		return nil, err
	}
	stateRequest.Response.DriveState = stateRequestGui.Response.DriveState

	// gui_settings
	stateRequestSettings, err := fetchState("/gui_settings", v.ID)
	if err != nil {
		log.Println("Error getting gui_settings")
		return nil, err
	}
	stateRequest.Response.GuiSettings = stateRequestSettings.Response.GuiSettings

	// vehicle_state
	stateRequestVehicle, err := fetchState("/vehicle_state", v.ID)
	if err != nil {
		log.Println("Error getting vehicle_state")
		return nil, err
	}
	stateRequest.Response.VehicleState = stateRequestVehicle.Response.VehicleState

	// charge_state
	stateRequestCharge, err := fetchState("/charge_state", v.ID)
	if err != nil {
		log.Println("Error getting charge_state")
		return nil, err
	}
	stateRequest.Response.ChargeState = stateRequestCharge.Response.ChargeState

	return stateRequest, nil
}
<|endoftext|>


<commit_before>package main

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

// PromptYesNo provides a y/n prompt. Returns true if the user enters y, false otherwise.
func PromptYesNo(prompt string) bool {
	return Prompt(prompt+" (y/n) ") == "y"
}

// Prompt provides a string prompt, returns the entered string with no whitespace (hopefully)
func Prompt(prompt string) string {
	fmt.Print(prompt)
	reader := bufio.NewReader(os.Stdin)
	res, err := reader.ReadString('\n')

	if err != nil {
		if err.Error() == "EOF" {
			return res
		}
		return ""
	}
	return strings.TrimSpace(res)
}
<commit_msg>PromptYesNo now indicates the default<commit_after>package main

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

// PromptYesNo provides a y/n prompt. Returns true if the user enters y, false otherwise.
func PromptYesNo(prompt string) bool {
	return Prompt(prompt+" (y/N) ") == "y"
}

// Prompt provides a string prompt, returns the entered string with no whitespace (hopefully)
func Prompt(prompt string) string {
	fmt.Print(prompt)
	reader := bufio.NewReader(os.Stdin)
	res, err := reader.ReadString('\n')

	if err != nil {
		if err.Error() == "EOF" {
			return res
		}
		return ""
	}
	return strings.TrimSpace(res)
}

func ShiftArgument(args []string, kindOfThing string) (string, bool) {
	if len(args) > 0 {
		return args[0], true
	} else {
		fmt.Fprintf(os.Stderr, "Not enough arguments. A %s was not specified.\r\n", kindOfThing)
		return "", false
	}
}
<|endoftext|>


<commit_before>package sitemap

import (
	"encoding/xml"
	"time"
)

const (
	headerXmlns = "http://www.sitemaps.org/schemas/sitemap/0.9"
)

// Those values represent the posible change frequences
const (
	Always  ChangeFreq = "always"
	Hourly  ChangeFreq = "hourly"
	Daily   ChangeFreq = "daily"
	Weekly  ChangeFreq = "weekly"
	Monthly ChangeFreq = "monthly"
	Yearly  ChangeFreq = "yearly"
	Never   ChangeFreq = "never"
)

// ChangeFreq is a type to only permit coerant choice
type ChangeFreq string

// Page is the XML page
type Page struct {
	// Set the name of the element
	XMLName xml.Name   `xml:"urlset"`
	Urlset  []*Sitemap `xml:"url"`
	Xmlns   string     `xml:"xmlns,attr"`
}

// GetXML return the corresponding sitemap XML
func (c Page) GetXML() ([]byte, error) {
	// Add the sitemap attribut
	c.Xmlns = headerXmlns

	// Marshal the object to bytes
	retXML, err := xml.Marshal(c)
	// retXML, err := xml.MarshalIndent(c, "", "	")
	if err != nil {
		return nil, err
	}

	// Add the XML header at the first place and concat the rest of the XML export
	ret := []byte(xml.Header)
	ret = append(ret, retXML...)

	return ret, nil
}

// IndexPage represent the sitemap index element
type IndexPage struct {
	Page
	// Set the name of the element
	XMLName xml.Name   `xml:"sitemapindex"`
	Urlset  []*Sitemap `xml:"sitemap"`
}

// GetXML return the corresponding sitemap XML
func (c *IndexPage) GetXML() ([]byte, error) {
	// Add the sitemap attribut
	c.Xmlns = headerXmlns

	// Marshal the object to bytes
	retXML, err := xml.Marshal(c)
	// retXML, err := xml.MarshalIndent(c, "", "	")
	if err != nil {
		return nil, err
	}

	// Add the XML header at the first place and concat the rest of the XML export
	ret := []byte(xml.Header)
	ret = append(ret, retXML...)

	return ret, nil
}

// Sitemap is actualy the real sitemap element
type Sitemap struct {
	Loc        string     `xml:"loc"`
	LastMod    *time.Time `xml:"lastmod,omitempty"`
	Changefreq ChangeFreq `xml:"changefreq,omitempty"`
	Priority   float32    `xml:"priority,omitempty"`
}
<commit_msg>Make convergent function<commit_after>package sitemap

import (
	"encoding/xml"
	"time"
)

const (
	headerXmlns = "http://www.sitemaps.org/schemas/sitemap/0.9"
)

// Those values represent the posible change frequences
const (
	Always  ChangeFreq = "always"
	Hourly  ChangeFreq = "hourly"
	Daily   ChangeFreq = "daily"
	Weekly  ChangeFreq = "weekly"
	Monthly ChangeFreq = "monthly"
	Yearly  ChangeFreq = "yearly"
	Never   ChangeFreq = "never"
)

// ChangeFreq is a type to only permit coerant choice
type ChangeFreq string

// Page is the XML page
type Page struct {
	// Set the name of the element
	XMLName xml.Name   `xml:"urlset"`
	Urlset  []*Sitemap `xml:"url"`
	Xmlns   string     `xml:"xmlns,attr"`
}

// GetXML return the corresponding sitemap XML
func (p *Page) GetXML() ([]byte, error) {
	// Add the sitemap attribut
	p.Xmlns = headerXmlns

	// Marshal the object to bytes
	return getXML(xml.Marshal(p))
}

// IndexPage represent the sitemap index element
type IndexPage struct {
	Page
	// Set the name of the element
	XMLName xml.Name   `xml:"sitemapindex"`
	Urlset  []*Sitemap `xml:"sitemap"`
}

// GetXML return the corresponding sitemap XML
func (p *IndexPage) GetXML() ([]byte, error) {
	// Add the sitemap attribut
	p.Xmlns = headerXmlns

	// Marshal the object to bytes
	return getXML(xml.Marshal(p))
}

// Sitemap is actualy the real sitemap element
type Sitemap struct {
	Loc        string     `xml:"loc"`
	LastMod    *time.Time `xml:"lastmod,omitempty"`
	Changefreq ChangeFreq `xml:"changefreq,omitempty"`
	Priority   float32    `xml:"priority,omitempty"`
}

// This function is a convergent function as workaround for subclasses
func getXML(retXML []byte, err error) ([]byte, error) {
	if err != nil {
		return nil, err
	}

	// Add the XML header at the first place and concat the rest of the XML export
	ret := []byte(xml.Header)
	ret = append(ret, retXML...)

	return ret, nil
}
<|endoftext|>


<commit_before>package main

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

func main() {
	fmt.Println("Trying to generate diagram from diagram/test.out...")
	file, err := os.Open("diagram/test.out")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)

	fileOut, _ := os.Create("diagram/data/content.js")
	writer := bufio.NewWriter(fileOut)
	defer fileOut.Close()

	funcSplit := func(c rune) bool {
		return (c == '|')
	}

	fmt.Fprintln(writer, "var dataContent = [")
	writer.Flush()

	var line string
	var evType string
	for scanner.Scan() {
		line = scanner.Text()
		if (len(line) > 0) {
			if (string(line[0]) == "@") {
				//fmt.Println(line)
				words := strings.FieldsFunc(line, funcSplit)
				evType = words[1]
				switch(evType) {
				case "msg":
					origin := words[2]
					dest := words[4]
					label := words[5]
					newLine := fmt.Sprintf("{ type: \"msg\", from: \"%s\", to: \"%s\", label: \"%s\" },", origin, dest, label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "title":
					label := words[2]
					newLine := fmt.Sprintf("{ type: \"title\", label: \"%s\" },", label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "info":
					node := words[2]
					label := words[3]
					newLine := fmt.Sprintf("{ type: \"info\", node: \"%s\", label: \"%s\" },", node, label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "table":
					node := words[2]
					text := words[3]
					newLine := fmt.Sprintf("{ type: \"table\", node: \"%s\", text: \"%s\" },", node, text)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "state":
					color := words[2]
					node := words[3]
					label := words[4]
					newLine := fmt.Sprintf("{ type: \"state\", color: \"%s\", node: \"%s\", label: \"%s\" },", color, node, label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "next":
					fmt.Fprintln(writer, "{ type: \"next\" },")
					writer.Flush()
					break
				}

			}
		}
	}

	fmt.Fprintln(writer, "]")
	writer.Flush()
	fmt.Println("Process finished.")

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>handle msg with an empty label<commit_after>package main

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

func main() {
	fmt.Println("Trying to generate diagram from diagram/test.out...")
	file, err := os.Open("diagram/test.out")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)

	fileOut, _ := os.Create("diagram/data/content.js")
	writer := bufio.NewWriter(fileOut)
	defer fileOut.Close()

	funcSplit := func(c rune) bool {
		return (c == '|')
	}

	fmt.Fprintln(writer, "var dataContent = [")
	writer.Flush()

	var line string
	var evType string
	for scanner.Scan() {
		line = scanner.Text()
		if (len(line) > 0) {
			if (string(line[0]) == "@") {
				//fmt.Println(line)
				words := strings.FieldsFunc(line, funcSplit)
				evType = words[1]
				switch(evType) {
				case "msg":
					if (len(words) >= 5) {
						origin := words[2]
						dest := words[4]
						label := ""
						if (len(words) == 6) {
							label = words[5]
						}
						newLine := fmt.Sprintf("{ type: \"msg\", from: \"%s\", to: \"%s\", label: \"%s\" },", origin, dest, label)
						fmt.Fprintln(writer, newLine)
						writer.Flush()
					} else {
						fmt.Println("ERROR: Could not parse output line:", line, ". IGNORING (please solve)...")
					}

					break
				case "title":
					label := words[2]
					newLine := fmt.Sprintf("{ type: \"title\", label: \"%s\" },", label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "info":
					node := words[2]
					label := words[3]
					newLine := fmt.Sprintf("{ type: \"info\", node: \"%s\", label: \"%s\" },", node, label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "table":
					node := words[2]
					text := words[3]
					newLine := fmt.Sprintf("{ type: \"table\", node: \"%s\", text: \"%s\" },", node, text)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "state":
					color := words[2]
					node := words[3]
					label := words[4]
					newLine := fmt.Sprintf("{ type: \"state\", color: \"%s\", node: \"%s\", label: \"%s\" },", color, node, label)
					fmt.Fprintln(writer, newLine)
					writer.Flush()
					break
				case "next":
					fmt.Fprintln(writer, "{ type: \"next\" },")
					writer.Flush()
					break
				}

			}
		}
	}

	fmt.Fprintln(writer, "]")
	writer.Flush()
	fmt.Println("Process finished.")

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package datastream

import (
	"database/sql"
	"errors"

	log "github.com/Sirupsen/logrus"
)

/*
The datastream table:

CREATE TABLE IF NOT EXISTS datastream (
    StreamId BIGINT NOT NULL,
	Substream VARCHAR,
    EndTime DOUBLE PRECISION,
    EndIndex BIGINT,
	Version INTEGER,
    Data BYTEA,
    UNIQUE (StreamId, Substream, EndIndex),
    PRIMARY KEY (StreamId, Substream, EndIndex)
    );
*/

var (
	//ErrorDatabaseCorrupted is returned when there is data loss or inconsistency in the database
	ErrorDatabaseCorrupted = errors.New("Database is corrupted!")
	//ErrWTF is returned when an internal assertion fails - it shoudl not happen. Ever.
	ErrWTF = errors.New("Something is seriously wrong. A internal assertion failed.")
)

//The SqlStore stores and queries arrays of Datapoints in an SQL database. The table 'datastream' is assumed
//to already exist and the correct indices are assumed to already exist.
type SqlStore struct {
	inserter     *sql.Stmt
	timequery    *sql.Stmt
	indexquery   *sql.Stmt
	endindex     *sql.Stmt
	delsubstream *sql.Stmt
	delstream    *sql.Stmt
	clearall     *sql.Stmt

	db *sql.DB

	insertversion int
}

//This function is to allow daisy-chaining errors from statement creation
func prepStatement(db *sql.DB, statement string, err error) (*sql.Stmt, error) {
	if err != nil {
		return nil, err
	}
	return db.Prepare(statement)
}

//prepareSqlStore sets up the inserts (it assumes that the database was already prepared)
func prepareSqlStore(db *sql.DB, insertStatement, timequeryStatement, indexqueryStatement,
	endindexStatement, delsubstreamStatement, delstreamStatement, clearallStatement string) (*SqlStore, error) {
	if err := db.Ping(); err != nil {
		return nil, err
	}

	inserter, err := prepStatement(db, insertStatement, nil)
	timequery, err := prepStatement(db, timequeryStatement, err)
	indexquery, err := prepStatement(db, indexqueryStatement, err)
	endindex, err := prepStatement(db, endindexStatement, err)
	delsubstream, err := prepStatement(db, delsubstreamStatement, err)
	delstream, err := prepStatement(db, delstreamStatement, err)
	clearall, err := prepStatement(db, clearallStatement, err)

	ss := &SqlStore{inserter, timequery, indexquery, endindex, delsubstream, delstream, clearall, db, 2}

	if err != nil {
		ss.Close()
		return nil, err
	}

	return ss, nil
}

//OpenPostgresStore initializes a postgres database to work with an SqlStore.
func OpenPostgresStore(db *sql.DB) (*SqlStore, error) {
	return prepareSqlStore(db, "INSERT INTO datastream VALUES ($1,$2,$3,$4,$5,$6);",
		"SELECT Version,EndIndex,Data FROM datastream WHERE StreamID=$1 AND Substream=$2 AND EndTime > $3 ORDER BY EndTime ASC;",
		"SELECT Version,EndIndex,Data FROM datastream WHERE StreamID=$1 AND Substream=$2 AND EndIndex > $3 ORDER BY EndIndex ASC;",
		"SELECT COALESCE(MAX(EndIndex),0) FROM datastream WHERE StreamID=$1 AND Substream=$2;",
		"DELETE FROM datastream WHERE StreamID=$1 AND Substream=$2;",
		"DELETE FROM datastream WHERE StreamID=$1;",
		"DELETE FROM datastream;")
}

//OpenSqlStore uses the correct initializer for the given database driver
func OpenSqlStore(db *sql.DB) (*SqlStore, error) {
	return OpenPostgresStore(db)
}

//Close all resources associated with the SqlStore.
func (s *SqlStore) Close() {
	//The if statements allow to close a partially initialized store
	if s.inserter != nil {
		s.inserter.Close()
	}
	if s.timequery != nil {
		s.timequery.Close()
	}
	if s.indexquery != nil {
		s.indexquery.Close()
	}
	if s.endindex != nil {
		s.endindex.Close()
	}
	if s.delstream != nil {
		s.delstream.Close()
	}
	if s.delsubstream != nil {
		s.delsubstream.Close()
	}
}

//Clear the entire table of all data
func (s *SqlStore) Clear() error {
	_, err := s.clearall.Exec()
	return err
}

//GetEndIndex returns the first index point outside of the most recent datapointarray stored within the database.
//In effect, if the datapoints in a key were all in one huge array, returns array.length
//(not including the datapoints which are not yet committed to the SqlStore)
func (s *SqlStore) GetEndIndex(streamID int64, substream string) (ei int64, err error) {
	rows, err := s.endindex.Query(streamID, substream)
	if err != nil {
		return 0, err
	}
	if !rows.Next() {
		return 0, ErrWTF //This should never happen
	}
	err = rows.Scan(&ei)
	rows.Close()
	return ei, err
}

//Insert the given DatapointArray into the sql database given the startindex of the array for the key.
func (s *SqlStore) Insert(streamID int64, substream string, startindex int64, da DatapointArray) error {
	return stmtInsert(s.inserter, streamID, substream, startindex, da)
}

func stmtInsert(stmt *sql.Stmt, streamID int64, substream string, startindex int64, da DatapointArray) error {
	dbytes, err := da.Encode(s.insertversion)
	if err != nil {
		return err
	}
	_, err = stmt.Exec(streamID, substream, da[len(da)-1].Timestamp, startindex+int64(len(da)),
		s.insertversion, dbytes)
	return err
}

//WriteBatches writes the given batch array
func (s *SqlStore) WriteBatches(b []Batch) error {
	t, err := s.db.Begin()
	if err != nil {
		return err
	}

	for i := 0; i < len(b); i++ {
		log.Debugf("Writing batch %s/%s i=%d #=%d", b[i].Stream, b[i].Substream, b[i].StartIndex, len(b[i].Data))
		streamID, err := b[i].GetStreamID()
		if err != nil {
			t.Rollback()
			return err
		}

		//Now the transaction-specific insert statement
		err = s.stmtInsert(t.Stmt(s.inserter), streamID, b[i].Substream, b[i].StartIndex, b[i].Data)
		if err != nil {
			t.Rollback()
			return err
		}
	}
	err = t.Commit()
	if err == nil && len(b) > 1 {
		log.Debugf("...successfully wrote %d batches", len(b))
	}
	return err
}

//Append the given DatapointArray to the data stream for key
func (s *SqlStore) Append(streamID int64, substream string, dp DatapointArray) error {
	i, err := s.GetEndIndex(streamID, substream)
	if err != nil {
		return err
	}
	return s.Insert(streamID, substream, i, dp)
}

//DeleteStream deletes all data associated with the given stream in the database
func (s *SqlStore) DeleteStream(streamID int64) error {
	_, err := s.delstream.Exec(streamID)
	return err
}

//DeleteSubstream deletes all data associated with the given substream in the database
func (s *SqlStore) DeleteSubstream(streamID int64, substream string) error {
	_, err := s.delsubstream.Exec(streamID, substream)
	return err
}

//GetByTime returns a ExtendedDataRange of datapoints starting at the starttime
func (s *SqlStore) GetByTime(streamID int64, substream string, starttime float64) (dr ExtendedDataRange, startindex int64, err error) {
	rows, err := s.timequery.Query(streamID, substream, starttime)
	if err != nil {
		return nil, 0, err
	}

	if !rows.Next() { //Check if there is any data to read
		startindex, err = s.GetEndIndex(streamID, substream)
		if rows.Err() != nil {
			err = rows.Err()
		}
		rows.Close()
		return EmptyRange{}, startindex, err
	}

	//There is some data!
	var version int
	var endindex int64
	var data []byte
	if err = rows.Scan(&version, &endindex, &data); err != nil {
		return EmptyRange{}, endindex, err
	}

	da, err := DecodeDatapointArray(data, version)
	if err != nil {
		rows.Close()
		return EmptyRange{}, endindex, err
	}
	tmp := da.TStart(starttime)
	da = &tmp
	if da == nil || int64(da.Length()) > endindex {
		rows.Close()
		return EmptyRange{}, endindex, ErrorDatabaseCorrupted
	}
	curindex := endindex - int64(da.Length())
	return &SqlRange{rows, da, curindex}, curindex, nil
}

//GetByIndex returns a ExtendedDataRange of datapoints starting at the nearest dataindex to the given startindex
func (s *SqlStore) GetByIndex(streamID int64, substream string, startindex int64) (dr ExtendedDataRange, dataindex int64, err error) {
	rows, err := s.indexquery.Query(streamID, substream, startindex)
	if err != nil {
		return nil, 0, err
	}

	if !rows.Next() { //Check if there is any data to read
		startindex, err = s.GetEndIndex(streamID, substream)
		if rows.Err() != nil {
			err = rows.Err()
		}
		rows.Close()
		return EmptyRange{}, startindex, err
	}

	//There is some data!
	var version int
	var endindex int64
	var data []byte
	if err = rows.Scan(&version, &endindex, &data); err != nil {
		return EmptyRange{}, endindex, err
	}

	da, err := DecodeDatapointArray(data, version)
	if err != nil {
		rows.Close()
		return EmptyRange{}, endindex, err
	}

	if da == nil || int64(da.Length()) > endindex {
		rows.Close()
		return EmptyRange{}, endindex, ErrorDatabaseCorrupted
	}

	//Lastly, we start the DatapointArray from the correct index
	//This subtraction is guaranteed to work, since query requires $gt
	fromend := endindex - startindex
	if fromend < int64(da.Length()) {
		//The index we want is within the datarange
		da = da.IRange(da.Length()-int(fromend), da.Length())
	}
	curindex := endindex - int64(da.Length())
	return &SqlRange{rows, da, curindex}, curindex, nil
}
<commit_msg>Fixed sql error<commit_after>package datastream

import (
	"database/sql"
	"errors"

	log "github.com/Sirupsen/logrus"
)

/*
The datastream table:

CREATE TABLE IF NOT EXISTS datastream (
    StreamId BIGINT NOT NULL,
	Substream VARCHAR,
    EndTime DOUBLE PRECISION,
    EndIndex BIGINT,
	Version INTEGER,
    Data BYTEA,
    UNIQUE (StreamId, Substream, EndIndex),
    PRIMARY KEY (StreamId, Substream, EndIndex)
    );
*/

var (
	//ErrorDatabaseCorrupted is returned when there is data loss or inconsistency in the database
	ErrorDatabaseCorrupted = errors.New("Database is corrupted!")
	//ErrWTF is returned when an internal assertion fails - it shoudl not happen. Ever.
	ErrWTF = errors.New("Something is seriously wrong. A internal assertion failed.")
)

//The SqlStore stores and queries arrays of Datapoints in an SQL database. The table 'datastream' is assumed
//to already exist and the correct indices are assumed to already exist.
type SqlStore struct {
	inserter     *sql.Stmt
	timequery    *sql.Stmt
	indexquery   *sql.Stmt
	endindex     *sql.Stmt
	delsubstream *sql.Stmt
	delstream    *sql.Stmt
	clearall     *sql.Stmt

	db *sql.DB

	insertversion int
}

//This function is to allow daisy-chaining errors from statement creation
func prepStatement(db *sql.DB, statement string, err error) (*sql.Stmt, error) {
	if err != nil {
		return nil, err
	}
	return db.Prepare(statement)
}

//prepareSqlStore sets up the inserts (it assumes that the database was already prepared)
func prepareSqlStore(db *sql.DB, insertStatement, timequeryStatement, indexqueryStatement,
	endindexStatement, delsubstreamStatement, delstreamStatement, clearallStatement string) (*SqlStore, error) {
	if err := db.Ping(); err != nil {
		return nil, err
	}

	inserter, err := prepStatement(db, insertStatement, nil)
	timequery, err := prepStatement(db, timequeryStatement, err)
	indexquery, err := prepStatement(db, indexqueryStatement, err)
	endindex, err := prepStatement(db, endindexStatement, err)
	delsubstream, err := prepStatement(db, delsubstreamStatement, err)
	delstream, err := prepStatement(db, delstreamStatement, err)
	clearall, err := prepStatement(db, clearallStatement, err)

	ss := &SqlStore{inserter, timequery, indexquery, endindex, delsubstream, delstream, clearall, db, 2}

	if err != nil {
		ss.Close()
		return nil, err
	}

	return ss, nil
}

//OpenPostgresStore initializes a postgres database to work with an SqlStore.
func OpenPostgresStore(db *sql.DB) (*SqlStore, error) {
	return prepareSqlStore(db, "INSERT INTO datastream VALUES ($1,$2,$3,$4,$5,$6);",
		"SELECT Version,EndIndex,Data FROM datastream WHERE StreamID=$1 AND Substream=$2 AND EndTime > $3 ORDER BY EndTime ASC;",
		"SELECT Version,EndIndex,Data FROM datastream WHERE StreamID=$1 AND Substream=$2 AND EndIndex > $3 ORDER BY EndIndex ASC;",
		"SELECT COALESCE(MAX(EndIndex),0) FROM datastream WHERE StreamID=$1 AND Substream=$2;",
		"DELETE FROM datastream WHERE StreamID=$1 AND Substream=$2;",
		"DELETE FROM datastream WHERE StreamID=$1;",
		"DELETE FROM datastream;")
}

//OpenSqlStore uses the correct initializer for the given database driver
func OpenSqlStore(db *sql.DB) (*SqlStore, error) {
	return OpenPostgresStore(db)
}

//Close all resources associated with the SqlStore.
func (s *SqlStore) Close() {
	//The if statements allow to close a partially initialized store
	if s.inserter != nil {
		s.inserter.Close()
	}
	if s.timequery != nil {
		s.timequery.Close()
	}
	if s.indexquery != nil {
		s.indexquery.Close()
	}
	if s.endindex != nil {
		s.endindex.Close()
	}
	if s.delstream != nil {
		s.delstream.Close()
	}
	if s.delsubstream != nil {
		s.delsubstream.Close()
	}
}

//Clear the entire table of all data
func (s *SqlStore) Clear() error {
	_, err := s.clearall.Exec()
	return err
}

//GetEndIndex returns the first index point outside of the most recent datapointarray stored within the database.
//In effect, if the datapoints in a key were all in one huge array, returns array.length
//(not including the datapoints which are not yet committed to the SqlStore)
func (s *SqlStore) GetEndIndex(streamID int64, substream string) (ei int64, err error) {
	rows, err := s.endindex.Query(streamID, substream)
	if err != nil {
		return 0, err
	}
	if !rows.Next() {
		return 0, ErrWTF //This should never happen
	}
	err = rows.Scan(&ei)
	rows.Close()
	return ei, err
}

//Insert the given DatapointArray into the sql database given the startindex of the array for the key.
func (s *SqlStore) Insert(streamID int64, substream string, startindex int64, da DatapointArray) error {
	return s.stmtInsert(s.inserter, streamID, substream, startindex, da)
}

func (s *SqlStore) stmtInsert(stmt *sql.Stmt, streamID int64, substream string, startindex int64, da DatapointArray) error {
	dbytes, err := da.Encode(s.insertversion)
	if err != nil {
		return err
	}
	_, err = stmt.Exec(streamID, substream, da[len(da)-1].Timestamp, startindex+int64(len(da)),
		s.insertversion, dbytes)
	return err
}

//WriteBatches writes the given batch array
func (s *SqlStore) WriteBatches(b []Batch) error {
	t, err := s.db.Begin()
	if err != nil {
		return err
	}

	for i := 0; i < len(b); i++ {
		log.Debugf("Writing batch %s/%s i=%d #=%d", b[i].Stream, b[i].Substream, b[i].StartIndex, len(b[i].Data))
		streamID, err := b[i].GetStreamID()
		if err != nil {
			t.Rollback()
			return err
		}

		//Now the transaction-specific insert statement
		err = s.stmtInsert(t.Stmt(s.inserter), streamID, b[i].Substream, b[i].StartIndex, b[i].Data)
		if err != nil {
			t.Rollback()
			return err
		}
	}
	err = t.Commit()
	if err == nil && len(b) > 1 {
		log.Debugf("...successfully wrote %d batches", len(b))
	}
	return err
}

//Append the given DatapointArray to the data stream for key
func (s *SqlStore) Append(streamID int64, substream string, dp DatapointArray) error {
	i, err := s.GetEndIndex(streamID, substream)
	if err != nil {
		return err
	}
	return s.Insert(streamID, substream, i, dp)
}

//DeleteStream deletes all data associated with the given stream in the database
func (s *SqlStore) DeleteStream(streamID int64) error {
	_, err := s.delstream.Exec(streamID)
	return err
}

//DeleteSubstream deletes all data associated with the given substream in the database
func (s *SqlStore) DeleteSubstream(streamID int64, substream string) error {
	_, err := s.delsubstream.Exec(streamID, substream)
	return err
}

//GetByTime returns a ExtendedDataRange of datapoints starting at the starttime
func (s *SqlStore) GetByTime(streamID int64, substream string, starttime float64) (dr ExtendedDataRange, startindex int64, err error) {
	rows, err := s.timequery.Query(streamID, substream, starttime)
	if err != nil {
		return nil, 0, err
	}

	if !rows.Next() { //Check if there is any data to read
		startindex, err = s.GetEndIndex(streamID, substream)
		if rows.Err() != nil {
			err = rows.Err()
		}
		rows.Close()
		return EmptyRange{}, startindex, err
	}

	//There is some data!
	var version int
	var endindex int64
	var data []byte
	if err = rows.Scan(&version, &endindex, &data); err != nil {
		return EmptyRange{}, endindex, err
	}

	da, err := DecodeDatapointArray(data, version)
	if err != nil {
		rows.Close()
		return EmptyRange{}, endindex, err
	}
	tmp := da.TStart(starttime)
	da = &tmp
	if da == nil || int64(da.Length()) > endindex {
		rows.Close()
		return EmptyRange{}, endindex, ErrorDatabaseCorrupted
	}
	curindex := endindex - int64(da.Length())
	return &SqlRange{rows, da, curindex}, curindex, nil
}

//GetByIndex returns a ExtendedDataRange of datapoints starting at the nearest dataindex to the given startindex
func (s *SqlStore) GetByIndex(streamID int64, substream string, startindex int64) (dr ExtendedDataRange, dataindex int64, err error) {
	rows, err := s.indexquery.Query(streamID, substream, startindex)
	if err != nil {
		return nil, 0, err
	}

	if !rows.Next() { //Check if there is any data to read
		startindex, err = s.GetEndIndex(streamID, substream)
		if rows.Err() != nil {
			err = rows.Err()
		}
		rows.Close()
		return EmptyRange{}, startindex, err
	}

	//There is some data!
	var version int
	var endindex int64
	var data []byte
	if err = rows.Scan(&version, &endindex, &data); err != nil {
		return EmptyRange{}, endindex, err
	}

	da, err := DecodeDatapointArray(data, version)
	if err != nil {
		rows.Close()
		return EmptyRange{}, endindex, err
	}

	if da == nil || int64(da.Length()) > endindex {
		rows.Close()
		return EmptyRange{}, endindex, ErrorDatabaseCorrupted
	}

	//Lastly, we start the DatapointArray from the correct index
	//This subtraction is guaranteed to work, since query requires $gt
	fromend := endindex - startindex
	if fromend < int64(da.Length()) {
		//The index we want is within the datarange
		da = da.IRange(da.Length()-int(fromend), da.Length())
	}
	curindex := endindex - int64(da.Length())
	return &SqlRange{rows, da, curindex}, curindex, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
)

var newline = []uint8("\n")
var help = flag.Bool("help", false, "help")

func main() {
	flag.Parse()
	if *help {
		cmd := os.Args[0]
		if cmd[0:2] == "./" {
			cmd = cmd[2:]
		}
		fmt.Fprintf(os.Stderr, "Usage: "+cmd+" [file]"+"\n")
		fmt.Fprintf(os.Stderr, "   or: $COMMAND | "+cmd+"\n")
		os.Exit(0)
	}

	bufIn := bufio.NewReader(fileFromArguments())
	lastLine := []uint8("")

	arr := make([]byte, 0, 1024*1024)
	buf := bytes.NewBuffer(arr)
	lineNum := int64(1)
	for {
		line, isPrefix, err := bufIn.ReadLine()
		if err != nil && err != io.EOF {
			genericError(err)
		}

		lastLine = append(lastLine, line...)
		if !isPrefix && len(lastLine) != 0 {
			indentAndPrint(buf, lastLine, lineNum)
			lineNum += 1
			lastLine = []uint8("")
		}

		if err == io.EOF {
			os.Exit(0)
		}
	}
}

func indentAndPrint(buf *bytes.Buffer, js []uint8, lineNum int64) {
	jsErr := json.Indent(buf, js, "", "  ")
	if jsErr != nil {
		malformedJSON(jsErr, js, lineNum)
	}
	os.Stdout.Write(buf.Bytes())
	os.Stdout.Write(newline)
	buf.Reset()
}

func malformedJSON(jsErr error, js []uint8, lineNum int64) {
	os.Stdout.Sync()

	synErr, isSynError := (jsErr).(*json.SyntaxError)

	fmt.Fprintf(os.Stderr, "ERROR: Broken json on line %d: %s\n", lineNum, jsErr)

	if isSynError {
		prefix := ""
		suffix := ""

		begin := 0
		if synErr.Offset > 15 {
			begin = int(synErr.Offset - 15)
			prefix = "..."
		}

		end := begin + 30
		if end > len(js) {
			end = len(js)
		} else {
			suffix = "..."
		}

		fmt.Fprintf(os.Stderr, "  Context: %s%s%s\n", prefix, js[begin:end], suffix)
	}

	os.Exit(1)
}

func fileFromArguments() *os.File {
	flag.Parse()
	args := flag.Args()
	if len(args) > 1 {
		msg := fmt.Sprintf("only specify 0 or 1 files in the arguments, not %d\n", len(args))
		genericError(errors.New(msg))
	}
	if len(args) == 0 {
		return os.Stdin
	}

	file, err := os.OpenFile(args[0], os.O_RDONLY, 0)
	if err != nil {
		genericError(err)
	}
	return file
}

func genericError(err error) {
	os.Stdout.Sync()
	fmt.Fprintf(os.Stderr, "ERROR: %s", err)
	os.Exit(2)
}
<commit_msg>clean up the lastLine slice allocs<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
)

var newline = []uint8("\n")
var help = flag.Bool("help", false, "help")

func main() {
	flag.Parse()
	if *help {
		cmd := os.Args[0]
		if cmd[0:2] == "./" {
			cmd = cmd[2:]
		}
		fmt.Fprintf(os.Stderr, "Usage: "+cmd+" [file]"+"\n")
		fmt.Fprintf(os.Stderr, "   or: $COMMAND | "+cmd+"\n")
		os.Exit(0)
	}

	bufIn := bufio.NewReader(fileFromArguments())
	lastLine := []byte{}

	arr := make([]byte, 0, 1024*1024)
	buf := bytes.NewBuffer(arr)
	lineNum := int64(1)
	for {
		line, isPrefix, err := bufIn.ReadLine()
		if err != nil && err != io.EOF {
			genericError(err)
		}

		lastLine = append(lastLine, line...)
		if !isPrefix && len(lastLine) != 0 {
			indentAndPrint(buf, lastLine, lineNum)
			lineNum += 1
			lastLine = []byte{}
		}

		if err == io.EOF {
			os.Exit(0)
		}
	}
}

func indentAndPrint(buf *bytes.Buffer, js []byte, lineNum int64) {
	jsErr := json.Indent(buf, js, "", "  ")
	if jsErr != nil {
		malformedJSON(jsErr, js, lineNum)
	}
	os.Stdout.Write(buf.Bytes())
	os.Stdout.Write(newline)
	buf.Reset()
}

func malformedJSON(jsErr error, js []uint8, lineNum int64) {
	os.Stdout.Sync()

	synErr, isSynError := (jsErr).(*json.SyntaxError)

	fmt.Fprintf(os.Stderr, "ERROR: Broken json on line %d: %s\n", lineNum, jsErr)

	if isSynError {
		prefix := ""
		suffix := ""

		begin := 0
		if synErr.Offset > 15 {
			begin = int(synErr.Offset - 15)
			prefix = "..."
		}

		end := begin + 30
		if end > len(js) {
			end = len(js)
		} else {
			suffix = "..."
		}

		fmt.Fprintf(os.Stderr, "  Context: %s%s%s\n", prefix, js[begin:end], suffix)
	}

	os.Exit(1)
}

func fileFromArguments() *os.File {
	flag.Parse()
	args := flag.Args()
	if len(args) > 1 {
		msg := fmt.Sprintf("only specify 0 or 1 files in the arguments, not %d\n", len(args))
		genericError(errors.New(msg))
	}
	if len(args) == 0 {
		return os.Stdin
	}

	file, err := os.OpenFile(args[0], os.O_RDONLY, 0)
	if err != nil {
		genericError(err)
	}
	return file
}

func genericError(err error) {
	os.Stdout.Sync()
	fmt.Fprintf(os.Stderr, "ERROR: %s", err)
	os.Exit(2)
}
<|endoftext|>


<commit_before>// Package keccak implements the Keccak (SHA-3) hash algorithm.
// http://keccak.noekeon.org / FIPS 202 draft.
package keccak

import (
	"hash"
)

const (
	domainNone  = 1
	domainSHA3  = 0x06
	domainSHAKE = 0x1f
)

const rounds = 24

var roundConstants = []uint64{
	0x0000000000000001, 0x0000000000008082,
	0x800000000000808A, 0x8000000080008000,
	0x000000000000808B, 0x0000000080000001,
	0x8000000080008081, 0x8000000000008009,
	0x000000000000008A, 0x0000000000000088,
	0x0000000080008009, 0x000000008000000A,
	0x000000008000808B, 0x800000000000008B,
	0x8000000000008089, 0x8000000000008003,
	0x8000000000008002, 0x8000000000000080,
	0x000000000000800A, 0x800000008000000A,
	0x8000000080008081, 0x8000000000008080,
	0x0000000080000001, 0x8000000080008008,
}

var rotationConstants = [24]uint{
	1, 3, 6, 10, 15, 21, 28, 36,
	45, 55, 2, 14, 27, 41, 56, 8,
	25, 43, 62, 18, 39, 61, 20, 44,
}

var piLane = [24]uint{
	10, 7, 11, 17, 18, 3, 5, 16,
	8, 21, 24, 4, 15, 23, 19, 13,
	12, 2, 20, 14, 22, 9, 6, 1,
}

type keccak struct {
	S         [25]uint64
	size      int
	blockSize int
	buf       []byte
	domain    byte
}

func newKeccak(capacity, output int, domain byte) hash.Hash {
	var h keccak
	h.size = output / 8
	h.blockSize = (200 - capacity/8)
	h.domain = domain
	return &h
}

func New224() hash.Hash {
	return newKeccak(224*2, 224, domainNone)
}

func New256() hash.Hash {
	return newKeccak(256*2, 256, domainNone)
}

func New384() hash.Hash {
	return newKeccak(384*2, 384, domainNone)
}

func New512() hash.Hash {
	return newKeccak(512*2, 512, domainNone)
}

func (k *keccak) Write(b []byte) (int, error) {
	n := len(b)

	if len(k.buf) > 0 {
		x := k.blockSize - len(k.buf)
		if x > len(b) {
			x = len(b)
		}
		k.buf = append(k.buf, b[:x]...)
		b = b[x:]

		if len(k.buf) < k.blockSize {
			return n, nil
		}

		k.absorb(k.buf)
		k.buf = nil
	}

	for len(b) >= k.blockSize {
		k.absorb(b[:k.blockSize])
		b = b[k.blockSize:]
	}

	k.buf = b

	return n, nil
}

func (k0 *keccak) Sum(b []byte) []byte {
	k := *k0
	k.final()
	return k.squeeze(b)
}

func (k *keccak) Reset() {
	for i := range k.S {
		k.S[i] = 0
	}
	k.buf = nil
}

func (k *keccak) Size() int {
	return k.size
}

func (k *keccak) BlockSize() int {
	return k.blockSize
}

func (k *keccak) f() {
	for r := 0; r < rounds; r++ {
		var bc [5]uint64

		// theta
		for i := range bc {
			bc[i] = k.S[i] ^ k.S[5+i] ^ k.S[10+i] ^ k.S[15+i] ^ k.S[20+i]
		}
		for i := range bc {
			t := bc[(i+4)%5] ^ rotl64(bc[(i+1)%5], 1)
			for j := 0; j < len(k.S); j += 5 {
				k.S[i+j] ^= t
			}
		}

		// rho phi
		temp := k.S[1]
		for i := range piLane {
			j := piLane[i]
			temp2 := k.S[j]
			k.S[j] = rotl64(temp, rotationConstants[i])
			temp = temp2
		}

		// chi
		for j := 0; j < len(k.S); j += 5 {
			for i := range bc {
				bc[i] = k.S[j+i]
			}
			for i := range bc {
				k.S[j+i] ^= (^bc[(i+1)%5]) & bc[(i+2)%5]
			}
		}

		// iota
		k.S[0] ^= roundConstants[r]
	}
}

func (k *keccak) absorb(block []byte) {
	if len(block) != k.blockSize {
		panic("absorb() called with invalid block size")
	}

	for i := 0; i < k.blockSize/8; i++ {
		k.S[i] ^= uint64le(block[i*8:])
	}
	k.f()
}

func (k *keccak) pad(block []byte) []byte {

	padded := make([]byte, k.blockSize)

	copy(padded, k.buf)
	padded[len(k.buf)] = k.domain
	padded[len(padded)-1] |= 0x80

	return padded
}

func (k *keccak) final() {
	last := k.pad(k.buf)
	k.absorb(last)
}

func (k *keccak) squeeze(b []byte) []byte {
	buf := make([]byte, 8*len(k.S))
	n := k.size
	for {
		for i := range k.S {
			putUint64le(buf[i*8:], k.S[i])
		}
		if n <= k.blockSize {
			b = append(b, buf[:n]...)
			break
		}
		b = append(b, buf[:k.blockSize]...)
		n -= k.blockSize
		k.f()
	}
	return b
}

func rotl64(x uint64, n uint) uint64 {
	return (x << n) | (x >> (64 - n))
}

func uint64le(v []byte) uint64 {
	return uint64(v[0]) |
		uint64(v[1])<<8 |
		uint64(v[2])<<16 |
		uint64(v[3])<<24 |
		uint64(v[4])<<32 |
		uint64(v[5])<<40 |
		uint64(v[6])<<48 |
		uint64(v[7])<<56

}

func putUint64le(v []byte, x uint64) {
	v[0] = byte(x)
	v[1] = byte(x >> 8)
	v[2] = byte(x >> 16)
	v[3] = byte(x >> 24)
	v[4] = byte(x >> 32)
	v[5] = byte(x >> 40)
	v[6] = byte(x >> 48)
	v[7] = byte(x >> 56)
}
<commit_msg>keccakf<commit_after>// Package keccak implements the Keccak (SHA-3) hash algorithm.
// http://keccak.noekeon.org / FIPS 202 draft.
package keccak

import (
	"hash"
)

const (
	domainNone  = 1
	domainSHA3  = 0x06
	domainSHAKE = 0x1f
)

const rounds = 24

var roundConstants = []uint64{
	0x0000000000000001, 0x0000000000008082,
	0x800000000000808A, 0x8000000080008000,
	0x000000000000808B, 0x0000000080000001,
	0x8000000080008081, 0x8000000000008009,
	0x000000000000008A, 0x0000000000000088,
	0x0000000080008009, 0x000000008000000A,
	0x000000008000808B, 0x800000000000008B,
	0x8000000000008089, 0x8000000000008003,
	0x8000000000008002, 0x8000000000000080,
	0x000000000000800A, 0x800000008000000A,
	0x8000000080008081, 0x8000000000008080,
	0x0000000080000001, 0x8000000080008008,
}

var rotationConstants = [24]uint{
	1, 3, 6, 10, 15, 21, 28, 36,
	45, 55, 2, 14, 27, 41, 56, 8,
	25, 43, 62, 18, 39, 61, 20, 44,
}

var piLane = [24]uint{
	10, 7, 11, 17, 18, 3, 5, 16,
	8, 21, 24, 4, 15, 23, 19, 13,
	12, 2, 20, 14, 22, 9, 6, 1,
}

type keccak struct {
	S         [25]uint64
	size      int
	blockSize int
	buf       []byte
	domain    byte
}

func newKeccak(capacity, output int, domain byte) hash.Hash {
	var h keccak
	h.size = output / 8
	h.blockSize = (200 - capacity/8)
	h.domain = domain
	return &h
}

func New224() hash.Hash {
	return newKeccak(224*2, 224, domainNone)
}

func New256() hash.Hash {
	return newKeccak(256*2, 256, domainNone)
}

func New384() hash.Hash {
	return newKeccak(384*2, 384, domainNone)
}

func New512() hash.Hash {
	return newKeccak(512*2, 512, domainNone)
}

func (k *keccak) Write(b []byte) (int, error) {
	n := len(b)

	if len(k.buf) > 0 {
		x := k.blockSize - len(k.buf)
		if x > len(b) {
			x = len(b)
		}
		k.buf = append(k.buf, b[:x]...)
		b = b[x:]

		if len(k.buf) < k.blockSize {
			return n, nil
		}

		k.absorb(k.buf)
		k.buf = nil
	}

	for len(b) >= k.blockSize {
		k.absorb(b[:k.blockSize])
		b = b[k.blockSize:]
	}

	k.buf = b

	return n, nil
}

func (k0 *keccak) Sum(b []byte) []byte {
	k := *k0
	k.final()
	return k.squeeze(b)
}

func (k *keccak) Reset() {
	for i := range k.S {
		k.S[i] = 0
	}
	k.buf = nil
}

func (k *keccak) Size() int {
	return k.size
}

func (k *keccak) BlockSize() int {
	return k.blockSize
}

func (k *keccak) absorb(block []byte) {
	if len(block) != k.blockSize {
		panic("absorb() called with invalid block size")
	}

	for i := 0; i < k.blockSize/8; i++ {
		k.S[i] ^= uint64le(block[i*8:])
	}
	keccakf(&k.S)
}

func (k *keccak) pad(block []byte) []byte {

	padded := make([]byte, k.blockSize)

	copy(padded, k.buf)
	padded[len(k.buf)] = k.domain
	padded[len(padded)-1] |= 0x80

	return padded
}

func (k *keccak) final() {
	last := k.pad(k.buf)
	k.absorb(last)
}

func (k *keccak) squeeze(b []byte) []byte {
	buf := make([]byte, 8*len(k.S))
	n := k.size
	for {
		for i := range k.S {
			putUint64le(buf[i*8:], k.S[i])
		}
		if n <= k.blockSize {
			b = append(b, buf[:n]...)
			break
		}
		b = append(b, buf[:k.blockSize]...)
		n -= k.blockSize
		keccakf(&k.S)
	}
	return b
}

func keccakf(S *[25]uint64) {
	var bc [5]uint64
	for r := 0; r < rounds; r++ {
		// theta
		for i := range bc {
			bc[i] = S[i] ^ S[5+i] ^ S[10+i] ^ S[15+i] ^ S[20+i]
		}
		for i := range bc {
			t := bc[(i+4)%5] ^ rotl64(bc[(i+1)%5], 1)
			for j := 0; j < len(S); j += 5 {
				S[i+j] ^= t
			}
		}

		// rho phi
		temp := S[1]
		for i := range piLane {
			j := piLane[i]
			temp2 := S[j]
			S[j] = rotl64(temp, rotationConstants[i])
			temp = temp2
		}

		// chi
		for j := 0; j < len(S); j += 5 {
			for i := range bc {
				bc[i] = S[j+i]
			}
			for i := range bc {
				S[j+i] ^= (^bc[(i+1)%5]) & bc[(i+2)%5]
			}
		}

		// iota
		S[0] ^= roundConstants[r]
	}
}

func rotl64(x uint64, n uint) uint64 {
	return (x << n) | (x >> (64 - n))
}

func uint64le(v []byte) uint64 {
	return uint64(v[0]) |
		uint64(v[1])<<8 |
		uint64(v[2])<<16 |
		uint64(v[3])<<24 |
		uint64(v[4])<<32 |
		uint64(v[5])<<40 |
		uint64(v[6])<<48 |
		uint64(v[7])<<56

}

func putUint64le(v []byte, x uint64) {
	v[0] = byte(x)
	v[1] = byte(x >> 8)
	v[2] = byte(x >> 16)
	v[3] = byte(x >> 24)
	v[4] = byte(x >> 32)
	v[5] = byte(x >> 40)
	v[6] = byte(x >> 48)
	v[7] = byte(x >> 56)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019 Andrew Ayer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name(s) of the above copyright
 * holders shall not be used in advertising or otherwise to promote the
 * sale, use or other dealings in this Software without prior written
 * authorization.
 */

package config

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"io/ioutil"
	"strings"
)

func loadConfigFile(filename string) (map[string]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	config := make(map[string]string)
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) == 2 {
			config[fields[0]] = fields[1]
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("Error reading %s: %s", filename, err)
	}
	return config, nil
}

func loadUsersFile(filename string) (map[string]UserConfig, error) {
	params, err := loadConfigFile(filename)
	if err != nil {
		return nil, err
	}
	users := make(map[string]UserConfig)
	for userJID, userSpec := range params {
		fields := strings.SplitN(userSpec, ":", 2)
		if len(fields) != 2 {
			return nil, fmt.Errorf("User %s in %s has malformed configuration (should look like provider:phonenumber)", userJID, filename)
		}
		users[userJID] = UserConfig{
			Provider: fields[0],
			PhoneNumber: fields[1],
		}
	}
	return users, nil
}

func loadProviderConfigFile(filename string) (ProviderConfig, error) {
	params, err := loadConfigFile(filename)
	if err != nil {
		return ProviderConfig{}, err
	}

	typeParam, exists := params["type"]
	if !exists {
		return ProviderConfig{}, fmt.Errorf("%s lacks type parameter", filename)
	}
	delete(params, "type")
	return ProviderConfig{
		Type: typeParam,
		Params: params,
	}, nil
}

func loadProvidersDirectory(dirpath string) (map[string]ProviderConfig, error) {
	providerFiles, err := ioutil.ReadDir(dirpath)
	if err != nil {
		return nil, err
	}
	providers := make(map[string]ProviderConfig)
	for _, providerFile := range providerFiles {
		providerFileName := providerFile.Name()
		if strings.HasPrefix(providerFileName, ".") {
			continue
		}
		providerConfig, err := loadProviderConfigFile(filepath.Join(dirpath, providerFileName))
		if err != nil {
			return nil, err
		}
		providers[providerFileName] = providerConfig
	}
	return providers, nil
}

func FromDirectory(dirpath string) (*Config, error) {
	config := new(Config)

	params, err := loadConfigFile(filepath.Join(dirpath, "config"))
	if err != nil {
		return nil, err
	}
	config.XMPPServer = params["xmpp_server"]
	config.XMPPDomain = params["xmpp_domain"]
	config.XMPPSecret = params["xmpp_secret"]
	config.PublicURL = params["public_url"]
	config.Users, err = loadUsersFile(filepath.Join(dirpath, "users"))
	if err != nil {
		return nil, err
	}
	config.Providers, err = loadProvidersDirectory(filepath.Join(dirpath, "providers"))
	if err != nil {
		return nil, err
	}
	config.Rosters, err = loadConfigFile(filepath.Join(dirpath, "rosters"))
	if err != nil {
		return nil, err
	}
	return config, nil
}
<commit_msg>Allow rosters file to not exist<commit_after>/*
 * Copyright (c) 2019 Andrew Ayer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name(s) of the above copyright
 * holders shall not be used in advertising or otherwise to promote the
 * sale, use or other dealings in this Software without prior written
 * authorization.
 */

package config

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"io/fs"
	"io/ioutil"
	"strings"
)

func loadConfigFile(filename string) (map[string]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	config := make(map[string]string)
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) == 2 {
			config[fields[0]] = fields[1]
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("Error reading %s: %s", filename, err)
	}
	return config, nil
}

func loadUsersFile(filename string) (map[string]UserConfig, error) {
	params, err := loadConfigFile(filename)
	if err != nil {
		return nil, err
	}
	users := make(map[string]UserConfig)
	for userJID, userSpec := range params {
		fields := strings.SplitN(userSpec, ":", 2)
		if len(fields) != 2 {
			return nil, fmt.Errorf("User %s in %s has malformed configuration (should look like provider:phonenumber)", userJID, filename)
		}
		users[userJID] = UserConfig{
			Provider: fields[0],
			PhoneNumber: fields[1],
		}
	}
	return users, nil
}

func loadProviderConfigFile(filename string) (ProviderConfig, error) {
	params, err := loadConfigFile(filename)
	if err != nil {
		return ProviderConfig{}, err
	}

	typeParam, exists := params["type"]
	if !exists {
		return ProviderConfig{}, fmt.Errorf("%s lacks type parameter", filename)
	}
	delete(params, "type")
	return ProviderConfig{
		Type: typeParam,
		Params: params,
	}, nil
}

func loadProvidersDirectory(dirpath string) (map[string]ProviderConfig, error) {
	providerFiles, err := ioutil.ReadDir(dirpath)
	if err != nil {
		return nil, err
	}
	providers := make(map[string]ProviderConfig)
	for _, providerFile := range providerFiles {
		providerFileName := providerFile.Name()
		if strings.HasPrefix(providerFileName, ".") {
			continue
		}
		providerConfig, err := loadProviderConfigFile(filepath.Join(dirpath, providerFileName))
		if err != nil {
			return nil, err
		}
		providers[providerFileName] = providerConfig
	}
	return providers, nil
}

func FromDirectory(dirpath string) (*Config, error) {
	config := new(Config)

	params, err := loadConfigFile(filepath.Join(dirpath, "config"))
	if err != nil {
		return nil, err
	}
	config.XMPPServer = params["xmpp_server"]
	config.XMPPDomain = params["xmpp_domain"]
	config.XMPPSecret = params["xmpp_secret"]
	config.PublicURL = params["public_url"]
	config.Users, err = loadUsersFile(filepath.Join(dirpath, "users"))
	if err != nil {
		return nil, err
	}
	config.Providers, err = loadProvidersDirectory(filepath.Join(dirpath, "providers"))
	if err != nil {
		return nil, err
	}
	config.Rosters, err = loadConfigFile(filepath.Join(dirpath, "rosters"))
	if err != nil && !errors.Is(err, fs.ErrNotExist) {
		return nil, err
	}
	return config, nil
}
<|endoftext|>


<commit_before>package peco

import (
	"encoding/json"
	"fmt"
	"os"
	"unicode"

	"github.com/nsf/termbox-go"
)

type KeymapHandler func(*Input, termbox.Event)
type Keymap map[termbox.Key]KeymapHandler
type KeymapStringKey string
type KeymapStringHandler string

// This map is populated using some magic numbers, which must match
// the values defined in termbox-go. Verification against the actual
// termbox constants are done in the test
var stringToKey = map[string]termbox.Key{}

func init() {
	fidx := 12
	for k := termbox.KeyF1; k > termbox.KeyF12; k-- {
		sk := fmt.Sprintf("F%d", fidx)
		stringToKey[sk] = k
		fidx--
	}

	names := []string{
		"Insert",
		"Delete",
		"Home",
		"End",
		"Pgup",
		"Pgdn",
		"ArrowUp",
		"ArrowDown",
		"ArrowLeft",
		"ArrowRight",
	}
	for i, n := range names {
		stringToKey[n] = termbox.Key(int(termbox.KeyF12) - (i + 1))
	}

	names = []string{
		"Left",
		"Middle",
		"Right",
	}
	for i, n := range names {
		sk := fmt.Sprintf("Mouse%s", n)
		stringToKey[sk] = termbox.Key(int(termbox.KeyArrowRight) - (i + 2))
	}

	whacky := [][]string{
		{"~", "2", "Space"},
		{"a"},
		{"b"},
		{"c"},
		{"d"},
		{"e"},
		{"f"},
		{"g"},
		{"h"},
		{"i"},
		{"j"},
		{"k"},
		{"l"},
		{"m"},
		{"n"},
		{"o"},
		{"p"},
		{"q"},
		{"r"},
		{"s"},
		{"t"},
		{"u"},
		{"v"},
		{"w"},
		{"x"},
		{"y"},
		{"z"},
		{"[", "3"},
		{"4", "\\"},
		{"5", "]"},
		{"6"},
		{"7", "/", "_"},
	}
	for i, list := range whacky {
		for _, n := range list {
			sk := fmt.Sprintf("C-%s", n)
			stringToKey[sk] = termbox.Key(int(termbox.KeyCtrlTilde) + i)
		}
	}

	stringToKey["BS"] = termbox.KeyBackspace
	stringToKey["Tab"] = termbox.KeyTab
	stringToKey["Enter"] = termbox.KeyEnter
	stringToKey["Esc"] = termbox.KeyEsc
	stringToKey["Space"] = termbox.KeySpace
	stringToKey["BS2"] = termbox.KeyBackspace2
	stringToKey["C-8"] = termbox.KeyCtrl8

	//	panic(fmt.Sprintf("%#q", stringToKey))
}

func handleAcceptChar(i *Input, ev termbox.Event) {
	if ev.Key == termbox.KeySpace {
		ev.Ch = ' '
	}

	if ev.Ch > 0 {
		if len(i.query) == i.caretPos {
			i.query = append(i.query, ev.Ch)
		} else {
			buf := make([]rune, len(i.query)+1)
			copy(buf, i.query[:i.caretPos])
			buf[i.caretPos] = ev.Ch
			copy(buf[i.caretPos+1:], i.query[i.caretPos:])
			i.query = buf
		}
		i.caretPos++
		i.ExecQuery(string(i.query))
	}
}

// peco.Finish -> end program, exit with success
func handleFinish(i *Input, _ termbox.Event) {
	if len(i.current) == 1 {
		i.result = i.current[0].line
	} else if i.selectedLine > 0 && i.selectedLine < len(i.current) {
		i.result = i.current[i.selectedLine-1].line
	}
	i.Finish()
}

// peco.Cancel -> end program, exit with failure
func handleCancel(i *Input, ev termbox.Event) {
	i.ExitStatus = 1
	i.Finish()
}

func handleSelectPrevious(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToPrevLine
	i.DrawMatches(nil)
}

func handleSelectNext(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToNextLine
	i.DrawMatches(nil)
}

func handleSelectPreviousPage(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToPrevPage
	i.DrawMatches(nil)
}

func handleSelectNextPage(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToNextPage
	i.DrawMatches(nil)
}

func handleForwardWord(i *Input, _ termbox.Event) {
	if i.caretPos >= len(i.query) {
		return
	}

	foundSpace := false
	for pos := i.caretPos; pos < len(i.query); pos++ {
		r := i.query[pos]
		if foundSpace {
			if !unicode.IsSpace(r) {
				i.caretPos = pos
				i.DrawMatches(nil)
				return
			}
		} else {
			if unicode.IsSpace(r) {
				foundSpace = true
			}
		}
	}

	// not found. just move to the end of the buffer
	i.caretPos = len(i.query)
	i.DrawMatches(nil)

}

func handleBackwardWord(i *Input, _ termbox.Event) {
	if i.caretPos == 0 {
		return
	}

	if i.caretPos >= len(i.query) {
		i.caretPos--
	}

	// if we start from a whitespace-ish position, we should
	// rewind to the end of the previous word, and then do the
	// search all over again
SEARCH_PREV_WORD:
	if unicode.IsSpace(i.query[i.caretPos]) {
		for pos := i.caretPos; pos > 0; pos-- {
			if !unicode.IsSpace(i.query[pos]) {
				i.caretPos = pos
				break
			}
		}
	}

	// if we start from the first character of a word, we
	// should attempt to move back and search for the previous word
	if i.caretPos > 0 && unicode.IsSpace(i.query[i.caretPos-1]) {
		i.caretPos--
		goto SEARCH_PREV_WORD
	}

	// Now look for a space
	for pos := i.caretPos; pos > 0; pos-- {
		if unicode.IsSpace(i.query[pos]) {
			i.caretPos = pos + 1
			i.DrawMatches(nil)
			return
		}
	}

	// not found. just move to the beginning of the buffer
	i.caretPos = 0
	i.DrawMatches(nil)
}

func handleForwardChar(i *Input, _ termbox.Event) {
	if i.caretPos >= len(i.query) {
		return
	}
	i.caretPos++
	i.DrawMatches(nil)
}

func handleBackwardChar(i *Input, _ termbox.Event) {
	if i.caretPos <= 0 {
		return
	}
	i.caretPos--
	i.DrawMatches(nil)
}

func handleBeginningOfLine(i *Input, _ termbox.Event) {
	i.caretPos = 0
	i.DrawMatches(nil)
}

func handleEndOfLine(i *Input, _ termbox.Event) {
	i.caretPos = len(i.query)
	i.DrawMatches(nil)
}

func handleKillEndOfLine(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	i.query = i.query[0:i.caretPos]
	i.DrawMatches(nil)
}

func handleDeleteForwardChar(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	buf := make([]rune, len(i.query)-1)
	copy(buf, i.query[:i.caretPos])
	copy(buf[i.caretPos:], i.query[i.caretPos+1:])
	i.query = buf
	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteBackwardChar(i *Input, ev termbox.Event) {
	if len(i.query) <= 0 {
		return
	}

	switch i.caretPos {
	case 0:
		// No op
		return
	case len(i.query):
		i.query = i.query[:len(i.query)-1]
	default:
		buf := make([]rune, len(i.query)-1)
		copy(buf, i.query[:i.caretPos])
		copy(buf[i.caretPos-1:], i.query[i.caretPos:])
		i.query = buf
	}
	i.caretPos--
	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteForwardWord(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	for pos := i.caretPos; pos < len(i.query); pos++ {
		if pos == len(i.query)-1 {
			i.query = i.query[:i.caretPos]
			break
		}

		if unicode.IsSpace(i.query[pos]) {
			buf := make([]rune, len(i.query)-(pos-i.caretPos))
			copy(buf, i.query[:i.caretPos])
			copy(buf[i.caretPos:], i.query[pos:])
			i.query = buf
			break
		}
	}

	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteBackwardWord(i *Input, _ termbox.Event) {
	if i.caretPos == 0 {
		return
	}

	for pos := i.caretPos - 1; pos >= 0; pos-- {
		if pos == 0 {
			i.query = i.query[i.caretPos:]
			break
		}

		if unicode.IsSpace(i.query[pos]) {
			buf := make([]rune, len(i.query)-(i.caretPos-pos))
			copy(buf, i.query[:pos])
			copy(buf[pos:], i.query[i.caretPos:])
			i.query = buf
			i.caretPos = pos
			break
		}
	}

	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func (ksk KeymapStringKey) ToKey() (k termbox.Key, err error) {
	k, ok := stringToKey[string(ksk)]
	if !ok {
		err = fmt.Errorf("No such key %s", ksk)
	}
	return
}

func (ksh KeymapStringHandler) ToHandler() (h KeymapHandler, err error) {
	switch ksh {
	case "peco.KillEndOfLine":
		h = handleKillEndOfLine
	case "peco.BeginningOfLine":
		h = handleBeginningOfLine
	case "peco.EndOfLine":
		h = handleEndOfLine
	case "peco.ForwardChar":
		h = handleForwardChar
	case "peco.BackwardChar":
		h = handleBackwardChar
	case "peco.ForwardWord":
		h = handleForwardWord
	case "peco.BackwardWord":
		h = handleBackwardWord
	case "peco.DeleteForwardChar":
		h = handleDeleteForwardChar
	case "peco.DeleteBackwardChar":
		h = handleDeleteBackwardChar
	case "peco.DeleteForwardWord":
		h = handleDeleteForwardWord
	case "peco.DeleteBackwardWord":
		h = handleDeleteBackwardWord
	case "peco.SelectPreviousPage":
		h = handleSelectPreviousPage
	case "peco.SelectNextPage":
		h = handleSelectNextPage
	case "peco.SelectPrevious":
		h = handleSelectPrevious
	case "peco.SelectNext":
		h = handleSelectNext
	case "peco.Finish":
		h = handleFinish
	case "peco.Cancel":
		h = handleCancel
	default:
		err = fmt.Errorf("No such handler %s", ksh)
	}
	return
}

func NewKeymap() Keymap {
	return Keymap{
		termbox.KeyEsc:        handleCancel,
		termbox.KeyEnter:      handleFinish,
		termbox.KeyArrowUp:    handleSelectPrevious,
		termbox.KeyCtrlK:      handleSelectPrevious,
		termbox.KeyArrowDown:  handleSelectNext,
		termbox.KeyCtrlJ:      handleSelectNext,
		termbox.KeyArrowLeft:  handleSelectPreviousPage,
		termbox.KeyArrowRight: handleSelectNextPage,
		termbox.KeyBackspace:  handleDeleteBackwardChar,
		termbox.KeyBackspace2: handleDeleteBackwardChar,
		termbox.KeyCtrlF:      handleForwardChar,
		termbox.KeyCtrlB:      handleBackwardChar,
	}
}

func (km Keymap) Handler(k termbox.Key) KeymapHandler {
	h, ok := km[k]
	if ok {
		return h
	}
	return handleAcceptChar
}

func (km Keymap) UnmarshalJSON(buf []byte) error {
	raw := map[string]string{}
	if err := json.Unmarshal(buf, &raw); err != nil {
		return err
	}

	for ks, vs := range raw {
		k, err := KeymapStringKey(ks).ToKey()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unknown key %s", ks)
			continue
		}

		v, err := KeymapStringHandler(vs).ToHandler()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unknown handler %s", vs)
			continue
		}

		km[k] = v
	}

	return nil
}
<commit_msg>Make sure to execute the new query after KillEndOfLine<commit_after>package peco

import (
	"encoding/json"
	"fmt"
	"os"
	"unicode"

	"github.com/nsf/termbox-go"
)

type KeymapHandler func(*Input, termbox.Event)
type Keymap map[termbox.Key]KeymapHandler
type KeymapStringKey string
type KeymapStringHandler string

// This map is populated using some magic numbers, which must match
// the values defined in termbox-go. Verification against the actual
// termbox constants are done in the test
var stringToKey = map[string]termbox.Key{}

func init() {
	fidx := 12
	for k := termbox.KeyF1; k > termbox.KeyF12; k-- {
		sk := fmt.Sprintf("F%d", fidx)
		stringToKey[sk] = k
		fidx--
	}

	names := []string{
		"Insert",
		"Delete",
		"Home",
		"End",
		"Pgup",
		"Pgdn",
		"ArrowUp",
		"ArrowDown",
		"ArrowLeft",
		"ArrowRight",
	}
	for i, n := range names {
		stringToKey[n] = termbox.Key(int(termbox.KeyF12) - (i + 1))
	}

	names = []string{
		"Left",
		"Middle",
		"Right",
	}
	for i, n := range names {
		sk := fmt.Sprintf("Mouse%s", n)
		stringToKey[sk] = termbox.Key(int(termbox.KeyArrowRight) - (i + 2))
	}

	whacky := [][]string{
		{"~", "2", "Space"},
		{"a"},
		{"b"},
		{"c"},
		{"d"},
		{"e"},
		{"f"},
		{"g"},
		{"h"},
		{"i"},
		{"j"},
		{"k"},
		{"l"},
		{"m"},
		{"n"},
		{"o"},
		{"p"},
		{"q"},
		{"r"},
		{"s"},
		{"t"},
		{"u"},
		{"v"},
		{"w"},
		{"x"},
		{"y"},
		{"z"},
		{"[", "3"},
		{"4", "\\"},
		{"5", "]"},
		{"6"},
		{"7", "/", "_"},
	}
	for i, list := range whacky {
		for _, n := range list {
			sk := fmt.Sprintf("C-%s", n)
			stringToKey[sk] = termbox.Key(int(termbox.KeyCtrlTilde) + i)
		}
	}

	stringToKey["BS"] = termbox.KeyBackspace
	stringToKey["Tab"] = termbox.KeyTab
	stringToKey["Enter"] = termbox.KeyEnter
	stringToKey["Esc"] = termbox.KeyEsc
	stringToKey["Space"] = termbox.KeySpace
	stringToKey["BS2"] = termbox.KeyBackspace2
	stringToKey["C-8"] = termbox.KeyCtrl8

	//	panic(fmt.Sprintf("%#q", stringToKey))
}

func handleAcceptChar(i *Input, ev termbox.Event) {
	if ev.Key == termbox.KeySpace {
		ev.Ch = ' '
	}

	if ev.Ch > 0 {
		if len(i.query) == i.caretPos {
			i.query = append(i.query, ev.Ch)
		} else {
			buf := make([]rune, len(i.query)+1)
			copy(buf, i.query[:i.caretPos])
			buf[i.caretPos] = ev.Ch
			copy(buf[i.caretPos+1:], i.query[i.caretPos:])
			i.query = buf
		}
		i.caretPos++
		i.ExecQuery(string(i.query))
	}
}

// peco.Finish -> end program, exit with success
func handleFinish(i *Input, _ termbox.Event) {
	if len(i.current) == 1 {
		i.result = i.current[0].line
	} else if i.selectedLine > 0 && i.selectedLine < len(i.current) {
		i.result = i.current[i.selectedLine-1].line
	}
	i.Finish()
}

// peco.Cancel -> end program, exit with failure
func handleCancel(i *Input, ev termbox.Event) {
	i.ExitStatus = 1
	i.Finish()
}

func handleSelectPrevious(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToPrevLine
	i.DrawMatches(nil)
}

func handleSelectNext(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToNextLine
	i.DrawMatches(nil)
}

func handleSelectPreviousPage(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToPrevPage
	i.DrawMatches(nil)
}

func handleSelectNextPage(i *Input, ev termbox.Event) {
	i.PagingCh() <- ToNextPage
	i.DrawMatches(nil)
}

func handleForwardWord(i *Input, _ termbox.Event) {
	if i.caretPos >= len(i.query) {
		return
	}

	foundSpace := false
	for pos := i.caretPos; pos < len(i.query); pos++ {
		r := i.query[pos]
		if foundSpace {
			if !unicode.IsSpace(r) {
				i.caretPos = pos
				i.DrawMatches(nil)
				return
			}
		} else {
			if unicode.IsSpace(r) {
				foundSpace = true
			}
		}
	}

	// not found. just move to the end of the buffer
	i.caretPos = len(i.query)
	i.DrawMatches(nil)

}

func handleBackwardWord(i *Input, _ termbox.Event) {
	if i.caretPos == 0 {
		return
	}

	if i.caretPos >= len(i.query) {
		i.caretPos--
	}

	// if we start from a whitespace-ish position, we should
	// rewind to the end of the previous word, and then do the
	// search all over again
SEARCH_PREV_WORD:
	if unicode.IsSpace(i.query[i.caretPos]) {
		for pos := i.caretPos; pos > 0; pos-- {
			if !unicode.IsSpace(i.query[pos]) {
				i.caretPos = pos
				break
			}
		}
	}

	// if we start from the first character of a word, we
	// should attempt to move back and search for the previous word
	if i.caretPos > 0 && unicode.IsSpace(i.query[i.caretPos-1]) {
		i.caretPos--
		goto SEARCH_PREV_WORD
	}

	// Now look for a space
	for pos := i.caretPos; pos > 0; pos-- {
		if unicode.IsSpace(i.query[pos]) {
			i.caretPos = pos + 1
			i.DrawMatches(nil)
			return
		}
	}

	// not found. just move to the beginning of the buffer
	i.caretPos = 0
	i.DrawMatches(nil)
}

func handleForwardChar(i *Input, _ termbox.Event) {
	if i.caretPos >= len(i.query) {
		return
	}
	i.caretPos++
	i.DrawMatches(nil)
}

func handleBackwardChar(i *Input, _ termbox.Event) {
	if i.caretPos <= 0 {
		return
	}
	i.caretPos--
	i.DrawMatches(nil)
}

func handleBeginningOfLine(i *Input, _ termbox.Event) {
	i.caretPos = 0
	i.DrawMatches(nil)
}

func handleEndOfLine(i *Input, _ termbox.Event) {
	i.caretPos = len(i.query)
	i.DrawMatches(nil)
}

func handleKillEndOfLine(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	i.query = i.query[0:i.caretPos]
	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}
	i.DrawMatches(nil)
}

func handleDeleteForwardChar(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	buf := make([]rune, len(i.query)-1)
	copy(buf, i.query[:i.caretPos])
	copy(buf[i.caretPos:], i.query[i.caretPos+1:])
	i.query = buf
	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteBackwardChar(i *Input, ev termbox.Event) {
	if len(i.query) <= 0 {
		return
	}

	switch i.caretPos {
	case 0:
		// No op
		return
	case len(i.query):
		i.query = i.query[:len(i.query)-1]
	default:
		buf := make([]rune, len(i.query)-1)
		copy(buf, i.query[:i.caretPos])
		copy(buf[i.caretPos-1:], i.query[i.caretPos:])
		i.query = buf
	}
	i.caretPos--
	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteForwardWord(i *Input, _ termbox.Event) {
	if len(i.query) <= i.caretPos {
		return
	}

	for pos := i.caretPos; pos < len(i.query); pos++ {
		if pos == len(i.query)-1 {
			i.query = i.query[:i.caretPos]
			break
		}

		if unicode.IsSpace(i.query[pos]) {
			buf := make([]rune, len(i.query)-(pos-i.caretPos))
			copy(buf, i.query[:i.caretPos])
			copy(buf[i.caretPos:], i.query[pos:])
			i.query = buf
			break
		}
	}

	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func handleDeleteBackwardWord(i *Input, _ termbox.Event) {
	if i.caretPos == 0 {
		return
	}

	for pos := i.caretPos - 1; pos >= 0; pos-- {
		if pos == 0 {
			i.query = i.query[i.caretPos:]
			break
		}

		if unicode.IsSpace(i.query[pos]) {
			buf := make([]rune, len(i.query)-(i.caretPos-pos))
			copy(buf, i.query[:pos])
			copy(buf[pos:], i.query[i.caretPos:])
			i.query = buf
			i.caretPos = pos
			break
		}
	}

	if len(i.query) > 0 {
		i.ExecQuery(string(i.query))
		return
	}

	i.current = nil
	i.DrawMatches(nil)
}

func (ksk KeymapStringKey) ToKey() (k termbox.Key, err error) {
	k, ok := stringToKey[string(ksk)]
	if !ok {
		err = fmt.Errorf("No such key %s", ksk)
	}
	return
}

func (ksh KeymapStringHandler) ToHandler() (h KeymapHandler, err error) {
	switch ksh {
	case "peco.KillEndOfLine":
		h = handleKillEndOfLine
	case "peco.BeginningOfLine":
		h = handleBeginningOfLine
	case "peco.EndOfLine":
		h = handleEndOfLine
	case "peco.ForwardChar":
		h = handleForwardChar
	case "peco.BackwardChar":
		h = handleBackwardChar
	case "peco.ForwardWord":
		h = handleForwardWord
	case "peco.BackwardWord":
		h = handleBackwardWord
	case "peco.DeleteForwardChar":
		h = handleDeleteForwardChar
	case "peco.DeleteBackwardChar":
		h = handleDeleteBackwardChar
	case "peco.DeleteForwardWord":
		h = handleDeleteForwardWord
	case "peco.DeleteBackwardWord":
		h = handleDeleteBackwardWord
	case "peco.SelectPreviousPage":
		h = handleSelectPreviousPage
	case "peco.SelectNextPage":
		h = handleSelectNextPage
	case "peco.SelectPrevious":
		h = handleSelectPrevious
	case "peco.SelectNext":
		h = handleSelectNext
	case "peco.Finish":
		h = handleFinish
	case "peco.Cancel":
		h = handleCancel
	default:
		err = fmt.Errorf("No such handler %s", ksh)
	}
	return
}

func NewKeymap() Keymap {
	return Keymap{
		termbox.KeyEsc:        handleCancel,
		termbox.KeyEnter:      handleFinish,
		termbox.KeyArrowUp:    handleSelectPrevious,
		termbox.KeyCtrlK:      handleSelectPrevious,
		termbox.KeyArrowDown:  handleSelectNext,
		termbox.KeyCtrlJ:      handleSelectNext,
		termbox.KeyArrowLeft:  handleSelectPreviousPage,
		termbox.KeyArrowRight: handleSelectNextPage,
		termbox.KeyBackspace:  handleDeleteBackwardChar,
		termbox.KeyBackspace2: handleDeleteBackwardChar,
		termbox.KeyCtrlF:      handleForwardChar,
		termbox.KeyCtrlB:      handleBackwardChar,
	}
}

func (km Keymap) Handler(k termbox.Key) KeymapHandler {
	h, ok := km[k]
	if ok {
		return h
	}
	return handleAcceptChar
}

func (km Keymap) UnmarshalJSON(buf []byte) error {
	raw := map[string]string{}
	if err := json.Unmarshal(buf, &raw); err != nil {
		return err
	}

	for ks, vs := range raw {
		k, err := KeymapStringKey(ks).ToKey()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unknown key %s", ks)
			continue
		}

		v, err := KeymapStringHandler(vs).ToHandler()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unknown handler %s", vs)
			continue
		}

		km[k] = v
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/signal"
	"path"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cblomart/vsphere-graphite/backend"
	"github.com/cblomart/vsphere-graphite/config"
	"github.com/cblomart/vsphere-graphite/vsphere"

	"github.com/takama/daemon"

	"github.com/vmware/govmomi/vim25/types"
)

const (
	// name of the service
	name        = "vsphere-graphite"
	description = "send vsphere stats to graphite"
)

var dependencies = []string{}

var stdlog, errlog *log.Logger

// Service has embedded daemon
type Service struct {
	daemon.Daemon
}

// Informations to query about an entity
type EntityQuery struct {
	Name    string
	Entity  types.ManagedObjectReference
	Metrics []int
}

func queryVCenter(vcenter vsphere.VCenter, config config.Configuration, channel *chan []backend.Point) {
	vcenter.Query(config.Interval, config.Domain, channel)
}

// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {

	usage := "Usage: vsphere-graphite install | remove | start | stop | status"

	// if received any kind of command, do it
	if len(os.Args) > 1 {
		command := os.Args[1]
		switch command {
		case "install":
			return service.Install()
		case "remove":
			return service.Remove()
		case "start":
			return service.Start()
		case "stop":
			return service.Stop()
		case "status":
			return service.Status()
		default:
			return usage, nil
		}
	}

	stdlog.Println("Starting daemon:", path.Base(os.Args[0]))

	// read the configuration
	file, err := os.Open("/etc/" + path.Base(os.Args[0]) + ".json")
	if err != nil {
		return "Could not open configuration file", err
	}
	jsondec := json.NewDecoder(file)
	config := config.Configuration{}
	err = jsondec.Decode(&config)
	if err != nil {
		return "Could not decode configuration file", err
	}

	//force backend values to environement varialbles if present
	s := reflect.ValueOf(&config.Backend).Elem()
	numfields := s.NumField()
	for i := 0; i < numfields; i++ {
		f := s.Field(i)
		if f.CanSet() {
			//exported field
			envname := strings.ToUpper(s.Type().Name() + "_" + s.Type().Field(i).Name)
			envval := os.Getenv(envname)
			if len(envval) > 0 {
				//environment variable set with name
				switch ftype := f.Type().Name(); ftype {
				case "string":
					f.SetString(envval)
				case "int":
					val, err := strconv.ParseInt(envval, 10, 64)
					if err == nil {
						f.SetInt(val)
					}
				}
			}
		}
	}

	for _, vcenter := range config.VCenters {
		vcenter.Init(config.Metrics, stdlog, errlog)
	}

	err = config.Backend.Init(stdlog, errlog)
	if err != nil {
		return "Could not initialize backend", err
	}
	defer config.Backend.Disconnect()

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	// Set up a channel to recieve the metrics
	metrics := make(chan []backend.Point)

	// Set up a ticker to collect metrics at givent interval
	ticker := time.NewTicker(time.Second * time.Duration(config.Interval))
	defer ticker.Stop()

	// Start retriveing and sending metrics
	stdlog.Println("Retrieving metrics")
	for _, vcenter := range config.VCenters {
		go queryVCenter(*vcenter, config, &metrics)
	}
	for {
		select {
		case values := <-metrics:
			config.Backend.SendMetrics(values)
			stdlog.Printf("Sent %d logs to backend", len(values))
		case <-ticker.C:
			stdlog.Println("Retrieving metrics")
			for _, vcenter := range config.VCenters {
				go queryVCenter(*vcenter, config, &metrics)
			}
		case killSignal := <-interrupt:
			stdlog.Println("Got signal:", killSignal)
			if killSignal == os.Interrupt {
				return "Daemon was interruped by system signal", nil
			}
			return "Daemon was killed", nil
		}
	}
}

func init() {
	stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
	errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
}

func main() {
	srv, err := daemon.New(name, description, dependencies...)
	if err != nil {
		errlog.Println("Error: ", err)
		os.Exit(1)
	}
	service := &Service{srv}
	status, err := service.Manage()
	if err != nil {
		errlog.Println(status, "\nError: ", err)
		os.Exit(1)
	}
	fmt.Println(status)
}
<commit_msg>misspell corrections<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/signal"
	"path"
	"reflect"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/cblomart/vsphere-graphite/backend"
	"github.com/cblomart/vsphere-graphite/config"
	"github.com/cblomart/vsphere-graphite/vsphere"

	"github.com/takama/daemon"

	"github.com/vmware/govmomi/vim25/types"
)

const (
	// name of the service
	name        = "vsphere-graphite"
	description = "send vsphere stats to graphite"
)

var dependencies = []string{}

var stdlog, errlog *log.Logger

// Service has embedded daemon
type Service struct {
	daemon.Daemon
}

// Informations to query about an entity
type EntityQuery struct {
	Name    string
	Entity  types.ManagedObjectReference
	Metrics []int
}

func queryVCenter(vcenter vsphere.VCenter, config config.Configuration, channel *chan []backend.Point) {
	vcenter.Query(config.Interval, config.Domain, channel)
}

// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {

	usage := "Usage: vsphere-graphite install | remove | start | stop | status"

	// if received any kind of command, do it
	if len(os.Args) > 1 {
		command := os.Args[1]
		switch command {
		case "install":
			return service.Install()
		case "remove":
			return service.Remove()
		case "start":
			return service.Start()
		case "stop":
			return service.Stop()
		case "status":
			return service.Status()
		default:
			return usage, nil
		}
	}

	stdlog.Println("Starting daemon:", path.Base(os.Args[0]))

	// read the configuration
	file, err := os.Open("/etc/" + path.Base(os.Args[0]) + ".json")
	if err != nil {
		return "Could not open configuration file", err
	}
	jsondec := json.NewDecoder(file)
	config := config.Configuration{}
	err = jsondec.Decode(&config)
	if err != nil {
		return "Could not decode configuration file", err
	}

	//force backend values to environement varialbles if present
	s := reflect.ValueOf(&config.Backend).Elem()
	numfields := s.NumField()
	for i := 0; i < numfields; i++ {
		f := s.Field(i)
		if f.CanSet() {
			//exported field
			envname := strings.ToUpper(s.Type().Name() + "_" + s.Type().Field(i).Name)
			envval := os.Getenv(envname)
			if len(envval) > 0 {
				//environment variable set with name
				switch ftype := f.Type().Name(); ftype {
				case "string":
					f.SetString(envval)
				case "int":
					val, err := strconv.ParseInt(envval, 10, 64)
					if err == nil {
						f.SetInt(val)
					}
				}
			}
		}
	}

	for _, vcenter := range config.VCenters {
		vcenter.Init(config.Metrics, stdlog, errlog)
	}

	err = config.Backend.Init(stdlog, errlog)
	if err != nil {
		return "Could not initialize backend", err
	}
	defer config.Backend.Disconnect()

	// Set up channel on which to send signal notifications.
	// We must use a buffered channel or risk missing the signal
	// if we're not ready to receive when the signal is sent.
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	// Set up a channel to receive the metrics
	metrics := make(chan []backend.Point)

	// Set up a ticker to collect metrics at givent interval
	ticker := time.NewTicker(time.Second * time.Duration(config.Interval))
	defer ticker.Stop()

	// Start retriveing and sending metrics
	stdlog.Println("Retrieving metrics")
	for _, vcenter := range config.VCenters {
		go queryVCenter(*vcenter, config, &metrics)
	}
	for {
		select {
		case values := <-metrics:
			config.Backend.SendMetrics(values)
			stdlog.Printf("Sent %d logs to backend", len(values))
		case <-ticker.C:
			stdlog.Println("Retrieving metrics")
			for _, vcenter := range config.VCenters {
				go queryVCenter(*vcenter, config, &metrics)
			}
		case killSignal := <-interrupt:
			stdlog.Println("Got signal:", killSignal)
			if killSignal == os.Interrupt {
				return "Daemon was interrupted by system signal", nil
			}
			return "Daemon was killed", nil
		}
	}
}

func init() {
	stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
	errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
}

func main() {
	srv, err := daemon.New(name, description, dependencies...)
	if err != nil {
		errlog.Println("Error: ", err)
		os.Exit(1)
	}
	service := &Service{srv}
	status, err := service.Manage()
	if err != nil {
		errlog.Println(status, "\nError: ", err)
		os.Exit(1)
	}
	fmt.Println(status)
}
<|endoftext|>