<commit_before>package model

import (
	"database/sql"
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"io/ioutil"
	"os"
	"time"
)

var modelLog = logrus.WithField("module", "model")

/*
	The structs defined in this file are stored in a database using the `gorm` package.

	Remember to
		Set primary key for a struct.
		Set constraints on specific fields where appropriate.
		Define UniqueIndexes either through a tag or through gorm.DB.AddUniqueIndex()
			for a Unique constraint over multiple fields

	Unless you have a good reason, declare attributes of a struct not null.

	Example:

		type MyType struct {
			Name string `gorm:"not null"`
		}

	Special Cases:

	Enums: 	EnumType.EnumItem => const EnumTypeEnumItem

		Structs using such 'enums' should declare appropriate constraints in the corresponding FieldTag,
		using go-sqlite3 syntax

		Example:

			type MyType struct {
				Name string `sql:"unique"`
			}

*/

type Slave struct {
	ID                   int64  `gorm:"primary_key"`
	Hostname             string `gorm:"unique_index"`
	Port                 PortNumber
	MongodPortRangeBegin PortNumber
	MongodPortRangeEnd   PortNumber
	PersistentStorage    bool
	Mongods              []*Mongod `gorm:"ForeignKey:ParentSlaveID"`
	ConfiguredState      SlaveState

	Problems []*Problem

	// Foreign keys
	RiskGroupID sql.NullInt64 `sql:"type:integer NULL REFERENCES risk_groups(id) DEFERRABLE INITIALLY DEFERRED"`
}

type PortNumber uint16

const (
	PortNumberMin PortNumber = 1
	PortNumberMax            = 65535
)

type SlaveState uint

const (
	_                           = 0
	SlaveStateActive SlaveState = iota
	SlaveStateMaintenance
	SlaveStateDisabled
)

type ReplicaSet struct {
	ID                              int64  `gorm:"primary_key"` //TODO needs to start incrementing at 1
	Name                            string `gorm:"unique_index"`
	PersistentMemberCount           uint
	VolatileMemberCount             uint
	ConfigureAsShardingConfigServer bool
	Mongods                         []*Mongod

	Problems []*Problem
}

type RiskGroup struct {
	ID     int64  `gorm:"primary_key"` //TODO needs to start incrementing at 1, 0 is special value for slaves "out of risk" => define a constant?
	Name   string `gorm:"unique_index"`
	Slaves []*Slave
}

type Mongod struct {
	// TODO missing UNIQUE constraint
	ID          int64 `gorm:"primary_key"`
	Port        PortNumber
	ReplSetName string

	ObservationError   MSPError
	ObservationErrorID sql.NullInt64 `sql:"type:integer NULL REFERENCES msp_errors(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`

	LastEstablishStateError   MSPError
	LastEstablishStateErrorID sql.NullInt64 `sql:"type:integer NULL REFERENCES msp_errors(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`

	ParentSlave   *Slave
	ParentSlaveID int64 `sql:"type:integer REFERENCES slaves(id) DEFERRABLE INITIALLY DEFERRED"`

	ReplicaSet   *ReplicaSet
	ReplicaSetID int64 `sql:"type:integer NULL REFERENCES replica_sets(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`

	DesiredState   MongodState
	DesiredStateID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongod_states(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"` // NOTE: we cascade on delete, i.e. when a desired state is deleted, the Mongod is deleted, too. This is the inversion of the semantic object hierarchy, but we'll stay with it for now.

	ObservedState   MongodState
	ObservedStateID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongod_states(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`
}

type MongodState struct {
	ID                     int64 `gorm:"primary_key"`
	ParentMongod           *Mongod
	ParentMongodID         sql.NullInt64 `sql:"type:integer NOT NULL REFERENCES mongods(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`
	IsShardingConfigServer bool
	ExecutionState         MongodExecutionState
	ReplicaSetMembers      []ReplicaSetMember
}

type MongodExecutionState uint

const (
	_                                                  = 0
	MongodExecutionStateDestroyed MongodExecutionState = iota
	MongodExecutionStateNotRunning
	MongodExecutionStateRecovering // invalid for a desired MongodState
	MongodExecutionStateRunning
)

type ReplicaSetMember struct { // was ReplicaSetMember in UML
	// TODO missing primary key.
	ID       int64 `gorm:"primary_key"`
	Hostname string
	Port     PortNumber

	// Foreign key to parent MongodState
	MongodStateID int64 `sql:"type:integer REFERENCES mongod_states(id) DEFERRABLE INITIALLY DEFERRED"`
}

// msp.Error
// duplicated for decoupling protocol & internal representation
type MSPError struct {
	ID              int64 `gorm:"primary_key"`
	Identifier      string
	Description     string
	LongDescription string
}

type ProblemType uint

const (
	_                                 = 0
	ProblemTypeConnection ProblemType = iota
	ProblemTypeMismatch
	ProblemTypeDesiredReplicaSetConstraint
	ProblemTypeObservedReplicaSetConstraint
)

type Problem struct {
	ID              int64 `gorm:"primary_key"`
	Description     string
	LongDescription string
	ProblemType     ProblemType
	FirstOccurred   time.Time
	LastUpdated     time.Time

	Slave   *Slave
	SlaveID sql.NullInt64 `sql:"type:integer NULL REFERENCES slaves(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`

	ReplicaSet   *ReplicaSet
	ReplicaSetID sql.NullInt64 `sql:"type:integer NULL REFERENCES replica_sets(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`

	Mongod   *Mongod
	MongodID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongods(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`
}

type DB struct {
	gormDB *gorm.DB
}

func initializeDB(dsn string) (*DB, error) {

	gormDB, err := gorm.Open("sqlite3", dsn)
	if err != nil {
		return nil, err
	}

	db := &DB{
		gormDB: gormDB,
	}

	gormDB.SetLogger(modelLog)

	return db, nil

}

func (db *DB) Begin() *gorm.DB {
	tx := db.gormDB.Begin()
	return tx
}

func InitializeFileFromFile(path string) (db *DB, err error) {

	db, err = initializeDB(path)
	if err != nil {
		return nil, err
	}

	migrateDB(db)

	return db, nil

}

func createTestDBFile() (path string) {
	file, err := ioutil.TempFile(os.TempDir(), "mamid-")
	if err != nil {
		modelLog.Fatalf("could not create test database file: %s", err)
	} else {
		modelLog.Debugf("created test database: %s", file.Name())
	}
	return file.Name()
}

func InitializeTestDB() (db *DB, path string, err error) {

	path = createTestDBFile()
	db, err = initializeDB(path)
	if err != nil {
		return nil, "", err
	}

	migrateDB(db)

	return db, path, nil

}

func InitializeTestDBWithSQL(sqlFilePath string) (db *DB, path string, err error) {

	path = createTestDBFile()
	db, err = initializeDB(path)
	if err != nil {
		return nil, "", err
	}

	tx := db.Begin()
	if sqlFilePath != "" {
		statements, err := ioutil.ReadFile(sqlFilePath)
		if err != nil {
			return nil, "", err
		}

		tx.Exec(string(statements), []interface{}{})

	}
	tx.Commit()

	migrateDB(db)

	return db, path, nil

}

func migrateDB(db *DB) {
	tx := db.Begin()
	tx.AutoMigrate(&Slave{}, &ReplicaSet{}, &RiskGroup{}, &Mongod{}, &MongodState{}, &ReplicaSetMember{}, &Problem{}, &MSPError{})
	if err := createSlaveUtilizationView(tx); err != nil {
		panic(err)
	}
	if err := createReplicaSetEffectiveMembersView(tx); err != nil {
		panic(err)
	}
	if err := createReplicaSetConfiguredMembersView(tx); err != nil {
		panic(err)
	}
	tx.Commit()
}

func createReplicaSetEffectiveMembersView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS replica_set_effective_members;
		CREATE VIEW replica_set_effective_members AS
		SELECT r.id as replica_set_id, m.id as mongod_id, s.persistent_storage
		FROM replica_sets r
		JOIN mongods m ON m.replica_set_id = r.id
		JOIN slaves s ON s.id = m.parent_slave_id
		JOIN mongod_states observed ON observed.id = m.observed_state_id
		JOIN mongod_states desired ON desired.id = m.desired_state_id
		WHERE
		observed.execution_state = ` + fmt.Sprintf("%d", MongodExecutionStateRunning) + `
		AND
		desired.execution_state = ` + fmt.Sprintf("%d", MongodExecutionStateRunning) + `;`).Error
}

func createSlaveUtilizationView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS slave_utilization;
		CREATE VIEW slave_utilization AS
		SELECT
			*,
			CASE WHEN max_mongods = 0 THEN 1 ELSE current_mongods*1.0/max_mongods END AS utilization,
			(max_mongods - current_mongods) AS free_mongods
		FROM (
			SELECT
				s.*,
				s.mongod_port_range_end - s.mongod_port_range_begin AS max_mongods,
				COUNT(DISTINCT m.id) as current_mongods
			FROM slaves s
			LEFT OUTER JOIN mongods m ON m.parent_slave_id = s.id
			GROUP BY s.id
		);`).Error
}

func createReplicaSetConfiguredMembersView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS replica_set_configured_members;
		CREATE VIEW replica_set_configured_members AS
		SELECT r.id as replica_set_id, m.id as mongod_id, s.persistent_storage
		FROM replica_sets r
		JOIN mongods m ON m.replica_set_id = r.id
		JOIN mongod_states desired_state ON m.desired_state_id = desired_state.id
		JOIN slaves s ON m.parent_slave_id = s.id
		WHERE
			s.configured_state != ` + fmt.Sprintf("%d", SlaveStateDisabled) + `
			AND
			desired_state.execution_state NOT IN (` +
		fmt.Sprintf("%d", MongodExecutionStateNotRunning) +
		`, ` + fmt.Sprintf("%d", MongodExecutionStateDestroyed) +
		`);`).Error
}

func RollbackOnTransactionError(tx *gorm.DB, rollbackError *error) {
	switch e := recover(); e {
	case e == gorm.ErrInvalidTransaction:
		modelLog.Infof("ClusterAllocator: rolling back transaction after error: %v", e)
		*rollbackError = tx.Rollback().Error
		if *rollbackError != nil {
			modelLog.WithError(*rollbackError).Errorf("ClusterAllocator: failed rolling back transaction")
		}
	default:
		panic(e)
	}
}

func NullIntValue(value int64) sql.NullInt64 {
	return sql.NullInt64{Int64: value, Valid: true}
}

func NullInt() sql.NullInt64 {
	return sql.NullInt64{}
}

func NullIntToPtr(nullint sql.NullInt64) *int64 {
	if nullint.Valid {
		value := nullint.Int64
		return &value
	} else {
		return nil
	}
}

func PtrToNullInt(value *int64) sql.NullInt64 {
	if value != nil {
		return NullIntValue(*value)
	} else {
		return NullInt()
	}
}
<commit_msg>UPD: model: TODO on missing referential action for cleanup<commit_after>package model

import (
	"database/sql"
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"io/ioutil"
	"os"
	"time"
)

var modelLog = logrus.WithField("module", "model")

/*
	The structs defined in this file are stored in a database using the `gorm` package.

	Remember to
		Set primary key for a struct.
		Set constraints on specific fields where appropriate.
		Define UniqueIndexes either through a tag or through gorm.DB.AddUniqueIndex()
			for a Unique constraint over multiple fields

	Unless you have a good reason, declare attributes of a struct not null.

	Example:

		type MyType struct {
			Name string `gorm:"not null"`
		}

	Special Cases:

	Enums: 	EnumType.EnumItem => const EnumTypeEnumItem

		Structs using such 'enums' should declare appropriate constraints in the corresponding FieldTag,
		using go-sqlite3 syntax

		Example:

			type MyType struct {
				Name string `sql:"unique"`
			}

*/

type Slave struct {
	ID                   int64  `gorm:"primary_key"`
	Hostname             string `gorm:"unique_index"`
	Port                 PortNumber
	MongodPortRangeBegin PortNumber
	MongodPortRangeEnd   PortNumber
	PersistentStorage    bool
	Mongods              []*Mongod `gorm:"ForeignKey:ParentSlaveID"`
	ConfiguredState      SlaveState

	Problems []*Problem

	// Foreign keys
	RiskGroupID sql.NullInt64 `sql:"type:integer NULL REFERENCES risk_groups(id) DEFERRABLE INITIALLY DEFERRED"`
}

