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

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages.
// Use Check and Config.Check to invoke the type-checker.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (exact.Value) for
// every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"

	"golang.org/x/tools/go/exact"
)

// Check type-checks a package and returns the resulting complete package
// object, or a nil package and the first error. The package is specified
// by a list of *ast.Files and corresponding file set, and the import path
// the package is identified with. The clean path must not be empty or dot (".").
//
// For more control over type-checking and results, use Config.Check.
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
	var conf Config
	pkg, err := conf.Check(path, fset, files, nil)
	if err != nil {
		return nil, err
	}
	return pkg, nil
}

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An importer resolves import paths to Packages.
// The imports map records packages already known,
// indexed by package path. The type-checker
// will invoke Import with Config.Packages.
// An importer must determine the canonical package path and
// check imports to see if it is already present in the map.
// If so, the Importer can return the map entry.  Otherwise,
// the importer must load the package data for the given path
// into a new *Package, record it in imports map, and return
// the package.
// TODO(gri) Need to be clearer about requirements of completeness.
type Importer func(map[string]*Package, string) (*Package, error)

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// Packages is used to look up (and thus canonicalize) packages by
	// package path. If Packages is nil, it is set to a new empty map.
	// During type-checking, imported packages are added to the map.
	Packages map[string]*Package

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// If Import != nil, it is called for each imported package.
	// Otherwise, DefaultImport is called.
	Import Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes
}

// DefaultImport is the default importer invoked if Config.Import == nil.
// The declaration:
//
//	import _ "golang.org/x/tools/go/gcimporter"
//
// in a client of go/types will initialize DefaultImport to gcimporter.Import.
var DefaultImport Importer

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, their values. Invalid expressions are omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// Identifiers on the lhs of declarations (i.e., the identifiers
	// which are being declared) are collected in the Defs map.
	// Identifiers denoting packages are collected in the Uses maps.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous struct field or parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, ok := e.(*ast.Ident); ok {
		return info.ObjectOf(id).Type()
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj, ok := info.Defs[id]; ok {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value exact.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (http://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the lhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object,
// the first error if any, and if info != nil, additional type information.
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<commit_msg>go/types: add missing nil check in Info.TypeOf<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package types declares the data types and implements
// the algorithms for type-checking of Go packages.
// Use Check and Config.Check to invoke the type-checker.
//
// Type-checking consists of several interdependent phases:
//
// Name resolution maps each identifier (ast.Ident) in the program to the
// language object (Object) it denotes.
// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
//
// Constant folding computes the exact constant value (exact.Value) for
// every expression (ast.Expr) that is a compile-time constant.
// Use Info.Types[expr].Value for the results of constant folding.
//
// Type inference computes the type (Type) of every expression (ast.Expr)
// and checks for compliance with the language specification.
// Use Info.Types[expr].Type for the results of type inference.
//
package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"

	"golang.org/x/tools/go/exact"
)

// Check type-checks a package and returns the resulting complete package
// object, or a nil package and the first error. The package is specified
// by a list of *ast.Files and corresponding file set, and the import path
// the package is identified with. The clean path must not be empty or dot (".").
//
// For more control over type-checking and results, use Config.Check.
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
	var conf Config
	pkg, err := conf.Check(path, fset, files, nil)
	if err != nil {
		return nil, err
	}
	return pkg, nil
}

// An Error describes a type-checking error; it implements the error interface.
// A "soft" error is an error that still permits a valid interpretation of a
// package (such as "unused variable"); "hard" errors may lead to unpredictable
// behavior if ignored.
type Error struct {
	Fset *token.FileSet // file set for interpretation of Pos
	Pos  token.Pos      // error position
	Msg  string         // error message
	Soft bool           // if set, error is "soft"
}

// Error returns an error string formatted as follows:
// filename:line:column: message
func (err Error) Error() string {
	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
}

// An importer resolves import paths to Packages.
// The imports map records packages already known,
// indexed by package path. The type-checker
// will invoke Import with Config.Packages.
// An importer must determine the canonical package path and
// check imports to see if it is already present in the map.
// If so, the Importer can return the map entry.  Otherwise,
// the importer must load the package data for the given path
// into a new *Package, record it in imports map, and return
// the package.
// TODO(gri) Need to be clearer about requirements of completeness.
type Importer func(map[string]*Package, string) (*Package, error)

// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
	// If IgnoreFuncBodies is set, function bodies are not
	// type-checked.
	IgnoreFuncBodies bool

	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
	// declares an empty "C" package and errors are omitted for qualified
	// identifiers referring to package C (which won't find an object).
	// This feature is intended for the standard library cmd/api tool.
	//
	// Caution: Effects may be unpredictable due to follow-up errors.
	//          Do not use casually!
	FakeImportC bool

	// Packages is used to look up (and thus canonicalize) packages by
	// package path. If Packages is nil, it is set to a new empty map.
	// During type-checking, imported packages are added to the map.
	Packages map[string]*Package

	// If Error != nil, it is called with each error found
	// during type checking; err has dynamic type Error.
	// Secondary errors (for instance, to enumerate all types
	// involved in an invalid recursive type declaration) have
	// error strings that start with a '\t' character.
	// If Error == nil, type-checking stops with the first
	// error found.
	Error func(err error)

	// If Import != nil, it is called for each imported package.
	// Otherwise, DefaultImport is called.
	Import Importer

	// If Sizes != nil, it provides the sizing functions for package unsafe.
	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
	Sizes Sizes
}

// DefaultImport is the default importer invoked if Config.Import == nil.
// The declaration:
//
//	import _ "golang.org/x/tools/go/gcimporter"
//
// in a client of go/types will initialize DefaultImport to gcimporter.Import.
var DefaultImport Importer

// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
	// Types maps expressions to their types, and for constant
	// expressions, their values. Invalid expressions are omitted.
	//
	// For (possibly parenthesized) identifiers denoting built-in
	// functions, the recorded signatures are call-site specific:
	// if the call result is not a constant, the recorded type is
	// an argument-specific signature. Otherwise, the recorded type
	// is invalid.
	//
	// Identifiers on the lhs of declarations (i.e., the identifiers
	// which are being declared) are collected in the Defs map.
	// Identifiers denoting packages are collected in the Uses maps.
	Types map[ast.Expr]TypeAndValue

	// Defs maps identifiers to the objects they define (including
	// package names, dots "." of dot-imports, and blank "_" identifiers).
	// For identifiers that do not denote objects (e.g., the package name
	// in package clauses, or symbolic variables t in t := x.(type) of
	// type switch headers), the corresponding objects are nil.
	//
	// For an anonymous field, Defs returns the field *Var it defines.
	//
	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
	Defs map[*ast.Ident]Object

	// Uses maps identifiers to the objects they denote.
	//
	// For an anonymous field, Uses returns the *TypeName it denotes.
	//
	// Invariant: Uses[id].Pos() != id.Pos()
	Uses map[*ast.Ident]Object

	// Implicits maps nodes to their implicitly declared objects, if any.
	// The following node and object types may appear:
	//
	//	node               declared object
	//
	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
	//      *ast.Field         anonymous struct field or parameter *Var
	//
	Implicits map[ast.Node]Object

	// Selections maps selector expressions (excluding qualified identifiers)
	// to their corresponding selections.
	Selections map[*ast.SelectorExpr]*Selection

	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
	// associated with a specific node but with all files belonging to a package.
	// Thus, the package scope can be found in the type-checked Package object.
	// Scopes nest, with the Universe scope being the outermost scope, enclosing
	// the package scope, which contains (one or more) files scopes, which enclose
	// function scopes which in turn enclose statement and function literal scopes.
	// Note that even though package-level functions are declared in the package
	// scope, the function scopes are embedded in the file scope of the file
	// containing the function declaration.
	//
	// The following node types may appear in Scopes:
	//
	//	*ast.File
	//	*ast.FuncType
	//	*ast.BlockStmt
	//	*ast.IfStmt
	//	*ast.SwitchStmt
	//	*ast.TypeSwitchStmt
	//	*ast.CaseClause
	//	*ast.CommClause
	//	*ast.ForStmt
	//	*ast.RangeStmt
	//
	Scopes map[ast.Node]*Scope

	// InitOrder is the list of package-level initializers in the order in which
	// they must be executed. Initializers referring to variables related by an
	// initialization dependency appear in topological order, the others appear
	// in source order. Variables without an initialization expression do not
	// appear in this list.
	InitOrder []*Initializer
}

// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.
//
func (info *Info) TypeOf(e ast.Expr) Type {
	if t, ok := info.Types[e]; ok {
		return t.Type
	}
	if id, _ := e.(*ast.Ident); id != nil {
		if obj := info.ObjectOf(id); obj != nil {
			return obj.Type()
		}
	}
	return nil
}

// ObjectOf returns the object denoted by the specified id,
// or nil if not found.
//
// If id is an anonymous struct field, ObjectOf returns the field (*Var)
// it uses, not the type (*TypeName) it defines.
//
// Precondition: the Uses and Defs maps are populated.
//
func (info *Info) ObjectOf(id *ast.Ident) Object {
	if obj, _ := info.Defs[id]; obj != nil {
		return obj
	}
	return info.Uses[id]
}

// TypeAndValue reports the type and value (for constants)
// of the corresponding expression.
type TypeAndValue struct {
	mode  operandMode
	Type  Type
	Value exact.Value
}

// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
// "void" values as regular values but with the empty tuple type.

// IsVoid reports whether the corresponding expression
// is a function call without results.
func (tv TypeAndValue) IsVoid() bool {
	return tv.mode == novalue
}

// IsType reports whether the corresponding expression specifies a type.
func (tv TypeAndValue) IsType() bool {
	return tv.mode == typexpr
}

// IsBuiltin reports whether the corresponding expression denotes
// a (possibly parenthesized) built-in function.
func (tv TypeAndValue) IsBuiltin() bool {
	return tv.mode == builtin
}

