<commit_before>package ui

import (
	"strings"

	"github.com/moncho/dry/search"
	"github.com/nsf/termbox-go"
)

const (
	endtext   = "(end)"
	starttext = "(start)"
)

//Less is a View with less-like behaviour and characteristics, meaning:
// * The cursor is always shown at the bottom of the screen
type Less struct {
	*View
	searchResult *search.Result
}

//NewLess creates a view that partially simulates less.
func NewLess() *Less {
	width, height := termbox.Size()
	view := &View{
		name:       "",
		x1:         width,
		y1:         height,
		cursorX:    0,
		cursorY:    height - 1, //Last line is at height -1
		showCursor: true,
	}
	return &Less{
		view, nil,
	}
}

//Focus sets the view as active, it starts handling terminal events
//and user actions
func (less *Less) Focus(keyboardQueue <-chan termbox.Event) error {
	clear()
	if err := less.Render(); err != nil {
		return err
	}
	termbox.Flush()
	inputMode := false
	inputBoxEventChan := make(chan termbox.Event)
	inputBoxOuput := make(chan string, 1)
	defer close(inputBoxOuput)
	defer close(inputBoxEventChan)
loop:
	for {
		select {
		case input := <-inputBoxOuput:
			inputMode = false
			less.Search(input)
			clear()
			if err := less.Render(); err != nil {
				return err
			}
			termbox.Flush()
		case event := <-keyboardQueue:
			switch event.Type {
			case termbox.EventKey:
				if !inputMode {
					if event.Key == termbox.KeyEsc {
						break loop
					} else if event.Key == termbox.KeyArrowDown { //cursor down
						less.ScrollDown()
					} else if event.Key == termbox.KeyArrowUp { // cursor up
						less.ScrollUp()
					} else if event.Key == termbox.KeyPgdn { //cursor one page down
						less.ScrollPageDown()
					} else if event.Key == termbox.KeyPgup { // cursor one page up
						less.ScrollPageUp()
					} else if event.Ch == 'N' { //to the top of the view
						less.gotoPreviousSearchHit()
					} else if event.Ch == 'n' { //to the bottom of the view
						less.gotoNextSearchHit()
					} else if event.Ch == 'g' { //to the top of the view
						less.ScrollToTop()
					} else if event.Ch == 'G' { //to the bottom of the view
						less.ScrollToBottom()
					} else if event.Ch == '/' {
						inputMode = true
						less.tainted = false
						go less.readInput(inputBoxEventChan, inputBoxOuput)
					}

					if less.tainted {
						clear()
						if err := less.Render(); err != nil {
							return err
						}
						termbox.Flush()
					}
				} else {
					inputBoxEventChan <- event
				}
			}
		}
	}
	return nil
}

//Search searchs in the view buffer the given pattern
func (less *Less) Search(pattern string) error {
	if pattern != "" {
		less.tainted = true
		searchResult, err := search.NewSearch(less.lines, pattern)
		if err == nil {
			less.searchResult = searchResult
			_, y := less.Position()
			searchResult.InitialLine(y)
		} else {
			return err
		}
	} else {
		less.searchResult = nil
	}
	return nil
}

func (less *Less) readInput(inputBoxEventChan chan termbox.Event, inputBoxOuput chan string) error {
	_, height := less.ViewSize()
	eb := NewInputBox(0, height, "/", inputBoxOuput, inputBoxEventChan)
	eb.Focus()
	return nil
}

// Render renders the view buffer contents.
func (less *Less) Render() error {
	_, maxY := less.renderSize()

	//less.prepareViewForRender()

	y := 0
	for i, vline := range less.lines {
		if i < less.bufferY {
			continue
		}
		if y > maxY {
			break
		}
		less.renderLine(0, y, string(vline))
		y++
	}

	less.renderMessage()
	less.drawCursor()
	return nil
}

//ScrollDown moves the cursor down one line
func (less *Less) ScrollDown() {
	less.scrollDown(1)
}

//ScrollUp moves the cursor up one line
func (less *Less) ScrollUp() {
	less.scrollUp(1)
}

//ScrollPageDown moves the buffer position down by the length of the screen,
//at the end of buffer it also moves the cursor position to the bottom
//of the screen
func (less *Less) ScrollPageDown() {
	_, height := less.ViewSize()
	less.scrollDown(height)
}

//ScrollPageUp moves the buffer position up by the length of the screen,
//at the beginning of buffer it also moves the cursor position to the beginning
//of the screen
func (less *Less) ScrollPageUp() {
	_, height := less.ViewSize()
	less.scrollUp(height)
}

//ScrollToBottom moves the cursor to the bottom of the view buffer
func (less *Less) ScrollToBottom() {
	less.bufferY = less.bufferSize() - less.y1
	less.tainted = true

}

//ScrollToTop moves the cursor to the top of the view buffer
func (less *Less) ScrollToTop() {
	less.bufferY = 0
	less.tainted = true

}

func (less *Less) atTheStartOfBuffer() bool {
	_, y := less.Position()
	if y == 0 {
		return true
	}
	return false
}

func (less *Less) atTheEndOfBuffer() bool {
	viewLength := less.bufferSize()
	_, y := less.Position()
	_, height := less.ViewSize()
	if y+height >= viewLength-1 {
		return true
	}
	return false
}

func (less *Less) bufferSize() int {
	return len(less.lines)
}

func (less *Less) gotoPreviousSearchHit() {
	sr := less.searchResult
	if sr != nil {
		x, _ := less.Position()
		if newy, err := sr.PreviousLine(); err == nil {
			less.setPosition(x, newy)
		}
	}
}
func (less *Less) gotoNextSearchHit() {
	sr := less.searchResult
	if sr != nil {
		x, _ := less.Position()
		if newy, err := sr.NextLine(); err == nil {
			less.setPosition(x, newy)
		}
	}
}

//renderSize return the part of the view size available for rendering.
func (less *Less) renderSize() (int, int) {
	maxX, maxY := less.ViewSize()
	return maxX, maxY - 1
}

func (less *Less) renderLine(x int, y int, line string) error {
	var fg, bg = termbox.ColorDefault, termbox.ColorDefault
	for _, token := range strings.Fields(line) {
		if less.searchResult != nil && strings.Contains(token, less.searchResult.Pattern) {
			fg = termbox.ColorYellow
		}
		renderString(x, y, line, fg, bg)
	}
	return nil
}

//scrollDown moves the buffer position down by the given number of lines
func (less *Less) scrollDown(lines int) {
	_, height := less.ViewSize()
	viewLength := less.bufferSize()

	posX, posY := less.Position()
	//This is a down as scrolling can go
	maxY := viewLength - height
	if posY+lines < maxY {
		newOy := posY + lines
		if newOy >= viewLength {
			less.setPosition(posX, viewLength-height)
		} else {
			less.setPosition(posX, newOy)
		}
	} else {

		less.ScrollToBottom()
	}
	less.tainted = true
}

//scrollUp moves the buffer position up by the given number of lines
func (less *Less) scrollUp(lines int) {
	ox, bufferY := less.Position()
	if bufferY-lines >= 0 {
		less.setPosition(ox, bufferY-lines)
	} else {
		less.setPosition(ox, 0)
	}
	less.tainted = true
}

func (less *Less) renderMessage() {
	_, maxY := less.ViewSize()
	var cursorX = 1
	switch {
	case less.searchResult != nil:
		{
			renderString(0, maxY, less.searchResult.String(), termbox.ColorWhite, termbox.ColorDefault)
			cursorX = len(less.searchResult.String())
		}
	case !less.atTheEndOfBuffer() && !less.atTheStartOfBuffer():
		termbox.SetCell(0, maxY, ':', termbox.ColorDefault, termbox.ColorDefault)
	case less.atTheStartOfBuffer():
		renderString(0, maxY, starttext, termbox.ColorWhite, termbox.ColorDefault)
		cursorX = len(starttext)
	default:
		{
			renderString(0, maxY, endtext, termbox.ColorWhite, termbox.ColorDefault)
			cursorX = len(endtext)
		}
	}
	less.cursorX = cursorX
}

func (less *Less) drawCursor() {
	x, y := less.Cursor()

	termbox.SetCursor(x, y)
}

func clear() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	termbox.Flush()
}
<commit_msg>Refresh less-like view on first write<commit_after>package ui

import (
	"strings"
	"time"

	"github.com/moncho/dry/search"
	"github.com/nsf/termbox-go"
)

const (
	endtext   = "(end)"
	starttext = "(start)"
)

//Less is a View with less-like behaviour and characteristics, meaning:
// * The cursor is always shown at the bottom of the screen
type Less struct {
	*View
	searchResult *search.Result
}

//NewLess creates a view that partially simulates less.
func NewLess() *Less {
	width, height := termbox.Size()
	view := &View{
		name:       "",
		x1:         width,
		y1:         height,
		cursorX:    0,
		cursorY:    height - 1, //Last line is at height -1
		showCursor: true,
	}
	return &Less{
		view, nil,
	}
}

//Focus sets the view as active, so it starts handling terminal events
//and user actions
func (less *Less) Focus(events <-chan termbox.Event) error {
	clear()
	if err := less.Render(); err != nil {
		return err
	}
	termbox.Flush()
	inputMode := false
	inputBoxEventChan := make(chan termbox.Event)
	inputBoxOuput := make(chan string, 1)
	//the first render is done when some content is added to the buffer
	go func() {
		for {
			if less.bufferSize() > 0 {
				less.Render()
				termbox.Flush()
				return
			}
			time.Sleep(250 * time.Millisecond)
		}
	}()
	defer close(inputBoxOuput)
	defer close(inputBoxEventChan)
loop:
	for {
		select {
		case input := <-inputBoxOuput:
			inputMode = false
			less.Search(input)
			clear()
			if err := less.Render(); err != nil {
				return err
			}
			termbox.Flush()
		case event := <-events:
			switch event.Type {
			case termbox.EventKey:
				if !inputMode {
					if event.Key == termbox.KeyEsc {
						break loop
					} else if event.Key == termbox.KeyArrowDown { //cursor down
						less.ScrollDown()
					} else if event.Key == termbox.KeyArrowUp { // cursor up
						less.ScrollUp()
					} else if event.Key == termbox.KeyPgdn { //cursor one page down
						less.ScrollPageDown()
					} else if event.Key == termbox.KeyPgup { // cursor one page up
						less.ScrollPageUp()
					} else if event.Ch == 'N' { //to the top of the view
						less.gotoPreviousSearchHit()
					} else if event.Ch == 'n' { //to the bottom of the view
						less.gotoNextSearchHit()
					} else if event.Ch == 'g' { //to the top of the view
						less.ScrollToTop()
					} else if event.Ch == 'G' { //to the bottom of the view
						less.ScrollToBottom()
					} else if event.Ch == '/' {
						inputMode = true
						less.tainted = false
						go less.readInput(inputBoxEventChan, inputBoxOuput)
					}

					if less.tainted {
						clear()
						if err := less.Render(); err != nil {
							return err
						}
						termbox.Flush()
					}
				} else {
					inputBoxEventChan <- event
				}
			}
		}
	}
	return nil
}

//Search searchs in the view buffer for the given pattern
func (less *Less) Search(pattern string) error {
	if pattern != "" {
		less.tainted = true
		searchResult, err := search.NewSearch(less.lines, pattern)
		if err == nil {
			less.searchResult = searchResult
			_, y := less.Position()
			searchResult.InitialLine(y)
		} else {
			return err
		}
	} else {
		less.searchResult = nil
	}
	return nil
}

func (less *Less) readInput(inputBoxEventChan chan termbox.Event, inputBoxOuput chan string) error {
	_, height := less.ViewSize()
	eb := NewInputBox(0, height, "/", inputBoxOuput, inputBoxEventChan)
	eb.Focus()
	return nil
}

// Render renders the view buffer contents.
func (less *Less) Render() error {
	_, maxY := less.renderSize()

	//less.prepareViewForRender()

	y := 0
	for i, vline := range less.lines {
		if i < less.bufferY {
			continue
		}
		if y > maxY {
			break
		}
		less.renderLine(0, y, string(vline))
		y++
	}

	less.renderMessage()
	less.drawCursor()
	return nil
}

