<commit_before>package main

import "C"
import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"unsafe"

	"github.com/tdewolff/minify/v2"
	"github.com/tdewolff/minify/v2/css"
	"github.com/tdewolff/minify/v2/html"
	"github.com/tdewolff/minify/v2/js"
	"github.com/tdewolff/minify/v2/json"
	"github.com/tdewolff/minify/v2/svg"
	"github.com/tdewolff/minify/v2/xml"
	"github.com/tdewolff/parse/v2/buffer"
)

var m *minify.M

func init() {
	minifyConfig(nil, nil, 0)
}

func goBytes(str *C.char, length C.longlong) []byte {
	return (*[1 << 32]byte)(unsafe.Pointer(str))[:length:length]
}

func goStringArray(carr **C.char, length C.longlong) []string {
	if length == 0 {
		return []string{}
	}

	strs := make([]string, length)
	arr := (*[1 << 32]*C.char)(unsafe.Pointer(carr))[:length:length]
	for i := 0; i < int(length); i++ {
		strs[i] = C.GoString(arr[i])
	}
	return strs
}

//export minifyConfig
func minifyConfig(ckeys **C.char, cvals **C.char, length C.longlong) *C.char {
	keys := goStringArray(ckeys, length)
	vals := goStringArray(cvals, length)

	cssMinifier := &css.Minifier{}
	htmlMinifier := &html.Minifier{}
	jsMinifier := &js.Minifier{}
	jsonMinifier := &json.Minifier{}
	svgMinifier := &svg.Minifier{}
	xmlMinifier := &xml.Minifier{}

	var err error
	for i := 0; i < len(keys); i++ {
		switch keys[i] {
		case "css-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			cssMinifier.Precision = int(precision)
		case "html-keep-comments":
			htmlMinifier.KeepComments, err = strconv.ParseBool(vals[i])
		case "html-keep-conditional-comments":
			htmlMinifier.KeepConditionalComments, err = strconv.ParseBool(vals[i])
		case "html-keep-default-attr-vals":
			htmlMinifier.KeepDefaultAttrVals, err = strconv.ParseBool(vals[i])
		case "html-keep-document-tags":
			htmlMinifier.KeepDocumentTags, err = strconv.ParseBool(vals[i])
		case "html-keep-end-tags":
			htmlMinifier.KeepEndTags, err = strconv.ParseBool(vals[i])
		case "html-keep-whitespace":
			htmlMinifier.KeepWhitespace, err = strconv.ParseBool(vals[i])
		case "html-keep-quotes":
			htmlMinifier.KeepQuotes, err = strconv.ParseBool(vals[i])
		case "js-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			jsMinifier.Precision = int(precision)
		case "js-keep-var-names":
			jsMinifier.KeepVarNames, err = strconv.ParseBool(vals[i])
		case "js-no-nullish-operator":
			jsMinifier.NoNullishOperator, err = strconv.ParseBool(vals[i])
		case "json-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			jsonMinifier.Precision = int(precision)
		case "json-keep-numbers":
			jsonMinifier.KeepNumbers, err = strconv.ParseBool(vals[i])
		case "svg-keep-comments":
			svgMinifier.KeepComments, err = strconv.ParseBool(vals[i])
		case "svg-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			svgMinifier.Precision = int(precision)
		case "xml-keep-whitespace":
			xmlMinifier.KeepWhitespace, err = strconv.ParseBool(vals[i])
		default:
			return C.CString(fmt.Sprintf("unknown config key: %s", keys[i]))
		}
		if err != nil {
			if err.(*strconv.NumError).Func == "ParseInt" {
				err = fmt.Errorf("\"%s\" is not an integer", vals[i])
			} else if err.(*strconv.NumError).Func == "ParseBool" {
				err = fmt.Errorf("\"%s\" is not a boolean", vals[i])
			}
			return C.CString(fmt.Sprintf("bad config value for %s: %v", keys[i], err))
		}
	}

	m = minify.New()
	m.Add("text/css", cssMinifier)
	m.Add("text/html", htmlMinifier)
	m.Add("image/svg+xml", svgMinifier)
	m.AddRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma|j|live)script(1\\.[0-5])?$|^module$"), jsMinifier)
	m.AddRegexp(regexp.MustCompile("[/+]json$"), jsonMinifier)
	m.AddRegexp(regexp.MustCompile("[/+]xml$"), xmlMinifier)
	return nil
}

//export minifyString
func minifyString(cmediatype, cinput *C.char, input_length C.longlong, coutput *C.char, output_length *C.longlong) *C.char {
	mediatype := C.GoString(cmediatype) // copy
	input := goBytes(cinput, input_length)
	output := goBytes(coutput, input_length)

	out := buffer.NewStaticWriter(output[:0])
	if err := m.Minify(mediatype, out, buffer.NewReader(input)); err != nil {
		return C.CString(err.Error())
	} else if err := out.Close(); err != nil {
		return C.CString(err.Error())
	}
	*output_length = C.longlong(out.Len())
	return nil
}

//export minifyFile
func minifyFile(cmediatype, cinput, coutput *C.char) *C.char {
	mediatype := C.GoString(cmediatype) // copy
	input := C.GoString(cinput)
	output := C.GoString(coutput)

	fi, err := os.Open(input)
	if err != nil {
		return C.CString(err.Error())
	}

	fo, err := os.Create(output)
	if err != nil {
		return C.CString(err.Error())
	}

	if err := m.Minify(mediatype, fo, fi); err != nil {
		fi.Close()
		fo.Close()
		return C.CString(err.Error())
	} else if err := fi.Close(); err != nil {
		fo.Close()
		return C.CString(err.Error())
	} else if err := fo.Close(); err != nil {
		return C.CString(err.Error())
	}
	return nil
}

//export minifyCleanup
func minifyCleanup() {
	os.Exit(0)
}

func main() {}
<commit_msg>Remove os.Exit(0) for JS binding<commit_after>package main

import "C"
import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"unsafe"

	"github.com/tdewolff/minify/v2"
	"github.com/tdewolff/minify/v2/css"
	"github.com/tdewolff/minify/v2/html"
	"github.com/tdewolff/minify/v2/js"
	"github.com/tdewolff/minify/v2/json"
	"github.com/tdewolff/minify/v2/svg"
	"github.com/tdewolff/minify/v2/xml"
	"github.com/tdewolff/parse/v2/buffer"
)

var m *minify.M

func init() {
	minifyConfig(nil, nil, 0)
}

func goBytes(str *C.char, length C.longlong) []byte {
	return (*[1 << 32]byte)(unsafe.Pointer(str))[:length:length]
}

func goStringArray(carr **C.char, length C.longlong) []string {
	if length == 0 {
		return []string{}
	}

	strs := make([]string, length)
	arr := (*[1 << 32]*C.char)(unsafe.Pointer(carr))[:length:length]
	for i := 0; i < int(length); i++ {
		strs[i] = C.GoString(arr[i])
	}
	return strs
}

//export minifyConfig
func minifyConfig(ckeys **C.char, cvals **C.char, length C.longlong) *C.char {
	keys := goStringArray(ckeys, length)
	vals := goStringArray(cvals, length)

	cssMinifier := &css.Minifier{}
	htmlMinifier := &html.Minifier{}
	jsMinifier := &js.Minifier{}
	jsonMinifier := &json.Minifier{}
	svgMinifier := &svg.Minifier{}
	xmlMinifier := &xml.Minifier{}

	var err error
	for i := 0; i < len(keys); i++ {
		switch keys[i] {
		case "css-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			cssMinifier.Precision = int(precision)
		case "html-keep-comments":
			htmlMinifier.KeepComments, err = strconv.ParseBool(vals[i])
		case "html-keep-conditional-comments":
			htmlMinifier.KeepConditionalComments, err = strconv.ParseBool(vals[i])
		case "html-keep-default-attr-vals":
			htmlMinifier.KeepDefaultAttrVals, err = strconv.ParseBool(vals[i])
		case "html-keep-document-tags":
			htmlMinifier.KeepDocumentTags, err = strconv.ParseBool(vals[i])
		case "html-keep-end-tags":
			htmlMinifier.KeepEndTags, err = strconv.ParseBool(vals[i])
		case "html-keep-whitespace":
			htmlMinifier.KeepWhitespace, err = strconv.ParseBool(vals[i])
		case "html-keep-quotes":
			htmlMinifier.KeepQuotes, err = strconv.ParseBool(vals[i])
		case "js-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			jsMinifier.Precision = int(precision)
		case "js-keep-var-names":
			jsMinifier.KeepVarNames, err = strconv.ParseBool(vals[i])
		case "js-no-nullish-operator":
			jsMinifier.NoNullishOperator, err = strconv.ParseBool(vals[i])
		case "json-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			jsonMinifier.Precision = int(precision)
		case "json-keep-numbers":
			jsonMinifier.KeepNumbers, err = strconv.ParseBool(vals[i])
		case "svg-keep-comments":
			svgMinifier.KeepComments, err = strconv.ParseBool(vals[i])
		case "svg-precision":
			var precision int64
			precision, err = strconv.ParseInt(vals[i], 10, 64)
			svgMinifier.Precision = int(precision)
		case "xml-keep-whitespace":
			xmlMinifier.KeepWhitespace, err = strconv.ParseBool(vals[i])
		default:
			return C.CString(fmt.Sprintf("unknown config key: %s", keys[i]))
		}
		if err != nil {
			if err.(*strconv.NumError).Func == "ParseInt" {
				err = fmt.Errorf("\"%s\" is not an integer", vals[i])
			} else if err.(*strconv.NumError).Func == "ParseBool" {
				err = fmt.Errorf("\"%s\" is not a boolean", vals[i])
			}
			return C.CString(fmt.Sprintf("bad config value for %s: %v", keys[i], err))
		}
	}

	m = minify.New()
	m.Add("text/css", cssMinifier)
	m.Add("text/html", htmlMinifier)
	m.Add("image/svg+xml", svgMinifier)
	m.AddRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma|j|live)script(1\\.[0-5])?$|^module$"), jsMinifier)
	m.AddRegexp(regexp.MustCompile("[/+]json$"), jsonMinifier)
	m.AddRegexp(regexp.MustCompile("[/+]xml$"), xmlMinifier)
	return nil
}

//export minifyString
func minifyString(cmediatype, cinput *C.char, input_length C.longlong, coutput *C.char, output_length *C.longlong) *C.char {
	mediatype := C.GoString(cmediatype) // copy
	input := goBytes(cinput, input_length)
	output := goBytes(coutput, input_length)

	out := buffer.NewStaticWriter(output[:0])
	if err := m.Minify(mediatype, out, buffer.NewReader(input)); err != nil {
		return C.CString(err.Error())
	} else if err := out.Close(); err != nil {
		return C.CString(err.Error())
	}
	*output_length = C.longlong(out.Len())
	return nil
}

//export minifyFile
func minifyFile(cmediatype, cinput, coutput *C.char) *C.char {
	mediatype := C.GoString(cmediatype) // copy
	input := C.GoString(cinput)
	output := C.GoString(coutput)

	fi, err := os.Open(input)
	if err != nil {
		return C.CString(err.Error())
	}

	fo, err := os.Create(output)
	if err != nil {
		return C.CString(err.Error())
	}

	if err := m.Minify(mediatype, fo, fi); err != nil {
		fi.Close()
		fo.Close()
		return C.CString(err.Error())
	} else if err := fi.Close(); err != nil {
		fo.Close()
		return C.CString(err.Error())
	} else if err := fo.Close(); err != nil {
		return C.CString(err.Error())
	}
	return nil
}

//export minifyCleanup
func minifyCleanup() {
	//os.Exit(0)
}

func main() {}
<|endoftext|>


<commit_before>// Copyright 2014 Benny Scetbun. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package Jsongo is a simple library to help you build Json without static struct
//
// Source code and project home:
// https://github.com/benny-deluxe/jsongo
//

