<commit_before>package video

import "image"

var color_channel = [12]int{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2}

type Macroblock struct {
	macroblock_address_increment int
	macroblock_type              *MacroblockType
	spatial_temporal_weight_code uint32
	frame_motion_type            uint32
	field_motion_type            uint32
	dct_type                     bool

	cpb int
}

func (br *VideoSequence) macroblock(
	// location
	mb_address, mb_row int,
	// dct predictors
	dcp *dcDctPredictors, resetDCPredictors dcDctPredictorResetter,
	mvd *motionVectorData,
	qsc *uint32,
	frameSlice *image.YCbCr) (int, error) {

	mb := Macroblock{}

	for {
		if nextbits, err := br.Peek32(11); err != nil {
			return 0, err
		} else if nextbits == 0x08 { // 0000 0001 000
			br.Trash(11)
			mb.macroblock_address_increment += 33
		} else {
			break
		}
	}

	if incr, err := macroblockAddressIncrementDecoder.Decode(br); err != nil {
		return 0, err
	} else {
		mb.macroblock_address_increment += incr
	}

	if br.PictureHeader.picture_coding_type == PFrame && mb.macroblock_address_increment > 1 {
		copy_macroblocks(mb_row, mb_address+1, mb.macroblock_address_increment-1, frameSlice, br.frameStore.past)
	}

	// Reset dcDctPredictors: whenever a macroblock is skipped. (7.2.1)
	if mb.macroblock_address_increment > 1 {
		resetDCPredictors()
	}

	// Reset motion vector predictors: P-picture with a skipped macroblock (7.6.4.3)
	if br.PictureHeader.picture_coding_type == PFrame &&
		mb.macroblock_address_increment > 1 {
		mvd.reset()
	}

	if err := br.macroblock_mode(&mb); err != nil {
		return 0, err
	}

	// Reset dcDctPredictors: whenever a non-intra macroblock is decoded. (7.2.1)
	if mb.macroblock_type.macroblock_intra == false {
		resetDCPredictors()
	}

	// Reset motion vector predictors: intra macroblock without concealment motion vectors (7.6.4.3)
	if mb.macroblock_type.macroblock_intra == true &&
		br.PictureCodingExtension.concealment_motion_vectors == false {
		mvd.reset()
	}

	// Reset motion vector predictors: non-intra P-picture with no forward motion vectors (7.6.4.3)
	if br.PictureHeader.picture_coding_type == PFrame &&
		mb.macroblock_type.macroblock_intra == false &&
		mb.macroblock_type.macroblock_motion_forward == false {
		mvd.reset()
	}

	if mb.macroblock_type.macroblock_quant {
		if mb_qsc, err := br.Read32(5); err != nil {
			return 0, err
		} else {
			*qsc = mb_qsc
		}
	}

	if mb.macroblock_type.macroblock_motion_forward ||
		(mb.macroblock_type.macroblock_intra && br.PictureCodingExtension.concealment_motion_vectors) {
		if err := br.motion_vectors(0, &mb, mvd); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_motion_backward {
		if err := br.motion_vectors(1, &mb, mvd); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_intra && br.PictureCodingExtension.concealment_motion_vectors {
		if err := marker_bit(br); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_pattern {
		if cpb, err := coded_block_pattern(br, br.SequenceExtension.chroma_format); err != nil {
			return 0, nil
		} else {
			mb.cpb = cpb
		}
	}

	var block_count int
	switch br.SequenceExtension.chroma_format {
	case ChromaFormat_420:
		block_count = 6
	case ChromaFormat_422:
		block_count = 8
	case ChromaFormat_444:
		block_count = 12
	}

	mb_address += mb.macroblock_address_increment
	pattern_code := mb.decodePatternCode(br.SequenceExtension.chroma_format)

	var b block

	for i := 0; i < block_count; i++ {
		cc := color_channel[i]

		if pattern_code[i] {
			if err := b.read(br, dcp, br.PictureCodingExtension.intra_vlc_format, cc, mb.macroblock_type.macroblock_intra); err != nil {
				return 0, err
			}
			b.decode_block(br, cc, *qsc, mb.macroblock_type.macroblock_intra)
			b.idct()
		} else {
			b.empty()
		}

		br.motion_compensation(mvd, i, mb_row, mb_address, &mb, &b)
		updateFrameSlice(i, mb_address, mb.dct_type, frameSlice, &b)
	}

	return mb_address, nil
}

func updateFrameSlice(i, mb_address int, interlaced bool, frameSlice *image.YCbCr, b *block) {

	var cb clampedblock
	b.clamp(&cb)

	if interlaced {
		switch i {
		case 0:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := (y*2)*frameSlice.YStride + xs
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 1:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := (y*2)*frameSlice.YStride + (xs + 8)
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 2:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := ((y*2)+1)*frameSlice.YStride + xs
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 3:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := ((y*2)+1)*frameSlice.YStride + (xs + 8)
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 4:
			xs := mb_address * 8
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.CStride + xs
				copy(frameSlice.Cb[di:di+8], cb[si:si+8])
			}
		case 5:
			xs := mb_address * 8
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.CStride + xs
				copy(frameSlice.Cr[di:di+8], cb[si:si+8])
			}
		}
	} else {
		switch i {
		case 0:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.YStride + xs
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 1:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.YStride + (xs + 8)
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 2:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := (y+8)*frameSlice.YStride + xs
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 3:
			xs := mb_address * 16
			for y := 0; y < 8; y++ {
				si := y * 8
				di := (y+8)*frameSlice.YStride + (xs + 8)
				copy(frameSlice.Y[di:di+8], cb[si:si+8])
			}
		case 4:
			xs := mb_address * 8
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.CStride + xs
				copy(frameSlice.Cb[di:di+8], cb[si:si+8])
			}
		case 5:
			xs := mb_address * 8
			for y := 0; y < 8; y++ {
				si := y * 8
				di := y*frameSlice.CStride + xs
				copy(frameSlice.Cr[di:di+8], cb[si:si+8])
			}
		}
	}

}

type PatternCode [12]bool

func (mb *Macroblock) decodePatternCode(chroma_format chromaFormat) (pattern_code PatternCode) {
	for i := 0; i < 12; i++ {
		if mb.macroblock_type.macroblock_intra {
			pattern_code[i] = true
		} else {
			pattern_code[i] = false
		}
	}

	if mb.macroblock_type.macroblock_pattern {
		for i := 0; i < 6; i++ {
			if mask := 1 << uint(5-i); mb.cpb&mask == mask {
				pattern_code[i] = true
			}
		}

		if chroma_format == ChromaFormat_422 || chroma_format == ChromaFormat_444 {
			panic("unsupported: coded block pattern chroma format")
		}
	}

	return
}

