<commit_before>package gophermail

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/sloonz/go-qprintable"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"path/filepath"
	"strings"
)

// Message Lint: http://tools.ietf.org/tools/msglint/

const crlf = "\r\n"

var ErrMissingRecipient = errors.New("No recipient specified. At one To, Cc, or Bcc recipient is required.")
var ErrMissingFromAddress = errors.New("No from address specified.")

// A Message represents an email message.
// Addresses may be of any form permitted by RFC 5322.
type Message struct {
	// TODO(JPOEHLS): Add support for specifying the Sender header.

	// Technically this could be a list of addresses but we don't support that. See RFC 2822 s3.6.2.
	From mail.Address

	// Technically this could be a list of addresses but we don't support that. See RFC 2822 s3.6.2.
	ReplyTo mail.Address // optional

	To, Cc, Bcc []mail.Address

	Subject string // optional

	Body     string // optional
	HTMLBody string // optional

	Attachments []Attachment // optional

	// Extra mail headers.
	Headers mail.Header
}

// appendMailAddresses parses any number of addresses and appends them to a
// destination slice. If any of the addresses fail to parse, none of them are
// appended.
func appendMailAddresses(dest *[]mail.Address, addresses ...string) error {
	var parsedAddresses []mail.Address
	var err error

	for _, address := range addresses {
		parsed, err := mail.ParseAddress(address)
		if err != nil {
			return err
		}
		parsedAddresses = append(parsedAddresses, *parsed)
	}

	*dest = append(*dest, parsedAddresses...)
	return err
}

// setMailAddress parses an address and sets it to a destination mail address.
func setMailAddress(dest *mail.Address, address string) error {
	parsed, err := mail.ParseAddress(address)
	if err != nil {
		return err
	}
	*dest = *parsed
	return nil
}

// SetFrom creates a mail.Address and assigns it to the message's From
// field.
func (m *Message) SetFrom(address string) error {
	return setMailAddress(&m.From, address)
}

// SetReplyTo creates a mail.Address and assigns it to the message's ReplyTo
// field.
func (m *Message) SetReplyTo(address string) error {
	return setMailAddress(&m.ReplyTo, address)
}

// AddTo creates a mail.Address and adds it to the list of To addresses in the
// message
func (m *Message) AddTo(addresses ...string) error {
	return appendMailAddresses(&m.To, addresses...)
}

// AddCc creates a mail.Address and adds it to the list of Cc addresses in the
// message
func (m *Message) AddCc(addresses ...string) error {
	return appendMailAddresses(&m.Cc, addresses...)
}

// AddBcc creates a mail.Address and adds it to the list of Bcc addresses in the
// message
func (m *Message) AddBcc(addresses ...string) error {
	return appendMailAddresses(&m.Bcc, addresses...)
}

// An Attachment represents an email attachment.
type Attachment struct {
	// Name must be set to a valid file name.
	Name string

	// Optional.
	// Uses mime.TypeByExtension and falls back
	// to application/octet-stream if unknown.
	ContentType string

	Data io.Reader
}

// Bytes gets the encoded MIME message.
func (m *Message) Bytes() ([]byte, error) {
	var buffer = &bytes.Buffer{}

	header := textproto.MIMEHeader{}

	var err error

	// Require To, Cc, or Bcc
	// We'll parse the slices into a list of addresses
	// and then make sure that list isn't empty.
	toAddrs := getAddressListString(m.To)
	ccAddrs := getAddressListString(m.Cc)
	bccAddrs := getAddressListString(m.Bcc)

	var hasTo = toAddrs != ""
	var hasCc = ccAddrs != ""
	var hasBcc = bccAddrs != ""

	if !hasTo && !hasCc && !hasBcc {
		return nil, ErrMissingRecipient
	} else {
		if hasTo {
			header.Add("To", toAddrs)
		}
		if hasCc {
			header.Add("Cc", ccAddrs)
		}
		// BCC header is excluded on purpose.
		// BCC recipients aren't included in the message
		// headers and are only used at the SMTP level.
	}

	var emptyAddress mail.Address
	// Require From address
	if m.From == emptyAddress {
		return nil, ErrMissingFromAddress
	} else {
		header.Add("From", m.From.String())
	}

	// Optional ReplyTo
	if m.ReplyTo != emptyAddress {
		header.Add("Reply-To", m.ReplyTo.String())
	}

	// Optional Subject
	if m.Subject != "" {
		header.Add("Subject", qEncodeAndWrap(m.Subject, 9 /* len("Subject: ") */))
	}

	for k, v := range m.Headers {
		header[k] = v
	}

	// Top level multipart writer for our `multipart/mixed` body.
	mixedw := multipart.NewWriter(buffer)

	header.Add("MIME-Version", "1.0")
	header.Add("Content-Type", fmt.Sprintf("multipart/mixed;%s boundary=%s", crlf, mixedw.Boundary()))

	err = writeHeader(buffer, header)
	if err != nil {
		return nil, err
	}

	// Write the start of our `multipart/mixed` body.
	_, err = fmt.Fprintf(buffer, "--%s%s", mixedw.Boundary(), crlf)
	if err != nil {
		return nil, err
	}

	// Does the message have a body?
	if m.Body != "" || m.HTMLBody != "" {

		// Nested multipart writer for our `multipart/alternative` body.
		altw := multipart.NewWriter(buffer)

		header = textproto.MIMEHeader{}
		header.Add("Content-Type", fmt.Sprintf("multipart/alternative;%s boundary=%s", crlf, altw.Boundary()))
		err := writeHeader(buffer, header)
		if err != nil {
			return nil, err
		}

		if m.Body != "" {
			header = textproto.MIMEHeader{}
			header.Add("Content-Type", "text/plain; charset=utf-8")
			header.Add("Content-Transfer-Encoding", "quoted-printable")
			//header.Add("Content-Transfer-Encoding", "base64")

			partw, err := altw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			bodyBytes := []byte(m.Body)
			//encoder := NewBase64MimeEncoder(partw)
			encoder := qprintable.NewEncoder(qprintable.DetectEncoding(m.Body), partw)
			_, err = encoder.Write(bodyBytes)
			if err != nil {
				return nil, err
			}
			err = encoder.Close()
			if err != nil {
				return nil, err
			}
		}

		if m.HTMLBody != "" {
			header = textproto.MIMEHeader{}
			header.Add("Content-Type", "text/html; charset=utf-8")
			//header.Add("Content-Transfer-Encoding", "quoted-printable")
			header.Add("Content-Transfer-Encoding", "base64")

			partw, err := altw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			htmlBodyBytes := []byte(m.HTMLBody)
			encoder := NewBase64MimeEncoder(partw)
			//encoder := qprintable.NewEncoder(qprintable.DetectEncoding(m.HTMLBody), partw)
			_, err = encoder.Write(htmlBodyBytes)
			if err != nil {
				return nil, err
			}
			err = encoder.Close()
			if err != nil {
				return nil, err
			}
		}

		altw.Close()
	}

	if m.Attachments != nil && len(m.Attachments) > 0 {

		for _, attachment := range m.Attachments {

			contentType := attachment.ContentType
			if contentType == "" {
				contentType = mime.TypeByExtension(filepath.Ext(attachment.Name))
				if contentType == "" {
					contentType = "application/octet-stream"
				}
			}

			header := textproto.MIMEHeader{}
			header.Add("Content-Type", contentType)
			header.Add("Content-Disposition", fmt.Sprintf(`attachment;%s filename="%s"`, crlf, attachment.Name))
			header.Add("Content-Transfer-Encoding", "base64")

			attachmentPart, err := mixedw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			if attachment.Data != nil {
				encoder := NewBase64MimeEncoder(attachmentPart)
				_, err = io.Copy(encoder, attachment.Data)
				if err != nil {
					return nil, err
				}
				err = encoder.Close()
				if err != nil {
					return nil, err
				}
			}
		}

	}

	mixedw.Close()

	return buffer.Bytes(), nil
}

// writeHeader writes the specified MIMEHeader to the io.Writer.
// Header values will be trimmed but otherwise left alone.
// Headers with multiple values are not supported and will return an error.
func writeHeader(w io.Writer, header textproto.MIMEHeader) error {
	for k, vs := range header {
		_, err := fmt.Fprintf(w, "%s: ", k)
		if err != nil {
			return err
		}

		for i, v := range vs {
			v = textproto.TrimString(v)

			_, err := fmt.Fprintf(w, "%s", v)
			if err != nil {
				return err
			}

			if i < len(vs)-1 {
				return errors.New("Multiple header values are not supported.")
			}
		}

		_, err = fmt.Fprint(w, crlf)
		if err != nil {
			return err
		}
	}

	// Write a blank line as a spacer
	_, err := fmt.Fprint(w, crlf)
	if err != nil {
		return err
	}

	return nil
}

// qEncode encodes a string with Q encoding defined as an 'encoded-word' in RFC 2047.
// The maximum encoded word length of 75 characters is not accounted for.
// Use qEncodeAndWrap if you need that.
//
// Inspired by https://gist.github.com/andelf/5004821
func qEncode(input string) string {
	// use mail's rfc2047 to encode any string
	addr := mail.Address{input, ""}
	s := addr.String()
	return s[:len(s)-3]
}

// qEncodeAndWrap encodes the input as potentially multiple 'encoded-words'
// with CRLF SPACE line breaks between them to (as best as possible)
// guarantee that each encoded-word is no more than 75 characters
// and, padding included, each line is no longer than 76 characters.
// See RFC 2047 s2.
func qEncodeAndWrap(input string, padding int) string {

	// Split at any whitespace but prefer "; " or  ", " or " >" or "> " which
	// denotes a clear semantic break.
	// Remember that the qEncoded input isn't guaranteed to have the same
	// length as the unencoded input (obvious). Example: http://play.golang.org/p/dXA5IJnL22

	// Increase the padding to account for
	// the encoded-word 'envelop' tokens.
	// "?" charset (utf-8 is always assumed) "?" encoding "?" encoded-text "?="
	padding += 11

	// Tokenization included, the encoded word must not
	// be longer than 75 characters.
	const maxEncodedWordLength = 75

	var firstTry = qEncode(input)
	if len(firstTry) > maxEncodedWordLength-padding {

		// TODO(JPOEHLS): Implement an algorithm to break the input into multiple encoded-words.

		return firstTry
	} else {
		return firstTry
	}
}

