<commit_before>package main

import (
	"flag"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	//"regexp"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/leibowitz/goproxy"
)

type ContextUserData struct {
	Store bool
	Time  int64
	//Body   io.Reader
	Body   []byte
	Header http.Header
}

type Content struct {
	//Id       bson.ObjectId
	Request  Request   "request"
	Response Response  "response"
	Date     time.Time "date"
}

type Request struct {
	Origin	string "origin"
	Body   string "body"
	FileId bson.ObjectId
	Query  string "query"
	//Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	FileId  bson.ObjectId
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func NewResponse(r *http.Request, contentType string, status int, body []byte) *http.Response {
	resp := &http.Response{}
	resp.Request = r
	resp.TransferEncoding = r.TransferEncoding
	resp.Header = make(http.Header)
	resp.Header.Add("Content-Type", contentType)
	resp.StatusCode = status
	buf := bytes.NewBuffer(body)
	resp.ContentLength = int64(buf.Len())
	resp.Body = ioutil.NopCloser(buf)
	return resp
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	tmpdir := filepath.Join(os.TempDir(), "proxy-service")

	if _, err := os.Stat(tmpdir); err != nil {
		if os.IsNotExist(err) {
			// Create temp directory to store body response
			err = os.MkdirAll(tmpdir, 0777)
		}

		// err should be nil if we just created the directory
		if err != nil {
			panic(err)
		}
	}

	db := new(mgo.Database)
	c := new(mgo.Collection)

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		db = session.DB("proxyservice")
		c = db.C("log_logentry")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {

		//log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		/*if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
		} else if strings.Contains(host, ".proxy.dev") {
			host = strings.Replace(host, ".proxy.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
		}*/

		/*r, _ := regexp.Compile(".([0-9]+)$")
		// Check if host is hostname.80 (host with port number)
		res := r.FindStringSubmatch(host)
		if res != nil && len(res[1]) != 0 {
			host = strings.Replace(host, strings.Join([]string{".", res[1]}, ""), "", 1)
			host = strings.Join([]string{host, res[1]}, ":")
			log.Printf("Changing host to %v", host);
		}*/

		//log.Printf("Target Host: %s - Headers: %+v", host, req.Header)
		req.Host = host

		//log.Printf("%+v", req)

		var reqbody []byte

		if c.Database != nil && *mock && req.Method != "CONNECT" {
			//reqbody := string(body[:])
			//log.Printf("request body: %s", reqbody)
			result := Content{}
			//ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
			err := c.Find(bson.M{"request.host": req.Host, "request.method": req.Method, "response.status": 200, "request.path": req.URL.Path}).Sort("-date").One(&result)
			if err == nil {
				//ctx.Logf("Found one")
				/*fmt.Println("Path:", result.Request.Path)
				  //fmt.Println("Body:", result.Request.Body)
				  fmt.Println("Method:", result.Request.Method)
				  fmt.Println("Host:", result.Request.Host)
				  fmt.Println("Time:", result.Request.Time)
				  fmt.Println("Date:", result.Request.Date)
				  fmt.Println("Headers:", result.Request.Headers)

				  //fmt.Println("Body:", result.Response.Body)
				  fmt.Println("Status:", result.Response.Status)
				  fmt.Println("Headers:", result.Response.Headers)*/

				//resp := goproxy.NewResponse(req, result.Response.Headers.Get("Content-Type"), result.Response.Status, result.Response.Body)
				//ctx.UserData = ContextUserData{Store: false, Time: 0}
				//return req, resp
			}

			// read the whole body
			reqbody, err = ioutil.ReadAll(req.Body)
			if err != nil {
				ctx.Warnf("Cannot read request body %s", err)
			}

			defer req.Body.Close()
			req.Body = ioutil.NopCloser(bytes.NewBuffer(reqbody))

		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano(), Body: reqbody, Header: req.Header}
		return req, nil
	})

	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		//ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
		if c.Database != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.Request.Method != "CONNECT" {
			// get response content type
			respctype := getContentType(ctx.Resp.Header.Get("Content-Type"))

			//log.Printf("Resp Contenttype %s", respctype)

			respid := bson.NewObjectId()
			//log.Printf("Resp id: %s, host: %s", respid.Hex(), ctx.Resp.Request.Host)

			filename := filepath.Join(tmpdir, respid.Hex())

			//log.Printf("Duplicating Body file id: %s", respid.String())
			resp.Body = NewTeeReadCloser(resp.Body, NewFileStream(filename, *db, respctype, respid))

			reqctype := getContentType(ctx.Resp.Request.Header.Get("Content-Type"))

			//log.Printf("Req Contenttype %s", reqctype)

			if reqctype == "application/x-www-form-urlencoded" {
				//log.Printf("setting req content type to text/plain for saving to mongo")
				reqctype = "text/plain"
			}

			bodyreader := bytes.NewReader(ctx.UserData.(ContextUserData).Body)

			reqid := bson.NewObjectId()

			saveFileToMongo(*db, reqid, reqctype, bodyreader, reqid.Hex())

			// prepare document
			content := Content{
				//Id: docid,
				Request: Request{
					Origin:	 ipAddrFromRemoteAddr(ctx.Resp.Request.RemoteAddr),
					Path:    ctx.Resp.Request.URL.Path,
					Query:   ctx.Resp.Request.URL.Query().Encode(),
					FileId:  reqid,
					Host:    ctx.Resp.Request.Host,
					Method:  ctx.Resp.Request.Method,
					Time:    float32(time.Now().UnixNano()-ctx.UserData.(ContextUserData).Time) / 1.0e9,
					Headers: ctx.UserData.(ContextUserData).Header},
				Response: Response{
					Status:  ctx.Resp.StatusCode,
					Headers: ctx.Resp.Header,
					FileId:  respid},
				Date: time.Now(),
			}

			err := c.Insert(content)
			if err != nil {
				ctx.Logf("Can't insert document: %v\n", err)
			}

		}
		return resp
	})

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}

type TeeReadCloser struct {
	r io.Reader
	w io.WriteCloser
	c io.Closer
}

func NewTeeReadCloser(r io.ReadCloser, w io.WriteCloser) io.ReadCloser {
	return &TeeReadCloser{io.TeeReader(r, w), w, r}
}

func (t *TeeReadCloser) Read(b []byte) (int, error) {
	return t.r.Read(b)
}

func (t *TeeReadCloser) Close() error {
	err1 := t.c.Close()
	err2 := t.w.Close()
	if err1 == nil && err2 == nil {
		return nil
	}
	if err1 != nil {
		return err2
	}
	return err1
}

type FileStream struct {
	path        string
	db          mgo.Database
	contentType string
	objectId    bson.ObjectId
	f           *os.File
}

func NewFileStream(path string, db mgo.Database, contentType string, objectId bson.ObjectId) *FileStream {
	return &FileStream{path: path, db: db, contentType: contentType, objectId: objectId, f: nil}
}

func (fs *FileStream) Write(b []byte) (nr int, err error) {
	if fs.f == nil {
		fs.f, err = os.Create(fs.path)
		if err != nil {
			return 0, err
		}
	}
	return fs.f.Write(b)
}

func (fs *FileStream) Close() error {
	if fs.f == nil {
		return errors.New("FileStream was never written into")
	}
	fs.f.Seek(0, 0)
	saveFileToMongo(fs.db, fs.objectId, fs.contentType, fs.f, fs.objectId.Hex())
	err := fs.f.Close()
	if err == nil {
		err2 := os.Remove(fs.path)
		if err2 != nil {
			log.Printf("Unable to delete file")
		}
	}
	return err
}

// Store file in MongoDB GridFS
func saveFileToMongo(db mgo.Database, objId bson.ObjectId, contentType string, openFile io.Reader, fileName string) {
	mdbfile, err := db.GridFS("fs").Create(fileName)
	if err == nil {
		mdbfile.SetContentType(contentType)
		mdbfile.SetId(objId)
		_, err = io.Copy(mdbfile, openFile)
		if err != nil {
			log.Printf("Unable to copy to mongo")
		}
		err = mdbfile.Close()
		if err != nil {
			log.Printf("Unable to close copy to mongo")
		}
	}
}

