<commit_before>package ld

// Compact operation compacts the given input using the context
// according to the steps in the Compaction Algorithm:
//
// http://www.w3.org/TR/json-ld-api/#compaction-algorithm
//
// Returns the compacted JSON-LD object.
// Returns an error if there was an error during compaction.
func (api *JsonLdApi) Compact(activeCtx *Context, activeProperty string, element interface{},
	compactArrays bool) (interface{}, error) {
	// 2)
	if elementList, isList := element.([]interface{}); isList {
		// 2.1)
		result := make([]interface{}, 0)
		// 2.2)
		for _, item := range elementList {
			// 2.2.1)
			compactedItem, err := api.Compact(activeCtx, activeProperty, item, compactArrays)
			if err != nil {
				return nil, err
			}
			// 2.2.2)
			if compactedItem != nil {
				result = append(result, compactedItem)
			}
		}
		// 2.3)
		if compactArrays && len(result) == 1 && activeCtx.GetContainer(activeProperty) == "" {
			return result[0], nil
		}
		// 2.4)
		return result, nil
	}

	// 3)
	if elem, isMap := element.(map[string]interface{}); isMap {
		// 4
		_, containsValue := elem["@value"]
		_, containsID := elem["@id"]
		if containsValue || containsID {
			compactedValue := activeCtx.CompactValue(activeProperty, elem)
			_, isMap := compactedValue.(map[string]interface{})
			_, isList := compactedValue.([]interface{})
			if !(isMap || isList) {
				return compactedValue, nil
			}
		}
		// 5)
		insideReverse := activeProperty == "@reverse"

		// 6)
		result := make(map[string]interface{})
		// 7)
		for _, expandedProperty := range GetOrderedKeys(elem) {
			expandedValue := elem[expandedProperty]

			// 7.1)
			if expandedProperty == "@id" || expandedProperty == "@type" {
				var compactedValue interface{}

				// 7.1.1)
				if expandedValueStr, isString := expandedValue.(string); isString {
					compactedValue = activeCtx.CompactIri(expandedValueStr, nil, expandedProperty == "@type", false)
				} else { // 7.1.2)
					types := make([]string, 0)
					// 7.1.2.2)
					for _, expandedTypeVal := range expandedValue.([]interface{}) {
						expandedType := expandedTypeVal.(string)
						types = append(types, activeCtx.CompactIri(expandedType, nil, true, false))
					}
					// 7.1.2.3)
					if len(types) == 1 {
						compactedValue = types[0]
					} else {
						compactedValue = types
					}
				}

				// 7.1.3)
				alias := activeCtx.CompactIri(expandedProperty, nil, true, false)
				// 7.1.4)
				result[alias] = compactedValue
				continue
			}

			// 7.2)
			if expandedProperty == "@reverse" {
				// 7.2.1)
				compactedObject, _ := api.Compact(activeCtx, "@reverse", expandedValue, compactArrays)
				compactedValue := compactedObject.(map[string]interface{})
				// 7.2.2)
				for _, property := range GetKeys(compactedValue) {
					value := compactedValue[property]
					// 7.2.2.1)
					if activeCtx.IsReverseProperty(property) {
						// 7.2.2.1.1)
						valueList, isList := value.([]interface{})
						if (activeCtx.GetContainer(property) == "@set" || !compactArrays) && !isList {
							result[property] = []interface{}{value}
						}
						// 7.2.2.1.2)
						if _, present := result[property]; !present {
							result[property] = value
						} else { // 7.2.2.1.3)
							propertyValueList, isPropertyList := result[property].([]interface{})
							if !isPropertyList {
								propertyValueList = []interface{}{result[property]}
							}
							if isList {
								propertyValueList = append(propertyValueList, valueList...)
							} else {
								propertyValueList = append(propertyValueList, value)
							}
							result[property] = propertyValueList
						}
						// 7.2.2.1.4)
						delete(compactedValue, property)
					}

				}
				// 7.2.3)
				if len(compactedValue) > 0 {
					// 7.2.3.1)
					alias := activeCtx.CompactIri("@reverse", nil, true, false)
					// 7.2.3.2)
					result[alias] = compactedValue
				}
				// 7.2.4)
				continue
			}
			// 7.3)
			if expandedProperty == "@index" && activeCtx.GetContainer(activeProperty) == "@index" {
				continue
			} else if expandedProperty == "@index" || expandedProperty == "@value" ||
				expandedProperty == "@language" { // 7.4)
				// 7.4.1)
				alias := activeCtx.CompactIri(expandedProperty, nil, true, false)
				// 7.4.2)
				result[alias] = expandedValue
				continue
			}

			// NOTE: expanded value must be an array due to expansion
			// algorithm.

			// 7.5)
			expandedValueList, isList := expandedValue.([]interface{})
			if isList && len(expandedValueList) == 0 {
				// 7.5.1)
				itemActiveProperty := activeCtx.CompactIri(expandedProperty, expandedValue, true, insideReverse)
				// 7.5.2)
				itemActivePropertyVal, present := result[itemActiveProperty]
				if !present {
					result[itemActiveProperty] = make([]interface{}, 0)
				} else {
					if _, isList := itemActivePropertyVal.([]interface{}); !isList {
						result[itemActiveProperty] = []interface{}{itemActivePropertyVal}
					}
				}
			}

			// 7.6)
			for _, expandedItem := range expandedValueList {
				// 7.6.1)
				itemActiveProperty := activeCtx.CompactIri(expandedProperty, expandedItem, true, insideReverse)
				// 7.6.2)
				container := activeCtx.GetContainer(itemActiveProperty)

				// get @list value if appropriate
				expandedItemMap, isMap := expandedItem.(map[string]interface{})
				list, containsList := expandedItemMap["@list"]
				isList := isMap && containsList

				// 7.6.3)
				var elementToCompact interface{}
				if isList {
					elementToCompact = list
				} else {
					elementToCompact = expandedItem
				}
				compactedItem, _ := api.Compact(activeCtx, itemActiveProperty, elementToCompact, compactArrays)

				// 7.6.4)
				if isList {
					// 7.6.4.1)

					if _, isCompactedList := compactedItem.([]interface{}); !isCompactedList {
						compactedItem = []interface{}{compactedItem}
					}
					// 7.6.4.2)
					if container != "@list" {
						// 7.6.4.2.1)
						wrapper := make(map[string]interface{})
						// TODO: SPEC: no mention of vocab = true
						wrapper[activeCtx.CompactIri("@list", nil, true, false)] = compactedItem
						compactedItem = wrapper

						// 7.6.4.2.2)
						if indexVal, containsIndex := expandedItemMap["@index"]; containsIndex {
							// TODO: SPEC: no mention of vocab = true
							wrapper[activeCtx.CompactIri("@index", nil, true, false)] = indexVal
						}
					} else if _, present := result[itemActiveProperty]; present { // 7.6.4.3)
						return nil, NewJsonLdError(CompactionToListOfLists,
							"There cannot be two list objects associated with an active property that has a container mapping")
					}
				}
				// 7.6.5)
				if container == "@language" || container == "@index" {
					// 7.6.5.1)

					var mapObject map[string]interface{}
					if v, present := result[itemActiveProperty]; present {
						mapObject = v.(map[string]interface{})
					} else {
						mapObject = make(map[string]interface{})
						result[itemActiveProperty] = mapObject
					}

					// 7.6.5.2)
					compactedItemMap, isMap := compactedItem.(map[string]interface{})
					compactedItemValue, containsValue := compactedItemMap["@value"]
					if container == "@language" && isMap && containsValue {
						compactedItem = compactedItemValue
					}

					// 7.6.5.3)
					mapKey := expandedItemMap[container].(string)
					// 7.6.5.4)
					mapValue, hasMapKey := mapObject[mapKey]
					if !hasMapKey {
						mapObject[mapKey] = compactedItem
					} else {
						mapValueList, isList := mapValue.([]interface{})
						var tmp []interface{}
						if !isList {
							tmp = []interface{}{mapValue}
						} else {
							tmp = mapValueList
						}
						tmp = append(tmp, compactedItem)
						mapObject[mapKey] = tmp
					}
				} else { // 7.6.6)
					// 7.6.6.1)
					_, isList := compactedItem.([]interface{})
					check := (!compactArrays || container == "@set" || container == "@list" ||
						expandedProperty == "@list" || expandedProperty == "@graph") && !isList
					if check {
						compactedItem = []interface{}{compactedItem}
					}
					// 7.6.6.2)
					itemActivePropertyVal, present := result[itemActiveProperty]
					if !present {
						result[itemActiveProperty] = compactedItem
					} else {
						itemActivePropertyValueList, isList := itemActivePropertyVal.([]interface{})
						if !isList {
							itemActivePropertyValueList = []interface{}{itemActivePropertyVal}
							result[itemActiveProperty] = itemActivePropertyValueList
						}
						compactedItemList, isList := compactedItem.([]interface{})
						if isList {
							itemActivePropertyValueList = append(itemActivePropertyValueList, compactedItemList...)
						} else {
							itemActivePropertyValueList = append(itemActivePropertyValueList, compactedItem)
						}
						result[itemActiveProperty] = itemActivePropertyValueList
					}
				}
			}
		}
		// 8)
		return result, nil
	}
	// 2)
	return element, nil
}
<commit_msg>Minor bug fix in compaction logic<commit_after>package ld