type PortNumber uint16

const (
	PortNumberMin PortNumber = 1
	PortNumberMax            = 65535
)

type SlaveState uint

const (
	_                           = 0
	SlaveStateActive SlaveState = iota
	SlaveStateMaintenance
	SlaveStateDisabled
)

type ReplicaSet struct {
	ID                              int64  `gorm:"primary_key"` //TODO needs to start incrementing at 1
	Name                            string `gorm:"unique_index"`
	PersistentMemberCount           uint
	VolatileMemberCount             uint
	ConfigureAsShardingConfigServer bool
	Mongods                         []*Mongod

	Problems []*Problem
}

type RiskGroup struct {
	ID     int64  `gorm:"primary_key"` //TODO needs to start incrementing at 1, 0 is special value for slaves "out of risk" => define a constant?
	Name   string `gorm:"unique_index"`
	Slaves []*Slave
}

type Mongod struct {
	// TODO missing UNIQUE constraint
	ID          int64 `gorm:"primary_key"`
	Port        PortNumber
	ReplSetName string

	ObservationError   MSPError
	ObservationErrorID sql.NullInt64 `sql:"type:integer NULL REFERENCES msp_errors(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"` // TODO not cleaned up on Mongod deletion right now

	LastEstablishStateError   MSPError
	LastEstablishStateErrorID sql.NullInt64 `sql:"type:integer NULL REFERENCES msp_errors(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"` // TODO not cleaned up on Mongod deletion right now

	ParentSlave   *Slave
	ParentSlaveID int64 `sql:"type:integer REFERENCES slaves(id) DEFERRABLE INITIALLY DEFERRED"`

	ReplicaSet   *ReplicaSet
	ReplicaSetID int64 `sql:"type:integer NULL REFERENCES replica_sets(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`

	DesiredState   MongodState
	DesiredStateID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongod_states(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"` // NOTE: we cascade on delete, i.e. when a desired state is deleted, the Mongod is deleted, too. This is the inversion of the semantic object hierarchy, but we'll stay with it for now.

	ObservedState   MongodState
	ObservedStateID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongod_states(id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED"`
}

type MongodState struct {
	ID                     int64 `gorm:"primary_key"`
	ParentMongod           *Mongod
	ParentMongodID         sql.NullInt64 `sql:"type:integer NOT NULL REFERENCES mongods(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`
	IsShardingConfigServer bool
	ExecutionState         MongodExecutionState
	ReplicaSetMembers      []ReplicaSetMember
}

type MongodExecutionState uint

const (
	_                                                  = 0
	MongodExecutionStateDestroyed MongodExecutionState = iota
	MongodExecutionStateNotRunning
	MongodExecutionStateRecovering // invalid for a desired MongodState
	MongodExecutionStateRunning
)

type ReplicaSetMember struct { // was ReplicaSetMember in UML
	// TODO missing primary key.
	ID       int64 `gorm:"primary_key"`
	Hostname string
	Port     PortNumber

	// Foreign key to parent MongodState
	MongodStateID int64 `sql:"type:integer REFERENCES mongod_states(id) DEFERRABLE INITIALLY DEFERRED"`
}

// msp.Error
// duplicated for decoupling protocol & internal representation
type MSPError struct {
	ID              int64 `gorm:"primary_key"`
	Identifier      string
	Description     string
	LongDescription string
}

type ProblemType uint

const (
	_                                 = 0
	ProblemTypeConnection ProblemType = iota
	ProblemTypeMismatch
	ProblemTypeDesiredReplicaSetConstraint
	ProblemTypeObservedReplicaSetConstraint
)

type Problem struct {
	ID              int64 `gorm:"primary_key"`
	Description     string
	LongDescription string
	ProblemType     ProblemType
	FirstOccurred   time.Time
	LastUpdated     time.Time

	Slave   *Slave
	SlaveID sql.NullInt64 `sql:"type:integer NULL REFERENCES slaves(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`

	ReplicaSet   *ReplicaSet
	ReplicaSetID sql.NullInt64 `sql:"type:integer NULL REFERENCES replica_sets(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`

	Mongod   *Mongod
	MongodID sql.NullInt64 `sql:"type:integer NULL REFERENCES mongods(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"`
}

type DB struct {
	gormDB *gorm.DB
}

func initializeDB(dsn string) (*DB, error) {

	gormDB, err := gorm.Open("sqlite3", dsn)
	if err != nil {
		return nil, err
	}

	db := &DB{
		gormDB: gormDB,
	}

	gormDB.SetLogger(modelLog)

	return db, nil

}

func (db *DB) Begin() *gorm.DB {
	tx := db.gormDB.Begin()
	return tx
}

func InitializeFileFromFile(path string) (db *DB, err error) {

	db, err = initializeDB(path)
	if err != nil {
		return nil, err
	}

	migrateDB(db)

	return db, nil

}

func createTestDBFile() (path string) {
	file, err := ioutil.TempFile(os.TempDir(), "mamid-")
	if err != nil {
		modelLog.Fatalf("could not create test database file: %s", err)
	} else {
		modelLog.Debugf("created test database: %s", file.Name())
	}
	return file.Name()
}

func InitializeTestDB() (db *DB, path string, err error) {

	path = createTestDBFile()
	db, err = initializeDB(path)
	if err != nil {
		return nil, "", err
	}

	migrateDB(db)

	return db, path, nil

}

func InitializeTestDBWithSQL(sqlFilePath string) (db *DB, path string, err error) {

	path = createTestDBFile()
	db, err = initializeDB(path)
	if err != nil {
		return nil, "", err
	}

	tx := db.Begin()
	if sqlFilePath != "" {
		statements, err := ioutil.ReadFile(sqlFilePath)
		if err != nil {
			return nil, "", err
		}

		tx.Exec(string(statements), []interface{}{})

	}
	tx.Commit()

	migrateDB(db)

	return db, path, nil

}

func migrateDB(db *DB) {
	tx := db.Begin()
	tx.AutoMigrate(&Slave{}, &ReplicaSet{}, &RiskGroup{}, &Mongod{}, &MongodState{}, &ReplicaSetMember{}, &Problem{}, &MSPError{})
	if err := createSlaveUtilizationView(tx); err != nil {
		panic(err)
	}
	if err := createReplicaSetEffectiveMembersView(tx); err != nil {
		panic(err)
	}
	if err := createReplicaSetConfiguredMembersView(tx); err != nil {
		panic(err)
	}
	tx.Commit()
}

func createReplicaSetEffectiveMembersView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS replica_set_effective_members;
		CREATE VIEW replica_set_effective_members AS
		SELECT r.id as replica_set_id, m.id as mongod_id, s.persistent_storage
		FROM replica_sets r
		JOIN mongods m ON m.replica_set_id = r.id
		JOIN slaves s ON s.id = m.parent_slave_id
		JOIN mongod_states observed ON observed.id = m.observed_state_id
		JOIN mongod_states desired ON desired.id = m.desired_state_id
		WHERE
		observed.execution_state = ` + fmt.Sprintf("%d", MongodExecutionStateRunning) + `
		AND
		desired.execution_state = ` + fmt.Sprintf("%d", MongodExecutionStateRunning) + `;`).Error
}

func createSlaveUtilizationView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS slave_utilization;
		CREATE VIEW slave_utilization AS
		SELECT
			*,
			CASE WHEN max_mongods = 0 THEN 1 ELSE current_mongods*1.0/max_mongods END AS utilization,
			(max_mongods - current_mongods) AS free_mongods
		FROM (
			SELECT
				s.*,
				s.mongod_port_range_end - s.mongod_port_range_begin AS max_mongods,
				COUNT(DISTINCT m.id) as current_mongods
			FROM slaves s
			LEFT OUTER JOIN mongods m ON m.parent_slave_id = s.id
			GROUP BY s.id
		);`).Error
}

func createReplicaSetConfiguredMembersView(tx *gorm.DB) error {
	return tx.Exec(`
		DROP VIEW IF EXISTS replica_set_configured_members;
		CREATE VIEW replica_set_configured_members AS
		SELECT r.id as replica_set_id, m.id as mongod_id, s.persistent_storage
		FROM replica_sets r
		JOIN mongods m ON m.replica_set_id = r.id
		JOIN mongod_states desired_state ON m.desired_state_id = desired_state.id
		JOIN slaves s ON m.parent_slave_id = s.id
		WHERE
			s.configured_state != ` + fmt.Sprintf("%d", SlaveStateDisabled) + `
			AND
			desired_state.execution_state NOT IN (` +
		fmt.Sprintf("%d", MongodExecutionStateNotRunning) +
		`, ` + fmt.Sprintf("%d", MongodExecutionStateDestroyed) +
		`);`).Error
}

func RollbackOnTransactionError(tx *gorm.DB, rollbackError *error) {
	switch e := recover(); e {
	case e == gorm.ErrInvalidTransaction:
		modelLog.Infof("ClusterAllocator: rolling back transaction after error: %v", e)
		*rollbackError = tx.Rollback().Error
		if *rollbackError != nil {
			modelLog.WithError(*rollbackError).Errorf("ClusterAllocator: failed rolling back transaction")
		}
	default:
		panic(e)
	}
}

func NullIntValue(value int64) sql.NullInt64 {
	return sql.NullInt64{Int64: value, Valid: true}
}

func NullInt() sql.NullInt64 {
	return sql.NullInt64{}
}

func NullIntToPtr(nullint sql.NullInt64) *int64 {
	if nullint.Valid {
		value := nullint.Int64
		return &value
	} else {
		return nil
	}
}

func PtrToNullInt(value *int64) sql.NullInt64 {
	if value != nil {
		return NullIntValue(*value)
	} else {
		return NullInt()
	}
}
<|endoftext|>


<commit_before>// Status-bar
package mastodon

import (
    "bytes"
    "fmt"
    "os"
    "runtime"
    "syscall"
    "time"
)

type Config struct {
    Data map[string]string
    BarSize int
}

const (
    STATUS_GOOD = iota
    STATUS_BAD
    STATUS_NORMAL
)

type StatusInfo struct {
    FullText string
    Status int64
}

func NewStatus() *StatusInfo {
    si := new(StatusInfo)
    si.Status = STATUS_NORMAL
    return si
}

func (si *StatusInfo) IsGood() bool {
    return si.Status == STATUS_GOOD
}

func (si *StatusInfo) IsBad() bool {
    return si.Status == STATUS_BAD
}

func getBarString(percent float64, bar_size int) string {
    var bar bytes.Buffer
    cutoff := int(percent * .01 * float64(bar_size))
    bar.WriteString("[")
    for i := 0; i < bar_size; i += 1 {
        if i <= cutoff {
            bar.WriteString("#")
        } else {
            bar.WriteString(" ")
        }
    }
    bar.WriteString("]")
    return bar.String()
}

func Battery(c *Config) *StatusInfo {
    si := NewStatus()
    bi := ReadBatteryInfo(0)
    barString := getBarString(bi.PercentRemaining, c.BarSize)
    prefix := "BAT"
    if bi.IsCharging() {
        prefix = "CHR"
    }
    if bi.IsFull() {
        prefix = "FULL"
        si.FullText = fmt.Sprintf("%s %s", prefix, barString)
    } else {
        si.FullText = fmt.Sprintf(
            "%s %s (%s %.1fW)",
            prefix,
            barString,
            HumanDuration(int64(bi.SecondsRemaining)),
            bi.Consumption)
    }
    if bi.PercentRemaining < 15 {
        si.Status = STATUS_BAD
    }
    return si
}

func CPU(c *Config) *StatusInfo {
    si := NewStatus()
    cpuUsage := CpuUsage()
    barString := getBarString(cpuUsage, c.BarSize)
    si.FullText = fmt.Sprintf("C %s", barString)
    if cpuUsage > 80 {
        si.Status = STATUS_BAD
    }
    return si
}

func Disk(c *Config) *StatusInfo {
    si := NewStatus()
    free, total := DiskUsage("/")
    freePercent := 100 * (free / total)
    barString := getBarString(freePercent, c.BarSize)
    si.FullText = fmt.Sprintf("D %s", barString)
    if (free / total) < .1 {
        si.Status = STATUS_BAD
    }
    return si
}