//ScrollDown moves the cursor down one line
func (less *Less) ScrollDown() {
	less.scrollDown(1)
}

//ScrollUp moves the cursor up one line
func (less *Less) ScrollUp() {
	less.scrollUp(1)
}

//ScrollPageDown moves the buffer position down by the length of the screen,
//at the end of buffer it also moves the cursor position to the bottom
//of the screen
func (less *Less) ScrollPageDown() {
	_, height := less.ViewSize()
	less.scrollDown(height)
}

//ScrollPageUp moves the buffer position up by the length of the screen,
//at the beginning of buffer it also moves the cursor position to the beginning
//of the screen
func (less *Less) ScrollPageUp() {
	_, height := less.ViewSize()
	less.scrollUp(height)
}

//ScrollToBottom moves the cursor to the bottom of the view buffer
func (less *Less) ScrollToBottom() {
	less.bufferY = less.bufferSize() - less.y1
	less.tainted = true

}

//ScrollToTop moves the cursor to the top of the view buffer
func (less *Less) ScrollToTop() {
	less.bufferY = 0
	less.tainted = true

}

func (less *Less) atTheStartOfBuffer() bool {
	_, y := less.Position()
	if y == 0 {
		return true
	}
	return false
}

func (less *Less) atTheEndOfBuffer() bool {
	viewLength := less.bufferSize()
	_, y := less.Position()
	_, height := less.ViewSize()
	if y+height >= viewLength-1 {
		return true
	}
	return false
}

func (less *Less) bufferSize() int {
	return len(less.lines)
}

func (less *Less) gotoPreviousSearchHit() {
	sr := less.searchResult
	if sr != nil {
		x, _ := less.Position()
		if newy, err := sr.PreviousLine(); err == nil {
			less.setPosition(x, newy)
		}
	}
}
func (less *Less) gotoNextSearchHit() {
	sr := less.searchResult
	if sr != nil {
		x, _ := less.Position()
		if newy, err := sr.NextLine(); err == nil {
			less.setPosition(x, newy)
		}
	}
}

//renderSize return the part of the view size available for rendering.
func (less *Less) renderSize() (int, int) {
	maxX, maxY := less.ViewSize()
	return maxX, maxY - 1
}

func (less *Less) renderLine(x int, y int, line string) error {
	var fg, bg = termbox.ColorDefault, termbox.ColorDefault
	for _, token := range strings.Fields(line) {
		if less.searchResult != nil && strings.Contains(token, less.searchResult.Pattern) {
			fg = termbox.ColorYellow
		}
		renderString(x, y, line, fg, bg)
	}
	return nil
}

//scrollDown moves the buffer position down by the given number of lines
func (less *Less) scrollDown(lines int) {
	_, height := less.ViewSize()
	viewLength := less.bufferSize()

	posX, posY := less.Position()
	//This is a down as scrolling can go
	maxY := viewLength - height
	if posY+lines < maxY {
		newOy := posY + lines
		if newOy >= viewLength {
			less.setPosition(posX, viewLength-height)
		} else {
			less.setPosition(posX, newOy)
		}
	} else {

		less.ScrollToBottom()
	}
	less.tainted = true
}

//scrollUp moves the buffer position up by the given number of lines
func (less *Less) scrollUp(lines int) {
	ox, bufferY := less.Position()
	if bufferY-lines >= 0 {
		less.setPosition(ox, bufferY-lines)
	} else {
		less.setPosition(ox, 0)
	}
	less.tainted = true
}

func (less *Less) renderMessage() {
	_, maxY := less.ViewSize()
	var cursorX = 1
	switch {
	case less.searchResult != nil:
		{
			renderString(0, maxY, less.searchResult.String(), termbox.ColorWhite, termbox.ColorDefault)
			cursorX = len(less.searchResult.String())
		}
	case !less.atTheEndOfBuffer() && !less.atTheStartOfBuffer():
		termbox.SetCell(0, maxY, ':', termbox.ColorDefault, termbox.ColorDefault)
	case less.atTheStartOfBuffer():
		renderString(0, maxY, starttext, termbox.ColorWhite, termbox.ColorDefault)
		cursorX = len(starttext)
	default:
		{
			renderString(0, maxY, endtext, termbox.ColorWhite, termbox.ColorDefault)
			cursorX = len(endtext)
		}
	}
	less.cursorX = cursorX
}

func (less *Less) drawCursor() {
	x, y := less.Cursor()

	termbox.SetCursor(x, y)
}

func clear() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	termbox.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gorilla/websocket"
	"github.com/gin-gonic/gin"
	"fmt"
)

var ws = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

var connections []*websocket.Conn

func handleWsRoute(c *gin.Context) {
	// Upgrade the connection to a websocket connection
	conn, err := ws.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Println("Failed to upgrade websocket: %s", err)
		return
	}

	// Get the session for the current connection
	session, err := store.Get(c.Request, "user")
	if err != nil {
		fmt.Println("Error trying to get session: %s", err)
	}

	// Set a session value for our connection id
	session.Values["conn_id"] = len(connections)

	// Figure out who the user is and get their db row
	user := GetUser(session.Values["username"].(string))

	fmt.Println(user)

	// Add the connection to the list
	connections = append(connections, conn)

	// Prepare insert statements for new messages
	stmt, err := db.Prepare("INSERT INTO messages(sender, receiver, message) VALUES(?, ?, ?)")
	if err != nil {
		fmt.Println("Error preparing database statement: %s", err)
	}

	for {
		var event Event
		err := conn.ReadJSON(&event)
		if err != nil {
			// The connection is being closed
			i := session.Values["conn_id"].(int)
			// Remove the connection from our slice of connections
			connections = append(connections[:i], connections[i+1:]...)
			// Now break out of the for loop since we're done
			break
		}

		// Figure out who the receiver is
		receiver := GetUser(event.Message.Receiver)

		// Add a new message into the database
		stmt.Exec(user.Id, receiver.Id, event.Message.Message)

		// Broadcast to everyone currently.
		for _, c := range connections {
			c.WriteJSON(&Message{
				Sender: user.Username,
				Message: event.Message.Message,
				Receiver: event.Message.Receiver,
			})
		}
	}
}
<commit_msg>Adding a wrapper around *websocket.Conn<commit_after>package main

import (
	"github.com/gorilla/websocket"
	"github.com/gin-gonic/gin"
	"fmt"
)

var ws = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

type Conn struct {
	conn *websocket.Conn
}

var connections []*Conn

func handleWsRoute(c *gin.Context) {
	// Upgrade the connection to a websocket connection
	conn, err := ws.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Println("Failed to upgrade websocket: %s", err)
		return
	}

	// Get the session for the current connection
	session, err := store.Get(c.Request, "user")
	if err != nil {
		fmt.Println("Error trying to get session: %s", err)
	}

	// Set a session value for our connection id
	session.Values["conn_id"] = len(connections)

	// Figure out who the user is and get their db row
	user := GetUser(session.Values["username"].(string))

	fmt.Println(user)

	// Add the connection to the list
	connections = append(connections, &Conn{
		conn: conn,
	})

	// Prepare insert statements for new messages
	stmt, err := db.Prepare("INSERT INTO messages(sender, receiver, message) VALUES(?, ?, ?)")
	if err != nil {
		fmt.Println("Error preparing database statement: %s", err)
	}

	for {
		var event Event
		err := conn.ReadJSON(&event)
		if err != nil {
			// The connection is being closed
			i := session.Values["conn_id"].(int)
			// Remove the connection from our slice of connections
			connections = append(connections[:i], connections[i+1:]...)
			// Now break out of the for loop since we're done
			break
		}

		// Figure out who the receiver is
		receiver := GetUser(event.Message.Receiver)

		// Add a new message into the database
		stmt.Exec(user.Id, receiver.Id, event.Message.Message)

		// Broadcast to everyone currently.
		for _, c := range connections {
			c.conn.WriteJSON(&Message{
				Sender: user.Username,
				Message: event.Message.Message,
				Receiver: event.Message.Receiver,
			})
		}
	}
}
<|endoftext|>


<commit_before>package svfs

import (
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/ncw/swift"
)

var (
	SwiftConnection *swift.Connection
)

// SVFS implements the Swift Virtual File System.
type SVFS struct {
	conf *Config
}

type Config struct {
	Container             string
	ConnectTimeout        time.Duration
	ReadAheadSize         uint
	MaxReaddirConcurrency uint64
}

func (s *SVFS) Init(sc *swift.Connection, conf *Config, cconf *CacheConfig) error {
	s.conf = conf
	SwiftConnection = sc
	SwiftConnection.ConnectTimeout = conf.ConnectTimeout
	EntryCache = NewCache(cconf)
	DirectoryLister = &DirLister{concurrency: conf.MaxReaddirConcurrency}

	// Authenticate if we don't have a token
	// and storage URL
	if !SwiftConnection.Authenticated() {
		return SwiftConnection.Authenticate()
	}

	// Start directory lister
	DirectoryLister.Start()

	return nil
}

func (s *SVFS) Root() (fs.Node, error) {
	if s.conf.Container != "" {
		// If a specific container is specified
		// in mount options, find it and relevant
		// segment container too if present.
		baseC, _, err := SwiftConnection.Container(s.conf.Container)
		if err != nil {
			return nil, fuse.ENOENT
		}
		segC, _, err := SwiftConnection.Container(s.conf.Container + "_segments")
		if err != nil && err != swift.ContainerNotFound {
			return nil, fuse.EIO
		}

		return &Container{
			Directory: &Directory{
				apex: true,
				c:    &baseC,
			},
			cs: &segC,
		}, nil
	}
	return &Root{
		Directory: &Directory{
			apex: true,
		},
	}, nil
}

var _ fs.FS = (*SVFS)(nil)
<commit_msg>Fixed directory lister execution<commit_after>package svfs

import (
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/ncw/swift"
)

var (
	SwiftConnection *swift.Connection
)

// SVFS implements the Swift Virtual File System.
type SVFS struct {
	conf *Config
}

type Config struct {
	Container             string
	ConnectTimeout        time.Duration
	ReadAheadSize         uint
	MaxReaddirConcurrency uint64
}

func (s *SVFS) Init(sc *swift.Connection, conf *Config, cconf *CacheConfig) error {
	s.conf = conf
	SwiftConnection = sc
	SwiftConnection.ConnectTimeout = conf.ConnectTimeout
	EntryCache = NewCache(cconf)
	DirectoryLister = &DirLister{concurrency: conf.MaxReaddirConcurrency}

	// Start directory lister
	DirectoryLister.Start()

	// Authenticate if we don't have a token
	// and storage URL
	if !SwiftConnection.Authenticated() {
		return SwiftConnection.Authenticate()
	}

	return nil
}

func (s *SVFS) Root() (fs.Node, error) {
	if s.conf.Container != "" {
		// If a specific container is specified
		// in mount options, find it and relevant
		// segment container too if present.
		baseC, _, err := SwiftConnection.Container(s.conf.Container)
		if err != nil {
			return nil, fuse.ENOENT
		}
		segC, _, err := SwiftConnection.Container(s.conf.Container + "_segments")
		if err != nil && err != swift.ContainerNotFound {
			return nil, fuse.EIO
		}

		return &Container{
			Directory: &Directory{
				apex: true,
				c:    &baseC,
			},
			cs: &segC,
		}, nil
	}
	return &Root{
		Directory: &Directory{
			apex: true,
		},
	}, nil
}

var _ fs.FS = (*SVFS)(nil)
<|endoftext|>


<commit_before>package hello

import (
    "fmt"
    "net/http"
)

func init() {
    http.HandleFunc("/svg/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, world!")
}
<commit_msg>set up<commit_after>package hello

import (
    "fmt"
    "net/http"
    "time"
)

func init() {
    http.HandleFunc("/svg/month", handler)
}

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

text := r.URL.Query().Get("text")
width := r.URL.Query().Get("width")
if width == "" {
   width = "300"
}

height := r.URL.Query().Get("height")
if height  == "" {
   height = "20"
}
dy := r.URL.Query().Get("dy")