// Compact operation compacts the given input using the context
// according to the steps in the Compaction Algorithm:
//
// http://www.w3.org/TR/json-ld-api/#compaction-algorithm
//
// Returns the compacted JSON-LD object.
// Returns an error if there was an error during compaction.
func (api *JsonLdApi) Compact(activeCtx *Context, activeProperty string, element interface{},
	compactArrays bool) (interface{}, error) {
	// 2)
	if elementList, isList := element.([]interface{}); isList {
		// 2.1)
		result := make([]interface{}, 0)
		// 2.2)
		for _, item := range elementList {
			// 2.2.1)
			compactedItem, err := api.Compact(activeCtx, activeProperty, item, compactArrays)
			if err != nil {
				return nil, err
			}
			// 2.2.2)
			if compactedItem != nil {
				result = append(result, compactedItem)
			}
		}
		// 2.3)
		if compactArrays && len(result) == 1 && activeCtx.GetContainer(activeProperty) == "" {
			return result[0], nil
		}
		// 2.4)
		return result, nil
	}

	// 3)
	if elem, isMap := element.(map[string]interface{}); isMap {
		// 4
		_, containsValue := elem["@value"]
		_, containsID := elem["@id"]
		if containsValue || containsID {
			compactedValue := activeCtx.CompactValue(activeProperty, elem)
			_, isMap := compactedValue.(map[string]interface{})
			_, isList := compactedValue.([]interface{})
			if !(isMap || isList) {
				return compactedValue, nil
			}
		}
		// 5)
		insideReverse := activeProperty == "@reverse"

		// 6)
		result := make(map[string]interface{})
		// 7)
		for _, expandedProperty := range GetOrderedKeys(elem) {
			expandedValue := elem[expandedProperty]

			// 7.1)
			if expandedProperty == "@id" || expandedProperty == "@type" {
				var compactedValue interface{}

				// 7.1.1)
				if expandedValueStr, isString := expandedValue.(string); isString {
					compactedValue = activeCtx.CompactIri(expandedValueStr, nil, expandedProperty == "@type", false)
				} else { // 7.1.2)
					types := make([]interface{}, 0)
					// 7.1.2.2)
					for _, expandedTypeVal := range expandedValue.([]interface{}) {
						expandedType := expandedTypeVal.(string)
						types = append(types, activeCtx.CompactIri(expandedType, nil, true, false))
					}
					// 7.1.2.3)
					if len(types) == 1 {
						compactedValue = types[0]
					} else {
						compactedValue = types
					}
				}

				// 7.1.3)
				alias := activeCtx.CompactIri(expandedProperty, nil, true, false)
				// 7.1.4)
				result[alias] = compactedValue
				continue
			}

			// 7.2)
			if expandedProperty == "@reverse" {
				// 7.2.1)
				compactedObject, _ := api.Compact(activeCtx, "@reverse", expandedValue, compactArrays)
				compactedValue := compactedObject.(map[string]interface{})
				// 7.2.2)
				for _, property := range GetKeys(compactedValue) {
					value := compactedValue[property]
					// 7.2.2.1)
					if activeCtx.IsReverseProperty(property) {
						// 7.2.2.1.1)
						valueList, isList := value.([]interface{})
						if (activeCtx.GetContainer(property) == "@set" || !compactArrays) && !isList {
							result[property] = []interface{}{value}
						}
						// 7.2.2.1.2)
						if _, present := result[property]; !present {
							result[property] = value
						} else { // 7.2.2.1.3)
							propertyValueList, isPropertyList := result[property].([]interface{})
							if !isPropertyList {
								propertyValueList = []interface{}{result[property]}
							}
							if isList {
								propertyValueList = append(propertyValueList, valueList...)
							} else {
								propertyValueList = append(propertyValueList, value)
							}
							result[property] = propertyValueList
						}
						// 7.2.2.1.4)
						delete(compactedValue, property)
					}

				}
				// 7.2.3)
				if len(compactedValue) > 0 {
					// 7.2.3.1)
					alias := activeCtx.CompactIri("@reverse", nil, true, false)
					// 7.2.3.2)
					result[alias] = compactedValue
				}
				// 7.2.4)
				continue
			}
			// 7.3)
			if expandedProperty == "@index" && activeCtx.GetContainer(activeProperty) == "@index" {
				continue
			} else if expandedProperty == "@index" || expandedProperty == "@value" ||
				expandedProperty == "@language" { // 7.4)
				// 7.4.1)
				alias := activeCtx.CompactIri(expandedProperty, nil, true, false)
				// 7.4.2)
				result[alias] = expandedValue
				continue
			}

			// NOTE: expanded value must be an array due to expansion
			// algorithm.

			// 7.5)
			expandedValueList, isList := expandedValue.([]interface{})
			if isList && len(expandedValueList) == 0 {
				// 7.5.1)
				itemActiveProperty := activeCtx.CompactIri(expandedProperty, expandedValue, true, insideReverse)
				// 7.5.2)
				itemActivePropertyVal, present := result[itemActiveProperty]
				if !present {
					result[itemActiveProperty] = make([]interface{}, 0)
				} else {
					if _, isList := itemActivePropertyVal.([]interface{}); !isList {
						result[itemActiveProperty] = []interface{}{itemActivePropertyVal}
					}
				}
			}

			// 7.6)
			for _, expandedItem := range expandedValueList {
				// 7.6.1)
				itemActiveProperty := activeCtx.CompactIri(expandedProperty, expandedItem, true, insideReverse)
				// 7.6.2)
				container := activeCtx.GetContainer(itemActiveProperty)

				// get @list value if appropriate
				expandedItemMap, isMap := expandedItem.(map[string]interface{})
				list, containsList := expandedItemMap["@list"]
				isList := isMap && containsList

				// 7.6.3)
				var elementToCompact interface{}
				if isList {
					elementToCompact = list
				} else {
					elementToCompact = expandedItem
				}
				compactedItem, _ := api.Compact(activeCtx, itemActiveProperty, elementToCompact, compactArrays)

				// 7.6.4)
				if isList {
					// 7.6.4.1)

					if _, isCompactedList := compactedItem.([]interface{}); !isCompactedList {
						compactedItem = []interface{}{compactedItem}
					}
					// 7.6.4.2)
					if container != "@list" {
						// 7.6.4.2.1)
						wrapper := make(map[string]interface{})
						// TODO: SPEC: no mention of vocab = true
						wrapper[activeCtx.CompactIri("@list", nil, true, false)] = compactedItem
						compactedItem = wrapper

						// 7.6.4.2.2)
						if indexVal, containsIndex := expandedItemMap["@index"]; containsIndex {
							// TODO: SPEC: no mention of vocab = true
							wrapper[activeCtx.CompactIri("@index", nil, true, false)] = indexVal
						}
					} else if _, present := result[itemActiveProperty]; present { // 7.6.4.3)
						return nil, NewJsonLdError(CompactionToListOfLists,
							"There cannot be two list objects associated with an active property that has a container mapping")
					}
				}
				// 7.6.5)
				if container == "@language" || container == "@index" {
					// 7.6.5.1)

					var mapObject map[string]interface{}
					if v, present := result[itemActiveProperty]; present {
						mapObject = v.(map[string]interface{})
					} else {
						mapObject = make(map[string]interface{})
						result[itemActiveProperty] = mapObject
					}

					// 7.6.5.2)
					compactedItemMap, isMap := compactedItem.(map[string]interface{})
					compactedItemValue, containsValue := compactedItemMap["@value"]
					if container == "@language" && isMap && containsValue {
						compactedItem = compactedItemValue
					}

					// 7.6.5.3)
					mapKey := expandedItemMap[container].(string)
					// 7.6.5.4)
					mapValue, hasMapKey := mapObject[mapKey]
					if !hasMapKey {
						mapObject[mapKey] = compactedItem
					} else {
						mapValueList, isList := mapValue.([]interface{})
						var tmp []interface{}
						if !isList {
							tmp = []interface{}{mapValue}
						} else {
							tmp = mapValueList
						}
						tmp = append(tmp, compactedItem)
						mapObject[mapKey] = tmp
					}
				} else { // 7.6.6)
					// 7.6.6.1)
					_, isList := compactedItem.([]interface{})
					check := (!compactArrays || container == "@set" || container == "@list" ||
						expandedProperty == "@list" || expandedProperty == "@graph") && !isList
					if check {
						compactedItem = []interface{}{compactedItem}
					}
					// 7.6.6.2)
					itemActivePropertyVal, present := result[itemActiveProperty]
					if !present {
						result[itemActiveProperty] = compactedItem
					} else {
						itemActivePropertyValueList, isList := itemActivePropertyVal.([]interface{})
						if !isList {
							itemActivePropertyValueList = []interface{}{itemActivePropertyVal}
							result[itemActiveProperty] = itemActivePropertyValueList
						}
						compactedItemList, isList := compactedItem.([]interface{})
						if isList {
							itemActivePropertyValueList = append(itemActivePropertyValueList, compactedItemList...)
						} else {
							itemActivePropertyValueList = append(itemActivePropertyValueList, compactedItem)
						}
						result[itemActiveProperty] = itemActivePropertyValueList
					}
				}
			}
		}
		// 8)
		return result, nil
	}
	// 2)
	return element, nil
}
<|endoftext|>


<commit_before>package main

/*
TODO
pass in host on CLI
deal with no values found
set up webserver
create new keys
add user for key
add admin for key
front end with appache
appache user auth
dockerize
api doc
figure out way to load secrets
encrypt keys in DB
DB backup

*/

import (
        "database/sql"
	_ "github.com/lib/pq"
        "log"
	"fmt"
	"os"
)

var db *sql.DB