func Memory(c *Config) *StatusInfo {
    si := NewStatus()
    free, total := MemInfo()
    percentUsed := 100 * (total - free) / total
    si.FullText = fmt.Sprintf("R %s", getBarString(percentUsed, c.BarSize))
    if percentUsed > 75 {
        si.Status = STATUS_BAD
    }
    return si
}

func LoadAvg(c *Config) *StatusInfo {
    si := NewStatus()
    cpu := float64(runtime.NumCPU())
    one, five, fifteen := ReadLoadAvg()
    si.FullText = fmt.Sprintf("%.2f %.2f %.2f", one, five, fifteen)
    if one > cpu {
        si.Status = STATUS_BAD
    }
    return si
}

func Clock(c *Config) *StatusInfo {
    si := NewStatus()
    si.FullText = time.Now().Format("2006-01-02 15:04:05")
    return si
}

func IPAddress(c *Config) *StatusInfo {
    si := NewStatus()
    si.FullText = IfaceAddr("wlan0")
    return si
}

func Hostname(c *Config) *StatusInfo {
    si := NewStatus()
    host, _ := os.Hostname()
    si.FullText = host
    return si
}

func Uptime(c *Config) *StatusInfo {
    buf := new(syscall.Sysinfo_t)
    syscall.Sysinfo(buf)
    si := NewStatus()
    si.FullText = fmt.Sprintf("U: %s", HumanDuration(buf.Uptime))
    return si
}

// Cache weather data.
var latestWeatherStatus StatusInfo
var latestWeatherCheck time.Time

func Weather(c *Config) *StatusInfo {
    si := NewStatus()
    if time.Since(latestWeatherCheck) < (time.Duration(1800) * time.Second) {
        return &latestWeatherStatus
    }
    forecast, err := ReadWeather(c.Data["weather_key"], c.Data["weather_zip"])
    latestWeatherCheck = time.Now()
    if err != nil || len(forecast.Forecast.SimpleForecast.ForecastDay) == 0 {
        si.FullText = "Error fetching weather"
        si.Status = STATUS_BAD
    } else {
        today := forecast.Forecast.SimpleForecast.ForecastDay[0]
        si.FullText = fmt.Sprintf(
            "%s H %s, L %s",
            today.Conditions,
            today.High.Fahrenheit,
            today.Low.Fahrenheit)
    }
    latestWeatherStatus = *si
    return si
}
<commit_msg>Show next weather if diff<commit_after>// Status-bar
package mastodon

import (
    "bytes"
    "fmt"
    "os"
    "runtime"
    "syscall"
    "time"
)

type Config struct {
    Data map[string]string
    BarSize int
}

const (
    STATUS_GOOD = iota
    STATUS_BAD
    STATUS_NORMAL
)

type StatusInfo struct {
    FullText string
    Status int64
}

func NewStatus() *StatusInfo {
    si := new(StatusInfo)
    si.Status = STATUS_NORMAL
    return si
}

func (si *StatusInfo) IsGood() bool {
    return si.Status == STATUS_GOOD
}

func (si *StatusInfo) IsBad() bool {
    return si.Status == STATUS_BAD
}

func getBarString(percent float64, bar_size int) string {
    var bar bytes.Buffer
    cutoff := int(percent * .01 * float64(bar_size))
    bar.WriteString("[")
    for i := 0; i < bar_size; i += 1 {
        if i <= cutoff {
            bar.WriteString("#")
        } else {
            bar.WriteString(" ")
        }
    }
    bar.WriteString("]")
    return bar.String()
}

func Battery(c *Config) *StatusInfo {
    si := NewStatus()
    bi := ReadBatteryInfo(0)
    barString := getBarString(bi.PercentRemaining, c.BarSize)
    prefix := "BAT"
    if bi.IsCharging() {
        prefix = "CHR"
    }
    if bi.IsFull() {
        prefix = "FULL"
        si.FullText = fmt.Sprintf("%s %s", prefix, barString)
    } else {
        si.FullText = fmt.Sprintf(
            "%s %s (%s %.1fW)",
            prefix,
            barString,
            HumanDuration(int64(bi.SecondsRemaining)),
            bi.Consumption)
    }
    if bi.PercentRemaining < 15 {
        si.Status = STATUS_BAD
    }
    return si
}

func CPU(c *Config) *StatusInfo {
    si := NewStatus()
    cpuUsage := CpuUsage()
    barString := getBarString(cpuUsage, c.BarSize)
    si.FullText = fmt.Sprintf("C %s", barString)
    if cpuUsage > 80 {
        si.Status = STATUS_BAD
    }
    return si
}

func Disk(c *Config) *StatusInfo {
    si := NewStatus()
    free, total := DiskUsage("/")
    freePercent := 100 * (free / total)
    barString := getBarString(freePercent, c.BarSize)
    si.FullText = fmt.Sprintf("D %s", barString)
    if (free / total) < .1 {
        si.Status = STATUS_BAD
    }
    return si
}

func Memory(c *Config) *StatusInfo {
    si := NewStatus()
    free, total := MemInfo()
    percentUsed := 100 * (total - free) / total
    si.FullText = fmt.Sprintf("R %s", getBarString(percentUsed, c.BarSize))
    if percentUsed > 75 {
        si.Status = STATUS_BAD
    }
    return si
}

func LoadAvg(c *Config) *StatusInfo {
    si := NewStatus()
    cpu := float64(runtime.NumCPU())
    one, five, fifteen := ReadLoadAvg()
    si.FullText = fmt.Sprintf("%.2f %.2f %.2f", one, five, fifteen)
    if one > cpu {
        si.Status = STATUS_BAD
    }
    return si
}

func Clock(c *Config) *StatusInfo {
    si := NewStatus()
    si.FullText = time.Now().Format("2006-01-02 15:04:05")
    return si
}

func IPAddress(c *Config) *StatusInfo {
    si := NewStatus()
    si.FullText = IfaceAddr("wlan0")
    return si
}

func Hostname(c *Config) *StatusInfo {
    si := NewStatus()
    host, _ := os.Hostname()
    si.FullText = host
    return si
}

func Uptime(c *Config) *StatusInfo {
    buf := new(syscall.Sysinfo_t)
    syscall.Sysinfo(buf)
    si := NewStatus()
    si.FullText = fmt.Sprintf("U: %s", HumanDuration(buf.Uptime))
    return si
}

// Cache weather data.
var latestWeatherStatus StatusInfo
var latestWeatherCheck time.Time

func Weather(c *Config) *StatusInfo {
    si := NewStatus()
    if time.Since(latestWeatherCheck) < (time.Duration(1800) * time.Second) {
        return &latestWeatherStatus
    }
    forecast, err := ReadWeather(c.Data["weather_key"], c.Data["weather_zip"])
    latestWeatherCheck = time.Now()
    if err != nil || len(forecast.Forecast.SimpleForecast.ForecastDay) == 0 {
        si.FullText = "Error fetching weather"
        si.Status = STATUS_BAD
    } else {
        today := forecast.Forecast.SimpleForecast.ForecastDay[0]
        next := forecast.Forecast.SimpleForecast.ForecastDay[1]
        si.FullText = fmt.Sprintf(
            "%s %s/%s",
            today.Conditions,
            today.High.Fahrenheit,
            today.Low.Fahrenheit)
        if next.Conditions != today.Conditions {
            si.FullText += fmt.Sprintf(" (%s)", next.Conditions)
        }
    }
    latestWeatherStatus = *si
    return si
}
<|endoftext|>


<commit_before>// Package mastodon provides functions and structs for accessing the mastodon API.
package mastodon

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tomnomnom/linkheader"
)

// Config is a setting for access mastodon APIs.
type Config struct {
	Server       string
	ClientID     string
	ClientSecret string
	AccessToken  string
}

// Client is a API client for mastodon.
type Client struct {
	http.Client
	Config    *Config
	UserAgent string
}

func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) error {
	u, err := url.Parse(c.Config.Server)
	if err != nil {
		return err
	}
	u.Path = path.Join(u.Path, uri)

	var req *http.Request
	ct := "application/x-www-form-urlencoded"
	if values, ok := params.(url.Values); ok {
		var body io.Reader
		if method == http.MethodGet {
			if pg != nil {
				values = pg.setValues(values)
			}
			u.RawQuery = values.Encode()
		} else {
			body = strings.NewReader(values.Encode())
		}
		req, err = http.NewRequest(method, u.String(), body)
		if err != nil {
			return err
		}
	} else if file, ok := params.(string); ok {
		f, err := os.Open(file)
		if err != nil {
			return err
		}
		defer f.Close()

		var buf bytes.Buffer
		mw := multipart.NewWriter(&buf)
		part, err := mw.CreateFormFile("file", filepath.Base(file))
		if err != nil {
			return err
		}
		_, err = io.Copy(part, f)
		if err != nil {
			return err
		}
		err = mw.Close()
		if err != nil {
			return err
		}
		req, err = http.NewRequest(method, u.String(), &buf)
		if err != nil {
			return err
		}
		ct = mw.FormDataContentType()
	} else if reader, ok := params.(io.Reader); ok {
		var buf bytes.Buffer
		mw := multipart.NewWriter(&buf)
		part, err := mw.CreateFormFile("file", "upload")
		if err != nil {
			return err
		}
		_, err = io.Copy(part, reader)
		if err != nil {
			return err
		}
		err = mw.Close()
		if err != nil {
			return err
		}
		req, err = http.NewRequest(method, u.String(), &buf)
		if err != nil {
			return err
		}
		ct = mw.FormDataContentType()
	} else {
		if method == http.MethodGet && pg != nil {
			u.RawQuery = pg.toValues().Encode()
		}
		req, err = http.NewRequest(method, u.String(), nil)
		if err != nil {
			return err
		}
	}
	req = req.WithContext(ctx)
	req.Header.Set("Authorization", "Bearer "+c.Config.AccessToken)
	if params != nil {
		req.Header.Set("Content-Type", ct)
	}
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}

	var resp *http.Response
	backoff := time.Second
	for {
		resp, err = c.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// handle status code 429, which indicates the server is throttling
		// our requests. Do an exponential backoff and retry the request.
		if resp.StatusCode == 429 {
			if backoff > time.Hour {
				break
			}

			select {
			case <-time.After(backoff):
			case <-ctx.Done():
				return ctx.Err()
			}

			backoff = time.Duration(1.5 * float64(backoff))
			continue
		}
		break
	}

	if resp.StatusCode != http.StatusOK {
		return parseAPIError("bad request", resp)
	} else if res == nil {
		return nil
	} else if pg != nil {
		if lh := resp.Header.Get("Link"); lh != "" {
			pg2, err := newPagination(lh)
			if err != nil {
				return err
			}
			*pg = *pg2
		}
	}
	return json.NewDecoder(resp.Body).Decode(&res)
}

// NewClient return new mastodon API client.
func NewClient(config *Config) *Client {
	return &Client{
		Client: *http.DefaultClient,
		Config: config,
	}
}

// Authenticate get access-token to the API.
func (c *Client) Authenticate(ctx context.Context, username, password string) error {
	params := url.Values{
		"client_id":     {c.Config.ClientID},
		"client_secret": {c.Config.ClientSecret},
		"grant_type":    {"password"},
		"username":      {username},
		"password":      {password},
		"scope":         {"read write follow"},
	}

	return c.authenticate(ctx, params)
}

// AuthenticateToken logs in using a grant token returned by Application.AuthURI.
//
// redirectURI should be the same as Application.RedirectURI.
func (c *Client) AuthenticateToken(ctx context.Context, authCode, redirectURI string) error {
	params := url.Values{
		"client_id":     {c.Config.ClientID},
		"client_secret": {c.Config.ClientSecret},
		"grant_type":    {"authorization_code"},
		"code":          {authCode},
		"redirect_uri":  {redirectURI},
	}

	return c.authenticate(ctx, params)
}

func (c *Client) authenticate(ctx context.Context, params url.Values) error {
	u, err := url.Parse(c.Config.Server)
	if err != nil {
		return err
	}
	u.Path = path.Join(u.Path, "/oauth/token")

	req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return parseAPIError("bad authorization", resp)
	}

	var res struct {
		AccessToken string `json:"access_token"`
	}
	err = json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		return err
	}
	c.Config.AccessToken = res.AccessToken
	return nil
}

// Convenience constants for Toot.Visibility
const (
	VisibilityPublic        = "public"
	VisibilityUnlisted      = "unlisted"
	VisibilityFollowersOnly = "private"
	VisibilityDirectMessage = "direct"
)