func getContentType(s string) string {
	arr := strings.Split(s, ";")
	return arr[0]
}
func ipAddrFromRemoteAddr(s string) string {
        idx := strings.LastIndex(s, ":")
        if idx == -1 {
                return s
        }
        return s[:idx]
}
<commit_msg>Check rules and return stored body and headers<commit_after>package main

import (
	"flag"
	"strconv"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"fmt"
	//"regexp"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/leibowitz/goproxy"
)

type ContextUserData struct {
	Store bool
	Time  int64
	Body   io.Reader
	//Body   []byte
	Header http.Header
	Origin string
}

type Content struct {
	//Id       bson.ObjectId
	Request  Request   "request"
	Response Response  "response"
	Date     time.Time "date"
}

type Rule struct {
	//Id       bson.ObjectId
	Active	bool "active"
	Dynamic bool "dynamic"
	Host	string "host"
	Path	string "path"
	Query	string "query"
	Method	string "method"
	Status	string "status"
	Response string "response"
	Body	string "body"
	ReqBody string "reqbody"
	ReqHeader http.Header "reqheaders"
	RespHeader http.Header "respheaders"
	Origin  string "origin"
}

type Request struct {
	Origin	string "origin"
	Body   string "body"
	FileId bson.ObjectId
	Query  string "query"
	//Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	FileId  bson.ObjectId
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func NewResponse(r *http.Request, headers http.Header, status int, body io.ReadCloser) *http.Response {
	resp := &http.Response{}
	resp.Request = r
	resp.TransferEncoding = r.TransferEncoding
	resp.Header = headers
	resp.StatusCode = status
	//resp.ContentLength = int64(buf.Len())
	resp.Body = body
	return resp
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	tmpdir := filepath.Join(os.TempDir(), "proxy-service")

	if _, err := os.Stat(tmpdir); err != nil {
		if os.IsNotExist(err) {
			// Create temp directory to store body response
			err = os.MkdirAll(tmpdir, 0777)
		}

		// err should be nil if we just created the directory
		if err != nil {
			panic(err)
		}
	}

	db := new(mgo.Database)
	c := new(mgo.Collection)
	rules := new(mgo.Collection)

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		db = session.DB("proxyservice")
		c = db.C("log_logentry")
		rules = db.C("log_rules")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		origin := ipAddrFromRemoteAddr(ctx.Req.RemoteAddr)

		//log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		/*if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
		} else if strings.Contains(host, ".proxy.dev") {
			host = strings.Replace(host, ".proxy.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
		}*/

		/*r, _ := regexp.Compile(".([0-9]+)$")
		// Check if host is hostname.80 (host with port number)
		res := r.FindStringSubmatch(host)
		if res != nil && len(res[1]) != 0 {
			host = strings.Replace(host, strings.Join([]string{".", res[1]}, ""), "", 1)
			host = strings.Join([]string{host, res[1]}, ":")
			log.Printf("Changing host to %v", host);
		}*/

		//log.Printf("Target Host: %s - Headers: %+v", host, req.Header)
		req.Host = host

		//log.Printf("%+v", req)

		var reqbody []byte

		var bodyreader io.Reader
		if rules.Database != nil && *mock && req.Method != "CONNECT" {
			//reqbody := string(body[:])
			//log.Printf("request body: %s", reqbody)
			rule := Rule{}
			//ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
b := bson.M{"$and": []bson.M{
	bson.M{"active": true},
	bson.M{"dynamic": false},
	bson.M{"origin":
	    bson.M{"$in":
		[]interface{}{origin, false},
	    },
	},
	bson.M{"host":
	    bson.M{"$in":
		[]interface{}{req.Host, false},
	    },
	},
	bson.M{"method":
	    bson.M{"$in":
		[]interface{}{req.Method, false},
	    },
	},
	bson.M{"path":
	    bson.M{"$in":
		[]interface{}{req.URL.Path, false},
	    },
	},
	bson.M{"query":
	    bson.M{"$in":
		[]interface{}{req.URL.Query().Encode(), false},
	    },
	},
    }}

			//b := bson.M{"active": true, "dynamic": false, "host": req.Host, "method": req.Method, "path": req.URL.Path, "query": req.URL.Query().Encode()}
			err := rules.Find(b).One(&rule)//.Sort("priority")
			//log.Printf("Query: %+v, Res: %+v", b, rule)
			if err == nil {
			    status, err := strconv.Atoi(rule.Status)
			    reqbody := ioutil.NopCloser(bytes.NewBufferString(rule.ReqBody))
			    respbody := ioutil.NopCloser(bytes.NewBufferString(rule.Body))
			    log.Printf("%+v", rule)
			    resp := NewResponse(req, rule.RespHeader, status, respbody)
			    ctx.UserData = ContextUserData{Store: true, Time: 0, Body: reqbody, Header: rule.RespHeader, Origin: origin}
			    return req, resp
			}

			// read the whole body
			reqbody, err = ioutil.ReadAll(req.Body)
			if err != nil {
				ctx.Warnf("Cannot read request body %s", err)
			}

			defer req.Body.Close()
			req.Body = ioutil.NopCloser(bytes.NewBuffer(reqbody))

			bodyreader = bytes.NewReader(reqbody)

		} else {
		    bodyreader = req.Body
		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano(), Body: bodyreader, Header: req.Header, Origin: origin}
		return req, nil
	})

	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		//ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
		if c.Database != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.Request.Method != "CONNECT" {
			// get response content type
			respctype := getContentType(ctx.Resp.Header.Get("Content-Type"))

			//log.Printf("Resp Contenttype %s", respctype)

			respid := bson.NewObjectId()
			//log.Printf("Resp id: %s, host: %s", respid.Hex(), ctx.Resp.Request.Host)

			filename := filepath.Join(tmpdir, respid.Hex())

			//log.Printf("Duplicating Body file id: %s", respid.String())
			resp.Body = NewTeeReadCloser(resp.Body, NewFileStream(filename, *db, respctype, respid))

			reqctype := getContentType(ctx.Resp.Request.Header.Get("Content-Type"))

			//log.Printf("Req Contenttype %s", reqctype)

			if reqctype == "application/x-www-form-urlencoded" {
				//log.Printf("setting req content type to text/plain for saving to mongo")
				reqctype = "text/plain"
			}

			reqid := bson.NewObjectId()
			//log.Printf("Req id: %s, host: %s", reqid.Hex(), ctx.Resp.Request.Host)

			saveFileToMongo(*db, reqid, reqctype, ctx.UserData.(ContextUserData).Body, reqid.Hex())

			// prepare document
			content := Content{
				//Id: docid,
				Request: Request{
					Origin:	 ctx.UserData.(ContextUserData).Origin,
					Path:    ctx.Resp.Request.URL.Path,
					Query:   ctx.Resp.Request.URL.Query().Encode(),
					FileId:  reqid,
					Host:    ctx.Resp.Request.Host,
					Method:  ctx.Resp.Request.Method,
					Time:    float32(time.Now().UnixNano()-ctx.UserData.(ContextUserData).Time) / 1.0e9,
					Headers: ctx.UserData.(ContextUserData).Header},
				Response: Response{
					Status:  ctx.Resp.StatusCode,
					Headers: ctx.Resp.Header,
					FileId:  respid},
				Date: time.Now(),
			}

			err := c.Insert(content)
			if err != nil {
				ctx.Logf("Can't insert document: %v\n", err)
			}

		}
		return resp
	})

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}

type TeeReadCloser struct {
	r io.Reader
	w io.WriteCloser
	c io.Closer
}