func setupDatabase( hostName string, pgPassword string ) { // todo pass in hostname, port, username
        var err error

        // set up DB
        db, err = sql.Open("postgres", "password='"+pgPassword+"' user=postgres dbname=postgres host="+hostName+" port=5432 sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}

	// a postgess bigint is signed 64 bit int
	sqlSetup := `
        CREATE TABLE IF NOT EXISTS keys ( kID BIGINT NOT NULL, kVal bytea NOT NULL ,  oID BIGINT NOT NULL, PRIMARY KEY( kID ) );
        CREATE TABLE IF NOT EXISTS keyUsers ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        CREATE TABLE IF NOT EXISTS keyAdmins ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        `
        _, err = db.Exec(sqlSetup)
        if err != nil {
                log.Println("sql fatal error in setupDatabase")
                log.Printf("%q\n", err)
        }

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Setup Database\n")
}

func getKey( keyID, userID int64 ) {
	// note if using mySQL use ? but Postgres is $1 in prepare statements
	stmt, err := db.Prepare(
		"SELECT keys.kVal  FROM keyUsers JOIN keys ON  keys.kID = keyUsers.kID WHERE keyUsers.uID = $2 AND keyUsers.kID = $1")
	if err != nil {
		log.Println("sql fatal error in getKey prep")
		log.Fatal(err)
	}
	var keyVal string
	err = stmt.QueryRow(keyID,userID).Scan( &keyVal )
	if err != nil {
		log.Println("sql fatal error in getKey querry")
		log.Fatal(err)
	}
	fmt.Println(keyVal)
}

func main() {
	var err error

	var pgPassword string = os.Getenv("SECM_DB_SECRET")
	var hostName string = os.Args[1]

	setupDatabase(hostName,pgPassword)
        defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	getKey( 101, 1 )
}
<commit_msg>detect no key error<commit_after>package main

/*
TODO
deal with no values found
set up webserver
create new keys
add user for key
add admin for key
front end with appache
appache user auth
dockerize
api doc
figure out way to load secrets
encrypt keys in DB
DB backup

*/

import (
        "database/sql"
	_ "github.com/lib/pq"
        "log"
	"fmt"
	"os"
)

var db *sql.DB

func setupDatabase( hostName string, pgPassword string ) { // todo pass in hostname, port, username
        var err error

        // set up DB
        db, err = sql.Open("postgres", "password='"+pgPassword+"' user=postgres dbname=postgres host="+hostName+" port=5432 sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}

	// a postgess bigint is signed 64 bit int
	sqlSetup := `
        CREATE TABLE IF NOT EXISTS keys ( kID BIGINT NOT NULL, kVal bytea NOT NULL ,  oID BIGINT NOT NULL, PRIMARY KEY( kID ) );
        CREATE TABLE IF NOT EXISTS keyUsers ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        CREATE TABLE IF NOT EXISTS keyAdmins ( kID BIGINT NOT NULL, uID BIGINT NOT NULL , PRIMARY KEY( kID,uID ) );
        `
        _, err = db.Exec(sqlSetup)
        if err != nil {
                log.Println("sql fatal error in setupDatabase")
                log.Printf("%q\n", err)
        }

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Setup Database\n")
}

func getKey( keyID, userID int64 ) {
	// note if using mySQL use ? but Postgres is $1 in prepare statements
	stmt, err := db.Prepare(
		"SELECT keys.kVal  FROM keyUsers JOIN keys ON  keys.kID = keyUsers.kID WHERE keyUsers.uID = $2 AND keyUsers.kID = $1")
	if err != nil {
		log.Println("sql fatal error in getKey prep")
		log.Fatal(err)
	}
	var keyVal string
	err = stmt.QueryRow(keyID,userID).Scan( &keyVal )
	switch {
	case err == sql.ErrNoRows:
            log.Printf("no key found")
	case err != nil:
		log.Println("sql fatal error in getKey querry")
		log.Fatal(err)
	default:
		fmt.Println(keyVal)
	}
}

func main() {
	var err error

	var pgPassword string = os.Getenv("SECM_DB_SECRET")
	var hostName string = os.Args[1]

	setupDatabase(hostName,pgPassword)
        defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	getKey( 101, 2 )
}
<|endoftext|>


<commit_before>package nbt

import (
	"bytes"
	"encoding/base64"
	"testing"
)

func TestSize(t *testing.T) {
	for i := TagID(1); i < 12; i++ {
		o := new(bytes.Buffer)
		tag, _ := defaultConfig.newFromTag(i)
		d := NewTag("test", tag)
		n, _ := d.WriteTo(o)
		_, m, _ := ReadNBTFrom(o)
		if n != m {
			t.Errorf("written and read sizes for %s do not match, written %d, read %d", i, n, m)
		}
	}
}

func TestSmall(t *testing.T) { //test.nbt
	testNBT(`CgALaGVsbG8gd29ybGQIAARuYW1lAAlCYW5hbnJhbWEA`,
		NewTag("hello world", NewCompound([]*Tag{
			NewTag("name", NewString("Bananrama")),
		})), t)
}

func TestLarge(t *testing.T) { //bigtest.nbt
	data := make([]int8, 1000)
	for i := 0; i < 1000; i++ {
		data[i] = int8((i*i*255 + i*7) % 100)
	}
	testNBT(`CgAFTGV2ZWwEAAhsb25nVGVzdH//////////AgAJc2hvcnRUZXN0f/8IAApzdHJpbmdUZXN0AClI`+
		`RUxMTyBXT1JMRCBUSElTIElTIEEgVEVTVCBTVFJJTkcgw4XDhMOWIQUACWZsb2F0VGVzdD7/GDID`+
		`AAdpbnRUZXN0f////woAFG5lc3RlZCBjb21wb3VuZCB0ZXN0CgADaGFtCAAEbmFtZQAGSGFtcHVz`+
		`BQAFdmFsdWU/QAAAAAoAA2VnZwgABG5hbWUAB0VnZ2JlcnQFAAV2YWx1ZT8AAAAAAAkAD2xpc3RU`+
		`ZXN0IChsb25nKQQAAAAFAAAAAAAAAAsAAAAAAAAADAAAAAAAAAANAAAAAAAAAA4AAAAAAAAADwkA`+
		`E2xpc3RUZXN0IChjb21wb3VuZCkKAAAAAggABG5hbWUAD0NvbXBvdW5kIHRhZyAjMAQACmNyZWF0`+
		`ZWQtb24AAAEmUjfVjQAIAARuYW1lAA9Db21wb3VuZCB0YWcgIzEEAApjcmVhdGVkLW9uAAABJlI3`+
		`1Y0AAQAIYnl0ZVRlc3R/BwBlYnl0ZUFycmF5VGVzdCAodGhlIGZpcnN0IDEwMDAgdmFsdWVzIG9m`+
		`IChuKm4qMjU1K24qNyklMTAwLCBzdGFydGluZyB3aXRoIG49MCAoMCwgNjIsIDM0LCAxNiwgOCwg`+
		`Li4uKSkAAAPoAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIY`+
		`OGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAI`+
		`ChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRS`+
		`NiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4u`+
		`WCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIA`+
		`DCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6Ckgs`+
		`GhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCRO`+
		`HlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoC`+
		`GDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQ`+
		`CAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQU`+
		`UjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwO`+
		`LlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZi`+
		`AAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpI`+
		`LBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQk`+
		`Th5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFha`+
		`Ahg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4i`+
		`EAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpE`+
		`FFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAYACmRvdWJsZVRlc3Q/349r`+
		`u/9qXgA=`,
		NewTag("Level", NewCompound([]*Tag{
			NewTag("longTest", NewLong(9223372036854775807)),
			NewTag("shortTest", NewShort(32767)),
			NewTag("stringTest", NewString("HELLO WORLD THIS IS A TEST STRING ÅÄÖ!")),
			NewTag("floatTest", NewFloat(0.49823147)),
			NewTag("intTest", NewInt(2147483647)),
			NewTag("nested compound test", NewCompound([]*Tag{
				NewTag("ham", NewCompound([]*Tag{
					NewTag("name", NewString("Hampus")),
					NewTag("value", NewFloat(0.75)),
				})),
				NewTag("egg", NewCompound([]*Tag{
					NewTag("name", NewString("Eggbert")),
					NewTag("value", NewFloat(0.5)),
				})),
			})),
			NewTag("listTest (long)", NewList([]Data{
				NewLong(11),
				NewLong(12),
				NewLong(13),
				NewLong(14),
				NewLong(15),
			})),
			NewTag("listTest (compound)", NewList([]Data{
				NewCompound([]*Tag{
					NewTag("name", NewString("Compound tag #0")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
				NewCompound([]*Tag{
					NewTag("name", NewString("Compound tag #1")),
					NewTag("created-on", NewLong(1264099775885)),
				}),
			})),
			NewTag("byteTest", NewByte(127)),
			NewTag("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", NewByteArray(data)),
			NewTag("doubleTest", NewDouble(0.4931287132182315)),
		})), t)
}

func testNBT(input string, middle *Tag, t *testing.T) {
	n, c, err := ReadNBTFrom(base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(input)))
	if err != nil {
		t.Errorf("error encountered while reading nbt data: %q", err)
		return
	}
	if !n.Equal(middle) {
		t.Error("parsed nbt data did not match given nbt structure")
		return
	}
	o := new(bytes.Buffer)
	b := base64.NewEncoder(base64.StdEncoding, o)
	d, err := n.WriteTo(b)
	b.Close()
	if err != nil {
		t.Errorf("error encountered while writing nbt data: %q", err)
		return
	}
	if c != d {
		t.Errorf("read and write byte counts do not match, read %d, wrote %d", c, d)
		return
	}
	if o.String() != input {
		t.Error("input and output do not match")
	}
}
<commit_msg>reworked test<commit_after>package nbt

import (
	"bytes"
	"encoding/base64"
	"testing"
)

/*func TestSize(t *testing.T) {
	for i := TagID(1); i < 12; i++ {
		o := new(bytes.Buffer)
		tag, _ := defaultConfig.newFromTag(i)
		d := NewTag("test", tag)
		n, _ := d.WriteTo(o)
		_, m, _ := ReadNBTFrom(o)
		if n != m {
			t.Errorf("written and read sizes for %s do not match, written %d, read %d", i, n, m)
		}
	}
}*/

func TestSmall(t *testing.T) { //test.nbt
	testNBT(`CgALaGVsbG8gd29ybGQIAARuYW1lAAlCYW5hbnJhbWEA`,
		NewTag("hello world", Compound{
			NewTag("name", String("Bananrama")),
		}), t)
}

func TestLarge(t *testing.T) { //bigtest.nbt
	data := make([]int8, 1000)
	for i := 0; i < 1000; i++ {
		data[i] = int8((i*i*255 + i*7) % 100)
	}
	testNBT(`CgAFTGV2ZWwEAAhsb25nVGVzdH//////////AgAJc2hvcnRUZXN0f/8IAApzdHJpbmdUZXN0AClI`+
		`RUxMTyBXT1JMRCBUSElTIElTIEEgVEVTVCBTVFJJTkcgw4XDhMOWIQUACWZsb2F0VGVzdD7/GDID`+
		`AAdpbnRUZXN0f////woAFG5lc3RlZCBjb21wb3VuZCB0ZXN0CgADaGFtCAAEbmFtZQAGSGFtcHVz`+
		`BQAFdmFsdWU/QAAAAAoAA2VnZwgABG5hbWUAB0VnZ2JlcnQFAAV2YWx1ZT8AAAAAAAkAD2xpc3RU`+
		`ZXN0IChsb25nKQQAAAAFAAAAAAAAAAsAAAAAAAAADAAAAAAAAAANAAAAAAAAAA4AAAAAAAAADwkA`+
		`E2xpc3RUZXN0IChjb21wb3VuZCkKAAAAAggABG5hbWUAD0NvbXBvdW5kIHRhZyAjMAQACmNyZWF0`+
		`ZWQtb24AAAEmUjfVjQAIAARuYW1lAA9Db21wb3VuZCB0YWcgIzEEAApjcmVhdGVkLW9uAAABJlI3`+
		`1Y0AAQAIYnl0ZVRlc3R/BwBlYnl0ZUFycmF5VGVzdCAodGhlIGZpcnN0IDEwMDAgdmFsdWVzIG9m`+
		`IChuKm4qMjU1K24qNyklMTAwLCBzdGFydGluZyB3aXRoIG49MCAoMCwgNjIsIDM0LCAxNiwgOCwg`+
		`Li4uKSkAAAPoAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIY`+
		`OGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAI`+
		`ChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRS`+
		`NiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4u`+
		`WCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIA`+
		`DCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6Ckgs`+
		`GhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCRO`+
		`HlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpILBoSFCA2VhxQKg5gWFoC`+
		`GDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQkTh5cQC4mKDRKBjAAPiIQ`+
		`CAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFhaAhg4YjIMVEI6PEheGkQU`+
		`UjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4iEAgKFixMEkYgBFZOUFwO`+
		`LlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpEFFI2JBweKkBgJlo0GAZi`+
		`AAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAA+IhAIChYsTBJGIARWTlBcDi5YKAJKODAyPlQQOgpI`+
		`LBoSFCA2VhxQKg5gWFoCGDhiMgxUQjo8SF4aRBRSNiQcHipAYCZaNBgGYgAMIkIIPBZeTERGUgQk`+
		`Th5cQC4mKDRKBjAAPiIQCAoWLEwSRiAEVk5QXA4uWCgCSjgwMj5UEDoKSCwaEhQgNlYcUCoOYFha`+
		`Ahg4YjIMVEI6PEheGkQUUjYkHB4qQGAmWjQYBmIADCJCCDwWXkxERlIEJE4eXEAuJig0SgYwAD4i`+
		`EAgKFixMEkYgBFZOUFwOLlgoAko4MDI+VBA6CkgsGhIUIDZWHFAqDmBYWgIYOGIyDFRCOjxIXhpE`+
		`FFI2JBweKkBgJlo0GAZiAAwiQgg8Fl5MREZSBCROHlxALiYoNEoGMAYACmRvdWJsZVRlc3Q/349r`+
		`u/9qXgA=`,
		NewTag("Level", Compound{
			NewTag("longTest", Long(9223372036854775807)),
			NewTag("shortTest", Short(32767)),
			NewTag("stringTest", String("HELLO WORLD THIS IS A TEST STRING ÅÄÖ!")),
			NewTag("floatTest", Float(0.49823147)),
			NewTag("intTest", Int(2147483647)),
			NewTag("nested compound test", Compound{
				NewTag("ham", Compound{
					NewTag("name", String("Hampus")),
					NewTag("value", Float(0.75)),
				}),
				NewTag("egg", Compound{
					NewTag("name", String("Eggbert")),
					NewTag("value", Float(0.5)),
				}),
			}),
			NewTag("listTest (long)", NewList([]Data{
				Long(11),
				Long(12),
				Long(13),
				Long(14),
				Long(15),
			})),
			NewTag("listTest (compound)", NewList([]Data{
				Compound{
					NewTag("name", String("Compound tag #0")),
					NewTag("created-on", Long(1264099775885)),
				},
				Compound{
					NewTag("name", String("Compound tag #1")),
					NewTag("created-on", Long(1264099775885)),
				},
			})),
			NewTag("byteTest", Byte(127)),
			NewTag("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))", ByteArray(data)),
			NewTag("doubleTest", Double(0.4931287132182315)),
		}), t)
}

func testNBT(input string, middle Tag, t *testing.T) {
	tag, err := NewDecoder(base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(input))).DecodeTag()
	if err != nil {
		t.Errorf("error encountered while reading nbt data: %q", err)
		return
	}
	if !tag.Equal(middle) {
		t.Error("parsed nbt data did not match given nbt structure")
		return
	}
	o := new(bytes.Buffer)
	b := base64.NewEncoder(base64.StdEncoding, o)
	err = NewEncoder(b).EncodeTag(tag)
	b.Close()
	if err != nil {
		t.Errorf("error encountered while writing nbt data: %q", err)
		return
	}
	if o.String() != input {
		t.Error("input and output do not match")
	}
}
<|endoftext|>


<commit_before><commit_msg>udemyTraining rune and string and []byte utf8 string and for loop<commit_after>package main

import "fmt"

func main() {
	for i := 50; i < 140; i++ {
		fmt.Printf("%v - %v - %v", i, string(i), []byte(string(i)))
		println()
	}
}<|endoftext|>


<commit_before>package tokenauth

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"github.com/ant0ine/go-json-rest/rest"
	"log"
	"net/http"
	"strings"
)

// AuthTokenMiddleware provides a Token Auth implementation. On success, the wrapped middleware
// is called, and the userID is made available as request.Env["REMOTE_USER"].(string)
type AuthTokenMiddleware struct {
	// Realm name to display to the user. Required.
	Realm string

	// Callback function that should perform the authentication of the user based on token.
	// Must return userID as string on success, empty string on failure. Required.
	// The returned userID is normally the primary key for your user record.
	Authenticator func(token string) string

	// Callback function that should perform the authorization of the authenticated user.
	// Must return true on success, false on failure. Optional, defaults to success.
	// Called only after an authentication success.
	Authorizer func(request *rest.Request) bool

	// Nominal token entropy in bytes. Optional, defaults to recommended 32 bytes / 256-bit.
	TokenEntropy int
}

// MiddlewareFunc makes AuthTokenMiddleware implement the Middleware interface.
func (mw *AuthTokenMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	if mw.Realm == "" {
		log.Fatal("Realm is required")
	}

	if mw.Authenticator == nil {
		log.Fatal("Authenticator is required")
	}

	if mw.Authorizer == nil {
		mw.Authorizer = func(request *rest.Request) bool {
			return true
		}
	}

	if mw.TokenEntropy == 0 {
		mw.TokenEntropy = 32 // 32 byte == 256 bit == recommended secure ID entropy
	}

	return func(writer rest.ResponseWriter, request *rest.Request) {
		authHeader := request.Header.Get("Authorization")
		// Authorization header was not provided
		if authHeader == "" {
			mw.unauthorized(writer)
			return
		}

		token, err := mw.decodeAuthHeader(authHeader)
		// Authorization header was *malformed* such that we couldn't extract a token
		if err != nil {
			mw.unauthorized(writer)
			return
		}

		userID := mw.Authenticator(token)
		// The token didn't map to a user, it's most likely either invalid or expired
		if userID == "" {
			mw.unauthorized(writer)
			return
		}

		// The user's token was valid, but they're not authorized for the current request
		if !mw.Authorizer(request) {
			mw.unauthorized(writer)
			return
		}

		request.Env["REMOTE_USER"] = userID
		handler(writer, request)
	}
}

// Extract the token from the current request.
func (mw *AuthTokenMiddleware) decodeAuthHeader(header string) (string, error) {
	parts := strings.SplitN(header, " ", 2)
	if !(len(parts) == 2 && parts[0] == "Token") {
		return "", errors.New("Invalid authentication")
	}
	token, err := base64.URLEncoding.DecodeString(parts[1])
	if err != nil {
		return "", errors.New("Invalid base64")
	}
	return string(token), nil
}

// New generates a new random token
func (mw *AuthTokenMiddleware) New() (string, error) {
	bytes := make([]byte, mw.TokenEntropy)
	_, err := rand.Read(bytes[:cap(bytes)])
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(bytes), nil
}

// Equal does constant-time XOR comparison of two tokens
func (mw *AuthTokenMiddleware) Equal(a, b string) bool {
	return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}

// Hash applies a simple MD5 hash over a token, making it safe to store
func (mw *AuthTokenMiddleware) Hash(token string) string {
	hashed := md5.Sum([]byte(token))
	return base64.URLEncoding.EncodeToString(hashed[:])
}

func (mw *AuthTokenMiddleware) unauthorized(writer rest.ResponseWriter) {
	writer.Header().Set("WWW-Authenticate", "Token realm="+mw.Realm)
	rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
}
<commit_msg>Fix tokens at 256-bit, move helpers off middleware<commit_after>package tokenauth

import (
	"crypto/md5"
	"crypto/rand"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"github.com/ant0ine/go-json-rest/rest"
	"log"
	"net/http"
	"strings"
)

var tokenEntropy = 32

// AuthTokenMiddleware provides a Token Auth implementation. On success, the wrapped middleware
// is called, and the userID is made available as request.Env["REMOTE_USER"].(string)
type AuthTokenMiddleware struct {
	// Realm name to display to the user. Required.
	Realm string

	// Callback function that should perform the authentication of the user based on token.
	// Must return userID as string on success, empty string on failure. Required.
	// The returned userID is normally the primary key for your user record.
	Authenticator func(token string) string

	// Callback function that should perform the authorization of the authenticated user.
	// Must return true on success, false on failure. Optional, defaults to success.
	// Called only after an authentication success.
	Authorizer func(request *rest.Request) bool
}

// MiddlewareFunc makes AuthTokenMiddleware implement the Middleware interface.
func (mw *AuthTokenMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	if mw.Realm == "" {
		log.Fatal("Realm is required")
	}

	if mw.Authenticator == nil {
		log.Fatal("Authenticator is required")
	}

	if mw.Authorizer == nil {
		mw.Authorizer = func(request *rest.Request) bool {
			return true
		}
	}

	return func(writer rest.ResponseWriter, request *rest.Request) {
		authHeader := request.Header.Get("Authorization")
		// Authorization header was not provided
		if authHeader == "" {
			mw.unauthorized(writer)
			return
		}

		token, err := mw.decodeAuthHeader(authHeader)
		// Authorization header was *malformed* such that we couldn't extract a token
		if err != nil {
			mw.unauthorized(writer)
			return
		}

		userID := mw.Authenticator(token)
		// The token didn't map to a user, it's most likely either invalid or expired
		if userID == "" {
			mw.unauthorized(writer)
			return
		}

		// The user's token was valid, but they're not authorized for the current request
		if !mw.Authorizer(request) {
			mw.unauthorized(writer)
			return
		}

		request.Env["REMOTE_USER"] = userID
		handler(writer, request)
	}
}

// Extract the token from the current request.
func (mw *AuthTokenMiddleware) decodeAuthHeader(header string) (string, error) {
	parts := strings.SplitN(header, " ", 2)
	if !(len(parts) == 2 && parts[0] == "Token") {
		return "", errors.New("Invalid authentication")
	}
	token, err := base64.URLEncoding.DecodeString(parts[1])
	if err != nil {
		return "", errors.New("Invalid base64")
	}
	return string(token), nil
}

func (mw *AuthTokenMiddleware) unauthorized(writer rest.ResponseWriter) {
	writer.Header().Set("WWW-Authenticate", "Token realm="+mw.Realm)
	rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
}

// New generates a new random token
func New() (string, error) {
	bytes := make([]byte, tokenEntropy)
	_, err := rand.Read(bytes[:cap(bytes)])
	if err != nil {
		return "", err
	}
	return base64.URLEncoding.EncodeToString(bytes), nil
}

// Equal does constant-time XOR comparison of two tokens
func Equal(a, b string) bool {
	return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}

// Hash applies a simple MD5 hash over a token, making it safe to store
func Hash(token string) string {
	hashed := md5.Sum([]byte(token))
	return base64.URLEncoding.EncodeToString(hashed[:])
}
<|endoftext|>


<commit_before>/*

Package moves is a convenience package that implements composable Moves to make
it easy to implement common logic. The Base move type is a very simple move that
implements the basic stubs necessary for your straightforward moves to have
minimal boilerplate. Although it's technically optional, a lot of the magic
features throughout the framework depend on some if its base logic, so it's
recommended to always embed it anonymously in your move struct (or embed a
struct that embeds it).

You interact with and configure various move types by implementing interfaces.
Those interfaes are defined in the interfaces subpackage, to make this package's
design more clear.

There are many move types defined. Some are designed to be used directly with
minimal modification; others are powerful move types that are designed to be
sub-classed.

Automatic MoveConfig Generation

Creating MoveConfig's is a necessary part of installing moves on your
GameManager, but it's verbose and error-prone. You need to create a lot of extra
structs, and then remember to provide the right properties in your config. And
to use many of the powerful moves in the moves package, you need to write a lot
of boilerplate methods to integrate correctly. Finally, you end up repeating
yourself often--which makes it a pain if you change the name of a move.

Take this example:

    //boardgame:codegen
    type MoveDealInitialCards struct {
        moves.DealComponentsUntilPlayerCountReached
    }

    var moveDealInitialCardsConfig = boardgame.MoveConfig {
        Name: "Deal Initial Cards",
        Constructor: func() boardgame.Move {
            return new(MoveDealInitialCards)
        },
    }

    func (m *MoveDealInitialCards) GameStack(gState boardgame.MutableSubState) boardgame.MutableStack {
        return gState.(*gameState).DrawStack
    }

    func (m *MoveDealInitialCards) PlayerStack(pState boardgame.MutablePlayerState) boardgame.MutableStack {
        return pState.(*playerState).Hand
    }

    func (m *MoveDealInitialCards) TargetCount() int {
        return 2
    }

    func (g *gameDelegate) ConfigureMoves() []boardgame.MoveConfig {
        return moves.Add(
            &moveDealInitialCardsConfig,
        )
    }

auto.Config (and its panic-y sibling auto.MustConfig) help reduce this
signficantly:

    func (g *gameDelegate) ConfigureMoves() []boardgame.MoveConfig {

        auto := moves.NewAutoConfigurer(g)

        return moves.Add(
            auto.MustConfig(
                new(moves.DealComponentsUntilPlayerCountReached),
                moves.WithGameProperty("DrawStack"),
                moves.WithPlayerProperty("Hand"),
                moves.WithTargetCount(2),
            )
        )
    }

Basic Usage

AutoConfigurer takes an example struct representing your move, and then a list
of 0 to n interfaces.CustomConfigurationOption. These options are given a
boardgame.PropertyCollection and then add specific properties to it, and then
stash that on the CustomConfiguration property of the returned MoveTypeConfig.
Different move methods will then reach into that configuration to alter the
behavior of moves of that type.

The moves/with package defines a large collection of CustomConfigurationOption
for use with the moves in the moves package.

Moves that are used with AutoConfigurer must satisfy the AutoConfigurableMove
interface, which adds one method: DeriveName() string. AutoConfigurer.Config()
primarily consists of some set up and then using those return values as fields
on the returned MoveConfig. These methods are implemented in moves.Default,
which means that any move structs that embed moves.Default (directly or
indirectly) can be used with AutoConfigurer.

moves.Default does a fair bit of magic in these methods to implement much of the
logic of AutoConfigurer. In general, if you pass a configuration option (via
WithMoveName, for example) then that option will be used for that method.
moves.Default.DeriveName() also will use reflection to automatically set a
struct name like "MoveDealInitialCards" to "Deal Initial Cards". All of the
moves in the moves package will also automatically return reasonable names for
DeriveName(), so in many cases you can use those structs directly without having
to pass WithMoveName().

Other moves in the moves package, like DealCountComponents, will use
configuration, like WithGameProperty(), to power their default GameStack()
method.

All moves in the moves package are designed to return an error from
ValidConfiguration(), which means that if you forgot to pass a required
configuration property (e.g. you don't override GameStack and also don't provide
WithGameProperty), when you try to create NewGameManager() and all moves'
ValidConfiguration() is checked, you'll get an error. This helps catch
mis-configurations during boot time.

Refer to the documentation of the various methods in that package for their
precise behavior and how to configure them.

Idiomatic Move Definition and Installation

AutoConfigurer is at the core of idiomatic definition and installation of moves,
and typically is used for every move you install in your game. The following
paragraphs describe the high-level idioms to follow.

Never create your own MoveConfig objects--it's just another global variable that
clutters up your code and makes it harder to change. Instead, use
AutoConfigurer. There are some rare cases where you do want to refer to the move
by name (and not rely on finicky string-based lookup), such as when you want an
Agent to propose a speciifc type of move. In those cases use AutoConfigurer to
create the move type config, then save the resulting config's Name to a global
variable that you use elsewhere, and then pass the created config to moves.Add()
(and its cousins)

In general, you should only create a bespoke Move struct in your game if it is
not possible to use one of the off-the-shelf moves from the moves package,
combined with configuarion options, to do what you want. In practice this means
that only if you need to override a method on one of the base moves do you need
to create a bespoke struct. This typically allows you to drastically reduce the
number of bespoke move structs your game defines, saving thousands of lines of
code (each bespoke struct also has hundreds of lines of auto-generated
PropertyReader code).

If you do create a bespoke struct, name it like this: "MoveNameOfMyMove", so
that moves.Default's default DeriveName() will give it a reasonable name
automatically (in this example, "Name Of My Move").

In many cases if you subclass powerful moves like DealCountComponents the
default HelpText() value is sufficient (especially if it's a FixUp move that
won't ever be seen by players). In other cases, WithHelpText() is often the only
config option you will pass to AutoConfigurer.

If your move will be a FixUp move that doesn't sublcass one of the more advanced
fix up moves (like RoundRobin or DealCountComponents), embed moves.FixUp into
your struct. That will cause IsFixUp to return the right value even without
using WithIsFixUp--because WithIsFixUp is easy to forget given that it's often
in a different file. In almost all cases if you use WithIsFixUp you should
simply embed moves.FixUp instead.

AutoConfigurer.MustConfig is like AutoConfigurer.Config, but instead of
returning a MoveConfig and an error, it simply returns a MoveConfig--and panics
if it would have returned an error. Since your GameDelegate's ConfigureMoves()
is typically called during the boot-up sequence of your game, it is safe to use
AutoConfigurer.MustConfig exclusively, which saves many lines of boilerplate
error checking.

Configure Move Helpers

Your Game Delegate's ConfigureMoves() []boardgame.MoveConfig is where the action
happens for installing moves. In practice you can do whatever you want in there
as long as you return a list of MoveConfigs. In practice you often use
AutoConfigurer (see section above). If you have a very simple game type you
might not need to do anythign special.

If, however, your game type is complicated enough to need the notion of phases,
then you'll probably want to use some of the convenience methods for installing
moves: Combine, Add, AddForPhase, and AddOrderedForPhase. These methods make
sure that enough information is stored for the Legal() methods of those moves to
know when the move is legal. Technically they're just convenience wrappers (each
describes the straightforward things it's doing), but in practice they're the
best way to do it. See the tutorial in the main package for more.

Move Type Hierarchy

The moves in this package are all defined as a hierarchy of structs that
anonymously embed higher level structs, overriding, modifying, and extending the
behavior of the struct they embed.

You can use many of these moves directly, using the configuration options like
WithSourceProperty() to configure which properties they should operate on.
Alternatively, you can embed them in your own move struct, overriding or
tweaking their behavior, perhaps adding an additional check to their Legal
check.

For convenience, here's the type hierarchy, with a brief description of the diff
each has on the one above it. See the documentation for each struct for more.

    * base.Move - The simplest, unopinonated stub of a move, from the base package.
        * Default - Substantial base logic, including base property overriding for with and especially in Legal() around move progressions and phases.
            * Done - A simple move that does nothing in its Apply and has no extra Legal() logic, meaning it's primarily a non-fix-up move applied by a player to move out of a move progression.
            * CurrentPlayer - Defaults to the GameDelegate.CurrentPlayerIndex, and only lets the move be made if it's on behalf of that player.
            * FixUp - Overrides IsFixUp() to always return true, making the move eligible for base.GameDelegate.ProposeFixUpMove.
                * NoOp - A move that does nothing. Useful for specific edge cases of MoveProessionMatching, and also to signal to AddOrderedForPhase that the lack of a StartPhase move was intentional.
                * Increment - Increments the provided SourceProperty by Amount. Useful to run automatically at a given spot in a move progression.
                * ShuffleStack - Shuffles the stack at SourceProperty. Useful to run automatically at a certain time in a MoveProgression.
                * StartPhase - Calls BeforeLeavePhase, then BeforeEnterPhase, then SetCurrentPhase. Generally you have one of these at the end of an AddOrderedForPhase.
                * FinishTurn - Checks if State.CurrentPlayer().TurnDone() is true, and if so increments CurrentPlayerIndex to the next player, calling playerState.ResetForTurnEnd() and then ResetForTurnStart.
                * FixUpMulti - Overrides AllowMultipleInProgression() to true, meaning multiple of the same move are legal to apply in a row according to Deafult.Legal()
                    * DefaultComponent - Looks at each component in SourceStack() and sees which one's method of Legal() returns nil, selecting that component for you to operate on in your own Apply.
                    * ActivateInactivePlayer - Activates any players who are not currently active
                    * ApplyUntil - Legal() returns nil only once ConditionMet() returns nil.
                        * ApplyUntilCount - Supplies a ConditionMet that returns true when Count() is the same as TargetCount().
                            * ApplyCountTimes - Supplies a Count() that is the number of times this move has been applied in a row.
                                * MoveCountComponents - Moves components from SourceStack to DestinationStack until TargetCount have been moved.
                                    * MoveComponentsUntilCountReached - Overrides Count to be how many components are in DestinatinoStack
                                    * MoveComponentsUntilCountLeft - Overrides Count to be how many components are left in SourceStack
                                        * MoveAllComponents - Overrides TargetCount to be 0
                        * RoundRobin - Applies around and aroudn for each player until PlayerConditionMet returns true for all. You must embed RoundRobinGameStateProperties in your GameState, as all of these moves store state in properties.
                            * RoundRobinNumRounds - Also checks that no more than NumRounds() around have happened
                                * DealCountComponents - Moves a component from GameStack to PlayerSTack() one at a time until each player has been dealt TargetCount() components.
                                    * DealComponentsUntilPlayerCountReached - Instead of a fixed number, done when every player has TargetCount or more components in PlayerStack.
                                        * CollectComponentsUntilPlayerCountReached - Flip so that the components move from PlayerStack to GameStack.
                                            * CollectComponentsUntilPlayerCountLeft - Flips it so the TargetCount is when each PlayerStack has that many items or fewer.
                                                *CollectAllComponents - Overrides TargetCount to 0, colleting all components.
                                        * CollectComponentsUntilPlayerCountLeft - Flip movement to be from PlayerStack to GameStack, and flip TargetCount to be when all PlayerStack have TargetCount or less.
                                    * DealComponentsUntilGameCountLeft - Instead of a fixed number, done when GameStack's count is TargetCount or less.
                                        * DealAllComponents - Overrides TargetCount to be 0
                                        * CollectComponentsUntilGameCountLeft - Flips move so it's from PlayerStack to GameStack
                                    * CollectCountComponents - Flips so components move from PlayerStacks to GameStack

Move Deal and Collect Component Moves

Generally when moving components from one place to another it makes sense to
move one component at a time, so that each component is animated separately.
However, this is a pain to implement, because it requires implementing a move
that knows how many times to apply itself in a row, which is fincky and error-
prone.

There is a collection of 9 moves that all do basically the same thing for moving
components, one at a time, from stack to stack. Move-type moves move components
between two specific stacks, often both on your GameState. Deal and Collect type
moves move components between a stack in GameState and a stack in each Player's
PlayerState. Deal-type moves move components from the game stack to the player
stack, and Collect-type moves move components from each player to the GameState.

All of these moves define a way to define the source and destination stack. For
Move-type moves, you define SourceStack() and DestinationStack(). For Deal and
Collect-type moves, you implement GameStack() and PlayerStack().

All moves in this collection implement TargetCount() int, and all of them
default to 1. Override this if you want a different number of components checked
for in the end condition.

In practice you'll often use WithTargetCount, WithGameProperty, and friends as
configuration to AutoConfigurer.Config instead of overriding those yourself. In
fact, in many cases configuartion options are powerful enough to allow you to
use these moves types on their own directly in your game. See the documentation
in the sections above for more examples.

Each of Move, Deal, and Collect have three variants based on the end condition.
Note that Move-type moves have only two stacks, but Deal and Collect type moves
operate on n pairs of stacks, where n is the number of players in the game. In
general for Deal and Collect type moves, the condition is met when all pairs of
stacks meet the end condition.

{Move,Deal,Collect}CountComponents simply apply that many moves without regard
to the number of components in the source or destination stacks. Move names that
end in CountReached operate until the destination stacks all have TargetCount or
more items. Move names that end in CountLeft operate until the source stacks all
have TargetCount or fewer items in them.

Since a common configuration of these moves is to use
{Move,Deal,Collect}ComponentsUntil*Reached with a TargetCount of 0, each also
provides a *AllComponents as sugar.

Groups

Groups allow you to specify a specific set of moves that must occur in a given
order. You pass them to AddOrderedForPhase. All of the groups are of type
MoveProgressionGroup, and this package defines 5: Serial, Parallel,
ParallelCount, Repeat, and Optional. They can be nested as often as you'd like
to express the semantics of your move progression.

They are defined as functions that return anonymous underlying structs so that
when used in configuration you can avoid needing to wrap your children list with
[]MoveProgressionGroup, saving you typing.

    //Example

    //AddOrderedForPhase accepts move configs from auto.Config, or
    //groups.
    moves.AddOrderedForPhase(PhaseNormal,
        //Top level groups are all joined implicitly into a group.Serial.
        auto.MustConfig(new(MoveZero)),
        moves.Serial(
            auto.MustConfig(new(MoveOne)),
            moves.Optional(
                moves.Serial(
                    auto.MustConfig(new(MoveTwo)),
                    auto.MustConfig(new(MoveThree)),
                ),
            ),
            moves.ParallelCount(
                CountAny(),
                auto.MustConfig(new(MoveFour)),
                auto.MustConfig(new(MoveFive)),
                moves.Repeat(
                    CountAtMost(2),
                    moves.Serial(
                        auto.MustConfig(new(MoveSix)),
                        auto.MustConfig(new(MoveSeven)),
                    ),
                ),
            ),
        ),
    )

Move names must be unique, but sometimes you want to use the same underlying
move at multiple points in a progression. WithMoveNameSuffix is useful for that
case.
*/
package moves
<commit_msg>Added moves.SeatPlayer to the overview of all move types in package doc. Part of #755.<commit_after>/*

Package moves is a convenience package that implements composable Moves to make
it easy to implement common logic. The Base move type is a very simple move that
implements the basic stubs necessary for your straightforward moves to have
minimal boilerplate. Although it's technically optional, a lot of the magic
features throughout the framework depend on some if its base logic, so it's
recommended to always embed it anonymously in your move struct (or embed a
struct that embeds it).

You interact with and configure various move types by implementing interfaces.
Those interfaes are defined in the interfaces subpackage, to make this package's
design more clear.

There are many move types defined. Some are designed to be used directly with
minimal modification; others are powerful move types that are designed to be
sub-classed.

Automatic MoveConfig Generation

Creating MoveConfig's is a necessary part of installing moves on your
GameManager, but it's verbose and error-prone. You need to create a lot of extra
structs, and then remember to provide the right properties in your config. And
to use many of the powerful moves in the moves package, you need to write a lot
of boilerplate methods to integrate correctly. Finally, you end up repeating
yourself often--which makes it a pain if you change the name of a move.

Take this example:

    //boardgame:codegen
    type MoveDealInitialCards struct {
        moves.DealComponentsUntilPlayerCountReached
    }

    var moveDealInitialCardsConfig = boardgame.MoveConfig {
        Name: "Deal Initial Cards",
        Constructor: func() boardgame.Move {
            return new(MoveDealInitialCards)
        },
    }

    func (m *MoveDealInitialCards) GameStack(gState boardgame.MutableSubState) boardgame.MutableStack {
        return gState.(*gameState).DrawStack
    }

    func (m *MoveDealInitialCards) PlayerStack(pState boardgame.MutablePlayerState) boardgame.MutableStack {
        return pState.(*playerState).Hand
    }

    func (m *MoveDealInitialCards) TargetCount() int {
        return 2
    }

    func (g *gameDelegate) ConfigureMoves() []boardgame.MoveConfig {
        return moves.Add(
            &moveDealInitialCardsConfig,
        )
    }

auto.Config (and its panic-y sibling auto.MustConfig) help reduce this
signficantly:

    func (g *gameDelegate) ConfigureMoves() []boardgame.MoveConfig {

        auto := moves.NewAutoConfigurer(g)

        return moves.Add(
            auto.MustConfig(
                new(moves.DealComponentsUntilPlayerCountReached),
                moves.WithGameProperty("DrawStack"),
                moves.WithPlayerProperty("Hand"),
                moves.WithTargetCount(2),
            )
        )
    }

Basic Usage

AutoConfigurer takes an example struct representing your move, and then a list
of 0 to n interfaces.CustomConfigurationOption. These options are given a
boardgame.PropertyCollection and then add specific properties to it, and then
stash that on the CustomConfiguration property of the returned MoveTypeConfig.
Different move methods will then reach into that configuration to alter the
behavior of moves of that type.

The moves/with package defines a large collection of CustomConfigurationOption
for use with the moves in the moves package.

Moves that are used with AutoConfigurer must satisfy the AutoConfigurableMove
interface, which adds one method: DeriveName() string. AutoConfigurer.Config()
primarily consists of some set up and then using those return values as fields
on the returned MoveConfig. These methods are implemented in moves.Default,
which means that any move structs that embed moves.Default (directly or
indirectly) can be used with AutoConfigurer.

moves.Default does a fair bit of magic in these methods to implement much of the
logic of AutoConfigurer. In general, if you pass a configuration option (via
WithMoveName, for example) then that option will be used for that method.
moves.Default.DeriveName() also will use reflection to automatically set a
struct name like "MoveDealInitialCards" to "Deal Initial Cards". All of the
moves in the moves package will also automatically return reasonable names for
DeriveName(), so in many cases you can use those structs directly without having
to pass WithMoveName().

Other moves in the moves package, like DealCountComponents, will use
configuration, like WithGameProperty(), to power their default GameStack()
method.

All moves in the moves package are designed to return an error from
ValidConfiguration(), which means that if you forgot to pass a required
configuration property (e.g. you don't override GameStack and also don't provide
WithGameProperty), when you try to create NewGameManager() and all moves'
ValidConfiguration() is checked, you'll get an error. This helps catch
mis-configurations during boot time.

Refer to the documentation of the various methods in that package for their
precise behavior and how to configure them.

Idiomatic Move Definition and Installation

AutoConfigurer is at the core of idiomatic definition and installation of moves,
and typically is used for every move you install in your game. The following
paragraphs describe the high-level idioms to follow.

Never create your own MoveConfig objects--it's just another global variable that
clutters up your code and makes it harder to change. Instead, use
AutoConfigurer. There are some rare cases where you do want to refer to the move
by name (and not rely on finicky string-based lookup), such as when you want an
Agent to propose a speciifc type of move. In those cases use AutoConfigurer to
create the move type config, then save the resulting config's Name to a global
variable that you use elsewhere, and then pass the created config to moves.Add()
(and its cousins)

In general, you should only create a bespoke Move struct in your game if it is
not possible to use one of the off-the-shelf moves from the moves package,
combined with configuarion options, to do what you want. In practice this means
that only if you need to override a method on one of the base moves do you need
to create a bespoke struct. This typically allows you to drastically reduce the
number of bespoke move structs your game defines, saving thousands of lines of
code (each bespoke struct also has hundreds of lines of auto-generated
PropertyReader code).

If you do create a bespoke struct, name it like this: "MoveNameOfMyMove", so
that moves.Default's default DeriveName() will give it a reasonable name
automatically (in this example, "Name Of My Move").

In many cases if you subclass powerful moves like DealCountComponents the
default HelpText() value is sufficient (especially if it's a FixUp move that
won't ever be seen by players). In other cases, WithHelpText() is often the only
config option you will pass to AutoConfigurer.

If your move will be a FixUp move that doesn't sublcass one of the more advanced
fix up moves (like RoundRobin or DealCountComponents), embed moves.FixUp into
your struct. That will cause IsFixUp to return the right value even without
using WithIsFixUp--because WithIsFixUp is easy to forget given that it's often
in a different file. In almost all cases if you use WithIsFixUp you should
simply embed moves.FixUp instead.

AutoConfigurer.MustConfig is like AutoConfigurer.Config, but instead of
returning a MoveConfig and an error, it simply returns a MoveConfig--and panics
if it would have returned an error. Since your GameDelegate's ConfigureMoves()
is typically called during the boot-up sequence of your game, it is safe to use
AutoConfigurer.MustConfig exclusively, which saves many lines of boilerplate
error checking.

Configure Move Helpers

Your Game Delegate's ConfigureMoves() []boardgame.MoveConfig is where the action
happens for installing moves. In practice you can do whatever you want in there
as long as you return a list of MoveConfigs. In practice you often use
AutoConfigurer (see section above). If you have a very simple game type you
might not need to do anythign special.

If, however, your game type is complicated enough to need the notion of phases,
then you'll probably want to use some of the convenience methods for installing
moves: Combine, Add, AddForPhase, and AddOrderedForPhase. These methods make
sure that enough information is stored for the Legal() methods of those moves to
know when the move is legal. Technically they're just convenience wrappers (each
describes the straightforward things it's doing), but in practice they're the
best way to do it. See the tutorial in the main package for more.

Move Type Hierarchy

The moves in this package are all defined as a hierarchy of structs that
anonymously embed higher level structs, overriding, modifying, and extending the
behavior of the struct they embed.

You can use many of these moves directly, using the configuration options like
WithSourceProperty() to configure which properties they should operate on.
Alternatively, you can embed them in your own move struct, overriding or
tweaking their behavior, perhaps adding an additional check to their Legal
check.

For convenience, here's the type hierarchy, with a brief description of the diff
each has on the one above it. See the documentation for each struct for more.

    * base.Move - The simplest, unopinonated stub of a move, from the base package.
        * Default - Substantial base logic, including base property overriding for with and especially in Legal() around move progressions and phases.
            * Done - A simple move that does nothing in its Apply and has no extra Legal() logic, meaning it's primarily a non-fix-up move applied by a player to move out of a move progression.
            * CurrentPlayer - Defaults to the GameDelegate.CurrentPlayerIndex, and only lets the move be made if it's on behalf of that player.
            * SeatPlayer - A special move that the server package uses to tell the game logic that a new player has been added to the game.
            * FixUp - Overrides IsFixUp() to always return true, making the move eligible for base.GameDelegate.ProposeFixUpMove.
                * NoOp - A move that does nothing. Useful for specific edge cases of MoveProessionMatching, and also to signal to AddOrderedForPhase that the lack of a StartPhase move was intentional.
                * Increment - Increments the provided SourceProperty by Amount. Useful to run automatically at a given spot in a move progression.
                * ShuffleStack - Shuffles the stack at SourceProperty. Useful to run automatically at a certain time in a MoveProgression.
                * StartPhase - Calls BeforeLeavePhase, then BeforeEnterPhase, then SetCurrentPhase. Generally you have one of these at the end of an AddOrderedForPhase.
                * FinishTurn - Checks if State.CurrentPlayer().TurnDone() is true, and if so increments CurrentPlayerIndex to the next player, calling playerState.ResetForTurnEnd() and then ResetForTurnStart.
                * FixUpMulti - Overrides AllowMultipleInProgression() to true, meaning multiple of the same move are legal to apply in a row according to Deafult.Legal()
                    * DefaultComponent - Looks at each component in SourceStack() and sees which one's method of Legal() returns nil, selecting that component for you to operate on in your own Apply.
                    * ActivateInactivePlayer - Activates any players who are not currently active
                    * ApplyUntil - Legal() returns nil only once ConditionMet() returns nil.
                        * ApplyUntilCount - Supplies a ConditionMet that returns true when Count() is the same as TargetCount().
                            * ApplyCountTimes - Supplies a Count() that is the number of times this move has been applied in a row.
                                * MoveCountComponents - Moves components from SourceStack to DestinationStack until TargetCount have been moved.
                                    * MoveComponentsUntilCountReached - Overrides Count to be how many components are in DestinatinoStack
                                    * MoveComponentsUntilCountLeft - Overrides Count to be how many components are left in SourceStack
                                        * MoveAllComponents - Overrides TargetCount to be 0
                        * RoundRobin - Applies around and aroudn for each player until PlayerConditionMet returns true for all. You must embed RoundRobinGameStateProperties in your GameState, as all of these moves store state in properties.
                            * RoundRobinNumRounds - Also checks that no more than NumRounds() around have happened
                                * DealCountComponents - Moves a component from GameStack to PlayerSTack() one at a time until each player has been dealt TargetCount() components.
                                    * DealComponentsUntilPlayerCountReached - Instead of a fixed number, done when every player has TargetCount or more components in PlayerStack.
                                        * CollectComponentsUntilPlayerCountReached - Flip so that the components move from PlayerStack to GameStack.
                                            * CollectComponentsUntilPlayerCountLeft - Flips it so the TargetCount is when each PlayerStack has that many items or fewer.
                                                *CollectAllComponents - Overrides TargetCount to 0, colleting all components.
                                        * CollectComponentsUntilPlayerCountLeft - Flip movement to be from PlayerStack to GameStack, and flip TargetCount to be when all PlayerStack have TargetCount or less.
                                    * DealComponentsUntilGameCountLeft - Instead of a fixed number, done when GameStack's count is TargetCount or less.
                                        * DealAllComponents - Overrides TargetCount to be 0
                                        * CollectComponentsUntilGameCountLeft - Flips move so it's from PlayerStack to GameStack
                                    * CollectCountComponents - Flips so components move from PlayerStacks to GameStack

Move Deal and Collect Component Moves

Generally when moving components from one place to another it makes sense to
move one component at a time, so that each component is animated separately.
However, this is a pain to implement, because it requires implementing a move
that knows how many times to apply itself in a row, which is fincky and error-
prone.

There is a collection of 9 moves that all do basically the same thing for moving
components, one at a time, from stack to stack. Move-type moves move components
between two specific stacks, often both on your GameState. Deal and Collect type
moves move components between a stack in GameState and a stack in each Player's
PlayerState. Deal-type moves move components from the game stack to the player
stack, and Collect-type moves move components from each player to the GameState.

All of these moves define a way to define the source and destination stack. For
Move-type moves, you define SourceStack() and DestinationStack(). For Deal and
Collect-type moves, you implement GameStack() and PlayerStack().

All moves in this collection implement TargetCount() int, and all of them
default to 1. Override this if you want a different number of components checked
for in the end condition.

In practice you'll often use WithTargetCount, WithGameProperty, and friends as
configuration to AutoConfigurer.Config instead of overriding those yourself. In
fact, in many cases configuartion options are powerful enough to allow you to
use these moves types on their own directly in your game. See the documentation
in the sections above for more examples.

Each of Move, Deal, and Collect have three variants based on the end condition.
Note that Move-type moves have only two stacks, but Deal and Collect type moves
operate on n pairs of stacks, where n is the number of players in the game. In
general for Deal and Collect type moves, the condition is met when all pairs of
stacks meet the end condition.

{Move,Deal,Collect}CountComponents simply apply that many moves without regard
to the number of components in the source or destination stacks. Move names that
end in CountReached operate until the destination stacks all have TargetCount or
more items. Move names that end in CountLeft operate until the source stacks all
have TargetCount or fewer items in them.

Since a common configuration of these moves is to use
{Move,Deal,Collect}ComponentsUntil*Reached with a TargetCount of 0, each also
provides a *AllComponents as sugar.

Groups

Groups allow you to specify a specific set of moves that must occur in a given
order. You pass them to AddOrderedForPhase. All of the groups are of type
MoveProgressionGroup, and this package defines 5: Serial, Parallel,
ParallelCount, Repeat, and Optional. They can be nested as often as you'd like
to express the semantics of your move progression.

They are defined as functions that return anonymous underlying structs so that
when used in configuration you can avoid needing to wrap your children list with
[]MoveProgressionGroup, saving you typing.

    //Example

    //AddOrderedForPhase accepts move configs from auto.Config, or
    //groups.
    moves.AddOrderedForPhase(PhaseNormal,
        //Top level groups are all joined implicitly into a group.Serial.
        auto.MustConfig(new(MoveZero)),
        moves.Serial(
            auto.MustConfig(new(MoveOne)),
            moves.Optional(
                moves.Serial(
                    auto.MustConfig(new(MoveTwo)),
                    auto.MustConfig(new(MoveThree)),
                ),
            ),
            moves.ParallelCount(
                CountAny(),
                auto.MustConfig(new(MoveFour)),
                auto.MustConfig(new(MoveFive)),
                moves.Repeat(
                    CountAtMost(2),
                    moves.Serial(
                        auto.MustConfig(new(MoveSix)),
                        auto.MustConfig(new(MoveSeven)),
                    ),
                ),
            ),
        ),
    )

Move names must be unique, but sometimes you want to use the same underlying
move at multiple points in a progression. WithMoveNameSuffix is useful for that
case.
*/
package moves
<|endoftext|>


<commit_before>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gvisor provides support for gVisor, user-space kernel, testing.
// See https://github.com/google/gvisor
package gvisor

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/vm/vmimpl"
)

func init() {
	vmimpl.Register("gvisor", ctor)
}

type Config struct {
	Count     int    `json:"count"` // number of VMs to use
	RunscArgs string `json:"runsc_args"`
}

type Pool struct {
	env *vmimpl.Env
	cfg *Config
}

type instance struct {
	cfg      *Config
	image    string
	debug    bool
	rootDir  string
	imageDir string
	name     string
	port     int
	cmd      *exec.Cmd
	merger   *vmimpl.OutputMerger
}

func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
	cfg := &Config{
		Count: 1,
	}
	if err := config.LoadData(env.Config, cfg); err != nil {
		return nil, fmt.Errorf("failed to parse vm config: %v", err)
	}
	if cfg.Count < 1 || cfg.Count > 1000 {
		return nil, fmt.Errorf("invalid config param count: %v, want [1, 1000]", cfg.Count)
	}
	if env.Debug {
		cfg.Count = 1
	}
	if !osutil.IsExist(env.Image) {
		return nil, fmt.Errorf("image file %q does not exist", env.Image)
	}
	pool := &Pool{
		cfg: cfg,
		env: env,
	}
	return pool, nil
}

func (pool *Pool) Count() int {
	return pool.cfg.Count
}

func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
	rootDir := filepath.Clean(filepath.Join(workdir, "..", "gvisor_root"))
	imageDir := filepath.Join(workdir, "image")
	bundleDir := filepath.Join(workdir, "bundle")
	osutil.MkdirAll(rootDir)
	osutil.MkdirAll(bundleDir)
	osutil.MkdirAll(imageDir)

	caps := ""
	for _, c := range sandboxCaps {
		if caps != "" {
			caps += ", "
		}
		caps += "\"" + c + "\""
	}
	vmConfig := fmt.Sprintf(configTempl, imageDir, caps)
	if err := osutil.WriteFile(filepath.Join(bundleDir, "config.json"), []byte(vmConfig)); err != nil {
		return nil, err
	}
	if err := osutil.CopyFile(os.Args[0], filepath.Join(imageDir, "init")); err != nil {
		return nil, err
	}

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, err
	}
	var tee io.Writer
	if pool.env.Debug {
		tee = os.Stdout
	}
	merger := vmimpl.NewOutputMerger(tee)
	merger.Add("gvisor", rpipe)

	inst := &instance{
		cfg:      pool.cfg,
		image:    pool.env.Image,
		debug:    pool.env.Debug,
		rootDir:  rootDir,
		imageDir: imageDir,
		name:     fmt.Sprintf("%v-%v", pool.env.Name, index),
		merger:   merger,
	}

	// Kill the previous instance in case it's still running.
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)

	cmd := inst.runscCmd("run", "-bundle", bundleDir, inst.name)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe
	if err := cmd.Start(); err != nil {
		wpipe.Close()
		merger.Wait()
		return nil, err
	}
	inst.cmd = cmd
	wpipe.Close()

	if err := inst.waitBoot(); err != nil {
		inst.Close()
		return nil, err
	}
	return inst, nil
}

