<commit_before>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import (
	"fmt"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

type (
	PlatformType uint

	// GPIOPin is the logical GPIO pin
	GPIOPin uint8

	// GPIOState is the GPIO Pin state
	GPIOState uint8

	// GPIOMode is the GPIO Pin mode
	GPIOMode uint8

	// GPIOPull is the GPIO Pin resistor configuration (pull up/down or floating)
	GPIOPull uint8

	// GPIOEdge is a rising or falling edge
	GPIOEdge uint8

	// SPIMode is the SPI Mode
	SPIMode uint8

	// LIRCMode is the LIRC Mode
	LIRCMode uint32

	// LIRCType is the LIRC Type
	LIRCType uint32
)

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

type Platform interface {

	// Product returns product name
	Product() string

	// Type returns flags identifying platform type
	Type() PlatformType

	// SerialNumber returns unique serial number for host
	SerialNumber() string

	// Uptime returns uptime for host
	Uptime() time.Duration

	// LoadAverages returns 1, 5 and 15 minute load averages
	LoadAverages() (float64, float64, float64)

	// NumberOfDisplays returns the number of possible displays for this host
	NumberOfDisplays() uint

	// Implements gopi.Unit
	Unit
}

// Display implements a pixel-based display device. Displays are always numbered
// from zero onwards
type Display interface {
	// Return display number
	DisplayId() uint

	// Return name of the display
	Name() string

	// Return display size for nominated display number, or (0,0) if display does not exist
	Size() (uint32, uint32)

	// Return the PPI (pixels-per-inch) for the display, or return zero if unknown
	PixelsPerInch() uint32

	// Implements gopi.Unit
	Unit
}

// GPIO implements the GPIO interface for simple input and output
type GPIO interface {
	// Return number of physical pins, or 0 if if cannot be returned
	// or nothing is known about physical pins
	NumberOfPhysicalPins() uint

	// Return array of available logical pins or nil if nothing is
	// known about pins
	Pins() []GPIOPin

	// Return logical pin for physical pin number. Returns
	// GPIO_PIN_NONE where there is no logical pin at that position
	// or we don't now about the physical pins
	PhysicalPin(uint) GPIOPin

	// Return physical pin number for logical pin. Returns 0 where there
	// is no physical pin for this logical pin, or we don't know anything
	// about the layout
	PhysicalPinForPin(GPIOPin) uint

	// Read pin state
	ReadPin(GPIOPin) GPIOState

	// Write pin state
	WritePin(GPIOPin, GPIOState)

	// Get pin mode
	GetPinMode(GPIOPin) GPIOMode

	// Set pin mode
	SetPinMode(GPIOPin, GPIOMode)

	// Set pull mode to pull down or pull up - will
	// return ErrNotImplemented if not supported
	SetPullMode(GPIOPin, GPIOPull) error

	// Start watching for rising and/or falling edge,
	// or stop watching when GPIO_EDGE_NONE is passed.
	// Will return ErrNotImplemented if not supported
	Watch(GPIOPin, GPIOEdge) error

	// Implements gopi.Unit
	Unit
}

// I2C implements the I2C interface for sensors, etc.
type I2C interface {

	// Set current slave address
	SetSlave(uint8) error

	// Get current slave address
	GetSlave() uint8

	// Return true if a slave was detected at a particular address
	DetectSlave(uint8) (bool, error)

	// Read Byte (8-bits), Word (16-bits) & Block ([]byte) from registers
	ReadUint8(reg uint8) (uint8, error)
	ReadInt8(reg uint8) (int8, error)
	ReadUint16(reg uint8) (uint16, error)
	ReadInt16(reg uint8) (int16, error)
	ReadBlock(reg, length uint8) ([]byte, error)

	// Write Byte (8-bits) & Word (16-bits) to registers
	WriteUint8(reg, value uint8) error
	WriteInt8(reg uint8, value int8) error
	WriteUint16(reg uint8, value uint16) error
	WriteInt16(reg uint8, value int16) error

	// Implements gopi.Unit
	Unit
}

// SPI implements the SPI interface for sensors, etc.
type SPI interface {
	// Get SPI mode
	Mode() SPIMode
	// Get SPI speed
	MaxSpeedHz() uint32
	// Get Bits Per Word
	BitsPerWord() uint8
	// Set SPI mode
	SetMode(SPIMode) error
	// Set SPI speed
	SetMaxSpeedHz(uint32) error
	// Set Bits Per Word
	SetBitsPerWord(uint8) error

	// Read/Write
	Transfer(send []byte) ([]byte, error)

	// Read
	Read(len uint32) ([]byte, error)

	// Write
	Write(send []byte) error

	// Implements gopi.Unit
	Unit
}

// PWM implements the PWM interface for actuators, motors, etc.
type PWM interface {
	// Return array of pins which are enabled for PWM
	Pins() []GPIOPin

	// Period
	Period(GPIOPin) (time.Duration, error)
	SetPeriod(time.Duration, ...GPIOPin) error

	// Duty Cycle between 0.0 and 1.0 (0.0 is always off, 1.0 is always on)
	DutyCycle(GPIOPin) (float32, error)
	SetDutyCycle(float32, ...GPIOPin) error

	// Implements gopi.Unit
	Unit
}

// LIRC implements the IR send & receive interface
type LIRC interface {
	// Get receive and send modes
	RcvMode() LIRCMode
	SendMode() LIRCMode
	SetRcvMode(mode LIRCMode) error
	SetSendMode(mode LIRCMode) error

	// Receive parameters
	RcvDutyCycle() uint32
	RcvResolutionMicros() uint32

	// Receive parameters
	SetRcvTimeout(micros uint32) error
	SetRcvTimeoutReports(enable bool) error
	SetRcvCarrierHz(value uint32) error
	SetRcvCarrierRangeHz(min uint32, max uint32) error

	// Send parameters
	SendDutyCycle() uint32
	SetSendCarrierHz(value uint32) error
	SetSendDutyCycle(value uint32) error

	// Send Pulse Mode, values are in milliseconds
	PulseSend(values []uint32) error

	// Implements gopi.Unit
	Unit
}

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	PLATFORM_NONE   PlatformType = 0
	PLATFORM_DARWIN PlatformType = (1 << iota) >> 1
	PLATFORM_RPI
	PLATFORM_LINUX
	PLATFORM_MIN = PLATFORM_DARWIN
	PLATFORM_MAX = PLATFORM_LINUX
)

const (
	// Invalid pin constant
	GPIO_PIN_NONE GPIOPin = 0xFF
)

const (
	GPIO_LOW GPIOState = iota
	GPIO_HIGH
)

const (
	// Set pin mode and/or function
	GPIO_INPUT GPIOMode = iota
	GPIO_OUTPUT
	GPIO_ALT5
	GPIO_ALT4
	GPIO_ALT0
	GPIO_ALT1
	GPIO_ALT2
	GPIO_ALT3
	GPIO_NONE
)

const (
	GPIO_PULL_OFF GPIOPull = iota
	GPIO_PULL_DOWN
	GPIO_PULL_UP
)

const (
	GPIO_EDGE_NONE GPIOEdge = iota
	GPIO_EDGE_RISING
	GPIO_EDGE_FALLING
	GPIO_EDGE_BOTH
)

const (
	SPI_MODE_CPHA SPIMode = 0x01
	SPI_MODE_CPOL SPIMode = 0x02
	SPI_MODE_0    SPIMode = 0x00
	SPI_MODE_1    SPIMode = (0x00 | SPI_MODE_CPHA)
	SPI_MODE_2    SPIMode = (SPI_MODE_CPOL | 0x00)
	SPI_MODE_3    SPIMode = (SPI_MODE_CPOL | SPI_MODE_CPHA)
	SPI_MODE_NONE SPIMode = 0xFF
)

const (
	LIRC_MODE_NONE     LIRCMode = 0x00000000
	LIRC_MODE_RAW      LIRCMode = 0x00000001
	LIRC_MODE_PULSE    LIRCMode = 0x00000002 // send only
	LIRC_MODE_MODE2    LIRCMode = 0x00000004 // rcv only
	LIRC_MODE_LIRCCODE LIRCMode = 0x00000010 // rcv only
	LIRC_MODE_MAX      LIRCMode = LIRC_MODE_LIRCCODE
)

const (
	LIRC_TYPE_SPACE     LIRCType = 0x00000000
	LIRC_TYPE_PULSE     LIRCType = 0x01000000
	LIRC_TYPE_FREQUENCY LIRCType = 0x02000000
	LIRC_TYPE_TIMEOUT   LIRCType = 0x03000000
	LIRC_TYPE_MAX       LIRCType = LIRC_TYPE_TIMEOUT
)

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (p PlatformType) String() string {
	str := ""
	if p == 0 {
		return p.FlagString()
	}
	for v := PLATFORM_MIN; v <= PLATFORM_MAX; v <<= 1 {
		if p&v == v {
			str += "|" + v.FlagString()
		}
	}
	return strings.TrimPrefix(str, "|")
}

func (p PlatformType) FlagString() string {
	switch p {
	case PLATFORM_NONE:
		return "PLATFORM_NONE"
	case PLATFORM_DARWIN:
		return "PLATFORM_DARWIN"
	case PLATFORM_RPI:
		return "PLATFORM_RPI"
	case PLATFORM_LINUX:
		return "PLATFORM_LINUX"
	default:
		return "[?? Invalid PlatformType value]"
	}
}

