<commit_before>package models

import (
	"log"
	"time"

	"github.com/brnstz/bus/internal/etc"
)

const (
	// midnightSecs is what a depature_sec value of midnight looks like. We
	// use this for trying to find departures after midnight.
	midnightSecs = 86400

	// maximum departures to return in a result
	MaxDepartures = 5
)

type Departure struct {
	Time         time.Time `json:"time" db:"-"`
	DepartureSec int       `json:"-" db:"departure_sec"`
	TripID       string    `json:"trip_id" db:"trip_id"`
	ServiceID    string    `json:"service_id" db:"service_id"`
	Live         bool      `json:"live" db:"-" upsert:"omit"`

	// CompassDir is the direction to the next stop
	CompassDir float64 `json:"compass_dir" db:"-" upsert:"omit"`

	baseTime time.Time `json:"-" db:"-"`
}

func (d *Departure) Initialize() error {
	d.Time = d.baseTime.Add(time.Second * time.Duration(d.DepartureSec))

	return nil
}

type SortableDepartures []*Departure

func (d SortableDepartures) Len() int {
	return len(d)
}

func (d SortableDepartures) Less(i, j int) bool {
	return d[i].Time.Before(d[j].Time)
}

func (d SortableDepartures) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

func getDepartures(agencyID, routeID, stopID, serviceID string, minSec int, base time.Time) (d []*Departure, err error) {
	q := `
		SELECT departure_sec, trip_id, service_id
		FROM   scheduled_stop_time
		WHERE
			   agency_id  =	$1 AND
			   route_id   =	$2 AND
			   stop_id    =	$3 AND
			   service_id =	$4 AND

			   departure_sec    >= $5

		ORDER BY departure_sec LIMIT $6
	`

	err = etc.DBConn.Select(&d, q, agencyID, routeID, stopID, serviceID,
		minSec, MaxDepartures)

	if err != nil {
		log.Println("can't get departures", err)
		return
	}

	for _, departure := range d {
		departure.baseTime = base
		err = departure.Initialize()
		if err != nil {
			log.Println("can't init departure", err)
			return
		}
	}

	return
}
<commit_msg>remove old getDepartures<commit_after>package models

import "time"

const (
	// midnightSecs is what a depature_sec value of midnight looks like. We
	// use this for trying to find departures after midnight.
	midnightSecs = 86400

	// maximum departures to return in a result
	MaxDepartures = 5
)

type Departure struct {
	Time         time.Time `json:"time" db:"-"`
	DepartureSec int       `json:"-" db:"departure_sec"`
	TripID       string    `json:"trip_id" db:"trip_id"`
	ServiceID    string    `json:"service_id" db:"service_id"`
	Live         bool      `json:"live" db:"-" upsert:"omit"`

	// CompassDir is the direction to the next stop
	CompassDir float64 `json:"compass_dir" db:"-" upsert:"omit"`

	baseTime time.Time `json:"-" db:"-"`
}

func (d *Departure) Initialize() error {
	d.Time = d.baseTime.Add(time.Second * time.Duration(d.DepartureSec))

	return nil
}

type SortableDepartures []*Departure

func (d SortableDepartures) Len() int {
	return len(d)
}

func (d SortableDepartures) Less(i, j int) bool {
	return d[i].Time.Before(d[j].Time)
}

func (d SortableDepartures) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}
<|endoftext|>


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

// Package shaderir offers intermediate representation for shader programs.
package shaderir

type Program struct {
	Uniforms     []Type
	Attributes   []Type
	Varyings     []Type
	Funcs        []Func
	VertexFunc   VertexFunc
	FragmentFunc FragmentFunc

	structNames map[string]string
	structTypes []Type
}

type Func struct {
	Index       int
	InParams    []Type
	InOutParams []Type
	OutParams   []Type
	Return      Type
	Block       Block
}

// VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
// If 0 <= index < len(attributes), the params are in-params and treated as attribute variables.
// If len(attributes) <= index < len(attributes) + len(varyings), the params are out-params and treated as varying
// variables.
// The last param represents the position in vec4 (gl_Position in GLSL).
type VertexFunc struct {
	Block Block
}

// FragmentFunc takes pseudo in-params, and the number is len(varyings) + 1.
// The last param represents the coordinate of the fragment (gl_FragCoord in GLSL)
type FragmentFunc struct {
	Block Block
}

type Block struct {
	LocalVars []Type
	Stmts     []Stmt
}

type Stmt struct {
	Type     StmtType
	Exprs    []Expr
	Blocks   []Block
	ForInit  int
	ForEnd   int
	ForOp    Op
	ForDelta int
}

type StmtType int

const (
	ExprStmt StmtType = iota
	BlockStmt
	Assign
	If
	For
	Continue
	Break
	Return
	Discard
)

type Expr struct {
	Type        ExprType
	Exprs       []Expr
	Int         int32
	Float       float32
	BuiltinFunc BuiltinFunc
	Swizzling   string
	Index       int
	Op          Op
}

type ExprType int

const (
	IntExpr ExprType = iota
	FloatExpr
	UniformVariable
	LocalVariable
	StructMember
	BuiltinFuncExpr
	SwizzlingExpr
	FunctionExpr
	Unary
	Binary
	Selection
	Call
	FieldSelector
	Index
)

type Op string

const (
	Add                Op = "+"
	Sub                Op = "-"
	Neg                Op = "!"
	Mul                Op = "*"
	Div                Op = "/"
	ModOp              Op = "%"
	LeftShift          Op = "<<"
	RightShift         Op = ">>"
	LessThanOp         Op = "<"
	LessThanEqualOp    Op = "<="
	GreaterThanOp      Op = ">"
	GreaterThanEqualOp Op = ">="
	EqualOp            Op = "=="
	NotEqualOp         Op = "!="
	And                Op = "&"
	Xor                Op = "^"
	Or                 Op = "|"
	AndAnd             Op = "&&"
	OrOr               Op = "||"
)

type BuiltinFunc string

const (
	Radians          BuiltinFunc = "radians"
	Degrees          BuiltinFunc = "degrees"
	Sin              BuiltinFunc = "sin"
	Cos              BuiltinFunc = "cos"
	Tan              BuiltinFunc = "tan"
	Asin             BuiltinFunc = "asin"
	Acos             BuiltinFunc = "acos"
	Atan             BuiltinFunc = "atan"
	Pow              BuiltinFunc = "pow"
	Exp              BuiltinFunc = "exp"
	Log              BuiltinFunc = "log"
	Exp2             BuiltinFunc = "exp2"
	Log2             BuiltinFunc = "log2"
	Sqrt             BuiltinFunc = "sqrt"
	Inversesqrt      BuiltinFunc = "inversesqrt"
	Abs              BuiltinFunc = "abs"
	Sign             BuiltinFunc = "sign"
	Floor            BuiltinFunc = "floor"
	Ceil             BuiltinFunc = "ceil"
	Fract            BuiltinFunc = "fract"
	Mod              BuiltinFunc = "mod"
	Min              BuiltinFunc = "min"
	Max              BuiltinFunc = "max"
	Clamp            BuiltinFunc = "clamp"
	Mix              BuiltinFunc = "mix"
	Step             BuiltinFunc = "step"
	Smoothstep       BuiltinFunc = "smoothstep"
	Length           BuiltinFunc = "length"
	Distance         BuiltinFunc = "distance"
	Dot              BuiltinFunc = "dot"
	Cross            BuiltinFunc = "cross"
	Normalize        BuiltinFunc = "normalize"
	Faceforward      BuiltinFunc = "faceforward"
	Reflect          BuiltinFunc = "reflect"
	MatrixCompMult   BuiltinFunc = "matrixCompMult"
	OuterProduct     BuiltinFunc = "outerProduct"
	Transpose        BuiltinFunc = "transpose"
	LessThan         BuiltinFunc = "lessThan"
	LessThanEqual    BuiltinFunc = "lessThanEqual"
	GreaterThan      BuiltinFunc = "greaterThan"
	GreaterThanEqual BuiltinFunc = "greaterThanEqual"
	Equal            BuiltinFunc = "equal"
	NotEqual         BuiltinFunc = "notEqual"
	Any              BuiltinFunc = "any"
	All              BuiltinFunc = "all"
	Not              BuiltinFunc = "not"
	Texture2D        BuiltinFunc = "texture2D"
)
<commit_msg>shaderir: Add more builtin functions<commit_after>// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package shaderir offers intermediate representation for shader programs.
package shaderir

type Program struct {
	Uniforms     []Type
	Attributes   []Type
	Varyings     []Type
	Funcs        []Func
	VertexFunc   VertexFunc
	FragmentFunc FragmentFunc

	structNames map[string]string
	structTypes []Type
}

type Func struct {
	Index       int
	InParams    []Type
	InOutParams []Type
	OutParams   []Type
	Return      Type
	Block       Block
}

// VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
// If 0 <= index < len(attributes), the params are in-params and treated as attribute variables.
// If len(attributes) <= index < len(attributes) + len(varyings), the params are out-params and treated as varying
// variables.
// The last param represents the position in vec4 (gl_Position in GLSL).
type VertexFunc struct {
	Block Block
}

// FragmentFunc takes pseudo in-params, and the number is len(varyings) + 1.
// The last param represents the coordinate of the fragment (gl_FragCoord in GLSL)
type FragmentFunc struct {
	Block Block
}

type Block struct {
	LocalVars []Type
	Stmts     []Stmt
}

type Stmt struct {
	Type     StmtType
	Exprs    []Expr
	Blocks   []Block
	ForInit  int
	ForEnd   int
	ForOp    Op
	ForDelta int
}

type StmtType int

const (
	ExprStmt StmtType = iota
	BlockStmt
	Assign
	If
	For
	Continue
	Break
	Return
	Discard
)

type Expr struct {
	Type        ExprType
	Exprs       []Expr
	Int         int32
	Float       float32
	BuiltinFunc BuiltinFunc
	Swizzling   string
	Index       int
	Op          Op
}

type ExprType int

const (
	IntExpr ExprType = iota
	FloatExpr
	UniformVariable
	LocalVariable
	StructMember
	BuiltinFuncExpr
	SwizzlingExpr
	FunctionExpr
	Unary
	Binary
	Selection
	Call
	FieldSelector
	Index
)

type Op string

const (
	Add                Op = "+"
	Sub                Op = "-"
	Neg                Op = "!"
	Mul                Op = "*"
	Div                Op = "/"
	ModOp              Op = "%"
	LeftShift          Op = "<<"
	RightShift         Op = ">>"
	LessThanOp         Op = "<"
	LessThanEqualOp    Op = "<="
	GreaterThanOp      Op = ">"
	GreaterThanEqualOp Op = ">="
	EqualOp            Op = "=="
	NotEqualOp         Op = "!="
	And                Op = "&"
	Xor                Op = "^"
	Or                 Op = "|"
	AndAnd             Op = "&&"
	OrOr               Op = "||"
)

type BuiltinFunc string