// getAddressListString encodes a slice of email addresses into
// a string value suitable for a MIME header. Each address is
// Q encoded and wrapped onto its own line to help ensure that
// the header line doesn't cross the 78 character maximum.
func getAddressListString(addresses []mail.Address) string {
	var addressStrings []string

	for _, address := range addresses {
		addressStrings = append(addressStrings, address.String())
	}
	return strings.Join(addressStrings, ","+crlf+" ")
}
<commit_msg>dropped implicit else statements<commit_after>package gophermail

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/sloonz/go-qprintable"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"path/filepath"
	"strings"
)

// Message Lint: http://tools.ietf.org/tools/msglint/

const crlf = "\r\n"

var ErrMissingRecipient = errors.New("No recipient specified. At one To, Cc, or Bcc recipient is required.")
var ErrMissingFromAddress = errors.New("No from address specified.")

// A Message represents an email message.
// Addresses may be of any form permitted by RFC 5322.
type Message struct {
	// TODO(JPOEHLS): Add support for specifying the Sender header.

	// Technically this could be a list of addresses but we don't support that. See RFC 2822 s3.6.2.
	From mail.Address

	// Technically this could be a list of addresses but we don't support that. See RFC 2822 s3.6.2.
	ReplyTo mail.Address // optional

	To, Cc, Bcc []mail.Address

	Subject string // optional

	Body     string // optional
	HTMLBody string // optional

	Attachments []Attachment // optional

	// Extra mail headers.
	Headers mail.Header
}

// appendMailAddresses parses any number of addresses and appends them to a
// destination slice. If any of the addresses fail to parse, none of them are
// appended.
func appendMailAddresses(dest *[]mail.Address, addresses ...string) error {
	var parsedAddresses []mail.Address
	var err error

	for _, address := range addresses {
		parsed, err := mail.ParseAddress(address)
		if err != nil {
			return err
		}
		parsedAddresses = append(parsedAddresses, *parsed)
	}

	*dest = append(*dest, parsedAddresses...)
	return err
}

// setMailAddress parses an address and sets it to a destination mail address.
func setMailAddress(dest *mail.Address, address string) error {
	parsed, err := mail.ParseAddress(address)
	if err != nil {
		return err
	}
	*dest = *parsed
	return nil
}

// SetFrom creates a mail.Address and assigns it to the message's From
// field.
func (m *Message) SetFrom(address string) error {
	return setMailAddress(&m.From, address)
}

// SetReplyTo creates a mail.Address and assigns it to the message's ReplyTo
// field.
func (m *Message) SetReplyTo(address string) error {
	return setMailAddress(&m.ReplyTo, address)
}

// AddTo creates a mail.Address and adds it to the list of To addresses in the
// message
func (m *Message) AddTo(addresses ...string) error {
	return appendMailAddresses(&m.To, addresses...)
}

// AddCc creates a mail.Address and adds it to the list of Cc addresses in the
// message
func (m *Message) AddCc(addresses ...string) error {
	return appendMailAddresses(&m.Cc, addresses...)
}

// AddBcc creates a mail.Address and adds it to the list of Bcc addresses in the
// message
func (m *Message) AddBcc(addresses ...string) error {
	return appendMailAddresses(&m.Bcc, addresses...)
}

// An Attachment represents an email attachment.
type Attachment struct {
	// Name must be set to a valid file name.
	Name string

	// Optional.
	// Uses mime.TypeByExtension and falls back
	// to application/octet-stream if unknown.
	ContentType string

	Data io.Reader
}

// Bytes gets the encoded MIME message.
func (m *Message) Bytes() ([]byte, error) {
	var buffer = &bytes.Buffer{}

	header := textproto.MIMEHeader{}

	var err error

	// Require To, Cc, or Bcc
	// We'll parse the slices into a list of addresses
	// and then make sure that list isn't empty.
	toAddrs := getAddressListString(m.To)
	ccAddrs := getAddressListString(m.Cc)
	bccAddrs := getAddressListString(m.Bcc)

	var hasTo = toAddrs != ""
	var hasCc = ccAddrs != ""
	var hasBcc = bccAddrs != ""

	if !hasTo && !hasCc && !hasBcc {
		return nil, ErrMissingRecipient
	}

	if hasTo {
		header.Add("To", toAddrs)
	}
	if hasCc {
		header.Add("Cc", ccAddrs)
	}
	// BCC header is excluded on purpose.
	// BCC recipients aren't included in the message
	// headers and are only used at the SMTP level.

	var emptyAddress mail.Address
	// Require From address
	if m.From == emptyAddress {
		return nil, ErrMissingFromAddress
	}
	header.Add("From", m.From.String())

	// Optional ReplyTo
	if m.ReplyTo != emptyAddress {
		header.Add("Reply-To", m.ReplyTo.String())
	}

	// Optional Subject
	if m.Subject != "" {
		header.Add("Subject", qEncodeAndWrap(m.Subject, 9 /* len("Subject: ") */))
	}

	for k, v := range m.Headers {
		header[k] = v
	}

	// Top level multipart writer for our `multipart/mixed` body.
	mixedw := multipart.NewWriter(buffer)

	header.Add("MIME-Version", "1.0")
	header.Add("Content-Type", fmt.Sprintf("multipart/mixed;%s boundary=%s", crlf, mixedw.Boundary()))

	err = writeHeader(buffer, header)
	if err != nil {
		return nil, err
	}

	// Write the start of our `multipart/mixed` body.
	_, err = fmt.Fprintf(buffer, "--%s%s", mixedw.Boundary(), crlf)
	if err != nil {
		return nil, err
	}

	// Does the message have a body?
	if m.Body != "" || m.HTMLBody != "" {

		// Nested multipart writer for our `multipart/alternative` body.
		altw := multipart.NewWriter(buffer)

		header = textproto.MIMEHeader{}
		header.Add("Content-Type", fmt.Sprintf("multipart/alternative;%s boundary=%s", crlf, altw.Boundary()))
		err := writeHeader(buffer, header)
		if err != nil {
			return nil, err
		}

		if m.Body != "" {
			header = textproto.MIMEHeader{}
			header.Add("Content-Type", "text/plain; charset=utf-8")
			header.Add("Content-Transfer-Encoding", "quoted-printable")
			//header.Add("Content-Transfer-Encoding", "base64")

			partw, err := altw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			bodyBytes := []byte(m.Body)
			//encoder := NewBase64MimeEncoder(partw)
			encoder := qprintable.NewEncoder(qprintable.DetectEncoding(m.Body), partw)
			_, err = encoder.Write(bodyBytes)
			if err != nil {
				return nil, err
			}
			err = encoder.Close()
			if err != nil {
				return nil, err
			}
		}

		if m.HTMLBody != "" {
			header = textproto.MIMEHeader{}
			header.Add("Content-Type", "text/html; charset=utf-8")
			//header.Add("Content-Transfer-Encoding", "quoted-printable")
			header.Add("Content-Transfer-Encoding", "base64")

			partw, err := altw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			htmlBodyBytes := []byte(m.HTMLBody)
			encoder := NewBase64MimeEncoder(partw)
			//encoder := qprintable.NewEncoder(qprintable.DetectEncoding(m.HTMLBody), partw)
			_, err = encoder.Write(htmlBodyBytes)
			if err != nil {
				return nil, err
			}
			err = encoder.Close()
			if err != nil {
				return nil, err
			}
		}

		altw.Close()
	}

	if m.Attachments != nil && len(m.Attachments) > 0 {

		for _, attachment := range m.Attachments {

			contentType := attachment.ContentType
			if contentType == "" {
				contentType = mime.TypeByExtension(filepath.Ext(attachment.Name))
				if contentType == "" {
					contentType = "application/octet-stream"
				}
			}

			header := textproto.MIMEHeader{}
			header.Add("Content-Type", contentType)
			header.Add("Content-Disposition", fmt.Sprintf(`attachment;%s filename="%s"`, crlf, attachment.Name))
			header.Add("Content-Transfer-Encoding", "base64")

			attachmentPart, err := mixedw.CreatePart(header)
			if err != nil {
				return nil, err
			}

			if attachment.Data != nil {
				encoder := NewBase64MimeEncoder(attachmentPart)
				_, err = io.Copy(encoder, attachment.Data)
				if err != nil {
					return nil, err
				}
				err = encoder.Close()
				if err != nil {
					return nil, err
				}
			}
		}

	}

	mixedw.Close()

	return buffer.Bytes(), nil
}

// writeHeader writes the specified MIMEHeader to the io.Writer.
// Header values will be trimmed but otherwise left alone.
// Headers with multiple values are not supported and will return an error.
func writeHeader(w io.Writer, header textproto.MIMEHeader) error {
	for k, vs := range header {
		_, err := fmt.Fprintf(w, "%s: ", k)
		if err != nil {
			return err
		}

		for i, v := range vs {
			v = textproto.TrimString(v)

			_, err := fmt.Fprintf(w, "%s", v)
			if err != nil {
				return err
			}

			if i < len(vs)-1 {
				return errors.New("Multiple header values are not supported.")
			}
		}

		_, err = fmt.Fprint(w, crlf)
		if err != nil {
			return err
		}
	}

	// Write a blank line as a spacer
	_, err := fmt.Fprint(w, crlf)
	if err != nil {
		return err
	}

	return nil
}

// qEncode encodes a string with Q encoding defined as an 'encoded-word' in RFC 2047.
// The maximum encoded word length of 75 characters is not accounted for.
// Use qEncodeAndWrap if you need that.
//
// Inspired by https://gist.github.com/andelf/5004821
func qEncode(input string) string {
	// use mail's rfc2047 to encode any string
	addr := mail.Address{input, ""}
	s := addr.String()
	return s[:len(s)-3]
}