// IsValue reports whether the corresponding expression is a value.
// Builtins are not considered values. Constant values have a non-
// nil Value.
func (tv TypeAndValue) IsValue() bool {
	switch tv.mode {
	case constant, variable, mapindex, value, commaok:
		return true
	}
	return false
}

// IsNil reports whether the corresponding expression denotes the
// predeclared value nil.
func (tv TypeAndValue) IsNil() bool {
	return tv.mode == value && tv.Type == Typ[UntypedNil]
}

// Addressable reports whether the corresponding expression
// is addressable (http://golang.org/ref/spec#Address_operators).
func (tv TypeAndValue) Addressable() bool {
	return tv.mode == variable
}

// Assignable reports whether the corresponding expression
// is assignable to (provided a value of the right type).
func (tv TypeAndValue) Assignable() bool {
	return tv.mode == variable || tv.mode == mapindex
}

// HasOk reports whether the corresponding expression may be
// used on the lhs of a comma-ok assignment.
func (tv TypeAndValue) HasOk() bool {
	return tv.mode == commaok || tv.mode == mapindex
}

// An Initializer describes a package-level variable, or a list of variables in case
// of a multi-valued initialization expression, and the corresponding initialization
// expression.
type Initializer struct {
	Lhs []*Var // var Lhs = Rhs
	Rhs ast.Expr
}

func (init *Initializer) String() string {
	var buf bytes.Buffer
	for i, lhs := range init.Lhs {
		if i > 0 {
			buf.WriteString(", ")
		}
		buf.WriteString(lhs.Name())
	}
	buf.WriteString(" = ")
	WriteExpr(&buf, init.Rhs)
	return buf.String()
}

// Check type-checks a package and returns the resulting package object,
// the first error if any, and if info != nil, additional type information.
// The package is marked as complete if no errors occurred, otherwise it is
// incomplete. See Config.Error for controlling behavior in the presence of
// errors.
//
// The package is specified by a list of *ast.Files and corresponding
// file set, and the package path the package is identified with.
// The clean path must not be empty or dot (".").
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
	pkg := NewPackage(path, "")
	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
}

// AssertableTo reports whether a value of type V can be asserted to have type T.
func AssertableTo(V *Interface, T Type) bool {
	m, _ := assertableTo(V, T)
	return m == nil
}

// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.assignableTo(nil, T) // config not needed for non-constant x
}

// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
func ConvertibleTo(V, T Type) bool {
	x := operand{mode: value, typ: V}
	return x.convertibleTo(nil, T) // config not needed for non-constant x
}

// Implements reports whether type V implements interface T.
func Implements(V Type, T *Interface) bool {
	f, _ := MissingMethod(V, T, true)
	return f == nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"strings"

	"github.com/kennygrant/sanitize"
)

const ()

var (
	preferredMimeTypes    = []string{"video/webm", "video/mp4", "video/ogg", "audio/ogg", "audio/opus", "audio/mpeg", "application/x-subrip"}
	extensionForMimeTypes = make(map[string]string)

	downloadPath string
	acronym      string
	language     string
)

type Conference struct {
	Acronym        string `json:"acronym"`
	AspectRatio    string `json:"aspect_ratio"`
	ImagesURL      string `json:"images_url"`
	LogoURL        string `json:"logo_url"`
	RecordingsURL  string `json:"recordings_url"`
	ScheduleURL    string `json:"schedule_url"`
	Slug           string `json:"slug"`
	Title          string `json:"title"`
	UpdatedAt      string `json:"updated_at"`
	URL            string `json:"url"`
	WebgenLocation string `json:"webgen_location"`
}

type Conferences struct {
	Conferences []Conference `json:"conferences"`
}

func priorityForMimeType(mime string) int {
	for i, v := range preferredMimeTypes {
		if strings.ToLower(mime) == v {
			return i
		}
	}

	return -1
}

func findConferences(url string) (Conferences, error) {
	ci := Conferences{}

	r, err := http.Get(url)
	if err != nil {
		return ci, err
	}
	defer r.Body.Close()

	err = json.NewDecoder(r.Body).Decode(&ci)
	return ci, err
}

func main() {
	flag.StringVar(&acronym, "acronym", "", "download only media belonging to this conference-acronym (e.g. '33c3')")
	flag.StringVar(&downloadPath, "destination", "./downloads/", "where to store downloaded media")
	flag.StringVar(&language, "language", "", "preferred language if available (eng, deu or fra)")
	flag.Parse()

	acronym = strings.ToLower(acronym)
	language = strings.ToLower(language)

	extensionForMimeTypes["video/webm"] = "webm"
	extensionForMimeTypes["video/mp4"] = "mp4"
	extensionForMimeTypes["video/ogg"] = "ogm"
	extensionForMimeTypes["audio/ogg"] = "ogg"
	extensionForMimeTypes["audio/opus"] = "opus"
	extensionForMimeTypes["audio/mpeg"] = "mp3"

	ci, err := findConferences("https://api.media.ccc.de/public/conferences")
	if err != nil {
		panic(err)
	}

	for _, v := range ci.Conferences {
		fmt.Printf("Conference: %s, acronym: %s (URL: %s)\n", v.Title, v.Acronym, v.URL)
		if len(acronym) > 0 && acronym != strings.ToLower(v.Acronym) {
			continue
		}

		events, err := findEvents(v.URL)
		if err != nil {
			panic(err)
		}

		for _, e := range events.Events {
			desc := strings.Replace(sanitize.HTML(e.Description), "\n", "", -1)
			if len(desc) > 48 {
				desc = desc[:45] + "..."
			}
			if len(desc) > 0 {
				desc = " - " + desc
			}
			fmt.Printf("Event: %s%s\n", e.Title, desc)

			media, err := findMedia(e.URL)
			if err != nil {
				panic(err)
			}

			bestMatch := Recording{}
			highestPriority := -1
			if len(media.Recordings) == 0 {
				panic("No recordings found for this event!")
			}
			for _, m := range media.Recordings {
				if (len(language) == 0 || language != strings.ToLower(m.Language)) &&
					m.Language != e.OriginalLanguage {
					continue
				}

				if m.Width == 0 {
					fmt.Printf("\tFound audio (%s): %d minutes (HD: %t, %dMiB) %s\n", m.MimeType, m.Length/60, m.HighQuality, m.Size, m.URL)
				} else {
					fmt.Printf("\tFound video (%s): %d minutes, %dx%d (HD: %t, %dMiB) %s\n", m.MimeType, m.Length/60, m.Width, m.Height, m.HighQuality, m.Size, m.URL)
				}

				prio := priorityForMimeType(m.MimeType)
				if prio < 0 {
					panic("Unknown mimetype encountered:" + m.MimeType)
				}

				if prio < highestPriority ||
					(prio == highestPriority && m.Width > bestMatch.Width) ||
					(strings.ToLower(bestMatch.Language) != language && strings.ToLower(m.Language) == language) ||
					highestPriority == -1 {
					highestPriority = prio
					bestMatch = m
				}
			}

			err = download(v, e, bestMatch)
			if err != nil {
				panic(err)
			}

			fmt.Println()
		}
	}

	fmt.Println("Done.")
}
<commit_msg>Fix logic error<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"strings"

	"github.com/kennygrant/sanitize"
)

const ()

var (
	preferredMimeTypes    = []string{"video/webm", "video/mp4", "video/ogg", "audio/ogg", "audio/opus", "audio/mpeg", "application/x-subrip"}
	extensionForMimeTypes = make(map[string]string)

	downloadPath string
	acronym      string
	language     string
)

type Conference struct {
	Acronym        string `json:"acronym"`
	AspectRatio    string `json:"aspect_ratio"`
	ImagesURL      string `json:"images_url"`
	LogoURL        string `json:"logo_url"`
	RecordingsURL  string `json:"recordings_url"`
	ScheduleURL    string `json:"schedule_url"`
	Slug           string `json:"slug"`
	Title          string `json:"title"`
	UpdatedAt      string `json:"updated_at"`
	URL            string `json:"url"`
	WebgenLocation string `json:"webgen_location"`
}

type Conferences struct {
	Conferences []Conference `json:"conferences"`
}

func priorityForMimeType(mime string) int {
	for i, v := range preferredMimeTypes {
		if strings.ToLower(mime) == v {
			return i
		}
	}

	return -1
}

func findConferences(url string) (Conferences, error) {
	ci := Conferences{}

	r, err := http.Get(url)
	if err != nil {
		return ci, err
	}
	defer r.Body.Close()

	err = json.NewDecoder(r.Body).Decode(&ci)
	return ci, err
}