const (
	Vec2F            BuiltinFunc = "vec2"
	Vec3F            BuiltinFunc = "vec3"
	Vec4F            BuiltinFunc = "vec4"
	Radians          BuiltinFunc = "radians"
	Degrees          BuiltinFunc = "degrees"
	Sin              BuiltinFunc = "sin"
	Cos              BuiltinFunc = "cos"
	Tan              BuiltinFunc = "tan"
	Asin             BuiltinFunc = "asin"
	Acos             BuiltinFunc = "acos"
	Atan             BuiltinFunc = "atan"
	Pow              BuiltinFunc = "pow"
	Exp              BuiltinFunc = "exp"
	Log              BuiltinFunc = "log"
	Exp2             BuiltinFunc = "exp2"
	Log2             BuiltinFunc = "log2"
	Sqrt             BuiltinFunc = "sqrt"
	Inversesqrt      BuiltinFunc = "inversesqrt"
	Abs              BuiltinFunc = "abs"
	Sign             BuiltinFunc = "sign"
	Floor            BuiltinFunc = "floor"
	Ceil             BuiltinFunc = "ceil"
	Fract            BuiltinFunc = "fract"
	Mod              BuiltinFunc = "mod"
	Min              BuiltinFunc = "min"
	Max              BuiltinFunc = "max"
	Clamp            BuiltinFunc = "clamp"
	Mix              BuiltinFunc = "mix"
	Step             BuiltinFunc = "step"
	Smoothstep       BuiltinFunc = "smoothstep"
	Length           BuiltinFunc = "length"
	Distance         BuiltinFunc = "distance"
	Dot              BuiltinFunc = "dot"
	Cross            BuiltinFunc = "cross"
	Normalize        BuiltinFunc = "normalize"
	Faceforward      BuiltinFunc = "faceforward"
	Reflect          BuiltinFunc = "reflect"
	MatrixCompMult   BuiltinFunc = "matrixCompMult"
	OuterProduct     BuiltinFunc = "outerProduct"
	Transpose        BuiltinFunc = "transpose"
	LessThan         BuiltinFunc = "lessThan"
	LessThanEqual    BuiltinFunc = "lessThanEqual"
	GreaterThan      BuiltinFunc = "greaterThan"
	GreaterThanEqual BuiltinFunc = "greaterThanEqual"
	Equal            BuiltinFunc = "equal"
	NotEqual         BuiltinFunc = "notEqual"
	Any              BuiltinFunc = "any"
	All              BuiltinFunc = "all"
	Not              BuiltinFunc = "not"
	Texture2D        BuiltinFunc = "texture2D"
)
<|endoftext|>


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

// Package shaderir offers intermediate representation for shader programs.
package shaderir

type Program struct {
	Uniforms     []Type
	Attributes   []Type
	Varyings     []Type
	Funcs        []Func
	VertexFunc   VertexFunc
	FragmentFunc FragmentFunc

	structNames map[string]string
	structTypes []Type
}

type Func struct {
	Index       int
	InParams    []Type
	InOutParams []Type
	OutParams   []Type
	Return      Type
	Block       Block
}

// VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
// If 0 <= index < len(attributes), the params are in-params and treated as attribute variables.
// If len(attributes) <= index < len(attributes) + len(varyings), the params are out-params and treated as varying
// variables.
// The last param represents the position in vec4 (gl_Position in GLSL).
type VertexFunc struct {
	Block Block
}

// FragmentFunc takes pseudo in-params, and the number is len(varyings) + 1.
// The last param represents the coordinate of the fragment (gl_FragCoord in GLSL)
type FragmentFunc struct {
	Block Block
}

type Block struct {
	LocalVars []Type
	Stmts     []Stmt
}

type Stmt struct {
	Type     StmtType
	Exprs    []Expr
	Blocks   []Block
	ForInit  int
	ForEnd   int
	ForOp    Op
	ForDelta int
}

type StmtType int

const (
	ExprStmt StmtType = iota
	BlockStmt
	Assign
	If
	For
	Continue
	Break
	Return
	Discard
)

type Expr struct {
	Type        ExprType
	Exprs       []Expr
	Int         int32
	Float       float32
	BuiltinFunc BuiltinFunc
	Swizzling   string
	Index       int
	Op          Op
}

type ExprType int

const (
	IntExpr ExprType = iota
	FloatExpr
	UniformVariable
	LocalVariable
	StructMember
	BuiltinFuncExpr
	SwizzlingExpr
	FunctionExpr
	Unary
	Binary
	Selection
	Call
	FieldSelector
	Index
)

type Op string

const (
	Add                Op = "+"
	Sub                Op = "-"
	Neg                Op = "!"
	Mul                Op = "*"
	Div                Op = "/"
	ModOp              Op = "%"
	LeftShift          Op = "<<"
	RightShift         Op = ">>"
	LessThanOp         Op = "<"
	LessThanEqualOp    Op = "<="
	GreaterThanOp      Op = ">"
	GreaterThanEqualOp Op = ">="
	EqualOp            Op = "=="
	NotEqualOp         Op = "!="
	And                Op = "&"
	Xor                Op = "^"
	Or                 Op = "|"
	AndAnd             Op = "&&"
	OrOr               Op = "||"
)

type BuiltinFunc string

const (
	Vec2F            BuiltinFunc = "vec2"
	Vec3F            BuiltinFunc = "vec3"
	Vec4F            BuiltinFunc = "vec4"
	Radians          BuiltinFunc = "radians"
	Degrees          BuiltinFunc = "degrees"
	Sin              BuiltinFunc = "sin"
	Cos              BuiltinFunc = "cos"
	Tan              BuiltinFunc = "tan"
	Asin             BuiltinFunc = "asin"
	Acos             BuiltinFunc = "acos"
	Atan             BuiltinFunc = "atan"
	Pow              BuiltinFunc = "pow"
	Exp              BuiltinFunc = "exp"
	Log              BuiltinFunc = "log"
	Exp2             BuiltinFunc = "exp2"
	Log2             BuiltinFunc = "log2"
	Sqrt             BuiltinFunc = "sqrt"
	Inversesqrt      BuiltinFunc = "inversesqrt"
	Abs              BuiltinFunc = "abs"
	Sign             BuiltinFunc = "sign"
	Floor            BuiltinFunc = "floor"
	Ceil             BuiltinFunc = "ceil"
	Fract            BuiltinFunc = "fract"
	Mod              BuiltinFunc = "mod"
	Min              BuiltinFunc = "min"
	Max              BuiltinFunc = "max"
	Clamp            BuiltinFunc = "clamp"
	Mix              BuiltinFunc = "mix"
	Step             BuiltinFunc = "step"
	Smoothstep       BuiltinFunc = "smoothstep"
	Length           BuiltinFunc = "length"
	Distance         BuiltinFunc = "distance"
	Dot              BuiltinFunc = "dot"
	Cross            BuiltinFunc = "cross"
	Normalize        BuiltinFunc = "normalize"
	Faceforward      BuiltinFunc = "faceforward"
	Reflect          BuiltinFunc = "reflect"
	MatrixCompMult   BuiltinFunc = "matrixCompMult"
	OuterProduct     BuiltinFunc = "outerProduct"
	Transpose        BuiltinFunc = "transpose"
	LessThan         BuiltinFunc = "lessThan"
	LessThanEqual    BuiltinFunc = "lessThanEqual"
	GreaterThan      BuiltinFunc = "greaterThan"
	GreaterThanEqual BuiltinFunc = "greaterThanEqual"
	Equal            BuiltinFunc = "equal"
	NotEqual         BuiltinFunc = "notEqual"
	Any              BuiltinFunc = "any"
	All              BuiltinFunc = "all"
	Not              BuiltinFunc = "not"
	Texture2D        BuiltinFunc = "texture2D"
)
<commit_msg>shaderir: Add more builtin functions<commit_after>// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package shaderir offers intermediate representation for shader programs.
package shaderir

type Program struct {
	Uniforms     []Type
	Attributes   []Type
	Varyings     []Type
	Funcs        []Func
	VertexFunc   VertexFunc
	FragmentFunc FragmentFunc

	structNames map[string]string
	structTypes []Type
}

type Func struct {
	Index       int
	InParams    []Type
	InOutParams []Type
	OutParams   []Type
	Return      Type
	Block       Block
}

// VertexFunc takes pseudo params, and the number if len(attributes) + len(varyings) + 1.
// If 0 <= index < len(attributes), the params are in-params and treated as attribute variables.
// If len(attributes) <= index < len(attributes) + len(varyings), the params are out-params and treated as varying
// variables.
// The last param represents the position in vec4 (gl_Position in GLSL).
type VertexFunc struct {
	Block Block
}

// FragmentFunc takes pseudo in-params, and the number is len(varyings) + 1.
// The last param represents the coordinate of the fragment (gl_FragCoord in GLSL)
type FragmentFunc struct {
	Block Block
}

type Block struct {
	LocalVars []Type
	Stmts     []Stmt
}

type Stmt struct {
	Type     StmtType
	Exprs    []Expr
	Blocks   []Block
	ForInit  int
	ForEnd   int
	ForOp    Op
	ForDelta int
}

type StmtType int

const (
	ExprStmt StmtType = iota
	BlockStmt
	Assign
	If
	For
	Continue
	Break
	Return
	Discard
)

type Expr struct {
	Type        ExprType
	Exprs       []Expr
	Int         int32
	Float       float32
	BuiltinFunc BuiltinFunc
	Swizzling   string
	Index       int
	Op          Op
}

type ExprType int

const (
	IntExpr ExprType = iota
	FloatExpr
	UniformVariable
	LocalVariable
	StructMember
	BuiltinFuncExpr
	SwizzlingExpr
	FunctionExpr
	Unary
	Binary
	Selection
	Call
	FieldSelector
	Index
)

type Op string

const (
	Add                Op = "+"
	Sub                Op = "-"
	Neg                Op = "!"
	Mul                Op = "*"
	Div                Op = "/"
	ModOp              Op = "%"
	LeftShift          Op = "<<"
	RightShift         Op = ">>"
	LessThanOp         Op = "<"
	LessThanEqualOp    Op = "<="
	GreaterThanOp      Op = ">"
	GreaterThanEqualOp Op = ">="
	EqualOp            Op = "=="
	NotEqualOp         Op = "!="
	And                Op = "&"
	Xor                Op = "^"
	Or                 Op = "|"
	AndAnd             Op = "&&"
	OrOr               Op = "||"
)

type BuiltinFunc string

