<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
	log "github.com/sirupsen/logrus"
	"github.com/yuin/gopher-lua"
)

// FutureStatus is useful when redirecting in combination with writing to a
// buffer before writing to a client. May contain more fields in the future.
type FutureStatus struct {
	code int
}

func exportBasicSystemFunctions(L *lua.LState) {

	// Return the version string
	L.SetGlobal("version", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(versionString))
		return 1 // number of results
	}))

	// Log text with the "Info" log type
	L.SetGlobal("log", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Info(buf.String())
		return 0 // number of results
	}))

	// Log text with the "Warn" log type
	L.SetGlobal("warn", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Warn(buf.String())
		return 0 // number of results
	}))

	// Log text with the "Error" log type
	L.SetGlobal("err", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Error(buf.String())
		return 0 // number of results
	}))

	// Sleep for the given number of seconds (can be a float)
	L.SetGlobal("sleep", L.NewFunction(func(L *lua.LState) int {
		// Extract the correct number of nanoseconds
		duration := time.Duration(float64(L.ToNumber(1)) * 1000000000.0)
		// Wait and block the current thread of execution.
		time.Sleep(duration)
		return 0
	}))

	// Return the current unixtime, with an attempt at nanosecond resolution
	L.SetGlobal("unixnano", L.NewFunction(func(L *lua.LState) int {
		// Extract the correct number of nanoseconds
		L.Push(lua.LNumber(time.Now().UnixNano()))
		return 1 // number of results
	}))

	// Convert Markdown to HTML
	L.SetGlobal("markdown", L.NewFunction(func(L *lua.LState) int {
		// Retrieve all the function arguments as a bytes.Buffer
		buf := arguments2buffer(L, true)
		// Convert the buffer to markdown and output the translated string
		html := strings.TrimSpace(string(blackfriday.MarkdownCommon([]byte(buf.String()))))
		L.Push(lua.LString(html))
		return 1 // number of results
	}))

	// Get the full filename of a given file that is in the directory
	// where the server is running (root directory for the server).
	// If no filename is given, the directory where the server is
	// currently running is returned.
	L.SetGlobal("serverdir", L.NewFunction(func(L *lua.LState) int {
		serverdir, err := os.Getwd()
		if err != nil {
			// Could not retrieve a directory
			serverdir = ""
		} else if L.GetTop() == 1 {
			// Also include a separator and a filename
			fn := L.ToString(1)
			serverdir = filepath.Join(serverdir, fn)
		}
		L.Push(lua.LString(serverdir))
		return 1 // number of results
	}))

}

// Make functions related to HTTP requests and responses available to Lua scripts.
// Filename can be an empty string.
// realW is only used for flushing the buffer in debug mode, and is the underlying ResponseWriter.
func exportBasicWeb(w http.ResponseWriter, req *http.Request, L *lua.LState, filename string, flushFunc func(), httpStatus *FutureStatus) {

	// Print text to the webpage that is being served. Add a newline.
	L.SetGlobal("print", L.NewFunction(func(L *lua.LState) int {
		var buf bytes.Buffer
		top := L.GetTop()
		for i := 1; i <= top; i++ {
			buf.WriteString(L.Get(i).String())
			if i != top {
				buf.WriteString("\t")
			}
		}
		// Final newline
		buf.WriteString("\n")

		// Write the combined text to the http.ResponseWriter
		buf.WriteTo(w)

		return 0 // number of results
	}))

	// Pretty print text to the webpage that is being served. Add a newline.
	L.SetGlobal("pprint", L.NewFunction(func(L *lua.LState) int {
		var buf bytes.Buffer
		top := L.GetTop()
		for i := 1; i <= top; i++ {
			pprintToWriter(&buf, L.Get(i))
			if i != top {
				buf.WriteString("\t")
			}
		}
		// Final newline
		buf.WriteString("\n")

		// Write the combined text to the http.ResponseWriter
		buf.WriteTo(w)

		return 0 // number of results
	}))

	// Flush the ResponseWriter.
	// Needed in debug mode, where ResponseWriter is buffered.
	L.SetGlobal("flush", L.NewFunction(func(L *lua.LState) int {
		if flushFunc != nil {
			flushFunc()
		}
		return 0 // number of results
	}))

	// Set the Content-Type for the page
	L.SetGlobal("content", L.NewFunction(func(L *lua.LState) int {
		lv := L.ToString(1)
		w.Header().Add("Content-Type", lv)
		return 0 // number of results
	}))

	// Return the current URL Path
	L.SetGlobal("urlpath", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(req.URL.Path))
		return 1 // number of results
	}))

	// Return the current HTTP method (GET, POST etc)
	L.SetGlobal("method", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(req.Method))
		return 1 // number of results
	}))

	// Return the HTTP headers as a table
	L.SetGlobal("headers", L.NewFunction(func(L *lua.LState) int {
		luaTable := L.NewTable()
		for key := range req.Header {
			L.RawSet(luaTable, lua.LString(key), lua.LString(req.Header.Get(key)))
		}
		L.Push(luaTable)
		return 1 // number of results
	}))

	// Return the HTTP header in the request, for a given key/string
	L.SetGlobal("header", L.NewFunction(func(L *lua.LState) int {
		key := L.ToString(1)
		value := req.Header.Get(key)
		L.Push(lua.LString(value))
		return 1 // number of results
	}))

	// Set the HTTP header in the request, for a given key and value
	L.SetGlobal("setheader", L.NewFunction(func(L *lua.LState) int {
		key := L.ToString(1)
		value := L.ToString(2)
		w.Header().Set(key, value)
		return 0 // number of results
	}))

	// Return the HTTP body in the request
	L.SetGlobal("body", L.NewFunction(func(L *lua.LState) int {
		body, err := ioutil.ReadAll(req.Body)
		var result lua.LString
		if err != nil {
			result = lua.LString("")
		} else {
			result = lua.LString(string(body))
		}
		L.Push(result)
		return 1 // number of results
	}))

	// Set the HTTP status code (must come before print)
	L.SetGlobal("status", L.NewFunction(func(L *lua.LState) int {
		code := int(L.ToNumber(1))
		if httpStatus != nil {
			httpStatus.code = code
		}
		w.WriteHeader(code)
		return 0 // number of results
	}))

	// Set a HTTP status code and print a message (optional)
	L.SetGlobal("error", L.NewFunction(func(L *lua.LState) int {
		code := int(L.ToNumber(1))
		if httpStatus != nil {
			httpStatus.code = code
		}
		w.WriteHeader(code)
		if L.GetTop() == 2 {
			message := L.ToString(2)
			fmt.Fprint(w, message)
		}
		return 0 // number of results
	}))

	// Get the full filename of a given file that is in the directory
	// of the script that is about to be run. If no filename is given,
	// the directory of the script is returned.
	L.SetGlobal("scriptdir", L.NewFunction(func(L *lua.LState) int {
		scriptpath, err := filepath.Abs(filename)
		if err != nil {
			scriptpath = filename
		}
		scriptdir := filepath.Dir(scriptpath)
		scriptpath = scriptdir
		top := L.GetTop()
		if top == 1 {
			// Also include a separator and a filename
			fn := L.ToString(1)
			scriptpath = filepath.Join(scriptdir, fn)
		}
		// Now have the correct absolute scriptpath
		L.Push(lua.LString(scriptpath))
		return 1 // number of results
	}))

	// Given a filename, return the URL path
	L.SetGlobal("file2url", L.NewFunction(func(L *lua.LState) int {
		fn := L.ToString(1)
		targetpath := filepath.Join(filepath.Dir(filename), fn)
		if strings.HasPrefix(targetpath, serverDir) {
			targetpath = targetpath[len(serverDir):]
		}
		if pathsep != "/" {
			// For operating systems that use another path separator for files than for URLs
			targetpath = strings.Replace(targetpath, pathsep, "/", everyInstance)
		}
		withSlashPrefix := path.Join("/", targetpath)
		L.Push(lua.LString(withSlashPrefix))
		return 1 // number of results
	}))

	// Retrieve a table with keys and values from the form in the request
	L.SetGlobal("formdata", L.NewFunction(func(L *lua.LState) int {
		// Place the form data in a map
		m := make(map[string]string)
		req.ParseForm()
		for key, values := range req.Form {
			m[key] = values[0]
		}
		// Convert the map to a table and return it
		L.Push(map2table(L, m))
		return 1 // number of results
	}))

	// Retrieve a table with keys and values from the URL in the request
	L.SetGlobal("urldata", L.NewFunction(func(L *lua.LState) int {

		var valueMap url.Values
		var err error

		if L.GetTop() == 1 {
			// If given an argument
			rawurl := L.ToString(1)
			valueMap, err = url.ParseQuery(rawurl)
			// Log error as warning if there are issues.
			// An empty Value map will then be used.
			if err != nil {
				log.Error(err)
				// return 0
			}
		} else {
			// If not given an argument
			valueMap = req.URL.Query() // map[string][]string
		}

		// Place the Value data in a map, using the first values
		// if there are many values for a given key.
		m := make(map[string]string)
		for key, values := range valueMap {
			m[key] = values[0]
		}
		// Convert the map to a table and return it
		L.Push(map2table(L, m))
		return 1 // number of results
	}))

	// Redirect a request (as found, by default)
	L.SetGlobal("redirect", L.NewFunction(func(L *lua.LState) int {
		newurl := L.ToString(1)
		httpStatusCode := http.StatusFound
		if L.GetTop() == 2 {
			httpStatusCode = int(L.ToNumber(2))
		}
		if httpStatus != nil {
			httpStatus.code = httpStatusCode
		}
		http.Redirect(w, req, newurl, httpStatusCode)
		return 0 // number of results
	}))

	// Permanently redirect a request, which is the same as redirect(url, 301)
	L.SetGlobal("permanent_redirect", L.NewFunction(func(L *lua.LState) int {
		newurl := L.ToString(1)
		httpStatusCode := http.StatusMovedPermanently
		if httpStatus != nil {
			httpStatus.code = httpStatusCode
		}
		http.Redirect(w, req, newurl, httpStatusCode)
		return 0 // number of results
	}))

	// Run the given Lua file (replacement for the built-in dofile, to look in the right directory)
	// Returns whatever the Lua file returns when it is being run.
	L.SetGlobal("dofile", L.NewFunction(func(L *lua.LState) int {
		givenFilename := L.ToString(1)
		luaFilename := filepath.Join(filepath.Dir(filename), givenFilename)
		if !fs.exists(luaFilename) {
			log.Error("Could not find:", luaFilename)
			return 0 // number of results
		}
		if err := L.DoFile(luaFilename); err != nil {
			log.Errorf("Error running %s: %s\n", luaFilename, err.Error())
			return 0 // number of results
		}
		// Retrieve the returned value from the script
		retval := L.Get(-1)
		L.Pop(1)
		// Return the value returned from the script
		L.Push(retval)
		return 1 // number of results
	}))

}
<commit_msg>Add ppstr function<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
	log "github.com/sirupsen/logrus"
	"github.com/yuin/gopher-lua"
)

// FutureStatus is useful when redirecting in combination with writing to a
// buffer before writing to a client. May contain more fields in the future.
type FutureStatus struct {
	code int
}