func (p GPIOPin) String() string {
	return fmt.Sprintf("GPIO%v", uint8(p))
}

func (s GPIOState) String() string {
	switch s {
	case GPIO_LOW:
		return "GPIO_LOW"
	case GPIO_HIGH:
		return "GPIO_HIGH"
	default:
		return "[??? Invalid GPIOState value]"
	}
}

func (m GPIOMode) String() string {
	switch m {
	case GPIO_INPUT:
		return "GPIO_INPUT"
	case GPIO_OUTPUT:
		return "GPIO_OUTPUT"
	case GPIO_ALT0:
		return "GPIO_ALT0"
	case GPIO_ALT1:
		return "GPIO_ALT1"
	case GPIO_ALT2:
		return "GPIO_ALT2"
	case GPIO_ALT3:
		return "GPIO_ALT3"
	case GPIO_ALT4:
		return "GPIO_ALT4"
	case GPIO_ALT5:
		return "GPIO_ALT5"
	case GPIO_NONE:
		return "GPIO_NONE"
	default:
		return "[??? Invalid GPIOMode value]"
	}
}

func (p GPIOPull) String() string {
	switch p {
	case GPIO_PULL_OFF:
		return "GPIO_PULL_OFF"
	case GPIO_PULL_DOWN:
		return "GPIO_PULL_DOWN"
	case GPIO_PULL_UP:
		return "GPIO_PULL_UP"
	default:
		return "[??? Invalid GPIOPull value]"
	}
}

func (e GPIOEdge) String() string {
	switch e {
	case GPIO_EDGE_NONE:
		return "GPIO_EDGE_NONE"
	case GPIO_EDGE_RISING:
		return "GPIO_EDGE_RISING"
	case GPIO_EDGE_FALLING:
		return "GPIO_EDGE_FALLING"
	case GPIO_EDGE_BOTH:
		return "GPIO_EDGE_BOTH"
	default:
		return "[??? Invalid GPIOEdge value]"
	}
}

func (m SPIMode) String() string {
	switch m {
	case SPI_MODE_0:
		return "SPI_MODE_0"
	case SPI_MODE_1:
		return "SPI_MODE_1"
	case SPI_MODE_2:
		return "SPI_MODE_2"
	case SPI_MODE_3:
		return "SPI_MODE_3"
	default:
		return "[?? Invalid SPIMode]"
	}
}

func (m LIRCMode) String() string {
	switch m {
	case LIRC_MODE_NONE:
		return "LIRC_MODE_NONE"
	case LIRC_MODE_RAW:
		return "LIRC_MODE_RAW"
	case LIRC_MODE_PULSE:
		return "LIRC_MODE_PULSE"
	case LIRC_MODE_MODE2:
		return "LIRC_MODE_MODE2"
	case LIRC_MODE_LIRCCODE:
		return "LIRC_MODE_LIRCCODE"
	default:
		return "[?? Invalid LIRCMode value]"
	}
}

func (t LIRCType) String() string {
	switch t {
	case LIRC_TYPE_SPACE:
		return "LIRC_TYPE_SPACE"
	case LIRC_TYPE_PULSE:
		return "LIRC_TYPE_PULSE"
	case LIRC_TYPE_FREQUENCY:
		return "LIRC_TYPE_FREQUENCY"
	case LIRC_TYPE_TIMEOUT:
		return "LIRC_TYPE_TIMEOUT"
	default:
		return "[?? Invalid LIRCType value]"
	}
}
<commit_msg>udpated to include cpi<commit_after>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package gopi

import (
	"fmt"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

type (
	PlatformType uint32

	// GPIOPin is the logical GPIO pin
	GPIOPin uint8

	// GPIOState is the GPIO Pin state
	GPIOState uint8

	// GPIOMode is the GPIO Pin mode
	GPIOMode uint8

	// GPIOPull is the GPIO Pin resistor configuration (pull up/down or floating)
	GPIOPull uint8

	// GPIOEdge is a rising or falling edge
	GPIOEdge uint8

	// SPIMode is the SPI Mode
	SPIMode uint8

	// LIRCMode is the LIRC Mode
	LIRCMode uint32

	// LIRCType is the LIRC Type
	LIRCType uint32
)

////////////////////////////////////////////////////////////////////////////////
// INTERFACES

type Platform interface {

	// Product returns product name
	Product() string

	// Type returns flags identifying platform type
	Type() PlatformType

	// SerialNumber returns unique serial number for host
	SerialNumber() string

	// Uptime returns uptime for host
	Uptime() time.Duration

	// LoadAverages returns 1, 5 and 15 minute load averages
	LoadAverages() (float64, float64, float64)

	// NumberOfDisplays returns the number of possible displays for this host
	NumberOfDisplays() uint

	// Implements gopi.Unit
	Unit
}

// Display implements a pixel-based display device. Displays are always numbered
// from zero onwards
type Display interface {
	// Return display number
	DisplayId() uint

	// Return name of the display
	Name() string

	// Return display size for nominated display number, or (0,0) if display does not exist
	Size() (uint32, uint32)

	// Return the PPI (pixels-per-inch) for the display, or return zero if unknown
	PixelsPerInch() uint32

	// Implements gopi.Unit
	Unit
}

// GPIO implements the GPIO interface for simple input and output
type GPIO interface {
	// Return number of physical pins, or 0 if if cannot be returned
	// or nothing is known about physical pins
	NumberOfPhysicalPins() uint

	// Return array of available logical pins or nil if nothing is
	// known about pins
	Pins() []GPIOPin

	// Return logical pin for physical pin number. Returns
	// GPIO_PIN_NONE where there is no logical pin at that position
	// or we don't now about the physical pins
	PhysicalPin(uint) GPIOPin

	// Return physical pin number for logical pin. Returns 0 where there
	// is no physical pin for this logical pin, or we don't know anything
	// about the layout
	PhysicalPinForPin(GPIOPin) uint

	// Read pin state
	ReadPin(GPIOPin) GPIOState

	// Write pin state
	WritePin(GPIOPin, GPIOState)

	// Get pin mode
	GetPinMode(GPIOPin) GPIOMode

	// Set pin mode
	SetPinMode(GPIOPin, GPIOMode)

	// Set pull mode to pull down or pull up - will
	// return ErrNotImplemented if not supported
	SetPullMode(GPIOPin, GPIOPull) error

	// Start watching for rising and/or falling edge,
	// or stop watching when GPIO_EDGE_NONE is passed.
	// Will return ErrNotImplemented if not supported
	Watch(GPIOPin, GPIOEdge) error

	// Implements gopi.Unit
	Unit
}

// I2C implements the I2C interface for sensors, etc.
type I2C interface {

	// Set current slave address
	SetSlave(uint8) error

	// Get current slave address
	GetSlave() uint8

	// Return true if a slave was detected at a particular address
	DetectSlave(uint8) (bool, error)

	// Read Byte (8-bits), Word (16-bits) & Block ([]byte) from registers
	ReadUint8(reg uint8) (uint8, error)
	ReadInt8(reg uint8) (int8, error)
	ReadUint16(reg uint8) (uint16, error)
	ReadInt16(reg uint8) (int16, error)
	ReadBlock(reg, length uint8) ([]byte, error)

	// Write Byte (8-bits) & Word (16-bits) to registers
	WriteUint8(reg, value uint8) error
	WriteInt8(reg uint8, value int8) error
	WriteUint16(reg uint8, value uint16) error
	WriteInt16(reg uint8, value int16) error

	// Implements gopi.Unit
	Unit
}

// SPI implements the SPI interface for sensors, etc.
type SPI interface {
	// Get SPI mode
	Mode() SPIMode
	// Get SPI speed
	MaxSpeedHz() uint32
	// Get Bits Per Word
	BitsPerWord() uint8
	// Set SPI mode
	SetMode(SPIMode) error
	// Set SPI speed
	SetMaxSpeedHz(uint32) error
	// Set Bits Per Word
	SetBitsPerWord(uint8) error

	// Read/Write
	Transfer(send []byte) ([]byte, error)

	// Read
	Read(len uint32) ([]byte, error)

	// Write
	Write(send []byte) error

	// Implements gopi.Unit
	Unit
}

// PWM implements the PWM interface for actuators, motors, etc.
type PWM interface {
	// Return array of pins which are enabled for PWM
	Pins() []GPIOPin

	// Period
	Period(GPIOPin) (time.Duration, error)
	SetPeriod(time.Duration, ...GPIOPin) error

	// Duty Cycle between 0.0 and 1.0 (0.0 is always off, 1.0 is always on)
	DutyCycle(GPIOPin) (float32, error)
	SetDutyCycle(float32, ...GPIOPin) error

	// Implements gopi.Unit
	Unit
}

// LIRC implements the IR send & receive interface
type LIRC interface {
	// Get receive and send modes
	RcvMode() LIRCMode
	SendMode() LIRCMode
	SetRcvMode(mode LIRCMode) error
	SetSendMode(mode LIRCMode) error

	// Receive parameters
	RcvDutyCycle() uint32
	RcvResolutionMicros() uint32

	// Receive parameters
	SetRcvTimeout(micros uint32) error
	SetRcvTimeoutReports(enable bool) error
	SetRcvCarrierHz(value uint32) error
	SetRcvCarrierRangeHz(min uint32, max uint32) error

	// Send parameters
	SendDutyCycle() uint32
	SetSendCarrierHz(value uint32) error
	SetSendDutyCycle(value uint32) error

	// Send Pulse Mode, values are in milliseconds
	PulseSend(values []uint32) error

	// Implements gopi.Unit
	Unit
}

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
	PLATFORM_NONE PlatformType = 0
	// OS
	PLATFORM_DARWIN PlatformType = (1 << iota) >> 1
	PLATFORM_RPI
	PLATFORM_LINUX
	// CPU
	PLATFORM_X86_32
	PLATFORM_X86_64
	PLATFORM_BCM2835_ARM6
	PLATFORM_BCM2836_ARM7
	PLATFORM_BCM2837_ARM8
	PLATFORM_BCM2838_ARM8
	// MIN AND MAX
	PLATFORM_MIN = PLATFORM_DARWIN
	PLATFORM_MAX = PLATFORM_BCM2838_ARM8
)