func (inst *instance) waitBoot() error {
	errorMsg := []byte("FATAL ERROR:")
	bootedMsg := []byte(initStartMsg)
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	var output []byte
	for {
		select {
		case out := <-inst.merger.Output:
			output = append(output, out...)
			if pos := bytes.Index(output, errorMsg); pos != -1 {
				end := bytes.IndexByte(output[pos:], '\n')
				if end == -1 {
					end = len(output)
				} else {
					end += pos
				}
				return vmimpl.BootError{
					Title:  string(output[pos:end]),
					Output: output,
				}
			}
			if bytes.Contains(output, bootedMsg) {
				return nil
			}
		case err := <-inst.merger.Err:
			return vmimpl.BootError{
				Title:  fmt.Sprintf("runsc failed: %v", err),
				Output: output,
			}
		case <-timeout.C:
			return vmimpl.BootError{
				Title:  "init process did not start",
				Output: output,
			}
		}
	}
}

func (inst *instance) runscCmd(add ...string) *exec.Cmd {
	args := []string{
		"-root", inst.rootDir,
		"-watchdog-action=panic",
		"-network=none",
	}
	if inst.cfg.RunscArgs != "" {
		args = append(args, strings.Split(inst.cfg.RunscArgs, " ")...)
	}
	args = append(args, add...)
	cmd := osutil.Command(inst.image, args...)
	cmd.Env = []string{
		"GOTRACEBACK=all",
		"GORACE=halt_on_error=1",
	}
	return cmd
}

