<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 main

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

	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

var ballIndex []string

type Ball struct{
	Name string
	Color string
	Size int
	User string
}

func (t *SimpleChaincode) init(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var A, B string    																// Entities
	var Aval, Bval int 																// Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Run
// ============================================================================================================================
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	fmt.Println("run is running " + function)

	// Handle different functions
	if function == "init" {													// Initialize the entities and their asset holdings
		return t.init(stub, args)
	} else if function == "delete" {										// Deletes an entity from its state
		return t.Delete(stub, args)
	} else if function == "write" {											// Writes a value to the chaincode state
		return t.Write(stub, args)
	} else if function == "readnames" {										// Read all variable names in chaincode state
		return t.ReadNames(stub, args)
	} else if function == "init_ball" {										//init_ball
		return t.init_ball(stub, args)
	} else if function == "set_user" {										//set user permissions
		return t.set_user(stub, args)
	}
	fmt.Println("run issues " + function)

	return nil, errors.New("Received unknown function invocation")
}

// Deletes an entity from state
func (t *SimpleChaincode) Delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

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

// ============================================================================================================================
// Write var into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) Write(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var name, value string // Entities
	var err error
	fmt.Println("running write - start")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the variable and value to set")
	}

	name = args[0]
	value = args[1]

	// Write the state back to the ledger
	err = stub.PutState(name, []byte(value))
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, name)

	fmt.Println("running write - fin - for name " + name)
	return nil, nil
}

// ============================================================================================================================
// Read Names return list of variables in state space
// ============================================================================================================================
func (t *SimpleChaincode) ReadNames(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	var ben = "_ben_knows"
	var storedNames string

	storedNamesAsBytes, err := stub.GetState(ben)
	if err != nil {
		return nil, errors.New("Failed to get ben")
	}
	storedNames = string(storedNamesAsBytes)
	fmt.Println(storedNames)

	return storedNamesAsBytes, nil
}
// ============================================================================================================================
// Remember Me - remember the name of variables we stored in ledger
// ============================================================================================================================
func (t *SimpleChaincode) remember_me(stub *shim.ChaincodeStub, name string) ([]byte, error) {		//dsh - to do, should probably not exist here, move to stub
	var err error
	var ben = "_ben_knows"
	var storedNames string
	storeNamesAsBytes, err := stub.GetState(ben)
	if err != nil {
		return nil, errors.New("Failed to get ben")
	}
	storedNames = string(storeNamesAsBytes)
	// Write the state back to the ledger
	err = stub.PutState(ben, []byte(storedNames + "," + name))										//dsh - to do, should probably be json
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// ============================================================================================================================
// Init Person
// ============================================================================================================================
func (t *SimpleChaincode) init_ball(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	str := `{"name": "` + args[0] + `", "color": "` + args[1] + `", "size": "` + args[2] + `", "owner": "` + args[3] + `"}`

	// Write the state back to the ledger
	err = stub.PutState(args[0], []byte(str))							//store ball with id as key
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, args[0])

	ballIndex = append(ballIndex, args[0])								//add ball name to index list
	jsonAsBytes, _ := json.Marshal(ballIndex)
	err = stub.PutState("ballIndex", jsonAsBytes)						//store name of ball

	return nil, nil
}

// ============================================================================================================================
// Set User Permissions
// ============================================================================================================================
func (t *SimpleChaincode) set_user(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	ballAsBytes, err := stub.GetState(args[0])
	if err != nil {
		return nil, errors.New("Failed to get thing")
	}
	res := Ball{}
	json.Unmarshal(ballAsBytes, &res)
	fmt.Println(res)

	/*for i,perm := range res.Users{
		if perm.UserId == args[1]{							//find the correct user
			res.Users[i].Permissions[0] = args[2]			//set new perm, dsh - to do make this input as array of all perms
			fmt.Println(res.Users[i].Permissions)
			break
		}
	}*/
	res.User = args[1]

	// Write the state back to the ledger
	jsonAsBytes, _ := json.Marshal(res)
	err = stub.PutState(args[0], jsonAsBytes)
	if err != nil {
		return nil, err
	}

	return nil, nil
}<commit_msg>- added json fieldtags<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 main

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

	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

var ballIndex []string

type Ball struct{
	Name string `json:"name"`				//the fieldtags are needed to keep case from bouncing around
	Color string `json:"color"`
	Size int `json:"size"`
	User string `json:"user"`
}

func (t *SimpleChaincode) init(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var A, B string    																// Entities
	var Aval, Bval int 																// Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Run
// ============================================================================================================================
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	fmt.Println("run is running " + function)

	// Handle different functions
	if function == "init" {													// Initialize the entities and their asset holdings
		return t.init(stub, args)
	} else if function == "delete" {										// Deletes an entity from its state
		return t.Delete(stub, args)
	} else if function == "write" {											// Writes a value to the chaincode state
		return t.Write(stub, args)
	} else if function == "readnames" {										// Read all variable names in chaincode state
		return t.ReadNames(stub, args)
	} else if function == "init_ball" {										//init_ball
		return t.init_ball(stub, args)
	} else if function == "set_user" {										//set user permissions
		return t.set_user(stub, args)
	}
	fmt.Println("run issues " + function)

	return nil, errors.New("Received unknown function invocation")
}

// Deletes an entity from state
func (t *SimpleChaincode) Delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

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

// ============================================================================================================================
// Write var into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) Write(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var name, value string // Entities
	var err error
	fmt.Println("running write - start")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the variable and value to set")
	}

	name = args[0]
	value = args[1]

	// Write the state back to the ledger
	err = stub.PutState(name, []byte(value))
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, name)

	fmt.Println("running write - fin - for name " + name)
	return nil, nil
}

// ============================================================================================================================
// Read Names return list of variables in state space
// ============================================================================================================================
func (t *SimpleChaincode) ReadNames(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	var ben = "_ben_knows"
	var storedNames string

	storedNamesAsBytes, err := stub.GetState(ben)
	if err != nil {
		return nil, errors.New("Failed to get ben")
	}
	storedNames = string(storedNamesAsBytes)
	fmt.Println(storedNames)

	return storedNamesAsBytes, nil
}
// ============================================================================================================================
// Remember Me - remember the name of variables we stored in ledger
// ============================================================================================================================
func (t *SimpleChaincode) remember_me(stub *shim.ChaincodeStub, name string) ([]byte, error) {		//dsh - to do, should probably not exist here, move to stub
	var err error
	var ben = "_ben_knows"
	var storedNames string
	storeNamesAsBytes, err := stub.GetState(ben)
	if err != nil {
		return nil, errors.New("Failed to get ben")
	}
	storedNames = string(storeNamesAsBytes)
	// Write the state back to the ledger
	err = stub.PutState(ben, []byte(storedNames + "," + name))										//dsh - to do, should probably be json
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// ============================================================================================================================
// Init Person
// ============================================================================================================================
func (t *SimpleChaincode) init_ball(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	val, err := strconv.Atoi(args[2])
	if err != nil {
		val = 16
	}
	str := `{"name": "` + args[0] + `", "color": "` + args[1] + `", "size": "` + strconv.Itoa(val) + `", "user": "` + args[3] + `"}`

	// Write the state back to the ledger
	err = stub.PutState(args[0], []byte(str))							//store ball with id as key
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, args[0])

	ballIndex = append(ballIndex, args[0])								//add ball name to index list
	jsonAsBytes, _ := json.Marshal(ballIndex)
	err = stub.PutState("ballIndex", jsonAsBytes)						//store name of ball

	return nil, nil
}

// ============================================================================================================================
// Set User Permissions
// ============================================================================================================================
func (t *SimpleChaincode) set_user(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	ballAsBytes, err := stub.GetState(args[0])
	if err != nil {
		return nil, errors.New("Failed to get thing")
	}
	res := Ball{}
	json.Unmarshal(ballAsBytes, &res)
	fmt.Println(res)

	/*for i,perm := range res.Users{
		if perm.UserId == args[1]{							//find the correct user
			res.Users[i].Permissions[0] = args[2]			//set new perm, dsh - to do make this input as array of all perms
			fmt.Println(res.Users[i].Permissions)
			break
		}
	}*/
	res.User = args[1]

	// Write the state back to the ledger
	jsonAsBytes, _ := json.Marshal(res)
	err = stub.PutState(args[0], jsonAsBytes)
	if err != nil {
		return nil, err
	}

	return nil, nil
}<|endoftext|>


<commit_before>package buildbox

const (
  Version = "0.2-beta.3"
)
<commit_msg>Bumping version to 0.2-beta.4<commit_after>package buildbox

const (
  Version = "0.2-beta.4"
)
<|endoftext|>


<commit_before>package beaglebone

import (
	"github.com/hybridgroup/gobot"
	"strconv"
)

const Slots = "/sys/devices/bone_capemgr.*"
const Ocp = "/sys/devices/ocp.*"
const I2CLocation = "/dev/i2c-1"

var pins = map[string]int{
	"P8_3":  38,
	"P8_4":  39,
	"P8_5":  34,
	"P8_6":  35,
	"P8_7":  66,
	"P8_8":  67,
	"P8_9":  69,
	"P8_10": 68,
	"P8_11": 45,
	"P8_12": 44,
	"P8_13": 23,
	"P8_14": 26,
	"P8_15": 47,
	"P8_16": 46,
	"P8_17": 27,
	"P8_18": 65,
	"P8_19": 22,
	"P8_20": 63,
	"P8_21": 62,
	"P8_22": 37,
	"P8_23": 36,
	"P8_24": 33,
	"P8_25": 32,
	"P8_26": 61,
	"P8_27": 86,
	"P8_28": 88,
	"P8_29": 87,
	"P8_30": 89,
	"P8_31": 10,
	"P8_32": 11,
	"P8_33": 9,
	"P8_34": 81,
	"P8_35": 8,
	"P8_36": 80,
	"P8_37": 78,
	"P8_38": 79,
	"P8_39": 76,
	"P8_40": 77,
	"P8_41": 74,
	"P8_42": 75,
	"P8_43": 72,
	"P8_44": 73,
	"P8_45": 70,
	"P8_46": 71,
	"P9_11": 30,
	"P9_12": 60,
	"P9_13": 31,
	"P9_14": 50,
	"P9_15": 48,
	"P9_16": 51,
	"P9_17": 5,
	"P9_18": 4,
	"P9_19": 13,
	"P9_20": 12,
	"P9_21": 3,
	"P9_22": 2,
	"P9_23": 49,
	"P9_24": 15,
	"P9_25": 117,
	"P9_26": 14,
	"P9_27": 115,
	"P9_28": 113,
	"P9_29": 111,
	"P9_30": 112,
	"P9_31": 110,
}
var pwmPins = map[string]string{
	"P9_14": "P9_14",
	"P9_21": "P9_21",
	"P9_22": "P9_22",
	"P9_29": "P9_29",
	"P9_42": "P9_42",
	"P8_13": "P8_13",
	"P8_34": "P8_34",
	"P8_45": "P8_45",
	"P8_46": "P8_46",
}
var analogPins = map[string]string{
	"P9_39": "AIN0",
	"P9_40": "AIN1",
	"P9_37": "AIN2",
	"P9_38": "AIN3",
	"P9_33": "AIN4",
	"P8_36": "AIN5",
	"P8_35": "AIN6",
}

