<commit_before>package utee

import (
	"crypto/md5"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/smtp"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

var (
	//passwd md5
	PlainMd5 = Md5Str("")
)

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

func Md5Str(salt string) func(string) string {
	return func(s string) string {
		h := md5.New()
		io.WriteString(h, s)
		io.WriteString(h, salt)
		return hex.EncodeToString(h.Sum(nil))
	}
}

func Chk(err error) {
	if err != nil {
		panic(err)
	}
}

func Log(err error, prefix ...string) {
	if err == nil {
		return
	}

	s := ""
	if len(prefix) > 0 {
		s = prefix[0]
	}
	log.Println(s, err)
}

//truncate string
func Truncate(s string, n int) string {
	length := utf8.RuneCountInString(s)
	if length <= n || n < 0 {
		return ""
	}

	l := []rune{}
	for _, r := range s {
		l = append(l, r)
	}

	l = l[:(length - n)]
	return string(l)
}

func Tick(t ...time.Time) int64 {
	if len(t) == 0 {
		return time.Now().UnixNano() / 1e6
	} else {
		return t[0].UnixNano() / 1e6
	}
}

func TickSec() int64 {
	return time.Now().Unix()
}

func TickHour() int64 {
	return time.Now().Unix() / 3600 * 3600
}

func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func ContainsInf(s []interface{}, e interface{}) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func Millis(fmt string, timeStr string) (int64, error) {
	data, err := time.Parse(fmt, timeStr)
	if err != nil {
		return 0, err
	}
	return data.UnixNano() / 1e6, nil
}

func Md5(b []byte) []byte {
	h := md5.New()
	h.Write(b)
	return h.Sum(nil)
}

// parse form into J
func F2j(r *http.Request) J {
	r.ParseForm()
	j := J{}
	for k, v := range r.Form {
		if len(v) == 1 {
			if len(v[0]) > 0 {
				j[k] = v[0]
			}
		} else {
			j[k] = v
		}
	}
	return j
}

func Fint64(s interface{}, dft ...int64) int64 {
	var i int64
	var err error
	if s == nil {
		if len(dft) > 0 {
			return dft[0]
		} else {
			s = "0"
		}
	}
	i, err = strconv.ParseInt(s.(string), 10, 64)
	if err != nil && len(dft) > 0 {
		i = dft[0]
	}
	return i
}

func Fint(s interface{}, dft ...int64) int {
	if len(dft) > 0 {
		return int(Fint64(s, dft[0]))
	} else {
		return int(Fint64(s))
	}
}

func DeleteMap(m map[string]interface{}, ks ...string) {
	for _, v := range ks {
		delete(m, v)
	}
}

func IsPemExpire(b []byte) (bool, error) {
	block, _ := pem.Decode(b)
	if block == nil {
		return false, errors.New("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return false, err
	}
	return cert.NotAfter.Before(time.Now()), nil
}

func Shuffle(src []string) []string {
	dest := make([]string, len(src))
	perm := rand.Perm(len(src))
	for i, v := range perm {
		dest[v] = src[i]
	}
	return dest
}

func SendMail(user, password, host, to, subject, body, mailtype string) error {
	hp := strings.Split(host, ":")
	auth := smtp.PlainAuth("", user, password, hp[0])
	var content_type string
	if mailtype == "html" {
		content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
	} else {
		content_type = "Content-Type: text/plain" + "; charset=UTF-8"
	}

	msg := []byte("To: " + to + "\r\nFrom: " + user + "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
	send_to := strings.Split(to, ";")
	err := smtp.SendMail(host, auth, user, send_to, msg)
	return err
}

func ParseAddr(s string) (string, int, error) {
	a := strings.Split(s, ":")
	if len(a) != 2 {
		return "", 0, fmt.Errorf("bad url %s", s)
	}
	port, err := strconv.Atoi(a[1])
	return a[0], port, err
}

func Unique(data []interface{}) []interface{} {
	m := map[interface{}]interface{}{}

	for _, d := range data {
		m[d] = "0"
	}

	l := []interface{}{}
	for key := range m {
		l = append(l, key)
	}
	return l
}

func UniqueStr(data []string) []string {
	m := map[string]string{}

	for _, d := range data {
		m[d] = "0"
	}

	l := []string{}
	for key := range m {
		l = append(l, key)
	}
	return l
}

//split a into several parts, no more than n
func SplitSlice(a []string, n int) [][]string {
	if len(a) < n || n == 1 {
		return [][]string{a}
	}

	result := make([][]string, n)
	for i, s := range a {
		idx := i % n
		result[idx] = append(result[idx], s)
	}
	return result
}

func IntToInf(src []int) []interface{} {
	result := []interface{}{}
	for _, v := range src {
		result = append(result, v)
	}
	return result
}

func StrToInf(src []string) []interface{} {
	result := []interface{}{}
	for _, v := range src {
		result = append(result, v)
	}
	return result
}
<commit_msg>IndexOf  functions<commit_after>package utee

import (
	"crypto/md5"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/smtp"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

var (
	//passwd md5
	PlainMd5 = Md5Str("")
)

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

func Md5Str(salt string) func(string) string {
	return func(s string) string {
		h := md5.New()
		io.WriteString(h, s)
		io.WriteString(h, salt)
		return hex.EncodeToString(h.Sum(nil))
	}
}

func Chk(err error) {
	if err != nil {
		panic(err)
	}
}

func Log(err error, prefix ...string) {
	if err == nil {
		return
	}

	s := ""
	if len(prefix) > 0 {
		s = prefix[0]
	}
	log.Println(s, err)
}

//truncate string
func Truncate(s string, n int) string {
	length := utf8.RuneCountInString(s)
	if length <= n || n < 0 {
		return ""
	}

	l := []rune{}
	for _, r := range s {
		l = append(l, r)
	}

	l = l[:(length - n)]
	return string(l)
}

func Tick(t ...time.Time) int64 {
	if len(t) == 0 {
		return time.Now().UnixNano() / 1e6
	} else {
		return t[0].UnixNano() / 1e6
	}
}

func TickSec() int64 {
	return time.Now().Unix()
}

func TickHour() int64 {
	return time.Now().Unix() / 3600 * 3600
}

func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func ContainsInf(s []interface{}, e interface{}) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func ContainsInt(s []int, e int) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func IndexOf(s []string, e string) int {
	for i, a := range s {
		if a == e {
			return i
		}
	}
	return -1
}

func IndexOfInf(s []interface{}, e interface{}) int {
	for i, a := range s {
		if a == e {
			return i
		}
	}
	return -1
}

func IndexOfInt(s []int, e int) int {
	for i, a := range s {
		if a == e {
			return i
		}
	}
	return -1
}

func Millis(fmt string, timeStr string) (int64, error) {
	data, err := time.Parse(fmt, timeStr)
	if err != nil {
		return 0, err
	}
	return data.UnixNano() / 1e6, nil
}

func Md5(b []byte) []byte {
	h := md5.New()
	h.Write(b)
	return h.Sum(nil)
}

// parse form into J
func F2j(r *http.Request) J {
	r.ParseForm()
	j := J{}
	for k, v := range r.Form {
		if len(v) == 1 {
			if len(v[0]) > 0 {
				j[k] = v[0]
			}
		} else {
			j[k] = v
		}
	}
	return j
}

func Fint64(s interface{}, dft ...int64) int64 {
	var i int64
	var err error
	if s == nil {
		if len(dft) > 0 {
			return dft[0]
		} else {
			s = "0"
		}
	}
	i, err = strconv.ParseInt(s.(string), 10, 64)
	if err != nil && len(dft) > 0 {
		i = dft[0]
	}
	return i
}

func Fint(s interface{}, dft ...int64) int {
	if len(dft) > 0 {
		return int(Fint64(s, dft[0]))
	} else {
		return int(Fint64(s))
	}
}

func DeleteMap(m map[string]interface{}, ks ...string) {
	for _, v := range ks {
		delete(m, v)
	}
}

func IsPemExpire(b []byte) (bool, error) {
	block, _ := pem.Decode(b)
	if block == nil {
		return false, errors.New("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return false, err
	}
	return cert.NotAfter.Before(time.Now()), nil
}

func Shuffle(src []string) []string {
	dest := make([]string, len(src))
	perm := rand.Perm(len(src))
	for i, v := range perm {
		dest[v] = src[i]
	}
	return dest
}

func SendMail(user, password, host, to, subject, body, mailtype string) error {
	hp := strings.Split(host, ":")
	auth := smtp.PlainAuth("", user, password, hp[0])
	var content_type string
	if mailtype == "html" {
		content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
	} else {
		content_type = "Content-Type: text/plain" + "; charset=UTF-8"
	}

	msg := []byte("To: " + to + "\r\nFrom: " + user + "<" + user + ">\r\nSubject: " + subject + "\r\n" + content_type + "\r\n\r\n" + body)
	send_to := strings.Split(to, ";")
	err := smtp.SendMail(host, auth, user, send_to, msg)
	return err
}

func ParseAddr(s string) (string, int, error) {
	a := strings.Split(s, ":")
	if len(a) != 2 {
		return "", 0, fmt.Errorf("bad url %s", s)
	}
	port, err := strconv.Atoi(a[1])
	return a[0], port, err
}

func Unique(data []interface{}) []interface{} {
	m := map[interface{}]interface{}{}

	for _, d := range data {
		m[d] = "0"
	}

	l := []interface{}{}
	for key := range m {
		l = append(l, key)
	}
	return l
}

func UniqueStr(data []string) []string {
	m := map[string]string{}

	for _, d := range data {
		m[d] = "0"
	}

	l := []string{}
	for key := range m {
		l = append(l, key)
	}
	return l
}

//split a into several parts, no more than n
func SplitSlice(a []string, n int) [][]string {
	if len(a) < n || n == 1 {
		return [][]string{a}
	}

	result := make([][]string, n)
	for i, s := range a {
		idx := i % n
		result[idx] = append(result[idx], s)
	}
	return result
}

func IntToInf(src []int) []interface{} {
	result := []interface{}{}
	for _, v := range src {
		result = append(result, v)
	}
	return result
}

func StrToInf(src []string) []interface{} {
	result := []interface{}{}
	for _, v := range src {
		result = append(result, v)
	}
	return result
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
)

const (
	ZSDIR  = ".zs"
	PUBDIR = ".pub"
)

type EvalFn func(args []string, vars map[string]string) (string, error)

func split2(s, delim string) (string, string) {
	parts := strings.SplitN(s, delim, 2)
	if len(parts) == 2 {
		return parts[0], parts[1]
	} else {
		return parts[0], ""
	}
}

func md(path, s string) (map[string]string, string) {
	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
	v := map[string]string{
		"file":   path,
		"url":    url,
		"output": filepath.Join(PUBDIR, url),
		"layout": "index.html",
	}
	if strings.Index(s, "\n\n") == -1 {
		return map[string]string{}, s
	}
	header, body := split2(s, "\n\n")
	for _, line := range strings.Split(header, "\n") {
		key, value := split2(line, ":")
		v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
	}
	if strings.HasPrefix(v["url"], "./") {
		v["url"] = v["url"][2:]
	}
	return v, body
}

func render(s string, vars map[string]string, eval EvalFn) (string, error) {
	delim_open := "{{"
	delim_close := "}}"

	out := bytes.NewBuffer(nil)
	for {
		if from := strings.Index(s, delim_open); from == -1 {
			out.WriteString(s)
			return out.String(), nil
		} else {
			if to := strings.Index(s, delim_close); to == -1 {
				return "", fmt.Errorf("Close delim not found")
			} else {
				out.WriteString(s[:from])
				cmd := s[from+len(delim_open) : to]
				s = s[to+len(delim_close):]
				m := strings.Fields(cmd)
				if len(m) == 1 {
					if v, ok := vars[m[0]]; ok {
						out.WriteString(v)
						continue
					}
				}
				if res, err := eval(m, vars); err == nil {
					out.WriteString(res)
				} else {
					log.Println(err) // silent
				}
			}
		}
	}
}

func env(vars map[string]string) []string {
	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
	env = append(env, os.Environ()...)
	if vars != nil {
		for k, v := range vars {
			env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
		}
	}
	return env
}

func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
	var errbuf bytes.Buffer
	c := exec.Command(cmd, args...)
	c.Env = env(vars)
	c.Stdout = output
	c.Stderr = &errbuf

	err := c.Run()

	if errbuf.Len() > 0 {
		log.Println(errbuf.String())
	}

	if err != nil {
		return err
	}
	return nil
}

func eval(cmd []string, vars map[string]string) (string, error) {
	outbuf := bytes.NewBuffer(nil)
	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
	if err != nil {
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
		outbuf = bytes.NewBuffer(nil)
		err := run(cmd[0], cmd[1:], vars, outbuf)
		// Return exit errors, but ignore if the command was not found
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
	}
	return outbuf.String(), nil
}

func buildMarkdown(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	v, body := md(path, string(b))
	content, err := render(body, v, eval)
	if err != nil {
		return err
	}
	v["content"] = string(blackfriday.MarkdownBasic([]byte(content)))
	b, err = ioutil.ReadFile(filepath.Join(ZSDIR, v["layout"]))
	if err != nil {
		return err
	}
	content, err = render(string(b), v, eval)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(v["output"], []byte(content), 0666)
	if err != nil {
		return err
	}
	return nil
}

func copyFile(path string) (err error) {
	var in, out *os.File
	if in, err = os.Open(path); err == nil {
		defer in.Close()
		if out, err = os.Create(filepath.Join(PUBDIR, path)); err == nil {
			defer out.Close()
			_, err = io.Copy(out, in)
		}
	}
	return err
}

func buildAll(once bool) {
	lastModified := time.Unix(0, 0)
	modified := false
	for {
		os.Mkdir(PUBDIR, 0755)
		err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
			// ignore hidden files and directories
			if filepath.Base(path)[0] == '.' || strings.HasPrefix(path, ".") {
				return nil
			}

			if info.IsDir() {
				os.Mkdir(filepath.Join(PUBDIR, path), 0755)
				return nil
			} else if info.ModTime().After(lastModified) {
				if !modified {
					// About to be modified, so run pre-build hook
					run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil)
					modified = true
				}
				ext := filepath.Ext(path)
				if ext == ".md" || ext == "mkd" {
					log.Println("mkd: ", path)
					return buildMarkdown(path)
				} else {
					log.Println("raw: ", path)
					return copyFile(path)
				}
			}
			return nil
		})
		if err != nil {
			log.Println("ERROR:", err)
		}
		if modified {
			// Something was modified, so post-build hook
			run(filepath.Join(ZSDIR, "post"), []string{}, nil, nil)
			modified = false
		}
		lastModified = time.Now()
		if once {
			break
		}
		time.Sleep(1 * time.Second)
	}
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println(os.Args[0], "<command> [args]")
		return
	}
	cmd := os.Args[1]
	args := os.Args[2:]
	switch cmd {
	case "build":
		buildAll(true)
	case "watch":
		buildAll(false) // pass duration
	case "var":
		if len(args) == 0 {
			log.Println("ERROR: filename expected")
			return
		}
		if b, err := ioutil.ReadFile(args[0]); err == nil {
			vars, _ := md(args[0], string(b))
			if len(args) > 1 {
				for _, a := range args[1:] {
					fmt.Println(vars[a])
				}
			} else {
				for k, v := range vars {
					fmt.Println(k + ":" + v)
				}
			}
		} else {
			log.Println(err)
		}
	default:
		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
		if err != nil {
			log.Println(err)
		}
	}
}
<commit_msg>fixed mkd extension typo<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/russross/blackfriday"
)