// qEncodeAndWrap encodes the input as potentially multiple 'encoded-words'
// with CRLF SPACE line breaks between them to (as best as possible)
// guarantee that each encoded-word is no more than 75 characters
// and, padding included, each line is no longer than 76 characters.
// See RFC 2047 s2.
func qEncodeAndWrap(input string, padding int) string {

	// Split at any whitespace but prefer "; " or  ", " or " >" or "> " which
	// denotes a clear semantic break.
	// Remember that the qEncoded input isn't guaranteed to have the same
	// length as the unencoded input (obvious). Example: http://play.golang.org/p/dXA5IJnL22

	// Increase the padding to account for
	// the encoded-word 'envelop' tokens.
	// "?" charset (utf-8 is always assumed) "?" encoding "?" encoded-text "?="
	padding += 11

	// Tokenization included, the encoded word must not
	// be longer than 75 characters.
	const maxEncodedWordLength = 75

	var firstTry = qEncode(input)
	if len(firstTry) > maxEncodedWordLength-padding {

		// TODO(JPOEHLS): Implement an algorithm to break the input into multiple encoded-words.

		return firstTry
	} else {
		return firstTry
	}
}

// getAddressListString encodes a slice of email addresses into
// a string value suitable for a MIME header. Each address is
// Q encoded and wrapped onto its own line to help ensure that
// the header line doesn't cross the 78 character maximum.
func getAddressListString(addresses []mail.Address) string {
	var addressStrings []string

	for _, address := range addresses {
		addressStrings = append(addressStrings, address.String())
	}
	return strings.Join(addressStrings, ","+crlf+" ")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/centralmarinsoccer/teams/handler"
	"github.com/centralmarinsoccer/teams/teamsnap"

	"net/http"
	"time"
	"github.com/centralmarinsoccer/teams/geocode"
)

const defaultPort = 8080
const urlPath = "/teams/"
const defaultInterval = 60

// Environment contains all of the required and optional environment variables
type Environment struct {
	Token           string
	Division        int
	URL             string
	RefreshInterval time.Duration
	GoogleAPIKey	string
}

func main() {
	// Make sure we have the appropriate environment variables
	var env Environment
	var ok bool
	if env, ok = ValidateEnvs(); !ok {
		os.Exit(-2)
	}

	// Create a geocoder
	geocoder := geocode.New(env.GoogleAPIKey)

	ts, err := teamsnap.New(&teamsnap.Configuration{
		Division:      env.Division,
		Token:         env.Token,
		Geocoder:  geocoder,
	})
	if err != nil {
		log.Printf("Failed to create a new TeamSnap. Error: %v\n", err)
		os.Exit(-1)
	}

	// create a channel to update TeamSnap data
	update := make(chan bool)

	// Setup our HTTP Server
	mux := http.NewServeMux()
	h, err := handler.New(ts, update)

	if err != nil {
		log.Printf("Handlers error: %v\n", err)
		os.Exit(-2)
	}

	mux.Handle(urlPath, h)
	mux.Handle("/metrics", prometheus.Handler()) // Add Metrics Handler

	log.Printf("Starting up server at %s%s with data refresh interval of %d for TeamSnap division %d\n", env.URL, urlPath, env.RefreshInterval, env.Division)

	ticker := time.NewTicker(env.RefreshInterval * time.Minute)
	go func() {
		for {
			select {
			case <- ticker.C:
				log.Println("Updating data")
				if ok := ts.Update(); ok {
					update <- true
					log.Println("Complete")
				} else {
					log.Println("Failed to update data")
				}
			}
		}
	}()

	http.ListenAndServe(env.URL, mux)

}

// ValidateEnvs checks to make sure the necessary environment variables are set
func ValidateEnvs() (Environment, bool) {

	var env Environment
	state := true

	// Required Parameters
	var ok bool
	if env.Division, ok = getEnvInt("DIVISION", 0, true); !ok {
		state = false
	}
	if env.Token, ok = getEnvString("TOKEN", "", true); !ok {
		state = false
	}

	var port int
	var domain string
	if port, ok = getEnvInt("PORT", defaultPort, false); !ok {
		state = false
	}
	if domain, ok = getEnvString("DOMAIN", "", false); !ok {
		state = false
	}

	if len(domain) != 0 {
		domain = "http://" + domain
	}
	env.URL = fmt.Sprintf("%s:%d", domain, port)

	var interval int
	if interval, ok = getEnvInt("REFRESHINTERVAL", defaultInterval, false); ok {
		env.RefreshInterval = time.Duration(interval)
	} else {
		state = false
	}

	if env.GoogleAPIKey, ok = getEnvString("GOOGLE_API_KEY", "", true); !ok {
		state = false
	}

	return env, state
}

func getEnvString(name string, defaultVal string, required bool) (string, bool) {
	val := os.Getenv(name)
	if val == "" {
		if required {
			log.Printf("Missing required environment variable '%s'\n", name)
			return "", false
		}
		return defaultVal, true
	}

	return val, true
}

func getEnvInt(name string, defaultVal int, required bool) (int, bool) {

	if val, ok := getEnvString(name, "", required); ok {
		if val == "" {
			return defaultVal, true
		}

		i, err := strconv.Atoi(val)
		if err != nil {
			log.Printf("%s's value %s is not an integer.\n", name, val)
			return -1, false
		}
		return i, true
	}

	return -1, false
}
<commit_msg>Added gorilla mux<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"net/http"
	"time"

	"github.com/centralmarinsoccer/teams/geocode"
	"github.com/centralmarinsoccer/teams/handler"
	"github.com/centralmarinsoccer/teams/teamsnap"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/gorilla/mux"
)

const defaultPort = 8080
const urlPath = "/teams/"
const defaultInterval = 60

// Environment contains all of the required and optional environment variables
type Environment struct {
	Token           string
	Division        int
	URL             string
	RefreshInterval time.Duration
	GoogleAPIKey	string
}

func main() {
	// Make sure we have the appropriate environment variables
	var env Environment
	var ok bool
	if env, ok = ValidateEnvs(); !ok {
		os.Exit(-2)
	}

	// Create a geocoder
	geocoder := geocode.New(env.GoogleAPIKey)

	ts, err := teamsnap.New(&teamsnap.Configuration{
		Division:      env.Division,
		Token:         env.Token,
		Geocoder:  geocoder,
	})
	if err != nil {
		log.Printf("Failed to create a new TeamSnap. Error: %v\n", err)
		os.Exit(-1)
	}

	// create a channel to update TeamSnap data
	update := make(chan bool)

	// Setup our HTTP Server
	h, err := handler.New(ts, update)
	if err != nil {
		log.Printf("Handlers error: %v\n", err)
		os.Exit(-2)
	}

	//mux.Handle(urlPath, h)
	//mux.Handle("/metrics", prometheus.Handler()) // Add Metrics Handler

	r := mux.NewRouter()
	r.HandleFunc("/teams/", h)
	r.Handle("/metrics", prometheus.Handler()) // Add Metrics Handler

	log.Printf("Starting up server at %s%s with data refresh interval of %d for TeamSnap division %d\n", env.URL, urlPath, env.RefreshInterval, env.Division)

	ticker := time.NewTicker(env.RefreshInterval * time.Minute)
	go func() {
		for {
			select {
			case <- ticker.C:
				log.Println("Updating data")
				if ok := ts.Update(); ok {
					update <- true
					log.Println("Complete")
				} else {
					log.Println("Failed to update data")
				}
			}
		}
	}()

//	http.ListenAndServe(env.URL, mux)
	http.ListenAndServe(env.URL, r)

}

// ValidateEnvs checks to make sure the necessary environment variables are set
func ValidateEnvs() (Environment, bool) {

	var env Environment
	state := true

	// Required Parameters
	var ok bool
	if env.Division, ok = getEnvInt("DIVISION", 0, true); !ok {
		state = false
	}
	if env.Token, ok = getEnvString("TOKEN", "", true); !ok {
		state = false
	}

	var port int
	var domain string
	if port, ok = getEnvInt("PORT", defaultPort, false); !ok {
		state = false
	}
	if domain, ok = getEnvString("DOMAIN", "", false); !ok {
		state = false
	}

	if len(domain) != 0 {
		domain = "http://" + domain
	}
	env.URL = fmt.Sprintf("%s:%d", domain, port)

	var interval int
	if interval, ok = getEnvInt("REFRESHINTERVAL", defaultInterval, false); ok {
		env.RefreshInterval = time.Duration(interval)
	} else {
		state = false
	}

	if env.GoogleAPIKey, ok = getEnvString("GOOGLE_API_KEY", "", true); !ok {
		state = false
	}

	return env, state
}

func getEnvString(name string, defaultVal string, required bool) (string, bool) {
	val := os.Getenv(name)
	if val == "" {
		if required {
			log.Printf("Missing required environment variable '%s'\n", name)
			return "", false
		}
		return defaultVal, true
	}

	return val, true
}

func getEnvInt(name string, defaultVal int, required bool) (int, bool) {

	if val, ok := getEnvString(name, "", required); ok {
		if val == "" {
			return defaultVal, true
		}

		i, err := strconv.Atoi(val)
		if err != nil {
			log.Printf("%s's value %s is not an integer.\n", name, val)
			return -1, false
		}
		return i, true
	}

	return -1, false
}
<|endoftext|>


<commit_before>package main

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

	"github.com/cloud66/habitus/build"
	"github.com/cloud66/habitus/configuration"
	"github.com/op/go-logging"

	"github.com/bugsnag/bugsnag-go"
)

var format = logging.MustStringFormatter(
	"%{color}▶ %{message} %{color:reset}",
)

var (
	flagLevel  string
	VERSION    string = "dev"
	BUILD_DATE string = ""
)

func init() {
	bugsnag.Configure(bugsnag.Configuration{
		APIKey:     "ba9d7ae6b333e27971d86e5bf7abe996",
		AppVersion: VERSION,
	})
}