type BeagleboneAdaptor struct {
	gobot.Adaptor
	digitalPins []*digitalPin
	pwmPins     map[string]*pwmPin
	analogPins  map[string]*analogPin
	i2cDevice   *i2cDevice
}

func NewBeagleboneAdaptor(name string) *BeagleboneAdaptor {
	return &BeagleboneAdaptor{
		Adaptor: gobot.Adaptor{
			Name: name,
		},
	}
}

func (b *BeagleboneAdaptor) Connect() bool {
	b.digitalPins = make([]*digitalPin, 120)
	b.pwmPins = make(map[string]*pwmPin)
	b.analogPins = make(map[string]*analogPin)
	return true
}

func (b *BeagleboneAdaptor) Finalize() bool {
	for _, pin := range b.pwmPins {
		if pin != nil {
			pin.release()
		}
	}
	for _, pin := range b.digitalPins {
		if pin != nil {
			pin.close()
		}
	}
	if b.i2cDevice != nil {
		b.i2cDevice.i2cDevice.Close()
	}
	return true
}
func (b *BeagleboneAdaptor) Reconnect() bool  { return true }
func (b *BeagleboneAdaptor) Disconnect() bool { return true }

func (b *BeagleboneAdaptor) PwmWrite(pin string, val byte) {
	i := b.pwmPin(pin)
	period := 500000.0
	duty := gobot.FromScale(float64(^val), 0, 255.0)
	b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
}

func (b *BeagleboneAdaptor) InitServo() {}
func (b *BeagleboneAdaptor) ServoWrite(pin string, val byte) {
	i := b.pwmPin(pin)
	period := 20000000.0
	duty := gobot.FromScale(float64(^val), 0, 180.0)
	b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
}

func (b *BeagleboneAdaptor) DigitalWrite(pin string, val byte) {
	i := b.digitalPin(pin, "w")
	b.digitalPins[i].digitalWrite(strconv.Itoa(int(val)))
}

func (b *BeagleboneAdaptor) AnalogRead(pin string) int {
	i := b.analogPin(pin)
	return b.analogPins[i].analogRead()
}

func (b *BeagleboneAdaptor) I2cStart(address byte) {
	b.i2cDevice = newI2cDevice(I2CLocation, address)
	b.i2cDevice.start()
}

func (b *BeagleboneAdaptor) I2cWrite(data []byte) {
	b.i2cDevice.write(data)
}

func (b *BeagleboneAdaptor) I2cRead(size uint) []byte {
	return b.i2cDevice.read(size)
}

func (b *BeagleboneAdaptor) translatePin(pin string) int {
	for key, value := range pins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) translatePwmPin(pin string) string {
	for key, value := range pwmPins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) translateAnalogPin(pin string) string {
	for key, value := range analogPins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) analogPin(pin string) string {
	i := b.translateAnalogPin(pin)
	if b.analogPins[i] == nil {
		b.analogPins[i] = newAnalogPin(i)
	}
	return i
}

func (b *BeagleboneAdaptor) digitalPin(pin string, mode string) int {
	i := b.translatePin(pin)
	if b.digitalPins[i] == nil || b.digitalPins[i].Mode != mode {
		b.digitalPins[i] = newDigitalPin(i, mode)
	}
	return i
}

func (b *BeagleboneAdaptor) pwmPin(pin string) string {
	i := b.translatePwmPin(pin)
	if b.pwmPins[i] == nil {
		b.pwmPins[i] = newPwmPin(i)
	}
	return i
}
<commit_msg>Update beaglebone package<commit_after>package beaglebone

import (
	"github.com/hybridgroup/gobot"
	"strconv"
)

const Slots = "/sys/devices/bone_capemgr.*"
const Ocp = "/sys/devices/ocp.*"
const I2CLocation = "/dev/i2c-1"

var pins = map[string]int{
	"P8_3":  38,
	"P8_4":  39,
	"P8_5":  34,
	"P8_6":  35,
	"P8_7":  66,
	"P8_8":  67,
	"P8_9":  69,
	"P8_10": 68,
	"P8_11": 45,
	"P8_12": 44,
	"P8_13": 23,
	"P8_14": 26,
	"P8_15": 47,
	"P8_16": 46,
	"P8_17": 27,
	"P8_18": 65,
	"P8_19": 22,
	"P8_20": 63,
	"P8_21": 62,
	"P8_22": 37,
	"P8_23": 36,
	"P8_24": 33,
	"P8_25": 32,
	"P8_26": 61,
	"P8_27": 86,
	"P8_28": 88,
	"P8_29": 87,
	"P8_30": 89,
	"P8_31": 10,
	"P8_32": 11,
	"P8_33": 9,
	"P8_34": 81,
	"P8_35": 8,
	"P8_36": 80,
	"P8_37": 78,
	"P8_38": 79,
	"P8_39": 76,
	"P8_40": 77,
	"P8_41": 74,
	"P8_42": 75,
	"P8_43": 72,
	"P8_44": 73,
	"P8_45": 70,
	"P8_46": 71,
	"P9_11": 30,
	"P9_12": 60,
	"P9_13": 31,
	"P9_14": 50,
	"P9_15": 48,
	"P9_16": 51,
	"P9_17": 5,
	"P9_18": 4,
	"P9_19": 13,
	"P9_20": 12,
	"P9_21": 3,
	"P9_22": 2,
	"P9_23": 49,
	"P9_24": 15,
	"P9_25": 117,
	"P9_26": 14,
	"P9_27": 115,
	"P9_28": 113,
	"P9_29": 111,
	"P9_30": 112,
	"P9_31": 110,
}
var pwmPins = map[string]string{
	"P9_14": "P9_14",
	"P9_21": "P9_21",
	"P9_22": "P9_22",
	"P9_29": "P9_29",
	"P9_42": "P9_42",
	"P8_13": "P8_13",
	"P8_34": "P8_34",
	"P8_45": "P8_45",
	"P8_46": "P8_46",
}
var analogPins = map[string]string{
	"P9_39": "AIN0",
	"P9_40": "AIN1",
	"P9_37": "AIN2",
	"P9_38": "AIN3",
	"P9_33": "AIN4",
	"P8_36": "AIN5",
	"P8_35": "AIN6",
}

type BeagleboneAdaptor struct {
	gobot.Adaptor
	digitalPins []*digitalPin
	pwmPins     map[string]*pwmPin
	analogPins  map[string]*analogPin
	i2cDevice   *i2cDevice
}

func NewBeagleboneAdaptor(name string) *BeagleboneAdaptor {
	return &BeagleboneAdaptor{
		Adaptor: *gobot.NewAdaptor(
			name,
			"BeagleboneAdaptor",
		),
	}
}

func (b *BeagleboneAdaptor) Connect() bool {
	b.digitalPins = make([]*digitalPin, 120)
	b.pwmPins = make(map[string]*pwmPin)
	b.analogPins = make(map[string]*analogPin)
	return true
}

func (b *BeagleboneAdaptor) Finalize() bool {
	for _, pin := range b.pwmPins {
		if pin != nil {
			pin.release()
		}
	}
	for _, pin := range b.digitalPins {
		if pin != nil {
			pin.close()
		}
	}
	if b.i2cDevice != nil {
		b.i2cDevice.i2cDevice.Close()
	}
	return true
}
func (b *BeagleboneAdaptor) Reconnect() bool  { return true }
func (b *BeagleboneAdaptor) Disconnect() bool { return true }

func (b *BeagleboneAdaptor) PwmWrite(pin string, val byte) {
	i := b.pwmPin(pin)
	period := 500000.0
	duty := gobot.FromScale(float64(^val), 0, 255.0)
	b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
}

func (b *BeagleboneAdaptor) InitServo() {}
func (b *BeagleboneAdaptor) ServoWrite(pin string, val byte) {
	i := b.pwmPin(pin)
	period := 20000000.0
	duty := gobot.FromScale(float64(^val), 0, 180.0)
	b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
}

func (b *BeagleboneAdaptor) DigitalWrite(pin string, val byte) {
	i := b.digitalPin(pin, "w")
	b.digitalPins[i].digitalWrite(strconv.Itoa(int(val)))
}

func (b *BeagleboneAdaptor) AnalogRead(pin string) int {
	i := b.analogPin(pin)
	return b.analogPins[i].analogRead()
}

func (b *BeagleboneAdaptor) I2cStart(address byte) {
	b.i2cDevice = newI2cDevice(I2CLocation, address)
	b.i2cDevice.start()
}

func (b *BeagleboneAdaptor) I2cWrite(data []byte) {
	b.i2cDevice.write(data)
}

func (b *BeagleboneAdaptor) I2cRead(size uint) []byte {
	return b.i2cDevice.read(size)
}

func (b *BeagleboneAdaptor) translatePin(pin string) int {
	for key, value := range pins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) translatePwmPin(pin string) string {
	for key, value := range pwmPins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) translateAnalogPin(pin string) string {
	for key, value := range analogPins {
		if key == pin {
			return value
		}
	}
	panic("Not a valid pin")
}

func (b *BeagleboneAdaptor) analogPin(pin string) string {
	i := b.translateAnalogPin(pin)
	if b.analogPins[i] == nil {
		b.analogPins[i] = newAnalogPin(i)
	}
	return i
}

func (b *BeagleboneAdaptor) digitalPin(pin string, mode string) int {
	i := b.translatePin(pin)
	if b.digitalPins[i] == nil || b.digitalPins[i].Mode != mode {
		b.digitalPins[i] = newDigitalPin(i, mode)
	}
	return i
}

