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

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import (
	"fmt";
	"strconv";
)

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota;
	EOF;
	COMMENT;

	literal_beg;
	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	IDENT;		// main
	INT;		// 12345
	FLOAT;		// 123.45
	CHAR;		// 'a'
	STRING;		// "abc"
	literal_end;

	operator_beg;
	// Operators and delimiters
	ADD;		// +
	SUB;		// -
	MUL;		// *
	QUO;		// /
	REM;		// %

	AND;		// &
	OR;		// |
	XOR;		// ^
	SHL;		// <<
	SHR;		// >>
	AND_NOT;	// &^

	ADD_ASSIGN;	// +=
	SUB_ASSIGN;	// -=
	MUL_ASSIGN;	// *=
	QUO_ASSIGN;	// /=
	REM_ASSIGN;	// %=

	AND_ASSIGN;	// &=
	OR_ASSIGN;	// |=
	XOR_ASSIGN;	// ^=
	SHL_ASSIGN;	// <<=
	SHR_ASSIGN;	// >>=
	AND_NOT_ASSIGN;	// &^=

	LAND;		// &&
	LOR;		// ||
	ARROW;		// <-
	INC;		// ++
	DEC;		// --

	EQL;		// ==
	LSS;		// <
	GTR;		// >
	ASSIGN;		// =
	NOT;		// !

	NEQ;		// !=
	LEQ;		// <=
	GEQ;		// >=
	DEFINE;		// :=
	ELLIPSIS;	// ...

	LPAREN;		// (
	LBRACK;		// [
	LBRACE;		// {
	COMMA;		// ,
	PERIOD;		// .

	RPAREN;		// )
	RBRACK;		// ]
	RBRACE;		// }
	SEMICOLON;	// ;
	COLON;		// :
	operator_end;

	keyword_beg;
	// Keywords
	BREAK;
	CASE;
	CHAN;
	CONST;
	CONTINUE;

	DEFAULT;
	DEFER;
	ELSE;
	FALLTHROUGH;
	FOR;

	FUNC;
	GO;
	GOTO;
	IF;
	IMPORT;

	INTERFACE;
	MAP;
	PACKAGE;
	RANGE;
	RETURN;

	SELECT;
	STRUCT;
	SWITCH;
	TYPE;
	VAR;
	keyword_end;
)

// At the moment we have no array literal syntax that lets us describe
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map [Token] string {
	ILLEGAL : "ILLEGAL",

	EOF : "EOF",
	COMMENT : "COMMENT",

	IDENT : "IDENT",
	INT : "INT",
	FLOAT : "FLOAT",
	CHAR : "CHAR",
	STRING : "STRING",

	ADD : "+",
	SUB : "-",
	MUL : "*",
	QUO : "/",
	REM : "%",

	AND : "&",
	OR : "|",
	XOR : "^",
	SHL : "<<",
	SHR : ">>",
	AND_NOT : "&^",

	ADD_ASSIGN : "+=",
	SUB_ASSIGN : "-=",
	MUL_ASSIGN : "*=",
	QUO_ASSIGN : "/=",
	REM_ASSIGN : "%=",

	AND_ASSIGN : "&=",
	OR_ASSIGN : "|=",
	XOR_ASSIGN : "^=",
	SHL_ASSIGN : "<<=",
	SHR_ASSIGN : ">>=",
	AND_NOT_ASSIGN : "&^=",

	LAND : "&&",
	LOR : "||",
	ARROW : "<-",
	INC : "++",
	DEC : "--",

	EQL : "==",
	LSS : "<",
	GTR : ">",
	ASSIGN : "=",
	NOT : "!",

	NEQ : "!=",
	LEQ : "<=",
	GEQ : ">=",
	DEFINE : ":=",
	ELLIPSIS : "...",

	LPAREN : "(",
	LBRACK : "[",
	LBRACE : "{",
	COMMA : ",",
	PERIOD : ".",

	RPAREN : ")",
	RBRACK : "]",
	RBRACE : "}",
	SEMICOLON : ";",
	COLON : ":",

	BREAK : "break",
	CASE : "case",
	CHAN : "chan",
	CONST : "const",
	CONTINUE : "continue",

	DEFAULT : "default",
	DEFER : "defer",
	ELSE : "else",
	FALLTHROUGH : "fallthrough",
	FOR : "for",

	FUNC : "func",
	GO : "go",
	GOTO : "goto",
	IF : "if",
	IMPORT : "import",

	INTERFACE : "interface",
	MAP : "map",
	PACKAGE : "package",
	RANGE : "range",
	RETURN : "return",

	SELECT : "select",
	STRUCT : "struct",
	SWITCH : "switch",
	TYPE : "type",
	VAR : "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	if str, exists := tokens[tok]; exists {
		return str;
	}
	return "token(" + strconv.Itoa(int(tok)) + ")";
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec = 0;  // non-operators
	UnaryPrec = 7;
	HighestPrec = 8;
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1;
	case LAND:
		return 2;
	case ARROW:
		return 3;
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 4;
	case ADD, SUB, OR, XOR:
		return 5;
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 6;
	}
	return LowestPrec;
}

var keywords map [string] Token;

func init() {
	keywords = make(map [string] Token);
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i;
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok;
	}
	return IDENT;
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool {
	return literal_beg < tok && tok < literal_end;
}

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool {
	return operator_beg < tok && tok < operator_end;
}

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool {
	return keyword_beg < tok && tok < keyword_end;
}

// Token source positions are represented by a Position value.
// A Position is valid if the line number is > 0.
//
type Position struct {
	Filename string;  // filename, if any
	Offset int;  // byte offset, starting at 0
	Line int;  // line number, starting at 1
	Column int;  // column number, starting at 1 (character count)
}

// Pos is an accessor method for anonymous Position fields.
// It returns its receiver.
//
func (pos *Position) Pos() Position {
	return *pos;
}

// IsValid returns true if the position is valid.
func (pos *Position) IsValid() bool {
	return pos.Line > 0
}

func (pos *Position) String() string {
	if pos != nil {
		s := pos.Filename;
		if pos.IsValid() {
			if s != "" {
				s += ":";
			}
			s += fmt.Sprintf("%d:%d", pos.Line, pos.Column);
		}
		if s != "" {
			return s;
		}
	}
	return "<unknown position>";
}
<commit_msg>make String work on Position values, to enable<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import (
	"fmt";
	"strconv";
)

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota;
	EOF;
	COMMENT;

	literal_beg;
	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	IDENT;		// main
	INT;		// 12345
	FLOAT;		// 123.45
	CHAR;		// 'a'
	STRING;		// "abc"
	literal_end;

	operator_beg;
	// Operators and delimiters
	ADD;		// +
	SUB;		// -
	MUL;		// *
	QUO;		// /
	REM;		// %

	AND;		// &
	OR;		// |
	XOR;		// ^
	SHL;		// <<
	SHR;		// >>
	AND_NOT;	// &^

	ADD_ASSIGN;	// +=
	SUB_ASSIGN;	// -=
	MUL_ASSIGN;	// *=
	QUO_ASSIGN;	// /=
	REM_ASSIGN;	// %=

	AND_ASSIGN;	// &=
	OR_ASSIGN;	// |=
	XOR_ASSIGN;	// ^=
	SHL_ASSIGN;	// <<=
	SHR_ASSIGN;	// >>=
	AND_NOT_ASSIGN;	// &^=

	LAND;		// &&
	LOR;		// ||
	ARROW;		// <-
	INC;		// ++
	DEC;		// --

	EQL;		// ==
	LSS;		// <
	GTR;		// >
	ASSIGN;		// =
	NOT;		// !

	NEQ;		// !=
	LEQ;		// <=
	GEQ;		// >=
	DEFINE;		// :=
	ELLIPSIS;	// ...

	LPAREN;		// (
	LBRACK;		// [
	LBRACE;		// {
	COMMA;		// ,
	PERIOD;		// .

	RPAREN;		// )
	RBRACK;		// ]
	RBRACE;		// }
	SEMICOLON;	// ;
	COLON;		// :
	operator_end;

	keyword_beg;
	// Keywords
	BREAK;
	CASE;
	CHAN;
	CONST;
	CONTINUE;

	DEFAULT;
	DEFER;
	ELSE;
	FALLTHROUGH;
	FOR;

	FUNC;
	GO;
	GOTO;
	IF;
	IMPORT;

	INTERFACE;
	MAP;
	PACKAGE;
	RANGE;
	RETURN;

	SELECT;
	STRUCT;
	SWITCH;
	TYPE;
	VAR;
	keyword_end;
)

// At the moment we have no array literal syntax that lets us describe
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map [Token] string {
	ILLEGAL : "ILLEGAL",

	EOF : "EOF",
	COMMENT : "COMMENT",

	IDENT : "IDENT",
	INT : "INT",
	FLOAT : "FLOAT",
	CHAR : "CHAR",
	STRING : "STRING",

	ADD : "+",
	SUB : "-",
	MUL : "*",
	QUO : "/",
	REM : "%",

	AND : "&",
	OR : "|",
	XOR : "^",
	SHL : "<<",
	SHR : ">>",
	AND_NOT : "&^",

	ADD_ASSIGN : "+=",
	SUB_ASSIGN : "-=",
	MUL_ASSIGN : "*=",
	QUO_ASSIGN : "/=",
	REM_ASSIGN : "%=",

	AND_ASSIGN : "&=",
	OR_ASSIGN : "|=",
	XOR_ASSIGN : "^=",
	SHL_ASSIGN : "<<=",
	SHR_ASSIGN : ">>=",
	AND_NOT_ASSIGN : "&^=",

	LAND : "&&",
	LOR : "||",
	ARROW : "<-",
	INC : "++",
	DEC : "--",

	EQL : "==",
	LSS : "<",
	GTR : ">",
	ASSIGN : "=",
	NOT : "!",

	NEQ : "!=",
	LEQ : "<=",
	GEQ : ">=",
	DEFINE : ":=",
	ELLIPSIS : "...",

	LPAREN : "(",
	LBRACK : "[",
	LBRACE : "{",
	COMMA : ",",
	PERIOD : ".",

	RPAREN : ")",
	RBRACK : "]",
	RBRACE : "}",
	SEMICOLON : ";",
	COLON : ":",

	BREAK : "break",
	CASE : "case",
	CHAN : "chan",
	CONST : "const",
	CONTINUE : "continue",

	DEFAULT : "default",
	DEFER : "defer",
	ELSE : "else",
	FALLTHROUGH : "fallthrough",
	FOR : "for",

	FUNC : "func",
	GO : "go",
	GOTO : "goto",
	IF : "if",
	IMPORT : "import",

	INTERFACE : "interface",
	MAP : "map",
	PACKAGE : "package",
	RANGE : "range",
	RETURN : "return",

	SELECT : "select",
	STRUCT : "struct",
	SWITCH : "switch",
	TYPE : "type",
	VAR : "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	if str, exists := tokens[tok]; exists {
		return str;
	}
	return "token(" + strconv.Itoa(int(tok)) + ")";
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec = 0;  // non-operators
	UnaryPrec = 7;
	HighestPrec = 8;
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1;
	case LAND:
		return 2;
	case ARROW:
		return 3;
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 4;
	case ADD, SUB, OR, XOR:
		return 5;
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 6;
	}
	return LowestPrec;
}

var keywords map [string] Token;

func init() {
	keywords = make(map [string] Token);
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i;
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok;
	}
	return IDENT;
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool {
	return literal_beg < tok && tok < literal_end;
}

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool {
	return operator_beg < tok && tok < operator_end;
}

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool {
	return keyword_beg < tok && tok < keyword_end;
}

// Token source positions are represented by a Position value.
// A Position is valid if the line number is > 0.
//
type Position struct {
	Filename string;  // filename, if any
	Offset int;  // byte offset, starting at 0
	Line int;  // line number, starting at 1
	Column int;  // column number, starting at 1 (character count)
}