func (inst *instance) Close() {
	time.Sleep(3 * time.Second)
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	inst.cmd.Process.Kill()
	inst.merger.Wait()
	inst.cmd.Wait()
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)
}

func (inst *instance) Forward(port int) (string, error) {
	if inst.port != 0 {
		return "", fmt.Errorf("forward port is already setup")
	}
	inst.port = port
	return "stdin", nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	fname := filepath.Base(hostSrc)
	if err := osutil.CopyFile(hostSrc, filepath.Join(inst.imageDir, fname)); err != nil {
		return "", err
	}
	if err := os.Chmod(inst.imageDir, 0777); err != nil {
		return "", err
	}
	return filepath.Join("/", fname), nil
}

func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (
	<-chan []byte, <-chan error, error) {
	args := []string{"exec", "-user=0:0"}
	for _, c := range sandboxCaps {
		args = append(args, "-cap", c)
	}
	args = append(args, inst.name)
	args = append(args, strings.Split(command, " ")...)
	cmd := inst.runscCmd(args...)

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, nil, err
	}
	defer wpipe.Close()
	inst.merger.Add("cmd", rpipe)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe

	guestSock, err := inst.guestProxy()
	if err != nil {
		return nil, nil, err
	}
	if guestSock != nil {
		defer guestSock.Close()
		cmd.Stdin = guestSock
	}

	if err := cmd.Start(); err != nil {
		return nil, nil, err
	}
	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vmimpl.ErrTimeout)
		case <-stop:
			signal(vmimpl.ErrTimeout)
		case err := <-inst.merger.Err:
			cmd.Process.Kill()
			if cmdErr := cmd.Wait(); cmdErr == nil {
				// If the command exited successfully, we got EOF error from merger.
				// But in this case no error has happened and the EOF is expected.
				err = nil
			}
			signal(err)
			return
		}
		cmd.Process.Kill()
		cmd.Wait()
	}()
	return inst.merger.Output, errc, nil
}