package jsongo

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

//ErrorKeyAlreadyExist error if a key already exist in current JSONNode
var ErrorKeyAlreadyExist = errors.New("jsongo key already exist")

//ErrorMultipleType error if a JSONNode already got a different type of value
var ErrorMultipleType = errors.New("jsongo this node is already set to a different jsonNodeType")

//ErrorArrayNegativeValue error if you ask for a negative index in an array
var ErrorArrayNegativeValue = errors.New("jsongo negative index for array")

//ErrorArrayNegativeValue error if you ask for a negative index in an array
var ErrorAtUnsupportedType = errors.New("jsongo Unsupported Type as At argument")

//ErrorRetrieveUserValue error if you ask the value of a node that is not a value node
var ErrorRetrieveUserValue = errors.New("jsongo Cannot retrieve node's value which is not of type value")

//ErrorTypeUnmarshaling error if you try to unmarshal something in the wrong type
var ErrorTypeUnmarshaling = errors.New("jsongo Wrong type when Unmarshaling")

//ErrorUnknowType error if you try to use an unknow JSONNodeType
var ErrorUnknowType = errors.New("jsongo Unknow JSONNodeType")

//ErrorValNotPointer error if you try to use Val without a valid pointer
var ErrorValNotPointer = errors.New("jsongo: Val: arguments must be a pointer and not nil")

//ErrorGetKeys error if you try to get the keys from a JSONNode that isnt a TypeMap or a TypeArray
var ErrorGetKeys = errors.New("jsongo: GetKeys: JSONNode is not a TypeMap or TypeArray")

//ErrorDeleteKey error if you try call DelKey on a JSONNode that isnt a TypeMap
var ErrorDeleteKey = errors.New("jsongo: DelKey: This JSONNode is not a TypeMap")

//JSONNode Datastructure to build and maintain Nodes
type JSONNode struct {
	m          map[string]*JSONNode
	a          []JSONNode
	v          interface{}
	vChanged   bool         //True if we changed the type of the value
	t          JSONNodeType //Type of that JSONNode 0: Not defined, 1: map, 2: array, 3: value
	dontExpand bool         //dont expand while Unmarshal
}

//JSONNodeType is used to set, check and get the inner type of a JSONNode
type JSONNodeType uint

const (
	//TypeUndefined is set by default for empty JSONNode
	TypeUndefined JSONNodeType = iota
	//TypeMap is set when a JSONNode is a Map
	TypeMap
	//TypeArray is set when a JSONNode is an Array
	TypeArray
	//TypeValue is set when a JSONNode is a Value Node
	TypeValue
	//typeError help us detect errors
	typeError
)

//At helps you move through your node by building them on the fly
//
//val can be string or int only
//
//strings are keys for TypeMap
//
//ints are index in TypeArray (it will make array grow on the fly, so you should start to populate with the biggest index first)*
func (that *JSONNode) At(val ...interface{}) *JSONNode {
	if len(val) == 0 {
		return that
	}
	switch vv := val[0].(type) {
	case string:
		return that.atMap(vv, val[1:]...)
	case int:
		return that.atArray(vv, val[1:]...)
	}
	panic(ErrorAtUnsupportedType)
}

//atMap return the JSONNode in current map
func (that *JSONNode) atMap(key string, val ...interface{}) *JSONNode {
	if that.t != TypeUndefined && that.t != TypeMap {
		panic(ErrorMultipleType)
	}
	if that.m == nil {
		that.m = make(map[string]*JSONNode)
		that.t = TypeMap
	}
	if next, ok := that.m[key]; ok {
		return next.At(val...)
	}
	that.m[key] = new(JSONNode)
	return that.m[key].At(val...)
}

//atArray return the JSONNode in current TypeArray (and make it grow if necessary)
func (that *JSONNode) atArray(key int, val ...interface{}) *JSONNode {
	if that.t == TypeUndefined {
		that.t = TypeArray
	} else if that.t != TypeArray {
		panic(ErrorMultipleType)
	}
	if key < 0 {
		panic(ErrorArrayNegativeValue)
	}
	if key >= len(that.a) {
		newa := make([]JSONNode, key+1)
		for i := 0; i < len(that.a); i++ {
			newa[i] = that.a[i]
		}
		that.a = newa
	}
	return that.a[key].At(val...)
}

//Map Turn this JSONNode to a TypeMap and/or Create a new element for key if necessary and return it
func (that *JSONNode) Map(key string) *JSONNode {
	if that.t != TypeUndefined && that.t != TypeMap {
		panic(ErrorMultipleType)
	}
	if that.m == nil {
		that.m = make(map[string]*JSONNode)
		that.t = TypeMap
	}
	if _, ok := that.m[key]; ok {
		return that.m[key]
	}
	that.m[key] = &JSONNode{}
	return that.m[key]
}

//Array Turn this JSONNode to a TypeArray and/or set the array size (reducing size will make you loose data)
func (that *JSONNode) Array(size int) *[]JSONNode {
	if that.t == TypeUndefined {
		that.t = TypeArray
	} else if that.t != TypeArray {
		panic(ErrorMultipleType)
	}
	if size < 0 {
		panic(ErrorArrayNegativeValue)
	}
	var min int
	if size < len(that.a) {
		min = size
	} else {
		min = len(that.a)
	}
	newa := make([]JSONNode, size)
	for i := 0; i < min; i++ {
		newa[i] = that.a[i]
	}
	that.a = newa
	return &(that.a)
}

//Val Turn this JSONNode to Value type and/or set that value to val
func (that *JSONNode) Val(val interface{}) {
	if that.t == TypeUndefined {
		that.t = TypeValue
	} else if that.t != TypeValue {
		panic(ErrorMultipleType)
	}
	rt := reflect.TypeOf(val)
	var finalval interface{}
	if val == nil {
		finalval = &val
		that.vChanged = true
	} else if rt.Kind() != reflect.Ptr {
		rv := reflect.ValueOf(val)
		var tmp reflect.Value
		if rv.CanAddr() {
			tmp = rv.Addr()
		} else {
			tmp = reflect.New(rt)
			tmp.Elem().Set(rv)
		}
		finalval = tmp.Interface()
		that.vChanged = true
	} else {
		finalval = val
	}
	that.v = finalval
}

//Get Return value of a TypeValue as interface{}
func (that *JSONNode) Get() interface{} {
	if that.t != TypeValue {
		panic(ErrorRetrieveUserValue)
	}
	if that.vChanged {
		rv := reflect.ValueOf(that.v)
		return rv.Elem().Interface()
	}
	return that.v
}

//GetKeys Return a slice interface that represent the keys to use with the At fonction (Works only on TypeMap and TypeArray)
func (that *JSONNode) GetKeys() []interface{} {
	var ret []interface{}
	switch that.t {
	case TypeMap:
		nb := len(that.m)
		ret = make([]interface{}, nb)
		for key := range that.m {
			nb--
			ret[nb] = key
		}
	case TypeArray:
		nb := len(that.a)
		ret = make([]interface{}, nb)
		for nb > 0 {
			nb--
			ret[nb] = nb
		}
	default:
		panic(ErrorGetKeys)
	}
	return ret
}

//Len Return the length of the current Node
//
// if TypeUndefined return 0
//
// if TypeValue return 1
//
// if TypeArray return the size of the array
//
// if TypeMap return the size of the map
func (that *JSONNode) Len() int {
	var ret int
	switch that.t {
	case TypeMap:
		ret = len(that.m)
	case TypeArray:
		ret = len(that.a)
	case TypeValue:
		ret = 1
	}
	return ret
}

//SetType Is use to set the Type of a node and return the current Node you are working on
func (that *JSONNode) SetType(t JSONNodeType) *JSONNode {
	if that.t != TypeUndefined && that.t != t {
		panic(ErrorMultipleType)
	}
	if t >= typeError {
		panic(ErrorUnknowType)
	}
	that.t = t
	switch t {
	case TypeMap:
		that.m = make(map[string]*JSONNode, 0)
	case TypeArray:
		that.a = make([]JSONNode, 0)
	case TypeValue:
		that.Val(nil)
	}
	return that
}

//GetType Is use to Get the Type of a node
func (that *JSONNode) GetType() JSONNodeType {
	return that.t
}

//Unset Will unset everything in the JSONnode. All the children data will be lost
func (that *JSONNode) Unset() {
	*that = JSONNode{}
}

//DelKey will remove a key in the map.
//
//return the current JSONNode.
func (that *JSONNode) DelKey(key string) *JSONNode {
	if that.t != TypeMap {
		panic(ErrorDeleteKey)
	}
	delete(that.m, key)
	return that
}

//UnmarshalDontExpand set or not if Unmarshall will generate anything in that JSONNode and its children
//
//val: will change the expanding rules for this node
//
//- The type wont be change for any type
//
//- Array wont grow
//
//- New keys wont be added to Map
//
//- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
//
//- It will respect any current mapping and will return errors if needed
//
//recurse: if true, it will set all the children of that JSONNode with val
func (that *JSONNode) UnmarshalDontExpand(val bool, recurse bool) *JSONNode {
	that.dontExpand = val
	if recurse {
		switch that.t {
		case TypeMap:
			for k := range that.m {
				that.m[k].UnmarshalDontExpand(val, recurse)
			}
		case TypeArray:
			for k := range that.a {
				that.a[k].UnmarshalDontExpand(val, recurse)
			}
		}
	}
	return that
}

//MarshalJSON Make JSONNode a Marshaler Interface compatible
func (that *JSONNode) MarshalJSON() ([]byte, error) {
	var ret []byte
	var err error
	switch that.t {
	case TypeMap:
		ret, err = json.Marshal(that.m)
	case TypeArray:
		ret, err = json.Marshal(that.a)
	case TypeValue:
		ret, err = json.Marshal(that.v)
	default:
		ret, err = json.Marshal(nil)
	}
	if err != nil {
		return nil, err
	}
	return ret, err
}