const (
	ZSDIR  = ".zs"
	PUBDIR = ".pub"
)

type EvalFn func(args []string, vars map[string]string) (string, error)

func split2(s, delim string) (string, string) {
	parts := strings.SplitN(s, delim, 2)
	if len(parts) == 2 {
		return parts[0], parts[1]
	} else {
		return parts[0], ""
	}
}

func md(path, s string) (map[string]string, string) {
	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
	v := map[string]string{
		"file":   path,
		"url":    url,
		"output": filepath.Join(PUBDIR, url),
		"layout": "index.html",
	}
	if strings.Index(s, "\n\n") == -1 {
		return map[string]string{}, s
	}
	header, body := split2(s, "\n\n")
	for _, line := range strings.Split(header, "\n") {
		key, value := split2(line, ":")
		v[strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
	}
	if strings.HasPrefix(v["url"], "./") {
		v["url"] = v["url"][2:]
	}
	return v, body
}

func render(s string, vars map[string]string, eval EvalFn) (string, error) {
	delim_open := "{{"
	delim_close := "}}"

	out := bytes.NewBuffer(nil)
	for {
		if from := strings.Index(s, delim_open); from == -1 {
			out.WriteString(s)
			return out.String(), nil
		} else {
			if to := strings.Index(s, delim_close); to == -1 {
				return "", fmt.Errorf("Close delim not found")
			} else {
				out.WriteString(s[:from])
				cmd := s[from+len(delim_open) : to]
				s = s[to+len(delim_close):]
				m := strings.Fields(cmd)
				if len(m) == 1 {
					if v, ok := vars[m[0]]; ok {
						out.WriteString(v)
						continue
					}
				}
				if res, err := eval(m, vars); err == nil {
					out.WriteString(res)
				} else {
					log.Println(err) // silent
				}
			}
		}
	}
}

func env(vars map[string]string) []string {
	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
	env = append(env, os.Environ()...)
	if vars != nil {
		for k, v := range vars {
			env = append(env, "ZS_"+strings.ToUpper(k)+"="+v)
		}
	}
	return env
}

func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
	var errbuf bytes.Buffer
	c := exec.Command(cmd, args...)
	c.Env = env(vars)
	c.Stdout = output
	c.Stderr = &errbuf

	err := c.Run()

	if errbuf.Len() > 0 {
		log.Println(errbuf.String())
	}

	if err != nil {
		return err
	}
	return nil
}

func eval(cmd []string, vars map[string]string) (string, error) {
	outbuf := bytes.NewBuffer(nil)
	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
	if err != nil {
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
		outbuf = bytes.NewBuffer(nil)
		err := run(cmd[0], cmd[1:], vars, outbuf)
		// Return exit errors, but ignore if the command was not found
		if _, ok := err.(*exec.ExitError); ok {
			return "", err
		}
	}
	return outbuf.String(), nil
}

func buildMarkdown(path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	v, body := md(path, string(b))
	content, err := render(body, v, eval)
	if err != nil {
		return err
	}
	v["content"] = string(blackfriday.MarkdownBasic([]byte(content)))
	b, err = ioutil.ReadFile(filepath.Join(ZSDIR, v["layout"]))
	if err != nil {
		return err
	}
	content, err = render(string(b), v, eval)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(v["output"], []byte(content), 0666)
	if err != nil {
		return err
	}
	return nil
}

func copyFile(path string) (err error) {
	var in, out *os.File
	if in, err = os.Open(path); err == nil {
		defer in.Close()
		if out, err = os.Create(filepath.Join(PUBDIR, path)); err == nil {
			defer out.Close()
			_, err = io.Copy(out, in)
		}
	}
	return err
}

func buildAll(once bool) {
	lastModified := time.Unix(0, 0)
	modified := false
	for {
		os.Mkdir(PUBDIR, 0755)
		err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
			// ignore hidden files and directories
			if filepath.Base(path)[0] == '.' || strings.HasPrefix(path, ".") {
				return nil
			}

			if info.IsDir() {
				os.Mkdir(filepath.Join(PUBDIR, path), 0755)
				return nil
			} else if info.ModTime().After(lastModified) {
				if !modified {
					// About to be modified, so run pre-build hook
					run(filepath.Join(ZSDIR, "pre"), []string{}, nil, nil)
					modified = true
				}
				ext := filepath.Ext(path)
				if ext == ".md" || ext == ".mkd" {
					log.Println("mkd: ", path)
					return buildMarkdown(path)
				} else {
					log.Println("raw: ", path)
					return copyFile(path)
				}
			}
			return nil
		})
		if err != nil {
			log.Println("ERROR:", err)
		}
		if modified {
			// Something was modified, so post-build hook
			run(filepath.Join(ZSDIR, "post"), []string{}, nil, nil)
			modified = false
		}
		lastModified = time.Now()
		if once {
			break
		}
		time.Sleep(1 * time.Second)
	}
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println(os.Args[0], "<command> [args]")
		return
	}
	cmd := os.Args[1]
	args := os.Args[2:]
	switch cmd {
	case "build":
		buildAll(true)
	case "watch":
		buildAll(false) // pass duration
	case "var":
		if len(args) == 0 {
			log.Println("ERROR: filename expected")
			return
		}
		if b, err := ioutil.ReadFile(args[0]); err == nil {
			vars, _ := md(args[0], string(b))
			if len(args) > 1 {
				for _, a := range args[1:] {
					fmt.Println(vars[a])
				}
			} else {
				for k, v := range vars {
					fmt.Println(k + ":" + v)
				}
			}
		} else {
			log.Println(err)
		}
	default:
		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
		if err != nil {
			log.Println(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	for _, d := range daysOfMonth(now) {
		sep := ""
		if now.Day() == d.Day() {
			sep = "*"
		}
		fmt.Printf("%s%d%s ", sep, d.Day(), sep)
	}
	fmt.Println()
}

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}
<commit_msg>Add basic ui<commit_after>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"time"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		now := time.Now()
		err := indexTmpl.Execute(w, map[string]interface{}{
			"Title": "900 words",

			"Now":  now,
			"Days": daysOfMonth(now),
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		}
	})
	http.ListenAndServe("localhost:12345", nil)
}

