<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
)

/**
 * I can't use http.ServeFile due to https://github.com/golang/go/issues/13892
 *
 * As a workaround I'm going to spool the entire file into memory and then
 * write it back.. This won't fly on a popular server, but ehh right now
 * I'm only serving myself ;-)
 */
func serveFile(w http.ResponseWriter, r *http.Request, path string, content_type string) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		sendResponse(w, InternalError,
			map[string]interface{}{
				"code":    "InternalError",
				"message": fmt.Sprintf("Failed to read file %s: %v", path, err),
			})
		return
	}

	h := w.Header()
	h.Set("Server", "Norbye Public Images Repo")
	h.Set("Content-Type", content_type)
	h.Set("Content-Length", strconv.Itoa(len(content)))
	_, err = w.Write(content)
	if err != nil {
		log.Printf("Failed to send %s: %v", path, err)
	}
}

func sendResponse(w http.ResponseWriter, code int, content map[string]interface{}) {
	h := w.Header()
	h.Set("Server", "Norbye Public Images Repo")

	if content == nil {
		w.WriteHeader(code)
		return
	}

	h.Set("Content-Type", "application/json; charset=utf-8")

	a, err := json.MarshalIndent(content, "", "  ")
	if err != nil {
		log.Printf("Failed to convert response to JSON: %v",
			err)
		a, err = json.MarshalIndent(map[string]interface{}{
			"code":    "InvalidError",
			"message": fmt.Sprintf("%v", err),
		}, "", "")
		code = InternalError
	}

	w.WriteHeader(code)
	w.Write(a)
}

/**
 * Split up the /images/:uuid/file URL
 */
func splitImagesUrl(url string) (uuid string, file string, err error) {
	if strings.Index(url, "/images/") != 0 {
		return uuid, file, errors.New("Invalid url")
	}

	// pick out the uuid
	uuid = url[8:] // everything after "/images/"
	if len(uuid) == 0 {
		return uuid, file, errors.New("Invalid url")
	}

	index := strings.Index(uuid, "/")
	file = ""
	if index != -1 {
		file = uuid[index:]
		uuid = uuid[0:index]
	}

	return uuid, file, nil
}

/*
Name	Endpoint	Notes
ListImages	GET /images	List available images.
GetImage	GET /images/:uuid	Get a particular image manifest.
GetImageFile	GET /images/:uuid/file	Get the file for this image.
GetImageIcon	GET /images/:uuid/icon	Get the image icon file.
*/

// Handle all GET request made to /images
func doHandleGetImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	if r.URL.Path == "/images" {
		serverListImages(configuration.Datadir, w, r)
		return
	}

	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": fmt.Sprintf("%v", err),
			})
		return
	}

	// check if the resource exists
	filename := configuration.Datadir + "/" + uuid
	_, err = os.Stat(filename)
	if err != nil {
		sendResponse(w, ResourceNotFound,
			map[string]interface{}{
				"code":    "ResourceNotFound",
				"message": fmt.Sprintf("Failed to locate %s: %v", filename, err),
			})
		return
	}

	// Ok, everything should be OK.. go do it!
	if len(file) == 0 {
		serverGetImage(w, r, params, filename)
		return
	}

	if file == "/icon" {
		serverGetImageIcon(w, r, params, filename)
		return
	}

	if file == "/file" {
		serverGetImageFile(w, r, params, filename)
		return
	}

	sendResponse(w, ResourceNotFound,
		map[string]interface{}{
			"code":    "ResourceNotFound",
			"message": "Requested resource does not exist",
		})
}

/*
Handle all DELETE request made to /images
DeleteImage	DELETE /images/:uuid	Delete an image (and its file).
DeleteImageIcon	DELETE /images/:uuid/icon	Remove the image icon.
*/
func doHandleDeleteImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	if len(file) > 0 {
		if file == "/icon" {
			serverDeleteImageIcon(w, r, params, path)
		} else {
			sendResponse(w, ResourceNotFound,
				map[string]interface{}{
					"code":    "ResourceNotFound",
					"message": "Resource does not exists",
				})
		}
	} else {
		serverDeleteImage(w, r, params, path)
	}
}

// Handle all POST request made to /images
/*
CreateImage	POST /images	Create a new (unactivated) image from a manifest.

ActivateImage	POST /images/:uuid?action=activate	Activate the image.
UpdateImage	POST /images/:uuid?action=update	Update image manifest fields. This is limited. Some fields are immutable.
DisableImage	POST /images/:uuid?action=disable	Disable the image.
EnableImage	POST /images/:uuid?action=enable	Enable the image.
ExportImage	POST /images/:uuid?action=export	Exports an image to the specified Manta path.
CopyRemoteImage	POST /images/$uuid?action=copy-remote&dc=us-west-1	NYI (IMGAPI-278) Copy one's own image from another DC in the same cloud.
AdminImportRemoteImage	POST /images/$uuid?action=import-remote&source=$imgapi-url	Import an image from another IMGAPI
AdminImportImage	POST /images/$uuid?action=import	Only for operators to import an image and maintain uuid and published_at.
ChannelAddImage	POST /images/:uuid?action=channel-add	Add an existing image to another channel.

AddImageAcl	POST /images/:uuid/acl?action=add	Add account UUIDs to the image ACL.
RemoveImageAcl	POST /images/:uuid/acl?action=remove	Remove account UUIDs from the image ACL.

AddImageIcon	POST /images/:uuid/icon	Add the image icon.

CreateImageFromVm	POST /images?action=create-from-vm	Create a new (activated) image from an existing VM.

*/
func doHandlePostImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	if "/images" == r.URL.Path {
		serverCreateImage(w, r, params, configuration.Datadir)
		return
	}

	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	_, err = os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			sendResponse(w, ResourceNotFound,
				map[string]interface{}{
					"code":    "ResourceNotFound",
					"message": "Failed to locate resource",
				})
		} else {
			sendResponse(w, InternalError,
				map[string]interface{}{
					"code":    "InternalError",
					"message": fmt.Sprintf("Failed to locate resource %v", err),
				})
		}
		return
	}

	switch file {
	case "/icon":
		serverAddImageIcon(w, r, params, path)
		return

	case "/acl":
		sendResponse(w, InsufficientServerVersion,
			map[string]interface{}{
				"code":    "InsufficientServerVersion",
				"message": "acl is not implemented",
			})
		break

	case "": // the path just contains the UUID and optional parameters
		action, ok := params["action"]
		if ok {
			switch action[0] {
			case "activate":
				serverActivateImage(w, r, params, path)
				break
			case "update":
				serverUpdateImage(w, r, params, path)
				break
			case "disable":
				serverDisableImage(w, r, params, path)
				break
			case "enable":
				serverEnableImage(w, r, params, path)
				break

			case "export":
				fallthrough
			case "copy-remote":
				fallthrough
			case "import-remote":
				fallthrough
			case "import":
				fallthrough
			case "channel-add":
				// Not implemented yet
				sendResponse(w, InsufficientServerVersion,
					map[string]interface{}{
						"code":    "InsufficientServerVersion",
						"message": fmt.Sprintf("action=\"%s\" is not implemented", action[0]),
					})
				break

			default:
				sendResponse(w, InvalidParameter,
					map[string]interface{}{
						"code":    "InvalidParameter",
						"message": fmt.Sprintf("Invalid action \"%s\"", action[0]),
					})
			}
		} else {
			sendResponse(w, InvalidParameter,
				map[string]interface{}{
					"code":    "InvalidParameter",
					"message": "action parameter not specified",
				})
		}
		return
	default:
		// The request was for an invalid resource
		sendResponse(w, ResourceNotFound,
			map[string]interface{}{
				"code":    "ResourceNotFound",
				"message": "Invalid URL specified",
			})
		return
	}
}

/*
 * Handle all PUT request made to /images
 *  AddImageFile	PUT /images/:uuid/file	Upload the image file.
 */
func doHandlePutImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil || file != "/file" {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	serverAddImageFile(w, r, params, path)
}

/**
 * Handle all of the requests to "/images*" and dispatch the
 * request to the correct handler function.
 *
 * All operations that modify data _DO_ requre that the user
 * provides a username and password. (currently all users
 * have access to all commands)
 */
func doHandleImages(w http.ResponseWriter, r *http.Request) {
	authenticated := false

	username, password, ok := r.BasicAuth()
	if ok {
		found := false
		for i := 0; i < len(configuration.Userdb); i++ {
			entry := configuration.Userdb[i]
			if username != entry.Name {
				continue
			}

			found = true
			if password != entry.Password {
				log.Printf("Invalid username password combo for %s", username)
				sendResponse(w, UnauthorizedError,
					map[string]interface{}{
						"code":    "UnauthorizedError",
						"message": "Invalid username/password combination",
					})

				return
			}
		}

		if !found {
			log.Printf("User %s does not exists", username)
			sendResponse(w, AccountDoesNotExist,
				map[string]interface{}{
					"code":    "AccountDoesNotExist",
					"message": fmt.Sprintf("User %s does not exist", username),
				})
			return
		}

		authenticated = true
	}

	parameters, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		sendResponse(w, InternalError,
			map[string]interface{}{
				"code":    "InternalError",
				"message": "Failed to parse query",
			})
		return
	}
	if len(r.Method) == 0 || r.Method == "GET" {
		doHandleGetImages(w, r, parameters)
	} else if r.Method == "DELETE" {
		if authenticated {
			doHandleDeleteImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	} else if r.Method == "POST" {
		if authenticated {
			doHandlePostImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	} else if r.Method == "PUT" {
		if authenticated {
			doHandlePutImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	}
}

/*
AdminGetState	GET /state	Dump internal server state (for dev/debugging)
ListChannels	GET /channels	List image channels (if the server uses channels).
Ping	GET /ping	Ping if the server is up.
*/

func startImageServer() {
	_, err := os.Stat(configuration.Datadir)
	if err != nil && os.IsNotExist(err) {
		err = os.MkdirAll(configuration.Datadir, 0777)
		if err != nil {
			panic(fmt.Sprintf("Failed to create %s: %v",
				configuration.Datadir, err))
		}
	}

	http.HandleFunc("/images", doHandleImages)
	http.HandleFunc("/images/", doHandleImages)
	http.HandleFunc("/channels", serverListChannels)
	http.HandleFunc("/ping", serverPing)
	http.ListenAndServe(":"+strconv.Itoa(configuration.Port), nil)
}
<commit_msg>Report error if size of sent payload does not match<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
)

/**
 * I can't use http.ServeFile due to https://github.com/golang/go/issues/13892
 *
 * As a workaround I'm going to spool the entire file into memory and then
 * write it back.. This won't fly on a popular server, but ehh right now
 * I'm only serving myself ;-)
 */
func serveFile(w http.ResponseWriter, r *http.Request, path string, content_type string) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		sendResponse(w, InternalError,
			map[string]interface{}{
				"code":    "InternalError",
				"message": fmt.Sprintf("Failed to read file %s: %v", path, err),
			})
		return
	}

	h := w.Header()
	h.Set("Server", "Norbye Public Images Repo")
	h.Set("Content-Type", content_type)
	contentLength := len(content)
	h.Set("Content-Length", strconv.Itoa(contentLength))
	nw, err := w.Write(content)
	if err != nil {
		log.Printf("Failed to send %s: %v", path, err)
	}
	if nw != contentLength {
		log.Printf("Size of sent payload (%d) does not match expected (%d) fo %s", nw, contentLength, path)
	}
}

func sendResponse(w http.ResponseWriter, code int, content map[string]interface{}) {
	h := w.Header()
	h.Set("Server", "Norbye Public Images Repo")

	if content == nil {
		w.WriteHeader(code)
		return
	}

	h.Set("Content-Type", "application/json; charset=utf-8")

	a, err := json.MarshalIndent(content, "", "  ")
	if err != nil {
		log.Printf("Failed to convert response to JSON: %v",
			err)
		a, err = json.MarshalIndent(map[string]interface{}{
			"code":    "InvalidError",
			"message": fmt.Sprintf("%v", err),
		}, "", "")
		code = InternalError
	}

	w.WriteHeader(code)
	w.Write(a)
}

/**
 * Split up the /images/:uuid/file URL
 */
func splitImagesUrl(url string) (uuid string, file string, err error) {
	if strings.Index(url, "/images/") != 0 {
		return uuid, file, errors.New("Invalid url")
	}

	// pick out the uuid
	uuid = url[8:] // everything after "/images/"
	if len(uuid) == 0 {
		return uuid, file, errors.New("Invalid url")
	}

	index := strings.Index(uuid, "/")
	file = ""
	if index != -1 {
		file = uuid[index:]
		uuid = uuid[0:index]
	}

	return uuid, file, nil
}