func main() {
	args := os.Args[1:]
	defer bugsnag.AutoNotify()

	var log = logging.MustGetLogger("cxbuilder")
	logging.SetFormatter(format)

	config := configuration.CreateConfig()
	flag.StringVar(&config.Buildfile, "f", "build.yml", "Build file path. Defaults to build.yml in the workdir")
	flag.StringVar(&config.Workdir, "d", "", "work directory for this build. Defaults to the current directory")
	flag.BoolVar(&config.NoCache, "no-cache", false, "Use cache in build")
	flag.BoolVar(&config.SuppressOutput, "suppress", false, "Suppress build output")
	flag.BoolVar(&config.RmTmpContainers, "rm", true, "Remove intermediate containers")
	flag.BoolVar(&config.ForceRmTmpContainer, "force-rm", false, "Force remove intermediate containers")
	flag.StringVar(&config.UniqueID, "uid", "", "Unique ID for the build. Used only for multi-tenanted build environments")
	flag.StringVar(&flagLevel, "level", "debug", "Log level: debug, info, notice, warning, error and critical")
	flag.StringVar(&config.DockerHost, "host", os.Getenv("DOCKER_HOST"), "Docker host link. Uses DOCKER_HOST if missing")
	flag.StringVar(&config.DockerCert, "certs", os.Getenv("DOCKER_CERT_PATH"), "Docker cert folder. Uses DOCKER_CERT_PATH if missing")
	flag.Var(&config.EnvVars, "env", "Environment variables to be used during build. If empty cxbuild uses parent process environment variables")
	flag.BoolVar(&config.KeepSteps, "keep-steps", false, "Keep all stpes. Used for debugging each step")
	flag.BoolVar(&config.NoSquash, "no-cleanup", false, "Skip cleanup commands for this run. Used for debugging")
	flag.BoolVar(&config.FroceRmImages, "force-rmi", false, "Force remove of unwanted images")
	flag.BoolVar(&config.NoPruneRmImages, "noprune-rmi", false, "No pruning of unwanted images")

	config.Logger = *log

	flag.Parse()

	if len(args) > 0 && args[0] == "help" {
		fmt.Println("cxbuild - (c) 2015 Cloud 66 Inc.")
		flag.PrintDefaults()
		return
	}

	level, err := logging.LogLevel(flagLevel)
	if err != nil {
		fmt.Println("Invalid log level value. Falling back to debug")
		level = logging.DEBUG
	}
	logging.SetLevel(level, "cxbuilder")

	if config.Workdir == "" {
		if curr, err := os.Getwd(); err != nil {
			log.Fatal("Failed to get the current directory")
			os.Exit(1)
		} else {
			config.Workdir = curr
		}
	}

	if config.Buildfile == "build.yml" {
		config.Buildfile = filepath.Join(config.Workdir, "build.yml")
	}

	c, err := build.LoadBuildFromFile(&config)
	if err != nil {
		log.Fatalf("Failed: %s", err.Error())
	}

	if c.IsPrivileged && os.Getenv("SUDO_USER") == "" {
		log.Fatal("Some of the build steps require admin privileges (sudo). Please run with sudo\nYou might want to use --certs=$DOCKER_CERT_PATH --host=$DOCKER_HOST params to make sure all environment variables are available to the process")
		os.Exit(1)
	}

	b := build.NewBuilder(c, &config)
	err = b.StartBuild()
	if err != nil {
		log.Error("Error during build %s", err.Error())
	}
}
<commit_msg>added version flag<commit_after>package main

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

	"github.com/cloud66/habitus/build"
	"github.com/cloud66/habitus/configuration"
	"github.com/op/go-logging"

	"github.com/bugsnag/bugsnag-go"
)

var format = logging.MustStringFormatter(
	"%{color}▶ %{message} %{color:reset}",
)

var (
	flagLevel       string
	flagShowHelp    bool
	flagShowVersion bool
	VERSION         string = "dev"
	BUILD_DATE      string = ""
)

func init() {
	bugsnag.Configure(bugsnag.Configuration{
		APIKey:     "ba9d7ae6b333e27971d86e5bf7abe996",
		AppVersion: VERSION,
	})
}