func (that *JSONNode) unmarshalMap(data []byte) error {
	tmp := make(map[string]json.RawMessage)
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	for k := range tmp {
		if _, ok := that.m[k]; ok {
			err := json.Unmarshal(tmp[k], that.m[k])
			if err != nil {
				return err
			}
		} else if !that.dontExpand {
			err := json.Unmarshal(tmp[k], that.Map(k))
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (that *JSONNode) unmarshalArray(data []byte) error {
	var tmp []json.RawMessage
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	for i := len(tmp) - 1; i >= 0; i-- {
		if !that.dontExpand || i < len(that.a) {
			err := json.Unmarshal(tmp[i], that.At(i))
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (that *JSONNode) unmarshalValue(data []byte) error {
	if that.v != nil {
		return json.Unmarshal(data, that.v)
	}
	var tmp interface{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	that.Val(tmp)
	return nil
}

//UnmarshalJSON Make JSONNode a Unmarshaler Interface compatible
func (that *JSONNode) UnmarshalJSON(data []byte) error {
	if len(data) == 0 {
		return nil
	}
	if that.dontExpand && that.t == TypeUndefined {
		return nil
	}
	if that.t == TypeValue {
		return that.unmarshalValue(data)
	}
	if data[0] == '{' {
		if that.t != TypeMap && that.t != TypeUndefined {
			return ErrorTypeUnmarshaling
		}
		return that.unmarshalMap(data)
	}
	if data[0] == '[' {
		if that.t != TypeArray && that.t != TypeUndefined {
			return ErrorTypeUnmarshaling
		}
		return that.unmarshalArray(data)

	}
	if that.t == TypeUndefined {
		return that.unmarshalValue(data)
	}
	return ErrorTypeUnmarshaling
}
<commit_msg>Adding Copy function<commit_after>// Copyright 2014 Benny Scetbun. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Package Jsongo is a simple library to help you build Json without static struct
//
// Source code and project home:
// https://github.com/benny-deluxe/jsongo
//

package jsongo

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

//ErrorKeyAlreadyExist error if a key already exist in current JSONNode
var ErrorKeyAlreadyExist = errors.New("jsongo key already exist")

//ErrorMultipleType error if a JSONNode already got a different type of value
var ErrorMultipleType = errors.New("jsongo this node is already set to a different jsonNodeType")

//ErrorArrayNegativeValue error if you ask for a negative index in an array
var ErrorArrayNegativeValue = errors.New("jsongo negative index for array")

//ErrorArrayNegativeValue error if you ask for a negative index in an array
var ErrorAtUnsupportedType = errors.New("jsongo Unsupported Type as At argument")

//ErrorRetrieveUserValue error if you ask the value of a node that is not a value node
var ErrorRetrieveUserValue = errors.New("jsongo Cannot retrieve node's value which is not of type value")

//ErrorTypeUnmarshaling error if you try to unmarshal something in the wrong type
var ErrorTypeUnmarshaling = errors.New("jsongo Wrong type when Unmarshaling")

//ErrorUnknowType error if you try to use an unknow JSONNodeType
var ErrorUnknowType = errors.New("jsongo Unknow JSONNodeType")

//ErrorValNotPointer error if you try to use Val without a valid pointer
var ErrorValNotPointer = errors.New("jsongo: Val: arguments must be a pointer and not nil")

//ErrorGetKeys error if you try to get the keys from a JSONNode that isnt a TypeMap or a TypeArray
var ErrorGetKeys = errors.New("jsongo: GetKeys: JSONNode is not a TypeMap or TypeArray")

//ErrorDeleteKey error if you try to call DelKey on a JSONNode that isnt a TypeMap
var ErrorDeleteKey = errors.New("jsongo: DelKey: This JSONNode is not a TypeMap")

//ErrorCopyType error if you try to call Copy on a JSONNode that isnt a TypeUndefined
var ErrorCopyType = errors.New("jsongo: Copy: This JSONNode is not a TypeUndefined")

//JSONNode Datastructure to build and maintain Nodes
type JSONNode struct {
	m          map[string]*JSONNode
	a          []JSONNode
	v          interface{}
	vChanged   bool         //True if we changed the type of the value
	t          JSONNodeType //Type of that JSONNode 0: Not defined, 1: map, 2: array, 3: value
	dontExpand bool         //dont expand while Unmarshal
}

//JSONNodeType is used to set, check and get the inner type of a JSONNode
type JSONNodeType uint

const (
	//TypeUndefined is set by default for empty JSONNode
	TypeUndefined JSONNodeType = iota
	//TypeMap is set when a JSONNode is a Map
	TypeMap
	//TypeArray is set when a JSONNode is an Array
	TypeArray
	//TypeValue is set when a JSONNode is a Value Node
	TypeValue
	//typeError help us detect errors
	typeError
)

//At helps you move through your node by building them on the fly
//
//val can be string or int only
//
//strings are keys for TypeMap
//
//ints are index in TypeArray (it will make array grow on the fly, so you should start to populate with the biggest index first)*
func (that *JSONNode) At(val ...interface{}) *JSONNode {
	if len(val) == 0 {
		return that
	}
	switch vv := val[0].(type) {
	case string:
		return that.atMap(vv, val[1:]...)
	case int:
		return that.atArray(vv, val[1:]...)
	}
	panic(ErrorAtUnsupportedType)
}

//atMap return the JSONNode in current map
func (that *JSONNode) atMap(key string, val ...interface{}) *JSONNode {
	if that.t != TypeUndefined && that.t != TypeMap {
		panic(ErrorMultipleType)
	}
	if that.m == nil {
		that.m = make(map[string]*JSONNode)
		that.t = TypeMap
	}
	if next, ok := that.m[key]; ok {
		return next.At(val...)
	}
	that.m[key] = new(JSONNode)
	return that.m[key].At(val...)
}

//atArray return the JSONNode in current TypeArray (and make it grow if necessary)
func (that *JSONNode) atArray(key int, val ...interface{}) *JSONNode {
	if that.t == TypeUndefined {
		that.t = TypeArray
	} else if that.t != TypeArray {
		panic(ErrorMultipleType)
	}
	if key < 0 {
		panic(ErrorArrayNegativeValue)
	}
	if key >= len(that.a) {
		newa := make([]JSONNode, key+1)
		for i := 0; i < len(that.a); i++ {
			newa[i] = that.a[i]
		}
		that.a = newa
	}
	return that.a[key].At(val...)
}

//Map Turn this JSONNode to a TypeMap and/or Create a new element for key if necessary and return it
func (that *JSONNode) Map(key string) *JSONNode {
	if that.t != TypeUndefined && that.t != TypeMap {
		panic(ErrorMultipleType)
	}
	if that.m == nil {
		that.m = make(map[string]*JSONNode)
		that.t = TypeMap
	}
	if _, ok := that.m[key]; ok {
		return that.m[key]
	}
	that.m[key] = &JSONNode{}
	return that.m[key]
}

//Array Turn this JSONNode to a TypeArray and/or set the array size (reducing size will make you loose data)
func (that *JSONNode) Array(size int) *[]JSONNode {
	if that.t == TypeUndefined {
		that.t = TypeArray
	} else if that.t != TypeArray {
		panic(ErrorMultipleType)
	}
	if size < 0 {
		panic(ErrorArrayNegativeValue)
	}
	var min int
	if size < len(that.a) {
		min = size
	} else {
		min = len(that.a)
	}
	newa := make([]JSONNode, size)
	for i := 0; i < min; i++ {
		newa[i] = that.a[i]
	}
	that.a = newa
	return &(that.a)
}

//Val Turn this JSONNode to Value type and/or set that value to val
func (that *JSONNode) Val(val interface{}) {
	if that.t == TypeUndefined {
		that.t = TypeValue
	} else if that.t != TypeValue {
		panic(ErrorMultipleType)
	}
	rt := reflect.TypeOf(val)
	var finalval interface{}
	if val == nil {
		finalval = &val
		that.vChanged = true
	} else if rt.Kind() != reflect.Ptr {
		rv := reflect.ValueOf(val)
		var tmp reflect.Value
		if rv.CanAddr() {
			tmp = rv.Addr()
		} else {
			tmp = reflect.New(rt)
			tmp.Elem().Set(rv)
		}
		finalval = tmp.Interface()
		that.vChanged = true
	} else {
		finalval = val
	}
	that.v = finalval
}

//Get Return value of a TypeValue as interface{}
func (that *JSONNode) Get() interface{} {
	if that.t != TypeValue {
		panic(ErrorRetrieveUserValue)
	}
	if that.vChanged {
		rv := reflect.ValueOf(that.v)
		return rv.Elem().Interface()
	}
	return that.v
}

//GetKeys Return a slice interface that represent the keys to use with the At fonction (Works only on TypeMap and TypeArray)
func (that *JSONNode) GetKeys() []interface{} {
	var ret []interface{}
	switch that.t {
	case TypeMap:
		nb := len(that.m)
		ret = make([]interface{}, nb)
		for key := range that.m {
			nb--
			ret[nb] = key
		}
	case TypeArray:
		nb := len(that.a)
		ret = make([]interface{}, nb)
		for nb > 0 {
			nb--
			ret[nb] = nb
		}
	default:
		panic(ErrorGetKeys)
	}
	return ret
}

//Len Return the length of the current Node
//
// if TypeUndefined return 0
//
// if TypeValue return 1
//
// if TypeArray return the size of the array
//
// if TypeMap return the size of the map
func (that *JSONNode) Len() int {
	var ret int
	switch that.t {
	case TypeMap:
		ret = len(that.m)
	case TypeArray:
		ret = len(that.a)
	case TypeValue:
		ret = 1
	}
	return ret
}

//SetType Is use to set the Type of a node and return the current Node you are working on
func (that *JSONNode) SetType(t JSONNodeType) *JSONNode {
	if that.t != TypeUndefined && that.t != t {
		panic(ErrorMultipleType)
	}
	if t >= typeError {
		panic(ErrorUnknowType)
	}
	that.t = t
	switch t {
	case TypeMap:
		that.m = make(map[string]*JSONNode, 0)
	case TypeArray:
		that.a = make([]JSONNode, 0)
	case TypeValue:
		that.Val(nil)
	}
	return that
}

//GetType Is use to Get the Type of a node
func (that *JSONNode) GetType() JSONNodeType {
	return that.t
}

//Copy Will set this node like the one in argument. this node must be of type TypeUndefined
//
//if deepCopy is true we will copy all the children recursively else we will share the children
//
//return the current JSONNode
func (that *JSONNode) Copy(other *JSONNode, deepCopy bool) *JSONNode {
	if that.t != TypeUndefined {
		panic(ErrorCopyType)
	}

	if other.t == TypeValue {
		*that = *other
	} else if other.t == TypeArray {
		if !deepCopy {
			*that = *other
		} else {
			that.Array(len(other.a))
			for i := range other.a {
				that.At(i).Copy(other.At(i), deepCopy)
			}
		}
	} else if other.t == TypeMap {
		that.SetType(other.t)
		if !deepCopy {
			for val := range other.m {
				that.m[val] = other.m[val]
			}
		} else {
			for val := range other.m {
				that.Map(val).Copy(other.At(val), deepCopy)
			}
		}
	}
	return that
}

//Unset Will unset everything in the JSONnode. All the children data will be lost
func (that *JSONNode) Unset() {
	*that = JSONNode{}
}

//DelKey will remove a key in the map.
//
//return the current JSONNode.
func (that *JSONNode) DelKey(key string) *JSONNode {
	if that.t != TypeMap {
		panic(ErrorDeleteKey)
	}
	delete(that.m, key)
	return that
}

//UnmarshalDontExpand set or not if Unmarshall will generate anything in that JSONNode and its children
//
//val: will change the expanding rules for this node
//
//- The type wont be change for any type
//
//- Array wont grow
//
//- New keys wont be added to Map
//
//- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
//
//- It will respect any current mapping and will return errors if needed
//
//recurse: if true, it will set all the children of that JSONNode with val
func (that *JSONNode) UnmarshalDontExpand(val bool, recurse bool) *JSONNode {
	that.dontExpand = val
	if recurse {
		switch that.t {
		case TypeMap:
			for k := range that.m {
				that.m[k].UnmarshalDontExpand(val, recurse)
			}
		case TypeArray:
			for k := range that.a {
				that.a[k].UnmarshalDontExpand(val, recurse)
			}
		}
	}
	return that
}

//MarshalJSON Make JSONNode a Marshaler Interface compatible
func (that *JSONNode) MarshalJSON() ([]byte, error) {
	var ret []byte
	var err error
	switch that.t {
	case TypeMap:
		ret, err = json.Marshal(that.m)
	case TypeArray:
		ret, err = json.Marshal(that.a)
	case TypeValue:
		ret, err = json.Marshal(that.v)
	default:
		ret, err = json.Marshal(nil)
	}
	if err != nil {
		return nil, err
	}
	return ret, err
}

func (that *JSONNode) unmarshalMap(data []byte) error {
	tmp := make(map[string]json.RawMessage)
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	for k := range tmp {
		if _, ok := that.m[k]; ok {
			err := json.Unmarshal(tmp[k], that.m[k])
			if err != nil {
				return err
			}
		} else if !that.dontExpand {
			err := json.Unmarshal(tmp[k], that.Map(k))
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (that *JSONNode) unmarshalArray(data []byte) error {
	var tmp []json.RawMessage
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	for i := len(tmp) - 1; i >= 0; i-- {
		if !that.dontExpand || i < len(that.a) {
			err := json.Unmarshal(tmp[i], that.At(i))
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (that *JSONNode) unmarshalValue(data []byte) error {
	if that.v != nil {
		return json.Unmarshal(data, that.v)
	}
	var tmp interface{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	that.Val(tmp)
	return nil
}

//UnmarshalJSON Make JSONNode a Unmarshaler Interface compatible
func (that *JSONNode) UnmarshalJSON(data []byte) error {
	if len(data) == 0 {
		return nil
	}
	if that.dontExpand && that.t == TypeUndefined {
		return nil
	}
	if that.t == TypeValue {
		return that.unmarshalValue(data)
	}
	if data[0] == '{' {
		if that.t != TypeMap && that.t != TypeUndefined {
			return ErrorTypeUnmarshaling
		}
		return that.unmarshalMap(data)
	}
	if data[0] == '[' {
		if that.t != TypeArray && that.t != TypeUndefined {
			return ErrorTypeUnmarshaling
		}
		return that.unmarshalArray(data)

	}
	if that.t == TypeUndefined {
		return that.unmarshalValue(data)
	}
	return ErrorTypeUnmarshaling
}
<|endoftext|>


<commit_before>package fields

import (
	. "launchpad.net/gocheck"
)

type CharFieldTestSuite struct{}

var _ = Suite(&CharFieldTestSuite{})

func (s *CharFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewCharField("description")
	f.SetValue("Testing 1, 2, 3")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, "Testing 1, 2, 3")
}

func (s *CharFieldTestSuite) TestMinLength(c *C) {
	f := NewCharField("description")
	f.MinLength = 20
	f.SetValue("Testing 1, 2, 3")

	err := f.Clean()

	c.Check(err.Error(), Equals,
		"The value must have a minimum length of 20 characters.")
}

func (s *CharFieldTestSuite) TestMaxLength(c *C) {
	f := NewCharField("description")
	f.MaxLength = 10
	f.SetValue("Testing 1, 2, 3")

	err := f.Clean()

	c.Check(err.Error(), Equals,
		"The value must have a maximum length of 10 characters.")
}

type IntegerFieldTestSuite struct{}

var _ = Suite(&IntegerFieldTestSuite{})

func (s *IntegerFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewIntegerField("num_purchases")
	f.SetValue("12345")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, 12345)
}

func (s *IntegerFieldTestSuite) TestCleanInvalid(c *C) {
	f := NewIntegerField("num_purchases")
	f.SetValue("a12345")

	err := f.Clean()
	c.Check(err.Error(), Equals, "The value must be a valid integer.")
}

type RegexFieldTestSuite struct{}

var _ = Suite(&RegexFieldTestSuite{})

func (s *RegexFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewRegexField("alphabet", "a.c")
	f.SetValue("abc")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, "abc")
}

func (s *RegexFieldTestSuite) TestCleanInvalid(c *C) {
	f := NewRegexField("alphabet", "a.c")
	f.SetValue("abz")

	err := f.Clean()
	c.Check(err.Error(), Equals, "The input 'abz' did not match 'a.c'.")
	c.Check(f.CleanedValue(), IsNil)
}
<commit_msg>Ensure tests for fields package are run.<commit_after>package fields

import (
	. "launchpad.net/gocheck"
	"testing"
)

// Hooks up gocheck into the gotest runner.
func Test(t *testing.T) { TestingT(t) }
type CharFieldTestSuite struct{}

var _ = Suite(&CharFieldTestSuite{})

func (s *CharFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewCharField("description")
	f.SetValue("Testing 1, 2, 3")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, "Testing 1, 2, 3")
}

func (s *CharFieldTestSuite) TestMinLength(c *C) {
	f := NewCharField("description")
	f.MinLength = 20
	f.SetValue("Testing 1, 2, 3")

	err := f.Clean()

	c.Check(err.Error(), Equals,
		"The value must have a minimum length of 20 characters.")
}

func (s *CharFieldTestSuite) TestMaxLength(c *C) {
	f := NewCharField("description")
	f.MaxLength = 10
	f.SetValue("Testing 1, 2, 3")

	err := f.Clean()

	c.Check(err.Error(), Equals,
		"The value must have a maximum length of 10 characters.")
}

type IntegerFieldTestSuite struct{}

var _ = Suite(&IntegerFieldTestSuite{})

func (s *IntegerFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewIntegerField("num_purchases")
	f.SetValue("12345")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, 12345)
}

func (s *IntegerFieldTestSuite) TestCleanInvalid(c *C) {
	f := NewIntegerField("num_purchases")
	f.SetValue("a12345")

	err := f.Clean()
	c.Check(err.Error(), Equals, "The value must be a valid integer.")
}

type RegexFieldTestSuite struct{}

var _ = Suite(&RegexFieldTestSuite{})

func (s *RegexFieldTestSuite) TestCleanSuccess(c *C) {
	f := NewRegexField("alphabet", "a.c")
	f.SetValue("abc")

	c.Check(f.Clean(), Equals, nil)
	c.Check(f.CleanedValue(), Equals, "abc")
}

func (s *RegexFieldTestSuite) TestCleanInvalid(c *C) {
	f := NewRegexField("alphabet", "a.c")
	f.SetValue("abz")

	err := f.Clean()
	c.Check(err.Error(), Equals, "The input 'abz' did not match 'a.c'.")
	c.Check(f.CleanedValue(), IsNil)
}
<|endoftext|>


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

package graph

import (
	"math"
	"runtime"
	"sync"
)

// FIXME Use Index() instead of ID() on edges and nodes - this requires a change to node.go

const sqrt2 = 1.4142135623730950488016887242096980785696718753769480

var MaxProcs = runtime.GOMAXPROCS(0)

func FastRandMinCut(g *Undirected, iter int) (c []Edge, w float64) {
	ka := newKarger(g)
	ka.init()
	w = math.Inf(1)
	for i := 0; i < iter; i++ {
		ka.fastRandMinCut()
		if ka.w < w {
			w = ka.w
			c = ka.c
		}
	}

	return
}

type karger struct {
	g     *Undirected
	order int
	ind   []super
	sel   Selector
	c     []Edge
	w     float64
}

type super struct {
	label int
	nodes []int
}

func newKarger(g *Undirected) *karger {
	return &karger{
		g:   g,
		ind: make([]super, g.NextNodeID()),
		sel: make(Selector, g.Size()),
	}
}

func (ka *karger) init() {
	ka.order = ka.g.Order()
	for i := range ka.ind {
		ka.ind[i].label = -1
		ka.ind[i].nodes = nil
	}
	for _, n := range ka.g.Nodes() {
		id := n.ID()
		ka.ind[id].label = id
	}
	for i, e := range ka.g.Edges() {
		ka.sel[i] = WeightedItem{Index: e.ID(), Weight: e.Weight()}
	}
	ka.sel.Init()
}

func (ka *karger) clone() (c *karger) {
	c = &karger{
		g:     ka.g,
		ind:   make([]super, ka.g.NextNodeID()),
		sel:   make(Selector, ka.g.Size()),
		order: ka.order,
	}

	copy(c.sel, ka.sel)
	for i, n := range ka.ind {
		s := &c.ind[i]
		s.label = n.label
		if n.nodes != nil {
			s.nodes = make([]int, len(n.nodes))
			copy(s.nodes, n.nodes)
		}
	}

	return
}

func (ka *karger) fastRandMinCut() {
	if ka.order <= 6 {
		ka.randCompact(2)
		return
	}

	t := int(math.Ceil(float64(ka.order)/sqrt2 + 1))

	sub := []*karger{ka, ka.clone()}
	for i := range sub {
		sub[i].randContract(t)
		sub[i].fastRandMinCut()
	}

	if sub[0].w < sub[1].w {
		*ka = *sub[0]
		return
	}
	*ka = *sub[1]
}

func (ka *karger) randContract(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}
}

func (ka *karger) randCompact(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}

	ka.c, ka.w = []Edge{}, 0
	for _, e := range ka.g.Edges() {
		if ka.loop(e) {
			continue
		}
		ka.c = append(ka.c, e)
		ka.w += e.Weight()
	}
}

func (ka *karger) loop(e Edge) bool {
	return ka.ind[e.Head().ID()].label == ka.ind[e.Tail().ID()].label
}

// parallelised within the recursion tree

func ParFastRandMinCut(g *Undirected, iter, threads int) (c []Edge, w float64) {
	k := newKargerP(g)
	k.split = threads
	if k.split == 0 {
		k.split = -1
	}
	k.init()
	w = math.Inf(1)
	for i := 0; i < iter; i++ {
		k.fastRandMinCut()
		if k.w < w {
			w = k.w
			c = k.c
		}
	}

	return
}

type kargerP struct {
	g     *Undirected
	order int
	ind   []super
	sel   Selector
	c     []Edge
	w     float64
	count int
	split int
}

func newKargerP(g *Undirected) *kargerP {
	return &kargerP{
		g:   g,
		ind: make([]super, g.NextNodeID()),
		sel: make(Selector, g.Size()),
	}
}

func (ka *kargerP) init() {
	ka.order = ka.g.Order()
	for i := range ka.ind {
		ka.ind[i].label = -1
		ka.ind[i].nodes = nil
	}
	for _, n := range ka.g.Nodes() {
		id := n.ID()
		ka.ind[id].label = id
	}
	for i, e := range ka.g.Edges() {
		ka.sel[i] = WeightedItem{Index: e.ID(), Weight: e.Weight()}
	}
	ka.sel.Init()
}

func (ka *kargerP) clone() (c *kargerP) {
	c = &kargerP{
		g:     ka.g,
		ind:   make([]super, ka.g.NextNodeID()),
		sel:   make(Selector, ka.g.Size()),
		order: ka.order,
		count: ka.count,
	}

	copy(c.sel, ka.sel)
	for i, n := range ka.ind {
		s := &c.ind[i]
		s.label = n.label
		if n.nodes != nil {
			s.nodes = make([]int, len(n.nodes))
			copy(s.nodes, n.nodes)
		}
	}

	return
}

func (ka *kargerP) fastRandMinCut() {
	if ka.order <= 6 {
		ka.randCompact(2)
		return
	}

	t := int(math.Ceil(float64(ka.order)/sqrt2 + 1))

	var wg *sync.WaitGroup
	if ka.count < ka.split {
		wg = &sync.WaitGroup{}
	}
	ka.count++

	sub := []*kargerP{ka, ka.clone()}
	for i := range sub {
		if wg != nil {
			wg.Add(1)
			go func(i int) {
				runtime.LockOSThread()
				defer wg.Done()
				sub[i].randContract(t)
				sub[i].fastRandMinCut()
			}(i)
		} else {
			sub[i].randContract(t)
			sub[i].fastRandMinCut()
		}
	}

	if wg != nil {
		wg.Wait()
	}

	if sub[0].w < sub[1].w {
		*ka = *sub[0]
		return
	}
	*ka = *sub[1]
}

func (ka *kargerP) randContract(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}
}

func (ka *kargerP) randCompact(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}

	ka.c, ka.w = []Edge{}, 0
	for _, e := range ka.g.Edges() {
		if ka.loop(e) {
			continue
		}
		ka.c = append(ka.c, e)
		ka.w += e.Weight()
	}
}

func (ka *kargerP) loop(e Edge) bool {
	return ka.ind[e.Head().ID()].label == ka.ind[e.Tail().ID()].label
}
<commit_msg>Remove duplicated lines<commit_after>// Copyright ©2012 The bíogo.graph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package graph

import (
	"math"
	"runtime"
	"sync"
)

// FIXME Use Index() instead of ID() on edges and nodes - this requires a change to node.go

const sqrt2 = 1.4142135623730950488016887242096980785696718753769480

var MaxProcs = runtime.GOMAXPROCS(0)

func FastRandMinCut(g *Undirected, iter int) (c []Edge, w float64) {
	ka := newKarger(g)
	ka.init()
	w = math.Inf(1)
	for i := 0; i < iter; i++ {
		ka.fastRandMinCut()
		if ka.w < w {
			w = ka.w
			c = ka.c
		}
	}

	return
}

type karger struct {
	g     *Undirected
	order int
	ind   []super
	sel   Selector
	c     []Edge
	w     float64
}

type super struct {
	label int
	nodes []int
}

func newKarger(g *Undirected) *karger {
	return &karger{
		g:   g,
		ind: make([]super, g.NextNodeID()),
		sel: make(Selector, g.Size()),
	}
}

func (ka *karger) init() {
	ka.order = ka.g.Order()
	for i := range ka.ind {
		ka.ind[i].label = -1
		ka.ind[i].nodes = nil
	}
	for _, n := range ka.g.Nodes() {
		id := n.ID()
		ka.ind[id].label = id
	}
	for i, e := range ka.g.Edges() {
		ka.sel[i] = WeightedItem{Index: e.ID(), Weight: e.Weight()}
	}
	ka.sel.Init()
}

func (ka *karger) clone() (c *karger) {
	c = &karger{
		g:     ka.g,
		ind:   make([]super, ka.g.NextNodeID()),
		sel:   make(Selector, ka.g.Size()),
		order: ka.order,
	}

	copy(c.sel, ka.sel)
	for i, n := range ka.ind {
		s := &c.ind[i]
		s.label = n.label
		if n.nodes != nil {
			s.nodes = make([]int, len(n.nodes))
			copy(s.nodes, n.nodes)
		}
	}

	return
}

func (ka *karger) fastRandMinCut() {
	if ka.order <= 6 {
		ka.randCompact(2)
		return
	}

	t := int(math.Ceil(float64(ka.order)/sqrt2 + 1))

	sub := []*karger{ka, ka.clone()}
	for i := range sub {
		sub[i].randContract(t)
		sub[i].fastRandMinCut()
	}

	if sub[0].w < sub[1].w {
		*ka = *sub[0]
		return
	}
	*ka = *sub[1]
}

func (ka *karger) randContract(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}
}

func (ka *karger) randCompact(k int) {
	for ka.order > k {
		id, err := ka.sel.Select()
		if err != nil {
			break
		}

		e := ka.g.Edge(id)
		if ka.loop(e) {
			continue
		}

		hid, tid := e.Head().ID(), e.Tail().ID()
		hl, tl := ka.ind[hid].label, ka.ind[tid].label
		if len(ka.ind[hl].nodes) < len(ka.ind[tl].nodes) {
			hid, tid = tid, hid
			hl, tl = tl, hl
		}

		if ka.ind[hl].nodes == nil {
			ka.ind[hl].nodes = []int{hid}
		}
		if ka.ind[tl].nodes == nil {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, tid)
		} else {
			ka.ind[hl].nodes = append(ka.ind[hl].nodes, ka.ind[tl].nodes...)
			ka.ind[tl].nodes = nil
		}
		for _, i := range ka.ind[hl].nodes {
			ka.ind[i].label = ka.ind[hid].label
		}

		ka.order--
	}

	ka.c, ka.w = []Edge{}, 0
	for _, e := range ka.g.Edges() {
		if ka.loop(e) {
			continue
		}
		ka.c = append(ka.c, e)
		ka.w += e.Weight()
	}
}

func (ka *karger) loop(e Edge) bool {
	return ka.ind[e.Head().ID()].label == ka.ind[e.Tail().ID()].label
}

// parallelised within the recursion tree

func ParFastRandMinCut(g *Undirected, iter, threads int) (c []Edge, w float64) {
	k := newKargerP(g)
	k.split = threads
	if k.split == 0 {
		k.split = -1
	}
	k.init()
	w = math.Inf(1)
	for i := 0; i < iter; i++ {
		k.fastRandMinCut()
		if k.w < w {
			w = k.w
			c = k.c
		}
	}

	return
}

type kargerP struct {
	karger
	count int
	split int
}

func newKargerP(g *Undirected) *kargerP {
	return &kargerP{karger: karger{
		g:   g,
		ind: make([]super, g.NextNodeID()),
		sel: make(Selector, g.Size()),
	}}
}

func (ka *kargerP) clone() (c *kargerP) {
	c = &kargerP{karger: *ka.karger.clone()}
	c.count = ka.count

	return
}

func (ka *kargerP) fastRandMinCut() {
	if ka.order <= 6 {
		ka.randCompact(2)
		return
	}

	t := int(math.Ceil(float64(ka.order)/sqrt2 + 1))

	var wg *sync.WaitGroup
	if ka.count < ka.split {
		wg = &sync.WaitGroup{}
	}
	ka.count++

	sub := []*kargerP{ka, ka.clone()}
	for i := range sub {
		if wg != nil {
			wg.Add(1)
			go func(i int) {
				defer wg.Done()
				sub[i].randContract(t)
				sub[i].fastRandMinCut()
			}(i)
		} else {
			sub[i].randContract(t)
			sub[i].fastRandMinCut()
		}
	}

	if wg != nil {
		wg.Wait()
	}

	if sub[0].w < sub[1].w {
		*ka = *sub[0]
		return
	}
	*ka = *sub[1]
}
<|endoftext|>


<commit_before>package bitset

import "fmt"

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

// PrintByte displays each bit value of the specific `byte` of `bf.data`
// at index `idx`.
func (bf *BitField) PrintByte(idx int64) {
	if idx < 0 || idx >= bf.bitCount/8 {
		fmt.Printf("Index out of range\n")
	}

	fmt.Printf(
		"%d%d%d%d%d%d%d%d",
		bf.data[idx]>>7&1,
		bf.data[idx]>>6&1,
		bf.data[idx]>>5&1,
		bf.data[idx]>>4&1,
		bf.data[idx]>>3&1,
		bf.data[idx]>>2&1,
		bf.data[idx]>>1&1,
		bf.data[idx]>>0&1,
	)
}

// Pos returns the value of the bit at index `idx` in `bf.data`.
func (bf *BitField) Pos(idx int64) int {
	if idx < 0 || idx >= bf.bitCount {
		return 0
	}
	return int(bf.data[idx/8]>>(7-uint(idx%8))) & 1
}

// WhichSet returns a slice of `[]int64` of up to `limit` values representing
// indexes of `bf.data` where a bit is set to `v`.
func (bf *BitField) WhichSet(v int, limit int64) (res []int64) {
	for i, j := int64(0), int64(0); i < bf.bitCount && j < limit; i++ {
		if int(bf.data[i/8]>>(7-uint(i%8))&1) == v {
			res = append(res, int64(i))
			j++
		}
	}
	return res
}

// BitCount returns the number of bit contained in bf.data.
func (bf *BitField) BitCount() int64 { return bf.bitCount }

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

// BitField is a `struct` exposing methods related to bit manipulation.
type BitField struct {
	data     []byte
	bitCount int64
}

// NewBitField returns a new `BitField`.
func NewBitField(data []byte) *BitField { return &BitField{data: data, bitCount: int64(len(data) * 8)} }
<commit_msg>feat(bitfield): add WhichSetInclusive function<commit_after>package bitset

import (
	"fmt"
	"strconv"

	"github.com/timtosi/gotools/slices"
)

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

// PrintByte displays each bit value of the specific `byte` of `bf.data`
// at index `idx`.
func (bf *BitField) PrintByte(idx int64) {
	if idx < 0 || idx >= bf.bitCount/8 {
		fmt.Printf("Index out of range\n")
	}

	fmt.Printf(
		"%d%d%d%d%d%d%d%d",
		bf.data[idx]>>7&1,
		bf.data[idx]>>6&1,
		bf.data[idx]>>5&1,
		bf.data[idx]>>4&1,
		bf.data[idx]>>3&1,
		bf.data[idx]>>2&1,
		bf.data[idx]>>1&1,
		bf.data[idx]>>0&1,
	)
}

// Pos returns the value of the bit at index `idx` in `bf.data`.
func (bf *BitField) Pos(idx int64) int {
	if idx < 0 || idx >= bf.bitCount {
		return 0
	}
	return int(bf.data[idx/8]>>(7-uint(idx%8))) & 1
}

// WhichSet returns a slice of `[]int64` of up to `limit` values representing
// indexes of `bf.data` where a bit is set to `v`.
func (bf *BitField) WhichSet(v int, limit int64) (res []int64) {
	for i, j := int64(0), int64(0); i < bf.bitCount && j < limit; i++ {
		if int(bf.data[i/8]>>(7-uint(i%8))&1) == v {
			res = append(res, int64(i))
			j++
		}
	}
	return res
}

// WhichSetInclusive returns a slice of `[]int64` values representing indexes
// of `bf.data` where a bit is set to `1`. If `inclusive` is `true`, values
// found in `res` are composed of a subset of `idxs`. If `inclusive` is `false`,
// values found in `res` cannot be found in `idxs`.
func (bf *BitField) WhichSetInclusive(idxs []string, inclusive bool) (res []int64) {
	if inclusive == true {
		for _, idx := range idxs {
			i, err := strconv.ParseInt(idx, 10, 64)
			if err != nil {
				continue
			}
			if int(bf.data[i/8]>>(7-uint(i%8))&1) == 1 {
				res = append(res, i)
			}
		}
	} else {
		for i, j := int64(0), int64(0); i < bf.bitCount && j < 10; i++ {
			if int(bf.data[i/8]>>(7-uint(i%8))&1) == 1 &&
				slices.StringInArray(idxs, strconv.FormatInt(i, 10)) == false {
				res = append(res, int64(i))
				j++
			}
		}
		return res
	}
}

// BitCount returns the number of bit contained in bf.data.
func (bf *BitField) BitCount() int64 { return bf.bitCount }

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

// BitMatrix is a `slice` of `bitset.BitField`.
// type BitMatrix []*BitField

// BitField is a `struct` exposing methods related to bit manipulation.
type BitField struct {
	data     []byte
	bitCount int64
}

// NewBitField returns a new `BitField`.
func NewBitField(data []byte) *BitField { return &BitField{data: data, bitCount: int64(len(data) * 8)} }
<|endoftext|>


<commit_before>package bassh

import (
	"crypto/x509"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"

	"encoding/pem"
	"strings"
	"syscall"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/terminal"
)

//SSHParams contains params to setup the Session
type SSHParams struct {
	Env    []string
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

//SSHClient wraps the ssh client configuration and the host/port information
type SSHClient struct {
	Session *ssh.Session
	Config  *ssh.ClientConfig
	Host    string
	Port    int
}

//InitSession returns a session initialised with the given params
func (client *SSHClient) InitSession(params *SSHParams) (*SSHClient, error) {
	var (
		session *ssh.Session
		err     error
	)

	if session, err = client.newSession(); err != nil {
		return nil, err
	}
	defer session.Close()

	if err = client.prepareCommand(session, params); err != nil {
		return nil, err
	}

	client.Session = session

	return client, nil
}

func (client *SSHClient) prepareCommand(session *ssh.Session, params *SSHParams) error {
	for _, env := range params.Env {
		variable := strings.Split(env, "=")
		if len(variable) != 2 {
			continue
		}
		fmt.Println("Setting env variable ", variable[0], " to ", variable[1])
		if err := session.Setenv(variable[0], variable[1]); err != nil {
			fmt.Println("The remote system doesn't accept the setEnv command: ", err)
			return err
		}
	}

	if params.Stdin != nil {
		stdin, err := session.StdinPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stdin for session: %v", err)
		}
		go io.Copy(stdin, params.Stdin)
	}

	if params.Stdout != nil {
		stdout, err := session.StdoutPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stdout for session: %v", err)
		}
		go io.Copy(params.Stdout, stdout)
	}

	if params.Stderr != nil {
		stderr, err := session.StderrPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stderr for session: %v", err)
		}
		go io.Copy(params.Stderr, stderr)
	}

	return nil
}

func (client *SSHClient) newSession() (*ssh.Session, error) {
	connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Host, client.Port), client.Config)
	if err != nil {
		return nil, fmt.Errorf("Failed to dial: %s", err)
	}

	session, err := connection.NewSession()
	if err != nil {
		return nil, fmt.Errorf("Failed to create session: %s", err)
	}

	modes := ssh.TerminalModes{
		// ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}

	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		session.Close()
		return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
	}

	return session, nil
}