func exportBasicSystemFunctions(L *lua.LState) {

	// Return the version string
	L.SetGlobal("version", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(versionString))
		return 1 // number of results
	}))

	// Log text with the "Info" log type
	L.SetGlobal("log", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Info(buf.String())
		return 0 // number of results
	}))

	// Log text with the "Warn" log type
	L.SetGlobal("warn", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Warn(buf.String())
		return 0 // number of results
	}))

	// Log text with the "Error" log type
	L.SetGlobal("err", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L, false)
		// Log the combined text
		log.Error(buf.String())
		return 0 // number of results
	}))

	// Sleep for the given number of seconds (can be a float)
	L.SetGlobal("sleep", L.NewFunction(func(L *lua.LState) int {
		// Extract the correct number of nanoseconds
		duration := time.Duration(float64(L.ToNumber(1)) * 1000000000.0)
		// Wait and block the current thread of execution.
		time.Sleep(duration)
		return 0
	}))

	// Return the current unixtime, with an attempt at nanosecond resolution
	L.SetGlobal("unixnano", L.NewFunction(func(L *lua.LState) int {
		// Extract the correct number of nanoseconds
		L.Push(lua.LNumber(time.Now().UnixNano()))
		return 1 // number of results
	}))

	// Convert Markdown to HTML
	L.SetGlobal("markdown", L.NewFunction(func(L *lua.LState) int {
		// Retrieve all the function arguments as a bytes.Buffer
		buf := arguments2buffer(L, true)
		// Convert the buffer to markdown and output the translated string
		html := strings.TrimSpace(string(blackfriday.MarkdownCommon([]byte(buf.String()))))
		L.Push(lua.LString(html))
		return 1 // number of results
	}))

	// Get the full filename of a given file that is in the directory
	// where the server is running (root directory for the server).
	// If no filename is given, the directory where the server is
	// currently running is returned.
	L.SetGlobal("serverdir", L.NewFunction(func(L *lua.LState) int {
		serverdir, err := os.Getwd()
		if err != nil {
			// Could not retrieve a directory
			serverdir = ""
		} else if L.GetTop() == 1 {
			// Also include a separator and a filename
			fn := L.ToString(1)
			serverdir = filepath.Join(serverdir, fn)
		}
		L.Push(lua.LString(serverdir))
		return 1 // number of results
	}))

}

// Make functions related to HTTP requests and responses available to Lua scripts.
// Filename can be an empty string.
// realW is only used for flushing the buffer in debug mode, and is the underlying ResponseWriter.
func exportBasicWeb(w http.ResponseWriter, req *http.Request, L *lua.LState, filename string, flushFunc func(), httpStatus *FutureStatus) {

	// Print text to the webpage that is being served. Add a newline.
	L.SetGlobal("print", L.NewFunction(func(L *lua.LState) int {
		var buf bytes.Buffer
		top := L.GetTop()
		for i := 1; i <= top; i++ {
			buf.WriteString(L.Get(i).String())
			if i != top {
				buf.WriteString("\t")
			}
		}
		// Final newline
		buf.WriteString("\n")

		// Write the combined text to the http.ResponseWriter
		buf.WriteTo(w)

		return 0 // number of results
	}))

	// Pretty print text to the webpage that is being served. Add a newline.
	L.SetGlobal("pprint", L.NewFunction(func(L *lua.LState) int {
		var buf bytes.Buffer
		top := L.GetTop()
		for i := 1; i <= top; i++ {
			pprintToWriter(&buf, L.Get(i))
			if i != top {
				buf.WriteString("\t")
			}
		}
		// Final newline
		buf.WriteString("\n")

		// Write the combined text to the http.ResponseWriter
		buf.WriteTo(w)

		return 0 // number of results
	}))

	// Pretty print to string
	L.SetGlobal("ppstr", L.NewFunction(func(L *lua.LState) int {
		var buf bytes.Buffer
		top := L.GetTop()
		for i := 1; i <= top; i++ {
			pprintToWriter(&buf, L.Get(i))
			if i != top {
				buf.WriteString("\t")
			}
		}
		// Final newline
		buf.WriteString("\n")

		// Return the string
		L.Push(lua.LString(buf.String()))

		return 1 // number of results
	}))

	// Flush the ResponseWriter.
	// Needed in debug mode, where ResponseWriter is buffered.
	L.SetGlobal("flush", L.NewFunction(func(L *lua.LState) int {
		if flushFunc != nil {
			flushFunc()
		}
		return 0 // number of results
	}))

	// Set the Content-Type for the page
	L.SetGlobal("content", L.NewFunction(func(L *lua.LState) int {
		lv := L.ToString(1)
		w.Header().Add("Content-Type", lv)
		return 0 // number of results
	}))

	// Return the current URL Path
	L.SetGlobal("urlpath", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(req.URL.Path))
		return 1 // number of results
	}))

	// Return the current HTTP method (GET, POST etc)
	L.SetGlobal("method", L.NewFunction(func(L *lua.LState) int {
		L.Push(lua.LString(req.Method))
		return 1 // number of results
	}))

	// Return the HTTP headers as a table
	L.SetGlobal("headers", L.NewFunction(func(L *lua.LState) int {
		luaTable := L.NewTable()
		for key := range req.Header {
			L.RawSet(luaTable, lua.LString(key), lua.LString(req.Header.Get(key)))
		}
		L.Push(luaTable)
		return 1 // number of results
	}))

	// Return the HTTP header in the request, for a given key/string
	L.SetGlobal("header", L.NewFunction(func(L *lua.LState) int {
		key := L.ToString(1)
		value := req.Header.Get(key)
		L.Push(lua.LString(value))
		return 1 // number of results
	}))

	// Set the HTTP header in the request, for a given key and value
	L.SetGlobal("setheader", L.NewFunction(func(L *lua.LState) int {
		key := L.ToString(1)
		value := L.ToString(2)
		w.Header().Set(key, value)
		return 0 // number of results
	}))

	// Return the HTTP body in the request
	L.SetGlobal("body", L.NewFunction(func(L *lua.LState) int {
		body, err := ioutil.ReadAll(req.Body)
		var result lua.LString
		if err != nil {
			result = lua.LString("")
		} else {
			result = lua.LString(string(body))
		}
		L.Push(result)
		return 1 // number of results
	}))

	// Set the HTTP status code (must come before print)
	L.SetGlobal("status", L.NewFunction(func(L *lua.LState) int {
		code := int(L.ToNumber(1))
		if httpStatus != nil {
			httpStatus.code = code
		}
		w.WriteHeader(code)
		return 0 // number of results
	}))

	// Set a HTTP status code and print a message (optional)
	L.SetGlobal("error", L.NewFunction(func(L *lua.LState) int {
		code := int(L.ToNumber(1))
		if httpStatus != nil {
			httpStatus.code = code
		}
		w.WriteHeader(code)
		if L.GetTop() == 2 {
			message := L.ToString(2)
			fmt.Fprint(w, message)
		}
		return 0 // number of results
	}))

	// Get the full filename of a given file that is in the directory
	// of the script that is about to be run. If no filename is given,
	// the directory of the script is returned.
	L.SetGlobal("scriptdir", L.NewFunction(func(L *lua.LState) int {
		scriptpath, err := filepath.Abs(filename)
		if err != nil {
			scriptpath = filename
		}
		scriptdir := filepath.Dir(scriptpath)
		scriptpath = scriptdir
		top := L.GetTop()
		if top == 1 {
			// Also include a separator and a filename
			fn := L.ToString(1)
			scriptpath = filepath.Join(scriptdir, fn)
		}
		// Now have the correct absolute scriptpath
		L.Push(lua.LString(scriptpath))
		return 1 // number of results
	}))

	// Given a filename, return the URL path
	L.SetGlobal("file2url", L.NewFunction(func(L *lua.LState) int {
		fn := L.ToString(1)
		targetpath := filepath.Join(filepath.Dir(filename), fn)
		if strings.HasPrefix(targetpath, serverDir) {
			targetpath = targetpath[len(serverDir):]
		}
		if pathsep != "/" {
			// For operating systems that use another path separator for files than for URLs
			targetpath = strings.Replace(targetpath, pathsep, "/", everyInstance)
		}
		withSlashPrefix := path.Join("/", targetpath)
		L.Push(lua.LString(withSlashPrefix))
		return 1 // number of results
	}))

	// Retrieve a table with keys and values from the form in the request
	L.SetGlobal("formdata", L.NewFunction(func(L *lua.LState) int {
		// Place the form data in a map
		m := make(map[string]string)
		req.ParseForm()
		for key, values := range req.Form {
			m[key] = values[0]
		}
		// Convert the map to a table and return it
		L.Push(map2table(L, m))
		return 1 // number of results
	}))

	// Retrieve a table with keys and values from the URL in the request
	L.SetGlobal("urldata", L.NewFunction(func(L *lua.LState) int {

		var valueMap url.Values
		var err error

		if L.GetTop() == 1 {
			// If given an argument
			rawurl := L.ToString(1)
			valueMap, err = url.ParseQuery(rawurl)
			// Log error as warning if there are issues.
			// An empty Value map will then be used.
			if err != nil {
				log.Error(err)
				// return 0
			}
		} else {
			// If not given an argument
			valueMap = req.URL.Query() // map[string][]string
		}

		// Place the Value data in a map, using the first values
		// if there are many values for a given key.
		m := make(map[string]string)
		for key, values := range valueMap {
			m[key] = values[0]
		}
		// Convert the map to a table and return it
		L.Push(map2table(L, m))
		return 1 // number of results
	}))

	// Redirect a request (as found, by default)
	L.SetGlobal("redirect", L.NewFunction(func(L *lua.LState) int {
		newurl := L.ToString(1)
		httpStatusCode := http.StatusFound
		if L.GetTop() == 2 {
			httpStatusCode = int(L.ToNumber(2))
		}
		if httpStatus != nil {
			httpStatus.code = httpStatusCode
		}
		http.Redirect(w, req, newurl, httpStatusCode)
		return 0 // number of results
	}))

	// Permanently redirect a request, which is the same as redirect(url, 301)
	L.SetGlobal("permanent_redirect", L.NewFunction(func(L *lua.LState) int {
		newurl := L.ToString(1)
		httpStatusCode := http.StatusMovedPermanently
		if httpStatus != nil {
			httpStatus.code = httpStatusCode
		}
		http.Redirect(w, req, newurl, httpStatusCode)
		return 0 // number of results
	}))

	// Run the given Lua file (replacement for the built-in dofile, to look in the right directory)
	// Returns whatever the Lua file returns when it is being run.
	L.SetGlobal("dofile", L.NewFunction(func(L *lua.LState) int {
		givenFilename := L.ToString(1)
		luaFilename := filepath.Join(filepath.Dir(filename), givenFilename)
		if !fs.exists(luaFilename) {
			log.Error("Could not find:", luaFilename)
			return 0 // number of results
		}
		if err := L.DoFile(luaFilename); err != nil {
			log.Errorf("Error running %s: %s\n", luaFilename, err.Error())
			return 0 // number of results
		}
		// Retrieve the returned value from the script
		retval := L.Get(-1)
		L.Pop(1)
		// Return the value returned from the script
		L.Push(retval)
		return 1 // number of results
	}))

}
<|endoftext|>