func (b *BeagleboneAdaptor) pwmPin(pin string) string {
	i := b.translatePwmPin(pin)
	if b.pwmPins[i] == nil {
		b.pwmPins[i] = newPwmPin(i)
	}
	return i
}
<|endoftext|>


<commit_before>// Package exec is used to invoke child processes across various platforms to
// provide the following features:
//
// - Least privilege
// - Resource constraints
// - Process isolation
//
// A "platform" may be defined as coarsely as "Windows" or as specifically as
// "linux 3.20 with systemd". This allows Nomad to use best-effort, best-
// available capabilities of each platform to provide resource constraints,
// process isolation, and security features, or otherwise take advantage of
// features that are unique to that platform.
//
// The `semantics of any particular instance are left up to the implementation.
// However, these should be completely transparent to the calling context. In
// other words, the Java driver should be able to call exec for any platform and
// just work.
package executor

import (
	"fmt"
	"os/exec"
	"path/filepath"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/nomad/structs"
)

var errNoResources = fmt.Errorf("No resources are associated with this task")

// Executor is an interface that any platform- or capability-specific exec
// wrapper must implement. You should not need to implement a Java executor.
// Rather, you would implement a cgroups executor that the Java driver will use.
type Executor interface {
	// Limit must be called before Start and restricts the amount of resources
	// the process can use. Note that an error may be returned ONLY IF the
	// executor implements resource limiting. Otherwise Limit is ignored.
	Limit(*structs.Resources) error

	// ConfigureTaskDir must be called before Start and ensures that the tasks
	// directory is properly configured.
	ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error

	// Start the process. This may wrap the actual process in another command,
	// depending on the capabilities in this environment. Errors that arise from
	// Limits or Runas may bubble through Start()
	Start() error

	// Open should be called to restore a previous execution. This might be needed if
	// nomad is restarted.
	Open(string) error

	// Wait waits till the user's command is completed.
	Wait() error

	// Returns a handle that is executor specific for use in reopening.
	ID() (string, error)

	// Shutdown should use a graceful stop mechanism so the application can
	// perform checkpointing or cleanup, if such a mechanism is available.
	// If such a mechanism is not available, Shutdown() should call ForceStop().
	Shutdown() error

	// ForceStop will terminate the process without waiting for cleanup. Every
	// implementations must provide this.
	ForceStop() error

	// Command provides access the underlying Cmd struct in case the Executor
	// interface doesn't expose the functionality you need.
	Command() *cmd
}

// Command is a mirror of exec.Command that returns a platform-specific Executor
func Command(name string, arg ...string) Executor {
	executor := NewExecutor()
	cmd := executor.Command()
	cmd.Path = name
	cmd.Args = append([]string{name}, arg...)

	if filepath.Base(name) == name {
		if lp, err := exec.LookPath(name); err != nil {
			// cmd.lookPathErr = err
		} else {
			cmd.Path = lp
		}
	}
	return executor
}

// OpenId is similar to executor.Command but will attempt to reopen with the
// passed ID.
func OpenId(id string) (Executor, error) {
	executor := NewExecutor()
	err := executor.Open(id)
	if err != nil {
		return nil, err
	}
	return executor, nil
}

// Cmd is an extension of exec.Cmd that incorporates functionality for
// re-attaching to processes, dropping priviledges, etc., based on platform-
// specific implementations.
type cmd struct {
	exec.Cmd

	// Resources is used to limit CPU and RAM used by the process, by way of
	// cgroups or a similar mechanism.
	Resources structs.Resources

	// RunAs may be a username or Uid. The implementation will decide how to use it.
	RunAs string
}
<commit_msg>Clarified package documentation for executor in response to #232<commit_after>s// Package executor is used to invoke child processes across various "platforms"
// in a way that provides the following features:
//
// - Least privilege
// - Resource constraints
// - Process isolation
//
// A "platform" may something like "windows" or "linux with systemd". Executors
// allow drivers like `exec` and `java` to share a common implementation of the
// isolation capabilities on a particular operating system.
//
// For example:
//
// - `exec` and `java` on Linux will use a cgroups executor
// - `exec` and `java` on FreeBSD will use a jails executor
//
// However, drivers that provide their own isolation should not use executors.
// For example, using an executor to start QEMU means that the QEMU call is
// run inside a chroot+cgroup, even though the VM already provides isolation for
// the task running inside it. That's not what we want.
package executor

import (
	"fmt"
	"os/exec"
	"path/filepath"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/nomad/structs"
)

var errNoResources = fmt.Errorf("No resources are associated with this task")

// Executor is an interface that any platform- or capability-specific exec
// wrapper must implement. You should not need to implement a Java executor.
// Rather, you would implement a cgroups executor that the Java driver will use.
type Executor interface {
	// Limit must be called before Start and restricts the amount of resources
	// the process can use. Note that an error may be returned ONLY IF the
	// executor implements resource limiting. Otherwise Limit is ignored.
	Limit(*structs.Resources) error

	// ConfigureTaskDir must be called before Start and ensures that the tasks
	// directory is properly configured.
	ConfigureTaskDir(taskName string, alloc *allocdir.AllocDir) error

	// Start the process. This may wrap the actual process in another command,
	// depending on the capabilities in this environment. Errors that arise from
	// Limits or Runas may bubble through Start()
	Start() error

	// Open should be called to restore a previous execution. This might be needed if
	// nomad is restarted.
	Open(string) error

	// Wait waits till the user's command is completed.
	Wait() error

	// Returns a handle that is executor specific for use in reopening.
	ID() (string, error)

	// Shutdown should use a graceful stop mechanism so the application can
	// perform checkpointing or cleanup, if such a mechanism is available.
	// If such a mechanism is not available, Shutdown() should call ForceStop().
	Shutdown() error

	// ForceStop will terminate the process without waiting for cleanup. Every
	// implementations must provide this.
	ForceStop() error

	// Command provides access the underlying Cmd struct in case the Executor
	// interface doesn't expose the functionality you need.
	Command() *cmd
}

// Command is a mirror of exec.Command that returns a platform-specific Executor
func Command(name string, arg ...string) Executor {
	executor := NewExecutor()
	cmd := executor.Command()
	cmd.Path = name
	cmd.Args = append([]string{name}, arg...)

	if filepath.Base(name) == name {
		if lp, err := exec.LookPath(name); err != nil {
			// cmd.lookPathErr = err
		} else {
			cmd.Path = lp
		}
	}
	return executor
}

// OpenId is similar to executor.Command but will attempt to reopen with the
// passed ID.
func OpenId(id string) (Executor, error) {
	executor := NewExecutor()
	err := executor.Open(id)
	if err != nil {
		return nil, err
	}
	return executor, nil
}

// Cmd is an extension of exec.Cmd that incorporates functionality for
// re-attaching to processes, dropping priviledges, etc., based on platform-
// specific implementations.
type cmd struct {
	exec.Cmd

	// Resources is used to limit CPU and RAM used by the process, by way of
	// cgroups or a similar mechanism.
	Resources structs.Resources

	// RunAs may be a username or Uid. The implementation will decide how to use it.
	RunAs string
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/bmizerany/mc"
	"github.com/elazarl/goproxy"
	"github.com/jackc/pgx"
)

var (
	cn    *mc.Conn
	pool  *pgx.ConnPool
	proxy *goproxy.ProxyHttpServer
)

func urlHasPrefix(prefix string) goproxy.ReqConditionFunc {
	return func(req *http.Request, ctx *goproxy.ProxyCtx) bool {
		isGET := req.Method == http.MethodGet
		hasPrefix := strings.HasPrefix(req.URL.Path, prefix)
		isSearch := strings.HasPrefix(req.URL.Path, "/packages/search/")
		return isGET && hasPrefix && !isSearch
	}
}

func pathIs(path string) goproxy.ReqConditionFunc {
	return func(req *http.Request, ctx *goproxy.ProxyCtx) bool {
		return req.Method == http.MethodGet && req.URL.Path == path
	}
}

func getEnv(key, def string) string {
	k := os.Getenv(key)
	if k == "" {
		return def
	}
	return k
}

func main() {
	memcachedURL := getEnv("MEMCACHEDCLOUD_SERVERS", "localhost:11211")
	var err error
	cn, err = mc.Dial("tcp", memcachedURL)
	if err != nil {
		log.Fatalf("Memcached connection error: %s", err)
	}

	memcachedUsername := os.Getenv("MEMCACHEDCLOUD_USERNAME")
	memcachedPassword := os.Getenv("MEMCACHEDCLOUD_PASSWORD")
	if memcachedUsername != "" && memcachedPassword != "" {
		if err := cn.Auth(memcachedUsername, memcachedPassword); err != nil {
			log.Fatalf("Memcached auth error: %s", err)
		}
	}

	pgxcfg, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatalf("Parse URI error: %s", err)
	}
	pool, err = pgx.NewConnPool(pgx.ConnPoolConfig{
		ConnConfig:     pgxcfg,
		MaxConnections: 20,
		AfterConnect: func(conn *pgx.Conn) error {
			_, err := conn.Prepare("getPackage", `SELECT name, url FROM packages WHERE name = $1`)
			return err
		},
	})
	if err != nil {
		log.Fatalf("Connection error: %s", err)
	}
	defer pool.Close()

	binary, err := exec.LookPath("node")
	if err != nil {
		log.Fatalf("Could not lookup node path: %s", err)
	}

	cmd := exec.Command(binary, "--expose_gc", "index.js")
	env := os.Environ()
	env = append([]string{"PORT=3001"}, env...)
	cmd.Env = env
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		log.Fatalf("Could not start node: %s", err)
	}
	go func() {
		if err := cmd.Wait(); err != nil {
			log.Fatalf("Node process failed: %s", err)
		}
	}()

	proxy = goproxy.NewProxyHttpServer()
	proxy.Verbose = false
	proxy.NonproxyHandler = http.HandlerFunc(nonProxy)
	proxy.OnRequest().DoFunc(
		func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			if r.Method == "GET" && r.Host != "registry.bower.io" && r.Host != "components.bower.io" {
				response := goproxy.NewResponse(r, "application/json", http.StatusPermanentRedirect, "")
				target := "https://registry.bower.io" + r.URL.Path
				if len(r.URL.RawQuery) > 0 {
					target += "?" + r.URL.RawQuery
				}
				response.Header.Set("Location", target)
				return r, response
			}

			return r, nil
		})

	proxy.OnRequest(pathIs("/packages")).DoFunc(listPackages)
	proxy.OnRequest(urlHasPrefix("/packages/")).DoFunc(getPackage)

	port := getEnv("PORT", "3000")
	log.Println("Starting web server at port", port)
	log.Fatal(http.ListenAndServe(":"+port, proxy))
}