func NewTeeReadCloser(r io.ReadCloser, w io.WriteCloser) io.ReadCloser {
	return &TeeReadCloser{io.TeeReader(r, w), w, r}
}

func (t *TeeReadCloser) Read(b []byte) (int, error) {
	return t.r.Read(b)
}

func (t *TeeReadCloser) Close() error {
	err1 := t.c.Close()
	err2 := t.w.Close()
	if err1 == nil && err2 == nil {
		return nil
	}
	if err1 != nil {
		return err2
	}
	return err1
}

type FileStream struct {
	path        string
	db          mgo.Database
	contentType string
	objectId    bson.ObjectId
	f           *os.File
}

func NewFileStream(path string, db mgo.Database, contentType string, objectId bson.ObjectId) *FileStream {
	return &FileStream{path: path, db: db, contentType: contentType, objectId: objectId, f: nil}
}

func (fs *FileStream) Write(b []byte) (nr int, err error) {
	if fs.f == nil {
		fs.f, err = os.Create(fs.path)
		if err != nil {
			return 0, err
		}
	}
	return fs.f.Write(b)
}

func (fs *FileStream) Close() error {
	if fs.f == nil {
		return errors.New("FileStream was never written into")
	}
	fs.f.Seek(0, 0)
	saveFileToMongo(fs.db, fs.objectId, fs.contentType, fs.f, fs.objectId.Hex())
	err := fs.f.Close()
	if err == nil {
		err2 := os.Remove(fs.path)
		if err2 != nil {
			log.Printf("Unable to delete file")
		}
	}
	return err
}

func getMongoFileContent(db mgo.Database, objId bson.ObjectId) (file *mgo.GridFile, err error) {
    file, err = db.GridFS("fs").OpenId(objId)

    if err != nil {
	return file, err
	if err == mgo.ErrNotFound {
	}
    }
    //defer file.Close()

    return file, err
}

// Store file in MongoDB GridFS
func saveFileToMongo(db mgo.Database, objId bson.ObjectId, contentType string, openFile io.Reader, fileName string) {
	mdbfile, err := db.GridFS("fs").Create(fileName)
	if err == nil {
		mdbfile.SetContentType(contentType)
		mdbfile.SetId(objId)
		_, err = io.Copy(mdbfile, openFile)
		if err != nil {
			log.Printf("Unable to copy to mongo: %s - %v", fileName, err)
		}
		err = mdbfile.Close()
		if err != nil {
			log.Printf("Unable to close copy to mongo")
		}
	}
}

func getContentType(s string) string {
	arr := strings.Split(s, ";")
	return arr[0]
}
func ipAddrFromRemoteAddr(s string) string {
        idx := strings.LastIndex(s, ":")
        if idx == -1 {
                return s
        }
        return s[:idx]
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/elazarl/goproxy"
	//"github.com/elazarl/goproxy/ext/html"
)

type ContextUserData struct {
	Store bool
	Time  int64
}

type Content struct {
	//Id bson.ObjectId
	Request  Request  "request"
	Response Response "response"
	Date    time.Time   "date"
}

type Request struct {
	Body    string      "body"
	//Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	c := &mgo.Collection{}

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		c = session.DB("proxyservice").C("log_logentry")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
			log.Printf("Target Host: %s", host)
			req.Host = host

		}

		if c != nil && *mock && req.Method != "CONNECT" {
			result := Content{}
			ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
			err := c.Find(bson.M{"request.host": req.Host, "request.method": req.Method, "response.status": 200, "request.path": req.URL.Path}).Sort("-date").One(&result)
			if err == nil {
				ctx.Logf("Found one")
				/*fmt.Println("Path:", result.Request.Path)
				  //fmt.Println("Body:", result.Request.Body)
				  fmt.Println("Method:", result.Request.Method)
				  fmt.Println("Host:", result.Request.Host)
				  fmt.Println("Time:", result.Request.Time)
				  fmt.Println("Date:", result.Request.Date)
				  fmt.Println("Headers:", result.Request.Headers)

				  //fmt.Println("Body:", result.Response.Body)
				  fmt.Println("Status:", result.Response.Status)
				  fmt.Println("Headers:", result.Response.Headers)*/

				resp := goproxy.NewResponse(req, result.Response.Headers.Get("Content-Type"), result.Response.Status, result.Response.Body)
				ctx.UserData = ContextUserData{Store: false, Time: 0}
				return req, resp
			}

		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano()}
		return req, nil
	})

	proxy.OnResponse().Do(goproxy.HandleBytes(
		func(b []byte, ctx *goproxy.ProxyCtx) []byte {
			ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
			if c != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.StatusCode == 200 && ctx.Resp.Request.Method != "CONNECT" {
				// Get Body as string
				s := string(b[:])
				contentType := ctx.Resp.Header.Get("Content-Type")
				ctx.Logf(contentType)
				arr := strings.Split(contentType, ";")
				switch arr[0] {
				case "application/json", "text/html":
					ctx.Logf("Recording both request/response")
					content := Content{
						//Id: bson.NewObjectId(),
						Request:  Request{Path: ctx.Resp.Request.URL.Path, Host: ctx.Resp.Request.Host, Method: ctx.Resp.Request.Method, Time: float32(time.Now().UnixNano()-ctx.UserData.(ContextUserData).Time) / 1.0e9, Headers: ctx.Resp.Request.Header},
						Response: Response{Status: ctx.Resp.StatusCode, Headers: ctx.Resp.Header, Body: s},
						Date:     time.Now(),
					}

					err := c.Insert(content)
					if err != nil {
						ctx.Logf("Can't insert document: %v\n", err)
					}
					ctx.Logf("Body: %s", s)
				}
			}

			return b
		}))

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}
<commit_msg>Save only text response and fix mgo.Collection<commit_after>package main

import (
	"flag"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/elazarl/goproxy"
	//"github.com/elazarl/goproxy/ext/html"
)

type ContextUserData struct {
	Store bool
	Time  int64
}

type Content struct {
	//Id bson.ObjectId
	Request  Request  "request"
	Response Response "response"
	Date    time.Time   "date"
}

type Request struct {
	Body    string      "body"
	//Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	c := new(mgo.Collection)

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		c = session.DB("proxyservice").C("log_logentry")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
		}

		log.Printf("Target Host: %s", host)
		req.Host = host
		log.Printf("%+v", req)

		if c.Database != nil && *mock && req.Method != "CONNECT" {
			result := Content{}
			ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
			err := c.Find(bson.M{"request.host": req.Host, "request.method": req.Method, "response.status": 200, "request.path": req.URL.Path}).Sort("-date").One(&result)
			if err == nil {
				ctx.Logf("Found one")
				/*fmt.Println("Path:", result.Request.Path)
				  //fmt.Println("Body:", result.Request.Body)
				  fmt.Println("Method:", result.Request.Method)
				  fmt.Println("Host:", result.Request.Host)
				  fmt.Println("Time:", result.Request.Time)
				  fmt.Println("Date:", result.Request.Date)
				  fmt.Println("Headers:", result.Request.Headers)

				  //fmt.Println("Body:", result.Response.Body)
				  fmt.Println("Status:", result.Response.Status)
				  fmt.Println("Headers:", result.Response.Headers)*/

				resp := goproxy.NewResponse(req, result.Response.Headers.Get("Content-Type"), result.Response.Status, result.Response.Body)
				ctx.UserData = ContextUserData{Store: false, Time: 0}
				return req, resp
			}

		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano()}
		return req, nil
	})

	proxy.OnResponse().Do(goproxy.HandleBytes(
		func(b []byte, ctx *goproxy.ProxyCtx) []byte {
			ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
			if c.Database != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.Request.Method != "CONNECT" {
				contentType := ctx.Resp.Header.Get("Content-Type")
				ctx.Logf(contentType)
				arr := strings.Split(contentType, ";")
				switch arr[0] {
				case "application/json", "text/html":
					// Get Body as string
					s := string(b[:])

					if (ctx.Resp.StatusCode == 200) {
						ctx.Logf("Recording both request/response")

						content := Content{
							//Id: bson.NewObjectId(),
							Request: Request{
								Path:    ctx.Resp.Request.URL.Path,
								Host:    ctx.Resp.Request.Host,
								Method:  ctx.Resp.Request.Method,
								Time:    float32(time.Now().UnixNano()-ctx.UserData.(ContextUserData).Time) / 1.0e9,
								Headers: ctx.Resp.Request.Header},
							Response: Response{
								Status:  ctx.Resp.StatusCode,
								Headers: ctx.Resp.Header,
								Body:    s},
							Date: time.Now(),
						}

						err := c.Insert(content)
						if err != nil {
							ctx.Logf("Can't insert document: %v\n", err)
						}
					}

					ctx.Logf("Body: %s", s)
				}
			}

			return b
		}))

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/elazarl/goproxy"
	//"github.com/elazarl/goproxy/ext/html"
)