// Pos is an accessor method for anonymous Position fields.
// It returns its receiver.
//
func (pos *Position) Pos() Position {
	return *pos;
}

// IsValid returns true if the position is valid.
func (pos *Position) IsValid() bool {
	return pos.Line > 0
}

func (pos Position) String() string {
	s := pos.Filename;
	if pos.IsValid() {
		if s != "" {
			s += ":";
		}
		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column);
	}
	if s == "" {
		s = "???";
	}
	return s;
}
<|endoftext|>


<commit_before>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
// #include <stdlib.h>
import "C"
import (
	"unsafe"
)

// MediaState represents the state of a media file.
type MediaState uint

// Media states.
const (
	MediaNothingSpecial MediaState = iota
	MediaOpening
	MediaBuffering
	MediaPlaying
	MediaPaused
	MediaStopped
	MediaEnded
	MediaError
)

// Media is an abstract representation of a playable media file.
type Media struct {
	media *C.libvlc_media_t
}

// NewMediaFromPath creates a Media instance from the provided path.
func NewMediaFromPath(path string) (*Media, error) {
	return newMedia(path, true)
}

// NewMediaFromURL creates a Media instance from the provided URL.
func NewMediaFromURL(url string) (*Media, error) {
	return newMedia(url, false)
}

// Release destroys the media instance.
func (m *Media) Release() error {
	if m.media == nil {
		return nil
	}

	C.libvlc_media_release(m.media)
	m.media = nil

	return getError()
}

// AddOptions adds the specified options to the media. The specified options
// determine how a media player reads the media, allowing advanced reading or
// streaming on a per-media basis.
func (m *Media) AddOptions(options ...string) error {
	if m == nil || m.media == nil {
		return ErrMediaNotInitialized
	}

	for _, option := range options {
		if err := m.addOption(option); err != nil {
			return err
		}
	}

	return nil
}

// EventManager returns the event manager responsible for the media.
func (m *Media) EventManager() (*EventManager, error) {
	if m == nil || m.media == nil {
		return nil, ErrMediaNotInitialized
	}

	manager := C.libvlc_media_event_manager(m.media)
	if manager == nil {
		return nil, ErrMissingEventManager
	}

	return newEventManager(manager), nil
}

func (m *Media) addOption(option string) error {
	if option == "" {
		return nil
	}

	cOption := C.CString(option)
	defer C.free(unsafe.Pointer(cOption))

	C.libvlc_media_add_option(m.media, cOption)
	return getError()
}

func newMedia(path string, local bool) (*Media, error) {
	if inst == nil {
		return nil, ErrModuleNotInitialized
	}

	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))

	var media *C.libvlc_media_t
	if local {
		media = C.libvlc_media_new_path(inst.handle, cPath)
	} else {
		media = C.libvlc_media_new_location(inst.handle, cPath)
	}

	if media == nil {
		return nil, getError()
	}

	return &Media{media: media}, nil
}
<commit_msg>Add media stats binding<commit_after>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
// #include <stdlib.h>
import "C"
import (
	"unsafe"
)

// MediaState represents the state of a media file.
type MediaState uint

// Media states.
const (
	MediaNothingSpecial MediaState = iota
	MediaOpening
	MediaBuffering
	MediaPlaying
	MediaPaused
	MediaStopped
	MediaEnded
	MediaError
)

// MediaStats contains playback statistics for a media file.
type MediaStats struct {
	// Input statistics.
	ReadBytes    int     // input bytes read.
	InputBitRate float64 // input bitrate.

	// Demux statistics.
	DemuxReadBytes     int     // demux bytes read (demuxed data size).
	DemuxBitRate       float64 // demux bitrate (content bitrate).
	DemuxCorrupted     int     // demux corruptions (discarded).
	DemuxDiscontinuity int     // demux discontinuities (dropped).

	// Video output statistics.
	DecodedVideo      int // number of decoded video blocks.
	DisplayedPictures int // number of displayed frames.
	LostPictures      int // number of lost frames.

	// Audio output statistics.
	DecodedAudio       int // number of decoded audio blocks.
	PlayedAudioBuffers int // number of played audio buffers.
	LostAudioBuffers   int // number of lost audio buffers.
}

func newMediaStats(st *C.libvlc_media_stats_t) (*MediaStats, error) {
	if st == nil {
		return nil, ErrInvalidMediaStats
	}

	return &MediaStats{
		// Input statistics.
		ReadBytes:    int(st.i_read_bytes),
		InputBitRate: float64(st.f_input_bitrate),

		// Demux statistics.
		DemuxReadBytes:     int(st.i_demux_read_bytes),
		DemuxBitRate:       float64(st.f_demux_bitrate),
		DemuxCorrupted:     int(st.i_demux_corrupted),
		DemuxDiscontinuity: int(st.i_demux_discontinuity),

		// Video output statistics.
		DecodedVideo:      int(st.i_decoded_video),
		DisplayedPictures: int(st.i_displayed_pictures),
		LostPictures:      int(st.i_lost_pictures),

		// Audio output statistics.
		DecodedAudio:       int(st.i_decoded_audio),
		PlayedAudioBuffers: int(st.i_played_abuffers),
		LostAudioBuffers:   int(st.i_lost_abuffers),
	}, nil
}

// Media is an abstract representation of a playable media file.
type Media struct {
	media *C.libvlc_media_t
}

// NewMediaFromPath creates a Media instance from the provided path.
func NewMediaFromPath(path string) (*Media, error) {
	return newMedia(path, true)
}

// NewMediaFromURL creates a Media instance from the provided URL.
func NewMediaFromURL(url string) (*Media, error) {
	return newMedia(url, false)
}

// Release destroys the media instance.
func (m *Media) Release() error {
	if m.media == nil {
		return nil
	}

	C.libvlc_media_release(m.media)
	m.media = nil

	return getError()
}

// AddOptions adds the specified options to the media. The specified options
// determine how a media player reads the media, allowing advanced reading or
// streaming on a per-media basis.
func (m *Media) AddOptions(options ...string) error {
	if m == nil || m.media == nil {
		return ErrMediaNotInitialized
	}

	for _, option := range options {
		if err := m.addOption(option); err != nil {
			return err
		}
	}

	return nil
}

// Stats returns playback statistics for the media.
func (m *Media) Stats() (*MediaStats, error) {
	if m == nil || m.media == nil {
		return nil, ErrMediaNotInitialized
	}

	var stats C.libvlc_media_stats_t
	if int(C.libvlc_media_get_stats(m.media, &stats)) != 1 {
		return nil, errOrDefault(getError(), ErrMissingMediaStats)
	}

	return newMediaStats(&stats)
}

// EventManager returns the event manager responsible for the media.
func (m *Media) EventManager() (*EventManager, error) {
	if m == nil || m.media == nil {
		return nil, ErrMediaNotInitialized
	}

	manager := C.libvlc_media_event_manager(m.media)
	if manager == nil {
		return nil, ErrMissingEventManager
	}

	return newEventManager(manager), nil
}

func (m *Media) addOption(option string) error {
	if option == "" {
		return nil
	}

	cOption := C.CString(option)
	defer C.free(unsafe.Pointer(cOption))

	C.libvlc_media_add_option(m.media, cOption)
	return getError()
}

func newMedia(path string, local bool) (*Media, error) {
	if inst == nil {
		return nil, ErrModuleNotInitialized
	}

	cPath := C.CString(path)
	defer C.free(unsafe.Pointer(cPath))

	var media *C.libvlc_media_t
	if local {
		media = C.libvlc_media_new_path(inst.handle, cPath)
	} else {
		media = C.libvlc_media_new_location(inst.handle, cPath)
	}

	if media == nil {
		return nil, getError()
	}

	return &Media{media: media}, nil
}
<|endoftext|>


<commit_before>package conjungo

import (
	"context"
	"errors"
	"fmt"
	"reflect"
)

type Options struct {
	// Overwrite a target value with source value even if it already exists
	Overwrite bool

	// Unexported fields on a struct can not be set. When a struct contains an unexported
	// field, the default behavior is to treat the entire struct as a single entity and
	// replace according to Overwrite settings. If this is enabled, an error will be thrown instead.
	//
	// Note: this is used by the default mergeStruct function, and may not apply if that is
	// overwritten with a custom function. Custom struct merge functions should consider
	// using this value as well.
	ErrorOnUnexported bool

	// A set of default and customizable functions that define how values are merged
	MergeFuncs *funcSelector

	// To be used by merge functions to pass values down into recursive calls freely
	Context context.Context
}

func NewOptions() *Options {
	return &Options{
		Overwrite:  true,
		MergeFuncs: newFuncSelector(),
	}
}

// public wrapper
func Merge(target, source interface{}, opt *Options) error {
	vT := reflect.ValueOf(target)
	vS := reflect.ValueOf(source)

	if target != nil && vT.Type() == reflect.TypeOf(reflect.Value{}) {
		vT = vT.Interface().(reflect.Value)
	}
	if source != nil && vS.Type() == reflect.TypeOf(reflect.Value{}) {
		vS = vS.Interface().(reflect.Value)
	}

	if vT.Kind() != reflect.Ptr {
		return errors.New("target must be a pointer")
	}

	if !reflect.Indirect(vT).IsValid() {
		return errors.New("target can not be zero value")
	}

	// use defaults if none are provided
	if opt == nil {
		opt = NewOptions()
	}

	//make a copy here so if there is an error mid way, the target stays in tact
	cp := vT.Elem()

	//TODO reflect.Indirect(vS)?
	merged, err := merge(cp, vS, opt)
	if err != nil {
		return err
	}

	if !isSettable(vT.Elem(), merged) {
		return fmt.Errorf("Merge failed: expected merged result to be %v but got %v",
			vT.Elem().Type(), merged.Type())
	}

	vT.Elem().Set(merged)
	return nil
}

func isSettable(t, s reflect.Value) bool {
	if t.Kind() != reflect.Interface && t.Type() != s.Type() {
		return false
	}

	return true
}

func merge(valT, valS reflect.Value, opt *Options) (reflect.Value, error) {
	// if source is nil, skip
	if !valS.IsValid() ||
		valS.Kind() == reflect.Ptr && valS.IsNil() {
		return valT, nil
	}

	// if target is nil write to it
	if !valT.IsValid() ||
		valT.Kind() == reflect.Ptr && valT.IsNil() {
		return valS, nil
	}

	// get to the real type
	if valT.Kind() == reflect.Interface || valS.Kind() == reflect.Interface {
		valT = reflect.ValueOf(valT.Interface())
		valS = reflect.ValueOf(valS.Interface())
	}

	// if types do not match, bail
	if valT.Type() != valS.Type() {
		return reflect.Value{}, fmt.Errorf("Types do not match: %v, %v", valT.Type(), valS.Type())
	}

	// look for a merge function
	f := opt.MergeFuncs.GetFunc(valT)
	val, err := f(valT, valS, opt)
	if err != nil {
		return reflect.Value{}, err
	}

	return val, nil
}
<commit_msg>always the same<commit_after>package conjungo

import (
	"context"
	"errors"
	"fmt"
	"reflect"
)

type Options struct {
	// Overwrite a target value with source value even if it already exists
	Overwrite bool

	// Unexported fields on a struct can not be set. When a struct contains an unexported
	// field, the default behavior is to treat the entire struct as a single entity and
	// replace according to Overwrite settings. If this is enabled, an error will be thrown instead.
	//
	// Note: this is used by the default mergeStruct function, and may not apply if that is
	// overwritten with a custom function. Custom struct merge functions should consider
	// using this value as well.
	ErrorOnUnexported bool

	// A set of default and customizable functions that define how values are merged
	MergeFuncs *funcSelector

	// To be used by merge functions to pass values down into recursive calls freely
	Context context.Context
}

func NewOptions() *Options {
	return &Options{
		Overwrite:  true,
		MergeFuncs: newFuncSelector(),
	}
}