const (
	// Invalid pin constant
	GPIO_PIN_NONE GPIOPin = 0xFF
)

const (
	GPIO_LOW GPIOState = iota
	GPIO_HIGH
)

const (
	// Set pin mode and/or function
	GPIO_INPUT GPIOMode = iota
	GPIO_OUTPUT
	GPIO_ALT5
	GPIO_ALT4
	GPIO_ALT0
	GPIO_ALT1
	GPIO_ALT2
	GPIO_ALT3
	GPIO_NONE
)

const (
	GPIO_PULL_OFF GPIOPull = iota
	GPIO_PULL_DOWN
	GPIO_PULL_UP
)

const (
	GPIO_EDGE_NONE GPIOEdge = iota
	GPIO_EDGE_RISING
	GPIO_EDGE_FALLING
	GPIO_EDGE_BOTH
)

const (
	SPI_MODE_CPHA SPIMode = 0x01
	SPI_MODE_CPOL SPIMode = 0x02
	SPI_MODE_0    SPIMode = 0x00
	SPI_MODE_1    SPIMode = (0x00 | SPI_MODE_CPHA)
	SPI_MODE_2    SPIMode = (SPI_MODE_CPOL | 0x00)
	SPI_MODE_3    SPIMode = (SPI_MODE_CPOL | SPI_MODE_CPHA)
	SPI_MODE_NONE SPIMode = 0xFF
)

const (
	LIRC_MODE_NONE     LIRCMode = 0x00000000
	LIRC_MODE_RAW      LIRCMode = 0x00000001
	LIRC_MODE_PULSE    LIRCMode = 0x00000002 // send only
	LIRC_MODE_MODE2    LIRCMode = 0x00000004 // rcv only
	LIRC_MODE_LIRCCODE LIRCMode = 0x00000010 // rcv only
	LIRC_MODE_MAX      LIRCMode = LIRC_MODE_LIRCCODE
)

const (
	LIRC_TYPE_SPACE     LIRCType = 0x00000000
	LIRC_TYPE_PULSE     LIRCType = 0x01000000
	LIRC_TYPE_FREQUENCY LIRCType = 0x02000000
	LIRC_TYPE_TIMEOUT   LIRCType = 0x03000000
	LIRC_TYPE_MAX       LIRCType = LIRC_TYPE_TIMEOUT
)

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (p PlatformType) String() string {
	str := ""
	if p == 0 {
		return p.FlagString()
	}
	for v := PLATFORM_MIN; v <= PLATFORM_MAX; v <<= 1 {
		if p&v == v {
			str += "|" + v.FlagString()
		}
	}
	return strings.TrimPrefix(str, "|")
}

func (p PlatformType) FlagString() string {
	switch p {
	case PLATFORM_NONE:
		return "PLATFORM_NONE"
	case PLATFORM_DARWIN:
		return "PLATFORM_DARWIN"
	case PLATFORM_RPI:
		return "PLATFORM_RPI"
	case PLATFORM_LINUX:
		return "PLATFORM_LINUX"
	case PLATFORM_X86_32:
		return "PLATFORM_X86_32"
	case PLATFORM_X86_64:
		return "PLATFORM_X86_64"
	case PLATFORM_BCM2835_ARM6:
		return "PLATFORM_BCM2835_ARM6"
	case PLATFORM_BCM2836_ARM7:
		return "PLATFORM_BCM2836_ARM7"
	case PLATFORM_BCM2837_ARM8:
		return "PLATFORM_BCM2837_ARM8"
	case PLATFORM_BCM2838_ARM8:
		return "PLATFORM_BCM2838_ARM8"
	default:
		return "[?? Invalid PlatformType value]"
	}
}

func (p GPIOPin) String() string {
	return fmt.Sprintf("GPIO%v", uint8(p))
}

func (s GPIOState) String() string {
	switch s {
	case GPIO_LOW:
		return "GPIO_LOW"
	case GPIO_HIGH:
		return "GPIO_HIGH"
	default:
		return "[??? Invalid GPIOState value]"
	}
}

func (m GPIOMode) String() string {
	switch m {
	case GPIO_INPUT:
		return "GPIO_INPUT"
	case GPIO_OUTPUT:
		return "GPIO_OUTPUT"
	case GPIO_ALT0:
		return "GPIO_ALT0"
	case GPIO_ALT1:
		return "GPIO_ALT1"
	case GPIO_ALT2:
		return "GPIO_ALT2"
	case GPIO_ALT3:
		return "GPIO_ALT3"
	case GPIO_ALT4:
		return "GPIO_ALT4"
	case GPIO_ALT5:
		return "GPIO_ALT5"
	case GPIO_NONE:
		return "GPIO_NONE"
	default:
		return "[??? Invalid GPIOMode value]"
	}
}

func (p GPIOPull) String() string {
	switch p {
	case GPIO_PULL_OFF:
		return "GPIO_PULL_OFF"
	case GPIO_PULL_DOWN:
		return "GPIO_PULL_DOWN"
	case GPIO_PULL_UP:
		return "GPIO_PULL_UP"
	default:
		return "[??? Invalid GPIOPull value]"
	}
}

func (e GPIOEdge) String() string {
	switch e {
	case GPIO_EDGE_NONE:
		return "GPIO_EDGE_NONE"
	case GPIO_EDGE_RISING:
		return "GPIO_EDGE_RISING"
	case GPIO_EDGE_FALLING:
		return "GPIO_EDGE_FALLING"
	case GPIO_EDGE_BOTH:
		return "GPIO_EDGE_BOTH"
	default:
		return "[??? Invalid GPIOEdge value]"
	}
}

func (m SPIMode) String() string {
	switch m {
	case SPI_MODE_0:
		return "SPI_MODE_0"
	case SPI_MODE_1:
		return "SPI_MODE_1"
	case SPI_MODE_2:
		return "SPI_MODE_2"
	case SPI_MODE_3:
		return "SPI_MODE_3"
	default:
		return "[?? Invalid SPIMode]"
	}
}

func (m LIRCMode) String() string {
	switch m {
	case LIRC_MODE_NONE:
		return "LIRC_MODE_NONE"
	case LIRC_MODE_RAW:
		return "LIRC_MODE_RAW"
	case LIRC_MODE_PULSE:
		return "LIRC_MODE_PULSE"
	case LIRC_MODE_MODE2:
		return "LIRC_MODE_MODE2"
	case LIRC_MODE_LIRCCODE:
		return "LIRC_MODE_LIRCCODE"
	default:
		return "[?? Invalid LIRCMode value]"
	}
}

func (t LIRCType) String() string {
	switch t {
	case LIRC_TYPE_SPACE:
		return "LIRC_TYPE_SPACE"
	case LIRC_TYPE_PULSE:
		return "LIRC_TYPE_PULSE"
	case LIRC_TYPE_FREQUENCY:
		return "LIRC_TYPE_FREQUENCY"
	case LIRC_TYPE_TIMEOUT:
		return "LIRC_TYPE_TIMEOUT"
	default:
		return "[?? Invalid LIRCType value]"
	}
}
<|endoftext|>


<commit_before>package c4

import (
	"bytes"
	"crypto/sha512"
	"math/big"
	"strconv"

	"hash"
)

// using the flickr character set which removes:
// ['=', '+', '_', '0', 'O', 'I', 'l'] from base64
// to reduce transcription errors, and make friendlier URLs
const (
	charset = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
	base    = 58
)

var (
	lut     [256]byte
	lowbyte = []byte("1")
	prefix  = []byte{'c', '4'}
	idlen   = len(`c41111111111111111111111111111111111111111111111111111111111111111111111111111111111111111`)
)

func init() {
	for i := 0; i < len(lut); i++ {
		lut[i] = 0xFF
	}
	for i := 0; i < len(charset); i++ {
		lut[charset[i]] = byte(i)
	}
}

type errBadChar int

func (e errBadChar) Error() string {
	return "non c4 character at position " + strconv.Itoa(int(e))
}

// ID represents a C4 Asset ID.
type ID big.Int

// ParseID parses a C4 ID string into an ID.
func ParseID(src string) (*ID, error) {
	return ParseBytesID([]byte(src))
}

// ParseBytesID parses a C4 ID as []byte into an ID.
func ParseBytesID(src []byte) (*ID, error) {
	bigNum := new(big.Int)
	bigBase := big.NewInt(base)
	for i := 2; i < len(src); i++ {
		b := lut[src[i]]
		if b == 0xFF {
			return nil, errBadChar(i)
		}
		bigNum.Mul(bigNum, bigBase)
		bigNum.Add(bigNum, big.NewInt(int64(b)))
	}
	id := ID(*bigNum)
	return &id, nil
}