const (
	Vec2F            BuiltinFunc = "vec2"
	Vec3F            BuiltinFunc = "vec3"
	Vec4F            BuiltinFunc = "vec4"
	Mat2F            BuiltinFunc = "mat2"
	Mat3F            BuiltinFunc = "mat3"
	Mat4F            BuiltinFunc = "mat4"
	Radians          BuiltinFunc = "radians"
	Degrees          BuiltinFunc = "degrees"
	Sin              BuiltinFunc = "sin"
	Cos              BuiltinFunc = "cos"
	Tan              BuiltinFunc = "tan"
	Asin             BuiltinFunc = "asin"
	Acos             BuiltinFunc = "acos"
	Atan             BuiltinFunc = "atan"
	Pow              BuiltinFunc = "pow"
	Exp              BuiltinFunc = "exp"
	Log              BuiltinFunc = "log"
	Exp2             BuiltinFunc = "exp2"
	Log2             BuiltinFunc = "log2"
	Sqrt             BuiltinFunc = "sqrt"
	Inversesqrt      BuiltinFunc = "inversesqrt"
	Abs              BuiltinFunc = "abs"
	Sign             BuiltinFunc = "sign"
	Floor            BuiltinFunc = "floor"
	Ceil             BuiltinFunc = "ceil"
	Fract            BuiltinFunc = "fract"
	Mod              BuiltinFunc = "mod"
	Min              BuiltinFunc = "min"
	Max              BuiltinFunc = "max"
	Clamp            BuiltinFunc = "clamp"
	Mix              BuiltinFunc = "mix"
	Step             BuiltinFunc = "step"
	Smoothstep       BuiltinFunc = "smoothstep"
	Length           BuiltinFunc = "length"
	Distance         BuiltinFunc = "distance"
	Dot              BuiltinFunc = "dot"
	Cross            BuiltinFunc = "cross"
	Normalize        BuiltinFunc = "normalize"
	Faceforward      BuiltinFunc = "faceforward"
	Reflect          BuiltinFunc = "reflect"
	MatrixCompMult   BuiltinFunc = "matrixCompMult"
	OuterProduct     BuiltinFunc = "outerProduct"
	Transpose        BuiltinFunc = "transpose"
	LessThan         BuiltinFunc = "lessThan"
	LessThanEqual    BuiltinFunc = "lessThanEqual"
	GreaterThan      BuiltinFunc = "greaterThan"
	GreaterThanEqual BuiltinFunc = "greaterThanEqual"
	Equal            BuiltinFunc = "equal"
	NotEqual         BuiltinFunc = "notEqual"
	Any              BuiltinFunc = "any"
	All              BuiltinFunc = "all"
	Not              BuiltinFunc = "not"
	Texture2D        BuiltinFunc = "texture2D"
)
<|endoftext|>


<commit_before>package main

import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"

	uaaclient "github.com/cloudfoundry-community/go-uaa"
)

var _ = Describe("UAA", func() {
	Context("Users Aggregation", func() {
		It("Should aggregate users correctly for no users", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{})

			Expect(gauges).To(HaveLen(0))
		})

		It("Should aggregate users correctly for a UAA user", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{
				{Origin: "uaa"},
			})

			Expect(gauges).To(HaveLen(1))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})

		It("Should aggregate users correctly for some UAA users", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{
				{Origin: "uaa"}, {Origin: "uaa"},
				{Origin: "google"}, {Origin: "microsoft"},
				{Origin: "uaa"}, {Origin: "uaa"}, {Origin: "google"},
			})

			Expect(gauges).To(HaveLen(3))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 4),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 2),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("microsoft"),
					})),
				}),
			))
		})
	})

	Context("Active Users", func() {
		It("Should select active users", func() {
			activeUsers := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour).Unix() * 1000),
			}}

			Expect(UAAActiveUsers(activeUsers)).To(HaveLen(1))
		})

		It("Should reject inactive users", func() {
			inactiveUsers := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*31).Unix() * 1000),
			}}

			Expect(UAAActiveUsers(inactiveUsers)).To(HaveLen(0))
		})

		It("Should select active and reject inactive users", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*31).Unix() * 1000),
			}}

			activeUsers := UAAActiveUsers(users)

			Expect(activeUsers).To(HaveLen(1))
			Expect(activeUsers[0].Origin).To(Equal("google"))
		})
	})

	Context("Active Users Aggregation", func() {
		It("Should select active users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour).Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(1))
			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})

		It("Should reject inactive users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*31).Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(0))
		})

		It("Should select active and reject inactive users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*31).Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(1))
			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))
		})

		It("Should select active and reject inactive users as gauges for many users", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour).Unix() * 1000),
			}, {
				Origin:        "google",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*60).Unix() * 1000),
			}, {
				Origin:        "microsoft",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*2).Unix() * 1000),
			}, {
				Origin:        "microsoft",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*91).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*2).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(-1*24*time.Hour*31).Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(3))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("microsoft"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})
	})
})
<commit_msg>Make timespans clearer in paas-metrics/gauges_uaa_test.go<commit_after>package main

import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"

	uaaclient "github.com/cloudfoundry-community/go-uaa"
)

var _ = Describe("UAA", func() {

	MinusOneDay := -1 * 24 * time.Hour
	OneDayAgo := time.Now().Add(MinusOneDay)
	ThirtyOneDaysAgo := time.Now().Add(MinusOneDay * 31)

	Context("Users Aggregation", func() {
		It("Should aggregate users correctly for no users", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{})

			Expect(gauges).To(HaveLen(0))
		})

		It("Should aggregate users correctly for a UAA user", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{
				{Origin: "uaa"},
			})

			Expect(gauges).To(HaveLen(1))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})

		It("Should aggregate users correctly for some UAA users", func() {
			gauges := UAAUsersByOriginGauges([]uaaclient.User{
				{Origin: "uaa"}, {Origin: "uaa"},
				{Origin: "google"}, {Origin: "microsoft"},
				{Origin: "uaa"}, {Origin: "uaa"}, {Origin: "google"},
			})

			Expect(gauges).To(HaveLen(3))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 4),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 2),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("microsoft"),
					})),
				}),
			))
		})
	})

	Context("Active Users (logged in within 30 days)", func() {
		It("Should select active users", func() {
			activeUsers := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(OneDayAgo.Unix() * 1000),
			}}

			Expect(UAAActiveUsers(activeUsers)).To(HaveLen(1))
		})

		It("Should reject inactive users", func() {
			inactiveUsers := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(ThirtyOneDaysAgo.Unix() * 1000),
			}}

			Expect(UAAActiveUsers(inactiveUsers)).To(HaveLen(0))
		})

		It("Should select active and reject inactive users", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(OneDayAgo.Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(ThirtyOneDaysAgo.Unix() * 1000),
			}}

			activeUsers := UAAActiveUsers(users)

			Expect(activeUsers).To(HaveLen(1))
			Expect(activeUsers[0].Origin).To(Equal("google"))
		})
	})

	Context("Active Users Aggregation (logged in within 30 days)", func() {
		It("Should select active users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(OneDayAgo.Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(1))
			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})

		It("Should reject inactive users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "uaa",
				LastLogonTime: int(ThirtyOneDaysAgo.Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(0))
		})

		It("Should select active and reject inactive users as gauges", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(OneDayAgo.Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(ThirtyOneDaysAgo.Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(1))
			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))
		})

		It("Should select active and reject inactive users as gauges for many users", func() {
			users := []uaaclient.User{{
				Origin:        "google",
				LastLogonTime: int(OneDayAgo.Unix() * 1000),
			}, {
				Origin:        "google",
				LastLogonTime: int(time.Now().Add(MinusOneDay * 60).Unix() * 1000),
			}, {
				Origin:        "microsoft",
				LastLogonTime: int(time.Now().Add(MinusOneDay * 2).Unix() * 1000),
			}, {
				Origin:        "microsoft",
				LastLogonTime: int(time.Now().Add(MinusOneDay * 91).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(MinusOneDay * 2).Unix() * 1000),
			}, {
				Origin:        "uaa",
				LastLogonTime: int(time.Now().Add(MinusOneDay * 31).Unix() * 1000),
			}}

			gauges := UAAActiveUsersByOriginGauges(users)

			Expect(gauges).To(HaveLen(3))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("google"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("microsoft"),
					})),
				}),
			))

			Expect(gauges).To(ContainElement(
				MatchFields(IgnoreExtras, Fields{
					"Name":  Equal("uaa.active.users"),
					"Unit":  Equal("count"),
					"Kind":  Equal(Gauge),
					"Value": BeNumerically("==", 1),
					"Tags": ContainElement(MatchFields(IgnoreExtras, Fields{
						"Label": Equal("origin"), "Value": Equal("uaa"),
					})),
				}),
			))
		})
	})
})
<|endoftext|>


<commit_before>package s3bucket_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
	"github.com/pivotal-cf/cf-redis-broker/s3bucket"
)

var _ = Describe("s3bucket", func() {
	var fakeRegion aws.Region
	var goamzBucketClient *s3.Bucket
	var bucketName = "i_am_bucket"

	BeforeEach(func() {
		fakeRegion = aws.Region{
			Name:                 "rake_region",
			S3Endpoint:           fakeS3EndpointURL,
			S3LocationConstraint: true,
		}
		goamzBucketClient = s3.New(aws.Auth{}, fakeRegion).Bucket(bucketName)
	})

	Describe("GetOrCreate", func() {
		Context("when the bucket already exists", func() {
			BeforeEach(func() {
				err := goamzBucketClient.PutBucket(s3.BucketOwnerFull)
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				err := goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the bucket and no error", func() {
				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				bucket, err := client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())
				Expect(bucket.Name).To(Equal(bucketName))
			})
		})

		Context("when the bucket does not exist", func() {
			It("creates the bucket", func() {
				bucketList, err := goamzBucketClient.ListBuckets()
				Expect(err).NotTo(HaveOccurred())
				Expect(bucketList.Buckets).To(HaveLen(0))

				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				_, err = client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())

				bucketList, err = goamzBucketClient.ListBuckets()
				Expect(err).NotTo(HaveOccurred())
				Expect(bucketList.Buckets).To(HaveLen(1))
				Expect(bucketList.Buckets[0].Name).To(Equal(bucketName))
			})

			It("returns the bucket and no error", func() {
				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				bucket, err := client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())
				Expect(bucket.Name).To(Equal(bucketName))
			})
		})

		Context("when goamz returns an error", func() {
			It("returns the same error", func() {
				client := s3bucket.NewClient("not-a-real-endpoint", "region", "accessKey", "secretKey")
				_, err := client.GetOrCreate(bucketName)
				Expect(err).To(MatchError(ContainSubstring("unsupported protocol scheme")))
			})
		})
	})

	Describe("Upload", func() {
		var bucket s3bucket.Bucket
		var path = "some/test/path"
		var data = []byte("some test data")

		BeforeEach(func() {
			var err error
			bucket, err = s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey").GetOrCreate(bucketName)
			Expect(err).NotTo(HaveOccurred())
		})

		Context("when everything works", func() {
			AfterEach(func() {
				err := goamzBucketClient.Del(path)
				Expect(err).NotTo(HaveOccurred())
				err = goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("uploads data to the correct path", func() {
				err := bucket.Upload(data, path)
				Expect(err).NotTo(HaveOccurred())

				content, err := goamzBucketClient.Get(path)
				Expect(content).To(Equal(data))
			})
		})

		Context("when goamz returns an error", func() {
			BeforeEach(func() {
				err := goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the same error", func() {
				err := bucket.Upload(data, path)
				Expect(err).To(MatchError("The specified bucket does not exist"))
			})
		})
	})
})
<commit_msg>ensure bucket is deleted after each spec<commit_after>package s3bucket_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
	"github.com/pivotal-cf/cf-redis-broker/s3bucket"
)