func (br *VideoSequence) macroblock_mode(mb *Macroblock) (err error) {

	var typeDecoder macroblockTypeDecoderFn
	switch br.PictureHeader.picture_coding_type {
	case IntraCoded:
		typeDecoder = macroblockTypeDecoder.IFrame
	case PredictiveCoded:
		typeDecoder = macroblockTypeDecoder.PFrame
	case BidirectionallyPredictiveCoded:
		typeDecoder = macroblockTypeDecoder.BFrame
	default:
		panic("not implemented: macroblock type decoder")
	}

	mb.macroblock_type, err = typeDecoder(br)
	if err != nil {
		return err
	}

	if mb.macroblock_type.spatial_temporal_weight_code_flag &&
		false /* ( spatial_temporal_weight_code_table_index != ‘00’) */ {
		mb.spatial_temporal_weight_code, err = br.Read32(2)
		if err != nil {
			return err
		}
	}

	if mb.macroblock_type.macroblock_motion_forward ||
		mb.macroblock_type.macroblock_motion_backward {
		if br.PictureCodingExtension.picture_structure == PictureStructure_FramePicture {
			if br.PictureCodingExtension.frame_pred_frame_dct == 0 {
				mb.frame_motion_type, err = br.Read32(2)
				if err != nil {
					return err
				}
			}
		} else {
			mb.field_motion_type, err = br.Read32(2)
			if err != nil {
				return err
			}
		}
	}

	if br.PictureCodingExtension.picture_structure == PictureStructure_FramePicture &&
		br.PictureCodingExtension.frame_pred_frame_dct == 0 &&
		(mb.macroblock_type.macroblock_intra || mb.macroblock_type.macroblock_pattern) {
		mb.dct_type, err = br.ReadBit() //dct_type 1 uimsbf
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>clearer implementation of block-to-image copy.<commit_after>package video

import "image"

var color_channel = [12]int{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2}

type Macroblock struct {
	macroblock_address_increment int
	macroblock_type              *MacroblockType
	spatial_temporal_weight_code uint32
	frame_motion_type            uint32
	field_motion_type            uint32
	dct_type                     bool

	cpb int
}

func (br *VideoSequence) macroblock(
	// location
	mb_address, mb_row int,
	// dct predictors
	dcp *dcDctPredictors, resetDCPredictors dcDctPredictorResetter,
	mvd *motionVectorData,
	qsc *uint32,
	frameSlice *image.YCbCr) (int, error) {

	mb := Macroblock{}

	for {
		if nextbits, err := br.Peek32(11); err != nil {
			return 0, err
		} else if nextbits == 0x08 { // 0000 0001 000
			br.Trash(11)
			mb.macroblock_address_increment += 33
		} else {
			break
		}
	}

	if incr, err := macroblockAddressIncrementDecoder.Decode(br); err != nil {
		return 0, err
	} else {
		mb.macroblock_address_increment += incr
	}

	if br.PictureHeader.picture_coding_type == PFrame && mb.macroblock_address_increment > 1 {
		copy_macroblocks(mb_row, mb_address+1, mb.macroblock_address_increment-1, frameSlice, br.frameStore.past)
	}

	// Reset dcDctPredictors: whenever a macroblock is skipped. (7.2.1)
	if mb.macroblock_address_increment > 1 {
		resetDCPredictors()
	}

	// Reset motion vector predictors: P-picture with a skipped macroblock (7.6.4.3)
	if br.PictureHeader.picture_coding_type == PFrame &&
		mb.macroblock_address_increment > 1 {
		mvd.reset()
	}

	if err := br.macroblock_mode(&mb); err != nil {
		return 0, err
	}

	// Reset dcDctPredictors: whenever a non-intra macroblock is decoded. (7.2.1)
	if mb.macroblock_type.macroblock_intra == false {
		resetDCPredictors()
	}

	// Reset motion vector predictors: intra macroblock without concealment motion vectors (7.6.4.3)
	if mb.macroblock_type.macroblock_intra == true &&
		br.PictureCodingExtension.concealment_motion_vectors == false {
		mvd.reset()
	}

	// Reset motion vector predictors: non-intra P-picture with no forward motion vectors (7.6.4.3)
	if br.PictureHeader.picture_coding_type == PFrame &&
		mb.macroblock_type.macroblock_intra == false &&
		mb.macroblock_type.macroblock_motion_forward == false {
		mvd.reset()
	}

	if mb.macroblock_type.macroblock_quant {
		if mb_qsc, err := br.Read32(5); err != nil {
			return 0, err
		} else {
			*qsc = mb_qsc
		}
	}

	if mb.macroblock_type.macroblock_motion_forward ||
		(mb.macroblock_type.macroblock_intra && br.PictureCodingExtension.concealment_motion_vectors) {
		if err := br.motion_vectors(0, &mb, mvd); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_motion_backward {
		if err := br.motion_vectors(1, &mb, mvd); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_intra && br.PictureCodingExtension.concealment_motion_vectors {
		if err := marker_bit(br); err != nil {
			return 0, err
		}
	}

	if mb.macroblock_type.macroblock_pattern {
		if cpb, err := coded_block_pattern(br, br.SequenceExtension.chroma_format); err != nil {
			return 0, nil
		} else {
			mb.cpb = cpb
		}
	}

	var block_count int
	switch br.SequenceExtension.chroma_format {
	case ChromaFormat_420:
		block_count = 6
	case ChromaFormat_422:
		block_count = 8
	case ChromaFormat_444:
		block_count = 12
	}

	mb_address += mb.macroblock_address_increment
	pattern_code := mb.decodePatternCode(br.SequenceExtension.chroma_format)

	var b block

	for i := 0; i < block_count; i++ {
		cc := color_channel[i]

		if pattern_code[i] {
			if err := b.read(br, dcp, br.PictureCodingExtension.intra_vlc_format, cc, mb.macroblock_type.macroblock_intra); err != nil {
				return 0, err
			}
			b.decode_block(br, cc, *qsc, mb.macroblock_type.macroblock_intra)
			b.idct()
		} else {
			b.empty()
		}

		br.motion_compensation(mvd, i, mb_row, mb_address, &mb, &b)
		updateFrameSlice(i, mb_address, mb.dct_type, frameSlice, &b)
	}

	return mb_address, nil
}

func updateFrameSlice(i, mb_address int, interlaced bool, frameSlice *image.YCbCr, b *block) {

	var cb clampedblock
	b.clamp(&cb)

	var (
		base_i  int
		channel []uint8
		stride  int
	)

	// channel switch
	switch i {
	case 0, 1, 2, 3:
		channel = frameSlice.Y
	case 4:
		channel = frameSlice.Cb
	case 5:
		channel = frameSlice.Cr
	}

	// base address and stride switch
	switch i {
	case 0, 1, 2, 3:
		stride = frameSlice.YStride
		base_i = mb_address * 16
	case 4, 5:
		stride = frameSlice.CStride
		base_i = mb_address * 8
	}

	// position switch
	if interlaced {
		// Field DCT coding alternates lines from each block:
		//
		//  <-8px-> <-8px->
		//  ───0───│───1───
		//  ───2───│───3───
		//  ───0───│───1───
		//  ───2───│───3───
		//  ───0───│───1───
		//  ───2───│───3───
		//  ───0───│───1───
		//  ───2───│───3───
		switch i {
		case 0, 1, 2, 3:
			base_i += (i & 1) << 3
			base_i += ((i & 2) >> 1) * stride
			stride *= 2
		}
	} else {
		// Frame DCT coding are mapped in the follow order:
		//
		//  <-8px-> <-8px->
		//  ───0───│───1───
		//  ───0───│───1───
		//  ───0───│───1───
		//  ───0───│───1───
		//  ───2───│───3───
		//  ───2───│───3───
		//  ───2───│───3───
		//  ───2───│───3───
		switch i {
		case 0, 1, 2, 3:
			base_i += (i & 1) << 3            // horiztonal positioning
			base_i += ((i & 2) << 2) * stride // vertical positioning
		}
	}

	// perform copy
	for y := 0; y < 8; y++ {
		si := y * 8
		di := base_i + (y * stride)
		copy(channel[di:di+8], cb[si:si+8])
	}

}

type PatternCode [12]bool

func (mb *Macroblock) decodePatternCode(chroma_format chromaFormat) (pattern_code PatternCode) {
	for i := 0; i < 12; i++ {
		if mb.macroblock_type.macroblock_intra {
			pattern_code[i] = true
		} else {
			pattern_code[i] = false
		}
	}

	if mb.macroblock_type.macroblock_pattern {
		for i := 0; i < 6; i++ {
			if mask := 1 << uint(5-i); mb.cpb&mask == mask {
				pattern_code[i] = true
			}
		}

		if chroma_format == ChromaFormat_422 || chroma_format == ChromaFormat_444 {
			panic("unsupported: coded block pattern chroma format")
		}
	}

	return
}

func (br *VideoSequence) macroblock_mode(mb *Macroblock) (err error) {

	var typeDecoder macroblockTypeDecoderFn
	switch br.PictureHeader.picture_coding_type {
	case IntraCoded:
		typeDecoder = macroblockTypeDecoder.IFrame
	case PredictiveCoded:
		typeDecoder = macroblockTypeDecoder.PFrame
	case BidirectionallyPredictiveCoded:
		typeDecoder = macroblockTypeDecoder.BFrame
	default:
		panic("not implemented: macroblock type decoder")
	}

	mb.macroblock_type, err = typeDecoder(br)
	if err != nil {
		return err
	}

	if mb.macroblock_type.spatial_temporal_weight_code_flag &&
		false /* ( spatial_temporal_weight_code_table_index != ‘00’) */ {
		mb.spatial_temporal_weight_code, err = br.Read32(2)
		if err != nil {
			return err
		}
	}

	if mb.macroblock_type.macroblock_motion_forward ||
		mb.macroblock_type.macroblock_motion_backward {
		if br.PictureCodingExtension.picture_structure == PictureStructure_FramePicture {
			if br.PictureCodingExtension.frame_pred_frame_dct == 0 {
				mb.frame_motion_type, err = br.Read32(2)
				if err != nil {
					return err
				}
			}
		} else {
			mb.field_motion_type, err = br.Read32(2)
			if err != nil {
				return err
			}
		}
	}

	if br.PictureCodingExtension.picture_structure == PictureStructure_FramePicture &&
		br.PictureCodingExtension.frame_pred_frame_dct == 0 &&
		(mb.macroblock_type.macroblock_intra || mb.macroblock_type.macroblock_pattern) {
		mb.dct_type, err = br.ReadBit() //dct_type 1 uimsbf
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package influxdb

import (
	"errors"
	"fmt"
	"path/filepath"
)

var (
	// ErrAuthorizerNotSupported notes that the provided authorizer is not supported for the action you are trying to perform.
	ErrAuthorizerNotSupported = errors.New("your authorizer is not supported, please use *platform.Authorization as authorizer")
	// ErrInvalidResourceType notes that the provided resource is invalid
	ErrInvalidResourceType = errors.New("unknown resource type for permission")
	// ErrInvalidAction notes that the provided action is invalid
	ErrInvalidAction = errors.New("unknown action for permission")
)

// Authorizer will authorize a permission.
type Authorizer interface {
	// Allowed returns true is the associated permission is allowed by the authorizer
	Allowed(p Permission) bool

	// ID returns an identifier used for auditing.
	Identifier() ID

	// GetUserID returns the user id.
	GetUserID() ID

	// Kind metadata for auditing.
	Kind() string
}

// PermissionAllowed determines if a permission is allowed.
func PermissionAllowed(perm Permission, ps []Permission) bool {
	for _, p := range ps {
		if p.Matches(perm) {
			return true
		}
	}
	return false
}

// Action is an enum defining all possible resource operations
type Action string

const (
	// ReadAction is the action for reading.
	ReadAction Action = "read" // 1
	// WriteAction is the action for writing.
	WriteAction Action = "write" // 2
)

var actions = []Action{
	ReadAction,  // 1
	WriteAction, // 2
}

// Valid checks if the action is a member of the Action enum
func (a Action) Valid() (err error) {
	switch a {
	case ReadAction: // 1
	case WriteAction: // 2
	default:
		err = ErrInvalidAction
	}

	return err
}

// ResourceType is an enum defining all resource types that have a permission model in platform
type ResourceType string

// Resource is an authorizable resource.
type Resource struct {
	Type  ResourceType `json:"type"`
	ID    *ID          `json:"id,omitempty"`
	OrgID *ID          `json:"orgID,omitempty"`
}

// String stringifies a resource
func (r Resource) String() string {
	if r.OrgID != nil && r.ID != nil {
		return filepath.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type), r.ID.String())
	}

	if r.OrgID != nil {
		return filepath.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type))
	}

	if r.ID != nil {
		return filepath.Join(string(r.Type), r.ID.String())
	}

	return string(r.Type)
}

const (
	// AuthorizationsResourceType gives permissions to one or more authorizations.
	AuthorizationsResourceType = ResourceType("authorizations") // 0
	// BucketsResourceType gives permissions to one or more buckets.
	BucketsResourceType = ResourceType("buckets") // 1
	// DashboardsResourceType gives permissions to one or more dashboards.
	DashboardsResourceType = ResourceType("dashboards") // 2
	// OrgsResourceType gives permissions to one or more orgs.
	OrgsResourceType = ResourceType("orgs") // 3
	// SourcesResourceType gives permissions to one or more sources.
	SourcesResourceType = ResourceType("sources") // 4
	// TasksResourceType gives permissions to one or more tasks.
	TasksResourceType = ResourceType("tasks") // 5
	// TelegrafsResourceType type gives permissions to a one or more telegrafs.
	TelegrafsResourceType = ResourceType("telegrafs") // 6
	// UsersResourceType gives permissions to one or more users.
	UsersResourceType = ResourceType("users") // 7
	// MacrosResourceType gives permission to one or more macros.
	MacrosResourceType = ResourceType("macros") // 8
	// ScraperResourceType gives permission to one or more scrapers.
	ScraperResourceType = ResourceType("scrapers") // 9
)

// AllResourceTypes is the list of all known resource types.
var AllResourceTypes = []ResourceType{
	AuthorizationsResourceType, // 0
	BucketsResourceType,        // 1
	DashboardsResourceType,     // 2
	OrgsResourceType,           // 3
	SourcesResourceType,        // 4
	TasksResourceType,          // 5
	TelegrafsResourceType,      // 6
	UsersResourceType,          // 7
	MacrosResourceType,         // 8
	ScraperResourceType,        // 9
}

// OrgResourceTypes is the list of all known resource types that belong to an organization.
var OrgResourceTypes = []ResourceType{
	BucketsResourceType,    // 1
	DashboardsResourceType, // 2
	SourcesResourceType,    // 4
	TasksResourceType,      // 5
	TelegrafsResourceType,  // 6
	UsersResourceType,      // 7
	MacrosResourceType,     // 8
}

// Valid checks if the resource type is a member of the ResourceType enum.
func (r Resource) Valid() (err error) {
	return r.Type.Valid()
}

// Valid checks if the resource type is a member of the ResourceType enum.
func (t ResourceType) Valid() (err error) {
	switch t {
	case AuthorizationsResourceType: // 0
	case BucketsResourceType: // 1
	case DashboardsResourceType: // 2
	case OrgsResourceType: // 3
	case TasksResourceType: // 4
	case TelegrafsResourceType: // 5
	case SourcesResourceType: // 6
	case UsersResourceType: // 7
	case MacrosResourceType: // 8
	case ScraperResourceType: // 9
	default:
		err = ErrInvalidResourceType
	}

	return err
}

// Permission defines an action and a resource.
type Permission struct {
	Action   Action   `json:"action"`
	Resource Resource `json:"resource"`
}

// Matches returns whether or not one permission matches the other.
func (p Permission) Matches(perm Permission) bool {
	if p.Action != perm.Action {
		return false
	}

	if p.Resource.Type != perm.Resource.Type {
		return false
	}

	if p.Resource.OrgID == nil && p.Resource.ID == nil {
		return true
	}

	if p.Resource.OrgID != nil && p.Resource.ID == nil {
		pOrgID := *p.Resource.OrgID
		if perm.Resource.OrgID != nil {
			permOrgID := *perm.Resource.OrgID
			if pOrgID == permOrgID {
				return true
			}
		}
	}

	if p.Resource.ID != nil {
		pID := *p.Resource.ID
		if perm.Resource.ID != nil {
			permID := *perm.Resource.ID
			if pID == permID {
				return true
			}
		}
	}

	return false
}

func (p Permission) String() string {
	return fmt.Sprintf("%s:%s", p.Action, p.Resource)
}

// Valid checks if there the resource and action provided is known.
func (p *Permission) Valid() error {
	if err := p.Resource.Valid(); err != nil {
		return &Error{
			Code: EInvalid,
			Err:  err,
			Msg:  "invalid resource type for permission",
		}
	}

	if err := p.Action.Valid(); err != nil {
		return &Error{
			Code: EInvalid,
			Err:  err,
			Msg:  "invalid action type for permission",
		}
	}

	if p.Resource.OrgID != nil && !(*p.Resource.OrgID).Valid() {
		return &Error{
			Code: EInvalid,
			Err:  ErrInvalidID,
			Msg:  "invalid org id for permission",
		}
	}

	if p.Resource.ID != nil && !(*p.Resource.ID).Valid() {
		return &Error{
			Code: EInvalid,
			Err:  ErrInvalidID,
			Msg:  "invalid id for permission",
		}
	}

	return nil
}

// NewPermission returns a permission with provided arguments.
func NewPermission(a Action, rt ResourceType, orgID ID) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type:  rt,
			OrgID: &orgID,
		},
	}

	return p, p.Valid()
}