if dy  == "" {
   dy = "-2.6em"
}

fill := r.URL.Query().Get("fill")

if fill  == "" {
   fill = "000000"
}

format := r.URL.Query().Get("format")

if format  == "" {
   format = "January 2006"
}

if text == "" {
   text = time.Now().Format(format)
} else {
   text = text + " " + time.Now().Format(format)
}
    w.Header().Set("Content-Type","image/svg+xml")

   output := fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  viewBox="0 0 %s %s">

    <text text-anchor="left"  style="font-family: Arial, Helvetica, Verdana" font-weight="bold" fill="#%s" dy='%s' font-size="ANY SIZE">%s</text>
</svg>`, width, height, fill, dy, text)

  //  w.Header().Set("Content-Length", fmt.Sprintf("%d",len(output)))
    fmt.Fprint(w, output)
}
<|endoftext|>


<commit_before>package svn

import (
	"encoding/xml"
	"fmt"
	"strconv"

	"github.com/pkg/errors"
)

type Log struct {
	XMLName   xml.Name   `xml:"log"`
	Revisions []Revision `xml:"logentry"`
}

type Revision struct {
	*Commit
	XMLName xml.Name `xml:"logentry"`
	Paths   []Path   `xml:"paths>path"`
	Message string   `xml:"msg"`
}

type Path struct {
	XMLName               xml.Name `xml:"path"`
	TextModifications     bool     `xml:"text-mods,attr"`
	Kind                  string   `xml:"kind,attr"`
	CopyFromPath          *string  `xml:"copyfrom-path,attr,omitempty"`
	CopyFromRevision      *int     `xml:"copyfrom-rev,attr,omitempty"`
	Action                string   `xml:"action,attr"`
	PropertyModifications bool     `xml:"prop-mods,attr"`
	Name                  string   `xml:",chardata"`
}

func GetLog(address string) (*Log, error) {
	log := Log{}

	if err := Execute(&log, "log", "--xml", "--verbose", address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s", address)
	}

	return &log, nil
}

func GetLogRange(address string, start int, end *int) (*Log, error) {
	log := Log{}

	revision := strconv.Itoa(start) + ":"

	if end == nil {
		revision += "HEAD"
	} else {
		revision += strconv.Itoa(*end)
	}

	if err := Execute(&log, "log", "--xml", "--verbose", "--revision", revision, address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s (revision %d)", address, revision)
	}

	return &log, nil
}

func GetRevision(address string, revision int) (*Revision, error) {
	log := Log{}

	if err := Execute(&log, "log", "--xml", "--verbose", "--revision", strconv.Itoa(revision), address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s (revision %d)", address, revision)
	}

	if len(log.Revisions) != 1 {
		return nil, fmt.Errorf("found %d log entries but expected 1 for %s (revison %d)", len(log.Revisions), address, revision)
	}

	return &log.Revisions[0], nil
}

func GetLatestRevision(address string) (*Revision, error) {
	log := Log{}

	if err := Execute(&log, "log", "--xml", "--verbose", "--limit", "1", address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s", address)
	}

	if len(log.Revisions) != 1 {
		return nil, fmt.Errorf("found %d log entries but expected 1 for %s", len(log.Revisions), address)
	}

	return &log.Revisions[0], nil
}
<commit_msg>Make log type private and return arrays of revisions instead<commit_after>package svn

import (
	"encoding/xml"
	"fmt"
	"strconv"

	"github.com/pkg/errors"
)

type log struct {
	XMLName   xml.Name   `xml:"log"`
	Revisions []Revision `xml:"logentry"`
}

type Revision struct {
	*Commit
	XMLName xml.Name `xml:"logentry"`
	Paths   []Path   `xml:"paths>path"`
	Message string   `xml:"msg"`
}

type Path struct {
	XMLName               xml.Name `xml:"path"`
	TextModifications     bool     `xml:"text-mods,attr"`
	Kind                  string   `xml:"kind,attr"`
	CopyFromPath          *string  `xml:"copyfrom-path,attr,omitempty"`
	CopyFromRevision      *int     `xml:"copyfrom-rev,attr,omitempty"`
	Action                string   `xml:"action,attr"`
	PropertyModifications bool     `xml:"prop-mods,attr"`
	Name                  string   `xml:",chardata"`
}

func GetLog(address string) ([]Revision, error) {
	log := log{}

	if err := Execute(&log, "log", "--xml", "--verbose", address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s", address)
	}

	return log.Revisions, nil
}

func GetLogRange(address string, start int, end *int) ([]Revision, error) {
	log := log{}

	revision := strconv.Itoa(start) + ":"

	if end == nil {
		revision += "HEAD"
	} else {
		revision += strconv.Itoa(*end)
	}

	if err := Execute(&log, "log", "--xml", "--verbose", "--revision", revision, address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s (revision %d)", address, revision)
	}

	return log.Revisions, nil
}

func GetRevision(address string, revision int) (*Revision, error) {
	log := log{}

	if err := Execute(&log, "log", "--xml", "--verbose", "--revision", strconv.Itoa(revision), address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s (revision %d)", address, revision)
	}

	if len(log.Revisions) != 1 {
		return nil, fmt.Errorf("found %d log entries but expected 1 for %s (revison %d)", len(log.Revisions), address, revision)
	}

	return &log.Revisions[0], nil
}

func GetLatestRevision(address string) (*Revision, error) {
	log := log{}

	if err := Execute(&log, "log", "--xml", "--verbose", "--limit", "1", address); err != nil {
		return nil, errors.Wrapf(err, "failed to get log for %s", address)
	}

	if len(log.Revisions) != 1 {
		return nil, fmt.Errorf("found %d log entries but expected 1 for %s", len(log.Revisions), address)
	}

	return &log.Revisions[0], nil
}
<|endoftext|>


<commit_before>package upframe

import (
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/gorilla/sessions"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/upframe/fest/pages"
)

// Upframe is the startup struct
type Upframe struct {
	Next httpserver.Handler
	Root string
}

func (u Upframe) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// Checks if a static file (not directory) exists for this path. If it doesn't, we
	// handle the request.
	if info, err := os.Stat(u.Root + r.URL.Path); !(os.IsNotExist(err) || info.IsDir()) {
		return u.Next.ServeHTTP(w, r)
	}

	// Gets the current session or creates a new one if there is some error
	// decrypting it or if it doesn't exist
	s, _ := store.Get(r, "upframe-auth")

	// If it is a new session, initialize it, setting 'IsLoggedIn' as false
	if s.IsNew {
		s.Values["IsLoggedIn"] = false
	}

	// Saves the session in the cookie and checks for errors. This is useful
	// to reset the expiration time.
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Routes the pages to the respective functions
	switch {
	case r.URL.Path == "/" && r.Method == http.MethodGet:
		return pages.IndexGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodGet:
		return pages.RegisterGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodPost:
		return pages.RegisterPOST(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodGet:
		return pages.LoginGET(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodPost:
		return pages.LoginPOST(w, r, s)
	case r.URL.Path == "/settings" && r.Method == http.MethodGet:
		return pages.SettingsGET(w, r, s)
	case r.URL.Path == "/store" && r.Method == http.MethodGet:
		return pages.StoreGET(w, r, s)
	case r.URL.Path == "/cart" && r.Method == http.MethodGet:
		return pages.CartGET(w, r, s)
	case r.URL.Path == "/checkout" && r.Method == http.MethodGet:
		return pages.CheckoutGET(w, r, s)
	case r.URL.Path == "/logout":
		return logout(w, r, s)
	}

	// Admin router: if the user is an admin and the page starts with /admin
	if pages.IsAdmin(s) && strings.HasPrefix(r.URL.Path, "/admin") {
		if strings.HasPrefix(r.URL.Path, "/admin/promocodes") {
			switch r.Method {
			case http.MethodGet:
				return pages.AdminPromocodesGET(w, r, s)
			case http.MethodPost:
				return pages.AdminPromocodesPOST(w, r)
			case http.MethodDelete:
				return pages.AdminPromocodesDELETE(w, r)
			case http.MethodPut:
				return pages.AdminPromocodesPUT(w, r)
			}
		}
	}

	// If the request doesn't match any route and it isn't a GET request
	// return a Status Not Implemented
	if r.Method != http.MethodGet {
		return http.StatusNotImplemented, nil
	}

	// Checks if there is a static template for this page. If so, show it!
	if _, err := os.Stat(filepath.Clean("templates/static" + r.URL.Path + ".tmpl")); err == nil {
		return pages.RenderHTML(w, nil, r.URL.Path)
	}

	// Return 404 Not Found for the rest
	return http.StatusNotFound, nil
}

// logout resets the session values and saves the cookie
func logout(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	// Reset the session values
	s.Values = map[interface{}]interface{}{}
	s.Values["IsLoggedIn"] = false

	// Saves the session and checks for error
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}
<commit_msg>add admin functions to router<commit_after>package upframe

import (
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/gorilla/sessions"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/upframe/fest/pages"
)

// Upframe is the startup struct
type Upframe struct {
	Next httpserver.Handler
	Root string
}

func (u Upframe) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// Checks if a static file (not directory) exists for this path. If it doesn't, we
	// handle the request.
	if info, err := os.Stat(u.Root + r.URL.Path); !(os.IsNotExist(err) || info.IsDir()) {
		return u.Next.ServeHTTP(w, r)
	}

	// Gets the current session or creates a new one if there is some error
	// decrypting it or if it doesn't exist
	s, _ := store.Get(r, "upframe-auth")

	// If it is a new session, initialize it, setting 'IsLoggedIn' as false
	if s.IsNew {
		s.Values["IsLoggedIn"] = false
	}

	// Saves the session in the cookie and checks for errors. This is useful
	// to reset the expiration time.
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Routes the pages to the respective functions
	switch {
	case r.URL.Path == "/" && r.Method == http.MethodGet:
		return pages.IndexGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodGet:
		return pages.RegisterGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodPost:
		return pages.RegisterPOST(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodGet:
		return pages.LoginGET(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodPost:
		return pages.LoginPOST(w, r, s)
	case r.URL.Path == "/settings" && r.Method == http.MethodGet:
		return pages.SettingsGET(w, r, s)
	case r.URL.Path == "/store" && r.Method == http.MethodGet:
		return pages.StoreGET(w, r, s)
	case r.URL.Path == "/cart" && r.Method == http.MethodGet:
		return pages.CartGET(w, r, s)
	case r.URL.Path == "/checkout" && r.Method == http.MethodGet:
		return pages.CheckoutGET(w, r, s)
	case r.URL.Path == "/logout":
		return logout(w, r, s)
	}

	// Admin router: if the user is an admin and the page starts with /admin
	if pages.IsAdmin(s) && strings.HasPrefix(r.URL.Path, "/admin") {
		if strings.HasPrefix(r.URL.Path, "/admin/promocodes") {
			switch r.Method {
			case http.MethodGet:
				return pages.AdminPromocodesGET(w, r, s)
			case http.MethodPost:
				return pages.AdminPromocodesPOST(w, r)
			case http.MethodDelete:
				return pages.AdminPromocodesDELETE(w, r)
			case http.MethodPut:
				return pages.AdminPromocodesPUT(w, r)
			}
		}

		if strings.HasPrefix(r.URL.Path, "/admin/orders") {
			switch r.Method {
			case http.MethodGet:
				return pages.AdminOrdersGET(w, r, s)
			case http.MethodPost:
				return pages.AdminOrdersPOST(w, r)
			case http.MethodDelete:
				return pages.AdminOrdersDELETE(w, r)
			case http.MethodPut:
				return pages.AdminOrdersPUT(w, r)
			}
		}

		if strings.HasPrefix(r.URL.Path, "/admin/users") {
			switch r.Method {
			case http.MethodGet:
				return pages.AdminUsersGET(w, r, s)
			case http.MethodPost:
				return pages.AdminUsersPOST(w, r)
			case http.MethodDelete:
				return pages.AdminUsersDELETE(w, r)
			case http.MethodPut:
				return pages.AdminUsersPUT(w, r)
			}
		}

		if strings.HasPrefix(r.URL.Path, "/admin/products") {
			switch r.Method {
			case http.MethodGet:
				return pages.AdminProductsGET(w, r, s)
			case http.MethodPost:
				return pages.AdminProductsPOST(w, r)
			case http.MethodDelete:
				return pages.AdminProductsDELETE(w, r)
			case http.MethodPut:
				return pages.AdminProductsPUT(w, r)
			}
		}
	}

	// If the request doesn't match any route and it isn't a GET request
	// return a Status Not Implemented
	if r.Method != http.MethodGet {
		return http.StatusNotImplemented, nil
	}

	// Checks if there is a static template for this page. If so, show it!
	if _, err := os.Stat(filepath.Clean("templates/static" + r.URL.Path + ".tmpl")); err == nil {
		return pages.RenderHTML(w, nil, r.URL.Path)
	}

	// Return 404 Not Found for the rest
	return http.StatusNotFound, nil
}

// logout resets the session values and saves the cookie
func logout(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	// Reset the session values
	s.Values = map[interface{}]interface{}{}
	s.Values["IsLoggedIn"] = false

	// Saves the session and checks for error
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}
<|endoftext|>


<commit_before>package gohm

import (
	"bytes"
	"context"
	"net/http"
	"strconv"
	"sync/atomic"
	"time"

	"github.com/karrick/gorill"
)

// New returns a new http.Handler that calls the specified next http.Handler,
// and performs the requested operations before and after the downstream handler
// as specified by the gohm.Config structure passed to it.
//
// It receives a gohm.Config struct rather than a pointer to one, so users less
// likely to consider modification after creating the http.Handler.
//
//  // Used to control how long it takes to serve a static file.
//	const staticTimeout = time.Second
//
//	var (
//		// Will store statistics counters for status codes 1xx, 2xx, 3xx, 4xx,
//		// 5xx, as well as a counter for all responses
//		counters gohm.Counters
//
//		// Used to dynamically control log level of HTTP logging. After handler
//      // created, this must be accessed using the sync/atomic package.
//		logBitmask = gohm.LogStatusErrors
//
//		// Determines HTTP log format
//		logFormat = "{http-CLIENT-IP} {client-ip} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration} {message}"
//	)
//
//	func main() {
//
//		h := http.StripPrefix("/static/", http.FileServer(http.Dir("static")))
//
//		h = gohm.WithGzip(h) // gzip response if client accepts gzip encoding
//
//		// gohm was designed to wrap other http.Handler functions.
//		h = gohm.New(h, gohm.Config{
//			Counters:   &counters,   // pointer given so counters can be collected and optionally reset
//			LogBitmask: &logBitmask, // pointer given so bitmask can be updated using sync/atomic
//			LogFormat:  logFormat,
//			LogWriter:  os.Stderr,
//			Timeout:    staticTimeout,
//		})
//
//		http.Handle("/static/", h)
//		log.Fatal(http.ListenAndServe(":8080", nil))
//	}
func New(next http.Handler, config Config) http.Handler {
	var emitters []func(*responseWriter, *http.Request, *[]byte)
	var loggedHeaders []string

	if config.LogWriter != nil {
		if config.LogBitmask == nil {
			// Set a default bitmask to log all requests
			logBitmask := LogStatusAll
			config.LogBitmask = &logBitmask
		}
		if config.LogFormat == "" {
			// Set a default log line format
			config.LogFormat = DefaultLogFormat
		}
		emitters, loggedHeaders = compileFormat(config.LogFormat)
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var er *gorill.EscrowReader
		var hm map[string]string

		if len(loggedHeaders) > 0 {
			// When any request headers are to be logged, this must copy the
			// respective values before it creates a go routine to handle
			// request.  Otherwise, if this must later time out the invoked
			// request header before that returns, that handler might
			// concurrently try to alter request headers while this is reading
			// them to emit the log line.
			hm = make(map[string]string)
			for _, name := range loggedHeaders {
				value := r.Header.Get(name)
				if value == "" {
					value = "-"
				}
				hm[name] = value // NOTE: only saves first value, because that is all that is logged.
			}
		}

		if config.EscrowReader {
			var erb *bytes.Buffer // escrow read buffer
			if config.BufPool != nil {
				// Obtain a bytes.Buffer from the buffer pool, but use defer to
				// return the used buffer to the pool because we cannot control
				// whether the specified next http.Handler or callback function
				// will panic.
				erb = config.BufPool.Get()
				defer config.BufPool.Put(erb)
			}

			// Only pre-allocate buffer when the Content-Length parses. It would
			// be really nice to provide some signaling mechanism to the next
			// handler when the Content-Length fails to parse, but I suppose if
			// it cares, it will also check the same thing.
			if contentLengthString := r.Header.Get("Content-Length"); contentLengthString != "" {
				if contentLength, err := strconv.Atoi(contentLengthString); err == nil {
					if erb != nil {
						// Ensure existing buffer is large enough to read
						// Content-Length bytes.
						erb.Grow(contentLength)
					} else {
						// Pre-allocate a buffer large enough to read
						// Content-Length bytes.
						erb = bytes.NewBuffer(make([]byte, 0, contentLength))
					}
				}
			}

			// Update the original request's Body to point to a newly created
			// structure, from which the next handler may read the request body,
			// and from which the callback may also read the request body if
			// required.
			er = gorill.NewEscrowReader(r.Body, erb)
			r.Body = er
		}

		ctx := r.Context()

		if config.Timeout > 0 {
			// Adding a timeout to a request context spins off a goroutine that
			// will invoke the specified cancel function for us after the
			// timeout has elapsed.  Invoking the cancel function causes the
			// context's Done channel to close.  Detecting timeout is done by
			// waiting for context.Done() to close.
			var cancel func()
			ctx, cancel = context.WithTimeout(ctx, config.Timeout)
			defer cancel()
			r = r.WithContext(ctx)
		}

		var bb *bytes.Buffer
		if config.BufPool != nil {
			bb = config.BufPool.Get()
			defer config.BufPool.Put(bb)
		} else {
			bb = new(bytes.Buffer)
		}

		// Create a responseWriter to pass to next.ServeHTTP and collect
		// downstream handler's response to query.  It will eventually be used
		// to flush to the client, assuming neither the handler panics, nor the
		// client connection is detected to be closed.
		grw := &responseWriter{hrw: w, begin: time.Now(), body: bb}

		// Create a couple of channels to detect one of 3 ways to exit this
		// handler.
		handlerCompleted := make(chan struct{})
		handlerPanicked := make(chan string, 1)

		// We must invoke downstream handler in separate goroutine in order to
		// ensure this handler only responds to one of the three events below,
		// whichever event takes place first.
		go serveWithPanicProtection(grw, r, next, handlerCompleted, handlerPanicked)

		// Wait for the first of either of 3 events:
		//   * serveComplete: the next.ServeHTTP method completed normally
		//     (possibly even with an erroneous status code).
		//   * servePanicked: the next.ServeHTTP method failed to complete, and
		//     panicked instead with a text message.
		//   * context is done: triggered when timeout or client disconnect.
		select {
		case <-handlerCompleted:
			grw.handlerComplete()
		case error := <-handlerPanicked:
			if config.AllowPanics {
				panic(error) // do not need to tell downstream to cancel, because it already panicked.
			}
			grw.handlerError(error, http.StatusInternalServerError)
		case <-ctx.Done():
			// While there are several reasons why the context may be closed,
			// when it is because the client terminates the request while the
			// handler is still working, the handler might still interact with
			// the response writer given to it.  Therefore, create and use a new
			// response writer for the remaining duration of this call that the
			// handler does not have simultaneous access to it.
			grw = &responseWriter{hrw: w, begin: grw.begin, body: bytes.NewBuffer(make([]byte, 0, 128))}

			// When the context is canceled, ctx.Err() will say why.  Returning
			// a 503 because this is what http.TimeoutHandler returns for same
			// case, even though this means 503 will be logged in server log
			// when client has terminated the connection.
			grw.handlerError(ctx.Err().Error(), http.StatusServiceUnavailable)
		}

		statusClass := grw.status / 100 // integer division (429 / 100 -> 4)

		// Update status counters
		if config.Counters != nil {
			atomic.AddUint64(&config.Counters.counters[0], 1)           // all
			atomic.AddUint64(&config.Counters.counters[statusClass], 1) // 1xx, 2xx, 3xx, 4xx, 5xx
		}

		// Invoke callback if provided, prior to logging request.
		var stats *Statistics
		if config.Callback != nil {
			stats = &Statistics{
				RequestBegin:   grw.begin,
				ResponseStatus: grw.status,
				ResponseEnd:    grw.end,
			}
			if er != nil {
				stats.RequestBody = er.Bytes()
			}
			config.Callback(stats)
		}

		// Update log
		if config.LogWriter != nil {
			if (stats != nil && stats.emitLog) || (atomic.LoadUint32(config.LogBitmask))&(1<<uint32(statusClass-1)) > 0 {
				if len(loggedHeaders) > 0 {
					grw.loggedRequestHeaders = hm
				}
				buf := make([]byte, 0, 128)
				for _, emitter := range emitters {
					emitter(grw, r, &buf)
				}
				_, _ = config.LogWriter.Write(buf)
			}
		}
	})
}
<commit_msg>creates map with known length<commit_after>package gohm

import (
	"bytes"
	"context"
	"net/http"
	"strconv"
	"sync/atomic"
	"time"

	"github.com/karrick/gorill"
)

// New returns a new http.Handler that calls the specified next http.Handler,
// and performs the requested operations before and after the downstream handler
// as specified by the gohm.Config structure passed to it.
//
// It receives a gohm.Config struct rather than a pointer to one, so users less
// likely to consider modification after creating the http.Handler.
//
//  // Used to control how long it takes to serve a static file.
//	const staticTimeout = time.Second
//
//	var (
//		// Will store statistics counters for status codes 1xx, 2xx, 3xx, 4xx,
//		// 5xx, as well as a counter for all responses
//		counters gohm.Counters
//
//		// Used to dynamically control log level of HTTP logging. After handler
//      // created, this must be accessed using the sync/atomic package.
//		logBitmask = gohm.LogStatusErrors
//
//		// Determines HTTP log format
//		logFormat = "{http-CLIENT-IP} {client-ip} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration} {message}"
//	)
//
//	func main() {
//
//		h := http.StripPrefix("/static/", http.FileServer(http.Dir("static")))
//
//		h = gohm.WithGzip(h) // gzip response if client accepts gzip encoding
//
//		// gohm was designed to wrap other http.Handler functions.
//		h = gohm.New(h, gohm.Config{
//			Counters:   &counters,   // pointer given so counters can be collected and optionally reset
//			LogBitmask: &logBitmask, // pointer given so bitmask can be updated using sync/atomic
//			LogFormat:  logFormat,
//			LogWriter:  os.Stderr,
//			Timeout:    staticTimeout,
//		})
//
//		http.Handle("/static/", h)
//		log.Fatal(http.ListenAndServe(":8080", nil))
//	}
func New(next http.Handler, config Config) http.Handler {
	var emitters []func(*responseWriter, *http.Request, *[]byte)
	var loggedHeaders []string

	if config.LogWriter != nil {
		if config.LogBitmask == nil {
			// Set a default bitmask to log all requests
			logBitmask := LogStatusAll
			config.LogBitmask = &logBitmask
		}
		if config.LogFormat == "" {
			// Set a default log line format
			config.LogFormat = DefaultLogFormat
		}
		emitters, loggedHeaders = compileFormat(config.LogFormat)
	}

	lhrh := len(loggedHeaders)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var er *gorill.EscrowReader
		var hm map[string]string

		if lhrh > 0 {
			// When any request headers are to be logged, this must copy the
			// respective values before it creates a go routine to handle
			// request.  Otherwise, if this must later time out the invoked
			// request header before that returns, that handler might
			// concurrently try to alter request headers while this is reading
			// them to emit the log line.
			hm = make(map[string]string, lhrh)
			for _, name := range loggedHeaders {
				value := r.Header.Get(name)
				if value == "" {
					value = "-"
				}
				hm[name] = value // NOTE: only saves first value, because that is all that is logged.
			}
		}

		if config.EscrowReader {
			var erb *bytes.Buffer // escrow read buffer
			if config.BufPool != nil {
				// Obtain a bytes.Buffer from the buffer pool, but use defer to
				// return the used buffer to the pool because we cannot control
				// whether the specified next http.Handler or callback function
				// will panic.
				erb = config.BufPool.Get()
				defer config.BufPool.Put(erb)
			}

			// Only pre-allocate buffer when the Content-Length parses. It would
			// be really nice to provide some signaling mechanism to the next
			// handler when the Content-Length fails to parse, but I suppose if
			// it cares, it will also check the same thing.
			if contentLengthString := r.Header.Get("Content-Length"); contentLengthString != "" {
				if contentLength, err := strconv.Atoi(contentLengthString); err == nil {
					if erb != nil {
						// Ensure existing buffer is large enough to read
						// Content-Length bytes.
						erb.Grow(contentLength)
					} else {
						// Pre-allocate a buffer large enough to read
						// Content-Length bytes.
						erb = bytes.NewBuffer(make([]byte, 0, contentLength))
					}
				}
			}

			// Update the original request's Body to point to a newly created
			// structure, from which the next handler may read the request body,
			// and from which the callback may also read the request body if
			// required.
			er = gorill.NewEscrowReader(r.Body, erb)
			r.Body = er
		}

		ctx := r.Context()

		if config.Timeout > 0 {
			// Adding a timeout to a request context spins off a goroutine that
			// will invoke the specified cancel function for us after the
			// timeout has elapsed.  Invoking the cancel function causes the
			// context's Done channel to close.  Detecting timeout is done by
			// waiting for context.Done() to close.
			var cancel func()
			ctx, cancel = context.WithTimeout(ctx, config.Timeout)
			defer cancel()
			r = r.WithContext(ctx)
		}

		var bb *bytes.Buffer
		if config.BufPool != nil {
			bb = config.BufPool.Get()
			defer config.BufPool.Put(bb)
		} else {
			bb = new(bytes.Buffer)
		}

		// Create a responseWriter to pass to next.ServeHTTP and collect
		// downstream handler's response to query.  It will eventually be used
		// to flush to the client, assuming neither the handler panics, nor the
		// client connection is detected to be closed.
		grw := &responseWriter{hrw: w, begin: time.Now(), body: bb}

		// Create a couple of channels to detect one of 3 ways to exit this
		// handler.
		handlerCompleted := make(chan struct{})
		handlerPanicked := make(chan string, 1)

		// We must invoke downstream handler in separate goroutine in order to
		// ensure this handler only responds to one of the three events below,
		// whichever event takes place first.
		go serveWithPanicProtection(grw, r, next, handlerCompleted, handlerPanicked)

		// Wait for the first of either of 3 events:
		//   * serveComplete: the next.ServeHTTP method completed normally
		//     (possibly even with an erroneous status code).
		//   * servePanicked: the next.ServeHTTP method failed to complete, and
		//     panicked instead with a text message.
		//   * context is done: triggered when timeout or client disconnect.
		select {
		case <-handlerCompleted:
			grw.handlerComplete()
		case error := <-handlerPanicked:
			if config.AllowPanics {
				panic(error) // do not need to tell downstream to cancel, because it already panicked.
			}
			grw.handlerError(error, http.StatusInternalServerError)
		case <-ctx.Done():
			// While there are several reasons why the context may be closed,
			// when it is because the client terminates the request while the
			// handler is still working, the handler might still interact with
			// the response writer given to it.  Therefore, create and use a new
			// response writer for the remaining duration of this call that the
			// handler does not have simultaneous access to it.
			grw = &responseWriter{hrw: w, begin: grw.begin, body: bytes.NewBuffer(make([]byte, 0, 128))}

			// When the context is canceled, ctx.Err() will say why.  Returning
			// a 503 because this is what http.TimeoutHandler returns for same
			// case, even though this means 503 will be logged in server log
			// when client has terminated the connection.
			grw.handlerError(ctx.Err().Error(), http.StatusServiceUnavailable)
		}

		statusClass := grw.status / 100 // integer division (429 / 100 -> 4)

		// Update status counters
		if config.Counters != nil {
			atomic.AddUint64(&config.Counters.counters[0], 1)           // all
			atomic.AddUint64(&config.Counters.counters[statusClass], 1) // 1xx, 2xx, 3xx, 4xx, 5xx
		}

		// Invoke callback if provided, prior to logging request.
		var stats *Statistics
		if config.Callback != nil {
			stats = &Statistics{
				RequestBegin:   grw.begin,
				ResponseStatus: grw.status,
				ResponseEnd:    grw.end,
			}
			if er != nil {
				stats.RequestBody = er.Bytes()
			}
			config.Callback(stats)
		}

		// Update log
		if config.LogWriter != nil {
			if (stats != nil && stats.emitLog) || (atomic.LoadUint32(config.LogBitmask))&(1<<uint32(statusClass-1)) > 0 {
				grw.loggedRequestHeaders = hm
				buf := make([]byte, 0, 128)
				for _, emitter := range emitters {
					emitter(grw, r, &buf)
				}
				_, _ = config.LogWriter.Write(buf)
			}
		}
	})
}
<|endoftext|>


<commit_before>package tar

import (
	archivetar "archive/tar"
	"compress/gzip"
	"errors"
	"io"
	"os"
	"path/filepath"

	"github.com/dgageot/getme/files"
	"github.com/dgageot/getme/urls"
)

func Extract(url string, source string, destinationFolder string) error {
	reader, err := os.Open(source)
	if err != nil {
		return err
	}
	defer reader.Close()

	var tarReader *archivetar.Reader
	if urls.IsGzipArchive(url) {
		archive, err := gzip.NewReader(reader)
		if err != nil {
			return err
		}
		defer archive.Close()
		tarReader = archivetar.NewReader(archive)
	} else {
		tarReader = archivetar.NewReader(reader)
	}

	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		path := filepath.Join(destinationFolder, header.Name)
		info := header.FileInfo()
		if info.IsDir() {
			if err = os.MkdirAll(path, info.Mode()); err != nil {
				return err
			}
			continue
		}

		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
			if err := os.Symlink(header.Linkname, path); err != nil {
				return err
			}
			continue
		}

		if err := files.CopyFrom(path, info.Mode(), tarReader); err != nil {
			return err
		}
	}

	return nil
}

func ExtractFiles(url string, source string, filesToExtract []files.ExtractedFile) error {
	reader, err := os.Open(source)
	if err != nil {
		return err
	}
	defer reader.Close()

	var tarReader *archivetar.Reader
	if urls.IsGzipArchive(url) {
		archive, err := gzip.NewReader(reader)
		if err != nil {
			return err
		}
		defer archive.Close()
		tarReader = archivetar.NewReader(archive)
	} else {
		tarReader = archivetar.NewReader(reader)
	}

	extracted := 0
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		fileToExtract := files.FindExtractedFile(header.Name, filesToExtract)
		if fileToExtract == nil {
			continue
		}

		if err := files.CopyFrom(fileToExtract.Destination, header.FileInfo().Mode(), tarReader); err != nil {
			return err
		}

		extracted++
		if extracted == len(filesToExtract) {
			return nil
		}
	}

	return errors.New("Files not found")
}
<commit_msg>Simplify import<commit_after>package tar

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"io"
	"os"
	"path/filepath"

	"github.com/dgageot/getme/files"
	"github.com/dgageot/getme/urls"
)

func Extract(url string, source string, destinationFolder string) error {
	reader, err := os.Open(source)
	if err != nil {
		return err
	}
	defer reader.Close()

	var tarReader *tar.Reader
	if urls.IsGzipArchive(url) {
		archive, err := gzip.NewReader(reader)
		if err != nil {
			return err
		}
		defer archive.Close()
		tarReader = tar.NewReader(archive)
	} else {
		tarReader = tar.NewReader(reader)
	}

	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		path := filepath.Join(destinationFolder, header.Name)
		info := header.FileInfo()
		if info.IsDir() {
			if err = os.MkdirAll(path, info.Mode()); err != nil {
				return err
			}
			continue
		}

		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
			if err := os.Symlink(header.Linkname, path); err != nil {
				return err
			}
			continue
		}

		if err := files.CopyFrom(path, info.Mode(), tarReader); err != nil {
			return err
		}
	}

	return nil
}

func ExtractFiles(url string, source string, filesToExtract []files.ExtractedFile) error {
	reader, err := os.Open(source)
	if err != nil {
		return err
	}
	defer reader.Close()

	var tarReader *tar.Reader
	if urls.IsGzipArchive(url) {
		archive, err := gzip.NewReader(reader)
		if err != nil {
			return err
		}
		defer archive.Close()
		tarReader = tar.NewReader(archive)
	} else {
		tarReader = tar.NewReader(reader)
	}

	extracted := 0
	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		fileToExtract := files.FindExtractedFile(header.Name, filesToExtract)
		if fileToExtract == nil {
			continue
		}

		if err := files.CopyFrom(fileToExtract.Destination, header.FileInfo().Mode(), tarReader); err != nil {
			return err
		}

		extracted++
		if extracted == len(filesToExtract) {
			return nil
		}
	}

	return errors.New("Files not found")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

//var mainFinder = regexp.MustCompile(`^\s*package\s+main`)
var mainFinder = regexp.MustCompile(`^(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/\n)*|(//.*\n)*package\s+main`)

func getTargets() map[string]string {
	targets := map[string]string{}
	processed := map[string]bool{}
	toResolve := map[string][]string{}

	walkFn := func(path string, info os.FileInfo, err error) error {
		if string(path[0]) == "." {
			return filepath.SkipDir
		}
		if !info.IsDir() {
			// We're looking at a file somewhere

			fileDir := filepath.Dir(path)
			if processed[fileDir] {
				// only need to process one .go file per directory
				return nil
			}
			if filepath.Ext(path) == ".go" {
				// We've found the first .go file in this directory

				// check for "package main"
				fh, err := os.Open(path)
				if err != nil {
					fatal("error opening source file:", err)
				}
				defer fh.Close()
				buf := bufio.NewReader(fh)

				if !mainFinder.MatchReader(buf) {
					// If the first .go file we find doesn't have "package main"
					// at the beginning, we're not interested in this directory
					processed[fileDir] = true
					return nil
				}

				// Found package main, this is a binary
				targetName := filepath.Base(fileDir)

				// See if there is a conflicting target name
				if _, found := targets[targetName]; found {
					debug("Conflicting target name", targetName, "found")
					// Is this the first conflict? Start the queue with the
					// original if so.
					if _, found := toResolve[targetName]; !found {
						toResolve[targetName] = []string{targets[targetName]}
					}
					// Add the conflicting target
					toResolve[targetName] = append(toResolve[targetName], fileDir)

				} else {
					// Add the target hame
					targets[targetName] = fileDir
				}
				processed[fileDir] = true
			}
		}
		return nil
	}
	err := filepath.Walk(cwd, walkFn)
	if err != nil {
		fatal("Error scanning directory:", err)
	}
	// resolve any conflicting target names
	for targetName, paths := range toResolve {
		// remove the conflicting entry from the targets list
		delete(targets, targetName)
		for _, path := range paths {
			newTargetName := strings.Replace(path, cwd, "", 1)
			newTargetName = strings.Replace(newTargetName, string(os.PathSeparator), "", 1)
			newTargetName = strings.Replace(newTargetName, string(os.PathSeparator), "_", -1)
			targets[newTargetName] = path
		}
	}
	return targets
}
<commit_msg>let's try non-greedy<commit_after>package main

import (
	"bufio"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var mainFinder = regexp.MustCompile(`^(?:/\*(?:.|[\r\n])*?\*/)*|(?://.*\n)*package\s+main`)

func getTargets() map[string]string {
	targets := map[string]string{}
	processed := map[string]bool{}
	toResolve := map[string][]string{}

	walkFn := func(path string, info os.FileInfo, err error) error {
		if string(path[0]) == "." {
			return filepath.SkipDir
		}
		if !info.IsDir() {
			// We're looking at a file somewhere

			fileDir := filepath.Dir(path)
			if processed[fileDir] {
				// only need to process one .go file per directory
				return nil
			}
			if filepath.Ext(path) == ".go" {
				// We've found the first .go file in this directory

				// check for "package main"
				fh, err := os.Open(path)
				if err != nil {
					fatal("error opening source file:", err)
				}
				defer fh.Close()
				buf := bufio.NewReader(fh)

				if !mainFinder.MatchReader(buf) {
					// If the first .go file we find doesn't have "package main"
					// at the beginning, we're not interested in this directory
					processed[fileDir] = true
					return nil
				}

				// Found package main, this is a binary
				targetName := filepath.Base(fileDir)

				// See if there is a conflicting target name
				if _, found := targets[targetName]; found {
					debug("Conflicting target name", targetName, "found")
					// Is this the first conflict? Start the queue with the
					// original if so.
					if _, found := toResolve[targetName]; !found {
						toResolve[targetName] = []string{targets[targetName]}
					}
					// Add the conflicting target
					toResolve[targetName] = append(toResolve[targetName], fileDir)

				} else {
					// Add the target hame
					targets[targetName] = fileDir
				}
				processed[fileDir] = true
			}
		}
		return nil
	}
	err := filepath.Walk(cwd, walkFn)
	if err != nil {
		fatal("Error scanning directory:", err)
	}
	// resolve any conflicting target names
	for targetName, paths := range toResolve {
		// remove the conflicting entry from the targets list
		delete(targets, targetName)
		for _, path := range paths {
			newTargetName := strings.Replace(path, cwd, "", 1)
			newTargetName = strings.Replace(newTargetName, string(os.PathSeparator), "", 1)
			newTargetName = strings.Replace(newTargetName, string(os.PathSeparator), "_", -1)
			targets[newTargetName] = path
		}
	}
	return targets
}
<|endoftext|>


<commit_before>package tdigest

import (
	"fmt"
	"math"
	"math/rand"
)

// A TDigest is an efficient data structure for computing streaming
// approximate quantiles of a dataset. It supports two methods:
//
// Add will add a value to the TDigest, updating all quantiles. A
// weight can be specified; use weight of 1 if you don't care about
// weighting your dataset.
//
// Quantile(q) will estimate the qth quantile value of the
// dataset. The input value of q should be in the range [0.0, 1.0]; if
// it is outside that range, it will be clipped into it automatically.
//
// Calling Quantile on a TDigest with no data should return NaN.
//
// MergeInto(other) will add all of the data within a TDigest into
// other, combining them into one larger TDigest.
type TDigest interface {
	Add(val float64, weight int64)
	Quantile(q float64) (val float64)
	MergeInto(other TDigest)
}

// New produces a new TDigest using the default compression level of
// 100.
func New() TDigest {
	return NewWithCompression(100)
}

// NewWithCompression produces a new TDigest with a specific
// compression level. The input compression value, which should be >=
// 1.0, will control how aggressively the TDigest compresses data
// together.
//
// The original TDigest paper suggests using a value of 100 for a good
// balance between precision and efficiency. It will land at very
// small (think like 1e-6 percentile points) errors at extreme points
// in the distribution, and compression ratios of around 500 for large
// data sets (1 millionish datapoints).
func NewWithCompression(compression float64) TDigest {
	return newCentroidSet(compression)
}

// centroid is a simple container for a mean,count pair.
type centroid struct {
	mean  float64
	count int64
}

func (c *centroid) String() string {
	return fmt.Sprintf("c{%f x%d}", c.mean, c.count)
}

type centroidSet struct {
	centroids   []*centroid
	compression float64
	countTotal  int64

	reclusterAt int
}

func newCentroidSet(compression float64) *centroidSet {
	return &centroidSet{
		centroids:   make([]*centroid, 0),
		compression: compression,
		countTotal:  0,
	}
}

// Find the indexes of centroids which have the minimum distance to the
// input value.
//
// TODO: Use a better data structure to avoid this loop.
func (cs *centroidSet) nearest(val float64) []int {
	var (
		nearestDist float64 = math.Inf(+1)
		thisDist    float64
		delta       float64
		result      []int = make([]int, 0)
	)
	for i, c := range cs.centroids {
		thisDist = val - c.mean
		if thisDist < 0 {
			thisDist *= -1
		}

		delta = thisDist - nearestDist
		switch {
		case delta < 0:
			// we have a new winner!
			nearestDist = thisDist
			result = result[0:0] // wipe result
			result = append(result, i)
		case delta == 0:
			// we have a tie
			result = append(result, i)
		default:
			// Since cs.centroids is sorted by mean, this means we
			// have passed the best spot, so we may as well break
			break
		}
	}
	return result
}

// returns the maximum weight that can be placed at specified index
func (cs *centroidSet) weightLimit(idx int) int64 {
	ptile := cs.quantileOf(idx)
	limit := int64(4 * cs.compression * ptile * (1 - ptile) * float64(len(cs.centroids)))
	return limit
}

// checks whether the centroid has room for more weight
func (cs *centroidSet) centroidHasRoom(idx int) bool {
	return cs.centroids[idx].count < cs.weightLimit(idx)
}

// find which centroid to add the value to (by index)
func (cs *centroidSet) findAddTarget(val float64) int {
	var (
		nearest  []int = cs.nearest(val)
		eligible []int
	)

	for _, c := range nearest {
		// if there is room for more weight at this centroid...
		if cs.centroidHasRoom(c) {
			eligible = append(eligible, c)
		}
	}

	if len(eligible) == 0 {
		return -1
	}
	if len(eligible) == 1 {
		return eligible[0]
	}

	// Multiple eligible centroids to add to. They must be equidistant
	// from this value. Four cases are possible:
	//
	//   1. All eligible centroids' means are less than val
	//   2. Some eligible centroids' means are less than val, some are greater
	//   3. All eligible centroids' means are exactly equal to val
	//   4. All eligible centroids' means are greater than val
	//
	// If 1, then we should take the highest indexed centroid to
	// preserve ordering.  If 4, we should take the lowest for the
	// same reason. If 2 or 3, we can pick randomly.

	var anyLesser, anyGreater bool
	for _, c := range eligible {
		m := cs.centroids[c].mean
		if m < val {
			anyLesser = true
		} else if m > val {
			anyGreater = true
		}
	}

	// case 1: all are less, none are greater. Take highest one.
	if anyLesser && !anyGreater {
		greatest := eligible[0]
		for _, c := range eligible[1:] {
			if c > greatest {
				greatest = c
			}
		}
		return greatest
	}

	// case 4: all are greater, none are less. Take lowest one.
	if !anyLesser && anyGreater {
		least := eligible[0]
		for _, c := range eligible[1:] {
			if c < least {
				least = c
			}
		}
		return least
	}

	// case 2 or 3: Anything else. Pick randomly.
	return eligible[rand.Intn(len(eligible))]
}

func (cs *centroidSet) addNewCentroid(mean float64, weight int64) {
	var idx int = len(cs.centroids)

	for i, c := range cs.centroids {
		// add in sorted order
		if mean < c.mean {
			idx = i
			break
		}
	}

	cs.centroids = append(cs.centroids, nil)
	copy(cs.centroids[idx+1:], cs.centroids[idx:])
	cs.centroids[idx] = &centroid{mean, weight}
}

// Add a value to the centroidSet.
func (cs *centroidSet) Add(val float64, weight int64) {
	cs.countTotal += weight
	var idx = cs.findAddTarget(val)

	if idx == -1 {
		cs.addNewCentroid(val, weight)
		return
	}

	c := cs.centroids[idx]

	limit := cs.weightLimit(idx)
	// how much weight will we be adding?
	// if adding this node to this centroid would put it over the
	// weight limit, just add the most we can and recur with the remainder
	if c.count+weight > limit {
		add := limit - c.count
		if add < 0 {
			// this node was already overweight
			add = 0
		}
		remainder := weight - add

		c.count += add
		c.mean = c.mean + float64(add)*(val-c.mean)/float64(c.count)

		cs.Add(val, remainder)
	} else {
		c.count += weight
		c.mean = c.mean + float64(weight)*(val-c.mean)/float64(c.count)
	}

}

// returns the approximate quantile that a particular centroid
// represents
func (cs *centroidSet) quantileOf(idx int) float64 {
	var total int64
	for _, c := range cs.centroids[:idx] {
		total += c.count
	}
	return (float64(cs.centroids[idx].count/2) + float64(total)) / float64(cs.countTotal)
}

// Quantile returns the approximate value at a quantile (eg the 99th
// percentile value would be centroidSet.quantileValue(0.99))
func (cs *centroidSet) Quantile(q float64) float64 {
	var n = len(cs.centroids)
	if n == 0 {
		return math.NaN()
	}
	if n == 1 {
		return cs.centroids[0].mean
	}

	if q < 0 {
		q = 0
	} else if q > 1 {
		q = 1
	}

	// rescale into count units instead of 0 to 1 units
	q = float64(cs.countTotal) * q
	// find the first centroid which straddles q
	var (
		qTotal float64 = 0
		i      int
	)
	for i = 0; i < n && float64(cs.centroids[i].count)/2+qTotal < q; i++ {
		qTotal += float64(cs.centroids[i].count)
	}

	if i == 0 {
		// special case 1: the targeted quantile is before the
		// left-most centroid. extrapolate from the slope from
		// centroid0 to centroid1.
		c0 := cs.centroids[0]
		c1 := cs.centroids[1]
		slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
		deltaQ := q - float64(c0.count)/2 // this is negative
		return c0.mean + slope*deltaQ
	}
	if i == n {
		// special case 2: the targeted quantile is from the
		// right-most centroid. extrapolate from the slope at the
		// right edge.
		c0 := cs.centroids[n-2]
		c1 := cs.centroids[n-1]
		slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
		deltaQ := q - (qTotal - float64(c1.count)/2)
		return c1.mean + slope*deltaQ
	}
	// common case: targeted quantile is between 2 centroids
	c0 := cs.centroids[i-1]
	c1 := cs.centroids[i]
	slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
	deltaQ := q - (float64(c1.count)/2 + qTotal)
	return c1.mean + slope*deltaQ
}

func (cs *centroidSet) MergeInto(other TDigest) {
	// Add each centroid in cs into other. They should be added in
	// random order.
	addOrder := rand.Perm(len(cs.centroids))
	for _, idx := range addOrder {
		c := cs.centroids[idx]
		// gradually write up the volume written so that the tdigest doesnt overload early
		added := int64(0)
		for i := int64(1); i < 10; i++ {
			toAdd := i * 2
			if added+i > c.count {
				toAdd = c.count - added
			}
			other.Add(c.mean, toAdd)
			added += toAdd
			if added >= c.count {
				break
			}
		}
		if added < c.count {
			other.Add(c.mean, c.count-added)
		}
		other.Add(c.mean, c.count)
	}
}
<commit_msg>Remove unused 'reclusterAt' field of *centroidSet<commit_after>package tdigest

import (
	"fmt"
	"math"
	"math/rand"
)

// A TDigest is an efficient data structure for computing streaming
// approximate quantiles of a dataset. It supports two methods:
//
// Add will add a value to the TDigest, updating all quantiles. A
// weight can be specified; use weight of 1 if you don't care about
// weighting your dataset.
//
// Quantile(q) will estimate the qth quantile value of the
// dataset. The input value of q should be in the range [0.0, 1.0]; if
// it is outside that range, it will be clipped into it automatically.
//
// Calling Quantile on a TDigest with no data should return NaN.
//
// MergeInto(other) will add all of the data within a TDigest into
// other, combining them into one larger TDigest.
type TDigest interface {
	Add(val float64, weight int64)
	Quantile(q float64) (val float64)
	MergeInto(other TDigest)
}

// New produces a new TDigest using the default compression level of
// 100.
func New() TDigest {
	return NewWithCompression(100)
}

// NewWithCompression produces a new TDigest with a specific
// compression level. The input compression value, which should be >=
// 1.0, will control how aggressively the TDigest compresses data
// together.
//
// The original TDigest paper suggests using a value of 100 for a good
// balance between precision and efficiency. It will land at very
// small (think like 1e-6 percentile points) errors at extreme points
// in the distribution, and compression ratios of around 500 for large
// data sets (1 millionish datapoints).
func NewWithCompression(compression float64) TDigest {
	return newCentroidSet(compression)
}

// centroid is a simple container for a mean,count pair.
type centroid struct {
	mean  float64
	count int64
}

func (c *centroid) String() string {
	return fmt.Sprintf("c{%f x%d}", c.mean, c.count)
}

type centroidSet struct {
	centroids   []*centroid
	compression float64
	countTotal  int64
}

func newCentroidSet(compression float64) *centroidSet {
	return &centroidSet{
		centroids:   make([]*centroid, 0),
		compression: compression,
		countTotal:  0,
	}
}

// Find the indexes of centroids which have the minimum distance to the
// input value.
//
// TODO: Use a better data structure to avoid this loop.
func (cs *centroidSet) nearest(val float64) []int {
	var (
		nearestDist float64 = math.Inf(+1)
		thisDist    float64
		delta       float64
		result      []int = make([]int, 0)
	)
	for i, c := range cs.centroids {
		thisDist = val - c.mean
		if thisDist < 0 {
			thisDist *= -1
		}

		delta = thisDist - nearestDist
		switch {
		case delta < 0:
			// we have a new winner!
			nearestDist = thisDist
			result = result[0:0] // wipe result
			result = append(result, i)
		case delta == 0:
			// we have a tie
			result = append(result, i)
		default:
			// Since cs.centroids is sorted by mean, this means we
			// have passed the best spot, so we may as well break
			break
		}
	}
	return result
}

// returns the maximum weight that can be placed at specified index
func (cs *centroidSet) weightLimit(idx int) int64 {
	ptile := cs.quantileOf(idx)
	limit := int64(4 * cs.compression * ptile * (1 - ptile) * float64(len(cs.centroids)))
	return limit
}

// checks whether the centroid has room for more weight
func (cs *centroidSet) centroidHasRoom(idx int) bool {
	return cs.centroids[idx].count < cs.weightLimit(idx)
}

// find which centroid to add the value to (by index)
func (cs *centroidSet) findAddTarget(val float64) int {
	var (
		nearest  []int = cs.nearest(val)
		eligible []int
	)

	for _, c := range nearest {
		// if there is room for more weight at this centroid...
		if cs.centroidHasRoom(c) {
			eligible = append(eligible, c)
		}
	}

	if len(eligible) == 0 {
		return -1
	}
	if len(eligible) == 1 {
		return eligible[0]
	}

	// Multiple eligible centroids to add to. They must be equidistant
	// from this value. Four cases are possible:
	//
	//   1. All eligible centroids' means are less than val
	//   2. Some eligible centroids' means are less than val, some are greater
	//   3. All eligible centroids' means are exactly equal to val
	//   4. All eligible centroids' means are greater than val
	//
	// If 1, then we should take the highest indexed centroid to
	// preserve ordering.  If 4, we should take the lowest for the
	// same reason. If 2 or 3, we can pick randomly.

	var anyLesser, anyGreater bool
	for _, c := range eligible {
		m := cs.centroids[c].mean
		if m < val {
			anyLesser = true
		} else if m > val {
			anyGreater = true
		}
	}

	// case 1: all are less, none are greater. Take highest one.
	if anyLesser && !anyGreater {
		greatest := eligible[0]
		for _, c := range eligible[1:] {
			if c > greatest {
				greatest = c
			}
		}
		return greatest
	}

	// case 4: all are greater, none are less. Take lowest one.
	if !anyLesser && anyGreater {
		least := eligible[0]
		for _, c := range eligible[1:] {
			if c < least {
				least = c
			}
		}
		return least
	}

	// case 2 or 3: Anything else. Pick randomly.
	return eligible[rand.Intn(len(eligible))]
}

func (cs *centroidSet) addNewCentroid(mean float64, weight int64) {
	var idx int = len(cs.centroids)

	for i, c := range cs.centroids {
		// add in sorted order
		if mean < c.mean {
			idx = i
			break
		}
	}

	cs.centroids = append(cs.centroids, nil)
	copy(cs.centroids[idx+1:], cs.centroids[idx:])
	cs.centroids[idx] = &centroid{mean, weight}
}

// Add a value to the centroidSet.
func (cs *centroidSet) Add(val float64, weight int64) {
	cs.countTotal += weight
	var idx = cs.findAddTarget(val)

	if idx == -1 {
		cs.addNewCentroid(val, weight)
		return
	}

	c := cs.centroids[idx]

	limit := cs.weightLimit(idx)
	// how much weight will we be adding?
	// if adding this node to this centroid would put it over the
	// weight limit, just add the most we can and recur with the remainder
	if c.count+weight > limit {
		add := limit - c.count
		if add < 0 {
			// this node was already overweight
			add = 0
		}
		remainder := weight - add

		c.count += add
		c.mean = c.mean + float64(add)*(val-c.mean)/float64(c.count)

		cs.Add(val, remainder)
	} else {
		c.count += weight
		c.mean = c.mean + float64(weight)*(val-c.mean)/float64(c.count)
	}

}

// returns the approximate quantile that a particular centroid
// represents
func (cs *centroidSet) quantileOf(idx int) float64 {
	var total int64
	for _, c := range cs.centroids[:idx] {
		total += c.count
	}
	return (float64(cs.centroids[idx].count/2) + float64(total)) / float64(cs.countTotal)
}

// Quantile returns the approximate value at a quantile (eg the 99th
// percentile value would be centroidSet.quantileValue(0.99))
func (cs *centroidSet) Quantile(q float64) float64 {
	var n = len(cs.centroids)
	if n == 0 {
		return math.NaN()
	}
	if n == 1 {
		return cs.centroids[0].mean
	}

	if q < 0 {
		q = 0
	} else if q > 1 {
		q = 1
	}

	// rescale into count units instead of 0 to 1 units
	q = float64(cs.countTotal) * q
	// find the first centroid which straddles q
	var (
		qTotal float64 = 0
		i      int
	)
	for i = 0; i < n && float64(cs.centroids[i].count)/2+qTotal < q; i++ {
		qTotal += float64(cs.centroids[i].count)
	}

	if i == 0 {
		// special case 1: the targeted quantile is before the
		// left-most centroid. extrapolate from the slope from
		// centroid0 to centroid1.
		c0 := cs.centroids[0]
		c1 := cs.centroids[1]
		slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
		deltaQ := q - float64(c0.count)/2 // this is negative
		return c0.mean + slope*deltaQ
	}
	if i == n {
		// special case 2: the targeted quantile is from the
		// right-most centroid. extrapolate from the slope at the
		// right edge.
		c0 := cs.centroids[n-2]
		c1 := cs.centroids[n-1]
		slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
		deltaQ := q - (qTotal - float64(c1.count)/2)
		return c1.mean + slope*deltaQ
	}
	// common case: targeted quantile is between 2 centroids
	c0 := cs.centroids[i-1]
	c1 := cs.centroids[i]
	slope := (c1.mean - c0.mean) / (float64(c1.count)/2 + float64(c0.count)/2)
	deltaQ := q - (float64(c1.count)/2 + qTotal)
	return c1.mean + slope*deltaQ
}

func (cs *centroidSet) MergeInto(other TDigest) {
	// Add each centroid in cs into other. They should be added in
	// random order.
	addOrder := rand.Perm(len(cs.centroids))
	for _, idx := range addOrder {
		c := cs.centroids[idx]
		// gradually write up the volume written so that the tdigest doesnt overload early
		added := int64(0)
		for i := int64(1); i < 10; i++ {
			toAdd := i * 2
			if added+i > c.count {
				toAdd = c.count - added
			}
			other.Add(c.mean, toAdd)
			added += toAdd
			if added >= c.count {
				break
			}
		}
		if added < c.count {
			other.Add(c.mean, c.count-added)
		}
		other.Add(c.mean, c.count)
	}
}
<|endoftext|>


<commit_before>// vcfanno is a command-line application and an api for annotating intervals (bed or vcf).
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"

	"time"

	"github.com/BurntSushi/toml"
	"github.com/brentp/bix"
	"github.com/brentp/irelate"
	"github.com/brentp/irelate/interfaces"
	. "github.com/brentp/vcfanno/api"
	. "github.com/brentp/vcfanno/shared"
	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

const VERSION = "0.0.8"

func main() {
	fmt.Fprintf(os.Stderr, `
=============================================
vcfanno version %s [built with %s]

see: https://github.com/brentp/vcfanno
=============================================
`, VERSION, runtime.Version())

	ends := flag.Bool("ends", false, "annotate the start and end as well as the interval itself.")
	notstrict := flag.Bool("permissive-overlap", false, "annotate with an overlapping variant even it doesn't"+
		" share the same ref and alt alleles. Default is to require exact match between variants.")
	js := flag.String("js", "", "optional path to a file containing custom javascript functions to be used as ops")
	base := flag.String("base-path", "", "optional base-path to prepend to annotation files in the config")
	flag.Parse()
	inFiles := flag.Args()
	if len(inFiles) != 2 {
		fmt.Printf(`Usage:
%s config.toml intput.vcf > annotated.vcf

To run a server:

%s server

`, os.Args[0], os.Args[0])
		flag.PrintDefaults()
		return
	}
	queryFile := inFiles[1]
	if !(xopen.Exists(queryFile) || queryFile == "-") {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find query file: %s\n", queryFile)
		os.Exit(2)
	}

	var config Config
	if _, err := toml.DecodeFile(inFiles[0], &config); err != nil {
		panic(err)
	}
	config.Base = *base
	for _, a := range config.Annotation {
		err := CheckAnno(&a)
		if err != nil {
			log.Fatal("CheckAnno err:", err)
		}
	}
	sources, e := config.Sources()
	if e != nil {
		log.Fatal(e)
	}

	log.Printf("found %d sources from %d files\n", len(sources), len(config.Annotation))
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	jsString := ReadJs(*js)
	strict := !*notstrict
	var a = NewAnnotator(sources, jsString, *ends, strict)

	var out io.Writer = os.Stdout
	defer os.Stdout.Close()

	var err error
	var bx interfaces.RelatableIterator
	b, err := bix.New(queryFile, 1)

	a.UpdateHeader(b)

	if err != nil {
		log.Fatal(err)
	}
	bx, err = b.Query(nil)
	if err != nil {
		log.Fatal(err)
	}

	files, err := a.SetupStreams()
	if err != nil {
		log.Fatal(err)
	}
	aends := INTERVAL
	if *ends {
		aends = BOTH
	}

	fn := func(v interfaces.Relatable) {
		a.AnnotateEnds(v, aends)
	}

	queryables := make([]interfaces.Queryable, len(files))
	for i, f := range files {
		q, err := bix.New(f, 1)
		if err != nil {
			log.Fatal(err)
		}
		queryables[i] = q
	}
	stream := irelate.PIRelate(6000, 70000, bx, *ends, fn, queryables...)

	// make a reader from the string header.
	hdr := strings.NewReader(b.Header)
	v, err := vcfgo.NewReader(hdr, true)
	out, err = vcfgo.NewWriter(out, v.Header)

	if err != nil {
		log.Fatal(err)
	}

	start := time.Now()
	n := 0

	if os.Getenv("IRELATE_PROFILE") == "TRUE" {
		log.Println("profiling to: irelate.pprof")
		f, err := os.Create("irelate.pprof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	for interval := range stream {
		fmt.Fprintf(out, "%s\n", interval)
		n++
	}
	printTime(start, n)
}

func printTime(start time.Time, n int) {
	dur := time.Since(start)
	duri, duru := dur.Seconds(), "second"
	if duri > float64(600) {
		duri, duru = dur.Minutes(), "minute"
	}
	log.Printf("annotated %d variants in %.2f %ss (%.1f / %s)", n, duri, duru, float64(n)/duri, duru)
}
<commit_msg>add -p flag to set GOMAXPROCS<commit_after>// vcfanno is a command-line application and an api for annotating intervals (bed or vcf).
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"

	"time"

	"github.com/BurntSushi/toml"
	"github.com/brentp/bix"
	"github.com/brentp/irelate"
	"github.com/brentp/irelate/interfaces"
	. "github.com/brentp/vcfanno/api"
	. "github.com/brentp/vcfanno/shared"
	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

const VERSION = "0.0.8"

func main() {
	fmt.Fprintf(os.Stderr, `
=============================================
vcfanno version %s [built with %s]

see: https://github.com/brentp/vcfanno
=============================================
`, VERSION, runtime.Version())

	ends := flag.Bool("ends", false, "annotate the start and end as well as the interval itself.")
	notstrict := flag.Bool("permissive-overlap", false, "annotate with an overlapping variant even it doesn't"+
		" share the same ref and alt alleles. Default is to require exact match between variants.")
	js := flag.String("js", "", "optional path to a file containing custom javascript functions to be used as ops")
	base := flag.String("base-path", "", "optional base-path to prepend to annotation files in the config")
	procs := flag.Int("p", 2, "number of processes to use. default is 2")
	flag.Parse()
	inFiles := flag.Args()
	if len(inFiles) != 2 {
		fmt.Printf(`Usage:
%s config.toml intput.vcf > annotated.vcf

To run a server:

%s server

`, os.Args[0], os.Args[0])
		flag.PrintDefaults()
		return
	}
	queryFile := inFiles[1]
	if !(xopen.Exists(queryFile) || queryFile == "-") {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find query file: %s\n", queryFile)
		os.Exit(2)
	}
	runtime.GOMAXPROCS(*procs)

	var config Config
	if _, err := toml.DecodeFile(inFiles[0], &config); err != nil {
		panic(err)
	}
	config.Base = *base
	for _, a := range config.Annotation {
		err := CheckAnno(&a)
		if err != nil {
			log.Fatal("CheckAnno err:", err)
		}
	}
	sources, e := config.Sources()
	if e != nil {
		log.Fatal(e)
	}

	log.Printf("found %d sources from %d files\n", len(sources), len(config.Annotation))
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	jsString := ReadJs(*js)
	strict := !*notstrict
	var a = NewAnnotator(sources, jsString, *ends, strict)

	var out io.Writer = os.Stdout
	defer os.Stdout.Close()

	var err error
	var bx interfaces.RelatableIterator
	b, err := bix.New(queryFile, 1)

	a.UpdateHeader(b)

	if err != nil {
		log.Fatal(err)
	}
	bx, err = b.Query(nil)
	if err != nil {
		log.Fatal(err)
	}

	files, err := a.SetupStreams()
	if err != nil {
		log.Fatal(err)
	}
	aends := INTERVAL
	if *ends {
		aends = BOTH
	}

	fn := func(v interfaces.Relatable) {
		a.AnnotateEnds(v, aends)
	}

	queryables := make([]interfaces.Queryable, len(files))
	for i, f := range files {
		q, err := bix.New(f, 1)
		if err != nil {
			log.Fatal(err)
		}
		queryables[i] = q
	}
	stream := irelate.PIRelate(6000, 70000, bx, *ends, fn, queryables...)

	// make a reader from the string header.
	hdr := strings.NewReader(b.Header)
	v, err := vcfgo.NewReader(hdr, true)
	out, err = vcfgo.NewWriter(out, v.Header)

	if err != nil {
		log.Fatal(err)
	}

	start := time.Now()
	n := 0

	if os.Getenv("IRELATE_PROFILE") == "TRUE" {
		log.Println("profiling to: irelate.pprof")
		f, err := os.Create("irelate.pprof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	for interval := range stream {
		fmt.Fprintf(out, "%s\n", interval)
		n++
	}
	printTime(start, n)
}

func printTime(start time.Time, n int) {
	dur := time.Since(start)
	duri, duru := dur.Seconds(), "second"
	if duri > float64(600) {
		duri, duru = dur.Minutes(), "minute"
	}
	log.Printf("annotated %d variants in %.2f %ss (%.1f / %s)", n, duri, duru, float64(n)/duri, duru)
}
<|endoftext|>


<commit_before>/*
Package vec implements functions that create or act upon 1D slices of
`float64`.
*/
package vec

import (
	"log"
	"math"
	"runtime"
)

// Ones returns a new 1D slice where all the elements are equal to `1.0`.
func Ones(l int) []float64 {
	o := make([]float64, l)
	f := func(i float64) float64 {
		return 1.0
	}
	MapInPlace(f, o)
	return o
}

// Inc returns a 1D slice, where element `[0] == 0.0`, and each
// subsequent element is incremented by `1.0`.
//
// For example, `m := Inc(3)` is
//
// `[1.0, 2.0 3.0]`.
func Inc(l int) []float64 {
	v := make([]float64, l)
	for i := 0; i < l; i++ {
		v[i] = float64(i)
	}
	return v
}

// Equals checks if two 1D slices have the same length, and contain the same
// entries at each slot.
func Equal(v1, v2 []float64) bool {
	if len(v1) != len(v2) {
		return false
	}
	for i := 0; i < len(v1); i++ {
		if v1[i] != v2[i] {
			return false
		}
	}
	return true
}

// Mul returns a new 1D slice that is the result of element-wise multiplication
// of two 1D slices.
func Mul(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Mul", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] * v2[i]
	}
	return o
}

// Add returns a new 1D slice that is the result of element-wise addition
// of two 1D slices.
func Add(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Add", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] + v2[i]
	}
	return o
}

// Sub returns a new 1D slice that is the result of element-wise subtraction
// of two 1D slices.
func Sub(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Sub", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] - v2[i]
	}
	return o
}

// Div returns a new 1D slice that is the result of element-wise division
// of two 1D slices. If any elements in the 2nd 1D slice are 0, then this
// function call aborts.
func Div(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Div", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		if v2[i] == 0.0 {
			msg := "vec.%v Error: in %v [%v line %v].\n"
			msg += "Entry %v in the second slice is 0.0. Cannot devide by 0.0\n"
			p, f, l, _ := runtime.Caller(1)
			log.Fatalf(msg, "Div", f, runtime.FuncForPC(p).Name(), l, i)
		}
		o[i] = v1[i] * v2[i]
	}
	return o
}