<commit_before>/*
 A Naive Bayesian Classifier
 Jake Brukhman <jbrukh@gmail.com>

 BAYESIAN CLASSIFICATION REFRESHER: suppose you have a set
 of classes (e.g. categories) C := {C_1, ..., C_n}, and a
 document D consisting of words D := {W_1, ..., W_k}.
 We wish to ascertain the probability that the document
 belongs to some class C_j given some set of training data
 associating documents and classes.

 By Bayes' Theorem, we have that

    P(C_j|D) = P(D|C_j)*P(C_j)/P(D).

 The LHS is the probability that the document belongs to class
 C_j given the document itself (by which is meant, in practice,
 the word frequencies occurring in this document), and our program
 will calculate this probability for each j and spit out the
 most likely class for this document.

 P(C_j) is referred to as the "prior" probability, or the
 probability that a document belongs to C_j in general, without
 seeing the document first. P(D|C_j) is the probability of seeing
 such a document, given that it belongs to C_j. Here, by assuming
 that words appear independently in documents (this being the
 "naive" assumption), we can estimate

    P(D|C_j) ~= P(W_1|C_j)*...*P(W_k|C_j)

 where P(W_i|C_j) is the probability of seeing the given word
 in a document of the given class. Finally, P(D) can be seen as
 merely a scaling factor and is not strictly relevant to
 classificiation, unless you want to normalize the resulting
 scores and actually see probabilities. In this case, note that

    P(D) = SUM_j(P(D|C_j)*P(C_j))

 One practical issue with performing these calculations is the
 possibility of float64 underflow when calculating P(D|C_j), as
 individual word probabilities can be arbitrarily small, and
 a document can have an arbitrarily large number of them. A
 typical method for dealing with this case is to transform the
 probability to the log domain and perform additions instead
 of multiplications:

   log P(C_j|D) ~ log(P(C_j)) + SUM_i(log P(W_i|C_j))

 where i = 1, ..., k. Note that by doing this, we are discarding
 the scaling factor P(D) and our scores are no longer
 probabilities.
*/
package bayesian

import (
    "math"
    "gob"
    "os"
)

// defaultProb is the tiny non-zero probability that a word
// we have not seen before appears in the class.
const defaultProb = 0.00000000001

// Class defines a set of classes that the classifier will
// filter: C = {C_1, ..., C_n}. You should define your classes
// as a set of constants, for example as follows:
//
//    const (
//        Good Class = "Good"
//        Bad Class = "Bad
//    )
//
// Class values should be unique.
type Class string

// Classifier implements the Naive Bayesian Classifier.
type Classifier struct {
    Classes []Class
    learned int             // docs learned
    seen int                // docs seen
    datas map[Class]*classData
}

// serializableClassifier represents a container for
// Classifier objects whose fields are modifiable by
// reflection and are therefore writeable by gob.
type serializableClassifier struct {
    Classes []Class
    Learned int
    Seen int
    Datas map[Class]*classData
}

// classData holds the frequency data for words in a
// particular class. In the future, we may replace this
// structure with a trie-like structure for more
// efficient storage.
type classData struct {
    Freqs map[string]int
    Total int
}

// newClassData creates a new empty classData node.
func newClassData() *classData {
    return &classData{
        Freqs: make(map[string]int),
    }
}

// getWordProb returns P(W|C_j) -- the probability of seeing
// a particular word W in a document of this class.
func (d *classData) getWordProb(word string) float64 {
    value, ok := d.Freqs[word]
    if !ok {
        return defaultProb
    }
    return float64(value)/float64(d.Total)
}

// getWordsProb returns P(D|C_j) -- the probability of seeing
// this set of words in a document of this class.
//
// Note that words should not be empty, and this method of
// calulation is prone to underflow if there are many words
// and their individual probabilties are small.
func (d *classData) getWordsProb(words []string) (prob float64) {
    prob = 1
    for _, word := range words {
        prob *= d.getWordProb(word)
    }
    return
}

// NewClassifier returns a new classifier. The classes the provided
// should be at least 2 in number and unique, or this method will
// panic.
func NewClassifier(classes ...Class) (c *Classifier) {
    n := len(classes)

    // check size
    if n < 2 {
        panic("provide at least two classes")
    }

    // check uniqueness
    check := make(map[Class]bool, n)
    for _, class := range classes {
        check[class] = true
    }
    if len(check) != n {
        panic("classes must be unique")
    }
    // create the classifier
    c = &Classifier{
            Classes: classes,
            datas: make(map[Class]*classData, n),
    }
    for _, class := range classes {
        c.datas[class] = newClassData()
    }
    return
}

// NewClassifierFromFile loads an existing classifier from
// file. The classifier was previously saved with a call
// to c.WriteToFile(string).
func NewClassifierFromFile(name string) (c *Classifier, err os.Error) {
    file, err := os.Open(name)
    if err != nil {
        return nil, err
    }
    dec := gob.NewDecoder(file)
    w := new(serializableClassifier)
    err = dec.Decode(w)

    return &Classifier{w.Classes, w.Learned, w.Seen, w.Datas}, err
}

// getPriors returns the prior probabilities for the
// classes provided -- P(C_j).
//
// TODO: There is a way to smooth priors, currently
// not implemented here.
func (c *Classifier) getPriors() (priors []float64) {
    n := len(c.Classes)
    priors = make([]float64, n, n)
    sum := 0
    for index, class := range c.Classes {
        total := c.datas[class].Total;
        priors[index] = float64(total)
        sum += total
    }
    if sum != 0 {
        for i := 0; i < n; i++ {
            priors[i] /= float64(sum)
        }
    }
    return
}

// Learned returns the number of documents ever learned
// in the lifetime of this classifier.
func (c *Classifier) Learned() int {
    return c.learned
}

// Seen returns the number of documents ever classified
// in the lifetime of this classifier.
func (c *Classifier) Seen() int {
    return c.seen
}

// WordCount returns the number of words counted for
// each class in the lifetime of the classifier.
func (c *Classifier) WordCount() (result []int) {
    result = make([]int, len(c.Classes))
    for inx, class := range c.Classes {
        data := c.datas[class]
        result[inx] = data.Total
    }
    return
}

// Learn will accept new training documents for
// supervised learning.
func (c *Classifier) Learn(document []string, which Class) {
    data := c.datas[which]
    for _, word := range document {
        data.Freqs[word]++
        data.Total++
    }
    c.learned++
}

// LogScores produces "log-likelihood"-like scores that can
// be used to classify documents into classes.
//
// The value of the score is proportional to the likelihood,
// as determined by the classifier, that the given document
// belongs to the given class. This is true even when scores
// returned are negative, which they will be (since we are
// taking logs of probabilities).
//
// The index j of the score corresponds to the class given
// by c.Classes[j].
//
// Additionally returned are "inx" and "strict" values. The
// inx corresponds to the maximum score in the array. If more
// than one of the scores holds the maximum values, then
// strict is false.
//
// Unlike c.Probabilities(), this function is not prone to
// floating point underflow and is relatively safe to use.
func (c *Classifier) LogScores(document []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    priors := c.getPriors()

    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := math.Log(priors[index])
        for _, word := range document {
            score += math.Log(data.getWordProb(word))
        }
        scores[index] = score
    }
    inx, strict = findMax(scores)
    c.seen++
    return scores, inx, strict
}

// ProbScores works the same as LogScores, but delivers
// actual probabilities as discussed above. Note that float64
// underflow is possible if the word list contains too
// many words that have probabilities very close to 0.
//
// Notes on underflow: underflow is going to occur when you're
// trying to assess large numbers of words that you have
// never seen before. Depending on the application, this
// may or may not be a concern. Consider using SafeProbScores()
// instead.
func (c *Classifier) ProbScores(doc []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    priors := c.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        for _, word := range doc {
            score *= data.getWordProb(word)
        }
        scores[index] = score
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    c.seen++
    return scores, inx, strict
}

// SafeProbScores works the same as ProbScores, but is
// able to detect underflow. If an underflow is detected,
// this method panics, allowing the user to recover as
// necessary.
//
// Underflow detection is more costly because it also
// has to make additional log score calculations.
func (c *Classifier) SafeProbScores(doc []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    logScores := make([]float64, n, n)
    priors := c.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        logScore := math.Log(priors[index])
        for _, word := range doc {
            p := data.getWordProb(word)
            score *= p
            logScore += math.Log(p)
        }
        scores[index] = score
        logScores[index] = logScore
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    logInx, logStrict := findMax(logScores)

    // detect underflow -- the size
    // relation between scores and logScores
    // must be preserved or something is wrong
    if inx != logInx || strict != logStrict {
        panic("possible underflow detected")
    }
    c.seen++
    return scores, inx, strict
}

// WordFrequencies returns a matrix of word frequencies that currently
// exist in the classifier for each class state for the given input
// words. In other words, if you obtain the frequencies
//
//    freqs := c.WordFrequencies(/* [j]string */)
//
// then the expression freq[i][j] represents the frequency of the j-th
// word within the i-th class.
func (c *Classifier) WordFrequencies(words []string) (freqMatrix [][]float64) {
    n, l := len(c.Classes), len(words)
    freqMatrix = make([][]float64, n)
    for i, _ := range freqMatrix {
        arr := make([]float64, l)
        data := c.datas[c.Classes[i]]
        for j, _ := range arr {
            arr[j] = data.getWordProb(words[j])
        }
        freqMatrix[i] = arr
    }
    return
}

// Serialize this classifier to a file.
func (c *Classifier) WriteToFile(name string) (err os.Error) {
    file, err := os.OpenFile(name, os.O_WRONLY | os.O_CREATE, 0655)
    if err != nil {
        return err
    }
    enc := gob.NewEncoder(file)
    err = enc.Encode(&serializableClassifier{c.Classes, c.learned, c.seen, c.datas})
    return
}

// findMax finds the maximum of a set of scores; if the
// maximum is strict -- that is, it is the single unique
// maximum from the set -- then strict has return value
// true. Otherwise it is false.
func findMax(scores []float64) (inx int, strict bool) {
    inx = 0
    strict = true
    for i := 1; i < len(scores); i++ {
        if scores[inx] < scores[i] {
            inx = i
            strict = true
        } else if scores[inx] == scores[i] {
            strict = false
        }
    }
    return
}
<commit_msg>Added clarifying comment.<commit_after>/*
 A Naive Bayesian Classifier
 Jake Brukhman <jbrukh@gmail.com>

 BAYESIAN CLASSIFICATION REFRESHER: suppose you have a set
 of classes (e.g. categories) C := {C_1, ..., C_n}, and a
 document D consisting of words D := {W_1, ..., W_k}.
 We wish to ascertain the probability that the document
 belongs to some class C_j given some set of training data
 associating documents and classes.

 By Bayes' Theorem, we have that

    P(C_j|D) = P(D|C_j)*P(C_j)/P(D).

 The LHS is the probability that the document belongs to class
 C_j given the document itself (by which is meant, in practice,
 the word frequencies occurring in this document), and our program
 will calculate this probability for each j and spit out the
 most likely class for this document.

 P(C_j) is referred to as the "prior" probability, or the
 probability that a document belongs to C_j in general, without
 seeing the document first. P(D|C_j) is the probability of seeing
 such a document, given that it belongs to C_j. Here, by assuming
 that words appear independently in documents (this being the
 "naive" assumption), we can estimate

    P(D|C_j) ~= P(W_1|C_j)*...*P(W_k|C_j)

 where P(W_i|C_j) is the probability of seeing the given word
 in a document of the given class. Finally, P(D) can be seen as
 merely a scaling factor and is not strictly relevant to
 classificiation, unless you want to normalize the resulting
 scores and actually see probabilities. In this case, note that

    P(D) = SUM_j(P(D|C_j)*P(C_j))

 One practical issue with performing these calculations is the
 possibility of float64 underflow when calculating P(D|C_j), as
 individual word probabilities can be arbitrarily small, and
 a document can have an arbitrarily large number of them. A
 typical method for dealing with this case is to transform the
 probability to the log domain and perform additions instead
 of multiplications:

   log P(C_j|D) ~ log(P(C_j)) + SUM_i(log P(W_i|C_j))

 where i = 1, ..., k. Note that by doing this, we are discarding
 the scaling factor P(D) and our scores are no longer
 probabilities.
*/
package bayesian