var valType = reflect.TypeOf(reflect.Value{})

// public wrapper
func Merge(target, source interface{}, opt *Options) error {
	vT := reflect.ValueOf(target)
	vS := reflect.ValueOf(source)

	if target != nil && vT.Type() == valType {
		vT = vT.Interface().(reflect.Value)
	}
	if source != nil && vS.Type() == valType {
		vS = vS.Interface().(reflect.Value)
	}

	if vT.Kind() != reflect.Ptr {
		return errors.New("target must be a pointer")
	}

	if !reflect.Indirect(vT).IsValid() {
		return errors.New("target can not be zero value")
	}

	// use defaults if none are provided
	if opt == nil {
		opt = NewOptions()
	}

	//make a copy here so if there is an error mid way, the target stays in tact
	cp := vT.Elem()

	//TODO reflect.Indirect(vS)?
	merged, err := merge(cp, vS, opt)
	if err != nil {
		return err
	}

	if !isSettable(vT.Elem(), merged) {
		return fmt.Errorf("Merge failed: expected merged result to be %v but got %v",
			vT.Elem().Type(), merged.Type())
	}

	vT.Elem().Set(merged)
	return nil
}

func isSettable(t, s reflect.Value) bool {
	if t.Kind() != reflect.Interface && t.Type() != s.Type() {
		return false
	}

	return true
}

func merge(valT, valS reflect.Value, opt *Options) (reflect.Value, error) {
	// if source is nil, skip
	if !valS.IsValid() ||
		valS.Kind() == reflect.Ptr && valS.IsNil() {
		return valT, nil
	}

	// if target is nil write to it
	if !valT.IsValid() ||
		valT.Kind() == reflect.Ptr && valT.IsNil() {
		return valS, nil
	}

	// get to the real type
	if valT.Kind() == reflect.Interface || valS.Kind() == reflect.Interface {
		valT = reflect.ValueOf(valT.Interface())
		valS = reflect.ValueOf(valS.Interface())
	}

	// if types do not match, bail
	if valT.Type() != valS.Type() {
		return reflect.Value{}, fmt.Errorf("Types do not match: %v, %v", valT.Type(), valS.Type())
	}

	// look for a merge function
	f := opt.MergeFuncs.GetFunc(valT)
	val, err := f(valT, valS, opt)
	if err != nil {
		return reflect.Value{}, err
	}

	return val, nil
}
<|endoftext|>


<commit_before>package gl

// #include <GLES2/gl2.h>
import "C"

import "unsafe"

type TextureFormat C.GLenum
type TextureUnit C.GLenum
type Texture C.GLuint
type TextureTarget C.GLenum
type TextureParameter C.GLenum
type TextureParameterValue C.GLint

const (
	DEPTH_COMPONENT TextureFormat = C.GL_DEPTH_COMPONENT
	ALPHA                         = C.GL_ALPHA
	RGB                           = C.GL_RGB
	RGBA                          = C.GL_RGBA
	LUMINANCE                     = C.GL_LUMINANCE
	LUMINANCE_ALPHA               = C.GL_LUMINANCE_ALPHA

	TEXTURE_MAG_FILTER TextureParameter = C.GL_TEXTURE_MAG_FILTER
	TEXTURE_MIN_FILTER                  = C.GL_TEXTURE_MIN_FILTER
	TEXTURE_WRAP_S                      = C.GL_TEXTURE_WRAP_S
	TEXTURE_WRAP_T                      = C.GL_TEXTURE_WRAP_T

	TEXTURE_2D                  TextureTarget = C.GL_TEXTURE_2D
	TEXTURE_CUBE_MAP                          = C.GL_TEXTURE_CUBE_MAP
	TEXTURE_CUBE_MAP_POSITIVE_X               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_X
	TEXTURE_CUBE_MAP_NEGATIVE_X               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_X
	TEXTURE_CUBE_MAP_POSITIVE_Y               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_Y
	TEXTURE_CUBE_MAP_NEGATIVE_Y               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
	TEXTURE_CUBE_MAP_POSITIVE_Z               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_Z
	TEXTURE_CUBE_MAP_NEGATIVE_Z               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
	MAX_CUBE_MAP_TEXTURE_SIZE                 = C.GL_MAX_CUBE_MAP_TEXTURE_SIZE

	TEXTURE0  TextureUnit = C.GL_TEXTURE0
	TEXTURE1              = C.GL_TEXTURE1
	TEXTURE2              = C.GL_TEXTURE2
	TEXTURE3              = C.GL_TEXTURE3
	TEXTURE4              = C.GL_TEXTURE4
	TEXTURE5              = C.GL_TEXTURE5
	TEXTURE6              = C.GL_TEXTURE6
	TEXTURE7              = C.GL_TEXTURE7
	TEXTURE8              = C.GL_TEXTURE8
	TEXTURE9              = C.GL_TEXTURE9
	TEXTURE10             = C.GL_TEXTURE10
	TEXTURE11             = C.GL_TEXTURE11
	TEXTURE12             = C.GL_TEXTURE12
	TEXTURE13             = C.GL_TEXTURE13
	TEXTURE14             = C.GL_TEXTURE14
	TEXTURE15             = C.GL_TEXTURE15
	TEXTURE16             = C.GL_TEXTURE16
	TEXTURE17             = C.GL_TEXTURE17
	TEXTURE18             = C.GL_TEXTURE18
	TEXTURE19             = C.GL_TEXTURE19
	TEXTURE20             = C.GL_TEXTURE20
	TEXTURE21             = C.GL_TEXTURE21
	TEXTURE22             = C.GL_TEXTURE22
	TEXTURE23             = C.GL_TEXTURE23
	TEXTURE24             = C.GL_TEXTURE24
	TEXTURE25             = C.GL_TEXTURE25
	TEXTURE26             = C.GL_TEXTURE26
	TEXTURE27             = C.GL_TEXTURE27
	TEXTURE28             = C.GL_TEXTURE28
	TEXTURE29             = C.GL_TEXTURE29
	TEXTURE30             = C.GL_TEXTURE30
	TEXTURE31             = C.GL_TEXTURE31

	NEAREST                TextureParameterValue = C.GL_NEAREST
	LINEAR                                       = C.GL_LINEAR
	NEAREST_MIPMAP_NEAREST                       = C.GL_NEAREST_MIPMAP_NEAREST
	LINEAR_MIPMAP_NEAREST                        = C.GL_LINEAR_MIPMAP_NEAREST
	NEAREST_MIPMAP_LINEAR                        = C.GL_NEAREST_MIPMAP_LINEAR
	LINEAR_MIPMAP_LINEAR                         = C.GL_LINEAR_MIPMAP_LINEAR
	REPEAT                                       = C.GL_REPEAT
	CLAMP_TO_EDGE                                = C.GL_CLAMP_TO_EDGE
	MIRRORED_REPEAT                              = C.GL_MIRRORED_REPEAT
)

func ActiveTexture(texture TextureUnit) {
	C.glActiveTexture(C.GLenum(texture))
}

func GetActiveTexture() TextureUnit {
	texture := C.GLint(0)
	C.glGetIntegerv(C.GL_ACTIVE_TEXTURE, &texture)
	return TextureUnit(texture)
}

func BindTexture(target TextureTarget, texture Texture) {
	C.glBindTexture(C.GLenum(target), C.GLuint(texture))
}

// TODO:
// func CompressedTexImage2D(target TextureTarget, level int, internalformat TextureFormat, width, height int, data []interface{}) {
// 	C.glCompressedTexImage2D(C.GLenum(target), C.GLint(level), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height), 0, unsafe.Sizeof(data[0])*len(data), data)
// }

// func CompressedTexSubImage2D(target TextureTarget, level, xoffset, yoffset, width, height, format TextureFormat, data []interface{}) {
// 	C.glCompressedTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), unsafe.Sizeof(data[0])*len(data), data)
// }

func CopyTexImage2D(target TextureTarget, level int, internalformat TextureFormat, x, y, width, height int) {
	C.glCopyTexImage2D(C.GLenum(target), C.GLint(level), C.GLenum(internalformat), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), 0)
}

func CopyTexSubImage2D(target TextureTarget, level, xoffset, yoffset, x, y, width, height int) {
	C.glCopyTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
}

func DeleteTextures(textures []Texture) {
	C.glDeleteTextures(C.GLsizei(len(textures)), (*C.GLuint)(&textures[0]))
}

func GenTexture() Texture {
	texture := Texture(0)
	C.glGenTextures(1, (*C.GLuint)(&texture))
	return texture
}

func GenTextures(n int) []Texture {
	textures := make([]Texture, n)
	C.glGenTextures(C.GLsizei(n), (*C.GLuint)(&textures[0]))
	return textures
}

func GenerateMipmap(target TextureTarget) {
	C.glGenerateMipmap(C.GLenum(target))
}

func GetTexParameterf(target TextureTarget, pname TextureParameter) float32 {
	param := float32(0)
	C.glGetTexParameterfv(C.GLenum(target), C.GLenum(pname), (*C.GLfloat)(&param))
	return param
}

func GetTexParameteri(target TextureTarget, pname TextureParameter) int {
	param := C.GLint(0)
	C.glGetTexParameteriv(C.GLenum(target), C.GLenum(pname), &param)
	return int(param)
}

func TexImage2D(target TextureTarget, level int, internalformat TextureFormat, width, height int, datatype DataType, pixels []interface{}) {
	C.glTexImage2D(C.GLenum(target), C.GLint(level), C.GLint(internalformat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(internalformat), C.GLenum(datatype), unsafe.Pointer(&pixels[0]))
}

func TexParameter(target TextureTarget, pname TextureParameter, param TextureParameterValue) {
	C.glTexParameteri(C.GLenum(target), C.GLenum(pname), C.GLint(param))
}

func TexSubImage2D(target TextureTarget, level, xoffset, yoffset, width, height int, format TextureFormat, datatype DataType, pixels []interface{}) {
	C.glTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(datatype), unsafe.Pointer(&pixels[0]))
}
<commit_msg>fix pixels parameter of TexImage2D and TexSubImage2D<commit_after>package gl

// #include <GLES2/gl2.h>
import "C"

import "unsafe"

type TextureFormat C.GLenum
type TextureUnit C.GLenum
type Texture C.GLuint
type TextureTarget C.GLenum
type TextureParameter C.GLenum
type TextureParameterValue C.GLint