var indexTmpl = template.Must(template.New("index").Parse(`<!doctype html>

		<meta charset="utf-8" />
		<title>{{ .Title }}</title>

{{ .Title }}

			{{ $now := .Now }}
			{{ range $day := .Days -}}

{{ $day.Day }}

			{{ end }}

				<textarea id="editor"></textarea>

				Made with <3 by strange adventures.  /about

`))

func daysOfMonth(t time.Time) []time.Time {
	s := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
	e := s.AddDate(0, 1, 0)
	ts := make([]time.Time, 0, 31)
	for s.Before(e) {
		ts = append(ts, s)
		s = s.AddDate(0, 0, 1)
	}
	return ts
}
<|endoftext|>


<commit_before>package byteio

// ReadUintX reads an unsinged integer that was encoded using a variable number
// of bytes
func (e *LittleEndianReader) ReadUintX() (uint64, int, error) {
	var (
		n   int
		val uint64
	)
	for n < 9 {
		c, err := e.ReadByte()
		if err != nil {
			return 0, n, err
		}
		val |= uint64(c&0x7f) << uint(n*7)
		n++
		if c&0x80 == 0 {
			break
		}
	}
	return val, n, nil
}

// ReadIntX reads an integer that was encoded using a variable number of bytes
func (e *LittleEndianReader) ReadIntX() (int64, int, error) {
	i, n, err := e.ReadUintX()
	return unzigzag(i), n, err
}
<commit_msg>removed needless byte masking<commit_after>package byteio

// ReadUintX reads an unsinged integer that was encoded using a variable number
// of bytes
func (e *LittleEndianReader) ReadUintX() (uint64, int, error) {
	var (
		n   int
		val uint64
	)
	for n < 9 {
		c, err := e.ReadByte()
		if err != nil {
			return 0, n, err
		}
		val += uint64(c) << uint(n*7)
		n++
		if c&0x80 == 0 {
			break
		}
	}
	return val, n, nil
}

// ReadIntX reads an integer that was encoded using a variable number of bytes
func (e *LittleEndianReader) ReadIntX() (int64, int, error) {
	i, n, err := e.ReadUintX()
	return unzigzag(i), n, err
}
<|endoftext|>


<commit_before>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fetch

import (
	"encoding/json"
	"fmt"
	"net"
	"regexp"
	"strings"
	"time"
)

// LogItemHandler defines an object which is able to
// process individual LogRecord instances
type LogItemHandler interface {
	ProcItem(appType string, record *LogRecord)
}

func importDatetimeString(dateStr string, localTimezone string) (string, error) {
	rg := regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2})(\\s|T)([012]\\d:[0-5]\\d:[0-5]\\d\\.\\d+)")
	srch := rg.FindStringSubmatch(dateStr)
	if len(srch) > 0 {
		return fmt.Sprintf("%sT%s%s", srch[1], srch[3], localTimezone), nil
	}
	return "", fmt.Errorf("Failed to import datetime \"%s\"", dateStr)
}

// ImportJSONLog parses original JSON record with some
// additional value corrections.
func ImportJSONLog(jsonLine []byte, localTimezone string) (*LogRecord, error) {
	var record LogRecord
	err := json.Unmarshal(jsonLine, &record)
	if err != nil {
		return nil, err
	}
	dt, err := importDatetimeString(record.Date, localTimezone)
	if err != nil {
		return nil, err
	}
	record.Date = dt
	return &record, nil
}

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

// Request is a simple representation of
// HTTP request metadata used in KonText logging
type Request struct {
	HTTPForwardedFor string `json:"HTTP_X_FORWARDED_FOR"`
	HTTPUserAgent    string `json:"HTTP_USER_AGENT"`
	HTTPRemoteAddr   string `json:"HTTP_REMOTE_ADDR"`
	RemoteAddr       string `json:"REMOTE_ADDR"`
}

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

// LogRecord represents a parsed KonText record
type LogRecord struct {
	UserID   int                    `json:"user_id"`
	ProcTime float32                `json:"proc_time"`
	Date     string                 `json:"date"`
	Action   string                 `json:"action"`
	Request  Request                `json:"request"`
	Params   map[string]interface{} `json:"params"`
	PID      int                    `json:"pid"`
	Settings map[string]interface{} `json:"settings"`
}

// GetTime returns record's time as a Golang's Time
// instance. Please note that the value is truncated
// to seconds.
func (rec *LogRecord) GetTime() time.Time {
	p := regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2}T[012]\\d:[0-5]\\d:[0-5]\\d)\\.\\d+")
	srch := p.FindStringSubmatch(rec.Date)
	if srch != nil {
		if t, err := time.Parse("2006-01-02T15:04:05", srch[1]); err == nil {
			return t
		}
	}
	return time.Time{}
}

// GetClientIP returns a client IP no matter in which
// part of the record it was found
// (e.g. REMOTE_ADDR vs. HTTP_REMOTE_ADDR vs. HTTP_FORWARDED_FOR)
func (rec *LogRecord) GetClientIP() net.IP {
	if rec.Request.HTTPForwardedFor != "" {
		return net.ParseIP(rec.Request.HTTPForwardedFor)

	} else if rec.Request.HTTPRemoteAddr != "" {
		return net.ParseIP(rec.Request.HTTPRemoteAddr)

	} else if rec.Request.RemoteAddr != "" {
		return net.ParseIP(rec.Request.RemoteAddr)
	}
	return make([]byte, 0)
}

// AgentIsBot returns true if user agent information suggests
// that the client is not human. The rules are currently
// hardcoded and quite simple.
func (rec *LogRecord) AgentIsBot() bool {
	agentStr := strings.ToLower(rec.Request.HTTPUserAgent)
	return strings.Index(agentStr, "googlebot") > -1 ||
		strings.Index(agentStr, "ahrefsbot") > -1 ||
		strings.Index(agentStr, "yandexbot") > -1 ||
		strings.Index(agentStr, "yahoo") > -1 && strings.Index(agentStr, "slurp") > -1 ||
		strings.Index(agentStr, "baiduspider") > -1 ||
		strings.Index(agentStr, "seznambot") > -1 ||
		strings.Index(agentStr, "bingbot") > -1 ||
		strings.Index(agentStr, "megaindex.ru") > -1 ||
		strings.Index(agentStr, "duckduckbot") > -1 ||
		strings.Index(agentStr, "ia_archiver") > -1
}

// AgentIsMonitor returns true if user agent information
// matches one of "bots" used by the Instatute Czech National Corpus
// to monitor service availability. The rules are currently
// hardcoded.
func (rec *LogRecord) AgentIsMonitor() bool {
	agentStr := strings.ToLower(rec.Request.HTTPUserAgent)
	return strings.Index(agentStr, "python-urllib/2.7") > -1 ||
		strings.Index(agentStr, "zabbix-test") > -1
}

// AgentIsLoggable returns true if the current record
// is determined to be saved (we ignore bots, monitors etc.).
func (rec *LogRecord) AgentIsLoggable() bool {
	return !rec.AgentIsBot() && !rec.AgentIsMonitor()
}

// GetStringParam fetches a string parameter from
// a special "params" sub-object
func (rec *LogRecord) GetStringParam(name string) string {
	switch v := rec.Params[name].(type) {
	case string:
		return v
	}
	return ""
}

// GetIntParam fetches an integer parameter from
// a special "params" sub-object
func (rec *LogRecord) GetIntParam(name string) int {
	switch v := rec.Params[name].(type) {
	case int:
		return v
	}
	return -1
}

// GetAlignedCorpora fetches aligned corpora names from arguments
// found in record's "Params" attribute. It isolates
// user from miscellaneous idiosyncrasies of KonText/Bonito
// URL parameter handling (= it's not always that straightforward
// to detect aligned languages from raw URL).
func (rec *LogRecord) GetAlignedCorpora() []string {
	tmp := make(map[string]bool)
	for k := range rec.Params {
		if strings.HasPrefix(k, "queryselector_") {
			tmp[k[len("queryselector_"):]] = true
		}
		if strings.HasPrefix(k, "pcq_pos_neg_") {
			tmp[k[len("pcq_pos_neg_"):]] = true
		}
	}
	ans := make([]string, len(tmp))
	i := 0
	for k := range tmp {
		ans[i] = k
		i++
	}
	return ans
}
<commit_msg>Filter out more bots<commit_after>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fetch

import (
	"encoding/json"
	"fmt"
	"net"
	"regexp"
	"strings"
	"time"
)

// LogItemHandler defines an object which is able to
// process individual LogRecord instances
type LogItemHandler interface {
	ProcItem(appType string, record *LogRecord)
}

func importDatetimeString(dateStr string, localTimezone string) (string, error) {
	rg := regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2})(\\s|T)([012]\\d:[0-5]\\d:[0-5]\\d\\.\\d+)")
	srch := rg.FindStringSubmatch(dateStr)
	if len(srch) > 0 {
		return fmt.Sprintf("%sT%s%s", srch[1], srch[3], localTimezone), nil
	}
	return "", fmt.Errorf("Failed to import datetime \"%s\"", dateStr)
}

// ImportJSONLog parses original JSON record with some
// additional value corrections.
func ImportJSONLog(jsonLine []byte, localTimezone string) (*LogRecord, error) {
	var record LogRecord
	err := json.Unmarshal(jsonLine, &record)
	if err != nil {
		return nil, err
	}
	dt, err := importDatetimeString(record.Date, localTimezone)
	if err != nil {
		return nil, err
	}
	record.Date = dt
	return &record, nil
}

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

// Request is a simple representation of
// HTTP request metadata used in KonText logging
type Request struct {
	HTTPForwardedFor string `json:"HTTP_X_FORWARDED_FOR"`
	HTTPUserAgent    string `json:"HTTP_USER_AGENT"`
	HTTPRemoteAddr   string `json:"HTTP_REMOTE_ADDR"`
	RemoteAddr       string `json:"REMOTE_ADDR"`
}

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

// LogRecord represents a parsed KonText record
type LogRecord struct {
	UserID   int                    `json:"user_id"`
	ProcTime float32                `json:"proc_time"`
	Date     string                 `json:"date"`
	Action   string                 `json:"action"`
	Request  Request                `json:"request"`
	Params   map[string]interface{} `json:"params"`
	PID      int                    `json:"pid"`
	Settings map[string]interface{} `json:"settings"`
}

// GetTime returns record's time as a Golang's Time
// instance. Please note that the value is truncated
// to seconds.
func (rec *LogRecord) GetTime() time.Time {
	p := regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2}T[012]\\d:[0-5]\\d:[0-5]\\d)\\.\\d+")
	srch := p.FindStringSubmatch(rec.Date)
	if srch != nil {
		if t, err := time.Parse("2006-01-02T15:04:05", srch[1]); err == nil {
			return t
		}
	}
	return time.Time{}
}