func decodeKeyForAuthMethod(file string) ssh.AuthMethod {
	fmt.Printf("Private key is at: %s", file)
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Println("Error while reading the file: ", err)
		return nil
	}
	decryptedBuffer := decryptIfEncrypted(buffer)
	key, err := ssh.ParsePrivateKey(decryptedBuffer)
	if err != nil {
		fmt.Println("Error while parsing private key: ", err)
		return nil
	}
	fmt.Println("Private key succesfully decripted and decoded.")
	return ssh.PublicKeys(key)
}

func decryptIfEncrypted(buffer []byte) []byte {
	//  Decode the key extracting the pem.Block structure
	block, _ := pem.Decode(buffer)
	if block == nil {
		panic("failed to parse certificate PEM")
	}
	//  Verify if the pem.block is Ecnrypted
	if x509.IsEncryptedPEMBlock(block) {
		fmt.Println("Key is encrypted, specify decrypt passphrase: ")
		bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
		if err == nil {
			fmt.Println("\nPassword typed: " + string(bytePassword))
		}
		passphrase := string(bytePassword)
		decryptedPem, err := x509.DecryptPEMBlock(block, []byte(strings.TrimSpace(passphrase)))
		if err != nil {
			fmt.Println("Error while reading the file: ", err)
			panic("failed to decrypt certificate PEM")
		}
		//  Recreating the decoded block to be returned
		var newBlock pem.Block
		newBlock.Type = block.Type
		newBlock.Headers = block.Headers
		newBlock.Bytes = decryptedPem
		//  Encoding block into []byte and returning
		return pem.EncodeToMemory(&newBlock)
	}
	fmt.Println("Key is not encrypted.")
	return buffer
}