const (
	DEPTH_COMPONENT TextureFormat = C.GL_DEPTH_COMPONENT
	ALPHA                         = C.GL_ALPHA
	RGB                           = C.GL_RGB
	RGBA                          = C.GL_RGBA
	LUMINANCE                     = C.GL_LUMINANCE
	LUMINANCE_ALPHA               = C.GL_LUMINANCE_ALPHA

	TEXTURE_MAG_FILTER TextureParameter = C.GL_TEXTURE_MAG_FILTER
	TEXTURE_MIN_FILTER                  = C.GL_TEXTURE_MIN_FILTER
	TEXTURE_WRAP_S                      = C.GL_TEXTURE_WRAP_S
	TEXTURE_WRAP_T                      = C.GL_TEXTURE_WRAP_T

	TEXTURE_2D                  TextureTarget = C.GL_TEXTURE_2D
	TEXTURE_CUBE_MAP                          = C.GL_TEXTURE_CUBE_MAP
	TEXTURE_CUBE_MAP_POSITIVE_X               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_X
	TEXTURE_CUBE_MAP_NEGATIVE_X               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_X
	TEXTURE_CUBE_MAP_POSITIVE_Y               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_Y
	TEXTURE_CUBE_MAP_NEGATIVE_Y               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
	TEXTURE_CUBE_MAP_POSITIVE_Z               = C.GL_TEXTURE_CUBE_MAP_POSITIVE_Z
	TEXTURE_CUBE_MAP_NEGATIVE_Z               = C.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
	MAX_CUBE_MAP_TEXTURE_SIZE                 = C.GL_MAX_CUBE_MAP_TEXTURE_SIZE

	TEXTURE0  TextureUnit = C.GL_TEXTURE0
	TEXTURE1              = C.GL_TEXTURE1
	TEXTURE2              = C.GL_TEXTURE2
	TEXTURE3              = C.GL_TEXTURE3
	TEXTURE4              = C.GL_TEXTURE4
	TEXTURE5              = C.GL_TEXTURE5
	TEXTURE6              = C.GL_TEXTURE6
	TEXTURE7              = C.GL_TEXTURE7
	TEXTURE8              = C.GL_TEXTURE8
	TEXTURE9              = C.GL_TEXTURE9
	TEXTURE10             = C.GL_TEXTURE10
	TEXTURE11             = C.GL_TEXTURE11
	TEXTURE12             = C.GL_TEXTURE12
	TEXTURE13             = C.GL_TEXTURE13
	TEXTURE14             = C.GL_TEXTURE14
	TEXTURE15             = C.GL_TEXTURE15
	TEXTURE16             = C.GL_TEXTURE16
	TEXTURE17             = C.GL_TEXTURE17
	TEXTURE18             = C.GL_TEXTURE18
	TEXTURE19             = C.GL_TEXTURE19
	TEXTURE20             = C.GL_TEXTURE20
	TEXTURE21             = C.GL_TEXTURE21
	TEXTURE22             = C.GL_TEXTURE22
	TEXTURE23             = C.GL_TEXTURE23
	TEXTURE24             = C.GL_TEXTURE24
	TEXTURE25             = C.GL_TEXTURE25
	TEXTURE26             = C.GL_TEXTURE26
	TEXTURE27             = C.GL_TEXTURE27
	TEXTURE28             = C.GL_TEXTURE28
	TEXTURE29             = C.GL_TEXTURE29
	TEXTURE30             = C.GL_TEXTURE30
	TEXTURE31             = C.GL_TEXTURE31

	NEAREST                TextureParameterValue = C.GL_NEAREST
	LINEAR                                       = C.GL_LINEAR
	NEAREST_MIPMAP_NEAREST                       = C.GL_NEAREST_MIPMAP_NEAREST
	LINEAR_MIPMAP_NEAREST                        = C.GL_LINEAR_MIPMAP_NEAREST
	NEAREST_MIPMAP_LINEAR                        = C.GL_NEAREST_MIPMAP_LINEAR
	LINEAR_MIPMAP_LINEAR                         = C.GL_LINEAR_MIPMAP_LINEAR
	REPEAT                                       = C.GL_REPEAT
	CLAMP_TO_EDGE                                = C.GL_CLAMP_TO_EDGE
	MIRRORED_REPEAT                              = C.GL_MIRRORED_REPEAT
)

func ActiveTexture(texture TextureUnit) {
	C.glActiveTexture(C.GLenum(texture))
}

func GetActiveTexture() TextureUnit {
	texture := C.GLint(0)
	C.glGetIntegerv(C.GL_ACTIVE_TEXTURE, &texture)
	return TextureUnit(texture)
}

func BindTexture(target TextureTarget, texture Texture) {
	C.glBindTexture(C.GLenum(target), C.GLuint(texture))
}

// TODO:
// func CompressedTexImage2D(target TextureTarget, level int, internalformat TextureFormat, width, height int, data []interface{}) {
// 	C.glCompressedTexImage2D(C.GLenum(target), C.GLint(level), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height), 0, unsafe.Sizeof(data[0])*len(data), data)
// }

// func CompressedTexSubImage2D(target TextureTarget, level, xoffset, yoffset, width, height, format TextureFormat, data []interface{}) {
// 	C.glCompressedTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), unsafe.Sizeof(data[0])*len(data), data)
// }

func CopyTexImage2D(target TextureTarget, level int, internalformat TextureFormat, x, y, width, height int) {
	C.glCopyTexImage2D(C.GLenum(target), C.GLint(level), C.GLenum(internalformat), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), 0)
}

func CopyTexSubImage2D(target TextureTarget, level, xoffset, yoffset, x, y, width, height int) {
	C.glCopyTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height))
}

func DeleteTextures(textures []Texture) {
	C.glDeleteTextures(C.GLsizei(len(textures)), (*C.GLuint)(&textures[0]))
}

func GenTexture() Texture {
	texture := Texture(0)
	C.glGenTextures(1, (*C.GLuint)(&texture))
	return texture
}

func GenTextures(n int) []Texture {
	textures := make([]Texture, n)
	C.glGenTextures(C.GLsizei(n), (*C.GLuint)(&textures[0]))
	return textures
}

func GenerateMipmap(target TextureTarget) {
	C.glGenerateMipmap(C.GLenum(target))
}

func GetTexParameterf(target TextureTarget, pname TextureParameter) float32 {
	param := float32(0)
	C.glGetTexParameterfv(C.GLenum(target), C.GLenum(pname), (*C.GLfloat)(&param))
	return param
}

func GetTexParameteri(target TextureTarget, pname TextureParameter) int {
	param := C.GLint(0)
	C.glGetTexParameteriv(C.GLenum(target), C.GLenum(pname), &param)
	return int(param)
}

func TexImage2D(target TextureTarget, level int, internalformat TextureFormat, width, height int, datatype DataType, pixels []uint8) {
	C.glTexImage2D(C.GLenum(target), C.GLint(level), C.GLint(internalformat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(internalformat), C.GLenum(datatype), unsafe.Pointer(&pixels[0]))
}

func TexParameter(target TextureTarget, pname TextureParameter, param TextureParameterValue) {
	C.glTexParameteri(C.GLenum(target), C.GLenum(pname), C.GLint(param))
}

func TexSubImage2D(target TextureTarget, level, xoffset, yoffset, width, height int, format TextureFormat, datatype DataType, pixels []uint8) {
	C.glTexSubImage2D(C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(datatype), unsafe.Pointer(&pixels[0]))
}
<|endoftext|>


<commit_before>/*
   Copyright 2017 Simon J Mudd

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package inst

/*
  query holds information about query metrics and records the time taken
  waiting before doing the query plus the time taken executing the query.
*/
import (
	"time"

	"github.com/github/orchestrator/go/collection"
	"github.com/montanaflynn/stats"
)

// Metric records query metrics of backend writes that go through
// a sized channel.  It allows us to compare the time waiting to
// execute the query against the time needed to run it and in a
// "sized channel" the wait time may be significant and is good to
// measure.
type WriteBufferMetric struct {
	Timestamp         time.Time     // time the metric was started
	WaitLatency       time.Duration // time that we had to wait before flushing the buffer
	FlushLatency      time.Duration // time that it took to flush all instances from buffer
	EnqueuedInstances int
}

// When records the timestamp of the start of the recording
func (m WriteBufferMetric) When() time.Time {
	return m.Timestamp
}

type AggregatedWriteBufferMetric struct {
	// InstanceFlushIntervalMilliseconds int // config setting
	// InstanceWriteBufferSize           int // config setting
	Count              int
	MaxWaitSeconds     float64
	MeanWaitSeconds    float64
	MedianWaitSeconds  float64
	P95WaitSeconds     float64
	MaxFlushSeconds    float64
	MeanFlushSeconds   float64
	MedianFlushSeconds float64
	P95FlushSeconds    float64
}

// AggregatedSince returns the aggregated query metrics for the period
// given from the values provided.
func AggregatedSince(c *collection.Collection, t time.Time) AggregatedWriteBufferMetric {

	// Initialise timing metrics
	var waitTimings []float64
	var flushTimings []float64

	// Retrieve values since the time specified
	values, err := c.Since(t)
	a := AggregatedWriteBufferMetric{}
	if err != nil {
		return a // empty data
	}

	// generate the metrics
	for _, v := range values {
		waitTimings = append(waitTimings, v.(*WriteBufferMetric).WaitLatency.Seconds())
		flushTimings = append(flushTimings, v.(*WriteBufferMetric).FlushLatency.Seconds())
		a.Count += v.(*WriteBufferMetric).EnqueuedInstances
	}

	// generate aggregate values
	if s, err := stats.Max(stats.Float64Data(waitTimings)); err == nil {
		a.MaxWaitSeconds = s
	}
	if s, err := stats.Mean(stats.Float64Data(waitTimings)); err == nil {
		a.MeanWaitSeconds = s
	}
	if s, err := stats.Median(stats.Float64Data(waitTimings)); err == nil {
		a.MedianWaitSeconds = s
	}
	if s, err := stats.Percentile(stats.Float64Data(waitTimings), 95); err == nil {
		a.P95WaitSeconds = s
	}
	if s, err := stats.Max(stats.Float64Data(flushTimings)); err == nil {
		a.MaxWaitSeconds = s
	}
	if s, err := stats.Mean(stats.Float64Data(flushTimings)); err == nil {
		a.MeanWaitSeconds = s
	}
	if s, err := stats.Median(stats.Float64Data(flushTimings)); err == nil {
		a.MedianWaitSeconds = s
	}
	if s, err := stats.Percentile(stats.Float64Data(flushTimings), 95); err == nil {
		a.P95WaitSeconds = s
	}

	return a
}
<commit_msg>add config to aggregated metrics<commit_after>/*
   Copyright 2017 Simon J Mudd

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package inst

/*
  query holds information about query metrics and records the time taken
  waiting before doing the query plus the time taken executing the query.
*/
import (
	"time"

	"github.com/github/orchestrator/go/collection"
	"github.com/github/orchestrator/go/config"

	"github.com/montanaflynn/stats"
)

// Metric records query metrics of backend writes that go through
// a sized channel.  It allows us to compare the time waiting to
// execute the query against the time needed to run it and in a
// "sized channel" the wait time may be significant and is good to
// measure.
type WriteBufferMetric struct {
	Timestamp         time.Time     // time the metric was started
	WaitLatency       time.Duration // time that we had to wait before flushing the buffer
	FlushLatency      time.Duration // time that it took to flush all instances from buffer
	EnqueuedInstances int
}

// When records the timestamp of the start of the recording
func (m WriteBufferMetric) When() time.Time {
	return m.Timestamp
}

type AggregatedWriteBufferMetric struct {
	InstanceWriteBufferSize           int // config setting
	InstanceFlushIntervalMilliseconds int // config setting
	Count                             int
	MaxWaitSeconds                    float64
	MeanWaitSeconds                   float64
	MedianWaitSeconds                 float64
	P95WaitSeconds                    float64
	MaxFlushSeconds                   float64
	MeanFlushSeconds                  float64
	MedianFlushSeconds                float64
	P95FlushSeconds                   float64
}

// AggregatedSince returns the aggregated query metrics for the period
// given from the values provided.
func AggregatedSince(c *collection.Collection, t time.Time) AggregatedWriteBufferMetric {

	// Initialise timing metrics
	var waitTimings []float64
	var flushTimings []float64

	// Retrieve values since the time specified
	values, err := c.Since(t)
	a := AggregatedWriteBufferMetric{
		InstanceWriteBufferSize:           config.Config.InstanceWriteBufferSize,
		InstanceFlushIntervalMilliseconds: config.Config.InstanceFlushIntervalMilliseconds,
	}
	if err != nil {
		return a // empty data
	}

	// generate the metrics
	for _, v := range values {
		waitTimings = append(waitTimings, v.(*WriteBufferMetric).WaitLatency.Seconds())
		flushTimings = append(flushTimings, v.(*WriteBufferMetric).FlushLatency.Seconds())
		a.Count += v.(*WriteBufferMetric).EnqueuedInstances
	}

	// generate aggregate values
	if s, err := stats.Max(stats.Float64Data(waitTimings)); err == nil {
		a.MaxWaitSeconds = s
	}
	if s, err := stats.Mean(stats.Float64Data(waitTimings)); err == nil {
		a.MeanWaitSeconds = s
	}
	if s, err := stats.Median(stats.Float64Data(waitTimings)); err == nil {
		a.MedianWaitSeconds = s
	}
	if s, err := stats.Percentile(stats.Float64Data(waitTimings), 95); err == nil {
		a.P95WaitSeconds = s
	}
	if s, err := stats.Max(stats.Float64Data(flushTimings)); err == nil {
		a.MaxWaitSeconds = s
	}
	if s, err := stats.Mean(stats.Float64Data(flushTimings)); err == nil {
		a.MeanWaitSeconds = s
	}
	if s, err := stats.Median(stats.Float64Data(flushTimings)); err == nil {
		a.MedianWaitSeconds = s
	}
	if s, err := stats.Percentile(stats.Float64Data(flushTimings), 95); err == nil {
		a.P95WaitSeconds = s
	}

	return a
}
<|endoftext|>


<commit_before>package posix

func (k *PosixKernel) Ioctl()         {}
func (k *PosixKernel) RtSigprocmask() {}
func (k *PosixKernel) RtSigaction()   {}
func (k *PosixKernel) Futex()         {}
func (k *PosixKernel) Fcntl()         {}
<commit_msg>add some syscall stubs<commit_after>package posix

func (k *PosixKernel) Ioctl()         {}
func (k *PosixKernel) RtSigprocmask() {}
func (k *PosixKernel) RtSigaction()   {}
func (k *PosixKernel) Futex()         {}
func (k *PosixKernel) Fcntl()         {}
func (k *PosixKernel) SchedYield()    {}
func (k *PosixKernel) Madvise()       {}
func (k *PosixKernel) Mlock()         {}
func (k *PosixKernel) Munlock()       {}
func (k *PosixKernel) Mlockall()      {}
func (k *PosixKernel) Munlockall()    {}
<|endoftext|>


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

package storage

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/google/logger"
	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

// Partition represents a MSFT_Partition object.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition
type Partition struct {
	DiskNumber           int32
	PartitionNumber      int32
	DriveLetter          string
	AccessPaths          []string
	OperationalStatus    int32
	TransitionState      int32
	Size                 uint64
	MbrType              int32
	GptType              string
	GUID                 string
	IsReadOnly           bool
	IsOffline            bool
	IsSystem             bool
	IsBoot               bool
	IsActive             bool
	IsHidden             bool
	IsShadowCopy         bool
	NoDefaultDriveLetter bool

	handle *ole.IDispatch
}

// PartitionSupportedSize represents the minimum and maximum sizes a partition can be resized to.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-getsupportedsizes
type PartitionSupportedSize struct {
	SizeMin uint64
	SizeMax uint64
}

// Close releases the handle to the partition.
func (p *Partition) Close() {
	if p.handle != nil {
		p.handle.Release()
	}
}

// Delete attempts to delete a partition.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-deleteobject
func (p *Partition) Delete() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	resultRaw, err := oleutil.CallMethod(p.handle, "DeleteObject", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("DeleteObject: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during deletion: %d", val)
	}
	return stat, nil
}