import (
    "math"
    "gob"
    "os"
)

// defaultProb is the tiny non-zero probability that a word
// we have not seen before appears in the class.
const defaultProb = 0.00000000001

// Class defines a set of classes that the classifier will
// filter: C = {C_1, ..., C_n}. You should define your classes
// as a set of constants, for example as follows:
//
//    const (
//        Good Class = "Good"
//        Bad Class = "Bad
//    )
//
// Class values should be unique.
type Class string

// Classifier implements the Naive Bayesian Classifier.
type Classifier struct {
    Classes []Class
    learned int             // docs learned
    seen int                // docs seen
    datas map[Class]*classData
}

// serializableClassifier represents a container for
// Classifier objects whose fields are modifiable by
// reflection and are therefore writeable by gob.
type serializableClassifier struct {
    Classes []Class
    Learned int
    Seen int
    Datas map[Class]*classData
}

// classData holds the frequency data for words in a
// particular class. In the future, we may replace this
// structure with a trie-like structure for more
// efficient storage.
type classData struct {
    Freqs map[string]int
    Total int
}

// newClassData creates a new empty classData node.
func newClassData() *classData {
    return &classData{
        Freqs: make(map[string]int),
    }
}

// getWordProb returns P(W|C_j) -- the probability of seeing
// a particular word W in a document of this class.
func (d *classData) getWordProb(word string) float64 {
    value, ok := d.Freqs[word]
    if !ok {
        return defaultProb
    }
    return float64(value)/float64(d.Total)
}

// getWordsProb returns P(D|C_j) -- the probability of seeing
// this set of words in a document of this class.
//
// Note that words should not be empty, and this method of
// calulation is prone to underflow if there are many words
// and their individual probabilties are small.
func (d *classData) getWordsProb(words []string) (prob float64) {
    prob = 1
    for _, word := range words {
        prob *= d.getWordProb(word)
    }
    return
}

// NewClassifier returns a new classifier. The classes the provided
// should be at least 2 in number and unique, or this method will
// panic.
func NewClassifier(classes ...Class) (c *Classifier) {
    n := len(classes)

    // check size
    if n < 2 {
        panic("provide at least two classes")
    }

    // check uniqueness
    check := make(map[Class]bool, n)
    for _, class := range classes {
        check[class] = true
    }
    if len(check) != n {
        panic("classes must be unique")
    }
    // create the classifier
    c = &Classifier{
            Classes: classes,
            datas: make(map[Class]*classData, n),
    }
    for _, class := range classes {
        c.datas[class] = newClassData()
    }
    return
}

// NewClassifierFromFile loads an existing classifier from
// file. The classifier was previously saved with a call
// to c.WriteToFile(string).
func NewClassifierFromFile(name string) (c *Classifier, err os.Error) {
    file, err := os.Open(name)
    if err != nil {
        return nil, err
    }
    dec := gob.NewDecoder(file)
    w := new(serializableClassifier)
    err = dec.Decode(w)

    return &Classifier{w.Classes, w.Learned, w.Seen, w.Datas}, err
}

// getPriors returns the prior probabilities for the
// classes provided -- P(C_j).
//
// TODO: There is a way to smooth priors, currently
// not implemented here.
func (c *Classifier) getPriors() (priors []float64) {
    n := len(c.Classes)
    priors = make([]float64, n, n)
    sum := 0
    for index, class := range c.Classes {
        total := c.datas[class].Total;
        priors[index] = float64(total)
        sum += total
    }
    if sum != 0 {
        for i := 0; i < n; i++ {
            priors[i] /= float64(sum)
        }
    }
    return
}

// Learned returns the number of documents ever learned
// in the lifetime of this classifier.
func (c *Classifier) Learned() int {
    return c.learned
}

// Seen returns the number of documents ever classified
// in the lifetime of this classifier.
func (c *Classifier) Seen() int {
    return c.seen
}

// WordCount returns the number of words counted for
// each class in the lifetime of the classifier.
func (c *Classifier) WordCount() (result []int) {
    result = make([]int, len(c.Classes))
    for inx, class := range c.Classes {
        data := c.datas[class]
        result[inx] = data.Total
    }
    return
}

// Learn will accept new training documents for
// supervised learning.
func (c *Classifier) Learn(document []string, which Class) {
    data := c.datas[which]
    for _, word := range document {
        data.Freqs[word]++
        data.Total++
    }
    c.learned++
}

// LogScores produces "log-likelihood"-like scores that can
// be used to classify documents into classes.
//
// The value of the score is proportional to the likelihood,
// as determined by the classifier, that the given document
// belongs to the given class. This is true even when scores
// returned are negative, which they will be (since we are
// taking logs of probabilities).
//
// The index j of the score corresponds to the class given
// by c.Classes[j].
//
// Additionally returned are "inx" and "strict" values. The
// inx corresponds to the maximum score in the array. If more
// than one of the scores holds the maximum values, then
// strict is false.
//
// Unlike c.Probabilities(), this function is not prone to
// floating point underflow and is relatively safe to use.
func (c *Classifier) LogScores(document []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    priors := c.getPriors()

    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := math.Log(priors[index])
        for _, word := range document {
            score += math.Log(data.getWordProb(word))
        }
        scores[index] = score
    }
    inx, strict = findMax(scores)
    c.seen++
    return scores, inx, strict
}

// ProbScores works the same as LogScores, but delivers
// actual probabilities as discussed above. Note that float64
// underflow is possible if the word list contains too
// many words that have probabilities very close to 0.
//
// Notes on underflow: underflow is going to occur when you're
// trying to assess large numbers of words that you have
// never seen before. Depending on the application, this
// may or may not be a concern. Consider using SafeProbScores()
// instead.
func (c *Classifier) ProbScores(doc []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    priors := c.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        for _, word := range doc {
            score *= data.getWordProb(word)
        }
        scores[index] = score
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    c.seen++
    return scores, inx, strict
}

// SafeProbScores works the same as ProbScores, but is
// able to detect underflow in those cases where underflow
// results in the reverse classification. If an underflow is detected,
// this method panics, allowing the user to recover as
// necessary. Note that underflow, under certain rare circumstances,
// may still result in incorrect probabilities being returned,
// but this method guarantees that all panic-less invokations
// are properly classified.
//
// Underflow detection is more costly because it also
// has to make additional log score calculations.
func (c *Classifier) SafeProbScores(doc []string) (scores []float64, inx int, strict bool) {
    n := len(c.Classes)
    scores = make([]float64, n, n)
    logScores := make([]float64, n, n)
    priors := c.getPriors()
    sum := float64(0)
    // calculate the score for each class
    for index, class := range c.Classes {
        data := c.datas[class]
        // c is the sum of the logarithms
        // as outlined in the refresher
        score := priors[index]
        logScore := math.Log(priors[index])
        for _, word := range doc {
            p := data.getWordProb(word)
            score *= p
            logScore += math.Log(p)
        }
        scores[index] = score
        logScores[index] = logScore
        sum += score
    }
    for i := 0; i < n; i++ {
        scores[i] /= sum
    }
    inx, strict = findMax(scores)
    logInx, logStrict := findMax(logScores)

    // detect underflow -- the size
    // relation between scores and logScores
    // must be preserved or something is wrong
    if inx != logInx || strict != logStrict {
        panic("possible underflow detected")
    }
    c.seen++
    return scores, inx, strict
}

// WordFrequencies returns a matrix of word frequencies that currently
// exist in the classifier for each class state for the given input
// words. In other words, if you obtain the frequencies
//
//    freqs := c.WordFrequencies(/* [j]string */)
//
// then the expression freq[i][j] represents the frequency of the j-th
// word within the i-th class.
func (c *Classifier) WordFrequencies(words []string) (freqMatrix [][]float64) {
    n, l := len(c.Classes), len(words)
    freqMatrix = make([][]float64, n)
    for i, _ := range freqMatrix {
        arr := make([]float64, l)
        data := c.datas[c.Classes[i]]
        for j, _ := range arr {
            arr[j] = data.getWordProb(words[j])
        }
        freqMatrix[i] = arr
    }
    return
}

// Serialize this classifier to a file.
func (c *Classifier) WriteToFile(name string) (err os.Error) {
    file, err := os.OpenFile(name, os.O_WRONLY | os.O_CREATE, 0655)
    if err != nil {
        return err
    }
    enc := gob.NewEncoder(file)
    err = enc.Encode(&serializableClassifier{c.Classes, c.learned, c.seen, c.datas})
    return
}

// findMax finds the maximum of a set of scores; if the
// maximum is strict -- that is, it is the single unique
// maximum from the set -- then strict has return value
// true. Otherwise it is false.
func findMax(scores []float64) (inx int, strict bool) {
    inx = 0
    strict = true
    for i := 1; i < len(scores); i++ {
        if scores[inx] < scores[i] {
            inx = i
            strict = true
        } else if scores[inx] == scores[i] {
            strict = false
        }
    }
    return
}
<|endoftext|>


<commit_before>package mugendb

import (
    "github.com/jinzhu/gorm"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "fmt"
)

var (
    Db  gorm.DB
)

func InitDB() {
    fmt.Println("called")
    var err error

    // connect mysql
    Db, err = gorm.Open("mysql", "root:@/?charset=utf8&parseTime=True&loc=Local")
    checkErr(err, "mysql Open failed.")

    // create db if not exists
    Db.Exec( "CREATE DATABASE IF NOT EXISTS godb DEFAULT CHARACTER SET utf8;")

    // connect db
    Db, err = gorm.Open("mysql", "root:@/godb?charset=utf8&parseTime=True&loc=Local")
    checkErr(err, "mysql Connect failed.")

    Db.DB().Ping()
    Db.DB().SetMaxIdleConns(10)
    Db.DB().SetMaxOpenConns(100)
    Db.SingularTable(true)

     // migration
     // db.CreateTable(&User{})
}

func checkErr(err error, msg string) {
    if err != nil {
        log.Fatalln(msg, err)
    }
}

<commit_msg>create<commit_after>package mugendb

import (
    "github.com/jinzhu/gorm"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "fmt"
    "goassimp/app/models"
)

var (
    Db  gorm.DB
)

func InitDB() {
    fmt.Println("called")
    var err error

    // connect mysql
    Db, err = gorm.Open("mysql", "root:@/?charset=utf8&parseTime=True&loc=Local")
    checkErr(err, "mysql Open failed.")

    // create db if not exists
    Db.Exec( "CREATE DATABASE IF NOT EXISTS godb DEFAULT CHARACTER SET utf8;")

    // connect db
    Db, err = gorm.Open("mysql", "root:@/godb?charset=utf8&parseTime=True&loc=Local")
    checkErr(err, "mysql Connect failed.")

    // Db.DB().Ping()
    Db.DB().SetMaxIdleConns(10)
    Db.DB().SetMaxOpenConns(100)

    // migration
    Db.AutoMigrate(&models.User{})

    // get
    //Db.Create(&models.User{Name: "Jinzhu"})
    //user := models.User{}
    //Db.First(&user)
    //log.Fatalln(user.Name, nil)
}

func checkErr(err error, msg string) {
    if err != nil {
        log.Fatalln(msg, err)
    }
}

<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"fmt"
	"net/http"
	"testing"
)

type CommentInfo struct {
	content string
}

func TestCommentsCtrlPost(t *testing.T) {
	client := new(http.Client)
	var topicId string = "1"
	path := fmt.Sprintf("/topics/%s/comments", topicId)
	data, _ := json.Marshal(&CommentInfo{content: "test"})
	resp, err := client.Post(path, "application/json", data)
	if resp.StatusCode != 201 {
		t.Error(err)
	}
}