func nonProxy(w http.ResponseWriter, req *http.Request) {
	req.URL.Scheme = "http"
	req.URL.Host = "localhost:3001"
	proxy.ServeHTTP(w, req)
}

type Package struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}

func getPackage(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	elements := strings.Split(r.URL.Path, "/")
	packageName := elements[len(elements)-1]

	var name, url string
	if err := pool.QueryRow("getPackage", packageName).Scan(&name, &url); err != nil {
		if err == pgx.ErrNoRows {
			return r, goproxy.NewResponse(r, "text/html", http.StatusNotFound, "Package not found")
		}
		return r, goproxy.NewResponse(r, "text/html", http.StatusInternalServerError, "Internal server error")
	}

	data, err := json.Marshal(Package{Name: name, URL: url})
	if err != nil {
		return r, goproxy.NewResponse(r, "text/html", http.StatusInternalServerError, "Internal server error")
	}
	response := goproxy.NewResponse(r, "application/json", http.StatusOK, string(data))
	response.Header.Add("Cache-Control", "public, max-age=86400")
	return r, response
}

func listPackages(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	val, _, _, err := cn.Get("packages")
	if err != nil {
		return r, nil
	}
	response := goproxy.NewResponse(r, "application/json", http.StatusOK, val)
	response.Header.Add("Cache-Control", "public, max-age=86400")
	return r, response
}
<commit_msg>Re-introduce correct env appending<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/bmizerany/mc"
	"github.com/elazarl/goproxy"
	"github.com/jackc/pgx"
)

var (
	cn    *mc.Conn
	pool  *pgx.ConnPool
	proxy *goproxy.ProxyHttpServer
)

func urlHasPrefix(prefix string) goproxy.ReqConditionFunc {
	return func(req *http.Request, ctx *goproxy.ProxyCtx) bool {
		isGET := req.Method == http.MethodGet
		hasPrefix := strings.HasPrefix(req.URL.Path, prefix)
		isSearch := strings.HasPrefix(req.URL.Path, "/packages/search/")
		return isGET && hasPrefix && !isSearch
	}
}

func pathIs(path string) goproxy.ReqConditionFunc {
	return func(req *http.Request, ctx *goproxy.ProxyCtx) bool {
		return req.Method == http.MethodGet && req.URL.Path == path
	}
}

func getEnv(key, def string) string {
	k := os.Getenv(key)
	if k == "" {
		return def
	}
	return k
}

func main() {
	memcachedURL := getEnv("MEMCACHEDCLOUD_SERVERS", "localhost:11211")
	var err error
	cn, err = mc.Dial("tcp", memcachedURL)
	if err != nil {
		log.Fatalf("Memcached connection error: %s", err)
	}

	memcachedUsername := os.Getenv("MEMCACHEDCLOUD_USERNAME")
	memcachedPassword := os.Getenv("MEMCACHEDCLOUD_PASSWORD")
	if memcachedUsername != "" && memcachedPassword != "" {
		if err := cn.Auth(memcachedUsername, memcachedPassword); err != nil {
			log.Fatalf("Memcached auth error: %s", err)
		}
	}

	pgxcfg, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatalf("Parse URI error: %s", err)
	}
	pool, err = pgx.NewConnPool(pgx.ConnPoolConfig{
		ConnConfig:     pgxcfg,
		MaxConnections: 20,
		AfterConnect: func(conn *pgx.Conn) error {
			_, err := conn.Prepare("getPackage", `SELECT name, url FROM packages WHERE name = $1`)
			return err
		},
	})
	if err != nil {
		log.Fatalf("Connection error: %s", err)
	}
	defer pool.Close()

	binary, err := exec.LookPath("node")
	if err != nil {
		log.Fatalf("Could not lookup node path: %s", err)
	}

	cmd := exec.Command(binary, "--expose_gc", "index.js")
	env := os.Environ()
	env = append(env, "PORT=3001")
	cmd.Env = env
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Start(); err != nil {
		log.Fatalf("Could not start node: %s", err)
	}
	go func() {
		if err := cmd.Wait(); err != nil {
			log.Fatalf("Node process failed: %s", err)
		}
	}()

	proxy = goproxy.NewProxyHttpServer()
	proxy.Verbose = false
	proxy.NonproxyHandler = http.HandlerFunc(nonProxy)
	proxy.OnRequest().DoFunc(
		func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			if r.Method == "GET" && r.Host != "registry.bower.io" && r.Host != "components.bower.io" {
				response := goproxy.NewResponse(r, "application/json", http.StatusPermanentRedirect, "")
				target := "https://registry.bower.io" + r.URL.Path
				if len(r.URL.RawQuery) > 0 {
					target += "?" + r.URL.RawQuery
				}
				response.Header.Set("Location", target)
				return r, response
			}

			return r, nil
		})

	proxy.OnRequest(pathIs("/packages")).DoFunc(listPackages)
	proxy.OnRequest(urlHasPrefix("/packages/")).DoFunc(getPackage)

	port := getEnv("PORT", "3000")
	log.Println("Starting web server at port", port)
	log.Fatal(http.ListenAndServe(":"+port, proxy))
}

func nonProxy(w http.ResponseWriter, req *http.Request) {
	req.URL.Scheme = "http"
	req.URL.Host = "localhost:3001"
	proxy.ServeHTTP(w, req)
}

type Package struct {
	Name string `json:"name"`
	URL  string `json:"url"`
}

func getPackage(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	elements := strings.Split(r.URL.Path, "/")
	packageName := elements[len(elements)-1]

	var name, url string
	if err := pool.QueryRow("getPackage", packageName).Scan(&name, &url); err != nil {
		if err == pgx.ErrNoRows {
			return r, goproxy.NewResponse(r, "text/html", http.StatusNotFound, "Package not found")
		}
		return r, goproxy.NewResponse(r, "text/html", http.StatusInternalServerError, "Internal server error")
	}

	data, err := json.Marshal(Package{Name: name, URL: url})
	if err != nil {
		return r, goproxy.NewResponse(r, "text/html", http.StatusInternalServerError, "Internal server error")
	}
	response := goproxy.NewResponse(r, "application/json", http.StatusOK, string(data))
	response.Header.Add("Cache-Control", "public, max-age=86400")
	return r, response
}

func listPackages(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	val, _, _, err := cn.Get("packages")
	if err != nil {
		return r, nil
	}
	response := goproxy.NewResponse(r, "application/json", http.StatusOK, val)
	response.Header.Add("Cache-Control", "public, max-age=86400")
	return r, response
}
<|endoftext|>


<commit_before>package interceptor

// InterceptorRegistry is a collector for interceptors.
type Registry struct {
	interceptors []Interceptor
}

// Add adds a new Interceptor to the registry.
func (i *Registry) Add(icpr Interceptor) {
	i.interceptors = append(i.interceptors, icpr)
}

func (i *Registry) build() Interceptor {
	if len(i.interceptors) == 0 {
		return &NoOp{}
	}

	return NewChain(i.interceptors)
}
<commit_msg>Expose Build on Registry<commit_after>package interceptor

// InterceptorRegistry is a collector for interceptors.
type Registry struct {
	interceptors []Interceptor
}

// Add adds a new Interceptor to the registry.
func (i *Registry) Add(icpr Interceptor) {
	i.interceptors = append(i.interceptors, icpr)
}

// Build constructs a single Interceptor from a InterceptorRegistry
func (i *Registry) Build() Interceptor {
	if len(i.interceptors) == 0 {
		return &NoOp{}
	}

	return NewChain(i.interceptors)
}
<|endoftext|>


<commit_before>// The term package implements rendering HTML content for the terminal.
package term

import (
	"bytes"
	"errors"
	"io"
	"os"
	"runtime"
	"strings"
	"unicode"

	"github.com/PuerkitoBio/goquery"
	"github.com/andybalholm/cascadia"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/net/html"
)

// Renderer implements a rendering HTML content in a stripped down format
// suitable for the terminal.
type Renderer struct {
	// Width sets the assumed width of the terminal, which aids in wrapping
	// text. If == 0, then the width is treated as 80. If < 0, then the width is
	// treated as unbounded.
	Width int
	// TabSize indicates the number of characters that the terminal uses to
	// render a tab. If <= 0, then tabs are assumed to have a size of 8.
	TabSize int
}

var (
	stop         = errors.New("stop")          // Stop walking without erroring.
	skipChildren = errors.New("skip children") // Skip all child nodes.
	skipText     = errors.New("skip text")     // Skip child text nodes.
)

type walker func(node *html.Node, entering bool) error

func walk(node *html.Node, cb walker) error {
	err := cb(node, true)
	if err != nil && err != skipChildren && err != skipText {
		return err
	}
	if err != skipChildren {
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			if c.Type == html.TextNode && err == skipText {
				continue
			}
			if err := walk(c, cb); err != nil {
				return err
			}
		}
	}
	if err = cb(node, false); err != nil && err != skipChildren && err != skipText {
		return err
	}
	return err
}

// Facilitates wrapped text.
type writer struct {
	bytes.Buffer
	w io.Writer

	// If wrapping, wrap to this width.
	width int

	// Size of tab character.
	tabSize int
}

func (w *writer) Flush() error {
	b := w.Buffer.Bytes()
	defer w.Buffer.Reset()

	b = bytes.TrimSpace(b)
	var paragraphs [][]rune
	for i := 0; i < len(b); {
		if b[i] == '\n' {
			// Bounds check unneeded; if b[i], being a \n, was at the end, it
			// would have been trimmed.
			if b[i+1] == '\n' {
				// New paragraph.
				paragraphs = append(paragraphs, []rune(string(b[:i])))
				i += 2
				for b[i] == '\n' {
					// Collapse extra newlines.
					i++
				}
				b = b[i:]
				i = 0
				continue
			} else {
				// Unwrap.
				b[i] = ' '
			}
		}
		i++
	}
	paragraphs = append(paragraphs, []rune(string(b)))
	if w.width > 0 {
		for j, p := range paragraphs {
			for i := 0; i < len(p); {
				n := i + w.width
				if n+1 >= len(p) {
					break
				}
				for n > i && !unicode.IsSpace(p[n]) {
					n--
				}
				if n <= i {
					// Long word.
					n = i + w.width
					p = append(p, 0)
					copy(p[n+1:], p[n:])
					p[n] = '\n'
					i = n + 1
				} else {
					p[n] = '\n'
					i = n + 1
				}
			}
			paragraphs[j] = p
		}
		if runtime.GOOS == "windows" {
			// Remove newlines that are inserted just after the edge of the
			// width. This prevents the terminal from incorrectly producing an
			// extra gap when wrapping. This removes the newline entirely, so it
			// is assumed that the wrapping will separate the previous word from
			// the next word.
			for i, p := range paragraphs {
				for h, i := 0, 0; i < len(p); i++ {
					if p[i] != '\n' {
						continue
					}
					if i-h >= w.width {
						copy(p[i:], p[i+1:])
						p = p[:len(p)-1]
						h = i
						i--
					} else {
						h = i + 1
					}
				}
				paragraphs[i] = p
			}
		}
	}
	for i, p := range paragraphs {
		if i > 0 {
			w.w.Write([]byte{'\n', '\n'})
		}
		if _, err := w.w.Write([]byte(string(p))); err != nil {
			return err
		}
	}
	return nil
}