func (id *ID) String() string {
	return string(id.Bytes())
}

// Bytes encodes the written bytes to C4 ID format.
func (id *ID) Bytes() []byte {
	bigNum := big.Int(*id)
	bigBase := big.NewInt(base)
	bigZero := big.NewInt(0)
	bigMod := new(big.Int)
	var encoded []byte
	for bigNum.Cmp(bigZero) > 0 {
		bigNum.DivMod(&bigNum, bigBase, bigMod)
		encoded = append([]byte{charset[bigMod.Int64()]}, encoded...)
	}
	// padding
	diff := idlen - 2 - len(encoded)
	encoded = append(bytes.Repeat(lowbyte, diff), encoded...)
	// c4... prefix
	encoded = append(prefix, encoded...)
	return encoded
}

// IDEncoder generates C4 Asset IDs.
type IDEncoder struct {
	h hash.Hash
}

// NewIDEncoder makes a new IDEncoder.
func NewIDEncoder() *IDEncoder {
	return &IDEncoder{
		h: sha512.New(),
	}
}

// Write writes bytes to the hash that makes up the ID.
func (e *IDEncoder) Write(b []byte) (int, error) {
	return e.h.Write(b)
}

// ID gets the ID for the written bytes.
func (e *IDEncoder) ID() *ID {
	b := new(big.Int)
	b.SetBytes(e.h.Sum(nil))
	id := ID(*b)
	return &id
}
<commit_msg>made id length clearer<commit_after>package c4

import (
	"bytes"
	"crypto/sha512"
	"math/big"
	"strconv"

	"hash"
)

// using the flickr character set which removes:
// ['=', '+', '_', '0', 'O', 'I', 'l'] from base64
// to reduce transcription errors, and make friendlier URLs
const (
	charset = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
	base    = 58
)

var (
	lut     [256]byte
	lowbyte = []byte("1")
	prefix  = []byte{'c', '4'}
	idlen   = 90
)

func init() {
	for i := 0; i < len(lut); i++ {
		lut[i] = 0xFF
	}
	for i := 0; i < len(charset); i++ {
		lut[charset[i]] = byte(i)
	}
}

type errBadChar int

func (e errBadChar) Error() string {
	return "non c4 character at position " + strconv.Itoa(int(e))
}

// ID represents a C4 Asset ID.
type ID big.Int

// ParseID parses a C4 ID string into an ID.
func ParseID(src string) (*ID, error) {
	return ParseBytesID([]byte(src))
}

// ParseBytesID parses a C4 ID as []byte into an ID.
func ParseBytesID(src []byte) (*ID, error) {
	bigNum := new(big.Int)
	bigBase := big.NewInt(base)
	for i := 2; i < len(src); i++ {
		b := lut[src[i]]
		if b == 0xFF {
			return nil, errBadChar(i)
		}
		bigNum.Mul(bigNum, bigBase)
		bigNum.Add(bigNum, big.NewInt(int64(b)))
	}
	id := ID(*bigNum)
	return &id, nil
}

func (id *ID) String() string {
	return string(id.Bytes())
}

// Bytes encodes the written bytes to C4 ID format.
func (id *ID) Bytes() []byte {
	bigNum := big.Int(*id)
	bigBase := big.NewInt(base)
	bigZero := big.NewInt(0)
	bigMod := new(big.Int)
	var encoded []byte
	for bigNum.Cmp(bigZero) > 0 {
		bigNum.DivMod(&bigNum, bigBase, bigMod)
		encoded = append([]byte{charset[bigMod.Int64()]}, encoded...)
	}
	// padding
	diff := idlen - 2 - len(encoded)
	encoded = append(bytes.Repeat(lowbyte, diff), encoded...)
	// c4... prefix
	encoded = append(prefix, encoded...)
	return encoded
}

// IDEncoder generates C4 Asset IDs.
type IDEncoder struct {
	h hash.Hash
}

// NewIDEncoder makes a new IDEncoder.
func NewIDEncoder() *IDEncoder {
	return &IDEncoder{
		h: sha512.New(),
	}
}

// Write writes bytes to the hash that makes up the ID.
func (e *IDEncoder) Write(b []byte) (int, error) {
	return e.h.Write(b)
}

// ID gets the ID for the written bytes.
func (e *IDEncoder) ID() *ID {
	b := new(big.Int)
	b.SetBytes(e.h.Sum(nil))
	id := ID(*b)
	return &id
}
<|endoftext|>


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