// GetClientIP returns a client IP no matter in which
// part of the record it was found
// (e.g. REMOTE_ADDR vs. HTTP_REMOTE_ADDR vs. HTTP_FORWARDED_FOR)
func (rec *LogRecord) GetClientIP() net.IP {
	if rec.Request.HTTPForwardedFor != "" {
		return net.ParseIP(rec.Request.HTTPForwardedFor)

	} else if rec.Request.HTTPRemoteAddr != "" {
		return net.ParseIP(rec.Request.HTTPRemoteAddr)

	} else if rec.Request.RemoteAddr != "" {
		return net.ParseIP(rec.Request.RemoteAddr)
	}
	return make([]byte, 0)
}

// AgentIsBot returns true if user agent information suggests
// that the client is not human. The rules are currently
// hardcoded and quite simple.
func (rec *LogRecord) AgentIsBot() bool {
	agentStr := strings.ToLower(rec.Request.HTTPUserAgent)
	// TODO move this to some external file
	return strings.Index(agentStr, "ahrefsbot") > -1 ||
		strings.Index(agentStr, "applebot") > -1 ||
		strings.Index(agentStr, "baiduspider") > -1 ||
		strings.Index(agentStr, "bingbot") > -1 ||
		strings.Index(agentStr, "blexbot") > -1 ||
		strings.Index(agentStr, "dotbot") > -1 ||
		strings.Index(agentStr, "duckduckbot") > -1 ||
		strings.Index(agentStr, "exabot") > -1 ||
		strings.Index(agentStr, "googlebot") > -1 ||
		strings.Index(agentStr, "ia_archiver") > -1 ||
		strings.Index(agentStr, "mail.ru_bot") > -1 ||
		strings.Index(agentStr, "mauibot") > -1 ||
		strings.Index(agentStr, "mediatoolkitbot") > -1 ||
		strings.Index(agentStr, "megaindex.ru") > -1 ||
		strings.Index(agentStr, "mj12bot") > -1 ||
		strings.Index(agentStr, "semanticscholarbot") > -1 ||
		strings.Index(agentStr, "semrushbot") > -1 ||
		strings.Index(agentStr, "seokicks-robot") > -1 ||
		strings.Index(agentStr, "seznambot") > -1 ||
		strings.Index(agentStr, "yacybot") > -1 ||
		strings.Index(agentStr, "yahoo") > -1 && strings.Index(agentStr, "slurp") > -1 ||
		strings.Index(agentStr, "yandexbot") > -1
}

// AgentIsMonitor returns true if user agent information
// matches one of "bots" used by the Instatute Czech National Corpus
// to monitor service availability. The rules are currently
// hardcoded.
func (rec *LogRecord) AgentIsMonitor() bool {
	agentStr := strings.ToLower(rec.Request.HTTPUserAgent)
	return strings.Index(agentStr, "python-urllib/2.7") > -1 ||
		strings.Index(agentStr, "zabbix-test") > -1
}

// AgentIsLoggable returns true if the current record
// is determined to be saved (we ignore bots, monitors etc.).
func (rec *LogRecord) AgentIsLoggable() bool {
	return !rec.AgentIsBot() && !rec.AgentIsMonitor()
}

// GetStringParam fetches a string parameter from
// a special "params" sub-object
func (rec *LogRecord) GetStringParam(name string) string {
	switch v := rec.Params[name].(type) {
	case string:
		return v
	}
	return ""
}

// GetIntParam fetches an integer parameter from
// a special "params" sub-object
func (rec *LogRecord) GetIntParam(name string) int {
	switch v := rec.Params[name].(type) {
	case int:
		return v
	}
	return -1
}

// GetAlignedCorpora fetches aligned corpora names from arguments
// found in record's "Params" attribute. It isolates
// user from miscellaneous idiosyncrasies of KonText/Bonito
// URL parameter handling (= it's not always that straightforward
// to detect aligned languages from raw URL).
func (rec *LogRecord) GetAlignedCorpora() []string {
	tmp := make(map[string]bool)
	for k := range rec.Params {
		if strings.HasPrefix(k, "queryselector_") {
			tmp[k[len("queryselector_"):]] = true
		}
		if strings.HasPrefix(k, "pcq_pos_neg_") {
			tmp[k[len("pcq_pos_neg_"):]] = true
		}
	}
	ans := make([]string, len(tmp))
	i := 0
	for k := range tmp {
		ans[i] = k
		i++
	}
	return ans
}
<|endoftext|>


<commit_before>package java

import (
	"fmt"
	"io"
	"strings"

	"github.com/anchore/syft/internal/log"

	"github.com/anchore/syft/internal"
	"github.com/anchore/syft/internal/file"
	"github.com/anchore/syft/syft/cataloger/common"
	"github.com/anchore/syft/syft/pkg"
)

// integrity check
var _ common.ParserFn = parseJavaArchive

var archiveFormatGlobs = []string{
	"**/*.jar",
	"**/*.war",
	"**/*.ear",
	"**/*.jpi",
	"**/*.hpi",
}

type archiveParser struct {
	discoveredPkgs internal.StringSet
	fileManifest   file.ZipFileManifest
	virtualPath    string
	archivePath    string
	contentPath    string
	fileInfo       archiveFilename
	detectNested   bool
}

// parseJavaArchive is a parser function for java archive contents, returning all Java libraries and nested archives.
func parseJavaArchive(virtualPath string, reader io.Reader) ([]pkg.Package, error) {
	parser, cleanupFn, err := newJavaArchiveParser(virtualPath, reader, true)
	// note: even on error, we should always run cleanup functions
	defer cleanupFn()
	if err != nil {
		return nil, err
	}
	return parser.parse()
}

// uniquePkgKey creates a unique string to identify the given package.
func uniquePkgKey(p *pkg.Package) string {
	if p == nil {
		return ""
	}
	return fmt.Sprintf("%s|%s", p.Name, p.Version)
}

// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
// and parse nested archives or ignore them.
func newJavaArchiveParser(virtualPath string, reader io.Reader, detectNested bool) (*archiveParser, func(), error) {
	contentPath, archivePath, cleanupFn, err := saveArchiveToTmp(reader)
	if err != nil {
		return nil, cleanupFn, fmt.Errorf("unable to process java archive: %w", err)
	}

	fileManifest, err := file.NewZipFileManifest(archivePath)
	if err != nil {
		return nil, cleanupFn, fmt.Errorf("unable to read files from java archive: %w", err)
	}

	// fetch the last element of the virtual path
	virtualElements := strings.Split(virtualPath, ":")
	currentFilepath := virtualElements[len(virtualElements)-1]

	return &archiveParser{
		discoveredPkgs: internal.NewStringSet(),
		fileManifest:   fileManifest,
		virtualPath:    virtualPath,
		archivePath:    archivePath,
		contentPath:    contentPath,
		fileInfo:       newJavaArchiveFilename(currentFilepath),
		detectNested:   detectNested,
	}, cleanupFn, nil
}

// parse the loaded archive and return all packages found.
func (j *archiveParser) parse() ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)

	// find the parent package from the java manifest
	parentPkg, err := j.discoverMainPackage()
	if err != nil {
		return nil, fmt.Errorf("could not generate package from %s: %w", j.virtualPath, err)
	}

	// don't add the parent package yet, we still may discover aux info to add to the metadata (but still track it as added to prevent duplicates)
	parentKey := uniquePkgKey(parentPkg)
	if parentKey != "" {
		j.discoveredPkgs.Add(parentKey)
	}

	// find aux packages from pom.properties
	auxPkgs, err := j.discoverPkgsFromPomProperties(parentPkg)
	if err != nil {
		return nil, err
	}
	pkgs = append(pkgs, auxPkgs...)

	// find nested java archive packages
	nestedPkgs, err := j.discoverPkgsFromNestedArchives(parentPkg)
	if err != nil {
		return nil, err
	}
	pkgs = append(pkgs, nestedPkgs...)

	// lastly, add the parent package to the list (assuming the parent exists)
	if parentPkg != nil {
		// only the parent package gets the type, nested packages may be of a different package type (or not of a package type at all, since they may not be bundled)
		parentPkg.Type = j.fileInfo.pkgType()
		pkgs = append([]pkg.Package{*parentPkg}, pkgs...)
	}

	return pkgs, nil
}

// discoverMainPackage parses the root Java manifest used as the parent package to all discovered nested packages.
func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
	// search and parse java manifest files
	manifestMatches := j.fileManifest.GlobMatch(manifestGlob)
	if len(manifestMatches) > 1 {
		return nil, fmt.Errorf("found multiple manifests in the jar: %+v", manifestMatches)
	} else if len(manifestMatches) == 0 {
		// we did not find any manifests, but that may not be a problem (there may be other information to generate packages for)
		return nil, nil
	}

	// fetch the manifest file
	contents, err := file.ContentsFromZip(j.archivePath, manifestMatches...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract java manifests (%s): %w", j.virtualPath, err)
	}

	// parse the manifest file into a rich object
	manifestContents := contents[manifestMatches[0]]
	manifest, err := parseJavaManifest(j.archivePath, strings.NewReader(manifestContents))
	if err != nil {
		return nil, fmt.Errorf("failed to parse java manifest (%s): %w", j.virtualPath, err)
	}

	return &pkg.Package{
		Name:         selectName(manifest, j.fileInfo),
		Version:      selectVersion(manifest, j.fileInfo),
		Language:     pkg.Java,
		Type:         pkg.JavaPkg,
		MetadataType: pkg.JavaMetadataType,
		Metadata: pkg.JavaMetadata{
			VirtualPath: j.virtualPath,
			Manifest:    manifest,
		},
	}, nil
}