type ContextUserData struct {
	Store bool
	Time  int64
}

type Content struct {
	//Id bson.ObjectId
	Request  Request  "request"
	Response Response "response"
}

type Request struct {
	Body    string      "body"
	Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	c := &mgo.Collection{}

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		c = session.DB("proxyservice").C("log")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
			log.Printf("Target Host: %s", host)
			req.Host = host

		}

		if c != nil && *mock && req.Method != "CONNECT" {
			result := Content{}
			ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
			err := c.Find(bson.M{"request.host": req.Host, "request.method": req.Method, "response.status": 200, "request.path": req.URL.Path}).Sort("-request.date").One(&result)
			if err == nil {
				ctx.Logf("Found one")
				/*fmt.Println("Path:", result.Request.Path)
				  //fmt.Println("Body:", result.Request.Body)
				  fmt.Println("Method:", result.Request.Method)
				  fmt.Println("Host:", result.Request.Host)
				  fmt.Println("Time:", result.Request.Time)
				  fmt.Println("Date:", result.Request.Date)
				  fmt.Println("Headers:", result.Request.Headers)

				  //fmt.Println("Body:", result.Response.Body)
				  fmt.Println("Status:", result.Response.Status)
				  fmt.Println("Headers:", result.Response.Headers)*/

				resp := goproxy.NewResponse(req, goproxy.ContentTypeHtml, result.Response.Status, result.Response.Body)
				ctx.UserData = ContextUserData{Store: false, Time: 0}
				return req, resp
			}

		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano()}
		return req, nil
	})

	proxy.OnResponse().Do(goproxy.HandleBytes(
		func(b []byte, ctx *goproxy.ProxyCtx) []byte {
			ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
			if c != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.StatusCode == 200 && ctx.Resp.Request.Method != "CONNECT" {
				// Get Body as string
				s := string(b[:])
				ctx.Logf("Recording both request/response")
				content := Content{
					//Id: bson.NewObjectId(),
					Request:  Request{Path: ctx.Resp.Request.URL.Path, Host: ctx.Resp.Request.Host, Method: ctx.Resp.Request.Method, Date: time.Now(), Time: float32(ctx.UserData.(ContextUserData).Time) / 1.0e9, Headers: ctx.Resp.Request.Header},
					Response: Response{Status: ctx.Resp.StatusCode, Headers: ctx.Resp.Header, Body: s}}

				err := c.Insert(content)
				if err != nil {
					ctx.Logf("Can't insert document: %v\n", err)
				}
				ctx.Logf("Body: %s", s)
			}

			return b
		}))

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}
<commit_msg>Move Date field into content<commit_after>package main

import (
	"flag"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/elazarl/goproxy"
	//"github.com/elazarl/goproxy/ext/html"
)

type ContextUserData struct {
	Store bool
	Time  int64
}

type Content struct {
	//Id bson.ObjectId
	Request  Request  "request"
	Response Response "response"
	Date    time.Time   "date"
}

type Request struct {
	Body    string      "body"
	//Date    time.Time   "date"
	Host    string      "host"
	Method  string      "method"
	Path    string      "path"
	Time    float32     "time"
	Headers http.Header "headers"
}

type Response struct {
	Body    string      "body"
	Headers http.Header "headers"
	Status  int         "status"
}

func main() {
	verbose := flag.Bool("v", false, "should every proxy request be logged to stdout")
	mongourl := flag.String("mongourl", "", "record request/response in mongodb")
	mock := flag.Bool("m", false, "send fake responses")
	addr := flag.String("l", ":8080", "on which address should the proxy listen")

	flag.Parse()

	c := &mgo.Collection{}

	if len(*mongourl) != 0 {
		// Mongo DB connection
		session, err := mgo.Dial(*mongourl)
		if err != nil {
			panic(err)
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		c = session.DB("proxyservice").C("log")
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		log.Printf("Request: %s %s %s", req.Method, req.Host, req.RequestURI)

		host := req.Host
		// Request to domain--name-co-uk.mocky.dev
		// will be forwarded to domain-name.co.uk
		if strings.Contains(host, ".mocky.dev") {
			host = strings.Replace(host, ".mocky.dev", "", 1)
			host = strings.Replace(host, "-", ".", -1)
			host = strings.Replace(host, "..", "-", -1)
			log.Printf("Target Host: %s", host)
			req.Host = host

		}

		if c != nil && *mock && req.Method != "CONNECT" {
			result := Content{}
			ctx.Logf("Looking for existing request")
			/*fmt.Println("RequestURI:", req.RequestURI)
			  fmt.Println("Path:", req.URL.Path)
			  fmt.Println("Host:", req.Host)
			  fmt.Println("Method:", req.Method)*/
			err := c.Find(bson.M{"request.host": req.Host, "request.method": req.Method, "response.status": 200, "request.path": req.URL.Path}).Sort("-date").One(&result)
			if err == nil {
				ctx.Logf("Found one")
				/*fmt.Println("Path:", result.Request.Path)
				  //fmt.Println("Body:", result.Request.Body)
				  fmt.Println("Method:", result.Request.Method)
				  fmt.Println("Host:", result.Request.Host)
				  fmt.Println("Time:", result.Request.Time)
				  fmt.Println("Date:", result.Request.Date)
				  fmt.Println("Headers:", result.Request.Headers)

				  //fmt.Println("Body:", result.Response.Body)
				  fmt.Println("Status:", result.Response.Status)
				  fmt.Println("Headers:", result.Response.Headers)*/

				resp := goproxy.NewResponse(req, goproxy.ContentTypeHtml, result.Response.Status, result.Response.Body)
				ctx.UserData = ContextUserData{Store: false, Time: 0}
				return req, resp
			}

		}

		ctx.UserData = ContextUserData{Store: true, Time: time.Now().UnixNano()}
		return req, nil
	})

	proxy.OnResponse().Do(goproxy.HandleBytes(
		func(b []byte, ctx *goproxy.ProxyCtx) []byte {
			ctx.Logf("Method: %s - host: %s", ctx.Resp.Request.Method, ctx.Resp.Request.Host)
			if c != nil && ctx.UserData != nil && ctx.UserData.(ContextUserData).Store && ctx.Resp.StatusCode == 200 && ctx.Resp.Request.Method != "CONNECT" {
				// Get Body as string
				s := string(b[:])
				ctx.Logf("Recording both request/response")
				content := Content{
					//Id: bson.NewObjectId(),
					Request:  Request{Path: ctx.Resp.Request.URL.Path, Host: ctx.Resp.Request.Host, Method: ctx.Resp.Request.Method, Date: time.Now(), Time: float32(ctx.UserData.(ContextUserData).Time) / 1.0e9, Headers: ctx.Resp.Request.Header},
					Response: Response{Status: ctx.Resp.StatusCode, Headers: ctx.Resp.Header, Body: s}}

				err := c.Insert(content)
				if err != nil {
					ctx.Logf("Can't insert document: %v\n", err)
				}
				ctx.Logf("Body: %s", s)
			}

			return b
		}))

	log.Println("Starting Proxy")
	log.Fatalln(http.ListenAndServe(*addr, proxy))
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	verbose    bool
	keepGopath bool
	runTests   bool
	enableCGO  bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "rest-server",                             // name of the program executable and directory
	Namespace: "github.com/restic/rest-server",           // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "github.com/restic/rest-server",           // package name for the main package
	Tests:     []string{"github.com/restic/rest-server"}, // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" || ext == ".h" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer fdst.Close()

	_, err = io.Copy(fdst, fsrc)
	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}
	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return err
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --enable-cgo    use CGO to link against libc\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	args = append([]string{"build"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos)
	if !enableCGO {
		cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
	}

	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	ver := runtime.Version()
	if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
		fmt.Fprintf(os.Stderr, "Go version %s detected, restic requires at least Go 1.7\n", ver)
		os.Exit(1)
	}

	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--enable-cgo":
			enableCGO = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, root, config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, ""); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := filepath.Join(cwd, outputFilename)

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<commit_msg>build.go: Strip temporary path, allow reproducible builds<commit_after>// +build ignore

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	verbose    bool
	keepGopath bool
	runTests   bool
	enableCGO  bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "rest-server",                             // name of the program executable and directory
	Namespace: "github.com/restic/rest-server",           // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "github.com/restic/rest-server",           // package name for the main package
	Tests:     []string{"github.com/restic/rest-server"}, // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" || ext == ".h" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer fdst.Close()

	_, err = io.Copy(fdst, fsrc)
	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}
	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return err
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --enable-cgo    use CGO to link against libc\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	a := []string{"build"}
	a = append(a, "-asmflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, "-gcflags", fmt.Sprintf("-trimpath=%s", gopath))
	a = append(a, args...)
	cmd := exec.Command("go", a...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos)
	if !enableCGO {
		cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
	}

	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	ver := runtime.Version()
	if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
		fmt.Fprintf(os.Stderr, "Go version %s detected, restic requires at least Go 1.7\n", ver)
		os.Exit(1)
	}

	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--enable-cgo":
			enableCGO = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, root, config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, ""); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := filepath.Join(cwd, outputFilename)

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"path/filepath"
	"sort"
	"unicode/utf8"
)

