<commit_before>// Copyright 2015, Cerevo Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"libvsw"
	"log"
	"os"
	"time"
	"math/rand"
)

const PARAM_VERSION = 5
const PARAMS_FILE = "autotrans.json"

type Params struct {
	Param_version      int
	Input              [4]bool
	Interval           int /* sec */
	Trans              int /* bit0-7 {CUT, MIX, DIP, WIPE, ..}, bit8-9:dip_src */
	Rate               int /* msec */
	StartLiveBroadcast bool
	UploadStillPicture bool
	Picture string
}

var defaultParams = Params{
	Param_version:      PARAM_VERSION,
	Input:              [4]bool{true, true, false, false},
	Interval:           30,
	Trans:              0x302, /* Dip to 4 */
	Rate:               5000,
	StartLiveBroadcast: false,
	UploadStillPicture: false,
	Picture: "",
}

func random(min, max int) int {
    rand.Seed(time.Now().Unix())
    return rand.Intn(max - min) + min
}

func loop(vsw *libvsw.Vsw, pa Params, notify chan Params) {
	index := 0
	for {
		select {
		case pa = <-notify:
			log.Printf("got from chan\n")
			saveParams(pa)
			if pa.StartLiveBroadcast {
				vsw.ChangeLiveBroadcastState(1)
			} else {
				vsw.ChangeLiveBroadcastState(0)
			}
			if pa.UploadStillPicture {
				vsw.UploadFile(pa.Picture)
			}
		case <-time.After(time.Second * time.Duration(pa.Interval)):
			log.Printf("periodic timer\n")
		}
		index = (index + 1) % 4
		i := 0
		for ; i < 4; i++ {
			if pa.Input[i] == true {
				break
			}
		}
		if i == 4 {
			// no input checked
			pa.Interval = 1000000
			continue
		}
		for pa.Input[index] == false {
			index = (index + 1) % 4
		}
		switch pa.Trans & 0xff {
		case 0:
			vsw.Cut(index + 1)
		case 1:
			vsw.Mix(pa.Rate, index+1)
		case 2:
			vsw.Dip(pa.Rate, index+1, ((pa.Trans>>8)&3)+1)
		case 255:
			vsw.Wipe(pa.Rate, index+1, random(0, libvsw.WIPE_TYPE_NUM - 1))
		default:
			vsw.Wipe(pa.Rate, index+1, pa.Trans-libvsw.TRANSITION_TYPE_WIPE)
		}
	}
}

func loadParams(filename string) Params {
	f, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return defaultParams
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	var pa Params
	err = dec.Decode(&pa)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return defaultParams
	}
	if pa.Param_version != PARAM_VERSION {
		fmt.Fprintf(os.Stderr, "Param_version mismatch. Use default.\n")
		return defaultParams
	}
	return pa
}

func saveParams(pa Params) {
	f, err := os.OpenFile(PARAMS_FILE, os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return
	}
	defer f.Close()
	enc := json.NewEncoder(f)
	err = enc.Encode(pa)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
	}
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: %s IP_address_of_livewedge\n", os.Args[0])
		os.Exit(1)
	}
	vsw, err := libvsw.NewVsw(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open LiveWedge: %s\n", err)
		os.Exit(1)
	}
	defer vsw.Close()

	vsw.Cut(1)

	pa := loadParams(PARAMS_FILE)
	if pa.StartLiveBroadcast {
		vsw.ChangeLiveBroadcastState(1)
	} else {
		vsw.ChangeLiveBroadcastState(0)
	}
	if pa.UploadStillPicture {
		vsw.UploadFile(pa.Picture)
	}

	notify := make(chan Params, 1)
	go loop(vsw, pa, notify)

	WebUI(pa, notify)
}
<commit_msg>autotrans: Change default trans mode to 'Random wipe'<commit_after>// Copyright 2015, Cerevo Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"libvsw"
	"log"
	"math/rand"
	"os"
	"time"
)

const PARAM_VERSION = 5
const PARAMS_FILE = "autotrans.json"

type Params struct {
	Param_version      int
	Input              [4]bool
	Interval           int /* sec */
	Trans              int /* bit0-7 {CUT, MIX, DIP, WIPE, ..}, bit8-9:dip_src */
	Rate               int /* msec */
	StartLiveBroadcast bool
	UploadStillPicture bool
	Picture            string
}

var defaultParams = Params{
	Param_version:      PARAM_VERSION,
	Input:              [4]bool{true, true, false, false},
	Interval:           30,
	Trans:              255, /* Random wipe */
	Rate:               3000,
	StartLiveBroadcast: false,
	UploadStillPicture: false,
	Picture:            "",
}

func random(min, max int) int {
	rand.Seed(time.Now().Unix())
	return rand.Intn(max-min) + min
}

func loop(vsw *libvsw.Vsw, pa Params, notify chan Params) {
	index := 0
	for {
		select {
		case pa = <-notify:
			log.Printf("got from chan\n")
			saveParams(pa)
			if pa.StartLiveBroadcast {
				vsw.ChangeLiveBroadcastState(1)
			} else {
				vsw.ChangeLiveBroadcastState(0)
			}
			if pa.UploadStillPicture {
				vsw.UploadFile(pa.Picture)
			}
		case <-time.After(time.Second * time.Duration(pa.Interval)):
			log.Printf("periodic timer\n")
		}
		index = (index + 1) % 4
		i := 0
		for ; i < 4; i++ {
			if pa.Input[i] == true {
				break
			}
		}
		if i == 4 {
			// no input checked
			pa.Interval = 1000000
			continue
		}
		for pa.Input[index] == false {
			index = (index + 1) % 4
		}
		switch pa.Trans & 0xff {
		case 0:
			vsw.Cut(index + 1)
		case 1:
			vsw.Mix(pa.Rate, index+1)
		case 2:
			vsw.Dip(pa.Rate, index+1, ((pa.Trans>>8)&3)+1)
		case 255:
			vsw.Wipe(pa.Rate, index+1, random(0, libvsw.WIPE_TYPE_NUM-1))
		default:
			vsw.Wipe(pa.Rate, index+1, pa.Trans-libvsw.TRANSITION_TYPE_WIPE)
		}
	}
}

func loadParams(filename string) Params {
	f, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return defaultParams
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	var pa Params
	err = dec.Decode(&pa)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return defaultParams
	}
	if pa.Param_version != PARAM_VERSION {
		fmt.Fprintf(os.Stderr, "Param_version mismatch. Use default.\n")
		return defaultParams
	}
	return pa
}

func saveParams(pa Params) {
	f, err := os.OpenFile(PARAMS_FILE, os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return
	}
	defer f.Close()
	enc := json.NewEncoder(f)
	err = enc.Encode(pa)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
	}
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: %s IP_address_of_livewedge\n", os.Args[0])
		os.Exit(1)
	}
	vsw, err := libvsw.NewVsw(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open LiveWedge: %s\n", err)
		os.Exit(1)
	}
	defer vsw.Close()

	vsw.Cut(1)

	pa := loadParams(PARAMS_FILE)
	if pa.StartLiveBroadcast {
		vsw.ChangeLiveBroadcastState(1)
	} else {
		vsw.ChangeLiveBroadcastState(0)
	}
	if pa.UploadStillPicture {
		vsw.UploadFile(pa.Picture)
	}

	notify := make(chan Params, 1)
	go loop(vsw, pa, notify)

	WebUI(pa, notify)
}
<|endoftext|>


<commit_before>// Package usl provides functionality to build Universal Scalability Law models
// from sets of observed measurements.
package usl

import (
	"errors"
	"fmt"
	"math"
	"sort"

	"code.google.com/p/gomatrix/matrix"
)

var (
	// ErrInsufficientMeasurements is returned when less than 6 measurements
	// were provided.
	ErrInsufficientMeasurements = errors.New("usl: need at least 6 measurements")
)

// Measurement is a simultaneous measurement of both an independent variable and
// a dependent variable.
type Measurement struct {
	X float64 // X is a measurement of the independent variable.
	Y float64 // Y is a simultaneous measurement of the dependent variable.
}

// MeasurementSet is a sortable set of measurements.
type MeasurementSet []Measurement

// Len is the number of measurements in the set.
func (m MeasurementSet) Len() int {
	return len(m)
}

// Less reports whether the measurement with index i should sort before the
// measurement with index j.
func (m MeasurementSet) Less(i, j int) bool {
	return m[i].X < m[j].X
}

// Swap swaps the measurements with indexes i and j.
func (m MeasurementSet) Swap(i, j int) {
	x := m[i]
	m[i] = m[j]
	m[j] = x
}

// Model is a Universal Scalability Law model.
type Model struct {
	Alpha float64 // Alpha represents the levels of contention.
	Beta  float64 // Beta represents the coherency delay.
	Y     float64 // Y is the system's unloaded behavior.
	Peak  float64 // Peak is the usage level at which output is maximized.
}

// Predict returns the predicted value at a given utilization level.
func (m Model) Predict(x float64) float64 {
	c := x / (1 + (m.Alpha * (x - 1)) + (m.Beta * x * (x - 1)))
	return c * m.Y
}

func (m Model) String() string {
	var a, b string
	if m.Alpha > m.Beta {
		a = " (constrained by contention effects)"
	} else if m.Alpha < m.Beta {
		b = " (constrained by coherency effects)"
	}

	return fmt.Sprintf(
		"Model:\n\tα:    %f%s\n\tβ:    %f%s\n\tpeak: X=%.0f, Y=%2.2f\n",
		m.Alpha, a, m.Beta, b, m.Peak, m.Predict(m.Peak),
	)
}

// Build returns a model whose parameters are generated from the given
// measurements.
func Build(measurements MeasurementSet) (m Model, err error) {
	if len(measurements) < 6 {
		err = ErrInsufficientMeasurements
		return
	}

	sort.Sort(measurements)
	y0 := measurements[0].Y / measurements[0].X

	xs := make([]float64, 0, len(measurements))
	ys := make([]float64, 0, len(measurements))

	for _, m := range measurements {
		xs = append(xs, m.X-1)
		ys = append(ys, (m.X/(m.Y/y0))-1)
	}

	var c [3]float64 // do quadratic regression

	y := matrix.MakeDenseMatrix(ys, len(xs), 1)
	x := matrix.Zeros(len(ys), len(c))
	for i := 0; i < len(xs); i++ {
		ip := 1.0
		for j := 0; j < len(c); j++ {
			x.Set(i, j, ip)
			ip *= xs[i]
		}
	}

	q, r := x.QR()
	qty, err := q.Transpose().Times(y)
	if err != nil {
		return
	}

	for i := len(c) - 1; i >= 0; i-- {
		c[i] = qty.Get(i, 0)
		for j := i + 1; j < len(c); j++ {
			c[i] -= c[j] * r.Get(i, j)
		}
		c[i] /= r.Get(i, i)
	}

	m.Alpha = math.Abs(c[2] - c[1])
	m.Beta = math.Abs(c[2])
	m.Y = y0
	m.Peak = math.Floor(math.Sqrt((1 - m.Alpha) / m.Beta))

	return
}
<commit_msg>Fix Model.String().<commit_after>// Package usl provides functionality to build Universal Scalability Law models
// from sets of observed measurements.
package usl

import (
	"errors"
	"fmt"
	"math"
	"sort"

	"code.google.com/p/gomatrix/matrix"
)

var (
	// ErrInsufficientMeasurements is returned when less than 6 measurements
	// were provided.
	ErrInsufficientMeasurements = errors.New("usl: need at least 6 measurements")
)