// discoverPkgsFromPomProperties parses Maven POM properties for a given parent package, returning all listed Java packages found and
// associating each discovered package to the given parent package.
// nolint:funlen,gocognit
func (j *archiveParser) discoverPkgsFromPomProperties(parentPkg *pkg.Package) ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)
	parentKey := uniquePkgKey(parentPkg)

	// search and parse pom.properties files & fetch the contents
	contents, err := file.ContentsFromZip(j.archivePath, j.fileManifest.GlobMatch(pomPropertiesGlob)...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract pom.properties: %w", err)
	}

	// parse the manifest file into a rich object
	for propsPath, propsContents := range contents {
		propsObj, err := parsePomProperties(propsPath, strings.NewReader(propsContents))
		if err != nil {
			return nil, fmt.Errorf("failed to parse pom.properties (%s): %w", j.virtualPath, err)
		}

		if propsObj != nil {
			if propsObj.Version != "" && propsObj.ArtifactID != "" {
				// TODO: if there is no parentPkg (no java manifest) one of these poms could be the parent. We should discover the right parent and attach the correct info accordingly to each discovered package

				// keep the artifact name within the virtual path if this package does not match the parent package
				vPathSuffix := ""
				if parentPkg != nil && !strings.HasPrefix(propsObj.ArtifactID, parentPkg.Name) {
					vPathSuffix += ":" + propsObj.ArtifactID
				}
				virtualPath := j.virtualPath + vPathSuffix

				// discovered props = new package
				p := pkg.Package{
					Name:         propsObj.ArtifactID,
					Version:      propsObj.Version,
					Language:     pkg.Java,
					Type:         pkg.JavaPkg,
					MetadataType: pkg.JavaMetadataType,
					Metadata: pkg.JavaMetadata{
						VirtualPath:   virtualPath,
						PomProperties: propsObj,
						Parent:        parentPkg,
					},
				}

				pkgKey := uniquePkgKey(&p)

				// the name/version pair matches...
				matchesParentPkg := pkgKey == parentKey

				if parentPkg != nil {
					// the virtual path matches...
					matchesParentPkg = matchesParentPkg || parentPkg.Metadata.(pkg.JavaMetadata).VirtualPath == virtualPath

					// the pom artifactId has the parent name or vice versa
					if propsObj.ArtifactID != "" {
						matchesParentPkg = matchesParentPkg || strings.Contains(parentPkg.Name, propsObj.ArtifactID) || strings.Contains(propsObj.ArtifactID, parentPkg.Name)
					}

					if matchesParentPkg {
						// we've run across more information about our parent package, add this info to the parent package metadata
						// the pom properties is typically a better source of information for name and version than the manifest
						if p.Name != parentPkg.Name {
							parentPkg.Name = p.Name
						}
						if p.Version != parentPkg.Version {
							parentPkg.Version = p.Version
						}

						parentMetadata, ok := parentPkg.Metadata.(pkg.JavaMetadata)
						if ok {
							parentMetadata.PomProperties = propsObj
							parentPkg.Metadata = parentMetadata
						}
					}
				}

				if !matchesParentPkg && !j.discoveredPkgs.Contains(pkgKey) {
					// only keep packages we haven't seen yet (and are not related to the parent package)
					pkgs = append(pkgs, p)
				}
			}
		}
	}
	return pkgs, nil
}

// discoverPkgsFromNestedArchives finds Java archives within Java archives, returning all listed Java packages found and
// associating each discovered package to the given parent package.
func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)

	if !j.detectNested {
		return pkgs, nil
	}

	// search and parse pom.properties files & fetch the contents
	openers, err := file.ExtractFromZipToUniqueTempFile(j.archivePath, j.contentPath, j.fileManifest.GlobMatch(archiveFormatGlobs...)...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract files from zip: %w", err)
	}

	// discover nested artifacts
	for archivePath, archiveOpener := range openers {
		archiveReadCloser, err := archiveOpener.Open()
		if err != nil {
			return nil, fmt.Errorf("unable to open archived file from tempdir: %w", err)
		}
		nestedPath := fmt.Sprintf("%s:%s", j.virtualPath, archivePath)
		nestedPkgs, err := parseJavaArchive(nestedPath, archiveReadCloser)
		if err != nil {
			if closeErr := archiveReadCloser.Close(); closeErr != nil {
				log.Warnf("unable to close archived file from tempdir: %+v", closeErr)
			}
			return nil, fmt.Errorf("unable to process nested java archive (%s): %w", archivePath, err)
		}
		if err = archiveReadCloser.Close(); err != nil {
			return nil, fmt.Errorf("unable to close archived file from tempdir: %w", err)
		}

		// attach the parent package to all discovered packages that are not already associated with a java archive
		for _, p := range nestedPkgs {
			if metadata, ok := p.Metadata.(pkg.JavaMetadata); ok {
				if metadata.Parent == nil {
					metadata.Parent = parentPkg
				}
				p.Metadata = metadata
			}
			pkgs = append(pkgs, p)
		}
	}

	return pkgs, nil
}
<commit_msg>Invert if statement to reduce nesting in archive parser<commit_after>package java

import (
	"fmt"
	"io"
	"strings"

	"github.com/anchore/syft/internal/log"

	"github.com/anchore/syft/internal"
	"github.com/anchore/syft/internal/file"
	"github.com/anchore/syft/syft/cataloger/common"
	"github.com/anchore/syft/syft/pkg"
)

// integrity check
var _ common.ParserFn = parseJavaArchive

var archiveFormatGlobs = []string{
	"**/*.jar",
	"**/*.war",
	"**/*.ear",
	"**/*.jpi",
	"**/*.hpi",
}

type archiveParser struct {
	discoveredPkgs internal.StringSet
	fileManifest   file.ZipFileManifest
	virtualPath    string
	archivePath    string
	contentPath    string
	fileInfo       archiveFilename
	detectNested   bool
}

// parseJavaArchive is a parser function for java archive contents, returning all Java libraries and nested archives.
func parseJavaArchive(virtualPath string, reader io.Reader) ([]pkg.Package, error) {
	parser, cleanupFn, err := newJavaArchiveParser(virtualPath, reader, true)
	// note: even on error, we should always run cleanup functions
	defer cleanupFn()
	if err != nil {
		return nil, err
	}
	return parser.parse()
}

// uniquePkgKey creates a unique string to identify the given package.
func uniquePkgKey(p *pkg.Package) string {
	if p == nil {
		return ""
	}
	return fmt.Sprintf("%s|%s", p.Name, p.Version)
}

// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
// and parse nested archives or ignore them.
func newJavaArchiveParser(virtualPath string, reader io.Reader, detectNested bool) (*archiveParser, func(), error) {
	contentPath, archivePath, cleanupFn, err := saveArchiveToTmp(reader)
	if err != nil {
		return nil, cleanupFn, fmt.Errorf("unable to process java archive: %w", err)
	}

	fileManifest, err := file.NewZipFileManifest(archivePath)
	if err != nil {
		return nil, cleanupFn, fmt.Errorf("unable to read files from java archive: %w", err)
	}

	// fetch the last element of the virtual path
	virtualElements := strings.Split(virtualPath, ":")
	currentFilepath := virtualElements[len(virtualElements)-1]

	return &archiveParser{
		discoveredPkgs: internal.NewStringSet(),
		fileManifest:   fileManifest,
		virtualPath:    virtualPath,
		archivePath:    archivePath,
		contentPath:    contentPath,
		fileInfo:       newJavaArchiveFilename(currentFilepath),
		detectNested:   detectNested,
	}, cleanupFn, nil
}

// parse the loaded archive and return all packages found.
func (j *archiveParser) parse() ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)

	// find the parent package from the java manifest
	parentPkg, err := j.discoverMainPackage()
	if err != nil {
		return nil, fmt.Errorf("could not generate package from %s: %w", j.virtualPath, err)
	}

	// don't add the parent package yet, we still may discover aux info to add to the metadata (but still track it as added to prevent duplicates)
	parentKey := uniquePkgKey(parentPkg)
	if parentKey != "" {
		j.discoveredPkgs.Add(parentKey)
	}

	// find aux packages from pom.properties
	auxPkgs, err := j.discoverPkgsFromPomProperties(parentPkg)
	if err != nil {
		return nil, err
	}
	pkgs = append(pkgs, auxPkgs...)

	// find nested java archive packages
	nestedPkgs, err := j.discoverPkgsFromNestedArchives(parentPkg)
	if err != nil {
		return nil, err
	}
	pkgs = append(pkgs, nestedPkgs...)

	// lastly, add the parent package to the list (assuming the parent exists)
	if parentPkg != nil {
		// only the parent package gets the type, nested packages may be of a different package type (or not of a package type at all, since they may not be bundled)
		parentPkg.Type = j.fileInfo.pkgType()
		pkgs = append([]pkg.Package{*parentPkg}, pkgs...)
	}

	return pkgs, nil
}

// discoverMainPackage parses the root Java manifest used as the parent package to all discovered nested packages.
func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
	// search and parse java manifest files
	manifestMatches := j.fileManifest.GlobMatch(manifestGlob)
	if len(manifestMatches) > 1 {
		return nil, fmt.Errorf("found multiple manifests in the jar: %+v", manifestMatches)
	} else if len(manifestMatches) == 0 {
		// we did not find any manifests, but that may not be a problem (there may be other information to generate packages for)
		return nil, nil
	}

	// fetch the manifest file
	contents, err := file.ContentsFromZip(j.archivePath, manifestMatches...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract java manifests (%s): %w", j.virtualPath, err)
	}

	// parse the manifest file into a rich object
	manifestContents := contents[manifestMatches[0]]
	manifest, err := parseJavaManifest(j.archivePath, strings.NewReader(manifestContents))
	if err != nil {
		return nil, fmt.Errorf("failed to parse java manifest (%s): %w", j.virtualPath, err)
	}

	return &pkg.Package{
		Name:         selectName(manifest, j.fileInfo),
		Version:      selectVersion(manifest, j.fileInfo),
		Language:     pkg.Java,
		Type:         pkg.JavaPkg,
		MetadataType: pkg.JavaMetadataType,
		Metadata: pkg.JavaMetadata{
			VirtualPath: j.virtualPath,
			Manifest:    manifest,
		},
	}, nil
}

// discoverPkgsFromPomProperties parses Maven POM properties for a given parent package, returning all listed Java packages found and
// associating each discovered package to the given parent package.
// nolint:funlen,gocognit
func (j *archiveParser) discoverPkgsFromPomProperties(parentPkg *pkg.Package) ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)
	parentKey := uniquePkgKey(parentPkg)

	// search and parse pom.properties files & fetch the contents
	contents, err := file.ContentsFromZip(j.archivePath, j.fileManifest.GlobMatch(pomPropertiesGlob)...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract pom.properties: %w", err)
	}

	// parse the manifest file into a rich object
	for propsPath, propsContents := range contents {
		propsObj, err := parsePomProperties(propsPath, strings.NewReader(propsContents))
		if err != nil {
			return nil, fmt.Errorf("failed to parse pom.properties (%s): %w", j.virtualPath, err)
		}

		if propsObj == nil {
			continue
		}

		if propsObj.Version != "" && propsObj.ArtifactID != "" {
			// TODO: if there is no parentPkg (no java manifest) one of these poms could be the parent. We should discover the right parent and attach the correct info accordingly to each discovered package

			// keep the artifact name within the virtual path if this package does not match the parent package
			vPathSuffix := ""
			if parentPkg != nil && !strings.HasPrefix(propsObj.ArtifactID, parentPkg.Name) {
				vPathSuffix += ":" + propsObj.ArtifactID
			}
			virtualPath := j.virtualPath + vPathSuffix

			// discovered props = new package
			p := pkg.Package{
				Name:         propsObj.ArtifactID,
				Version:      propsObj.Version,
				Language:     pkg.Java,
				Type:         pkg.JavaPkg,
				MetadataType: pkg.JavaMetadataType,
				Metadata: pkg.JavaMetadata{
					VirtualPath:   virtualPath,
					PomProperties: propsObj,
					Parent:        parentPkg,
				},
			}

			pkgKey := uniquePkgKey(&p)

			// the name/version pair matches...
			matchesParentPkg := pkgKey == parentKey

			if parentPkg != nil {
				// the virtual path matches...
				matchesParentPkg = matchesParentPkg || parentPkg.Metadata.(pkg.JavaMetadata).VirtualPath == virtualPath

				// the pom artifactId has the parent name or vice versa
				if propsObj.ArtifactID != "" {
					matchesParentPkg = matchesParentPkg || strings.Contains(parentPkg.Name, propsObj.ArtifactID) || strings.Contains(propsObj.ArtifactID, parentPkg.Name)
				}

				if matchesParentPkg {
					// we've run across more information about our parent package, add this info to the parent package metadata
					// the pom properties is typically a better source of information for name and version than the manifest
					if p.Name != parentPkg.Name {
						parentPkg.Name = p.Name
					}
					if p.Version != parentPkg.Version {
						parentPkg.Version = p.Version
					}

					parentMetadata, ok := parentPkg.Metadata.(pkg.JavaMetadata)
					if ok {
						parentMetadata.PomProperties = propsObj
						parentPkg.Metadata = parentMetadata
					}
				}
			}

			if !matchesParentPkg && !j.discoveredPkgs.Contains(pkgKey) {
				// only keep packages we haven't seen yet (and are not related to the parent package)
				pkgs = append(pkgs, p)
			}
		}
	}
	return pkgs, nil
}