func (inst *instance) guestProxy() (*os.File, error) {
	if inst.port == 0 {
		return nil, nil
	}
	// One does not simply let gvisor guest connect to host tcp port.
	// We create a unix socket, pass it to guest in stdin.
	// Guest will use it instead of dialing manager directly.
	// On host we connect to manager tcp port and proxy between the tcp and unix connections.
	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, err
	}
	hostSock := os.NewFile(uintptr(socks[0]), "host unix proxy")
	guestSock := os.NewFile(uintptr(socks[1]), "guest unix proxy")
	conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%v", inst.port))
	if err != nil {
		conn.Close()
		hostSock.Close()
		guestSock.Close()
		return nil, err
	}
	go func() {
		io.Copy(hostSock, conn)
		hostSock.Close()
	}()
	go func() {
		io.Copy(conn, hostSock)
		conn.Close()
	}()
	return guestSock, nil
}

func (inst *instance) Diagnose() bool {
	osutil.Run(time.Minute, inst.runscCmd("debug", "-stacks", inst.name))
	return true
}

func init() {
	if os.Getenv("SYZ_GVISOR_PROXY") != "" {
		fmt.Fprintf(os.Stderr, initStartMsg)
		select {}
	}
}

const initStartMsg = "SYZKALLER INIT STARTED\n"