func TestCommentsCtrlGet(t *testing.T) {
}

func TestCommentCtrlGet(t *testing.T) {

}
func TestCommentCtrlDelete(t *testing.T) {

}
<commit_msg>Update comment_test.go<commit_after>package comment

import (
    "testing"
)

func TestCommentsCtrlPost(t *testing.T) {
    var topicId string = "1"
    req := http.NewRequest("POST", fmt.Printf("/topics/%d/comments"), nil)
    c := CommentsCtrl{Request: req, PathParams: []string{topicId}, AccountId: 1}
    resp := c.Post()
    switch resp.StatusCode {
    case 500:
        t.Error("server error")
    case 201:
        url, err := resp.Location()
        if err != nil || url == nil {
            t.Error("response's location error")
        }
        etag := resp.Header.Get("ETag")
        if etag == nil {
            t.Error("response header has no etag")
        }
        h := md5.New()
        io.WriteString(h, string(resp.Body))
        buffer := bytes.NewBuffer(nil)
        fmt.Fprintf(buffer, "%x\n", h.Sum(nil))
        if etag != buffer.String() {
            t.Error("response's etag is err")
        }
    }
}
<|endoftext|>


<commit_before>package calc

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

type Calc struct {
	variables map[string]string
}

// return the priority of given operator
// error will be not nil if given operator is not support
func (this *Calc) GetOptPriority(operator string) (int, error) {
	const (
		optPriority0 = iota
		optPriority1
		optPriority2
		optPriority3
		optPriority4
		optPriority5
	)

	var optPriority map[string]int = map[string]int{
		"||": optPriority1,

		"&&": optPriority2,

		"=":  optPriority3, // the same as ==
		"==": optPriority3,
		">=": optPriority3,
		"<=": optPriority3,
		">":  optPriority3,
		"<":  optPriority3,

		"+": optPriority4,
		"-": optPriority4,

		"*": optPriority5,
		"/": optPriority5,
	}

	if _, ok := optPriority[operator]; ok {
		return optPriority[operator], nil
	} else {
		return optPriority0, errors.New(fmt.Sprintf("operator '%s' not support", operator))
	}
}

// calculate the simple expression "a operator b"
// eg. normalCalculate(1,2,"+") returns 3, nil
func (this *Calc) normalCalculate(a, b float64, operator string) (float64, error) {
	var (
		result        float64          = 0
		err           error            = nil
		boolToFloat64 map[bool]float64 = map[bool]float64{
			true:  1,
			false: 0,
		}
	)
	switch operator {
	case "+":
		result = a + b
	case "-":
		result = a - b
	case "*":
		result = a * b
	case "/":
		result = a / b
	case ">":
		result = boolToFloat64[a > b]
	case "<":
		result = boolToFloat64[a < b]
	case "=":
		result = boolToFloat64[a == b]
	case "==":
		result = boolToFloat64[a == b]
	case ">=":
		result = boolToFloat64[a >= b]
	case "<=":
		result = boolToFloat64[a <= b]
	case "&&":
		result = boolToFloat64[a != 0 && b != 0]
	case "||":
		result = boolToFloat64[a != 0 || b != 0]
	default:
		err = errors.New(fmt.Sprintf("operator '%s' not support", operator))
	}
	return result, err
}

// set variable for expression
func (this *Calc) SetVariable(key string, value string) {
	if this.variables == nil {
		this.variables = make(map[string]string)
	}
	this.variables[key] = value
}

// remove all variables setted for expression
func (this *Calc) CleanUpVariable() {
	if this.variables == nil {
		this.variables = make(map[string]string)
	}
	for key, _ := range this.variables {
		delete(this.variables, key)
	}
}

// calculate the given expression string
// return the result
// eg. Calculate("1+2") returns 3, nil
func (this *Calc) Calculate(expression string) (float64, error) {
	var spiltedStr []string
	var err error
	var result float64

	spiltedStr, err = this.generateRPN(expression)
	if err != nil {
		return 0, errors.New(fmt.Sprintf("generateRPN fail, %s", err.Error()))
	}

	spiltedStr = this.replaceVar(spiltedStr)

	result, err = this.calculateRPN(spiltedStr)
	if err != nil {
		return 0, errors.New(fmt.Sprintf("calculateRPN fail, %s", err.Error()))
	}

	return result, nil
}

func (this *Calc) replaceVar(spiltedStr []string) []string {
	var outSpiltedStr []string
	for _, value := range spiltedStr {
		if _, ok := this.variables[value]; ok {
			outSpiltedStr = append(outSpiltedStr, this.variables[value])
		} else {
			outSpiltedStr = append(outSpiltedStr, value)
		}
	}

	return outSpiltedStr
}

// calculate the Reverse Polish Notation
// return the result of given Reverse Polish Notation which is generate by generateRPN() function
func (this *Calc) calculateRPN(rpn []string) (float64, error) {
	var stack LinkStack
	stack.Init()
	for i := 0; i < len(rpn); i++ {
		if caleIsOperand(rpn[i]) {
			if f, err := strconv.ParseFloat(rpn[i], 64); err != nil {
				return 0, errors.New(fmt.Sprintf("operand expected a float number but given is '%s' ", rpn[i]))
			} else {
				stack.Push(f)
			}
		} else {
			if stack.Count < 2 {
				return 0, errors.New("operand not enough")
			}

			p1 := stack.Pop().(float64)
			p2 := stack.Pop().(float64)

			p3, err := this.normalCalculate(p2, p1, rpn[i])
			if err != nil {
				return 0, errors.New(fmt.Sprintf("normalCalculate fail, %s", err.Error()))
			}

			stack.Push(p3)
		}
	}

	if stack.Count > 1 {
		return 0, errors.New("operator not enough")
	} else if stack.Count == 0 {
		return 0, errors.New("operand not enough")
	}

	result := stack.Pop().(float64)
	return result, nil
}

func (this *Calc) generateRPN(exp string) ([]string, error) {
	var stack LinkStack
	stack.Init()

	var spiltedStr []string = this.splitString(exp)
	var rpn []string

	for i := 0; i < len(spiltedStr); i++ { // 遍历每一个元素
		curSpilt := spiltedStr[i] //当前元素

		if !caleIsOperand(curSpilt) {
			// 如果不是操作数

			// 四种情况入栈
			// 1 当前元素为左括号直接入栈
			// 2 栈内为空直接入栈
			// 3 栈顶为左括号，且当前元素不是右括号，直接入栈
			// 4 当前元素不为右括号时，在比较栈顶元素与当前元素的运算符优先级，如果当前元素大，直接入栈。
			if curSpilt == "(" ||
				stack.LookTop() == nil ||
				(stack.LookTop().(string) == "(" && curSpilt != ")") ||
				(this.compareOperator(curSpilt, stack.LookTop().(string)) == 1 && curSpilt != ")") {
				stack.Push(curSpilt)
			} else {
				if curSpilt == ")" { //当前元素为右括号时，提取操作符，直到碰见左括号
					for {
						if stack.Count <= 0 {
							return rpn, errors.New("operator '(' expected but not found")
						}
						if pop := stack.Pop().(string); pop == "(" {
							break
						} else {
							rpn = append(rpn, pop)
						}
					}
				} else { //当前元素为操作符时，不断地与栈顶元素比较直到遇到比自己小的（或者栈空了），然后入栈。
					for {
						pop := stack.LookTop()
						if pop != nil && pop != "(" && this.compareOperator(curSpilt, pop.(string)) != 1 {
							rpn = append(rpn, stack.Pop().(string))
						} else {
							stack.Push(curSpilt)
							break
						}
					}
				}
			}
		} else {
			// 如果是操作数，直接添加到后缀表达式中
			rpn = append(rpn, curSpilt)
		}
	}

	//将栈内剩余的操作符全部弹出。
	for {
		if pop := stack.Pop(); pop != nil {
			rpn = append(rpn, pop.(string))
		} else {
			break
		}
	}
	return rpn, nil
}

// compare the priority of two given operators
// if return 1, o1Priority > o2Priority
// if return 0, o1Priority = o2Priority
// if return -1, o1Priority < o2Priority
func (this *Calc) compareOperator(operator1, operator2 string) int {
	o1Priority, _ := this.GetOptPriority(operator1)
	o2Priority, _ := this.GetOptPriority(operator2)

	if o1Priority > o2Priority {
		return 1
	} else if o1Priority == o2Priority {
		return 0
	} else {
		return -1
	}
}

// split the given expression string to string array consist of Operand and Operator
// eg. 5>4||(2<1)&&(1+2==3) split to [5 > 4 || ( 2 < 1 ) && ( 1 + 2 == 3 )]
func (this *Calc) splitString(expression string) []string {
	// remove all space
	expression = strings.Replace(expression, " ", "", -1)
	// remove all tab
	expression = strings.Replace(expression, "\t", "", -1)

	var splitArr []string
	byteExp := []byte(expression)

	var operand string
	var operator string
	var curByte byte

	for i := 0; i < len(byteExp); i++ {
		curByte = byteExp[i]

		if caleIsOperandByte(curByte) {
			operand += string(curByte)
		} else {
			completeOpt := false
			if curByte == '(' || curByte == ')' {
				if operand != "" {
					splitArr = append(splitArr, operand)
					operand = ""
				}
				if operator != "" {
					splitArr = append(splitArr, operator)
					operator = ""
				}
				completeOpt = true
			}

			operator += string(curByte)

			if i+1 >= len(byteExp) {
				completeOpt = true
			}
			if i+1 < len(byteExp) && (caleIsOperandByte(byteExp[i+1]) || calcIsSpace(byteExp[i+1])) {
				completeOpt = true
			}

			if completeOpt {
				if operand != "" {
					splitArr = append(splitArr, operand)
					operand = ""
				}
				if operator != "" {
					splitArr = append(splitArr, operator)
					operator = ""
				}
			}
		}
	}
	if operand != "" {
		splitArr = append(splitArr, operand)
		operand = ""
	}
	if operator != "" {
		splitArr = append(splitArr, operator)
		operator = ""
	}
	return splitArr
}

func caleIsOperandByte(ch byte) bool {
	if calcIsAlpha(ch) || calcIsNumber(ch) {
		return true
	}
	return false
}

// 判断是否是合法的操作数（数字或变量）
// return a bool if given operand string is a valid operand(number or variable)
func caleIsOperand(operand string) bool {
	operand = strings.TrimSpace(operand)

	// 判断是否是数字
	// judge if given operand string is number
	if _, err := strconv.ParseFloat(operand, 64); err == nil {
		return true
	}

	// 判断是否是潜在的变量
	// 变量名只支持大小写字母和数字
	// judge if given operand string is variable
	// a vaild variable name here only contains [A..Za..z0..9]
	for _, v := range []byte(operand) {
		if !(calcIsAlpha(v) || (v >= '0' && v <= '9')) {
			return false
		}
	}
	return true
}

func calcIsNumber(o1 byte) bool {
	if o1 >= '0' && o1 <= '9' || o1 == '.' {
		return true
	}
	return false
}

func calcIsAlpha(o1 byte) bool {
	if o1 >= 'a' && o1 <= 'z' || o1 >= 'A' && o1 <= 'Z' {
		return true
	}
	return false
}

func calcIsSpace(ch byte) bool {
	return ch == ' ' || ch == '\t'
}

////////////////////////////

// stack used for calc
type StackNode struct {
	Data interface{}
	next *StackNode
}

type LinkStack struct {
	top   *StackNode
	Count int
}