type Build struct {
	File       string
	Dir        string
	Name       string
	Default    string
	Doc        string
	Properties map[string]string
	Targets    map[string]*Target
	Context    *Context
}

func (build *Build) Init(file string) {
	build.File = file
	build.Dir = filepath.Dir(build.File)
	build.Context = NewContext(build)
	for name, target := range build.Targets {
		target.Init(build, name)
	}
}

func (build *Build) ParseTargets() []string {
	targets := flag.Args()
	if len(targets) == 0 {
		if build.Default != "" {
			targets = []string{build.Default}
		} else {
			StopWithError("No default target", 3)
		}
	}
	return targets
}

func (build *Build) Run() {
	targets := build.ParseTargets()
	for _, target := range targets {
		target := build.Target(target)
		target.Run()
	}
	PrintOK()
}

func (build *Build) Target(name string) *Target {
	if target, ok := build.Targets[name]; ok {
		return target
	} else {
		StopWithError(fmt.Sprintf("Target '%s' was not found", name), 6)
		return nil
	}
}

func (build *Build) Help() {
	newLine := false
	// print build documentation
	if build.Doc != "" {
		fmt.Println(build.Doc)
		newLine = true
	}
	// print build properties
	length := 0
	properties := []string{}
	for name, _ := range build.Properties {
		if utf8.RuneCountInString(name) > length {
			length = utf8.RuneCountInString(name)
		}
		properties = append(properties, name)
	}
	sort.Strings(properties)
	if len(properties) > 0 {
		if newLine {
			fmt.Println()
		}
		fmt.Println("Properties:")
		for _, name := range properties {
			value := build.Context.GetProperty(name).String()
			PrintTargetHelp(name, value, []string{}, length)
		}
		newLine = true
	}
	// print targets documentation
	length = 0
	targets := []string{}
	for name, _ := range build.Targets {
		if utf8.RuneCountInString(name) > length {
			length = utf8.RuneCountInString(name)
		}
		targets = append(targets, name)
	}
	sort.Strings(targets)
	if len(targets) > 0 {
		if newLine {
			fmt.Println()
		}
		fmt.Println("Targets:")
		for _, name := range targets {
			target := build.Target(name)
			PrintTargetHelp(name, target.Doc, target.Depends, length)
		}
	}
}
<commit_msg>Properties typing<commit_after>package main

import (
	"flag"
	"fmt"
	"path/filepath"
	"sort"
	"unicode/utf8"
)

type Build struct {
	File       string
	Dir        string
	Name       string
	Default    string
	Doc        string
	Properties map[string]interface{}
	Targets    map[string]*Target
	Context    *Context
}

func (build *Build) Init(file string) {
	build.File = file
	build.Dir = filepath.Dir(build.File)
	build.Context = NewContext(build)
	for name, target := range build.Targets {
		target.Init(build, name)
	}
}

func (build *Build) ParseTargets() []string {
	targets := flag.Args()
	if len(targets) == 0 {
		if build.Default != "" {
			targets = []string{build.Default}
		} else {
			StopWithError("No default target", 3)
		}
	}
	return targets
}

func (build *Build) Run() {
	targets := build.ParseTargets()
	for _, target := range targets {
		target := build.Target(target)
		target.Run()
	}
	PrintOK()
}

func (build *Build) Target(name string) *Target {
	if target, ok := build.Targets[name]; ok {
		return target
	} else {
		StopWithError(fmt.Sprintf("Target '%s' was not found", name), 6)
		return nil
	}
}

func (build *Build) Help() {
	newLine := false
	// print build documentation
	if build.Doc != "" {
		fmt.Println(build.Doc)
		newLine = true
	}
	// print build properties
	length := 0
	properties := []string{}
	for name, _ := range build.Properties {
		if utf8.RuneCountInString(name) > length {
			length = utf8.RuneCountInString(name)
		}
		properties = append(properties, name)
	}
	sort.Strings(properties)
	if len(properties) > 0 {
		if newLine {
			fmt.Println()
		}
		fmt.Println("Properties:")
		for _, name := range properties {
			value := build.Context.GetProperty(name)
			valueString := fmt.Sprintf("%#v", value)
			PrintTargetHelp(name, valueString, []string{}, length)
		}
		newLine = true
	}
	// print targets documentation
	length = 0
	targets := []string{}
	for name, _ := range build.Targets {
		if utf8.RuneCountInString(name) > length {
			length = utf8.RuneCountInString(name)
		}
		targets = append(targets, name)
	}
	sort.Strings(targets)
	if len(targets) > 0 {
		if newLine {
			fmt.Println()
		}
		fmt.Println("Targets:")
		for _, name := range targets {
			target := build.Target(name)
			PrintTargetHelp(name, target.Doc, target.Depends, length)
		}
	}
}
<|endoftext|>


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

package w32

import (
	"syscall"
	"unsafe"
)

var (
	modpsapi = syscall.NewLazyDLL("psapi.dll")

	procEnumProcesses           = modpsapi.NewProc("EnumProcesses")
	procGetProcessMemoryInfo    = modpsapi.NewProc("GetProcessMemoryInfo")
	procGetProcessImageFileName = modpsapi.NewProc("GetProcessImageFileNameA")
)

func EnumProcesses(processIds []uint32, cb uint32, bytesReturned *uint32) bool {
	ret, _, _ := procEnumProcesses.Call(
		uintptr(unsafe.Pointer(&processIds[0])),
		uintptr(cb),
		uintptr(unsafe.Pointer(bytesReturned)))

	return ret != 0
}