const configTempl = `
{
	"root": {
		"path": "%[1]v",
		"readonly": true
	},
	"process":{
                "args": ["/init"],
                "cwd": "/tmp",
                "env": ["SYZ_GVISOR_PROXY=1"],
                "capabilities": {
                	"bounding": [%[2]v],
                	"effective": [%[2]v],
                	"inheritable": [%[2]v],
                	"permitted": [%[2]v],
                	"ambient": [%[2]v]
                }
	}
}
`

var sandboxCaps = []string{
	"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID",
	"CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE",
	"CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW",
	"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT",
	"CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE",
	"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE",
	"CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN",
	"CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ",
}
<commit_msg>vm/gvisor: fix current binary lookup<commit_after>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gvisor provides support for gVisor, user-space kernel, testing.
// See https://github.com/google/gvisor
package gvisor

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/vm/vmimpl"
)

func init() {
	vmimpl.Register("gvisor", ctor)
}

type Config struct {
	Count     int    `json:"count"` // number of VMs to use
	RunscArgs string `json:"runsc_args"`
}

type Pool struct {
	env *vmimpl.Env
	cfg *Config
}

type instance struct {
	cfg      *Config
	image    string
	debug    bool
	rootDir  string
	imageDir string
	name     string
	port     int
	cmd      *exec.Cmd
	merger   *vmimpl.OutputMerger
}