func (this *LinkStack) Init() {
	this.top = nil
	this.Count = 0
}

func (this *LinkStack) Push(data interface{}) {
	var node *StackNode = new(StackNode)
	node.Data = data
	node.next = this.top
	this.top = node
	this.Count++
}

func (this *LinkStack) Pop() interface{} {
	if this.top == nil {
		return nil
	}
	returnData := this.top.Data
	this.top = this.top.next
	this.Count--
	return returnData
}

//Look up the top element in the stack, but not pop.
func (this *LinkStack) LookTop() interface{} {
	if this.top == nil {
		return nil
	}
	return this.top.Data
}
<commit_msg>增加 ParseVariableList(expression string) ([]string, error) 函数用于获得 expression 表达式的变量列表<commit_after>package calc

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

type Calc struct {
	variables map[string]string
}

// return the priority of given operator
// error will be not nil if given operator is not support
func (this *Calc) GetOptPriority(operator string) (int, error) {
	const (
		optPriority0 = iota
		optPriority1
		optPriority2
		optPriority3
		optPriority4
		optPriority5
	)

	var optPriority map[string]int = map[string]int{
		"||": optPriority1,

		"&&": optPriority2,

		"=":  optPriority3, // the same as ==
		"==": optPriority3,
		">=": optPriority3,
		"<=": optPriority3,
		">":  optPriority3,
		"<":  optPriority3,

		"+": optPriority4,
		"-": optPriority4,

		"*": optPriority5,
		"/": optPriority5,
	}

	if _, ok := optPriority[operator]; ok {
		return optPriority[operator], nil
	} else {
		return optPriority0, errors.New(fmt.Sprintf("operator '%s' not support", operator))
	}
}

// calculate the simple expression "a operator b"
// eg. normalCalculate(1,2,"+") returns 3, nil
func (this *Calc) normalCalculate(a, b float64, operator string) (float64, error) {
	var (
		result        float64          = 0
		err           error            = nil
		boolToFloat64 map[bool]float64 = map[bool]float64{
			true:  1,
			false: 0,
		}
	)
	switch operator {
	case "+":
		result = a + b
	case "-":
		result = a - b
	case "*":
		result = a * b
	case "/":
		result = a / b
	case ">":
		result = boolToFloat64[a > b]
	case "<":
		result = boolToFloat64[a < b]
	case "=":
		result = boolToFloat64[a == b]
	case "==":
		result = boolToFloat64[a == b]
	case ">=":
		result = boolToFloat64[a >= b]
	case "<=":
		result = boolToFloat64[a <= b]
	case "&&":
		result = boolToFloat64[a != 0 && b != 0]
	case "||":
		result = boolToFloat64[a != 0 || b != 0]
	default:
		err = errors.New(fmt.Sprintf("operator '%s' not support", operator))
	}
	return result, err
}

// set variable for expression
func (this *Calc) SetVariable(key string, value string) {
	if this.variables == nil {
		this.variables = make(map[string]string)
	}
	this.variables[key] = value
}

// remove all variables setted for expression
func (this *Calc) CleanUpVariable() {
	if this.variables == nil {
		this.variables = make(map[string]string)
	}
	for key, _ := range this.variables {
		delete(this.variables, key)
	}
}

func (this *Calc) ParseVariableList(expression string) ([]string, error) {
	var spiltedStr []string
	var err error
	var varList []string

	spiltedStr, err = this.generateRPN(expression)
	if err != nil {
		return varList, errors.New(fmt.Sprintf("generateRPN fail, %s", err.Error()))
	}

	for _, value := range spiltedStr {
		if calcIsVariable(value) {
			varList = append(varList, value)
		}
	}

	return varList, nil
}

// calculate the given expression string
// return the result
// eg. Calculate("1+2") returns 3, nil
func (this *Calc) Calculate(expression string) (float64, error) {
	var spiltedStr []string
	var err error
	var result float64

	spiltedStr, err = this.generateRPN(expression)
	if err != nil {
		return 0, errors.New(fmt.Sprintf("generateRPN fail, %s", err.Error()))
	}

	spiltedStr = this.replaceVar(spiltedStr)

	result, err = this.calculateRPN(spiltedStr)
	if err != nil {
		return 0, errors.New(fmt.Sprintf("calculateRPN fail, %s", err.Error()))
	}

	return result, nil
}

func (this *Calc) replaceVar(spiltedStr []string) []string {
	var outSpiltedStr []string
	for _, value := range spiltedStr {
		if _, ok := this.variables[value]; ok {
			outSpiltedStr = append(outSpiltedStr, this.variables[value])
		} else {
			outSpiltedStr = append(outSpiltedStr, value)
		}
	}

	return outSpiltedStr
}

// calculate the Reverse Polish Notation
// return the result of given Reverse Polish Notation which is generate by generateRPN() function
func (this *Calc) calculateRPN(rpn []string) (float64, error) {
	var stack LinkStack
	stack.Init()
	for i := 0; i < len(rpn); i++ {
		if calcIsOperand(rpn[i]) {
			if f, err := strconv.ParseFloat(rpn[i], 64); err != nil {
				return 0, errors.New(fmt.Sprintf("operand expected a float number but given is '%s' ", rpn[i]))
			} else {
				stack.Push(f)
			}
		} else {
			if stack.Count < 2 {
				return 0, errors.New("operand not enough")
			}

			p1 := stack.Pop().(float64)
			p2 := stack.Pop().(float64)

			p3, err := this.normalCalculate(p2, p1, rpn[i])
			if err != nil {
				return 0, errors.New(fmt.Sprintf("normalCalculate fail, %s", err.Error()))
			}

			stack.Push(p3)
		}
	}

	if stack.Count > 1 {
		return 0, errors.New("operator not enough")
	} else if stack.Count == 0 {
		return 0, errors.New("operand not enough")
	}

	result := stack.Pop().(float64)
	return result, nil
}

func (this *Calc) generateRPN(exp string) ([]string, error) {
	var stack LinkStack
	stack.Init()

	var spiltedStr []string = this.splitString(exp)
	var rpn []string

	for i := 0; i < len(spiltedStr); i++ { // 遍历每一个元素
		curSpilt := spiltedStr[i] //当前元素

		if !calcIsOperand(curSpilt) {
			// 如果不是操作数

			// 四种情况入栈
			// 1 当前元素为左括号直接入栈
			// 2 栈内为空直接入栈
			// 3 栈顶为左括号，且当前元素不是右括号，直接入栈
			// 4 当前元素不为右括号时，在比较栈顶元素与当前元素的运算符优先级，如果当前元素大，直接入栈。
			if curSpilt == "(" ||
				stack.LookTop() == nil ||
				(stack.LookTop().(string) == "(" && curSpilt != ")") ||
				(this.compareOperator(curSpilt, stack.LookTop().(string)) == 1 && curSpilt != ")") {
				stack.Push(curSpilt)
			} else {
				if curSpilt == ")" { //当前元素为右括号时，提取操作符，直到碰见左括号
					for {
						if stack.Count <= 0 {
							return rpn, errors.New("operator '(' expected but not found")
						}
						if pop := stack.Pop().(string); pop == "(" {
							break
						} else {
							rpn = append(rpn, pop)
						}
					}
				} else { //当前元素为操作符时，不断地与栈顶元素比较直到遇到比自己小的（或者栈空了），然后入栈。
					for {
						pop := stack.LookTop()
						if pop != nil && pop != "(" && this.compareOperator(curSpilt, pop.(string)) != 1 {
							rpn = append(rpn, stack.Pop().(string))
						} else {
							stack.Push(curSpilt)
							break
						}
					}
				}
			}
		} else {
			// 如果是操作数，直接添加到后缀表达式中
			rpn = append(rpn, curSpilt)
		}
	}

	//将栈内剩余的操作符全部弹出。
	for {
		if pop := stack.Pop(); pop != nil {
			rpn = append(rpn, pop.(string))
		} else {
			break
		}
	}
	return rpn, nil
}

// compare the priority of two given operators
// if return 1, o1Priority > o2Priority
// if return 0, o1Priority = o2Priority
// if return -1, o1Priority < o2Priority
func (this *Calc) compareOperator(operator1, operator2 string) int {
	o1Priority, _ := this.GetOptPriority(operator1)
	o2Priority, _ := this.GetOptPriority(operator2)

	if o1Priority > o2Priority {
		return 1
	} else if o1Priority == o2Priority {
		return 0
	} else {
		return -1
	}
}

// split the given expression string to string array consist of Operand and Operator
// eg. 5>4||(2<1)&&(1+2==3) split to [5 > 4 || ( 2 < 1 ) && ( 1 + 2 == 3 )]
func (this *Calc) splitString(expression string) []string {
	// remove all space
	expression = strings.Replace(expression, " ", "", -1)
	// remove all tab
	expression = strings.Replace(expression, "\t", "", -1)

	var splitArr []string
	byteExp := []byte(expression)

	var operand string
	var operator string
	var curByte byte

	for i := 0; i < len(byteExp); i++ {
		curByte = byteExp[i]

		if calcIsOperandByte(curByte) {
			operand += string(curByte)
		} else {
			completeOpt := false
			if curByte == '(' || curByte == ')' {
				if operand != "" {
					splitArr = append(splitArr, operand)
					operand = ""
				}
				if operator != "" {
					splitArr = append(splitArr, operator)
					operator = ""
				}
				completeOpt = true
			}

			operator += string(curByte)

			if i+1 >= len(byteExp) {
				completeOpt = true
			}
			if i+1 < len(byteExp) && (calcIsOperandByte(byteExp[i+1]) || calcIsSpace(byteExp[i+1])) {
				completeOpt = true
			}

			if completeOpt {
				if operand != "" {
					splitArr = append(splitArr, operand)
					operand = ""
				}
				if operator != "" {
					splitArr = append(splitArr, operator)
					operator = ""
				}
			}
		}
	}
	if operand != "" {
		splitArr = append(splitArr, operand)
		operand = ""
	}
	if operator != "" {
		splitArr = append(splitArr, operator)
		operator = ""
	}
	return splitArr
}

func calcIsOperandByte(ch byte) bool {
	if calcIsAlpha(ch) || calcIsNumber(ch) {
		return true
	}
	return false
}

// 判断是否是合法的操作数（数字或变量）
// return a bool if given operand string is a valid operand(number or variable)
func calcIsOperand(operand string) bool {
	operand = strings.TrimSpace(operand)

	// 判断是否是数字
	// judge if given operand string is number
	if _, err := strconv.ParseFloat(operand, 64); err == nil {
		return true
	}

	// 判断是否是潜在的变量
	// 变量名只支持大小写字母和数字
	// judge if given operand string is variable
	// a vaild variable name here only contains [A..Za..z0..9]
	for _, v := range []byte(operand) {
		if !(calcIsAlpha(v) || (v >= '0' && v <= '9')) {
			return false
		}
	}
	return true
}

// 判断是否是变量
// return a bool if given operand string is a valid variable
func calcIsVariable(operand string) bool {
	operand = strings.TrimSpace(operand)

	// 判断是否是数字
	// judge if given operand string is number
	if _, err := strconv.ParseFloat(operand, 64); err == nil {
		return false
	}

	// 判断是否是潜在的变量
	// 变量名只支持大小写字母和数字
	// judge if given operand string is variable
	// a vaild variable name here only contains [A..Za..z0..9]
	for _, v := range []byte(operand) {
		if !(calcIsAlpha(v) || (v >= '0' && v <= '9')) {
			return false
		}
	}
	return true
}