// Toot is struct to post status.
type Toot struct {
	Status      string     `json:"status"`
	InReplyToID ID         `json:"in_reply_to_id"`
	MediaIDs    []ID       `json:"media_ids"`
	Sensitive   bool       `json:"sensitive"`
	SpoilerText string     `json:"spoiler_text"`
	Visibility  string     `json:"visibility"`
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
}

// Mention hold information for mention.
type Mention struct {
	URL      string `json:"url"`
	Username string `json:"username"`
	Acct     string `json:"acct"`
	ID       ID     `json:"id"`
}

// Tag hold information for tag.
type Tag struct {
	Name    string    `json:"name"`
	URL     string    `json:"url"`
	History []History `json:"history"`
}

// History hold information for history.
type History struct {
	Day      string `json:"day"`
	Uses     int64  `json:"uses"`
	Accounts int64  `json:"accounts"`
}

// Attachment hold information for attachment.
type Attachment struct {
	ID          ID             `json:"id"`
	Type        string         `json:"type"`
	URL         string         `json:"url"`
	RemoteURL   string         `json:"remote_url"`
	PreviewURL  string         `json:"preview_url"`
	TextURL     string         `json:"text_url"`
	Description string         `json:"description"`
	Meta        AttachmentMeta `json:"meta"`
}

// AttachmentMeta holds information for attachment metadata.
type AttachmentMeta struct {
	Original AttachmentSize `json:"original"`
	Small    AttachmentSize `json:"small"`
}

// AttachmentSize holds information for attatchment size.
type AttachmentSize struct {
	Width  int64   `json:"width"`
	Height int64   `json:"height"`
	Size   string  `json:"size"`
	Aspect float64 `json:"aspect"`
}

// Emoji hold information for CustomEmoji.
type Emoji struct {
	ShortCode       string `json:"shortcode"`
	StaticURL       string `json:"static_url"`
	URL             string `json:"url"`
	VisibleInPicker bool   `json:"visible_in_picker"`
}

// Results hold information for search result.
type Results struct {
	Accounts []*Account `json:"accounts"`
	Statuses []*Status  `json:"statuses"`
	Hashtags []*Tag     `json:"hashtags"`
}

// Pagination is a struct for specifying the get range.
type Pagination struct {
	MaxID   ID
	SinceID ID
	MinID   ID
	Limit   int64
}

func newPagination(rawlink string) (*Pagination, error) {
	if rawlink == "" {
		return nil, errors.New("empty link header")
	}

	p := &Pagination{}
	for _, link := range linkheader.Parse(rawlink) {
		switch link.Rel {
		case "next":
			maxID, err := getPaginationID(link.URL, "max_id")
			if err != nil {
				return nil, err
			}
			p.MaxID = maxID
		case "prev":
			sinceID, err := getPaginationID(link.URL, "since_id")
			if err != nil {
				return nil, err
			}
			p.SinceID = sinceID

			minID, err := getPaginationID(link.URL, "min_id")
			if err != nil {
				return nil, err
			}
			p.MinID = minID
		}
	}

	return p, nil
}

func getPaginationID(rawurl, key string) (ID, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}

	return ID(u.Query().Get(key)), nil
}

func (p *Pagination) toValues() url.Values {
	return p.setValues(url.Values{})
}

func (p *Pagination) setValues(params url.Values) url.Values {
	if p.MaxID != "" {
		params.Set("max_id", string(p.MaxID))
	}
	if p.SinceID != "" {
		params.Set("since_id", string(p.SinceID))
	}
	if p.MinID != "" {
		params.Set("min_id", string(p.MinID))
	}
	if p.Limit > 0 {
		params.Set("limit", fmt.Sprint(p.Limit))
	}

	return params
}
<commit_msg>Fix History struct members<commit_after>// Package mastodon provides functions and structs for accessing the mastodon API.
package mastodon

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tomnomnom/linkheader"
)

// Config is a setting for access mastodon APIs.
type Config struct {
	Server       string
	ClientID     string
	ClientSecret string
	AccessToken  string
}

// Client is a API client for mastodon.
type Client struct {
	http.Client
	Config    *Config
	UserAgent string
}

func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) error {
	u, err := url.Parse(c.Config.Server)
	if err != nil {
		return err
	}
	u.Path = path.Join(u.Path, uri)

	var req *http.Request
	ct := "application/x-www-form-urlencoded"
	if values, ok := params.(url.Values); ok {
		var body io.Reader
		if method == http.MethodGet {
			if pg != nil {
				values = pg.setValues(values)
			}
			u.RawQuery = values.Encode()
		} else {
			body = strings.NewReader(values.Encode())
		}
		req, err = http.NewRequest(method, u.String(), body)
		if err != nil {
			return err
		}
	} else if file, ok := params.(string); ok {
		f, err := os.Open(file)
		if err != nil {
			return err
		}
		defer f.Close()

		var buf bytes.Buffer
		mw := multipart.NewWriter(&buf)
		part, err := mw.CreateFormFile("file", filepath.Base(file))
		if err != nil {
			return err
		}
		_, err = io.Copy(part, f)
		if err != nil {
			return err
		}
		err = mw.Close()
		if err != nil {
			return err
		}
		req, err = http.NewRequest(method, u.String(), &buf)
		if err != nil {
			return err
		}
		ct = mw.FormDataContentType()
	} else if reader, ok := params.(io.Reader); ok {
		var buf bytes.Buffer
		mw := multipart.NewWriter(&buf)
		part, err := mw.CreateFormFile("file", "upload")
		if err != nil {
			return err
		}
		_, err = io.Copy(part, reader)
		if err != nil {
			return err
		}
		err = mw.Close()
		if err != nil {
			return err
		}
		req, err = http.NewRequest(method, u.String(), &buf)
		if err != nil {
			return err
		}
		ct = mw.FormDataContentType()
	} else {
		if method == http.MethodGet && pg != nil {
			u.RawQuery = pg.toValues().Encode()
		}
		req, err = http.NewRequest(method, u.String(), nil)
		if err != nil {
			return err
		}
	}
	req = req.WithContext(ctx)
	req.Header.Set("Authorization", "Bearer "+c.Config.AccessToken)
	if params != nil {
		req.Header.Set("Content-Type", ct)
	}
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}

	var resp *http.Response
	backoff := time.Second
	for {
		resp, err = c.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// handle status code 429, which indicates the server is throttling
		// our requests. Do an exponential backoff and retry the request.
		if resp.StatusCode == 429 {
			if backoff > time.Hour {
				break
			}

			select {
			case <-time.After(backoff):
			case <-ctx.Done():
				return ctx.Err()
			}

			backoff = time.Duration(1.5 * float64(backoff))
			continue
		}
		break
	}

	if resp.StatusCode != http.StatusOK {
		return parseAPIError("bad request", resp)
	} else if res == nil {
		return nil
	} else if pg != nil {
		if lh := resp.Header.Get("Link"); lh != "" {
			pg2, err := newPagination(lh)
			if err != nil {
				return err
			}
			*pg = *pg2
		}
	}
	return json.NewDecoder(resp.Body).Decode(&res)
}

// NewClient return new mastodon API client.
func NewClient(config *Config) *Client {
	return &Client{
		Client: *http.DefaultClient,
		Config: config,
	}
}

// Authenticate get access-token to the API.
func (c *Client) Authenticate(ctx context.Context, username, password string) error {
	params := url.Values{
		"client_id":     {c.Config.ClientID},
		"client_secret": {c.Config.ClientSecret},
		"grant_type":    {"password"},
		"username":      {username},
		"password":      {password},
		"scope":         {"read write follow"},
	}

	return c.authenticate(ctx, params)
}

// AuthenticateToken logs in using a grant token returned by Application.AuthURI.
//
// redirectURI should be the same as Application.RedirectURI.
func (c *Client) AuthenticateToken(ctx context.Context, authCode, redirectURI string) error {
	params := url.Values{
		"client_id":     {c.Config.ClientID},
		"client_secret": {c.Config.ClientSecret},
		"grant_type":    {"authorization_code"},
		"code":          {authCode},
		"redirect_uri":  {redirectURI},
	}

	return c.authenticate(ctx, params)
}

func (c *Client) authenticate(ctx context.Context, params url.Values) error {
	u, err := url.Parse(c.Config.Server)
	if err != nil {
		return err
	}
	u.Path = path.Join(u.Path, "/oauth/token")

	req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(params.Encode()))
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	resp, err := c.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return parseAPIError("bad authorization", resp)
	}

	var res struct {
		AccessToken string `json:"access_token"`
	}
	err = json.NewDecoder(resp.Body).Decode(&res)
	if err != nil {
		return err
	}
	c.Config.AccessToken = res.AccessToken
	return nil
}

// Convenience constants for Toot.Visibility
const (
	VisibilityPublic        = "public"
	VisibilityUnlisted      = "unlisted"
	VisibilityFollowersOnly = "private"
	VisibilityDirectMessage = "direct"
)

// Toot is struct to post status.
type Toot struct {
	Status      string     `json:"status"`
	InReplyToID ID         `json:"in_reply_to_id"`
	MediaIDs    []ID       `json:"media_ids"`
	Sensitive   bool       `json:"sensitive"`
	SpoilerText string     `json:"spoiler_text"`
	Visibility  string     `json:"visibility"`
	ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
}

// Mention hold information for mention.
type Mention struct {
	URL      string `json:"url"`
	Username string `json:"username"`
	Acct     string `json:"acct"`
	ID       ID     `json:"id"`
}

// Tag hold information for tag.
type Tag struct {
	Name    string    `json:"name"`
	URL     string    `json:"url"`
	History []History `json:"history"`
}

// History hold information for history.
type History struct {
	Day      string `json:"day"`
	Uses     string `json:"uses"`
	Accounts string `json:"accounts"`
}

// Attachment hold information for attachment.
type Attachment struct {
	ID          ID             `json:"id"`
	Type        string         `json:"type"`
	URL         string         `json:"url"`
	RemoteURL   string         `json:"remote_url"`
	PreviewURL  string         `json:"preview_url"`
	TextURL     string         `json:"text_url"`
	Description string         `json:"description"`
	Meta        AttachmentMeta `json:"meta"`
}

// AttachmentMeta holds information for attachment metadata.
type AttachmentMeta struct {
	Original AttachmentSize `json:"original"`
	Small    AttachmentSize `json:"small"`
}

// AttachmentSize holds information for attatchment size.
type AttachmentSize struct {
	Width  int64   `json:"width"`
	Height int64   `json:"height"`
	Size   string  `json:"size"`
	Aspect float64 `json:"aspect"`
}

// Emoji hold information for CustomEmoji.
type Emoji struct {
	ShortCode       string `json:"shortcode"`
	StaticURL       string `json:"static_url"`
	URL             string `json:"url"`
	VisibleInPicker bool   `json:"visible_in_picker"`
}

// Results hold information for search result.
type Results struct {
	Accounts []*Account `json:"accounts"`
	Statuses []*Status  `json:"statuses"`
	Hashtags []*Tag     `json:"hashtags"`
}

// Pagination is a struct for specifying the get range.
type Pagination struct {
	MaxID   ID
	SinceID ID
	MinID   ID
	Limit   int64
}

func newPagination(rawlink string) (*Pagination, error) {
	if rawlink == "" {
		return nil, errors.New("empty link header")
	}

	p := &Pagination{}
	for _, link := range linkheader.Parse(rawlink) {
		switch link.Rel {
		case "next":
			maxID, err := getPaginationID(link.URL, "max_id")
			if err != nil {
				return nil, err
			}
			p.MaxID = maxID
		case "prev":
			sinceID, err := getPaginationID(link.URL, "since_id")
			if err != nil {
				return nil, err
			}
			p.SinceID = sinceID

			minID, err := getPaginationID(link.URL, "min_id")
			if err != nil {
				return nil, err
			}
			p.MinID = minID
		}
	}

	return p, nil
}

func getPaginationID(rawurl, key string) (ID, error) {
	u, err := url.Parse(rawurl)
	if err != nil {
		return "", err
	}

	return ID(u.Query().Get(key)), nil
}

func (p *Pagination) toValues() url.Values {
	return p.setValues(url.Values{})
}