/*
	Serves a webpage for easy management of Skia bugs.

	WARNING: This server is NOT secure and should not be made publicly
	accessible.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"issue_tracker"
	"log"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

import "github.com/gorilla/securecookie"

const (
	certFile          = "certs/cert.pem"
	keyFile           = "certs/key.pem"
	issueComment      = "Edited by BugChomper"
	oauthCallbackPath = "/oauth2callback"
	oauthConfigFile   = "oauth_client_secret.json"
	localHost         = "127.0.0.1"
	maxSessionLen     = time.Duration(3600 * time.Second)
	priorityPrefix    = "Priority-"
	project           = "skia"
	cookieName        = "BugChomperCookie"
)

// Flags:
var (
	port   = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')")
	public = flag.Bool("public", false, "Make this server publicly accessible.")
)

var (
	scheme = "http"

	curdir, _       = filepath.Abs(".")
	templatePath, _ = filepath.Abs("templates")
	templates       = template.Must(template.ParseFiles(
		path.Join(templatePath, "bug_chomper.html"),
		path.Join(templatePath, "submitted.html"),
		path.Join(templatePath, "error.html")))

	hashKey      = securecookie.GenerateRandomKey(32)
	blockKey     = securecookie.GenerateRandomKey(32)
	secureCookie = securecookie.New(hashKey, blockKey)
)

// SessionState contains data for a given session.
type SessionState struct {
	IssueTracker   *issue_tracker.IssueTracker
	OrigRequestURL string
	SessionStart   time.Time
}

// getAbsoluteURL returns the absolute URL of the given Request.
func getAbsoluteURL(r *http.Request) string {
	return scheme + "://" + r.Host + r.URL.Path
}

// getOAuth2CallbackURL returns a callback URL to be used by the OAuth2 login
// page.
func getOAuth2CallbackURL(r *http.Request) string {
	return scheme + "://" + r.Host + oauthCallbackPath
}

func saveSession(session *SessionState, w http.ResponseWriter, r *http.Request) error {
	encodedSession, err := secureCookie.Encode(cookieName, session)
	if err != nil {
		return fmt.Errorf("unable to encode session state: %s", err)
	}
	cookie := &http.Cookie{
		Name:     cookieName,
		Value:    encodedSession,
		Domain:   strings.Split(r.Host, ":")[0],
		Path:     "/",
		HttpOnly: true,
	}
	http.SetCookie(w, cookie)
	return nil
}

// makeSession creates a new session for the Request.
func makeSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) {
	log.Println("Creating new session.")
	// Create the session state.
	issueTracker, err := issue_tracker.MakeIssueTracker(
		oauthConfigFile, getOAuth2CallbackURL(r))
	if err != nil {
		return nil, fmt.Errorf("unable to create IssueTracker for session: %s", err)
	}
	session := SessionState{
		IssueTracker:   issueTracker,
		OrigRequestURL: getAbsoluteURL(r),
		SessionStart:   time.Now(),
	}

	// Encode and store the session state.
	if err := saveSession(&session, w, r); err != nil {
		return nil, err
	}

	return &session, nil
}

// getSession retrieves the active SessionState or creates and returns a new
// SessionState.
func getSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) {
	cookie, err := r.Cookie(cookieName)
	if err != nil {
		log.Println("No cookie found! Starting new session.")
		return makeSession(w, r)
	}
	var session SessionState
	if err := secureCookie.Decode(cookieName, cookie.Value, &session); err != nil {
		log.Printf("Invalid or corrupted session. Starting another: %s", err.Error())
		return makeSession(w, r)
	}

	currentTime := time.Now()
	if currentTime.Sub(session.SessionStart) > maxSessionLen {
		log.Printf("Session starting at %s is expired. Starting another.",
			session.SessionStart.Format(time.RFC822))
		return makeSession(w, r)
	}
	saveSession(&session, w, r)
	return &session, nil
}

// reportError serves the error page with the given message.
func reportError(w http.ResponseWriter, msg string, code int) {
	errData := struct {
		Code       int
		CodeString string
		Message    string
	}{
		Code:       code,
		CodeString: http.StatusText(code),
		Message:    msg,
	}
	w.WriteHeader(code)
	err := templates.ExecuteTemplate(w, "error.html", errData)
	if err != nil {
		log.Println("Failed to display error.html!!")
	}
}

// makeBugChomperPage builds and serves the BugChomper page.
func makeBugChomperPage(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	issueTracker := session.IssueTracker
	user, err := issueTracker.GetLoggedInUser()
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	log.Println("Loading bugs for " + user)
	bugList, err := issueTracker.GetBugs(project, user)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	bugsById := make(map[string]*issue_tracker.Issue)
	bugsByPriority := make(map[string][]*issue_tracker.Issue)
	for _, bug := range bugList.Items {
		bugsById[strconv.Itoa(bug.Id)] = bug
		var bugPriority string
		for _, label := range bug.Labels {
			if strings.HasPrefix(label, priorityPrefix) {
				bugPriority = label[len(priorityPrefix):]
			}
		}
		if _, ok := bugsByPriority[bugPriority]; !ok {
			bugsByPriority[bugPriority] = make(
				[]*issue_tracker.Issue, 0)
		}
		bugsByPriority[bugPriority] = append(
			bugsByPriority[bugPriority], bug)
	}
	bugsJson, err := json.Marshal(bugsById)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data := struct {
		Title          string
		User           string
		BugsJson       template.JS
		BugsByPriority *map[string][]*issue_tracker.Issue
		Priorities     []string
		PriorityPrefix string
	}{
		Title:          "BugChomper",
		User:           user,
		BugsJson:       template.JS(string(bugsJson)),
		BugsByPriority: &bugsByPriority,
		Priorities:     issue_tracker.BugPriorities,
		PriorityPrefix: priorityPrefix,
	}

	if err := templates.ExecuteTemplate(w, "bug_chomper.html", data); err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// authIfNeeded determines whether the current user is logged in. If not, it
// redirects to a login page. Returns true if the user is redirected and false
// otherwise.
func authIfNeeded(w http.ResponseWriter, r *http.Request) bool {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return false
	}
	issueTracker := session.IssueTracker
	if !issueTracker.IsAuthenticated() {
		loginURL := issueTracker.MakeAuthRequestURL()
		log.Println("Redirecting for login:", loginURL)
		http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
		return true
	}
	return false
}

// submitData attempts to submit data from a POST request to the IssueTracker.
func submitData(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	issueTracker := session.IssueTracker
	edits := r.FormValue("all_edits")
	var editsMap map[string]*issue_tracker.Issue
	if err := json.Unmarshal([]byte(edits), &editsMap); err != nil {
		errMsg := "Could not parse edits from form response: " + err.Error()
		reportError(w, errMsg, http.StatusInternalServerError)
		return
	}
	data := struct {
		Title    string
		Message  string
		BackLink string
	}{}
	if len(editsMap) == 0 {
		data.Title = "No Changes Submitted"
		data.Message = "You didn't change anything!"
		data.BackLink = ""
		if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil {
			reportError(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	}
	errorList := make([]error, 0)
	for issueId, newIssue := range editsMap {
		log.Println("Editing issue " + issueId)
		if err := issueTracker.SubmitIssueChanges(newIssue, issueComment); err != nil {
			errorList = append(errorList, err)
		}
	}
	if len(errorList) > 0 {
		errorStrings := ""
		for _, err := range errorList {
			errorStrings += err.Error() + "\n"
		}
		errMsg := "Not all changes could be submitted: \n" + errorStrings
		reportError(w, errMsg, http.StatusInternalServerError)
		return
	}
	data.Title = "Submitted Changes"
	data.Message = "Your changes were submitted to the issue tracker."
	data.BackLink = ""
	if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	return
}

// handleBugChomper handles HTTP requests for the bug_chomper page.
func handleBugChomper(w http.ResponseWriter, r *http.Request) {
	if authIfNeeded(w, r) {
		return
	}
	switch r.Method {
	case "GET":
		makeBugChomperPage(w, r)
	case "POST":
		submitData(w, r)
	}
}

// handleOAuth2Callback handles callbacks from the OAuth2 sign-in.
func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
	}
	issueTracker := session.IssueTracker
	invalidLogin := "Invalid login credentials"
	params, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		reportError(w, invalidLogin+": "+err.Error(), http.StatusForbidden)
		return
	}
	code, ok := params["code"]
	if !ok {
		reportError(w, invalidLogin+": redirect did not include auth code.",
			http.StatusForbidden)
		return
	}
	log.Println("Upgrading auth token:", code[0])
	if err := issueTracker.UpgradeCode(code[0]); err != nil {
		errMsg := "failed to upgrade token: " + err.Error()
		reportError(w, errMsg, http.StatusForbidden)
		return
	}
	if err := saveSession(session, w, r); err != nil {
		reportError(w, "failed to save session: "+err.Error(),
			http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, session.OrigRequestURL, http.StatusTemporaryRedirect)
	return
}

// handleRoot is the handler function for all HTTP requests at the root level.
func handleRoot(w http.ResponseWriter, r *http.Request) {
	log.Println("Fetching " + r.URL.Path)
	if r.URL.Path == "/" || r.URL.Path == "/index.html" {
		handleBugChomper(w, r)
		return
	}
	http.NotFound(w, r)
}

// Run the BugChomper server.
func main() {
	flag.Parse()

	http.HandleFunc("/", handleRoot)
	http.HandleFunc(oauthCallbackPath, handleOAuth2Callback)
	http.Handle("/res/", http.FileServer(http.Dir(curdir)))
	log.Println("Server is running at " + scheme + "://" + localHost + *port)
	var err error
	if *public {
		log.Println("WARNING: This server is not secure and should not be made " +
			"publicly accessible.")
		scheme = "https"
		err = http.ListenAndServeTLS(*port, certFile, keyFile, nil)
	} else {
		scheme = "http"
		err = http.ListenAndServe(localHost+*port, nil)
	}
	if err != nil {
		log.Println(err.Error())
	}
}
<commit_msg>bug_chomper: Cleanup template initialization.<commit_after>// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/*
	Serves a webpage for easy management of Skia bugs.

	WARNING: This server is NOT secure and should not be made publicly
	accessible.
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"issue_tracker"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

import "github.com/gorilla/securecookie"

const (
	certFile          = "certs/cert.pem"
	keyFile           = "certs/key.pem"
	issueComment      = "Edited by BugChomper"
	oauthCallbackPath = "/oauth2callback"
	oauthConfigFile   = "oauth_client_secret.json"
	localHost         = "127.0.0.1"
	maxSessionLen     = time.Duration(3600 * time.Second)
	priorityPrefix    = "Priority-"
	project           = "skia"
	cookieName        = "BugChomperCookie"
)

// Flags:
var (
	port   = flag.String("port", ":8000", "HTTP service address (e.g., ':8000')")
	public = flag.Bool("public", false, "Make this server publicly accessible.")
)

var (
	// templates is the list of html templates used by bug_chomper.
	templates *template.Template = nil

	scheme       = "http"
	hashKey      = securecookie.GenerateRandomKey(32)
	blockKey     = securecookie.GenerateRandomKey(32)
	secureCookie = securecookie.New(hashKey, blockKey)
)

func init() {
	// Change the current working directory to two directories up from this
	// source file so that we can read templates.
	_, filename, _, _ := runtime.Caller(0)
	cwd := filepath.Join(filepath.Dir(filename), "../..")
	if err := os.Chdir(cwd); err != nil {
		log.Fatal(err)
	}

	templates = template.Must(template.ParseFiles(
		filepath.Join(cwd, "templates/bug_chomper.html"),
		filepath.Join(cwd, "templates/submitted.html"),
		filepath.Join(cwd, "templates/error.html"),
	))
}

// SessionState contains data for a given session.
type SessionState struct {
	IssueTracker   *issue_tracker.IssueTracker
	OrigRequestURL string
	SessionStart   time.Time
}

// getAbsoluteURL returns the absolute URL of the given Request.
func getAbsoluteURL(r *http.Request) string {
	return scheme + "://" + r.Host + r.URL.Path
}

// getOAuth2CallbackURL returns a callback URL to be used by the OAuth2 login
// page.
func getOAuth2CallbackURL(r *http.Request) string {
	return scheme + "://" + r.Host + oauthCallbackPath
}

func saveSession(session *SessionState, w http.ResponseWriter, r *http.Request) error {
	encodedSession, err := secureCookie.Encode(cookieName, session)
	if err != nil {
		return fmt.Errorf("unable to encode session state: %s", err)
	}
	cookie := &http.Cookie{
		Name:     cookieName,
		Value:    encodedSession,
		Domain:   strings.Split(r.Host, ":")[0],
		Path:     "/",
		HttpOnly: true,
	}
	http.SetCookie(w, cookie)
	return nil
}

// makeSession creates a new session for the Request.
func makeSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) {
	log.Println("Creating new session.")
	// Create the session state.
	issueTracker, err := issue_tracker.MakeIssueTracker(
		oauthConfigFile, getOAuth2CallbackURL(r))
	if err != nil {
		return nil, fmt.Errorf("unable to create IssueTracker for session: %s", err)
	}
	session := SessionState{
		IssueTracker:   issueTracker,
		OrigRequestURL: getAbsoluteURL(r),
		SessionStart:   time.Now(),
	}

	// Encode and store the session state.
	if err := saveSession(&session, w, r); err != nil {
		return nil, err
	}

	return &session, nil
}

// getSession retrieves the active SessionState or creates and returns a new
// SessionState.
func getSession(w http.ResponseWriter, r *http.Request) (*SessionState, error) {
	cookie, err := r.Cookie(cookieName)
	if err != nil {
		log.Println("No cookie found! Starting new session.")
		return makeSession(w, r)
	}
	var session SessionState
	if err := secureCookie.Decode(cookieName, cookie.Value, &session); err != nil {
		log.Printf("Invalid or corrupted session. Starting another: %s", err.Error())
		return makeSession(w, r)
	}

	currentTime := time.Now()
	if currentTime.Sub(session.SessionStart) > maxSessionLen {
		log.Printf("Session starting at %s is expired. Starting another.",
			session.SessionStart.Format(time.RFC822))
		return makeSession(w, r)
	}
	saveSession(&session, w, r)
	return &session, nil
}

// reportError serves the error page with the given message.
func reportError(w http.ResponseWriter, msg string, code int) {
	errData := struct {
		Code       int
		CodeString string
		Message    string
	}{
		Code:       code,
		CodeString: http.StatusText(code),
		Message:    msg,
	}
	w.WriteHeader(code)
	err := templates.ExecuteTemplate(w, "error.html", errData)
	if err != nil {
		log.Println("Failed to display error.html!!")
	}
}

// makeBugChomperPage builds and serves the BugChomper page.
func makeBugChomperPage(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	issueTracker := session.IssueTracker
	user, err := issueTracker.GetLoggedInUser()
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	log.Println("Loading bugs for " + user)
	bugList, err := issueTracker.GetBugs(project, user)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	bugsById := make(map[string]*issue_tracker.Issue)
	bugsByPriority := make(map[string][]*issue_tracker.Issue)
	for _, bug := range bugList.Items {
		bugsById[strconv.Itoa(bug.Id)] = bug
		var bugPriority string
		for _, label := range bug.Labels {
			if strings.HasPrefix(label, priorityPrefix) {
				bugPriority = label[len(priorityPrefix):]
			}
		}
		if _, ok := bugsByPriority[bugPriority]; !ok {
			bugsByPriority[bugPriority] = make(
				[]*issue_tracker.Issue, 0)
		}
		bugsByPriority[bugPriority] = append(
			bugsByPriority[bugPriority], bug)
	}
	bugsJson, err := json.Marshal(bugsById)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	data := struct {
		Title          string
		User           string
		BugsJson       template.JS
		BugsByPriority *map[string][]*issue_tracker.Issue
		Priorities     []string
		PriorityPrefix string
	}{
		Title:          "BugChomper",
		User:           user,
		BugsJson:       template.JS(string(bugsJson)),
		BugsByPriority: &bugsByPriority,
		Priorities:     issue_tracker.BugPriorities,
		PriorityPrefix: priorityPrefix,
	}

	if err := templates.ExecuteTemplate(w, "bug_chomper.html", data); err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// authIfNeeded determines whether the current user is logged in. If not, it
// redirects to a login page. Returns true if the user is redirected and false
// otherwise.
func authIfNeeded(w http.ResponseWriter, r *http.Request) bool {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return false
	}
	issueTracker := session.IssueTracker
	if !issueTracker.IsAuthenticated() {
		loginURL := issueTracker.MakeAuthRequestURL()
		log.Println("Redirecting for login:", loginURL)
		http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
		return true
	}
	return false
}

// submitData attempts to submit data from a POST request to the IssueTracker.
func submitData(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	issueTracker := session.IssueTracker
	edits := r.FormValue("all_edits")
	var editsMap map[string]*issue_tracker.Issue
	if err := json.Unmarshal([]byte(edits), &editsMap); err != nil {
		errMsg := "Could not parse edits from form response: " + err.Error()
		reportError(w, errMsg, http.StatusInternalServerError)
		return
	}
	data := struct {
		Title    string
		Message  string
		BackLink string
	}{}
	if len(editsMap) == 0 {
		data.Title = "No Changes Submitted"
		data.Message = "You didn't change anything!"
		data.BackLink = ""
		if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil {
			reportError(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	}
	errorList := make([]error, 0)
	for issueId, newIssue := range editsMap {
		log.Println("Editing issue " + issueId)
		if err := issueTracker.SubmitIssueChanges(newIssue, issueComment); err != nil {
			errorList = append(errorList, err)
		}
	}
	if len(errorList) > 0 {
		errorStrings := ""
		for _, err := range errorList {
			errorStrings += err.Error() + "\n"
		}
		errMsg := "Not all changes could be submitted: \n" + errorStrings
		reportError(w, errMsg, http.StatusInternalServerError)
		return
	}
	data.Title = "Submitted Changes"
	data.Message = "Your changes were submitted to the issue tracker."
	data.BackLink = ""
	if err := templates.ExecuteTemplate(w, "submitted.html", data); err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	return
}

// handleBugChomper handles HTTP requests for the bug_chomper page.
func handleBugChomper(w http.ResponseWriter, r *http.Request) {
	if authIfNeeded(w, r) {
		return
	}
	switch r.Method {
	case "GET":
		makeBugChomperPage(w, r)
	case "POST":
		submitData(w, r)
	}
}

// handleOAuth2Callback handles callbacks from the OAuth2 sign-in.
func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
	session, err := getSession(w, r)
	if err != nil {
		reportError(w, err.Error(), http.StatusInternalServerError)
	}
	issueTracker := session.IssueTracker
	invalidLogin := "Invalid login credentials"
	params, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		reportError(w, invalidLogin+": "+err.Error(), http.StatusForbidden)
		return
	}
	code, ok := params["code"]
	if !ok {
		reportError(w, invalidLogin+": redirect did not include auth code.",
			http.StatusForbidden)
		return
	}
	log.Println("Upgrading auth token:", code[0])
	if err := issueTracker.UpgradeCode(code[0]); err != nil {
		errMsg := "failed to upgrade token: " + err.Error()
		reportError(w, errMsg, http.StatusForbidden)
		return
	}
	if err := saveSession(session, w, r); err != nil {
		reportError(w, "failed to save session: "+err.Error(),
			http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, session.OrigRequestURL, http.StatusTemporaryRedirect)
	return
}

// handleRoot is the handler function for all HTTP requests at the root level.
func handleRoot(w http.ResponseWriter, r *http.Request) {
	log.Println("Fetching " + r.URL.Path)
	if r.URL.Path == "/" || r.URL.Path == "/index.html" {
		handleBugChomper(w, r)
		return
	}
	http.NotFound(w, r)
}

// Run the BugChomper server.
func main() {
	flag.Parse()

	http.HandleFunc("/", handleRoot)
	http.HandleFunc(oauthCallbackPath, handleOAuth2Callback)
	http.Handle("/res/", http.FileServer(http.Dir("./")))
	log.Println("Server is running at " + scheme + "://" + localHost + *port)
	var err error
	if *public {
		log.Println("WARNING: This server is not secure and should not be made " +
			"publicly accessible.")
		scheme = "https"
		err = http.ListenAndServeTLS(*port, certFile, keyFile, nil)
	} else {
		scheme = "http"
		err = http.ListenAndServe(localHost+*port, nil)
	}
	if err != nil {
		log.Println(err.Error())
	}
}
<|endoftext|>


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

package main

import (
	"fmt"

	// Need to do btrfs driver initializations
	_ "github.com/control-center/serviced/volume/btrfs"
	// Need to do rsync driver initializations
	_ "github.com/control-center/serviced/volume/rsync"

	"github.com/control-center/serviced/volume/devicemapper"
	log "github.com/Sirupsen/logrus"
)

// Execute displays orphaned volumes
func (c *CheckOrphans) Execute(args []string) error {
	App.initializeLogging()
	directory := GetDefaultDriver(string(c.Args.Path))
	dmd, err := InitDriverIfExists(directory)
	if err != nil {
		return err
	}
	drv, ok := dmd.(*devicemapper.DeviceMapperDriver)
	if !ok {
		log.Fatal("This only works on devicemapper devices")
	}

	//  we retrieve the list of all devices that CC has access to
	var ccDevices []string
	for _, v := range drv.ListTenants() {
		_vol, err := drv.Get(v)
		if err != nil {
			return err
		}
		vol, ok := _vol.(*devicemapper.DeviceMapperVolume)
		if !ok {
			log.Fatal("Volume", v, "is not of DeviceMapper type.")
		}
		ccDevices = append(ccDevices, vol.Metadata.CurrentDevice())
		for _, dHash := range vol.Metadata.Snapshots {
			ccDevices = append(ccDevices, dHash)
		}
	}

	// next we compare CC-visible device hashes to the device hashes stored by the device driver
	var orphans []string
	for _, d := range drv.DeviceSet.List() {
		found := false
		for _, c := range ccDevices {
			// (*devicemapper.DeviceMapperDriver).DeviceSet.List() will contain an empty string for the base device
			if d == c || d == "" {
				found = true
				break
			}
		}
		if !found {
			orphans = append(orphans, d)
		}
	}

	if len(orphans) > 0 {
		fmt.Println("Orphaned devices were found")
		// delete the actual devices
		for _, v := range orphans {
			if c.Clean {
				drv.DeviceSet.UnmountDevice(v, drv.Root())
				drv.DeviceSet.Lock()
				if err := drv.DeactivateDevice(v); err != nil {
					log.Info("An error occurred while attempting to deactivate the device:", err)
				}
				drv.DeviceSet.Unlock()
				if err := drv.DeviceSet.DeleteDevice(v, false); err != nil {
					log.Info("An error occurred while attempting to remove the device:", err)
				}
				fmt.Println("Removed orphaned snapshot", v)
			} else {
				fmt.Println(v)
			}
		}
	} else {
		fmt.Println("No orphaned devices found.")
	}
	return nil
}
<commit_msg>CC-3502 Orphan removal change (#3513)<commit_after>// Copyright 2016 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"

	// Need to do btrfs driver initializations
	_ "github.com/control-center/serviced/volume/btrfs"
	// Need to do rsync driver initializations
	_ "github.com/control-center/serviced/volume/rsync"

	log "github.com/Sirupsen/logrus"
	"github.com/control-center/serviced/volume/devicemapper"
)

// Execute displays orphaned volumes
func (c *CheckOrphans) Execute(args []string) error {
	App.initializeLogging()
	directory := GetDefaultDriver(string(c.Args.Path))
	dmd, err := InitDriverIfExists(directory)
	if err != nil {
		return err
	}
	drv, ok := dmd.(*devicemapper.DeviceMapperDriver)
	if !ok {
		log.Fatal("This only works on devicemapper devices")
	}

	//  we retrieve the list of all devices that CC has access to
	var ccDevices []string
	for _, v := range drv.ListTenants() {
		_vol, err := drv.Get(v)
		if err != nil {
			return err
		}
		vol, ok := _vol.(*devicemapper.DeviceMapperVolume)
		if !ok {
			log.Fatal("Volume", v, "is not of DeviceMapper type.")
		}
		ccDevices = append(ccDevices, vol.Metadata.CurrentDevice())
		for _, dHash := range vol.Metadata.Snapshots {
			ccDevices = append(ccDevices, dHash)
		}
	}

	// next we compare CC-visible device hashes to the device hashes stored by the device driver
	var orphans []string
	for _, d := range drv.DeviceSet.List() {
		found := false
		for _, c := range ccDevices {
			// (*devicemapper.DeviceMapperDriver).DeviceSet.List() will contain an empty string for the base device
			if d == c || d == "" {
				found = true
				break
			}
		}
		if !found {
			orphans = append(orphans, d)
		}
	}

	if len(orphans) > 0 {
		fmt.Println("Orphaned devices were found")
		// delete the actual devices
		for _, v := range orphans {
			if c.Clean {
				if err := drv.DeviceSet.DeleteDevice(v, false); err != nil {
					log.WithError(err).Error("An error occurred while attempting to remove the device:")
				} else {
					fmt.Println("Removed orphaned snapshot", v)
				}
			} else {
				fmt.Println(v)
			}
		}
	} else {
		fmt.Println("No orphaned devices found.")
	}
	return nil
}
<|endoftext|>


<commit_before>package manet

import (
	"bytes"

	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// Loopback Addresses
var (
	// IP4Loopback is the ip4 loopback multiaddr
	IP4Loopback = ma.StringCast("/ip4/127.0.0.1")

	// IP6Loopback is the ip6 loopback multiaddr
	IP6Loopback = ma.StringCast("/ip6/::1")

	// IP6LinkLocalLoopback is the ip6 link-local loopback multiaddr
	IP6LinkLocalLoopback = ma.StringCast("/ip6/fe80::1")
)

// Unspecified Addresses (used for )
var (
	IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
	IP6Unspecified = ma.StringCast("/ip6/::")
)

// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
	p := m.Protocols()

	// nothing? not even a waist.
	if len(p) == 0 {
		return false
	}

	if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
		return false
	}

	// only IP? still counts.
	if len(p) == 1 {
		return true
	}

	switch p[1].Code {
	case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
		return true
	default:
		return false
	}
}

// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
// This means either /ip4/127.0.0.1 or /ip6/::1
func IsIPLoopback(m ma.Multiaddr) bool {
	b := m.Bytes()

	// /ip4/127 prefix (_entire_ /8 is loopback...)
	if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) {
		return true
	}

	// /ip6/::1
	if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) {
		return true
	}

	return false
}

// IP6 Link Local addresses are non routable. The prefix is technically
// fe80::/10, but we test fe80::/12 for simplicity (no need to mask).
// So far, no hardware interfaces exist long enough to use those 2 bits.
// Send a PR if there is.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
	return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80, 0})
}

// IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address
// This means either /ip4/0.0.0.0 or /ip6/::
func IsIPUnspecified(m ma.Multiaddr) bool {
	return IP4Unspecified.Equal(m) || IP6Unspecified.Equal(m)
}
<commit_msg>fixed link local check<commit_after>package manet

import (
	"bytes"

	ma "github.com/jbenet/go-multiaddr-net/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// Loopback Addresses
var (
	// IP4Loopback is the ip4 loopback multiaddr
	IP4Loopback = ma.StringCast("/ip4/127.0.0.1")

	// IP6Loopback is the ip6 loopback multiaddr
	IP6Loopback = ma.StringCast("/ip6/::1")

	// IP6LinkLocalLoopback is the ip6 link-local loopback multiaddr
	IP6LinkLocalLoopback = ma.StringCast("/ip6/fe80::1")
)

// Unspecified Addresses (used for )
var (
	IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
	IP6Unspecified = ma.StringCast("/ip6/::")
)

// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
	p := m.Protocols()

	// nothing? not even a waist.
	if len(p) == 0 {
		return false
	}

	if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
		return false
	}

	// only IP? still counts.
	if len(p) == 1 {
		return true
	}

	switch p[1].Code {
	case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
		return true
	default:
		return false
	}
}

// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address
// This means either /ip4/127.0.0.1 or /ip6/::1
func IsIPLoopback(m ma.Multiaddr) bool {
	b := m.Bytes()

	// /ip4/127 prefix (_entire_ /8 is loopback...)
	if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) {
		return true
	}

	// /ip6/::1
	if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) {
		return true
	}

	return false
}

// IP6 Link Local addresses are non routable. The prefix is technically
// fe80::/10, but we test fe80::/16 for simplicity (no need to mask).
// So far, no hardware interfaces exist long enough to use those 2 bits.
// Send a PR if there is.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
	return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80})
}

// IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address
// This means either /ip4/0.0.0.0 or /ip6/::
func IsIPUnspecified(m ma.Multiaddr) bool {
	return IP4Unspecified.Equal(m) || IP6Unspecified.Equal(m)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
)

//The IP struct
type IP struct {
	Address     string
	CountryName string
	CommonName  string
	OrgName     string
	ServerName  string
	Delay       int
	Bandwidth   int
}

// The status of type IP
const (
	okIP = iota
	noIP
	errIP
)

//IPs []IP
type IPs []IP

//Len return the length of []IP
func (ips IPs) Len() int {
	return len(ips)
}

//Swap swap two value of []IP
func (ips IPs) Swap(i, j int) {
	ips[i], ips[j] = ips[j], ips[i]
}

//ByDelay sort by delay
type ByDelay struct {
	IPs
}

//Less return false if the first value less than the second one
func (s ByDelay) Less(i, j int) bool {
	return s.IPs[i].Delay < s.IPs[j].Delay
}

//ByBandwidth sort by bandwidth
type ByBandwidth struct {
	IPs
}

//Less return false if the first value less than the second one
func (s ByBandwidth) Less(i, j int) bool {
	return s.IPs[i].Bandwidth < s.IPs[j].Bandwidth
}

//get last ok ip
func getLastOkIP() []IP {
	m := make(map[string]IP)
	var checkedip IP
	var ips []IP
	if isFileExist(tmpOkIPFileName) {
		bytes, err := ioutil.ReadFile(tmpOkIPFileName)
		checkErr(fmt.Sprintf("read file %s error: ", tmpOkIPFileName), err, Error)
		lines := strings.Split(string(bytes), "\n")
		for _, line := range lines {
			ipInfo := strings.Split(line, " ")
			if len(ipInfo) == 6 {
				delay, err := strconv.Atoi(ipInfo[1][:len(ipInfo[1])-2])
				checkErr("delay conversion failed: ", err, Warning)
				bandwidth, err := strconv.Atoi(ipInfo[5][:len(ipInfo[5])-4])
				checkErr("bandwidth conversion failed: ", err, Warning)
				checkedip = IP{
					Address:     ipInfo[0],
					Delay:       delay,
					CommonName:  ipInfo[2],
					ServerName:  ipInfo[3],
					CountryName: ipInfo[4],
					Bandwidth:   bandwidth,
				}
				m[ipInfo[0]] = checkedip
			}
		}
	}
	for _, v := range m {
		ips = append(ips, v)
	}
	return ips
}

//get all google ip range from googleip.txt file
func getGoogleIPRange() []string {
	m := make(map[string]string)
	var ipRanges []string
	bytes, err := ioutil.ReadFile(googleIPFileName)
	checkErr(fmt.Sprintf("read file %s error: ", googleIPFileName), err, Error)

	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		line = strings.Replace(line, "\r", "", -1)
		if len(line) > 7 {
			m[line] = line
		}
	}
	for _, v := range m {
		ipRanges = append(ipRanges, v)
	}

	return ipRanges
}

/**
  Parse google ip range, support the following formats:
  1. xxx.xxx.xxx.xxx
  2. xxx.xxx.xxx.xxx/xx
  3. xxx.xxx.xxx.xxx-xxx.xxx.xxx.xxx
  4. xxx.xxx.xxx.xxx-xxx.
  5. xxx.-xxx.
*/
func parseGoogleIPRange(ipRange string) []string {
	var ips []string
	if strings.Contains(ipRange, "/") {
		//CIDR: https://zh.wikipedia.org/wiki/%E6%97%A0%E7%B1%BB%E5%88%AB%E5%9F%9F%E9%97%B4%E8%B7%AF%E7%94%B1
		ip, ipNet, err := net.ParseCIDR(ipRange)
		checkErr(fmt.Sprintf("parse CIDR %s error: ", ipRange), err, Error)

		for iptmp := ip.Mask(ipNet.Mask); ipNet.Contains(iptmp); inc(iptmp) {
			ips = append(ips, iptmp.String())
		}
		// remove network address and broadcast address
		return ips[1 : len(ips)-1]
	} else if strings.Contains(ipRange, "-") {
		startIP := ipRange[:strings.Index(ipRange, "-")]
		endIP := ipRange[strings.Index(ipRange, "-")+1:]
		if strings.HasSuffix(startIP, ".") {
			switch strings.Count(startIP, ".") {
			case 1:
				startIP += "0.0.0"
			case 2:
				startIP += "0.0"
			case 3:
				startIP += "0"
			}
		}
		if strings.HasSuffix(endIP, ".") {
			switch strings.Count(endIP, ".") {
			case 1:
				endIP += "255.255.255"
			case 2:
				endIP += "255.255"
			case 3:
				endIP += "255"
			}
		}
		sIP := net.ParseIP(startIP)
		eIP := net.ParseIP(endIP)

		for ip := sIP; bytes.Compare(ip, eIP) <= 0; inc(ip) {
			ips = append(ips, ip.String())

		}
	} else {
		ips = append(ips, ipRange)
	}

	return ips
}