// discoverPkgsFromNestedArchives finds Java archives within Java archives, returning all listed Java packages found and
// associating each discovered package to the given parent package.
func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) ([]pkg.Package, error) {
	var pkgs = make([]pkg.Package, 0)

	if !j.detectNested {
		return pkgs, nil
	}

	// search and parse pom.properties files & fetch the contents
	openers, err := file.ExtractFromZipToUniqueTempFile(j.archivePath, j.contentPath, j.fileManifest.GlobMatch(archiveFormatGlobs...)...)
	if err != nil {
		return nil, fmt.Errorf("unable to extract files from zip: %w", err)
	}

	// discover nested artifacts
	for archivePath, archiveOpener := range openers {
		archiveReadCloser, err := archiveOpener.Open()
		if err != nil {
			return nil, fmt.Errorf("unable to open archived file from tempdir: %w", err)
		}
		nestedPath := fmt.Sprintf("%s:%s", j.virtualPath, archivePath)
		nestedPkgs, err := parseJavaArchive(nestedPath, archiveReadCloser)
		if err != nil {
			if closeErr := archiveReadCloser.Close(); closeErr != nil {
				log.Warnf("unable to close archived file from tempdir: %+v", closeErr)
			}
			return nil, fmt.Errorf("unable to process nested java archive (%s): %w", archivePath, err)
		}
		if err = archiveReadCloser.Close(); err != nil {
			return nil, fmt.Errorf("unable to close archived file from tempdir: %w", err)
		}

		// attach the parent package to all discovered packages that are not already associated with a java archive
		for _, p := range nestedPkgs {
			if metadata, ok := p.Metadata.(pkg.JavaMetadata); ok {
				if metadata.Parent == nil {
					metadata.Parent = parentPkg
				}
				p.Metadata = metadata
			}
			pkgs = append(pkgs, p)
		}
	}

	return pkgs, nil
}
<|endoftext|>


<commit_before>package filecache

import (
	"bytes"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	cache_dir = "src/cache"   // Cache directory
	expire    = 8 * time.Hour // Hours to keep the cache
)

func Set(key string, data interface{}) error {

	clean(key)

	file := "cache." + key + "." + strconv.FormatInt(time.Now().Add(expire).Unix(), 10)
	fpath := filepath.Join(cache_dir, file)

	serialized, err := serialize(data)
	if err != nil {
		return err
	}

	var fmutex sync.RWMutex

	fmutex.Lock()
	fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer fp.Close()

	if _, err = fp.Write(serialized); err != nil {
		return err
	}
	defer fmutex.Unlock()

	return nil
}

func Get(key string, dst interface{}) error {

	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, err := filepath.Glob(pattern)
	if len(files) == 0 || err != nil {
		return errors.New("filecache: no cache file found")
	}

	if _, err := os.Stat(files[0]); err != nil {
		return err
	}

	fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()

	buf := make([]byte, 128)
	var serialized []byte
	for {
		_, err := fp.Read(buf)
		if err != nil || err == io.EOF {
			break
		}
		serialized = append(serialized, buf[0:]...)
	}

	if err := deserialize(serialized, dst); err != nil {
		return err
	}

	for _, file := range files {
		exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
		if err != nil {
			return err
		}

		if exptime < time.Now().Unix() {
			if _, err := os.Stat(file); err == nil {
				os.Remove(file)
			}
		}
	}

	log.Println("Accessing filecache: ", key)
	return nil
}

func clean(key string) {
	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, _ := filepath.Glob(pattern)
	for _, file := range files {
		if _, err := os.Stat(file); err == nil {
			os.Remove(file)
		}
	}
}

// serialize encodes a value using binary.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using binary.
func deserialize(src []byte, dst interface{}) error {
	buf := bytes.NewReader(src)
	if err := gob.NewDecoder(buf).Decode(dst); err != nil {
		log.Println(dst)
		return err
	}
	return nil
}
<commit_msg>Add filecache string, Other changes<commit_after>//Copyright 2014 Mahendra Kathirvel. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package filecache

import (
	"bytes"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	cache_dir = "src/cache"   // Cache directory
	expire    = 8 * time.Hour // Hours to keep the cache
)

func Set(key string, data interface{}) error {

	clean(key)

	file := "filecache." + key + "." + strconv.FormatInt(time.Now().Add(expire).Unix(), 10)
	fpath := filepath.Join(cache_dir, file)

	serialized, err := serialize(data)
	if err != nil {
		return err
	}

	var fmutex sync.RWMutex

	fmutex.Lock()
	fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer fp.Close()

	if _, err = fp.Write(serialized); err != nil {
		return err
	}
	defer fmutex.Unlock()

	return nil
}

func Get(key string, dst interface{}) error {

	pattern := filepath.Join(cache_dir, "filecache."+key+".*")
	files, err := filepath.Glob(pattern)
	if len(files) == 0 || err != nil {
		return errors.New("filecache: no cache file found")
	}

	if _, err := os.Stat(files[0]); err != nil {
		return err
	}

	fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()

	buf := make([]byte, 128)
	var serialized []byte
	for {
		_, err := fp.Read(buf)
		if err != nil || err == io.EOF {
			break
		}
		serialized = append(serialized, buf[0:]...)
	}

	if err := deserialize(serialized, dst); err != nil {
		return err
	}

	for _, file := range files {
		exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
		if err != nil {
			return err
		}

		if exptime < time.Now().Unix() {
			if _, err := os.Stat(file); err == nil {
				os.Remove(file)
			}
		}
	}

	log.Println("Accessing filecache: ", key)
	return nil
}

func clean(key string) {
	pattern := filepath.Join(cache_dir, "filecache."+key+".*")
	files, _ := filepath.Glob(pattern)
	for _, file := range files {
		if _, err := os.Stat(file); err == nil {
			os.Remove(file)
		}
	}
}