func ctor(env *vmimpl.Env) (vmimpl.Pool, error) {
	cfg := &Config{
		Count: 1,
	}
	if err := config.LoadData(env.Config, cfg); err != nil {
		return nil, fmt.Errorf("failed to parse vm config: %v", err)
	}
	if cfg.Count < 1 || cfg.Count > 1000 {
		return nil, fmt.Errorf("invalid config param count: %v, want [1, 1000]", cfg.Count)
	}
	if env.Debug {
		cfg.Count = 1
	}
	if !osutil.IsExist(env.Image) {
		return nil, fmt.Errorf("image file %q does not exist", env.Image)
	}
	pool := &Pool{
		cfg: cfg,
		env: env,
	}
	return pool, nil
}

func (pool *Pool) Count() int {
	return pool.cfg.Count
}

func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) {
	rootDir := filepath.Clean(filepath.Join(workdir, "..", "gvisor_root"))
	imageDir := filepath.Join(workdir, "image")
	bundleDir := filepath.Join(workdir, "bundle")
	osutil.MkdirAll(rootDir)
	osutil.MkdirAll(bundleDir)
	osutil.MkdirAll(imageDir)

	caps := ""
	for _, c := range sandboxCaps {
		if caps != "" {
			caps += ", "
		}
		caps += "\"" + c + "\""
	}
	vmConfig := fmt.Sprintf(configTempl, imageDir, caps)
	if err := osutil.WriteFile(filepath.Join(bundleDir, "config.json"), []byte(vmConfig)); err != nil {
		return nil, err
	}
	bin, err := exec.LookPath(os.Args[0])
	if err != nil {
		return nil, fmt.Errorf("failed to lookup %v: %v", os.Args[0], err)
	}
	if err := osutil.CopyFile(bin, filepath.Join(imageDir, "init")); err != nil {
		return nil, err
	}

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, err
	}
	var tee io.Writer
	if pool.env.Debug {
		tee = os.Stdout
	}
	merger := vmimpl.NewOutputMerger(tee)
	merger.Add("gvisor", rpipe)

	inst := &instance{
		cfg:      pool.cfg,
		image:    pool.env.Image,
		debug:    pool.env.Debug,
		rootDir:  rootDir,
		imageDir: imageDir,
		name:     fmt.Sprintf("%v-%v", pool.env.Name, index),
		merger:   merger,
	}

	// Kill the previous instance in case it's still running.
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)

	cmd := inst.runscCmd("run", "-bundle", bundleDir, inst.name)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe
	if err := cmd.Start(); err != nil {
		wpipe.Close()
		merger.Wait()
		return nil, err
	}
	inst.cmd = cmd
	wpipe.Close()

	if err := inst.waitBoot(); err != nil {
		inst.Close()
		return nil, err
	}
	return inst, nil
}

func (inst *instance) waitBoot() error {
	errorMsg := []byte("FATAL ERROR:")
	bootedMsg := []byte(initStartMsg)
	timeout := time.NewTimer(time.Minute)
	defer timeout.Stop()
	var output []byte
	for {
		select {
		case out := <-inst.merger.Output:
			output = append(output, out...)
			if pos := bytes.Index(output, errorMsg); pos != -1 {
				end := bytes.IndexByte(output[pos:], '\n')
				if end == -1 {
					end = len(output)
				} else {
					end += pos
				}
				return vmimpl.BootError{
					Title:  string(output[pos:end]),
					Output: output,
				}
			}
			if bytes.Contains(output, bootedMsg) {
				return nil
			}
		case err := <-inst.merger.Err:
			return vmimpl.BootError{
				Title:  fmt.Sprintf("runsc failed: %v", err),
				Output: output,
			}
		case <-timeout.C:
			return vmimpl.BootError{
				Title:  "init process did not start",
				Output: output,
			}
		}
	}
}

func (inst *instance) runscCmd(add ...string) *exec.Cmd {
	args := []string{
		"-root", inst.rootDir,
		"-watchdog-action=panic",
		"-network=none",
	}
	if inst.cfg.RunscArgs != "" {
		args = append(args, strings.Split(inst.cfg.RunscArgs, " ")...)
	}
	args = append(args, add...)
	cmd := osutil.Command(inst.image, args...)
	cmd.Env = []string{
		"GOTRACEBACK=all",
		"GORACE=halt_on_error=1",
	}
	return cmd
}

func (inst *instance) Close() {
	time.Sleep(3 * time.Second)
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	inst.cmd.Process.Kill()
	inst.merger.Wait()
	inst.cmd.Wait()
	osutil.Run(time.Minute, inst.runscCmd("delete", "-force", inst.name))
	time.Sleep(3 * time.Second)
}

func (inst *instance) Forward(port int) (string, error) {
	if inst.port != 0 {
		return "", fmt.Errorf("forward port is already setup")
	}
	inst.port = port
	return "stdin", nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	fname := filepath.Base(hostSrc)
	if err := osutil.CopyFile(hostSrc, filepath.Join(inst.imageDir, fname)); err != nil {
		return "", err
	}
	if err := os.Chmod(inst.imageDir, 0777); err != nil {
		return "", err
	}
	return filepath.Join("/", fname), nil
}

func (inst *instance) Run(timeout time.Duration, stop <-chan bool, command string) (
	<-chan []byte, <-chan error, error) {
	args := []string{"exec", "-user=0:0"}
	for _, c := range sandboxCaps {
		args = append(args, "-cap", c)
	}
	args = append(args, inst.name)
	args = append(args, strings.Split(command, " ")...)
	cmd := inst.runscCmd(args...)

	rpipe, wpipe, err := osutil.LongPipe()
	if err != nil {
		return nil, nil, err
	}
	defer wpipe.Close()
	inst.merger.Add("cmd", rpipe)
	cmd.Stdout = wpipe
	cmd.Stderr = wpipe

	guestSock, err := inst.guestProxy()
	if err != nil {
		return nil, nil, err
	}
	if guestSock != nil {
		defer guestSock.Close()
		cmd.Stdin = guestSock
	}

	if err := cmd.Start(); err != nil {
		return nil, nil, err
	}
	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vmimpl.ErrTimeout)
		case <-stop:
			signal(vmimpl.ErrTimeout)
		case err := <-inst.merger.Err:
			cmd.Process.Kill()
			if cmdErr := cmd.Wait(); cmdErr == nil {
				// If the command exited successfully, we got EOF error from merger.
				// But in this case no error has happened and the EOF is expected.
				err = nil
			}
			signal(err)
			return
		}
		cmd.Process.Kill()
		cmd.Wait()
	}()
	return inst.merger.Output, errc, nil
}

func (inst *instance) guestProxy() (*os.File, error) {
	if inst.port == 0 {
		return nil, nil
	}
	// One does not simply let gvisor guest connect to host tcp port.
	// We create a unix socket, pass it to guest in stdin.
	// Guest will use it instead of dialing manager directly.
	// On host we connect to manager tcp port and proxy between the tcp and unix connections.
	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		return nil, err
	}
	hostSock := os.NewFile(uintptr(socks[0]), "host unix proxy")
	guestSock := os.NewFile(uintptr(socks[1]), "guest unix proxy")
	conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%v", inst.port))
	if err != nil {
		conn.Close()
		hostSock.Close()
		guestSock.Close()
		return nil, err
	}
	go func() {
		io.Copy(hostSock, conn)
		hostSock.Close()
	}()
	go func() {
		io.Copy(conn, hostSock)
		conn.Close()
	}()
	return guestSock, nil
}

func (inst *instance) Diagnose() bool {
	osutil.Run(time.Minute, inst.runscCmd("debug", "-stacks", inst.name))
	return true
}

func init() {
	if os.Getenv("SYZ_GVISOR_PROXY") != "" {
		fmt.Fprintf(os.Stderr, initStartMsg)
		select {}
	}
}

const initStartMsg = "SYZKALLER INIT STARTED\n"

const configTempl = `
{
	"root": {
		"path": "%[1]v",
		"readonly": true
	},
	"process":{
                "args": ["/init"],
                "cwd": "/tmp",
                "env": ["SYZ_GVISOR_PROXY=1"],
                "capabilities": {
                	"bounding": [%[2]v],
                	"effective": [%[2]v],
                	"inheritable": [%[2]v],
                	"permitted": [%[2]v],
                	"ambient": [%[2]v]
                }
	}
}
`

var sandboxCaps = []string{
	"CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID",
	"CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE",
	"CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW",
	"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT",
	"CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE",
	"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE",
	"CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN",
	"CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ",
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry Authors
//
// 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 otel // import "go.opentelemetry.io/otel"

import (
	"go.opentelemetry.io/otel/internal/global"
	"go.opentelemetry.io/otel/trace"
)

// Tracer creates a named tracer that implements Tracer interface.
// If the name is an empty string then provider uses default name.
//
// This is short for TracerProvider().Tracer(name)
func Tracer(name string) trace.Tracer {
	return GetTracerProvider().Tracer(name)
}

// TracerProvider returns the registered global trace provider.
// If none is registered then an instance of NoopTracerProvider is returned.
//
// Use the trace provider to create a named tracer. E.g.
//     tracer := global.GetTracerProvider().Tracer("example.com/foo")
// or
//     tracer := global.Tracer("example.com/foo")
func GetTracerProvider() trace.TracerProvider {
	return global.TracerProvider()
}

// SetTracerProvider registers `tp` as the global trace provider.
func SetTracerProvider(tp trace.TracerProvider) {
	global.SetTracerProvider(tp)
}
<commit_msg>Fix golint issue caused by typo in trace.go (#1436)<commit_after>// Copyright The OpenTelemetry Authors
//
// 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 otel // import "go.opentelemetry.io/otel"

import (
	"go.opentelemetry.io/otel/internal/global"
	"go.opentelemetry.io/otel/trace"
)

// Tracer creates a named tracer that implements Tracer interface.
// If the name is an empty string then provider uses default name.
//
// This is short for TracerProvider().Tracer(name)
func Tracer(name string) trace.Tracer {
	return GetTracerProvider().Tracer(name)
}

// GetTracerProvider returns the registered global trace provider.
// If none is registered then an instance of NoopTracerProvider is returned.
//
// Use the trace provider to create a named tracer. E.g.
//     tracer := global.GetTracerProvider().Tracer("example.com/foo")
// or
//     tracer := global.Tracer("example.com/foo")
func GetTracerProvider() trace.TracerProvider {
	return global.TracerProvider()
}

// SetTracerProvider registers `tp` as the global trace provider.
func SetTracerProvider(tp trace.TracerProvider) {
	global.SetTracerProvider(tp)
}
<|endoftext|>