func main() {
	flag.StringVar(&acronym, "acronym", "", "download only media belonging to this conference-acronym (e.g. '33c3')")
	flag.StringVar(&downloadPath, "destination", "./downloads/", "where to store downloaded media")
	flag.StringVar(&language, "language", "", "preferred language if available (eng, deu or fra)")
	flag.Parse()

	acronym = strings.ToLower(acronym)
	language = strings.ToLower(language)

	extensionForMimeTypes["video/webm"] = "webm"
	extensionForMimeTypes["video/mp4"] = "mp4"
	extensionForMimeTypes["video/ogg"] = "ogm"
	extensionForMimeTypes["audio/ogg"] = "ogg"
	extensionForMimeTypes["audio/opus"] = "opus"
	extensionForMimeTypes["audio/mpeg"] = "mp3"

	ci, err := findConferences("https://api.media.ccc.de/public/conferences")
	if err != nil {
		panic(err)
	}

	for _, v := range ci.Conferences {
		fmt.Printf("Conference: %s, acronym: %s (URL: %s)\n", v.Title, v.Acronym, v.URL)
		if len(acronym) > 0 && acronym != strings.ToLower(v.Acronym) {
			continue
		}

		events, err := findEvents(v.URL)
		if err != nil {
			panic(err)
		}

		for _, e := range events.Events {
			desc := strings.Replace(sanitize.HTML(e.Description), "\n", "", -1)
			if len(desc) > 48 {
				desc = desc[:45] + "..."
			}
			if len(desc) > 0 {
				desc = " - " + desc
			}
			fmt.Printf("Event: %s%s\n", e.Title, desc)

			media, err := findMedia(e.URL)
			if err != nil {
				panic(err)
			}

			bestMatch := Recording{}
			highestPriority := -1
			if len(media.Recordings) == 0 {
				panic("No recordings found for this event!")
			}
			for _, m := range media.Recordings {
				if (len(language) == 0 || language != strings.ToLower(m.Language)) &&
					m.Language != e.OriginalLanguage {
					continue
				}

				if m.Width == 0 {
					fmt.Printf("\tFound audio (%s): %d minutes (HD: %t, %dMiB) %s\n", m.MimeType, m.Length/60, m.HighQuality, m.Size, m.URL)
				} else {
					fmt.Printf("\tFound video (%s): %d minutes, %dx%d (HD: %t, %dMiB) %s\n", m.MimeType, m.Length/60, m.Width, m.Height, m.HighQuality, m.Size, m.URL)
				}

				prio := priorityForMimeType(m.MimeType)
				if prio < 0 {
					panic("Unknown mimetype encountered:" + m.MimeType)
				}

				pick := false
				if highestPriority == -1 {
					// if we got nothing so far, always pick any available option
					pick = true
				}
				if strings.ToLower(bestMatch.Language) != language && strings.ToLower(m.Language) == language {
					// we already found something, but this is the preferred language
					pick = true
				} else {
					if prio < highestPriority || (prio == highestPriority && m.Width > bestMatch.Width) {
						// we already found something, but this has a higher resolution
						pick = true
					}
				}

				if pick {
					highestPriority = prio
					bestMatch = m
				}
			}

			if len(bestMatch.RecordingURL) == 0 {
				fmt.Println("Could not find any desired version of this talk, sorry. Skipping!")
				continue
			}
			err = download(v, e, bestMatch)
			if err != nil {
				panic(err)
			}

			fmt.Println()
		}
	}

	fmt.Println("Done.")
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package cmd

import (
	"encoding/hex"
	"fmt"

	"github.com/TheThingsNetwork/ttn/core"
	"github.com/TheThingsNetwork/ttn/ttnctl/mqtt"
	"github.com/TheThingsNetwork/ttn/ttnctl/util"
	"github.com/apex/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// registerCmd represents the `register` command
var registerCmd = &cobra.Command{
	Use:   "register",
	Short: "Register an entity with TTN",
	Long:  `Register a user`,
	Run: func(cmd *cobra.Command, args []string) {
		ctx.Fatal("register is not implemented.")
	},
}

// registerPersonalizedDeviceCmd represents the `register personalized-device` command
var registerPersonalizedDeviceCmd = &cobra.Command{
	Use:   "personalized-device [DevAddr] [NwkSKey] [AppSKey]",
	Short: "Register a new personalized device",
	Long:  `Register a new personalized device`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 3 {
			ctx.Fatal("Insufficient arguments")
		}

		devAddr, err := util.Parse32(args[0])
		if err != nil {
			ctx.Fatalf("Invalid DevAddr: %s", err)
		}

		nwkSKey, err := util.Parse128(args[1])
		if err != nil {
			ctx.Fatalf("Invalid NwkSKey: %s", err)
		}

		appSKey, err := util.Parse128(args[2])
		if err != nil {
			ctx.Fatalf("Invalid AppSKey: %s", err)
		}

		payload, err := core.ABPSubAppReq{
			DevAddr: args[0],
			NwkSKey: args[1],
			AppSKey: args[2],
		}.MarshalMsg(nil)

		if err != nil {
			ctx.WithError(err).Fatal("Unable to create a registration")
		}

		mqtt.Setup(viper.GetString("handler.mqtt-broker"), ctx)
		mqtt.Connect()

		ctx.WithFields(log.Fields{
			"DevAddr": hex.EncodeToString(devAddr),
			"NwkSKey": hex.EncodeToString(nwkSKey),
			"AppSKey": hex.EncodeToString(appSKey),
		}).Info("Registering device...")

		token := mqtt.Client.Publish(fmt.Sprintf("%s/devices/personalized/activations", viper.GetString("handler.app-eui")), 2, false, payload)
		if token.Wait() && token.Error() != nil {
			ctx.WithError(token.Error()).Fatal("Registration failed.")
		} else {
			// Although we can't be sure whether it actually succeeded, we can know when the command is published to the MQTT.
			ctx.Info("Registration finished.")
		}

	},
}

func init() {
	RootCmd.AddCommand(registerCmd)

	registerCmd.AddCommand(registerPersonalizedDeviceCmd)

	registerPersonalizedDeviceCmd.Flags().String("mqtt-broker", "localhost:1883", "The address of the MQTT broker")
	viper.BindPFlag("handler.mqtt-broker", registerPersonalizedDeviceCmd.Flags().Lookup("mqtt-broker"))

	registerPersonalizedDeviceCmd.Flags().String("app-eui", "0102030405060708", "The app EUI to use")
	viper.BindPFlag("handler.app-eui", registerPersonalizedDeviceCmd.Flags().Lookup("app-eui"))

}
<commit_msg>[feature/manager] Remove register from ttnctl<commit_after><|endoftext|>


<commit_before>package gobotsdottxt

import (
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

type Robots struct {
	URL        string
	Groups     []Group
	SiteMap    []string
	CrawlDelay int
}

type Group struct {
	UserAgent string
	Allow     []string
	Disallow  []string
}

func NewRobots(url string) (Robots, error) {
	robots := Robots{URL: url}
	resp, err := http.Get(url + "/robots.txt")
	if err != nil {
		return robots, err
	}

	//Pretty much no robots.txt
	if resp.StatusCode != 200 {
		return robots, nil
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return robots, err
	}

	var group Group
	lines := strings.Split(string(body), "\n")
	for _, line := range lines {
		options := strings.SplitN(line, ":", 2)
		if len(options) == 1 {
			robots.Groups = append(robots.Groups, group)
			group = Group{}
			continue
		}

		command := strings.ToLower(strings.Trim(options[0], " "))
		value := strings.Trim(options[1], " ")
		switch command {
		case "user-agent":
			group.UserAgent = value
		case "disallow":
			group.Disallow = append(group.Disallow, value)
		case "allow":
			group.Allow = append(group.Allow, value)
		case "sitemap":
			robots.SiteMap = append(robots.SiteMap, value)
		case "crawl-delay":
			delay, err := strconv.Atoi(value)
			if err != nil {
				continue
			}
			robots.CrawlDelay = delay
		}
	}

	return robots, nil
}
<commit_msg>can now verify if a url is visitable<commit_after>package gobotsdottxt

import (
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

type Robots struct {
	URL        string
	Groups     []Group
	SiteMap    []string
	CrawlDelay int
}

type Group struct {
	UserAgent string
	Allow     []string
	Disallow  []string
}

func NewRobots(url string) (Robots, error) {
	robots := Robots{URL: url}
	resp, err := http.Get(url + "/robots.txt")
	if err != nil {
		return robots, err
	}

	//Pretty much no robots.txt
	if resp.StatusCode != 200 {
		return robots, nil
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return robots, err
	}

	var group Group
	lines := strings.Split(string(body), "\n")
	for _, line := range lines {
		options := strings.SplitN(line, ":", 2)
		if len(options) == 1 {
			robots.Groups = append(robots.Groups, group)
			group = Group{}
			continue
		}

		command := strings.ToLower(strings.Trim(options[0], " "))
		value := strings.Trim(options[1], " ")
		switch command {
		case "user-agent":
			group.UserAgent = value
		case "disallow":
			group.Disallow = append(group.Disallow, value)
		case "allow":
			group.Allow = append(group.Allow, value)
		case "sitemap":
			robots.SiteMap = append(robots.SiteMap, value)
		case "crawl-delay":
			delay, err := strconv.Atoi(value)
			if err != nil {
				continue
			}
			robots.CrawlDelay = delay
		}
	}

	return robots, nil
}

func (r Robots) CanVisitFullUrl(useragent, url string) bool {
	if !strings.HasPrefix(url, r.URL) {
		return false
	}

	url = strings.Trim(url, r.URL)
	for _, group := range r.Groups {
		if group.UserAgent == "*" || useragent == group.UserAgent {
			for _, u := range group.Disallow {
				if u == "/" {
					return false
				}

				if strings.HasPrefix(url, u) {
					return false
				}
			}
		}
	}

	return true
}
<|endoftext|>


<commit_before>package tcp

import (
	"fmt"
	"io"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/task"
	"v2ray.com/core/transport/pipe"
)

type Server struct {
	Port         net.Port
	MsgProcessor func(msg []byte) []byte
	ShouldClose  bool
	SendFirst    []byte
	Listen       net.Address
	listener     *net.TCPListener
}

func (server *Server) Start() (net.Destination, error) {
	listenerAddr := server.Listen
	if listenerAddr == nil {
		listenerAddr = net.LocalHostIP
	}
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   listenerAddr.IP(),
		Port: int(server.Port),
		Zone: "",
	})
	if err != nil {
		return net.Destination{}, err
	}
	server.Port = net.Port(listener.Addr().(*net.TCPAddr).Port)
	server.listener = listener
	go server.acceptConnections(listener)
	localAddr := listener.Addr().(*net.TCPAddr)
	return net.TCPDestination(net.IPAddress(localAddr.IP), net.Port(localAddr.Port)), nil
}

func (server *Server) acceptConnections(listener *net.TCPListener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("Failed accept TCP connection: %v\n", err)
			return
		}

		go server.handleConnection(conn)
	}
}

func (server *Server) handleConnection(conn net.Conn) {
	if len(server.SendFirst) > 0 {
		conn.Write(server.SendFirst)
	}

	pReader, pWriter := pipe.New(pipe.WithoutSizeLimit())
	err := task.Run(task.Parallel(func() error {
		for {
			b := buf.New()
			if err := b.AppendSupplier(buf.ReadFrom(conn)); err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
			copy(b.Bytes(), server.MsgProcessor(b.Bytes()))
			if err := pWriter.WriteMultiBuffer(buf.NewMultiBufferValue(b)); err != nil {
				return err
			}
		}
	}, func() error {
		w := buf.NewWriter(conn)
		for {
			mb, err := pReader.ReadMultiBuffer()
			if err != nil {
				return err
			}
			if err := w.WriteMultiBuffer(mb); err != nil {
				return err
			}
		}
	}))()

	if err != nil {
		fmt.Println("failed to transfer data: ", err.Error())
	}

	conn.Close() // nolint: errcheck
}