var _ = Describe("s3bucket", func() {
	var fakeRegion aws.Region
	var goamzBucketClient *s3.Bucket
	var bucketName = "i_am_bucket"

	BeforeEach(func() {
		fakeRegion = aws.Region{
			Name:                 "rake_region",
			S3Endpoint:           fakeS3EndpointURL,
			S3LocationConstraint: true,
		}
		goamzBucketClient = s3.New(aws.Auth{}, fakeRegion).Bucket(bucketName)
	})

	Describe("GetOrCreate", func() {
		Context("when the bucket already exists", func() {
			BeforeEach(func() {
				err := goamzBucketClient.PutBucket(s3.BucketOwnerFull)
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				err := goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the bucket and no error", func() {
				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				bucket, err := client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())
				Expect(bucket.Name).To(Equal(bucketName))
			})
		})

		Context("when the bucket does not exist", func() {
			It("creates the bucket", func() {
				bucketList, err := goamzBucketClient.ListBuckets()
				Expect(err).NotTo(HaveOccurred())
				Expect(bucketList.Buckets).To(HaveLen(0))

				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				_, err = client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())

				bucketList, err = goamzBucketClient.ListBuckets()
				Expect(err).NotTo(HaveOccurred())
				Expect(bucketList.Buckets).To(HaveLen(1))
				Expect(bucketList.Buckets[0].Name).To(Equal(bucketName))
			})

			It("returns the bucket and no error", func() {
				client := s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey")
				bucket, err := client.GetOrCreate(bucketName)
				Expect(err).NotTo(HaveOccurred())
				Expect(bucket.Name).To(Equal(bucketName))
			})

			AfterEach(func() {
				err := goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})
		})

		Context("when goamz returns an error", func() {
			It("returns the same error", func() {
				client := s3bucket.NewClient("not-a-real-endpoint", "region", "accessKey", "secretKey")
				_, err := client.GetOrCreate(bucketName)
				Expect(err).To(MatchError(ContainSubstring("unsupported protocol scheme")))
			})
		})
	})

	Describe("Upload", func() {
		var bucket s3bucket.Bucket
		var path = "some/test/path"
		var data = []byte("some test data")

		BeforeEach(func() {
			var err error
			bucket, err = s3bucket.NewClient(fakeS3EndpointURL, "region", "accessKey", "secretKey").GetOrCreate(bucketName)
			Expect(err).NotTo(HaveOccurred())
		})

		Context("when everything works", func() {
			AfterEach(func() {
				err := goamzBucketClient.Del(path)
				Expect(err).NotTo(HaveOccurred())
				err = goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("uploads data to the correct path", func() {
				err := bucket.Upload(data, path)
				Expect(err).NotTo(HaveOccurred())

				content, err := goamzBucketClient.Get(path)
				Expect(content).To(Equal(data))
			})
		})

		Context("when goamz returns an error", func() {
			BeforeEach(func() {
				err := goamzBucketClient.DelBucket()
				Expect(err).NotTo(HaveOccurred())
			})

			It("returns the same error", func() {
				err := bucket.Upload(data, path)
				Expect(err).To(MatchError("The specified bucket does not exist"))
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"strconv"
	"errors"
	"sync"
	"time"

	"golang.org/x/oauth2"

	heroku "github.com/bgentry/heroku-go"
	"github.com/gocarina/gocsv"
	"github.com/google/go-github/github"
	"github.com/olekukonko/tablewriter"
)

type CMS struct {
	Name     string `csv:"name"`
	CName    string `csv:"cname"`
	String   string `csv:"string"`
	OverHTTP string `csv:"http"`
}

type ScanResult struct {
	Domain       string
	Cname        string
	Provider     string
	IsVulnerable bool
	IsTakenOver  bool
	Response     string
}

type Configuration struct {
	domainsFilePath *string
	recordsFilePath *string
	outputFilePath  *string
	takeOver        *bool
	githubtoken     *string
	herokuusername  *string
	herokuapikey    *string
	herokuappname   *string
	domain          *string
	threadCount     *int
}

func main() {
	config := Configuration {
		domainsFilePath : flag.String("domains", "domains.txt", "List of domains to check"),
		recordsFilePath : flag.String("data", "providers-data.csv", "CSV file containing CMS providers' string for identification"),
		outputFilePath  : flag.String("output", "output.csv", "Output file to save the results"),
		takeOver        : flag.Bool("takeover", false, "Flag to denote if a vulnerable domain needs to be taken over or not"),
		githubtoken     : flag.String("githubtoken", "", "Github personal access token"),
		herokuusername  : flag.String("herokuusername", "", "Heroku username"),
		herokuapikey    : flag.String("herokuapikey", "", "Heroku API key"),
		herokuappname   : flag.String("herokuappname", "", "Heroku app name"),
		domain          : flag.String("domain", "", "Domains separated by ,"),
		threadCount     : flag.Int("threads", 5, "Number of threads to run parallel")}
	flag.Parse()

	cmsRecords := loadProviders(*config.recordsFilePath)
	var allResults []ScanResult

	if *config.domain != "" {
		for _, domain := range strings.Split(*config.domain, ",") {
			scanResults, err := scanDomain(domain, cmsRecords, config)
			if (err == nil) {
				allResults = append(allResults, scanResults...)
			} else {
				fmt.Printf("[%s] Domain problem : %s\n", domain, err)
			}
		}
	} else {
		domainsFile, err := os.Open(*config.domainsFilePath)
		panicOnError(err)
		defer domainsFile.Close()
		domainsScanner := bufio.NewScanner(domainsFile)

		var wg sync.WaitGroup
		sem := make(chan bool, *config.threadCount)

		for domainsScanner.Scan() {
			wg.Add(1)
			sem <- true
			go func(domain string) {
				scanResults, err := scanDomain(domain, cmsRecords, config)
				if (err == nil) {
					allResults = append(allResults, scanResults...)
				} else {
					fmt.Printf("[%s] Domain problem : %s\n", domain, err)
				}
				<- sem
			    	wg.Done()
			}(domainsScanner.Text())
		}
		wg.Wait()
	}

	printResults(allResults)

	if (*config.outputFilePath != "") {
		writeResultsToCsv(allResults, *config.outputFilePath)
		Info("Results saved to: " + *config.outputFilePath)
	}
}

//panicOnError function as a generic check for error function
func panicOnError(e error) {
	if e != nil {
		panic(e)
	}
}

//Info function to print pretty output
func Info(format string, args ...interface{}) {
	fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...))
}

//takeoversub function to decide what to do depending upon the CMS
func takeoversub(domain string, provider string, config Configuration) (bool, error) {
	switch provider {
	case "github":
		return githubcreate(domain, config)
	case "heroku":
		return herokucreate(domain, config)
	}
	return false, nil
}

//githubcreate function to take over dangling Github Pages
// Connecting to your Github account using the Personal Access Token
func githubcreate(domain string, config Configuration) (bool, error) {
	ctx := context.Background()
	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: *config.githubtoken})
	tc := oauth2.NewClient(ctx, ts)
	client := github.NewClient(tc)

	repo := &github.Repository{
		Name:            github.String(domain),
		Description:     github.String("testing subdomain takeovers"),
		Private:         github.Bool(false),
		LicenseTemplate: github.String("mit"),
	}

	// Creating a repo
	repocreate, _, err := client.Repositories.Create(ctx, "", repo)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	reponame := *repocreate.Name
	ownername := *repocreate.Owner.Login
	refURL := *repocreate.URL
	ref := "refs/heads/master"

	// Retrieving the SHA value of the head branch
	SHAvalue, _, err := client.Repositories.GetCommitSHA1(ctx, ownername, reponame, ref, "")
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	opt := &github.Reference{
		Ref: github.String("refs/heads/gh-pages"),
		URL: github.String(refURL + "/git/refs/heads/gh-pages"),
		Object: &github.GitObject{
			SHA: github.String(SHAvalue),
		},
	}

	// Creating the gh-pages branch using the SHA value obtained above
	_, _, err = client.Git.CreateRef(ctx, ownername, reponame, opt)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	Indexpath := "index.html"
	CNAMEpath := "CNAME"
	data := "This domain is temporarily suspended"

	indexfile := &github.RepositoryContentFileOptions{
		Message: github.String("Adding the index.html page"),
		Content: []byte(data),
		Branch:  github.String("gh-pages"),
	}

	// Creating the index file with the text you want to see when the domain is taken over
	_, _, err = client.Repositories.CreateFile(ctx, ownername, reponame, Indexpath, indexfile)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	cnamefile := &github.RepositoryContentFileOptions{
		Message: github.String("Adding the subdomain to takeover to the CNAME file"),
		Content: []byte(domain),
		Branch:  github.String("gh-pages"),
	}

	// Creating the CNAME file with the domain that needs to be taken over
	_, _, err = client.Repositories.CreateFile(ctx, ownername, reponame, CNAMEpath, cnamefile)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	Info("Please check " + domain + " after a few minutes to ensure that it has been taken over..")
	return true, nil
}

//herokucreate function to take over dangling Heroku apps
// Connecting to your Heroku account using the username and the API key provided as flags
// Adding the dangling domain as a custom domain for your appname that is retrieved from the flag
// This results in the dangling domain pointing to your Heroku appname
func herokucreate(domain string, config Configuration) (bool, error) {
	client := heroku.Client{Username: *config.herokuusername, Password: *config.herokuapikey}
	client.DomainCreate(*config.herokuappname, domain)
	Info("Please check " + domain + " after a few minutes to ensure that it has been taken over..")

	return true, nil
}

//scanforeachDomain function to scan for each domain being read from the domains file
//Doing CNAME lookups using GOLANG's net package or for that matter just doing a host on a domain
//does not necessarily let us know about any dead DNS records. So, we need to use dig CNAME <domain> +short
//to properly figure out if there are any dead DNS records
func scanDomain(domain string, cmsRecords []*CMS, config Configuration) ([]ScanResult, error) {
	cname, err := getCnameForDomain(domain)
	if (err != nil) {
		return nil, err
	} else {
		scanResults := checkCnameAgainstProviders(domain, cname, cmsRecords, config)
		if (len(scanResults) == 0) {
			err = errors.New(fmt.Sprintf("Cname [%s] found but could not determine provider", cname))
		}
		return scanResults, err
	}
}

func getCnameForDomain(domain string) (string, error) {
	var out, errorOutput bytes.Buffer
	cmd := exec.Command("dig", "CNAME", domain, "+short")
	cmd.Stdout = &out
	cmd.Stderr = &errorOutput
	err := cmd.Run()

	cname := strings.TrimSpace(out.String())
	if (err != nil) {
		return "", err
	} else if (len(errorOutput.String()) > 0) {
		return "", errors.New(errorOutput.String())
	} else if (len(cname) == 0) {
		return "", errors.New("Cname not found")
	}
	return cname, nil
}

//Now, for each entry in the data providers file, we will check to see if the output
//from the dig command against the current domain matches the CNAME for that data provider
//if it matches the CNAME, we need to now check if it matches the string for that data provider
//So, we curl it and see if it matches. At this point, we know its vulnerable
//Next, if we have the -takeover flag set to 1, we will also try to take over the dangling subdomain
func checkCnameAgainstProviders(domain string, cname string, cmsRecords []*CMS, config Configuration) ([]ScanResult) {
	transport := &http.Transport{
		Dial: (&net.Dialer{ Timeout: 10 * time.Second }).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}

	client := &http.Client{Transport: transport, Timeout: time.Duration(10 * time.Second)}
	var scanResults []ScanResult

	for _, cmsRecord := range cmsRecords {
		usesprovider, _ := regexp.MatchString(cmsRecord.CName, cname)
		if usesprovider {
			scanResult := evaluateDomainProvider(domain, cname, cmsRecord, client)
			if (*config.takeOver && scanResult.IsVulnerable) {
				_, err := takeoversub(scanResult.Domain, scanResult.Provider, config)
				if (err != nil) {
					scanResult.IsTakenOver = true
					scanResult.Response = err.Error()
				}
			}
			scanResults = append(scanResults, scanResult)
		}
	}
	return scanResults
}

//Heroku behaves slightly different. Even if there is a dead DNS record for Heroku
//it would not resolve using host and you can't curl the website unlike other CMS
//but you will find it using dig
//So, if there is a CNAME match for heroku and can't curl it, we will assume its vulnerable
//if its not heroku, we will try to curl and regex match the string obtained in the response with
//the string specified in the data providers file to see if its vulnerable or not
func evaluateDomainProvider(domain string, cname string, cmsRecord *CMS, client *http.Client) (ScanResult) {
	scanResult := ScanResult{ Domain: domain, Cname: cname,
		IsTakenOver: false, IsVulnerable: false, Provider : cmsRecord.Name }
	protocol := "https://"
	if cmsRecord.OverHTTP == "true" {
		protocol = "http://"
	}

	response, err := client.Get(protocol + scanResult.Domain)

	if err != nil && cmsRecord.Name == "heroku" {
		scanResult.IsVulnerable = true
		scanResult.Response = "Can't CURL it but dig shows a dead DNS record"
	} else if err != nil && cmsRecord.Name != "heroku" {
		scanResult.Response = err.Error()
	} else if err == nil {
		text, err := ioutil.ReadAll(response.Body)
		if (err != nil) {
			scanResult.Response = err.Error()
		} else {
			scanResult.IsVulnerable, err = regexp.MatchString(cmsRecord.String, string(text))
			if (err != nil) {
				scanResult.Response = err.Error()
			}
		}
	}
	return scanResult
}

func loadProviders(recordsFilePath string) ([]*CMS) {
	clientsFile, err := os.OpenFile(recordsFilePath, os.O_RDWR|os.O_CREATE, os.ModePerm)
	panicOnError(err)
	defer clientsFile.Close()

	cmsRecords := []*CMS{}
	err = gocsv.UnmarshalFile(clientsFile, &cmsRecords)
	panicOnError(err)
	return cmsRecords
}

func writeResultsToCsv(scanResults []ScanResult, outputFilePath string) {
	outputFile, err := os.Create(outputFilePath)
	panicOnError(err)
	defer outputFile.Close()

	err = gocsv.MarshalFile(&scanResults, outputFile)
	panicOnError(err)
}

func printResults(scanResults []ScanResult) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Domain", "Cname", "Provider", "Vulnerable", "Taken Over", "Response"})

	for _, scanResult := range scanResults {
		if ((len(scanResult.Cname) > 0 && len(scanResult.Provider) > 0) || len(scanResult.Response) > 0) {
			table.Append([]string{scanResult.Domain, scanResult.Cname, scanResult.Provider,
				strconv.FormatBool(scanResult.IsVulnerable),
				strconv.FormatBool(scanResult.IsTakenOver),
				scanResult.Response });
		}
	}
	table.Render()
}
<commit_msg>Fix wrong takeover detection logic<commit_after>package main

import (
	"bufio"
	"bytes"
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"strconv"
	"errors"
	"sync"
	"time"

	"golang.org/x/oauth2"

	heroku "github.com/bgentry/heroku-go"
	"github.com/gocarina/gocsv"
	"github.com/google/go-github/github"
	"github.com/olekukonko/tablewriter"
)

type CMS struct {
	Name     string `csv:"name"`
	CName    string `csv:"cname"`
	String   string `csv:"string"`
	OverHTTP string `csv:"http"`
}

type ScanResult struct {
	Domain       string
	Cname        string
	Provider     string
	IsVulnerable bool
	IsTakenOver  bool
	Response     string
}

type Configuration struct {
	domainsFilePath *string
	recordsFilePath *string
	outputFilePath  *string
	takeOver        *bool
	githubtoken     *string
	herokuusername  *string
	herokuapikey    *string
	herokuappname   *string
	domain          *string
	threadCount     *int
}

func main() {
	config := Configuration {
		domainsFilePath : flag.String("domains", "domains.txt", "List of domains to check"),
		recordsFilePath : flag.String("data", "providers-data.csv", "CSV file containing CMS providers' string for identification"),
		outputFilePath  : flag.String("output", "output.csv", "Output file to save the results"),
		takeOver        : flag.Bool("takeover", false, "Flag to denote if a vulnerable domain needs to be taken over or not"),
		githubtoken     : flag.String("githubtoken", "", "Github personal access token"),
		herokuusername  : flag.String("herokuusername", "", "Heroku username"),
		herokuapikey    : flag.String("herokuapikey", "", "Heroku API key"),
		herokuappname   : flag.String("herokuappname", "", "Heroku app name"),
		domain          : flag.String("domain", "", "Domains separated by ,"),
		threadCount     : flag.Int("threads", 5, "Number of threads to run parallel")}
	flag.Parse()

	cmsRecords := loadProviders(*config.recordsFilePath)
	var allResults []ScanResult

	if *config.domain != "" {
		for _, domain := range strings.Split(*config.domain, ",") {
			scanResults, err := scanDomain(domain, cmsRecords, config)
			if (err == nil) {
				allResults = append(allResults, scanResults...)
			} else {
				fmt.Printf("[%s] Domain problem : %s\n", domain, err)
			}
		}
	} else {
		domainsFile, err := os.Open(*config.domainsFilePath)
		panicOnError(err)
		defer domainsFile.Close()
		domainsScanner := bufio.NewScanner(domainsFile)

		var wg sync.WaitGroup
		sem := make(chan bool, *config.threadCount)

		for domainsScanner.Scan() {
			wg.Add(1)
			sem <- true
			go func(domain string) {
				scanResults, err := scanDomain(domain, cmsRecords, config)
				if (err == nil) {
					allResults = append(allResults, scanResults...)
				} else {
					fmt.Printf("[%s] Domain problem : %s\n", domain, err)
				}
				<- sem
			    wg.Done()
			}(domainsScanner.Text())
		}
		wg.Wait()
	}

	printResults(allResults)

	if (*config.outputFilePath != "") {
		writeResultsToCsv(allResults, *config.outputFilePath)
		Info("Results saved to: " + *config.outputFilePath)
	}
}

//panicOnError function as a generic check for error function
func panicOnError(e error) {
	if e != nil {
		panic(e)
	}
}

//Info function to print pretty output
func Info(format string, args ...interface{}) {
	fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...))
}