func sshAgent() ssh.AuthMethod {
	if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
		return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	}
	return nil
}

func configureCredentialsInteractive() *ssh.ClientConfig {
	var config ssh.ClientConfig
	fmt.Printf("SSH username: ")
	fmt.Scanf("%s", &config.User)
	var pemKeyCommand string
	fmt.Printf("SSH pem key location (absolute path): ")
	fmt.Scanf("%s", &pemKeyCommand)
	config.Auth = []ssh.AuthMethod{(decodeKeyForAuthMethod(pemKeyCommand))}
	return &config
}

//ConfigureCredentials returns the ClientConfig struct to be used as part of the
//SSHClient definition
func ConfigureCredentials(username string, keypath string) *ssh.ClientConfig {
	var config ssh.ClientConfig
	config.User = username
	pemKeyCommand := keypath
	config.Auth = []ssh.AuthMethod{(decodeKeyForAuthMethod(pemKeyCommand))}
	return &config
}

func createClientInteractive(sshConfig *ssh.ClientConfig) *SSHClient {
	fmt.Printf("IP address: ")
	var ipAddr string
	var port int
	fmt.Scanf("%s", &ipAddr)
	fmt.Printf("SSH port: ")
	fmt.Scanf("%d", &port)

	return CreateClient(sshConfig, ipAddr, port)
}