func main() {
	args := os.Args[1:]
	defer bugsnag.AutoNotify()

	var log = logging.MustGetLogger("cxbuilder")
	logging.SetFormatter(format)

	config := configuration.CreateConfig()
	flag.StringVar(&config.Buildfile, "f", "build.yml", "Build file path. Defaults to build.yml in the workdir")
	flag.StringVar(&config.Workdir, "d", "", "work directory for this build. Defaults to the current directory")
	flag.BoolVar(&config.NoCache, "no-cache", false, "Use cache in build")
	flag.BoolVar(&config.SuppressOutput, "suppress", false, "Suppress build output")
	flag.BoolVar(&config.RmTmpContainers, "rm", true, "Remove intermediate containers")
	flag.BoolVar(&config.ForceRmTmpContainer, "force-rm", false, "Force remove intermediate containers")
	flag.StringVar(&config.UniqueID, "uid", "", "Unique ID for the build. Used only for multi-tenanted build environments")
	flag.StringVar(&flagLevel, "level", "debug", "Log level: debug, info, notice, warning, error and critical")
	flag.StringVar(&config.DockerHost, "host", os.Getenv("DOCKER_HOST"), "Docker host link. Uses DOCKER_HOST if missing")
	flag.StringVar(&config.DockerCert, "certs", os.Getenv("DOCKER_CERT_PATH"), "Docker cert folder. Uses DOCKER_CERT_PATH if missing")
	flag.Var(&config.EnvVars, "env", "Environment variables to be used during build. If empty cxbuild uses parent process environment variables")
	flag.BoolVar(&config.KeepSteps, "keep-steps", false, "Keep all stpes. Used for debugging each step")
	flag.BoolVar(&config.NoSquash, "no-cleanup", false, "Skip cleanup commands for this run. Used for debugging")
	flag.BoolVar(&config.FroceRmImages, "force-rmi", false, "Force remove of unwanted images")
	flag.BoolVar(&config.NoPruneRmImages, "noprune-rmi", false, "No pruning of unwanted images")
	flag.BoolVar(&flagShowHelp, "help", false, "Display the help")
	flag.BoolVar(&flagShowVersion, "version", false, "Display version information")

	config.Logger = *log

	flag.Parse()

	if flagShowHelp || (len(args) > 0 && args[0] == "help") {
		fmt.Println("Habitus - (c) 2016 Cloud 66 Inc.")
		flag.PrintDefaults()
		return
	}

	if flagShowVersion || (len(args) > 0 && args[0] == "version") {
		if BUILD_DATE == "" {
			fmt.Printf("Habitus - v%s (c) 2016 Cloud 66 Inc.\n", VERSION)
		} else {
			fmt.Printf("Habitus - v%s (%s) (c) 2016 Cloud 66 Inc.\n", VERSION, BUILD_DATE)
		}
		return
	}

	level, err := logging.LogLevel(flagLevel)
	if err != nil {
		fmt.Println("Invalid log level value. Falling back to debug")
		level = logging.DEBUG
	}
	logging.SetLevel(level, "cxbuilder")

	if config.Workdir == "" {
		if curr, err := os.Getwd(); err != nil {
			log.Fatal("Failed to get the current directory")
			os.Exit(1)
		} else {
			config.Workdir = curr
		}
	}

	if config.Buildfile == "build.yml" {
		config.Buildfile = filepath.Join(config.Workdir, "build.yml")
	}

	c, err := build.LoadBuildFromFile(&config)
	if err != nil {
		log.Fatalf("Failed: %s", err.Error())
	}

	if c.IsPrivileged && os.Getenv("SUDO_USER") == "" {
		log.Fatal("Some of the build steps require admin privileges (sudo). Please run with sudo\nYou might want to use --certs=$DOCKER_CERT_PATH --host=$DOCKER_HOST params to make sure all environment variables are available to the process")
		os.Exit(1)
	}

	b := build.NewBuilder(c, &config)
	err = b.StartBuild()
	if err != nil {
		log.Error("Error during build %s", err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"math/rand"

	"runtime"
	"time"
)

func fibonacci(iterations uint64) []uint64 {
	var results []uint64
	for n := uint64(0); n < iterations; n++ {
		if n == 0 {
			results = append(results, 0)
		}
		if n == 1 {
			results = append(results, 1)
		}
		if n > 1 {
			f := (results[len(results)-1]) + (results[len(results)-2])
			results = append(results, f)
		}
	}
	return results
}

func compression(size int) {
	var b bytes.Buffer
	data := make([]byte, size)
	for i := 0; i < size; i++ {
		data[i] = byte(rand.Intn(1337))
	}
	w := gzip.NewWriter(&b)
	w.Write(data)
	w.Close()
	r, err := gzip.NewReader(&b)
	if err != nil {
		panic(err)
	}
	r.Close()
}

func main() {
	fmt.Println("Number of logical cores:", runtime.NumCPU())
	t0 := time.Now()
	fibonacci(100000000)
	t1 := time.Now()
	fmt.Printf("Fibonacci took %v to run.\n", t1.Sub(t0))
	t0 = time.Now()
	compression(10000000)
	t1 = time.Now()
	fmt.Printf("gzip took %v to run.\n", t1.Sub(t0))
}
<commit_msg>use all threads<commit_after>package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"math/rand"
	"runtime"
	"time"
)

func fibonacci(iterations uint64) []uint64 {
	var results []uint64
	for n := uint64(0); n < iterations; n++ {
		if n == 0 {
			results = append(results, 0)
		}
		if n == 1 {
			results = append(results, 1)
		}
		if n > 1 {
			f := (results[len(results)-1]) + (results[len(results)-2])
			results = append(results, f)
		}
	}
	return results
}

func compression(size int) {
	var b bytes.Buffer
	data := make([]byte, size)
	for i := 0; i < size; i++ {
		data[i] = byte(rand.Intn(1337))
	}
	w := gzip.NewWriter(&b)
	w.Write(data)
	w.Close()
	r, err := gzip.NewReader(&b)
	if err != nil {
		panic(err)
	}
	r.Close()
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	fmt.Println("Number of logical cores:", runtime.NumCPU())
	t0 := time.Now()
	fibonacci(100000000)
	t1 := time.Now()
	fmt.Printf("Fibonacci took %v to run.\n", t1.Sub(t0))
	t0 = time.Now()
	compression(10000000)
	t1 = time.Now()
	fmt.Printf("gzip took %v to run.\n", t1.Sub(t0))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/ActiveState/tail"
	"log"
	"strings"
)

func WatchFileSystem(path string, triggerwords []string, token string, user string) {

	t, err := tail.TailFile(path, tail.Config{
		Follow: true,
		ReOpen: true})
	if err != nil {
		log.Fatalf("Uhh I can't read %s ... Maybe I am not root? Maybe you are on windows?", path)
	}
	lc := CountLines(path) - 1
	cnt := 0
	log.Printf("Now watching %s", path)
	for line := range t.Lines {
		if cnt < lc {
			cnt++
		} else {
			for _, v := range triggerwords {
				if strings.Contains(line.Text, v) {
					SendPushOver(fmt.Sprintf("Log from %s", GetHostName()), token, user, line.Text)
				}
			}
		}
	}
}

func main() {
	log.Println("PushOver Auth Notifier")
	cfg := GetCFG()
	for _, v := range cfg.Watches {
		log.Printf("Setting up watching for %s", v.Path)
		go WatchFileSystem(v.Path, v.TriggerWords, cfg.AppToken, cfg.UserToken)
	}
	select {}
}
<commit_msg>Better messages<commit_after>package main

import (
	"fmt"
	"github.com/ActiveState/tail"
	"log"
	"regexp"
	"strings"
)

func WatchFileSystem(path string, triggerwords []string, token string, user string) {
	fRgx, err := regexp.Compile("[\\w\\d]+ from [\\.\\d]+")
	if err != nil {
		log.Fatalf("The regex didn't compile. This shouldn't be happening.")
	}

	t, err := tail.TailFile(path, tail.Config{ Follow: true, ReOpen: true})
	if err != nil {
		log.Fatalf("Uhh I can't read %s ... Maybe I am not root? Maybe you are on windows?", path)
	}

	lc := CountLines(path) - 1
	cnt := 0
	log.Printf("Now watching %s", path)
	for line := range t.Lines {
		if cnt < lc {
			cnt++
		} else {
			for _, v := range triggerwords {
				if strings.Contains(line.Text, v) {
					if fRgx.Match([]byte(line.Text)) {
						matches := strings.Split(fRgx.FindString(line.Text), " from ")
						notice := fmt.Sprintf("%s@%s logged into %s", matches[0], matches[1], GetHostName())
						SendPushOver(fmt.Sprintf("Login at %s", GetHostName()), token, user, notice)
					} else {
						SendPushOver(fmt.Sprintf("Login at %s", GetHostName()), token, user, line.Text)
					}
				}
			}
		}
	}
}

func main() {
	log.Println("PushOver Auth Notifier")
	cfg := GetCFG()
	for _, v := range cfg.Watches {
		log.Printf("Setting up watching for %s", v.Path)
		go WatchFileSystem(v.Path, v.TriggerWords, cfg.AppToken, cfg.UserToken)
	}
	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	_ "go-blog/models/db"
	_ "go-blog/routers"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

var (
	syncdb = flag.Bool("syncdb", false, "\t同步数据库结构")
	force  = flag.Bool("force", false, "\tsyncdb 的强制模式，会丢失所有数据")
	run    = flag.Bool("run", true, "\t\t运行系统")
)

func main() {
	flag.Parse()
	if flag.NFlag() == 0 { //没有使用参数就打印帮助
		fmt.Println("命令行参数：")
		flag.PrintDefaults()
		os.Exit(1)
	}

	switch {
	case *syncdb: //同步数据库结构
		err := orm.RunSyncdb("default", *force, true)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case *run: //运行
		beego.Run()
	}

	os.Exit(0)
}
<commit_msg>update main.go<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	_ "go-blog/models/db"
	_ "go-blog/routers"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

var (
	syncdb = flag.Bool("syncdb", false, "\t同步数据库结构")
	force  = flag.Bool("force", false, "\tsyncdb 的强制模式，会丢失所有数据")
	run    = flag.Bool("run", false, "\t\t运行系统")
)

func main() {
	flag.Parse()
	if flag.NFlag() == 0 { //没有使用参数就打印帮助
		fmt.Println("命令行参数及默认值：")
		flag.PrintDefaults()
		os.Exit(1)
	}

	switch {
	case *syncdb: //同步数据库结构
		err := orm.RunSyncdb("default", *force, true)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case *run: //运行
		beego.Run()
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package main // import "github.com/tutumcloud/weave-daemon"

import (
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/tutumcloud/go-tutum/tutum"
	"github.com/tutumcloud/weave-daemon/nodes"
)

func AttachContainer(c *docker.Client, container_id string) error {
	inspect, err := c.InspectContainer(container_id)

	if err != nil {
		return err
	}

	cidr := ""
	env_vars := inspect.Config.Env

	for i := range env_vars {
		if strings.HasPrefix(env_vars[i], "TUTUM_IP_ADDRESS=") {
			cidr = env_vars[i][len("TUTUM_IP_ADDRESS="):]
			break
		}
	}

	if cidr != "" {
		tries := 0
		for tries < 3 {

			log.Printf("%s: adding to weave with IP %s", container_id, cidr)
			cmd := exec.Command("/weave", "--local", "attach", cidr, container_id)

			_, err := cmd.StdoutPipe()
			if err != nil {
				return err
			}

			if err := cmd.Start(); err != nil {
				return err
			}

			if err := cmd.Wait(); err != nil {
				tries++
				return err
				if tries > 3 {
					break
				}
			} else {
				break
			}
		}
	} else {
		log.Printf("%s: cannot find the IP address to add to weave", container_id)
	}
	return nil
}

func ContainerAttachThread(c *docker.Client) error {

	listener := make(chan *docker.APIEvents)

	containers, err := c.ListContainers(docker.ListContainersOptions{All: false, Size: true, Limit: 0, Since: "", Before: ""})
	if err != nil {
		return err
	}

	for _, container := range containers {
		err := AttachContainer(c, container.ID)
		if err != nil {
			return err
		}

	}
	err = c.AddEventListener(listener)
	if err != nil {
		return err
	}

	defer func() error {

		err = c.RemoveEventListener(listener)
		if err != nil {
			return err
		}
		return nil
	}()

	timeout := time.After(1 * time.Second)

	for {
		select {
		case msg := <-listener:
			if msg.Status == "start" && !strings.HasPrefix(msg.From, "weaveworks/weave") {
				err := AttachContainer(c, msg.ID)
				if err != nil {
					log.Fatal(err)
					break
				}
			}
		case <-timeout:
			break
		}
	}
}

func discovering() {
	c := make(chan tutum.Event)
	e := make(chan error)
	nodes.DiscoverPeers()
	go tutum.TutumEvents(c, e)
Loop:
	for {
		select {
		case event := <-c:
			if event.Type == "node" && (event.State == "Deployed" || event.State == "Terminated") {
				err := nodes.DiscoverPeers()
				if err != nil {
					log.Println(err)
				}
			}
		case err := <-e:
			log.Println(err)
			go discovering()
			break Loop
		}
	}
}

func connectToDocker() (*docker.Client, error) {
	endpoint := "unix:///var/run/docker.sock"

	client, err := docker.NewClient(endpoint)

	if err != nil {

		log.Println(err)
	}
	return client, nil
}

func main() {

	log.Println("Start running daemon")

	//Init Docker client
	client, err := connectToDocker()
	if err != nil {
		log.Fatal(err)
	}

	node, err := tutum.GetNode(nodes.Tutum_Node_Api_Uri)
	if err != nil {
		log.Fatal(err)
	}
	nodes.Tutum_Node_Public_Ip = node.Public_ip
	log.Printf("This node IP is %s", nodes.Tutum_Node_Public_Ip)
	if os.Getenv("TUTUM_AUTH") != "" {
		log.Println("Detected Tutum API access - starting peer discovery thread")
		go discovering()
	}
	err = ContainerAttachThread(client)
	if err != nil {
		log.Println("ATTACH THREAD ERR")
		log.Println(err)
	}
}
<commit_msg>fix log.Fatal<commit_after>package main // import "github.com/tutumcloud/weave-daemon"

import (
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/tutumcloud/go-tutum/tutum"
	"github.com/tutumcloud/weave-daemon/nodes"
)

func AttachContainer(c *docker.Client, container_id string) error {
	inspect, err := c.InspectContainer(container_id)

	if err != nil {
		return err
	}

	cidr := ""
	env_vars := inspect.Config.Env

	for i := range env_vars {
		if strings.HasPrefix(env_vars[i], "TUTUM_IP_ADDRESS=") {
			cidr = env_vars[i][len("TUTUM_IP_ADDRESS="):]
			break
		}
	}

	if cidr != "" {
		tries := 0
		for tries < 3 {

			log.Printf("%s: adding to weave with IP %s", container_id, cidr)
			cmd := exec.Command("/weave", "--local", "attach", cidr, container_id)

			_, err := cmd.StdoutPipe()
			if err != nil {
				return err
			}

			if err := cmd.Start(); err != nil {
				return err
			}

			if err := cmd.Wait(); err != nil {
				tries++

				if tries > 3 {
					break
				}
				return err
			} else {
				break
			}
		}
	} else {
		log.Printf("%s: cannot find the IP address to add to weave", container_id)
	}
	return nil
}

func ContainerAttachThread(c *docker.Client) error {

	listener := make(chan *docker.APIEvents)

	containers, err := c.ListContainers(docker.ListContainersOptions{All: false, Size: true, Limit: 0, Since: "", Before: ""})
	if err != nil {
		return err
	}

	for _, container := range containers {
		err := AttachContainer(c, container.ID)
		if err != nil {
			return err
		}

	}
	err = c.AddEventListener(listener)
	if err != nil {
		return err
	}

	defer func() error {

		err = c.RemoveEventListener(listener)
		if err != nil {
			return err
		}
		return nil
	}()

	timeout := time.After(1 * time.Second)

	for {
		select {
		case msg := <-listener:
			if msg.Status == "start" && !strings.HasPrefix(msg.From, "weaveworks/weave") {
				err := AttachContainer(c, msg.ID)
				if err != nil {
					log.Println(err)
					break
				}
			}
		case <-timeout:
			break
		}
	}
}

func discovering() {
	c := make(chan tutum.Event)
	e := make(chan error)
	nodes.DiscoverPeers()
	go tutum.TutumEvents(c, e)
Loop:
	for {
		select {
		case event := <-c:
			if event.Type == "node" && (event.State == "Deployed" || event.State == "Terminated") {
				err := nodes.DiscoverPeers()
				if err != nil {
					log.Println(err)
				}
			}
		case err := <-e:
			log.Println(err)
			go discovering()
			break Loop
		}
	}
}

func connectToDocker() (*docker.Client, error) {
	endpoint := "unix:///var/run/docker.sock"

	client, err := docker.NewClient(endpoint)

	if err != nil {

		log.Println(err)
	}
	return client, nil
}

func main() {

	log.Println("Start running daemon")

	//Init Docker client
	client, err := connectToDocker()
	if err != nil {
		log.Println(err)
	}

	node, err := tutum.GetNode(nodes.Tutum_Node_Api_Uri)
	if err != nil {
		log.Println(err)
	}
	nodes.Tutum_Node_Public_Ip = node.Public_ip
	log.Printf("This node IP is %s", nodes.Tutum_Node_Public_Ip)
	if os.Getenv("TUTUM_AUTH") != "" {
		log.Println("Detected Tutum API access - starting peer discovery thread")
		go discovering()
	}
	err = ContainerAttachThread(client)
	if err != nil {
		log.Println("ATTACH THREAD ERR")
		log.Println(err)
	}
}
<|endoftext|>


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

package main

import (
	"context"
	"flag"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/util/appdefaults"
	"github.com/tsuru/deploy-agent/pkg/build"
	"google.golang.org/grpc"

	pb "github.com/tsuru/deploy-agent/api/v1alpha1"
)

var cfg struct {
	BuildkitAddress string
	BuildkitTmpDir  string
	Port            int
}

func main() {
	flag.IntVar(&cfg.Port, "port", 4444, "Server TCP port")
	flag.StringVar(&cfg.BuildkitAddress, "buildkit-addr", os.Getenv("BUILDKIT_HOST"), fmt.Sprintf("Buildkit daemon address (default: %s)", appdefaults.Address))
	flag.StringVar(&cfg.BuildkitTmpDir, "buildkit-tmp-dir", os.TempDir(), "Directory path to store temp files during container image builds")
	flag.Parse()

	l, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.Port))
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to listen: %v", err)
		os.Exit(1)
	}

	if cfg.BuildkitAddress == "" {
		cfg.BuildkitAddress = appdefaults.Address
	}

	ctx := context.Background()

	c, err := client.New(ctx, cfg.BuildkitAddress, client.WithFailFast())
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create Buildkit client: %v", err)
		os.Exit(1)
	}
	defer c.Close()

	s := grpc.NewServer()
	pb.RegisterBuildServer(s, build.NewDocker(c, build.DockerOptions{TempDir: cfg.BuildkitTmpDir}))

	go handleGracefulTermination(s)

	fmt.Println("Starting gRPC server at", l.Addr().String())

	if err := s.Serve(l); err != nil {
		fmt.Fprintln(os.Stderr, "failed to run gRPC server:", err)
		os.Exit(1)
	}

	fmt.Println("gRPC server terminated")
}