func GetProcessImageFileName(hProcess HANDLE) (string, bool) {
	buf := make([]byte, 1024)
	ret, _, _ := procGetProcessImageFileName.Call(
		uintptr(hProcess),
		uintptr(unsafe.Pointer(&buf[0])),
		uintptr(uint32(len(buf))),
	)

	return string(buf[:ret]), ret != 0
}

func GetProcessMemoryInfo(process HANDLE) (PROCESS_MEMORY_COUNTERS, bool) {
	output := PROCESS_MEMORY_COUNTERS{}
	cb := unsafe.Sizeof(output)
	ret, _, _ := procGetProcessMemoryInfo.Call(
		uintptr(process),
		uintptr(unsafe.Pointer(&output)),
		cb,
	)

	return output, ret != 0
}

type PROCESS_MEMORY_COUNTERS struct {
	Cb                         uint32
	PageFaultCount             uint32
	PeakWorkingSetSize         uintptr
	WorkingSetSize             uintptr
	QuotaPeakPagedPoolUsage    uintptr
	QuotaPagedPoolUsage        uintptr
	QuotaPeakNonPagedPoolUsage uintptr
	QuotaNonPagedPoolUsage     uintptr
	PagefileUsage              uintptr
	PeakPagefileUsage          uintptr
}
<commit_msg>add PrivateUsage to PROCESS_MEMORY_COUNTERS struct<commit_after>// Copyright 2010-2012 The W32 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package w32

import (
	"syscall"
	"unsafe"
)

var (
	modpsapi = syscall.NewLazyDLL("psapi.dll")

	procEnumProcesses           = modpsapi.NewProc("EnumProcesses")
	procGetProcessMemoryInfo    = modpsapi.NewProc("GetProcessMemoryInfo")
	procGetProcessImageFileName = modpsapi.NewProc("GetProcessImageFileNameA")
)

func EnumProcesses(processIds []uint32, cb uint32, bytesReturned *uint32) bool {
	ret, _, _ := procEnumProcesses.Call(
		uintptr(unsafe.Pointer(&processIds[0])),
		uintptr(cb),
		uintptr(unsafe.Pointer(bytesReturned)))

	return ret != 0
}

func GetProcessImageFileName(hProcess HANDLE) (string, bool) {
	buf := make([]byte, 1024)
	ret, _, _ := procGetProcessImageFileName.Call(
		uintptr(hProcess),
		uintptr(unsafe.Pointer(&buf[0])),
		uintptr(uint32(len(buf))),
	)

	return string(buf[:ret]), ret != 0
}

func GetProcessMemoryInfo(process HANDLE) (PROCESS_MEMORY_COUNTERS, bool) {
	output := PROCESS_MEMORY_COUNTERS{}
	cb := unsafe.Sizeof(output)
	ret, _, _ := procGetProcessMemoryInfo.Call(
		uintptr(process),
		uintptr(unsafe.Pointer(&output)),
		cb,
	)

	return output, ret != 0
}

type PROCESS_MEMORY_COUNTERS struct {
	Cb                         uint32
	PageFaultCount             uint32
	PeakWorkingSetSize         uintptr
	WorkingSetSize             uintptr
	QuotaPeakPagedPoolUsage    uintptr
	QuotaPagedPoolUsage        uintptr
	QuotaPeakNonPagedPoolUsage uintptr
	QuotaNonPagedPoolUsage     uintptr
	PagefileUsage              uintptr
	PeakPagefileUsage          uintptr
	PrivateUsage               uintptr
}
<|endoftext|>


<commit_before>package acme

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"
)

type simpleHTTPChallenge struct {
	jws     *jws
	optPort string
}

// SimpleHTTPS checks for DNS, public IP and port bindings
func (s *simpleHTTPChallenge) CanSolve(domain string) bool {
	// determine public ip
	resp, err := http.Get("https://icanhazip.com/")
	if err != nil {
		logger().Printf("Could not get public IP -> %v", err)
		return false
	}

	ip, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logger().Printf("Could not get public IP -> %v", err)
		return false
	}
	ipStr := string(ip)
	ipStr = strings.Replace(ipStr, "\n", "", -1)

	// resolve domain we should solve for
	resolvedIPs, err := net.LookupHost(domain)
	if err != nil {
		logger().Printf("Could not lookup DNS A record for %s", domain)
		return false
	}

	// if the resolve does not resolve to our public ip, we can't solve.
	for _, resolvedIP := range resolvedIPs {
		if resolvedIP == ipStr {
			return true
		}
	}

	logger().Printf("SimpleHTTPS: Domain %s does not resolve to the public ip of this server. Determined ip: %s", domain, ipStr)
	return false
}

func (s *simpleHTTPChallenge) Solve(chlng challenge, domain string) error {

	logger().Print("Trying to solve SimpleHTTPS")

	// Generate random string for the path. The acme server will
	// access this path on the server in order to validate the request
	responseToken := getRandomString(15)
	listener, err := s.startHTTPSServer(domain, chlng.Token, responseToken)
	if err != nil {
		return fmt.Errorf("Could not start HTTPS server for challenge -> %v", err)
	}

	// Tell the server about the generated random path
	jsonBytes, err := json.Marshal(challenge{Type: chlng.Type, Path: responseToken})
	if err != nil {
		return errors.New("Failed to marshal network message...")
	}

	resp, err := s.jws.post(chlng.URI, jsonBytes)
	if err != nil {
		return fmt.Errorf("Failed to post JWS message. -> %v", err)
	}

	// After the path is sent, the ACME server will access our server.
	// Repeatedly check the server for an updated status on our request.
	var challengeResponse challenge
loop:
	for {
		decoder := json.NewDecoder(resp.Body)
		decoder.Decode(&challengeResponse)

		switch challengeResponse.Status {
		case "valid":
			logger().Print("The server validated our request")
			listener.Close()
			break loop
		case "pending":
			break
		case "invalid":
			listener.Close()
			return errors.New("The server could not validate our request.")
		default:
			listener.Close()
			return errors.New("The server returned an unexpected state.")
		}

		time.Sleep(1 * time.Second)
		resp, err = http.Get(chlng.URI)
	}

	return nil
}

// Starts a temporary HTTPS server on port 443. As soon as the challenge passed validation,
// this server will get shut down. The certificate generated here is only held in memory.
func (s *simpleHTTPChallenge) startHTTPSServer(domain string, token string, responseToken string) (net.Listener, error) {

	// Generate a new RSA key and a self-signed certificate.
	tempPrivKey, err := generatePrivateKey(2048)
	if err != nil {
		return nil, err
	}
	tempCertPEM, err := generateCert(tempPrivKey, domain)
	if err != nil {
		return nil, err
	}
	pemBytes := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(tempPrivKey)})
	tempKeyPair, err := tls.X509KeyPair(
		tempCertPEM,
		pemBytes)
	if err != nil {
		logger().Print("error here!")
		return nil, err
	}

	tlsConf := new(tls.Config)
	tlsConf.Certificates = []tls.Certificate{tempKeyPair}

	path := "/.well-known/acme-challenge/" + responseToken

	// Allow for CLI override
	port := ":443"
	if s.optPort != "" {
		port = ":" + s.optPort
	}

	tlsListener, err := tls.Listen("tcp", port, tlsConf)
	if err != nil {
		logger().Fatalf("Could not start HTTP listener! -> %v", err)
	}

	// The handler validates the HOST header and request type.
	// For validation it then writes the token the server returned with the challenge
	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		if r.Host == domain && r.Method == "GET" {
			w.Write([]byte(token))
		}
	})

	go http.Serve(tlsListener, nil)

	return tlsListener, nil
}

func getRandomString(length int) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, length)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}

func generateCert(privKey *rsa.PrivateKey, domain string) ([]byte, error) {
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	if err != nil {
		return nil, err
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			CommonName: "ACME Challenge TEMP",
		},
		NotBefore: time.Now(),
		NotAfter:  time.Now().Add(365),

		KeyUsage:              x509.KeyUsageKeyEncipherment,
		BasicConstraintsValid: true,
		DNSNames:              []string{domain},
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
	if err != nil {
		return nil, err
	}

	return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}), nil
}
<commit_msg>Program should not exit on bind error, but return the error to get handled<commit_after>package acme

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"
)