func (server *Server) Close() error {
	return server.listener.Close()
}
<commit_msg>close pipe when finish<commit_after>package tcp

import (
	"fmt"
	"io"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/task"
	"v2ray.com/core/transport/pipe"
)

type Server struct {
	Port         net.Port
	MsgProcessor func(msg []byte) []byte
	ShouldClose  bool
	SendFirst    []byte
	Listen       net.Address
	listener     *net.TCPListener
}

func (server *Server) Start() (net.Destination, error) {
	listenerAddr := server.Listen
	if listenerAddr == nil {
		listenerAddr = net.LocalHostIP
	}
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   listenerAddr.IP(),
		Port: int(server.Port),
		Zone: "",
	})
	if err != nil {
		return net.Destination{}, err
	}
	server.Port = net.Port(listener.Addr().(*net.TCPAddr).Port)
	server.listener = listener
	go server.acceptConnections(listener)
	localAddr := listener.Addr().(*net.TCPAddr)
	return net.TCPDestination(net.IPAddress(localAddr.IP), net.Port(localAddr.Port)), nil
}

func (server *Server) acceptConnections(listener *net.TCPListener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("Failed accept TCP connection: %v\n", err)
			return
		}

		go server.handleConnection(conn)
	}
}

func (server *Server) handleConnection(conn net.Conn) {
	if len(server.SendFirst) > 0 {
		conn.Write(server.SendFirst)
	}

	pReader, pWriter := pipe.New(pipe.WithoutSizeLimit())
	err := task.Run(task.Parallel(func() error {
		defer pWriter.Close() // nolint: errcheck

		for {
			b := buf.New()
			if err := b.AppendSupplier(buf.ReadFrom(conn)); err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
			copy(b.Bytes(), server.MsgProcessor(b.Bytes()))
			if err := pWriter.WriteMultiBuffer(buf.NewMultiBufferValue(b)); err != nil {
				return err
			}
		}
	}, func() error {
		defer pReader.CloseError()

		w := buf.NewWriter(conn)
		for {
			mb, err := pReader.ReadMultiBuffer()
			if err != nil {
				return err
			}
			if err := w.WriteMultiBuffer(mb); err != nil {
				return err
			}
		}
	}))()

	if err != nil {
		fmt.Println("failed to transfer data: ", err.Error())
	}

	conn.Close() // nolint: errcheck
}

func (server *Server) Close() error {
	return server.listener.Close()
}
<|endoftext|>


<commit_before>// Copyright 2015 LinkedIn Corp. 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.Copyright [201X] LinkedIn Corp. 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.

package goavro

import (
	"encoding/json"
	"fmt"
	"strings"
)

// Record is an abstract data type used to hold data corresponding to
// an Avro record. Wherever an Avro schema specifies a record, this
// library's Decode method will return a Record initialized to the
// record's values read from the io.Reader. Likewise, when using
// Encode to convert data to an Avro record, it is necessary to create
// and send a Record instance to the Encoder method.
type Record struct {
	Name      string
	Fields    []*recordField
	aliases   []string
	doc       string
	n         *name
	ens       string
	schemaMap map[string]interface{}
}

// Get returns the datum of the specified Record field.
func (r Record) Get(fieldName string) (interface{}, error) {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			return field.Datum, nil
		}
	}
	return nil, fmt.Errorf("no such field: %s", fieldName)
}

// GetFieldSchema returns the schema of the specified Record field.
func (r Record) GetFieldSchema(fieldName string) (interface{}, error) {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			return field.schema, nil
		}
	}
	return nil, fmt.Errorf("no such field: %s", fieldName)
}

// Set updates the datum of the specified Record field.
func (r Record) Set(fieldName string, value interface{}) error {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			field.Datum = value
			return nil
		}
	}
	return fmt.Errorf("no such field: %s", fieldName)
}

// String returns a string representation of the Record.
func (r Record) String() string {
	fields := make([]string, len(r.Fields))
	for idx, f := range r.Fields {
		fields[idx] = fmt.Sprintf("%v", f)
	}
	return fmt.Sprintf("{%s: [%v]}", r.Name, strings.Join(fields, ", "))
}

// NewRecord will create a Record instance corresponding to the
// specified schema.
//
//    func recordExample(codec goavro.Codec, w io.Writer, recordSchema string) error {
//         // To encode a Record, you need to instantiate a Record instance
//         // that adheres to the schema the Encoder expect.
//         someRecord, err := goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             return err
//         }
//         // Once you have a Record, you can set the values of the various fields.
//         someRecord.Set("username", "Aquaman")
//         someRecord.Set("comment", "The Atlantic is oddly cold this morning!")
//         // Feel free to fully qualify the field name if you'd like
//         someRecord.Set("com.example.timestamp", int64(1082196484))
//
//         // Once the fields of the Record have the correct data, you can encode it
//         err = codec.Encode(w, someRecord)
//         return err
//     }
func NewRecord(setters ...RecordSetter) (*Record, error) {
	record := &Record{n: &name{}}
	for _, setter := range setters {
		err := setter(record)
		if err != nil {
			return nil, err
		}
	}
	if record.schemaMap == nil {
		return nil, newCodecBuildError("record", "no schema defined")
	}
	var err error
	record.n, err = newName(nameSchema(record.schemaMap), nameEnclosingNamespace(record.ens))
	if err != nil {
		return nil, newCodecBuildError("record", err)
	}
	record.Name = record.n.n
	ns := record.n.namespace()

	val, ok := record.schemaMap["fields"]
	if !ok {
		return nil, newCodecBuildError("record", "record requires one or more fields")
	}
	fields, ok := val.([]interface{})
	if !ok || len(fields) == 0 {
		return nil, newCodecBuildError("record", "record fields ought to be non-empty array")
	}

	record.Fields = make([]*recordField, len(fields))
	for i, field := range fields {
		rf, err := newRecordField(field, recordFieldEnclosingNamespace(ns))
		if err != nil {
			return nil, newCodecBuildError("record", err)
		}
		record.Fields[i] = rf
	}

	// fields optional to the avro spec

	if val, ok = record.schemaMap["doc"]; ok {
		record.doc, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record", "doc ought to be string")
		}
	}
	if val, ok = record.schemaMap["aliases"]; ok {
		record.aliases, ok = val.([]string)
		if !ok {
			return nil, newCodecBuildError("record", "aliases ought to be array of strings")
		}
	}
	record.schemaMap = nil
	return record, nil
}

// RecordSetter functions are those those which are used to
// instantiate a new Record.
type RecordSetter func(*Record) error

// recordSchemaRaw specifies the schema of the record to create. Schema
// must be `map[string]interface{}`.
func recordSchemaRaw(schema interface{}) RecordSetter {
	return func(r *Record) error {
		var ok bool
		r.schemaMap, ok = schema.(map[string]interface{})
		if !ok {
			return newCodecBuildError("record", "expected: map[string]interface{}; received: %T", schema)
		}
		return nil
	}
}

// RecordSchema specifies the schema of the record to
// create. Schema must be a JSON string.
func RecordSchema(recordSchemaJSON string) RecordSetter {
	return func(r *Record) error {
		var schema interface{}
		err := json.Unmarshal([]byte(recordSchemaJSON), &schema)
		if err != nil {
			return newCodecBuildError("record", err)
		}
		var ok bool
		r.schemaMap, ok = schema.(map[string]interface{})
		if !ok {
			return newCodecBuildError("record", "expected: map[string]interface{}; received: %T", schema)
		}
		return nil
	}
}

// RecordEnclosingNamespace specifies the enclosing namespace of the
// record to create. For instance, if the enclosing namespace is
// `com.example`, and the record name is `Foo`, then the full record
// name will be `com.example.Foo`.
func RecordEnclosingNamespace(someNamespace string) RecordSetter {
	return func(r *Record) error {
		r.ens = someNamespace
		return nil
	}
}

////////////////////////////////////////

type recordField struct {
	Name       string
	Datum      interface{}
	doc        string
	defval     interface{}
	hasDefault bool
	order      string
	aliases    []string
	schema     interface{}
	ens        string
}

func (rf recordField) String() string {
	return fmt.Sprintf("%s: %v", rf.Name, rf.Datum)
}

type recordFieldSetter func(*recordField) error

func recordFieldEnclosingNamespace(someNamespace string) recordFieldSetter {
	return func(rf *recordField) error {
		rf.ens = someNamespace
		return nil
	}
}

func newRecordField(schema interface{}, setters ...recordFieldSetter) (*recordField, error) {
	schemaMap, ok := schema.(map[string]interface{})
	if !ok {
		return nil, newCodecBuildError("record field", "schema expected: map[string]interface{}; received: %T", schema)
	}

	rf := &recordField{}
	for _, setter := range setters {
		err := setter(rf)
		if err != nil {
			return nil, newCodecBuildError("record field", err)
		}
	}

	n, err := newName(nameSchema(schemaMap), nameEnclosingNamespace(rf.ens))
	if err != nil {
		return nil, newCodecBuildError("record field", err)
	}
	rf.Name = n.n

	typeName, ok := schemaMap["type"]
	if !ok {
		return nil, newCodecBuildError("record field", "ought to have type key")
	}
	rf.schema = schema

	// fields optional to the avro spec

	val, ok := schemaMap["default"]
	if ok {
		rf.hasDefault = true
		switch typeName.(type) {
		case string:
			switch typeName {
			case "int":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "int32", val)
				}
				rf.defval = int32(dv)
			case "long":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "int64", val)
				}
				rf.defval = int64(dv)
			case "float":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "float32", val)
				}
				rf.defval = float32(dv)
			case "bytes":
				dv, ok := val.(string)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "string", val)
				}
				rf.defval = []byte(dv)
			default:
				rf.defval = val
			}
		default:
			rf.defval = val
		}
	}

	if val, ok = schemaMap["doc"]; ok {
		rf.doc, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field doc ought to be string")
		}
	}

	if val, ok = schemaMap["order"]; ok {
		rf.order, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field order ought to be string")
		}
		switch rf.order {
		case "ascending", "descending", "ignore":
			// ok
		default:
			return nil, newCodecBuildError("record field", "record field order ought to bescending, descending, or ignore")
		}
	}

	if val, ok = schemaMap["aliases"]; ok {
		rf.aliases, ok = val.([]string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field aliases ought to be array of strings")
		}
	}

	return rf, nil
}
<commit_msg>RecordSchema only decodes the JSON once.<commit_after>// Copyright 2015 LinkedIn Corp. 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.Copyright [201X] LinkedIn Corp. 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.