// MapInPlace calls a given elemental function on each Element of a 1D slice,
// returning it afterwards. This function modifies the original 1D slice. If
// a non-mutating operation is desired, use the "Map" function instead.
func MapInPlace(f func(float64) float64, v []float64) {
	for i := 0; i < len(v); i++ {
		v[i] = f(v[i])
	}
}

// Map created a new 1D slice which is populated throw Maping the given
// function to the corresponding entries of a given 1D slice. This function
// does not modify its arguments, instead allocating a new 1D slice to
// contain the result. This is a performance hit. If you are OK with mutating
// the original vector, then use the "ApllyInPlace" function instead.
func Map(f func(float64) float64, v []float64) []float64 {
	o := make([]float64, len(v))
	for i := 0; i < len(v); i++ {
		o[i] = f(v[i])
	}
	return o
}

// Dot is the inner product of two 1D slices of `float64`.
func Dot(v1, v2 []float64) float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Dot", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	var o float64
	for i := 0; i < len(v1); i++ {
		o += v1[i] * v2[i]
	}
	return o
}

// Reset sets the values of all entries in a 2D slice of `float64` to `0.0`.
func Reset(v []float64) {
	f := func(i float64) float64 {
		return 0.0
	}
	MapInPlace(f, v)
	return
}

// Sum returns the sum of the elements of a 1D slice of `float64`.
func Sum(v []float64) float64 {
	var o float64
	for i := 0; i < len(v); i++ {
		o += v[i]
	}
	return o
}