/*
Name	Endpoint	Notes
ListImages	GET /images	List available images.
GetImage	GET /images/:uuid	Get a particular image manifest.
GetImageFile	GET /images/:uuid/file	Get the file for this image.
GetImageIcon	GET /images/:uuid/icon	Get the image icon file.
*/

// Handle all GET request made to /images
func doHandleGetImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	if r.URL.Path == "/images" {
		serverListImages(configuration.Datadir, w, r)
		return
	}

	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": fmt.Sprintf("%v", err),
			})
		return
	}

	// check if the resource exists
	filename := configuration.Datadir + "/" + uuid
	_, err = os.Stat(filename)
	if err != nil {
		sendResponse(w, ResourceNotFound,
			map[string]interface{}{
				"code":    "ResourceNotFound",
				"message": fmt.Sprintf("Failed to locate %s: %v", filename, err),
			})
		return
	}

	// Ok, everything should be OK.. go do it!
	if len(file) == 0 {
		serverGetImage(w, r, params, filename)
		return
	}

	if file == "/icon" {
		serverGetImageIcon(w, r, params, filename)
		return
	}

	if file == "/file" {
		serverGetImageFile(w, r, params, filename)
		return
	}

	sendResponse(w, ResourceNotFound,
		map[string]interface{}{
			"code":    "ResourceNotFound",
			"message": "Requested resource does not exist",
		})
}

/*
Handle all DELETE request made to /images
DeleteImage	DELETE /images/:uuid	Delete an image (and its file).
DeleteImageIcon	DELETE /images/:uuid/icon	Remove the image icon.
*/
func doHandleDeleteImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	if len(file) > 0 {
		if file == "/icon" {
			serverDeleteImageIcon(w, r, params, path)
		} else {
			sendResponse(w, ResourceNotFound,
				map[string]interface{}{
					"code":    "ResourceNotFound",
					"message": "Resource does not exists",
				})
		}
	} else {
		serverDeleteImage(w, r, params, path)
	}
}

// Handle all POST request made to /images
/*
CreateImage	POST /images	Create a new (unactivated) image from a manifest.

ActivateImage	POST /images/:uuid?action=activate	Activate the image.
UpdateImage	POST /images/:uuid?action=update	Update image manifest fields. This is limited. Some fields are immutable.
DisableImage	POST /images/:uuid?action=disable	Disable the image.
EnableImage	POST /images/:uuid?action=enable	Enable the image.
ExportImage	POST /images/:uuid?action=export	Exports an image to the specified Manta path.
CopyRemoteImage	POST /images/$uuid?action=copy-remote&dc=us-west-1	NYI (IMGAPI-278) Copy one's own image from another DC in the same cloud.
AdminImportRemoteImage	POST /images/$uuid?action=import-remote&source=$imgapi-url	Import an image from another IMGAPI
AdminImportImage	POST /images/$uuid?action=import	Only for operators to import an image and maintain uuid and published_at.
ChannelAddImage	POST /images/:uuid?action=channel-add	Add an existing image to another channel.

AddImageAcl	POST /images/:uuid/acl?action=add	Add account UUIDs to the image ACL.
RemoveImageAcl	POST /images/:uuid/acl?action=remove	Remove account UUIDs from the image ACL.

AddImageIcon	POST /images/:uuid/icon	Add the image icon.

CreateImageFromVm	POST /images?action=create-from-vm	Create a new (activated) image from an existing VM.

*/
func doHandlePostImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	if "/images" == r.URL.Path {
		serverCreateImage(w, r, params, configuration.Datadir)
		return
	}

	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	_, err = os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			sendResponse(w, ResourceNotFound,
				map[string]interface{}{
					"code":    "ResourceNotFound",
					"message": "Failed to locate resource",
				})
		} else {
			sendResponse(w, InternalError,
				map[string]interface{}{
					"code":    "InternalError",
					"message": fmt.Sprintf("Failed to locate resource %v", err),
				})
		}
		return
	}

	switch file {
	case "/icon":
		serverAddImageIcon(w, r, params, path)
		return

	case "/acl":
		sendResponse(w, InsufficientServerVersion,
			map[string]interface{}{
				"code":    "InsufficientServerVersion",
				"message": "acl is not implemented",
			})
		break

	case "": // the path just contains the UUID and optional parameters
		action, ok := params["action"]
		if ok {
			switch action[0] {
			case "activate":
				serverActivateImage(w, r, params, path)
				break
			case "update":
				serverUpdateImage(w, r, params, path)
				break
			case "disable":
				serverDisableImage(w, r, params, path)
				break
			case "enable":
				serverEnableImage(w, r, params, path)
				break

			case "export":
				fallthrough
			case "copy-remote":
				fallthrough
			case "import-remote":
				fallthrough
			case "import":
				fallthrough
			case "channel-add":
				// Not implemented yet
				sendResponse(w, InsufficientServerVersion,
					map[string]interface{}{
						"code":    "InsufficientServerVersion",
						"message": fmt.Sprintf("action=\"%s\" is not implemented", action[0]),
					})
				break

			default:
				sendResponse(w, InvalidParameter,
					map[string]interface{}{
						"code":    "InvalidParameter",
						"message": fmt.Sprintf("Invalid action \"%s\"", action[0]),
					})
			}
		} else {
			sendResponse(w, InvalidParameter,
				map[string]interface{}{
					"code":    "InvalidParameter",
					"message": "action parameter not specified",
				})
		}
		return
	default:
		// The request was for an invalid resource
		sendResponse(w, ResourceNotFound,
			map[string]interface{}{
				"code":    "ResourceNotFound",
				"message": "Invalid URL specified",
			})
		return
	}
}

/*
 * Handle all PUT request made to /images
 *  AddImageFile	PUT /images/:uuid/file	Upload the image file.
 */
func doHandlePutImages(w http.ResponseWriter, r *http.Request, params url.Values) {
	uuid, file, err := splitImagesUrl(r.URL.Path)
	if err != nil || file != "/file" {
		sendResponse(w, InvalidParameter,
			map[string]interface{}{
				"code":    "InvalidParameter",
				"message": "Failed to decode URL",
			})
		return
	}

	path := configuration.Datadir + "/" + uuid
	serverAddImageFile(w, r, params, path)
}

/**
 * Handle all of the requests to "/images*" and dispatch the
 * request to the correct handler function.
 *
 * All operations that modify data _DO_ requre that the user
 * provides a username and password. (currently all users
 * have access to all commands)
 */
func doHandleImages(w http.ResponseWriter, r *http.Request) {
	authenticated := false

	username, password, ok := r.BasicAuth()
	if ok {
		found := false
		for i := 0; i < len(configuration.Userdb); i++ {
			entry := configuration.Userdb[i]
			if username != entry.Name {
				continue
			}

			found = true
			if password != entry.Password {
				log.Printf("Invalid username password combo for %s", username)
				sendResponse(w, UnauthorizedError,
					map[string]interface{}{
						"code":    "UnauthorizedError",
						"message": "Invalid username/password combination",
					})

				return
			}
		}

		if !found {
			log.Printf("User %s does not exists", username)
			sendResponse(w, AccountDoesNotExist,
				map[string]interface{}{
					"code":    "AccountDoesNotExist",
					"message": fmt.Sprintf("User %s does not exist", username),
				})
			return
		}

		authenticated = true
	}

	parameters, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		sendResponse(w, InternalError,
			map[string]interface{}{
				"code":    "InternalError",
				"message": "Failed to parse query",
			})
		return
	}
	if len(r.Method) == 0 || r.Method == "GET" {
		doHandleGetImages(w, r, parameters)
	} else if r.Method == "DELETE" {
		if authenticated {
			doHandleDeleteImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	} else if r.Method == "POST" {
		if authenticated {
			doHandlePostImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	} else if r.Method == "PUT" {
		if authenticated {
			doHandlePutImages(w, r, parameters)
		} else {
			w.WriteHeader(UnauthorizedError)
		}
	}
}

/*
AdminGetState	GET /state	Dump internal server state (for dev/debugging)
ListChannels	GET /channels	List image channels (if the server uses channels).
Ping	GET /ping	Ping if the server is up.
*/

func startImageServer() {
	_, err := os.Stat(configuration.Datadir)
	if err != nil && os.IsNotExist(err) {
		err = os.MkdirAll(configuration.Datadir, 0777)
		if err != nil {
			panic(fmt.Sprintf("Failed to create %s: %v",
				configuration.Datadir, err))
		}
	}

	http.HandleFunc("/images", doHandleImages)
	http.HandleFunc("/images/", doHandleImages)
	http.HandleFunc("/channels", serverListChannels)
	http.HandleFunc("/ping", serverPing)
	http.ListenAndServe(":"+strconv.Itoa(configuration.Port), nil)
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
)

type Entry struct {
	ChainID string   `json:"chainid"`
	ExtIDs  [][]byte `json:"extids"`
	Content []byte   `json:"content"`
}

func (e *Entry) Hash() []byte {
	a, err := e.MarshalBinary()
	if err != nil {
		return make([]byte, 32)
	}
	return sha52(a)
}

func (e *Entry) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	ids, err := e.MarshalExtIDsBinary()
	if err != nil {
		return buf.Bytes(), err
	}

	// Header

	// 1 byte Version
	buf.Write([]byte{0})

	// 32 byte chainid
	if p, err := hex.DecodeString(e.ChainID); err != nil {
		return buf.Bytes(), err
	} else {
		buf.Write(p)
	}

	// 2 byte size of extids
	if err := binary.Write(buf, binary.BigEndian, int16(len(ids))); err != nil {
		return buf.Bytes(), err
	}

	// Body

	// ExtIDs
	buf.Write(ids)

	// Content
	buf.Write(e.Content)

	return buf.Bytes(), nil
}

func (e *Entry) MarshalExtIDsBinary() ([]byte, error) {
	buf := new(bytes.Buffer)

	for _, v := range e.ExtIDs {
		// 2 byte length of extid
		binary.Write(buf, binary.BigEndian, int16(len(v)))
		// extid
		buf.Write(v)
	}

	return buf.Bytes(), nil
}

func (e *Entry) MarshalJSON() ([]byte, error) {
	type js struct {
		ChainID string   `json:"chainid"`
		ExtIDs  []string `json:"extids"`
		Content string   `json:"content"`
	}

	j := new(js)

	j.ChainID = e.ChainID

	for _, id := range e.ExtIDs {
		j.ExtIDs = append(j.ExtIDs, hex.EncodeToString(id))
	}

	j.Content = hex.EncodeToString(e.Content)

	return json.Marshal(j)
}

func (e *Entry) String() string {
	var s string
	s += fmt.Sprintln("ChainID:", e.ChainID)
	for _, id := range e.ExtIDs {
		s += fmt.Sprintln("ExtID:", string(id))
	}
	s += fmt.Sprintln("Content:")
	s += fmt.Sprintln(string(e.Content))
	return s
}

func (e *Entry) UnmarshalJSON(data []byte) error {
	type js struct {
		ChainID   string   `json:"chainid"`
		ChainName []string `json:"chainname"`
		ExtIDs    []string `json:"extids"`
		Content   string   `json:"content"`
	}

	j := new(js)
	if err := json.Unmarshal(data, j); err != nil {
		return err
	}

	e.ChainID = j.ChainID

	if e.ChainID == "" {
		n := new(Entry)
		for _, v := range j.ChainName {
			if p, err := hex.DecodeString(v); err != nil {
				return fmt.Errorf("Could not decode ChainName %s: %s", v, err)
			} else {
				n.ExtIDs = append(n.ExtIDs, p)
			}
		}
		m := NewChain(n)
		e.ChainID = m.ChainID
	}

	for _, v := range j.ExtIDs {
		if p, err := hex.DecodeString(v); err != nil {
			return fmt.Errorf("Could not decode ExtID %s: %s", v, err)
		} else {
			e.ExtIDs = append(e.ExtIDs, p)
		}
	}

	p, err := hex.DecodeString(j.Content)
	if err != nil {
		return fmt.Errorf("Could not decode Content %s: %s", j.Content, err)
	}
	e.Content = p

	return nil
}