//CreateClient takes a *ssh.ClientConfig struct as input, ipAddress of the target
//machine and the ssh port, and returns an *SSHClient where a command can be Run on
func CreateClient(sshConfig *ssh.ClientConfig, ipAddr string, port int) *SSHClient {
	return &SSHClient{
		Config: sshConfig,
		Host:   ipAddr,
		Port:   port,
	}
}

//Run opens an SSH session and Runs the command passed as an argument
func (client *SSHClient) Run(command string) {
	if err := client.Session.Run(command); err != nil {
		fmt.Fprintf(os.Stderr, "command run error: %s\n", err)
		if client.Session == nil {
			fmt.Println("Session not initialised.")
		}
		os.Exit(1)
	}
}

//RunBash runs /bin/bash on the client
func (client *SSHClient) RunBash() {
	params := &SSHParams{
		Env:    []string{""},
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}

	client.InitSession(params)
	client.Run("/bin/bash")
}

//RunSSHInteractive allows the user to configure the SSH client interactively and
//executes /bin/bash on the remote host specified interactively by the user
func RunBashInteractive() {
	params := &SSHParams{
		Env:    []string{""},
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}

	sshConfig := configureCredentialsInteractive()
	client := createClientInteractive(sshConfig)

	client.InitSession(params)
	client.Run("/bin/bash")
}
<commit_msg>Fix defer that was preventing the session to be used<commit_after>package bassh

import (
	"crypto/x509"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"

	"encoding/pem"
	"strings"
	"syscall"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/terminal"
)

//SSHParams contains params to setup the Session
type SSHParams struct {
	Env    []string
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
}

//SSHClient wraps the ssh client configuration and the host/port information
type SSHClient struct {
	Session *ssh.Session
	Config  *ssh.ClientConfig
	Host    string
	Port    int
}

//InitSession returns a session initialised with the given params
func (client *SSHClient) InitSession(params *SSHParams) error {
	var (
		session *ssh.Session
		err     error
	)

	if session, err = client.newSession(); err != nil {
		return err
	}

	if err = client.prepareCommand(session, params); err != nil {
		return err
	}

	client.Session = session

	return nil
}

func (client *SSHClient) prepareCommand(session *ssh.Session, params *SSHParams) error {
	for _, env := range params.Env {
		variable := strings.Split(env, "=")
		if len(variable) != 2 {
			continue
		}
		fmt.Println("Setting env variable ", variable[0], " to ", variable[1])
		if err := session.Setenv(variable[0], variable[1]); err != nil {
			fmt.Println("The remote system doesn't accept the setEnv command: ", err)
			return err
		}
	}

	if params.Stdin != nil {
		stdin, err := session.StdinPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stdin for session: %v", err)
		}
		go io.Copy(stdin, params.Stdin)
	}

	if params.Stdout != nil {
		stdout, err := session.StdoutPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stdout for session: %v", err)
		}
		go io.Copy(params.Stdout, stdout)
	}

	if params.Stderr != nil {
		stderr, err := session.StderrPipe()
		if err != nil {
			return fmt.Errorf("Unable to setup stderr for session: %v", err)
		}
		go io.Copy(params.Stderr, stderr)
	}

	return nil
}

func (client *SSHClient) newSession() (*ssh.Session, error) {
	connection, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Host, client.Port), client.Config)
	if err != nil {
		return nil, fmt.Errorf("Failed to dial: %s", err)
	}

	session, err := connection.NewSession()
	if err != nil {
		return nil, fmt.Errorf("Failed to create session: %s", err)
	}

	modes := ssh.TerminalModes{
		// ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}

	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		session.Close()
		return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
	}

	return session, nil
}

func decodeKeyForAuthMethod(file string) ssh.AuthMethod {
	fmt.Printf("Private key is at: %s", file)
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Println("Error while reading the file: ", err)
		return nil
	}
	decryptedBuffer := decryptIfEncrypted(buffer)
	key, err := ssh.ParsePrivateKey(decryptedBuffer)
	if err != nil {
		fmt.Println("Error while parsing private key: ", err)
		return nil
	}
	fmt.Println("Private key succesfully decripted and decoded.")
	return ssh.PublicKeys(key)
}

func decryptIfEncrypted(buffer []byte) []byte {
	//  Decode the key extracting the pem.Block structure
	block, _ := pem.Decode(buffer)
	if block == nil {
		panic("failed to parse certificate PEM")
	}
	//  Verify if the pem.block is Ecnrypted
	if x509.IsEncryptedPEMBlock(block) {
		fmt.Println("Key is encrypted, specify decrypt passphrase: ")
		bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
		if err == nil {
			fmt.Println("\nPassword typed: " + string(bytePassword))
		}
		passphrase := string(bytePassword)
		decryptedPem, err := x509.DecryptPEMBlock(block, []byte(strings.TrimSpace(passphrase)))
		if err != nil {
			fmt.Println("Error while reading the file: ", err)
			panic("failed to decrypt certificate PEM")
		}
		//  Recreating the decoded block to be returned
		var newBlock pem.Block
		newBlock.Type = block.Type
		newBlock.Headers = block.Headers
		newBlock.Bytes = decryptedPem
		//  Encoding block into []byte and returning
		return pem.EncodeToMemory(&newBlock)
	}
	fmt.Println("Key is not encrypted.")
	return buffer
}

func sshAgent() ssh.AuthMethod {
	if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
		return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	}
	return nil
}

func configureCredentialsInteractive() *ssh.ClientConfig {
	var config ssh.ClientConfig
	fmt.Printf("SSH username: ")
	fmt.Scanf("%s", &config.User)
	var pemKeyCommand string
	fmt.Printf("SSH pem key location (absolute path): ")
	fmt.Scanf("%s", &pemKeyCommand)
	config.Auth = []ssh.AuthMethod{(decodeKeyForAuthMethod(pemKeyCommand))}
	return &config
}

//ConfigureCredentials returns the ClientConfig struct to be used as part of the
//SSHClient definition
func ConfigureCredentials(username string, keypath string) *ssh.ClientConfig {
	var config ssh.ClientConfig
	config.User = username
	pemKeyCommand := keypath
	config.Auth = []ssh.AuthMethod{(decodeKeyForAuthMethod(pemKeyCommand))}
	return &config
}

func createClientInteractive(sshConfig *ssh.ClientConfig) *SSHClient {
	fmt.Printf("IP address: ")
	var ipAddr string
	var port int
	fmt.Scanf("%s", &ipAddr)
	fmt.Printf("SSH port: ")
	fmt.Scanf("%d", &port)

	return CreateClient(sshConfig, ipAddr, port)
}

//CreateClient takes a *ssh.ClientConfig struct as input, ipAddress of the target
//machine and the ssh port, and returns an *SSHClient where a command can be Run on
func CreateClient(sshConfig *ssh.ClientConfig, ipAddr string, port int) *SSHClient {
	return &SSHClient{
		Config: sshConfig,
		Host:   ipAddr,
		Port:   port,
	}
}

//Run opens an SSH session and Runs the command passed as an argument
func (client *SSHClient) Run(command string) {
	defer client.Session.Close()
	if err := client.Session.Run(command); err != nil {
		fmt.Fprintf(os.Stderr, "command run error: %s\n", err)
		if client.Session == nil {
			fmt.Println("Session not initialised.")
		}
		os.Exit(1)
	}
}

//RunBash runs /bin/bash on the client
func (client *SSHClient) RunBash() {
	params := &SSHParams{
		Env:    []string{""},
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}

	if err := client.InitSession(params); err == nil {
		client.Run("/bin/bash")
	}
}

//RunBashInteractive allows the user to configure the SSH client interactively and
//executes /bin/bash on the remote host specified interactively by the user
func RunBashInteractive() {
	params := &SSHParams{
		Env:    []string{""},
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}

	sshConfig := configureCredentialsInteractive()
	client := createClientInteractive(sshConfig)

	if err := client.InitSession(params); err == nil {
		client.Run("/bin/bash")
	}
}
<|endoftext|>