// Norm calculated the norm of a given 1D slice. This is the Euclidean length
// of the slice.
func Norm(v []float64) float64 {
	square := func(i float64) float64 {
		return i * i
	}
	return math.Sqrt(Sum(Map(square, v)))
}
<commit_msg>Fixed an error in vec.Div where it was multiplying instead of deviding<commit_after>/*
Package vec implements functions that create or act upon 1D slices of
`float64`.
*/
package vec

import (
	"log"
	"math"
	"runtime"
)

// Ones returns a new 1D slice where all the elements are equal to `1.0`.
func Ones(l int) []float64 {
	o := make([]float64, l)
	f := func(i float64) float64 {
		return 1.0
	}
	MapInPlace(f, o)
	return o
}

// Inc returns a 1D slice, where element `[0] == 0.0`, and each
// subsequent element is incremented by `1.0`.
//
// For example, `m := Inc(3)` is
//
// `[1.0, 2.0 3.0]`.
func Inc(l int) []float64 {
	v := make([]float64, l)
	for i := 0; i < l; i++ {
		v[i] = float64(i)
	}
	return v
}

// Equals checks if two 1D slices have the same length, and contain the same
// entries at each slot.
func Equal(v1, v2 []float64) bool {
	if len(v1) != len(v2) {
		return false
	}
	for i := 0; i < len(v1); i++ {
		if v1[i] != v2[i] {
			return false
		}
	}
	return true
}