// Measurement is a simultaneous measurement of both an independent variable and
// a dependent variable.
type Measurement struct {
	X float64 // X is a measurement of the independent variable.
	Y float64 // Y is a simultaneous measurement of the dependent variable.
}

// MeasurementSet is a sortable set of measurements.
type MeasurementSet []Measurement

// Len is the number of measurements in the set.
func (m MeasurementSet) Len() int {
	return len(m)
}

// Less reports whether the measurement with index i should sort before the
// measurement with index j.
func (m MeasurementSet) Less(i, j int) bool {
	return m[i].X < m[j].X
}

// Swap swaps the measurements with indexes i and j.
func (m MeasurementSet) Swap(i, j int) {
	x := m[i]
	m[i] = m[j]
	m[j] = x
}

// Model is a Universal Scalability Law model.
type Model struct {
	Alpha float64 // Alpha represents the levels of contention.
	Beta  float64 // Beta represents the coherency delay.
	Y     float64 // Y is the system's unloaded behavior.
	Peak  float64 // Peak is the usage level at which output is maximized.
}

// Predict returns the predicted value at a given utilization level.
func (m Model) Predict(x float64) float64 {
	c := x / (1 + (m.Alpha * (x - 1)) + (m.Beta * x * (x - 1)))
	return c * m.Y
}

func (m Model) String() string {
	var a, b string
	if m.Alpha > m.Beta {
		a = " (constrained by contention effects)"
	} else if m.Alpha < m.Beta {
		b = " (constrained by coherency effects)"
	}

	return fmt.Sprintf(
		"Model:\n\tα:    %f%s\n\tβ:    %f%s\n\tpeak: X=%.0f, Y=%2.2f",
		m.Alpha, a, m.Beta, b, m.Peak, m.Predict(m.Peak),
	)
}

// Build returns a model whose parameters are generated from the given
// measurements.
func Build(measurements MeasurementSet) (m Model, err error) {
	if len(measurements) < 6 {
		err = ErrInsufficientMeasurements
		return
	}

	sort.Sort(measurements)
	y0 := measurements[0].Y / measurements[0].X

	xs := make([]float64, 0, len(measurements))
	ys := make([]float64, 0, len(measurements))

	for _, m := range measurements {
		xs = append(xs, m.X-1)
		ys = append(ys, (m.X/(m.Y/y0))-1)
	}

	var c [3]float64 // do quadratic regression

	y := matrix.MakeDenseMatrix(ys, len(xs), 1)
	x := matrix.Zeros(len(ys), len(c))
	for i := 0; i < len(xs); i++ {
		ip := 1.0
		for j := 0; j < len(c); j++ {
			x.Set(i, j, ip)
			ip *= xs[i]
		}
	}

	q, r := x.QR()
	qty, err := q.Transpose().Times(y)
	if err != nil {
		return
	}

	for i := len(c) - 1; i >= 0; i-- {
		c[i] = qty.Get(i, 0)
		for j := i + 1; j < len(c); j++ {
			c[i] -= c[j] * r.Get(i, j)
		}
		c[i] /= r.Get(i, i)
	}

	m.Alpha = math.Abs(c[2] - c[1])
	m.Beta = math.Abs(c[2])
	m.Y = y0
	m.Peak = math.Floor(math.Sqrt((1 - m.Alpha) / m.Beta))

	return
}
<|endoftext|>


<commit_before>package yago

import (
	"github.com/aacanakin/qb"
)

type Model interface {
	GetMapper() Mapper
}

type ScalarField struct {
	Column qb.ColumnElem
}

func NewScalarField(column qb.ColumnElem) ScalarField {
	return ScalarField{
		Column: column,
	}
}

func (f ScalarField) Eq(value interface{}) qb.Clause {
	return f.Column.Eq(value)
}
<commit_msg>Wrap all scalar operators<commit_after>package yago

import (
	"github.com/aacanakin/qb"
)

// A Model provides handy access to a struct definition.
type Model interface {
	GetMapper() Mapper
}

// ScalarField A simple scalar field
type ScalarField struct {
	Column qb.ColumnElem
}

// NewScalarField returns a new ScalarField
func NewScalarField(column qb.ColumnElem) ScalarField {
	return ScalarField{
		Column: column,
	}
}

// Like returns a LIKE clause
func (f ScalarField) Like(pattern string) qb.Clause {
	return f.Column.Like(pattern)
}

// NotIn returns a NOT IN clause
func (f ScalarField) NotIn(values ...interface{}) qb.Clause {
	return f.Column.NotIn(values...)
}

// In returns a IN clause
func (f ScalarField) In(values ...interface{}) qb.Clause {
	return f.Column.In(values...)
}

// NotEq returns a != clause
func (f ScalarField) NotEq(value interface{}) qb.Clause {
	return f.Column.NotEq(value)
}

// Eq returns a = clause
func (f ScalarField) Eq(value interface{}) qb.Clause {
	return f.Column.Eq(value)
}

// Gt returns a > clause
func (f ScalarField) Gt(value interface{}) qb.Clause {
	return f.Column.Gt(value)
}

// St returns a < clause
func (f ScalarField) St(value interface{}) qb.Clause {
	return f.Column.St(value)
}

// Gte returns a >= clause
func (f ScalarField) Gte(value interface{}) qb.Clause {
	return f.Column.Gte(value)
}

// Ste returns a <= clause
func (f ScalarField) Ste(value interface{}) qb.Clause {
	return f.Column.Ste(value)
}
<|endoftext|>


<commit_before>package tfjson

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/zclconf/go-cty/cty"
)

// ProviderSchemasFormatVersion is the version of the JSON provider
// schema format that is supported by this package.
const ProviderSchemasFormatVersion = "0.1"

// ProviderSchemas represents the schemas of all providers and
// resources in use by the configuration.
type ProviderSchemas struct {
	// The version of the plan format. This should always match the
	// ProviderSchemasFormatVersion constant in this package, or else
	// an unmarshal will be unstable.
	FormatVersion string `json:"format_version,omitempty"`

	// The schemas for the providers in this configuration, indexed by
	// provider type. Aliases are not included, and multiple instances
	// of a provider in configuration will be represented by a single
	// provider here.
	Schemas map[string]*ProviderSchema `json:"provider_schemas,omitempty"`
}

// Validate checks to ensure that ProviderSchemas is present, and the
// version matches the version supported by this library.
func (p *ProviderSchemas) Validate() error {
	if p == nil {
		return errors.New("provider schema data is nil")
	}

	if p.FormatVersion == "" {
		return errors.New("unexpected provider schema data, format version is missing")
	}

	if ProviderSchemasFormatVersion != p.FormatVersion {
		return fmt.Errorf("unsupported provider schema data format version: expected %q, got %q", PlanFormatVersion, p.FormatVersion)
	}

	return nil
}

func (p *ProviderSchemas) UnmarshalJSON(b []byte) error {
	type rawSchemas ProviderSchemas
	var schemas rawSchemas

	err := json.Unmarshal(b, &schemas)
	if err != nil {
		return err
	}

	*p = *(*ProviderSchemas)(&schemas)

	return p.Validate()
}

// ProviderSchema is the JSON representation of the schema of an
// entire provider, including the provider configuration and any
// resources and data sources included with the provider.
type ProviderSchema struct {
	// The schema for the provider's configuration.
	ConfigSchema *Schema `json:"provider,omitempty"`

	// The schemas for any resources in this provider.
	ResourceSchemas map[string]*Schema `json:"resource_schemas,omitempty"`

	// The schemas for any data sources in this provider.
	DataSourceSchemas map[string]*Schema `json:"data_source_schemas,omitempty"`
}

// Schema is the JSON representation of a particular schema
// (provider configuration, resources, data sources).
type Schema struct {
	// The version of the particular resource schema.
	Version uint64 `json:"version"`

	// The root-level block of configuration values.
	Block *SchemaBlock `json:"block,omitempty"`
}

// SchemaDescriptionKind is the format of a string
type SchemaDescriptionKind string

const (
	// SchemaDescriptionKindPlain indicates a string in plain text format.
	SchemaDescriptionKindPlain SchemaDescriptionKind = "plaintext"

	// SchemaDescriptionKindMarkdown indicates a Markdown string and may need to be
	// processed prior to presentation.
	SchemaDescriptionKindMarkdown SchemaDescriptionKind = "markdown"
)

// SchemaBlock represents a nested block within a particular schema.
type SchemaBlock struct {
	// The attributes defined at the particular level of this block.
	Attributes map[string]*SchemaAttribute `json:"attributes,omitempty"`

	// Any nested blocks within this particular block.
	NestedBlocks map[string]*SchemaBlockType `json:"block_types,omitempty"`

	// The description for this block and format of the description. If
	// no kind is provided, it can be assumed to be plain text.
	Description     string                `json:"description,omitempty"`
	DescriptionKind SchemaDescriptionKind `json:"description_kind,omitempty"`

	// If true, this block is deprecated.
	Deprecated bool `json:"deprecated,omitempty"`
}

// SchemaNestingMode is the nesting mode for a particular nested
// schema block.
type SchemaNestingMode string

const (
	// SchemaNestingModeSingle denotes single block nesting mode, which
	// allows a single block of this specific type only in
	// configuration. This is generally the same as list or set types
	// with a single-element constraint.
	SchemaNestingModeSingle SchemaNestingMode = "single"

	// SchemaNestingModeList denotes list block nesting mode, which
	// allows an ordered list of blocks where duplicates are allowed.
	SchemaNestingModeList SchemaNestingMode = "list"

	// SchemaNestingModeSet denotes set block nesting mode, which
	// allows an unordered list of blocks where duplicates are
	// generally not allowed. What is considered a duplicate is up to
	// the rules of the set itself, which may or may not cover all
	// fields in the block.
	SchemaNestingModeSet SchemaNestingMode = "set"

	// SchemaNestingModeMap denotes map block nesting mode. This
	// creates a map of all declared blocks of the block type within
	// the parent, keying them on the label supplied in the block
	// declaration. This allows for blocks to be declared in the same
	// style as resources.
	SchemaNestingModeMap SchemaNestingMode = "map"
)

// SchemaBlockType describes a nested block within a schema.
type SchemaBlockType struct {
	// The nesting mode for this block.
	NestingMode SchemaNestingMode `json:"nesting_mode,omitempty"`

	// The block data for this block type, including attributes and
	// subsequent nested blocks.
	Block *SchemaBlock `json:"block,omitempty"`

	// The lower limit on items that can be declared of this block
	// type.
	MinItems uint64 `json:"min_items,omitempty"`

	// The upper limit on items that can be declared of this block
	// type.
	MaxItems uint64 `json:"max_items,omitempty"`
}

// SchemaAttribute describes an attribute within a schema block.
type SchemaAttribute struct {
	// The attribute type.
	AttributeType cty.Type `json:"type,omitempty"`

	// The description field for this attribute. If no kind is
	// provided, it can be assumed to be plain text.
	Description     string                `json:"description,omitempty"`
	DescriptionKind SchemaDescriptionKind `json:"description_kind,omitempty"`

	// If true, this attribute is deprecated.
	Deprecated bool `json:"deprecated,omitempty"`

	// If true, this attribute is required - it has to be entered in
	// configuration.
	Required bool `json:"required,omitempty"`

	// If true, this attribute is optional - it does not need to be
	// entered in configuration.
	Optional bool `json:"optional,omitempty"`

	// If true, this attribute is computed - it can be set by the
	// provider. It may also be set by configuration if Optional is
	// true.
	Computed bool `json:"computed,omitempty"`

	// If true, this attribute is sensitive and will not be displayed
	// in logs. Future versions of Terraform may encrypt or otherwise
	// treat these values with greater care than non-sensitive fields.
	Sensitive bool `json:"sensitive,omitempty"`
}
<commit_msg>Update schemas.go<commit_after>package tfjson

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/zclconf/go-cty/cty"
)