// ComposeEntryCommit creates a JSON2Request to commit a new Entry via the
// factomd web api. The request includes the marshaled MessageRequest with the
// Entry Credit Signature.
func ComposeEntryCommit(e *Entry, ec *ECAddress) (*JSON2Request, error) {
	buf := new(bytes.Buffer)

	// 1 byte version
	buf.Write([]byte{0})

	// 6 byte milliTimestamp (truncated unix time)
	buf.Write(milliTime())

	// 32 byte Entry Hash
	buf.Write(e.Hash())

	// 1 byte number of entry credits to pay
	if c, err := entryCost(e); err != nil {
		return nil, err
	} else {
		buf.WriteByte(byte(c))
	}

	// 32 byte Entry Credit Address Public Key + 64 byte Signature
	sig := ec.Sign(buf.Bytes())
	buf.Write(ec.PubBytes())
	buf.Write(sig[:])

	params := entryRequest{Entry: hex.EncodeToString(buf.Bytes())}
	req := NewJSON2Request("commit-entry", apiCounter(), params)

	return req, nil
}

// ComposeEntryReveal creates a JSON2Request to reveal the Entry via the factomd
// web api.
func ComposeEntryReveal(e *Entry) (*JSON2Request, error) {
	p, err := e.MarshalBinary()
	if err != nil {
		return nil, err
	}

	params := entryRequest{Entry: hex.EncodeToString(p)}
	req := NewJSON2Request("reveal-entry", apiCounter(), params)

	return req, nil
}

// CommitEntry sends the signed Entry Hash and the Entry Credit public key to
// the factom network. Once the payment is verified and the network is commited
// to publishing the Entry it may be published with a call to RevealEntry.
func CommitEntry(e *Entry, ec *ECAddress) (string, error) {
	type commitResponse struct {
		Message string `json:"message"`
		TxID    string `json:"txid"`
	}

	req, err := ComposeEntryReveal(e)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}
	r := new(commitResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}

	return r.TxID, nil
}

func RevealEntry(e *Entry) error {
	req, err := ComposeEntryReveal(e)
	if err != nil {
		return err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return err
	}
	if resp.Error != nil {
		return resp.Error
	}

	return nil
}
<commit_msg>Fix entry commit. Calling wrong function before<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
)

type Entry struct {
	ChainID string   `json:"chainid"`
	ExtIDs  [][]byte `json:"extids"`
	Content []byte   `json:"content"`
}

func (e *Entry) Hash() []byte {
	a, err := e.MarshalBinary()
	if err != nil {
		return make([]byte, 32)
	}
	return sha52(a)
}

func (e *Entry) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	ids, err := e.MarshalExtIDsBinary()
	if err != nil {
		return buf.Bytes(), err
	}

	// Header

	// 1 byte Version
	buf.Write([]byte{0})

	// 32 byte chainid
	if p, err := hex.DecodeString(e.ChainID); err != nil {
		return buf.Bytes(), err
	} else {
		buf.Write(p)
	}

	// 2 byte size of extids
	if err := binary.Write(buf, binary.BigEndian, int16(len(ids))); err != nil {
		return buf.Bytes(), err
	}

	// Body

	// ExtIDs
	buf.Write(ids)

	// Content
	buf.Write(e.Content)

	return buf.Bytes(), nil
}

func (e *Entry) MarshalExtIDsBinary() ([]byte, error) {
	buf := new(bytes.Buffer)

	for _, v := range e.ExtIDs {
		// 2 byte length of extid
		binary.Write(buf, binary.BigEndian, int16(len(v)))
		// extid
		buf.Write(v)
	}

	return buf.Bytes(), nil
}

func (e *Entry) MarshalJSON() ([]byte, error) {
	type js struct {
		ChainID string   `json:"chainid"`
		ExtIDs  []string `json:"extids"`
		Content string   `json:"content"`
	}

	j := new(js)

	j.ChainID = e.ChainID

	for _, id := range e.ExtIDs {
		j.ExtIDs = append(j.ExtIDs, hex.EncodeToString(id))
	}

	j.Content = hex.EncodeToString(e.Content)

	return json.Marshal(j)
}

func (e *Entry) String() string {
	var s string
	s += fmt.Sprintln("ChainID:", e.ChainID)
	for _, id := range e.ExtIDs {
		s += fmt.Sprintln("ExtID:", string(id))
	}
	s += fmt.Sprintln("Content:")
	s += fmt.Sprintln(string(e.Content))
	return s
}

func (e *Entry) UnmarshalJSON(data []byte) error {
	type js struct {
		ChainID   string   `json:"chainid"`
		ChainName []string `json:"chainname"`
		ExtIDs    []string `json:"extids"`
		Content   string   `json:"content"`
	}

	j := new(js)
	if err := json.Unmarshal(data, j); err != nil {
		return err
	}

	e.ChainID = j.ChainID

	if e.ChainID == "" {
		n := new(Entry)
		for _, v := range j.ChainName {
			if p, err := hex.DecodeString(v); err != nil {
				return fmt.Errorf("Could not decode ChainName %s: %s", v, err)
			} else {
				n.ExtIDs = append(n.ExtIDs, p)
			}
		}
		m := NewChain(n)
		e.ChainID = m.ChainID
	}

	for _, v := range j.ExtIDs {
		if p, err := hex.DecodeString(v); err != nil {
			return fmt.Errorf("Could not decode ExtID %s: %s", v, err)
		} else {
			e.ExtIDs = append(e.ExtIDs, p)
		}
	}

	p, err := hex.DecodeString(j.Content)
	if err != nil {
		return fmt.Errorf("Could not decode Content %s: %s", j.Content, err)
	}
	e.Content = p

	return nil
}

// ComposeEntryCommit creates a JSON2Request to commit a new Entry via the
// factomd web api. The request includes the marshaled MessageRequest with the
// Entry Credit Signature.
func ComposeEntryCommit(e *Entry, ec *ECAddress) (*JSON2Request, error) {
	buf := new(bytes.Buffer)

	// 1 byte version
	buf.Write([]byte{0})

	// 6 byte milliTimestamp (truncated unix time)
	buf.Write(milliTime())

	// 32 byte Entry Hash
	buf.Write(e.Hash())

	// 1 byte number of entry credits to pay
	if c, err := entryCost(e); err != nil {
		return nil, err
	} else {
		buf.WriteByte(byte(c))
	}

	// 32 byte Entry Credit Address Public Key + 64 byte Signature
	sig := ec.Sign(buf.Bytes())
	buf.Write(ec.PubBytes())
	buf.Write(sig[:])

	params := entryRequest{Entry: hex.EncodeToString(buf.Bytes())}
	req := NewJSON2Request("commit-entry", apiCounter(), params)

	return req, nil
}

// ComposeEntryReveal creates a JSON2Request to reveal the Entry via the factomd
// web api.
func ComposeEntryReveal(e *Entry) (*JSON2Request, error) {
	p, err := e.MarshalBinary()
	if err != nil {
		return nil, err
	}

	params := entryRequest{Entry: hex.EncodeToString(p)}
	req := NewJSON2Request("reveal-entry", apiCounter(), params)

	return req, nil
}

// CommitEntry sends the signed Entry Hash and the Entry Credit public key to
// the factom network. Once the payment is verified and the network is commited
// to publishing the Entry it may be published with a call to RevealEntry.
func CommitEntry(e *Entry, ec *ECAddress) (string, error) {
	type commitResponse struct {
		Message string `json:"message"`
		TxID    string `json:"txid"`
	}

	req, err := ComposeEntryCommit(e, ec)
	if err != nil {
		return "", err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}
	r := new(commitResponse)
	if err := json.Unmarshal(resp.JSONResult(), r); err != nil {
		return "", err
	}

	return r.TxID, nil
}

func RevealEntry(e *Entry) error {
	req, err := ComposeEntryReveal(e)
	if err != nil {
		return err
	}

	resp, err := factomdRequest(req)
	if err != nil {
		return err
	}
	if resp.Error != nil {
		return resp.Error
	}

	return nil
}
<|endoftext|>


<commit_before>package logrus

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/burke/ttyutils"
	"github.com/tobi/airbrake-go"
)

type Entry struct {
	logger *Logger
	Data   Fields
}

func NewEntry(logger *Logger) *Entry {
	return &Entry{
		logger: logger,
		// Default is three fields, give a little extra room. Shouldn't hurt the
		// scale.
		Data: make(Fields, 5),
	}
}

// TODO: Other formats?
func (entry *Entry) Reader() (*bytes.Buffer, error) {
	var serialized []byte
	var err error

	if Environment == "production" {
		serialized, err = json.Marshal(entry.Data)
		if err != nil {
			return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
		}
		serialized = append(serialized, '\n')
	} else {
		if ttyutils.IsTerminal(os.Stdout.Fd()) {
			serialized = append(serialized, []byte(fmt.Sprintf("\x1b[34m%s: ", strings.ToUpper(entry.Data["level"].(string))))...)
		}

		// TODO: Pretty-print more by coloring when stdout is a tty
		// TODO: If this is a println, it'll do a newline and then closing quote.
		for k, v := range entry.Data {
			serialized = append(serialized, []byte(fmt.Sprintf("%s='%s' ", k, v))...)
		}

		if ttyutils.IsTerminal(os.Stdout.Fd()) {
			serialized = append(serialized, []byte("\x1b[0m")...)
		}

		serialized = append(serialized, '\n')
	}

	return bytes.NewBuffer(serialized), nil
}

func (entry *Entry) WithField(key string, value interface{}) *Entry {
	entry.Data[key] = value
	return entry
}

func (entry *Entry) WithFields(fields Fields) *Entry {
	for key, value := range fields {
		entry.WithField(key, value)
	}

	return entry
}

func (entry *Entry) log(level string, msg string) string {
	// TODO: Is the default format output from String() the one we want?
	entry.Data["time"] = time.Now().String()
	entry.Data["level"] = level
	// TODO: Is this the best name?
	entry.Data["msg"] = msg

	reader, err := entry.Reader()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
	}

	// Send HTTP request in a goroutine in warning environment to not halt the
	// main thread. It's sent before logging due to panic.
	if level == "warning" {
		// TODO: new() should spawn an airbrake goroutine and this should send to
		// that channel. This prevent us from spawning hundreds of goroutines in a
		// hot code path generating a warning.
		go entry.airbrake(reader.String())
	} else if level == "fatal" || level == "panic" {
		entry.airbrake(reader.String())
	}

	entry.logger.mu.Lock()
	defer entry.logger.mu.Unlock()

	_, err = io.Copy(entry.logger.Out, reader)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
	}

	return reader.String()
}

func (entry *Entry) Debug(args ...interface{}) {
	if Level >= LevelDebug {
		entry.log("debug", fmt.Sprint(args...))
	}
}

func (entry *Entry) Info(args ...interface{}) {
	if Level >= LevelInfo {
		entry.log("info", fmt.Sprint(args...))
	}
}

func (entry *Entry) Print(args ...interface{}) {
	if Level >= LevelInfo {
		entry.log("info", fmt.Sprint(args...))
	}
}

func (entry *Entry) Warning(args ...interface{}) {
	if Level >= LevelWarning {
		entry.log("warning", fmt.Sprint(args...))
	}
}

func (entry *Entry) Fatal(args ...interface{}) {
	if Level >= LevelFatal {
		entry.log("fatal", fmt.Sprint(args...))
	}
	os.Exit(1)
}

func (entry *Entry) Panic(args ...interface{}) {
	if Level >= LevelPanic {
		msg := entry.log("panic", fmt.Sprint(args...))
		panic(msg)
	}
	panic(fmt.Sprint(args...))
}

// Entry Printf family functions

func (entry *Entry) Debugf(format string, args ...interface{}) {
	entry.Debug(fmt.Sprintf(format, args...))
}

func (entry *Entry) Infof(format string, args ...interface{}) {
	entry.Info(fmt.Sprintf(format, args...))
}

func (entry *Entry) Printf(format string, args ...interface{}) {
	entry.Print(fmt.Sprintf(format, args...))
}

func (entry *Entry) Warningf(format string, args ...interface{}) {
	entry.Warning(fmt.Sprintf(format, args...))
}

func (entry *Entry) Fatalf(format string, args ...interface{}) {
	entry.Fatal(fmt.Sprintf(format, args...))
}

func (entry *Entry) Panicf(format string, args ...interface{}) {
	entry.Panic(fmt.Sprintf(format, args...))
}

// Entry Println family functions

func (entry *Entry) Debugln(args ...interface{}) {
	entry.Debug(fmt.Sprintln(args...))
}

func (entry *Entry) Infoln(args ...interface{}) {
	entry.Info(fmt.Sprintln(args...))
}

func (entry *Entry) Println(args ...interface{}) {
	entry.Print(fmt.Sprintln(args...))
}

func (entry *Entry) Warningln(args ...interface{}) {
	entry.Warning(fmt.Sprintln(args...))
}