type simpleHTTPChallenge struct {
	jws     *jws
	optPort string
}

// SimpleHTTPS checks for DNS, public IP and port bindings
func (s *simpleHTTPChallenge) CanSolve(domain string) bool {
	// determine public ip
	resp, err := http.Get("https://icanhazip.com/")
	if err != nil {
		logger().Printf("Could not get public IP -> %v", err)
		return false
	}

	ip, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logger().Printf("Could not get public IP -> %v", err)
		return false
	}
	ipStr := string(ip)
	ipStr = strings.Replace(ipStr, "\n", "", -1)

	// resolve domain we should solve for
	resolvedIPs, err := net.LookupHost(domain)
	if err != nil {
		logger().Printf("Could not lookup DNS A record for %s", domain)
		return false
	}

	// if the resolve does not resolve to our public ip, we can't solve.
	for _, resolvedIP := range resolvedIPs {
		if resolvedIP == ipStr {
			return true
		}
	}

	logger().Printf("SimpleHTTPS: Domain %s does not resolve to the public ip of this server. Determined ip: %s", domain, ipStr)
	return false
}

func (s *simpleHTTPChallenge) Solve(chlng challenge, domain string) error {

	logger().Print("Trying to solve SimpleHTTPS")

	// Generate random string for the path. The acme server will
	// access this path on the server in order to validate the request
	responseToken := getRandomString(15)
	listener, err := s.startHTTPSServer(domain, chlng.Token, responseToken)
	if err != nil {
		return fmt.Errorf("Could not start HTTPS server for challenge -> %v", err)
	}

	// Tell the server about the generated random path
	jsonBytes, err := json.Marshal(challenge{Type: chlng.Type, Path: responseToken})
	if err != nil {
		return errors.New("Failed to marshal network message...")
	}

	resp, err := s.jws.post(chlng.URI, jsonBytes)
	if err != nil {
		return fmt.Errorf("Failed to post JWS message. -> %v", err)
	}

	// After the path is sent, the ACME server will access our server.
	// Repeatedly check the server for an updated status on our request.
	var challengeResponse challenge
loop:
	for {
		decoder := json.NewDecoder(resp.Body)
		decoder.Decode(&challengeResponse)

		switch challengeResponse.Status {
		case "valid":
			logger().Print("The server validated our request")
			listener.Close()
			break loop
		case "pending":
			break
		case "invalid":
			listener.Close()
			return errors.New("The server could not validate our request.")
		default:
			listener.Close()
			return errors.New("The server returned an unexpected state.")
		}

		time.Sleep(1 * time.Second)
		resp, err = http.Get(chlng.URI)
	}

	return nil
}

// Starts a temporary HTTPS server on port 443. As soon as the challenge passed validation,
// this server will get shut down. The certificate generated here is only held in memory.
func (s *simpleHTTPChallenge) startHTTPSServer(domain string, token string, responseToken string) (net.Listener, error) {

	// Generate a new RSA key and a self-signed certificate.
	tempPrivKey, err := generatePrivateKey(2048)
	if err != nil {
		return nil, err
	}
	tempCertPEM, err := generateCert(tempPrivKey, domain)
	if err != nil {
		return nil, err
	}
	pemBytes := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(tempPrivKey)})
	tempKeyPair, err := tls.X509KeyPair(
		tempCertPEM,
		pemBytes)
	if err != nil {
		return nil, err
	}

	tlsConf := new(tls.Config)
	tlsConf.Certificates = []tls.Certificate{tempKeyPair}

	path := "/.well-known/acme-challenge/" + responseToken

	// Allow for CLI override
	port := ":443"
	if s.optPort != "" {
		port = ":" + s.optPort
	}

	tlsListener, err := tls.Listen("tcp", port, tlsConf)
	if err != nil {
		return nil, fmt.Errorf("Could not start HTTP listener! -> %v", err)
	}

	// The handler validates the HOST header and request type.
	// For validation it then writes the token the server returned with the challenge
	http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
		if r.Host == domain && r.Method == "GET" {
			w.Write([]byte(token))
		}
	})

	go http.Serve(tlsListener, nil)

	return tlsListener, nil
}

func getRandomString(length int) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, length)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}

func generateCert(privKey *rsa.PrivateKey, domain string) ([]byte, error) {
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
	if err != nil {
		return nil, err
	}

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			CommonName: "ACME Challenge TEMP",
		},
		NotBefore: time.Now(),
		NotAfter:  time.Now().Add(365),

		KeyUsage:              x509.KeyUsageKeyEncipherment,
		BasicConstraintsValid: true,
		DNSNames:              []string{domain},
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
	if err != nil {
		return nil, err
	}

	return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}), nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"
)

type Memory struct {
	Id        int       `json:"id"`
	Text      string    `json:"text"`
	CreatedAt time.Time `json:"created_at"`
	Active    bool      `json:"active"`
}

type Brain struct {
	Memories []Memory `json:"memories"`
}

// Load a brain
func (brain *Brain) Load() {
	var memories []Memory
	var memory Memory
	memory.Id = 0
	memory.Text = "Some circus subculture shit"
	memory.Active = true

	var memory2 Memory
	memory2.Id = 1
	memory2.Text = "cetacean junk"
	memory2.Active = true

	memories = append(memories, memory)
	memories = append(memories, memory2)

	brain.Memories = memories
}

// Persist a brain
func (brain *Brain) Save() {

}

// Add a memory
func (brain *Brain) Add(m Memory) Memory {
	m.Id = brain.GetNextId()
	m.Active = true
	m.CreatedAt = time.Now()

	brain.Memories = append(brain.Memories, m)

	// Return the memory since it's been given an Id and a CreatedAt
	return m
}

// Update a memory
func (brain *Brain) Update(m Memory) Memory {
	var idx int
	for k, v := range brain.Memories {
		if v.Id == m.Id {
			idx = k
			brain.Memories[k].Text = m.Text
		}
	}
	return brain.Memories[idx]
}

// Return the current brain
func getBrain() Brain {
	return brain
}

// Get the next Id for the brain
func (brain *Brain) GetNextId() int {
	i := 0
	for _, v := range brain.Memories {
		if v.Id > i {
			i = v.Id
		}
	}

	return i+1
}
<commit_msg>Added an 'AddedBy' and changed 'CreatedAt' to 'AddedAt'<commit_after>package main

import (
	"time"
)

type Memory struct {
	Id      int       `json:"id"`
	Text    string    `json:"text"`
	AddedBy string    `json:"added_by"`
	AddedAt time.Time `json:"added_at"`
	Active  bool      `json:"active"`
}

type Brain struct {
	Memories []Memory `json:"memories"`
}

// Load a brain
func (brain *Brain) Load() {
	var memories []Memory
	var memory Memory
	memory.Id = 0
	memory.Text = "Some circus subculture shit"
	memory.Active = true

	var memory2 Memory
	memory2.Id = 1
	memory2.Text = "cetacean junk"
	memory2.Active = true

	memories = append(memories, memory)
	memories = append(memories, memory2)

	brain.Memories = memories
}

// Persist a brain
func (brain *Brain) Save() {

}

// Add a memory
func (brain *Brain) Add(m Memory) Memory {
	m.Id = brain.GetNextId()
	m.Active = true
	m.AddedAt = time.Now()

	brain.Memories = append(brain.Memories, m)

	// Return the memory since it's been given an Id and a AddedAt
	return m
}

// Update a memory
func (brain *Brain) Update(m Memory) Memory {
	var idx int
	for k, v := range brain.Memories {
		if v.Id == m.Id {
			idx = k
			brain.Memories[k].Text = m.Text
		}
	}
	return brain.Memories[idx]
}