func (p *Pagination) setValues(params url.Values) url.Values {
	if p.MaxID != "" {
		params.Set("max_id", string(p.MaxID))
	}
	if p.SinceID != "" {
		params.Set("since_id", string(p.SinceID))
	}
	if p.MinID != "" {
		params.Set("min_id", string(p.MinID))
	}
	if p.Limit > 0 {
		params.Set("limit", fmt.Sprint(p.Limit))
	}

	return params
}
<|endoftext|>


<commit_before>// Copyright ©2017 The gonum 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 mat

import (
	"gonum.org/v1/gonum/blas/blas64"
)

var (
	bandDense *BandDense
	_         Matrix    = bandDense
	_         Banded    = bandDense
	_         RawBander = bandDense
)

// BandDense represents a band matrix in dense storage format.
type BandDense struct {
	mat blas64.Band
}

// Banded is a band matrix representation.
type Banded interface {
	Matrix
	// Bandwidth returns the lower and upper bandwidth values for
	// the matrix. The total bandwidth of the matrix is kl+ku+1.
	Bandwidth() (kl, ku int)

	// TBand is the equivalent of the T() method in the Matrix
	// interface but guarantees the transpose is of banded type.
	TBand() Banded
}

// A RawBander can return a blas64.Band representation of the receiver.
// Changes to the blas64.Band.Data slice will be reflected in the original
// matrix, changes to the Rows, Cols, KL, KU and Stride fields will not.
type RawBander interface {
	RawBand() blas64.Band
}

var (
	_ Matrix            = TransposeBand{}
	_ Banded            = TransposeBand{}
	_ UntransposeBander = TransposeBand{}
)

// TransposeBand is a type for performing an implicit transpose of a band
// matrix. It implements the Banded interface, returning values from the
// transpose of the matrix within.
type TransposeBand struct {
	Banded Banded
}

// At returns the value of the element at row i and column j of the transposed
// matrix, that is, row j and column i of the Banded field.
func (t TransposeBand) At(i, j int) float64 {
	return t.Banded.At(j, i)
}

// Dims returns the dimensions of the transposed matrix.
func (t TransposeBand) Dims() (r, c int) {
	c, r = t.Banded.Dims()
	return r, c
}

// T performs an implicit transpose by returning the Banded field.
func (t TransposeBand) T() Matrix {
	return t.Banded
}

// Bandwidth returns the number of rows/columns in the matrix and its orientation.
func (t TransposeBand) Bandwidth() (kl, ku int) {
	kl, ku = t.Banded.Bandwidth()
	return ku, kl
}

// TBand performs an implicit transpose by returning the Banded field.
func (t TransposeBand) TBand() Banded {
	return t.Banded
}

// Untranspose returns the Banded field.
func (t TransposeBand) Untranspose() Matrix {
	return t.Banded
}

// UntransposeBand returns the Banded field.
func (t TransposeBand) UntransposeBand() Banded {
	return t.Banded
}

// NewBandDense creates a new Band matrix with r rows and c columns. If data == nil,
// a new slice is allocated for the backing slice. If len(data) == min(r, c+kl)*(kl+ku+1),
// data is used as the backing slice, and changes to the elements of the returned
// BandDense will be reflected in data. If neither of these is true, NewBandDense
// will panic. kl must be at least zero and less r, and ku must be at least zero and
// less than c, otherwise NewBandDense will panic.
//
// The data must be arranged in row-major order constructed by removing the zeros
// from the rows outside the band and aligning the diagonals. For example, the matrix
//    1  2  3  0  0  0
//    4  5  6  7  0  0
//    0  8  9 10 11  0
//    0  0 12 13 14 15
//    0  0  0 16 17 18
//    0  0  0  0 19 20
// becomes (* entries are never accessed)
//     *  1  2  3
//     4  5  6  7
//     8  9 10 11
//    12 13 14 15
//    16 17 18  *
//    19 20  *  *
// which is passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2.
// Only the values in the band portion of the matrix are used.
func NewBandDense(r, c, kl, ku int, data []float64) *BandDense {
	if r < 0 || c < 0 || kl < 0 || ku < 0 {
		panic("mat: negative dimension")
	}
	if kl+1 > r || ku+1 > c {
		panic("mat: band out of range")
	}
	bc := kl + ku + 1
	if data != nil && len(data) != min(r, c+kl)*bc {
		panic(ErrShape)
	}
	if data == nil {
		data = make([]float64, min(r, c+kl)*bc)
	}
	return &BandDense{
		mat: blas64.Band{
			Rows:   r,
			Cols:   c,
			KL:     kl,
			KU:     ku,
			Stride: bc,
			Data:   data,
		},
	}
}

// NewDiagonalRect is a convenience function that returns a diagonal matrix represented by a
// BandDense. The length of data must be min(r, c) otherwise NewDiagonalRect will panic.
func NewDiagonalRect(r, c int, data []float64) *BandDense {
	return NewBandDense(r, c, 0, 0, data)
}

// Dims returns the number of rows and columns in the matrix.
func (b *BandDense) Dims() (r, c int) {
	return b.mat.Rows, b.mat.Cols
}