func handleGracefulTermination(s *grpc.Server) {
	defer func() {
		fmt.Fprintln(os.Stdout, "Received termination signal. Terminating gRPC server...")
		s.GracefulStop()
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop
}
<commit_msg>refactor: adding helper func to get env or default value<commit_after>// Copyright 2022 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"flag"
	"fmt"
	"net"
	"os"
	"os/signal"
	"syscall"

	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/util/appdefaults"
	"github.com/tsuru/deploy-agent/pkg/build"
	"google.golang.org/grpc"

	pb "github.com/tsuru/deploy-agent/api/v1alpha1"
)

var cfg struct {
	BuildkitAddress string
	BuildkitTmpDir  string
	Port            int
}

func main() {
	flag.IntVar(&cfg.Port, "port", 4444, "Server TCP port")
	flag.StringVar(&cfg.BuildkitAddress, "buildkit-addr", getEnvOrDefault("BUILDKIT_HOST", appdefaults.Address), "Buildkit server address")
	flag.StringVar(&cfg.BuildkitTmpDir, "buildkit-tmp-dir", os.TempDir(), "Directory path to store temp files during container image builds")
	flag.Parse()

	l, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.Port))
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to listen: %v", err)
		os.Exit(1)
	}

	ctx := context.Background()

	c, err := client.New(ctx, cfg.BuildkitAddress, client.WithFailFast())
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create Buildkit client: %v", err)
		os.Exit(1)
	}
	defer c.Close()

	s := grpc.NewServer()
	pb.RegisterBuildServer(s, build.NewDocker(c, build.DockerOptions{TempDir: cfg.BuildkitTmpDir}))

	go handleGracefulTermination(s)

	fmt.Println("Starting gRPC server at", l.Addr().String())

	if err := s.Serve(l); err != nil {
		fmt.Fprintln(os.Stderr, "failed to run gRPC server:", err)
		os.Exit(1)
	}

	fmt.Println("gRPC server terminated")
}

func handleGracefulTermination(s *grpc.Server) {
	defer func() {
		fmt.Fprintln(os.Stdout, "Received termination signal. Terminating gRPC server...")
		s.GracefulStop()
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
	<-stop
}

func getEnvOrDefault(env, def string) string {
	if envvar, found := os.LookupEnv(env); found {
		return envvar
	}

	return def
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/canopener/PongPlusPlus-Server/connection"
	"github.com/canopener/serverlog"
	"net"
)

func main() {
	serverlog.Init(true, true, 7, "/home/mladen/Desktop/")
	serverlog.Startup("Server listening on localhost:3000")
	listener, err := net.Listen("tcp", "localhost:3000")
	if err != nil {
		serverlog.Fatal(err)
	}
	defer listener.Close()

	for {
		socket, err := listener.Accept()
		if err != nil {
			serverlog.Fatal(err)
		}
		conn := connection.NewConnection(socket)
		go listenMessage(conn)
	}
}

func listenMessage(conn *connection.Connection) {
	for {
		select {
		case message := <-conn.IncommingMessages:
			serverlog.General("New message: ", string(message))
			conn.Write(message)
		}
	}
}
<commit_msg>No more hardcoding, primitive flags available now<commit_after>package main

import (
	"flag"
	"github.com/canopener/PongPlusPlus-Server/connection"
	"github.com/canopener/serverlog"
	"net"
	"os"
	"strconv"
)

func main() {
	help := flag.Bool("h", false, "Display this help message")
	consoleLog := flag.Bool("C", false, "Allow logging to the console, default wont log")
	fileLog := flag.String("L", "", "Specify directory for logging logfiles, default wont log")
	logcount := flag.Int("N", -1, "Specify maximum logfiles in directory, default no limit")
	portno := flag.Int("PORT", 3000, "Specify the port on which the server should listen, default 3000")
	flag.Parse()

	if *help {
		flag.PrintDefaults()
		os.Exit(1)
	}

	serverlog.Init(*consoleLog, (*fileLog != ""), *logcount, *fileLog)
	serverlog.Startup("Server listening on localhost:", *portno)
	listener, err := net.Listen("tcp", ":"+strconv.Itoa(*portno))
	if err != nil {
		serverlog.Fatal(err)
	}
	defer listener.Close()

	for {
		socket, err := listener.Accept()
		if err != nil {
			serverlog.Fatal(err)
		}
		conn := connection.NewConnection(socket)
		go listenMessage(conn)
	}
}

func listenMessage(conn *connection.Connection) {
	for {
		select {
		case message := <-conn.IncommingMessages:
			serverlog.General("New message: ", string(message))
			conn.Write(message)
		}
	}
}
<|endoftext|>


<commit_before>// Workflow written in SciPipe.
// For more information about SciPipe, see: http://scipipe.org
package main

import (
	"bufio"
	"flag"
	"github.com/flowbase/flowbase"
	"log"
	"os"
)

func main() {
	flowbase.InitLogDebug()

	inFileName := flag.String("infile", "", "The input file name")
	flag.Parse()
	if *inFileName == "" {
		flowbase.Error.Println("No filename specified to --infile")
		os.Exit(1)
	}

	// Create a pipeline runner
	pipeRunner := flowbase.NewPipelineRunner()

	// Initialize processes and add to runner
	fileReader := NewFileReader()
	pipeRunner.AddProcess(fileReader)

	sink := flowbase.NewSinkString()
	pipeRunner.AddProcess(sink)

	// Connect workflow dependency network
	sink.Connect(fileReader.OutLine)

	// Run the pipeline!
	go func() {
		defer close(fileReader.InFileName)
		fileReader.InFileName <- *inFileName
	}()

	pipeRunner.Run()

}

// ================================================================================
// Components
// ================================================================================

type FileReader struct {
	InFileName chan string
	OutLine    chan string
}

func NewFileReader() *FileReader {
	return &FileReader{
		InFileName: make(chan string, flowbase.BUFSIZE),
		OutLine:    make(chan string, flowbase.BUFSIZE),
	}
}

func (p *FileReader) Run() {
	defer close(p.OutLine)

	flowbase.Debug.Println("Starting loop")
	for fileName := range p.InFileName {
		flowbase.Debug.Printf("Starting processing file %s\n", fileName)
		fh, err := os.Open(fileName)
		if err != nil {
			log.Fatal(err)
		}
		defer fh.Close()

		sc := bufio.NewScanner(fh)
		for sc.Scan() {
			if err := sc.Err(); err != nil {
				log.Fatal(err)
			}
			p.OutLine <- sc.Text()
		}
	}
}
<commit_msg>Add TripleParser and TriplePrinter components<commit_after>// Workflow written in SciPipe.
// For more information about SciPipe, see: http://scipipe.org
package main

import (
	"bufio"
	"flag"
	"fmt"
	"github.com/flowbase/flowbase"
	"log"
	"os"
	str "strings"
)

const (
	BUFSIZE = 16
)

func main() {
	flowbase.InitLogDebug()

	inFileName := flag.String("infile", "", "The input file name")
	flag.Parse()
	if *inFileName == "" {
		flowbase.Error.Println("No filename specified to --infile")
		os.Exit(1)
	}

	// Create a pipeline runner
	pipeRunner := flowbase.NewPipelineRunner()

	// Initialize processes and add to runner
	fileReader := NewFileReader()
	pipeRunner.AddProcess(fileReader)

	tripleParser := NewTripleParser()
	pipeRunner.AddProcess(tripleParser)

	triplePrinter := NewTriplePrinter()
	pipeRunner.AddProcess(triplePrinter)

	// Connect workflow dependency network
	tripleParser.In = fileReader.OutLine
	triplePrinter.In = tripleParser.Out

	// Run the pipeline!
	go func() {
		defer close(fileReader.InFileName)
		fileReader.InFileName <- *inFileName
	}()

	pipeRunner.Run()

}

// ================================================================================
// Components
// ================================================================================

// --------------------------------------------------------------------------------
// FileReader
// --------------------------------------------------------------------------------

type FileReader struct {
	InFileName chan string
	OutLine    chan string
}

func NewFileReader() *FileReader {
	return &FileReader{
		InFileName: make(chan string, BUFSIZE),
		OutLine:    make(chan string, BUFSIZE),
	}
}

func (p *FileReader) Run() {
	defer close(p.OutLine)

	flowbase.Debug.Println("Starting loop")
	for fileName := range p.InFileName {
		flowbase.Debug.Printf("Starting processing file %s\n", fileName)
		fh, err := os.Open(fileName)
		if err != nil {
			log.Fatal(err)
		}
		defer fh.Close()

		sc := bufio.NewScanner(fh)
		for sc.Scan() {
			if err := sc.Err(); err != nil {
				log.Fatal(err)
			}
			p.OutLine <- sc.Text()
		}
	}
}

// --------------------------------------------------------------------------------
// TripleParser
// --------------------------------------------------------------------------------

type TripleParser struct {
	In  chan string
	Out chan *RDFTriple
}

func NewTripleParser() *TripleParser {
	return &TripleParser{
		In:  make(chan string, BUFSIZE),
		Out: make(chan *RDFTriple, BUFSIZE),
	}
}

func (p *TripleParser) Run() {
	defer close(p.Out)
	for line := range p.In {
		triple := NewRDFTriple()
		bits := str.Split(line, " ")
		triple.Subject = bits[0]
		triple.Predicate = bits[1]
		triple.Object = bits[2]
		p.Out <- triple
	}
}

// --------------------------------------------------------------------------------
// TriplePrinter
// --------------------------------------------------------------------------------

type TriplePrinter struct {
	In chan *RDFTriple
}

func NewTriplePrinter() *TriplePrinter {
	return &TriplePrinter{
		In: make(chan *RDFTriple, BUFSIZE),
	}
}

func (p *TriplePrinter) Run() {
	for tr := range p.In {
		fmt.Printf("S: %s\nP: %s\nO: %s\n\n", tr.Subject, tr.Predicate, tr.Object)
	}
}

// --------------------------------------------------------------------------------
// IP: RDFTriple
// --------------------------------------------------------------------------------

type RDFTriple struct {
	Subject   string
	Predicate string
	Object    string
}

func NewRDFTriple() *RDFTriple {
	return &RDFTriple{}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	stdlog "log"
	"net/http"
	"net/http/httputil"
	"os"
	"os/signal"
	"syscall"

	"github.com/rchicoli/webapper/log"

	"github.com/gorilla/mux"
)

const (
	usage = `
Usage: curl http://127.0.0.1:8080/[endpoint]

    Perform HTTP request against the API for a specific action.

Endpoints:

    /           show this message
    /jsonp      beautify json object
    /raw        post raw request
    /trace        trace the request
    /echo       return the payload sent
    /headers    display all headers
    /health     check health status
    /hostname   display hostname
    /log        log the message
    /trace      dump the request
`
)

func echoHandler(w http.ResponseWriter, r *http.Request) {
	io.Copy(w, r.Body)
}

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", usage)
	stdlog.Printf(r.URL.Path)
}