func calcIsNumber(o1 byte) bool {
	if o1 >= '0' && o1 <= '9' || o1 == '.' {
		return true
	}
	return false
}

func calcIsAlpha(o1 byte) bool {
	if o1 >= 'a' && o1 <= 'z' || o1 >= 'A' && o1 <= 'Z' {
		return true
	}
	return false
}

func calcIsSpace(ch byte) bool {
	return ch == ' ' || ch == '\t'
}

////////////////////////////

// stack used for calc
type StackNode struct {
	Data interface{}
	next *StackNode
}

type LinkStack struct {
	top   *StackNode
	Count int
}

func (this *LinkStack) Init() {
	this.top = nil
	this.Count = 0
}

func (this *LinkStack) Push(data interface{}) {
	var node *StackNode = new(StackNode)
	node.Data = data
	node.next = this.top
	this.top = node
	this.Count++
}

func (this *LinkStack) Pop() interface{} {
	if this.top == nil {
		return nil
	}
	returnData := this.top.Data
	this.top = this.top.next
	this.Count--
	return returnData
}

//Look up the top element in the stack, but not pop.
func (this *LinkStack) LookTop() interface{} {
	if this.top == nil {
		return nil
	}
	return this.top.Data
}
<|endoftext|>


<commit_before>package handlers

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/arschles/gci/config"
	"github.com/arschles/gci/log"
	dockutil "github.com/arschles/gci/util/docker"
	tarutil "github.com/arschles/gci/util/tar"
	docker "github.com/fsouza/go-dockerclient"
)

const (
	tempDirPrefix = "gci_server_build"
)

type build struct {
	buildDir string
	dockerCl *docker.Client
}

func NewBuild(baseBuildDir string, dockerCl *docker.Client) http.Handler {
	return &build{buildDir: baseBuildDir, dockerCl: dockerCl}
}

func (b build) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "you must POST to this endpoint", http.StatusBadRequest)
		return
	}
	tr := tar.NewReader(r.Body)
	defer r.Body.Close()
	tmpDir, err := ioutil.TempDir(b.buildDir, tempDirPrefix)
	if err != nil {
		log.Err("creating temp directory under %s (%s)", b.buildDir, err)
		http.Error(w, "error creating temp directory", http.StatusInternalServerError)
		return
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			log.Err("Removing temporary build dir %s (%s)", tmpDir, err)
		}
	}()

	cfg := config.Empty()
	configFileFound := false
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			log.Err("Reading file (%s)", err)
			break
		}
		var gciFileBytes bytes.Buffer
		var otherWriters []io.Writer
		if isGCIFileName(hdr.Name) && !configFileFound {
			otherWriters = append(otherWriters, &gciFileBytes)
		} else if isGCIFileName(hdr.Name) && configFileFound {
			http.Error(w, "Multiple GCI config files found", http.StatusBadRequest)
			return
		}
		fileName := filepath.Join(tmpDir, hdr.Name)
		if err := tarutil.CopyToFile(tr, fileName, otherWriters...); err != nil {
			str := fmt.Sprintf("Copying %s to a file (%s)", hdr.Name, err)
			log.Err(str)
			http.Error(w, str, http.StatusInternalServerError)
			return
		}
		c, err := config.ReadBytes(gciFileBytes.Bytes())
		if err != nil {
			http.Error(w, fmt.Sprintf("%s was an invalid config file (%s)", hdr.Name, err), http.StatusBadRequest)
			return
		}
		cfg = c
	}
	outDir := filepath.Join(tmpDir, "built-binaries")
	if _, err := dockutil.Build(b.dockerCl, tmpDir, outDir, cfg); err != nil {
		http.Error(w, fmt.Sprintf("Error building (%s)", err), http.StatusInternalServerError)
		return
	}
	if err != nil {
		http.Error(w, fmt.Sprintf("Error opening completed binary (%s)", err), http.StatusInternalServerError)
		return
	}
	// TODO: tar up the outDir and send it to w
	// if _, err := io.Copy(w, []byte("hello world!")); err != nil {
	// http.Error(w, fmt.Sprintf("sending completed binary (%s)", err), http.StatusInternalServerError)
	// return
	// }
	w.Write([]byte("hello world!"))
}
<commit_msg>adding required import<commit_after>package handlers

import (
	"archive/tar"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/arschles/gci/config"
	"github.com/arschles/gci/log"
	dockutil "github.com/arschles/gci/util/docker"
	fileutil "github.com/arschles/gci/util/file"
	tarutil "github.com/arschles/gci/util/tar"
	docker "github.com/fsouza/go-dockerclient"
)

const (
	tempDirPrefix = "gci_server_build"
)

type build struct {
	buildDir string
	dockerCl *docker.Client
}

func NewBuild(baseBuildDir string, dockerCl *docker.Client) http.Handler {
	return &build{buildDir: baseBuildDir, dockerCl: dockerCl}
}

func (b build) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "you must POST to this endpoint", http.StatusBadRequest)
		return
	}
	tr := tar.NewReader(r.Body)
	defer r.Body.Close()

	tmpDir, err := ioutil.TempDir(b.buildDir, tempDirPrefix)
	if err != nil {
		log.Err("creating temp directory under %s (%s)", b.buildDir, err)
		http.Error(w, "error creating temp directory", http.StatusInternalServerError)
		return
	}
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			log.Err("Removing temporary build dir %s (%s)", tmpDir, err)
		}
	}()

	cfg := config.Empty()
	configFileFound := false
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			log.Err("Reading file (%s)", err)
			break
		}
		var gciFileBytes bytes.Buffer
		var otherWriters []io.Writer
		if isGCIFileName(hdr.Name) && !configFileFound {
			otherWriters = append(otherWriters, &gciFileBytes)
		} else if isGCIFileName(hdr.Name) && configFileFound {
			http.Error(w, "Multiple GCI config files found", http.StatusBadRequest)
			return
		}
		fileName := filepath.Join(tmpDir, hdr.Name)
		if err := tarutil.CopyToFile(tr, fileName, otherWriters...); err != nil {
			str := fmt.Sprintf("Copying %s to a file (%s)", hdr.Name, err)
			log.Err(str)
			http.Error(w, str, http.StatusInternalServerError)
			return
		}
		c, err := config.ReadBytes(gciFileBytes.Bytes())
		if err != nil {
			http.Error(w, fmt.Sprintf("%s was an invalid config file (%s)", hdr.Name, err), http.StatusBadRequest)
			return
		}
		cfg = c
	}
	outDir := filepath.Join(tmpDir, "built-binaries")
	if _, err := dockutil.Build(b.dockerCl, tmpDir, outDir, cfg); err != nil {
		http.Error(w, fmt.Sprintf("Error building (%s)", err), http.StatusInternalServerError)
		return
	}
	if err != nil {
		http.Error(w, fmt.Sprintf("Error opening completed binary (%s)", err), http.StatusInternalServerError)
		return
	}
	files, err := fileutil.WalkAndExclude(outDir, nil)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error listing all output binaries (%s)", err), http.StatusInternalServerError)
		return
	}
	if err := tarutil.CreateArchiveFromFiles(w, files); err != nil {
		http.Error(w, fmt.Sprintf("Error creating tar archive from files (%s)", err), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package GoSDK

import (
	"crypto/tls"
	"errors"
	mqtt "github.com/clearblade/mqtt_parsing"
	mqcli "github.com/clearblade/mqttclient"
)

const (
	//Mqtt QOS 0
	QOS_AtMostOnce = iota
	//Mqtt QOS 1
	QOS_AtLeastOnce
	//Mqtt QOS 2
	QOS_PreciselyOnce
)

//LastWillPacket is a type to represent the Last Will and Testament packet
type LastWillPacket struct {
	Topic  string
	Body   string
	Qos    int
	Retain bool
}

//herein we use the same trick we used for http clients

//InitializeMQTT allocates the mqtt client for the user. an empty string can be passed as the second argument for the user client
func (u *UserClient) InitializeMQTT(clientid string, ignore string, timeout int) error {
	mqc, err := initializeMqttClient(u.UserToken, u.SystemKey, u.SystemSecret, clientid, timeout)
	if err != nil {
		return err
	}
	u.MQTTClient = mqc
	return nil
}

//InitializeMQTT allocates the mqtt client for the developer. the second argument is a
//the systemkey you wish to use for authenticating with the message broker
//topics are isolated across systems, so in order to communicate with a specific
//system, you must supply the system key
func (d *DevClient) InitializeMQTT(clientid, systemkey string, timeout int) error {
	mqc, err := initializeMqttClient(d.DevToken, systemkey, "", clientid, timeout)
	if err != nil {
		return err
	}
	d.MQTTClient = mqc
	return nil
}

//ConnectMQTT allows the user to connect to the mqtt broker. If no TLS config is provided, a TCP socket will be used
func (u *UserClient) ConnectMQTT(ssl *tls.Config, lastWill *LastWillPacket) error {
	//a questionable pointer, mainly for ease of checking nil
	//be more efficient to pass on the stack
	return connectToBroker(u.MQTTClient, u.MqttAddr, ssl, lastWill)
}

//ConnectMQTT allows the user to connect to the mqtt broker. If no TLS config is provided, a TCP socket will be used
func (d *DevClient) ConnectMQTT(ssl *tls.Config, lastWill *LastWillPacket) error {
	return connectToBroker(d.MQTTClient, d.MqttAddr, ssl, lastWill)
}

//Publish publishes a message to the specified mqtt topic
func (u *UserClient) Publish(topic string, message []byte, qos int) error {
	return publish(u.MQTTClient, topic, message, qos, u.getMessageId())
}

//Publish publishes a message to the specified mqtt topic
func (d *DevClient) Publish(topic string, message []byte, qos int) error {
	return publish(d.MQTTClient, topic, message, qos, d.getMessageId())
}

//Subscribe subscribes a user to a topic. Incoming messages will be sent over the channel.
func (u *UserClient) Subscribe(topic string, qos int) (<-chan *mqtt.Publish, error) {
	return subscribe(u.MQTTClient, topic, qos)
}

//Subscribe subscribes a user to a topic. Incoming messages will be sent over the channel.
func (d *DevClient) Subscribe(topic string, qos int) (<-chan *mqtt.Publish, error) {
	return subscribe(d.MQTTClient, topic, qos)
}

//Unsubscribe stops the flow of messages over the corresponding subscription chan
func (u *UserClient) Unsubscribe(topic string) error {
	return unsubscribe(u.MQTTClient, topic)
}

//Unsubscribe stops the flow of messages over the corresponding subscription chan
func (d *DevClient) Unsubscribe(topic string) error {
	return unsubscribe(d.MQTTClient, topic)
}

//Disconnect stops the TCP connection and unsubscribes the client from any remaining topics
func (u *UserClient) Disconnect() error {
	return disconnect(u.MQTTClient)
}

//Disconnect stops the TCP connection and unsubscribes the client from any remaining topics
func (d *DevClient) Disconnect() error {
	return disconnect(d.MQTTClient)
}

//Below are a series of convience functions to allow the user to only need to import
//the clearblade go-sdk

//InitializeMqttClient allocates a mqtt client.
//the values for initialization are drawn from the client struct
//with the exception of the timeout and client id, which is mqtt specific.
func initializeMqttClient(token, systemkey, systemsecret, clientid string, timeout int) (*mqcli.Client, error) {
	cli := mqcli.NewClient(token,
		systemkey,
		systemsecret,
		clientid,
		timeout)
	return cli, nil
}

//ConnectToBroker connects to the broker and sends the connect packet
func connectToBroker(c *mqcli.Client, address string, ssl *tls.Config, lastWill *LastWillPacket) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	err := c.Start(address, ssl)
	if err != nil {
		return err
	}
	if lastWill == nil {
		return mqcli.SendConnect(c, false, false, 0, "", "")
	} else {
		return mqcli.SendConnect(c, true, lastWill.Retain, lastWill.Qos, lastWill.Topic, lastWill.Body)
	}
}

func publish(c *mqcli.Client, topic string, data []byte, qos int, mid uint16) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	pub, err := mqcli.MakeMeABytePublish(topic, data, mid)
	pub.Header.QOS = uint8(qos)
	if err != nil {
		return err
	}
	return mqcli.PublishFlow(c, pub)
}