//takeoversub function to decide what to do depending upon the CMS
func takeoversub(domain string, provider string, config Configuration) (bool, error) {
	switch provider {
	case "github":
		return githubcreate(domain, config)
	case "heroku":
		return herokucreate(domain, config)
	}
	return false, nil
}

//githubcreate function to take over dangling Github Pages
// Connecting to your Github account using the Personal Access Token
func githubcreate(domain string, config Configuration) (bool, error) {
	ctx := context.Background()
	ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: *config.githubtoken})
	tc := oauth2.NewClient(ctx, ts)
	client := github.NewClient(tc)

	repo := &github.Repository{
		Name:            github.String(domain),
		Description:     github.String("testing subdomain takeovers"),
		Private:         github.Bool(false),
		LicenseTemplate: github.String("mit"),
	}

	// Creating a repo
	repocreate, _, err := client.Repositories.Create(ctx, "", repo)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	reponame := *repocreate.Name
	ownername := *repocreate.Owner.Login
	refURL := *repocreate.URL
	ref := "refs/heads/master"

	// Retrieving the SHA value of the head branch
	SHAvalue, _, err := client.Repositories.GetCommitSHA1(ctx, ownername, reponame, ref, "")
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	opt := &github.Reference{
		Ref: github.String("refs/heads/gh-pages"),
		URL: github.String(refURL + "/git/refs/heads/gh-pages"),
		Object: &github.GitObject{
			SHA: github.String(SHAvalue),
		},
	}

	// Creating the gh-pages branch using the SHA value obtained above
	_, _, err = client.Git.CreateRef(ctx, ownername, reponame, opt)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	Indexpath := "index.html"
	CNAMEpath := "CNAME"
	data := "This domain is temporarily suspended"

	indexfile := &github.RepositoryContentFileOptions{
		Message: github.String("Adding the index.html page"),
		Content: []byte(data),
		Branch:  github.String("gh-pages"),
	}

	// Creating the index file with the text you want to see when the domain is taken over
	_, _, err = client.Repositories.CreateFile(ctx, ownername, reponame, Indexpath, indexfile)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	cnamefile := &github.RepositoryContentFileOptions{
		Message: github.String("Adding the subdomain to takeover to the CNAME file"),
		Content: []byte(domain),
		Branch:  github.String("gh-pages"),
	}

	// Creating the CNAME file with the domain that needs to be taken over
	_, _, err = client.Repositories.CreateFile(ctx, ownername, reponame, CNAMEpath, cnamefile)
	if _, ok := err.(*github.RateLimitError); ok {
		log.Println("hit rate limit")
		return false, err
	}

	Info("Please check " + domain + " after a few minutes to ensure that it has been taken over..")
	return true, nil
}

//herokucreate function to take over dangling Heroku apps
// Connecting to your Heroku account using the username and the API key provided as flags
// Adding the dangling domain as a custom domain for your appname that is retrieved from the flag
// This results in the dangling domain pointing to your Heroku appname
func herokucreate(domain string, config Configuration) (bool, error) {
	client := heroku.Client{Username: *config.herokuusername, Password: *config.herokuapikey}
	client.DomainCreate(*config.herokuappname, domain)
	Info("Please check " + domain + " after a few minutes to ensure that it has been taken over..")

	return true, nil
}

//scanforeachDomain function to scan for each domain being read from the domains file
//Doing CNAME lookups using GOLANG's net package or for that matter just doing a host on a domain
//does not necessarily let us know about any dead DNS records. So, we need to use dig CNAME <domain> +short
//to properly figure out if there are any dead DNS records
func scanDomain(domain string, cmsRecords []*CMS, config Configuration) ([]ScanResult, error) {
	cname, err := getCnameForDomain(domain)
	if (err != nil) {
		return nil, err
	} else {
		scanResults := checkCnameAgainstProviders(domain, cname, cmsRecords, config)
		if (len(scanResults) == 0) {
			err = errors.New(fmt.Sprintf("Cname [%s] found but could not determine provider", cname))
		}
		return scanResults, err
	}
}

func getCnameForDomain(domain string) (string, error) {
	var out, errorOutput bytes.Buffer
	cmd := exec.Command("dig", "CNAME", domain, "+short")
	cmd.Stdout = &out
	cmd.Stderr = &errorOutput
	err := cmd.Run()

	cname := strings.TrimSpace(out.String())
	if (err != nil) {
		return "", err
	} else if (len(errorOutput.String()) > 0) {
		return "", errors.New(errorOutput.String())
	} else if (len(cname) == 0) {
		return "", errors.New("Cname not found")
	}
	return cname, nil
}