func rawHandler(w http.ResponseWriter, r *http.Request) {

	b, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	fmt.Fprintf(w, "%s", b)
	stdlog.Printf("%s", b)
}

func headersHandler(w http.ResponseWriter, r *http.Request) {
	for k, v := range r.Header {
		fmt.Fprintf(w, "%s=%s\n", k, v)
	}
}

func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
}

func hostnameHandler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	hostname, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s\n", hostname)
	log.Printf(ctx, fmt.Sprintf("[context] %p: %s", ctx, r.URL.Path))
}

func jsonPrettyPrintHandler(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json")

	b, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	var jsonObject interface{}
	json.Unmarshal(b, &jsonObject)
	jsonPretty, err := json.MarshalIndent(jsonObject, "", "  ")
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	fmt.Fprintf(w, "%s", jsonPretty)
	stdlog.Printf("%s", jsonPretty)
}

func traceHandler(w http.ResponseWriter, req *http.Request) {
	requestDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Fprint(w, err.Error())
	} else {
		fmt.Fprint(w, string(requestDump))
	}
}

func main() {

	router := mux.NewRouter()

	router.HandleFunc("/", log.Decorate(endpointHandler)).Methods("GET")
	router.HandleFunc("/echo", log.Decorate(echoHandler)).Methods("GET", "POST")
	router.HandleFunc("/headers", log.Decorate(headersHandler)).Methods("GET")
	router.HandleFunc("/health", log.Decorate(healthCheckHandler)).Methods("GET")
	router.HandleFunc("/hostname", log.Decorate(hostnameHandler)).Methods("GET")
	router.HandleFunc("/jsonp", log.Decorate(jsonPrettyPrintHandler)).Methods("POST")
	router.HandleFunc("/log", log.Decorate(rawHandler)).Methods("POST")
	router.HandleFunc("/raw", log.Decorate(rawHandler)).Methods("POST")
	router.HandleFunc("/trace", log.Decorate(traceHandler)).Methods("GET", "POST")

	srv := http.Server{Addr: ":8080", Handler: router}

	idleConnsClosed := make(chan struct{})
	go func() {
		sigint := make(chan os.Signal, 1)

		// interrupt signal sent from terminal
		signal.Notify(sigint, os.Interrupt)
		// sigterm signal sent from kubernetes
		signal.Notify(sigint, syscall.SIGTERM)

		<-sigint

		// We received an interrupt signal, shut down.
		if err := srv.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			stdlog.Printf("HTTP server Shutdown: %v", err)
		}

		stdlog.Println("HTTP server shutdown gracefully")
		close(idleConnsClosed)
	}()

	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		// Error starting or closing listener:
		stdlog.Fatalf("HTTP server ListenAndServe: %v\n", err)
	}

	<-idleConnsClosed

}
<commit_msg>main: add prometheus metrics endpoint<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	stdlog "log"
	"net/http"
	"net/http/httputil"
	"os"
	"os/signal"
	"syscall"

	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/rchicoli/webapper/log"

	"github.com/gorilla/mux"
)

const (
	usage = `
Usage: curl http://127.0.0.1:8080/[endpoint]

    Perform HTTP request against the API for a specific action.

Endpoints:

    /           show this message
    /echo       return the payload sent
    /headers    display all headers
    /health     check health status
    /hostname   display hostname
    /jsonp      beautify json object
    /log        log the message
    /metrics    prometheus metrics
    /raw        post raw request
    /trace      dump the request
    /trace      trace the request
`
)

func echoHandler(w http.ResponseWriter, r *http.Request) {
	io.Copy(w, r.Body)
}

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", usage)
	stdlog.Printf(r.URL.Path)
}

func rawHandler(w http.ResponseWriter, r *http.Request) {

	b, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	fmt.Fprintf(w, "%s", b)
	stdlog.Printf("%s", b)
}

func headersHandler(w http.ResponseWriter, r *http.Request) {
	for k, v := range r.Header {
		fmt.Fprintf(w, "%s=%s\n", k, v)
	}
}

func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
}

func hostnameHandler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	hostname, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s\n", hostname)
	log.Printf(ctx, fmt.Sprintf("[context] %p: %s", ctx, r.URL.Path))
}

func jsonPrettyPrintHandler(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json")

	b, err := ioutil.ReadAll(r.Body)
	defer r.Body.Close()
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	var jsonObject interface{}
	json.Unmarshal(b, &jsonObject)
	jsonPretty, err := json.MarshalIndent(jsonObject, "", "  ")
	if err != nil {
		http.Error(w, "error: reading request body", http.StatusInternalServerError)
	}

	fmt.Fprintf(w, "%s", jsonPretty)
	stdlog.Printf("%s", jsonPretty)
}

func metricsHandler(w http.ResponseWriter, r *http.Request) {
	promhttp.Handler().ServeHTTP(w, r)
}

func traceHandler(w http.ResponseWriter, req *http.Request) {
	requestDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Fprint(w, err.Error())
	} else {
		fmt.Fprint(w, string(requestDump))
	}
}

func main() {

	router := mux.NewRouter()

	router.HandleFunc("/", log.Decorate(endpointHandler)).Methods("GET")
	router.HandleFunc("/echo", log.Decorate(echoHandler)).Methods("GET", "POST")
	router.HandleFunc("/headers", log.Decorate(headersHandler)).Methods("GET")
	router.HandleFunc("/health", log.Decorate(healthCheckHandler)).Methods("GET")
	router.HandleFunc("/hostname", log.Decorate(hostnameHandler)).Methods("GET")
	router.HandleFunc("/jsonp", log.Decorate(jsonPrettyPrintHandler)).Methods("POST")
	router.HandleFunc("/log", log.Decorate(rawHandler)).Methods("POST")
	router.HandleFunc("/metrics", log.Decorate(metricsHandler)).Methods("GET")
	router.HandleFunc("/raw", log.Decorate(rawHandler)).Methods("POST")
	router.HandleFunc("/trace", log.Decorate(traceHandler)).Methods("GET", "POST")

	srv := http.Server{Addr: ":8080", Handler: router}

	idleConnsClosed := make(chan struct{})
	go func() {
		sigint := make(chan os.Signal, 1)

		// interrupt signal sent from terminal
		signal.Notify(sigint, os.Interrupt)
		// sigterm signal sent from kubernetes
		signal.Notify(sigint, syscall.SIGTERM)

		<-sigint

		// We received an interrupt signal, shut down.
		if err := srv.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			stdlog.Printf("HTTP server Shutdown: %v", err)
		}

		stdlog.Println("HTTP server shutdown gracefully")
		close(idleConnsClosed)
	}()

	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
		// Error starting or closing listener:
		stdlog.Fatalf("HTTP server ListenAndServe: %v\n", err)
	}

	<-idleConnsClosed

}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/urfave/cli"
)