func (entry *Entry) Fatalln(args ...interface{}) {
	entry.Fatal(fmt.Sprintln(args...))
}

func (entry *Entry) Panicln(args ...interface{}) {
	entry.Panic(fmt.Sprintln(args...))
}

func (entry *Entry) airbrake(exception string) {
	err := airbrake.Notify(errors.New(exception))
	if err != nil {
		entry.logger.WithFields(Fields{
			"source":   "airbrake",
			"endpoint": airbrake.Endpoint,
		}).Infof("Failed to send exception to Airbrake")
	}
}
<commit_msg>quickhax<commit_after>package logrus

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/burke/ttyutils"
	"github.com/tobi/airbrake-go"
)

type Entry struct {
	logger *Logger
	Data   Fields
}

var baseTimestamp time.Time

func init() {
	baseTimestamp = time.Now()
}

func miniTS() int {
	return int(time.Since(baseTimestamp) / time.Second)
}

func NewEntry(logger *Logger) *Entry {
	return &Entry{
		logger: logger,
		// Default is three fields, give a little extra room. Shouldn't hurt the
		// scale.
		Data: make(Fields, 5),
	}
}

// TODO: Other formats?
func (entry *Entry) Reader() (*bytes.Buffer, error) {
	var serialized []byte
	var err error

	if Environment == "production" {
		serialized, err = json.Marshal(entry.Data)
		if err != nil {
			return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
		}
		serialized = append(serialized, '\n')
	} else {
		levelText := strings.ToUpper(entry.Data["level"].(string))
		levelColor := 34
		if levelText != "INFO" {
			levelColor = 31
		}
		if ttyutils.IsTerminal(os.Stdout.Fd()) {
			serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm%s\x1b[0m[%04d] %-45s \x1b[%dm(\x1b[0m", levelColor, levelText, miniTS(), entry.Data["msg"], levelColor))...)
		}

		// TODO: Pretty-print more by coloring when stdout is a tty
		// TODO: If this is a println, it'll do a newline and then closing quote.
		keys := make([]string, 0)
		for k, _ := range entry.Data {
			if k != "level" && k != "time" && k != "msg" {
				keys = append(keys, k)
			}
		}
		sort.Strings(keys)
		for _, k := range keys {
			v := entry.Data[k]
			serialized = append(serialized, []byte(fmt.Sprintf("\x1b[34m%s\x1b[0m='%s' ", k, v))...)
		}

		serialized = append(serialized, []byte(fmt.Sprintf("\x1b[%dm)\x1b[0m", levelColor))...)

		serialized = append(serialized, '\n')
	}

	return bytes.NewBuffer(serialized), nil
}

func (entry *Entry) WithField(key string, value interface{}) *Entry {
	entry.Data[key] = value
	return entry
}

func (entry *Entry) WithFields(fields Fields) *Entry {
	for key, value := range fields {
		entry.WithField(key, value)
	}

	return entry
}

func (entry *Entry) log(level string, msg string) string {
	// TODO: Is the default format output from String() the one we want?
	entry.Data["time"] = time.Now().String()
	entry.Data["level"] = level
	// TODO: Is this the best name?
	entry.Data["msg"] = msg

	reader, err := entry.Reader()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
	}

	// Send HTTP request in a goroutine in warning environment to not halt the
	// main thread. It's sent before logging due to panic.
	if level == "warning" {
		// TODO: new() should spawn an airbrake goroutine and this should send to
		// that channel. This prevent us from spawning hundreds of goroutines in a
		// hot code path generating a warning.
		go entry.airbrake(reader.String())
	} else if level == "fatal" || level == "panic" {
		entry.airbrake(reader.String())
	}

	entry.logger.mu.Lock()
	defer entry.logger.mu.Unlock()

	_, err = io.Copy(entry.logger.Out, reader)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v", err)
	}

	return reader.String()
}

func (entry *Entry) Debug(args ...interface{}) {
	if Level >= LevelDebug {
		entry.log("debug", fmt.Sprint(args...))
	}
}

func (entry *Entry) Info(args ...interface{}) {
	if Level >= LevelInfo {
		entry.log("info", fmt.Sprint(args...))
	}
}

func (entry *Entry) Print(args ...interface{}) {
	if Level >= LevelInfo {
		entry.log("info", fmt.Sprint(args...))
	}
}

func (entry *Entry) Warning(args ...interface{}) {
	if Level >= LevelWarning {
		entry.log("warning", fmt.Sprint(args...))
	}
}

func (entry *Entry) Fatal(args ...interface{}) {
	if Level >= LevelFatal {
		entry.log("fatal", fmt.Sprint(args...))
	}
	os.Exit(1)
}

func (entry *Entry) Panic(args ...interface{}) {
	if Level >= LevelPanic {
		msg := entry.log("panic", fmt.Sprint(args...))
		panic(msg)
	}
	panic(fmt.Sprint(args...))
}

// Entry Printf family functions

func (entry *Entry) Debugf(format string, args ...interface{}) {
	entry.Debug(fmt.Sprintf(format, args...))
}

func (entry *Entry) Infof(format string, args ...interface{}) {
	entry.Info(fmt.Sprintf(format, args...))
}

func (entry *Entry) Printf(format string, args ...interface{}) {
	entry.Print(fmt.Sprintf(format, args...))
}

func (entry *Entry) Warningf(format string, args ...interface{}) {
	entry.Warning(fmt.Sprintf(format, args...))
}

func (entry *Entry) Fatalf(format string, args ...interface{}) {
	entry.Fatal(fmt.Sprintf(format, args...))
}

func (entry *Entry) Panicf(format string, args ...interface{}) {
	entry.Panic(fmt.Sprintf(format, args...))
}

// Entry Println family functions

func (entry *Entry) Debugln(args ...interface{}) {
	entry.Debug(fmt.Sprintln(args...))
}

func (entry *Entry) Infoln(args ...interface{}) {
	entry.Info(fmt.Sprintln(args...))
}

func (entry *Entry) Println(args ...interface{}) {
	entry.Print(fmt.Sprintln(args...))
}

func (entry *Entry) Warningln(args ...interface{}) {
	entry.Warning(fmt.Sprintln(args...))
}

func (entry *Entry) Fatalln(args ...interface{}) {
	entry.Fatal(fmt.Sprintln(args...))
}

func (entry *Entry) Panicln(args ...interface{}) {
	entry.Panic(fmt.Sprintln(args...))
}

func (entry *Entry) airbrake(exception string) {
	err := airbrake.Notify(errors.New(exception))
	if err != nil {
		entry.logger.WithFields(Fields{
			"source":   "airbrake",
			"endpoint": airbrake.Endpoint,
		}).Infof("Failed to send exception to Airbrake")
	}
}
<|endoftext|>


<commit_before>// Package eport provides a simple API to write Erlang ports in Go.
//
// For more information on Erlang ports see http://www.erlang.org/doc/tutorial/c_port.html.
package eport

import (
	"bufio"
	. "encoding/binary"
	"errors"
	"io"
)

type Port interface {
	// ReadOne reads one packet (or line, if it's a line-based port).
	ReadOne() (data []byte, err error)
	// Write writes len(data) bytes from data to the port.
	// It returns the number of bytes written from data (0 <= n <= len(data))
	// and any error encountered that caused the write to stop early.
	// Write must return a non-nil error if it returns n < len(data).
	Write(data []byte) (n int, err error)
}

var (
	ErrSizeOverflow = errors.New("eport: packet size overflow")
	ErrBadSizeLen   = errors.New("eport: bad 'packet size' length")
)

// Line returns a new line-based port.
func Line(r io.ReadWriter, w io.Writer) (Port, error) {
	return &linePort{
		bufio.NewReader(r),
		w,
	}, nil
}

// Packet returns a new packet-based port.
// Each packet is preceded with its length.
// The size of the length of the packet is either 1, 2 or 4.
func Packet(r io.Reader, w io.Writer, sizeLen int) (Port, error) {
	switch sizeLen {
	case 1, 2, 4:
		return &packetPort{r, w, 1 << (uint(sizeLen) * 8), make([]byte, sizeLen)}, nil
	}

	return nil, ErrBadSizeLen
}

type linePort struct {
	r *bufio.Reader
	w io.Writer
}

func (p *linePort) ReadOne() ([]byte, error) {
	return p.r.ReadBytes('\n')
}

func (p *linePort) Write(data []byte) (int, error) {
	return p.w.Write(data)
}

type packetPort struct {
	r       io.Reader
	w       io.Writer
	max     int
	sizeBuf []byte
}

func (pr *packetPort) ReadOne() ([]byte, error) {
	if _, err := io.ReadFull(pr.r, pr.sizeBuf); err != nil {
		return nil, err
	}

	var size int

	switch len(pr.sizeBuf) {
	case 1:
		size = int(pr.sizeBuf[0])
	case 2:
		size = int(BigEndian.Uint16(pr.sizeBuf))
	case 4:
		size32 := BigEndian.Uint32(pr.sizeBuf)
		size = int(size32)
		if uint32(size) != size32 {
			return nil, ErrSizeOverflow
		}
	}

	if size == 0 {
		return []byte{}, nil
	}

	data := make([]byte, size)
	if _, err := io.ReadFull(pr.r, data); err != nil {
		return nil, err
	}

	return data, nil
}

func (pr *packetPort) Write(data []byte) (int, error) {
	size := len(data)
	if size > pr.max {
		return 0, ErrSizeOverflow
	}

	switch len(pr.sizeBuf) {
	case 1:
		pr.sizeBuf[0] = uint8(size)
	case 2:
		BigEndian.PutUint16(pr.sizeBuf, uint16(size))
	case 4:
		BigEndian.PutUint32(pr.sizeBuf, uint32(size))
	}

	if n, err := pr.w.Write(pr.sizeBuf); err != nil {
		return n, err
	}

	return pr.w.Write(data)
}
<commit_msg>ReadWriter -> Reader<commit_after>// Package eport provides a simple API to write Erlang ports in Go.
//
// For more information on Erlang ports see http://www.erlang.org/doc/tutorial/c_port.html.
package eport

import (
	"bufio"
	. "encoding/binary"
	"errors"
	"io"
)

type Port interface {
	// ReadOne reads one packet (or line, if it's a line-based port).
	ReadOne() (data []byte, err error)
	// Write writes len(data) bytes from data to the port.
	// It returns the number of bytes written from data (0 <= n <= len(data))
	// and any error encountered that caused the write to stop early.
	// Write must return a non-nil error if it returns n < len(data).
	Write(data []byte) (n int, err error)
}

var (
	ErrSizeOverflow = errors.New("eport: packet size overflow")
	ErrBadSizeLen   = errors.New("eport: bad 'packet size' length")
)

// Line returns a new line-based port.
func Line(r io.Reader, w io.Writer) (Port, error) {
	return &linePort{
		bufio.NewReader(r),
		w,
	}, nil
}

// Packet returns a new packet-based port.
// Each packet is preceded with its length.
// The size of the length of the packet is either 1, 2 or 4.
func Packet(r io.Reader, w io.Writer, sizeLen int) (Port, error) {
	switch sizeLen {
	case 1, 2, 4:
		return &packetPort{r, w, 1 << (uint(sizeLen) * 8), make([]byte, sizeLen)}, nil
	}

	return nil, ErrBadSizeLen
}

type linePort struct {
	r *bufio.Reader
	w io.Writer
}

func (p *linePort) ReadOne() ([]byte, error) {
	return p.r.ReadBytes('\n')
}

func (p *linePort) Write(data []byte) (int, error) {
	return p.w.Write(data)
}

type packetPort struct {
	r       io.Reader
	w       io.Writer
	max     int
	sizeBuf []byte
}

func (pr *packetPort) ReadOne() ([]byte, error) {
	if _, err := io.ReadFull(pr.r, pr.sizeBuf); err != nil {
		return nil, err
	}

	var size int

	switch len(pr.sizeBuf) {
	case 1:
		size = int(pr.sizeBuf[0])
	case 2:
		size = int(BigEndian.Uint16(pr.sizeBuf))
	case 4:
		size32 := BigEndian.Uint32(pr.sizeBuf)
		size = int(size32)
		if uint32(size) != size32 {
			return nil, ErrSizeOverflow
		}
	}

	if size == 0 {
		return []byte{}, nil
	}

	data := make([]byte, size)
	if _, err := io.ReadFull(pr.r, data); err != nil {
		return nil, err
	}

	return data, nil
}

func (pr *packetPort) Write(data []byte) (int, error) {
	size := len(data)
	if size > pr.max {
		return 0, ErrSizeOverflow
	}

	switch len(pr.sizeBuf) {
	case 1:
		pr.sizeBuf[0] = uint8(size)
	case 2:
		BigEndian.PutUint16(pr.sizeBuf, uint16(size))
	case 4:
		BigEndian.PutUint32(pr.sizeBuf, uint32(size))
	}

	if n, err := pr.w.Write(pr.sizeBuf); err != nil {
		return n, err
	}

	return pr.w.Write(data)
}
<|endoftext|>


<commit_before>/*

		ernst.go
		A very unfriendly IRC bot

*/

package main

import (
	"github.com/thoj/go-ircevent"
	"github.com/boltdb/bolt"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"log"
	"time"
	"math/rand"
	"strings"
	"strconv"
	elib "github.com/bnaucler/ernst/elib"
)

const dbname = "./ernst.db"

const ratemax = int(1000)
const kdelmax = int(1000)
const randelmax = int(10000)

func cherr(e error) { if e != nil { log.Fatal(e) } }

func askymf(db *bolt.DB, irccon *irc.Connection, event *irc.Event,
	rnd *rand.Rand, settings elib.Settings, skymf string, cbuc []byte) int {

	settings.Numln++
	senc, _ := json.Marshal(settings)
	err := elib.Wrdb(db, settings.Numln, []byte(skymf), cbuc)

	if err == nil {
		err := elib.Wrdb(db, 0, senc, cbuc)
		cherr(err)
		resp := fmt.Sprintf("%v: lade till \"%v\"", event.Nick, skymf)
		time.Sleep(time.Duration(len(resp) * settings.Kdel +
			rnd.Intn(settings.Randel)) * time.Millisecond)
		irccon.Privmsg(settings.Channel, resp)
	} else {
		cherr(err)
	}
	return settings.Numln
}

func sskymf(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	target string, settings elib.Settings, ln int) bool {

	if ln == 0 { ln = rnd.Intn(settings.Numln) }

	skymf, err := elib.Rdb(db, ln, cbuc)
	cherr(err)
	time.Sleep(time.Duration(len(skymf) *
		settings.Kdel + rnd.Intn(settings.Randel)) * time.Millisecond)
	resp := fmt.Sprintf("%v: %v", target, string(skymf))
	irccon.Privmsg(settings.Channel, resp)

	return true
}

func fskymf(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	target string, kw []string, index int, settings elib.Settings) bool {

	kwln := len(kw)
	var (reqnum, cqual, tqual int)

	for k := 0; k <= settings.Numln; k++ {
		v, err := elib.Rdb(db, k, cbuc)
		cqual = 0
		cstr := string(v)
		for a := index; a < kwln; a++ {
			if strings.Contains(cstr, strings.ToLower(kw[a])) {
				cqual++
				if cqual > tqual {
					tqual = cqual
					reqnum = k
				}
			}
		}
		cherr(err)
	}

	return sskymf(irccon, db, cbuc, rnd, target, settings, reqnum)
}

func csetlist(event *irc.Event, settings *elib.Settings) (resp string) {

	resp = fmt.Sprintf("%v: rate: %d/%d, kdel: %d/%d, randel: %d/%d",
		event.Nick, settings.Rate, ratemax,
		settings.Kdel, kdelmax, settings.Randel, randelmax)

	return
}

func csetshow(event *irc.Event, settings *elib.Settings, setvar string) (resp string) {

	if setvar == "rate" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Rate, ratemax)
	} else if setvar == "kdel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Kdel, kdelmax)
	} else if setvar == "randel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Randel, randelmax)
	}

	return
}