var sectionCounter = cascadia.MustCompile("body > section")

func (r Renderer) Render(w io.Writer, s *goquery.Selection) error {
	buf := &writer{
		w:       w,
		width:   r.Width,
		tabSize: r.TabSize,
	}
	if buf.width == 0 {
		buf.width, _, _ = terminal.GetSize(int(os.Stdout.Fd()))
	}
	var state walkState
	for _, node := range s.Nodes {
		if node.Type == html.TextNode {
			continue
		}
		// If the body contains more than one section, increase the depth to
		// force the section names to be rendered.
		isRoot := s.FindMatcher(sectionCounter).Length() > 1
		if isRoot {
			state.depth++
		}
		err := walk(node, func(node *html.Node, entering bool) error {
			switch node.Type {
			case html.ErrorNode:
			case html.TextNode:
				if entering {
					buf.WriteString(node.Data)
				}
			case html.DocumentNode:
			case html.ElementNode:
				h := handlers[elementMatcher{node.Data, entering}]
				if h != nil {
					return h(buf, node, &state)
				}
			case html.CommentNode:
			case html.DoctypeNode:
			case html.RawNode:
			}
			return nil
		})
		if err != nil && err != stop {
			return err
		}
		if isRoot {
			state.depth--
		}
	}
	return buf.Flush()
}

type elementMatcher struct {
	data     string
	entering bool
}

type walkState struct {
	depth int
}

type nodeHandlers map[elementMatcher]func(w *writer, node *html.Node, s *walkState) error

func isElement(node *html.Node, tag string) bool {
	return node.Type == html.ElementNode && node.Data == tag
}

func sectionName(node *html.Node) string {
	for _, attr := range node.Attr {
		if attr.Key == "data-name" {
			return attr.Val
		}
	}
	return ""
}

var handlers = nodeHandlers{
	{"code", true}: func(w *writer, node *html.Node, s *walkState) error {
		if isElement(node.Parent, "pre") { // May have syntax: `class="language-*"`
			// Block
			w.WriteString(node.FirstChild.Data)
			return skipChildren
		} else {
			// Inline
			return w.WriteByte('`')
		}
	},
	{"code", false}: func(w *writer, node *html.Node, s *walkState) error {
		if isElement(node.Parent, "pre") {
			// Block
		} else {
			// Inline
			return w.WriteByte('`')
		}
		return nil
	},
	{"section", true}: func(w *writer, node *html.Node, s *walkState) error {
		if s.depth > 0 {
			if name := sectionName(node); name != "" {
				w.WriteString(strings.Repeat("#", s.depth))
				w.WriteString(" ")
				w.WriteString(name)
				w.WriteString("\n\n")
			}
		}
		s.depth++
		return skipText
	},
	{"section", false}: func(w *writer, node *html.Node, s *walkState) error {
		s.depth--
		return nil
	},
	{"p", true}: func(w *writer, node *html.Node, s *walkState) error {
		_, err := w.WriteString("\n\n")
		return err
	},
	{"p", false}: func(w *writer, node *html.Node, s *walkState) error {
		_, err := w.WriteString("\n\n")
		return err
	},
}
<commit_msg>Improve terminal renderer.<commit_after>// The term package implements rendering HTML content for the terminal.
package term

import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/andybalholm/cascadia"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/net/html"
)

// Renderer implements a rendering HTML content in a stripped down format
// suitable for the terminal.
type Renderer struct {
	// Width sets the assumed width of the terminal, which aids in wrapping
	// text. If == 0, then the width is treated as 80. If < 0, then the width is
	// treated as unbounded.
	Width int
	// TabSize indicates the number of characters that the terminal uses to
	// render a tab. If <= 0, then tabs are assumed to have a size of 8.
	TabSize int
}

var (
	stop         = errors.New("stop")          // Stop walking without erroring.
	skipChildren = errors.New("skip children") // Skip all child nodes.
	skipText     = errors.New("skip text")     // Skip child text nodes.
)

type walker func(node *html.Node, entering bool) error

func walk(node *html.Node, cb walker) error {
	err := cb(node, true)
	if err != nil && err != skipChildren && err != skipText {
		return err
	}
	if err != skipChildren {
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			if c.Type == html.TextNode && err == skipText {
				continue
			}
			if err := walk(c, cb); err != nil {
				return err
			}
		}
	}
	if err = cb(node, false); err != nil && err != skipChildren && err != skipText {
		return err
	}
	return err
}

// Change to debug inserted spaces.
const z = ' '

// Get base-10 digit-count of integer.
func intlen(n int) (c int) {
	for n != 0 {
		n /= 10
		c++
	}
	return c
}

// Contains the state of a list marker.
type listState struct {
	// Slice of numeric portion of marker.
	i, j int
	// Current numeric value of marker.
	num int
	// Current marker content.
	marker []byte
}

// Facilitates wrapped text.
type writer struct {
	bytes.Buffer
	w io.Writer

	// If wrapping, wrap to this width.
	width int

	// Width of tab character.
	tabWidth int

	// Level of indentation.
	indent int

	// String used for single level of indentation.
	indentString []byte

	// Contains list marker states.
	listStack []listState

	// Current leading space for each line. Includes extra spacing equal to list
	// marker width.
	leading []byte

	// Displayed width of leading space.
	leadingWidth int

	// Remaining number of newlines allowed within a margin. Resets by entering
	// a block.
	margin int

	// Whether a block was just entered. Prevents writing another margin if a
	// block was entered multiple times (e.g. nested blocks).
	block bool

	// Whether a marker was just inserted. Prevents leading space from be added
	// to the start of a paragraph.
	marked bool
}

// Calculate leading space inserted before lines.
func (w *writer) updateLeadingSpace() {
	ind := w.indent
	if ind <= 0 {
		ind = 0
	} else {
		// Indentation is used primarily for lists, so reduce indent by one for
		// markers.
		ind--
	}
	indent := len(w.indentString) * ind
	marker := 0
	if len(w.listStack) > 0 {
		marker = len(w.listStack[len(w.listStack)-1].marker)
	}
	if cap(w.leading) < indent+marker {
		w.leading = make([]byte, 0, indent+marker)
	} else {
		w.leading = w.leading[:0]
	}
	for i := 0; i < ind; i++ {
		w.leading = append(w.leading, w.indentString...)
	}
	for i := 0; i < marker; i++ {
		//TODO: Should match grapheme width.
		w.leading = append(w.leading, z)
	}
	w.leadingWidth = 0
	for _, c := range w.leading {
		if c == '\t' {
			w.leadingWidth += w.tabWidth
		} else {
			w.leadingWidth += 1
		}
	}
}

// Start inserting list markers. prefix is the content of the marker appearing
// before the index. max is the maximum index that will be displayed, while
// start is the starting index. suffix is the content appearing after the index.
// If max is <= 0, start is < 0, or max < start, then no index is displayed.
func (w *writer) List(prefix string, start, max int, suffix string) {
	var state listState
	numlen := intlen(max)
	n := len(prefix) + numlen + len(suffix)
	state.marker = make([]byte, n)
	b := state.marker[:0]
	b = append(b, prefix...)
	if max > 0 && start >= 0 && max >= start {
		state.num = start
		for i := 0; i < numlen; i++ {
			b = append(b, z)
		}
		state.i = len(prefix)
		state.j = state.i + numlen
	}
	b = append(b, suffix...)
	w.listStack = append(w.listStack, state)
	w.Indent(1)
	w.updateLeadingSpace()
}

// Insert a new marker. The marker is inserted immediately, ahead of the buffer.
// Every line except the first after a marker will include additional leading
// spacing equal to the length of the marker.
func (w *writer) ListMarker() {
	if len(w.listStack) == 0 {
		return
	}
	last := len(w.listStack) - 1
	state := w.listStack[last]
	if state.j > 0 {
		b := state.marker[state.i:state.j]
		b = b[len(b)-intlen(state.num):]
		b = b[:0]
		strconv.AppendInt(b, int64(state.num), 10)
		state.num++
		w.listStack[last] = state
	}
	w.w.Write(w.leading[:len(w.leading)-len(state.marker)])
	w.w.Write(state.marker)
	w.marked = true
}

// Stop rendering list markers and leading marker space.
func (w *writer) ClearList() {
	if len(w.listStack) == 0 {
		return
	}
	w.listStack = w.listStack[:len(w.listStack)-1]
	w.Indent(-1)
	w.updateLeadingSpace()
	if w.indent <= 0 {
		// Compensate for shortened li margin.
		w.margin++
	}
}

// Increase or decrease the level of indentation.
func (w *writer) Indent(delta int) {
	w.indent += delta
	w.updateLeadingSpace()
}