// ProviderSchemasFormatVersion is the version of the JSON provider
// schema format that is supported by this package.
const ProviderSchemasFormatVersion = "0.1"

// ProviderSchemas represents the schemas of all providers and
// resources in use by the configuration.
type ProviderSchemas struct {
	// The version of the plan format. This should always match the
	// ProviderSchemasFormatVersion constant in this package, or else
	// an unmarshal will be unstable.
	FormatVersion string `json:"format_version,omitempty"`

	// The schemas for the providers in this configuration, indexed by
	// provider type. Aliases are not included, and multiple instances
	// of a provider in configuration will be represented by a single
	// provider here.
	Schemas map[string]*ProviderSchema `json:"provider_schemas,omitempty"`
}

// Validate checks to ensure that ProviderSchemas is present, and the
// version matches the version supported by this library.
func (p *ProviderSchemas) Validate() error {
	if p == nil {
		return errors.New("provider schema data is nil")
	}

	if p.FormatVersion == "" {
		return errors.New("unexpected provider schema data, format version is missing")
	}

	if ProviderSchemasFormatVersion != p.FormatVersion {
		return fmt.Errorf("unsupported provider schema data format version: expected %q, got %q", PlanFormatVersion, p.FormatVersion)
	}

	return nil
}

func (p *ProviderSchemas) UnmarshalJSON(b []byte) error {
	type rawSchemas ProviderSchemas
	var schemas rawSchemas

	err := json.Unmarshal(b, &schemas)
	if err != nil {
		return err
	}

	*p = *(*ProviderSchemas)(&schemas)

	return p.Validate()
}

// ProviderSchema is the JSON representation of the schema of an
// entire provider, including the provider configuration and any
// resources and data sources included with the provider.
type ProviderSchema struct {
	// The schema for the provider's configuration.
	ConfigSchema *Schema `json:"provider,omitempty"`

	// The schemas for any resources in this provider.
	ResourceSchemas map[string]*Schema `json:"resource_schemas,omitempty"`

	// The schemas for any data sources in this provider.
	DataSourceSchemas map[string]*Schema `json:"data_source_schemas,omitempty"`
}

// Schema is the JSON representation of a particular schema
// (provider configuration, resources, data sources).
type Schema struct {
	// The version of the particular resource schema.
	Version uint64 `json:"version"`

	// The root-level block of configuration values.
	Block *SchemaBlock `json:"block,omitempty"`
}

// SchemaDescriptionKind describes the format type for a particular description's field.
type SchemaDescriptionKind string

const (
	// SchemaDescriptionKindPlain indicates a string in plain text format.
	SchemaDescriptionKindPlain SchemaDescriptionKind = "plaintext"

	// SchemaDescriptionKindMarkdown indicates a Markdown string and may need to be
	// processed prior to presentation.
	SchemaDescriptionKindMarkdown SchemaDescriptionKind = "markdown"
)

// SchemaBlock represents a nested block within a particular schema.
type SchemaBlock struct {
	// The attributes defined at the particular level of this block.
	Attributes map[string]*SchemaAttribute `json:"attributes,omitempty"`

	// Any nested blocks within this particular block.
	NestedBlocks map[string]*SchemaBlockType `json:"block_types,omitempty"`

	// The description for this block and format of the description. If
	// no kind is provided, it can be assumed to be plain text.
	Description     string                `json:"description,omitempty"`
	DescriptionKind SchemaDescriptionKind `json:"description_kind,omitempty"`

	// If true, this block is deprecated.
	Deprecated bool `json:"deprecated,omitempty"`
}

// SchemaNestingMode is the nesting mode for a particular nested
// schema block.
type SchemaNestingMode string

const (
	// SchemaNestingModeSingle denotes single block nesting mode, which
	// allows a single block of this specific type only in
	// configuration. This is generally the same as list or set types
	// with a single-element constraint.
	SchemaNestingModeSingle SchemaNestingMode = "single"

	// SchemaNestingModeList denotes list block nesting mode, which
	// allows an ordered list of blocks where duplicates are allowed.
	SchemaNestingModeList SchemaNestingMode = "list"

	// SchemaNestingModeSet denotes set block nesting mode, which
	// allows an unordered list of blocks where duplicates are
	// generally not allowed. What is considered a duplicate is up to
	// the rules of the set itself, which may or may not cover all
	// fields in the block.
	SchemaNestingModeSet SchemaNestingMode = "set"

	// SchemaNestingModeMap denotes map block nesting mode. This
	// creates a map of all declared blocks of the block type within
	// the parent, keying them on the label supplied in the block
	// declaration. This allows for blocks to be declared in the same
	// style as resources.
	SchemaNestingModeMap SchemaNestingMode = "map"
)

// SchemaBlockType describes a nested block within a schema.
type SchemaBlockType struct {
	// The nesting mode for this block.
	NestingMode SchemaNestingMode `json:"nesting_mode,omitempty"`

	// The block data for this block type, including attributes and
	// subsequent nested blocks.
	Block *SchemaBlock `json:"block,omitempty"`

	// The lower limit on items that can be declared of this block
	// type.
	MinItems uint64 `json:"min_items,omitempty"`

	// The upper limit on items that can be declared of this block
	// type.
	MaxItems uint64 `json:"max_items,omitempty"`
}