//Now, for each entry in the data providers file, we will check to see if the output
//from the dig command against the current domain matches the CNAME for that data provider
//if it matches the CNAME, we need to now check if it matches the string for that data provider
//So, we curl it and see if it matches. At this point, we know its vulnerable
//Next, if we have the -takeover flag set to 1, we will also try to take over the dangling subdomain
func checkCnameAgainstProviders(domain string, cname string, cmsRecords []*CMS, config Configuration) ([]ScanResult) {
	transport := &http.Transport{
		Dial: (&net.Dialer{ Timeout: 10 * time.Second }).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}

	client := &http.Client{Transport: transport, Timeout: time.Duration(10 * time.Second)}
	var scanResults []ScanResult

	for _, cmsRecord := range cmsRecords {
		usesprovider, _ := regexp.MatchString(cmsRecord.CName, cname)
		if usesprovider {
			scanResult := evaluateDomainProvider(domain, cname, cmsRecord, client)
			if (*config.takeOver && scanResult.IsVulnerable) {
				isTakenOver, err := takeoversub(scanResult.Domain, scanResult.Provider, config)
				if (err != nil) {
					scanResult.Response = err.Error()
				}
				scanResult.IsTakenOver = isTakenOver
			}
			scanResults = append(scanResults, scanResult)
		}
	}
	return scanResults
}

//Heroku behaves slightly different. Even if there is a dead DNS record for Heroku
//it would not resolve using host and you can't curl the website unlike other CMS
//but you will find it using dig
//So, if there is a CNAME match for heroku and can't curl it, we will assume its vulnerable
//if its not heroku, we will try to curl and regex match the string obtained in the response with
//the string specified in the data providers file to see if its vulnerable or not
func evaluateDomainProvider(domain string, cname string, cmsRecord *CMS, client *http.Client) (ScanResult) {
	scanResult := ScanResult{ Domain: domain, Cname: cname,
		IsTakenOver: false, IsVulnerable: false, Provider : cmsRecord.Name }
	protocol := "https://"
	if cmsRecord.OverHTTP == "true" {
		protocol = "http://"
	}

	response, err := client.Get(protocol + scanResult.Domain)

	if err != nil && cmsRecord.Name == "heroku" {
		scanResult.IsVulnerable = true
		scanResult.Response = "Can't CURL it but dig shows a dead DNS record"
	} else if err != nil && cmsRecord.Name != "heroku" {
		scanResult.Response = err.Error()
	} else if err == nil {
		text, err := ioutil.ReadAll(response.Body)
		if (err != nil) {
			scanResult.Response = err.Error()
		} else {
			scanResult.IsVulnerable, err = regexp.MatchString(cmsRecord.String, string(text))
			if (err != nil) {
				scanResult.Response = err.Error()
			}
		}
	}
	return scanResult
}

func loadProviders(recordsFilePath string) ([]*CMS) {
	clientsFile, err := os.OpenFile(recordsFilePath, os.O_RDWR|os.O_CREATE, os.ModePerm)
	panicOnError(err)
	defer clientsFile.Close()

	cmsRecords := []*CMS{}
	err = gocsv.UnmarshalFile(clientsFile, &cmsRecords)
	panicOnError(err)
	return cmsRecords
}

func writeResultsToCsv(scanResults []ScanResult, outputFilePath string) {
	outputFile, err := os.Create(outputFilePath)
	panicOnError(err)
	defer outputFile.Close()

	err = gocsv.MarshalFile(&scanResults, outputFile)
	panicOnError(err)
}

func printResults(scanResults []ScanResult) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Domain", "Cname", "Provider", "Vulnerable", "Taken Over", "Response"})

	for _, scanResult := range scanResults {
		if ((len(scanResult.Cname) > 0 && len(scanResult.Provider) > 0) || len(scanResult.Response) > 0) {
			table.Append([]string{scanResult.Domain, scanResult.Cname, scanResult.Provider,
				strconv.FormatBool(scanResult.IsVulnerable),
				strconv.FormatBool(scanResult.IsTakenOver),
				scanResult.Response });
		}
	}
	table.Render()
}
<|endoftext|>


<commit_before>package proxyproto

import (
	"bufio"
	"bytes"
	"testing"
)

var (
	fixtureOneByteTLV    = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 1}
	fixtureTwoByteTLV    = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 2, 0x00}
	fixtureEmptyLenTLV   = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 3, 0x00, 0x01}
	fixturePartialLenTLV = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 3, 0x00, 0x02, 0x00}
)

func checkTLVs(t *testing.T, name string, raw []byte, expected []PP2Type) []TLV {
	header, err := parseVersion2(bufio.NewReader(bytes.NewReader(raw)))
	if err != nil {
		t.Fatalf("%s: Unexpected error reading header %#v", name, err)
	}

	tlvs, err := header.TLVs()
	if err != nil {
		t.Fatalf("%s: Unexpected error splitting TLVS %#v", name, err)
	}

	if len(tlvs) != len(expected) {
		t.Fatalf("%s: Expected %d TLVs, actual %d", name, len(expected), len(tlvs))
	}

	for i, et := range expected {
		if at := tlvs[i].Type; at != et {
			t.Fatalf("%s: Expected type %X, actual %X", name, et, at)
		}
	}

	return tlvs
}

var invalidTLVTests = []struct {
	name          string
	reader        *bufio.Reader
	expectedError error
}{
	{
		name: "One byte TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureOneByteTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Two byte TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureTwoByteTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Empty Len TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureEmptyLenTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Partial Len TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixturePartialLenTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
}

func TestInvalidV2TLV(t *testing.T) {
	for _, tc := range invalidTLVTests {
		t.Run(tc.name, func(t *testing.T) {
			if hdr, err := Read(tc.reader); err != nil {
				t.Fatalf("TestInvalidV2TLV %s: unexpected error reading proxy protocol %#v", tc.name, err)
			} else if _, err := hdr.TLVs(); err != tc.expectedError {
				t.Fatalf("TestInvalidV2TLV %s: expected %#v, actual %#v", tc.name, tc.expectedError, err)
			}
		})
	}
}

func TestV2TLVPP2Registered(t *testing.T) {
	pp2RegTypes := []PP2Type{
		PP2_TYPE_ALPN, PP2_TYPE_AUTHORITY, PP2_TYPE_CRC32C, PP2_TYPE_NOOP,
		PP2_TYPE_SSL, PP2_SUBTYPE_SSL_VERSION, PP2_SUBTYPE_SSL_CN,
		PP2_SUBTYPE_SSL_CIPHER, PP2_SUBTYPE_SSL_SIG_ALG, PP2_SUBTYPE_SSL_KEY_ALG,
		PP2_TYPE_NETNS,
	}
	pp2RegMap := make(map[PP2Type]bool)
	for _, p := range pp2RegTypes {
		pp2RegMap[p] = true
		if !p.Registered() {
			t.Fatalf("TestV2TLVPP2Registered: type %x should be registered", p)
		}
		if !p.Spec() {
			t.Fatalf("TestV2TLVPP2Registered: type %x should be in spec", p)
		}
		if p.App() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly app", p)
		}
		if p.Experiment() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly experiment", p)
		}
		if p.Future() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly future", p)
		}
	}

	lastType := PP2Type(0xFF)
	for i := PP2Type(0x00); i < lastType; i++ {
		if !pp2RegMap[i] {
			if i.Registered() {
				t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly registered", i)
			}
		}
	}

	if lastType.Registered() {
		t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly registered", lastType)
	}
}

func TestJoinTLVs(t *testing.T) {
	tests := []struct {
		name string
		raw  []byte
		tlvs []TLV
	}{
		{
			name: "authority TLV",
			raw:  append([]byte{byte(PP2_TYPE_AUTHORITY), 0x00, 0x0B}, []byte("example.org")...),
			tlvs: []TLV{{
				Type:  PP2_TYPE_AUTHORITY,
				Value: []byte("example.org"),
			}},
		},
		{
			name: "empty TLV",
			raw:  []byte{byte(PP2_TYPE_NOOP), 0x00, 0x00},
			tlvs: []TLV{{
				Type:  PP2_TYPE_NOOP,
				Value: nil,
			}},
		},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			if raw, err := JoinTLVs(tc.tlvs); err != nil {
				t.Fatalf("unexpected error: %v", err)
			} else if !bytes.Equal(raw, tc.raw) {
				t.Errorf("expected %#v, got %#v", tc.raw, raw)
			}
		})
	}
}
<commit_msg>Added unittest covering 0 byte tlv value<commit_after>package proxyproto

import (
	"bufio"
	"bytes"
	"testing"
)

var (
	fixtureOneByteTLV    = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 1}
	fixtureTwoByteTLV    = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 2, 0x00}
	fixtureEmptyLenTLV   = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 3, 0x00, 0x01}
	fixturePartialLenTLV = []byte{byte(PP2_TYPE_MIN_CUSTOM) + 3, 0x00, 0x02, 0x00}
)

func checkTLVs(t *testing.T, name string, raw []byte, expected []PP2Type) []TLV {
	header, err := parseVersion2(bufio.NewReader(bytes.NewReader(raw)))
	if err != nil {
		t.Fatalf("%s: Unexpected error reading header %#v", name, err)
	}

	tlvs, err := header.TLVs()
	if err != nil {
		t.Fatalf("%s: Unexpected error splitting TLVS %#v", name, err)
	}

	if len(tlvs) != len(expected) {
		t.Fatalf("%s: Expected %d TLVs, actual %d", name, len(expected), len(tlvs))
	}

	for i, et := range expected {
		if at := tlvs[i].Type; at != et {
			t.Fatalf("%s: Expected type %X, actual %X", name, et, at)
		}
	}

	return tlvs
}

var invalidTLVTests = []struct {
	name          string
	reader        *bufio.Reader
	expectedError error
}{
	{
		name: "One byte TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureOneByteTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Two byte TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureTwoByteTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Empty Len TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixtureEmptyLenTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
	{
		name: "Partial Len TLV",
		reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address,
			fixturePartialLenTLV)...)),
		expectedError: ErrTruncatedTLV,
	},
}

func TestValid0Length(t *testing.T) {
	r := bufio.NewReader(bytes.NewReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address, []byte{byte(PP2_TYPE_MIN_CUSTOM), 0x00, 0x00})...)))
	h, err := Read(r)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	tlvs, err := h.TLVs()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if len(tlvs) != 1 {
		t.Fatalf("expected 1 tlv, got %d", len(tlvs))
	}
	if len(tlvs[0].Value) != 0 {
		t.Fatalf("expected 0 byte tlv value, got %x", tlvs[0].Value)
	}
}

func TestInvalidV2TLV(t *testing.T) {
	for _, tc := range invalidTLVTests {
		t.Run(tc.name, func(t *testing.T) {
			if hdr, err := Read(tc.reader); err != nil {
				t.Fatalf("TestInvalidV2TLV %s: unexpected error reading proxy protocol %#v", tc.name, err)
			} else if _, err := hdr.TLVs(); err != tc.expectedError {
				t.Fatalf("TestInvalidV2TLV %s: expected %#v, actual %#v", tc.name, tc.expectedError, err)
			}
		})
	}
}