//Subscribe is a simple wrapper around the mqtt client library
func subscribe(c *mqcli.Client, topic string, qos int) (<-chan *mqtt.Publish, error) {
	if c == nil {
		return nil, errors.New("MQTTClient is uninitialized")
	}
	return mqcli.SubscribeFlow(c, topic, qos)
}

//Unsubscribe is a simple wrapper around the mqtt client library
func unsubscribe(c *mqcli.Client, topic string) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	return mqcli.UnsubscribeFlow(c, topic)
}

//Disconnect is a simple wrapper for sending mqtt disconnects
func disconnect(c *mqcli.Client) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	return mqcli.SendDisconnect(c)
}
<commit_msg>Helpful error message for calling Publish on a partially initialized client<commit_after>package GoSDK

import (
	"crypto/tls"
	"errors"
	mqtt "github.com/clearblade/mqtt_parsing"
	mqcli "github.com/clearblade/mqttclient"
)

const (
	//Mqtt QOS 0
	QOS_AtMostOnce = iota
	//Mqtt QOS 1
	QOS_AtLeastOnce
	//Mqtt QOS 2
	QOS_PreciselyOnce
)

//LastWillPacket is a type to represent the Last Will and Testament packet
type LastWillPacket struct {
	Topic  string
	Body   string
	Qos    int
	Retain bool
}

//herein we use the same trick we used for http clients

//InitializeMQTT allocates the mqtt client for the user. an empty string can be passed as the second argument for the user client
func (u *UserClient) InitializeMQTT(clientid string, ignore string, timeout int) error {
	mqc, err := initializeMqttClient(u.UserToken, u.SystemKey, u.SystemSecret, clientid, timeout)
	if err != nil {
		return err
	}
	u.MQTTClient = mqc
	return nil
}

//InitializeMQTT allocates the mqtt client for the developer. the second argument is a
//the systemkey you wish to use for authenticating with the message broker
//topics are isolated across systems, so in order to communicate with a specific
//system, you must supply the system key
func (d *DevClient) InitializeMQTT(clientid, systemkey string, timeout int) error {
	mqc, err := initializeMqttClient(d.DevToken, systemkey, "", clientid, timeout)
	if err != nil {
		return err
	}
	d.MQTTClient = mqc
	return nil
}

//ConnectMQTT allows the user to connect to the mqtt broker. If no TLS config is provided, a TCP socket will be used
func (u *UserClient) ConnectMQTT(ssl *tls.Config, lastWill *LastWillPacket) error {
	//a questionable pointer, mainly for ease of checking nil
	//be more efficient to pass on the stack
	return connectToBroker(u.MQTTClient, u.MqttAddr, ssl, lastWill)
}

//ConnectMQTT allows the user to connect to the mqtt broker. If no TLS config is provided, a TCP socket will be used
func (d *DevClient) ConnectMQTT(ssl *tls.Config, lastWill *LastWillPacket) error {
	return connectToBroker(d.MQTTClient, d.MqttAddr, ssl, lastWill)
}

//Publish publishes a message to the specified mqtt topic
func (u *UserClient) Publish(topic string, message []byte, qos int) error {
	return publish(u.MQTTClient, topic, message, qos, u.getMessageId())
}

//Publish publishes a message to the specified mqtt topic
func (d *DevClient) Publish(topic string, message []byte, qos int) error {
	return publish(d.MQTTClient, topic, message, qos, d.getMessageId())
}

//Subscribe subscribes a user to a topic. Incoming messages will be sent over the channel.
func (u *UserClient) Subscribe(topic string, qos int) (<-chan *mqtt.Publish, error) {
	return subscribe(u.MQTTClient, topic, qos)
}

//Subscribe subscribes a user to a topic. Incoming messages will be sent over the channel.
func (d *DevClient) Subscribe(topic string, qos int) (<-chan *mqtt.Publish, error) {
	return subscribe(d.MQTTClient, topic, qos)
}

//Unsubscribe stops the flow of messages over the corresponding subscription chan
func (u *UserClient) Unsubscribe(topic string) error {
	return unsubscribe(u.MQTTClient, topic)
}

//Unsubscribe stops the flow of messages over the corresponding subscription chan
func (d *DevClient) Unsubscribe(topic string) error {
	return unsubscribe(d.MQTTClient, topic)
}

//Disconnect stops the TCP connection and unsubscribes the client from any remaining topics
func (u *UserClient) Disconnect() error {
	return disconnect(u.MQTTClient)
}

//Disconnect stops the TCP connection and unsubscribes the client from any remaining topics
func (d *DevClient) Disconnect() error {
	return disconnect(d.MQTTClient)
}

//Below are a series of convience functions to allow the user to only need to import
//the clearblade go-sdk

//InitializeMqttClient allocates a mqtt client.
//the values for initialization are drawn from the client struct
//with the exception of the timeout and client id, which is mqtt specific.
func initializeMqttClient(token, systemkey, systemsecret, clientid string, timeout int) (*mqcli.Client, error) {
	cli := mqcli.NewClient(token,
		systemkey,
		systemsecret,
		clientid,
		timeout)
	return cli, nil
}

//ConnectToBroker connects to the broker and sends the connect packet
func connectToBroker(c *mqcli.Client, address string, ssl *tls.Config, lastWill *LastWillPacket) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	err := c.Start(address, ssl)
	if err != nil {
		return err
	}
	if lastWill == nil {
		return mqcli.SendConnect(c, false, false, 0, "", "")
	} else {
		return mqcli.SendConnect(c, true, lastWill.Retain, lastWill.Qos, lastWill.Topic, lastWill.Body)
	}
}

func publish(c *mqcli.Client, topic string, data []byte, qos int, mid uint16) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	if c.C == nil {
		return errors.New("Must successfully call ConnectMQTT first")
	}
	pub, err := mqcli.MakeMeABytePublish(topic, data, mid)
	pub.Header.QOS = uint8(qos)
	if err != nil {
		return err
	}
	return mqcli.PublishFlow(c, pub)
}

//Subscribe is a simple wrapper around the mqtt client library
func subscribe(c *mqcli.Client, topic string, qos int) (<-chan *mqtt.Publish, error) {
	if c == nil {
		return nil, errors.New("MQTTClient is uninitialized")
	}
	return mqcli.SubscribeFlow(c, topic, qos)
}

//Unsubscribe is a simple wrapper around the mqtt client library
func unsubscribe(c *mqcli.Client, topic string) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	return mqcli.UnsubscribeFlow(c, topic)
}

//Disconnect is a simple wrapper for sending mqtt disconnects
func disconnect(c *mqcli.Client) error {
	if c == nil {
		return errors.New("MQTTClient is uninitialized")
	}
	return mqcli.SendDisconnect(c)
}
<|endoftext|>


<commit_before><commit_msg>I got a gc view result with a strange key leading to crash.<commit_after><|endoftext|>


<commit_before><commit_msg>Don't print width and height if there was an error.<commit_after><|endoftext|>


<commit_before>/*
* 	Jayson Salkey
*	01/26/2016 02:54 UTC-5
*/

package kmeans

import (
	"math"
	"math/rand"
)

const DELTA = 0.001

type Point struct{
    entry[] float64
}

type Centroid struct{
    center Point
    Points []Point
}

func (p_1 Point) distanceTo(p_2 Point) float64{
	sum := float64(0)
	for e:=0;e<len(p_1.entry);e++{
		sum += math.Pow((p_1.entry[e] - p_2.entry[e]),2)
	}
    return math.Sqrt(sum)
}

func (c_1 *Centroid) reCenter() float64{
    new_Centroid := make([]float64,len(c_1.center.entry))
    for _, e := range c_1.Points{
    	for r:=0;r<len(new_Centroid);r++{
    		new_Centroid[r] += e.entry[r]
    	}
    }
    for r:=0;r<len(new_Centroid);r++{
    	new_Centroid[r] /= float64(len(c_1.Points))
    }
    old_center := c_1.center
    c_1.center = Point{new_Centroid}
    return old_center.distanceTo(c_1.center)
}

func KMEANS(data []Point, k uint64) (Centroids []Centroid){
    for i:=uint64(0); i<k; i++{
        Centroids = append(Centroids,Centroid{center: data[rand.Intn(len(data))]})
    }

    converged := false
    for !converged {
        for i:= range data{
            min_distance := 9999999.0
            z := 0
            for v,e:=range Centroids {
                distance := data[i].distanceTo(e.center)
                if distance < min_distance{
                    min_distance = distance;
                    z = v
                }
            }
            Centroids[z].Points = append(Centroids[z].Points, data[i])
        }
        max_delta := -9999999.0
        for i:= range Centroids {
            movement := Centroids[i].reCenter()
            if movement > max_delta{
                max_delta = movement
            }
        }
        if DELTA >= max_delta{
            converged = true
            return
        }
        for i:= range Centroids {
            Centroids[i].Points = nil
        }
    }
    return Centroids
}
<commit_msg>Update KMEANS.go<commit_after>/*
* 	Jayson Salkey
*	01/26/2016 02:54 UTC-5
*/

package kmeans

import (
	"math"
	"math/rand"
)

type Point struct{
    Entry[] float64
}

type Centroid struct{
    center Point
    Points []Point
}

func (p_1 Point) distanceTo(p_2 Point) float64{
	sum := float64(0)
	for e:=0;e<len(p_1.Entry);e++{
		sum += math.Pow((p_1.Entry[e] - p_2.Entry[e]),2)
	}
    return math.Sqrt(sum)
}

func (c_1 *Centroid) reCenter() float64{
    new_Centroid := make([]float64,len(c_1.center.Entry))
    for _, e := range c_1.Points{
    	for r:=0;r<len(new_Centroid);r++{
    		new_Centroid[r] += e.Entry[r]
    	}
    }
    for r:=0;r<len(new_Centroid);r++{
    	new_Centroid[r] /= float64(len(c_1.Points))
    }
    old_center := c_1.center
    c_1.center = Point{new_Centroid}
    return old_center.distanceTo(c_1.center)
}

func KMEANS(data []Point, k uint64, DELTA float64) (Centroids []Centroid){
    for i:=uint64(0); i<k; i++{
        Centroids = append(Centroids,Centroid{center: data[rand.Intn(len(data))]})
    }

    converged := false
    for !converged {
        for i:= range data{
            min_distance := math.MaxFloat64
            z := 0
            for v,e:=range Centroids {
                distance := data[i].distanceTo(e.center)
                if distance < min_distance{
                    min_distance = distance;
                    z = v
                }
            }
            Centroids[z].Points = append(Centroids[z].Points, data[i])
        }
        max_delta := -math.MaxFloat64
        for i:= range Centroids {
            movement := Centroids[i].reCenter()
            if movement > max_delta{
                max_delta = movement
            }
        }
        if DELTA >= max_delta{
            converged = true
            return
        }
        for i:= range Centroids {
            Centroids[i].Points = nil
        }
    }
    return Centroids
}
<|endoftext|>