func csetset(event *irc.Event, settings *elib.Settings, setvar,
	setval string) (resp string, dbchange bool) {

	nval, nerr := strconv.Atoi(setval)

	if setvar == "rate"  && nerr == nil && nval > -1 && nval <= ratemax {
		if settings.Rate != nval { dbchange = true }
		settings.Rate = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Rate, ratemax)

	} else if setvar == "kdel" && nerr == nil && nval > -1 && nval <= kdelmax {
		if settings.Kdel != nval { dbchange = true }
		settings.Kdel = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Kdel, kdelmax)

	} else if setvar == "randel" && nerr == nil && nval > -1 && nval <= randelmax {
		if settings.Randel != nval { dbchange = true }
		settings.Randel = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Randel, randelmax)
	}

	return
}

func cset(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	event *irc.Event, settings *elib.Settings) bool {

	ssp := strings.Split(event.Arguments[1], " ")

	var (
		setvar, setval, resp string
		dbchange bool
	)

	if len(ssp) > 1 { setvar = strings.ToLower(ssp[1]) }
	if len(ssp) > 2 { setval = ssp[2] }

	if len(ssp) == 1 { resp = csetlist(event, settings)
	} else if len(ssp) == 2 { resp = csetshow(event, settings, setvar)
	} else if len(ssp) == 3 {
		resp, dbchange = csetset (event, settings, setvar, setval)
	}

	if len(resp) != 0 {
		if dbchange {
			s, err:= json.Marshal(settings)
			cherr(err)
			err = elib.Wrdb(db, 0, s, cbuc)
			cherr(err)
		}
		irccon.Privmsg(settings.Channel, resp)
	}

	return true
}

func main() {

    rnd := rand.New(rand.NewSource(time.Now().UnixNano()))

	var cbuc = []byte("skymf")
	var incrt = int(0)

	settings := elib.Settings{}

	db, err := bolt.Open(dbname, 0640, nil)
	cherr(err)
	defer db.Close()

	addkey := "!skymf "
	setkey := "!sset"
	statkey := "!skymfstat"

	tmp, err := elib.Rdb(db, 0, cbuc)
	cherr(err)
	json.Unmarshal(tmp, &settings)

	irccon := irc.IRC(settings.Ircnick, settings.Uname)

	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	irccon.AddCallback("001", func(e *irc.Event) { irccon.Join(settings.Channel) })

	irccon.AddCallback("PRIVMSG", func(event *irc.Event) {
		go func(event *irc.Event) {

			lcnick := strings.ToLower(settings.Ircnick)
			lcstr := strings.ToLower(event.Arguments[1])

			if event.Arguments[0] == settings.Channel && strings.HasPrefix(lcstr, addkey) {
				skymf := strings.TrimPrefix(event.Arguments[1], addkey)
				settings.Numln = askymf(db, irccon, event, rnd, settings, skymf, cbuc)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, statkey) {

				resp := fmt.Sprintf("Jag kan %d skymfer.", settings.Numln)
				time.Sleep(time.Duration(len(resp) * settings.Kdel +
					rnd.Intn(settings.Randel)) * time.Millisecond)
				irccon.Privmsg(settings.Channel, resp)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, setkey) {
				cset(irccon, db, cbuc, rnd, event, &settings)

			} else if event.Arguments[0] == settings.Channel &&
				strings.Contains(lcstr, lcnick) {
				kw := strings.Split(event.Arguments[1], " ")

				if strings.Contains(kw[0], lcnick) {
					fskymf(irccon, db, cbuc, rnd, event.Nick, kw, 1, settings)
				} else {
					sskymf(irccon, db, cbuc, rnd, event.Nick, settings, 0)
				}
				incrt = 0

			} else if event.Arguments[0] == settings.Channel &&
				rnd.Intn(ratemax) < settings.Rate + incrt && event.Nick != settings.Ircnick {
				sskymf(irccon, db, cbuc, rnd, event.Nick, settings, 0)
				incrt = 0
			}

			if event.Arguments[0] == settings.Ircnick {
				var nval int

				target := strings.Split(event.Arguments[1], " ")
				if len(target) > 1 {
					nval, err = strconv.Atoi(target[1])

					debugresp := fmt.Sprintf("%+v, %d, %d", target, nval, len(target))
					irccon.Privmsg(settings.Channel, debugresp)

					if err == nil && nval > 0 && nval <= settings.Numln {
						sskymf(irccon, db, cbuc, rnd, target[0], settings, nval)
						incrt = 0
					} else if nval == 0 {
						fskymf(irccon, db, cbuc, rnd, target[0], target, 1, settings)
						incrt = 0
					}

				} else {
					sskymf(irccon, db, cbuc, rnd, target[0], settings, 0)
					incrt = 0
				}
			}

			incrt++
		}(event)
	});

	err = irccon.Connect(settings.Server)
	cherr(err)

	irccon.Loop()
}
<commit_msg>Performance improvement, string matching search<commit_after>/*

		ernst.go
		A very unfriendly IRC bot

*/

package main

import (
	"github.com/thoj/go-ircevent"
	"github.com/boltdb/bolt"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"log"
	"time"
	"math/rand"
	"strings"
	"strconv"
	elib "github.com/bnaucler/ernst/elib"
)

const dbname = "./ernst.db"

const ratemax = int(1000)
const kdelmax = int(1000)
const randelmax = int(10000)

func cherr(e error) { if e != nil { log.Fatal(e) } }

func askymf(db *bolt.DB, irccon *irc.Connection, event *irc.Event,
	rnd *rand.Rand, settings elib.Settings, skymf string, cbuc []byte) int {

	settings.Numln++
	senc, _ := json.Marshal(settings)
	err := elib.Wrdb(db, settings.Numln, []byte(skymf), cbuc)

	if err == nil {
		err := elib.Wrdb(db, 0, senc, cbuc)
		cherr(err)
		resp := fmt.Sprintf("%v: lade till \"%v\"", event.Nick, skymf)
		time.Sleep(time.Duration(len(resp) * settings.Kdel +
			rnd.Intn(settings.Randel)) * time.Millisecond)
		irccon.Privmsg(settings.Channel, resp)
	} else {
		cherr(err)
	}
	return settings.Numln
}

func sskymf(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	target string, settings elib.Settings, ln int) bool {

	if ln == 0 { ln = rnd.Intn(settings.Numln) }

	skymf, err := elib.Rdb(db, ln, cbuc)
	cherr(err)
	time.Sleep(time.Duration(len(skymf) *
		settings.Kdel + rnd.Intn(settings.Randel)) * time.Millisecond)
	resp := fmt.Sprintf("%v: %v", target, string(skymf))
	irccon.Privmsg(settings.Channel, resp)

	return true
}

func fskymf(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	target string, kw []string, index int, settings elib.Settings) bool {

	kwln := len(kw)
	var (reqnum, cqual, tqual int)
	lckw := make([]string, kwln)

	for a := 0; a < kwln; a++ { lckw[a] = strings.ToLower(kw[a]) }

	for k := 0; k <= settings.Numln; k++ {
		v, err := elib.Rdb(db, k, cbuc)
		cqual = 0
		cstr := string(v)
		for a := index; a < kwln; a++ {
			if strings.Contains(cstr, lckw[a]) {
				cqual++
				if cqual > tqual {
					tqual = cqual
					reqnum = k
				}
			}
		}
		cherr(err)
	}

	return sskymf(irccon, db, cbuc, rnd, target, settings, reqnum)
}

func csetlist(event *irc.Event, settings *elib.Settings) (resp string) {

	resp = fmt.Sprintf("%v: rate: %d/%d, kdel: %d/%d, randel: %d/%d",
		event.Nick, settings.Rate, ratemax,
		settings.Kdel, kdelmax, settings.Randel, randelmax)

	return
}

func csetshow(event *irc.Event, settings *elib.Settings, setvar string) (resp string) {

	if setvar == "rate" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Rate, ratemax)
	} else if setvar == "kdel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Kdel, kdelmax)
	} else if setvar == "randel" {
		resp = fmt.Sprintf("%v: %v: %d/%d", event.Nick, setvar, settings.Randel, randelmax)
	}

	return
}

func csetset(event *irc.Event, settings *elib.Settings, setvar,
	setval string) (resp string, dbchange bool) {

	nval, nerr := strconv.Atoi(setval)

	if setvar == "rate"  && nerr == nil && nval > -1 && nval <= ratemax {
		if settings.Rate != nval { dbchange = true }
		settings.Rate = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Rate, ratemax)

	} else if setvar == "kdel" && nerr == nil && nval > -1 && nval <= kdelmax {
		if settings.Kdel != nval { dbchange = true }
		settings.Kdel = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Kdel, kdelmax)

	} else if setvar == "randel" && nerr == nil && nval > -1 && nval <= randelmax {
		if settings.Randel != nval { dbchange = true }
		settings.Randel = nval
		resp = fmt.Sprintf("%s %d/%d.", setvar, settings.Randel, randelmax)
	}

	return
}