<commit_before>/**
 * (C) Copyright 2013, Deft Labs
 *
 * 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 dlshared

import (
	"os"
	"fmt"
	"time"
	"reflect"
	"strconv"
	"syscall"
	"os/signal"
	"math/rand"
)

type Kernel struct {
	Configuration *Configuration
	Components map[string]Component
	components []Component
	Id string
	Logger
	Pid int
}

type Component struct {
	componentId string
	singleton interface{}
	startMethodName string
	stopMethodName string
}

// Access another component. This method will panic if you attempt to reference a
// non-existent component. If the component id has a length of zero, it is also panics.
func (self *Kernel) GetComponent(componentId string) interface{} {

	if len(componentId) == 0 {
		panic("kernel.GetComponent called with an empty component id")
	}

	if _, found := self.Components[componentId]; !found {
		panic(fmt.Sprintf("kernel.GetComponent called with an invalid component id: %s", componentId))
	}

	return self.Components[componentId].singleton.(interface{})
}

// Register a component with a start and stop methods.
func (self *Kernel) AddComponentWithStartStopMethods(componentId string, singleton interface{}, startMethodName, stopMethodName string) {

	component := Component{ componentId : componentId, singleton : singleton, startMethodName : startMethodName, stopMethodName : stopMethodName }

	self.components = append(self.components , component)
	self.Components[componentId] = component
}

// Register a component with a start method.
func (self *Kernel) AddComponentWithStartMethod(componentId string, singleton interface{}, startMethodName string) {
	self.AddComponentWithStartStopMethods(componentId, singleton, startMethodName, "")
}

// Register a component with a stop method.
func (self *Kernel) AddComponentWithStopMethod(componentId string, singleton interface{}, stopMethodName string) {
	self.AddComponentWithStartStopMethods(componentId, singleton, "", stopMethodName)
}

// Register a component without a start or stop method.
func (self *Kernel) AddComponent(componentId string, singleton interface{}) {
	self.AddComponentWithStartStopMethods(componentId, singleton, "", "")
}

// Called by the kernel during Start/Stop.
func callStartStopMethod(methodTypeName, methodName string, singleton interface{}, kernel *Kernel) error {

	value := reflect.ValueOf(singleton)

	methodValue := value.MethodByName(methodName)

	if !methodValue.IsValid() {
		return fmt.Errorf("Start method: %s is NOT found on struct: %s", methodName, value.Type())
	}

	methodType := methodValue.Type()

	if methodType.NumOut() > 1 {
		panic(fmt.Sprintf("The %s method: %s on struct: %s has more than one return value - you can only return error or nothing", methodTypeName, methodName, value.Type()))
	}

	if methodType.NumIn() > 1 {
		return fmt.Errorf("The %s method: %s on struct: %s has more than one parameter - you can only accept Kernel or nothing", methodTypeName, methodName, value.Type())
	}

	// Verify the return type is error
	if methodType.NumOut() == 1 && methodType.Out(0).Name() != "error"  {

		return fmt.Errorf("The %s method: %s on struct: %s has an invalid return type - you can return nothing or error", methodTypeName, methodName, value.Type())
	}

	methodInputs := make([]reflect.Value, 0)
	if methodType.NumIn() == 1 {
		methodInputs = append(methodInputs, reflect.ValueOf(kernel))
	}

	returnValues := methodValue.Call(methodInputs)

	// Check to see if there was an error
	if len(returnValues) == 1 {
		err := returnValues[0].Interface()
		if err != nil {
			return err.(error)
		}
	}

	return nil
}

// Call this after the kernel has been created and components registered.
func (self *Kernel) Start() error {

	rand.Seed(time.Now().UTC().UnixNano())

	self.Logf(Info, "Starting %s - version: %s - config file: %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	for i := range self.components {
		if len(self.components[i].startMethodName) > 0 {
			if err := callStartStopMethod("start", self.components[i].startMethodName, self.components[i].singleton, self); err != nil {
				return err
			}
		}
	}

	self.Logf(Info, "Started %s - version: %s - config file: %s ", self.Id, self.Configuration.Version, self.Configuration.FileName)

	return nil
}

// Stop the kernel. Call this before exiting.
func (self *Kernel) Stop() error {

	self.Logf(Info, "Stopping %s - version: %s - config file %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	for i := len(self.components)-1 ; i >= 0 ; i-- {

		if len(self.components[i].stopMethodName) > 0 {
			if err := callStartStopMethod("stop", self.components[i].stopMethodName, self.components[i].singleton, self); err != nil {
				return err
			}
		}
	}

	self.Logf(Info, "Stopped %s - version: %s - config file: %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	return nil
}

func newKernel(id, configFileName string) (*Kernel, error) {

	// Init the application configuration
	conf, err := NewConfiguration(configFileName)

	if err != nil {
		return nil, err
	}

	// TODO: Add a logging structure to the configuration file and configure. Make
	// sure this supports configuring syslog.

	syslogAppender, err := NewSyslogAppender("tcp", "127.0.0.1:6514", id)
	if err != nil {
		return nil, err
	}

	logger := Logger {
		Prefix: id,
		Appenders: [] Appender{
			LevelFilter(Debug, StdErrAppender()),
			LevelFilter(Debug, syslogAppender),
		},
	}

	kernel := &Kernel{ Components : make(map[string]Component), Configuration : conf }
	kernel.Logger = logger
	kernel.Id = id

	if err = writePidFile(kernel); err != nil {
		return nil, err
	}

	return kernel, nil
}

func writePidFile(kernel *Kernel) error {
	kernel.Pid = os.Getpid()
	pidFile, err := os.Create(kernel.Configuration.PidFile)
	if err != nil {
		return NewStackError("Unable to start kernel - problem creating pid file %s - error: %v", kernel.Configuration.PidFile, err)
	}
	defer pidFile.Close()

	if _, err := pidFile.Write([]byte(strconv.Itoa(kernel.Pid))); err != nil {
		return NewStackError("Unable to start kernel - problem writing pid file %s - error: %v", kernel.Configuration.PidFile, err)
	}

	return nil
}

// Call this from your main to create the kernel. After init kernel is called you must add
// your components and then call kernel.Start()
func StartKernel(id string, configFileName string, addComponentsFunction func(kernel *Kernel)) (*Kernel, error) {

	kernel, err := newKernel(id, configFileName)
	if err != nil {
		return nil, err
	}

	addComponentsFunction(kernel)

    if err = kernel.Start(); err != nil {
		return nil, err
	}

	return kernel, nil
}

// ListenForInterrupt blocks until an interrupt signal is detected.
func (self *Kernel) ListenForInterrupt() error {
	quitChannel := make(chan bool)

	// Register the interrupt listener.
	interruptSignalChannel := make(chan os.Signal, 1)
	signal.Notify(interruptSignalChannel, os.Interrupt)
	go func() {
		for sig := range interruptSignalChannel {
			if sig == syscall.SIGINT {
				quitChannel <- true
			}
		}
	}()

	// Block until we receive the stop notification.
	select {
		case <- quitChannel: {
			return self.Stop()
		}
	}

	// Should never happen
	panic("How did we end up here?")
}

<commit_msg>moved to udp<commit_after>/**
 * (C) Copyright 2013, Deft Labs
 *
 * 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 dlshared

import (
	"os"
	"fmt"
	"time"
	"reflect"
	"strconv"
	"syscall"
	"os/signal"
	"math/rand"
)

type Kernel struct {
	Configuration *Configuration
	Components map[string]Component
	components []Component
	Id string
	Logger
	Pid int
}

type Component struct {
	componentId string
	singleton interface{}
	startMethodName string
	stopMethodName string
}

// Access another component. This method will panic if you attempt to reference a
// non-existent component. If the component id has a length of zero, it is also panics.
func (self *Kernel) GetComponent(componentId string) interface{} {

	if len(componentId) == 0 {
		panic("kernel.GetComponent called with an empty component id")
	}

	if _, found := self.Components[componentId]; !found {
		panic(fmt.Sprintf("kernel.GetComponent called with an invalid component id: %s", componentId))
	}

	return self.Components[componentId].singleton.(interface{})
}

// Register a component with a start and stop methods.
func (self *Kernel) AddComponentWithStartStopMethods(componentId string, singleton interface{}, startMethodName, stopMethodName string) {

	component := Component{ componentId : componentId, singleton : singleton, startMethodName : startMethodName, stopMethodName : stopMethodName }

	self.components = append(self.components , component)
	self.Components[componentId] = component
}

// Register a component with a start method.
func (self *Kernel) AddComponentWithStartMethod(componentId string, singleton interface{}, startMethodName string) {
	self.AddComponentWithStartStopMethods(componentId, singleton, startMethodName, "")
}

// Register a component with a stop method.
func (self *Kernel) AddComponentWithStopMethod(componentId string, singleton interface{}, stopMethodName string) {
	self.AddComponentWithStartStopMethods(componentId, singleton, "", stopMethodName)
}

// Register a component without a start or stop method.
func (self *Kernel) AddComponent(componentId string, singleton interface{}) {
	self.AddComponentWithStartStopMethods(componentId, singleton, "", "")
}

// Called by the kernel during Start/Stop.
func callStartStopMethod(methodTypeName, methodName string, singleton interface{}, kernel *Kernel) error {

	value := reflect.ValueOf(singleton)

	methodValue := value.MethodByName(methodName)

	if !methodValue.IsValid() {
		return fmt.Errorf("Start method: %s is NOT found on struct: %s", methodName, value.Type())
	}

	methodType := methodValue.Type()

	if methodType.NumOut() > 1 {
		panic(fmt.Sprintf("The %s method: %s on struct: %s has more than one return value - you can only return error or nothing", methodTypeName, methodName, value.Type()))
	}

	if methodType.NumIn() > 1 {
		return fmt.Errorf("The %s method: %s on struct: %s has more than one parameter - you can only accept Kernel or nothing", methodTypeName, methodName, value.Type())
	}

	// Verify the return type is error
	if methodType.NumOut() == 1 && methodType.Out(0).Name() != "error"  {

		return fmt.Errorf("The %s method: %s on struct: %s has an invalid return type - you can return nothing or error", methodTypeName, methodName, value.Type())
	}

	methodInputs := make([]reflect.Value, 0)
	if methodType.NumIn() == 1 {
		methodInputs = append(methodInputs, reflect.ValueOf(kernel))
	}

	returnValues := methodValue.Call(methodInputs)

	// Check to see if there was an error
	if len(returnValues) == 1 {
		err := returnValues[0].Interface()
		if err != nil {
			return err.(error)
		}
	}

	return nil
}

// Call this after the kernel has been created and components registered.
func (self *Kernel) Start() error {

	rand.Seed(time.Now().UTC().UnixNano())

	self.Logf(Info, "Starting %s - version: %s - config file: %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	for i := range self.components {
		if len(self.components[i].startMethodName) > 0 {
			if err := callStartStopMethod("start", self.components[i].startMethodName, self.components[i].singleton, self); err != nil {
				return err
			}
		}
	}

	self.Logf(Info, "Started %s - version: %s - config file: %s ", self.Id, self.Configuration.Version, self.Configuration.FileName)

	return nil
}

// Stop the kernel. Call this before exiting.
func (self *Kernel) Stop() error {

	self.Logf(Info, "Stopping %s - version: %s - config file %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	for i := len(self.components)-1 ; i >= 0 ; i-- {

		if len(self.components[i].stopMethodName) > 0 {
			if err := callStartStopMethod("stop", self.components[i].stopMethodName, self.components[i].singleton, self); err != nil {
				return err
			}
		}
	}

	self.Logf(Info, "Stopped %s - version: %s - config file: %s", self.Id, self.Configuration.Version, self.Configuration.FileName)

	return nil
}

func newKernel(id, configFileName string) (*Kernel, error) {

	// Init the application configuration
	conf, err := NewConfiguration(configFileName)

	if err != nil {
		return nil, err
	}

	// TODO: Add a logging structure to the configuration file and configure. Make
	// sure this supports configuring syslog.

	syslogAppender, err := NewSyslogAppender("udp", "127.0.0.1:514", id)
	if err != nil {
		return nil, err
	}

	logger := Logger {
		Prefix: id,
		Appenders: [] Appender{
			LevelFilter(Debug, StdErrAppender()),
			LevelFilter(Debug, syslogAppender),
		},
	}

	kernel := &Kernel{ Components : make(map[string]Component), Configuration : conf }
	kernel.Logger = logger
	kernel.Id = id

	if err = writePidFile(kernel); err != nil {
		return nil, err
	}

	return kernel, nil
}

func writePidFile(kernel *Kernel) error {
	kernel.Pid = os.Getpid()
	pidFile, err := os.Create(kernel.Configuration.PidFile)
	if err != nil {
		return NewStackError("Unable to start kernel - problem creating pid file %s - error: %v", kernel.Configuration.PidFile, err)
	}
	defer pidFile.Close()

	if _, err := pidFile.Write([]byte(strconv.Itoa(kernel.Pid))); err != nil {
		return NewStackError("Unable to start kernel - problem writing pid file %s - error: %v", kernel.Configuration.PidFile, err)
	}

	return nil
}

// Call this from your main to create the kernel. After init kernel is called you must add
// your components and then call kernel.Start()
func StartKernel(id string, configFileName string, addComponentsFunction func(kernel *Kernel)) (*Kernel, error) {

	kernel, err := newKernel(id, configFileName)
	if err != nil {
		return nil, err
	}

	addComponentsFunction(kernel)

    if err = kernel.Start(); err != nil {
		return nil, err
	}

	return kernel, nil
}

// ListenForInterrupt blocks until an interrupt signal is detected.
func (self *Kernel) ListenForInterrupt() error {
	quitChannel := make(chan bool)

	// Register the interrupt listener.
	interruptSignalChannel := make(chan os.Signal, 1)
	signal.Notify(interruptSignalChannel, os.Interrupt)
	go func() {
		for sig := range interruptSignalChannel {
			if sig == syscall.SIGINT {
				quitChannel <- true
			}
		}
	}()

	// Block until we receive the stop notification.
	select {
		case <- quitChannel: {
			return self.Stop()
		}
	}

	// Should never happen
	panic("How did we end up here?")
}

<|endoftext|>


<commit_before>// Package github implements the OAuth2 protocol for authenticating users through Github.
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
package github

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

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

// These vars define the Authentication, Token, and API URLS for GitHub. If
// using GitHub enterprise you should change these values before calling New.
//
// Examples:
//	github.AuthURL = "https://github.acme.com/login/oauth/authorize
//	github.TokenURL = "https://github.acme.com/login/oauth/access_token
//	github.ProfileURL = "https://github.acme.com/api/v3/user
//	github.EmailURL = "https://github.acme.com/api/v3/user/emails
var (
	AuthURL    = "https://github.com/login/oauth/authorize"
	TokenURL   = "https://github.com/login/oauth/access_token"
	ProfileURL = "https://api.github.com/user"
	EmailURL   = "https://api.github.com/user/emails"
)

// New creates a new Github provider, and sets up important connection details.
// You should always call `github.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	return NewCustomisedURL(clientKey, secret, callbackURL, AuthURL, TokenURL, ProfileURL, EmailURL, scopes...)
}

// NewCustomisedURL is similar to New(...) but can be used to set custom URLs to connect to
func NewCustomisedURL(clientKey, secret, callbackURL, authURL, tokenURL, profileURL, emailURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "github",
		profileURL:   profileURL,
		emailURL:     emailURL,
	}
	p.config = newConfig(p, authURL, tokenURL, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Github.
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
	profileURL   string
	emailURL     string
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is a no-op for the github package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Github for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	session := &Session{
		AuthURL: url,
	}
	return session, nil
}

// FetchUser will go to Github and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	sess := session.(*Session)
	user := goth.User{
		AccessToken: sess.AccessToken,
		Provider:    p.Name(),
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	response, err := p.Client().Get(p.profileURL + "?access_token=" + url.QueryEscape(sess.AccessToken))
	if err != nil {
		return user, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return user, fmt.Errorf("GitHub API responded with a %d trying to fetch user information", response.StatusCode)
	}

	bits, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return user, err
	}

	err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
	if err != nil {
		return user, err
	}

	err = userFromReader(bytes.NewReader(bits), &user)
	if err != nil {
		return user, err
	}

	if user.Email == "" {
		for _, scope := range p.config.Scopes {
			if strings.TrimSpace(scope) == "user" || strings.TrimSpace(scope) == "user:email" {
				user.Email, err = getPrivateMail(p, sess)
				if err != nil {
					return user, err
				}
				break
			}
		}
	}
	return user, err
}

func userFromReader(reader io.Reader, user *goth.User) error {
	u := struct {
		ID       int    `json:"id"`
		Email    string `json:"email"`
		Bio      string `json:"bio"`
		Name     string `json:"name"`
		Login    string `json:"login"`
		Picture  string `json:"avatar_url"`
		Location string `json:"location"`
	}{}

	err := json.NewDecoder(reader).Decode(&u)
	if err != nil {
		return err
	}

	user.Name = u.Name
	user.NickName = u.Login
	user.Email = u.Email
	user.Description = u.Bio
	user.AvatarURL = u.Picture
	user.UserID = strconv.Itoa(u.ID)
	user.Location = u.Location

	return err
}

func getPrivateMail(p *Provider, sess *Session) (email string, err error) {
	response, err := p.Client().Get(p.emailURL + "?access_token=" + url.QueryEscape(sess.AccessToken))
	if err != nil {
		if response != nil {
			response.Body.Close()
		}
		return email, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return email, fmt.Errorf("GitHub API responded with a %d trying to fetch user email", response.StatusCode)
	}

	var mailList = []struct {
		Email    string `json:"email"`
		Primary  bool   `json:"primary"`
		Verified bool   `json:"verified"`
	}{}
	err = json.NewDecoder(response.Body).Decode(&mailList)
	if err != nil {
		return email, err
	}
	for _, v := range mailList {
		if v.Primary && v.Verified {
			return v.Email, nil
		}
	}
	// can't get primary email - shouldn't be possible
	return
}

func newConfig(provider *Provider, authURL, tokenURL string, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	for _, scope := range scopes {
		c.Scopes = append(c.Scopes, scope)
	}

	return c
}

//RefreshToken refresh token is not provided by github
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	return nil, errors.New("Refresh token is not provided by github")
}

//RefreshTokenAvailable refresh token is not provided by github
func (p *Provider) RefreshTokenAvailable() bool {
	return false
}
<commit_msg>github: Use Authorization header for authentication<commit_after>// Package github implements the OAuth2 protocol for authenticating users through Github.
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
package github

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

	"github.com/markbates/goth"
	"golang.org/x/oauth2"
)

// These vars define the Authentication, Token, and API URLS for GitHub. If
// using GitHub enterprise you should change these values before calling New.
//
// Examples:
//	github.AuthURL = "https://github.acme.com/login/oauth/authorize
//	github.TokenURL = "https://github.acme.com/login/oauth/access_token
//	github.ProfileURL = "https://github.acme.com/api/v3/user
//	github.EmailURL = "https://github.acme.com/api/v3/user/emails
var (
	AuthURL    = "https://github.com/login/oauth/authorize"
	TokenURL   = "https://github.com/login/oauth/access_token"
	ProfileURL = "https://api.github.com/user"
	EmailURL   = "https://api.github.com/user/emails"
)

// New creates a new Github provider, and sets up important connection details.
// You should always call `github.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string, scopes ...string) *Provider {
	return NewCustomisedURL(clientKey, secret, callbackURL, AuthURL, TokenURL, ProfileURL, EmailURL, scopes...)
}

// NewCustomisedURL is similar to New(...) but can be used to set custom URLs to connect to
func NewCustomisedURL(clientKey, secret, callbackURL, authURL, tokenURL, profileURL, emailURL string, scopes ...string) *Provider {
	p := &Provider{
		ClientKey:    clientKey,
		Secret:       secret,
		CallbackURL:  callbackURL,
		providerName: "github",
		profileURL:   profileURL,
		emailURL:     emailURL,
	}
	p.config = newConfig(p, authURL, tokenURL, scopes)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Github.
type Provider struct {
	ClientKey    string
	Secret       string
	CallbackURL  string
	HTTPClient   *http.Client
	config       *oauth2.Config
	providerName string
	profileURL   string
	emailURL     string
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return p.providerName
}

// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
	p.providerName = name
}

func (p *Provider) Client() *http.Client {
	return goth.HTTPClientWithFallBack(p.HTTPClient)
}

// Debug is a no-op for the github package.
func (p *Provider) Debug(debug bool) {}

// BeginAuth asks Github for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	url := p.config.AuthCodeURL(state)
	session := &Session{
		AuthURL: url,
	}
	return session, nil
}

// FetchUser will go to Github and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	sess := session.(*Session)
	user := goth.User{
		AccessToken: sess.AccessToken,
		Provider:    p.Name(),
	}

	if user.AccessToken == "" {
		// data is not yet retrieved since accessToken is still empty
		return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
	}

	req, err := http.NewRequest("GET", p.profileURL, nil)
	req.Header.Add("Authorization", "Bearer "+sess.AccessToken)
	response, err := p.Client().Do(req)
	if err != nil {
		return user, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return user, fmt.Errorf("GitHub API responded with a %d trying to fetch user information", response.StatusCode)
	}

	bits, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return user, err
	}

	err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
	if err != nil {
		return user, err
	}

	err = userFromReader(bytes.NewReader(bits), &user)
	if err != nil {
		return user, err
	}

	if user.Email == "" {
		for _, scope := range p.config.Scopes {
			if strings.TrimSpace(scope) == "user" || strings.TrimSpace(scope) == "user:email" {
				user.Email, err = getPrivateMail(p, sess)
				if err != nil {
					return user, err
				}
				break
			}
		}
	}
	return user, err
}

func userFromReader(reader io.Reader, user *goth.User) error {
	u := struct {
		ID       int    `json:"id"`
		Email    string `json:"email"`
		Bio      string `json:"bio"`
		Name     string `json:"name"`
		Login    string `json:"login"`
		Picture  string `json:"avatar_url"`
		Location string `json:"location"`
	}{}

	err := json.NewDecoder(reader).Decode(&u)
	if err != nil {
		return err
	}

	user.Name = u.Name
	user.NickName = u.Login
	user.Email = u.Email
	user.Description = u.Bio
	user.AvatarURL = u.Picture
	user.UserID = strconv.Itoa(u.ID)
	user.Location = u.Location

	return err
}

func getPrivateMail(p *Provider, sess *Session) (email string, err error) {
	req, err := http.NewRequest("GET", p.emailURL, nil)
	req.Header.Add("Authorization", "Bearer "+sess.AccessToken)
	response, err := p.Client().Do(req)
	if err != nil {
		if response != nil {
			response.Body.Close()
		}
		return email, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return email, fmt.Errorf("GitHub API responded with a %d trying to fetch user email", response.StatusCode)
	}

	var mailList = []struct {
		Email    string `json:"email"`
		Primary  bool   `json:"primary"`
		Verified bool   `json:"verified"`
	}{}
	err = json.NewDecoder(response.Body).Decode(&mailList)
	if err != nil {
		return email, err
	}
	for _, v := range mailList {
		if v.Primary && v.Verified {
			return v.Email, nil
		}
	}
	// can't get primary email - shouldn't be possible
	return
}

func newConfig(provider *Provider, authURL, tokenURL string, scopes []string) *oauth2.Config {
	c := &oauth2.Config{
		ClientID:     provider.ClientKey,
		ClientSecret: provider.Secret,
		RedirectURL:  provider.CallbackURL,
		Endpoint: oauth2.Endpoint{
			AuthURL:  authURL,
			TokenURL: tokenURL,
		},
		Scopes: []string{},
	}

	for _, scope := range scopes {
		c.Scopes = append(c.Scopes, scope)
	}

	return c
}

//RefreshToken refresh token is not provided by github
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
	return nil, errors.New("Refresh token is not provided by github")
}

//RefreshTokenAvailable refresh token is not provided by github
func (p *Provider) RefreshTokenAvailable() bool {
	return false
}
<|endoftext|>