// Metric has a name, type, help and cardinality.
type Metric struct {
	Name        string
	Type        string
	Help        string
	Cardinality int
}

func main() {
	app := cli.NewApp()

	app.Action = ViewAction
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "Read metrics from file",
		},
		cli.StringFlag{
			Name:  "sort",
			Usage: "Sort by name, type or help",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

// ViewAction runs the default cli app.
func ViewAction(c *cli.Context) error {
	url := c.Args().First()
	sortFlag := c.String("sort")
	fileFlag := c.String("file")

	var metrics []Metric
	if fileFlag != "" {
		fileMetrics, err := FileMetrics(fileFlag)
		if err != nil {
			return err
		}
		metrics = fileMetrics
	} else {
		if url == "" {
			return errors.New("Please provide a URL, like http://localhost:8080/metrics")
		}
		httpMetrics, err := HTTPMetrics(url)
		if err != nil {
			return err
		}
		metrics = httpMetrics
	}

	switch sortFlag {
	case "type":
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Type < metrics[j].Type
		})
	case "help":
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Help < metrics[j].Help
		})
	default:
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Name < metrics[j].Name
		})
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.TabIndent)
	fmt.Fprintln(w, "Name\tType\tCardinality\tHelp")
	for _, metric := range metrics {
		if metric.Name != "" {
			fmt.Fprintf(w, "%s\t%s\t%d\t%s\n", metric.Name, metric.Type, metric.Cardinality, metric.Help)
		}
	}
	return w.Flush()

}

// FileMetrics reads a file and returns its metrics.
func FileMetrics(filename string) ([]Metric, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	return parseMetrics(file)
}

// HTTPMetrics makes an HTTP GET request again url and returns its metrics.
func HTTPMetrics(url string) ([]Metric, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}

	client := http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return parseMetrics(resp.Body)
}

func parseMetrics(r io.Reader) ([]Metric, error) {
	metricsMap := make(map[string]Metric, 64)

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "# HELP") {
			name, help := parseHelp(line)
			metricsMap[name] = Metric{
				Name: name,
				Help: help,
			}
		} else if strings.HasPrefix(line, "# TYPE") {
			name, types := parseType(line)
			metric := metricsMap[name]
			metric.Type = types
			metricsMap[name] = metric
		} else {
			name := parseMetric(line)
			metric := metricsMap[name]
			metric.Cardinality = metric.Cardinality + 1
			metricsMap[name] = metric
		}
	}

	metrics := make([]Metric, len(metricsMap))
	for _, metric := range metricsMap {
		if metric.Name != "" {
			metrics = append(metrics, metric)
		}
	}

	return metrics, nil
}

func parseHelp(line string) (string, string) {
	splits := strings.SplitN(line, " ", 4)
	return splits[2], splits[3]
}

func parseType(line string) (string, string) {
	splits := strings.SplitN(line, " ", 4)
	return splits[2], splits[3]
}

func parseMetric(line string) string {
	spaces := strings.Split(line, " ")
	return strings.Split(spaces[0], "{")[0]
}
<commit_msg>Implement an http server to start a UI<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/urfave/cli"
)

// Metric has a name, type, help and cardinality.
type Metric struct {
	Name        string
	Type        string
	Help        string
	Cardinality int
}

func main() {
	app := cli.NewApp()

	app.Action = ViewAction
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "Read metrics from file",
		},
		cli.BoolFlag{
			Name:  "http",
			Usage: "Show the overview via a website",
		},
		cli.StringFlag{
			Name:  "sort",
			Usage: "Sort by name, type or help",
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

// ViewAction runs the default cli app.
func ViewAction(c *cli.Context) error {
	url := c.Args().First()
	sortFlag := c.String("sort")
	httpFlag := c.Bool("http")
	fileFlag := c.String("file")

	var metrics []Metric
	if fileFlag != "" {
		fileMetrics, err := FileMetrics(fileFlag)
		if err != nil {
			return err
		}
		metrics = fileMetrics
	} else {
		if url == "" {
			return errors.New("Please provide a URL, like http://localhost:8080/metrics")
		}
		httpMetrics, err := HTTPMetrics(url)
		if err != nil {
			return err
		}
		metrics = httpMetrics
	}

	switch sortFlag {
	case "type":
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Type < metrics[j].Type
		})
	case "help":
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Help < metrics[j].Help
		})
	default:
		sort.Slice(metrics, func(i, j int) bool {
			return metrics[i].Name < metrics[j].Name
		})
	}

	if httpFlag {
		return printHttp(metrics)
	}

	return printCli(metrics)
}

func printHttp(metrics []Metric) error {
	html := `

			<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
			<title>prom-metric-viewer</title>

				{{range .}}

				{{.Name}}
				{{.Type}}
				{{.Cardinality}}
				{{.Help}}

				{{end}}

	`
	tem := template.New("")
	tem.Parse(html)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		tem.Execute(w, metrics)
	})

	return http.ListenAndServe(":8080", nil)
}

func printCli(metrics []Metric) error {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.TabIndent)
	fmt.Fprintln(w, "Name\tType\tCardinality\tHelp")
	for _, metric := range metrics {
		if metric.Name != "" {
			fmt.Fprintf(w, "%s\t%s\t%d\t%s\n", metric.Name, metric.Type, metric.Cardinality, metric.Help)
		}
	}
	return w.Flush()
}

// FileMetrics reads a file and returns its metrics.
func FileMetrics(filename string) ([]Metric, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	return parseMetrics(file)
}

// HTTPMetrics makes an HTTP GET request again url and returns its metrics.
func HTTPMetrics(url string) ([]Metric, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}

	client := http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return parseMetrics(resp.Body)
}

func parseMetrics(r io.Reader) ([]Metric, error) {
	metricsMap := make(map[string]Metric, 64)

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "# HELP") {
			name, help := parseHelp(line)
			metricsMap[name] = Metric{
				Name: name,
				Help: help,
			}
		} else if strings.HasPrefix(line, "# TYPE") {
			name, types := parseType(line)
			metric := metricsMap[name]
			metric.Type = types
			metricsMap[name] = metric
		} else {
			name := parseMetric(line)
			metric := metricsMap[name]
			metric.Cardinality = metric.Cardinality + 1
			metricsMap[name] = metric
		}
	}

	metrics := make([]Metric, len(metricsMap))
	for _, metric := range metricsMap {
		if metric.Name != "" {
			metrics = append(metrics, metric)
		}
	}

	return metrics, nil
}

func parseHelp(line string) (string, string) {
	splits := strings.SplitN(line, " ", 4)
	return splits[2], splits[3]
}

func parseType(line string) (string, string) {
	splits := strings.SplitN(line, " ", 4)
	return splits[2], splits[3]
}

func parseMetric(line string) string {
	spaces := strings.Split(line, " ")
	return strings.Split(spaces[0], "{")[0]
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	"sync"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("Cannot get the user home dir.\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("Cannot open the file %s, due to error '%s'.\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("Cannot save the current configurationFile structure!")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("Cannot access to your file to save the configurationFile structure!")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	var addCmd = &cobra.Command{
		Use:   "add",
		Short: "Add the current path as a VISIBLE repository",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if !utils.IsGitRepository(currentDir) {
				log.Fatalf("%s is not a git repository!\n", currentDir)
			}
			// If the path is/contains a .git directory, add this one as a VISIBLE repository
			if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
				traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
			}
		},
	}

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("There was an error retrieving your git repositories: '%s'\n", err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:   "state",
		Short: "Get the state of each local git repository",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			for _, gitStruct := range configurationFileStructure.VisibleRepositories {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init()
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	var switchCmd = &cobra.Command{
		Use:   "switch",
		Short: "Switch the visibility of the current git repository (given by the current path)",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.VisibleFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.HiddenFlag)
				traces.InfoTracer.Printf("%s has been set to an hidden repository!", currentDir)
				return
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.HiddenFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
				traces.InfoTracer.Printf("%s has been set to a visible repository!", currentDir)
				return
			}
			log.Fatalf("The repository %s is not saved as a VISIBLE or HIDDEN repository! Please to add it before.\n", currentDir)
		},
	}

	rootCmd.AddCommand(addCmd, crawlCmd, stateCmd, switchCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Use dichotomic search<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	"sync"

	"sort"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("Cannot get the user home dir.\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("Cannot open the file %s, due to error '%s'.\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("Cannot save the current configurationFile structure!")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("Cannot access to your file to save the configurationFile structure!")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	var addCmd = &cobra.Command{
		Use:   "add",
		Short: "Add the current path as a VISIBLE repository",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if !utils.IsGitRepository(currentDir) {
				log.Fatalf("%s is not a git repository!\n", currentDir)
			}
			// If the path is/contains a .git directory, add this one as a VISIBLE repository
			if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
				traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
			}
		},
	}

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("There was an error retrieving your git repositories: '%s'\n", err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			var gitStructs []configurationFile.GitRepository
			if len(args) == 0 {
				gitStructs = configurationFileStructure.VisibleRepositories
			} else {
				// Sort visible repositories by name
				sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
				repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
				for _, repositoryName := range args {
					repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
					if repositoryIndex != repositoriesListLength {
						gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
					}
				}
			}
			var wg sync.WaitGroup
			for _, gitStruct := range gitStructs {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init()
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	var switchCmd = &cobra.Command{
		Use:   "switch",
		Short: "Switch the visibility of the current git repository (given by the current path)",
		Run: func(cmd *cobra.Command, args []string) {
			// Get the path where the command has been executed
			currentDir, err := os.Getwd()
			if err != nil {
				log.Fatalln("There was a problem retrieving the current directory")
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.VisibleFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.HiddenFlag)
				traces.InfoTracer.Printf("%s has been set to an hidden repository!", currentDir)
				return
			}
			if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.HiddenFlag); err == nil {
				configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
				traces.InfoTracer.Printf("%s has been set to a visible repository!", currentDir)
				return
			}
			log.Fatalf("The repository %s is not saved as a VISIBLE or HIDDEN repository! Please to add it before.\n", currentDir)
		},
	}

	rootCmd.AddCommand(addCmd, crawlCmd, stateCmd, switchCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>