// Bandwidth returns the upper and lower bandwidths of the matrix.
func (b *BandDense) Bandwidth() (kl, ku int) {
	return b.mat.KL, b.mat.KU
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
func (b *BandDense) T() Matrix {
	return Transpose{b}
}

// TBand performs an implicit transpose by returning the receiver inside a TransposeBand.
func (b *BandDense) TBand() Banded {
	return TransposeBand{b}
}

// RawBand returns the underlying blas64.Band used by the receiver.
// Changes to elements in the receiver following the call will be reflected
// in returned blas64.Band.
func (b *BandDense) RawBand() blas64.Band {
	return b.mat
}
<commit_msg>mat: fix comment for TransposeBand.Bandwidth<commit_after>// Copyright ©2017 The gonum 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 mat

import (
	"gonum.org/v1/gonum/blas/blas64"
)

var (
	bandDense *BandDense
	_         Matrix    = bandDense
	_         Banded    = bandDense
	_         RawBander = bandDense
)

// BandDense represents a band matrix in dense storage format.
type BandDense struct {
	mat blas64.Band
}

// Banded is a band matrix representation.
type Banded interface {
	Matrix
	// Bandwidth returns the lower and upper bandwidth values for
	// the matrix. The total bandwidth of the matrix is kl+ku+1.
	Bandwidth() (kl, ku int)

	// TBand is the equivalent of the T() method in the Matrix
	// interface but guarantees the transpose is of banded type.
	TBand() Banded
}

// A RawBander can return a blas64.Band representation of the receiver.
// Changes to the blas64.Band.Data slice will be reflected in the original
// matrix, changes to the Rows, Cols, KL, KU and Stride fields will not.
type RawBander interface {
	RawBand() blas64.Band
}

var (
	_ Matrix            = TransposeBand{}
	_ Banded            = TransposeBand{}
	_ UntransposeBander = TransposeBand{}
)

// TransposeBand is a type for performing an implicit transpose of a band
// matrix. It implements the Banded interface, returning values from the
// transpose of the matrix within.
type TransposeBand struct {
	Banded Banded
}

// At returns the value of the element at row i and column j of the transposed
// matrix, that is, row j and column i of the Banded field.
func (t TransposeBand) At(i, j int) float64 {
	return t.Banded.At(j, i)
}

// Dims returns the dimensions of the transposed matrix.
func (t TransposeBand) Dims() (r, c int) {
	c, r = t.Banded.Dims()
	return r, c
}

// T performs an implicit transpose by returning the Banded field.
func (t TransposeBand) T() Matrix {
	return t.Banded
}

// Bandwidth returns the lower and upper bandwidth values for
// the transposed matrix.
func (t TransposeBand) Bandwidth() (kl, ku int) {
	kl, ku = t.Banded.Bandwidth()
	return ku, kl
}

// TBand performs an implicit transpose by returning the Banded field.
func (t TransposeBand) TBand() Banded {
	return t.Banded
}

// Untranspose returns the Banded field.
func (t TransposeBand) Untranspose() Matrix {
	return t.Banded
}

// UntransposeBand returns the Banded field.
func (t TransposeBand) UntransposeBand() Banded {
	return t.Banded
}

// NewBandDense creates a new Band matrix with r rows and c columns. If data == nil,
// a new slice is allocated for the backing slice. If len(data) == min(r, c+kl)*(kl+ku+1),
// data is used as the backing slice, and changes to the elements of the returned
// BandDense will be reflected in data. If neither of these is true, NewBandDense
// will panic. kl must be at least zero and less r, and ku must be at least zero and
// less than c, otherwise NewBandDense will panic.
//
// The data must be arranged in row-major order constructed by removing the zeros
// from the rows outside the band and aligning the diagonals. For example, the matrix
//    1  2  3  0  0  0
//    4  5  6  7  0  0
//    0  8  9 10 11  0
//    0  0 12 13 14 15
//    0  0  0 16 17 18
//    0  0  0  0 19 20
// becomes (* entries are never accessed)
//     *  1  2  3
//     4  5  6  7
//     8  9 10 11
//    12 13 14 15
//    16 17 18  *
//    19 20  *  *
// which is passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2.
// Only the values in the band portion of the matrix are used.
func NewBandDense(r, c, kl, ku int, data []float64) *BandDense {
	if r < 0 || c < 0 || kl < 0 || ku < 0 {
		panic("mat: negative dimension")
	}
	if kl+1 > r || ku+1 > c {
		panic("mat: band out of range")
	}
	bc := kl + ku + 1
	if data != nil && len(data) != min(r, c+kl)*bc {
		panic(ErrShape)
	}
	if data == nil {
		data = make([]float64, min(r, c+kl)*bc)
	}
	return &BandDense{
		mat: blas64.Band{
			Rows:   r,
			Cols:   c,
			KL:     kl,
			KU:     ku,
			Stride: bc,
			Data:   data,
		},
	}
}

// NewDiagonalRect is a convenience function that returns a diagonal matrix represented by a
// BandDense. The length of data must be min(r, c) otherwise NewDiagonalRect will panic.
func NewDiagonalRect(r, c int, data []float64) *BandDense {
	return NewBandDense(r, c, 0, 0, data)
}

// Dims returns the number of rows and columns in the matrix.
func (b *BandDense) Dims() (r, c int) {
	return b.mat.Rows, b.mat.Cols
}

// Bandwidth returns the upper and lower bandwidths of the matrix.
func (b *BandDense) Bandwidth() (kl, ku int) {
	return b.mat.KL, b.mat.KU
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
func (b *BandDense) T() Matrix {
	return Transpose{b}
}

// TBand performs an implicit transpose by returning the receiver inside a TransposeBand.
func (b *BandDense) TBand() Banded {
	return TransposeBand{b}
}

// RawBand returns the underlying blas64.Band used by the receiver.
// Changes to elements in the receiver following the call will be reflected
// in returned blas64.Band.
func (b *BandDense) RawBand() blas64.Band {
	return b.mat
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/i18n"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
)

type fileCmd struct {
	uid  int
	gid  int
	mode string
}

func (c *fileCmd) showByDefault() bool {
	return true
}

func (c *fileCmd) usage() string {
	return i18n.G(
		`Manage files on a container.

lxc file pull <source> [<source>...] <target>
lxc file push [--uid=UID] [--gid=GID] [--mode=MODE] <source> [<source>...] <target>
lxc file edit <file>

<source> in the case of pull, <target> in the case of push and <file> in the case of edit are <container name>/<path>`)
}

func (c *fileCmd) flags() {
	gnuflag.IntVar(&c.uid, "uid", -1, i18n.G("Set the file's uid on push"))
	gnuflag.IntVar(&c.gid, "gid", -1, i18n.G("Set the file's gid on push"))
	gnuflag.StringVar(&c.mode, "mode", "", i18n.G("Set the file's perms on push"))
}

func (c *fileCmd) push(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	target := args[len(args)-1]
	pathSpec := strings.SplitAfterN(target, "/", 2)

	if len(pathSpec) != 2 {
		return fmt.Errorf(i18n.G("Invalid target %s"), target)
	}

	targetPath := pathSpec[1]
	remote, container := config.ParseRemoteAndContainer(pathSpec[0])

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	mode := os.FileMode(0755)
	if c.mode != "" {
		m, err := strconv.ParseInt(c.mode, 0, 0)
		if err != nil {
			return err
		}
		mode = os.FileMode(m)
	}

	uid := 0
	if c.uid >= 0 {
		uid = c.uid
	}

	gid := 0
	if c.gid >= 0 {
		gid = c.gid
	}

	_, targetfilename := filepath.Split(targetPath)

	var sourcefilenames []string
	for _, fname := range args[:len(args)-1] {
		if !strings.HasPrefix(fname, "--") {
			sourcefilenames = append(sourcefilenames, fname)
		}
	}

	if (targetfilename != "") && (len(sourcefilenames) > 1) {
		return errArgs
	}

	/* Make sure all of the files are accessible by us before trying to
	 * push any of them. */
	var files []*os.File
	for _, f := range sourcefilenames {
		var file *os.File
		if f == "-" {
			file = os.Stdin
		} else {
			file, err = os.Open(f)
			if err != nil {
				return err
			}
		}

		defer file.Close()
		files = append(files, file)
	}

	for _, f := range files {
		fpath := targetPath
		if targetfilename == "" {
			fpath = path.Join(fpath, path.Base(f.Name()))
		}

		fMode, fUid, fGid, err := c.getOwner(f)
		if err != nil {
			return err
		}

		if c.mode != "" {
			mode = fMode
		}

		if c.uid == -1 {
			uid = fUid
		}

		if c.gid == -1 {
			gid = fGid
		}

		err = d.PushFile(container, fpath, gid, uid, mode, f)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *fileCmd) pull(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	target := args[len(args)-1]
	targetIsDir := false
	sb, err := os.Stat(target)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	/*
	 * If the path exists, just use it. If it doesn't exist, it might be a
	 * directory in one of two cases:
	 *   1. Someone explicitly put "/" at the end
	 *   2. Someone provided more than one source. In this case the target
	 *      should be a directory so we can save all the files into it.
	 */
	if err == nil {
		targetIsDir = sb.IsDir()
		if !targetIsDir && len(args)-1 > 1 {
			return fmt.Errorf(i18n.G("More than one file to download, but target is not a directory"))
		}
	} else if strings.HasSuffix(target, string(os.PathSeparator)) || len(args)-1 > 1 {
		if err := os.MkdirAll(target, 0755); err != nil {
			return err
		}
		targetIsDir = true
	}

	for _, f := range args[:len(args)-1] {
		pathSpec := strings.SplitN(f, "/", 2)
		if len(pathSpec) != 2 {
			return fmt.Errorf(i18n.G("Invalid source %s"), f)
		}

		remote, container := config.ParseRemoteAndContainer(pathSpec[0])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		_, _, _, buf, err := d.PullFile(container, pathSpec[1])
		if err != nil {
			return err
		}

		var targetPath string
		if targetIsDir {
			targetPath = path.Join(target, path.Base(pathSpec[1]))
		} else {
			targetPath = target
		}

		var f *os.File
		if targetPath == "-" {
			f = os.Stdout
		} else {
			f, err = os.Create(targetPath)
			if err != nil {
				return err
			}
			defer f.Close()
		}

		_, err = io.Copy(f, buf)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *fileCmd) edit(config *lxd.Config, args []string) error {
	if len(args) != 1 {
		return errArgs
	}

	// If stdin isn't a terminal, read text from it
	if !terminal.IsTerminal(int(syscall.Stdin)) {
		return c.push(config, append([]string{os.Stdin.Name()}, args[0]))
	}

	// Create temp file
	f, err := ioutil.TempFile("", "lxd_file_edit_")
	fname := f.Name()
	f.Close()
	os.Remove(fname)
	defer os.Remove(fname)

	// Extract current value
	err = c.pull(config, append([]string{args[0]}, fname))
	if err != nil {
		return err
	}

	_, err = shared.TextEditor(fname, []byte{})
	if err != nil {
		return err
	}

	err = c.push(config, append([]string{fname}, args[0]))
	if err != nil {
		return err
	}

	return nil
}

func (c *fileCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {
	case "push":
		return c.push(config, args[1:])
	case "pull":
		return c.pull(config, args[1:])
	case "edit":
		return c.edit(config, args[1:])
	default:
		return errArgs
	}
}
<commit_msg>Address review comments<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/i18n"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
)

type fileCmd struct {
	uid  int
	gid  int
	mode string
}

func (c *fileCmd) showByDefault() bool {
	return true
}

func (c *fileCmd) usage() string {
	return i18n.G(
		`Manage files on a container.

lxc file pull <source> [<source>...] <target>
lxc file push [--uid=UID] [--gid=GID] [--mode=MODE] <source> [<source>...] <target>
lxc file edit <file>

<source> in the case of pull, <target> in the case of push and <file> in the case of edit are <container name>/<path>`)
}

func (c *fileCmd) flags() {
	gnuflag.IntVar(&c.uid, "uid", -1, i18n.G("Set the file's uid on push"))
	gnuflag.IntVar(&c.gid, "gid", -1, i18n.G("Set the file's gid on push"))
	gnuflag.StringVar(&c.mode, "mode", "", i18n.G("Set the file's perms on push"))
}

func (c *fileCmd) push(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	target := args[len(args)-1]
	pathSpec := strings.SplitAfterN(target, "/", 2)

	if len(pathSpec) != 2 {
		return fmt.Errorf(i18n.G("Invalid target %s"), target)
	}

	targetPath := pathSpec[1]
	remote, container := config.ParseRemoteAndContainer(pathSpec[0])

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	mode := os.FileMode(0755)
	if c.mode != "" {
		m, err := strconv.ParseInt(c.mode, 0, 0)
		if err != nil {
			return err
		}
		mode = os.FileMode(m)
	}

	uid := 0
	if c.uid >= 0 {
		uid = c.uid
	}

	gid := 0
	if c.gid >= 0 {
		gid = c.gid
	}

	_, targetfilename := filepath.Split(targetPath)

	var sourcefilenames []string
	for _, fname := range args[:len(args)-1] {
		if !strings.HasPrefix(fname, "--") {
			sourcefilenames = append(sourcefilenames, fname)
		}
	}

	if (targetfilename != "") && (len(sourcefilenames) > 1) {
		return errArgs
	}

	/* Make sure all of the files are accessible by us before trying to
	 * push any of them. */
	var files []*os.File
	for _, f := range sourcefilenames {
		var file *os.File
		if f == "-" {
			file = os.Stdin
		} else {
			file, err = os.Open(f)
			if err != nil {
				return err
			}
		}

		defer file.Close()
		files = append(files, file)
	}

	for _, f := range files {
		fpath := targetPath
		if targetfilename == "" {
			fpath = path.Join(fpath, path.Base(f.Name()))
		}

		if c.mode == "" || c.uid == -1 || c.gid == -1 {
			fMode, fUid, fGid, err := c.getOwner(f)
			if err != nil {
				return err
			}

			if c.mode == "" {
				mode = fMode
			}

			if c.uid == -1 {
				uid = fUid
			}

			if c.gid == -1 {
				gid = fGid
			}
		}

		err = d.PushFile(container, fpath, gid, uid, mode, f)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *fileCmd) pull(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	target := args[len(args)-1]
	targetIsDir := false
	sb, err := os.Stat(target)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	/*
	 * If the path exists, just use it. If it doesn't exist, it might be a
	 * directory in one of two cases:
	 *   1. Someone explicitly put "/" at the end
	 *   2. Someone provided more than one source. In this case the target
	 *      should be a directory so we can save all the files into it.
	 */
	if err == nil {
		targetIsDir = sb.IsDir()
		if !targetIsDir && len(args)-1 > 1 {
			return fmt.Errorf(i18n.G("More than one file to download, but target is not a directory"))
		}
	} else if strings.HasSuffix(target, string(os.PathSeparator)) || len(args)-1 > 1 {
		if err := os.MkdirAll(target, 0755); err != nil {
			return err
		}
		targetIsDir = true
	}

	for _, f := range args[:len(args)-1] {
		pathSpec := strings.SplitN(f, "/", 2)
		if len(pathSpec) != 2 {
			return fmt.Errorf(i18n.G("Invalid source %s"), f)
		}

		remote, container := config.ParseRemoteAndContainer(pathSpec[0])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		_, _, _, buf, err := d.PullFile(container, pathSpec[1])
		if err != nil {
			return err
		}

		var targetPath string
		if targetIsDir {
			targetPath = path.Join(target, path.Base(pathSpec[1]))
		} else {
			targetPath = target
		}

		var f *os.File
		if targetPath == "-" {
			f = os.Stdout
		} else {
			f, err = os.Create(targetPath)
			if err != nil {
				return err
			}
			defer f.Close()
		}

		_, err = io.Copy(f, buf)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *fileCmd) edit(config *lxd.Config, args []string) error {
	if len(args) != 1 {
		return errArgs
	}

	// If stdin isn't a terminal, read text from it
	if !terminal.IsTerminal(int(syscall.Stdin)) {
		return c.push(config, append([]string{os.Stdin.Name()}, args[0]))
	}

	// Create temp file
	f, err := ioutil.TempFile("", "lxd_file_edit_")
	fname := f.Name()
	f.Close()
	os.Remove(fname)
	defer os.Remove(fname)

	// Extract current value
	err = c.pull(config, append([]string{args[0]}, fname))
	if err != nil {
		return err
	}

	_, err = shared.TextEditor(fname, []byte{})
	if err != nil {
		return err
	}

	err = c.push(config, append([]string{fname}, args[0]))
	if err != nil {
		return err
	}

	return nil
}

func (c *fileCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {
	case "push":
		return c.push(config, args[1:])
	case "pull":
		return c.pull(config, args[1:])
	case "edit":
		return c.edit(config, args[1:])
	default:
		return errArgs
	}
}
<|endoftext|>


<commit_before>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the LUDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type LUFactors struct {
	LU    *Dense
	Pivot []int
	Sign  int
}

// LUD performs an LU Decomposition for an m-by-n matrix a.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LU(a *Dense) LUFactors {
	// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Outer loop.
	luColj := make([]float64, m)
	for j := 0; j < n; j++ {

		// Make a copy of the j-th column to localize references.
		for i := 0; i < m; i++ {
			luColj[i] = lu.at(i, j)
		}

		// Apply previous transformations.
		for i := 0; i < m; i++ {
			luRowi := lu.RowView(i)

			// Most of the time is spent in the following dot product.
			kmax := min(i, j)
			var s float64
			for k, v := range luRowi[:kmax] {
				s += v * luColj[k]
			}

			luColj[i] -= s
			luRowi[j] = luColj[i]
		}

		// Find pivot and exchange if necessary.
		p := j
		for i := j + 1; i < m; i++ {
			if math.Abs(luColj[i]) > math.Abs(luColj[p]) {
				p = i
			}
		}
		if p != j {
			for k := 0; k < n; k++ {
				t := lu.at(p, k)
				lu.set(p, k, lu.at(j, k))
				lu.set(j, k, t)
			}
			piv[p], piv[j] = piv[j], piv[p]
			sign = -sign
		}

		// Compute multipliers.
		if j < m && lu.at(j, j) != 0 {
			for i := j + 1; i < m; i++ {
				lu.set(i, j, lu.at(i, j)/lu.at(j, j))
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// LUGaussian performs an LU Decomposition for an m-by-n matrix a using Gaussian elimination.
// L and U are found using the "daxpy"-based elimination algorithm used in LINPACK and
// MATLAB.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so the LUD will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations.  This
// will fail if IsSingular() returns true.
func LUGaussian(a *Dense) LUFactors {
	// Initialize.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Main loop.
	for k := 0; k < n; k++ {
		// Find pivot.
		p := k
		for i := k + 1; i < m; i++ {
			if math.Abs(lu.at(i, k)) > math.Abs(lu.at(p, k)) {
				p = i
			}
		}

		// Exchange if necessary.
		if p != k {
			for j := 0; j < n; j++ {
				t := lu.at(p, j)
				lu.set(p, j, lu.at(k, j))
				lu.set(k, j, t)
			}
			piv[p], piv[k] = piv[k], piv[p]
			sign = -sign
		}

		// Compute multipliers and eliminate k-th column.
		if lu.at(k, k) != 0 {
			for i := k + 1; i < m; i++ {
				lu.set(i, k, lu.at(i, k)/lu.at(k, k))
				for j := k + 1; j < n; j++ {
					lu.set(i, j, lu.at(i, j)-lu.at(i, k)*lu.at(k, j))
				}
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// IsSingular returns whether the the upper triangular factor and hence a is
// singular.
func (f LUFactors) IsSingular() bool {
	lu := f.LU
	_, n := lu.Dims()
	for j := 0; j < n; j++ {
		if lu.at(j, j) == 0 {
			return true
		}
	}
	return false
}

// L returns the lower triangular factor of the LU decomposition.
func (f LUFactors) L() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	l := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i > j {
				l.set(i, j, lu.at(i, j))
			} else if i == j {
				l.set(i, j, 1)
			}
		}
	}
	return l
}

// U returns the upper triangular factor of the LU decomposition.
func (f LUFactors) U() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	u := NewDense(m, n, nil)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i <= j {
				u.set(i, j, lu.at(i, j))
			}
		}
	}
	return u
}

// Det returns the determinant of matrix a decomposed into lu. The matrix
// a must have been square.
func (f LUFactors) Det() float64 {
	lu, sign := f.LU, f.Sign
	m, n := lu.Dims()
	if m != n {
		panic(ErrSquare)
	}
	d := float64(sign)
	for j := 0; j < n; j++ {
		d *= lu.at(j, j)
	}
	return d
}

// Solve computes a solution of a.x = b where b has as many rows as a. A matrix x
// is returned that minimizes the two norm of L*U*X = B(piv,:). QRSolve will panic
// if a is singular. The matrix b is overwritten during the call.
func (f LUFactors) Solve(b *Dense) (x *Dense) {
	lu, piv := f.LU, f.Pivot
	m, n := lu.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if f.IsSingular() {
		panic(ErrSingular)
	}

	// Copy right hand side with pivoting
	nx := bn
	x = pivotRows(b, piv)

	// Solve L*Y = B(piv,:)
	for k := 0; k < n; k++ {
		for i := k + 1; i < n; i++ {
			for j := 0; j < nx; j++ {
				x.set(i, j, x.at(i, j)-x.at(k, j)*lu.at(i, k))
			}
		}
	}

	// Solve U*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.set(k, j, x.at(k, j)/lu.at(k, k))
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.set(i, j, x.at(i, j)-x.at(k, j)*lu.at(i, k))
			}
		}
	}

	return x
}

func pivotRows(a *Dense, piv []int) *Dense {
	visit := make([]bool, len(piv))
	_, n := a.Dims()
	tmpRow := make([]float64, n)
	for to, from := range piv {
		for to != from && !visit[from] {
			visit[from], visit[to] = true, true
			a.Row(tmpRow, from)
			a.SetRow(from, a.rowView(to))
			a.SetRow(to, tmpRow)
			to, from = from, piv[from]
		}
	}
	return a
}
<commit_msg>Fix and update comments for LU decomposition<commit_after>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the LUDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type LUFactors struct {
	LU    *Dense
	Pivot []int
	Sign  int
}

// LU performs an LU Decomposition for an m-by-n matrix a.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so LU will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations. This
// will fail if IsSingular() returns true.
func LU(a *Dense) LUFactors {
	// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Outer loop.
	luColj := make([]float64, m)
	for j := 0; j < n; j++ {

		// Make a copy of the j-th column to localize references.
		for i := 0; i < m; i++ {
			luColj[i] = lu.at(i, j)
		}

		// Apply previous transformations.
		for i := 0; i < m; i++ {
			luRowi := lu.RowView(i)

			// Most of the time is spent in the following dot product.
			kmax := min(i, j)
			var s float64
			for k, v := range luRowi[:kmax] {
				s += v * luColj[k]
			}

			luColj[i] -= s
			luRowi[j] = luColj[i]
		}

		// Find pivot and exchange if necessary.
		p := j
		for i := j + 1; i < m; i++ {
			if math.Abs(luColj[i]) > math.Abs(luColj[p]) {
				p = i
			}
		}
		if p != j {
			for k := 0; k < n; k++ {
				t := lu.at(p, k)
				lu.set(p, k, lu.at(j, k))
				lu.set(j, k, t)
			}
			piv[p], piv[j] = piv[j], piv[p]
			sign = -sign
		}

		// Compute multipliers.
		if j < m && lu.at(j, j) != 0 {
			for i := j + 1; i < m; i++ {
				lu.set(i, j, lu.at(i, j)/lu.at(j, j))
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// LUGaussian performs an LU Decomposition for an m-by-n matrix a using Gaussian elimination.
// L and U are found using the "daxpy"-based elimination algorithm used in LINPACK and
// MATLAB.
//
// If m >= n, the LU decomposition is an m-by-n unit lower triangular matrix L,
// an n-by-n upper triangular matrix U, and a permutation vector piv of length m
// so that A(piv,:) = L*U.
//
// If m < n, then L is m-by-m and U is m-by-n.
//
// The LU decompostion with pivoting always exists, even if the matrix is
// singular, so LUGaussian will never fail. The primary use of the LU decomposition
// is in the solution of square systems of simultaneous linear equations. This
// will fail if IsSingular() returns true.
func LUGaussian(a *Dense) LUFactors {
	// Initialize.
	m, n := a.Dims()
	lu := a

	piv := make([]int, m)
	for i := range piv {
		piv[i] = i
	}
	sign := 1

	// Main loop.
	for k := 0; k < n; k++ {
		// Find pivot.
		p := k
		for i := k + 1; i < m; i++ {
			if math.Abs(lu.at(i, k)) > math.Abs(lu.at(p, k)) {
				p = i
			}
		}

		// Exchange if necessary.
		if p != k {
			for j := 0; j < n; j++ {
				t := lu.at(p, j)
				lu.set(p, j, lu.at(k, j))
				lu.set(k, j, t)
			}
			piv[p], piv[k] = piv[k], piv[p]
			sign = -sign
		}

		// Compute multipliers and eliminate k-th column.
		if lu.at(k, k) != 0 {
			for i := k + 1; i < m; i++ {
				lu.set(i, k, lu.at(i, k)/lu.at(k, k))
				for j := k + 1; j < n; j++ {
					lu.set(i, j, lu.at(i, j)-lu.at(i, k)*lu.at(k, j))
				}
			}
		}
	}

	return LUFactors{lu, piv, sign}
}

// IsSingular returns whether the the upper triangular factor and hence a is
// singular.
func (f LUFactors) IsSingular() bool {
	lu := f.LU
	_, n := lu.Dims()
	for j := 0; j < n; j++ {
		if lu.at(j, j) == 0 {
			return true
		}
	}
	return false
}

// L returns the lower triangular factor of the LU decomposition.
func (f LUFactors) L() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	l := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i > j {
				l.set(i, j, lu.at(i, j))
			} else if i == j {
				l.set(i, j, 1)
			}
		}
	}
	return l
}

// U returns the upper triangular factor of the LU decomposition.
func (f LUFactors) U() *Dense {
	lu := f.LU
	m, n := lu.Dims()
	u := NewDense(m, n, nil)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i <= j {
				u.set(i, j, lu.at(i, j))
			}
		}
	}
	return u
}

// Det returns the determinant of matrix a decomposed into lu. The matrix
// a must have been square.
func (f LUFactors) Det() float64 {
	lu, sign := f.LU, f.Sign
	m, n := lu.Dims()
	if m != n {
		panic(ErrSquare)
	}
	d := float64(sign)
	for j := 0; j < n; j++ {
		d *= lu.at(j, j)
	}
	return d
}

// Solve computes a solution of a.x = b where b has as many rows as a. A matrix x
// is returned that minimizes the two norm of L*U*X - B(piv,:). Solve will panic
// if a is singular. The matrix b is overwritten during the call.
func (f LUFactors) Solve(b *Dense) (x *Dense) {
	lu, piv := f.LU, f.Pivot
	m, n := lu.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if f.IsSingular() {
		panic(ErrSingular)
	}

	// Copy right hand side with pivoting
	nx := bn
	x = pivotRows(b, piv)

	// Solve L*Y = B(piv,:)
	for k := 0; k < n; k++ {
		for i := k + 1; i < n; i++ {
			for j := 0; j < nx; j++ {
				x.set(i, j, x.at(i, j)-x.at(k, j)*lu.at(i, k))
			}
		}
	}

	// Solve U*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			x.set(k, j, x.at(k, j)/lu.at(k, k))
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				x.set(i, j, x.at(i, j)-x.at(k, j)*lu.at(i, k))
			}
		}
	}

	return x
}