// serialize encodes a value using binary.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using binary.
func deserialize(src []byte, dst interface{}) error {
	buf := bytes.NewReader(src)
	if err := gob.NewDecoder(buf).Decode(dst); err != nil {
		log.Println(dst)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package library

import (
	"bytes"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	cache_dir = "src/cache"
	expire    = 8 * time.Hour // Hours to keep the cache
)

func SetCache(key string, data interface{}) error {

	clean(key)

	file := "cache." + key + "." + strconv.FormatInt(time.Now().Add(expire).Unix(), 10)
	fpath := filepath.Join(cache_dir, file)

	serialized, err := serialize(data)
	if err != nil {
		return err
	}

	var fmutex sync.RWMutex

	fmutex.Lock()
	fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer fp.Close()

	if _, err = fp.Write(serialized); err != nil {
		return err
	}
	defer fmutex.Unlock()

	return nil
}

func GetCache(key string, dst interface{}) error {

	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, err := filepath.Glob(pattern)
	if len(files) == 0 || err != nil {
		return errors.New("filecache: no cache file found")
	}

	if _, err := os.Stat(files[0]); err != nil {
		return err
	}

	fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()

	buf := make([]byte, 128)
	var serialized []byte
	for {
		_, err := fp.Read(buf)
		if err != nil || err == io.EOF {
			break
		}
		serialized = append(serialized, buf[0:]...)
	}

	if err := deserialize(serialized, dst); err != nil {
		return err
	}

	for _, file := range files {
		exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
		if err != nil {
			return err
		}

		if exptime < time.Now().Unix() {
			if _, err := os.Stat(file); err == nil {
				os.Remove(file)
			}
		}
	}

	log.Println("Accessing cache: ", key)
	return nil
}

func clean(key string) {
	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, _ := filepath.Glob(pattern)
	for _, file := range files {
		if _, err := os.Stat(file); err == nil {
			os.Remove(file)
		}
	}
}

// serialize encodes a value using binary.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// unserialize decodes a value using binary.
func deserialize(src []byte, dst interface{}) error {
	buf := bytes.NewReader(src)
	if err := gob.NewDecoder(buf).Decode(dst); err != nil {
		log.Println(dst)
		return err
	}
	return nil
}
<commit_msg>Method name change<commit_after>package library

import (
	"bytes"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	cache_dir = "src/cache"
	expire    = 8 * time.Hour // Hours to keep the cache
)

func Set(key string, data interface{}) error {

	clean(key)

	file := "cache." + key + "." + strconv.FormatInt(time.Now().Add(expire).Unix(), 10)
	fpath := filepath.Join(cache_dir, file)

	serialized, err := serialize(data)
	if err != nil {
		return err
	}

	var fmutex sync.RWMutex

	fmutex.Lock()
	fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer fp.Close()

	if _, err = fp.Write(serialized); err != nil {
		return err
	}
	defer fmutex.Unlock()

	return nil
}

func Get(key string, dst interface{}) error {

	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, err := filepath.Glob(pattern)
	if len(files) == 0 || err != nil {
		return errors.New("filecache: no cache file found")
	}

	if _, err := os.Stat(files[0]); err != nil {
		return err
	}

	fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
	if err != nil {
		return err
	}
	defer fp.Close()

	buf := make([]byte, 128)
	var serialized []byte
	for {
		_, err := fp.Read(buf)
		if err != nil || err == io.EOF {
			break
		}
		serialized = append(serialized, buf[0:]...)
	}

	if err := deserialize(serialized, dst); err != nil {
		return err
	}

	for _, file := range files {
		exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
		if err != nil {
			return err
		}

		if exptime < time.Now().Unix() {
			if _, err := os.Stat(file); err == nil {
				os.Remove(file)
			}
		}
	}

	log.Println("Accessing cache: ", key)
	return nil
}

func clean(key string) {
	pattern := filepath.Join(cache_dir, "cache."+key+".*")
	files, _ := filepath.Glob(pattern)
	for _, file := range files {
		if _, err := os.Stat(file); err == nil {
			os.Remove(file)
		}
	}
}

// serialize encodes a value using binary.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using binary.
func deserialize(src []byte, dst interface{}) error {
	buf := bytes.NewReader(src)
	if err := gob.NewDecoder(buf).Decode(dst); err != nil {
		log.Println(dst)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

import (
	"strings"
	"testing"
)

func substTestCase(t *testing.T, node *verbatim, expected string) {
	var result string

	for {
		result += node.text
		if node.next == nil {
			break
		}

		result += "[" + strings.Join(node.next.paramValues, ", ") + "]"

		node = &node.next.continuation
	}

	if result != expected {
		t.Error("Error: \"" + result + "\" != \"" + expected + "\"")
	}
}

func TestSubst(t *testing.T) {
	v := verbatim{"{Greetings}, {Who}!", nil}
	v.subst("Who", "Human")
	v.subst("Greetings", []string{"Hello", "Hi"})

	substTestCase(t, &v, "[Hello, Hi], Human!")

	v = verbatim{"{What}, {What} {Where}", nil}
	v.subst("What", "Mirror")
	v.subst("Where", "on the Wall")

	substTestCase(t, &v, "Mirror, Mirror on the Wall")
}
<commit_msg>Add a Println-based test of expandPathnameTemplate<commit_after>// Copyright (C) 2017 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

import (
	"fmt"
	"strings"
	"testing"
)

func substTestCase(t *testing.T, node *verbatim, expected string) {
	var result string

	for {
		result += node.text
		if node.next == nil {
			break
		}

		result += "[" + strings.Join(node.next.paramValues, ", ") + "]"

		node = &node.next.continuation
	}

	if result != expected {
		t.Error("Error: \"" + result + "\" != \"" + expected + "\"")
	}
}

func TestSubst(t *testing.T) {
	v := verbatim{"{Greetings}, {Who}!", nil}
	v.subst("Who", "Human")
	v.subst("Greetings", []string{"Hello", "Hi"})

	substTestCase(t, &v, "[Hello, Hi], Human!")

	v = verbatim{"{What}, {What} {Where}", nil}
	v.subst("What", "Mirror")
	v.subst("Where", "on the Wall")

	substTestCase(t, &v, "Mirror, Mirror on the Wall")
}

func TestExpandPathnameTemplate(t *testing.T) {
	fmt.Println(expandPathnameTemplate("{nil}{dir}/{name}.{ext}",
		map[string]interface{}{
			"nil":  []string{},
			"dir":  []string{"red", "blue", "yellow", "green"},
			"name": []string{"foo", "bar"},
			"ext":  []string{"js", "go", "rs"}}))
}
<|endoftext|>


<commit_before>// Package ppipwm allows to produce PWM signal using PPI, TIMER and GPIOTE
// peripherals.
package ppipwm

import (
	"nrf5/hal/gpio"
	"nrf5/hal/gpiote"
	"nrf5/hal/ppi"
	"nrf5/hal/timer"
)

// Toggle implementats three channel PWM usind GPIOTE OUT task configured in
// toggle mode. It is designed specifically for nRF51 chips because of
// limitations of their GPIOTE peripheral. Better solutions exists for nRF52.
//
// To produce desired PWM waveform Toggle configures a timer compare register,
// using simple algorithm, that usually generates glitches when used on working
// PWM channel. After that, PWM works without any CPU intervention and produces
// proper waveform until next duty cycle change. This is fine to drive LEDs but
// can cause trubles in case of receivers that rely on stable PWM frequency or
// phase (eg. some servos). Correct implementation is difficult and quite
// expensive in case of nRF51.
//
// Toggle cannot be used concurently by multiple gorutines without proper
// synchronisation.
type Toggle struct {
	t  *timer.Periph
	gc [3]gpiote.Chan
}

// MakeToggle returns configured Toggle implementation of PPI based PWM using
// timer t.
func MakeToggle(t *timer.Periph) Toggle {
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CLEAR).Trigger()
	t.StoreMODE(timer.TIMER)
	t.StoreBITMODE(timer.Bit16)
	t.StoreSHORTS(timer.COMPARE3_CLEAR)
	return Toggle{t: t}
}

// NewToggle provides convenient way to create heap allocated Toggle struct. See
// MakeToggle for more information.
func NewToggle(t *timer.Periph) *Toggle {
	pwm := new(Toggle)
	*pwm = MakeToggle(t)
	return pwm
}

// SetFreq sets timer prescaler to 2^log2pre and period to periodus microseconds
// (log2pre must be in range [0..9]). It allows to configure a duty cycle with
// a resolution = 16 * periodus / 2^log2pre. Toggle uses timer in 16-bit mode so
// the resolution must be <= 65536. SetFreq returns (resolution-1), which is a
// value that should be passed to SetDuty/SetInvDuty to produce PWM with 100%
// duty cycle.
func (pwm *Toggle) SetFreq(log2pre, periodus int) int {
	if uint(log2pre) > 9 {
		panic("pwm: bad prescaler")
	}
	if periodus < 1 {
		panic("pwm: bad period")
	}
	t := pwm.t
	t.StorePRESCALER(log2pre)
	div := uint32(1) << uint(log2pre)
	max := 16*uint32(periodus)/div - 1 // 16 MHz * period / div - 1
	if max > 0xFFFF {
		panic("pwm: max>0xFFFF")
	}
	t.StoreCC(3, max)
	return int(max)
}

// Max returns a value that corresponds to 100% PWM duty cycle. See SetFreq for
// more information.
func (pwm *Toggle) Max() int {
	return int(pwm.t.LoadCC(3))
}

func checkOutput(n int) {
	if uint(n) > 2 {
		panic("pwm: bad output")
	}
}

// Setup setups n-th of three PWM channels. Each PWM channel uses one GPIOTE
// channel and two PPI channels.
func (pwm *Toggle) Setup(n int, pin gpio.Pin, gc gpiote.Chan, pc0, pc1 ppi.Chan) {
	checkOutput(n)
	pin.Clear()
	pin.Setup(gpio.ModeOut)
	gc.Setup(pin, gpiote.ModeDiscon)
	pwm.gc[n] = gc
	t := pwm.t
	pc0.SetEEP(t.Event(timer.COMPARE(n)))
	pc0.SetTEP(gc.OUT().Task())
	pc0.Enable()
	pc1.SetEEP(t.Event(timer.COMPARE(3)))
	pc1.SetTEP(gc.OUT().Task())
	pc1.Enable()
}

// SetVal sets a duty cycle for n-th PWM channel.
func (pwm *Toggle) SetVal(n, val int) {
	checkOutput(n)
	gc := pwm.gc[n]
	t := pwm.t
	pin, _ := gc.Config()
	switch {
	case val <= 0:
		pin.Clear()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	case val >= pwm.Max():
		pin.Set()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	}
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CAPTURE(n)).Trigger()
	cfg := gpiote.ModeTask | gpiote.PolarityToggle
	if int(t.LoadCC(n)) < val {
		gc.Setup(pin, cfg|gpiote.OutInitHigh)
	} else {
		gc.Setup(pin, cfg|gpiote.OutInitLow)
	}
	t.StoreCC(n, uint32(val))
	t.Task(timer.START).Trigger()
}

// SetInvDuty sets a duty cycle for n-th PWM channel. It produces inverted
// waveform.
func (pwm *Toggle) SetInvVal(n, val int) {
	checkOutput(n)
	gc := pwm.gc[n]
	t := pwm.t
	pin, _ := gc.Config()
	switch {
	case val <= 0:
		pin.Set()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	case val >= pwm.Max():
		pin.Clear()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	}
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CAPTURE(n)).Trigger()
	cfg := gpiote.ModeTask | gpiote.PolarityToggle
	if int(t.LoadCC(n)) < val {
		gc.Setup(pin, cfg|gpiote.OutInitLow)
	} else {
		gc.Setup(pin, cfg|gpiote.OutInitHigh)
	}
	t.StoreCC(n, uint32(val))
	t.Task(timer.START).Trigger()
}
<commit_msg>nrf5/ppipwm: New SetVals, SetInvVals functions.<commit_after>// Package ppipwm allows to produce PWM signal using PPI, TIMER and GPIOTE
// peripherals.
package ppipwm

import (
	"nrf5/hal/gpio"
	"nrf5/hal/gpiote"
	"nrf5/hal/ppi"
	"nrf5/hal/timer"
)

// Toggle implementats three channel PWM usind GPIOTE OUT task configured in
// toggle mode. It is designed specifically for nRF51 chips because of
// limitations of their GPIOTE peripheral. Better solutions exists for nRF52.
//
// To produce desired PWM waveform Toggle configures a timer compare register,
// using simple algorithm, that usually generates glitches when used on working
// PWM channel. After that, PWM works without any CPU intervention and produces
// proper waveform until next duty cycle change. This is fine to drive LEDs but
// can cause trubles in case of receivers that rely on stable PWM frequency or
// phase (eg. some servos). Correct implementation is difficult and quite
// expensive in case of nRF51.
//
// Toggle cannot be used concurently by multiple gorutines without proper
// synchronisation.
type Toggle struct {
	t  *timer.Periph
	gc [3]gpiote.Chan
}

// MakeToggle returns configured Toggle implementation of PPI based PWM using
// timer t.
func MakeToggle(t *timer.Periph) Toggle {
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CLEAR).Trigger()
	t.StoreMODE(timer.TIMER)
	t.StoreBITMODE(timer.Bit16)
	t.StoreSHORTS(timer.COMPARE3_CLEAR)
	return Toggle{t: t}
}

// NewToggle provides convenient way to create heap allocated Toggle struct. See
// MakeToggle for more information.
func NewToggle(t *timer.Periph) *Toggle {
	pwm := new(Toggle)
	*pwm = MakeToggle(t)
	return pwm
}

// SetFreq sets timer prescaler to 2^log2pre and period to periodus microseconds
// (log2pre must be in range [0..9]). It allows to configure a duty cycle with
// a resolution = 16 * periodus / 2^log2pre. Toggle uses timer in 16-bit mode so
// the resolution must be <= 65536. SetFreq returns (resolution-1), which is a
// value that should be passed to SetDuty/SetInvDuty to produce PWM with 100%
// duty cycle.
func (pwm *Toggle) SetFreq(log2pre, periodus int) int {
	if uint(log2pre) > 9 {
		panic("pwm: bad prescaler")
	}
	if periodus < 1 {
		panic("pwm: bad period")
	}
	t := pwm.t
	t.StorePRESCALER(log2pre)
	div := uint32(1) << uint(log2pre)
	max := 16*uint32(periodus)/div - 1 // 16 MHz * period / div - 1
	if max > 0xFFFF {
		panic("pwm: max>0xFFFF")
	}
	t.StoreCC(3, max)
	return int(max)
}

// Max returns a value that corresponds to 100% PWM duty cycle. See SetFreq for
// more information.
func (pwm *Toggle) Max() int {
	return int(pwm.t.LoadCC(3))
}