// SchemaAttribute describes an attribute within a schema block.
type SchemaAttribute struct {
	// The attribute type.
	AttributeType cty.Type `json:"type,omitempty"`

	// The description field for this attribute. If no kind is
	// provided, it can be assumed to be plain text.
	Description     string                `json:"description,omitempty"`
	DescriptionKind SchemaDescriptionKind `json:"description_kind,omitempty"`

	// If true, this attribute is deprecated.
	Deprecated bool `json:"deprecated,omitempty"`

	// If true, this attribute is required - it has to be entered in
	// configuration.
	Required bool `json:"required,omitempty"`

	// If true, this attribute is optional - it does not need to be
	// entered in configuration.
	Optional bool `json:"optional,omitempty"`

	// If true, this attribute is computed - it can be set by the
	// provider. It may also be set by configuration if Optional is
	// true.
	Computed bool `json:"computed,omitempty"`

	// If true, this attribute is sensitive and will not be displayed
	// in logs. Future versions of Terraform may encrypt or otherwise
	// treat these values with greater care than non-sensitive fields.
	Sensitive bool `json:"sensitive,omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/topher200/baseutil"
)

type criterionCalculationFunction func(teams []Team) Score
type PlayerFilter func(player Player) bool
type criterion struct {
	name      string                       // human readable name
	calculate criterionCalculationFunction // how to calculate the raw score
	filter    PlayerFilter                 // cull down to players that match
	weight    int                          // how much weight to give this score
}

var criteriaToScore = [...]criterion{
	criterion{"number of players", playerCountDifference, nil, 10},
	criterion{"number of males", playerCountDifference, IsMale, 9},
	criterion{"number of females", playerCountDifference, IsFemale, 9},
}

func playerCountDifference(teams []Team) Score {
	teamLengths := make([]int, numTeams)
	for i, team := range teams {
		teamLengths[i] = len(team.players)
	}
	return Score(baseutil.StandardDeviationInt(teamLengths))
}

func AverageRating(team Team) Score {
	sum := float32(0.0)
	for _, player := range team.players {
		sum += player.rating
	}
	return Score(sum / float32(len(team.players)))
}

func Filter(players []Player, filter PlayerFilter) (filteredPlayers []Player) {
	for _, player := range players {
		if filter == nil || filter(player) {
			filteredPlayers = append(filteredPlayers, player)
		}
	}
	return
}

// runCriterion by filtering the input teams and running the criterion function
func runCriterion(
	c criterion, teams []Team) (rawScore Score, weightedScore Score) {
	filteredTeams := make([]Team, len(teams))
	for i, _ := range teams {
		filteredTeams[i].players = Filter(teams[i].players, c.filter)
	}

	rawScore = c.calculate(filteredTeams)
	weightedScore = Score(float64(rawScore) * float64(c.weight))
	return rawScore, weightedScore
}

// Score a solution based on all known criteria.
func ScoreSolution(players []Player) (totalScore Score) {
	teams := splitIntoTeams(players)
	for _, criterion := range criteriaToScore {
		_, weightedScore := runCriterion(criterion, teams)
		totalScore += weightedScore
	}
	return totalScore
}

func PrintSolutionScoring(solution Solution) {
	teams := splitIntoTeams(solution.players)
	totalScore := Score(0)
	for _, criterion := range criteriaToScore {
		rawScore, weightedScore := runCriterion(criterion, teams)
		totalScore += weightedScore
		log.Printf(
			"Balancing %s. Raw score %f, weighted score %f. Running total: %f\n",
			criterion.name, rawScore, weightedScore, totalScore)
	}
}
<commit_msg>add ratingDifference criterion<commit_after>package main

import (
	"log"

	"github.com/GaryBoone/GoStats/stats"
	"github.com/topher200/baseutil"
)

type criterionCalculationFunction func(teams []Team) Score
type PlayerFilter func(player Player) bool
type criterion struct {
	name      string                       // human readable name
	calculate criterionCalculationFunction // how to calculate the raw score
	filter    PlayerFilter                 // cull down to players that match
	weight    int                          // how much weight to give this score
}

var criteriaToScore = [...]criterion{
	criterion{"number of players", playerCountDifference, nil, 10},
	criterion{"number of males", playerCountDifference, IsMale, 9},
	criterion{"number of females", playerCountDifference, IsFemale, 9},
	criterion{"average rating", ratingDifference, nil, 8},
}

func playerCountDifference(teams []Team) Score {
	teamLengths := make([]int, numTeams)
	for i, team := range teams {
		teamLengths[i] = len(team.players)
	}
	return Score(baseutil.StandardDeviationInt(teamLengths))
}

func ratingDifference(teams []Team) Score {
	teamAverageRatings := make([]float64, numTeams)
	for i, team := range teams {
		teamAverageRatings[i] = float64(AverageRating(team))
	}
	return Score(stats.StatsSampleStandardDeviation(teamAverageRatings))
}

func AverageRating(team Team) Score {
	sum := float32(0.0)
	for _, player := range team.players {
		sum += player.rating
	}
	return Score(sum / float32(len(team.players)))
}

func Filter(players []Player, filter PlayerFilter) (filteredPlayers []Player) {
	for _, player := range players {
		if filter == nil || filter(player) {
			filteredPlayers = append(filteredPlayers, player)
		}
	}
	return
}

// runCriterion by filtering the input teams and running the criterion function
func runCriterion(
	c criterion, teams []Team) (rawScore Score, weightedScore Score) {
	filteredTeams := make([]Team, len(teams))
	for i, _ := range teams {
		filteredTeams[i].players = Filter(teams[i].players, c.filter)
	}

	rawScore = c.calculate(filteredTeams)
	weightedScore = Score(float64(rawScore) * float64(c.weight))
	return rawScore, weightedScore
}

// Score a solution based on all known criteria.
func ScoreSolution(players []Player) (totalScore Score) {
	teams := splitIntoTeams(players)
	for _, criterion := range criteriaToScore {
		_, weightedScore := runCriterion(criterion, teams)
		totalScore += weightedScore
	}
	return totalScore
}

func PrintSolutionScoring(solution Solution) {
	teams := splitIntoTeams(solution.players)
	totalScore := Score(0)
	for _, criterion := range criteriaToScore {
		rawScore, weightedScore := runCriterion(criterion, teams)
		totalScore += weightedScore
		log.Printf(
			"Balancing %s. Raw score %f, weighted score %f. Running total: %f\n",
			criterion.name, rawScore, weightedScore, totalScore)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
)

func parseNumber(s string) float64 {
	var value float64
	fmt.Sscanf(s, "%f", &value)
	return value
}

const (
	Lakh  = 100000.0
	Crore = 10000000.0
)

type InrAmount struct {
	Value float64
}

const (
	Million  = 1000000.0
	Billion  = 1000000000.0
	Trillion = 1000000000000.0
)

type UsdAmount struct {
	Value float64
}

type Amount interface {
	Convert(usdToInr float64) Amount
	FormatValue() string
}

func NewInrAmount(s string) *InrAmount {
	units := regexp.MustCompile(`lakh|crore`)
	unit := units.FindString(s)
	number := parseNumber(s)

	switch unit {
	case "lakh":
		return &InrAmount{Value: number * Lakh}
	case "crore":
		return &InrAmount{Value: number * Crore}
	default:
		return &InrAmount{Value: number}
	}
}

func (amount *InrAmount) Convert(usdToInr float64) Amount {
	return &UsdAmount{Value: amount.Value / usdToInr}
}

func (amount *InrAmount) FormatValue() string {
	if v := amount.Value / Crore; v >= 1.0 {
		return fmt.Sprintf("₹ %.1f crore", v)
	} else if v := amount.Value / Lakh; v >= 1.0 {
		return fmt.Sprintf("₹ %.1f lakh", v)
	} else {
		return fmt.Sprintf("₹ %.1f", amount.Value)
	}
}

func NewUsdAmount(s string) *UsdAmount {
	units := regexp.MustCompile("million|billion|trillion")
	unit := units.FindString(s)
	number := parseNumber(s)

	switch unit {
	case "million":
		return &UsdAmount{Value: number * Million}
	case "billion":
		return &UsdAmount{Value: number * Billion}
	case "trillion":
		return &UsdAmount{Value: number * Trillion}
	default:
		return &UsdAmount{Value: number}
	}
}

func (amount *UsdAmount) Convert(usdToInr float64) Amount {
	return &InrAmount{Value: amount.Value * usdToInr}
}

func (amount *UsdAmount) FormatValue() string {
	if v := amount.Value / Trillion; v >= 1.0 {
		return fmt.Sprintf("$ %.1f trillion", v)
	} else if v := amount.Value / Billion; v >= 1.0 {
		return fmt.Sprintf("$ %.1f billion", v)
	} else if v := amount.Value / Million; v >= 1.0 {
		return fmt.Sprintf("$ %.1f million", v)
	} else {
		return fmt.Sprintf("$ %.1f", amount.Value)
	}
}

var inrSignifiers = regexp.MustCompile(`lakh|crore|arab|rs|inr|₹|rupee`)
var usdSignifiers = regexp.MustCompile(`million|billion|trillion|\$|usd|dollar`)

func parseAmount(s string) (Amount, error) {
	if inrSignifiers.MatchString(s) {
		return NewInrAmount(s), nil
	} else if usdSignifiers.MatchString(s) {
		return NewUsdAmount(s), nil
	} else {
		return nil, errors.New("no currency recognized")
	}
}

type FixerResponse struct {
	Rates map[string]float64 `json:"rates"`
}

func getUsdToInr() (float64, error) {
	r, err := http.Get("http://api.fixer.io/latest?base=USD")
	if err != nil {
		return 0, err
	}
	defer r.Body.Close()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return 0, err
	}

	var response FixerResponse
	if err = json.Unmarshal(body, &response); err != nil {
		return 0, err
	}

	return response.Rates["INR"], nil
}

func main() {
	input := strings.Join(os.Args[1:], " ")
	amount, err := parseAmount(input)
	if err != nil {
		fmt.Println(err.Error())
	}

	usdToInr, err := getUsdToInr()
	if err != nil {
		fmt.Println(err.Error())
	}

	fmt.Println(amount.Convert(usdToInr).FormatValue())
}
<commit_msg>Use a default rate if fixer.io is unavailable<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
)

func parseNumber(s string) float64 {
	var value float64
	fmt.Sscanf(s, "%f", &value)
	return value
}

const (
	Lakh  = 100000.0
	Crore = 10000000.0
)

type InrAmount struct {
	Value float64
}

const (
	Million  = 1000000.0
	Billion  = 1000000000.0
	Trillion = 1000000000000.0
)

type UsdAmount struct {
	Value float64
}

type Amount interface {
	Convert(usdToInr float64) Amount
	FormatValue() string
}

func NewInrAmount(s string) *InrAmount {
	units := regexp.MustCompile(`lakh|crore`)
	unit := units.FindString(s)
	number := parseNumber(s)

	switch unit {
	case "lakh":
		return &InrAmount{Value: number * Lakh}
	case "crore":
		return &InrAmount{Value: number * Crore}
	default:
		return &InrAmount{Value: number}
	}
}

func (amount *InrAmount) Convert(usdToInr float64) Amount {
	return &UsdAmount{Value: amount.Value / usdToInr}
}

func (amount *InrAmount) FormatValue() string {
	if v := amount.Value / Crore; v >= 1.0 {
		return fmt.Sprintf("₹ %.1f crore", v)
	} else if v := amount.Value / Lakh; v >= 1.0 {
		return fmt.Sprintf("₹ %.1f lakh", v)
	} else {
		return fmt.Sprintf("₹ %.1f", amount.Value)
	}
}

func NewUsdAmount(s string) *UsdAmount {
	units := regexp.MustCompile("million|billion|trillion")
	unit := units.FindString(s)
	number := parseNumber(s)

	switch unit {
	case "million":
		return &UsdAmount{Value: number * Million}
	case "billion":
		return &UsdAmount{Value: number * Billion}
	case "trillion":
		return &UsdAmount{Value: number * Trillion}
	default:
		return &UsdAmount{Value: number}
	}
}

func (amount *UsdAmount) Convert(usdToInr float64) Amount {
	return &InrAmount{Value: amount.Value * usdToInr}
}

func (amount *UsdAmount) FormatValue() string {
	if v := amount.Value / Trillion; v >= 1.0 {
		return fmt.Sprintf("$ %.1f trillion", v)
	} else if v := amount.Value / Billion; v >= 1.0 {
		return fmt.Sprintf("$ %.1f billion", v)
	} else if v := amount.Value / Million; v >= 1.0 {
		return fmt.Sprintf("$ %.1f million", v)
	} else {
		return fmt.Sprintf("$ %.1f", amount.Value)
	}
}

var inrSignifiers = regexp.MustCompile(`lakh|crore|arab|rs|inr|₹|rupee`)
var usdSignifiers = regexp.MustCompile(`million|billion|trillion|\$|usd|dollar`)

func parseAmount(s string) (Amount, error) {
	if inrSignifiers.MatchString(s) {
		return NewInrAmount(s), nil
	} else if usdSignifiers.MatchString(s) {
		return NewUsdAmount(s), nil
	} else {
		return nil, errors.New("no currency recognized")
	}
}

type FixerResponse struct {
	Rates map[string]float64 `json:"rates"`
}

func getUsdToInr() float64 {
	defaultRate := 62.0

	r, err := http.Get("http://api.fixer.io/latest?base=USD")
	if err != nil {
		return defaultRate
	}
	defer r.Body.Close()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return defaultRate
	}

	var response FixerResponse
	if err = json.Unmarshal(body, &response); err != nil {
		return defaultRate
	}

	return response.Rates["INR"]
}

func main() {
	input := strings.Join(os.Args[1:], " ")
	amount, err := parseAmount(input)
	if err != nil {
		fmt.Println(err.Error())
	}

	fmt.Println(amount.Convert(getUsdToInr()).FormatValue())
}
<|endoftext|>


<commit_before>// Package month provides functionality, pertaining to months of the year, that
// is not available in standard Go libraries. Examples of this include the
// ability to return the last day of any given month.
package month

import "math"

// Month represents a standard calendar month, applicable to integer format.
type Month int

// Standard calendar months.
const (
	January = 1 + iota
	February
	March
	April
	May
	June
	July
	August
	September
	October
	November
	December
)

var monthNames = [12]string{
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December",
}

var monthDays = map[int]int{
	1:  31,
	3:  31,
	4:  30,
	5:  31,
	6:  30,
	7:  31,
	8:  31,
	9:  30,
	10: 31,
	11: 30,
	12: 31,
}

// String returns an English language based representation of m. E.g., January,
// February, etc.
func (m Month) String() string {

	return monthNames[m-1]
}

// LastDay returns the last day of m, based on year. The function takes into
// account leap years.
func (m Month) LastDay(year uint16) int {

	if m == 2 {
		isLeapYear := math.Mod(float64(year), 4) == 0
		if isLeapYear {
			return 29
		}
		return 28
	}
	return monthDays[int(m)]
}
<commit_msg>Fixed leap year computation<commit_after>// Package month provides functionality, pertaining to months of the year, that
// is not available in standard Go libraries. Examples of this include the
// ability to return the last day of any given month.
package month

import "math"

// Month represents a standard calendar month, applicable to integer format.
type Month int

// Standard calendar months.
const (
	January = 1 + iota
	February
	March
	April
	May
	June
	July
	August
	September
	October
	November
	December
)

var monthNames = [12]string{
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December",
}

var monthDays = map[int]int{
	1:  31,
	3:  31,
	4:  30,
	5:  31,
	6:  30,
	7:  31,
	8:  31,
	9:  30,
	10: 31,
	11: 30,
	12: 31,
}

// String returns an English language based representation of m. E.g., January,
// February, etc.
func (m Month) String() string {

	return monthNames[m-1]
}

// LastDay returns the last day of m, based on year. The function takes into
// account leap years.
func (m Month) LastDay(year uint16) int {

	if m == 2 {
		y := float64(year)

		isLeapYear := math.Mod(y, 4) == 0 &&
			(math.Mod(y, 100) != 0 || math.Mod(y, 400) == 0)

		if isLeapYear {
			return 29
		}
		return 28
	}
	return monthDays[int(m)]
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"

	"github.com/golang/glog"
	"github.com/google/mtail/metrics"
	"github.com/google/mtail/tailer"
	"github.com/google/mtail/vm"
	"github.com/google/mtail/watcher"
	"github.com/jaqx0r/afero"

	_ "net/http/pprof"
)

var (
	port  *string = flag.String("port", "3903", "HTTP port to listen on.")
	logs  *string = flag.String("logs", "", "List of files to monitor.")
	progs *string = flag.String("progs", "", "Directory containing programs")

	one_shot *bool = flag.Bool("one_shot", false, "Run once on a log file, dump json, and exit.")
)

type mtail struct {
	lines chan string   // Channel of lines from tailer to VM engine.
	store metrics.Store // Metrics storage.

	t *tailer.Tailer // t tails the watched files and feeds lines to the VM.

	webquit   chan struct{} // Channel to signal shutdown from web UI.
	closeOnce sync.Once     // Ensure shutdown happens only once.
}

func (m *mtail) OneShot(logfile string, lines chan string) error {
	defer m.Close()
	l, err := os.Open(logfile)
	if err != nil {
		return fmt.Errorf("Failed to open log file %q: %s", logfile, err)
	}
	defer l.Close()

	r := bufio.NewReader(l)

	for {
		line, err := r.ReadString('\n')
		switch {
		case err == io.EOF:
			return nil
		case err != nil:
			return fmt.Errorf("Failed to read from %q: %s", logfile, err)
		default:
			lines <- line
		}
	}
}

func (m *mtail) StartTailing(pathnames []string) {
	tw, err := watcher.NewLogWatcher()
	if err != nil {
		glog.Fatal("Couldn't create log path watcher:", err)
	}
	m.t = tailer.New(m.lines, tw, &afero.OsFs{})
	if m.t == nil {
		glog.Fatal("Couldn't create a log tailer.")
	}

	for _, pathname := range pathnames {
		m.t.Tail(pathname)
	}
}

func (m *mtail) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte(`<a href="/json">json</a>, <a href="/metrics">prometheus metrics</a>`))
}

func NewMtail() *mtail {
	return &mtail{
		lines:   make(chan string),
		webquit: make(chan struct{}),
	}
}

func (m *mtail) Serve() {

	if *progs == "" {
		glog.Fatalf("No mtail program directory specified; use -progs")
	}
	if *logs == "" {
		glog.Fatalf("No logs specified to tail; use -logs")
	}

	w, err := watcher.NewLogWatcher()
	if err != nil {
		glog.Fatal("Couldn't create an inotify watcher:", err)
	}

	p := vm.NewLoader(w, &m.store)
	if p == nil {
		glog.Fatal("Couldn't create a program loader.")
	}
	e, errors := p.LoadProgs(*progs)

	if *vm.Compile_only || *vm.Dump_bytecode {
		os.Exit(errors)
	}

	var pathnames []string
	for _, pathname := range strings.Split(*logs, ",") {
		if pathname != "" {
			pathnames = append(pathnames, pathname)
		}
	}
	if len(pathnames) == 0 {
		glog.Fatal("No logs to tail.")
	}

	go e.Run(m.lines)
	ex := &Exporter{m.store}

	if *one_shot {
		for _, pathname := range pathnames {
			err := m.OneShot(pathname, m.lines)
			if err != nil {
				glog.Fatalf("Failed one shot mode for %q: %s\n", pathname, err)
			}
		}
		b, err := json.MarshalIndent(m.store.Metrics, "", "  ")
		if err != nil {
			glog.Fatalf("Failed to marshal metrics into json: %s", err)
		}
		os.Stdout.Write(b)
		ex.WriteMetrics()
	} else {
		m.StartTailing(pathnames)

		http.Handle("/", m)
		http.HandleFunc("/json", http.HandlerFunc(ex.handleJson))
		http.HandleFunc("/metrics", http.HandlerFunc(ex.handlePrometheusMetrics))
		http.HandleFunc("/quitquitquit", http.HandlerFunc(m.handleQuit))
		ex.StartMetricPush()

		go func() {
			err := http.ListenAndServe(":"+*port, nil)
			if err != nil {
				glog.Fatal(err)
			}
		}()
		m.shutdownHandler()
	}
}

func (m *mtail) handleQuit(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Header().Add("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	fmt.Fprintf(w, "Exiting...")
	close(m.webquit)
}

// shutdownHandler handles external shutdown request events.
func (m *mtail) shutdownHandler() {
	n := make(chan os.Signal)
	signal.Notify(n, os.Interrupt, syscall.SIGTERM)
	select {
	case <-n:
		glog.Info("Received SIGTERM, exiting...")
	case <-m.webquit:
		glog.Info("Received Quit from UI, exiting...")
	}
	m.Close()
}

// Close handles the graceful shutdown of this mtail instance, ensuring that it only occurs once.
func (m *mtail) Close() {
	m.closeOnce.Do(func() {
		glog.Info("Shutdown requested.")
		if m.t != nil {
			m.t.Close()
		} else {
			close(m.lines)
		}
	})
}

func main() {
	flag.Parse()
	m := NewMtail()
	m.Serve()
}
<commit_msg>Factor out a method for starting up the program loader in the main object.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"

	"github.com/golang/glog"
	"github.com/google/mtail/metrics"
	"github.com/google/mtail/tailer"
	"github.com/google/mtail/vm"
	"github.com/google/mtail/watcher"
	"github.com/jaqx0r/afero"

	_ "net/http/pprof"
)

var (
	port  *string = flag.String("port", "3903", "HTTP port to listen on.")
	logs  *string = flag.String("logs", "", "List of files to monitor.")
	progs *string = flag.String("progs", "", "Directory containing programs")

	one_shot *bool = flag.Bool("one_shot", false, "Run once on a log file, dump json, and exit.")
)

type mtail struct {
	lines chan string   // Channel of lines from tailer to VM engine.
	store metrics.Store // Metrics storage.

	t *tailer.Tailer // t tails the watched files and feeds lines to the VMs.
	l *vm.Loader     // l loads programs and manages the VM lifecycle.

	webquit   chan struct{} // Channel to signal shutdown from web UI.
	closeOnce sync.Once     // Ensure shutdown happens only once.
}

func (m *mtail) OneShot(logfile string, lines chan string) error {
	defer m.Close()
	l, err := os.Open(logfile)
	if err != nil {
		return fmt.Errorf("Failed to open log file %q: %s", logfile, err)
	}
	defer l.Close()

	r := bufio.NewReader(l)

	for {
		line, err := r.ReadString('\n')
		switch {
		case err == io.EOF:
			return nil
		case err != nil:
			return fmt.Errorf("Failed to read from %q: %s", logfile, err)
		default:
			lines <- line
		}
	}
}

func (m *mtail) StartTailing(pathnames []string) {
	w, err := watcher.NewLogWatcher()
	if err != nil {
		glog.Fatal("Couldn't create log path watcher:", err)
	}
	m.t = tailer.New(m.lines, w, &afero.OsFs{})
	if m.t == nil {
		glog.Fatal("Couldn't create a log tailer.")
	}

	for _, pathname := range pathnames {
		m.t.Tail(pathname)
	}
}

func (m *mtail) InitLoader(path string) {
	w, err := watcher.NewLogWatcher()
	if err != nil {
		glog.Fatal("Couldn't create prog watcher:", err)
	}
	m.l = vm.NewLoader(w, &m.store)
	if m.l == nil {
		glog.Fatal("Couldn't create a program loader.")
	}
	e, errors := m.l.LoadProgs(path)
	if *vm.Compile_only || *vm.Dump_bytecode {
		os.Exit(errors)
	}

	go e.Run(m.lines)

}

func (m *mtail) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte(`<a href="/json">json</a>, <a href="/metrics">prometheus metrics</a>`))
}

func NewMtail() *mtail {
	return &mtail{
		lines:   make(chan string),
		webquit: make(chan struct{}),
	}
}

func (m *mtail) Serve() {
	if *progs == "" {
		glog.Fatalf("No mtail program directory specified; use -progs")
	}
	if *logs == "" {
		glog.Fatalf("No logs specified to tail; use -logs")
	}
	var pathnames []string
	for _, pathname := range strings.Split(*logs, ",") {
		if pathname != "" {
			pathnames = append(pathnames, pathname)
		}
	}
	if len(pathnames) == 0 {
		glog.Fatal("No logs to tail.")
	}

	m.InitLoader(*progs)

	ex := &Exporter{m.store}

	if *one_shot {
		for _, pathname := range pathnames {
			err := m.OneShot(pathname, m.lines)
			if err != nil {
				glog.Fatalf("Failed one shot mode for %q: %s\n", pathname, err)
			}
		}
		b, err := json.MarshalIndent(m.store.Metrics, "", "  ")
		if err != nil {
			glog.Fatalf("Failed to marshal metrics into json: %s", err)
		}
		os.Stdout.Write(b)
		ex.WriteMetrics()
	} else {
		m.StartTailing(pathnames)

		http.Handle("/", m)
		http.HandleFunc("/json", http.HandlerFunc(ex.handleJson))
		http.HandleFunc("/metrics", http.HandlerFunc(ex.handlePrometheusMetrics))
		http.HandleFunc("/quitquitquit", http.HandlerFunc(m.handleQuit))
		ex.StartMetricPush()

		go func() {
			err := http.ListenAndServe(":"+*port, nil)
			if err != nil {
				glog.Fatal(err)
			}
		}()
		m.shutdownHandler()
	}
}

func (m *mtail) handleQuit(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Header().Add("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	fmt.Fprintf(w, "Exiting...")
	close(m.webquit)
}

// shutdownHandler handles external shutdown request events.
func (m *mtail) shutdownHandler() {
	n := make(chan os.Signal)
	signal.Notify(n, os.Interrupt, syscall.SIGTERM)
	select {
	case <-n:
		glog.Info("Received SIGTERM, exiting...")
	case <-m.webquit:
		glog.Info("Received Quit from UI, exiting...")
	}
	m.Close()
}

// Close handles the graceful shutdown of this mtail instance, ensuring that it only occurs once.
func (m *mtail) Close() {
	m.closeOnce.Do(func() {
		glog.Info("Shutdown requested.")
		if m.t != nil {
			m.t.Close()
		} else {
			close(m.lines)
		}
	})
}

func main() {
	flag.Parse()
	m := NewMtail()
	m.Serve()
}
<|endoftext|>


<commit_before>package gorm

import (
	"fmt"

	"reflect"
)

type mysql struct{}

func (s *mysql) BinVar(i int) string {
	return "$$" // ?
}

func (s *mysql) SupportLastInsertId() bool {
	return true
}

func (d *mysql) SqlTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "int"
	case reflect.Int64, reflect.Uint64:
		return "bigint"
	case reflect.Float32, reflect.Float64:
		return "double"
	case reflect.String:
		if size > 0 && size < 65532 {
			return fmt.Sprintf("varchar(%d)", size)
		} else {
			return "longtext"
		}
	case reflect.Struct:
		if value.Type() == timeType {
			return "datetime"
		}
	default:
		if _, ok := value.Interface().([]byte); ok {
			if size > 0 && size < 65532 {
				return fmt.Sprintf("varbinary(%d)", size)
			} else {
				return "longblob"
			}
		}
	}
	panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", value.Type().Name(), value.Kind().String()))
}

func (s *mysql) PrimaryKeyTag(value reflect.Value, size int) string {
	suffix_str := " NOT NULL AUTO_INCREMENT PRIMARY KEY"
	switch value.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "int" + suffix_str
	case reflect.Int64, reflect.Uint64:
		return "bigint" + suffix_str
	default:
		panic("Invalid primary key type")
	}
}

func (s *mysql) ReturningStr(key string) string {
	return ""
}

func (s *mysql) Quote(key string) string {
	return fmt.Sprintf("`%s`", key)
}

func (s *mysql) HasTable(scope *Scope, tableName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM INFORMATION_SCHEMA.tables where table_name = %v", newScope.AddToVars(tableName)))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

func (s *mysql) HasColumn(scope *Scope, tableName string, columnName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM information_schema.columns WHERE table_name = %v AND column_name = %v",
		newScope.AddToVars(tableName),
		newScope.AddToVars(columnName),
	))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}
<commit_msg>Include table_schema when query from INFORMATION_SCHEMA for mysql<commit_after>package gorm

import (
	"fmt"
	"strings"

	"reflect"
)

type mysql struct{}

func (s *mysql) BinVar(i int) string {
	return "$$" // ?
}

func (s *mysql) SupportLastInsertId() bool {
	return true
}

func (d *mysql) SqlTag(value reflect.Value, size int) string {
	switch value.Kind() {
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "int"
	case reflect.Int64, reflect.Uint64:
		return "bigint"
	case reflect.Float32, reflect.Float64:
		return "double"
	case reflect.String:
		if size > 0 && size < 65532 {
			return fmt.Sprintf("varchar(%d)", size)
		} else {
			return "longtext"
		}
	case reflect.Struct:
		if value.Type() == timeType {
			return "datetime"
		}
	default:
		if _, ok := value.Interface().([]byte); ok {
			if size > 0 && size < 65532 {
				return fmt.Sprintf("varbinary(%d)", size)
			} else {
				return "longblob"
			}
		}
	}
	panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", value.Type().Name(), value.Kind().String()))
}

func (s *mysql) PrimaryKeyTag(value reflect.Value, size int) string {
	suffix_str := " NOT NULL AUTO_INCREMENT PRIMARY KEY"
	switch value.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
		return "int" + suffix_str
	case reflect.Int64, reflect.Uint64:
		return "bigint" + suffix_str
	default:
		panic("Invalid primary key type")
	}
}

func (s *mysql) ReturningStr(key string) string {
	return ""
}

func (s *mysql) Quote(key string) string {
	return fmt.Sprintf("`%s`", key)
}

func (s *mysql) databaseName(scope *Scope) string {
	from := strings.Index(scope.db.parent.source, "/") + 1
	to := strings.Index(scope.db.parent.source, "?")
	if to == -1 {
		to = len(scope.db.parent.source)
	}
	return scope.db.parent.source[from:to]
}

func (s *mysql) HasTable(scope *Scope, tableName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM INFORMATION_SCHEMA.tables where table_name = %v AND table_schema = %v",
		newScope.AddToVars(tableName),
		newScope.AddToVars(s.databaseName(scope))))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}

func (s *mysql) HasColumn(scope *Scope, tableName string, columnName string) bool {
	var count int
	newScope := scope.New(nil)
	newScope.Raw(fmt.Sprintf("SELECT count(*) FROM information_schema.columns WHERE table_schema = %v AND table_name = %v AND column_name = %v",
		newScope.AddToVars(s.databaseName(scope)),
		newScope.AddToVars(tableName),
		newScope.AddToVars(columnName),
	))
	newScope.DB().QueryRow(newScope.Sql, newScope.SqlVars...).Scan(&count)
	return count > 0
}
<|endoftext|>


<commit_before>package yiigo

import (
	"fmt"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var dbmap map[string]*sqlx.DB

// SQL expression
type expr struct {
	expr string
	args []interface{}
}

type grammar struct {
	table   string
	columns []string
	clauses []string
	binds   []interface{}
}

type MySQL struct {
	db      *sqlx.DB
	tx      *sqlx.Tx
	grammar *grammar
	sql     string
}

// initMySQL init db connections
func initMySQL() error {
	dbmap = make(map[string]*sqlx.DB)

	sections := childSections("mysql")

	for _, v := range sections {
		host := v.Key("host").MustString("localhost")
		port := v.Key("post").MustInt(3306)
		username := v.Key("username").MustString("root")
		password := v.Key("password").MustString("")
		database := v.Key("database").MustString("test")
		charset := v.Key("charset").MustString("utf8mb4")
		collection := v.Key("collection").MustString("utf8mb4_general_ci")

		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

		db, err := sqlx.Open("mysql", dsn)

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

		db.SetMaxOpenConns(EnvInt(k, "maxOpenConns", 20))
		db.SetMaxIdleConns(EnvInt(k, "maxIdleConns", 10))

		err = db.Ping()

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

		dbmap[v.Name()] = db
	}

	return nil
}

// DB get a db connection
func DB(connection ...string) (*MySQL, error) {
	conn := "default"

	if len(connection) > 0 {
		conn = connection[0]
	}

	db, ok := dbmap[fmt.Sprintf("mysql.%s", conn)]

	if !ok {
		return nil, fmt.Errorf("database %s is not connected", conn)
	}

	return &MySQL{
		db:      db,
		grammar: &grammar{},
	}, nil
}

// Expr build sql expression, eg: yiigo.Expr("price * ? + ?", 2, 100)
func Expr(expression string, args ...interface{}) *expr {
	return &expr{expr: expression, args: args}
}

func (m *MySQL) Table(table string) *MySQL {
	m.grammar.table = table
	return m
}

func (m *MySQL) Select(columns ...string) *MySQL {
	m.grammar.columns = columns
	return m
}

func (m *MySQL) InnerJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("INNER JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) LeftJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("LEFT JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) RightJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("RIGHT JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Where(where string) *MySQL {
	clause := fmt.Sprintf("WHERE %s", where)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) GroupBy(group string) *MySQL {
	clause := fmt.Sprintf("GROUP BY %s", group)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Having(having string) *MySQL {
	clause := fmt.Sprintf("HAVING %s", having)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) OrderBy(order string) *MySQL {
	clause := fmt.Sprintf("ORDER BY %s", order)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Limit(limit int) *MySQL {
	clause := fmt.Sprintf("LIMIT %d", limit)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Offset(offset int) *MySQL {
	join := fmt.Sprintf("OFFSET %d", offset)
	m.grammar.clauses = append(m.grammar.clauses, join)

	return m
}

func (m *MySQL) Insert(data X) {
	defer m.reset(false)

	columns := []string{}
	placeholders := []string{}
	binds := []interface{}{}

	for k, v := range data {
		columns = append(columns, k)
		placeholders = append(placeholders, "?")
		binds = append(binds, v)
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", m.table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	result, err := m.db.Exec(sql, binds...)

	if err != nil {
		m.Error = fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
		return
	}

	id, err := result.LastInsertId()

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, args: %v", err, sql, binds)
	}

	return id, nil
}

// BuildInsert build insert sql
func BuildInsert(table string, data X) (string, []interface{}) {
	columns := []string{}
	placeholders := []string{}
	binds := []interface{}{}

	for k, v := range data {
		columns = append(columns, k)
		placeholders = append(placeholders, "?")
		binds = append(binds, v)
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// BuildBatchInsert build batch insert sql
func BuildBatchInsert(table string, columns []string, data X) (string, []interface{}) {
	placeholders := []string{}
	binds := []interface{}{}

	for _, v := range data {
		bindvars := []string{}

		for _, c := range columns {
			binds = append(binds, v[c])
			bindvars = append(bindvars, "?")
		}

		placeholders = append(placeholders, fmt.Sprintf("(%s)", strings.Join(bindvars, ",")))
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// BuildUpdate build update sql
func BuildUpdate(table string, data X, condition ...interface{}) (string, []interface{}) {
	clauses := []string{}
	sets := []string{}
	binds := []interface{}{}

	clauses = append(clauses, fmt.Sprintf("UPDATE %s", table))

	for k, v := range data {
		if expr, ok := v.(*expr); ok {
			sets = append(sets, fmt.Sprintf("%s = %s", k, expr.expr))
			binds = append(binds, expr.args...)
		} else {
			sets = append(sets, fmt.Sprintf("%s = ?", k))
			binds = append(binds, v)
		}
	}

	clauses = append(clauses, fmt.Sprintf("SET %s", strings.Join(sets, ",")))

	length := len(condition)

	if length > 0 {
		clauses = append(clauses, fmt.Sprintf("WHERE %s", condition[0].(string)))
	}

	if length > 1 {
		binds = append(binds, condition[1:]...)
	}

	sql := strings.Join(clauses, " ")

	return sql, binds
}

func (m *MySQL) reset(tx bool) {
	if tx {
		m.tx = nil
	}

	m.grammar = &grammar{}
	m.sql = ""
}
<commit_msg>update<commit_after>package yiigo

import (
	"errors"
	"fmt"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var dbmap map[string]*sqlx.DB

// SQL expression
type expr struct {
	expr string
	args []interface{}
}

type grammar struct {
	table   string
	columns []string
	clauses []string
	binds   []interface{}
}

type MySQL struct {
	db      *sqlx.DB
	tx      *sqlx.Tx
	grammar *grammar
	sql     string
}

// initMySQL init db connections
func initMySQL() error {
	dbmap = make(map[string]*sqlx.DB)

	sections := childSections("mysql")

	for _, v := range sections {
		host := v.Key("host").MustString("localhost")
		port := v.Key("post").MustInt(3306)
		username := v.Key("username").MustString("root")
		password := v.Key("password").MustString("")
		database := v.Key("database").MustString("test")
		charset := v.Key("charset").MustString("utf8mb4")
		collection := v.Key("collection").MustString("utf8mb4_general_ci")

		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

		db, err := sqlx.Open("mysql", dsn)

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

		db.SetMaxOpenConns(EnvInt(k, "maxOpenConns", 20))
		db.SetMaxIdleConns(EnvInt(k, "maxIdleConns", 10))

		err = db.Ping()

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

		dbmap[v.Name()] = db
	}

	return nil
}

// DB get a db connection
func DB(connection ...string) (*MySQL, error) {
	conn := "default"

	if len(connection) > 0 {
		conn = connection[0]
	}

	db, ok := dbmap[fmt.Sprintf("mysql.%s", conn)]

	if !ok {
		return nil, fmt.Errorf("database %s is not connected", conn)
	}

	return &MySQL{
		db:      db,
		grammar: &grammar{},
	}, nil
}

// Expr build sql expression, eg: yiigo.Expr("price * ? + ?", 2, 100)
func Expr(expression string, args ...interface{}) *expr {
	return &expr{expr: expression, args: args}
}

func (m *MySQL) Table(table string) *MySQL {
	m.grammar.table = table
	return m
}

func (m *MySQL) Select(columns ...string) *MySQL {
	m.grammar.columns = columns
	return m
}

func (m *MySQL) InnerJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("INNER JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) LeftJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("LEFT JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) RightJoin(table string, on string) *MySQL {
	clause := fmt.Sprintf("RIGHT JOIN %s ON %s", table, on)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Where(where string) *MySQL {
	clause := fmt.Sprintf("WHERE %s", where)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) GroupBy(group string) *MySQL {
	clause := fmt.Sprintf("GROUP BY %s", group)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Having(having string) *MySQL {
	clause := fmt.Sprintf("HAVING %s", having)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) OrderBy(order string) *MySQL {
	clause := fmt.Sprintf("ORDER BY %s", order)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Limit(limit int) *MySQL {
	clause := fmt.Sprintf("LIMIT %d", limit)
	m.grammar.clauses = append(m.grammar.clauses, clause)

	return m
}

func (m *MySQL) Offset(offset int) *MySQL {
	join := fmt.Sprintf("OFFSET %d", offset)
	m.grammar.clauses = append(m.grammar.clauses, join)

	return m
}

func (m *MySQL) Binds(binds ...interface{}) {
	m.grammar.binds = binds

	return m
}

func (m *MySQL) Insert(data X) (int64, error) {
	defer m.reset(false)

	columns := []string{}
	placeholders := []string{}
	binds := []interface{}{}

	for k, v := range data {
		columns = append(columns, k)
		placeholders = append(placeholders, "?")
		binds = append(binds, v)
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", m.grammar.table, strings.Join(columns, ", "), strings.Join(placeholders, ","))

	result, err := m.db.Exec(sql, binds...)

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	id, err := result.LastInsertId()

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	return id, nil
}

func (m *MySQL) BatchInsert(columns []string, data []X) (int64, error) {
	defer m.reset(false)

	placeholders := []string{}
	binds := []interface{}{}

	for _, v := range data {
		bindvars := []string{}

		for _, c := range columns {
			binds = append(binds, v[c])
			bindvars = append(bindvars, "?")
		}

		placeholders = append(placeholders, fmt.Sprintf("(%s)", strings.Join(bindvars, ",")))
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", m.grammar.table, strings.Join(columns, ", "), strings.Join(placeholders, ","))

	result, err := m.db.Exec(sql, binds...)

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	rows, err := result.RowsAffected()

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	return rows, nil
}

func (m *MySQL) Update(data X) (int64, error) {
	defer m.reset(false)

	sets := []string{}
	binds := []interface{}{}

	for k, v := range data {
		if expr, ok := v.(*expr); ok {
			sets = append(sets, fmt.Sprintf("%s = %s", k, expr.expr))
			binds = append(binds, expr.args...)
		} else {
			sets = append(sets, fmt.Sprintf("%s = ?", k))
			binds = append(binds, v)
		}
	}

	binds = append(binds, m.grammar.binds...)

	sql := strings.TrimSpace(fmt.Sprintf("UPDATE %s SET %s %s", m.grammar.table, strings.Join(sets, ", "), strings.Join(m.grammar.clauses, " ")))

	_sql, args, err := sqlx.In(sql, binds...)

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	result, err := m.db.Exec(_sql, args...)

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, _sql, args)
	}

	rows, err := result.RowsAffected()

	if err != nil {
		return 0, fmt.Errorf("%v, SQL: %s, Args: %v", err, _sql, args)
	}

	return rows, nil
}

func (m *MySQL) One(dest interface{}) error {
	columns := "*"

	if len(m.grammar.columns) > 0 {
		columns = strings.Join(m.grammar.columns, ", ")
	}

	sql := strings.TrimSpace(fmt.Sprintf("SELECT %s FROM %s %s", columns, m.grammar.table, strings.Join(m.grammar.clauses, " ")))
	_sql, args, err := sqlx.In(sql, m.grammar.binds...)

	if err != nil {
		return fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	err = m.db.Get(dest, _sql, args...)

	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return errors.New("not found")
		}

		return fmt.Errorf("%v, SQL: %s, Args: %v", err, _sql, args)
	}

	return nil
}

func (m *MySQL) All(dest interface{}) error {
	columns := "*"

	if len(m.grammar.columns) > 0 {
		columns = strings.Join(m.grammar.columns, ", ")
	}

	sql := strings.TrimSpace(fmt.Sprintf("SELECT %s FROM %s %s", columns, m.grammar.table, strings.Join(m.grammar.clauses, " ")))
	_sql, args, err := sqlx.In(sql, m.grammar.binds...)

	if err != nil {
		return fmt.Errorf("%v, SQL: %s, Args: %v", err, sql, binds)
	}

	err = db.Get(dest, _sql, args...)

	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return errors.New("not found")
		}

		return fmt.Errorf("%v, SQL: %s, Args: %v", err, _sql, args)
	}

	return nil
}

func (m *MySQL) Delete() (int64, error) {

}

func (m *MySQL) reset(tx bool) {
	if tx {
		m.tx = nil
	}

	m.grammar = &grammar{}
	m.sql = ""
}
<|endoftext|>


<commit_before>// Package nexus is a client for Go code to pull data from a Sonatype Nexus instance. Nexus provides a REST API,
// although some information may require several calls to collate all the data. So this client provides some methods
// to abstract away the necessary plumbing.
package nexus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/hanjos/nexus/credentials"
	"github.com/hanjos/nexus/search"
)

// Client accesses a Nexus instance. The default Client should work for the newest Nexus versions. Older Nexus
// versions may need or benefit from a specific client.
type Client interface {
	// Returns all artifacts in this Nexus which satisfy the given criteria.
	Artifacts(criteria search.Criteria) ([]*Artifact, error)

	// Returns all repositories in this Nexus.
	Repositories() ([]*Repository, error)

	// Returns a Client which uses the given credentials to access this Nexus, without modifying the original client.
	// nil is understood to mean credentials.None.
	As(credentials credentials.Credentials) Client
}

// Nexus2x represents a Nexus v2.x instance. It's the default Client implementation.
type Nexus2x struct {
	Url string // e.g. http://nexus.somewhere.com:8080/nexus

	credentials.Credentials // e.g. BasicAuth{"username", "password"}
}

// New creates a new Nexus client, using the default Client implementation.
func New(url string, c credentials.Credentials) Client {
	return &Nexus2x{Url: url, Credentials: credentials.OrZero(c)}
}

// builds the proper URL with parameters for GET-ing.
func (nexus *Nexus2x) fullUrlFor(query string, filter map[string]string) string {
	params := []string{}

	for k, v := range filter {
		params = append(params, k+"="+v)
	}

	if len(params) == 0 {
		return nexus.Url + "/" + query
	} else {
		return nexus.Url + "/" + query + "?" + strings.Join(params, "&")
	}
}

// does the actual legwork, going to Nexus and validating the response.
func (nexus *Nexus2x) fetch(url string, params map[string]string) (*http.Response, error) {
	get, err := http.NewRequest("GET", nexus.fullUrlFor(url, params), nil)
	if err != nil {
		return nil, err
	}

	nexus.Credentials.Sign(get)
	get.Header.Add("Accept", "application/json")

	// go for it!
	response, err := http.DefaultClient.Do(get)
	if err != nil {
		return nil, err
	}

	// for us, 4xx are 5xx are errors, so we need to validate the response
	if 400 <= response.StatusCode && response.StatusCode < 600 {
		return response, &BadResponseError{Url: nexus.Url, StatusCode: response.StatusCode, Status: response.Status}
	}

	// everything alright, carry on
	return response, err
}

func bodyToBytes(body io.ReadCloser) ([]byte, error) {
	buf := new(bytes.Buffer)
	if _, err := buf.ReadFrom(body); err != nil {
		return nil, err
	}
	defer body.Close() // don't forget to Close() body at the end!

	return buf.Bytes(), nil
}

// As returns a copy of this client which uses the given credentials to access the same Nexus instance. Nil is
// understood to mean credentials.None.
func (nexus *Nexus2x) As(c credentials.Credentials) Client {
	return &Nexus2x{Url: nexus.Url, Credentials: credentials.OrZero(c)}
}

// Artifacts returns all artifacts in this Nexus which satisfy the given criteria. This implementation errors out on a
// full search (n.Artifacts(search.None)).
func (nexus *Nexus2x) Artifacts(criteria search.Criteria) ([]*Artifact, error) {
	params := criteria.Parameters()

	if len(params) == 0 {
		return nil, fmt.Errorf("Full search isn't supported!")
	}

	if len(params) == 1 {
		if repoId, ok := params["repositoryId"]; ok {
			return nexus.readArtifactsFrom(repoId)
		}
	}

	return nexus.readArtifactsWhere(params)
}

type artifactSearchResponse struct {
	TotalCount int
	Data       []struct {
		GroupId      string
		ArtifactId   string
		Version      string
		ArtifactHits []struct {
			ArtifactLinks []struct {
				Extension  string
				Classifier string
			}
		}
	}
}

func extractArtifactPayloadFrom(body []byte) (*artifactSearchResponse, error) {
	var payload *artifactSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractArtifactsFrom(payload *artifactSearchResponse) []*Artifact {
	var artifacts = []*Artifact{}

	for _, artifact := range payload.Data {
		g := artifact.GroupId
		a := artifact.ArtifactId
		v := artifact.Version

		for _, hit := range artifact.ArtifactHits {
			for _, link := range hit.ArtifactLinks {
				e := link.Extension
				c := link.Classifier

				artifacts = append(artifacts, &Artifact{g, a, v, c, e})
			}
		}
	}

	return artifacts
}

// returns all artifacts in this Nexus which pass the given filter. The expected keys in filter are the flags Nexus'
// REST API accepts, with the same semantics.
func (nexus *Nexus2x) readArtifactsWhere(filter map[string]string) ([]*Artifact, error) {
	// This implementation is slightly tricky. As artifactSearchResponse shows, Nexus always wraps the artifacts in a
	// GAV structure. This structure doesn't mean that within the wrapper are *all* the artifacts within that GAV, or
	// that the next page won't repeat artifacts if an incomplete GAV was returned earlier.
	//
	// On top of that, I haven't quite figured out how Nexus is counting artifacts for paging purposes. POMs don't
	// seem to count as artifacts, except when the project has a 'pom' packaging (which I can't know for sure without
	// GET-ing every POM), but the math still doesn't quite come together. So I took a conservative approach, which
	// forces a sequential algorithm. This search can be parallelized if the paging problem is solved.

	from := 0
	offset := 0
	started := false              // do-while can sometimes be useful
	artifacts := newArtifactSet() // acumulates the artifacts

	for offset != 0 || !started {
		started = true // do-while can sometimes be useful

		from = from + offset
		filter["from"] = strconv.Itoa(from)

		resp, err := nexus.fetch("service/local/lucene/search", filter)
		if err != nil {
			return nil, err
		}

		body, err := bodyToBytes(resp.Body)
		if err != nil {
			return nil, err
		}

		payload, err := extractArtifactPayloadFrom(body)
		if err != nil {
			return nil, err
		}

		// extract and store the artifacts. The set ensures we ignore repeated artifacts.
		artifacts.add(extractArtifactsFrom(payload))

		// a lower bound for the number of artifacts returned, since every GAV holds at least one artifact.
		// There will be some repetitions, but artifacts takes care of that.
		offset = len(payload.Data)
	}

	return artifacts.data, nil
}

// returns the first-level directories in the given repository.
func (nexus *Nexus2x) firstLevelDirsOf(repositoryId string) ([]string, error) {
	// XXX Don't forget the ending /, or the response is always XML!
	resp, err := nexus.fetch("service/local/repositories/"+repositoryId+"/content/", nil)
	if err != nil {
		return nil, err
	}

	// fill payload with the given response
	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	var payload *struct {
		Data []struct {
			Leaf bool
			Text string
		}
	}

	err = json.Unmarshal([]byte(body), &payload)
	if err != nil {
		return nil, err
	}

	// extract the directories from payload
	result := []string{}
	for _, dir := range payload.Data {
		if !dir.Leaf {
			result = append(result, dir.Text)
		}
	}

	return result, nil

}

// returns all artifacts in the given repository.
func (nexus *Nexus2x) readArtifactsFrom(repositoryId string) ([]*Artifact, error) {
	// This function also has some tricky details. In the olden days (around version 1.8 or so), one could get all the
	// artifacts in a given repository by searching for *. This has been disabled in the newer versions, without any
	// official alternative for "give me everything you have". So, the solution adopted here is:
	// 1) get the first level directories in repositoryId
	// 2) for every directory 'dir', do a search filtering for the groupId 'dir*' and the repository ID
	// 3) accumulate the results in an artifactSet to avoid duplicates (e.g. the results in common* appear also in com*)

	result := newArtifactSet()

	// 1)
	dirs, err := nexus.firstLevelDirsOf(repositoryId)
	if err != nil {
		return nil, err
	}

	// 2) these searches can be done concurrently :)
	artifacts := make(chan []*Artifact)
	errors := make(chan error)
	for _, dir := range dirs {
		go func(dir string) {
			a, err := nexus.readArtifactsWhere(map[string]string{"g": dir + "*", "repositoryId": repositoryId})
			if err != nil {
				errors <- err
				return
			}

			artifacts <- a
		}(dir)
	}

	// 3)
	for i := 0; i < len(dirs); i++ {
		select {
		case a := <-artifacts:
			result.add(a)
		case err := <-errors:
			return nil, err
		}
	}

	return result.data, nil
}

// Repositories

// Repositories returns all repositories in this Nexus.
func (nexus *Nexus2x) Repositories() ([]*Repository, error) {
	resp, err := nexus.fetch("service/local/repositories", nil)
	if err != nil {
		return nil, err
	}

	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	payload, err := extractRepoPayloadFrom(body)
	if err != nil {
		return nil, err
	}

	return extractReposFrom(payload), nil
}

type repoSearchResponse struct {
	Data []struct {
		Id         string
		Name       string
		RepoType   string
		RepoPolicy string
		Format     string
		RemoteUri  string
	}
}

func extractRepoPayloadFrom(body []byte) (*repoSearchResponse, error) {
	var payload *repoSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractReposFrom(payload *repoSearchResponse) []*Repository {
	result := []*Repository{}

	for _, repo := range payload.Data {
		newRepo := &Repository{
			Id:        repo.Id,
			Name:      repo.Name,
			Type:      repo.RepoType,
			Format:    repo.Format,
			Policy:    repo.RepoPolicy,
			RemoteURI: repo.RemoteUri,
		}

		result = append(result, newRepo)
	}

	return result
}
<commit_msg>Defining Nexus2x methods on the value, not the pointer.<commit_after>// Package nexus is a client for Go code to pull data from a Sonatype Nexus instance. Nexus provides a REST API,
// although some information may require several calls to collate all the data. So this client provides some methods
// to abstract away the necessary plumbing.
package nexus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/hanjos/nexus/credentials"
	"github.com/hanjos/nexus/search"
)

// Client accesses a Nexus instance. The default Client should work for the newest Nexus versions. Older Nexus
// versions may need or benefit from a specific client.
type Client interface {
	// Returns all artifacts in this Nexus which satisfy the given criteria.
	Artifacts(criteria search.Criteria) ([]*Artifact, error)

	// Returns all repositories in this Nexus.
	Repositories() ([]*Repository, error)

	// Returns a Client which uses the given credentials to access this Nexus, without modifying the original client.
	// nil is understood to mean credentials.None.
	As(credentials credentials.Credentials) Client
}

// Nexus2x represents a Nexus v2.x instance. It's the default Client implementation.
type Nexus2x struct {
	Url string // e.g. http://nexus.somewhere.com:8080/nexus

	credentials.Credentials // e.g. BasicAuth{"username", "password"}
}

// New creates a new Nexus client, using the default Client implementation.
func New(url string, c credentials.Credentials) Client {
	return &Nexus2x{Url: url, Credentials: credentials.OrZero(c)}
}

// builds the proper URL with parameters for GET-ing.
func (nexus Nexus2x) fullUrlFor(query string, filter map[string]string) string {
	params := []string{}

	for k, v := range filter {
		params = append(params, k+"="+v)
	}

	if len(params) == 0 {
		return nexus.Url + "/" + query
	} else {
		return nexus.Url + "/" + query + "?" + strings.Join(params, "&")
	}
}

// does the actual legwork, going to Nexus and validating the response.
func (nexus Nexus2x) fetch(url string, params map[string]string) (*http.Response, error) {
	get, err := http.NewRequest("GET", nexus.fullUrlFor(url, params), nil)
	if err != nil {
		return nil, err
	}

	nexus.Credentials.Sign(get)
	get.Header.Add("Accept", "application/json")

	// go for it!
	response, err := http.DefaultClient.Do(get)
	if err != nil {
		return nil, err
	}

	// for us, 4xx are 5xx are errors, so we need to validate the response
	if 400 <= response.StatusCode && response.StatusCode < 600 {
		return response, &BadResponseError{Url: nexus.Url, StatusCode: response.StatusCode, Status: response.Status}
	}

	// everything alright, carry on
	return response, err
}

func bodyToBytes(body io.ReadCloser) ([]byte, error) {
	buf := new(bytes.Buffer)
	if _, err := buf.ReadFrom(body); err != nil {
		return nil, err
	}
	defer body.Close() // don't forget to Close() body at the end!

	return buf.Bytes(), nil
}

// As returns a copy of this client which uses the given credentials to access the same Nexus instance. Nil is
// understood to mean credentials.None.
func (nexus Nexus2x) As(c credentials.Credentials) Client {
	return &Nexus2x{Url: nexus.Url, Credentials: credentials.OrZero(c)}
}

// Artifacts returns all artifacts in this Nexus which satisfy the given criteria. This implementation errors out on a
// full search (n.Artifacts(search.None)).
func (nexus Nexus2x) Artifacts(criteria search.Criteria) ([]*Artifact, error) {
	params := criteria.Parameters()

	if len(params) == 0 {
		return nil, fmt.Errorf("Full search isn't supported!")
	}

	if len(params) == 1 {
		if repoId, ok := params["repositoryId"]; ok {
			return nexus.readArtifactsFrom(repoId)
		}
	}

	return nexus.readArtifactsWhere(params)
}

type artifactSearchResponse struct {
	TotalCount int
	Data       []struct {
		GroupId      string
		ArtifactId   string
		Version      string
		ArtifactHits []struct {
			ArtifactLinks []struct {
				Extension  string
				Classifier string
			}
		}
	}
}

func extractArtifactPayloadFrom(body []byte) (*artifactSearchResponse, error) {
	var payload *artifactSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractArtifactsFrom(payload *artifactSearchResponse) []*Artifact {
	var artifacts = []*Artifact{}

	for _, artifact := range payload.Data {
		g := artifact.GroupId
		a := artifact.ArtifactId
		v := artifact.Version

		for _, hit := range artifact.ArtifactHits {
			for _, link := range hit.ArtifactLinks {
				e := link.Extension
				c := link.Classifier

				artifacts = append(artifacts, &Artifact{g, a, v, c, e})
			}
		}
	}

	return artifacts
}

// returns all artifacts in this Nexus which pass the given filter. The expected keys in filter are the flags Nexus'
// REST API accepts, with the same semantics.
func (nexus Nexus2x) readArtifactsWhere(filter map[string]string) ([]*Artifact, error) {
	// This implementation is slightly tricky. As artifactSearchResponse shows, Nexus always wraps the artifacts in a
	// GAV structure. This structure doesn't mean that within the wrapper are *all* the artifacts within that GAV, or
	// that the next page won't repeat artifacts if an incomplete GAV was returned earlier.
	//
	// On top of that, I haven't quite figured out how Nexus is counting artifacts for paging purposes. POMs don't
	// seem to count as artifacts, except when the project has a 'pom' packaging (which I can't know for sure without
	// GET-ing every POM), but the math still doesn't quite come together. So I took a conservative approach, which
	// forces a sequential algorithm. This search can be parallelized if the paging problem is solved.

	from := 0
	offset := 0
	started := false              // do-while can sometimes be useful
	artifacts := newArtifactSet() // acumulates the artifacts

	for offset != 0 || !started {
		started = true // do-while can sometimes be useful

		from = from + offset
		filter["from"] = strconv.Itoa(from)

		resp, err := nexus.fetch("service/local/lucene/search", filter)
		if err != nil {
			return nil, err
		}

		body, err := bodyToBytes(resp.Body)
		if err != nil {
			return nil, err
		}

		payload, err := extractArtifactPayloadFrom(body)
		if err != nil {
			return nil, err
		}

		// extract and store the artifacts. The set ensures we ignore repeated artifacts.
		artifacts.add(extractArtifactsFrom(payload))

		// a lower bound for the number of artifacts returned, since every GAV holds at least one artifact.
		// There will be some repetitions, but artifacts takes care of that.
		offset = len(payload.Data)
	}

	return artifacts.data, nil
}

// returns the first-level directories in the given repository.
func (nexus Nexus2x) firstLevelDirsOf(repositoryId string) ([]string, error) {
	// XXX Don't forget the ending /, or the response is always XML!
	resp, err := nexus.fetch("service/local/repositories/"+repositoryId+"/content/", nil)
	if err != nil {
		return nil, err
	}

	// fill payload with the given response
	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	var payload *struct {
		Data []struct {
			Leaf bool
			Text string
		}
	}

	err = json.Unmarshal([]byte(body), &payload)
	if err != nil {
		return nil, err
	}

	// extract the directories from payload
	result := []string{}
	for _, dir := range payload.Data {
		if !dir.Leaf {
			result = append(result, dir.Text)
		}
	}

	return result, nil

}

// returns all artifacts in the given repository.
func (nexus Nexus2x) readArtifactsFrom(repositoryId string) ([]*Artifact, error) {
	// This function also has some tricky details. In the olden days (around version 1.8 or so), one could get all the
	// artifacts in a given repository by searching for *. This has been disabled in the newer versions, without any
	// official alternative for "give me everything you have". So, the solution adopted here is:
	// 1) get the first level directories in repositoryId
	// 2) for every directory 'dir', do a search filtering for the groupId 'dir*' and the repository ID
	// 3) accumulate the results in an artifactSet to avoid duplicates (e.g. the results in common* appear also in com*)

	result := newArtifactSet()

	// 1)
	dirs, err := nexus.firstLevelDirsOf(repositoryId)
	if err != nil {
		return nil, err
	}

	// 2) these searches can be done concurrently :)
	artifacts := make(chan []*Artifact)
	errors := make(chan error)
	for _, dir := range dirs {
		go func(dir string) {
			a, err := nexus.readArtifactsWhere(map[string]string{"g": dir + "*", "repositoryId": repositoryId})
			if err != nil {
				errors <- err
				return
			}

			artifacts <- a
		}(dir)
	}

	// 3)
	for i := 0; i < len(dirs); i++ {
		select {
		case a := <-artifacts:
			result.add(a)
		case err := <-errors:
			return nil, err
		}
	}

	return result.data, nil
}

// Repositories

// Repositories returns all repositories in this Nexus.
func (nexus Nexus2x) Repositories() ([]*Repository, error) {
	resp, err := nexus.fetch("service/local/repositories", nil)
	if err != nil {
		return nil, err
	}

	body, err := bodyToBytes(resp.Body)
	if err != nil {
		return nil, err
	}

	payload, err := extractRepoPayloadFrom(body)
	if err != nil {
		return nil, err
	}

	return extractReposFrom(payload), nil
}

type repoSearchResponse struct {
	Data []struct {
		Id         string
		Name       string
		RepoType   string
		RepoPolicy string
		Format     string
		RemoteUri  string
	}
}

func extractRepoPayloadFrom(body []byte) (*repoSearchResponse, error) {
	var payload *repoSearchResponse

	err := json.Unmarshal(body, &payload)
	if err != nil {
		return nil, err
	}

	return payload, nil
}

func extractReposFrom(payload *repoSearchResponse) []*Repository {
	result := []*Repository{}

	for _, repo := range payload.Data {
		newRepo := &Repository{
			Id:        repo.Id,
			Name:      repo.Name,
			Type:      repo.RepoType,
			Format:    repo.Format,
			Policy:    repo.RepoPolicy,
			RemoteURI: repo.RemoteUri,
		}

		result = append(result, newRepo)
	}

	return result
}
<|endoftext|>