// NewGlobalPermission constructs a global permission capable of accessing any resource of type rt.
func NewGlobalPermission(a Action, rt ResourceType) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type: rt,
		},
	}
	return p, p.Valid()
}

// NewPermissionAtID creates a permission with the provided arguments.
func NewPermissionAtID(id ID, a Action, rt ResourceType, orgID ID) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type:  rt,
			OrgID: &orgID,
			ID:    &id,
		},
	}

	return p, p.Valid()
}

// OperPermissions are the default permissions for those who setup the application.
func OperPermissions() []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		for _, a := range actions {
			ps = append(ps, Permission{Action: a, Resource: Resource{Type: r}})
		}
	}

	return ps
}

// OwnerPermissions are the default permissions for those who own a resource.
func OwnerPermissions(orgID ID) []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		for _, a := range actions {
			if r == OrgsResourceType {
				ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, ID: &orgID}})
				continue
			}
			ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, OrgID: &orgID}})
		}
	}

	return ps
}

// MePermissions is the permission to read/write myself.
func MePermissions(userID ID) []Permission {
	ps := []Permission{}
	for _, a := range actions {
		ps = append(ps, Permission{Action: a, Resource: Resource{Type: UsersResourceType, ID: &userID}})
	}

	return ps
}

// MemberPermissions are the default permissions for those who can see a resource.
func MemberPermissions(orgID ID) []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		if r == OrgsResourceType {
			ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, ID: &orgID}})
			continue
		}
		ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, OrgID: &orgID}})
	}

	return ps
}
<commit_msg>feat(influxdb): secrets resource type<commit_after>package influxdb

import (
	"errors"
	"fmt"
	"path/filepath"
)

var (
	// ErrAuthorizerNotSupported notes that the provided authorizer is not supported for the action you are trying to perform.
	ErrAuthorizerNotSupported = errors.New("your authorizer is not supported, please use *platform.Authorization as authorizer")
	// ErrInvalidResourceType notes that the provided resource is invalid
	ErrInvalidResourceType = errors.New("unknown resource type for permission")
	// ErrInvalidAction notes that the provided action is invalid
	ErrInvalidAction = errors.New("unknown action for permission")
)

// Authorizer will authorize a permission.
type Authorizer interface {
	// Allowed returns true is the associated permission is allowed by the authorizer
	Allowed(p Permission) bool

	// ID returns an identifier used for auditing.
	Identifier() ID

	// GetUserID returns the user id.
	GetUserID() ID

	// Kind metadata for auditing.
	Kind() string
}

// PermissionAllowed determines if a permission is allowed.
func PermissionAllowed(perm Permission, ps []Permission) bool {
	for _, p := range ps {
		if p.Matches(perm) {
			return true
		}
	}
	return false
}

// Action is an enum defining all possible resource operations
type Action string

const (
	// ReadAction is the action for reading.
	ReadAction Action = "read" // 1
	// WriteAction is the action for writing.
	WriteAction Action = "write" // 2
)

var actions = []Action{
	ReadAction,  // 1
	WriteAction, // 2
}

// Valid checks if the action is a member of the Action enum
func (a Action) Valid() (err error) {
	switch a {
	case ReadAction: // 1
	case WriteAction: // 2
	default:
		err = ErrInvalidAction
	}

	return err
}

// ResourceType is an enum defining all resource types that have a permission model in platform
type ResourceType string

// Resource is an authorizable resource.
type Resource struct {
	Type  ResourceType `json:"type"`
	ID    *ID          `json:"id,omitempty"`
	OrgID *ID          `json:"orgID,omitempty"`
}

// String stringifies a resource
func (r Resource) String() string {
	if r.OrgID != nil && r.ID != nil {
		return filepath.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type), r.ID.String())
	}

	if r.OrgID != nil {
		return filepath.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type))
	}

	if r.ID != nil {
		return filepath.Join(string(r.Type), r.ID.String())
	}

	return string(r.Type)
}

const (
	// AuthorizationsResourceType gives permissions to one or more authorizations.
	AuthorizationsResourceType = ResourceType("authorizations") // 0
	// BucketsResourceType gives permissions to one or more buckets.
	BucketsResourceType = ResourceType("buckets") // 1
	// DashboardsResourceType gives permissions to one or more dashboards.
	DashboardsResourceType = ResourceType("dashboards") // 2
	// OrgsResourceType gives permissions to one or more orgs.
	OrgsResourceType = ResourceType("orgs") // 3
	// SourcesResourceType gives permissions to one or more sources.
	SourcesResourceType = ResourceType("sources") // 4
	// TasksResourceType gives permissions to one or more tasks.
	TasksResourceType = ResourceType("tasks") // 5
	// TelegrafsResourceType type gives permissions to a one or more telegrafs.
	TelegrafsResourceType = ResourceType("telegrafs") // 6
	// UsersResourceType gives permissions to one or more users.
	UsersResourceType = ResourceType("users") // 7
	// MacrosResourceType gives permission to one or more macros.
	MacrosResourceType = ResourceType("macros") // 8
	// ScraperResourceType gives permission to one or more scrapers.
	ScraperResourceType = ResourceType("scrapers") // 9
	// SecretsResourceType gives permission to one or more scrapers.
	SecretsResourceType = ResourceType("secrets") // 10
)

// AllResourceTypes is the list of all known resource types.
var AllResourceTypes = []ResourceType{
	AuthorizationsResourceType, // 0
	BucketsResourceType,        // 1
	DashboardsResourceType,     // 2
	OrgsResourceType,           // 3
	SourcesResourceType,        // 4
	TasksResourceType,          // 5
	TelegrafsResourceType,      // 6
	UsersResourceType,          // 7
	MacrosResourceType,         // 8
	ScraperResourceType,        // 9
	SecretsResourceType,        // 10
}

// OrgResourceTypes is the list of all known resource types that belong to an organization.
var OrgResourceTypes = []ResourceType{
	BucketsResourceType,    // 1
	DashboardsResourceType, // 2
	SourcesResourceType,    // 4
	TasksResourceType,      // 5
	TelegrafsResourceType,  // 6
	UsersResourceType,      // 7
	MacrosResourceType,     // 8
	SecretsResourceType,    // 10
}

// Valid checks if the resource type is a member of the ResourceType enum.
func (r Resource) Valid() (err error) {
	return r.Type.Valid()
}

// Valid checks if the resource type is a member of the ResourceType enum.
func (t ResourceType) Valid() (err error) {
	switch t {
	case AuthorizationsResourceType: // 0
	case BucketsResourceType: // 1
	case DashboardsResourceType: // 2
	case OrgsResourceType: // 3
	case TasksResourceType: // 4
	case TelegrafsResourceType: // 5
	case SourcesResourceType: // 6
	case UsersResourceType: // 7
	case MacrosResourceType: // 8
	case ScraperResourceType: // 9
	case SecretsResourceType: // 10
	default:
		err = ErrInvalidResourceType
	}

	return err
}

// Permission defines an action and a resource.
type Permission struct {
	Action   Action   `json:"action"`
	Resource Resource `json:"resource"`
}

// Matches returns whether or not one permission matches the other.
func (p Permission) Matches(perm Permission) bool {
	if p.Action != perm.Action {
		return false
	}

	if p.Resource.Type != perm.Resource.Type {
		return false
	}

	if p.Resource.OrgID == nil && p.Resource.ID == nil {
		return true
	}

	if p.Resource.OrgID != nil && p.Resource.ID == nil {
		pOrgID := *p.Resource.OrgID
		if perm.Resource.OrgID != nil {
			permOrgID := *perm.Resource.OrgID
			if pOrgID == permOrgID {
				return true
			}
		}
	}

	if p.Resource.ID != nil {
		pID := *p.Resource.ID
		if perm.Resource.ID != nil {
			permID := *perm.Resource.ID
			if pID == permID {
				return true
			}
		}
	}

	return false
}

func (p Permission) String() string {
	return fmt.Sprintf("%s:%s", p.Action, p.Resource)
}

// Valid checks if there the resource and action provided is known.
func (p *Permission) Valid() error {
	if err := p.Resource.Valid(); err != nil {
		return &Error{
			Code: EInvalid,
			Err:  err,
			Msg:  "invalid resource type for permission",
		}
	}

	if err := p.Action.Valid(); err != nil {
		return &Error{
			Code: EInvalid,
			Err:  err,
			Msg:  "invalid action type for permission",
		}
	}

	if p.Resource.OrgID != nil && !(*p.Resource.OrgID).Valid() {
		return &Error{
			Code: EInvalid,
			Err:  ErrInvalidID,
			Msg:  "invalid org id for permission",
		}
	}

	if p.Resource.ID != nil && !(*p.Resource.ID).Valid() {
		return &Error{
			Code: EInvalid,
			Err:  ErrInvalidID,
			Msg:  "invalid id for permission",
		}
	}

	return nil
}

// NewPermission returns a permission with provided arguments.
func NewPermission(a Action, rt ResourceType, orgID ID) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type:  rt,
			OrgID: &orgID,
		},
	}

	return p, p.Valid()
}

// NewGlobalPermission constructs a global permission capable of accessing any resource of type rt.
func NewGlobalPermission(a Action, rt ResourceType) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type: rt,
		},
	}
	return p, p.Valid()
}

// NewPermissionAtID creates a permission with the provided arguments.
func NewPermissionAtID(id ID, a Action, rt ResourceType, orgID ID) (*Permission, error) {
	p := &Permission{
		Action: a,
		Resource: Resource{
			Type:  rt,
			OrgID: &orgID,
			ID:    &id,
		},
	}

	return p, p.Valid()
}

// OperPermissions are the default permissions for those who setup the application.
func OperPermissions() []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		for _, a := range actions {
			ps = append(ps, Permission{Action: a, Resource: Resource{Type: r}})
		}
	}

	return ps
}

// OwnerPermissions are the default permissions for those who own a resource.
func OwnerPermissions(orgID ID) []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		for _, a := range actions {
			if r == OrgsResourceType {
				ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, ID: &orgID}})
				continue
			}
			ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, OrgID: &orgID}})
		}
	}

	return ps
}

// MePermissions is the permission to read/write myself.
func MePermissions(userID ID) []Permission {
	ps := []Permission{}
	for _, a := range actions {
		ps = append(ps, Permission{Action: a, Resource: Resource{Type: UsersResourceType, ID: &userID}})
	}

	return ps
}