func checkOutput(n int) {
	if uint(n) > 2 {
		panic("pwm: bad output")
	}
}

// Setup setups n-th of three PWM channels. Each PWM channel uses one GPIOTE
// channel and two PPI channels.
func (pwm *Toggle) Setup(n int, pin gpio.Pin, gc gpiote.Chan, pc0, pc1 ppi.Chan) {
	checkOutput(n)
	pin.Clear()
	pin.Setup(gpio.ModeOut)
	gc.Setup(pin, gpiote.ModeDiscon)
	pwm.gc[n] = gc
	t := pwm.t
	pc0.SetEEP(t.Event(timer.COMPARE(n)))
	pc0.SetTEP(gc.OUT().Task())
	pc0.Enable()
	pc1.SetEEP(t.Event(timer.COMPARE(3)))
	pc1.SetTEP(gc.OUT().Task())
	pc1.Enable()
}

// SetVal sets a duty cycle for n-th PWM channel. If val>0 or val<pwm.Max() it
// temporarily stops the PWM timer (this affects other two PWM channels too).
func (pwm *Toggle) SetVal(n, val int) {
	checkOutput(n)
	gc := pwm.gc[n]
	t := pwm.t
	pin, _ := gc.Config()
	switch {
	case val <= 0:
		pin.Clear()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	case val >= pwm.Max():
		pin.Set()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	}
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CAPTURE(n)).Trigger()
	cfg := gpiote.ModeTask | gpiote.PolarityToggle
	if int(t.LoadCC(n)) < val {
		gc.Setup(pin, cfg|gpiote.OutInitHigh)
	} else {
		gc.Setup(pin, cfg|gpiote.OutInitLow)
	}
	t.StoreCC(n, uint32(val))
	t.Task(timer.START).Trigger()
}

// SetInvVal works like SetVal but produces inverted waveform.
func (pwm *Toggle) SetInvVal(n, val int) {
	checkOutput(n)
	gc := pwm.gc[n]
	t := pwm.t
	pin, _ := gc.Config()
	switch {
	case val <= 0:
		pin.Set()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	case val >= pwm.Max():
		pin.Clear()
		gc.Setup(pin, gpiote.ModeDiscon)
		return
	}
	t.Task(timer.STOP).Trigger()
	t.Task(timer.CAPTURE(n)).Trigger()
	cfg := gpiote.ModeTask | gpiote.PolarityToggle
	if int(t.LoadCC(n)) < val {
		gc.Setup(pin, cfg|gpiote.OutInitLow)
	} else {
		gc.Setup(pin, cfg|gpiote.OutInitHigh)
	}
	t.StoreCC(n, uint32(val))
	t.Task(timer.START).Trigger()
}

// SetVals sets a duty cycle for PWM channels specifid by mask. If used for more
// than one channel, it minimizes the number of times the PWM timer is stopped
// and started, so should produce less glitches.
func (pwm *Toggle) SetVals(mask uint32, val0, val1, val2 int) {
	t := pwm.t
	t.Task(timer.STOP).Trigger()
	for n, val := range [...]int{val0, val1, val2} {
		if mask&1 != 0 {
			gc := pwm.gc[n]
			pin, _ := gc.Config()
			switch {
			case val <= 0:
				pin.Clear()
				gc.Setup(pin, gpiote.ModeDiscon)
			case val >= pwm.Max():
				pin.Set()
				gc.Setup(pin, gpiote.ModeDiscon)
			default:
				t.Task(timer.CAPTURE(n)).Trigger()
				cfg := gpiote.ModeTask | gpiote.PolarityToggle
				if int(t.LoadCC(n)) < val {
					gc.Setup(pin, cfg|gpiote.OutInitHigh)
				} else {
					gc.Setup(pin, cfg|gpiote.OutInitLow)
				}
				t.StoreCC(n, uint32(val))
			}
		}
		mask >>= 1
	}
	t.Task(timer.START).Trigger()
}

// SetInvVals works like SetVals but produces inverted waveform.
func (pwm *Toggle) SetInvVals(mask uint32, val0, val1, val2 int) {
	t := pwm.t
	t.Task(timer.STOP).Trigger()
	for n, val := range [...]int{val0, val1, val2} {
		if mask&1 != 0 {
			gc := pwm.gc[n]
			pin, _ := gc.Config()
			switch {
			case val <= 0:
				pin.Set()
				gc.Setup(pin, gpiote.ModeDiscon)
			case val >= pwm.Max():
				pin.Clear()
				gc.Setup(pin, gpiote.ModeDiscon)
			default:
				t.Task(timer.CAPTURE(n)).Trigger()
				cfg := gpiote.ModeTask | gpiote.PolarityToggle
				if int(t.LoadCC(n)) < val {
					gc.Setup(pin, cfg|gpiote.OutInitLow)
				} else {
					gc.Setup(pin, cfg|gpiote.OutInitHigh)
				}
				t.StoreCC(n, uint32(val))
			}
		}
		mask >>= 1
	}
	t.Task(timer.START).Trigger()
}
<|endoftext|>


<commit_before>package main

import (
	_ "github.com/spakin/netpbm"
	"image"
	"os"
)

func main() {
	file, err := os.Open("testi.pbm")
	if err != nil {
		panic(err)
	}
	imgfile, str, err := image.Decode(file)
	bound := imgfile.Bounds()
	if str == "pbm" {
		if bound.Max.X == 106 && bound.Max.Y == 17 {
			for x := 0; x < 106; x = x + 1 {
				for y := 0; y < 17; y = y + 1 {
					b, _, _, _ := imgfile.At(x, y).RGBA()
					if b == 0 {
						print(0)
					} else {
						print(1)
					}
				}
				println()
			}
		} else {
			println("Image dimensions must be 106x17.")
			os.Exit(1)
		}
	} else {
		println("Image must be in pbm format.")
		os.Exit(2)
	}
}
<commit_msg>print the image right way<commit_after>package main

import (
	_ "github.com/spakin/netpbm"
	"image"
	"os"
)

func main() {
	file, err := os.Open("testi.pbm")
	if err != nil {
		panic(err)
	}
	imgfile, str, err := image.Decode(file)
	bound := imgfile.Bounds()
	if str == "pbm" {
		if bound.Max.X == 106 && bound.Max.Y == 17 {
			for y := 0; y < 17; y = y + 1 {
				for x := 0; x < 106; x = x + 1 {
					b, _, _, _ := imgfile.At(x, y).RGBA()
					if b == 0 {
						print(0)
					} else {
						print(1)
					}
				}
				println()
			}
		} else {
			println("Image dimensions must be 106x17.")
			os.Exit(1)
		}
	} else {
		println("Image must be in pbm format.")
		os.Exit(2)
	}
}
<|endoftext|>


<commit_before>package smpp34

import "strconv"

type Field interface {
	Length() interface{}
	Value() interface{}
	String() string
	ByteArray() []byte
}

type VariableField struct {
	value []byte
}

type FixedField struct {
	size  uint8
	value uint8
}

func NewField(f string, v interface{}) Field {
	switch f {
	case SOURCE_ADDR_TON, SOURCE_ADDR_NPI, DEST_ADDR_TON, DEST_ADDR_NPI, ESM_CLASS, PROTOCOL_ID, PRIORITY_FLAG, REGISTERED_DELIVERY, REPLACE_IF_PRESENT_FLAG, DATA_CODING, SM_DEFAULT_MSG_ID, INTERFACE_VERSION, ADDR_TON, ADDR_NPI, SM_LENGTH:
		return NewFixedField(uint8(v.(int)))
	case SERVICE_TYPE, SOURCE_ADDR, DESTINATION_ADDR, SCHEDULE_DELIVERY_TIME, VALIDITY_PERIOD, SYSTEM_ID, PASSWORD, SYSTEM_TYPE, ADDRESS_RANGE, MESSAGE_ID, SHORT_MESSAGE:
		return NewVariableField([]byte(v.(string)))
	}
	return nil
}

func NewVariableField(v []byte) Field {
	i := &VariableField{v}
	f := Field(i)
	return f
}

func NewFixedField(v uint8) Field {
	i := &FixedField{1, v}
	f := Field(i)
	return f
}

func (v *VariableField) Length() interface{} {
	l := len(v.value)
	return l
}

func (v *VariableField) Value() interface{} {
	return v.value
}

func (v *VariableField) String() string {
	return string(v.value)
}

func (v *VariableField) ByteArray() []byte {
	return v.value
}

func (f *FixedField) Length() interface{} {
	return uint8(1)
}

func (f *FixedField) Value() interface{} {
	return f.value
}

func (f *FixedField) String() string {
	return strconv.Itoa(int(f.value))
}

func (f *FixedField) ByteArray() []byte {
	return packUi8(f.value)
}
<commit_msg>fixed var size fields to byte array<commit_after>package smpp34

import "strconv"

type Field interface {
	Length() interface{}
	Value() interface{}
	String() string
	ByteArray() []byte
}

type VariableField struct {
	value []byte
}

type FixedField struct {
	size  uint8
	value uint8
}

func NewField(f string, v interface{}) Field {
	switch f {
	case SOURCE_ADDR_TON, SOURCE_ADDR_NPI, DEST_ADDR_TON, DEST_ADDR_NPI, ESM_CLASS, PROTOCOL_ID, PRIORITY_FLAG, REGISTERED_DELIVERY, REPLACE_IF_PRESENT_FLAG, DATA_CODING, SM_DEFAULT_MSG_ID, INTERFACE_VERSION, ADDR_TON, ADDR_NPI, SM_LENGTH:
		return NewFixedField(uint8(v.(int)))
	case SERVICE_TYPE, SOURCE_ADDR, DESTINATION_ADDR, SCHEDULE_DELIVERY_TIME, VALIDITY_PERIOD, SYSTEM_ID, PASSWORD, SYSTEM_TYPE, ADDRESS_RANGE, MESSAGE_ID, SHORT_MESSAGE:
		return NewVariableField([]byte(v.(string)))
	}
	return nil
}

func NewVariableField(v []byte) Field {
	i := &VariableField{v}
	f := Field(i)
	return f
}

func NewFixedField(v uint8) Field {
	i := &FixedField{1, v}
	f := Field(i)
	return f
}

func (v *VariableField) Length() interface{} {
	l := len(v.value)
	return l
}

func (v *VariableField) Value() interface{} {
	return v.value
}

func (v *VariableField) String() string {
	return string(v.value)
}

func (v *VariableField) ByteArray() []byte {
	return append(v.value, 0x00)
}

func (f *FixedField) Length() interface{} {
	return uint8(1)
}

func (f *FixedField) Value() interface{} {
	return f.value
}

func (f *FixedField) String() string {
	return strconv.Itoa(int(f.value))
}

func (f *FixedField) ByteArray() []byte {
	return packUi8(f.value)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.96"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.63", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.97 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.97"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.64", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.111"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.78", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.112 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.112"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.79", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>