// Format accumulated paragraph text by wrapping.
func (w *writer) Flush() error {
	b := w.Buffer.Bytes()
	defer w.Buffer.Reset()

	b = bytes.TrimSpace(b)
	var paragraphs [][]byte
	for i := 0; i < len(b); {
		if b[i] == '\n' {
			// Bounds check unneeded; if b[i], being a \n, was at the end, it
			// would have been trimmed.
			if b[i+1] == '\n' {
				// New paragraph.
				if len(bytes.TrimSpace(b[:i])) > 0 {
					paragraphs = append(paragraphs, b[:i])
				}
				i += 2
				for b[i] == '\n' {
					// Collapse extra newlines.
					i++
				}
				b = b[i:]
				i = 0
				continue
			} else {
				// Unwrap.
				b[i] = ' '
			}
		}
		i++
	}
	if len(bytes.TrimSpace(b)) > 0 {
		paragraphs = append(paragraphs, b)
	}

	if width := w.width; width > 0 {
		for j, p := range paragraphs {
			i := w.leadingWidth
			if i >= width {
				// Lost-cause. Keep as-is.
				//
				//TODO: Fallback to unwrapped (<=0 width).
				continue
			}
			s := bufio.NewScanner(bytes.NewBuffer(p))
			s.Split(bufio.ScanWords)
			var buf bytes.Buffer
			if !w.marked {
				// Insert leading space. i is already set.
				buf.Write(w.leading)
			} else {
				w.marked = false
			}
			var prevWord bool
			for s.Scan() {
				word := s.Bytes()
				// 1 added to represent preceding space.
				if i+len(word)+1 > width {
					// Append newline with leading space.
					buf.WriteByte('\n')
					buf.Write(w.leading)
					i = w.leadingWidth
					prevWord = false
				} else {
					// Append entire word.
					if prevWord {
						buf.WriteByte(z)
						i++
					}
					prevWord = true
					buf.Write(word)
					i += len(word)
					continue
				}
				// Append word in chunks of the available space.
				if prevWord {
					buf.WriteByte(z)
					i++
				}
				prevWord = true
				for len(word) > 0 {
					n := width - i
					if n == 0 {
						// Ensure at least one character is written.
						n = 1
					} else if n >= len(word) {
						// Leftover word fits.
						buf.Write(word)
						i += len(word)
						break
					}
					buf.Write(word[:n])
					buf.WriteByte('\n')
					buf.Write(w.leading)
					i = w.leadingWidth
					word = word[n:]
				}
			}
			paragraphs[j] = buf.Bytes()
		}
	} else {
		for j, p := range paragraphs {
			s := bufio.NewScanner(bytes.NewBuffer(p))
			s.Split(bufio.ScanWords)
			var buf bytes.Buffer
			for s.Scan() {
				if buf.Len() > 0 {
					buf.WriteByte(z)
				}
				buf.Write(s.Bytes())
			}
			paragraphs[j] = buf.Bytes()
		}
	}
	for i, p := range paragraphs {
		if i > 0 {
			w.Block(2)
		}
		if _, err := w.w.Write([]byte(string(p))); err != nil {
			return err
		}
		w.Margin()
	}
	return nil
}

// Margin inserts up to two newlines between blocks.
func (w *writer) Margin() {
	if w.margin > 0 {
		// Because margin is initialized to 0, it wont be written at the start
		// of the content.
		w.w.Write([]byte{'\n'})
		w.margin--
	}
	w.block = false
}

// Block adds a margin, then starts a new block, which resets the available
// margins.
func (w *writer) Block(margin int) {
	if !w.block {
		w.Margin()
	}
	w.margin = margin
	w.block = true
}

var sectionCounter = cascadia.MustCompile("body > section")

// Elements that have margins inserted before and after. Value indicates the
// maximum allowed margin size after the block.
var block = map[string]int{
	"p":     2,
	"ol":    2,
	"ul":    2,
	"pre":   2,
	"table": 2,
	"li":    1,
}

func (r Renderer) Render(w io.Writer, s *goquery.Selection) error {
	buf := &writer{
		w:            w,
		width:        r.Width,
		tabWidth:     r.TabSize,
		indentString: []byte{'\t'},
	}
	if buf.tabWidth <= 0 {
		//TODO: Get from terminal somehow. 8 is the default most of the time,
		//but this can be adjusted by the user, so this value wont always be
		//correct. However, it at least wont overflow if the actual tab width is
		//less than the value.
		buf.tabWidth = 8
	}
	if buf.width == 0 {
		buf.width, _, _ = terminal.GetSize(int(os.Stdout.Fd()))
		if runtime.GOOS == "windows" && buf.width > 1 {
			// If a newline occurs on the edge, cmd.exe will incorrectly wrap it
			// around, producing a gap. Reducing the width by one ensures this
			// gap wont appear.
			buf.width--
		}
	}
	var state walkState
	for _, node := range s.Nodes {
		if node.Type == html.TextNode {
			continue
		}
		// If the body contains more than one section, increase the depth to
		// force the section names to be rendered.
		isRoot := s.FindMatcher(sectionCounter).Length() > 1
		if isRoot {
			state.depth++
		}
		err := walk(node, func(node *html.Node, entering bool) error {
			switch node.Type {
			case html.ErrorNode:
			case html.TextNode:
				if entering {
					if strings.TrimSpace(node.Data) != "" {
						buf.WriteString(node.Data)
					}
				}
			case html.DocumentNode:
			case html.ElementNode:
				if m := block[node.Data]; m != 0 && entering {
					buf.Flush()
					buf.Block(m)
				}
				h := handlers[elementMatcher{node.Data, entering}]
				var err error
				if h != nil {
					err = h(buf, node, &state)
				}
				if block[node.Data] != 0 && !entering {
					buf.Flush()
					buf.Margin()
				}
				return err
			case html.CommentNode:
			case html.DoctypeNode:
			case html.RawNode:
			}
			return nil
		})
		if err != nil && err != stop {
			return err
		}
		if isRoot {
			state.depth--
		}
	}
	return buf.Flush()
}

type elementMatcher struct {
	data     string
	entering bool
}

type walkState struct {
	depth int
}

type nodeHandlers map[elementMatcher]func(w *writer, node *html.Node, s *walkState) error

func isElement(node *html.Node, tag string) bool {
	return node.Type == html.ElementNode && node.Data == tag
}

func sectionName(node *html.Node) string {
	for _, attr := range node.Attr {
		if attr.Key == "data-name" {
			return attr.Val
		}
	}
	return ""
}

var handlers = nodeHandlers{
	{"code", true}: func(w *writer, node *html.Node, s *walkState) error {
		if isElement(node.Parent, "pre") { // May have syntax: `class="language-*"`
			// Block

			var buf bytes.Buffer
			walk(node, func(node *html.Node, entering bool) error {
				if entering && node.Type == html.TextNode {
					buf.WriteString(node.Data)
				}
				return nil
			})
			b := bytes.TrimSpace(buf.Bytes())

			ind := 1
			if w.indent <= 0 {
				// Compensate for reduced list indentation.
				ind = 2
			}
			w.Indent(ind)
			c := make([]byte, len(w.leading)+1)
			c[0] = '\n'
			copy(c[1:], w.leading)
			b = bytes.ReplaceAll(b, c[:1], c)
			w.w.Write(w.leading)
			w.w.Write(b)
			w.Indent(-ind)

			return skipChildren
		} else {
			// Inline

			// TODO: Content must be treated as one word.
			return w.WriteByte('`')
		}
	},
	{"code", false}: func(w *writer, node *html.Node, s *walkState) error {
		if isElement(node.Parent, "pre") {
			// Block
		} else {
			// Inline
			return w.WriteByte('`')
		}
		return nil
	},
	{"section", true}: func(w *writer, node *html.Node, s *walkState) error {
		if s.depth > 0 {
			if name := sectionName(node); name != "" {
				w.WriteString(strings.Repeat("#", s.depth))
				w.WriteString(" ")
				w.WriteString(name)
				w.WriteString("\n\n")
			}
		}
		s.depth++
		return skipText
	},
	{"section", false}: func(w *writer, node *html.Node, s *walkState) error {
		s.depth--
		return nil
	},
	{"ul", true}: func(w *writer, node *html.Node, s *walkState) error {
		w.List(" - ", 0, 0, "")
		return nil
	},
	{"ul", false}: func(w *writer, node *html.Node, s *walkState) error {
		w.ClearList()
		return nil
	},
	{"ol", true}: func(w *writer, node *html.Node, s *walkState) error {
		n := 0
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			if c.Type == html.ElementNode && c.Data == "li" {
				n++
			}
		}
		w.List(" ", 1, n, ". ")
		return nil
	},
	{"ol", false}: func(w *writer, node *html.Node, s *walkState) error {
		w.ClearList()
		return nil
	},
	{"li", true}: func(w *writer, node *html.Node, s *walkState) error {
		w.ListMarker()
		return nil
	},
	{"li", false}: func(w *writer, node *html.Node, s *walkState) error {
		w.Flush()
		return nil
	},
	{"table", true}: func(w *writer, node *html.Node, s *walkState) error {
		w.w.Write([]byte("<TODO:table>"))
		return skipChildren
	},
	{"table", false}: func(w *writer, node *html.Node, s *walkState) error {
		w.w.Write([]byte("</TODO:table>"))
		return nil
	},
}
<|endoftext|>


<commit_before>// Package parser implements the parsing stage of the compilation.
package parser

import (
	"github.com/saicheems/lexer"
	"github.com/saicheems/token"
)

type Parser struct {
	lex  *lexer.Lexer
	top  *token.SymbolTable
	look *token.Token
}

func New(l *lexer.Lexer, s *token.SymbolTable) *Parser {
	p := new(Parser)
	p.lex = l
	p.top = s
	return p
}

func (p *Parser) Parse() bool {
	p.move()
	if !p.parseBlock() {
		return false
	}
	if !p.match(token.TagPeriod) {
		return false
	}
	return true
}

func (p *Parser) parseBlock() bool {
	if !p.parseConsts() {
		return false
	}
	if !p.parseVars() {
		return false
	}
	if !p.parseProcedure() {
		return false
	}
	if !p.parseStatement() {
		return false
	}
	return true
}