//get all google ip
func getGoogleIP() []string {
	var ips []string
	ipRanges := getGoogleIPRange()
	for _, ipRange := range ipRanges {
		ips = append(ips, parseGoogleIPRange(ipRange)...)
	}

	return ips
}

func inc(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}
<commit_msg>support ip range xxx.xxx.<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
)

//The IP struct
type IP struct {
	Address     string
	CountryName string
	CommonName  string
	OrgName     string
	ServerName  string
	Delay       int
	Bandwidth   int
}

// The status of type IP
const (
	okIP = iota
	noIP
	errIP
)

//IPs []IP
type IPs []IP

//Len return the length of []IP
func (ips IPs) Len() int {
	return len(ips)
}

//Swap swap two value of []IP
func (ips IPs) Swap(i, j int) {
	ips[i], ips[j] = ips[j], ips[i]
}

//ByDelay sort by delay
type ByDelay struct {
	IPs
}

//Less return false if the first value less than the second one
func (s ByDelay) Less(i, j int) bool {
	return s.IPs[i].Delay < s.IPs[j].Delay
}

//ByBandwidth sort by bandwidth
type ByBandwidth struct {
	IPs
}

//Less return false if the first value less than the second one
func (s ByBandwidth) Less(i, j int) bool {
	return s.IPs[i].Bandwidth < s.IPs[j].Bandwidth
}