// Offline takes the partition offline.
//
// Example:
//		p.Offline()
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-offline
func (p *Partition) Offline() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	res, err := oleutil.CallMethod(p.handle, "Offline", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Offline(): %w", err)
	} else if val, ok := res.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during offline: %d", val)
	}
	return stat, nil
}

// Online brings the partition online by mounting the associated volume (if one exists).
//
// Example:
//		p.Online()
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-online
func (p *Partition) Online() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	res, err := oleutil.CallMethod(p.handle, "Online", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Online(): %w", err)
	} else if val, ok := res.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during online: %d", val)
	}
	return stat, nil
}

// AddAccessPath adds a mount path or drive letter assignment to the partition.
//
// Example: assign a Drive letter with D:
//		p.AddAccessPath("D:", false)
//
// Example: Automatically assign the next available Drive Letter:
//		p.AddAccessPath("", true)
//
// Note: You cannot specify both a valid drive letter and auto assignment as true together.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/addaccesspath-msft-partition
func (p *Partition) AddAccessPath(accessPath string, autoAssign bool) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	var resultRaw *ole.VARIANT
	var err error
	if autoAssign {
		resultRaw, err = oleutil.CallMethod(p.handle, "AddAccessPath", nil, autoAssign, &extendedStatus)
	} else {
		resultRaw, err = oleutil.CallMethod(p.handle, "AddAccessPath", accessPath, nil, &extendedStatus)
	}
	if err != nil {
		return stat, fmt.Errorf("AddAccessPath: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during AddAccessPath: %d", val)
	}
	return stat, nil
}

// RemoveAccessPath removes the access path from the partition.
//
// Example: Remove the driveLetter of D: from a partition
//		p.RemoveAccessPath("D:")
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/removeaccesspath-msft-partition
func (p *Partition) RemoveAccessPath(accessPath string) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	resultRaw, err := oleutil.CallMethod(p.handle, "RemoveAccessPath", accessPath, &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("RemoveAccessPath: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during RemoveAccessPath: %d", val)
	}
	return stat, nil
}

// Query reads and populates the partition state.
func (p *Partition) Query() error {
	if p.handle == nil {
		return fmt.Errorf("invalid handle")
	}

	// DriveLetter
	prop, err := oleutil.GetProperty(p.handle, "DriveLetter")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(DriveLetter): %w", err)
	}
	// DriveLetter is represented as Char16 (Ascii)
	if prop.Val != 0 { // leave NUL as empty string
		p.DriveLetter = string(rune(prop.Val))
	}

	// AccessPaths
	prop, err = oleutil.GetProperty(p.handle, "AccessPaths")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(AccessPaths): %w", err)
	}

	if prop.Val != 0 { // leave NUL as empty string
		for _, pa := range prop.ToArray().ToValueArray() {
			conv, ok := pa.(string)
			if !ok {
				return errors.New("error converting access path")
			}
			p.AccessPaths = append(p.AccessPaths, conv)
		}
	}

	// GptType
	prop, err = oleutil.GetProperty(p.handle, "GptType")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(GptType): %w", err)
	}
	p.GptType = prop.ToString()

	// GUID
	prop, err = oleutil.GetProperty(p.handle, "Guid")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(Guid): %w", err)
	}
	p.GUID = prop.ToString()

	// All the non-strings
	for _, prop := range [][]interface{}{
		[]interface{}{"DiskNumber", &p.DiskNumber},
		[]interface{}{"PartitionNumber", &p.PartitionNumber},
		[]interface{}{"OperationalStatus", &p.OperationalStatus},
		[]interface{}{"TransitionState", &p.TransitionState},
		[]interface{}{"Size", &p.Size},
		[]interface{}{"MbrType", &p.MbrType},
		[]interface{}{"IsReadOnly", &p.IsReadOnly},
		[]interface{}{"IsOffline", &p.IsOffline},
		[]interface{}{"IsSystem", &p.IsSystem},
		[]interface{}{"IsBoot", &p.IsBoot},
		[]interface{}{"IsActive", &p.IsActive},
		[]interface{}{"IsHidden", &p.IsHidden},
		[]interface{}{"IsShadowCopy", &p.IsShadowCopy},
		[]interface{}{"NoDefaultDriveLetter", &p.NoDefaultDriveLetter},
	} {
		val, err := oleutil.GetProperty(p.handle, prop[0].(string))
		if err != nil {
			return fmt.Errorf("oleutil.GetProperty(%s): %w", prop[0].(string), err)
		}
		if err := assignVariant(val.Value(), prop[1]); err != nil {
			logger.Warningf("assignVariant(%s): %v", prop[0].(string), err)
		}
	}
	return nil
}

// Resize attempts to resize a partition.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-resize
func (p *Partition) Resize(size uint64) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	// Convert the unint to a string because of because of https://docs.microsoft.com/en-us/previous-versions//aa393262%28v=vs.85%29?redirectedfrom=MSDN
	resultRaw, err := oleutil.CallMethod(p.handle, "Resize", strconv.FormatUint(size, 10), &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Resize: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during resize: %d", val)
	}
	return stat, nil
}

// A PartitionSet contains one or more Partitions.
type PartitionSet struct {
	Partitions []Partition
}

// Close releases all Partition handles inside a PartitionSet.
func (s *PartitionSet) Close() {
	for _, p := range s.Partitions {
		p.Close()
	}
}