package goavro

import (
	"encoding/json"
	"fmt"
	"strings"
)

// Record is an abstract data type used to hold data corresponding to
// an Avro record. Wherever an Avro schema specifies a record, this
// library's Decode method will return a Record initialized to the
// record's values read from the io.Reader. Likewise, when using
// Encode to convert data to an Avro record, it is necessary to create
// and send a Record instance to the Encoder method.
type Record struct {
	Name      string
	Fields    []*recordField
	aliases   []string
	doc       string
	n         *name
	ens       string
	schemaMap map[string]interface{}
}

// Get returns the datum of the specified Record field.
func (r Record) Get(fieldName string) (interface{}, error) {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			return field.Datum, nil
		}
	}
	return nil, fmt.Errorf("no such field: %s", fieldName)
}

// GetFieldSchema returns the schema of the specified Record field.
func (r Record) GetFieldSchema(fieldName string) (interface{}, error) {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			return field.schema, nil
		}
	}
	return nil, fmt.Errorf("no such field: %s", fieldName)
}

// Set updates the datum of the specified Record field.
func (r Record) Set(fieldName string, value interface{}) error {
	// qualify fieldName searches based on record namespace
	fn, _ := newName(nameName(fieldName), nameNamespace(r.n.ns))

	for _, field := range r.Fields {
		if field.Name == fn.n {
			field.Datum = value
			return nil
		}
	}
	return fmt.Errorf("no such field: %s", fieldName)
}

// String returns a string representation of the Record.
func (r Record) String() string {
	fields := make([]string, len(r.Fields))
	for idx, f := range r.Fields {
		fields[idx] = fmt.Sprintf("%v", f)
	}
	return fmt.Sprintf("{%s: [%v]}", r.Name, strings.Join(fields, ", "))
}

// NewRecord will create a Record instance corresponding to the
// specified schema.
//
//    func recordExample(codec goavro.Codec, w io.Writer, recordSchema string) error {
//         // To encode a Record, you need to instantiate a Record instance
//         // that adheres to the schema the Encoder expect.
//         someRecord, err := goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             return err
//         }
//         // Once you have a Record, you can set the values of the various fields.
//         someRecord.Set("username", "Aquaman")
//         someRecord.Set("comment", "The Atlantic is oddly cold this morning!")
//         // Feel free to fully qualify the field name if you'd like
//         someRecord.Set("com.example.timestamp", int64(1082196484))
//
//         // Once the fields of the Record have the correct data, you can encode it
//         err = codec.Encode(w, someRecord)
//         return err
//     }
func NewRecord(setters ...RecordSetter) (*Record, error) {
	record := &Record{n: &name{}}
	for _, setter := range setters {
		err := setter(record)
		if err != nil {
			return nil, err
		}
	}
	if record.schemaMap == nil {
		return nil, newCodecBuildError("record", "no schema defined")
	}
	var err error
	record.n, err = newName(nameSchema(record.schemaMap), nameEnclosingNamespace(record.ens))
	if err != nil {
		return nil, newCodecBuildError("record", err)
	}
	record.Name = record.n.n
	ns := record.n.namespace()

	val, ok := record.schemaMap["fields"]
	if !ok {
		return nil, newCodecBuildError("record", "record requires one or more fields")
	}
	fields, ok := val.([]interface{})
	if !ok || len(fields) == 0 {
		return nil, newCodecBuildError("record", "record fields ought to be non-empty array")
	}

	record.Fields = make([]*recordField, len(fields))
	for i, field := range fields {
		rf, err := newRecordField(field, recordFieldEnclosingNamespace(ns))
		if err != nil {
			return nil, newCodecBuildError("record", err)
		}
		record.Fields[i] = rf
	}

	// fields optional to the avro spec

	if val, ok = record.schemaMap["doc"]; ok {
		record.doc, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record", "doc ought to be string")
		}
	}
	if val, ok = record.schemaMap["aliases"]; ok {
		record.aliases, ok = val.([]string)
		if !ok {
			return nil, newCodecBuildError("record", "aliases ought to be array of strings")
		}
	}
	record.schemaMap = nil
	return record, nil
}

// RecordSetter functions are those those which are used to
// instantiate a new Record.
type RecordSetter func(*Record) error

// recordSchemaRaw specifies the schema of the record to create. Schema
// must be `map[string]interface{}`.
func recordSchemaRaw(schema interface{}) RecordSetter {
	return func(r *Record) error {
		var ok bool
		r.schemaMap, ok = schema.(map[string]interface{})
		if !ok {
			return newCodecBuildError("record", "expected: map[string]interface{}; received: %T", schema)
		}
		return nil
	}
}

// RecordSchema specifies the schema of the record to
// create. Schema must be a JSON string.
func RecordSchema(recordSchemaJSON string) RecordSetter {
	var schema map[string]interface{}
	err := json.Unmarshal([]byte(recordSchemaJSON), &schema)
	if err != nil {
		err = newCodecBuildError("record", err)
	}

	return func(r *Record) error {
		if err != nil {
			return err
		} else {
			r.schemaMap = schema
			return nil
		}
	}
}

// RecordEnclosingNamespace specifies the enclosing namespace of the
// record to create. For instance, if the enclosing namespace is
// `com.example`, and the record name is `Foo`, then the full record
// name will be `com.example.Foo`.
func RecordEnclosingNamespace(someNamespace string) RecordSetter {
	return func(r *Record) error {
		r.ens = someNamespace
		return nil
	}
}

////////////////////////////////////////

type recordField struct {
	Name       string
	Datum      interface{}
	doc        string
	defval     interface{}
	hasDefault bool
	order      string
	aliases    []string
	schema     interface{}
	ens        string
}

func (rf recordField) String() string {
	return fmt.Sprintf("%s: %v", rf.Name, rf.Datum)
}

type recordFieldSetter func(*recordField) error

func recordFieldEnclosingNamespace(someNamespace string) recordFieldSetter {
	return func(rf *recordField) error {
		rf.ens = someNamespace
		return nil
	}
}

func newRecordField(schema interface{}, setters ...recordFieldSetter) (*recordField, error) {
	schemaMap, ok := schema.(map[string]interface{})
	if !ok {
		return nil, newCodecBuildError("record field", "schema expected: map[string]interface{}; received: %T", schema)
	}

	rf := &recordField{}
	for _, setter := range setters {
		err := setter(rf)
		if err != nil {
			return nil, newCodecBuildError("record field", err)
		}
	}

	n, err := newName(nameSchema(schemaMap), nameEnclosingNamespace(rf.ens))
	if err != nil {
		return nil, newCodecBuildError("record field", err)
	}
	rf.Name = n.n

	typeName, ok := schemaMap["type"]
	if !ok {
		return nil, newCodecBuildError("record field", "ought to have type key")
	}
	rf.schema = schema

	// fields optional to the avro spec

	val, ok := schemaMap["default"]
	if ok {
		rf.hasDefault = true
		switch typeName.(type) {
		case string:
			switch typeName {
			case "int":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "int32", val)
				}
				rf.defval = int32(dv)
			case "long":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "int64", val)
				}
				rf.defval = int64(dv)
			case "float":
				dv, ok := val.(float64)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "float32", val)
				}
				rf.defval = float32(dv)
			case "bytes":
				dv, ok := val.(string)
				if !ok {
					return nil, newCodecBuildError("record field", "default value type mismatch: %s; expected: %s; received: %T", rf.Name, "string", val)
				}
				rf.defval = []byte(dv)
			default:
				rf.defval = val
			}
		default:
			rf.defval = val
		}
	}

	if val, ok = schemaMap["doc"]; ok {
		rf.doc, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field doc ought to be string")
		}
	}

	if val, ok = schemaMap["order"]; ok {
		rf.order, ok = val.(string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field order ought to be string")
		}
		switch rf.order {
		case "ascending", "descending", "ignore":
			// ok
		default:
			return nil, newCodecBuildError("record field", "record field order ought to bescending, descending, or ignore")
		}
	}

	if val, ok = schemaMap["aliases"]; ok {
		rf.aliases, ok = val.([]string)
		if !ok {
			return nil, newCodecBuildError("record field", "record field aliases ought to be array of strings")
		}
	}

	return rf, nil
}
<|endoftext|>


<commit_before>package gocardless_pro_go

import "fmt"

type RefundService service

type Refund struct {
	ID							string				`json:"id,omitempty"`
	CreatedAt					string				`json:"created_at,omitempty"`
	Reference 					string				`json:"reference,omitempty"`
	Currency					string				`json:"currency,omitempty"`
	Amount						int64				`json:"amount,omitempty"`
	Links						[]RefundLink		`json:"links,omitempty"`
	Metadata					map[string]string	`json:"metadata,omitempty"`
}

type RefundListRequest struct {
	CreatedAt 			CreatedAt	`json:"created_at,omitempty"`
	Limit				int			`json:"limit,omitempty"`
	Before				string		`json:"before,omitempty"`
	After				string		`json:"after,omitempty"`
	Creditor			string		`json:"creditor,omitempty"`
	Customer			string		`json:"customer,omitempty"`
	Status				string		`json:"status,omitempty"`
	Currency			string		`json:"currency,omitempty"`
	Mandate				string		`json:"mandate,omitempty"`
	Subscription		string		`json:"subscription,omitempty"`
}