//get last ok ip
func getLastOkIP() []IP {
	m := make(map[string]IP)
	var checkedip IP
	var ips []IP
	if isFileExist(tmpOkIPFileName) {
		bytes, err := ioutil.ReadFile(tmpOkIPFileName)
		checkErr(fmt.Sprintf("read file %s error: ", tmpOkIPFileName), err, Error)
		lines := strings.Split(string(bytes), "\n")
		for _, line := range lines {
			ipInfo := strings.Split(line, " ")
			if len(ipInfo) == 6 {
				delay, err := strconv.Atoi(ipInfo[1][:len(ipInfo[1])-2])
				checkErr("delay conversion failed: ", err, Warning)
				bandwidth, err := strconv.Atoi(ipInfo[5][:len(ipInfo[5])-4])
				checkErr("bandwidth conversion failed: ", err, Warning)
				checkedip = IP{
					Address:     ipInfo[0],
					Delay:       delay,
					CommonName:  ipInfo[2],
					ServerName:  ipInfo[3],
					CountryName: ipInfo[4],
					Bandwidth:   bandwidth,
				}
				m[ipInfo[0]] = checkedip
			}
		}
	}
	for _, v := range m {
		ips = append(ips, v)
	}
	return ips
}

//get all google ip range from googleip.txt file
func getGoogleIPRange() []string {
	m := make(map[string]string)
	var ipRanges []string
	bytes, err := ioutil.ReadFile(googleIPFileName)
	checkErr(fmt.Sprintf("read file %s error: ", googleIPFileName), err, Error)

	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		line = strings.Replace(line, "\r", "", -1)
		if len(line) > 1 {
			m[line] = line
		}
	}
	for _, v := range m {
		ipRanges = append(ipRanges, v)
	}

	return ipRanges
}