func cset(irccon *irc.Connection, db *bolt.DB, cbuc []byte, rnd *rand.Rand,
	event *irc.Event, settings *elib.Settings) bool {

	ssp := strings.Split(event.Arguments[1], " ")

	var (
		setvar, setval, resp string
		dbchange bool
	)

	if len(ssp) > 1 { setvar = strings.ToLower(ssp[1]) }
	if len(ssp) > 2 { setval = ssp[2] }

	if len(ssp) == 1 { resp = csetlist(event, settings)
	} else if len(ssp) == 2 { resp = csetshow(event, settings, setvar)
	} else if len(ssp) == 3 {
		resp, dbchange = csetset (event, settings, setvar, setval)
	}

	if len(resp) != 0 {
		if dbchange {
			s, err:= json.Marshal(settings)
			cherr(err)
			err = elib.Wrdb(db, 0, s, cbuc)
			cherr(err)
		}
		irccon.Privmsg(settings.Channel, resp)
	}

	return true
}

func main() {

    rnd := rand.New(rand.NewSource(time.Now().UnixNano()))

	var cbuc = []byte("skymf")
	var incrt = int(0)

	settings := elib.Settings{}

	db, err := bolt.Open(dbname, 0640, nil)
	cherr(err)
	defer db.Close()

	addkey := "!skymf "
	setkey := "!sset"
	statkey := "!skymfstat"

	tmp, err := elib.Rdb(db, 0, cbuc)
	cherr(err)
	json.Unmarshal(tmp, &settings)

	irccon := irc.IRC(settings.Ircnick, settings.Uname)

	irccon.VerboseCallbackHandler = true
	irccon.Debug = true
	irccon.UseTLS = true
	irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	irccon.AddCallback("001", func(e *irc.Event) { irccon.Join(settings.Channel) })

	irccon.AddCallback("PRIVMSG", func(event *irc.Event) {
		go func(event *irc.Event) {

			lcnick := strings.ToLower(settings.Ircnick)
			lcstr := strings.ToLower(event.Arguments[1])

			if event.Arguments[0] == settings.Channel && strings.HasPrefix(lcstr, addkey) {
				skymf := strings.TrimPrefix(event.Arguments[1], addkey)
				settings.Numln = askymf(db, irccon, event, rnd, settings, skymf, cbuc)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, statkey) {

				resp := fmt.Sprintf("Jag kan %d skymfer.", settings.Numln)
				time.Sleep(time.Duration(len(resp) * settings.Kdel +
					rnd.Intn(settings.Randel)) * time.Millisecond)
				irccon.Privmsg(settings.Channel, resp)

			} else if event.Arguments[0] == settings.Channel &&
				strings.HasPrefix(lcstr, setkey) {
				cset(irccon, db, cbuc, rnd, event, &settings)

			} else if event.Arguments[0] == settings.Channel &&
				strings.Contains(lcstr, lcnick) {
				kw := strings.Split(event.Arguments[1], " ")

				if strings.Contains(kw[0], lcnick) {
					fskymf(irccon, db, cbuc, rnd, event.Nick, kw, 1, settings)
				} else {
					sskymf(irccon, db, cbuc, rnd, event.Nick, settings, 0)
				}
				incrt = 0

			} else if event.Arguments[0] == settings.Channel &&
				rnd.Intn(ratemax) < settings.Rate + incrt && event.Nick != settings.Ircnick {
				sskymf(irccon, db, cbuc, rnd, event.Nick, settings, 0)
				incrt = 0
			}

			if event.Arguments[0] == settings.Ircnick {
				var nval int

				target := strings.Split(event.Arguments[1], " ")
				if len(target) > 1 {
					nval, err = strconv.Atoi(target[1])

					if err == nil && nval > 0 && nval <= settings.Numln {
						sskymf(irccon, db, cbuc, rnd, target[0], settings, nval)
						incrt = 0
					} else if nval == 0 {
						fskymf(irccon, db, cbuc, rnd, target[0], target, 1, settings)
						incrt = 0
					}

				} else {
					sskymf(irccon, db, cbuc, rnd, target[0], settings, 0)
					incrt = 0
				}
			}

			incrt++
		}(event)
	});

	err = irccon.Connect(settings.Server)
	cherr(err)

	irccon.Loop()
}
<|endoftext|>


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

//go:generate ./single_precision.bash

package gonum

import "math"

type Implementation struct{}

// The following are panic strings used during parameter checks.
const (
	zeroIncX = "blas: zero x index increment"
	zeroIncY = "blas: zero y index increment"

	mLT0  = "blas: m < 0"
	nLT0  = "blas: n < 0"
	kLT0  = "blas: k < 0"
	kLLT0 = "blas: kL < 0"
	kULT0 = "blas: kU < 0"

	badUplo      = "blas: illegal triangle"
	badTranspose = "blas: illegal transpose"
	badDiag      = "blas: illegal diagonal"
	badSide      = "blas: illegal side"

	badLdA = "blas: index of a out of range"
	badLdB = "blas: index of b out of range"
	badLdC = "blas: index of c out of range"

	badX = "blas: bad length of x"
	badY = "blas: bad length of y"
)

// [SD]gemm behavior constants. These are kept here to keep them out of the
// way during single precision code genration.
const (
	blockSize   = 64 // b x b matrix
	minParBlock = 4  // minimum number of blocks needed to go parallel
	buffMul     = 4  // how big is the buffer relative to the number of workers
)

// subMul is a common type shared by [SD]gemm.
type subMul struct {
	i, j int // index of block
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a > b {
		return b
	}
	return a
}

func checkSMatrix(name byte, m, n int, a []float32, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < n {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: index of " + string(name) + " out of range")
	}
}

func checkDMatrix(name byte, m, n int, a []float64, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < n {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: index of " + string(name) + " out of range")
	}
}

func checkZMatrix(name byte, m, n int, a []complex128, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < max(1, n) {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: insufficient " + string(name) + " matrix slice length")
	}
}

func checkZBandMatrix(name byte, m, n, kL, kU int, ab []complex128, ldab int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if kL < 0 {
		panic(kLLT0)
	}
	if kU < 0 {
		panic(kULT0)
	}
	if ldab < kL+kU+1 {
		panic("blas: illegal stride of band matrix " + string(name))
	}
	nRow := min(m, n+kL)
	if len(ab) < (nRow-1)*ldab+kL+1+kU {
		panic("blas: insufficient " + string(name) + " band matrix slice length")
	}
}

func checkZhbMatrix(name byte, n, k int, ab []complex128, ldab int) {
	if n < 0 {
		panic(nLT0)
	}
	if k < 0 {
		panic(kLT0)
	}
	if ldab < k+1 {
		panic("blas: illegal stride of Hermitian band matrix " + string(name))
	}
	if len(ab) < (n-1)*ldab+k+1 {
		panic("blas: insufficient " + string(name) + " Hermitian band matrix slice length")
	}
}

func checkZtbMatrix(name byte, n, k int, ab []complex128, ldab int) {
	if n < 0 {
		panic(nLT0)
	}
	if k < 0 {
		panic(kLT0)
	}
	if ldab < k+1 {
		panic("blas: illegal stride of triangular band matrix " + string(name))
	}
	if len(ab) < (n-1)*ldab+k+1 {
		panic("blas: insufficient " + string(name) + " triangular band matrix slice length")
	}
}

func checkZVector(name byte, n int, x []complex128, incX int) {
	if n < 0 {
		panic(nLT0)
	}
	if incX == 0 {
		panic(zeroIncX)
	}
	if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
		panic("blas: insufficient " + string(name) + " vector slice length")
	}
}

// blocks returns the number of divisions of the dimension length with the given
// block size.
func blocks(dim, bsize int) int {
	return (dim + bsize - 1) / bsize
}

// dcabs1 returns |real(z)|+|imag(z)|.
func dcabs1(z complex128) float64 {
	return math.Abs(real(z)) + math.Abs(imag(z))
}
<commit_msg>blas/gonum: change badLd* panic strings<commit_after>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:generate ./single_precision.bash

package gonum

import "math"

type Implementation struct{}

// The following are panic strings used during parameter checks.
const (
	zeroIncX = "blas: zero x index increment"
	zeroIncY = "blas: zero y index increment"

	mLT0  = "blas: m < 0"
	nLT0  = "blas: n < 0"
	kLT0  = "blas: k < 0"
	kLLT0 = "blas: kL < 0"
	kULT0 = "blas: kU < 0"

	badUplo      = "blas: illegal triangle"
	badTranspose = "blas: illegal transpose"
	badDiag      = "blas: illegal diagonal"
	badSide      = "blas: illegal side"

	badLdA = "blas: bad leading dimension of A"
	badLdB = "blas: bad leading dimension of B"
	badLdC = "blas: bad leading dimension of C"

	badX = "blas: bad length of x"
	badY = "blas: bad length of y"
)

// [SD]gemm behavior constants. These are kept here to keep them out of the
// way during single precision code genration.
const (
	blockSize   = 64 // b x b matrix
	minParBlock = 4  // minimum number of blocks needed to go parallel
	buffMul     = 4  // how big is the buffer relative to the number of workers
)

// subMul is a common type shared by [SD]gemm.
type subMul struct {
	i, j int // index of block
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a > b {
		return b
	}
	return a
}

func checkSMatrix(name byte, m, n int, a []float32, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < n {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: index of " + string(name) + " out of range")
	}
}

func checkDMatrix(name byte, m, n int, a []float64, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < n {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: index of " + string(name) + " out of range")
	}
}

func checkZMatrix(name byte, m, n int, a []complex128, lda int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if lda < max(1, n) {
		panic("blas: illegal stride of " + string(name))
	}
	if len(a) < (m-1)*lda+n {
		panic("blas: insufficient " + string(name) + " matrix slice length")
	}
}

func checkZBandMatrix(name byte, m, n, kL, kU int, ab []complex128, ldab int) {
	if m < 0 {
		panic(mLT0)
	}
	if n < 0 {
		panic(nLT0)
	}
	if kL < 0 {
		panic(kLLT0)
	}
	if kU < 0 {
		panic(kULT0)
	}
	if ldab < kL+kU+1 {
		panic("blas: illegal stride of band matrix " + string(name))
	}
	nRow := min(m, n+kL)
	if len(ab) < (nRow-1)*ldab+kL+1+kU {
		panic("blas: insufficient " + string(name) + " band matrix slice length")
	}
}

func checkZhbMatrix(name byte, n, k int, ab []complex128, ldab int) {
	if n < 0 {
		panic(nLT0)
	}
	if k < 0 {
		panic(kLT0)
	}
	if ldab < k+1 {
		panic("blas: illegal stride of Hermitian band matrix " + string(name))
	}
	if len(ab) < (n-1)*ldab+k+1 {
		panic("blas: insufficient " + string(name) + " Hermitian band matrix slice length")
	}
}

func checkZtbMatrix(name byte, n, k int, ab []complex128, ldab int) {
	if n < 0 {
		panic(nLT0)
	}
	if k < 0 {
		panic(kLT0)
	}
	if ldab < k+1 {
		panic("blas: illegal stride of triangular band matrix " + string(name))
	}
	if len(ab) < (n-1)*ldab+k+1 {
		panic("blas: insufficient " + string(name) + " triangular band matrix slice length")
	}
}

func checkZVector(name byte, n int, x []complex128, incX int) {
	if n < 0 {
		panic(nLT0)
	}
	if incX == 0 {
		panic(zeroIncX)
	}
	if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
		panic("blas: insufficient " + string(name) + " vector slice length")
	}
}

// blocks returns the number of divisions of the dimension length with the given
// block size.
func blocks(dim, bsize int) int {
	return (dim + bsize - 1) / bsize
}

// dcabs1 returns |real(z)|+|imag(z)|.
func dcabs1(z complex128) float64 {
	return math.Abs(real(z)) + math.Abs(imag(z))
}
<|endoftext|>


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

// pprof is a tool for visualization of profile.data. It is based on
// the upstream version at github.com/google/pprof, with minor
// modifications specific to the Go distribution. Please consider
// upstreaming any modifications to these packages.

package main

import (
	"crypto/tls"
	"debug/dwarf"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"sync"
	"time"

	"cmd/internal/objfile"
	"github.com/google/pprof/driver"
	"github.com/google/pprof/profile"
)

func main() {
	options := &driver.Options{
		Fetch: new(fetcher),
		Obj:   new(objTool),
	}
	if err := driver.PProf(options); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(2)
	}
}

type fetcher struct {
}

func (f *fetcher) Fetch(src string, duration, timeout time.Duration) (*profile.Profile, string, error) {
	sourceURL, timeout := adjustURL(src, duration, timeout)
	if sourceURL == "" {
		// Could not recognize URL, let regular pprof attempt to fetch the profile (eg. from a file)
		return nil, "", nil
	}
	fmt.Fprintln(os.Stderr, "Fetching profile over HTTP from", sourceURL)
	if duration > 0 {
		fmt.Fprintf(os.Stderr, "Please wait... (%v)\n", duration)
	}
	p, err := getProfile(sourceURL, timeout)
	return p, sourceURL, err
}