// Return the current brain
func getBrain() Brain {
	return brain
}

// Get the next Id for the brain
func (brain *Brain) GetNextId() int {
	i := 0
	for _, v := range brain.Memories {
		if v.Id > i {
			i = v.Id
		}
	}

	return i + 1
}
<|endoftext|>


<commit_before>// purse is a Go package and tool for loading and embedding SQL file contents into Go programs.
//
// To install the package, use go install:
//
// 		$ go get github.com/smotes/purse
//
// purse is also a command line tool to automate the creation of a Purse implementation given a specified
// directory of SQL files. Given the directory of SQL files and the directory of the output file,
// purse will create a Go source file (named out.go by default) which contains an implementation and
// instantiation (bound to variable gen by default) of a Purse interface driven by a map[string]string
// literal representing the SQL directory's files' contents.
//
// The purse package is meant to be used during development where SQL files are changing often
// and need to be reloaded into memory on each program execution. Contrastingly, the purse tool
// is meant to be used in production environments where the SQL files' contents can be embedded
// directly into the compiled binary, easing deployment.
//
// To install the tool, use go install:
//
//		$ go get github.com/smotes/purse/cmd/purse
// 		$ go install github.com/smotes/purse/cmd/purse
//		$ purse [args]
//
// The command syntax is:
//
//		$ purse -in="input/dir" -out="output/dir" [-file="out.go"] [-name="gen"]
//
// The input directory and output directory paths must either be absolute or relative to the
// package using it via go generate, or relative to the current working directory where the
// the command was executed.
//
// To override the default output source file name (out.go), provide the optional -file flag.
//
// To override the default variable name (gen) of the generated Purse, provide the optional -name flag.
//
// This process should generally be handled using go generate. Add a comment in one of your go source files,
// like so:
//
// 		//go:generate purse -in="./fixtures" -out="."
//
// Then run go generate:
//
//  	$ go generate
//
// Note that purse depends on certain environment variables to be set to execute properly, namely the
// $GOPACKAGE variable set automatically when running the go generate command. If you wish to explicitly
// use this tool without go generate, you will have to set the output source file's package name by
// setting this environment variable.
//
package purse

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

const (
	ext string = ".sql"
)

// Purse is the interface representing a collection of SQL files whose
// contents are accessed via the basic Get method.
//
// Implementations of this interface should be safe for concurrent use by
// multiple goroutines.
type Purse interface {
	Get(string) (string, bool)
}

// MemoryPurse is an implementation of Purse that uses a map of strings to
// represent the contents of SQL files found within a specified directory.
// It is safe for concurrent use by multiple goroutines.
type MemoryPurse struct {
	mu    sync.RWMutex
	files map[string]string
}

// New loads SQL files' contents in the specified directory dir into memory.
// A file's contents can be accessed with the Get method.
//
// New returns an error if the directory does not exist or is not a directory.
func New(dir string) (*MemoryPurse, error) {
	f, err := os.Open(dir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fis, err := f.Readdir(-1)
	if err != nil {
		return nil, err
	}

	p := &MemoryPurse{files: make(map[string]string, 0)}

	for _, fi := range fis {
		if !fi.IsDir() && filepath.Ext(fi.Name()) == ext {
			f, err := os.Open(filepath.Join(dir, fi.Name()))
			if err != nil {
				return nil, err
			}
			b, err := ioutil.ReadAll(f)
			if err != nil {
				return nil, err
			}
			p.files[fi.Name()] = string(b)
		}
	}
	return p, nil
}

// Get returns a SQL file's contents as a string.
// If the file does not exist or does exists but had a read error,
// then v == "" and ok == false.
func (p *MemoryPurse) Get(filename string) (v string, ok bool) {
	p.mu.RLock()
	v, ok = p.files[filename]
	p.mu.RUnlock()
	return
}

// Files returns a slice of filenames for all loaded SQL files.
func (p *MemoryPurse) Files() []string {
	fs := make([]string, len(p.files))
	i := 0
	for k, _ := range p.files {
		fs[i] = k
		i++
	}
	return fs
}
<commit_msg>updated godocs to match README<commit_after>// purse is a Go package and tool for loading and embedding SQL file contents into Go programs.
//
// To install the package, use go install:
//
// 		$ go get github.com/smotes/purse
//
// purse is also a command line tool to automate the creation of a Purse implementation given a specified
// directory of SQL files. Given the directory of SQL files and the directory of the output file,
// purse will create a Go source file (named out.go by default) which contains an implementation and
// instantiation (bound to variable gen by default) of a Purse interface driven by a map[string]string
// literal representing the SQL directory's files' contents.
//
// The purse package is meant to be used during development where SQL files are changing often
// and need to be reloaded into memory on each program execution. Contrastingly, the purse tool
// is meant to be used in production environments where the SQL files' contents can be embedded
// directly into the compiled binary, easing deployment.
//
// To install the tool, use go install:
//
//		$ go get github.com/smotes/purse/cmd/purse
// 		$ go install github.com/smotes/purse/cmd/purse
//		$ purse [args]
//
// The command syntax is:
//
//		$ purse -in="input/dir" -out="output/dir" [-file="out.go"] [-name="gen"] [-pack="main"]
//
// The input directory and output directory paths must either be absolute or relative to the
// package using it via go generate, or relative to the current working directory where the
// the command was executed.
//
// To override the default output source file name (out.go), provide the optional -file flag.
//
// To override the default variable name (gen) of the generated Purse, provide the optional -name flag.
//
// To set or override the `$GOPACKAGE` environment variable, provide the optional `-pack` flag.
//
// This process should generally be handled using go generate. Add a comment in one of your go source files,
// like so:
//
// 		//go:generate purse -in="./fixtures" -out="."
//
// Then run go generate:
//
//  	$ go generate
//
// Note that the `-pack` flag is not necessary when using go generate, as it sets the environment variable
// automatically. Refer to the [documentation](https://golang.org/cmd/go/) on the `go` command for more information.
//
package purse // import "github.com/smotes/purse"

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

const (
	ext string = ".sql"
)

// Purse is the interface representing a collection of SQL files whose
// contents are accessed via the basic Get method.
//
// Implementations of this interface should be safe for concurrent use by
// multiple goroutines.
type Purse interface {
	Get(string) (string, bool)
}

// MemoryPurse is an implementation of Purse that uses a map of strings to
// represent the contents of SQL files found within a specified directory.
// It is safe for concurrent use by multiple goroutines.
type MemoryPurse struct {
	mu    sync.RWMutex
	files map[string]string
}

// New loads SQL files' contents in the specified directory dir into memory.
// A file's contents can be accessed with the Get method.
//
// New returns an error if the directory does not exist or is not a directory.
func New(dir string) (*MemoryPurse, error) {
	f, err := os.Open(dir)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fis, err := f.Readdir(-1)
	if err != nil {
		return nil, err
	}

	p := &MemoryPurse{files: make(map[string]string, 0)}

	for _, fi := range fis {
		if !fi.IsDir() && filepath.Ext(fi.Name()) == ext {
			f, err := os.Open(filepath.Join(dir, fi.Name()))
			if err != nil {
				return nil, err
			}
			b, err := ioutil.ReadAll(f)
			if err != nil {
				return nil, err
			}
			p.files[fi.Name()] = string(b)
		}
	}
	return p, nil
}

// Get returns a SQL file's contents as a string.
// If the file does not exist or does exists but had a read error,
// then v == "" and ok == false.
func (p *MemoryPurse) Get(filename string) (v string, ok bool) {
	p.mu.RLock()
	v, ok = p.files[filename]
	p.mu.RUnlock()
	return
}

// Files returns a slice of filenames for all loaded SQL files.
func (p *MemoryPurse) Files() []string {
	fs := make([]string, len(p.files))
	i := 0
	for k, _ := range p.files {
		fs[i] = k
		i++
	}
	return fs
}
<|endoftext|>