// GetSupportedSize retrieves the minimum and maximum sizes that the partition can be resized to
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-getsupportedsizes
func (p *Partition) GetSupportedSize() (PartitionSupportedSize, ExtendedStatus, error) {
	size := PartitionSupportedSize{}
	stat := ExtendedStatus{}

	var sizemin ole.VARIANT
	ole.VariantInit(&sizemin)
	var sizemax ole.VARIANT
	ole.VariantInit(&sizemax)
	var extendedstatus ole.VARIANT
	ole.VariantInit(&extendedstatus)

	resultRaw, err := oleutil.CallMethod(p.handle, "GetSupportedSize", &sizemin, &sizemax, &extendedstatus)
	if err != nil {
		return size, stat, fmt.Errorf("GetSupportedSize: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return size, stat, fmt.Errorf("error code returned during GetSupportedSize: %d", val)
	}

	// Convert the results from an interface to uint64
	// Results are returned as strings because of https://docs.microsoft.com/en-us/previous-versions//aa393262%28v=vs.85%29?redirectedfrom=MSDN
	size.SizeMin, err = strconv.ParseUint(sizemin.Value().(string), 10, 64)
	if err != nil {
		return size, stat, fmt.Errorf("error attempting to parse sizemin: %w", err)
	}
	size.SizeMax, err = strconv.ParseUint(sizemax.Value().(string), 10, 64)
	if err != nil {
		return size, stat, fmt.Errorf("error attempting to parse sizemax: %w", err)
	}
	return size, stat, nil
}

// GetPartitions queries for local partitions.
//
// Close() must be called on the resulting PartitionSet to ensure all disks are released.
//
// Get all partitions:
//		svc.GetPartitions("")
//
// To get specific partitions, provide a valid WMI query filter string, for example:
//		svc.GetPartitions("WHERE DiskNumber=1")
func (svc *Service) GetPartitions(filter string) (PartitionSet, error) {
	parts := PartitionSet{}
	query := "SELECT * FROM MSFT_Partition"
	if filter != "" {
		query = fmt.Sprintf("%s %s", query, filter)
	}
	raw, err := oleutil.CallMethod(svc.wmiSvc, "ExecQuery", query)
	if err != nil {
		return parts, fmt.Errorf("ExecQuery(%s): %w", query, err)
	}
	result := raw.ToIDispatch()
	defer result.Release()

	countVar, err := oleutil.GetProperty(result, "Count")
	if err != nil {
		return parts, fmt.Errorf("oleutil.GetProperty(Count): %w", err)
	}
	count := int(countVar.Val)

	for i := 0; i < count; i++ {
		part := Partition{}
		itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
		if err != nil {
			return parts, fmt.Errorf("oleutil.CallMethod(ItemIndex, %d): %w", i, err)
		}
		part.handle = itemRaw.ToIDispatch()

		if err := part.Query(); err != nil {
			return parts, err
		}

		parts.Partitions = append(parts.Partitions, part)
	}

	return parts, nil
}
<commit_msg>Add a table for Operational Status` ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storage

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/google/logger"
	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

// Partition represents a MSFT_Partition object.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition
type Partition struct {
	DiskNumber           int32
	PartitionNumber      int32
	DriveLetter          string
	AccessPaths          []string
	OperationalStatus    int32
	TransitionState      int32
	Size                 uint64
	MbrType              int32
	GptType              string
	GUID                 string
	IsReadOnly           bool
	IsOffline            bool
	IsSystem             bool
	IsBoot               bool
	IsActive             bool
	IsHidden             bool
	IsShadowCopy         bool
	NoDefaultDriveLetter bool

	handle *ole.IDispatch
}

// PartitionSupportedSize represents the minimum and maximum sizes a partition can be resized to.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-getsupportedsizes
type PartitionSupportedSize struct {
	SizeMin uint64
	SizeMax uint64
}

// OperationalStatus describes an operational status.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition
type OperationalStatus uint16

const (
	// UnknownOperationalStatus is a type of Operational Status
	UnknownOperationalStatus OperationalStatus = 0
	// OnlineOperationalStatus is a type of Operational Status
	OnlineOperationalStatus OperationalStatus = 1
	// NoMediaOperationalStatus is a type of Operational Status
	NoMediaOperationalStatus OperationalStatus = 3
	// FailedOperationalStatus is a type of Operational Status
	FailedOperationalStatus OperationalStatus = 5
	// OfflineOperationalStatus is a type of Operational Status
	OfflineOperationalStatus OperationalStatus = 4
)

// Close releases the handle to the partition.
func (p *Partition) Close() {
	if p.handle != nil {
		p.handle.Release()
	}
}

// Delete attempts to delete a partition.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-deleteobject
func (p *Partition) Delete() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	resultRaw, err := oleutil.CallMethod(p.handle, "DeleteObject", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("DeleteObject: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during deletion: %d", val)
	}
	return stat, nil
}

// Offline takes the partition offline.
//
// Example:
//		p.Offline()
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-offline
func (p *Partition) Offline() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	res, err := oleutil.CallMethod(p.handle, "Offline", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Offline(): %w", err)
	} else if val, ok := res.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during offline: %d", val)
	}
	return stat, nil
}

// Online brings the partition online by mounting the associated volume (if one exists).
//
// Example:
//		p.Online()
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-online
func (p *Partition) Online() (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	res, err := oleutil.CallMethod(p.handle, "Online", &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Online(): %w", err)
	} else if val, ok := res.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during online: %d", val)
	}
	return stat, nil
}

// AddAccessPath adds a mount path or drive letter assignment to the partition.
//
// Example: assign a Drive letter with D:
//		p.AddAccessPath("D:", false)
//
// Example: Automatically assign the next available Drive Letter:
//		p.AddAccessPath("", true)
//
// Note: You cannot specify both a valid drive letter and auto assignment as true together.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/addaccesspath-msft-partition
func (p *Partition) AddAccessPath(accessPath string, autoAssign bool) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	var resultRaw *ole.VARIANT
	var err error
	if autoAssign {
		resultRaw, err = oleutil.CallMethod(p.handle, "AddAccessPath", nil, autoAssign, &extendedStatus)
	} else {
		resultRaw, err = oleutil.CallMethod(p.handle, "AddAccessPath", accessPath, nil, &extendedStatus)
	}
	if err != nil {
		return stat, fmt.Errorf("AddAccessPath: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during AddAccessPath: %d", val)
	}
	return stat, nil
}

// RemoveAccessPath removes the access path from the partition.
//
// Example: Remove the driveLetter of D: from a partition
//		p.RemoveAccessPath("D:")
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/removeaccesspath-msft-partition
func (p *Partition) RemoveAccessPath(accessPath string) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	resultRaw, err := oleutil.CallMethod(p.handle, "RemoveAccessPath", accessPath, &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("RemoveAccessPath: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during RemoveAccessPath: %d", val)
	}
	return stat, nil
}

// Query reads and populates the partition state.
func (p *Partition) Query() error {
	if p.handle == nil {
		return fmt.Errorf("invalid handle")
	}

	// DriveLetter
	prop, err := oleutil.GetProperty(p.handle, "DriveLetter")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(DriveLetter): %w", err)
	}
	// DriveLetter is represented as Char16 (Ascii)
	if prop.Val != 0 { // leave NUL as empty string
		p.DriveLetter = string(rune(prop.Val))
	}

	// AccessPaths
	prop, err = oleutil.GetProperty(p.handle, "AccessPaths")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(AccessPaths): %w", err)
	}

	if prop.Val != 0 { // leave NUL as empty string
		for _, pa := range prop.ToArray().ToValueArray() {
			conv, ok := pa.(string)
			if !ok {
				return errors.New("error converting access path")
			}
			p.AccessPaths = append(p.AccessPaths, conv)
		}
	}

	// GptType
	prop, err = oleutil.GetProperty(p.handle, "GptType")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(GptType): %w", err)
	}
	p.GptType = prop.ToString()

	// GUID
	prop, err = oleutil.GetProperty(p.handle, "Guid")
	if err != nil {
		return fmt.Errorf("oleutil.GetProperty(Guid): %w", err)
	}
	p.GUID = prop.ToString()

	// All the non-strings
	for _, prop := range [][]interface{}{
		[]interface{}{"DiskNumber", &p.DiskNumber},
		[]interface{}{"PartitionNumber", &p.PartitionNumber},
		[]interface{}{"OperationalStatus", &p.OperationalStatus},
		[]interface{}{"TransitionState", &p.TransitionState},
		[]interface{}{"Size", &p.Size},
		[]interface{}{"MbrType", &p.MbrType},
		[]interface{}{"IsReadOnly", &p.IsReadOnly},
		[]interface{}{"IsOffline", &p.IsOffline},
		[]interface{}{"IsSystem", &p.IsSystem},
		[]interface{}{"IsBoot", &p.IsBoot},
		[]interface{}{"IsActive", &p.IsActive},
		[]interface{}{"IsHidden", &p.IsHidden},
		[]interface{}{"IsShadowCopy", &p.IsShadowCopy},
		[]interface{}{"NoDefaultDriveLetter", &p.NoDefaultDriveLetter},
	} {
		val, err := oleutil.GetProperty(p.handle, prop[0].(string))
		if err != nil {
			return fmt.Errorf("oleutil.GetProperty(%s): %w", prop[0].(string), err)
		}
		if err := assignVariant(val.Value(), prop[1]); err != nil {
			logger.Warningf("assignVariant(%s): %v", prop[0].(string), err)
		}
	}
	return nil
}

// Resize attempts to resize a partition.
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-resize
func (p *Partition) Resize(size uint64) (ExtendedStatus, error) {
	stat := ExtendedStatus{}
	var extendedStatus ole.VARIANT
	ole.VariantInit(&extendedStatus)
	// Convert the unint to a string because of because of https://docs.microsoft.com/en-us/previous-versions//aa393262%28v=vs.85%29?redirectedfrom=MSDN
	resultRaw, err := oleutil.CallMethod(p.handle, "Resize", strconv.FormatUint(size, 10), &extendedStatus)
	if err != nil {
		return stat, fmt.Errorf("Resize: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return stat, fmt.Errorf("error code returned during resize: %d", val)
	}
	return stat, nil
}

// A PartitionSet contains one or more Partitions.
type PartitionSet struct {
	Partitions []Partition
}

// Close releases all Partition handles inside a PartitionSet.
func (s *PartitionSet) Close() {
	for _, p := range s.Partitions {
		p.Close()
	}
}

// GetSupportedSize retrieves the minimum and maximum sizes that the partition can be resized to
//
// Ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/stormgmt/msft-partition-getsupportedsizes
func (p *Partition) GetSupportedSize() (PartitionSupportedSize, ExtendedStatus, error) {
	size := PartitionSupportedSize{}
	stat := ExtendedStatus{}

	var sizemin ole.VARIANT
	ole.VariantInit(&sizemin)
	var sizemax ole.VARIANT
	ole.VariantInit(&sizemax)
	var extendedstatus ole.VARIANT
	ole.VariantInit(&extendedstatus)

	resultRaw, err := oleutil.CallMethod(p.handle, "GetSupportedSize", &sizemin, &sizemax, &extendedstatus)
	if err != nil {
		return size, stat, fmt.Errorf("GetSupportedSize: %w", err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return size, stat, fmt.Errorf("error code returned during GetSupportedSize: %d", val)
	}

	// Convert the results from an interface to uint64
	// Results are returned as strings because of https://docs.microsoft.com/en-us/previous-versions//aa393262%28v=vs.85%29?redirectedfrom=MSDN
	size.SizeMin, err = strconv.ParseUint(sizemin.Value().(string), 10, 64)
	if err != nil {
		return size, stat, fmt.Errorf("error attempting to parse sizemin: %w", err)
	}
	size.SizeMax, err = strconv.ParseUint(sizemax.Value().(string), 10, 64)
	if err != nil {
		return size, stat, fmt.Errorf("error attempting to parse sizemax: %w", err)
	}
	return size, stat, nil
}

// GetPartitions queries for local partitions.
//
// Close() must be called on the resulting PartitionSet to ensure all disks are released.
//
// Get all partitions:
//		svc.GetPartitions("")
//
// To get specific partitions, provide a valid WMI query filter string, for example:
//		svc.GetPartitions("WHERE DiskNumber=1")
func (svc *Service) GetPartitions(filter string) (PartitionSet, error) {
	parts := PartitionSet{}
	query := "SELECT * FROM MSFT_Partition"
	if filter != "" {
		query = fmt.Sprintf("%s %s", query, filter)
	}
	raw, err := oleutil.CallMethod(svc.wmiSvc, "ExecQuery", query)
	if err != nil {
		return parts, fmt.Errorf("ExecQuery(%s): %w", query, err)
	}
	result := raw.ToIDispatch()
	defer result.Release()

	countVar, err := oleutil.GetProperty(result, "Count")
	if err != nil {
		return parts, fmt.Errorf("oleutil.GetProperty(Count): %w", err)
	}
	count := int(countVar.Val)

	for i := 0; i < count; i++ {
		part := Partition{}
		itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
		if err != nil {
			return parts, fmt.Errorf("oleutil.CallMethod(ItemIndex, %d): %w", i, err)
		}
		part.handle = itemRaw.ToIDispatch()

		if err := part.Query(); err != nil {
			return parts, err
		}

		parts.Partitions = append(parts.Partitions, part)
	}

	return parts, nil
}
<|endoftext|>


<commit_before>package picarus
import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"bytes"
	"errors"
	"mime/multipart"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type Conn struct {
	Email string
	ApiKey string
	LoginKey string
	Server string
}

func (conn *Conn) call(method string, path []string, params url.Values, files map[string][]byte, key string) ([]byte, error) {
	var err error
	var req *http.Request
	serverPrefix := conn.Server + "/" + strings.Join(path, "/")
	if method == "GET" {
		req, err = http.NewRequest(method, serverPrefix + "?" + params.Encode(), nil)
	} else {
		buf := new(bytes.Buffer)
		w := multipart.NewWriter(buf)
		for fileName, fileData := range files {
			_, err = w.CreateFormFile(fileName, fileName) // fw
			if err != nil {
				return nil, err
			}
			buf.Write([]byte(fileData))
		}
		for name, values := range params {
			for _, value := range values {
				err = w.WriteField(name, value)
				if err != nil {
					return nil, err
				}
			}
		}
		w.Close()
		req, err = http.NewRequest(method, serverPrefix, buf)
		if err != nil {
			return nil, err
		}
		req.Header.Set("Content-Type", w.FormDataContentType())
	}
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(conn.Email, key)
	response, err := http.DefaultClient.Do(req) // res
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(response.Body)
	defer response.Body.Close()
	if err != nil {
		return nil, err
	}
	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Bad status[%d][%s]", response.StatusCode, body))
	}
	return body, nil
}

func decodeLod(values []map[string]string) ([]map[string]string, error) {
	out := []map[string]string{}
	for _, value := range values {
		curOut, err := decodeDict(value)
		if err != nil {
			return nil, err
		}
		out = append(out, curOut)
	}
	return out, nil
}

func decodeDict(value map[string]string) (map[string]string, error) {
	out := map[string]string{}
	for k, v := range value {
		// TODO: Use a checked version of b64dec
		if k == "row" {
			out[k] = B64Dec(v)
		} else {
			out[B64Dec(k)] = B64Dec(v)
		}
	}
	return out, nil
}

func decodeValues(value map[string]string) (map[string]string, error) {
	out := map[string]string{}
	for k, v := range value {
		// TODO: Use a checked version of b64dec
		out[k] = B64Dec(v)
	}
	return out, nil
}

func encodeDict(value map[string]string) map[string]string {
	out := map[string]string{}
	for k, v := range value {
		out[B64Enc(k)] = B64Enc(v)
	}
	return out
}

func encodeValues(value map[string]string) map[string]string {
	out := map[string]string{}
	for k, v := range value {
		out[k] = B64Enc(v)
	}
	return out
}

func encodeFiles(files map[string][]byte) map[string][]byte {
	out := map[string][]byte{}
	for k, v := range files {
		out[B64Enc(k)] = v
	}
	return out
}

func (conn *Conn) GetRow(table string, row string, columns []string) (map[string]string, error) {
	params := url.Values{}
	if len(columns) > 0 {
		params.Set("columns", encodeColumns(columns))
	}
	data, err := conn.call("GET", []string{"v0", "data", table, UB64Enc(row)}, params, map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func (conn *Conn) GetTable(table string, columns []string) ([]map[string]string, error) {
	params := url.Values{}
	if len(columns) > 0 {
		params.Set("columns", encodeColumns(columns))
	}
	data, err := conn.call("GET", []string{"v0", "data", table}, params, map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := []map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeLod(dataParsed)
}

func encodeColumns(columns []string) string {
	columnsB64 := []string{}
	for _, c := range columns {
		columnsB64 = append(columnsB64, B64Enc(c))
	}
	return strings.Join(columnsB64, ",")
}

func (conn *Conn) GetSlice(table string, startRow string, stopRow string, columns []string, params map[string]string) ([]map[string]string, error) {
	if len(columns) > 0 {
		params["columns"] = encodeColumns(columns)
	}
	data, err := conn.call("GET", []string{"v0", "slice", table, UB64Enc(startRow), UB64Enc(stopRow)}, mapToUrlValues(params), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := []map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeLod(dataParsed)
}

type ScannerState struct {
	startRow, stopRow string
	prevData *[]map[string]string
	nextRow int
	columns []string
	params map[string]string
	conn *Conn
	Done bool
}

func (conn *Conn) Scanner(table string, startRow string, stopRow string, columns []string, params map[string]string) *ScannerState {
	return &ScannerState{startRow: startRow, stopRow: stopRow, nextRow: 0, columns: columns, params: params, Done: false, conn: conn}
}

func (ss *ScannerState) Next() (string, map[string]string, error) {
	fmt.Println(*ss)
	if ss.Done {
		return "", nil, nil
	}
	if ss.prevData == nil || (ss.prevData != nil && len(*ss.prevData) == ss.nextRow) {
		var startRow string
		var excludeStart string
		if ss.prevData == nil {
			excludeStart = "0"
			startRow = ss.startRow
		} else {
			excludeStart = "1"
			startRow = (*ss.prevData)[ss.nextRow - 1]["row"]
		}
		ss.params["excludeStart"] = excludeStart
		data, err := ss.conn.GetSlice("images", startRow, ss.stopRow, ss.columns, ss.params)
		if err != nil {
			return "", nil, err
		}
		if len(data) == 0 {
			ss.Done = true
			return "", nil, nil
		}
		ss.prevData = &data
		ss.nextRow = 0
	}
	columns := (*ss.prevData)[ss.nextRow]
	row := columns["row"]
	delete(columns, "row")
	ss.nextRow += 1
	return row, columns, nil
}

func mapToUrlValues(data map[string]string) url.Values {
	out := url.Values{}
	for k, v := range data {
		out.Set(k, v)
	}
	return out
}

func (conn *Conn) PostSlice(table string, startRow string, stopRow string, params map[string]string) (map[string]string, error) {
	data, err := conn.call("POST", []string{"v0", "slice", table, UB64Enc(startRow), UB64Enc(stopRow)}, mapToUrlValues(encodeValues(params)), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

type Slice struct {
    StartRow, StopRow string
}

func encodeSlices(slices []Slice) string {
	out := []string{}
	for _, v := range slices {
		out = append(out, B64Enc(v.StartRow) + "," + B64Enc(v.StopRow))
	}
	return strings.Join(out, ";")
}

func (conn *Conn) PostTable(table string, params map[string]string, files map[string][]byte, slices []Slice) (map[string]string, error) {
	if len(slices) > 0 {
		params["slices"] = encodeSlices(slices)
	}
	data, err := conn.call("POST", []string{"v0", "data", table}, mapToUrlValues(encodeDict(params)), encodeFiles(files), conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeValues(dataParsed)
}

func (conn *Conn) PostRow(table string, row string, params map[string]string) (map[string]string, error) {
	data, err := conn.call("POST", []string{"v0", "data", table, UB64Enc(row)}, mapToUrlValues(encodeValues(params)), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func (conn *Conn) PatchRow(table string, row string, params map[string]string, files map[string][]byte) (map[string]string, error) {
	data, err := conn.call("PATCH", []string{"v0", "data", table, UB64Enc(row)}, mapToUrlValues(encodeDict(params)), encodeFiles(files), conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func UB64Dec(s string) string {
	decoded, err := base64.URLEncoding.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return string(decoded)
}

func B64Dec(s string) string {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		fmt.Println(s)
		panic(err)
	}
	return string(decoded)
}

func B64DecBytes(s string) []byte {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		fmt.Println(s)
		panic(err)
	}
	return decoded
}

func UB64Enc(s string) string {
	return base64.URLEncoding.EncodeToString([]byte(s))
}

func B64Enc(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func (conn *Conn) WatchJob(row string) (map[string]string, error) {
	for {
		data, err := conn.GetRow("jobs", row, []string{})
		if err != nil {
			return nil, err
		}
		fmt.Println(data)
		if data["status"] == "completed" {
			return data, nil
		}
		time.Sleep(1000 * time.Millisecond)
	}
}<commit_msg>Updated scanner<commit_after>package picarus
import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"bytes"
	"errors"
	"mime/multipart"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type Conn struct {
	Email string
	ApiKey string
	LoginKey string
	Server string
}

func (conn *Conn) call(method string, path []string, params url.Values, files map[string][]byte, key string) ([]byte, error) {
	var err error
	var req *http.Request
	serverPrefix := conn.Server + "/" + strings.Join(path, "/")
	if method == "GET" {
		req, err = http.NewRequest(method, serverPrefix + "?" + params.Encode(), nil)
	} else {
		buf := new(bytes.Buffer)
		w := multipart.NewWriter(buf)
		for fileName, fileData := range files {
			_, err = w.CreateFormFile(fileName, fileName) // fw
			if err != nil {
				return nil, err
			}
			buf.Write([]byte(fileData))
		}
		for name, values := range params {
			for _, value := range values {
				err = w.WriteField(name, value)
				if err != nil {
					return nil, err
				}
			}
		}
		w.Close()
		req, err = http.NewRequest(method, serverPrefix, buf)
		if err != nil {
			return nil, err
		}
		req.Header.Set("Content-Type", w.FormDataContentType())
	}
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(conn.Email, key)
	response, err := http.DefaultClient.Do(req) // res
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(response.Body)
	defer response.Body.Close()
	if err != nil {
		return nil, err
	}
	if response.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("Bad status[%d][%s]", response.StatusCode, body))
	}
	return body, nil
}

func decodeLod(values []map[string]string) ([]map[string]string, error) {
	out := []map[string]string{}
	for _, value := range values {
		curOut, err := decodeDict(value)
		if err != nil {
			return nil, err
		}
		out = append(out, curOut)
	}
	return out, nil
}

func decodeDict(value map[string]string) (map[string]string, error) {
	out := map[string]string{}
	for k, v := range value {
		// TODO: Use a checked version of b64dec
		if k == "row" {
			out[k] = B64Dec(v)
		} else {
			out[B64Dec(k)] = B64Dec(v)
		}
	}
	return out, nil
}

func decodeValues(value map[string]string) (map[string]string, error) {
	out := map[string]string{}
	for k, v := range value {
		// TODO: Use a checked version of b64dec
		out[k] = B64Dec(v)
	}
	return out, nil
}

func encodeDict(value map[string]string) map[string]string {
	out := map[string]string{}
	for k, v := range value {
		out[B64Enc(k)] = B64Enc(v)
	}
	return out
}

func encodeValues(value map[string]string) map[string]string {
	out := map[string]string{}
	for k, v := range value {
		out[k] = B64Enc(v)
	}
	return out
}

func encodeFiles(files map[string][]byte) map[string][]byte {
	out := map[string][]byte{}
	for k, v := range files {
		out[B64Enc(k)] = v
	}
	return out
}

func (conn *Conn) GetRow(table string, row string, columns []string) (map[string]string, error) {
	params := url.Values{}
	if len(columns) > 0 {
		params.Set("columns", encodeColumns(columns))
	}
	data, err := conn.call("GET", []string{"v0", "data", table, UB64Enc(row)}, params, map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func (conn *Conn) GetTable(table string, columns []string) ([]map[string]string, error) {
	params := url.Values{}
	if len(columns) > 0 {
		params.Set("columns", encodeColumns(columns))
	}
	data, err := conn.call("GET", []string{"v0", "data", table}, params, map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := []map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeLod(dataParsed)
}

func encodeColumns(columns []string) string {
	columnsB64 := []string{}
	for _, c := range columns {
		columnsB64 = append(columnsB64, B64Enc(c))
	}
	return strings.Join(columnsB64, ",")
}

func (conn *Conn) GetSlice(table string, startRow string, stopRow string, columns []string, params map[string]string) ([]map[string]string, error) {
	if len(columns) > 0 {
		params["columns"] = encodeColumns(columns)
	}
	data, err := conn.call("GET", []string{"v0", "slice", table, UB64Enc(startRow), UB64Enc(stopRow)}, mapToUrlValues(params), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := []map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeLod(dataParsed)
}

type ScannerState struct {
	startRow, prevRow, stopRow string
	prevData *[]map[string]string
	nextRow int
	columns []string
	params map[string]string
	conn *Conn
	Done bool
}

func (conn *Conn) Scanner(table string, startRow string, stopRow string, columns []string, params map[string]string) *ScannerState {
	return &ScannerState{startRow: startRow, stopRow: stopRow, nextRow: 0, columns: columns, params: params, Done: false, conn: conn}
}

func (ss *ScannerState) Next() (string, map[string]string, error) {
	fmt.Println(*ss)
	if ss.Done {
		return "", nil, nil
	}
	if ss.prevData == nil || (ss.prevData != nil && len(*ss.prevData) == ss.nextRow) {
		startRow := ss.startRow
		var excludeStart string
		if ss.prevData == nil {
			excludeStart = "0"
		} else {
			excludeStart = "1"
			startRow = ss.prevRow
		}
		ss.params["excludeStart"] = excludeStart
		data, err := ss.conn.GetSlice("images", startRow, ss.stopRow, ss.columns, ss.params)
		if err != nil {
			return "", nil, err
		}
		fmt.Println(data)
		if len(data) == 0 {
			ss.Done = true
			return "", nil, nil
		}
		ss.prevData = &data
		ss.nextRow = 0
	}
	columns := (*ss.prevData)[ss.nextRow]
	ss.prevRow = columns["row"]
	delete(columns, "row")
	ss.nextRow += 1
	return ss.prevRow, columns, nil
}

func mapToUrlValues(data map[string]string) url.Values {
	out := url.Values{}
	for k, v := range data {
		out.Set(k, v)
	}
	return out
}

func (conn *Conn) PostSlice(table string, startRow string, stopRow string, params map[string]string) (map[string]string, error) {
	data, err := conn.call("POST", []string{"v0", "slice", table, UB64Enc(startRow), UB64Enc(stopRow)}, mapToUrlValues(encodeValues(params)), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

type Slice struct {
    StartRow, StopRow string
}

func encodeSlices(slices []Slice) string {
	out := []string{}
	for _, v := range slices {
		out = append(out, B64Enc(v.StartRow) + "," + B64Enc(v.StopRow))
	}
	return strings.Join(out, ";")
}

func (conn *Conn) PostTable(table string, params map[string]string, files map[string][]byte, slices []Slice) (map[string]string, error) {
	if len(slices) > 0 {
		params["slices"] = encodeSlices(slices)
	}
	data, err := conn.call("POST", []string{"v0", "data", table}, mapToUrlValues(encodeDict(params)), encodeFiles(files), conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeValues(dataParsed)
}

func (conn *Conn) PostRow(table string, row string, params map[string]string) (map[string]string, error) {
	data, err := conn.call("POST", []string{"v0", "data", table, UB64Enc(row)}, mapToUrlValues(encodeValues(params)), map[string][]byte{}, conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func (conn *Conn) PatchRow(table string, row string, params map[string]string, files map[string][]byte) (map[string]string, error) {
	data, err := conn.call("PATCH", []string{"v0", "data", table, UB64Enc(row)}, mapToUrlValues(encodeDict(params)), encodeFiles(files), conn.ApiKey)
	if err != nil {
		return nil, err
	}
	dataParsed := map[string]string{}
	json.Unmarshal(data, &dataParsed)
	return decodeDict(dataParsed)
}

func UB64Dec(s string) string {
	decoded, err := base64.URLEncoding.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return string(decoded)
}

func B64Dec(s string) string {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		fmt.Println(s)
		panic(err)
	}
	return string(decoded)
}

func B64DecBytes(s string) []byte {
	decoded, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		fmt.Println(s)
		panic(err)
	}
	return decoded
}

func UB64Enc(s string) string {
	return base64.URLEncoding.EncodeToString([]byte(s))
}

func B64Enc(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func (conn *Conn) WatchJob(row string) (map[string]string, error) {
	for {
		data, err := conn.GetRow("jobs", row, []string{})
		if err != nil {
			return nil, err
		}
		fmt.Println(data)
		if data["status"] == "completed" {
			return data, nil
		}
		time.Sleep(1000 * time.Millisecond)
	}
}<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package worker_test

import (
	"strings"
	stdtesting "testing"
	"time"

	"github.com/juju/loggo"
	gc "launchpad.net/gocheck"
	"launchpad.net/tomb"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/juju/testing"
	"github.com/juju/juju/mongo"
	"github.com/juju/juju/state"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/worker"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type environSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&environSuite{})

func (s *environSuite) TestStop(c *gc.C) {
	w := s.State.WatchForEnvironConfigChanges()
	defer stopWatcher(c, w)
	stop := make(chan struct{})
	done := make(chan error)
	go func() {
		env, err := worker.WaitForEnviron(w, s.State, stop)
		c.Check(env, gc.IsNil)
		done <- err
	}()
	close(stop)
	c.Assert(<-done, gc.Equals, tomb.ErrDying)
}

func stopWatcher(c *gc.C, w state.NotifyWatcher) {
	err := w.Stop()
	c.Check(err, gc.IsNil)
}

func (s *environSuite) TestInvalidConfig(c *gc.C) {
	var oldType string
	oldType = s.Environ.Config().AllAttrs()["type"].(string)

	// Create an invalid config by taking the current config and
	// tweaking the provider type.
	info := s.MongoInfo(c)
	opts := mongo.DefaultDialOpts()
	st2, err := state.Open(info, opts, state.Policy(nil))
	c.Assert(err, gc.IsNil)
	defer st2.Close()
	err = st2.UpdateEnvironConfig(map[string]interface{}{"type": "unknown"}, nil, nil)
	c.Assert(err, gc.IsNil)

	w := st2.WatchForEnvironConfigChanges()
	defer stopWatcher(c, w)
	done := make(chan environs.Environ)
	go func() {
		env, err := worker.WaitForEnviron(w, st2, nil)
		c.Check(err, gc.IsNil)
		done <- env
	}()
	// Wait for the loop to process the invalid configuratrion
	<-worker.LoadedInvalid

	st2.UpdateEnvironConfig(map[string]interface{}{
		"type":   oldType,
		"secret": "environ_test",
	}, nil, nil)

	env := <-done
	c.Assert(env, gc.NotNil)
	c.Assert(env.Config().AllAttrs()["secret"], gc.Equals, "environ_test")
}

func (s *environSuite) TestErrorWhenEnvironIsInvalid(c *gc.C) {
	// reopen the state so that we can wangle a dodgy environ config in there.
	st, err := state.Open(s.MongoInfo(c), mongo.DefaultDialOpts(), state.Policy(nil))
	c.Assert(err, gc.IsNil)
	defer st.Close()
	err = st.UpdateEnvironConfig(map[string]interface{}{"secret": 999}, nil, nil)
	c.Assert(err, gc.IsNil)
	obs, err := worker.NewEnvironObserver(s.State)
	c.Assert(err, gc.ErrorMatches, `cannot make Environ: secret: expected string, got int\(999\)`)
	c.Assert(obs, gc.IsNil)
}

func (s *environSuite) TestEnvironmentChanges(c *gc.C) {
	originalConfig, err := s.State.EnvironConfig()
	c.Assert(err, gc.IsNil)

	logc := make(logChan, 1009)
	c.Assert(loggo.RegisterWriter("testing", logc, loggo.WARNING), gc.IsNil)
	defer loggo.RemoveWriter("testing")

	obs, err := worker.NewEnvironObserver(s.State)
	c.Assert(err, gc.IsNil)

	env := obs.Environ()
	c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())
	var oldType string
	oldType = env.Config().AllAttrs()["type"].(string)

	info := s.MongoInfo(c)
	opts := mongo.DefaultDialOpts()
	st2, err := state.Open(info, opts, state.Policy(nil))
	defer st2.Close()

	// Change to an invalid configuration and check
	// that the observer's environment remains the same.
	st2.UpdateEnvironConfig(map[string]interface{}{"type": "invalid"}, nil, nil)
	st2.StartSync()

	// Wait for the observer to register the invalid environment
	timeout := time.After(coretesting.LongWait)
loop:
	for {
		select {
		case msg := <-logc:
			if strings.Contains(msg, "error creating Environ") {
				break loop
			}
		case <-timeout:
			c.Fatalf("timed out waiting to see broken environment")
		}
	}
	// Check that the returned environ is still the same.
	env = obs.Environ()
	c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())

	// Change the environment back to a valid configuration
	// with a different name and check that we see it.
	st2.UpdateEnvironConfig(map[string]interface{}{"type": oldType, "name": "a-new-name"}, nil, nil)
	st2.StartSync()

	for a := coretesting.LongAttempt.Start(); a.Next(); {
		env := obs.Environ()
		if !a.HasNext() {
			c.Fatalf("timed out waiting for new environ")
		}
		if env.Config().Name() == "a-new-name" {
			break
		}
	}
}

type logChan chan string

func (logc logChan) Write(level loggo.Level, name, filename string, line int, timestamp time.Time, message string) {
	logc <- message
}
<commit_msg>driveby: fix slow tests<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package worker_test

import (
	"strings"
	stdtesting "testing"
	"time"

	"github.com/juju/loggo"
	gc "launchpad.net/gocheck"
	"launchpad.net/tomb"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/juju/testing"
	"github.com/juju/juju/mongo"
	"github.com/juju/juju/state"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/worker"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type environSuite struct {
	testing.JujuConnSuite
}

var _ = gc.Suite(&environSuite{})

func (s *environSuite) TestStop(c *gc.C) {
	w := s.State.WatchForEnvironConfigChanges()
	defer stopWatcher(c, w)
	stop := make(chan struct{})
	done := make(chan error)
	go func() {
		env, err := worker.WaitForEnviron(w, s.State, stop)
		c.Check(env, gc.IsNil)
		done <- err
	}()
	close(stop)
	c.Assert(<-done, gc.Equals, tomb.ErrDying)
}

func stopWatcher(c *gc.C, w state.NotifyWatcher) {
	err := w.Stop()
	c.Check(err, gc.IsNil)
}

func (s *environSuite) TestInvalidConfig(c *gc.C) {
	var oldType string
	oldType = s.Environ.Config().AllAttrs()["type"].(string)

	// Create an invalid config by taking the current config and
	// tweaking the provider type.
	info := s.MongoInfo(c)
	opts := mongo.DefaultDialOpts()
	st2, err := state.Open(info, opts, state.Policy(nil))
	c.Assert(err, gc.IsNil)
	defer st2.Close()
	err = st2.UpdateEnvironConfig(map[string]interface{}{"type": "unknown"}, nil, nil)
	c.Assert(err, gc.IsNil)

	w := st2.WatchForEnvironConfigChanges()
	defer stopWatcher(c, w)
	done := make(chan environs.Environ)
	go func() {
		env, err := worker.WaitForEnviron(w, st2, nil)
		c.Check(err, gc.IsNil)
		done <- env
	}()
	<-worker.LoadedInvalid

	st2.UpdateEnvironConfig(map[string]interface{}{
		"type":   oldType,
		"secret": "environ_test",
	}, nil, nil)

	st2.StartSync()
	env := <-done
	c.Assert(env, gc.NotNil)
	c.Assert(env.Config().AllAttrs()["secret"], gc.Equals, "environ_test")
}

func (s *environSuite) TestErrorWhenEnvironIsInvalid(c *gc.C) {
	// reopen the state so that we can wangle a dodgy environ config in there.
	st, err := state.Open(s.MongoInfo(c), mongo.DefaultDialOpts(), state.Policy(nil))
	c.Assert(err, gc.IsNil)
	defer st.Close()
	err = st.UpdateEnvironConfig(map[string]interface{}{"secret": 999}, nil, nil)
	c.Assert(err, gc.IsNil)
	obs, err := worker.NewEnvironObserver(s.State)
	c.Assert(err, gc.ErrorMatches, `cannot make Environ: secret: expected string, got int\(999\)`)
	c.Assert(obs, gc.IsNil)
}

func (s *environSuite) TestEnvironmentChanges(c *gc.C) {
	originalConfig, err := s.State.EnvironConfig()
	c.Assert(err, gc.IsNil)

	logc := make(logChan, 1009)
	c.Assert(loggo.RegisterWriter("testing", logc, loggo.WARNING), gc.IsNil)
	defer loggo.RemoveWriter("testing")

	obs, err := worker.NewEnvironObserver(s.State)
	c.Assert(err, gc.IsNil)

	env := obs.Environ()
	c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())
	var oldType string
	oldType = env.Config().AllAttrs()["type"].(string)

	info := s.MongoInfo(c)
	opts := mongo.DefaultDialOpts()
	st2, err := state.Open(info, opts, state.Policy(nil))
	defer st2.Close()

	// Change to an invalid configuration and check
	// that the observer's environment remains the same.
	st2.UpdateEnvironConfig(map[string]interface{}{"type": "invalid"}, nil, nil)
	s.State.StartSync()

	// Wait for the observer to register the invalid environment
loop:
	for {
		select {
		case msg := <-logc:
			if strings.Contains(msg, "error creating Environ") {
				break loop
			}
		case <-time.After(coretesting.ShortWait):
			c.Fatalf("timed out waiting to see broken environment")
		}
	}
	// Check that the returned environ is still the same.
	env = obs.Environ()
	c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())

	// Change the environment back to a valid configuration
	// with a different name and check that we see it.
	st2.UpdateEnvironConfig(map[string]interface{}{"type": oldType, "name": "a-new-name"}, nil, nil)
	s.State.StartSync()

	for a := coretesting.LongAttempt.Start(); a.Next(); {
		env := obs.Environ()
		if !a.HasNext() {
			c.Fatalf("timed out waiting for new environ")
		}
		if env.Config().Name() == "a-new-name" {
			break
		}
	}
}

type logChan chan string

func (logc logChan) Write(level loggo.Level, name, filename string, line int, timestamp time.Time, message string) {
	logc <- message
}
<|endoftext|>