// MemberPermissions are the default permissions for those who can see a resource.
func MemberPermissions(orgID ID) []Permission {
	ps := []Permission{}
	for _, r := range AllResourceTypes {
		if r == OrgsResourceType {
			ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, ID: &orgID}})
			continue
		}
		ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, OrgID: &orgID}})
	}

	return ps
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemIDFlag := flag.Int("new", 1, "new <problem ID>")
	flag.Parse()
	problemID := *problemIDFlag
	println("ProblemID: " + strconv.Itoa(problemID))
	folder := "p" + strconv.Itoa(problemID)
	err := os.Mkdir(folder, 0771)
	if err != nil {
		log.Fatal("Folder " + folder + " already exists! Remove it to generate problem template.")

	}
	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := "Project Euler - Problem: " + strconv.Itoa(problemID) + "\n\n"
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		info += "Description:\n" + s.Text() + "{{end_block}}"
	})

	yuckyStrings := map[string]string{
		"\n\n\n":           "\n\n",
		"\n{{end_block}}":  "",
		"Description:\n\n": "Description:\n",
		"Title:\n":         "Title: ",
		"You are currently using a secure connectionInfo:\n": "",
		"Problem " + strconv.Itoa(problemID):                 ""}

	for k, v := range yuckyStrings {
		for i := 0; i < 5; i++ { // Make sure all get replaced.
			info = strings.Replace(info, k, v, -1)
		}
	}
	return info
}
<commit_msg>I lied. More formatting<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemIDFlag := flag.Int("new", 1, "new <problem ID>")
	flag.Parse()
	problemID := *problemIDFlag
	println("ProblemID: " + strconv.Itoa(problemID))
	folder := "p" + strconv.Itoa(problemID)
	err := os.Mkdir(folder, 0771)
	if err != nil {
		log.Fatal("Folder " + folder + " already exists! Remove it to generate problem template.")

	}
	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := "Project Euler: Problem " + strconv.Itoa(problemID) + "\n\n"
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		info += "Description:\n" + s.Text() + "{{end_block}}"
	})

	yuckyStrings := map[string]string{
		"\n\n\n":           "\n\n",
		"\n{{end_block}}":  "",
		"Description:\n\n": "Description:\n",
		"Title:\n":         "Title: ",
		"You are currently using a secure connectionInfo:\n": "",
		"Problem " + strconv.Itoa(problemID):                 ""}

	for k, v := range yuckyStrings {
		for i := 0; i < 5; i++ { // Make sure all get replaced.
			info = strings.Replace(info, k, v, -1)
		}
	}
	return info
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemIDFlag := flag.Int("new", 1, "new <problem ID>")
	flag.Parse()
	problemID := *problemIDFlag
	println("ProblemID: " + strconv.Itoa(problemID))
	folder := "p" + strconv.Itoa(problemID)
	err := os.Mkdir(folder, 0771)
	if err != nil {
		log.Fatal("Folder " + folder + " already exists! Remove it to generate problem template.")

	}
	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := "Problem: " + strconv.Itoa(problemID) + "\n"
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		info += "Description:\n" + s.Text() + "{{end_block}}"
	})

	yuckyStrings := map[string]string{
		"\n\n\n":           "\n\n",
		"\n{{end_block}}":  "",
		"Description:\n\n": "Description:\n",
		"Title:\n":         "Title: ",
		"You are currently using a secure connectionInfo:\n": "",
		"Problem " + strconv.Itoa(problemID):                 ""}

	for k, v := range yuckyStrings {
		for i := 0; i < 5; i++ { // Make sure all get replaced.
			info = strings.Replace(info, k, v, -1)
		}
	}
	return info
}
<commit_msg>Add Project Euler to comment header<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemIDFlag := flag.Int("new", 1, "new <problem ID>")
	flag.Parse()
	problemID := *problemIDFlag
	println("ProblemID: " + strconv.Itoa(problemID))
	folder := "p" + strconv.Itoa(problemID)
	err := os.Mkdir(folder, 0771)
	if err != nil {
		log.Fatal("Folder " + folder + " already exists! Remove it to generate problem template.")

	}
	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := "[Project Euler] Problem: " + strconv.Itoa(problemID) + "\n"
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		info += "Description:\n" + s.Text() + "{{end_block}}"
	})

	yuckyStrings := map[string]string{
		"\n\n\n":           "\n\n",
		"\n{{end_block}}":  "",
		"Description:\n\n": "Description:\n",
		"Title:\n":         "Title: ",
		"You are currently using a secure connectionInfo:\n": "",
		"Problem " + strconv.Itoa(problemID):                 ""}

	for k, v := range yuckyStrings {
		for i := 0; i < 5; i++ { // Make sure all get replaced.
			info = strings.Replace(info, k, v, -1)
		}
	}
	return info
}
<|endoftext|>


<commit_before>package evaler_test

import (
	"math"
	"math/big"
	"testing"

	"github.com/soniah/evaler"
)

// -----------------------------------------------------------------------------

var testsEval = []struct {
	in  string
	out *big.Rat
	ok  bool
}{
	{"5 + 2", big.NewRat(7, 1), true},            // simple plus
	{"5 - 2", big.NewRat(3, 1), true},            // simple minus
	{"5 * 2", big.NewRat(10, 1), true},           // simple multiply
	{"5 / 2", big.NewRat(5, 2), true},            // simple divide
	{"U + U", nil, false},                        // letters 1
	{"2 + U", nil, false},                        // broken 1
	{"2 +  ", nil, false},                        // broken 2
	{"+ 2 - + * ", nil, false},                   // broken 3
	{"5.5+2*(3+1)", big.NewRat(27, 2), true},     // complex 1
	{"(((1+2.3)))", big.NewRat(33, 10), true},    // complex 2
	{"(1+(2))*(5-2.5)", big.NewRat(15, 2), true}, // complex 3
	{"3*(2<4)", big.NewRat(3, 1), true},          // less than
	{"3*(2>4)", new(big.Rat), true},              // greater than
	{"5 / 0", nil, false},                        // divide by zero
	{"2 ** 3", big.NewRat(8, 1), true},           // exponent 1
	{"9.0**0.5", big.NewRat(3, 1), true},         // exponent 2
	{"1.23", big.NewRat(123, 100), true},
	{"-1+2", big.NewRat(1, 1), true},          // unary minus (the beginning of a expression)
	{"3*-4", big.NewRat(-12, 1), true},        // unary minus (after an operator)
	{"4/(-1+3)", big.NewRat(2, 1), true},      // unary minus (after '(' )
	{"-(-1+2)--2**3", big.NewRat(7, 1), true}, // unary minus (complex)
}