type RefundList struct {
	Meta   ListMeta
	Values []Refund `json:"data"`
}

type RefundCreateRequest struct {
	Metadata				map[string]string		`json:"metadata,omitempty"`
	Reference				string					`json:"reference,omitempty"`
	Amount					string					`json:"amount,omitempty"`
	TotalAmountConfirmation	string					`json:"total_amount_confirmation,omitempty"`
	Links					[]string				`json:"links,omitempty"`
}

// Create creates a new refund
func (s *RefundService) CreateRefund(refundReq *RefundCreateRequest) (*Refund, error) {
	u := fmt.Sprintf("/refunds")
	refund := &Refund{}
	err := s.client.Call("POST", u, refundReq, refund)

	return refund, err
}

// List returns a list of refund
func (s *PaymentService) ListPayments(req *PaymentListRequest) (*PaymentList, error) {
	return s.ListNPayments(10, 0, req)
}

func (s *PaymentService) ListNPayments(count, offset int, req *PaymentListRequest) (*PaymentList, error) {
	params := url.Values{}
	params.Add("after", req.After)
	params.Add("before", req.Before)
	params.Add("created_at[gt]", req.CreatedAt.Gt)
	params.Add("created_at[gte]", req.CreatedAt.Gte)
	params.Add("created_at[lt]", req.CreatedAt.Lt)
	params.Add("created_at[lte]", req.CreatedAt.Lte)
	params.Add("limit", string(req.Limit))
	params.Add("status", req.Status)
	params.Add("mandate", req.Mandate)
	params.Add("customer", req.Customer)
	params.Add("creditor", req.Creditor)
	params.Add("currency", req.Currency)
	params.Add("subscription", req.Subscription)

	u := paginateURL("/payments", count, offset)
	payments := &PaymentList{}
	err := s.client.Call("GET", u, params, payments)

	return payments, err
}

func (s *PaymentService) GetPayment(id string) (*Payment, error) {
	u := fmt.Sprintf("/payments/%s", id)
	payment := &Payment{}
	err := s.client.Call("GET", u, nil, payment)

	return payment, err
}

func (s *PaymentService) UpdatePayment(updatedPayment *Payment, metadata map[string]string) (*Payment, error) {
	params := url.Values{}
	params.Add("metadata", string(metadata))
	u := fmt.Sprintf("payments/%d", updatedPayment.ID)
	payment := &Payment{}
	err := s.client.Call("PUT", u, params, payment)

	return payment, err
}
<commit_msg>List All refunds<commit_after>package gocardless_pro_go

import (
	"fmt"
	"net/url"
)

type RefundService service

type Refund struct {
	ID							string				`json:"id,omitempty"`
	CreatedAt					string				`json:"created_at,omitempty"`
	Reference 					string				`json:"reference,omitempty"`
	Currency					string				`json:"currency,omitempty"`
	Amount						int64				`json:"amount,omitempty"`
	Links						[]RefundLink		`json:"links,omitempty"`
	Metadata					map[string]string	`json:"metadata,omitempty"`
}

type RefundListRequest struct {
	CreatedAt 			CreatedAt	`json:"created_at,omitempty"`
	Limit				int			`json:"limit,omitempty"`
	Before				string		`json:"before,omitempty"`
	After				string		`json:"after,omitempty"`
	Payment				string		`json:"payment,omitempty"`
}

type RefundList struct {
	Meta   ListMeta
	Values []Refund `json:"data"`
}

type RefundCreateRequest struct {
	Metadata				map[string]string		`json:"metadata,omitempty"`
	Reference				string					`json:"reference,omitempty"`
	Amount					string					`json:"amount,omitempty"`
	TotalAmountConfirmation	string					`json:"total_amount_confirmation,omitempty"`
	Links					[]string				`json:"links,omitempty"`
}

// Create creates a new refund
func (s *RefundService) CreateRefund(refundReq *RefundCreateRequest) (*Refund, error) {
	u := fmt.Sprintf("/refunds")
	refund := &Refund{}
	err := s.client.Call("POST", u, refundReq, refund)

	return refund, err
}

// List returns a list of refunds
func (s *RefundService) ListRefunds(req *RefundListRequest) (*RefundList, error) {
	return s.ListNRefunds(10, 0, req)
}

func (s *RefundService) ListNRefunds(count, offset int, req *RefundListRequest) (*RefundList, error) {
	params := url.Values{}
	params.Add("after", req.After)
	params.Add("before", req.Before)
	params.Add("created_at[gt]", req.CreatedAt.Gt)
	params.Add("created_at[gte]", req.CreatedAt.Gte)
	params.Add("created_at[lt]", req.CreatedAt.Lt)
	params.Add("created_at[lte]", req.CreatedAt.Lte)
	params.Add("limit", string(req.Limit))
	params.Add("payment", req.Payment)

	u := paginateURL("/refunds", count, offset)
	refunds := &RefundList{}
	err := s.client.Call("GET", u, params, refunds)

	return refunds, err
}

func (s *PaymentService) GetRefund(id string) (*Payment, error) {
	u := fmt.Sprintf("/payments/%s", id)
	payment := &Payment{}
	err := s.client.Call("GET", u, nil, payment)

	return payment, err
}

func (s *PaymentService) UpdatePayment(updatedPayment *Payment, metadata map[string]string) (*Payment, error) {
	params := url.Values{}
	params.Add("metadata", string(metadata))
	u := fmt.Sprintf("payments/%d", updatedPayment.ID)
	payment := &Payment{}
	err := s.client.Call("PUT", u, params, payment)

	return payment, err
}
<|endoftext|>


<commit_before>package pt

import (
	"fmt"
	"image"
	"image/color"
	"math"
	"math/rand"
	"runtime"
	"time"
)

func showProgress(start time.Time, i, h int) {
	pct := int(100 * float64(i+1) / float64(h))
	elapsed := time.Since(start)
	hr := int(elapsed.Hours())
	min := int(elapsed.Minutes()) % 60
	sec := int(elapsed.Seconds()) % 60
	fmt.Printf("\r%4d / %d (%3d%%) [", i+1, h, pct)
	for p := 0; p < 100; p += 2 {
		if pct > p {
			fmt.Print("=")
		} else {
			fmt.Print(" ")
		}
	}
	fmt.Printf("] %d:%02d:%02d ", hr, min, sec)
}

func Render(scene *Scene, camera *Camera, w, h, cameraSamples, hitSamples, depth int) image.Image {
	image := image.NewNRGBA(image.Rect(0, 0, w, h))
	ncpu := runtime.GOMAXPROCS(0)
	ch := make(chan int, h)
	fmt.Printf("%d x %d pixels, %d x %d = %d samples, %d bounces, %d cores\n",
		w, h, cameraSamples, hitSamples, cameraSamples*hitSamples, depth, ncpu)
	start := time.Now()
	for i := 0; i < ncpu; i++ {
		go func(i int) {
			n := int(math.Sqrt(float64(cameraSamples)))
			rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
			for y := i; y < h; y += ncpu {
				for x := 0; x < w; x++ {
					c := Color{}
					for u := 0; u < n; u++ {
						for v := 0; v < n; v++ {
							fu := (float64(u) + 0.5) * (1 / float64(n))
							fv := (float64(v) + 0.5) * (1 / float64(n))
							ray := camera.CastRay(x, y, w, h, fu, fv)
							c = c.Add(scene.Sample(ray, hitSamples, depth, rnd))
						}
					}
					c = c.Div(float64(n * n))
					r := uint8(math.Min(255, c.R*255))
					g := uint8(math.Min(255, c.G*255))
					b := uint8(math.Min(255, c.B*255))
					image.SetNRGBA(x, y, color.NRGBA{r, g, b, 255})
				}
				ch <- 1
			}
		}(i)
	}
	showProgress(start, -1, h)
	for i := 0; i < h; i++ {
		<-ch
		showProgress(start, i, h)
	}
	fmt.Println()
	return image
}
<commit_msg>tweaked showProgress<commit_after>package pt

import (
	"fmt"
	"image"
	"image/color"
	"math"
	"math/rand"
	"runtime"
	"time"
)

func showProgress(start time.Time, i, h int) {
	pct := int(100 * float64(i) / float64(h))
	elapsed := time.Since(start)
	hr := int(elapsed.Hours())
	min := int(elapsed.Minutes()) % 60
	sec := int(elapsed.Seconds()) % 60
	fmt.Printf("\r%4d / %d (%3d%%) [", i, h, pct)
	for p := 0; p < 100; p += 2 {
		if pct > p {
			fmt.Print("=")
		} else {
			fmt.Print(" ")
		}
	}
	fmt.Printf("] %d:%02d:%02d ", hr, min, sec)
}

func Render(scene *Scene, camera *Camera, w, h, cameraSamples, hitSamples, depth int) image.Image {
	image := image.NewNRGBA(image.Rect(0, 0, w, h))
	ncpu := runtime.GOMAXPROCS(0)
	ch := make(chan int, h)
	fmt.Printf("%d x %d pixels, %d x %d = %d samples, %d bounces, %d cores\n",
		w, h, cameraSamples, hitSamples, cameraSamples*hitSamples, depth, ncpu)
	start := time.Now()
	for i := 0; i < ncpu; i++ {
		go func(i int) {
			n := int(math.Sqrt(float64(cameraSamples)))
			rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
			for y := i; y < h; y += ncpu {
				for x := 0; x < w; x++ {
					c := Color{}
					for u := 0; u < n; u++ {
						for v := 0; v < n; v++ {
							fu := (float64(u) + 0.5) * (1 / float64(n))
							fv := (float64(v) + 0.5) * (1 / float64(n))
							ray := camera.CastRay(x, y, w, h, fu, fv)
							c = c.Add(scene.Sample(ray, hitSamples, depth, rnd))
						}
					}
					c = c.Div(float64(n * n))
					r := uint8(math.Min(255, c.R*255))
					g := uint8(math.Min(255, c.G*255))
					b := uint8(math.Min(255, c.B*255))
					image.SetNRGBA(x, y, color.NRGBA{r, g, b, 255})
				}
				ch <- 1
			}
		}(i)
	}
	showProgress(start, 0, h)
	for i := 0; i < h; i++ {
		<-ch
		showProgress(start, i+1, h)
	}
	fmt.Println()
	return image
}
<|endoftext|>