func pivotRows(a *Dense, piv []int) *Dense {
	visit := make([]bool, len(piv))
	_, n := a.Dims()
	tmpRow := make([]float64, n)
	for to, from := range piv {
		for to != from && !visit[from] {
			visit[from], visit[to] = true, true
			a.Row(tmpRow, from)
			a.SetRow(from, a.rowView(to))
			a.SetRow(to, tmpRow)
			to, from = from, piv[from]
		}
	}
	return a
}
<|endoftext|>


<commit_before>package errorsx

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Error_Error(t *testing.T) {
	err := Errorf("test error created by: %q", "test user")
	assert.Equal(t, "test error created by: \"test user\"", err.Error())
	assert.NotEmpty(t, err.Stack)

	err2 := Wrap(err)
	assert.Equal(t, "test error created by: \"test user\"", err2.Error())
	assert.NotEmpty(t, err2.Stack)

	// stacks should be different
	assert.NotEqual(t, err.Stack, err2.Stack)
}

func Test_Error_Cause_new(t *testing.T) {
	err := errors.New("test error")
	err2 := Wrap(err)
	err3 := Wrap(err2)

	assert.Equal(t, err, Cause(err2))
	assert.Equal(t, err, Cause(err3))
}

func Test_Error_kv(t *testing.T) {
	err := errors.New("test error")
	err = Wrap(err, "k1", "v1", "k2", "v2")
	err = Wrap(err, "k3", "v3")

	assert.Equal(t, `test error [k1="v1", k2="v2", k3="v3"]`, err.Error())
}

func Test_Wrap(t *testing.T) {
	err := Errorf("test error")
	err2 := Wrap(err)
	err3 := Wrap(err2)

	assert.Equal(t, err.Stack(), err2.Stack())
	assert.Equal(t, err2.Stack(), err3.Stack())
}
<commit_msg>fix errorx tests<commit_after>package errorsx

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
)

func Test_Error_Error(t *testing.T) {
	err := Errorf("test error created by: %q", "test user")
	assert.Equal(t, "test error created by: \"test user\"", err.Error())
	assert.NotEmpty(t, err.Stack)

	err2 := Wrap(err)
	assert.Equal(t, "test error created by: \"test user\"", err2.Error())
	assert.NotEmpty(t, err2.Stack)

	// stacks should be the same (should take the stack from err)
	assert.Equal(t, err.Stack(), err2.Stack())
}

func Test_Error_Cause_new(t *testing.T) {
	err := errors.New("test error")
	err2 := Wrap(err)
	err3 := Wrap(err2)

	assert.Equal(t, err, Cause(err2))
	assert.Equal(t, err, Cause(err3))
}

func Test_Error_kv(t *testing.T) {
	err := errors.New("test error")
	err = Wrap(err, "k1", "v1", "k2", "v2")
	err = Wrap(err, "k3", "v3")

	assert.Equal(t, `test error [k1="v1", k2="v2", k3="v3"]`, err.Error())
}

func Test_Wrap(t *testing.T) {
	err := Errorf("test error")
	err2 := Wrap(err)
	err3 := Wrap(err2)

	assert.Equal(t, err.Stack(), err2.Stack())
	assert.Equal(t, err2.Stack(), err3.Stack())
}
<|endoftext|>


<commit_before>/*
  PUBLIC DOMAIN STATEMENT
  To the extent possible under law, Ian Davis has waived all copyright
  and related or neighboring rights to this Source Code file.
  This work is published from the United Kingdom.
*/

// Crops an image to its most interesting area
package salience

import (
	"fmt"
	"image"
	"image/color"
	"math"
)

type Section struct {
	x, y int
	e    float64
}

// Crops an image to its most interesting area with the specified extents
func Crop(img image.Image, cropWidth, cropHeight int) image.Image {
	r := img.Bounds()
	imageWidth := r.Max.X - r.Min.X
	imageHeight := r.Max.Y - r.Min.Y

	x, y := 0, 0
	sliceStep := imageWidth / 8
	if imageHeight/8 < sliceStep {
		sliceStep = imageHeight / 8
	}
	bestSection := Section{0, 0, 0.0}

	for x = 0; x < imageWidth-cropWidth; x += sliceStep {
		for y = 0; y < imageHeight-cropHeight; y += sliceStep {
			e := entropy(img, image.Rect(x, y, x+cropWidth, y+cropHeight))

			if e > bestSection.e {
				bestSection.e = e
				bestSection.x = x
				bestSection.y = y
			}
		}
	}

	return crop(img, image.Rect(bestSection.x, bestSection.y, bestSection.x+cropWidth, bestSection.y+cropHeight))
}