/**
  Parse google ip range, support the following formats:
  1. xxx.xxx.xxx.xxx
  2. xxx.xxx.xxx.xxx/xx
  3. xxx.xxx.xxx.xxx-xxx.xxx.xxx.xxx
  4. xxx.xxx.xxx.xxx-xxx.
  5. xxx.-xxx.
  6. xxx.xxx.
*/
func parseGoogleIPRange(ipRange string) []string {
	var ips []string
	if strings.Contains(ipRange, "/") {
		//CIDR: https://zh.wikipedia.org/wiki/%E6%97%A0%E7%B1%BB%E5%88%AB%E5%9F%9F%E9%97%B4%E8%B7%AF%E7%94%B1
		ip, ipNet, err := net.ParseCIDR(ipRange)
		checkErr(fmt.Sprintf("parse CIDR %s error: ", ipRange), err, Error)

		for iptmp := ip.Mask(ipNet.Mask); ipNet.Contains(iptmp); inc(iptmp) {
			ips = append(ips, iptmp.String())
		}
		// remove network address and broadcast address
		return ips[1 : len(ips)-1]
	} else if strings.Contains(ipRange, "-") {
		startIP := ipRange[:strings.Index(ipRange, "-")]
		endIP := ipRange[strings.Index(ipRange, "-")+1:]
		if strings.HasSuffix(startIP, ".") {
			switch strings.Count(startIP, ".") {
			case 1:
				startIP += "0.0.0"
			case 2:
				startIP += "0.0"
			case 3:
				startIP += "0"
			}
		}
		if strings.HasSuffix(endIP, ".") {
			switch strings.Count(endIP, ".") {
			case 1:
				endIP += "255.255.255"
			case 2:
				endIP += "255.255"
			case 3:
				endIP += "255"
			}
		}
		sIP := net.ParseIP(startIP)
		eIP := net.ParseIP(endIP)

		for ip := sIP; bytes.Compare(ip, eIP) <= 0; inc(ip) {
			ips = append(ips, ip.String())
		}
	} else {
		if strings.HasSuffix(ipRange, ".") {
			startIP, endIP := ipRange, ipRange
			switch strings.Count(ipRange, ".") {
			case 1:
				startIP += "0.0.0"
				endIP += "255.255.255"
			case 2:
				startIP += "0.0"
				endIP += "255.255"
			case 3:
				startIP += "0"
				endIP += "255"
			}
			sIP := net.ParseIP(startIP)
			eIP := net.ParseIP(endIP)

			for ip := sIP; bytes.Compare(ip, eIP) <= 0; inc(ip) {
				ips = append(ips, ip.String())
			}
		} else {
			ips = append(ips, ipRange)
		}
	}

	return ips
}

//get all google ip
func getGoogleIP() []string {
	var ips []string
	ipRanges := getGoogleIPRange()
	for _, ipRange := range ipRanges {
		ips = append(ips, parseGoogleIPRange(ipRange)...)
	}

	return ips
}

func inc(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}
<|endoftext|>


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

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	unicode format: U+1234; same as "U+%x" with 4 digits default
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	For numeric values, the width and precision flags control
	formatting; width sets the width of the field, precision the
	number of places after the decimal, if appropriate.  The
	format %6.2f prints 123.45. The width of a field is the number
	of Unicode code points in the string. This differs from C's printf where
	the field width is the number of bytes.  Either or both of the
	flags may be replaced with the character '*', causing their values
	to be obtained from the next operand, which must be of type int.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<commit_msg>fmt/doc: define width and precision for strings.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%x" with 4 digits default
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	The width and precision control formatting and are in units of Unicode
	code points.  (This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For numeric values, width sets the width of the field and precision
	sets the number of places after the decimal, if appropriate.  For
	example, the format %6.2f prints 123.45.

	For strings, width is the minimum number of characters to output,
	padding with spaces if necessary, and precision is the maximum
	number of characters to output, truncating if necessary.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<|endoftext|>


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

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16 notation with two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	For numeric values, the width and precision flags control
	formatting; width sets the width of the field, precision the
	number of places after the decimal, if appropriate.  The
	format %6.2f prints 123.45. The width of a field is the number
	of Unicode code points in the string. This differs from C's printf where
	the field width is the number of bytes.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23;
		fmt.Printf("%v\n", i);
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to conver the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, "%x"
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating
		point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.
*/
package fmt
<commit_msg>fmt: fix typo in package comment. No semantic change.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16 notation with two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	For numeric values, the width and precision flags control
	formatting; width sets the width of the field, precision the
	number of places after the decimal, if appropriate.  The
	format %6.2f prints 123.45. The width of a field is the number
	of Unicode code points in the string. This differs from C's printf where
	the field width is the number of bytes.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23;
		fmt.Printf("%v\n", i);
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, "%x"
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating
		point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc.  can read one character past the input
	they return, which means that a loop calling a scan routine
	may skip some of the input.  This is usually a problem only
	when there is no space between input values.
*/
package fmt
<|endoftext|>