<commit_before>// This is the main package for the `tapasd` application.
package main

import (
	"encoding/xml"
	"flag"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"regexp"
	"strings"
	"sync"
	"time"
)

const feedUrl = "https://rubytapas.dpdcart.com/feed"

type Enclosure struct {
	Url    string `xml:"url,attr"`
	Length int64  `xml:"length,attr"`
}

type Item struct {
	Title     string    `xml:"title"`
	Enclosure Enclosure `xml:"enclosure"`
}

func main() {
	defDataDir, _ := os.Getwd()
	user := flag.String("user", "[required]", "user for RubyTapas account (required)")
	pass := flag.String("pass", "[required]", "pass for RubyTapas account (required)")
	dataDir := flag.String("data", defDataDir, "data directory for downloads")
	concurrency := flag.Int("concurrency", 4, "data directory for downloads")
	daemon := flag.Bool("daemon", false, "daemon mode which checks feed periodically")
	interval := flag.Int("interval", 60*60*6, "number of seconds to sleep between reprocessing")
	flag.Parse()
	if *user == "[required]" || *pass == "[required]" {
		log.Fatal("-user and -pass flags are required")
	}

	for {
		items := make(chan Item)
		go generate(items, *user, *pass)
		process(items, *concurrency, *user, *pass, *dataDir)
		log.Println("Processing and downloading complete")
		if !*daemon {
			break
		}
		log.Printf("Sleeping for %d seconds\n", *interval)
		timer := time.NewTimer(time.Duration(*interval) * time.Second)
		<-timer.C
		log.Println("Waking to process and download")
	}
}

// generate creates the collection of episodes to be downloaded.
func generate(urls chan Item, user string, pass string) {
	defer close(urls)
	request, err := http.NewRequest("GET", feedUrl, nil)
	request.SetBasicAuth(user, pass)
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	defer response.Body.Close()
	if response.StatusCode != 200 {
		log.Fatalf("URL %s returned status: %s\n", feedUrl, response.Status)
	}

	decoder := xml.NewDecoder(response.Body)
	for {
		token, _ := decoder.Token()
		if token == nil {
			break
		}

		switch startElement := token.(type) {
		case xml.StartElement:
			if startElement.Name.Local == "item" {
				var item Item
				decoder.DecodeElement(&item, &startElement)
				urls <- item
			}
		}
	}
}

// process works through the episode collection with a worker pool.
func process(items chan Item, concurrency int, user string, pass string, dataDir string) {
	var wg sync.WaitGroup
	for i := 1; i <= concurrency; i++ {
		wg.Add(1)
		worker := i
		go func() {
			defer wg.Done()
			for item := range items {
				download(worker, item, user, pass, dataDir)
			}
		}()
	}
	wg.Wait()
}

// download will download an episode movie file and verify its size.
func download(worker int, item Item, user string, pass string, dataDir string) {
	url, err := url.Parse(item.Enclosure.Url)
	if err != nil {
		log.Fatal(err)
	}
	fname := path.Join(dataDir, "rubytapas-"+slugify(item.Title)+path.Ext(url.Path))

	existing, err := os.Stat(fname)
	if !os.IsNotExist(err) {
		if existing.Size() != item.Enclosure.Length {
			log.Printf("[%02d] Deleting and retrying %s, incorrect file size (expected: %d, actual: %d)", worker, fname, item.Enclosure.Length, existing.Size())
			os.Remove(fname)
		} else {
			log.Printf("[%02d] Skipping %s", worker, fname)
			return
		}
	}

	log.Printf("[%02d] Downloading: %s to %s\n", worker, url.String(), fname)
	request, err := http.NewRequest("GET", url.String(), nil)
	request.SetBasicAuth(user, pass)
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	defer response.Body.Close()
	if response.StatusCode != 200 {
		log.Printf("[%02d] URL %s returned status: %s\n", worker, url, response.Status)
		return
	}

	tempfile := path.Join(path.Dir(fname), "."+path.Base(fname))
	if _, err := os.Stat(tempfile); !os.IsNotExist(err) {
		os.Remove(tempfile)
	}
	temp, err := os.Create(tempfile)
	if err != nil {
		log.Fatal(err)
	}
	defer temp.Close()
	defer os.Remove(tempfile)

	written, err := io.Copy(temp, response.Body)
	if err != nil {
		log.Fatal(err)
	}
	if written != item.Enclosure.Length {
		log.Printf("[%02d] Deleting %s, incorrect file size (expected: %d, actual: %d)", worker, fname, item.Enclosure.Length, written)
		os.Remove(fname)
		return
	}
	err = os.Rename(tempfile, fname)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("[%02d] Download complete: %s\n", worker, fname)
}

// slugify takes a string and returns a sanitized string suitable for creating
// filenames and web site URL slugs.
func slugify(title string) string {
	invalidSlugPatterns := regexp.MustCompile(`[^a-z0-9 _-]`)
	whitespacePatterns := regexp.MustCompile(`\s+`)

	result := strings.ToLower(title)
	result = invalidSlugPatterns.ReplaceAllString(result, "")
	result = whitespacePatterns.ReplaceAllString(result, "-")
	return result
}
<commit_msg>Refactoring for line length.<commit_after>// This is the main package for the `tapasd` application.
package main

import (
	"encoding/xml"
	"flag"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"regexp"
	"strings"
	"sync"
	"time"
)

const feedUrl = "https://rubytapas.dpdcart.com/feed"

type Enclosure struct {
	Url    string `xml:"url,attr"`
	Length int64  `xml:"length,attr"`
}

type Item struct {
	Title     string    `xml:"title"`
	Enclosure Enclosure `xml:"enclosure"`
}

func main() {
	defDataDir, _ := os.Getwd()
	user := flag.String("user", "[required]", "user for RubyTapas account (required)")
	pass := flag.String("pass", "[required]", "pass for RubyTapas account (required)")
	dataDir := flag.String("data", defDataDir, "data directory for downloads")
	concurrency := flag.Int("concurrency", 4, "data directory for downloads")
	daemon := flag.Bool("daemon", false, "daemon mode which checks feed periodically")
	interval := flag.Int("interval", 60*60*6, "number of seconds to sleep between reprocessing")
	flag.Parse()
	if *user == "[required]" || *pass == "[required]" {
		log.Fatal("-user and -pass flags are required")
	}

	for {
		items := make(chan Item)
		go generate(items, *user, *pass)
		process(items, *concurrency, *user, *pass, *dataDir)
		log.Println("Processing and downloading complete")
		if !*daemon {
			break
		}
		log.Printf("Sleeping for %d seconds\n", *interval)
		timer := time.NewTimer(time.Duration(*interval) * time.Second)
		<-timer.C
		log.Println("Waking to process and download")
	}
}

// generate creates the collection of episodes to be downloaded.
func generate(urls chan Item, user string, pass string) {
	defer close(urls)
	request, err := http.NewRequest("GET", feedUrl, nil)
	request.SetBasicAuth(user, pass)
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	defer response.Body.Close()
	if response.StatusCode != 200 {
		log.Fatalf("URL %s returned status: %s\n", feedUrl, response.Status)
	}

	decoder := xml.NewDecoder(response.Body)
	for {
		token, _ := decoder.Token()
		if token == nil {
			break
		}

		switch startElement := token.(type) {
		case xml.StartElement:
			if startElement.Name.Local == "item" {
				var item Item
				decoder.DecodeElement(&item, &startElement)
				urls <- item
			}
		}
	}
}

// process works through the episode collection with a worker pool.
func process(items chan Item, concurrency int, user string, pass string, dataDir string) {
	var wg sync.WaitGroup
	for i := 1; i <= concurrency; i++ {
		wg.Add(1)
		worker := i
		go func() {
			defer wg.Done()
			for item := range items {
				download(worker, item, user, pass, dataDir)
			}
		}()
	}
	wg.Wait()
}

// download will download an episode movie file and verify its size.
func download(worker int, item Item, user string, pass string, dataDir string) {
	url, err := url.Parse(item.Enclosure.Url)
	if err != nil {
		log.Fatal(err)
	}
	fname := path.Join(dataDir, "rubytapas-"+slugify(item.Title)+path.Ext(url.Path))

	existing, err := os.Stat(fname)
	if !os.IsNotExist(err) {
		if existing.Size() != item.Enclosure.Length {
			log.Printf(
				"[%02d] Deleting and retrying %s, incorrect file size (expected: %d, actual: %d)",
				worker,
				fname,
				item.Enclosure.Length,
				existing.Size(),
			)
			os.Remove(fname)
		} else {
			log.Printf("[%02d] Skipping %s", worker, path.Base(fname))
			return
		}
	}

	log.Printf("[%02d] Downloading: %s to %s\n", worker, url.String(), fname)
	request, err := http.NewRequest("GET", url.String(), nil)
	request.SetBasicAuth(user, pass)
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	defer response.Body.Close()
	if response.StatusCode != 200 {
		log.Printf("[%02d] URL %s returned status: %s\n", worker, url, response.Status)
		return
	}

	tempfile := path.Join(path.Dir(fname), "."+path.Base(fname))
	if _, err := os.Stat(tempfile); !os.IsNotExist(err) {
		os.Remove(tempfile)
	}
	temp, err := os.Create(tempfile)
	if err != nil {
		log.Fatal(err)
	}
	defer temp.Close()
	defer os.Remove(tempfile)

	written, err := io.Copy(temp, response.Body)
	if err != nil {
		log.Fatal(err)
	}
	if written != item.Enclosure.Length {
		log.Printf(
			"[%02d] Deleting %s, incorrect file size (expected: %d, actual: %d)",
			worker,
			fname,
			item.Enclosure.Length,
			written,
		)
		os.Remove(fname)
		return
	}
	err = os.Rename(tempfile, fname)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("[%02d] Download complete: %s\n", worker, path.Base(fname))
}