func getProfile(source string, timeout time.Duration) (*profile.Profile, error) {
	url, err := url.Parse(source)
	if err != nil {
		return nil, err
	}

	var tlsConfig *tls.Config
	if url.Scheme == "https+insecure" {
		tlsConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
		url.Scheme = "https"
		source = url.String()
	}

	client := &http.Client{
		Transport: &http.Transport{
			ResponseHeaderTimeout: timeout + 5*time.Second,
			TLSClientConfig:       tlsConfig,
		},
	}
	resp, err := client.Get(source)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("server response: %s", resp.Status)
	}
	return profile.Parse(resp.Body)
}

// cpuProfileHandler is the Go pprof CPU profile handler URL.
const cpuProfileHandler = "/debug/pprof/profile"

// adjustURL applies the duration/timeout values and Go specific defaults
func adjustURL(source string, duration, timeout time.Duration) (string, time.Duration) {
	u, err := url.Parse(source)
	if err != nil || (u.Host == "" && u.Scheme != "" && u.Scheme != "file") {
		// Try adding http:// to catch sources of the form hostname:port/path.
		// url.Parse treats "hostname" as the scheme.
		u, err = url.Parse("http://" + source)
	}
	if err != nil || u.Host == "" {
		return "", 0
	}

	if u.Path == "" || u.Path == "/" {
		u.Path = cpuProfileHandler
	}

	// Apply duration/timeout overrides to URL.
	values := u.Query()
	if duration > 0 {
		values.Set("seconds", fmt.Sprint(int(duration.Seconds())))
	} else {
		if urlSeconds := values.Get("seconds"); urlSeconds != "" {
			if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
				duration = time.Duration(us) * time.Second
			}
		}
	}
	if timeout <= 0 {
		if duration > 0 {
			timeout = duration + duration/2
		} else {
			timeout = 60 * time.Second
		}
	}
	u.RawQuery = values.Encode()
	return u.String(), timeout
}

// objTool implements driver.ObjTool using Go libraries
// (instead of invoking GNU binutils).
type objTool struct {
	mu          sync.Mutex
	disasmCache map[string]*objfile.Disasm
}

func (*objTool) Open(name string, start, limit, offset uint64) (driver.ObjFile, error) {
	of, err := objfile.Open(name)
	if err != nil {
		return nil, err
	}
	f := &file{
		name: name,
		file: of,
	}
	if start != 0 {
		if load, err := of.LoadAddress(); err == nil {
			f.offset = start - load
		}
	}
	return f, nil
}

func (*objTool) Demangle(names []string) (map[string]string, error) {
	// No C++, nothing to demangle.
	return make(map[string]string), nil
}

func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error) {
	d, err := t.cachedDisasm(file)
	if err != nil {
		return nil, err
	}
	var asm []driver.Inst
	d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) {
		asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text})
	})
	return asm, nil
}

func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.disasmCache == nil {
		t.disasmCache = make(map[string]*objfile.Disasm)
	}
	d := t.disasmCache[file]
	if d != nil {
		return d, nil
	}
	f, err := objfile.Open(file)
	if err != nil {
		return nil, err
	}
	d, err = f.Disasm()
	f.Close()
	if err != nil {
		return nil, err
	}
	t.disasmCache[file] = d
	return d, nil
}

func (*objTool) SetConfig(config string) {
	// config is usually used to say what binaries to invoke.
	// Ignore entirely.
}

// file implements driver.ObjFile using Go libraries
// (instead of invoking GNU binutils).
// A file represents a single executable being analyzed.
type file struct {
	name   string
	offset uint64
	sym    []objfile.Sym
	file   *objfile.File
	pcln   objfile.Liner

	triedDwarf bool
	dwarf      *dwarf.Data
}

func (f *file) Name() string {
	return f.name
}

func (f *file) Base() uint64 {
	// No support for shared libraries.
	return 0
}

func (f *file) BuildID() string {
	// No support for build ID.
	return ""
}

func (f *file) SourceLine(addr uint64) ([]driver.Frame, error) {
	if f.pcln == nil {
		pcln, err := f.file.PCLineTable()
		if err != nil {
			return nil, err
		}
		f.pcln = pcln
	}
	addr -= f.offset
	file, line, fn := f.pcln.PCToLine(addr)
	if fn != nil {
		frame := []driver.Frame{
			{
				Func: fn.Name,
				File: file,
				Line: line,
			},
		}
		return frame, nil
	}

	frames := f.dwarfSourceLine(addr)
	if frames != nil {
		return frames, nil
	}

	return nil, fmt.Errorf("no line information for PC=%#x", addr)
}

// dwarfSourceLine tries to get file/line information using DWARF.
// This is for C functions that appear in the profile.
// Returns nil if there is no information available.
func (f *file) dwarfSourceLine(addr uint64) []driver.Frame {
	if f.dwarf == nil && !f.triedDwarf {
		// Ignore any error--we don't care exactly why there
		// is no DWARF info.
		f.dwarf, _ = f.file.DWARF()
		f.triedDwarf = true
	}

	if f.dwarf != nil {
		r := f.dwarf.Reader()
		unit, err := r.SeekPC(addr)
		if err == nil {
			if frames := f.dwarfSourceLineEntry(r, unit, addr); frames != nil {
				return frames
			}
		}
	}

	return nil
}

// dwarfSourceLineEntry tries to get file/line information from a
// DWARF compilation unit. Returns nil if it doesn't find anything.
func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []driver.Frame {
	lines, err := f.dwarf.LineReader(entry)
	if err != nil {
		return nil
	}
	var lentry dwarf.LineEntry
	if err := lines.SeekPC(addr, &lentry); err != nil {
		return nil
	}

	// Try to find the function name.
	name := ""
FindName:
	for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
		if entry.Tag == dwarf.TagSubprogram {
			ranges, err := f.dwarf.Ranges(entry)
			if err != nil {
				return nil
			}
			for _, pcs := range ranges {
				if pcs[0] <= addr && addr < pcs[1] {
					var ok bool
					// TODO: AT_linkage_name, AT_MIPS_linkage_name.
					name, ok = entry.Val(dwarf.AttrName).(string)
					if ok {
						break FindName
					}
				}
			}
		}
	}

	// TODO: Report inlined functions.

	frames := []driver.Frame{
		{
			Func: name,
			File: lentry.File.Name,
			Line: lentry.Line,
		},
	}

	return frames
}

func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*driver.Sym, error) {
	if f.sym == nil {
		sym, err := f.file.Symbols()
		if err != nil {
			return nil, err
		}
		f.sym = sym
	}
	var out []*driver.Sym
	for _, s := range f.sym {
		// Ignore a symbol with address 0 and size 0.
		// An ELF STT_FILE symbol will look like that.
		if s.Addr == 0 && s.Size == 0 {
			continue
		}
		if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
			out = append(out, &driver.Sym{
				Name:  []string{s.Name},
				File:  f.name,
				Start: s.Addr,
				End:   s.Addr + uint64(s.Size) - 1,
			})
		}
	}
	return out, nil
}

func (f *file) Close() error {
	f.file.Close()
	return nil
}
<commit_msg>cmd/pprof: use proxy from environment<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// pprof is a tool for visualization of profile.data. It is based on
// the upstream version at github.com/google/pprof, with minor
// modifications specific to the Go distribution. Please consider
// upstreaming any modifications to these packages.

package main

import (
	"crypto/tls"
	"debug/dwarf"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"sync"
	"time"

	"cmd/internal/objfile"

	"github.com/google/pprof/driver"
	"github.com/google/pprof/profile"
)

func main() {
	options := &driver.Options{
		Fetch: new(fetcher),
		Obj:   new(objTool),
	}
	if err := driver.PProf(options); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(2)
	}
}

type fetcher struct {
}

func (f *fetcher) Fetch(src string, duration, timeout time.Duration) (*profile.Profile, string, error) {
	sourceURL, timeout := adjustURL(src, duration, timeout)
	if sourceURL == "" {
		// Could not recognize URL, let regular pprof attempt to fetch the profile (eg. from a file)
		return nil, "", nil
	}
	fmt.Fprintln(os.Stderr, "Fetching profile over HTTP from", sourceURL)
	if duration > 0 {
		fmt.Fprintf(os.Stderr, "Please wait... (%v)\n", duration)
	}
	p, err := getProfile(sourceURL, timeout)
	return p, sourceURL, err
}

func getProfile(source string, timeout time.Duration) (*profile.Profile, error) {
	url, err := url.Parse(source)
	if err != nil {
		return nil, err
	}

	var tlsConfig *tls.Config
	if url.Scheme == "https+insecure" {
		tlsConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
		url.Scheme = "https"
		source = url.String()
	}

	client := &http.Client{
		Transport: &http.Transport{
			ResponseHeaderTimeout: timeout + 5*time.Second,
			Proxy:           http.ProxyFromEnvironment,
			TLSClientConfig: tlsConfig,
		},
	}
	resp, err := client.Get(source)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("server response: %s", resp.Status)
	}
	return profile.Parse(resp.Body)
}

// cpuProfileHandler is the Go pprof CPU profile handler URL.
const cpuProfileHandler = "/debug/pprof/profile"

// adjustURL applies the duration/timeout values and Go specific defaults
func adjustURL(source string, duration, timeout time.Duration) (string, time.Duration) {
	u, err := url.Parse(source)
	if err != nil || (u.Host == "" && u.Scheme != "" && u.Scheme != "file") {
		// Try adding http:// to catch sources of the form hostname:port/path.
		// url.Parse treats "hostname" as the scheme.
		u, err = url.Parse("http://" + source)
	}
	if err != nil || u.Host == "" {
		return "", 0
	}

	if u.Path == "" || u.Path == "/" {
		u.Path = cpuProfileHandler
	}

	// Apply duration/timeout overrides to URL.
	values := u.Query()
	if duration > 0 {
		values.Set("seconds", fmt.Sprint(int(duration.Seconds())))
	} else {
		if urlSeconds := values.Get("seconds"); urlSeconds != "" {
			if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
				duration = time.Duration(us) * time.Second
			}
		}
	}
	if timeout <= 0 {
		if duration > 0 {
			timeout = duration + duration/2
		} else {
			timeout = 60 * time.Second
		}
	}
	u.RawQuery = values.Encode()
	return u.String(), timeout
}

// objTool implements driver.ObjTool using Go libraries
// (instead of invoking GNU binutils).
type objTool struct {
	mu          sync.Mutex
	disasmCache map[string]*objfile.Disasm
}

func (*objTool) Open(name string, start, limit, offset uint64) (driver.ObjFile, error) {
	of, err := objfile.Open(name)
	if err != nil {
		return nil, err
	}
	f := &file{
		name: name,
		file: of,
	}
	if start != 0 {
		if load, err := of.LoadAddress(); err == nil {
			f.offset = start - load
		}
	}
	return f, nil
}

func (*objTool) Demangle(names []string) (map[string]string, error) {
	// No C++, nothing to demangle.
	return make(map[string]string), nil
}

func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error) {
	d, err := t.cachedDisasm(file)
	if err != nil {
		return nil, err
	}
	var asm []driver.Inst
	d.Decode(start, end, nil, func(pc, size uint64, file string, line int, text string) {
		asm = append(asm, driver.Inst{Addr: pc, File: file, Line: line, Text: text})
	})
	return asm, nil
}

func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
	t.mu.Lock()
	defer t.mu.Unlock()
	if t.disasmCache == nil {
		t.disasmCache = make(map[string]*objfile.Disasm)
	}
	d := t.disasmCache[file]
	if d != nil {
		return d, nil
	}
	f, err := objfile.Open(file)
	if err != nil {
		return nil, err
	}
	d, err = f.Disasm()
	f.Close()
	if err != nil {
		return nil, err
	}
	t.disasmCache[file] = d
	return d, nil
}

func (*objTool) SetConfig(config string) {
	// config is usually used to say what binaries to invoke.
	// Ignore entirely.
}

// file implements driver.ObjFile using Go libraries
// (instead of invoking GNU binutils).
// A file represents a single executable being analyzed.
type file struct {
	name   string
	offset uint64
	sym    []objfile.Sym
	file   *objfile.File
	pcln   objfile.Liner

	triedDwarf bool
	dwarf      *dwarf.Data
}

func (f *file) Name() string {
	return f.name
}