func (p *Parser) parseConsts() bool {
	if p.match(token.TagConst) {
		if !p.match(token.TagIdentifier) {
			return false
		}
		if !p.match(token.TagEquals) {
			return false
		}
		if !p.match(token.TagInteger) {
			return false
		}
		for {
			if !p.match(token.TagComma) {
				break
			}
			if !p.match(token.TagIdentifier) {
				return false
			}
			if !p.match(token.TagEquals) {
				return false
			}
			if !p.match(token.TagInteger) {
				return false
			}
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseVars() bool {
	if p.match(token.TagVar) {
		if !p.match(token.TagIdentifier) {
			return false
		}
		for {
			if !p.match(token.TagComma) {
				break
			}
			if !p.match(token.TagIdentifier) {
				return false
			}
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseProcedure() bool {
	for {
		if !p.match(token.TagProcedure) {
			break
		}
		if !p.match(token.TagIdentifier) {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
		if !p.parseBlock() {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseStatement() bool {
	if p.match(token.TagIdentifier) {
		if !p.match(token.TagAssignment) {
			return false
		}
		if !p.parseExpression() {
			return false
		}
	} else if p.match(token.TagCall) {
		if !p.match(token.TagIdentifier) {
			return false
		}
	} else if p.match(token.TagBegin) {
		if !p.parseStatement() {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
		for {
			if !p.parseStatement() {
				break
			}
			if !p.match(token.TagSemicolon) {
				return false
			}
		}
		if !p.match(token.TagEnd) {
			return false
		}
	} else if p.match(token.TagIf) {
		if !p.parseCondition() {
			return false
		}
		if !p.match(token.TagThen) {
			return false
		}
		if !p.parseStatement() {
			return false
		}
	} else {
		if !p.match(token.TagWhile) {
			// Expected statement.
			return false
		}
		if !p.parseCondition() {
			return false
		}
		if !p.match(token.TagDo) {
			return false
		}
		if !p.parseStatement() {
			return false
		}
	}
	return true
}

func (p *Parser) parseCondition() bool {
	if p.match(token.TagOdd) {
		if !p.parseExpression() {
			return false
		}
	} else {
		if !p.parseExpression() {
			// Expected condition.
			return false
		}
		if !p.parseComparisonOp() {
			return false
		}
		if !p.parseExpression() {
			return false
		}
	}
	return true
}

func (p *Parser) parseComparisonOp() bool {
	if p.match(token.TagEquals) {
	} else if p.match(token.TagNotEquals) {
	} else if p.match(token.TagLessThan) {
	} else if p.match(token.TagLessThanEqualTo) {
	} else if p.match(token.TagGreaterThan) {
	} else {
		if !p.match(token.TagGreaterThanEqualTo) {
			// Expected comparison operator.
			return false
		}
	}
	return true
}

func (p *Parser) parseExpression() bool {
	p.match(token.TagPlus)
	p.match(token.TagMinus)

	if !p.parseTerm() {
		return false
	}
	for {
		if !(p.match(token.TagPlus) || p.match(token.TagMinus)) {
			break
		}
		if !p.parseTerm() {
			return false
		}
	}
	return true
}

func (p *Parser) parseTerm() bool {
	if p.parseFactor() {
		for {
			if !(p.match(token.TagTimes) || p.match(token.TagDivide)) {
				break
			}
			if !p.parseFactor() {
				return false
			}
		}
		return true
	}
	return false
}

func (p *Parser) parseFactor() bool {
	if p.match(token.TagIdentifier) {
	} else if p.match(token.TagInteger) {
	} else {
		if !p.match(token.TagLeftParen) {
			return false
		}
		if !p.parseExpression() {
			return false
		}
		if !p.match(token.TagRightParen) {
			return false
		}
	}
	return true
}

func (p *Parser) move() {
	tok := p.lex.Scan()
	p.look = tok
}

func (p *Parser) match(t int) bool {
	if p.look.Tag == t {
		p.move()
		return true
	}
	return false
}
<commit_msg>Incorporated comparison parsing function. It didn't do anything important anyway.<commit_after>// Package parser implements the parsing stage of the compilation.
package parser

import (
	"github.com/saicheems/lexer"
	"github.com/saicheems/token"
)

type Parser struct {
	lex  *lexer.Lexer
	top  *token.SymbolTable
	look *token.Token
}

func New(l *lexer.Lexer, s *token.SymbolTable) *Parser {
	p := new(Parser)
	p.lex = l
	p.top = s
	return p
}

func (p *Parser) Parse() bool {
	p.move()
	if !p.parseBlock() {
		return false
	}
	if !p.match(token.TagPeriod) {
		return false
	}
	return true
}

func (p *Parser) parseBlock() bool {
	if !p.parseConsts() {
		return false
	}
	if !p.parseVars() {
		return false
	}
	if !p.parseProcedure() {
		return false
	}
	if !p.parseStatement() {
		return false
	}
	return true
}

func (p *Parser) parseConsts() bool {
	if p.match(token.TagConst) {
		if !p.match(token.TagIdentifier) {
			return false
		}
		if !p.match(token.TagEquals) {
			return false
		}
		if !p.match(token.TagInteger) {
			return false
		}
		for {
			if !p.match(token.TagComma) {
				break
			}
			if !p.match(token.TagIdentifier) {
				return false
			}
			if !p.match(token.TagEquals) {
				return false
			}
			if !p.match(token.TagInteger) {
				return false
			}
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseVars() bool {
	if p.match(token.TagVar) {
		if !p.match(token.TagIdentifier) {
			return false
		}
		for {
			if !p.match(token.TagComma) {
				break
			}
			if !p.match(token.TagIdentifier) {
				return false
			}
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseProcedure() bool {
	for {
		if !p.match(token.TagProcedure) {
			break
		}
		if !p.match(token.TagIdentifier) {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
		if !p.parseBlock() {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
	}
	return true
}

func (p *Parser) parseStatement() bool {
	if p.match(token.TagIdentifier) {
		if !p.match(token.TagAssignment) {
			return false
		}
		if !p.parseExpression() {
			return false
		}
	} else if p.match(token.TagCall) {
		if !p.match(token.TagIdentifier) {
			return false
		}
	} else if p.match(token.TagBegin) {
		if !p.parseStatement() {
			return false
		}
		if !p.match(token.TagSemicolon) {
			return false
		}
		for {
			if !p.parseStatement() {
				break
			}
			if !p.match(token.TagSemicolon) {
				return false
			}
		}
		if !p.match(token.TagEnd) {
			return false
		}
	} else if p.match(token.TagIf) {
		if !p.parseCondition() {
			return false
		}
		if !p.match(token.TagThen) {
			return false
		}
		if !p.parseStatement() {
			return false
		}
	} else {
		if !p.match(token.TagWhile) {
			// Expected statement.
			return false
		}
		if !p.parseCondition() {
			return false
		}
		if !p.match(token.TagDo) {
			return false
		}
		if !p.parseStatement() {
			return false
		}
	}
	return true
}

func (p *Parser) parseCondition() bool {
	if p.match(token.TagOdd) {
		if !p.parseExpression() {
			return false
		}
	} else {
		if !p.parseExpression() {
			// Expected condition.
			return false
		}
		if !(p.match(token.TagEquals) || p.match(token.TagNotEquals) ||
			p.match(token.TagLessThan) || p.match(token.TagLessThanEqualTo) ||
			p.match(token.TagGreaterThan) || p.match(token.TagGreaterThanEqualTo)) {
			return false
		}
		if !p.parseExpression() {
			return false
		}
	}
	return true
}

func (p *Parser) parseExpression() bool {
	p.match(token.TagPlus)
	p.match(token.TagMinus)

	if !p.parseTerm() {
		return false
	}
	for {
		if !(p.match(token.TagPlus) || p.match(token.TagMinus)) {
			break
		}
		if !p.parseTerm() {
			return false
		}
	}
	return true
}

func (p *Parser) parseTerm() bool {
	if p.parseFactor() {
		for {
			if !(p.match(token.TagTimes) || p.match(token.TagDivide)) {
				break
			}
			if !p.parseFactor() {
				return false
			}
		}
		return true
	}
	return false
}

func (p *Parser) parseFactor() bool {
	if p.match(token.TagIdentifier) {
	} else if p.match(token.TagInteger) {
	} else {
		if !p.match(token.TagLeftParen) {
			return false
		}
		if !p.parseExpression() {
			return false
		}
		if !p.match(token.TagRightParen) {
			return false
		}
	}
	return true
}

func (p *Parser) move() {
	tok := p.lex.Scan()
	p.look = tok
}

func (p *Parser) match(t int) bool {
	if p.look.Tag == t {
		p.move()
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package syslog

import (
	"fmt"
	"net"
	"time"
)

type Message struct {
	Time   time.Time
	Source net.Addr
	Facility
	Severity
	Timestamp time.Time // optional
	Hostname  string    // optional
	Tag       string    // message tag as defined in RFC 3164
	Content   string    // message content as defined in RFC 3164
	Tag1      string    // alternate message tag (white rune as separator)
	Content1  string    // alternate message content (white rune as separator)
}

// NetSrc only network part of Source as string (IP for UDP or Name for UDS)
func (m *Message) NetSrc() string {
	switch a := m.Source.(type) {
	case *net.UDPAddr:
		return a.IP.String()
	case *net.UnixAddr:
		return a.Name
	case *net.TCPAddr:
		return a.IP.String()
	}
	// Unknown type
	return m.Source.String()
}

func (m *Message) String() string {
	timeLayout := "2006-01-02 15:04:05"
	return fmt.Sprintf(
		"%s %s %s %s%s",
		m.Time.Format(timeLayout), m.Source,
		m.Hostname, m.Tag, m.Content,
	)
}
<commit_msg>fix(logger): remove Source and Tag from output<commit_after>package syslog

import (
	"fmt"
	"net"
	"time"
)

type Message struct {
	Time   time.Time
	Source net.Addr
	Facility
	Severity
	Timestamp time.Time // optional
	Hostname  string    // optional
	Tag       string    // message tag as defined in RFC 3164
	Content   string    // message content as defined in RFC 3164
	Tag1      string    // alternate message tag (white rune as separator)
	Content1  string    // alternate message content (white rune as separator)
}

// NetSrc only network part of Source as string (IP for UDP or Name for UDS)
func (m *Message) NetSrc() string {
	switch a := m.Source.(type) {
	case *net.UDPAddr:
		return a.IP.String()
	case *net.UnixAddr:
		return a.Name
	case *net.TCPAddr:
		return a.IP.String()
	}
	// Unknown type
	return m.Source.String()
}

func (m *Message) String() string {
	timeLayout := "2006-01-02 15:04:05"
	return fmt.Sprintf(
		"%s %s %s",
		m.Time.Format(timeLayout),
		m.Hostname,
		m.Content,
	)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes 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 options

import (
	"fmt"
	"strings"

	"github.com/spf13/pflag"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/admission/initializer"
	admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
	"k8s.io/apiserver/pkg/admission/plugin/initialization"
	"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
	mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
	validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
	apiserverapi "k8s.io/apiserver/pkg/apis/apiserver"
	apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
	"k8s.io/apiserver/pkg/server"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

var scheme = runtime.NewScheme()

func init() {
	apiserverapi.AddToScheme(scheme)
	apiserverapiv1alpha1.AddToScheme(scheme)
}

// AdmissionOptions holds the admission options
type AdmissionOptions struct {
	// RecommendedPluginOrder holds an ordered list of plugin names we recommend to use by default
	RecommendedPluginOrder []string
	// DefaultOffPlugins a list of plugin names that should be disabled by default
	DefaultOffPlugins []string
	PluginNames       []string
	ConfigFile        string

	Plugins *admission.Plugins
}

// NewAdmissionOptions creates a new instance of AdmissionOptions
// Note:
//  In addition it calls RegisterAllAdmissionPlugins to register
//  all generic admission plugins.
//
//  Provides the list of RecommendedPluginOrder that holds sane values
//  that can be used by servers that don't care about admission chain.
//  Servers that do care can overwrite/append that field after creation.
func NewAdmissionOptions() *AdmissionOptions {
	options := &AdmissionOptions{
		Plugins:     admission.NewPlugins(),
		PluginNames: []string{},
		// This list is mix of mutating admission plugins and validating
		// admission plugins. The apiserver always runs the validating ones
		// after all the mutating ones, so their relative order in this list
		// doesn't matter.
		RecommendedPluginOrder: []string{lifecycle.PluginName, initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
		DefaultOffPlugins:      []string{initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
	}
	server.RegisterAllAdmissionPlugins(options.Plugins)
	return options
}

// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
	fs.StringSliceVar(&a.PluginNames, "admission-control", a.PluginNames, ""+
		"Admission is divided into two phases. "+
		"In the first phase, only mutating admission plugins run. "+
		"In the second phase, only validating admission plugins run. "+
		"The names in the below list may represent a validating plugin, a mutating plugin, or both. "+
		"Within each phase, the plugins will run in the order in which they are passed to this flag. "+
		"Comma-delimited list of: "+strings.Join(a.Plugins.Registered(), ", ")+".")

	fs.StringVar(&a.ConfigFile, "admission-control-config-file", a.ConfigFile,
		"File with admission control configuration.")
}

// ApplyTo adds the admission chain to the server configuration.
// In case admission plugin names were not provided by a custer-admin they will be prepared from the recommended/default values.
// In addition the method lazily initializes a generic plugin that is appended to the list of pluginInitializers
// note this method uses:
//  genericconfig.Authorizer
func (a *AdmissionOptions) ApplyTo(
	c *server.Config,
	informers informers.SharedInformerFactory,
	kubeAPIServerClientConfig *rest.Config,
	scheme *runtime.Scheme,
	pluginInitializers ...admission.PluginInitializer,
) error {
	pluginNames := a.PluginNames
	if len(a.PluginNames) == 0 {
		pluginNames = a.enabledPluginNames()
	}

	pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(pluginNames, a.ConfigFile, scheme)
	if err != nil {
		return fmt.Errorf("failed to read plugin config: %v", err)
	}

	clientset, err := kubernetes.NewForConfig(kubeAPIServerClientConfig)
	if err != nil {
		return err
	}
	genericInitializer := initializer.New(clientset, informers, c.Authorizer, scheme)
	initializersChain := admission.PluginInitializers{}
	pluginInitializers = append(pluginInitializers, genericInitializer)
	initializersChain = append(initializersChain, pluginInitializers...)

	admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, admissionmetrics.WithControllerMetrics)
	if err != nil {
		return err
	}

	c.AdmissionControl = admissionmetrics.WithStepMetrics(admissionChain)
	return nil
}

func (a *AdmissionOptions) Validate() []error {
	errs := []error{}
	return errs
}

// enabledPluginNames makes use of RecommendedPluginOrder and DefaultOffPlugins fields
// to prepare a list of plugin names that are enabled.
//
// TODO(p0lyn0mial): In the end we will introduce two new flags:
// --disable-admission-plugin this would be a list of admission plugins that a cluster-admin wants to explicitly disable.
// --enable-admission-plugin  this would be a list of admission plugins that a cluster-admin wants to explicitly enable.
// both flags are going to be handled by this method
func (a *AdmissionOptions) enabledPluginNames() []string {
	//TODO(p0lyn0mial): first subtract plugins that a user wants to explicitly enable from allOffPlugins (DefaultOffPlugins)
	//TODO(p0lyn0miial): then add/append plugins that a user wants to explicitly disable to allOffPlugins
	//TODO(p0lyn0mial): so that --off=three --on=one,three default-off=one,two results in  "one" being enabled.
	allOffPlugins := a.DefaultOffPlugins
	onlyEnabledPluginNames := []string{}
	for _, pluginName := range a.RecommendedPluginOrder {
		disablePlugin := false
		for _, disabledPluginName := range allOffPlugins {
			if pluginName == disabledPluginName {
				disablePlugin = true
				break
			}
		}
		if disablePlugin {
			continue
		}
		onlyEnabledPluginNames = append(onlyEnabledPluginNames, pluginName)
	}

	return onlyEnabledPluginNames
}
<commit_msg>UPSTREAM: 58439: Fix loading structured admission plugin config<commit_after>/*
Copyright 2017 The Kubernetes 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 options

import (
	"fmt"
	"strings"

	"github.com/spf13/pflag"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/admission"
	"k8s.io/apiserver/pkg/admission/initializer"
	admissionmetrics "k8s.io/apiserver/pkg/admission/metrics"
	"k8s.io/apiserver/pkg/admission/plugin/initialization"
	"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
	mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
	validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
	apiserverapi "k8s.io/apiserver/pkg/apis/apiserver"
	apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
	"k8s.io/apiserver/pkg/server"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

var configScheme = runtime.NewScheme()

func init() {
	apiserverapi.AddToScheme(configScheme)
	apiserverapiv1alpha1.AddToScheme(configScheme)
}

// AdmissionOptions holds the admission options
type AdmissionOptions struct {
	// RecommendedPluginOrder holds an ordered list of plugin names we recommend to use by default
	RecommendedPluginOrder []string
	// DefaultOffPlugins a list of plugin names that should be disabled by default
	DefaultOffPlugins []string
	PluginNames       []string
	ConfigFile        string

	Plugins *admission.Plugins
}

// NewAdmissionOptions creates a new instance of AdmissionOptions
// Note:
//  In addition it calls RegisterAllAdmissionPlugins to register
//  all generic admission plugins.
//
//  Provides the list of RecommendedPluginOrder that holds sane values
//  that can be used by servers that don't care about admission chain.
//  Servers that do care can overwrite/append that field after creation.
func NewAdmissionOptions() *AdmissionOptions {
	options := &AdmissionOptions{
		Plugins:     admission.NewPlugins(),
		PluginNames: []string{},
		// This list is mix of mutating admission plugins and validating
		// admission plugins. The apiserver always runs the validating ones
		// after all the mutating ones, so their relative order in this list
		// doesn't matter.
		RecommendedPluginOrder: []string{lifecycle.PluginName, initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
		DefaultOffPlugins:      []string{initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName},
	}
	server.RegisterAllAdmissionPlugins(options.Plugins)
	return options
}

// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
	fs.StringSliceVar(&a.PluginNames, "admission-control", a.PluginNames, ""+
		"Admission is divided into two phases. "+
		"In the first phase, only mutating admission plugins run. "+
		"In the second phase, only validating admission plugins run. "+
		"The names in the below list may represent a validating plugin, a mutating plugin, or both. "+
		"Within each phase, the plugins will run in the order in which they are passed to this flag. "+
		"Comma-delimited list of: "+strings.Join(a.Plugins.Registered(), ", ")+".")

	fs.StringVar(&a.ConfigFile, "admission-control-config-file", a.ConfigFile,
		"File with admission control configuration.")
}

// ApplyTo adds the admission chain to the server configuration.
// In case admission plugin names were not provided by a custer-admin they will be prepared from the recommended/default values.
// In addition the method lazily initializes a generic plugin that is appended to the list of pluginInitializers
// note this method uses:
//  genericconfig.Authorizer
func (a *AdmissionOptions) ApplyTo(
	c *server.Config,
	informers informers.SharedInformerFactory,
	kubeAPIServerClientConfig *rest.Config,
	scheme *runtime.Scheme,
	pluginInitializers ...admission.PluginInitializer,
) error {
	pluginNames := a.PluginNames
	if len(a.PluginNames) == 0 {
		pluginNames = a.enabledPluginNames()
	}

	pluginsConfigProvider, err := admission.ReadAdmissionConfiguration(pluginNames, a.ConfigFile, configScheme)
	if err != nil {
		return fmt.Errorf("failed to read plugin config: %v", err)
	}

	clientset, err := kubernetes.NewForConfig(kubeAPIServerClientConfig)
	if err != nil {
		return err
	}
	genericInitializer := initializer.New(clientset, informers, c.Authorizer, scheme)
	initializersChain := admission.PluginInitializers{}
	pluginInitializers = append(pluginInitializers, genericInitializer)
	initializersChain = append(initializersChain, pluginInitializers...)

	admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, admissionmetrics.WithControllerMetrics)
	if err != nil {
		return err
	}

	c.AdmissionControl = admissionmetrics.WithStepMetrics(admissionChain)
	return nil
}

func (a *AdmissionOptions) Validate() []error {
	errs := []error{}
	return errs
}

// enabledPluginNames makes use of RecommendedPluginOrder and DefaultOffPlugins fields
// to prepare a list of plugin names that are enabled.
//
// TODO(p0lyn0mial): In the end we will introduce two new flags:
// --disable-admission-plugin this would be a list of admission plugins that a cluster-admin wants to explicitly disable.
// --enable-admission-plugin  this would be a list of admission plugins that a cluster-admin wants to explicitly enable.
// both flags are going to be handled by this method
func (a *AdmissionOptions) enabledPluginNames() []string {
	//TODO(p0lyn0mial): first subtract plugins that a user wants to explicitly enable from allOffPlugins (DefaultOffPlugins)
	//TODO(p0lyn0miial): then add/append plugins that a user wants to explicitly disable to allOffPlugins
	//TODO(p0lyn0mial): so that --off=three --on=one,three default-off=one,two results in  "one" being enabled.
	allOffPlugins := a.DefaultOffPlugins
	onlyEnabledPluginNames := []string{}
	for _, pluginName := range a.RecommendedPluginOrder {
		disablePlugin := false
		for _, disabledPluginName := range allOffPlugins {
			if pluginName == disabledPluginName {
				disablePlugin = true
				break
			}
		}
		if disablePlugin {
			continue
		}
		onlyEnabledPluginNames = append(onlyEnabledPluginNames, pluginName)
	}

	return onlyEnabledPluginNames
}
<|endoftext|>