// Mul returns a new 1D slice that is the result of element-wise multiplication
// of two 1D slices.
func Mul(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Mul", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] * v2[i]
	}
	return o
}

// Add returns a new 1D slice that is the result of element-wise addition
// of two 1D slices.
func Add(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Add", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] + v2[i]
	}
	return o
}

// Sub returns a new 1D slice that is the result of element-wise subtraction
// of two 1D slices.
func Sub(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Sub", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		o[i] = v1[i] - v2[i]
	}
	return o
}

// Div returns a new 1D slice that is the result of element-wise division
// of two 1D slices. If any elements in the 2nd 1D slice are 0, then this
// function call aborts.
func Div(v1, v2 []float64) []float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Div", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	o := make([]float64, len(v1))
	for i := 0; i < len(v1); i++ {
		if v2[i] == 0.0 {
			msg := "vec.%v Error: in %v [%v line %v].\n"
			msg += "Entry %v in the second slice is 0.0. Cannot devide by 0.0\n"
			p, f, l, _ := runtime.Caller(1)
			log.Fatalf(msg, "Div", f, runtime.FuncForPC(p).Name(), l, i)
		}
		o[i] = v1[i] / v2[i]
	}
	return o
}

// MapInPlace calls a given elemental function on each Element of a 1D slice,
// returning it afterwards. This function modifies the original 1D slice. If
// a non-mutating operation is desired, use the "Map" function instead.
func MapInPlace(f func(float64) float64, v []float64) {
	for i := 0; i < len(v); i++ {
		v[i] = f(v[i])
	}
}