func crop(img image.Image, r image.Rectangle) image.Image {
	cropped := image.NewRGBA(r)
	for x := r.Min.X; x < r.Max.X; x++ {
		for y := r.Min.Y; y < r.Max.Y; y++ {
			cropped.Set(x, y, img.At(x, y))
		}
	}
	return cropped
}

// Calculate the entropy of a portion of an image
// From http://www.astro.cornell.edu/research/projects/compression/entropy.html
func entropy(img image.Image, r image.Rectangle) float64 {
	arraySize := 256*2 - 1
	freq := make([]float64, arraySize)

	for x := r.Min.X; x < r.Max.X-1; x++ {
		for y := r.Min.Y; y < r.Max.Y; y++ {
			diff := greyvalue(img.At(x, y)) - greyvalue(img.At(x+1, y))
			if -(arraySize+1)/2 < diff && diff < (arraySize+1)/2 {
				freq[diff+(arraySize-1)/2] += 1
			}
		}
	}

	n := 0.0
	for _, v := range freq {
		n += v
	}

	e := 0.0
	for i := 0; i < len(freq); i++ {
		freq[i] = freq[i] / n
		if freq[i] != 0.0 {
			e -= freq[i] * math.Log2(freq[i])
		}
	}

	fmt.Printf("Entropy of (%d, %d) (%d, %d) is %0.2f\n", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y, e)

	return e

}

func greyvalue(c color.Color) int {
	r, g, b, _ := c.RGBA()
	return int((r*299 + g*587 + b*114) / 1000)
}
<commit_msg>Removed debugging messages, D'oh\!<commit_after>/*
  PUBLIC DOMAIN STATEMENT
  To the extent possible under law, Ian Davis has waived all copyright
  and related or neighboring rights to this Source Code file.
  This work is published from the United Kingdom.
*/

// Crops an image to its most interesting area
package salience

import (
	"image"
	"image/color"
	"math"
)

type Section struct {
	x, y int
	e    float64
}

// Crops an image to its most interesting area with the specified extents
func Crop(img image.Image, cropWidth, cropHeight int) image.Image {
	r := img.Bounds()
	imageWidth := r.Max.X - r.Min.X
	imageHeight := r.Max.Y - r.Min.Y

	x, y := 0, 0
	sliceStep := imageWidth / 8
	if imageHeight/8 < sliceStep {
		sliceStep = imageHeight / 8
	}
	bestSection := Section{0, 0, 0.0}

	for x = 0; x < imageWidth-cropWidth; x += sliceStep {
		for y = 0; y < imageHeight-cropHeight; y += sliceStep {
			e := entropy(img, image.Rect(x, y, x+cropWidth, y+cropHeight))

			if e > bestSection.e {
				bestSection.e = e
				bestSection.x = x
				bestSection.y = y
			}
		}
	}

	return crop(img, image.Rect(bestSection.x, bestSection.y, bestSection.x+cropWidth, bestSection.y+cropHeight))
}

func crop(img image.Image, r image.Rectangle) image.Image {
	cropped := image.NewRGBA(r)
	for x := r.Min.X; x < r.Max.X; x++ {
		for y := r.Min.Y; y < r.Max.Y; y++ {
			cropped.Set(x, y, img.At(x, y))
		}
	}
	return cropped
}

// Calculate the entropy of a portion of an image
// From http://www.astro.cornell.edu/research/projects/compression/entropy.html
func entropy(img image.Image, r image.Rectangle) float64 {
	arraySize := 256*2 - 1
	freq := make([]float64, arraySize)

	for x := r.Min.X; x < r.Max.X-1; x++ {
		for y := r.Min.Y; y < r.Max.Y; y++ {
			diff := greyvalue(img.At(x, y)) - greyvalue(img.At(x+1, y))
			if -(arraySize+1)/2 < diff && diff < (arraySize+1)/2 {
				freq[diff+(arraySize-1)/2] += 1
			}
		}
	}

	n := 0.0
	for _, v := range freq {
		n += v
	}

	e := 0.0
	for i := 0; i < len(freq); i++ {
		freq[i] = freq[i] / n
		if freq[i] != 0.0 {
			e -= freq[i] * math.Log2(freq[i])
		}
	}

	return e

}

func greyvalue(c color.Color) int {
	r, g, b, _ := c.RGBA()
	return int((r*299 + g*587 + b*114) / 1000)
}
<|endoftext|>


<commit_before>package clui

func MaxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<commit_msg>remove unused module<commit_after><|endoftext|>


<commit_before>package RTJobRunner

import (
	"fmt"
	"bytes"
	"text/template"
	"os"
	"math/rand"
	"github.com/akundu/utilities/statistics/distribution"
)

type KV struct {
	key   string
	value int
}

/*
func print_path(path []*KV) string {
	var result string
	for i := range(path) {
		result += fmt.Sprintf("%s ", path[i].key)
	}
	return result
}
*/

type JSONJobProcessor struct {
	Name              	string
	CommandToExecute 	string
	JSONFields
}
func (this JSONJobProcessor) GetName() string {
	if len(this.Name) > 0 {
		return this.Name
	}
	return this.CommandToExecute
}

func add_jobs(jhjp *JSONJobContainer, json_jobs *JobHandler) error {
	json_job := jhjp.Job
	t, err := template.New(jhjp.GetName()).Parse(json_job.CommandToExecute)
	if err != nil {
		return err
	}

	//create the results for each of the cases
	//1. get the list of keys
	keys := make([]string, len(json_job.Substitutes))
	var i int = 0
	for k := range json_job.Substitutes {
		keys[i] = k
		i++
	}
	//2. initialize some params
	path := make([]*KV, 0, 10)
	f_results := make([]map[string]string, 0, 10)
	//3. expand the substitutes
	expandSubstitutes(keys, 0, json_job.Substitutes, path, &f_results)
	//4. template expand and start the job
	lcw := bytes.NewBufferString("")
	for i = range f_results {
		t.Execute(lcw, f_results[i]) //expand the template
		json_jobs.AddJob(NewRTRequestResultObject(
			&JSONJobProcessor{
				Name:			  jhjp.GetName(),
				CommandToExecute: lcw.String(),
				JSONFields:       json_job.JSONFields,
			}))

		lcw.Reset()
	}

	return nil
}

func expandSubstitutes(keys []string,
	index int,
	substitutes map[string]*SubstituteData,
	path []*KV, //array of an object of
	result *[]map[string]string) {

	if index == len(keys) {
		//take the path till now and generate the data out of that
		obj_to_return := make(map[string]string)
		for _, path_obj := range path {
			kv_info := substitutes[path_obj.key]

			if kv_info.Type == "string" {
				obj_to_return[path_obj.key] = fmt.Sprintf("%s-%d", path_obj.key, path_obj.value)
			} else {
				obj_to_return[path_obj.key] = fmt.Sprintf("%d", path_obj.value)
			}
		}
		*result = append(*result, obj_to_return)
		return
	}

	kv_info := substitutes[keys[index]]
	uniform_distr := distribution.NewuniformGenerator(kv_info.Lower, kv_info.Upper)
	gaussian_distr := distribution.NewgaussianGenerator(kv_info.Lower, kv_info.Upper, kv_info.NumToGenerate)

	for i := 0; i < kv_info.NumToGenerate; i++ {
		val := i
		if(kv_info.Type == "random") {
			val = uniform_distr.GenerateNumber()
		} else if (kv_info.Type == "gaussian") {
			val = gaussian_distr.GenerateNumber()
		}
		path = append(path, &KV{
			key:   keys[index],
			value: val,
		})
		expandSubstitutes(keys, index+1, substitutes, path, result)
		//pop from path
		path = path[:len(path)-1]
	}

	return
}

func init() {
	rand.Seed(int64(os.Getpid()))
}
<commit_msg>order the keys of the command in the same way every time<commit_after>package RTJobRunner

import (
	"fmt"
	"bytes"
	"text/template"
	"os"
	"math/rand"
	"github.com/akundu/utilities/statistics/distribution"
	"regexp"
	"log"
)

type KV struct {
	key   string
	value int
}

/*
func print_path(path []*KV) string {
	var result string
	for i := range(path) {
		result += fmt.Sprintf("%s ", path[i].key)
	}
	return result
}
*/

type JSONJobProcessor struct {
	Name              	string
	CommandToExecute 	string
	JSONFields
}
func (this JSONJobProcessor) GetName() string {
	if len(this.Name) > 0 {
		return this.Name
	}
	return this.CommandToExecute
}

var template_expanders_regex *regexp.Regexp = nil
func add_jobs(jhjp *JSONJobContainer, json_jobs *JobHandler) error {
	json_job := jhjp.Job
	t, err := template.New(jhjp.GetName()).Parse(json_job.CommandToExecute)
	if err != nil {
		return err
	}

	//create the results for each of the cases
	//1. get the list of keys
	res := template_expanders_regex.FindAllStringSubmatch(json_job.CommandToExecute, -1)
	if len(res) == 0 { //didnt find anything to expand - simply add the job as it exists
		json_jobs.AddJob(NewRTRequestResultObject(
			&JSONJobProcessor{
				Name:			  jhjp.GetName(),
				CommandToExecute: json_job.CommandToExecute,
				JSONFields:       json_job.JSONFields,
			}))
		return nil
	}
	keys := make([]string, len(res))
	for i, match := range(res) {
		keys[i] = match[1]
	}

	//2. initialize some params
	path := make([]*KV, 0, 10)
	f_results := make([]map[string]string, 0, 10)
	//3. expand the substitutes
	expandSubstitutes(keys, 0, json_job.Substitutes, path, &f_results)
	//4. template expand and start the job
	lcw := bytes.NewBufferString("")
	for _, temp := range f_results {
		//t.Execute(lcw, f_results[i]) //expand the template
		t.Execute(lcw, temp)
		json_jobs.AddJob(NewRTRequestResultObject(
			&JSONJobProcessor{
				Name:			  jhjp.GetName(),
				CommandToExecute: lcw.String(),
				JSONFields:       json_job.JSONFields,
			}))

		lcw.Reset()
	}

	return nil
}

func expandSubstitutes(keys []string,
	index int,
	substitutes map[string]*SubstituteData,
	path []*KV, //array of an object of
	result *[]map[string]string) {

	//for i,data := range(path) {
	//	fmt.Printf("%d:%v ", i, data)
	//}
	//fmt.Println()

	if index == len(keys) {
		//take the path till now and generate the data out of that
		obj_to_return := make(map[string]string)
		for _, path_obj := range path {
			kv_info := substitutes[path_obj.key]

			if kv_info.Type == "string" {
				obj_to_return[path_obj.key] = fmt.Sprintf("%s-%d", path_obj.key, path_obj.value)
			} else {
				obj_to_return[path_obj.key] = fmt.Sprintf("%d", path_obj.value)
			}
		}
		*result = append(*result, obj_to_return)
		return
	}

	kv_info, ok := substitutes[keys[index]]
	if(ok == false) {
		return
	}
	uniform_distr := distribution.NewuniformGenerator(kv_info.Lower, kv_info.Upper)
	gaussian_distr := distribution.NewgaussianGenerator(kv_info.Lower, kv_info.Upper, kv_info.NumToGenerate)

	for i := 0; i < kv_info.NumToGenerate; i++ {
		val := i
		if(kv_info.Type == "random") {
			val = uniform_distr.GenerateNumber()
		} else if (kv_info.Type == "gaussian") {
			val = gaussian_distr.GenerateNumber()
		}
		path = append(path, &KV{
			key:   keys[index],
			value: val,
		})

		expandSubstitutes(keys, index+1, substitutes, path, result)
		//pop from path
		path = path[:len(path)-1]
	}
	return
}

func init() {
	rand.Seed(int64(os.Getpid()))

	var err error
	if template_expanders_regex, err = regexp.Compile(`{{\.([0-9a-zA-Z]+)}}`); err != nil {
		log.Fatal("couldnt create regex obj for template_expanders")
	}
}
<|endoftext|>