func TestEval(t *testing.T) {
	for i, test := range testsEval {
		ret, err := evaler.Eval(test.in)
		if ret == nil && test.out == nil {
			// ok, do nothing
		} else if ret == nil || test.out == nil {
			t.Errorf("#%d: %s: unexpected nil result: %v vs %v", i, test.in, ret, test.out)
		} else if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: %s: bad result: got %v expected %v", i, test.in, ret, test.out)
		}
		if (err == nil) != test.ok {
			t.Errorf("#%d: %s: unexpected err result: %t vs %t", i, test.in, (err == nil), test.ok)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToInt = []struct {
	in  *big.Rat
	out int64
	ok  bool
}{
	{big.NewRat(4, 2), int64(2), true},
	{big.NewRat(5, 2), int64(3), true},
	{big.NewRat(-4, 2), int64(-2), true},
	{new(big.Rat).Mul(big.NewRat(math.MaxInt64, 1), big.NewRat(math.MaxInt64, 1)), int64(0), false},
}

func TestBigratToInt(t *testing.T) {
	for i, test := range testsBigratToInt {
		ret, err := evaler.BigratToInt(test.in)
		if test.ok && (ret != test.out) {
			t.Errorf("#%d: got %d expected %d", i, ret, test.out)
		}
		if (err == nil) != test.ok {
			t.Errorf("#%d: %s: unexpected err result: %t vs %t", i, test.in, (err == nil), test.ok)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToBigint = []struct {
	in  *big.Rat
	out *big.Int
}{
	{big.NewRat(4, 2), big.NewInt(2)},
	{big.NewRat(5, 2), big.NewInt(3)},
	{big.NewRat(-4, 2), big.NewInt(-2)},
}

func TestBigratToBigint(t *testing.T) {
	for i, test := range testsBigratToBigint {
		ret := evaler.BigratToBigint(test.in)
		if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: got %d expected %d", i, ret, test.out)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToFloat = []struct {
	in  *big.Rat
	out float64
}{
	{big.NewRat(4, 2), float64(2.0)},
	{big.NewRat(5, 2), float64(2.5)},
	{big.NewRat(-4, 2), float64(-2.0)},
}

func TestBigratToFloat(t *testing.T) {
	for i, test := range testsBigratToFloat {
		ret := evaler.BigratToFloat(test.in)
		if ret != test.out {
			t.Errorf("#%d: got %f expected %f", i, ret, test.out)
		}
	}
}

// -----------------------------------------------------------------------------

var testsFloatToBigrat = []struct {
	in  float64
	out *big.Rat
}{
	{float64(2.0), big.NewRat(4, 2)},
	{float64(2.5), big.NewRat(5, 2)},
	{float64(-2.0), big.NewRat(-4, 2)},
}

func TestFloatToBigrat(t *testing.T) {
	for i, test := range testsFloatToBigrat {
		ret := evaler.FloatToBigrat(test.in)
		if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: got %s expected %s", i, ret, test.out)
		}
	}
}
<commit_msg>pull in cardinelli trig tests<commit_after>package evaler_test

import (
	"math"
	"math/big"
	"testing"

	"github.com/soniah/evaler"
)

// -----------------------------------------------------------------------------

var testsEval = []struct {
	in  string
	out *big.Rat
	ok  bool
}{
	{"5 + 2", big.NewRat(7, 1), true},            // simple plus
	{"5 - 2", big.NewRat(3, 1), true},            // simple minus
	{"5 * 2", big.NewRat(10, 1), true},           // simple multiply
	{"5 / 2", big.NewRat(5, 2), true},            // simple divide
	{"U + U", nil, false},                        // letters 1
	{"2 + U", nil, false},                        // broken 1
	{"2 +  ", nil, false},                        // broken 2
	{"+ 2 - + * ", nil, false},                   // broken 3
	{"5.5+2*(3+1)", big.NewRat(27, 2), true},     // complex 1
	{"(((1+2.3)))", big.NewRat(33, 10), true},    // complex 2
	{"(1+(2))*(5-2.5)", big.NewRat(15, 2), true}, // complex 3
	{"3*(2<4)", big.NewRat(3, 1), true},          // less than
	{"3*(2>4)", new(big.Rat), true},              // greater than
	{"5 / 0", nil, false},                        // divide by zero
	{"2 ** 3", big.NewRat(8, 1), true},           // exponent 1
	{"9.0**0.5", big.NewRat(3, 1), true},         // exponent 2
	{"4**-1", big.NewRat(1, 4), true},            // exponent 3
	{"1.23", big.NewRat(123, 100), true},
	{"-1+2", big.NewRat(1, 1), true},                                      // unary minus (the beginning of a expression)
	{"3*-4", big.NewRat(-12, 1), true},                                    // unary minus (after an operator)
	{"4/(-1+3)", big.NewRat(2, 1), true},                                  // unary minus (after '(' )
	{"-(-1+2)--2**3", big.NewRat(7, 1), true},                             // unary minus (complex)
	{"sin(1)", big.NewRat(1682941969615793, 2000000000000000), true},      // simple sin
	{"sin(1)+1", big.NewRat(3682941969615793, 2000000000000000), true},    // sin in an expression
	{"sin(1)+2**2", big.NewRat(9682941969615793, 2000000000000000), true}, // sin in more complex expression
	{"sin(2-1)", big.NewRat(1682941969615793, 2000000000000000), true},    // sin of expression
	{"sin(2**2)", big.NewRat(-3784012476539641, 5000000000000000), true},  // sin of expression
	{"1+sin(1)", big.NewRat(3682941969615793, 2000000000000000), true},    // THIS IS A BUG AND SHOULD NOT BREAK
	{"cos(1)", big.NewRat(2701511529340699, 5000000000000000), true},      // simple sin
	{"tan(1)", big.NewRat(778703862327451, 500000000000000), true},        // simple tan
	{"arcsin(1)", big.NewRat(7853981633974483, 5000000000000000), true},   // simple arcsin
	{"arccos(1)", big.NewRat(0, 1), true},                                 // simple arcsin
	{"arctan(1)", big.NewRat(7853981633974483, 10000000000000000), true},  // simple arcsin
	{"ln(1)", big.NewRat(0, 1), true},                                     // simple ln
	{".5 * 2", big.NewRat(1, 1), true},                                    // no leading zero
	{"1. * 2", big.NewRat(2, 1), true},                                    // no trailing numbers
	{". * 2", nil, false},                                                 // decimal, but no numbers at all
}

func TestEval(t *testing.T) {
	for i, test := range testsEval {
		ret, err := evaler.Eval(test.in)
		if ret == nil && test.out == nil {
			// ok, do nothing
		} else if ret == nil || test.out == nil {
			t.Errorf("#%d: %s: unexpected nil result: %v vs %v", i, test.in, ret, test.out)
		} else if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: %s: bad result: got %v expected %v", i, test.in, ret, test.out)
		}
		if (err == nil) != test.ok {
			t.Errorf("#%d: %s: unexpected err result: %t vs %t", i, test.in, (err == nil), test.ok)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToInt = []struct {
	in  *big.Rat
	out int64
	ok  bool
}{
	{big.NewRat(4, 2), int64(2), true},
	{big.NewRat(5, 2), int64(3), true},
	{big.NewRat(-4, 2), int64(-2), true},
	{new(big.Rat).Mul(big.NewRat(math.MaxInt64, 1), big.NewRat(math.MaxInt64, 1)), int64(0), false},
}

func TestBigratToInt(t *testing.T) {
	for i, test := range testsBigratToInt {
		ret, err := evaler.BigratToInt(test.in)
		if test.ok && (ret != test.out) {
			t.Errorf("#%d: got %d expected %d", i, ret, test.out)
		}
		if (err == nil) != test.ok {
			t.Errorf("#%d: %s: unexpected err result: %t vs %t", i, test.in, (err == nil), test.ok)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToBigint = []struct {
	in  *big.Rat
	out *big.Int
}{
	{big.NewRat(4, 2), big.NewInt(2)},
	{big.NewRat(5, 2), big.NewInt(3)},
	{big.NewRat(-4, 2), big.NewInt(-2)},
}

func TestBigratToBigint(t *testing.T) {
	for i, test := range testsBigratToBigint {
		ret := evaler.BigratToBigint(test.in)
		if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: got %d expected %d", i, ret, test.out)
		}
	}
}

// -----------------------------------------------------------------------------

var testsBigratToFloat = []struct {
	in  *big.Rat
	out float64
}{
	{big.NewRat(4, 2), float64(2.0)},
	{big.NewRat(5, 2), float64(2.5)},
	{big.NewRat(-4, 2), float64(-2.0)},
}

func TestBigratToFloat(t *testing.T) {
	for i, test := range testsBigratToFloat {
		ret := evaler.BigratToFloat(test.in)
		if ret != test.out {
			t.Errorf("#%d: got %f expected %f", i, ret, test.out)
		}
	}
}

// -----------------------------------------------------------------------------

var testsFloatToBigrat = []struct {
	in  float64
	out *big.Rat
}{
	{float64(2.0), big.NewRat(4, 2)},
	{float64(2.5), big.NewRat(5, 2)},
	{float64(-2.0), big.NewRat(-4, 2)},
}

func TestFloatToBigrat(t *testing.T) {
	for i, test := range testsFloatToBigrat {
		ret := evaler.FloatToBigrat(test.in)
		if ret.Cmp(test.out) != 0 {
			t.Errorf("#%d: got %s expected %s", i, ret, test.out)
		}
	}
}
<|endoftext|>


<commit_before>package sharings

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"

	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/tests/testutils"
	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var testInstance *instance.Instance
var clientOAuth *oauth.Client
var clientID string
var instanceURL *url.URL

func TestRecipientRefusedSharingWithNoState(t *testing.T) {
	res, err := postForm("/sharings/formRefuse", &url.Values{
		"state": {""},
	})
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, "400 Bad Request", res.Status)
}

func TestRecipientRefusedSharingWithNoClientID(t *testing.T) {
	res, err := postForm("/sharings/formRefuse", &url.Values{
		"state":     {"dummystate"},
		"client_id": {""},
	})
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, "400 Bad Request", res.Status)
}

func TestSharingAnswerBadState(t *testing.T) {
	state := ""
	res, err := postJSON("/sharings/answer", echo.Map{
		"state": state,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestSharingAnswerBadClientID(t *testing.T) {
	state := "stateoftheart"
	clientID2 := "myclient"
	res, err := postJSON("/sharings/answer", echo.Map{
		"state":     state,
		"client_id": clientID2,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestSharingRequestNoScope(t *testing.T) {
	urlVal := url.Values{
		"state":        {"dummystate"},
		"sharing_type": {consts.OneShotSharing},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 400, res.StatusCode)
}

func TestSharingRequestNoState(t *testing.T) {
	urlVal := url.Values{
		"scope": {"dummyscope"},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 400, res.StatusCode)
}

func TestSharingRequestNoSharingType(t *testing.T) {
	urlVal := url.Values{
		"scope": {"dummyscope"},
		"state": {"dummystate"},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
}

func TestSharingRequestBadScope(t *testing.T) {
	urlVal := url.Values{
		"scope":        []string{":"},
		"state":        {"dummystate"},
		"sharing_type": {consts.OneShotSharing},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 500, res.StatusCode)
}

func TestSharingRequestSuccess(t *testing.T) {

	rule := permissions.Rule{
		Type:        "io.cozy.events",
		Title:       "event",
		Description: "My event",
		Verbs:       permissions.VerbSet{permissions.POST: {}},
		Values:      []string{"1234"},
	}
	set := permissions.Set{rule}
	scope, err := set.MarshalScopeString()
	assert.NoError(t, err)

	state := "sharing_id"
	desc := "share cher"

	urlVal := url.Values{
		"desc":          {desc},
		"state":         {state},
		"scope":         {scope},
		"sharing_type":  {consts.OneShotSharing},
		"client_id":     {clientID},
		"redirect_uri":  {clientOAuth.RedirectURIs[0]},
		"response_type": {"code"},
	}

	req, _ := http.NewRequest("GET", ts.URL+"/sharings/request?"+urlVal.Encode(), nil)
	noRedirectClient := http.Client{CheckRedirect: noRedirect}
	res, err := noRedirectClient.Do(req)
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, http.StatusSeeOther, res.StatusCode)
}

func TestCreateSharingWithBadType(t *testing.T) {
	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": "shary pie",
	})
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
}

func TestSendMailsWithWrongSharingID(t *testing.T) {
	req, _ := http.NewRequest("PUT", ts.URL+"/sharings/wrongid/sendMails",
		nil)

	res, err := http.DefaultClient.Do(req)

	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestCreateSharingWithNonExistingRecipient(t *testing.T) {
	type recipient map[string]map[string]string

	rec := recipient{
		"recipient": {
			"id": "hodor",
		},
	}
	recipients := []recipient{rec}

	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": consts.OneShotSharing,
		"recipients":   recipients,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestCreateSharingSuccess(t *testing.T) {
	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": consts.OneShotSharing,
	})
	assert.NoError(t, err)
	assert.Equal(t, 201, res.StatusCode)
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	testutils.NeedCouchdb()
	setup := testutils.NewSetup(m, "sharing_test")
	testInstance = setup.GetTestInstance()
	instanceURL, _ = url.Parse("https://" + testInstance.Domain + "/")

	clientOAuth, _ = setup.GetTestClient("")
	clientID = clientOAuth.ClientID

	ts = setup.GetTestServer("/sharings", Routes)
	os.Exit(setup.Run())
}

func postJSON(u string, v echo.Map) (*http.Response, error) {
	body, _ := json.Marshal(v)
	return http.Post(ts.URL+u, "application/json", bytes.NewReader(body))
}

func requestGET(u string, v url.Values) (*http.Response, error) {
	if v != nil {
		reqURL := v.Encode()
		return http.Get(ts.URL + u + "?" + reqURL)
	}
	return http.Get(ts.URL + u)
}

func postForm(u string, v *url.Values) (*http.Response, error) {
	req, _ := http.NewRequest("POST", ts.URL+u, bytes.NewBufferString(v.Encode()))
	req.Host = domain
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(req)
}

func extractJSONRes(res *http.Response, mp *map[string]interface{}) error {
	if res.StatusCode >= 300 {
		return nil
	}
	return json.NewDecoder(res.Body).Decode(mp)
}

func injectInstance(i *instance.Instance) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set("instance", i)
			return next(c)
		}
	}
}

func noRedirect(*http.Request, []*http.Request) error {
	return http.ErrUseLastResponse
}
<commit_msg>Rebase cozy/master and fix tests<commit_after>package sharings

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"

	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/tests/testutils"
	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var testInstance *instance.Instance
var clientOAuth *oauth.Client
var clientID string
var instanceURL *url.URL
var jar http.CookieJar
var client *http.Client

func TestRecipientRefusedSharingWithNoState(t *testing.T) {
	res, err := postForm("/sharings/formRefuse", &url.Values{
		"state": {""},
	})
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, "400 Bad Request", res.Status)
}

func TestRecipientRefusedSharingWithNoClientID(t *testing.T) {
	res, err := postForm("/sharings/formRefuse", &url.Values{
		"state":     {"dummystate"},
		"client_id": {""},
	})
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, "400 Bad Request", res.Status)
}

func TestSharingAnswerBadState(t *testing.T) {
	state := ""
	res, err := postJSON("/sharings/answer", echo.Map{
		"state": state,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestSharingAnswerBadClientID(t *testing.T) {
	state := "stateoftheart"
	clientID2 := "myclient"
	res, err := postJSON("/sharings/answer", echo.Map{
		"state":     state,
		"client_id": clientID2,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestSharingRequestNoScope(t *testing.T) {
	urlVal := url.Values{
		"state":        {"dummystate"},
		"sharing_type": {consts.OneShotSharing},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 400, res.StatusCode)
}

func TestSharingRequestNoState(t *testing.T) {
	urlVal := url.Values{
		"scope": {"dummyscope"},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 400, res.StatusCode)
}

func TestSharingRequestNoSharingType(t *testing.T) {
	urlVal := url.Values{
		"scope": {"dummyscope"},
		"state": {"dummystate"},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
}

func TestSharingRequestBadScope(t *testing.T) {
	urlVal := url.Values{
		"scope":        []string{":"},
		"state":        {"dummystate"},
		"sharing_type": {consts.OneShotSharing},
	}
	res, err := requestGET("/sharings/request", urlVal)
	assert.NoError(t, err)
	assert.Equal(t, 500, res.StatusCode)
}

func TestSharingRequestSuccess(t *testing.T) {

	rule := permissions.Rule{
		Type:        "io.cozy.events",
		Title:       "event",
		Description: "My event",
		Verbs:       permissions.VerbSet{permissions.POST: {}},
		Values:      []string{"1234"},
	}
	set := permissions.Set{rule}
	scope, err := set.MarshalScopeString()
	assert.NoError(t, err)

	state := "sharing_id"
	desc := "share cher"

	urlVal := url.Values{
		"desc":          {desc},
		"state":         {state},
		"scope":         {scope},
		"sharing_type":  {consts.OneShotSharing},
		"client_id":     {clientID},
		"redirect_uri":  {clientOAuth.RedirectURIs[0]},
		"response_type": {"code"},
	}

	req, _ := http.NewRequest("GET", ts.URL+"/sharings/request?"+urlVal.Encode(), nil)
	noRedirectClient := http.Client{CheckRedirect: noRedirect}
	res, err := noRedirectClient.Do(req)
	assert.NoError(t, err)
	defer res.Body.Close()
	assert.Equal(t, http.StatusSeeOther, res.StatusCode)
}

func TestCreateSharingWithBadType(t *testing.T) {
	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": "shary pie",
	})
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
}

func TestSendMailsWithWrongSharingID(t *testing.T) {
	req, _ := http.NewRequest("PUT", ts.URL+"/sharings/wrongid/sendMails",
		nil)

	res, err := http.DefaultClient.Do(req)

	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestCreateSharingWithNonExistingRecipient(t *testing.T) {
	type recipient map[string]map[string]string

	rec := recipient{
		"recipient": {
			"id": "hodor",
		},
	}
	recipients := []recipient{rec}

	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": consts.OneShotSharing,
		"recipients":   recipients,
	})
	assert.NoError(t, err)
	assert.Equal(t, 404, res.StatusCode)
}

func TestCreateSharingSuccess(t *testing.T) {
	res, err := postJSON("/sharings/", echo.Map{
		"sharing_type": consts.OneShotSharing,
	})
	assert.NoError(t, err)
	assert.Equal(t, 201, res.StatusCode)
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	testutils.NeedCouchdb()
	setup := testutils.NewSetup(m, "sharing_test")
	testInstance = setup.GetTestInstance()
	instanceURL, _ = url.Parse("https://" + testInstance.Domain + "/")

	jar = setup.GetCookieJar()
	client = &http.Client{
		CheckRedirect: noRedirect,
		Jar:           jar,
	}

	clientOAuth, _ = setup.GetTestClient("")
	clientID = clientOAuth.ClientID

	ts = setup.GetTestServer("/sharings", Routes)
	os.Exit(setup.Run())
}

func postJSON(u string, v echo.Map) (*http.Response, error) {
	body, _ := json.Marshal(v)
	return http.Post(ts.URL+u, "application/json", bytes.NewReader(body))
}

func requestGET(u string, v url.Values) (*http.Response, error) {
	if v != nil {
		reqURL := v.Encode()
		return http.Get(ts.URL + u + "?" + reqURL)
	}
	return http.Get(ts.URL + u)
}

func postForm(u string, v *url.Values) (*http.Response, error) {
	req, _ := http.NewRequest("POST", ts.URL+u, bytes.NewBufferString(v.Encode()))
	req.Host = testInstance.Domain
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(req)
}

func extractJSONRes(res *http.Response, mp *map[string]interface{}) error {
	if res.StatusCode >= 300 {
		return nil
	}
	return json.NewDecoder(res.Body).Decode(mp)
}

func injectInstance(i *instance.Instance) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			c.Set("instance", i)
			return next(c)
		}
	}
}

func noRedirect(*http.Request, []*http.Request) error {
	return http.ErrUseLastResponse
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/namsral/flag"

	"github.com/ligato/cn-infra/logging/logrus"
)

const (
	// FlagSuffix is added to plugin name while loading plugins configuration.
	FlagSuffix = "-config"

	// EnvSuffix is added to plugin name while loading plugins configuration from ENV variable.
	EnvSuffix = "_CONFIG"

	// FileExtension is used as a default extension for config files in flags.
	FileExtension = ".conf"
)

// FlagName returns config flag name for the name, usually plugin.
func FlagName(name string) string {
	return strings.ToLower(name) + FlagSuffix
}

// Filename returns config filename for the name, usually plugin.
func Filename(name string) string {
	return name + FileExtension
}

// EnvVar returns config env variable for the name, usually plugin.
func EnvVar(name string) string {
	return strings.ToUpper(name) + EnvSuffix
}

const (
	// DirFlag as flag name (see implementation in declareFlags())
	// is used to define default directory where config files reside.
	// This flag name is derived from the name of the plugin.
	DirFlag = "config-dir"

	// DirDefault holds a default value "." for flag, which represents current working directory.
	DirDefault = "."

	// DirUsage used as a flag (see implementation in declareFlags()).
	DirUsage = "Location of the config files; can also be set via 'CONFIG_DIR' env variable."
)

// DefineDirFlag defines flag for configuration directory.
func DefineDirFlag() {
	if flag.CommandLine.Lookup(DirFlag) == nil {
		flag.CommandLine.String(DirFlag, DirDefault, DirUsage)
	}
}

// PluginConfig is API for plugins to access configuration.
//
// Aim of this API is to let a particular plugin to bind it's configuration
// without knowing a particular key name. The key name is injected into Plugin.
type PluginConfig interface {
	// LoadValue parses configuration for a plugin and stores the results in data.
	// The argument data is a pointer to an instance of a go structure.
	LoadValue(data interface{}) (found bool, err error)

	// GetConfigName returns config name derived from plugin name:
	// flag = PluginName + FlagSuffix (evaluated most often as absolute path to a config file)
	GetConfigName() string
}

// FlagSet is a type alias for flag.FlagSet.
type FlagSet = flag.FlagSet

// pluginFlags is used for storing flags for Plugins before agent starts.
var pluginFlags = make(map[string]*FlagSet)

// DefineFlagsFor registers defined flags for plugin with given name.
func DefineFlagsFor(name string) {
	if plugSet, ok := pluginFlags[name]; ok {
		plugSet.VisitAll(func(f *flag.Flag) {
			flag.CommandLine.Var(f.Value, f.Name, f.Usage)
		})
	}
}

type options struct {
	FlagName    string
	FlagDefault string
	FlagUsage   string

	flagSet *FlagSet
}

// Option is an option used in ForPlugin
type Option func(*options)

// WithCustomizedFlag is an option to customize config flag for plugin in ForPlugin.
// The parameters are used to replace defaults in this order: flag name, default, usage.
func WithCustomizedFlag(s ...string) Option {
	return func(o *options) {
		if len(s) > 0 {
			o.FlagName = s[0]
		}
		if len(s) > 1 {
			o.FlagDefault = s[1]
		}
		if len(s) > 2 {
			o.FlagUsage = s[2]
		}
	}
}

// WithExtraFlags is an option to define additional flags for plugin in ForPlugin.
func WithExtraFlags(f func(flags *FlagSet)) Option {
	return func(o *options) {
		f(o.flagSet)
	}
}

// ForPlugin returns API that is injectable to a particular Plugin
// and is used to read it's configuration.
//
// By default it tries to lookup `<plugin-name> + "-config"`in flags and declare
// the flag if it's not defined yet. There are options that can be used
// to customize the config flag for plugin and/or define additional flags for the plugin.
func ForPlugin(name string, opts ...Option) PluginConfig {
	opt := options{
		FlagName:    FlagName(name),
		FlagDefault: Filename(name),
		FlagUsage: fmt.Sprintf("Location of the %q plugin config file; can also be set via %q env variable.",
			name, EnvVar(name)),
		flagSet: flag.NewFlagSet(name, flag.ExitOnError),
	}
	for _, o := range opts {
		o(&opt)
	}

	if opt.FlagName != "" && opt.flagSet.Lookup(opt.FlagName) == nil {
		opt.flagSet.String(opt.FlagName, opt.FlagDefault, opt.FlagUsage)
	}

	pluginFlags[name] = opt.flagSet

	return &pluginConfig{
		configFlag: opt.FlagName,
	}
}

// Dir returns config directory by evaluating the flag DirFlag. It interprets "." as current working directory.
func Dir() (dir string, err error) {
	if flg := flag.CommandLine.Lookup(DirFlag); flg != nil {
		val := flg.Value.String()
		if strings.HasPrefix(val, ".") {
			cwd, err := os.Getwd()
			if err != nil {
				return cwd, err
			}
			if len(val) > 1 {
				return filepath.Join(cwd, val[1:]), nil
			}
			return cwd, nil
		}
		return val, nil
	}
	return "", nil
}

type pluginConfig struct {
	configFlag string
	access     sync.Mutex
	configName string
}

// LoadValue binds the configuration to config method argument.
func (p *pluginConfig) LoadValue(config interface{}) (found bool, err error) {
	cfgName := p.GetConfigName()
	if cfgName == "" {
		return false, nil
	}

	// TODO: switch to Viper (possible to have one huge config file)
	err = ParseConfigFromYamlFile(cfgName, config)
	if err != nil {
		return false, err
	}

	return true, nil
}

// GetConfigName looks up flag value and uses it to:
// 1. Find config in flag value location.
// 2. Alternatively, it tries to find it in config dir
// (see also Dir() comments).
func (p *pluginConfig) GetConfigName() string {
	p.access.Lock()
	defer p.access.Unlock()
	if p.configName == "" {
		p.configName = p.getConfigName()
	}
	return p.configName
}

func (p *pluginConfig) getConfigName() string {
	if flg := flag.CommandLine.Lookup(p.configFlag); flg != nil {
		if val := flg.Value.String(); val != "" {
			// if the file exists (value from flag)
			if _, err := os.Stat(val); !os.IsNotExist(err) {
				return val
			}
			cfgDir, err := Dir()
			if err != nil {
				logrus.DefaultLogger().Error(err)
				return ""
			}
			// if the file exists (flag value in config dir)
			dirVal := filepath.Join(cfgDir, val)
			if _, err := os.Stat(dirVal); !os.IsNotExist(err) {
				return dirVal
			}
		}
	}
	return ""
}
<commit_msg>Properly handle config dir paths starting with parent ref "..".<commit_after>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/namsral/flag"

	"github.com/ligato/cn-infra/logging/logrus"
)

const (
	// FlagSuffix is added to plugin name while loading plugins configuration.
	FlagSuffix = "-config"

	// EnvSuffix is added to plugin name while loading plugins configuration from ENV variable.
	EnvSuffix = "_CONFIG"

	// FileExtension is used as a default extension for config files in flags.
	FileExtension = ".conf"
)

// FlagName returns config flag name for the name, usually plugin.
func FlagName(name string) string {
	return strings.ToLower(name) + FlagSuffix
}

// Filename returns config filename for the name, usually plugin.
func Filename(name string) string {
	return name + FileExtension
}

// EnvVar returns config env variable for the name, usually plugin.
func EnvVar(name string) string {
	return strings.ToUpper(name) + EnvSuffix
}

const (
	// DirFlag as flag name (see implementation in declareFlags())
	// is used to define default directory where config files reside.
	// This flag name is derived from the name of the plugin.
	DirFlag = "config-dir"

	// DirDefault holds a default value "." for flag, which represents current working directory.
	DirDefault = "."

	// DirUsage used as a flag (see implementation in declareFlags()).
	DirUsage = "Location of the config files; can also be set via 'CONFIG_DIR' env variable."
)

// DefineDirFlag defines flag for configuration directory.
func DefineDirFlag() {
	if flag.CommandLine.Lookup(DirFlag) == nil {
		flag.CommandLine.String(DirFlag, DirDefault, DirUsage)
	}
}

// PluginConfig is API for plugins to access configuration.
//
// Aim of this API is to let a particular plugin to bind it's configuration
// without knowing a particular key name. The key name is injected into Plugin.
type PluginConfig interface {
	// LoadValue parses configuration for a plugin and stores the results in data.
	// The argument data is a pointer to an instance of a go structure.
	LoadValue(data interface{}) (found bool, err error)

	// GetConfigName returns config name derived from plugin name:
	// flag = PluginName + FlagSuffix (evaluated most often as absolute path to a config file)
	GetConfigName() string
}

// FlagSet is a type alias for flag.FlagSet.
type FlagSet = flag.FlagSet

// pluginFlags is used for storing flags for Plugins before agent starts.
var pluginFlags = make(map[string]*FlagSet)

// DefineFlagsFor registers defined flags for plugin with given name.
func DefineFlagsFor(name string) {
	if plugSet, ok := pluginFlags[name]; ok {
		plugSet.VisitAll(func(f *flag.Flag) {
			flag.CommandLine.Var(f.Value, f.Name, f.Usage)
		})
	}
}

type options struct {
	FlagName    string
	FlagDefault string
	FlagUsage   string

	flagSet *FlagSet
}

// Option is an option used in ForPlugin
type Option func(*options)

// WithCustomizedFlag is an option to customize config flag for plugin in ForPlugin.
// The parameters are used to replace defaults in this order: flag name, default, usage.
func WithCustomizedFlag(s ...string) Option {
	return func(o *options) {
		if len(s) > 0 {
			o.FlagName = s[0]
		}
		if len(s) > 1 {
			o.FlagDefault = s[1]
		}
		if len(s) > 2 {
			o.FlagUsage = s[2]
		}
	}
}

// WithExtraFlags is an option to define additional flags for plugin in ForPlugin.
func WithExtraFlags(f func(flags *FlagSet)) Option {
	return func(o *options) {
		f(o.flagSet)
	}
}

// ForPlugin returns API that is injectable to a particular Plugin
// and is used to read it's configuration.
//
// By default it tries to lookup `<plugin-name> + "-config"`in flags and declare
// the flag if it's not defined yet. There are options that can be used
// to customize the config flag for plugin and/or define additional flags for the plugin.
func ForPlugin(name string, opts ...Option) PluginConfig {
	opt := options{
		FlagName:    FlagName(name),
		FlagDefault: Filename(name),
		FlagUsage: fmt.Sprintf("Location of the %q plugin config file; can also be set via %q env variable.",
			name, EnvVar(name)),
		flagSet: flag.NewFlagSet(name, flag.ExitOnError),
	}
	for _, o := range opts {
		o(&opt)
	}

	if opt.FlagName != "" && opt.flagSet.Lookup(opt.FlagName) == nil {
		opt.flagSet.String(opt.FlagName, opt.FlagDefault, opt.FlagUsage)
	}

	pluginFlags[name] = opt.flagSet

	return &pluginConfig{
		configFlag: opt.FlagName,
	}
}

// Dir returns config directory by evaluating the flag DirFlag. It interprets "." as current working directory.
func Dir() (dir string, err error) {
	if flg := flag.CommandLine.Lookup(DirFlag); flg != nil {
		val := flg.Value.String()
		if strings.HasPrefix(val, ".") {
			cwd, err := os.Getwd()
			if err != nil {
				return cwd, err
			}
			return filepath.Join(cwd, val), nil
		}
		return val, nil
	}
	return "", nil
}

type pluginConfig struct {
	configFlag string
	access     sync.Mutex
	configName string
}

// LoadValue binds the configuration to config method argument.
func (p *pluginConfig) LoadValue(config interface{}) (found bool, err error) {
	cfgName := p.GetConfigName()
	if cfgName == "" {
		return false, nil
	}

	// TODO: switch to Viper (possible to have one huge config file)
	err = ParseConfigFromYamlFile(cfgName, config)
	if err != nil {
		return false, err
	}

	return true, nil
}

// GetConfigName looks up flag value and uses it to:
// 1. Find config in flag value location.
// 2. Alternatively, it tries to find it in config dir
// (see also Dir() comments).
func (p *pluginConfig) GetConfigName() string {
	p.access.Lock()
	defer p.access.Unlock()
	if p.configName == "" {
		p.configName = p.getConfigName()
	}
	return p.configName
}

func (p *pluginConfig) getConfigName() string {
	if flg := flag.CommandLine.Lookup(p.configFlag); flg != nil {
		if val := flg.Value.String(); val != "" {
			// if the file exists (value from flag)
			if _, err := os.Stat(val); !os.IsNotExist(err) {
				return val
			}
			cfgDir, err := Dir()
			if err != nil {
				logrus.DefaultLogger().Error(err)
				return ""
			}
			// if the file exists (flag value in config dir)
			dirVal := filepath.Join(cfgDir, val)
			if _, err := os.Stat(dirVal); !os.IsNotExist(err) {
				return dirVal
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
)

func TestEventsErrorInOptions(t *testing.T) {
	errorCases := []struct {
		options       types.EventsOptions
		expectedError string
	}{
		{
			options: types.EventsOptions{
				Since: "2006-01-02TZ",
			},
			expectedError: `parsing time "2006-01-02TZ"`,
		},
		{
			options: types.EventsOptions{
				Until: "2006-01-02TZ",
			},
			expectedError: `parsing time "2006-01-02TZ"`,
		},
	}
	for _, e := range errorCases {
		client := &Client{
			transport: newMockClient(nil, errorMock(http.StatusInternalServerError, "Server error")),
		}
		_, err := client.Events(context.Background(), e.options)
		if err == nil || !strings.Contains(err.Error(), e.expectedError) {
			t.Fatalf("expected a error %q, got %v", e.expectedError, err)
		}
	}
}

func TestEventsErrorFromServer(t *testing.T) {
	client := &Client{
		transport: newMockClient(nil, errorMock(http.StatusInternalServerError, "Server error")),
	}
	_, err := client.Events(context.Background(), types.EventsOptions{})
	if err == nil || err.Error() != "Error response from daemon: Server error" {
		t.Fatalf("expected a Server Error, got %v", err)
	}
}

func TestEvents(t *testing.T) {
	expectedURL := "/events"

	filters := filters.NewArgs()
	filters.Add("label", "label1")
	filters.Add("label", "label2")
	expectedFiltersJSON := `{"label":{"label1":true,"label2":true}}`

	eventsCases := []struct {
		options             types.EventsOptions
		expectedQueryParams map[string]string
	}{
		{
			options: types.EventsOptions{
				Since: "invalid but valid",
			},
			expectedQueryParams: map[string]string{
				"since": "invalid but valid",
			},
		},
		{
			options: types.EventsOptions{
				Until: "invalid but valid",
			},
			expectedQueryParams: map[string]string{
				"until": "invalid but valid",
			},
		},
		{
			options: types.EventsOptions{
				Filters: filters,
			},
			expectedQueryParams: map[string]string{
				"filters": expectedFiltersJSON,
			},
		},
	}

	for _, eventsCase := range eventsCases {
		client := &Client{
			transport: newMockClient(nil, func(req *http.Request) (*http.Response, error) {
				if !strings.HasPrefix(req.URL.Path, expectedURL) {
					return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
				}
				query := req.URL.Query()
				for key, expected := range eventsCase.expectedQueryParams {
					actual := query.Get(key)
					if actual != expected {
						return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
					}
				}
				return &http.Response{
					StatusCode: http.StatusOK,
					Body:       ioutil.NopCloser(bytes.NewReader([]byte("response"))),
				}, nil
			}),
		}
		body, err := client.Events(context.Background(), eventsCase.options)
		if err != nil {
			t.Fatal(err)
		}
		defer body.Close()
		content, err := ioutil.ReadAll(body)
		if err != nil {
			t.Fatal(err)
		}
		if string(content) != "response" {
			t.Fatalf("expected response to contain 'response', got %s", string(content))
		}
	}
}
<commit_msg>correct some nits in comments<commit_after>package client

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
)

func TestEventsErrorInOptions(t *testing.T) {
	errorCases := []struct {
		options       types.EventsOptions
		expectedError string
	}{
		{
			options: types.EventsOptions{
				Since: "2006-01-02TZ",
			},
			expectedError: `parsing time "2006-01-02TZ"`,
		},
		{
			options: types.EventsOptions{
				Until: "2006-01-02TZ",
			},
			expectedError: `parsing time "2006-01-02TZ"`,
		},
	}
	for _, e := range errorCases {
		client := &Client{
			transport: newMockClient(nil, errorMock(http.StatusInternalServerError, "Server error")),
		}
		_, err := client.Events(context.Background(), e.options)
		if err == nil || !strings.Contains(err.Error(), e.expectedError) {
			t.Fatalf("expected an error %q, got %v", e.expectedError, err)
		}
	}
}

func TestEventsErrorFromServer(t *testing.T) {
	client := &Client{
		transport: newMockClient(nil, errorMock(http.StatusInternalServerError, "Server error")),
	}
	_, err := client.Events(context.Background(), types.EventsOptions{})
	if err == nil || err.Error() != "Error response from daemon: Server error" {
		t.Fatalf("expected a Server Error, got %v", err)
	}
}

func TestEvents(t *testing.T) {
	expectedURL := "/events"

	filters := filters.NewArgs()
	filters.Add("label", "label1")
	filters.Add("label", "label2")
	expectedFiltersJSON := `{"label":{"label1":true,"label2":true}}`

	eventsCases := []struct {
		options             types.EventsOptions
		expectedQueryParams map[string]string
	}{
		{
			options: types.EventsOptions{
				Since: "invalid but valid",
			},
			expectedQueryParams: map[string]string{
				"since": "invalid but valid",
			},
		},
		{
			options: types.EventsOptions{
				Until: "invalid but valid",
			},
			expectedQueryParams: map[string]string{
				"until": "invalid but valid",
			},
		},
		{
			options: types.EventsOptions{
				Filters: filters,
			},
			expectedQueryParams: map[string]string{
				"filters": expectedFiltersJSON,
			},
		},
	}

	for _, eventsCase := range eventsCases {
		client := &Client{
			transport: newMockClient(nil, func(req *http.Request) (*http.Response, error) {
				if !strings.HasPrefix(req.URL.Path, expectedURL) {
					return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
				}
				query := req.URL.Query()
				for key, expected := range eventsCase.expectedQueryParams {
					actual := query.Get(key)
					if actual != expected {
						return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
					}
				}
				return &http.Response{
					StatusCode: http.StatusOK,
					Body:       ioutil.NopCloser(bytes.NewReader([]byte("response"))),
				}, nil
			}),
		}
		body, err := client.Events(context.Background(), eventsCase.options)
		if err != nil {
			t.Fatal(err)
		}
		defer body.Close()
		content, err := ioutil.ReadAll(body)
		if err != nil {
			t.Fatal(err)
		}
		if string(content) != "response" {
			t.Fatalf("expected response to contain 'response', got %s", string(content))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"errors"
	"flag"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/replaygaming/consumer"
	"github.com/replaygaming/eventsource"
)

var (
	topicName = flag.String("topic",
		fromEnvWithDefault("ES_TOPIC", "eventsource"),
		"Topic name")

	subscriptionName = flag.String("subscription",
		fromEnvWithDefault("ES_SUBSCRIPTION", "eventsource_"+generateSubId()),
		"Subscription name")

	port = flag.String("port",
		fromEnvWithDefault("ES_PORT", "80"),
		"Eventsource port")

	useMetrics = flag.Bool("metrics", os.Getenv("ES_METRICS") == "true", "Enable metrics")

	metricsPrefix = flag.String("metrics-prefix",
		fromEnvWithDefault("ES_METRICS_PREFIX", "production"),
		"Metrics prefix")

	metricsProvider = flag.String("metrics-provider",
		fromEnvWithDefault("ES_METRICS_PROVIDER", "log"),
		"Metrics provider. Available ones are: stackdriver and log")

	compress = flag.Bool("compression", os.Getenv("ES_COMPRESSION") == "true", "Enable zlib compression of data")

	verbose = flag.Bool("verbose", os.Getenv("ES_VERBOSE") == "true", "Enable verbose output")
)

func init() {
	flag.Parse()
}

// Create a new eventsource server, optionally with metrics
func newServerWithMetrics() *eventsource.Eventsource {
	server := &eventsource.Eventsource{
		ChannelSubscriber: eventsource.QueryStringChannels{Name: "channels"},
	}

	if *useMetrics {
		metrics, err := newMetrics()
		if err != nil {
			Fatal("Could not instantiate metrics", err)
		}
		server.Metrics = metrics
	}
	server.Start()
	return server
}

func newMetrics() (eventsource.Metrics, error) {
	Info("Instantiating " + *metricsProvider + " metrics")
	switch *metricsProvider {
	case "stackdriver":
		return NewStackdriverMetrics(*metricsPrefix, *subscriptionName)
	case "log":
		return NewLogMetrics(*metricsPrefix)
	default:
		return nil, errors.New("Don't know how to instantiate metrics provider: " + *metricsProvider)
	}
}

// Create new message consumer
func newConsumer() consumer.Consumer {
	return consumer.NewConsumer(*topicName, *subscriptionName)
}

// Create the channel that we'll receive messages
func consume(c consumer.Consumer) <-chan consumer.Message {
	messages, err := c.Consume()
	if err != nil {
		Fatal("Failed to consume messages", err)
	}
	return messages
}

// Pulls out messages from the channel
func messageLoop(messages <-chan consumer.Message, server *eventsource.Eventsource, c consumer.Consumer) {
	for m := range messages {
		messageData := m.Data()
		if *verbose {
			Debug("Got message: %s", string(messageData))
		}
		data, channels, err := parseMessage(messageData)
		if err != nil {
			Warn("json conversion failed %s", err)
		} else {
			e := eventsource.DefaultEvent{
				Message:  data,
				Channels: channels,
				Compress: *compress,
			}
			server.Send(e)
		}
		m.Done(true)
	}
}

// Handle GET /
func heartbeat(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
}

// Start HTTP server
func startServing(server *eventsource.Eventsource) {
	http.HandleFunc("/", heartbeat)
	http.Handle("/subscribe", server)

	Info("EventSource server started")
	Info("Configuration: port=%s subscription=%s topic=%s"+
		" compression=%t metrics=%t", *port, *subscriptionName,
		*topicName, *compress, *useMetrics)
	if *useMetrics {
		Info("Metrics configuration: metrics-prefix=%s", *metricsPrefix)
	}
	err := http.ListenAndServe(":"+*port, nil)
	if err != nil {
		Fatal("Error starting HTTP server: %v", err)
	}
}

func main() {
	server := newServerWithMetrics()
	c := newConsumer()
	messages := consume(c)

	setupSignalHandlers(c)

	if *verbose {
		go errorLoop(server)
	}
	go messageLoop(messages, server, c)

	startServing(server)
}

func errorLoop(server *eventsource.Eventsource) {
	for err := range server.Errors() {
		Error("Error: %v", err)
	}
}

var shuttingDown = false

// Catch signals to perform a graceful shutdown
func setupSignalHandlers(consumer consumer.Consumer) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		if shuttingDown {
			os.Exit(1)
		}
		Info("Shutting down gracefully. Repeat signal to force shutdown")
		shuttingDown = true
		Info("Removing consumer")
		err := consumer.Remove()
		if err != nil {
			Fatal("Could not remove subscription %s: %v", *subscriptionName, err)
		}
		Info("Consumer removed successfully. Exiting")
		os.Exit(0)
	}()
}

// Generates a random hexadecimal string
func generateSubId() string {
	id := make([]byte, 4)
	todo := len(id)
	offset := 0
	source := rand.NewSource(time.Now().UnixNano())
	for {
		val := int64(source.Int63())
		for i := 0; i < 8; i++ {
			id[offset] = byte(val & 0xff)
			todo--
			if todo == 0 {
				return hex.EncodeToString(id)
			}
			offset++
			val >>= 8
		}
	}
}

// Attempts to get a value from the environment with a default
func fromEnvWithDefault(varName string, defaultValue string) string {
	value := os.Getenv(varName)
	if value != "" {
		return value
	} else {
		return defaultValue
	}
}
<commit_msg>Always consume errors, but only show if verbose is true<commit_after>package main

import (
	"encoding/hex"
	"errors"
	"flag"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/replaygaming/consumer"
	"github.com/replaygaming/eventsource"
)

var (
	topicName = flag.String("topic",
		fromEnvWithDefault("ES_TOPIC", "eventsource"),
		"Topic name")

	subscriptionName = flag.String("subscription",
		fromEnvWithDefault("ES_SUBSCRIPTION", "eventsource_"+generateSubId()),
		"Subscription name")

	port = flag.String("port",
		fromEnvWithDefault("ES_PORT", "80"),
		"Eventsource port")

	useMetrics = flag.Bool("metrics", os.Getenv("ES_METRICS") == "true", "Enable metrics")

	metricsPrefix = flag.String("metrics-prefix",
		fromEnvWithDefault("ES_METRICS_PREFIX", "production"),
		"Metrics prefix")

	metricsProvider = flag.String("metrics-provider",
		fromEnvWithDefault("ES_METRICS_PROVIDER", "log"),
		"Metrics provider. Available ones are: stackdriver and log")

	compress = flag.Bool("compression", os.Getenv("ES_COMPRESSION") == "true", "Enable zlib compression of data")

	verbose = flag.Bool("verbose", os.Getenv("ES_VERBOSE") == "true", "Enable verbose output")
)

func init() {
	flag.Parse()
}

// Create a new eventsource server, optionally with metrics
func newServerWithMetrics() *eventsource.Eventsource {
	server := &eventsource.Eventsource{
		ChannelSubscriber: eventsource.QueryStringChannels{Name: "channels"},
	}

	if *useMetrics {
		metrics, err := newMetrics()
		if err != nil {
			Fatal("Could not instantiate metrics", err)
		}
		server.Metrics = metrics
	}
	server.Start()
	return server
}

func newMetrics() (eventsource.Metrics, error) {
	Info("Instantiating " + *metricsProvider + " metrics")
	switch *metricsProvider {
	case "stackdriver":
		return NewStackdriverMetrics(*metricsPrefix, *subscriptionName)
	case "log":
		return NewLogMetrics(*metricsPrefix)
	default:
		return nil, errors.New("Don't know how to instantiate metrics provider: " + *metricsProvider)
	}
}

// Create new message consumer
func newConsumer() consumer.Consumer {
	return consumer.NewConsumer(*topicName, *subscriptionName)
}

// Create the channel that we'll receive messages
func consume(c consumer.Consumer) <-chan consumer.Message {
	messages, err := c.Consume()
	if err != nil {
		Fatal("Failed to consume messages", err)
	}
	return messages
}

// Pulls out messages from the channel
func messageLoop(messages <-chan consumer.Message, server *eventsource.Eventsource, c consumer.Consumer) {
	for m := range messages {
		messageData := m.Data()
		if *verbose {
			Debug("Got message: %s", string(messageData))
		}
		data, channels, err := parseMessage(messageData)
		if err != nil {
			Warn("json conversion failed %s", err)
		} else {
			e := eventsource.DefaultEvent{
				Message:  data,
				Channels: channels,
				Compress: *compress,
			}
			server.Send(e)
		}
		m.Done(true)
	}
}

// Handle GET /
func heartbeat(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
}

// Start HTTP server
func startServing(server *eventsource.Eventsource) {
	http.HandleFunc("/", heartbeat)
	http.Handle("/subscribe", server)

	Info("EventSource server started")
	Info("Configuration: port=%s subscription=%s topic=%s"+
		" compression=%t metrics=%t", *port, *subscriptionName,
		*topicName, *compress, *useMetrics)
	if *useMetrics {
		Info("Metrics configuration: metrics-prefix=%s", *metricsPrefix)
	}
	err := http.ListenAndServe(":"+*port, nil)
	if err != nil {
		Fatal("Error starting HTTP server: %v", err)
	}
}

func main() {
	server := newServerWithMetrics()
	c := newConsumer()
	messages := consume(c)

	setupSignalHandlers(c)

	go errorLoop(server)
	go messageLoop(messages, server, c)

	startServing(server)
}

func errorLoop(server *eventsource.Eventsource) {
	for err := range server.Errors() {
		if *verbose {
			Error("Error: %v", err)
		}
	}
}

var shuttingDown = false

// Catch signals to perform a graceful shutdown
func setupSignalHandlers(consumer consumer.Consumer) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		if shuttingDown {
			os.Exit(1)
		}
		Info("Shutting down gracefully. Repeat signal to force shutdown")
		shuttingDown = true
		Info("Removing consumer")
		err := consumer.Remove()
		if err != nil {
			Fatal("Could not remove subscription %s: %v", *subscriptionName, err)
		}
		Info("Consumer removed successfully. Exiting")
		os.Exit(0)
	}()
}

// Generates a random hexadecimal string
func generateSubId() string {
	id := make([]byte, 4)
	todo := len(id)
	offset := 0
	source := rand.NewSource(time.Now().UnixNano())
	for {
		val := int64(source.Int63())
		for i := 0; i < 8; i++ {
			id[offset] = byte(val & 0xff)
			todo--
			if todo == 0 {
				return hex.EncodeToString(id)
			}
			offset++
			val >>= 8
		}
	}
}

// Attempts to get a value from the environment with a default
func fromEnvWithDefault(varName string, defaultValue string) string {
	value := os.Getenv(varName)
	if value != "" {
		return value
	} else {
		return defaultValue
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/flynn/go-discoverd"
)

func main() {
	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	if err := d.Register("example-server", os.Args[1]); err != nil {
		log.Fatal(err)
	}
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("Listening on " + os.Args[1]))
	})
	http.ListenAndServe(os.Args[1], nil)
}
<commit_msg>router: Fix server example<commit_after>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/flynn/go-discoverd"
)

func main() {
	d, err := discoverd.NewClient()
	if err != nil {
		log.Fatal(err)
	}
	if err := d.Register("example-server", os.Args[1]); err != nil {
		log.Fatal(err)
	}
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("Listening on " + os.Args[1]))
	})
	log.Fatal(http.ListenAndServe(":"+os.Args[1], nil))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/lukevers/gedcom"
	"log"
)