// Map created a new 1D slice which is populated throw Maping the given
// function to the corresponding entries of a given 1D slice. This function
// does not modify its arguments, instead allocating a new 1D slice to
// contain the result. This is a performance hit. If you are OK with mutating
// the original vector, then use the "ApllyInPlace" function instead.
func Map(f func(float64) float64, v []float64) []float64 {
	o := make([]float64, len(v))
	for i := 0; i < len(v); i++ {
		o[i] = f(v[i])
	}
	return o
}

// Dot is the inner product of two 1D slices of `float64`.
func Dot(v1, v2 []float64) float64 {
	if len(v1) != len(v2) {
		msg := "vec.%v Error: in %v [%v line %v].\n"
		msg += "Length of the first 1D slice is %v, length of the second 1D slice\n"
		msg += "is %v. They must match.\n"
		p, f, l, _ := runtime.Caller(1)
		log.Fatalf(msg, "Dot", f, runtime.FuncForPC(p).Name(), l, len(v1), len(v2))
	}
	var o float64
	for i := 0; i < len(v1); i++ {
		o += v1[i] * v2[i]
	}
	return o
}

// Reset sets the values of all entries in a 2D slice of `float64` to `0.0`.
func Reset(v []float64) {
	f := func(i float64) float64 {
		return 0.0
	}
	MapInPlace(f, v)
	return
}

// Sum returns the sum of the elements of a 1D slice of `float64`.
func Sum(v []float64) float64 {
	var o float64
	for i := 0; i < len(v); i++ {
		o += v[i]
	}
	return o
}

// Norm calculated the norm of a given 1D slice. This is the Euclidean length
// of the slice.
func Norm(v []float64) float64 {
	square := func(i float64) float64 {
		return i * i
	}
	return math.Sqrt(Sum(Map(square, v)))
}
<|endoftext|>