func TestV2TLVPP2Registered(t *testing.T) {
	pp2RegTypes := []PP2Type{
		PP2_TYPE_ALPN, PP2_TYPE_AUTHORITY, PP2_TYPE_CRC32C, PP2_TYPE_NOOP,
		PP2_TYPE_SSL, PP2_SUBTYPE_SSL_VERSION, PP2_SUBTYPE_SSL_CN,
		PP2_SUBTYPE_SSL_CIPHER, PP2_SUBTYPE_SSL_SIG_ALG, PP2_SUBTYPE_SSL_KEY_ALG,
		PP2_TYPE_NETNS,
	}
	pp2RegMap := make(map[PP2Type]bool)
	for _, p := range pp2RegTypes {
		pp2RegMap[p] = true
		if !p.Registered() {
			t.Fatalf("TestV2TLVPP2Registered: type %x should be registered", p)
		}
		if !p.Spec() {
			t.Fatalf("TestV2TLVPP2Registered: type %x should be in spec", p)
		}
		if p.App() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly app", p)
		}
		if p.Experiment() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly experiment", p)
		}
		if p.Future() {
			t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly future", p)
		}
	}

	lastType := PP2Type(0xFF)
	for i := PP2Type(0x00); i < lastType; i++ {
		if !pp2RegMap[i] {
			if i.Registered() {
				t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly registered", i)
			}
		}
	}

	if lastType.Registered() {
		t.Fatalf("TestV2TLVPP2Registered: type %x unexpectedly registered", lastType)
	}
}

func TestJoinTLVs(t *testing.T) {
	tests := []struct {
		name string
		raw  []byte
		tlvs []TLV
	}{
		{
			name: "authority TLV",
			raw:  append([]byte{byte(PP2_TYPE_AUTHORITY), 0x00, 0x0B}, []byte("example.org")...),
			tlvs: []TLV{{
				Type:  PP2_TYPE_AUTHORITY,
				Value: []byte("example.org"),
			}},
		},
		{
			name: "empty TLV",
			raw:  []byte{byte(PP2_TYPE_NOOP), 0x00, 0x00},
			tlvs: []TLV{{
				Type:  PP2_TYPE_NOOP,
				Value: nil,
			}},
		},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			if raw, err := JoinTLVs(tc.tlvs); err != nil {
				t.Fatalf("unexpected error: %v", err)
			} else if !bytes.Equal(raw, tc.raw) {
				t.Errorf("expected %#v, got %#v", tc.raw, raw)
			}
		})
	}
}
<|endoftext|>


<commit_before>/*
num2words implements numbers to words converter.
*/
package num2words

import "math"

// how many digit's groups to process
const groups_number int = 4

var _smallNumbers = []string{
	"zero", "one", "two", "three", "four",
	"five", "six", "seven", "eight", "nine",
	"ten", "eleven", "twelve", "thirteen", "fourteen",
	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
}
var _tens = []string{
	"", "", "twenty", "thirty", "forty", "fifty",
	"sixty", "seventy", "eighty", "ninety",
}
var _scaleNumbers = []string{
	"", "thousand", "million", "billion",
}

type digitGroup int

// Convert converts number into the words representation.
func Convert(number int) string {
	return convert(number, false)
}

// ConvertAnd converts number into the words representation
// with " and " added between number groups.
func ConvertAnd(number int) string {
	return convert(number, true)
}

func convert(number int, useAnd bool) string {
	// Zero rule
	if number == 0 {
		return _smallNumbers[0]
	}

	// Divide into three-digits group
	var groups [groups_number]digitGroup
	positive := math.Abs(float64(number))

	// Form three-digit groups
	for i := 0; i < groups_number; i++ {
		groups[i] = digitGroup(math.Mod(positive, 1000))
		positive /= 1000
	}

	var textGroup [groups_number]string
	for i := 0; i < groups_number; i++ {
		textGroup[i] = digitGroup2Text(groups[i], useAnd)
	}
	combined := textGroup[0]
	and := useAnd && (groups[0] > 0 && groups[0] < 100)

	for i := 1; i < groups_number; i++ {
		if groups[i] != 0 {
			prefix := textGroup[i] + " " + _scaleNumbers[i]

			if len(combined) != 0 {
				prefix += separator(and)
			}

			and = false

			combined = prefix + combined
		}
	}

	if number < 0 {
		combined = "minus " + combined
	}

	return combined
}

func intMod(x, y int) int {
	return int(math.Mod(float64(x), float64(y)))
}

func digitGroup2Text(group digitGroup, useAnd bool) (ret string) {
	hundreds := group / 100
	tensUnits := intMod(int(group), 100)

	if hundreds != 0 {
		ret += _smallNumbers[hundreds] + " hundred"

		if tensUnits != 0 {
			ret += separator(useAnd)
		}
	}

	tens := tensUnits / 10
	units := intMod(tensUnits, 10)

	if tens >= 2 {
		ret += _tens[tens]

		if units != 0 {
			ret += " " + _smallNumbers[units]
		}
	} else if tensUnits != 0 {
		ret += _smallNumbers[tensUnits]
	}

	return
}

// separator returns proper separator string between
// number groups.
func separator(useAnd bool) string {
	if useAnd {
		return " and "
	}
	return " "
}
<commit_msg>Make linter happy<commit_after>// Package num2words implements numbers to words converter.
package num2words

import "math"

// how many digit's groups to process
const groupsNumber int = 4

var _smallNumbers = []string{
	"zero", "one", "two", "three", "four",
	"five", "six", "seven", "eight", "nine",
	"ten", "eleven", "twelve", "thirteen", "fourteen",
	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen",
}
var _tens = []string{
	"", "", "twenty", "thirty", "forty", "fifty",
	"sixty", "seventy", "eighty", "ninety",
}
var _scaleNumbers = []string{
	"", "thousand", "million", "billion",
}

type digitGroup int

// Convert converts number into the words representation.
func Convert(number int) string {
	return convert(number, false)
}

// ConvertAnd converts number into the words representation
// with " and " added between number groups.
func ConvertAnd(number int) string {
	return convert(number, true)
}

func convert(number int, useAnd bool) string {
	// Zero rule
	if number == 0 {
		return _smallNumbers[0]
	}

	// Divide into three-digits group
	var groups [groupsNumber]digitGroup
	positive := math.Abs(float64(number))

	// Form three-digit groups
	for i := 0; i < groupsNumber; i++ {
		groups[i] = digitGroup(math.Mod(positive, 1000))
		positive /= 1000
	}

	var textGroup [groupsNumber]string
	for i := 0; i < groupsNumber; i++ {
		textGroup[i] = digitGroup2Text(groups[i], useAnd)
	}
	combined := textGroup[0]
	and := useAnd && (groups[0] > 0 && groups[0] < 100)

	for i := 1; i < groupsNumber; i++ {
		if groups[i] != 0 {
			prefix := textGroup[i] + " " + _scaleNumbers[i]

			if len(combined) != 0 {
				prefix += separator(and)
			}

			and = false

			combined = prefix + combined
		}
	}

	if number < 0 {
		combined = "minus " + combined
	}

	return combined
}

func intMod(x, y int) int {
	return int(math.Mod(float64(x), float64(y)))
}

func digitGroup2Text(group digitGroup, useAnd bool) (ret string) {
	hundreds := group / 100
	tensUnits := intMod(int(group), 100)

	if hundreds != 0 {
		ret += _smallNumbers[hundreds] + " hundred"

		if tensUnits != 0 {
			ret += separator(useAnd)
		}
	}

	tens := tensUnits / 10
	units := intMod(tensUnits, 10)

	if tens >= 2 {
		ret += _tens[tens]

		if units != 0 {
			ret += " " + _smallNumbers[units]
		}
	} else if tensUnits != 0 {
		ret += _smallNumbers[tensUnits]
	}

	return
}

// separator returns proper separator string between
// number groups.
func separator(useAnd bool) string {
	if useAnd {
		return " and "
	}
	return " "
}
<|endoftext|>


<commit_before>package osm

import (
	"fmt"
	"sort"
	"time"

	"github.com/paulmach/osm/internal/osmpb"
)

// CommitInfoStart is the start time when we know committed at information.
// Any update.Timestamp >= this date is a committed at time. Anything before
// this date is the element timestamp.
var CommitInfoStart = time.Date(2012, 9, 12, 9, 30, 3, 0, time.UTC)

// An Update is a change to children of a way or relation.
// The child type, id, ref and/or role are the same as the child
// at the given index. Lon/Lat are only updated for nodes.
type Update struct {
	Index   int `xml:"index,attr" json:"index"`
	Version int `xml:"version,attr" json:"version"`

	// Timestamp is the committed at time if time > CommitInfoStart or the
	// element timestamp if before that date.
	Timestamp time.Time `xml:"timestamp,attr" json:"timestamp"`

	ChangesetID ChangesetID `xml:"changeset,attr,omitempty" json:"changeset,omitempty"`
	Lat         float64     `xml:"lat,attr,omitempty" json:"lat,omitempty"`
	Lon         float64     `xml:"lon,attr,omitempty" json:"lon,omitempty"`
	Reverse     bool        `xml:"reverse,attr,omitempty" json:"reverse,omitempty"`
}

// Updates are collections of updates.
type Updates []Update

// UpTo will return the subset of updates taking place upto and on
// the given time.
func (us Updates) UpTo(t time.Time) Updates {
	var result Updates

	for _, u := range us {
		if u.Timestamp.After(t) {
			continue
		}

		result = append(result, u)
	}

	return result
}

// UpdateIndexOutOfRangeError is return when appling an update to an object
// and the update index is out of range.
type UpdateIndexOutOfRangeError struct {
	Index int
}

var _ error = &UpdateIndexOutOfRangeError{}

// Error returns a string representation of the error.
func (e *UpdateIndexOutOfRangeError) Error() string {
	return fmt.Sprintf("osm: index %d is out of range", e.Index)
}

type updatesSortTS Updates

// SortByTimestamp will sort the updates by timestamp in ascending order.
func (us Updates) SortByTimestamp()    { sort.Sort(updatesSortTS(us)) }
func (us updatesSortTS) Len() int      { return len(us) }
func (us updatesSortTS) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us updatesSortTS) Less(i, j int) bool {
	return us[i].Timestamp.Before(us[j].Timestamp)
}

type updatesSortIndex Updates

// SortByIndex will sort the updates by index in ascending order.
func (us Updates) SortByIndex()           { sort.Sort(updatesSortIndex(us)) }
func (us updatesSortIndex) Len() int      { return len(us) }
func (us updatesSortIndex) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us updatesSortIndex) Less(i, j int) bool {
	if us[i].Index != us[j].Index {
		return us[i].Index < us[j].Index
	}

	return us[i].Timestamp.Before(us[j].Timestamp)
}