func main() {
	tree, err := gedcom.ParseFromFile("simple.ged")
	if err != nil {
		log.Fatalln("Error loading file:", err)
	}

	err = tree.TraverseFamilies()
	if err != nil {
		log.Fatalln("Error traversing families:", err)
	}

	for i, family := range tree.Families {
		log.Printf("===== FAMILY %d =====", i)
		name, _ := family.Father.GetAttribute("NAME")
		log.Printf("Father: %s", name)
		name, _ = family.Mother.GetAttribute("NAME")
		log.Printf("Mother: %s", name)

		for j, child := range family.Children {
			name, _ = child.GetAttribute("NAME")
			log.Printf("Child %d: %s", j, name)
		}
	}
}
<commit_msg>Only output information if it exists in the family<commit_after>package main

import (
	"github.com/lukevers/gedcom"
	"log"
)

func main() {
	tree, err := gedcom.ParseFromFile("simple.ged")
	if err != nil {
		log.Fatalln("Error loading file:", err)
	}

	err = tree.TraverseFamilies()
	if err != nil {
		log.Fatalln("Error traversing families:", err)
	}

	for i, family := range tree.Families {
		log.Printf("===== FAMILY %d =====", i)
		if family.Father != nil {
			name, _ := family.Father.GetAttribute("NAME")
			log.Printf("Father: %s", name)
		}
		if family.Mother != nil {
			name, _ := family.Mother.GetAttribute("NAME")
			log.Printf("Mother: %s", name)
		}

		for j, child := range family.Children {
			name, _ := child.GetAttribute("NAME")
			log.Printf("Child %d: %s", j, name)
		}
	}
}
<|endoftext|>