// slugify takes a string and returns a sanitized string suitable for creating
// filenames and web site URL slugs.
func slugify(title string) string {
	invalidSlugPatterns := regexp.MustCompile(`[^a-z0-9 _-]`)
	whitespacePatterns := regexp.MustCompile(`\s+`)

	result := strings.ToLower(title)
	result = invalidSlugPatterns.ReplaceAllString(result, "")
	result = whitespacePatterns.ReplaceAllString(result, "-")
	return result
}
<|endoftext|>


<commit_before>package sdbot

import (
	"fmt"
)

// String values of all the auth levels.
const (
	Administrator = `~`
	Leader        = `&`
	RoomOwner     = `#`
	Moderator     = `@`
	Driver        = `%`
	TheImmortal   = `>`
	Battler       = `★`
	Voiced        = `+`
	Unvoiced      = ` `
	Muted         = `?`
	Locked        = `‽`
)

var authLevels = map[string]int{
	Locked:        0,
	Muted:         1,
	Unvoiced:      2,
	Voiced:        3,
	Battler:       4,
	TheImmortal:   5,
	Driver:        6,
	Moderator:     7,
	RoomOwner:     8,
	Leader:        9,
	Administrator: 10,
}

// User represents a user with their username and the auth levels in rooms
// that the bot knows about.
type User struct {
	Name  string
	Auths map[string]string
}

// Room represents a room with its name and the users currently in it.
type Room struct {
	Name  string
	Users []string // List of unique SANITIZED names of users in the room
}

// NewUser creates a new User, initializing the Auths map.
func NewUser(name string) *User {
	return &User{
		Name:  name,
		Auths: make(map[string]string),
	}
}

// Reply responds to a user in private message and prepends the user's name to
// the response.
func (u *User) Reply(m *Message, res string) {
	s := fmt.Sprintf("(%s) %s", m.User.Name, res)
	if len(s) > 300 {
		s = s[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("|/w %s,%s", u.Name, s))
}

// Reply responds to a user in a chat message and prepends the user's name to
// the response. The message is sent to the Room of the method's receiver.
func (r *Room) Reply(m *Message, res string) {
	s := fmt.Sprintf("(%s) %s", m.User.Name, res)
	if len(s) > 300 {
		s = s[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("%s|%s", r.Name, s))
}

// RawReply responds to a user in private message without prepending their
// username.
func (u *User) RawReply(m *Message, res string) {
	if len(res) > 300 {
		res = res[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("|/w %s,%s", u.Name, res))
}

// RawReply responds to a user in a room without prepending their username.
func (r *Room) RawReply(m *Message, res string) {
	if len(res) > 300 {
		res = res[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("%s|%s", r.Name, res))
}

// AddAuth adds a room authority level to a user.
func (u *User) AddAuth(room string, auth string) {
	u.Auths[Sanitize(room)] = auth
}

// AddUser adds a user to the room.
func (r *Room) AddUser(name string) {
	sn := Sanitize(name)
	for _, n := range r.Users {
		if n == sn {
			return
		}
	}

	r.Users = append(r.Users, sn)
}

// RemoveUser removes a user from the room.
func (r *Room) RemoveUser(name string) {
	sn := Sanitize(name)
	for i, n := range r.Users {
		if n == sn {
			r.Users = append(r.Users[:i], r.Users[i+1:]...)
			return
		}
	}
}

// FindUserEnsured finds a user if it exists, creates the user if it doesn't.
func FindUserEnsured(name string, bot *Bot) *User {
	sn := Sanitize(name)

	var updateUsers = func() interface{} {
		if bot.UserList[sn] != nil {
			return bot.UserList[sn]
		}

		user := NewUser(name)
		bot.UserList[sn] = user

		return user
	}

	return bot.Synchronize("room", &updateUsers).(*User)
}

// FindRoomEnsured finds a room if it exists, creates the room if it doesn't.
func FindRoomEnsured(name string, bot *Bot) *Room {
	sn := Sanitize(name)

	var updateRooms = func() interface{} {
		if bot.RoomList[sn] != nil {
			return bot.RoomList[sn]
		}

		room := &Room{Name: sn}
		bot.RoomList[name] = room

		return room
	}

	return bot.Synchronize("user", &updateRooms).(*Room)
}

// Rename renames a user and updates their record in the UserList.
// TODO Test this. Doesn't seem to work as intended.
func Rename(old string, s string, bot *Bot) {
	so := Sanitize(old)
	sn := Sanitize(s)

	var rename = func() interface{} {
		if bot.UserList[so] != nil {
			u := bot.UserList[so]
			delete(bot.UserList, so)
			u.Name = s
			bot.UserList[sn] = u
		}
		return nil
	}

	bot.Synchronize("user", &rename)
}

// HasAuth checks if a user has AT LEAST a given authorization level in a given room.
func (u *User) HasAuth(roomname string, level string) bool {
	return authLevels[u.Auths[roomname]] >= authLevels[level]
}

// Target represents either a Room or a User. The distinction is in where the bot will
// send its message in response.
type Target interface {
	Reply(*Message, string)
	RawReply(*Message, string)
}
<commit_msg>target: fix behaviour of Rename, TODO removed<commit_after>package sdbot

import (
	"fmt"
)

// String values of all the auth levels.
const (
	Administrator = `~`
	Leader        = `&`
	RoomOwner     = `#`
	Moderator     = `@`
	Driver        = `%`
	TheImmortal   = `>`
	Battler       = `★`
	Voiced        = `+`
	Unvoiced      = ` `
	Muted         = `?`
	Locked        = `‽`
)

var authLevels = map[string]int{
	Locked:        0,
	Muted:         1,
	Unvoiced:      2,
	Voiced:        3,
	Battler:       4,
	TheImmortal:   5,
	Driver:        6,
	Moderator:     7,
	RoomOwner:     8,
	Leader:        9,
	Administrator: 10,
}

// User represents a user with their username and the auth levels in rooms
// that the bot knows about.
type User struct {
	Name  string
	Auths map[string]string
}

// Room represents a room with its name and the users currently in it.
type Room struct {
	Name  string
	Users []string // List of unique SANITIZED names of users in the room
}

// NewUser creates a new User, initializing the Auths map.
func NewUser(name string) *User {
	return &User{
		Name:  name,
		Auths: make(map[string]string),
	}
}

// Reply responds to a user in private message and prepends the user's name to
// the response.
func (u *User) Reply(m *Message, res string) {
	s := fmt.Sprintf("(%s) %s", m.User.Name, res)
	if len(s) > 300 {
		s = s[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("|/w %s,%s", u.Name, s))
}

// Reply responds to a user in a chat message and prepends the user's name to
// the response. The message is sent to the Room of the method's receiver.
func (r *Room) Reply(m *Message, res string) {
	s := fmt.Sprintf("(%s) %s", m.User.Name, res)
	if len(s) > 300 {
		s = s[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("%s|%s", r.Name, s))
}

// RawReply responds to a user in private message without prepending their
// username.
func (u *User) RawReply(m *Message, res string) {
	if len(res) > 300 {
		res = res[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("|/w %s,%s", u.Name, res))
}

// RawReply responds to a user in a room without prepending their username.
func (r *Room) RawReply(m *Message, res string) {
	if len(res) > 300 {
		res = res[:300]
	}
	m.Bot.Connection.QueueMessage(fmt.Sprintf("%s|%s", r.Name, res))
}

// AddAuth adds a room authority level to a user.
func (u *User) AddAuth(room string, auth string) {
	u.Auths[Sanitize(room)] = auth
}

// AddUser adds a user to the room.
func (r *Room) AddUser(name string) {
	sn := Sanitize(name)
	for _, n := range r.Users {
		if n == sn {
			return
		}
	}

	r.Users = append(r.Users, sn)
}

// RemoveUser removes a user from the room.
func (r *Room) RemoveUser(name string) {
	sn := Sanitize(name)
	for i, n := range r.Users {
		if n == sn {
			r.Users = append(r.Users[:i], r.Users[i+1:]...)
			return
		}
	}
}

// FindUserEnsured finds a user if it exists, creates the user if it doesn't.
func FindUserEnsured(name string, b *Bot) *User {
	sn := Sanitize(name)

	var updateUsers = func() interface{} {
		if b.UserList[sn] != nil {
			return b.UserList[sn]
		}

		user := NewUser(name)
		b.UserList[sn] = user

		return user
	}

	return b.Synchronize("room", &updateUsers).(*User)
}

// FindRoomEnsured finds a room if it exists, creates the room if it doesn't.
func FindRoomEnsured(name string, b *Bot) *Room {
	sn := Sanitize(name)

	var updateRooms = func() interface{} {
		if b.RoomList[sn] != nil {
			return b.RoomList[sn]
		}

		room := &Room{Name: sn}
		b.RoomList[name] = room

		return room
	}

	return b.Synchronize("user", &updateRooms).(*Room)
}

// Rename renames a user and updates their record in the UserList.
func Rename(old string, s string, r *Room, b *Bot) {
	so := Sanitize(old)
	sn := Sanitize(s)

	var rename = func() interface{} {
		if so == sn {
			b.UserList[so].Name = s
		} else {
			r.RemoveUser(so)
			r.AddUser(sn)
			FindUserEnsured(s, b)
		}
		return nil
	}

	b.Synchronize("user", &rename)
}

// HasAuth checks if a user has AT LEAST a given authorization level in a given room.
func (u *User) HasAuth(roomname string, level string) bool {
	return authLevels[u.Auths[roomname]] >= authLevels[level]
}

// Target represents either a Room or a User. The distinction is in where the bot will
// send its message in response.
type Target interface {
	Reply(*Message, string)
	RawReply(*Message, string)
}
<|endoftext|>