func marshalUpdates(updates Updates) *osmpb.DenseMembers {
	if len(updates) == 0 {
		return nil
	}

	l := len(updates)
	indexes := make([]int32, l)
	versions := make([]int32, l)
	timestamps := make([]int64, l)
	changesetIDs := make([]int64, l)
	lats := make([]int64, l)
	lons := make([]int64, l)
	revs := make([]int32, l)

	hasLoc := false
	hasRev := false
	for i, u := range updates {
		indexes[i] = int32(u.Index)
		versions[i] = int32(u.Version)
		timestamps[i] = timeToUnix(u.Timestamp)
		changesetIDs[i] = int64(u.ChangesetID)
		if u.Lat != 0 || u.Lon != 0 {
			hasLoc = true
			lats[i] = geoToInt64(u.Lat)
			lons[i] = geoToInt64(u.Lon)
		}

		if u.Reverse {
			hasRev = true
			revs[i] = 1
		}
	}

	result := &osmpb.DenseMembers{
		Indexes:      encodeInt32(indexes),
		Versions:     versions,
		ChangesetIds: encodeInt64(changesetIDs),
		Timestamps:   encodeInt64(timestamps),
	}

	if hasLoc {
		result.Lats = encodeInt64(lats)
		result.Lons = encodeInt64(lons)
	}

	if hasRev {
		result.Orientation = revs
	}

	return result
}

func unmarshalUpdates(encoded *osmpb.DenseMembers) Updates {
	if encoded == nil {
		return nil
	}

	result := make([]Update, len(encoded.Indexes))

	decodeInt32(encoded.Indexes)
	decodeInt64(encoded.ChangesetIds)
	decodeInt64(encoded.Timestamps)

	decodeInt64(encoded.Lats)
	decodeInt64(encoded.Lons)

	for i := range encoded.Indexes {
		result[i] = Update{
			Index:       int(encoded.Indexes[i]),
			Version:     int(encoded.Versions[i]),
			ChangesetID: ChangesetID(encoded.ChangesetIds[i]),
			Timestamp:   unixToTime(encoded.Timestamps[i]),
		}

		if len(encoded.Lats) > i {
			result[i].Lat = float64(encoded.Lats[i]) / locMultiple
			result[i].Lon = float64(encoded.Lons[i]) / locMultiple
		}

		if len(encoded.Orientation) > i && encoded.Orientation[i] > 0 {
			result[i].Reverse = true
		}
	}

	return result
}
<commit_msg>Fix typo<commit_after>package osm

import (
	"fmt"
	"sort"
	"time"

	"github.com/paulmach/osm/internal/osmpb"
)

// CommitInfoStart is the start time when we know committed at information.
// Any update.Timestamp >= this date is a committed at time. Anything before
// this date is the element timestamp.
var CommitInfoStart = time.Date(2012, 9, 12, 9, 30, 3, 0, time.UTC)

// An Update is a change to children of a way or relation.
// The child type, id, ref and/or role are the same as the child
// at the given index. Lon/Lat are only updated for nodes.
type Update struct {
	Index   int `xml:"index,attr" json:"index"`
	Version int `xml:"version,attr" json:"version"`

	// Timestamp is the committed at time if time > CommitInfoStart or the
	// element timestamp if before that date.
	Timestamp time.Time `xml:"timestamp,attr" json:"timestamp"`

	ChangesetID ChangesetID `xml:"changeset,attr,omitempty" json:"changeset,omitempty"`
	Lat         float64     `xml:"lat,attr,omitempty" json:"lat,omitempty"`
	Lon         float64     `xml:"lon,attr,omitempty" json:"lon,omitempty"`
	Reverse     bool        `xml:"reverse,attr,omitempty" json:"reverse,omitempty"`
}

// Updates are collections of updates.
type Updates []Update

// UpTo will return the subset of updates taking place upto and on
// the given time.
func (us Updates) UpTo(t time.Time) Updates {
	var result Updates

	for _, u := range us {
		if u.Timestamp.After(t) {
			continue
		}

		result = append(result, u)
	}

	return result
}

// UpdateIndexOutOfRangeError is return when applying an update to an object
// and the update index is out of range.
type UpdateIndexOutOfRangeError struct {
	Index int
}

var _ error = &UpdateIndexOutOfRangeError{}

// Error returns a string representation of the error.
func (e *UpdateIndexOutOfRangeError) Error() string {
	return fmt.Sprintf("osm: index %d is out of range", e.Index)
}

type updatesSortTS Updates

// SortByTimestamp will sort the updates by timestamp in ascending order.
func (us Updates) SortByTimestamp()    { sort.Sort(updatesSortTS(us)) }
func (us updatesSortTS) Len() int      { return len(us) }
func (us updatesSortTS) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us updatesSortTS) Less(i, j int) bool {
	return us[i].Timestamp.Before(us[j].Timestamp)
}

type updatesSortIndex Updates

// SortByIndex will sort the updates by index in ascending order.
func (us Updates) SortByIndex()           { sort.Sort(updatesSortIndex(us)) }
func (us updatesSortIndex) Len() int      { return len(us) }
func (us updatesSortIndex) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
func (us updatesSortIndex) Less(i, j int) bool {
	if us[i].Index != us[j].Index {
		return us[i].Index < us[j].Index
	}

	return us[i].Timestamp.Before(us[j].Timestamp)
}

func marshalUpdates(updates Updates) *osmpb.DenseMembers {
	if len(updates) == 0 {
		return nil
	}

	l := len(updates)
	indexes := make([]int32, l)
	versions := make([]int32, l)
	timestamps := make([]int64, l)
	changesetIDs := make([]int64, l)
	lats := make([]int64, l)
	lons := make([]int64, l)
	revs := make([]int32, l)

	hasLoc := false
	hasRev := false
	for i, u := range updates {
		indexes[i] = int32(u.Index)
		versions[i] = int32(u.Version)
		timestamps[i] = timeToUnix(u.Timestamp)
		changesetIDs[i] = int64(u.ChangesetID)
		if u.Lat != 0 || u.Lon != 0 {
			hasLoc = true
			lats[i] = geoToInt64(u.Lat)
			lons[i] = geoToInt64(u.Lon)
		}

		if u.Reverse {
			hasRev = true
			revs[i] = 1
		}
	}

	result := &osmpb.DenseMembers{
		Indexes:      encodeInt32(indexes),
		Versions:     versions,
		ChangesetIds: encodeInt64(changesetIDs),
		Timestamps:   encodeInt64(timestamps),
	}

	if hasLoc {
		result.Lats = encodeInt64(lats)
		result.Lons = encodeInt64(lons)
	}

	if hasRev {
		result.Orientation = revs
	}

	return result
}

func unmarshalUpdates(encoded *osmpb.DenseMembers) Updates {
	if encoded == nil {
		return nil
	}

	result := make([]Update, len(encoded.Indexes))

	decodeInt32(encoded.Indexes)
	decodeInt64(encoded.ChangesetIds)
	decodeInt64(encoded.Timestamps)

	decodeInt64(encoded.Lats)
	decodeInt64(encoded.Lons)

	for i := range encoded.Indexes {
		result[i] = Update{
			Index:       int(encoded.Indexes[i]),
			Version:     int(encoded.Versions[i]),
			ChangesetID: ChangesetID(encoded.ChangesetIds[i]),
			Timestamp:   unixToTime(encoded.Timestamps[i]),
		}

		if len(encoded.Lats) > i {
			result[i].Lat = float64(encoded.Lats[i]) / locMultiple
			result[i].Lon = float64(encoded.Lons[i]) / locMultiple
		}

		if len(encoded.Orientation) > i && encoded.Orientation[i] > 0 {
			result[i].Reverse = true
		}
	}

	return result
}
<|endoftext|>


<commit_before>package alfred

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"time"

	"github.com/blang/semver"
)

// GitHubRelease describes a project release on GitHub
type GitHubRelease struct {
	DataURL    string `json:"url"`
	URL        string `json:"html_url"`
	Name       string `json:"name"`
	Prerelease bool   `json:"prerelease"`
	Tag        string `json:"tag_name"`
	Version    semver.Version
	Created    time.Time `json:"created_at"`
	Published  time.Time `json:"published_at"`
	Assets     []struct {
		URL         string `json:"url"`
		Name        string `json:"name"`
		DownloadURL string `json:"browser_download_url"`
	} `json:"assets"`
}

func getReleases(owner, repo string) (releases []GitHubRelease, err error) {
	var data []byte
	if data, err = get(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", owner, repo), nil); err != nil {
		return
	}

	if err = json.NewDecoder(bytes.NewReader(data)).Decode(&releases); err != nil {
		return
	}

	for i := range releases {
		releases[i].Version, _ = semver.ParseTolerant(releases[i].Tag)
	}

	sort.Sort(byVersion(releases))

	return
}

func get(requestURL string, params map[string]string) (data []byte, err error) {
	if params != nil {
		data := url.Values{}
		for key, value := range params {
			data.Set(key, value)
		}
		requestURL += "?" + data.Encode()
	}

	dlog.Printf("GET %s", requestURL)

	var resp *http.Response
	if resp, err = http.Get(requestURL); err != nil {
		return
	}
	defer resp.Body.Close()

	if data, err = ioutil.ReadAll(resp.Body); err != nil {
		return
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		err = fmt.Errorf(resp.Status)
	}

	return
}

type byVersion []GitHubRelease

func (b byVersion) Len() int {
	return len(b)
}

func (b byVersion) Less(i, j int) bool {
	vi := b[i].Version
	vj := b[j].Version
	return vi.GT(vj)
}

func (b byVersion) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}
<commit_msg>Add version comparison function<commit_after>package alfred

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"time"

	"github.com/blang/semver"
)

// GitHubRelease describes a project release on GitHub
type GitHubRelease struct {
	DataURL    string `json:"url"`
	URL        string `json:"html_url"`
	Name       string `json:"name"`
	Prerelease bool   `json:"prerelease"`
	Tag        string `json:"tag_name"`
	Version    semver.Version
	Created    time.Time `json:"created_at"`
	Published  time.Time `json:"published_at"`
	Assets     []struct {
		URL         string `json:"url"`
		Name        string `json:"name"`
		DownloadURL string `json:"browser_download_url"`
	} `json:"assets"`
}

// IsNewer returns true if this release is newer than a given semver string
func (g *GitHubRelease) IsNewer(ver string) (isNewer bool, err error) {
	var version semver.Version
	if version, err = semver.ParseTolerant(ver); err != nil {
		return
	}
	isNewer = g.Version.GT(version)
	return
}

func getReleases(owner, repo string) (releases []GitHubRelease, err error) {
	var data []byte
	if data, err = get(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases", owner, repo), nil); err != nil {
		return
	}

	if err = json.NewDecoder(bytes.NewReader(data)).Decode(&releases); err != nil {
		return
	}

	for i := range releases {
		releases[i].Version, _ = semver.ParseTolerant(releases[i].Tag)
	}

	sort.Sort(byVersion(releases))

	return
}

func get(requestURL string, params map[string]string) (data []byte, err error) {
	if params != nil {
		data := url.Values{}
		for key, value := range params {
			data.Set(key, value)
		}
		requestURL += "?" + data.Encode()
	}

	dlog.Printf("GET %s", requestURL)

	var resp *http.Response
	if resp, err = http.Get(requestURL); err != nil {
		return
	}
	defer resp.Body.Close()

	if data, err = ioutil.ReadAll(resp.Body); err != nil {
		return
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		err = fmt.Errorf(resp.Status)
	}

	return
}

type byVersion []GitHubRelease

func (b byVersion) Len() int {
	return len(b)
}

func (b byVersion) Less(i, j int) bool {
	vi := b[i].Version
	vj := b[j].Version
	return vi.GT(vj)
}

func (b byVersion) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}
<|endoftext|>