func (f *file) Base() uint64 {
	// No support for shared libraries.
	return 0
}

func (f *file) BuildID() string {
	// No support for build ID.
	return ""
}

func (f *file) SourceLine(addr uint64) ([]driver.Frame, error) {
	if f.pcln == nil {
		pcln, err := f.file.PCLineTable()
		if err != nil {
			return nil, err
		}
		f.pcln = pcln
	}
	addr -= f.offset
	file, line, fn := f.pcln.PCToLine(addr)
	if fn != nil {
		frame := []driver.Frame{
			{
				Func: fn.Name,
				File: file,
				Line: line,
			},
		}
		return frame, nil
	}

	frames := f.dwarfSourceLine(addr)
	if frames != nil {
		return frames, nil
	}

	return nil, fmt.Errorf("no line information for PC=%#x", addr)
}

// dwarfSourceLine tries to get file/line information using DWARF.
// This is for C functions that appear in the profile.
// Returns nil if there is no information available.
func (f *file) dwarfSourceLine(addr uint64) []driver.Frame {
	if f.dwarf == nil && !f.triedDwarf {
		// Ignore any error--we don't care exactly why there
		// is no DWARF info.
		f.dwarf, _ = f.file.DWARF()
		f.triedDwarf = true
	}

	if f.dwarf != nil {
		r := f.dwarf.Reader()
		unit, err := r.SeekPC(addr)
		if err == nil {
			if frames := f.dwarfSourceLineEntry(r, unit, addr); frames != nil {
				return frames
			}
		}
	}

	return nil
}

// dwarfSourceLineEntry tries to get file/line information from a
// DWARF compilation unit. Returns nil if it doesn't find anything.
func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []driver.Frame {
	lines, err := f.dwarf.LineReader(entry)
	if err != nil {
		return nil
	}
	var lentry dwarf.LineEntry
	if err := lines.SeekPC(addr, &lentry); err != nil {
		return nil
	}

	// Try to find the function name.
	name := ""
FindName:
	for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
		if entry.Tag == dwarf.TagSubprogram {
			ranges, err := f.dwarf.Ranges(entry)
			if err != nil {
				return nil
			}
			for _, pcs := range ranges {
				if pcs[0] <= addr && addr < pcs[1] {
					var ok bool
					// TODO: AT_linkage_name, AT_MIPS_linkage_name.
					name, ok = entry.Val(dwarf.AttrName).(string)
					if ok {
						break FindName
					}
				}
			}
		}
	}

	// TODO: Report inlined functions.

	frames := []driver.Frame{
		{
			Func: name,
			File: lentry.File.Name,
			Line: lentry.Line,
		},
	}

	return frames
}

func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*driver.Sym, error) {
	if f.sym == nil {
		sym, err := f.file.Symbols()
		if err != nil {
			return nil, err
		}
		f.sym = sym
	}
	var out []*driver.Sym
	for _, s := range f.sym {
		// Ignore a symbol with address 0 and size 0.
		// An ELF STT_FILE symbol will look like that.
		if s.Addr == 0 && s.Size == 0 {
			continue
		}
		if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
			out = append(out, &driver.Sym{
				Name:  []string{s.Name},
				File:  f.name,
				Start: s.Addr,
				End:   s.Addr + uint64(s.Size) - 1,
			})
		}
	}
	return out, nil
}

func (f *file) Close() error {
	f.file.Close()
	return nil
}
<|endoftext|>


<commit_before>// event.go

package main

import (
	"fmt"
	"os"

	"github.com/hashicorp/memberlist"
)

// EventHandler is a implentation of memberlists Deligate interface. It will be
// used to alert our decision system when node activity happens.
type EventHandler struct {
	Active bool //
}

// NotifyJoin is invoked when a node is detected to have joined. The Node argument
// must not be modified. We send advice to the decision engine and let it decide
// what to do
func (e EventHandler) NotifyJoin(n *memberlist.Node) {
	log.Debug("[event.NotifyJoin] '%s' joined the cluster...\n", n.Name)
	go func() {
		advice <- "join" + n.Name
	}()
}

// NotifyLeave is invoked when a node is detected to have left. The Node argument
// must not be modified. We send advice to the decision engine and let it decide
// what to do
func (e EventHandler) NotifyLeave(n *memberlist.Node) {
	log.Debug("[event.NotifyLeave] '%s' left the cluster...\n", n.Name)
	go func() {
		advice <- "leave" + n.Name
	}()
}

// NotifyUpdate is invoked when a node is detected to have updated, usually
// involving the meta data. The Node argument must not be modified. We send advice
// to the decision engine and let it decide what to do
func (e EventHandler) NotifyUpdate(n *memberlist.Node) {
	log.Debug("[event.NotifyUpdate] '%s' was updated\n", n.Name)
	go func() {
		advice <- "update" + n.Name
	}()
}

// NotifyConflict detects if we colide with a member of the same name and are
// unable to join
func (e EventHandler) NotifyConflict(existing, other *memberlist.Node) {

	//
	defer func() {
		recover()
		log.Fatal("[event.NotifyConflict] '%s' already exists in cluster... unable to join! Exiting...\n", n.Name)
		os.Exit(1)
	}()

	fmt.Println(len(list.Members()))
}
<commit_msg>better<commit_after>// event.go

package main

import (
	"fmt"
	"os"

	"github.com/hashicorp/memberlist"
)

// EventHandler is a implentation of memberlists Deligate interface. It will be
// used to alert our decision system when node activity happens.
type EventHandler struct {
	Active bool //
}

// NotifyJoin is invoked when a node is detected to have joined. The Node argument
// must not be modified. We send advice to the decision engine and let it decide
// what to do
func (e EventHandler) NotifyJoin(n *memberlist.Node) {
	log.Debug("[event.NotifyJoin] '%s' joined the cluster...\n", n.Name)
	go func() {
		advice <- "join" + n.Name
	}()
}

// NotifyLeave is invoked when a node is detected to have left. The Node argument
// must not be modified. We send advice to the decision engine and let it decide
// what to do
func (e EventHandler) NotifyLeave(n *memberlist.Node) {
	log.Debug("[event.NotifyLeave] '%s' left the cluster...\n", n.Name)
	go func() {
		advice <- "leave" + n.Name
	}()
}

// NotifyUpdate is invoked when a node is detected to have updated, usually
// involving the meta data. The Node argument must not be modified. We send advice
// to the decision engine and let it decide what to do
func (e EventHandler) NotifyUpdate(n *memberlist.Node) {
	log.Debug("[event.NotifyUpdate] '%s' was updated\n", n.Name)
	go func() {
		advice <- "update" + n.Name
	}()
}

// NotifyConflict detects if we colide with a member of the same name and are
// unable to join
func (e EventHandler) NotifyConflict(existing, other *memberlist.Node) {

	//
	defer func() {
    if r := recover(); r != nil {
			log.Fatal("[event.NotifyConflict] '%s' already exists in cluster... unable to join! Exiting...\n", existing.Name)
			log.Close()
			os.Exit(1)
    }
	}()

	fmt.Println(len(list.Members()))
}
<|endoftext|>


<commit_before>package slack

import (
	"encoding/json"
)

type messageWrapper struct {
	message *Message
	status  Status
}

// OnEvent registers handler to fire on the given type of event.
func (bot *Bot) OnEvent(event string, handler BotAction) {
	handlers, ok := bot.Handlers[event]
	if !ok {
		handlers = make([]BotAction, 0)
	}
	handlers = append(handlers, handler)
	bot.Handlers[event] = handlers
}

// OnEventWithSubtype registers handler to fire on the given type and subtype
// of event.
func (bot *Bot) OnEventWithSubtype(event, subtype string, handler BotAction) {
	subtypeMap, ok := bot.Subhandlers[event]
	if !ok {
		subtypeMap = make(map[string]([]BotAction))
		bot.Subhandlers[event] = subtypeMap
	}
	handlers, ok := bot.Subhandlers[event][subtype]
	if !ok {
		handlers = make([]BotAction, 0)
	}
	handlers = append(handlers, handler)
	bot.Subhandlers[event][subtype] = handlers
}

func unpackEvent(bytes []byte) (map[string]interface{}, error) {
	var message map[string]interface{}
	err := json.Unmarshal(bytes, &message)
	if err != nil {
		return nil, err
	}
	return message, nil
}

func (bot *Bot) handle(event map[string]interface{}) []messageWrapper {
	wrappers := make([]messageWrapper, 0)

	eventType, hasType := event["type"].(string)
	eventSubtype, hasSubtype := event["subtype"].(string)

	if hasSubtype {
		subhandlers, ok := bot.Subhandlers[eventType][eventSubtype]
		if ok {
			for _, subhandler := range subhandlers {
				message, status := subhandler(bot, event)
				wrappers = append(wrappers, messageWrapper{message, status})
			}
		}
	}
	if hasType {
		handlers, ok := bot.Handlers[eventType]
		if ok {
			for _, handler := range handlers {
				message, status := handler(bot, event)
				wrappers = append(wrappers, messageWrapper{message, status})
			}
		}
	}
	return wrappers
}
<commit_msg>make sure nested map is there before accessing it. closes #13<commit_after>package slack

import (
	"encoding/json"
)

type messageWrapper struct {
	message *Message
	status  Status
}

// OnEvent registers handler to fire on the given type of event.
func (bot *Bot) OnEvent(event string, handler BotAction) {
	handlers, ok := bot.Handlers[event]
	if !ok {
		handlers = make([]BotAction, 0)
	}
	handlers = append(handlers, handler)
	bot.Handlers[event] = handlers
}

// OnEventWithSubtype registers handler to fire on the given type and subtype
// of event.
func (bot *Bot) OnEventWithSubtype(event, subtype string, handler BotAction) {
	subtypeMap, ok := bot.Subhandlers[event]
	if !ok {
		subtypeMap = make(map[string]([]BotAction))
		bot.Subhandlers[event] = subtypeMap
	}
	handlers, ok := bot.Subhandlers[event][subtype]
	if !ok {
		handlers = make([]BotAction, 0)
	}
	handlers = append(handlers, handler)
	bot.Subhandlers[event][subtype] = handlers
}

func unpackEvent(bytes []byte) (map[string]interface{}, error) {
	var message map[string]interface{}
	err := json.Unmarshal(bytes, &message)
	if err != nil {
		return nil, err
	}
	return message, nil
}

func (bot *Bot) handle(event map[string]interface{}) []messageWrapper {
	wrappers := make([]messageWrapper, 0)

	eventType, hasType := event["type"].(string)
	eventSubtype, hasSubtype := event["subtype"].(string)

	if hasSubtype {
		subhandlerMap, ok := bot.Subhandlers[eventType]
		if ok {
			subhandlers, ok := subhandlerMap[eventSubtype]
			if ok {
				for _, subhandler := range subhandlers {
					message, status := subhandler(bot, event)
					wrappers = append(wrappers,
						messageWrapper{message, status})
				}
			}
		}
	}
	if hasType {
		handlers, ok := bot.Handlers[eventType]
		if ok {
			for _, handler := range handlers {
				message, status := handler(bot, event)
				wrappers = append(wrappers, messageWrapper{message, status})
			}
		}
	}
	return wrappers
}
<|endoftext|>


<commit_before>package ipip

import (
	"fmt"
	"testing"
)

func Test_Load(t *testing.T) {
	p := NewIpip()
	if err := p.Load("17monipdb.dat"); err != nil {
		t.Fatal(err)
	}
}

func Test_Find(t *testing.T) {
	p := NewIpip()
	if err := p.Load("17monipdb.dat"); err != nil {
		t.Fatal(err)
	}
	if _, err := p.Find("110.172.245.98"); err != nil {
		t.Fatal(err)
	}
	if _, err := p.Find("google.com"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
	if _, err := p.Find("110.172.245"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
	if _, err := p.Find("aaa"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
}
<commit_msg>clean<commit_after>package ipip

import (
	"testing"
)

func Test_Load(t *testing.T) {
	p := NewIpip()
	if err := p.Load("17monipdb.dat"); err != nil {
		t.Fatal(err)
	}
}

func Test_Find(t *testing.T) {
	p := NewIpip()
	if err := p.Load("17monipdb.dat"); err != nil {
		t.Fatal(err)
	}
	if _, err := p.Find("110.172.245.98"); err != nil {
		t.Fatal(err)
	}
	if _, err := p.Find("google.com"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
	if _, err := p.Find("110.172.245"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
	if _, err := p.Find("aaa"); err != nil && err != ErrInvalidIp {
		t.Fatal(err)
	}
}
<|endoftext|>